Repository: GoogleContainerTools/skaffold
Pull request #8584 (2023-03-24 16:12:00)

fix: use active gcp account
<!-- Include if applicable: -->
Fixes: #6996 <!-- tracking issues that this PR will close -->
**Description**
 - update the method to `get` gcp active account credential 
 - The original method to retrieve account credential always produces error when calling credential.tokenSource.token method. This might have not been verified when it was implemented, seems a little strange to `create` credential with an access token. My understanding is that the credential is used to retrieve an access token and the token can be used to initiate other requests to other services. oauth.google package can use adc(application default credential) 
```json
 "client_id": "..."
 "client_secret" :".."
 "refresh_token":"...."
 "type": ".."
 ``` 
to construct tokenSource which is used retrieve access token , we can also implement our own token source and provide it to google.Credentials struct , then the tokenSource.token() will be called when needed to request gcp services. 

## Test Plan
 - create a service account from your project 
 - create keyfile for your account
 - run ``gcloud auth activate-service-account {account_name} --key-file={file}`` to activate your account
 - run ``skaffold build -vdebug`` in ``integration/testdata/gcb-explicit-repo`` project, the run should fail if you didn't give your service account k8s-skaffold storage access and artifact registry, this is good to prove that we're using the active account to issue request
 - example message ``creating bucket if not exists: getting bucket "k8s-skaffold_cloudbuild": googleapi: Error 403: {{service-account-name}} does not have storage.buckets.get access to the Google Cloud Storage bucket. Permission 'storage.buckets.get' denied on resource (or it may not exist)., forbidden``






Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d4f6dfec8..167b2787b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,68 @@
+# v2.3.0 Release - 03/28/2023
+**Linux amd64**
+`curl -Lo skaffold https://storage.googleapis.com/skaffold/releases/v2.3.0/skaffold-linux-amd64 && chmod +x skaffold && sudo mv skaffold /usr/local/bin`
+
+**Linux arm64**
+`curl -Lo skaffold https://storage.googleapis.com/skaffold/releases/v2.3.0/skaffold-linux-arm64 && chmod +x skaffold && sudo mv skaffold /usr/local/bin`
+
+**macOS amd64**
+`curl -Lo skaffold https://storage.googleapis.com/skaffold/releases/v2.3.0/skaffold-darwin-amd64 && chmod +x skaffold && sudo mv skaffold /usr/local/bin`
+
+**macOS arm64**
+`curl -Lo skaffold https://storage.googleapis.com/skaffold/releases/v2.3.0/skaffold-darwin-arm64 && chmod +x skaffold && sudo mv skaffold /usr/local/bin`
+
+**Windows**
+https://storage.googleapis.com/skaffold/releases/v2.3.0/skaffold-windows-amd64.exe
+
+**Docker image**
+`gcr.io/k8s-skaffold/skaffold:v2.3.0`
+
+Note: This release comes with a new config version, `v4beta4`. To upgrade your skaffold.yaml, use `skaffold fix`. If you choose not to upgrade, skaffold will auto-upgrade as best as it can.
+
+Highlights:
+* `skaffold verify` functionality fixed to properly support environment variables and has updated support allowing users to now runs verify tests as Kubernetes Jobs (in additional to the previously supported local container option)
+* When using the `tolerateFailuresUntilDeadline` or `--tolerate-failures-until-deadline` flag, now Skaffold will also tolerate specific cluster connection issues until deadline (in additonal to the previous supported k8s status issues).
+
+New Features and Additions:
+* feat: add 'skaffold inspect jobManifestPath' and 'skaffold transform-schema jobManifestPath' commands [#8575](https://github.com/GoogleContainerTools/skaffold/pull/8575)
+* feat: add k8s Job support to verify and status check [#8415](https://github.com/GoogleContainerTools/skaffold/pull/8415)
+* feat: Whitelist strimzi.io CRDs [#8491](https://github.com/GoogleContainerTools/skaffold/pull/8491)
+
+Fixes:
+* fix: add upgrade logic to inject a kubectl deployer when an old kustomize deployer is detected [#8457](https://github.com/GoogleContainerTools/skaffold/pull/8457)
+* fix: can't use ctrl-c to terminate building with kaniko at uploading build context stage [#8516](https://github.com/GoogleContainerTools/skaffold/pull/8516)
+* fix: correctly rewrite /deploy/kubectl/manifests in patch upgrades [#8585](https://github.com/GoogleContainerTools/skaffold/pull/8585)
+* fix: improve verify command s.t. os envs not passed through to container envs and instead add a flag for this purpose [#8557](https://github.com/GoogleContainerTools/skaffold/pull/8557)
+* fix: make it so tolerateFailuresUntilDeadline also handles kubectl failures (vs. just parsing kubectl resource status values). [#8549](https://github.com/GoogleContainerTools/skaffold/pull/8549)
+* fix: move verify schema changes to v4beta4 and remove it from already released v4beta3 [#8514](https://github.com/GoogleContainerTools/skaffold/pull/8514)
+
+Updates and Refactors:
+* chore: "revert upgrade docker version in skaffold image (#8583)" [#8590](https://github.com/GoogleContainerTools/skaffold/pull/8590)
+* chore: Add output flag for diagnose [#8546](https://github.com/GoogleContainerTools/skaffold/pull/8546)
+* chore: change verify schema from v1.Container to subset of direct primitive types [#8577](https://github.com/GoogleContainerTools/skaffold/pull/8577)
+* chore: enhance vuln monitor [#8570](https://github.com/GoogleContainerTools/skaffold/pull/8570)
+* chore: fix transformer share config-map issues [#8582](https://github.com/GoogleContainerTools/skaffold/pull/8582)
+* chore: update cloudbuild config to publish distroless-skaffold image to artifact registry for vulns scanning [#8524](https://github.com/GoogleContainerTools/skaffold/pull/8524)
+* chore: upgrade docker version in skaffold image [#8583](https://github.com/GoogleContainerTools/skaffold/pull/8583)
+* chore: upgrade go version in skaffold image [#8540](https://github.com/GoogleContainerTools/skaffold/pull/8540)
+* dep: replace dockerignore.ReadAll withgithub.com/moby/buildkit/frontend/dockerfile/dockerignore.ReadAll [#8488](https://github.com/GoogleContainerTools/skaffold/pull/8488)
+
+Docs, Test, and Release Updates:
+* docs: add tooltip with yaml path in Skaffold yaml reference page [#8477](https://github.com/GoogleContainerTools/skaffold/pull/8477)
+
+
+Huge thanks goes out to all of our contributors for this release:
+
+- Aaron Prindle
+- catusax
+- Dan Williams
+- dependabot[bot]
+- ericzzzzzzz
+- Gaurav
+- Mike Roberts
+- Patryk Małek
+- Renzo Rojas
+
 # v2.2.0 Release - 03/06/2023
 **Linux amd64**
 `curl -Lo skaffold https://storage.googleapis.com/skaffold/releases/v2.2.0/skaffold-linux-amd64 && chmod +x skaffold && sudo mv skaffold /usr/local/bin`
diff --git a/Makefile b/Makefile
index 3d6bf2ebc..e0529afa0 100644
--- a/Makefile
+++ b/Makefile
@@ -210,6 +210,18 @@ build_deps:
 		deploy/skaffold
 	docker push gcr.io/$(GCP_PROJECT)/build_deps:$(DEPS_DIGEST)
 
+skaffold-builder-ci:
+	docker build \
+		--cache-from gcr.io/$(GCP_PROJECT)/build_deps \
+		-f deploy/skaffold/Dockerfile.deps \
+		-t gcr.io/$(GCP_PROJECT)/build_deps \
+		.
+	time docker build \
+		-f deploy/skaffold/Dockerfile \
+		--target builder \
+		-t gcr.io/$(GCP_PROJECT)/skaffold-builder \
+		.
+
 .PHONY: skaffold-builder
 skaffold-builder:
 	time docker build \
@@ -272,7 +284,7 @@ integration-in-k3d: skaffold-builder
 		'
 
 .PHONY: integration-in-docker
-integration-in-docker: skaffold-builder
+integration-in-docker: skaffold-builder-ci
 	docker run --rm \
 		-v /var/run/docker.sock:/var/run/docker.sock \
 		-v $(HOME)/.config/gcloud:/root/.config/gcloud \
diff --git a/cmd/skaffold/app/cmd/inspect.go b/cmd/skaffold/app/cmd/inspect.go
index fa3767f8a..8a6de4cf6 100644
--- a/cmd/skaffold/app/cmd/inspect.go
+++ b/cmd/skaffold/app/cmd/inspect.go
@@ -43,7 +43,7 @@ func NewCmdInspect() *cobra.Command {
 		WithDescription("Helper commands for Cloud Code IDEs to interact with and modify skaffold configuration files.").
 		WithPersistentFlagAdder(cmdInspectFlags).
 		Hidden().
-		WithCommands(cmdModules(), cmdProfiles(), cmdBuildEnv(), cmdTests(), cmdNamespaces())
+		WithCommands(cmdModules(), cmdProfiles(), cmdBuildEnv(), cmdTests(), cmdNamespaces(), cmdJobManifestPaths())
 }
 
 func cmdInspectFlags(f *pflag.FlagSet) {
diff --git a/cmd/skaffold/app/cmd/inspect_job_manifest_paths.go b/cmd/skaffold/app/cmd/inspect_job_manifest_paths.go
new file mode 100644
index 000000000..296168d29
--- /dev/null
+++ b/cmd/skaffold/app/cmd/inspect_job_manifest_paths.go
@@ -0,0 +1,85 @@
+/*
+Copyright 2021 The Skaffold Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package cmd
+
+import (
+	"context"
+	"errors"
+	"io"
+
+	"github.com/spf13/cobra"
+	"github.com/spf13/pflag"
+
+	"github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/inspect"
+	jobManifestPaths "github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/inspect/jobManifestPaths"
+	olog "github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/output/log"
+)
+
+func cmdJobManifestPaths() *cobra.Command {
+	return NewCmd("jobManifestPaths").
+		WithDescription("View skaffold jobManifestPath information defined in the specified skaffold configuration").
+		WithCommands(cmdJobManifestPathsList(), cmdJobManifestPathsModify())
+}
+
+func cmdJobManifestPathsList() *cobra.Command {
+	return NewCmd("list").
+		WithExample("Get list of jobManifestPaths", "inspect jobManifestPaths list --format json").
+		WithExample("Get list of jobManifestPaths targeting a specific configuration", "inspect jobManifestPaths list --profile local --format json").
+		WithDescription("Print the list of jobManifestPaths that would be run for a given configuration (default skaffold configuration, specific module, specific profile, etc).").
+		WithFlagAdder(cmdJobManifestPathsListFlags).
+		NoArgs(listJobManifestPaths)
+}
+
+func cmdJobManifestPathsModify() *cobra.Command {
+	return NewCmd("modify").
+		WithExample("Modify the skaffold verify jobManifestPaths", "inspect jobManifestPaths list --format json").
+		WithExample("Modify the jobManifestPaths targeting a specific configuration", "inspect jobManifestPaths modify --profile local --format json").
+		WithDescription("Print the list of jobManifestPaths that would be run for a given configuration (default skaffold configuration, specific module, specific profile, etc).").
+		WithCommonFlags().
+		WithFlags([]*Flag{
+			// TODO(aaron-prindle) vvv 2 commands use this, should add to common flags w/ those 2 commands added
+			{Value: &outputFile, Name: "output", DefValue: "", Usage: "File to write `inspect jobManifestPath modify` result"},
+		}).
+		WithArgs(func(cmd *cobra.Command, args []string) error {
+			if len(args) != 1 {
+				olog.Entry(context.TODO()).Errorf("`jobManifestPaths modify` requires exactly one manifest file path argument")
+				return errors.New("`jobManifestPaths modify` requires exactly one manifest file path argument")
+			}
+			return nil
+		}, modifyJobManifestPaths)
+}
+
+func listJobManifestPaths(ctx context.Context, out io.Writer) error {
+	return jobManifestPaths.PrintJobManifestPathsList(ctx, out, inspect.Options{
+		Filename:          inspectFlags.filename,
+		RepoCacheDir:      inspectFlags.repoCacheDir,
+		OutFormat:         inspectFlags.outFormat,
+		Modules:           inspectFlags.modules,
+		Profiles:          inspectFlags.profiles,
+		PropagateProfiles: inspectFlags.propagateProfiles,
+	})
+}
+
+func cmdJobManifestPathsListFlags(f *pflag.FlagSet) {
+	f.StringSliceVarP(&inspectFlags.profiles, "profile", "p", nil, `Profile names to activate`)
+	f.BoolVar(&inspectFlags.propagateProfiles, "propagate-profiles", true, `Setting '--propagate-profiles=false' disables propagating profiles set by the '--profile' flag across config dependencies. This mean that only profiles defined directly in the target 'skaffold.yaml' file are activated.`)
+	f.StringSliceVarP(&inspectFlags.modules, "module", "m", nil, "Names of modules to filter target action by.")
+}
+
+func modifyJobManifestPaths(ctx context.Context, out io.Writer, args []string) error {
+	return jobManifestPaths.Modify(ctx, out, opts, args[0], outputFile)
+}
diff --git a/cmd/skaffold/app/cmd/inspect_namespaces.go b/cmd/skaffold/app/cmd/inspect_namespaces.go
index 822f3de7f..1c0f0a3ac 100644
--- a/cmd/skaffold/app/cmd/inspect_namespaces.go
+++ b/cmd/skaffold/app/cmd/inspect_namespaces.go
@@ -26,6 +26,7 @@ import (
 
 	"github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/inspect"
 	namespaces "github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/inspect/namespaces"
+	olog "github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/output/log"
 )
 
 func cmdNamespaces() *cobra.Command {
@@ -42,6 +43,7 @@ func cmdNamespacesList() *cobra.Command {
 		WithFlagAdder(cmdNamespacesListFlags).
 		WithArgs(func(cmd *cobra.Command, args []string) error {
 			if len(args) != 1 {
+				olog.Entry(context.TODO()).Errorf("`inspect namespaces list` requires exactly one manifest file path argument")
 				return errors.New("`inspect namespaces list` requires exactly one manifest file path argument")
 			}
 			return nil
diff --git a/deploy/lts-vuln-monitor/report.sh b/deploy/lts-vuln-monitor/report.sh
deleted file mode 100755
index 44e30b6cb..000000000
--- a/deploy/lts-vuln-monitor/report.sh
+++ /dev/null
@@ -1,85 +0,0 @@
-#!/bin/bash
-# Copyright 2021 The Skaffold Authors
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# This script creates a github issue if it hasn't been created when there
-# are vulnerabilities found in the LTS image.
-
-set -xeo pipefail
-
-# Variables that will be substituted in cloudbuild.yaml.
-if [ -z "$_OS_VULN_LABEL" ]; then
-  _OS_VULN_LABEL="lts os vuln"
-fi
-if [ -z "$_REPO" ]; then
-  _REPO="GoogleContainerTools/skaffold"
-fi
-
-if [ -z "$_REF_ISSUE" ]; then
-  _REF_ISSUE="7169"
-fi
-
-TITLE_OS="LTS image has OS vulnerability!"
-OS_VULN_FILE=/workspace/os_vuln.txt
-IMAGES_TO_REPORT_FILE=/workspace/images_to_report.txt
-
-append() {
-  echo -e $1 >> $2
-}
-
-check_existing_issue() {
-  label=$1
-  # Returns the open issues. There should be only one issue opened at a time.
-  issue_num=$(gh issue list --label="$label" --repo="$_REPO" --json number | grep -oP 'number":\s*\K\d+' | head -n 1)
-
-  if [ "$issue_num" ]; then
-    echo >&2 "There is already an issue opened for the detected vulnerabilities in the LTS images." && echo "$issue_num"
-  else
-    echo "-1"
-  fi
-}
-
-init_body_file(){
- append "Please patch the below images with instructions mentioned [here](https://docs.google.com/document/d/1gYJVoBCZiRzUTQs_-wKsfhHdskiMtJtWWQyI-t0mhC8/edit?resourcekey=0-NdLapTumfpzxH_bri0fLZQ#heading=h.p4mphzyz8m7y).\n" "$IMAGES_TO_REPORT_FILE"
-
- # Only pick the last patched version.
- cat "$OS_VULN_FILE" |sort -nr | awk -F'[:.]' '$3$4!=p&&p=$3$4' >> "$IMAGES_TO_REPORT_FILE"
-
- append "\nOnce the patched images are available, please ping Cloud Deploy team until there is an automated way to notify (issue#$_REF_ISSUE)." "$IMAGES_TO_REPORT_FILE"
-}
-
-create_issue() {
-  title="$1"
-  body_file="$2"
-  label="$3"
-  gh issue create --title="${title}" --label="${label}" --body-file="$body_file" --repo="$_REPO"
-}
-
-update_issue() {
-  num="$1"
-  body_file="$2"
-  gh issue edit "$num" --body-file="$body_file" --repo="$_REPO"
-}
-
-gh auth login --with-token <token.txt
-issue_num=$(check_existing_issue "$_OS_VULN_LABEL")
-
-init_body_file
-if [ "$issue_num" -eq "-1" ]; then
-  echo "Creating an issue..."
-  create_issue "$TITLE_OS" "$IMAGES_TO_REPORT_FILE" "$_OS_VULN_LABEL"
-else
-  echo "Updating issue: #""$issue_num"
-  update_issue "$issue_num" "$IMAGES_TO_REPORT_FILE"
-fi
diff --git a/deploy/lts-vuln-monitor/scan.sh b/deploy/lts-vuln-monitor/scan.sh
deleted file mode 100755
index ef5edec03..000000000
--- a/deploy/lts-vuln-monitor/scan.sh
+++ /dev/null
@@ -1,68 +0,0 @@
-#!/bin/bash
-# Copyright 2021 The Skaffold Authors
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# This script scans the vulnerability report that is generated by Container Analysis.
-
-set -xeo pipefail
-# Variables that will be substituted in cloudbuild.yaml.
-if [ -z "$PROJECT_ID" ]; then
-  PROJECT_ID=k8s-skaffold
-fi
-if [ -z "$_IMAGE" ]; then
-  _IMAGE="skaffold"
-fi
-if [ -z "$_TAG_FILTER" ]; then
-  _TAG_FILTER="v.*lts"
-fi
-if [ -z "$_SEVERITIES" ]; then
-  _SEVERITIES="HIGH CRITICAL"
-fi
-
-# If changed, also change the same variable in report.sh.
-OS_VULN_FILE=/workspace/os_vuln.txt
-BASE_IMAGE="gcr.io/$PROJECT_ID/$_IMAGE"
-
-append() {
-  printf "%s\n" $1 >>$2
-}
-
-check_vulnerability(){
-  base_image=$1
-  tags_filter=$2
-  severities=$3
-  result_file=$4
-  tags=$5
-
-  if [ -z "$tags" ]; then
-    tags=$(gcloud container images list-tags "$base_image" --filter="tags~$tags_filter" --format='value(tags)')
-  fi
-  grep_args=""
-  for s in $severities; do
-    grep_args="$grep_args -e $s"
-  done
-  grep_cmd="grep $grep_args"
-
-  for tagsByComma in $tags; do
-    IFS="," read -ra tagArr <<< "${tagsByComma}"
-    image=$base_image:${tagArr[0]}
-    echo "Checking vulnerabilities of image:" $image
-    gcloud beta container images describe $image  --show-package-vulnerability \
-     | if eval "$grep_cmd"; then append "$base_image":"$tagsByComma" "$result_file"; fi
-  done
-}
-
-# Main
-# Scans the LTS images
-check_vulnerability $BASE_IMAGE "$_TAG_FILTER" "$_SEVERITIES" "$OS_VULN_FILE" "$_TAGS"
diff --git a/deploy/skaffold/Dockerfile.deps b/deploy/skaffold/Dockerfile.deps
index a9b5d2181..b92696381 100644
--- a/deploy/skaffold/Dockerfile.deps
+++ b/deploy/skaffold/Dockerfile.deps
@@ -122,7 +122,9 @@ RUN apt-get update && \
     git python unzip && \
     rm -rf /var/lib/apt/lists/*
 
-COPY --from=docker:19.03.13 /usr/local/bin/docker /usr/local/bin/
+COPY --from=docker:23.0.1 /usr/local/bin/docker /usr/local/bin/
+# From Docker Engine version 23.0.0, Buildx is distributed in a separate package: docker-buildx-plugin. In earlier versions, Buildx was included in the docker-ce-cli package
+COPY --from=docker/buildx-bin:0.10.4 /buildx /usr/libexec/docker/cli-plugins/docker-buildx
 COPY --from=download-kubectl kubectl /usr/local/bin/
 COPY --from=download-helm helm /usr/local/bin/
 COPY --from=download-kustomize kustomize /usr/local/bin/
diff --git a/deploy/lts-vuln-monitor/cloudbuild.yaml b/deploy/vuln-monitor/cloudbuild.yaml
similarity index 57%
rename from deploy/lts-vuln-monitor/cloudbuild.yaml
rename to deploy/vuln-monitor/cloudbuild.yaml
index b6298d848..05b6663e7 100644
--- a/deploy/lts-vuln-monitor/cloudbuild.yaml
+++ b/deploy/vuln-monitor/cloudbuild.yaml
@@ -7,26 +7,20 @@ steps:
   name: gcr.io/cloud-builders/gcloud
   entrypoint: /bin/bash
   args:
-  - ./deploy/lts-vuln-monitor/scan.sh
+  - ./deploy/vuln-monitor/scan.sh
   env:
   - 'PROJECT_ID=$PROJECT_ID'
-  - '_IMAGE=$_IMAGE'
+  - '_BASE_IMAGE=$_BASE_IMAGE'
   - '_TAG_FILTER=$_TAG_FILTER'
-  - '_SEVERITIES=$_SEVERITIES'
+  - '_TAGS=$_TAGS'
 - id: Report vulnerability.
   name: 'gcr.io/$PROJECT_ID/github'
   entrypoint: /bin/bash
   args:
   - -c
   - |
-    if test -f /workspace/os_vuln.txt; then ./deploy/lts-vuln-monitor/report.sh; fi
+    if test -f /workspace/skaffold_vuln.txt; then ./deploy/vuln-monitor/report.sh; fi
   env:
-  - '_OS_VULN_LABEL=$_OS_VULN_LABEL'
   - '_REPO=$_REPO'
-substitutions:
-  _IMAGE: skaffold
-  _TAG_FILTER: v.*lts
-  _SEVERITIES: HIGH CRITICAL
-  _OS_VULN_LABEL: lts os vuln
-  _REPO: GoogleContainerTools/skaffold
-  _GITHUB_TOKEN: LTS_IMAGE_CD_BOT_GITHUB_TOKEN
+  - '_LABEL_PREFIX=$_LABEL_PREFIX'
+  - '_TITLE_PREFIX=$_TITLE_PREFIX'
diff --git a/deploy/vuln-monitor/report.sh b/deploy/vuln-monitor/report.sh
new file mode 100755
index 000000000..41acb0c8b
--- /dev/null
+++ b/deploy/vuln-monitor/report.sh
@@ -0,0 +1,120 @@
+#!/bin/bash
+# Copyright 2021 The Skaffold Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# This script creates a github issue if it hasn't been created when there
+# are vulnerabilities found in the LTS image.
+
+set -xeo pipefail
+
+
+if [ -z "$_REPO" ]; then
+  _REPO="https://github.com/GoogleContainerTools/skaffold"
+fi
+
+if [ -z "$_LABEL_PREFIX" ]; then
+  _LABEL_PREFIX="bin-vul"
+fi
+
+if [ -z "$_TITLE_PREFIX" ]; then
+  _TITLE_PREFIX="vulnerabilities found in skaffold binary"
+fi
+
+VULN_FILE=/workspace/skaffold_vuln.txt
+TOKEN_FILE=token.txt
+
+append() {
+  echo -e $1 >> $2
+}
+
+find_issue() {
+  label=$1
+  issue=$(gh issue list --label "$label" --repo="$_REPO" --json number,title)
+  echo "$issue"
+}
+
+create_issue() {
+  title=$1
+  label=$2
+  image_tag=$3
+  body="Hi @GoogleContainerTools/skaffold-team,
+
+  Vulnerabilities were found in the skaffold binary or base image. Please fix the issue
+  with the instructions mentioned [here](https://docs.google.com/document/d/1gYJVoBCZiRzUTQs_-wKsfhHdskiMtJtWWQyI-t0mhC8/edit?resourcekey=0-NdLapTumfpzxH_bri0fLZQ#heading=h.p4mphzyz8m7y)
+
+  Thank you for your attention.
+  Vulnerabilities details: see [here](https://$image_tag)."
+
+  gh label create --repo="$_REPO" "$label" -c "1D76DB" -d "skaffold has vulnerabilities" --force
+  gh issue create --repo="$_REPO" --title="$title" --label="$label" --body="$body"
+}
+
+close_issue_as_fixed() {
+   issue_num=$1
+   tag=$2
+   gh issue close "$issue_num" --repo="$_REPO" -c "Closing as the issue is fixed in $tag"
+}
+
+close_issue_tracked_in_another() {
+   issue_num=$1
+   new_issue_url=$2
+   gh issue close "$issue_num" --repo="$_REPO" -c "Closing as the issue is tracked in $new_issue_url"
+}
+
+process_report_without_existing_issue() {
+  title=$1
+  label=$2
+  vulnerable=$3
+  image_tag=$4
+  if [ "$vulnerable" == "true" ]; then
+    new_issue_url=$(create_issue "$title" "$label" "$image_tag")
+  fi
+}
+
+process_report_with_existing_issue() {
+   issue=$1
+   title=$2
+   label=$3
+   vulnerable=$4
+   image_tag=$5
+
+   issue_title=$(echo "$issue" | grep -oP '"title": *\K"[^"]*"' | head -n 1 | tr -d '"')
+   issue_num=$(echo "$issue" | grep -oP 'number":\s*\K\d+' | head -n 1)
+
+   if [ "$vulnerable" == "false" ]; then
+      close_issue_as_fixed "$issue_num" "$image_tag"
+   elif [ "$issue_title" != "$title" ]; then
+      new_issue_url=$(create_issue "$title" "$label" "$image_tag")
+      close_issue_tracked_in_another "$issue_num" "$new_issue_url"
+   fi
+}
+gh auth login --with-token < "$TOKEN_FILE"
+# process each line from the file, each line is in the format of title:tag:vulnerable .
+while IFS= read -r line; do
+    echo "Text read from file: $line"
+    tag=$(echo "$line" | awk -F '[:]' '{print $2}')
+    image_tag=$(echo "$line" | awk -F '[:]' '{print $1":"$2}')
+    vulnerable=$(echo "$line" | awk -F '[:]' '{print $3}')
+    label="$_LABEL_PREFIX-${tag%.*}"
+    title="$_TITLE_PREFIX:$tag"
+    # the label is in the format of [bin|os]-vul-x where x is edge or a minor version, such as v1.37, v1.39, v2.0
+    # we use this label to find if the vuls are already tracked and if the original issues should be close due to
+    # the vuls have been fixed in the current tag, or tracked in another issue if the vuls still exist.
+    issue=$(find_issue "$label")
+    if [ '[]' == "$issue" ]; then
+      process_report_without_existing_issue "$title" "$label" "$vulnerable" "$image_tag"
+    else
+      process_report_with_existing_issue "$issue" "$title" "$label" "$vulnerable" "$image_tag"
+    fi
+done < "$VULN_FILE"
\ No newline at end of file
diff --git a/deploy/vuln-monitor/scan.sh b/deploy/vuln-monitor/scan.sh
new file mode 100755
index 000000000..9841fd6f7
--- /dev/null
+++ b/deploy/vuln-monitor/scan.sh
@@ -0,0 +1,66 @@
+#!/bin/bash
+# Copyright 2021 The Skaffold Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# This script scans the vulnerability report that is generated by Container Analysis.
+
+set -xeo pipefail
+# Variables that will be substituted by trigger configuration or valued provided through command line with --substitutions flag.
+if [ -z "$_BASE_IMAGE" ] ; then
+  _BASE_IMAGE="us-east1-docker.pkg.dev/k8s-skaffold/scanning/skaffold"
+fi
+# If changed, also change the same variable in report.sh.
+VULN_FILE=/workspace/skaffold_vuln.txt
+
+append() {
+  printf "%s\n" $1 >>$2
+}
+
+check_vulnerability(){
+  base_image=$1
+  result_file=$2
+  tags=$3
+  tags_filter=""
+
+  if [ -z "$tags" ]; then
+    # We should only scan lts images within 1 year window from the first patch of the release.
+    targeted_base_tags="$(gcloud container images list-tags "$base_image" --filter="timestamp.datetime > -P1Y AND tags~v.*\.1-lts" --format='value(tags)')"
+    for line in $targeted_base_tags; do
+      IFS="," read -ra t <<< "${line}"
+      replacement="\."
+      t[0]="${t[0]//./$replacement}"
+      tags_filter+="${t[0]/1-lts/.*-lts}|"
+    done
+    tags_filter+="^edge$"
+    # get the latest patches tags for lts images. gcloud will return extra tags if an image has multiple tags and we only want tags specified in the filter, so use grep to further filter the result.
+    tags=$(gcloud container images list-tags "$base_image" --filter="tags~$tags_filter" --format='value(tags)' | sort -nr | awk -F'[.]' '$1$2!=p&&p=$1$2' | grep -Po "$tags_filter|edge")
+  fi
+
+  for tagsByComma in $tags; do
+    IFS="," read -ra tagArr <<< "${tagsByComma}"
+    image=$base_image:${tagArr[0]}
+    echo "Checking vulnerabilities of image:" "$image"
+    gcloud beta container images describe "$image"  --show-package-vulnerability \
+     | if grep -e "effectiveSeverity: HIGH" -e "effectiveSeverity: CRITICAL";
+       then
+         append "$base_image:$tagsByComma:true" "$result_file";
+       else
+         append "$base_image:$tagsByComma:false" "$result_file"
+       fi
+  done
+}
+
+# Main
+# Scans images
+check_vulnerability $_BASE_IMAGE "$VULN_FILE" "$_TAGS"
\ No newline at end of file
diff --git a/docs-v2/content/en/docs/builders/build-environments/cloud-build.md b/docs-v2/content/en/docs/builders/build-environments/cloud-build.md
index c87fb0ba2..bad13f632 100644
--- a/docs-v2/content/en/docs/builders/build-environments/cloud-build.md
+++ b/docs-v2/content/en/docs/builders/build-environments/cloud-build.md
@@ -6,22 +6,27 @@ weight: 30
 
 Skaffold supports building remotely with Google Cloud Build.
 
-[Google Cloud Build](https://cloud.google.com/cloud-build/) is a
+[Cloud Build](https://cloud.google.com/cloud-build/) is a
 [Google Cloud Platform](https://cloud.google.com) service that executes
-your builds using Google infrastructure. To get started with Google
+your builds using Google infrastructure. To get started with Cloud
 Build, see [Cloud Build Quickstart](https://cloud.google.com/cloud-build/docs/quickstart-docker).
 
-Skaffold can automatically connect to Cloud Build, and run your builds
-with it. After Cloud Build finishes building your artifacts, they will
-be saved to the specified remote registry, such as
+Skaffold automatically connects to Cloud Build and runs your builds
+with it. After Cloud Build finishes building your artifacts, they are
+saved to the specified remote registry, such as
 [Google Container Registry](https://cloud.google.com/container-registry/).
 
-Skaffold Google Cloud Build process differs from the gcloud command
-`gcloud builds submit`. Skaffold will create a list of dependent files
-and submit a tar file to GCB. It will then generate a single step `cloudbuild.yaml`
-and will start the building process. Skaffold does not honor `.gitignore` or `.gcloudignore`
-exclusions. If you need to ignore files use `.dockerignore`. Any `cloudbuild.yaml` found will not
-be used in the build process.
+Skaffold's Cloud Build process differs from the gcloud command
+[`gcloud builds submit`](https://cloud.google.com/sdk/gcloud/reference/builds/submit).
+Skaffold does the following:
+* Creates a list of dependent files
+* Uploads a tar file of the dependent files to Google Cloud Storage
+* Submits the tar file to Cloud Build
+* Generates a single-step `cloudbuild.yaml`
+* Starts the build
+
+Skaffold does not honor `.gitignore` or `.gcloudignore` exclusions. If you need to ignore files, use `.dockerignore`.
+Any `cloudbuild.yaml` found will not be used in the build process.
 
 ## Configuration
 
@@ -39,16 +44,17 @@ The following options can optionally be configured:
 
 ## Faster builds
 
-Skaffold can build multiple artifacts in parallel, by settings a value higher than `1` to `concurrency`.
-For Google Cloud Build, the default is to build all the artifacts in parallel. If you hit a quota restriction,
-you might want to reduce  the `concurrency`.
+By default, Cloud Build (invoked by Skaffold) builds all artifacts in parallel. Set `concurrency` to a non-zero
+value to specify the maximum number of artifacts to build concurrently. Consider reducing `concurrency` if you
+hit a quota restriction.
 
 {{<alert title="Note">}}
-When artifacts are built in parallel, the build logs are still printed in sequence to make them easier to read.
+When Skaffold builds artifacts in parallel, it still prints the build logs in sequence to make them easier to read.
 {{</alert>}}
 
 ## Restrictions
 
-Skaffold currently supports [Docker]({{<relref "/docs/builders/builder-types/docker#dockerfile-remotely-with-google-cloud-build">}}),
-[Jib]({{<relref "/docs/builders/builder-types/jib#remotely-with-google-cloud-build">}})
-on Google Cloud Build.
+Skaffold currently supports the following [builder types]({{<relref "/docs/builders/builder-types">}})
+when building remotely with Cloud Build:
+* [Docker]({{<relref "/docs/builders/builder-types/docker#dockerfile-remotely-with-google-cloud-build">}})
+* [Jib]({{<relref "/docs/builders/builder-types/jib#remotely-with-google-cloud-build">}})
diff --git a/docs-v2/content/en/schemas/v4beta4.json b/docs-v2/content/en/schemas/v4beta4.json
index ca62e392f..8cbd98b7a 100755
--- a/docs-v2/content/en/schemas/v4beta4.json
+++ b/docs-v2/content/en/schemas/v4beta4.json
@@ -4275,6 +4275,57 @@
       "description": "describes the supported kpt validators.",
       "x-intellij-html-description": "describes the supported kpt validators."
     },
+    "VerifyContainer": {
+      "required": [
+        "name",
+        "image"
+      ],
+      "properties": {
+        "args": {
+          "items": {
+            "type": "string"
+          },
+          "type": "array",
+          "description": "arguments to the entrypoint. The container image's CMD is used if this is not provided.",
+          "x-intellij-html-description": "arguments to the entrypoint. The container image's CMD is used if this is not provided.",
+          "default": "[]"
+        },
+        "command": {
+          "items": {
+            "type": "string"
+          },
+          "type": "array",
+          "description": "entrypoint array. Not executed within a shell. The container image's ENTRYPOINT is used if this is not provided.",
+          "x-intellij-html-description": "entrypoint array. Not executed within a shell. The container image's ENTRYPOINT is used if this is not provided.",
+          "default": "[]"
+        },
+        "image": {
+          "type": "string",
+          "description": "container image name.",
+          "x-intellij-html-description": "container image name."
+        },
+        "name": {
+          "type": "string",
+          "description": "of the container.",
+          "x-intellij-html-description": "of the container."
+        }
+      },
+      "preferredOrder": [
+        "name",
+        "image",
+        "command",
+        "args"
+      ],
+      "additionalProperties": false,
+      "type": "object",
+      "description": "a list of tests to run on images that Skaffold builds.",
+      "x-intellij-html-description": "a list of tests to run on images that Skaffold builds."
+    },
+    "VerifyEnvVar": {
+      "type": "object",
+      "description": "represents an environment variable present in a Container.",
+      "x-intellij-html-description": "represents an environment variable present in a Container."
+    },
     "VerifyExecutionModeConfig": {
       "properties": {
         "kubernetesCluster": {
@@ -4303,6 +4354,7 @@
       ],
       "properties": {
         "container": {
+          "$ref": "#/definitions/VerifyContainer",
           "description": "container information for the verify test.",
           "x-intellij-html-description": "container information for the verify test."
         },
diff --git a/examples/bazel/skaffold.yaml b/examples/bazel/skaffold.yaml
index 42f232546..670688121 100644
--- a/examples/bazel/skaffold.yaml
+++ b/examples/bazel/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v4beta3
+apiVersion: skaffold/v4beta4
 kind: Config
 build:
   artifacts:
diff --git a/examples/buildpacks-java/skaffold.yaml b/examples/buildpacks-java/skaffold.yaml
index 23cf068e5..01723896d 100644
--- a/examples/buildpacks-java/skaffold.yaml
+++ b/examples/buildpacks-java/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v4beta3
+apiVersion: skaffold/v4beta4
 kind: Config
 build:
   artifacts:
diff --git a/examples/buildpacks-node/skaffold.yaml b/examples/buildpacks-node/skaffold.yaml
index 2610838d6..4c0f2c492 100644
--- a/examples/buildpacks-node/skaffold.yaml
+++ b/examples/buildpacks-node/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v4beta3
+apiVersion: skaffold/v4beta4
 kind: Config
 build:
   artifacts:
diff --git a/examples/buildpacks-python/skaffold.yaml b/examples/buildpacks-python/skaffold.yaml
index 78577389e..f0c80ca13 100644
--- a/examples/buildpacks-python/skaffold.yaml
+++ b/examples/buildpacks-python/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v4beta3
+apiVersion: skaffold/v4beta4
 kind: Config
 build:
   artifacts:
diff --git a/examples/buildpacks/skaffold.yaml b/examples/buildpacks/skaffold.yaml
index 00baec886..17fa09bd4 100644
--- a/examples/buildpacks/skaffold.yaml
+++ b/examples/buildpacks/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v4beta3
+apiVersion: skaffold/v4beta4
 kind: Config
 build:
   artifacts:
diff --git a/examples/cross-platform-builds/skaffold.yaml b/examples/cross-platform-builds/skaffold.yaml
index 0cabda4b4..1c53088f0 100644
--- a/examples/cross-platform-builds/skaffold.yaml
+++ b/examples/cross-platform-builds/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v4beta3
+apiVersion: skaffold/v4beta4
 kind: Config
 build:
   artifacts:
diff --git a/examples/custom-buildx/skaffold.yaml b/examples/custom-buildx/skaffold.yaml
index 2aab382a9..e99b9e5e4 100644
--- a/examples/custom-buildx/skaffold.yaml
+++ b/examples/custom-buildx/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v4beta3
+apiVersion: skaffold/v4beta4
 kind: Config
 build:
   platforms: ["linux/amd64", "linux/arm64"]
diff --git a/examples/custom/skaffold.yaml b/examples/custom/skaffold.yaml
index c0fd512a8..45bac9d53 100644
--- a/examples/custom/skaffold.yaml
+++ b/examples/custom/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v4beta3
+apiVersion: skaffold/v4beta4
 kind: Config
 build:
   artifacts:
diff --git a/examples/dev-journey-buildpacks/skaffold.yaml b/examples/dev-journey-buildpacks/skaffold.yaml
index 136d78def..ec8e85781 100644
--- a/examples/dev-journey-buildpacks/skaffold.yaml
+++ b/examples/dev-journey-buildpacks/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v4beta3
+apiVersion: skaffold/v4beta4
 kind: Config
 build:
   artifacts:
diff --git a/examples/docker-deploy/skaffold.yaml b/examples/docker-deploy/skaffold.yaml
index ccec1890b..3f7375df1 100644
--- a/examples/docker-deploy/skaffold.yaml
+++ b/examples/docker-deploy/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v4beta3
+apiVersion: skaffold/v4beta4
 kind: Config
 build:
   local:
diff --git a/examples/gcb-kaniko/skaffold.yaml b/examples/gcb-kaniko/skaffold.yaml
index f68b4d1c8..550d35473 100644
--- a/examples/gcb-kaniko/skaffold.yaml
+++ b/examples/gcb-kaniko/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v4beta3
+apiVersion: skaffold/v4beta4
 kind: Config
 build:
   googleCloudBuild:
diff --git a/examples/generate-pipeline/skaffold.yaml b/examples/generate-pipeline/skaffold.yaml
index 9f81b92da..58f9e32b8 100644
--- a/examples/generate-pipeline/skaffold.yaml
+++ b/examples/generate-pipeline/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v4beta3
+apiVersion: skaffold/v4beta4
 kind: Config
 build:
   artifacts:
diff --git a/examples/getting-started-kustomize/skaffold.yaml b/examples/getting-started-kustomize/skaffold.yaml
index 9444d372c..5d3899f32 100644
--- a/examples/getting-started-kustomize/skaffold.yaml
+++ b/examples/getting-started-kustomize/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v4beta3
+apiVersion: skaffold/v4beta4
 kind: Config
 metadata:
   name: getting-started-kustomize
diff --git a/examples/getting-started/skaffold.yaml b/examples/getting-started/skaffold.yaml
index 7b0f7aac5..b9d33f158 100644
--- a/examples/getting-started/skaffold.yaml
+++ b/examples/getting-started/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v4beta3
+apiVersion: skaffold/v4beta4
 kind: Config
 build:
   artifacts:
diff --git a/examples/google-cloud-build/skaffold.yaml b/examples/google-cloud-build/skaffold.yaml
index 909f051e4..da1d116ff 100644
--- a/examples/google-cloud-build/skaffold.yaml
+++ b/examples/google-cloud-build/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v4beta3
+apiVersion: skaffold/v4beta4
 kind: Config
 build:
   googleCloudBuild:
diff --git a/examples/helm-deployment-dependencies/skaffold.yaml b/examples/helm-deployment-dependencies/skaffold.yaml
index 5b855d482..802545d39 100644
--- a/examples/helm-deployment-dependencies/skaffold.yaml
+++ b/examples/helm-deployment-dependencies/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v4beta3
+apiVersion: skaffold/v4beta4
 kind: Config
 build:
   tagPolicy:
diff --git a/examples/helm-deployment/skaffold.yaml b/examples/helm-deployment/skaffold.yaml
index d14c728be..ffde3ae49 100644
--- a/examples/helm-deployment/skaffold.yaml
+++ b/examples/helm-deployment/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v4beta3
+apiVersion: skaffold/v4beta4
 kind: Config
 build:
   artifacts:
diff --git a/examples/helm-remote-repo/skaffold.yaml b/examples/helm-remote-repo/skaffold.yaml
index cc50252f7..57380c069 100644
--- a/examples/helm-remote-repo/skaffold.yaml
+++ b/examples/helm-remote-repo/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v4beta3
+apiVersion: skaffold/v4beta4
 kind: Config
 deploy:
   helm:
diff --git a/examples/helm-render/skaffold.yaml b/examples/helm-render/skaffold.yaml
index 5f9a820f8..f832154a4 100644
--- a/examples/helm-render/skaffold.yaml
+++ b/examples/helm-render/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v4beta3
+apiVersion: skaffold/v4beta4
 kind: Config
 build:
   artifacts:
diff --git a/examples/hot-reload/skaffold.yaml b/examples/hot-reload/skaffold.yaml
index 6ed43e717..bfacb510a 100644
--- a/examples/hot-reload/skaffold.yaml
+++ b/examples/hot-reload/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v4beta3
+apiVersion: skaffold/v4beta4
 kind: Config
 build:
   artifacts:
diff --git a/examples/jib-gradle/skaffold.yaml b/examples/jib-gradle/skaffold.yaml
index 7a00a8c4c..e8221f81d 100644
--- a/examples/jib-gradle/skaffold.yaml
+++ b/examples/jib-gradle/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v4beta3
+apiVersion: skaffold/v4beta4
 kind: Config
 build:
   artifacts:
diff --git a/examples/jib-multimodule/skaffold.yaml b/examples/jib-multimodule/skaffold.yaml
index e5898e4e2..ee7e65ef7 100644
--- a/examples/jib-multimodule/skaffold.yaml
+++ b/examples/jib-multimodule/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v4beta3
+apiVersion: skaffold/v4beta4
 kind: Config
 build:
   artifacts:
diff --git a/examples/jib-sync/skaffold-gradle.yaml b/examples/jib-sync/skaffold-gradle.yaml
index ebcf79d84..1da2cdba5 100644
--- a/examples/jib-sync/skaffold-gradle.yaml
+++ b/examples/jib-sync/skaffold-gradle.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v4beta3
+apiVersion: skaffold/v4beta4
 kind: Config
 build:
   artifacts:
diff --git a/examples/jib-sync/skaffold-maven.yaml b/examples/jib-sync/skaffold-maven.yaml
index 8e6123910..0aec95e34 100644
--- a/examples/jib-sync/skaffold-maven.yaml
+++ b/examples/jib-sync/skaffold-maven.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v4beta3
+apiVersion: skaffold/v4beta4
 kind: Config
 build:
   artifacts:
diff --git a/examples/jib/skaffold.yaml b/examples/jib/skaffold.yaml
index f15189040..d02a03df0 100644
--- a/examples/jib/skaffold.yaml
+++ b/examples/jib/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v4beta3
+apiVersion: skaffold/v4beta4
 kind: Config
 build:
   artifacts:
diff --git a/examples/kaniko/skaffold.yaml b/examples/kaniko/skaffold.yaml
index b3322b812..0c9de8a29 100644
--- a/examples/kaniko/skaffold.yaml
+++ b/examples/kaniko/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v4beta3
+apiVersion: skaffold/v4beta4
 kind: Config
 build:
   artifacts:
diff --git a/examples/ko-sync-infer/skaffold.yaml b/examples/ko-sync-infer/skaffold.yaml
index e093f0fa1..8d73b531d 100644
--- a/examples/ko-sync-infer/skaffold.yaml
+++ b/examples/ko-sync-infer/skaffold.yaml
@@ -12,7 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-apiVersion: skaffold/v4beta3
+apiVersion: skaffold/v4beta4
 kind: Config
 build:
   artifacts:
diff --git a/examples/ko/skaffold.yaml b/examples/ko/skaffold.yaml
index 8f409d6f3..fa1996a4e 100644
--- a/examples/ko/skaffold.yaml
+++ b/examples/ko/skaffold.yaml
@@ -12,7 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-apiVersion: skaffold/v4beta3
+apiVersion: skaffold/v4beta4
 kind: Config
 build:
   artifacts:
diff --git a/examples/kustomize/skaffold-kustomize-args.yaml b/examples/kustomize/skaffold-kustomize-args.yaml
index 4786a1bac..b51bce05a 100644
--- a/examples/kustomize/skaffold-kustomize-args.yaml
+++ b/examples/kustomize/skaffold-kustomize-args.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v4beta3
+apiVersion: skaffold/v4beta4
 kind: Config
 deploy:
   kustomize:
diff --git a/examples/kustomize/skaffold.yaml b/examples/kustomize/skaffold.yaml
index b92eb203b..ed1b46185 100644
--- a/examples/kustomize/skaffold.yaml
+++ b/examples/kustomize/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v4beta3
+apiVersion: skaffold/v4beta4
 kind: Config
 manifests:
   kustomize:
diff --git a/examples/lifecycle-hooks/skaffold.yaml b/examples/lifecycle-hooks/skaffold.yaml
index b7db9d760..4419bfb7e 100644
--- a/examples/lifecycle-hooks/skaffold.yaml
+++ b/examples/lifecycle-hooks/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v4beta3
+apiVersion: skaffold/v4beta4
 kind: Config
 manifests:
   rawYaml:
diff --git a/examples/microservices/skaffold.yaml b/examples/microservices/skaffold.yaml
index 786e2028b..3de8e7ba6 100644
--- a/examples/microservices/skaffold.yaml
+++ b/examples/microservices/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v4beta3
+apiVersion: skaffold/v4beta4
 kind: Config
 build:
   artifacts:
diff --git a/examples/multi-config-microservices/base/skaffold.yaml b/examples/multi-config-microservices/base/skaffold.yaml
index fb8e24706..55e4e3810 100644
--- a/examples/multi-config-microservices/base/skaffold.yaml
+++ b/examples/multi-config-microservices/base/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v4beta3
+apiVersion: skaffold/v4beta4
 kind: Config
 build:
   artifacts:
diff --git a/examples/multi-config-microservices/leeroy-app/skaffold.yaml b/examples/multi-config-microservices/leeroy-app/skaffold.yaml
index 34fb167ba..db9ef5fce 100644
--- a/examples/multi-config-microservices/leeroy-app/skaffold.yaml
+++ b/examples/multi-config-microservices/leeroy-app/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v4beta3
+apiVersion: skaffold/v4beta4
 kind: Config
 metadata:
   name: app-config
diff --git a/examples/multi-config-microservices/leeroy-web/skaffold.yaml b/examples/multi-config-microservices/leeroy-web/skaffold.yaml
index 780434a6b..dd8312978 100644
--- a/examples/multi-config-microservices/leeroy-web/skaffold.yaml
+++ b/examples/multi-config-microservices/leeroy-web/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v4beta3
+apiVersion: skaffold/v4beta4
 kind: Config
 metadata:
   name: web-config
diff --git a/examples/multi-config-microservices/skaffold.yaml b/examples/multi-config-microservices/skaffold.yaml
index 8f97fc77b..87d708570 100644
--- a/examples/multi-config-microservices/skaffold.yaml
+++ b/examples/multi-config-microservices/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v4beta3
+apiVersion: skaffold/v4beta4
 kind: Config
 requires:
 - path: ./leeroy-app
diff --git a/examples/multiple-renderers/skaffold.yaml b/examples/multiple-renderers/skaffold.yaml
index 30c340504..5d7a011e4 100644
--- a/examples/multiple-renderers/skaffold.yaml
+++ b/examples/multiple-renderers/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v4beta3
+apiVersion: skaffold/v4beta4
 kind: Config
 metadata:
   name: go-guestbook
diff --git a/examples/nodejs/skaffold.yaml b/examples/nodejs/skaffold.yaml
index b1d3856f8..091500b1c 100644
--- a/examples/nodejs/skaffold.yaml
+++ b/examples/nodejs/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v4beta3
+apiVersion: skaffold/v4beta4
 kind: Config
 
 build:
diff --git a/examples/profile-patches/skaffold.yaml b/examples/profile-patches/skaffold.yaml
index a294ad16e..cad6dc5f4 100644
--- a/examples/profile-patches/skaffold.yaml
+++ b/examples/profile-patches/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v4beta3
+apiVersion: skaffold/v4beta4
 kind: Config
 build:
   # only build and deploy "base-service" on main profile
diff --git a/examples/profiles/skaffold.yaml b/examples/profiles/skaffold.yaml
index cebf74853..16bffac24 100644
--- a/examples/profiles/skaffold.yaml
+++ b/examples/profiles/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v4beta3
+apiVersion: skaffold/v4beta4
 kind: Config
 build:
   # only build and deploy "world-service" on main profile
diff --git a/examples/react-reload-docker/skaffold.yaml b/examples/react-reload-docker/skaffold.yaml
index 8d84a97e2..cb576c93c 100644
--- a/examples/react-reload-docker/skaffold.yaml
+++ b/examples/react-reload-docker/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v4beta3
+apiVersion: skaffold/v4beta4
 kind: Config
 build:
   local:
diff --git a/examples/react-reload/skaffold.yaml b/examples/react-reload/skaffold.yaml
index 13e36f297..f68f400ae 100644
--- a/examples/react-reload/skaffold.yaml
+++ b/examples/react-reload/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v4beta3
+apiVersion: skaffold/v4beta4
 kind: Config
 build:
   artifacts:
diff --git a/examples/remote-multi-config-microservices/skaffold.yaml b/examples/remote-multi-config-microservices/skaffold.yaml
index 4780c8c3d..507a578fb 100644
--- a/examples/remote-multi-config-microservices/skaffold.yaml
+++ b/examples/remote-multi-config-microservices/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v4beta3
+apiVersion: skaffold/v4beta4
 kind: Config
 requires:
 - git:
diff --git a/examples/ruby/skaffold.yaml b/examples/ruby/skaffold.yaml
index c9ca746e5..be7ba5882 100644
--- a/examples/ruby/skaffold.yaml
+++ b/examples/ruby/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v4beta3
+apiVersion: skaffold/v4beta4
 kind: Config
 build:
   artifacts:
diff --git a/examples/simple-artifact-dependency/skaffold.yaml b/examples/simple-artifact-dependency/skaffold.yaml
index b3e45c2b4..0500ce37a 100644
--- a/examples/simple-artifact-dependency/skaffold.yaml
+++ b/examples/simple-artifact-dependency/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v4beta3
+apiVersion: skaffold/v4beta4
 kind: Config
 build:
   artifacts:
diff --git a/examples/tagging-with-environment-variables/skaffold.yaml b/examples/tagging-with-environment-variables/skaffold.yaml
index 221c98a4e..f05315f91 100644
--- a/examples/tagging-with-environment-variables/skaffold.yaml
+++ b/examples/tagging-with-environment-variables/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v4beta3
+apiVersion: skaffold/v4beta4
 kind: Config
 build:
   artifacts:
diff --git a/examples/templated-fields/skaffold.yaml b/examples/templated-fields/skaffold.yaml
index 2410e3917..fa9ad71e1 100644
--- a/examples/templated-fields/skaffold.yaml
+++ b/examples/templated-fields/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v4beta3
+apiVersion: skaffold/v4beta4
 kind: Config
 metadata:
   name: my-app
diff --git a/examples/typescript/skaffold.yaml b/examples/typescript/skaffold.yaml
index 6697e4708..1270982b5 100644
--- a/examples/typescript/skaffold.yaml
+++ b/examples/typescript/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v4beta3
+apiVersion: skaffold/v4beta4
 kind: Config
 
 build:
diff --git a/examples/using-env-file/skaffold.yaml b/examples/using-env-file/skaffold.yaml
index 9cd4b9e19..2da8e1bbe 100644
--- a/examples/using-env-file/skaffold.yaml
+++ b/examples/using-env-file/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v4beta3
+apiVersion: skaffold/v4beta4
 kind: Config
 build:
   artifacts:
diff --git a/go.mod b/go.mod
index 3ecbdb098..6a0a06a4a 100644
--- a/go.mod
+++ b/go.mod
@@ -58,6 +58,7 @@ require (
 	github.com/docker/docker v20.10.20+incompatible
 	github.com/docker/go-connections v0.4.0
 	github.com/dustin/go-humanize v1.0.1
+	github.com/evanphx/json-patch v4.12.0+incompatible
 	github.com/fatih/semgroup v1.2.0
 	github.com/go-git/go-git/v5 v5.5.2
 	github.com/golang/glog v1.0.0
@@ -184,7 +185,6 @@ require (
 	github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect
 	github.com/emicklei/go-restful/v3 v3.9.0 // indirect
 	github.com/emirpasic/gods v1.18.1 // indirect
-	github.com/evanphx/json-patch v4.12.0+incompatible // indirect
 	github.com/evanphx/json-patch/v5 v5.6.0 // indirect
 	github.com/francoispqt/gojay v1.2.13 // indirect
 	github.com/fsnotify/fsnotify v1.6.0 // indirect
@@ -249,7 +249,7 @@ require (
 	github.com/morikuni/aec v1.0.0 // indirect
 	github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
 	github.com/oklog/ulid v1.3.1 // indirect
-	github.com/opencontainers/runc v1.1.4 // indirect
+	github.com/opencontainers/runc v1.1.5 // indirect
 	github.com/opencontainers/selinux v1.11.0 // indirect
 	github.com/pelletier/go-toml v1.9.5 // indirect
 	github.com/pelletier/go-toml/v2 v2.0.6 // indirect
diff --git a/go.sum b/go.sum
index dff725684..5777cb7bb 100644
--- a/go.sum
+++ b/go.sum
@@ -2054,8 +2054,8 @@ github.com/opencontainers/runc v1.0.0-rc93/go.mod h1:3NOsor4w32B2tC0Zbl8Knk4Wg84
 github.com/opencontainers/runc v1.0.2/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0=
 github.com/opencontainers/runc v1.1.0/go.mod h1:Tj1hFw6eFWp/o33uxGf5yF2BX5yz2Z6iptFpuvbbKqc=
 github.com/opencontainers/runc v1.1.2/go.mod h1:Tj1hFw6eFWp/o33uxGf5yF2BX5yz2Z6iptFpuvbbKqc=
-github.com/opencontainers/runc v1.1.4 h1:nRCz/8sKg6K6jgYAFLDlXzPeITBZJyX28DBVhWD+5dg=
-github.com/opencontainers/runc v1.1.4/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg=
+github.com/opencontainers/runc v1.1.5 h1:L44KXEpKmfWDcS02aeGm8QNTFXTo2D+8MYGDIJ/GDEs=
+github.com/opencontainers/runc v1.1.5/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg=
 github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
 github.com/opencontainers/runtime-spec v1.0.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
 github.com/opencontainers/runtime-spec v1.0.2-0.20190207185410-29686dbc5559/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
diff --git a/pkg/skaffold/gcp/auth.go b/pkg/skaffold/gcp/auth.go
index 7781415fd..1f6547f2f 100644
--- a/pkg/skaffold/gcp/auth.go
+++ b/pkg/skaffold/gcp/auth.go
@@ -17,13 +17,16 @@ limitations under the License.
 package gcp
 
 import (
+	"bytes"
 	"context"
 	"encoding/json"
 	"fmt"
 	"os/exec"
 	"sync"
+	"time"
 
 	"github.com/docker/cli/cli/config/configfile"
+	"golang.org/x/oauth2"
 	"golang.org/x/oauth2/google"
 
 	"github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/output/log"
@@ -59,35 +62,51 @@ func AutoConfigureGCRCredentialHelper(cf *configfile.ConfigFile) {
 	}
 }
 
-func activeUserCredentials(ctx context.Context) (*google.Credentials, error) {
+type token struct {
+	AccessToken string    `json:"access_token"`
+	TokenExpiry time.Time `json:"token_expiry"`
+}
+
+type tokenSource struct {
+}
+
+func (ts tokenSource) Token() (*oauth2.Token, error) {
+	// the command return a json object containing id_token, access_token, token_expiry
+	cmd := exec.Command("gcloud", "auth", "print-identity-token", "--format=json")
+	var body bytes.Buffer
+	cmd.Stdout = &body
+	err := util.RunCmd(context.TODO(), cmd)
+	if err != nil {
+		return nil, fmt.Errorf("failed to get access token %v", err)
+	}
+	var t token
+	if err := json.Unmarshal(body.Bytes(), &t); err != nil {
+		return nil, fmt.Errorf("failed to unmarshal gcould command result into access token %v", err)
+	}
+	return &oauth2.Token{AccessToken: t.AccessToken, Expiry: t.TokenExpiry}, nil
+}
+
+func activeUserCredentialsOnce() (*google.Credentials, error) {
 	credsOnce.Do(func() {
-		cmd := exec.Command("gcloud", "auth", "print-access-token", "--format=json")
-		body, err := util.RunCmdOut(ctx, cmd)
+		c, err := activeUserCredentials()
 		if err != nil {
 			log.Entry(context.TODO()).Infof("unable to retrieve gcloud access token: %v", err)
 			log.Entry(context.TODO()).Info("falling back to application default credentials")
 			credsErr = fmt.Errorf("retrieving gcloud access token: %w", err)
 			return
 		}
-		jsonCreds := make(map[string]interface{})
-		json.Unmarshal(body, &jsonCreds)
-		jsonCreds["type"] = "authorized_user"
-		body, _ = json.Marshal(jsonCreds)
-
-		c, err := google.CredentialsFromJSON(context.Background(), body)
-		if err != nil {
-			log.Entry(context.TODO()).Infof("unable to retrieve google creds: %v", err)
-			log.Entry(context.TODO()).Info("falling back to application default credentials")
-			return
-		}
-		_, err = c.TokenSource.Token()
-		if err != nil {
-			log.Entry(context.TODO()).Infof("unable to retrieve token: %v", err)
-			log.Entry(context.TODO()).Info("falling back to application default credentials")
-			return
-		}
 		creds = c
 	})
 
 	return creds, credsErr
 }
+
+func activeUserCredentials() (*google.Credentials, error) {
+	var ts tokenSource
+	t, err := ts.Token()
+	if err != nil {
+		return nil, err
+	}
+	c := &google.Credentials{TokenSource: oauth2.ReuseTokenSource(t, ts)}
+	return c, nil
+}
diff --git a/pkg/skaffold/gcp/client.go b/pkg/skaffold/gcp/client.go
index 12beb73d3..20afde461 100644
--- a/pkg/skaffold/gcp/client.go
+++ b/pkg/skaffold/gcp/client.go
@@ -21,6 +21,7 @@ import (
 
 	"google.golang.org/api/option"
 
+	"github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/output/log"
 	"github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/version"
 )
 
@@ -31,7 +32,8 @@ func ClientOptions(ctx context.Context) []option.ClientOption {
 		option.WithUserAgent(version.UserAgent()),
 	}
 
-	creds, cErr := activeUserCredentials(ctx)
+	creds, cErr := activeUserCredentialsOnce()
+	log.Entry(ctx).Debug("unable to active user credentials %w", cErr)
 	if cErr == nil && creds != nil {
 		options = append(options, option.WithCredentials(creds))
 	}
diff --git a/pkg/skaffold/inspect/jobManifestPaths/list.go b/pkg/skaffold/inspect/jobManifestPaths/list.go
new file mode 100644
index 000000000..0b4bb0d6d
--- /dev/null
+++ b/pkg/skaffold/inspect/jobManifestPaths/list.go
@@ -0,0 +1,59 @@
+/*
+Copyright 2021 The Skaffold Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package inspect
+
+import (
+	"context"
+	"io"
+
+	"github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/config"
+	"github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/inspect"
+)
+
+type jobManifestPathList struct {
+	VerifyJobManifestPaths       map[string]string `json:"verifyJobManifestPaths"`
+	CustomActionJobManifestPaths map[string]string `json:"customActionJobManifestPaths"`
+}
+
+func PrintJobManifestPathsList(ctx context.Context, out io.Writer, opts inspect.Options) error {
+	formatter := inspect.OutputFormatter(out, opts.OutFormat)
+	cfgs, err := inspect.GetConfigSet(ctx, config.SkaffoldOptions{
+		ConfigurationFile:   opts.Filename,
+		ConfigurationFilter: opts.Modules,
+		RepoCacheDir:        opts.RepoCacheDir,
+		Profiles:            opts.Profiles,
+		PropagateProfiles:   opts.PropagateProfiles,
+	})
+	if err != nil {
+		formatter.WriteErr(err)
+		return err
+	}
+
+	l := &jobManifestPathList{
+		VerifyJobManifestPaths:       map[string]string{},
+		CustomActionJobManifestPaths: map[string]string{},
+	}
+	for _, c := range cfgs {
+		for _, tc := range c.Verify {
+			if tc.ExecutionMode.KubernetesClusterExecutionMode != nil && tc.ExecutionMode.KubernetesClusterExecutionMode.JobManifestPath != "" {
+				l.VerifyJobManifestPaths[tc.Name] = tc.ExecutionMode.KubernetesClusterExecutionMode.JobManifestPath
+			}
+			// TODO(#8572) add similar logic for customAction schema fields when they are complete
+		}
+	}
+	return formatter.Write(l)
+}
diff --git a/pkg/skaffold/inspect/jobManifestPaths/modify.go b/pkg/skaffold/inspect/jobManifestPaths/modify.go
new file mode 100644
index 000000000..fbadee529
--- /dev/null
+++ b/pkg/skaffold/inspect/jobManifestPaths/modify.go
@@ -0,0 +1,91 @@
+/*
+Copyright 2021 The Skaffold Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package inspect
+
+import (
+	"context"
+	"encoding/json"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"os"
+
+	"github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/config"
+	"github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/output/log"
+	"github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/parser"
+	"github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/schema/latest"
+	"github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/util"
+	"github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/yaml"
+)
+
+var (
+	getCfgs = parser.GetAllConfigs
+)
+
+func Modify(ctx context.Context, out io.Writer, opts config.SkaffoldOptions, inputFile, outputFile string) error {
+	// Open our jsonFile
+	jsonFile, err := os.Open(inputFile)
+	if err != nil {
+		log.Entry(context.TODO()).Error(err)
+		return err
+	}
+	// defer the closing of our jsonFile so that we can parse it later on
+	defer jsonFile.Close()
+
+	byteValue, _ := ioutil.ReadAll(jsonFile)
+
+	var result jobManifestPathList
+	err = json.Unmarshal(byteValue, &result)
+	if err != nil {
+		log.Entry(context.TODO()).Error(err)
+		return err
+	}
+
+	// force absolute path resolution during modify
+	opts.MakePathsAbsolute = util.Ptr(true)
+	configs, err := getCfgs(ctx, opts)
+	if err != nil {
+		log.Entry(context.TODO()).Error(err)
+		return err
+	}
+	if outputFile != "" {
+		f, err := os.Create(outputFile)
+		if err != nil {
+			return err
+		}
+		defer f.Close()
+		out = f
+	}
+
+	// remove the dependency config references since they have already been imported and will be marshalled together.
+	for i := range configs {
+		configs[i].(*latest.SkaffoldConfig).Dependencies = nil
+		for j := range configs[i].(*latest.SkaffoldConfig).Verify {
+			if jobManifestPath, ok := result.VerifyJobManifestPaths[configs[i].(*latest.SkaffoldConfig).Verify[j].Name]; ok {
+				configs[i].(*latest.SkaffoldConfig).Verify[j].ExecutionMode.KubernetesClusterExecutionMode.JobManifestPath = jobManifestPath
+			}
+		}
+	}
+
+	buf, err := yaml.MarshalWithSeparator(configs)
+	if err != nil {
+		return fmt.Errorf("marshalling configuration: %w", err)
+	}
+	out.Write(buf)
+
+	return nil
+}
diff --git a/pkg/skaffold/render/renderer/helm/helm.go b/pkg/skaffold/render/renderer/helm/helm.go
index cc9e5e3e7..f473dd29b 100644
--- a/pkg/skaffold/render/renderer/helm/helm.go
+++ b/pkg/skaffold/render/renderer/helm/helm.go
@@ -159,6 +159,16 @@ func (h Helm) generateHelmManifests(ctx context.Context, builds []graph.Artifact
 		outBuffer := new(bytes.Buffer)
 		errBuffer := new(bytes.Buffer)
 
+		// Build Chart dependencies, but allow a user to skip it.
+		if !release.SkipBuildDependencies && release.ChartPath != "" {
+			log.Entry(ctx).Info("Building helm dependencies...")
+
+			if err := helm.ExecWithStdoutAndStderr(ctx, h, outBuffer, errBuffer, false, helmEnv, "dep", "build", release.ChartPath); err != nil {
+				log.Entry(ctx).Infof(errBuffer.String())
+				return nil, helm.UserErr("building helm dependencies", err)
+			}
+		}
+
 		err = helm.ExecWithStdoutAndStderr(ctx, h, outBuffer, errBuffer, false, helmEnv, args...)
 		errorMsg := errBuffer.String()
 
diff --git a/pkg/skaffold/render/transform/transform.go b/pkg/skaffold/render/transform/transform.go
index 74df8d418..f266c1e1f 100644
--- a/pkg/skaffold/render/transform/transform.go
+++ b/pkg/skaffold/render/transform/transform.go
@@ -35,7 +35,7 @@ var (
 	allowListedTransformer = []string{"set-labels"}
 	transformerAllowlist   = map[string]kptfile.Function{
 		"set-namespace": {
-			Image:     "gcr.io/kpt-fn/set-namespace",
+			Image:     "gcr.io/kpt-fn/set-namespace:v0.4.1",
 			ConfigMap: map[string]string{},
 		},
 		"set-labels": {
@@ -135,9 +135,9 @@ func (v *Transformer) Transform(ctx context.Context, ml manifest.ManifestList) (
 		cmd.Stdin = reader
 		cmd.Stdout = buffer
 
-		err := cmd.Run()
+		err := util.RunCmd(ctx, cmd)
 		if err != nil {
-			return ml, err
+			return ml, fmt.Errorf("failed to run transfomer: %s, err: %v", transformer.Image, err)
 		}
 		ml, err = manifest.Load(buffer)
 		if err != nil {
@@ -182,6 +182,7 @@ func validateTransformers(config []latest.Transformer) ([]kptfile.Function, erro
 					},
 				})
 		}
+		newFunc = kptfile.Function{Image: newFunc.Image, ConfigMap: map[string]string{}}
 		if c.ConfigMap != nil {
 			for _, stringifiedData := range c.ConfigMap {
 				index := strings.Index(stringifiedData, ":")
diff --git a/pkg/skaffold/schema/v2beta29/upgrade.go b/pkg/skaffold/schema/v2beta29/upgrade.go
index 8efb06892..d8719791a 100644
--- a/pkg/skaffold/schema/v2beta29/upgrade.go
+++ b/pkg/skaffold/schema/v2beta29/upgrade.go
@@ -36,7 +36,7 @@ import (
 var artifactOverridesRegexp = regexp.MustCompile("/deploy/helm/releases/[0-9]+/artifactOverrides/image")
 
 var migrations = map[string]string{
-	"/deploy/kubectl":             "/manifests/rawYaml",
+	"/deploy/kubectl/manifests":   "/manifests/rawYaml",
 	"/deploy/kustomize/paths":     "/manifests/kustomize/paths",
 	"/deploy/kustomize/buildArgs": "/manifests/kustomize/buildArgs",
 	"/deploy/helm":                "/manifests/helm",
diff --git a/pkg/skaffold/verify/docker/verify.go b/pkg/skaffold/verify/docker/verify.go
index 0c893eabc..0875f0e3f 100644
--- a/pkg/skaffold/verify/docker/verify.go
+++ b/pkg/skaffold/verify/docker/verify.go
@@ -218,10 +218,8 @@ func (v *Verifier) createAndRunContainer(ctx context.Context, out io.Writer, art
 	opts.Bindings = bindings
 	// verify waits for run to complete
 	opts.Wait = true
-	// verify passes through os env to container env
-
-	envVars := []string{}
 	// adding in env vars from verify container schema field
+	envVars := []string{}
 	for _, env := range tc.Container.Env {
 		envVars = append(envVars, env.Name+"="+env.Value)
 	}
diff --git a/pkg/skaffold/verify/k8sjob/verify.go b/pkg/skaffold/verify/k8sjob/verify.go
index abd655bfd..657d3cf5a 100644
--- a/pkg/skaffold/verify/k8sjob/verify.go
+++ b/pkg/skaffold/verify/k8sjob/verify.go
@@ -327,7 +327,7 @@ func (v *Verifier) TrackContainerAndJobFromBuild(artifact graph.Artifact, contai
 	v.logger.RegisterJob(job.Name)
 }
 
-func (v *Verifier) createJob(jobName string, container corev1.Container) *batchv1.Job {
+func (v *Verifier) createJob(jobName string, container latest.VerifyContainer) *batchv1.Job {
 	job := &batchv1.Job{
 		TypeMeta: metav1.TypeMeta{
 			Kind:       "Job",
@@ -348,7 +348,7 @@ func (v *Verifier) createJob(jobName string, container corev1.Container) *batchv
 					},
 				},
 				Spec: corev1.PodSpec{
-					Containers:    []corev1.Container{container},
+					Containers:    []corev1.Container{verifyContainerToK8sContainer(container)},
 					RestartPolicy: corev1.RestartPolicyNever,
 				},
 			},
@@ -357,7 +357,27 @@ func (v *Verifier) createJob(jobName string, container corev1.Container) *batchv
 	return job
 }
 
-func (v *Verifier) createJobFromManifestPath(jobName string, container corev1.Container, manifestPath string) (*batchv1.Job, error) {
+func verifyContainerToK8sContainer(vc latest.VerifyContainer) corev1.Container {
+	c := corev1.Container{
+		Name:    vc.Name,
+		Image:   vc.Image,
+		Command: vc.Command,
+		Args:    vc.Args,
+	}
+	if len(vc.Env) > 0 {
+		cEnv := []corev1.EnvVar{}
+		for _, env := range vc.Env {
+			cEnv = append(cEnv, corev1.EnvVar{
+				Name:  env.Name,
+				Value: env.Value,
+			})
+		}
+		c.Env = cEnv
+	}
+	return c
+}
+
+func (v *Verifier) createJobFromManifestPath(jobName string, container latest.VerifyContainer, manifestPath string) (*batchv1.Job, error) {
 	var job *batchv1.Job
 
 	b, err := ioutil.ReadFile(manifestPath)
@@ -396,7 +416,7 @@ func (v *Verifier) createJobFromManifestPath(jobName string, container corev1.Co
 		job.Labels = map[string]string{}
 	}
 	job.Labels["skaffold.dev/run-id"] = v.labeller.GetRunID()
-	job.Spec.Template.Spec.Containers = []corev1.Container{container}
+	job.Spec.Template.Spec.Containers = []corev1.Container{verifyContainerToK8sContainer(container)}
 	job.Spec.Template.Spec.RestartPolicy = corev1.RestartPolicyNever
 	job.Spec.Template.Labels["skaffold.dev/run-id"] = v.labeller.GetRunID()
 


Test patch:
diff --git a/examples/custom-tests/skaffold.yaml b/examples/custom-tests/skaffold.yaml
index 521b23176..0e1478cbd 100644
--- a/examples/custom-tests/skaffold.yaml
+++ b/examples/custom-tests/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v4beta3
+apiVersion: skaffold/v4beta4
 kind: Config
 build:
   artifacts:
diff --git a/examples/grpc-e2e-tests/skaffold.yaml b/examples/grpc-e2e-tests/skaffold.yaml
index e0e3caf3a..d5af503eb 100644
--- a/examples/grpc-e2e-tests/skaffold.yaml
+++ b/examples/grpc-e2e-tests/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v4beta3
+apiVersion: skaffold/v4beta4
 kind: Config
 metadata:
   name: visitor-counter-e2e
diff --git a/examples/structure-tests/skaffold.yaml b/examples/structure-tests/skaffold.yaml
index 914aa3fcc..ec0a7d5f6 100644
--- a/examples/structure-tests/skaffold.yaml
+++ b/examples/structure-tests/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v4beta3
+apiVersion: skaffold/v4beta4
 kind: Config
 build:
   artifacts:
diff --git a/pkg/skaffold/deploy/helm/helm_test.go b/pkg/skaffold/deploy/helm/helm_test.go
index 781f7e266..efb7e31f8 100644
--- a/pkg/skaffold/deploy/helm/helm_test.go
+++ b/pkg/skaffold/deploy/helm/helm_test.go
@@ -1162,7 +1162,8 @@ func TestHelmRender(t *testing.T) {
 			description: "normal render v3",
 			shouldErr:   false,
 			commands: testutil.
-				CmdRun("helm --kube-context kubecontext template skaffold-helm examples/test --post-renderer SKAFFOLD-BINARY --set some.key=somevalue --kubeconfig kubeconfig"),
+				CmdRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig").
+				AndRun("helm --kube-context kubecontext template skaffold-helm examples/test --post-renderer SKAFFOLD-BINARY --set some.key=somevalue --kubeconfig kubeconfig"),
 			helm: testDeployConfig,
 			builds: []graph.Artifact{
 				{
@@ -1174,7 +1175,8 @@ func TestHelmRender(t *testing.T) {
 			description: "render with templated config",
 			shouldErr:   false,
 			commands: testutil.
-				CmdRun("helm --kube-context kubecontext template skaffold-helm examples/test --post-renderer SKAFFOLD-BINARY --set image.name=skaffold-helm --set image.tag=skaffold-helm:tag1 --set missing.key=<MISSING> --set other.key=FOOBAR --set some.key=somevalue --set FOOBAR=somevalue --kubeconfig kubeconfig"),
+				CmdRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig").
+				AndRun("helm --kube-context kubecontext template skaffold-helm examples/test --post-renderer SKAFFOLD-BINARY --set image.name=skaffold-helm --set image.tag=skaffold-helm:tag1 --set missing.key=<MISSING> --set other.key=FOOBAR --set some.key=somevalue --set FOOBAR=somevalue --kubeconfig kubeconfig"),
 			helm: testDeployConfigTemplated,
 			builds: []graph.Artifact{
 				{
@@ -1185,8 +1187,10 @@ func TestHelmRender(t *testing.T) {
 		{
 			description: "render with templated values file",
 			shouldErr:   false,
-			commands:    testutil.CmdRun("helm --kube-context kubecontext template skaffold-helm examples/test --post-renderer SKAFFOLD-BINARY -f /some/file-FOOBAR.yaml --kubeconfig kubeconfig"),
-			helm:        testDeployConfigValuesFilesTemplated,
+			commands: testutil.
+				CmdRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig").
+				AndRun("helm --kube-context kubecontext template skaffold-helm examples/test --post-renderer SKAFFOLD-BINARY -f /some/file-FOOBAR.yaml --kubeconfig kubeconfig"),
+			helm: testDeployConfigValuesFilesTemplated,
 			builds: []graph.Artifact{
 				{
 					ImageName: "skaffold-helm",
@@ -1203,15 +1207,18 @@ func TestHelmRender(t *testing.T) {
 			description: "render with templated release name",
 			env:         []string{"USER=user"},
 			commands: testutil.
-				CmdRun("helm --kube-context kubecontext template user-skaffold-helm examples/test --post-renderer SKAFFOLD-BINARY --set some.key=somevalue --kubeconfig kubeconfig"),
+				CmdRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig").
+				AndRun("helm --kube-context kubecontext template user-skaffold-helm examples/test --post-renderer SKAFFOLD-BINARY --set some.key=somevalue --kubeconfig kubeconfig"),
 			helm:   testDeployWithTemplatedName,
 			builds: testBuilds,
 		},
 		{
 			description: "render with namespace",
 			shouldErr:   false,
-			commands:    testutil.CmdRun("helm --kube-context kubecontext template skaffold-helm examples/test --post-renderer SKAFFOLD-BINARY --set some.key=somevalue --namespace testReleaseNamespace --kubeconfig kubeconfig"),
-			helm:        testDeployNamespacedConfig,
+			commands: testutil.
+				CmdRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig").
+				AndRun("helm --kube-context kubecontext template skaffold-helm examples/test --post-renderer SKAFFOLD-BINARY --set some.key=somevalue --namespace testReleaseNamespace --kubeconfig kubeconfig"),
+			helm: testDeployNamespacedConfig,
 			builds: []graph.Artifact{
 				{
 					ImageName: "skaffold-helm",
@@ -1221,8 +1228,10 @@ func TestHelmRender(t *testing.T) {
 		{
 			description: "render with namespace",
 			shouldErr:   false,
-			commands:    testutil.CmdRun("helm --kube-context kubecontext template skaffold-helm examples/test --post-renderer SKAFFOLD-BINARY --set some.key=somevalue --namespace testReleaseFOOBARNamespace --kubeconfig kubeconfig"),
-			helm:        testDeployEnvTemplateNamespacedConfig,
+			commands: testutil.
+				CmdRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig").
+				AndRun("helm --kube-context kubecontext template skaffold-helm examples/test --post-renderer SKAFFOLD-BINARY --set some.key=somevalue --namespace testReleaseFOOBARNamespace --kubeconfig kubeconfig"),
+			helm: testDeployEnvTemplateNamespacedConfig,
 			builds: []graph.Artifact{
 				{
 					ImageName: "skaffold-helm",
@@ -1232,8 +1241,10 @@ func TestHelmRender(t *testing.T) {
 		{
 			description: "render with remote repo",
 			shouldErr:   false,
-			commands:    testutil.CmdRun("helm --kube-context kubecontext template skaffold-helm examples/test --post-renderer SKAFFOLD-BINARY --set some.key=somevalue --repo https://charts.helm.sh/stable --kubeconfig kubeconfig"),
-			helm:        testDeployConfigRemoteRepo,
+			commands: testutil.
+				CmdRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig").
+				AndRun("helm --kube-context kubecontext template skaffold-helm examples/test --post-renderer SKAFFOLD-BINARY --set some.key=somevalue --repo https://charts.helm.sh/stable --kubeconfig kubeconfig"),
+			helm: testDeployConfigRemoteRepo,
 			builds: []graph.Artifact{
 				{
 					ImageName: "skaffold-helm",
@@ -1243,14 +1254,23 @@ func TestHelmRender(t *testing.T) {
 		{
 			description: "render with remote chart",
 			shouldErr:   false,
-			commands:    testutil.CmdRun("helm --kube-context kubecontext template skaffold-helm-remote stable/chartmuseum --repo https://charts.helm.sh/stable --kubeconfig kubeconfig"),
-			helm:        testDeployRemoteChart,
+			commands: testutil.
+				CmdRun("helm --kube-context kubecontext template skaffold-helm-remote stable/chartmuseum --repo https://charts.helm.sh/stable --kubeconfig kubeconfig"),
+			helm: testDeployRemoteChart,
 		},
 		{
 			description: "render with remote chart with version",
 			shouldErr:   false,
-			commands:    testutil.CmdRun("helm --kube-context kubecontext template skaffold-helm-remote stable/chartmuseum --version 1.0.0 --repo https://charts.helm.sh/stable --kubeconfig kubeconfig"),
-			helm:        testDeployRemoteChartVersion,
+			commands: testutil.
+				CmdRun("helm --kube-context kubecontext template skaffold-helm-remote stable/chartmuseum --version 1.0.0 --repo https://charts.helm.sh/stable --kubeconfig kubeconfig"),
+			helm: testDeployRemoteChartVersion,
+		},
+		{
+			description: "render without building chart dependencies",
+			shouldErr:   false,
+			commands: testutil.
+				CmdRun("helm --kube-context kubecontext template skaffold-helm stable/chartmuseum --kubeconfig kubeconfig"),
+			helm: testDeploySkipBuildDependencies,
 		},
 		// https://github.com/GoogleContainerTools/skaffold/issues/7595
 		// {
diff --git a/pkg/skaffold/gcp/auth_test.go b/pkg/skaffold/gcp/auth_test.go
index 8500ed1d5..5b54c2b67 100644
--- a/pkg/skaffold/gcp/auth_test.go
+++ b/pkg/skaffold/gcp/auth_test.go
@@ -20,10 +20,12 @@ limitations under the License.
 package gcp
 
 import (
+	"fmt"
 	"testing"
 
 	"github.com/docker/cli/cli/config/configfile"
 
+	"github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/util"
 	"github.com/GoogleContainerTools/skaffold/v2/testutil"
 )
 
@@ -111,3 +113,46 @@ func TestAutoConfigureGCRCredentialHelper(t *testing.T) {
 		})
 	}
 }
+
+func TestActiveUserCredentials(t *testing.T) {
+	output := `{
+		"access_token": "access_token_value",
+		"id_token": "id_token_value",
+		"token_expiry": "2023-03-23T23:10:40Z"
+	}`
+
+	tests := []struct {
+		name        string
+		mockCommand util.Command
+		shouldErr   bool
+		expected    string
+	}{
+		{
+			name: "get credential succeed",
+			mockCommand: testutil.CmdRunWithOutput("gcloud auth print-identity-token --format=json", output).
+				AndRunWithOutput("gcloud auth print-identity-token --format=json", output),
+			expected: "access_token_value",
+		},
+		{
+			name:        "command error, get error",
+			mockCommand: testutil.CmdRunErr("gcloud auth print-identity-token --format=json", fmt.Errorf("command exited with non-zero code")),
+			shouldErr:   true,
+		},
+		{
+			name:        "invalid json, get error",
+			mockCommand: testutil.CmdRunWithOutput("gcloud auth print-identity-token --format=json", "{{{"),
+			shouldErr:   true,
+		},
+	}
+	for _, test := range tests {
+		testutil.Run(t, test.name, func(t *testutil.T) {
+			t.Override(&util.DefaultExecCommand, test.mockCommand)
+			out, err := activeUserCredentials()
+			t.CheckError(test.shouldErr, err)
+			if err == nil {
+				token, _ := out.TokenSource.Token()
+				t.CheckDeepEqual(test.expected, token.AccessToken)
+			}
+		})
+	}
+}
diff --git a/pkg/skaffold/inspect/jobManifestPaths/list_test.go b/pkg/skaffold/inspect/jobManifestPaths/list_test.go
new file mode 100644
index 000000000..4d8ec3e22
--- /dev/null
+++ b/pkg/skaffold/inspect/jobManifestPaths/list_test.go
@@ -0,0 +1,148 @@
+/*
+Copyright 2021 The Skaffold Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package inspect
+
+import (
+	"bytes"
+	"context"
+	"errors"
+	"fmt"
+	"testing"
+
+	"github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/config"
+	"github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/inspect"
+	"github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/parser"
+	sErrors "github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/schema/errors"
+	"github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/schema/latest"
+	"github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/util/stringslice"
+	"github.com/GoogleContainerTools/skaffold/v2/testutil"
+)
+
+func TestPrintJobManifestPathsList(t *testing.T) {
+	tests := []struct {
+		description string
+		profiles    []string
+		module      []string
+		err         error
+		expected    string
+	}{
+		{
+			description: "print all jobManifestPaths where no jobManifestPath is set in the verify config",
+			expected:    "{\"verifyJobManifestPaths\":{},\"customActionJobManifestPaths\":{}}" + "\n",
+			module:      []string{"cfg-without-jobManifestPaths"},
+		},
+		{
+			description: "print all jobManifestPaths where one jobManifestPath is set in the verify config via a profile",
+			expected:    "{\"verifyJobManifestPaths\":{\"foo\":\"foo.yaml\"},\"customActionJobManifestPaths\":{}}" + "\n",
+			profiles:    []string{"has-jobManifestPath"},
+			module:      []string{"cfg-without-jobManifestPaths"},
+		},
+		{
+			description: "print all jobManifestPaths where one jobManifestPath is set in the verify config via a module",
+			expected:    "{\"verifyJobManifestPaths\":{\"bar\":\"bar.yaml\"},\"customActionJobManifestPaths\":{}}" + "\n",
+			module:      []string{"cfg-with-jobManifestPaths"},
+		},
+		{
+			description: "actionable error",
+			err:         sErrors.MainConfigFileNotFoundErr("path/to/skaffold.yaml", fmt.Errorf("failed to read file : %q", "skaffold.yaml")),
+			expected:    `{"errorCode":"CONFIG_FILE_NOT_FOUND_ERR","errorMessage":"unable to find configuration file \"path/to/skaffold.yaml\": failed to read file : \"skaffold.yaml\". Check that the specified configuration file exists at \"path/to/skaffold.yaml\"."}` + "\n",
+		},
+		{
+			description: "generic error",
+			err:         errors.New("some error occurred"),
+			expected:    `{"errorCode":"INSPECT_UNKNOWN_ERR","errorMessage":"some error occurred"}` + "\n",
+		},
+	}
+
+	for _, test := range tests {
+		testutil.Run(t, test.description, func(t *testutil.T) {
+			configSet := parser.SkaffoldConfigSet{
+				&parser.SkaffoldConfigEntry{SkaffoldConfig: &latest.SkaffoldConfig{
+					Metadata: latest.Metadata{Name: "cfg-without-jobManifestPaths"},
+					Pipeline: latest.Pipeline{},
+					Profiles: []latest.Profile{
+						{Name: "has-jobManifestPath",
+							Pipeline: latest.Pipeline{
+								Verify: []*latest.VerifyTestCase{
+									{
+										Name: "foo",
+										Container: latest.VerifyContainer{
+											Name:  "foo",
+											Image: "foo",
+										},
+										ExecutionMode: latest.VerifyExecutionModeConfig{
+											VerifyExecutionModeType: latest.VerifyExecutionModeType{
+												KubernetesClusterExecutionMode: &latest.KubernetesClusterVerifier{
+													JobManifestPath: "foo.yaml",
+												},
+											},
+										},
+									},
+								},
+							},
+						}},
+				}, SourceFile: "path/to/cfg-without-jobManifestPaths"},
+
+				&parser.SkaffoldConfigEntry{SkaffoldConfig: &latest.SkaffoldConfig{
+					Metadata: latest.Metadata{Name: "cfg-with-jobManifestPaths"},
+					Pipeline: latest.Pipeline{
+						Verify: []*latest.VerifyTestCase{
+							{
+								Name: "bar",
+								Container: latest.VerifyContainer{
+									Name:  "bar",
+									Image: "bar",
+								},
+								ExecutionMode: latest.VerifyExecutionModeConfig{
+									VerifyExecutionModeType: latest.VerifyExecutionModeType{
+										KubernetesClusterExecutionMode: &latest.KubernetesClusterVerifier{
+											JobManifestPath: "bar.yaml",
+										},
+									},
+								},
+							},
+						},
+					},
+				}, SourceFile: "path/to/cfg-with-default-namespace"},
+			}
+			t.Override(&inspect.GetConfigSet, func(_ context.Context, opts config.SkaffoldOptions) (parser.SkaffoldConfigSet, error) {
+				// mock profile activation
+				var set parser.SkaffoldConfigSet
+				for _, c := range configSet {
+					if len(opts.ConfigurationFilter) > 0 && !stringslice.Contains(opts.ConfigurationFilter, c.Metadata.Name) {
+						continue
+					}
+					for _, pName := range opts.Profiles {
+						for _, profile := range c.Profiles {
+							if profile.Name != pName {
+								continue
+							}
+							c.Verify = profile.Verify
+						}
+					}
+					set = append(set, c)
+				}
+				return set, test.err
+			})
+			var buf bytes.Buffer
+			err := PrintJobManifestPathsList(context.Background(), &buf, inspect.Options{
+				OutFormat: "json", Modules: test.module, Profiles: test.profiles})
+			t.CheckError(test.err != nil, err)
+			t.CheckDeepEqual(test.expected, buf.String())
+		})
+	}
+}
diff --git a/pkg/skaffold/inspect/jobManifestPaths/modify_test.go b/pkg/skaffold/inspect/jobManifestPaths/modify_test.go
new file mode 100644
index 000000000..9ca865b55
--- /dev/null
+++ b/pkg/skaffold/inspect/jobManifestPaths/modify_test.go
@@ -0,0 +1,95 @@
+/*
+Copyright 2021 The Skaffold Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package inspect
+
+import (
+	"bytes"
+	"context"
+	"testing"
+
+	"github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/config"
+	"github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/schema/latest"
+	"github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/schema/util"
+	"github.com/GoogleContainerTools/skaffold/v2/testutil"
+)
+
+func TestPrintJobManifestPathsModify(t *testing.T) {
+	tests := []struct {
+		description string
+		input       string
+		shouldErr   bool
+		expected    string
+	}{
+		{
+			description: "successfully modifies jobManifestPath as intended",
+			input:       "{\"verifyJobManifestPaths\":{\"foo\":\"modified-foo.yaml\"},\"customActionJobManifestPaths\":{}}",
+			expected: `apiVersion: skaffold/v4beta4
+kind: Config
+verify:
+  - name: foo
+    container:
+      name: foo
+      image: foo
+      env: []
+    executionMode:
+      kubernetesCluster:
+        jobManifestPath: modified-foo.yaml
+`,
+		},
+		{
+			description: "failure with invalid transform yaml input",
+			input:       "invalid",
+			shouldErr:   true,
+		},
+	}
+
+	for _, test := range tests {
+		testutil.Run(t, test.description, func(t *testutil.T) {
+			inputFile := t.TempFile("", []byte(test.input))
+
+			t.Override(&getCfgs, func(context.Context, config.SkaffoldOptions) ([]util.VersionedConfig, error) {
+				return []util.VersionedConfig{
+					&latest.SkaffoldConfig{
+						APIVersion: "skaffold/v4beta4",
+						Kind:       "Config",
+						Pipeline: latest.Pipeline{
+							Verify: []*latest.VerifyTestCase{
+								{
+									Name: "foo",
+									Container: latest.VerifyContainer{
+										Name:  "foo",
+										Image: "foo",
+									},
+									ExecutionMode: latest.VerifyExecutionModeConfig{
+										VerifyExecutionModeType: latest.VerifyExecutionModeType{
+											KubernetesClusterExecutionMode: &latest.KubernetesClusterVerifier{
+												JobManifestPath: "foo.yaml",
+											},
+										},
+									},
+								},
+							},
+						},
+					},
+				}, nil
+			})
+			var b bytes.Buffer
+			err := Modify(context.Background(), &b, config.SkaffoldOptions{}, inputFile, "")
+			t.CheckErrorAndDeepEqual(test.shouldErr, err, test.expected, b.String())
+		})
+	}
+}
diff --git a/pkg/skaffold/render/transform/transform_test.go b/pkg/skaffold/render/transform/transform_test.go
index ab29e280d..08c5f6285 100644
--- a/pkg/skaffold/render/transform/transform_test.go
+++ b/pkg/skaffold/render/transform/transform_test.go
@@ -54,6 +54,29 @@ func TestNewTransformer(t *testing.T) {
 	}
 }
 
+func TestNewTransformerDoesNotShareConfigMap(t *testing.T) {
+	tests := []struct {
+		description string
+		config      []latest.Transformer
+	}{
+		{
+			description: "set-labels",
+			config: []latest.Transformer{
+				{Name: "set-labels", ConfigMap: []string{"owner2:skaffold-test"}},
+				{Name: "set-labels", ConfigMap: []string{"owner:skaffold-test"}},
+			},
+		},
+	}
+	for _, test := range tests {
+		testutil.Run(t, test.description, func(t *testutil.T) {
+			transformer, err := NewTransformer(test.config)
+			t.CheckNoError(err)
+			t.CheckDeepEqual(1, len(transformer.kptFn[0].ConfigMap))
+			t.CheckDeepEqual(1, len(transformer.kptFn[1].ConfigMap))
+		})
+	}
+}
+
 func TestNewValidator_Error(t *testing.T) {
 	testutil.Run(t, "", func(t *testutil.T) {
 		_, err := NewTransformer([]latest.Transformer{
diff --git a/pkg/skaffold/schema/latest/config.go b/pkg/skaffold/schema/latest/config.go
index ed0b43a51..88fb77620 100644
--- a/pkg/skaffold/schema/latest/config.go
+++ b/pkg/skaffold/schema/latest/config.go
@@ -25,7 +25,7 @@ import (
 	"github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/schema/util"
 )
 
-// This config version is not yet released, it is SAFE TO MODIFY the structs in this file.
+// !!! WARNING !!! This config version is already released, please DO NOT MODIFY the structs in this file.
 const Version string = "skaffold/v4beta4"
 
 // NewSkaffoldConfig creates a SkaffoldConfig
@@ -603,11 +603,36 @@ type VerifyTestCase struct {
 	// Name is the name descriptor for the verify test.
 	Name string `yaml:"name" yamltags:"required"`
 	// Container is the container information for the verify test.
-	Container v1.Container `yaml:"container" yamltags:"required"`
+	Container VerifyContainer `yaml:"container" yamltags:"required"`
 	// ExecutionMode is the execution mode used to execute the verify test case.
 	ExecutionMode VerifyExecutionModeConfig `yaml:"executionMode,omitempty"`
 }
 
+// VerifyContainer is a list of tests to run on images that Skaffold builds.
+type VerifyContainer struct {
+	// Name of the container.
+	Name string `yaml:"name" yamltags:"required"`
+	// Image is the container image name.
+	Image string `yaml:"image" yamltags:"required"`
+	// Command is the entrypoint array. Not executed within a shell.
+	// The container image's ENTRYPOINT is used if this is not provided.
+	Command []string `yaml:"command,omitempty"`
+	// Args are the arguments to the entrypoint.
+	// The container image's CMD is used if this is not provided.
+	Args []string `yaml:"args,omitempty"`
+	// Env is the list of environment variables to set in the container.
+	Env []VerifyEnvVar `json:"env,omitempty"`
+}
+
+// VerifyEnvVar represents an environment variable present in a Container.
+type VerifyEnvVar struct {
+	// Name of the environment variable. Must be a C_IDENTIFIER.
+	Name string `json:"name" yamltags:"required"`
+
+	// Value of the environment variable
+	Value string `json:"value"`
+}
+
 // RenderConfig contains all the configuration needed by the render steps.
 type RenderConfig struct {
 
diff --git a/pkg/skaffold/schema/v2beta29/upgrade_test.go b/pkg/skaffold/schema/v2beta29/upgrade_test.go
index ba4689c58..5a6616b10 100644
--- a/pkg/skaffold/schema/v2beta29/upgrade_test.go
+++ b/pkg/skaffold/schema/v2beta29/upgrade_test.go
@@ -245,7 +245,9 @@ profiles:
 - name: kustomize
   patches:
   - op: remove
-    path: /deploy/kubectl
+    path: /deploy/kubectl/manifests
+  - op: remove
+    path: /deploy/kubectl/manifests/0
   - op: remove
     path: /deploy/helm
   deploy:
@@ -273,6 +275,8 @@ profiles:
   patches:
   - op: remove
     path: /manifests/rawYaml
+  - op: remove
+    path: /manifests/rawYaml/0
   - op: remove
     path: /manifests/helm
   - op: remove