Repository: linkerd/linkerd2
Pull request #7676 (2022-01-24 03:19:30)

build(deps): bump anyhow from 1.0.52 to 1.0.53
Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.52 to 1.0.53.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/dtolnay/anyhow/releases">anyhow's releases</a>.</em></p>
<blockquote>
<h2>1.0.53</h2>
<ul>
<li>Retrigger docs.rs build to work around rustdoc regression (<a href="https://github-redirect.dependabot.com/rust-lang/rust/issues/92331">rust-lang/rust#92331</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/dtolnay/anyhow/commit/729002834c66ae9e943fce4e026e292f41ed3c75"><code>7290028</code></a> Release 1.0.53</li>
<li><a href="https://github.com/dtolnay/anyhow/commit/4e73a1588177cc5ebca972c15f3541e13d8f783f"><code>4e73a15</code></a> Merge pull request <a href="https://github-redirect.dependabot.com/dtolnay/anyhow/issues/217">#217</a> from dtolnay/ensuretest</li>
<li><a href="https://github.com/dtolnay/anyhow/commit/dc087bceb302a1b580933509373674fc887e3862"><code>dc087bc</code></a> Update ensure tests to nightly-2022-01-04</li>
<li><a href="https://github.com/dtolnay/anyhow/commit/6b9978cf2a2955efa375c24a61b20be6791f49ab"><code>6b9978c</code></a> Merge pull request <a href="https://github-redirect.dependabot.com/dtolnay/anyhow/issues/216">#216</a> from dtolnay/ensuretest</li>
<li><a href="https://github.com/dtolnay/anyhow/commit/703182a68a12a0a8c9662654929302ad2e9aecc9"><code>703182a</code></a> Update ensure tests to nightly-2022-01-02</li>
<li><a href="https://github.com/dtolnay/anyhow/commit/2342773e007f6838b9e4a85313b2c8691bb84864"><code>2342773</code></a> Ignore irrefutable_let_patterns lint in test suite</li>
<li><a href="https://github.com/dtolnay/anyhow/commit/bae6962ea25ac6356d109622f4a9f0e0d761cf41"><code>bae6962</code></a> Detect warnings in CI</li>
<li><a href="https://github.com/dtolnay/anyhow/commit/2c2568a47849a78fdf061aefc0a9365f053d1a8f"><code>2c2568a</code></a> Merge pull request <a href="https://github-redirect.dependabot.com/dtolnay/anyhow/issues/215">#215</a> from dtolnay/ensuretest</li>
<li><a href="https://github.com/dtolnay/anyhow/commit/8b029fc149ae2fd39709c88d66e88b4ecb16e9a7"><code>8b029fc</code></a> Update ensure tests to nightly-2021-12-30</li>
<li>See full diff in <a href="https://github.com/dtolnay/anyhow/compare/1.0.52...1.0.53">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=anyhow&package-manager=cargo&previous-version=1.0.52&new-version=1.0.53)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>


Patch:
diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile
index 153ba7fd4..f188f6962 100644
--- a/.devcontainer/Dockerfile
+++ b/.devcontainer/Dockerfile
@@ -8,6 +8,7 @@ RUN apt update && apt upgrade -y
 RUN apt install -y \
     clang \
     cmake \
+    jq \
     libssl-dev \
     lldb \
     lsb-release \
@@ -27,7 +28,8 @@ RUN groupadd --gid=$USER_GID $USER \
 # Install a Docker client that uses the host's Docker daemon
 ARG USE_MOBY=false
 ENV DOCKER_BUILDKIT=1
-RUN curl --proto '=https' --tlsv1.3 -vsSfL https://raw.githubusercontent.com/microsoft/vscode-dev-containers/main/script-library/docker-debian.sh \
+COPY bin/scurl /usr/local/bin/scurl
+RUN scurl -v https://raw.githubusercontent.com/microsoft/vscode-dev-containers/main/script-library/docker-debian.sh \
     | bash -s --  true /var/run/docker-host.sock /var/run/docker.sock "${USER}" "${USE_MOBY}" latest
 
 RUN (echo "LC_ALL=en_US.UTF-8" \
@@ -39,20 +41,24 @@ ENV HOME=/home/$USER
 RUN mkdir -p $HOME/bin
 ENV PATH=$HOME/bin:$PATH
 
-RUN curl --proto '=https' --tlsv1.3 -vsSfLo $HOME/kubectl "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" \
-    && chmod 755 $HOME/kubectl
-RUN curl --proto '=https' --tlsv1.3 -vsSfL https://raw.githubusercontent.com/rancher/k3d/main/install.sh \
+RUN scurl -vo $HOME/bin/kubectl "https://dl.k8s.io/release/$(scurl https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" \
+    && chmod 755 $HOME/bin/kubectl
+RUN scurl -v https://raw.githubusercontent.com/rancher/k3d/main/install.sh \
     | USE_SUDO=false K3D_INSTALL_DIR=$HOME/bin bash
 
-RUN curl --proto '=https' --tlsv1.3 -vsSfL https://sh.rustup.rs \
+ARG YQ_VERSION=v4.2.0
+RUN scurl -vo $HOME/bin/yq "https://github.com/mikefarah/yq/releases/download/${YQ_VERSION}/yq_linux_amd64" \
+    && chmod +x $HOME/bin/yq
+
+RUN scurl -v https://sh.rustup.rs \
     | sh -s -- -y --default-toolchain 1.56.1 -c rustfmt -c clippy -c rls
 
 RUN mkdir /tmp/cargo-deny && cd /tmp/cargo-deny && \
-    curl --proto '=https' --tlsv1.3 -vsSfL https://github.com/EmbarkStudios/cargo-deny/releases/download/0.11.0/cargo-deny-0.11.0-x86_64-unknown-linux-musl.tar.gz | tar zxf - && \
+    scurl -v https://github.com/EmbarkStudios/cargo-deny/releases/download/0.11.0/cargo-deny-0.11.0-x86_64-unknown-linux-musl.tar.gz | tar zxf - && \
     mv cargo-deny-0.11.0-x86_64-unknown-linux-musl/cargo-deny $HOME/bin && \
     cd .. && rm -rf /tmp/cargo-deny
 
-RUN curl --proto '=https' --tlsv1.3 -vsSfL https://run.linkerd.io/install-edge | sh \
+RUN scurl -v https://run.linkerd.io/install-edge | sh \
     && ln -s $(readlink ~/.linkerd2/bin/linkerd) ~/bin/linkerd
 
 ENTRYPOINT ["/usr/local/share/docker-init.sh"]
diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
index 93c60d42e..defc95fec 100644
--- a/.devcontainer/devcontainer.json
+++ b/.devcontainer/devcontainer.json
@@ -1,9 +1,10 @@
 {
     "name": "linkerd2",
-    "image": "ghcr.io/linkerd/dev:v4",
-    // "dockerFile": "./Dockerfile",
+    "image": "ghcr.io/linkerd/dev:v5",
+    //"dockerFile": "./Dockerfile",
     "extensions": [
         "DavidAnson.vscode-markdownlint",
+        "golang.go",
         "matklad.rust-analyzer",
         "NathanRidley.autotrim",
         "samverschueren.final-newline",
diff --git a/.dockerignore b/.dockerignore
index ced00b0a0..eba0118fc 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -7,6 +7,7 @@
 **/node_modules
 bin
 !bin/fetch-proxy
+!bin/scurl
 !bin/install-deps
 !bin/web
 **/Dockerfile*
diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml
index 4ee7a9da1..fcfeb36a3 100644
--- a/.github/workflows/codecov.yml
+++ b/.github/workflows/codecov.yml
@@ -33,7 +33,7 @@ jobs:
     steps:
       - uses: actions/checkout@ec3a7ce113134d7a93b817d10a8272cb61118579
       - name: Yarn setup
-        run: curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version 1.21.1 --network-concurrency 1
+        run: bin/scurl -o- https://yarnpkg.com/install.sh | bash -s -- --version 1.21.1 --network-concurrency 1
       - name: Unit tests
         run: |
           export PATH="$HOME/.yarn/bin:$PATH"
@@ -54,7 +54,7 @@ jobs:
       options: --security-opt seccomp=unconfined
     steps:
       - uses: actions/checkout@ec3a7ce113134d7a93b817d10a8272cb61118579
-      - run: mkdir -p target && cd target && curl -vsL https://github.com/xd009642/tarpaulin/releases/download/0.18.0/cargo-tarpaulin-0.18.0-travis.tar.gz | tar zxvf - && chmod 755 cargo-tarpaulin
+      - run: mkdir -p target && cd target && bin/scurl -v https://github.com/xd009642/tarpaulin/releases/download/0.18.0/cargo-tarpaulin-0.18.0-travis.tar.gz | tar zxvf - && chmod 755 cargo-tarpaulin
       - run: target/cargo-tarpaulin tarpaulin --workspace --out Xml
       - uses: codecov/codecov-action@f32b3a3741e1053eb607407145bc9619351dc93b
         with:
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index f050a8d79..a5ad7a495 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -342,7 +342,7 @@ jobs:
       run: echo "INSTALL=install-edge" >> $GITHUB_ENV
     - name: Check published version
       run: |
-        until RES=$(curl -sL https://run.linkerd.io/$INSTALL | grep "LINKERD2_VERSION=\${LINKERD2_VERSION:-$TAG}") \
+        until RES=$(bin/scurl https://run.linkerd.io/$INSTALL | grep "LINKERD2_VERSION=\${LINKERD2_VERSION:-$TAG}") \
           || (( count++ >= 10 ))
         do
           sleep 30
@@ -361,7 +361,7 @@ jobs:
     - name: Checkout code
       uses: actions/checkout@ec3a7ce113134d7a93b817d10a8272cb61118579
     - name: Log into GCP
-      uses: 'google-github-actions/auth@c6c22902f6af237edb96ede5f25a00e864589b2f'
+      uses: 'google-github-actions/auth@7a360a247cce1245c1d13bc63d8b2ac927d201c8'
       with:
         credentials_json: ${{ secrets.LINKERD_SITE_TOKEN }}
     - name: Edge Helm chart creation and upload
diff --git a/.proxy-version b/.proxy-version
index 1273ca2b6..281405b60 100644
--- a/.proxy-version
+++ b/.proxy-version
@@ -1,1 +1,1 @@
-v2.170.0
+v2.171.0
diff --git a/Cargo.lock b/Cargo.lock
index 827c46b04..7b7f6c422 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -24,9 +24,9 @@ dependencies = [
 
 [[package]]
 name = "anyhow"
-version = "1.0.52"
+version = "1.0.53"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "84450d0b4a8bd1ba4144ce8ce718fbc5d071358b1e5384bace6536b3d1f2d5b3"
+checksum = "94a45b455c14666b85fc40a019e8ab9eb75e3a124e05494f5397122bc9eb06e0"
 
 [[package]]
 name = "async-stream"
@@ -1617,9 +1617,9 @@ dependencies = [
 
 [[package]]
 name = "serde"
-version = "1.0.133"
+version = "1.0.135"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "97565067517b60e2d1ea8b268e59ce036de907ac523ad83a0475da04e818989a"
+checksum = "2cf9235533494ea2ddcdb794665461814781c53f19d87b76e571a1c35acbad2b"
 dependencies = [
  "serde_derive",
 ]
@@ -1636,9 +1636,9 @@ dependencies = [
 
 [[package]]
 name = "serde_derive"
-version = "1.0.133"
+version = "1.0.135"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed201699328568d8d08208fdd080e3ff594e6c422e438b6705905da01005d537"
+checksum = "8dcde03d87d4c973c04be249e7d8f0b35db1c848c487bd43032808e59dd8328d"
 dependencies = [
  "proc-macro2",
  "quote",
diff --git a/Dockerfile-proxy b/Dockerfile-proxy
index 2d564f1d4..166b79e07 100644
--- a/Dockerfile-proxy
+++ b/Dockerfile-proxy
@@ -13,12 +13,13 @@ RUN ./bin/install-deps $TARGETARCH
 FROM --platform=$BUILDPLATFORM curlimages/curl:7.76.1 as fetch
 WORKDIR /build
 COPY bin/fetch-proxy bin/fetch-proxy
+COPY bin/scurl bin/scurl
 COPY .proxy-version proxy-version
 ARG TARGETARCH
 RUN (proxy=$(bin/fetch-proxy $(cat proxy-version) $TARGETARCH) && \
     mv "$proxy" linkerd2-proxy)
 ARG LINKERD_AWAIT_VERSION=v0.2.4
-RUN curl -fsSvLo linkerd-await https://github.com/linkerd/linkerd-await/releases/download/release%2F${LINKERD_AWAIT_VERSION}/linkerd-await-${LINKERD_AWAIT_VERSION}-${TARGETARCH} && chmod +x linkerd-await
+RUN bin/scurl -o linkerd-await https://github.com/linkerd/linkerd-await/releases/download/release%2F${LINKERD_AWAIT_VERSION}/linkerd-await-${LINKERD_AWAIT_VERSION}-${TARGETARCH} && chmod +x linkerd-await
 
 ## compile proxy-identity agent
 FROM go-deps as golang
diff --git a/bin/create-release-tag b/bin/create-release-tag
index fe2fc72f1..4f6467443 100755
--- a/bin/create-release-tag
+++ b/bin/create-release-tag
@@ -3,6 +3,8 @@
 set -o errexit
 set -o nounset
 
+bindir=$( cd "${0%/*}" && pwd )
+
 # Assert at least one and at most two arguments were passed.
 if [[ $# -lt 1 || $# -gt 2 ]]; then
     echo "Error: ${0##*/} accepts 1 or 2 arguments" >&2
@@ -61,7 +63,7 @@ if [ $# -ne 1 ]; then
     url="https://run.linkerd.io/install-edge"
 
     # Get the current edge version.
-    current_edge=$(curl -sL $url | awk -v tag_format="$edge_tag_regex" '$0 ~ tag_format')
+    current_edge=$("$bindir"/scurl $url | awk -v tag_format="$edge_tag_regex" '$0 ~ tag_format')
 
     # Get the third and fourth groups of the regex; they are the month and
     # month minor values for the current edge version.
diff --git a/bin/docker b/bin/docker
index 4998869ea..34039be9f 100755
--- a/bin/docker
+++ b/bin/docker
@@ -22,7 +22,7 @@ if [ ! -f "$dockerbin" ]; then
   mkdir -p "$targetbin"
   (
       cd "$tmp"
-      curl -Lsf -o ./docker.tar.gz "$url"
+      "$bindir"/scurl -o ./docker.tar.gz "$url"
       tar zf ./docker.tar.gz -x docker/docker
   )
   mv "$tmp/docker/docker" "$dockerbin"
diff --git a/bin/fetch-proxy b/bin/fetch-proxy
index 41fb158aa..b08b99cba 100755
--- a/bin/fetch-proxy
+++ b/bin/fetch-proxy
@@ -13,7 +13,7 @@ builddir="$rootdir/target/proxy"
 
 version=${1:-latest}
 if [ "$version" = latest ]; then
-  version=$(curl -sL https://api.github.com/repos/linkerd/linkerd2-proxy/releases/latest |jq -r .tag_name | sed 's,^release/,,')
+  version=$("$bindir"/scurl https://api.github.com/repos/linkerd/linkerd2-proxy/releases/latest |jq -r .tag_name | sed 's,^release/,,')
 fi
 
 assetbase="https://github.com/linkerd/linkerd2-proxy/releases/download/release%2F${version}"
@@ -24,8 +24,8 @@ shafile="${pkgname}.txt"
 
 mkdir -p "$builddir"
 cd "$builddir"
-curl -sLO "$assetbase/$pkgfile"
-curl -sLO "$assetbase/$shafile"
+"$bindir"/scurl -O "$assetbase/$pkgfile"
+"$bindir"/scurl -O "$assetbase/$shafile"
 
 tar -zxvf "$pkgfile" >&2
 expected=$(awk '{print $1}' "$shafile")
diff --git a/bin/helm b/bin/helm
index 7fe659253..1ab232b81 100755
--- a/bin/helm
+++ b/bin/helm
@@ -24,7 +24,7 @@ if [ ! -f "$helmbin" ]; then
     mkdir -p "$targetbin"
     (
         cd "$tmp"
-        curl -Lsf -o "./helm.tar.gz" "$helmcurl"
+        "$bindir"/scurl -o "./helm.tar.gz" "$helmcurl"
         tar zf "./helm.tar.gz" -x "$targetdir"
         chmod +x "$targetdir/helm"
     )
diff --git a/bin/helm-docs b/bin/helm-docs
index da5e72eab..0f0d04ae0 100755
--- a/bin/helm-docs
+++ b/bin/helm-docs
@@ -47,7 +47,7 @@ if [ ! -f "$helmdocsbin" ]; then
     mkdir -p "$targetbin"
     (
         cd "$tmp"
-        curl -Lsf -o "./helm-docs.tar.gz" "$helmdocscurl"
+        "$bindir"/scurl -o "./helm-docs.tar.gz" "$helmdocscurl"
         tar zf "./helm-docs.tar.gz" -x "helm-docs"
         chmod +x "helm-docs"
     )
diff --git a/bin/install-pr b/bin/install-pr
index 1baf4fda4..bbc749156 100755
--- a/bin/install-pr
+++ b/bin/install-pr
@@ -78,13 +78,14 @@ fi
 linkerd2_pulls_url="https://api.github.com/repos/linkerd/linkerd2/pulls"
 linkerd2_integration_url="https://api.github.com/repos/linkerd/linkerd2/actions/workflows/integration_tests.yml"
 
+bindir=$( cd "${BASH_SOURCE[0]%/*}" && pwd )
+
 # Get the URL for downloading the artifacts archive
 auth="Authorization: token $GITHUB_TOKEN"
-branch=$(curl -sL -H "$auth" "$linkerd2_pulls_url/$pr" | jq -r '.head.ref')
-artifacts=$(curl -sL -H "$auth" "$linkerd2_integration_url/runs?branch=$branch" | jq -r '.workflow_runs[0].artifacts_url')
-archive=$(curl -sL -H "$auth" "$artifacts" | jq -r '.artifacts[0].archive_download_url')
+branch=$("$bindir"/scurl -H "$auth" "$linkerd2_pulls_url/$pr" | jq -r '.head.ref')
+artifacts=$("$bindir"/scurl -H "$auth" "$linkerd2_integration_url/runs?branch=$branch" | jq -r '.workflow_runs[0].artifacts_url')
+archive=$("$bindir"/scurl -H "$auth" "$artifacts" | jq -r '.artifacts[0].archive_download_url')
 
-bindir=$( cd "${BASH_SOURCE[0]%/*}" && pwd )
 dir=$(mktemp -d -t "linkerd-pr-$pr.XXXXXXXXXX")
 
 # shellcheck source=_docker.sh
@@ -94,7 +95,7 @@ cd "$dir" || exit
 
 echo "### Downloading images ###"
 
-curl -L -o archive.zip -H "$auth" "$archive"
+"$bindir"/scurl -o archive.zip -H "$auth" "$archive"
 unzip -o archive.zip -d image-archives/
 
 echo "### Loading images into Docker ###"
diff --git a/bin/k3d b/bin/k3d
index 6546877b7..4629fb03d 100755
--- a/bin/k3d
+++ b/bin/k3d
@@ -22,7 +22,7 @@ if [ ! -f "$k3dbin" ]; then
   fi
 
   mkdir -p "$targetbin"
-  curl -sfL -o "$k3dbin" https://github.com/rancher/k3d/releases/latest/download/k3d-$os-$arch
+  "$bindir"/scurl -o "$k3dbin" https://github.com/rancher/k3d/releases/latest/download/k3d-$os-$arch
   chmod +x "$k3dbin"
 fi
 
diff --git a/bin/kind b/bin/kind
index f35717b5a..fe06e081f 100755
--- a/bin/kind
+++ b/bin/kind
@@ -24,7 +24,7 @@ if [ ! -f "$kindbin" ]; then
   fi
 
   mkdir -p "$targetbin"
-  curl -sfL -o "$kindbin" https://github.com/kubernetes-sigs/kind/releases/download/$kindversion/kind-$os-$arch
+  "$bindir"/scurl -o "$kindbin" https://github.com/kubernetes-sigs/kind/releases/download/$kindversion/kind-$os-$arch
   chmod +x "$kindbin"
 fi
 
diff --git a/bin/kubectl b/bin/kubectl
index 61e499f22..728210146 100755
--- a/bin/kubectl
+++ b/bin/kubectl
@@ -26,7 +26,7 @@ if [ ! -f "$kubectlbin" ]; then
   fi
 
   mkdir -p "$targetbin"
-  curl -sfL -o "$kubectlbin" https://storage.googleapis.com/kubernetes-release/release/$kubectlversion/bin/$os/$arch/kubectl${exe}
+  "$bindir"/scurl -o "$kubectlbin" https://storage.googleapis.com/kubernetes-release/release/$kubectlversion/bin/$os/$arch/kubectl${exe}
   chmod +x "$kubectlbin"
 fi
 
diff --git a/bin/lint b/bin/lint
index f27464c1a..d436ce0ce 100755
--- a/bin/lint
+++ b/bin/lint
@@ -24,7 +24,7 @@ lintbin=$targetbin/.golangci-lint-$lintversion$exe
 
 if [ ! -f "$lintbin" ]; then
   mkdir -p "$targetbin"
-  curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/v$lintversion/install.sh | sh -s -- -b . v$lintversion
+  "$bindir"/scurl https://raw.githubusercontent.com/golangci/golangci-lint/v$lintversion/install.sh | sh -s -- -b . v$lintversion
   mv ./golangci-lint$exe "$lintbin"
 fi
 
diff --git a/bin/protoc b/bin/protoc
index 5655e8fca..ece2fe6a9 100755
--- a/bin/protoc
+++ b/bin/protoc
@@ -29,7 +29,7 @@ if [ ! -f "$protocbin" ]; then
   mkdir -p "$targetbin"
   (
     cd "$tmp"
-    curl -L --silent --fail -o "./protoc.zip" "$protocurl"
+    "$bindir"/scurl -o "./protoc.zip" "$protocurl"
     unzip -q "./protoc.zip" bin/protoc
     chmod +x bin/protoc
   )
diff --git a/bin/scurl b/bin/scurl
new file mode 100755
index 000000000..5393dc846
--- /dev/null
+++ b/bin/scurl
@@ -0,0 +1,3 @@
+#!/usr/bin/env sh
+
+exec curl --proto '=https' --tlsv1.2 -sSfL "$@"
diff --git a/bin/shellcheck b/bin/shellcheck
index 36294cb17..23748f352 100755
--- a/bin/shellcheck
+++ b/bin/shellcheck
@@ -22,7 +22,7 @@ if [ ! -f "$scbin" ]; then
   fi
 
   mkdir -p "$targetbin"
-  curl -sLf "https://github.com/koalaman/shellcheck/releases/download/$scversion/shellcheck-${scversion?}.$file" | tar -OxJv "shellcheck-${scversion}/shellcheck" > "$scbin"
+  "$bindir"/scurl "https://github.com/koalaman/shellcheck/releases/download/$scversion/shellcheck-${scversion?}.$file" | tar -OxJv "shellcheck-${scversion}/shellcheck" > "$scbin"
   chmod +x "$scbin"
 fi
 
diff --git a/viz/metrics-api/http_server.go b/viz/metrics-api/http_server.go
index d098c5e81..4d6f95be5 100644
--- a/viz/metrics-api/http_server.go
+++ b/viz/metrics-api/http_server.go
@@ -29,9 +29,8 @@ type handler struct {
 }
 
 func (h *handler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
-	log.WithFields(log.Fields{
-		"req.Method": req.Method, "req.URL": req.URL, "req.Form": req.Form,
-	}).Debugf("Serving %s %s", req.Method, req.URL.Path)
+	log.Debugf("Serving %s %q", req.Method, req.URL.Path)
+
 	// Validate request method
 	if req.Method != http.MethodPost {
 		protohttp.WriteErrorToHTTPResponse(w, fmt.Errorf("POST required"))
diff --git a/viz/metrics-api/prometheus.go b/viz/metrics-api/prometheus.go
index 0f05b7a09..2961caf65 100644
--- a/viz/metrics-api/prometheus.go
+++ b/viz/metrics-api/prometheus.go
@@ -60,7 +60,7 @@ func extractSampleValue(sample *model.Sample) uint64 {
 }
 
 func (s *grpcServer) queryProm(ctx context.Context, query string) (model.Vector, error) {
-	log.Debugf("Query request:\n\t%+v", query)
+	log.Debugf("Query request: %q", query)
 
 	_, span := trace.StartSpan(ctx, "query.prometheus")
 	defer span.End()
@@ -73,8 +73,7 @@ func (s *grpcServer) queryProm(ctx context.Context, query string) (model.Vector,
 	// single data point (aka summary) query
 	res, warn, err := s.prometheusAPI.Query(ctx, query, time.Time{})
 	if err != nil {
-		log.Errorf("Query(%+v) failed with: %+v", query, err)
-		return nil, err
+		return nil, fmt.Errorf("Query failed: %q: %w", query, err)
 	}
 	if warn != nil {
 		log.Warnf("%v", warn)
@@ -82,9 +81,7 @@ func (s *grpcServer) queryProm(ctx context.Context, query string) (model.Vector,
 	log.Debugf("Query response:\n\t%+v", res)
 
 	if res.Type() != model.ValVector {
-		err = fmt.Errorf("Unexpected query result type (expected Vector): %s", res.Type())
-		log.Error(err)
-		return nil, err
+		return nil, fmt.Errorf("Unexpected query result type (expected Vector): %s", res.Type())
 	}
 
 	return res.(model.Vector), nil
diff --git a/viz/metrics-api/stat_summary.go b/viz/metrics-api/stat_summary.go
index d58332526..c15a72a72 100644
--- a/viz/metrics-api/stat_summary.go
+++ b/viz/metrics-api/stat_summary.go
@@ -392,7 +392,7 @@ func (s *grpcServer) serviceResourceQuery(ctx context.Context, req *pb.StatSumma
 			}] = weightedDst.Weight.String()
 		}
 	} else if !kerrors.IsNotFound(err) {
-		log.Errorf("Failed to get weights from ServiceProfile %s: %v", spName, err)
+		log.Errorf("Failed to get weights from ServiceProfile %q: %v", spName, err)
 	}
 
 	for k, weight := range weights {
diff --git a/viz/tap/api/grpc_server.go b/viz/tap/api/grpc_server.go
index 2f3d2b38c..651b99d52 100644
--- a/viz/tap/api/grpc_server.go
+++ b/viz/tap/api/grpc_server.go
@@ -102,7 +102,7 @@ func (s *GRPCTapServer) TapByResource(req *tapPb.TapByResourceRequest, stream ta
 
 	if len(pods) == 0 {
 		var errs strings.Builder
-		fmt.Fprintf(&errs, "no pods to tap for %s/%s\n", res.GetType(), res.GetName())
+		fmt.Fprintf(&errs, "no pods to tap for type=%q name=%q\n", res.GetType(), res.GetName())
 		if len(tapDisabled) > 0 {
 			fmt.Fprintf(&errs, "%d pods found with tap disabled via the %s annotation:\n", len(tapDisabled), vizLabels.VizTapDisabled)
 			for _, pod := range tapDisabled {
@@ -120,7 +120,7 @@ func (s *GRPCTapServer) TapByResource(req *tapPb.TapByResourceRequest, stream ta
 		return status.Errorf(codes.NotFound, errs.String())
 	}
 
-	log.Infof("Tapping %d pods for target: %s", len(pods), res.String())
+	log.Infof("Tapping %d pods for target: %q", len(pods), res.String())
 
 	events := make(chan *tapPb.TapEvent)
 
diff --git a/viz/tap/api/handlers.go b/viz/tap/api/handlers.go
index 4a9b3085a..a9bb0ce83 100644
--- a/viz/tap/api/handlers.go
+++ b/viz/tap/api/handlers.go
@@ -114,7 +114,7 @@ func (h *handler) handleTap(w http.ResponseWriter, req *http.Request, p httprout
 	} else if len(path) == 10 {
 		resource = path[7]
 	} else {
-		err := fmt.Errorf("invalid path: %s", req.URL.Path)
+		err := fmt.Errorf("invalid path: %q", req.URL.Path)
 		h.log.Error(err)
 		renderJSONError(w, err, http.StatusBadRequest)
 		return
@@ -140,7 +140,7 @@ func (h *handler) handleTap(w http.ResponseWriter, req *http.Request, p httprout
 		req.Header.Values(h.groupHeader),
 	)
 	if err != nil {
-		err = fmt.Errorf("tap authorization failed (%s), visit %s for more information", err, pkg.TapRbacURL)
+		err = fmt.Errorf("tap authorization failed (%w), visit %s for more information", err, pkg.TapRbacURL)
 		h.log.Error(err)
 		renderJSONError(w, err, http.StatusForbidden)
 		return
@@ -149,7 +149,7 @@ func (h *handler) handleTap(w http.ResponseWriter, req *http.Request, p httprout
 	tapReq := pb.TapByResourceRequest{}
 	err = protohttp.HTTPRequestToProto(req, &tapReq)
 	if err != nil {
-		err = fmt.Errorf("Error decoding Tap Request proto: %s", err)
+		err = fmt.Errorf("Error decoding Tap Request proto: %w", err)
 		h.log.Error(err)
 		protohttp.WriteErrorToHTTPResponse(w, err)
 		return
@@ -157,7 +157,7 @@ func (h *handler) handleTap(w http.ResponseWriter, req *http.Request, p httprout
 
 	url := pkg.TapReqToURL(&tapReq)
 	if url != req.URL.Path {
-		err = fmt.Errorf("tap request body did not match APIServer URL: %+v != %+v", url, req.URL.Path)
+		err = fmt.Errorf("tap request body did not match APIServer URL: %+v != %q", url, req.URL.Path)
 		h.log.Error(err)
 		protohttp.WriteErrorToHTTPResponse(w, err)
 		return
diff --git a/viz/tap/pkg/protohttp.go b/viz/tap/pkg/protohttp.go
index 26ec53542..ceff84c59 100644
--- a/viz/tap/pkg/protohttp.go
+++ b/viz/tap/pkg/protohttp.go
@@ -2,6 +2,7 @@ package pkg
 
 import (
 	"fmt"
+	"net/url"
 
 	"github.com/linkerd/linkerd2/pkg/k8s"
 	tapPb "github.com/linkerd/linkerd2/viz/tap/gen/tap"
@@ -16,13 +17,17 @@ func TapReqToURL(req *tapPb.TapByResourceRequest) string {
 	if res.GetType() == k8s.Namespace {
 		return fmt.Sprintf(
 			"/apis/tap.linkerd.io/v1alpha1/watch/namespaces/%s/tap",
-			res.GetName(),
+			url.PathEscape(res.GetName()),
 		)
 	}
 
 	// namespaced
 	return fmt.Sprintf(
 		"/apis/tap.linkerd.io/v1alpha1/watch/namespaces/%s/%s/%s/tap",
-		res.GetNamespace(), res.GetType()+"s", res.GetName(),
+		url.PathEscape(res.GetNamespace()),
+		// FIXME(olix0r): This pluralization is probably not correct for all
+		// resource types.
+		url.PathEscape(res.GetType()+"s"),
+		url.PathEscape(res.GetName()),
 	)
 }
diff --git a/web/Dockerfile b/web/Dockerfile
index 43992fecb..be135a8b9 100644
--- a/web/Dockerfile
+++ b/web/Dockerfile
@@ -11,7 +11,7 @@ RUN ./bin/install-deps $TARGETARCH
 
 ## bundle web assets
 FROM --platform=$BUILDPLATFORM node:16-bullseye as webpack-bundle
-RUN curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version 1.22.10 --network-concurrency 1
+RUN bin/scurl --retry=2 https://yarnpkg.com/install.sh | bash -s -- --version 1.22.10 --network-concurrency 1
 
 ENV PATH /root/.yarn/bin:$PATH
 ENV ROOT /linkerd-build
diff --git a/web/app/package.json b/web/app/package.json
index 68ee4bbdd..459fb7fdf 100644
--- a/web/app/package.json
+++ b/web/app/package.json
@@ -9,8 +9,8 @@
     "@fortawesome/free-regular-svg-icons": "5.15.4",
     "@fortawesome/free-solid-svg-icons": "5.15.4",
     "@fortawesome/react-fontawesome": "0.1.16",
-    "@lingui/core": "^3.13.0",
-    "@lingui/macro": "3.13.0",
+    "@lingui/core": "^3.13.2",
+    "@lingui/macro": "3.13.1",
     "@lingui/react": "3.13.0",
     "@material-ui/core": "4.12.3",
     "@material-ui/icons": "4.11.2",
@@ -41,13 +41,13 @@
     "whatwg-fetch": "3.6.2"
   },
   "devDependencies": {
-    "@babel/core": "^7.16.7",
+    "@babel/core": "^7.16.12",
     "@babel/eslint-parser": "^7.16.5",
     "@babel/plugin-proposal-class-properties": "^7.16.7",
-    "@babel/preset-env": "^7.16.8",
+    "@babel/preset-env": "^7.16.11",
     "@babel/preset-react": "^7.16.7",
     "@babel/runtime": "^7.16.7",
-    "@lingui/cli": "3.13.0",
+    "@lingui/cli": "3.13.1",
     "babel-core": "^7.0.0-bridge.0",
     "babel-jest": "^27.4.6",
     "babel-loader": "^8.2.3",
diff --git a/web/app/yarn.lock b/web/app/yarn.lock
index 5fb902647..7dddd9a56 100644
--- a/web/app/yarn.lock
+++ b/web/app/yarn.lock
@@ -14,20 +14,20 @@
   resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.16.8.tgz#31560f9f29fdf1868de8cb55049538a1b9732a60"
   integrity sha512-m7OkX0IdKLKPpBlJtF561YJal5y/jyI5fNfWbPxh2D/nbzzGI4qRyrD8xO2jB24u7l+5I2a43scCG2IrfjC50Q==
 
-"@babel/core@^7.1.0", "@babel/core@^7.12.3", "@babel/core@^7.16.7", "@babel/core@^7.7.2", "@babel/core@^7.8.0":
-  version "7.16.7"
-  resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.16.7.tgz#db990f931f6d40cb9b87a0dc7d2adc749f1dcbcf"
-  integrity sha512-aeLaqcqThRNZYmbMqtulsetOQZ/5gbR/dWruUCJcpas4Qoyy+QeagfDsPdMrqwsPRDNxJvBlRiZxxX7THO7qtA==
+"@babel/core@^7.1.0", "@babel/core@^7.12.3", "@babel/core@^7.16.12", "@babel/core@^7.7.2", "@babel/core@^7.8.0":
+  version "7.16.12"
+  resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.16.12.tgz#5edc53c1b71e54881315923ae2aedea2522bb784"
+  integrity sha512-dK5PtG1uiN2ikk++5OzSYsitZKny4wOCD0nrO4TqnW4BVBTQ2NGS3NgilvT/TEyxTST7LNyWV/T4tXDoD3fOgg==
   dependencies:
     "@babel/code-frame" "^7.16.7"
-    "@babel/generator" "^7.16.7"
+    "@babel/generator" "^7.16.8"
     "@babel/helper-compilation-targets" "^7.16.7"
     "@babel/helper-module-transforms" "^7.16.7"
     "@babel/helpers" "^7.16.7"
-    "@babel/parser" "^7.16.7"
+    "@babel/parser" "^7.16.12"
     "@babel/template" "^7.16.7"
-    "@babel/traverse" "^7.16.7"
-    "@babel/types" "^7.16.7"
+    "@babel/traverse" "^7.16.10"
+    "@babel/types" "^7.16.8"
     convert-source-map "^1.7.0"
     debug "^4.1.0"
     gensync "^1.0.0-beta.2"
@@ -51,16 +51,7 @@
   dependencies:
     eslint-rule-composer "^0.3.0"
 
-"@babel/generator@^7.11.6", "@babel/generator@^7.16.7", "@babel/generator@^7.7.2":
-  version "7.16.7"
-  resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.16.7.tgz#b42bf46a3079fa65e1544135f32e7958f048adbb"
-  integrity sha512-/ST3Sg8MLGY5HVYmrjOgL60ENux/HfO/CsUh7y4MalThufhE/Ff/6EibFDHi4jiDCaWfJKoqbE6oTh21c5hrRg==
-  dependencies:
-    "@babel/types" "^7.16.7"
-    jsesc "^2.5.1"
-    source-map "^0.5.0"
-
-"@babel/generator@^7.16.8":
+"@babel/generator@^7.11.6", "@babel/generator@^7.16.8", "@babel/generator@^7.7.2":
   version "7.16.8"
   resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.16.8.tgz#359d44d966b8cd059d543250ce79596f792f2ebe"
   integrity sha512-1ojZwE9+lOXzcWdWmO6TbUzDfqLD39CmEhN8+2cX9XkDo5yW1OpgfejfliysR2AWLpMamTiOiAp/mtroaymhpw==
@@ -94,6 +85,19 @@
     browserslist "^4.17.5"
     semver "^6.3.0"
 
+"@babel/helper-create-class-features-plugin@^7.16.10":
+  version "7.16.10"
+  resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.16.10.tgz#8a6959b9cc818a88815ba3c5474619e9c0f2c21c"
+  integrity sha512-wDeej0pu3WN/ffTxMNCPW5UCiOav8IcLRxSIyp/9+IF2xJUM9h/OYjg0IJLHaL6F8oU8kqMz9nc1vryXhMsgXg==
+  dependencies:
+    "@babel/helper-annotate-as-pure" "^7.16.7"
+    "@babel/helper-environment-visitor" "^7.16.7"
+    "@babel/helper-function-name" "^7.16.7"
+    "@babel/helper-member-expression-to-functions" "^7.16.7"
+    "@babel/helper-optimise-call-expression" "^7.16.7"
+    "@babel/helper-replace-supers" "^7.16.7"
+    "@babel/helper-split-export-declaration" "^7.16.7"
+
 "@babel/helper-create-class-features-plugin@^7.16.7":
   version "7.16.7"
   resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.16.7.tgz#9c5b34b53a01f2097daf10678d65135c1b9f84ba"
@@ -306,15 +310,10 @@
     chalk "^2.0.0"
     js-tokens "^4.0.0"
 
-"@babel/parser@^7.1.0", "@babel/parser@^7.11.5", "@babel/parser@^7.14.7", "@babel/parser@^7.16.7":
-  version "7.16.7"
-  resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.16.7.tgz#d372dda9c89fcec340a82630a9f533f2fe15877e"
-  integrity sha512-sR4eaSrnM7BV7QPzGfEX5paG/6wrZM3I0HDzfIAK06ESvo9oy3xBuVBxE3MbQaKNhvg8g/ixjMWo2CGpzpHsDA==
-
-"@babel/parser@^7.16.8":
-  version "7.16.8"
-  resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.16.8.tgz#61c243a3875f7d0b0962b0543a33ece6ff2f1f17"
-  integrity sha512-i7jDUfrVBWc+7OKcBzEe5n7fbv3i2fWtxKzzCvOjnzSxMfWMigAhtfJ7qzZNGFNMsCCd67+uz553dYKWXPvCKw==
+"@babel/parser@^7.1.0", "@babel/parser@^7.11.5", "@babel/parser@^7.14.7", "@babel/parser@^7.16.10", "@babel/parser@^7.16.12", "@babel/parser@^7.16.7":
+  version "7.16.12"
+  resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.16.12.tgz#9474794f9a650cf5e2f892444227f98e28cdf8b6"
+  integrity sha512-VfaV15po8RiZssrkPweyvbGVSe4x2y+aciFCgn0n0/SJMR22cwofRV1mtnJQYcSB1wUTaA/X1LnA3es66MCO5A==
 
 "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.16.7":
   version "7.16.7"
@@ -434,12 +433,12 @@
     "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0"
     "@babel/plugin-syntax-optional-chaining" "^7.8.3"
 
-"@babel/plugin-proposal-private-methods@^7.16.7":
-  version "7.16.7"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.7.tgz#e418e3aa6f86edd6d327ce84eff188e479f571e0"
-  integrity sha512-7twV3pzhrRxSwHeIvFE6coPgvo+exNDOiGUMg39o2LiLo1Y+4aKpfkcLGcg1UHonzorCt7SNXnoMyCnnIOA8Sw==
+"@babel/plugin-proposal-private-methods@^7.16.11":
+  version "7.16.11"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.11.tgz#e8df108288555ff259f4527dbe84813aac3a1c50"
+  integrity sha512-F/2uAkPlXDr8+BHpZvo19w3hLFKge+k75XUprE6jaqKxjGkSYcK+4c+bup5PdW/7W/Rpjwql7FTVEDW+fRAQsw==
   dependencies:
-    "@babel/helper-create-class-features-plugin" "^7.16.7"
+    "@babel/helper-create-class-features-plugin" "^7.16.10"
     "@babel/helper-plugin-utils" "^7.16.7"
 
 "@babel/plugin-proposal-private-property-in-object@^7.16.7":
@@ -516,14 +515,7 @@
   dependencies:
     "@babel/helper-plugin-utils" "^7.8.0"
 
-"@babel/plugin-syntax-jsx@^7.10.4":
-  version "7.16.0"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.0.tgz#f9624394317365a9a88c82358d3f8471154698f1"
-  integrity sha512-8zv2+xiPHwly31RK4RmnEYY5zziuF3O7W2kIDW+07ewWDh6Oi0dRq8kwvulRkFgt6DB97RlKs5c1y068iPlCUg==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.14.5"
-
-"@babel/plugin-syntax-jsx@^7.16.7":
+"@babel/plugin-syntax-jsx@^7.10.4", "@babel/plugin-syntax-jsx@^7.16.7":
   version "7.16.7"
   resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.7.tgz#50b6571d13f764266a113d77c82b4a6508bbe665"
   integrity sha512-Esxmk7YjA8QysKeT3VhTXvF6y77f/a91SIs4pWb4H2eWGQkCKFgQaG6hdoEVZtGsrAcb2K5BW66XsOErD4WU3Q==
@@ -876,10 +868,10 @@
     "@babel/helper-create-regexp-features-plugin" "^7.16.7"
     "@babel/helper-plugin-utils" "^7.16.7"
 
-"@babel/preset-env@^7.16.8":
-  version "7.16.8"
-  resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.16.8.tgz#e682fa0bcd1cf49621d64a8956318ddfb9a05af9"
-  integrity sha512-9rNKgVCdwHb3z1IlbMyft6yIXIeP3xz6vWvGaLHrJThuEIqWfHb0DNBH9VuTgnDfdbUDhkmkvMZS/YMCtP7Elg==
+"@babel/preset-env@^7.16.11":
+  version "7.16.11"
+  resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.16.11.tgz#5dd88fd885fae36f88fd7c8342475c9f0abe2982"
+  integrity sha512-qcmWG8R7ZW6WBRPZK//y+E3Cli151B20W1Rv7ln27vuPaXU/8TKms6jFdiJtF7UDTxcrb7mZd88tAeK9LjdT8g==
   dependencies:
     "@babel/compat-data" "^7.16.8"
     "@babel/helper-compilation-targets" "^7.16.7"
@@ -899,7 +891,7 @@
     "@babel/plugin-proposal-object-rest-spread" "^7.16.7"
     "@babel/plugin-proposal-optional-catch-binding" "^7.16.7"
     "@babel/plugin-proposal-optional-chaining" "^7.16.7"
-    "@babel/plugin-proposal-private-methods" "^7.16.7"
+    "@babel/plugin-proposal-private-methods" "^7.16.11"
     "@babel/plugin-proposal-private-property-in-object" "^7.16.7"
     "@babel/plugin-proposal-unicode-property-regex" "^7.16.7"
     "@babel/plugin-syntax-async-generators" "^7.8.4"
@@ -1003,26 +995,10 @@
     "@babel/parser" "^7.16.7"
     "@babel/types" "^7.16.7"
 
-"@babel/traverse@^7.13.0", "@babel/traverse@^7.16.7", "@babel/traverse@^7.7.2":
-  version "7.16.7"
-  resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.16.7.tgz#dac01236a72c2560073658dd1a285fe4e0865d76"
-  integrity sha512-8KWJPIb8c2VvY8AJrydh6+fVRo2ODx1wYBU2398xJVq0JomuLBZmVQzLPBblJgHIGYG4znCpUZUZ0Pt2vdmVYQ==
-  dependencies:
-    "@babel/code-frame" "^7.16.7"
-    "@babel/generator" "^7.16.7"
-    "@babel/helper-environment-visitor" "^7.16.7"
-    "@babel/helper-function-name" "^7.16.7"
-    "@babel/helper-hoist-variables" "^7.16.7"
-    "@babel/helper-split-export-declaration" "^7.16.7"
-    "@babel/parser" "^7.16.7"
-    "@babel/types" "^7.16.7"
-    debug "^4.1.0"
-    globals "^11.1.0"
-
-"@babel/traverse@^7.16.8":
-  version "7.16.8"
-  resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.16.8.tgz#bab2f2b09a5fe8a8d9cad22cbfe3ba1d126fef9c"
-  integrity sha512-xe+H7JlvKsDQwXRsBhSnq1/+9c+LlQcCK3Tn/l5sbx02HYns/cn7ibp9+RV1sIUqu7hKg91NWsgHurO9dowITQ==
+"@babel/traverse@^7.13.0", "@babel/traverse@^7.16.10", "@babel/traverse@^7.16.7", "@babel/traverse@^7.16.8", "@babel/traverse@^7.7.2":
+  version "7.16.10"
+  resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.16.10.tgz#448f940defbe95b5a8029975b051f75993e8239f"
+  integrity sha512-yzuaYXoRJBGMlBhsMJoUW7G1UmSb/eXr/JHYM/MsOJgavJibLwASijW7oXBdw3NQ6T0bW7Ty5P/VarOs9cHmqw==
   dependencies:
     "@babel/code-frame" "^7.16.7"
     "@babel/generator" "^7.16.8"
@@ -1030,7 +1006,7 @@
     "@babel/helper-function-name" "^7.16.7"
     "@babel/helper-hoist-variables" "^7.16.7"
     "@babel/helper-split-export-declaration" "^7.16.7"
-    "@babel/parser" "^7.16.8"
+    "@babel/parser" "^7.16.10"
     "@babel/types" "^7.16.8"
     debug "^4.1.0"
     globals "^11.1.0"
@@ -1331,28 +1307,28 @@
   resolved "https://registry.yarnpkg.com/@leichtgewicht/ip-codec/-/ip-codec-2.0.3.tgz#0300943770e04231041a51bd39f0439b5c7ab4f0"
   integrity sha512-nkalE/f1RvRGChwBnEIoBfSEYOXnCRdleKuv6+lePbMDrMZXeDQnqak5XDOeBgrPPyPfAdcCu/B5z+v3VhplGg==
 
-"@lingui/babel-plugin-extract-messages@^3.13.0":
-  version "3.13.0"
-  resolved "https://registry.yarnpkg.com/@lingui/babel-plugin-extract-messages/-/babel-plugin-extract-messages-3.13.0.tgz#cab57047a8e6d34903f3378eda6907f54210d6d4"
-  integrity sha512-akDiMq+CrF3m4ENA3DlEj+XfskZow6SqvrkOUVIStow5kUqcCBow635W7+YAem2TJNxH+CpVgpGV24osiQx+ZQ==
+"@lingui/babel-plugin-extract-messages@^3.13.1":
+  version "3.13.1"
+  resolved "https://registry.yarnpkg.com/@lingui/babel-plugin-extract-messages/-/babel-plugin-extract-messages-3.13.1.tgz#af5dddc18317cde7d113cabde2f74ad76dcd5405"
+  integrity sha512-K0ekhQI49ZTE90bVxvndqdxO80X1ZjacVdznWn4RJq6EEN9ElppMKkWUmAe/vfHGJRCH/2aUIp73xvaXPJPbGg==
   dependencies:
     "@babel/generator" "^7.11.6"
     "@babel/runtime" "^7.11.2"
-    "@lingui/conf" "^3.13.0"
+    "@lingui/conf" "^3.13.1"
     mkdirp "^1.0.4"
 
-"@lingui/cli@3.13.0":
-  version "3.13.0"
-  resolved "https://registry.yarnpkg.com/@lingui/cli/-/cli-3.13.0.tgz#d3ffa2143ee524ac436467336bf2db082f8f678b"
-  integrity sha512-hK/7z+hqxT9CSzUQUQEefurbjmZCJldLG9kbSp8mNgJ+XLAv1mWPve79pYCbtMK7M7vbyU4uG0ncnH+pHKFF/w==
+"@lingui/cli@3.13.1":
+  version "3.13.1"
+  resolved "https://registry.yarnpkg.com/@lingui/cli/-/cli-3.13.1.tgz#7d8f84d384a9df2d737b6cd8af3be097f3d939c5"
+  integrity sha512-JGfbdAn1qxHBjuhnLeERMhCLe7UXSFafqq9S//g3+VNHKHfVHfa0CKFUmISMDKMLFdKmbdJCZpYU3DRZNrUGyQ==
   dependencies:
     "@babel/generator" "^7.11.6"
     "@babel/parser" "^7.11.5"
     "@babel/plugin-syntax-jsx" "^7.10.4"
     "@babel/runtime" "^7.11.2"
     "@babel/types" "^7.11.5"
-    "@lingui/babel-plugin-extract-messages" "^3.13.0"
-    "@lingui/conf" "^3.13.0"
+    "@lingui/babel-plugin-extract-messages" "^3.13.1"
+    "@lingui/conf" "^3.13.1"
     babel-plugin-macros "^3.0.1"
     bcp-47 "^1.0.7"
     chalk "^4.1.0"
@@ -1378,10 +1354,10 @@
     pseudolocale "^1.1.0"
     ramda "^0.27.1"
 
-"@lingui/conf@^3.13.0":
-  version "3.13.0"
-  resolved "https://registry.yarnpkg.com/@lingui/conf/-/conf-3.13.0.tgz#caaef1b29e59e0e40adea92eb942edd676b239f7"
-  integrity sha512-1vl7NEZWMuiM2JCqnvlGmoyqlwB4isSEZrzvKWGAGMRLxMuuKR6PrH1Khgl4x2WRLZxfEysXTe6YR08Ra68irQ==
+"@lingui/conf@^3.13.1":
+  version "3.13.1"
+  resolved "https://registry.yarnpkg.com/@lingui/conf/-/conf-3.13.1.tgz#06d9ada1b9bd6a428e07a39ed5a6d0a9933abbe5"
+  integrity sha512-xWJVdgNiGqYzkYIxHg4c6KqSNleN5/96M2ly+GzBOmA5H75r4hz27DfQpxuC4FuBUAPC+Mk1HTBO9/aFO0BCZg==
   dependencies:
     "@babel/runtime" "^7.11.2"
     "@endemolshinegroup/cosmiconfig-typescript-loader" "^3.0.2"
@@ -1390,22 +1366,22 @@
     jest-validate "^26.5.2"
     lodash.get "^4.4.2"
 
-"@lingui/core@^3.13.0":
-  version "3.13.0"
-  resolved "https://registry.yarnpkg.com/@lingui/core/-/core-3.13.0.tgz#0b83ba400b0b4abb24a86eb9e24cf9148cb2d84b"
-  integrity sha512-UDmI8UL59rLmQDDjBK8JFMX0+i3+pncl3fWG+tD2cXNJkN+MEBrhECTQ2lsM1tCk09AfiATglPPXm1e0tLxxOw==
+"@lingui/core@^3.13.0", "@lingui/core@^3.13.2":
+  version "3.13.2"
+  resolved "https://registry.yarnpkg.com/@lingui/core/-/core-3.13.2.tgz#1c8b264c7eb5d7fa11c59916542bf5fc8e1b9309"
+  integrity sha512-ic1uC+bS7hpfM4oVugHKel8UhlLAwykSv2TYw3oyeEQhvCS232nSzh+PFbP0BXK1hZ0UdHve7mODpgADuwHIQA==
   dependencies:
     "@babel/runtime" "^7.11.2"
     make-plural "^6.2.2"
     messageformat-parser "^4.1.3"
 
-"@lingui/macro@3.13.0":
-  version "3.13.0"
-  resolved "https://registry.yarnpkg.com/@lingui/macro/-/macro-3.13.0.tgz#accb4a97ff7109d76647a1114f6527037cab5fef"
-  integrity sha512-TmwAiFnxtutDEKp7KFtUmq5vIfv56zn0FV0ZgrISUcW1liVlRyqW6YnQ7cv4AzsPnkBhO2+O2YVoHY1r5owMvA==
+"@lingui/macro@3.13.1":
+  version "3.13.1"
+  resolved "https://registry.yarnpkg.com/@lingui/macro/-/macro-3.13.1.tgz#5b0f57d7ef77b09bdf0d2107422dd3a4ace99c39"
+  integrity sha512-iXdAbREJpIUs3s78Erbg+7ZRuJsD0S0nyGCeEo9Ml/NDO/MtVYo7XCHecwtCdNxDe/h0NItB3m/7uPZ/BvOLOA==
   dependencies:
     "@babel/runtime" "^7.11.2"
-    "@lingui/conf" "^3.13.0"
+    "@lingui/conf" "^3.13.1"
     ramda "^0.27.1"
 
 "@lingui/react@3.13.0":


Test patch:
diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml
index d321cf42a..68b5128c9 100644
--- a/.github/workflows/unit_tests.yml
+++ b/.github/workflows/unit_tests.yml
@@ -34,7 +34,7 @@ jobs:
     - name: Checkout code
       uses: actions/checkout@ec3a7ce113134d7a93b817d10a8272cb61118579
     - name: Yarn setup
-      run: curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version 1.21.1 --network-concurrency 1
+      run: bin/scurl --retry=2 https://yarnpkg.com/install.sh | bash -s -- --version 1.21.1 --network-concurrency 1
     - name: JS unit tests
       run: |
         export PATH="$HOME/.yarn/bin:$PATH"
diff --git a/bin/_test-helpers.sh b/bin/_test-helpers.sh
index fe02a7b8c..080e1b37a 100644
--- a/bin/_test-helpers.sh
+++ b/bin/_test-helpers.sh
@@ -387,7 +387,7 @@ run_test(){
 # Returns the latest version for the release channel
 # $1: release channel to check
 latest_release_channel() {
-    curl -s https://versioncheck.linkerd.io/version.json | grep -o "$1-[0-9]*.[0-9]*.[0-9]*"
+    "$bindir"/scurl https://versioncheck.linkerd.io/version.json | grep -o "$1-[0-9]*.[0-9]*.[0-9]*"
 }
 
 # Install a specific Linkerd version.
@@ -399,7 +399,7 @@ install_version() {
     local install_url=$1
     local version=$2
 
-    curl -s "$install_url" | HOME=$tmp sh > /dev/null 2>&1
+    "$bindir"/scurl "$install_url" | HOME=$tmp sh > /dev/null 2>&1
 
     local linkerd_path=$tmp/.linkerd2/bin/linkerd
     local test_app_namespace=upgrade-test
diff --git a/bin/test-scale b/bin/test-scale
index 24d5cec8b..3a2c78718 100755
--- a/bin/test-scale
+++ b/bin/test-scale
@@ -15,6 +15,8 @@ set -e
 NAMESPACES=5
 REPLICAS=5
 
+bindir=$( cd "${0%/*}" && pwd )
+
 # TODO: share these functions with test-run
 
 check_linkerd_binary(){
@@ -75,11 +77,11 @@ linkerd_namespace=${2:-l5d-scale}
 # Deploy Books
 #
 
-BOOKS_BACKEND=$(curl -s https://raw.githubusercontent.com/BuoyantIO/booksapp/main/k8s/mysql-backend.yml)
+BOOKS_BACKEND=$("$bindir"/scurl https://raw.githubusercontent.com/BuoyantIO/booksapp/main/k8s/mysql-backend.yml)
 
-AUTHORS_SP=$(curl -s https://run.linkerd.io/booksapp/authors.swagger)
-BOOKS_SP=$(curl -s https://run.linkerd.io/booksapp/books.swagger)
-WEBAPP_SP=$(curl -s https://run.linkerd.io/booksapp/webapp.swagger)
+AUTHORS_SP=$("$bindir"/scurl https://run.linkerd.io/booksapp/authors.swagger)
+BOOKS_SP=$("$bindir"/scurl https://run.linkerd.io/booksapp/books.swagger)
+WEBAPP_SP=$("$bindir"/scurl https://run.linkerd.io/booksapp/webapp.swagger)
 
 # deploy books backend and service profiles to N namespaces
 for ((i=1; i <= NAMESPACES; i++)); do
@@ -92,7 +94,7 @@ for ((i=1; i <= NAMESPACES; i++)); do
     echo "$WEBAPP_SP"  | bin/linkerd profile -n "$booksns" webapp  --open-api - | kubectl apply -f -
 done
 
-BOOKS_APP=$(curl -s https://raw.githubusercontent.com/BuoyantIO/booksapp/main/k8s/mysql-app.yml)
+BOOKS_APP=$("$bindir"/scurl https://raw.githubusercontent.com/BuoyantIO/booksapp/main/k8s/mysql-app.yml)
 
 # add "-sleep=10ms" param to the traffic app (~100rps)
 traffic_param="        - \"webapp:7000\""
@@ -120,7 +122,7 @@ done
 # Deploy Emojivoto
 #
 
-EMOJIVOTO=$(curl -s https://run.linkerd.io/emojivoto.yml)
+EMOJIVOTO=$("$bindir"/scurl https://run.linkerd.io/emojivoto.yml)
 
 # delete namespace
 EMOJIVOTO=$(echo "$EMOJIVOTO" | tail -n +6)
@@ -146,7 +148,7 @@ done
 # Lifecycle / bb
 #
 
-LIFECYCLE=$(curl -s https://raw.githubusercontent.com/linkerd/linkerd-examples/master/lifecycle/lifecycle.yml)
+LIFECYCLE=$("$bindir"/scurl https://raw.githubusercontent.com/linkerd/linkerd-examples/master/lifecycle/lifecycle.yml)
 
 # inject
 LIFECYCLE=$(echo "$LIFECYCLE" | $linkerd_path -l "$linkerd_namespace" inject -)
diff --git a/test/integration/tap/tap_test.go b/test/integration/tap/tap_test.go
index 7643ef0fd..3dc836bb4 100644
--- a/test/integration/tap/tap_test.go
+++ b/test/integration/tap/tap_test.go
@@ -140,7 +140,7 @@ func TestCliTap(t *testing.T) {
 			if stderr == "" {
 				testutil.Fatal(t, "expected an error, got none")
 			}
-			expectedErr := `no pods to tap for deployment/t4
+			expectedErr := `no pods to tap for type="deployment" name="t4"
 1 pods found with tap disabled via the viz.linkerd.io/disable-tap annotation:`
 			split := strings.Split(stderr, "\n")
 			actualErr := strings.Join(split[:2], "\n")
diff --git a/viz/tap/api/grpc_server_test.go b/viz/tap/api/grpc_server_test.go
index d82f625c4..e8099b759 100644
--- a/viz/tap/api/grpc_server_test.go
+++ b/viz/tap/api/grpc_server_test.go
@@ -92,7 +92,7 @@ status:
 			},
 		},
 		{
-			err: status.Errorf(codes.NotFound, "no pods to tap for pod/emojivoto-not-meshed\n"),
+			err: status.Errorf(codes.NotFound, "no pods to tap for type=\"pod\" name=\"emojivoto-not-meshed\"\n"),
 			k8sRes: []string{`
 apiVersion: v1
 kind: Pod
@@ -158,7 +158,7 @@ status:
 			},
 		},
 		{
-			err: status.Errorf(codes.NotFound, "no pods to tap for pod/emojivoto-meshed\n"),
+			err: status.Errorf(codes.NotFound, "no pods to tap for type=\"pod\" name=\"emojivoto-meshed\"\n"),
 			k8sRes: []string{`
 apiVersion: v1
 kind: Pod
@@ -186,7 +186,7 @@ status:
 			},
 		},
 		{
-			err: status.Errorf(codes.NotFound, `no pods to tap for pod/emojivoto-meshed-tap-disabled
+			err: status.Errorf(codes.NotFound, `no pods to tap for type="pod" name="emojivoto-meshed-tap-disabled"
 1 pods found with tap disabled via the viz.linkerd.io/disable-tap annotation:
 	* emojivoto-meshed-tap-disabled
 remove this annotation to make these pods valid tap targets
@@ -224,7 +224,7 @@ status:
 			},
 		},
 		{
-			err: status.Errorf(codes.NotFound, `no pods to tap for pod/emojivoto-meshed-tap-not-enabled
+			err: status.Errorf(codes.NotFound, `no pods to tap for type="pod" name="emojivoto-meshed-tap-not-enabled"
 1 pods found with tap not enabled:
 	* emojivoto-meshed-tap-not-enabled
 restart these pods to enable tap and make them valid tap targets
diff --git a/viz/tap/api/handlers_test.go b/viz/tap/api/handlers_test.go
index 650160a07..ea68feda1 100644
--- a/viz/tap/api/handlers_test.go
+++ b/viz/tap/api/handlers_test.go
@@ -29,7 +29,7 @@ func TestHandleTap(t *testing.T) {
 			},
 			code:   http.StatusBadRequest,
 			header: http.Header{"Content-Type": []string{"application/json"}},
-			body:   `{"error":"invalid path: /apis"}`,
+			body:   `{"error":"invalid path: \"/apis\""}`,
 		},
 		{
 			req: &http.Request{