Repository: kubernetes-sigs/security-profiles-operator
Pull request #1237 (2022-10-17 07:59:59)

Bump to v0.5.0


#### What type of PR is this?


/kind documentation


#### What this PR does / why we need it:
Refers to #1144 
#### Which issue(s) this PR fixes:

<!--
*Automatically closes linked issue when PR is merged.
Usage: `Fixes #<issue number>`, or `Fixes (paste link of issue)`.

Fixes #

or

None
-->
None
#### Does this PR have test?
None
<!--
If tests aren't applicable just write N/A.
-->

#### Special notes for your reviewer:
PTAL @jhrozek @JAORMX @pjbgf 
#### Does this PR introduce a user-facing change?

<!--
If no, just write "NONE" in the release-note block below.
If yes, a release note is required:
Enter your extended release note in the block below. If the PR requires additional action from users switching to the new release, include the string "action required".

For more information on release notes see: https://git.k8s.io/community/contributors/guide/release-notes.md
-->

```release-note
None
```


k8s-ci-robot: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/kubernetes-sigs/security-profiles-operator/pull/1237#" title="Author self-approved">saschagrunert</a>*

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=kubernetes-sigs%2Fsecurity-profiles-operator).

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

<details >
Needs approval from an approver in each of these files:

- ~~[OWNERS](https://github.com/kubernetes-sigs/security-profiles-operator/blob/main/OWNERS)~~ [saschagrunert]

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":[]} -->
k8s-ci-robot: @saschagrunert: The following test **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Required | Rerun command
--- | --- | --- | --- | ---
pull-security-profiles-operator-verify | 9461c4091667bc423e8d263ba2a9fcf1c362e636 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/1237/pull-security-profiles-operator-verify/1581918829410258944) | true | `/test pull-security-profiles-operator-verify`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=security-profiles-operator&pr=1237). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Asaschagrunert). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-sigs/security-profiles-operator/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
saschagrunert: We can wait for https://github.com/kubernetes-sigs/security-profiles-operator/pull/1235

/hold
jhrozek: We seem to be having issues pulling images, with some additional debugging I see:
```
NAME                                          READY   STATUS             RESTARTS   AGE
security-profiles-operator-76d4498fbf-7x5sc   0/1     ImagePullBackOff   0          2m15s
security-profiles-operator-76d4498fbf-bkwjb   0/1     ImagePullBackOff   0          2m15s
security-profiles-operator-76d4498fbf-f845w   0/1     ImagePullBackOff   0          2m15s
```
...looking intensifies..
saschagrunert: > We seem to be having issues pulling images, with some additional debugging I see:

Is the image the localhost/ one? :thinking: 
jhrozek: No, it seems the deployment refers to the unreleased image:
```
2022-10-17T11:37:05.1515988Z     Image:      k8s.gcr.io/security-profiles-operator/security-profiles-operator:v0.5.0
```
saschagrunert: @jhrozek so the image seems to come out of the catalog container. Do you have any clue how we can fix that in the CI?
jhrozek: > @jhrozek so the image seems to come out of the catalog container. Do you have any clue how we can fix that in the CI?

So in the OLM script we make a deployment that should reference the local image with:
```
    OPERATOR_MANIFEST=deploy/operator-ci.yaml
    # Create a manifest with local image                                                                                                                                                                                                      
    pushd deploy/base                                                                                                                                                                                                                         
    kustomize edit set image security-profiles-operator=$IMG                                                                                                                                                                                  
    popd                                                                                                                                                                                                                                      
    kustomize build --reorder=none deploy/overlays/cluster -o ${OPERATOR_MANIFEST}  
```
but the result still references the gcr image:
```
grep -C3 image\: deploy/operator-ci.yaml
          spec:
            description: ProfileBindingSpec defines the desired state of ProfileBinding.
            properties:
              image:
                description: Image name within pod containers to match to the profile.
                type: string
              profileRef:
--
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        image: k8s.gcr.io/security-profiles-operator/security-profiles-operator:v0.5.0
        imagePullPolicy: Always
        name: security-profiles-operator
        resources:
```
I think the bug is here, but I don't see it right now
saschagrunert: /hold for https://github.com/kubernetes-sigs/security-profiles-operator/pull/1239

Patch:
diff --git a/VERSION b/VERSION
index 5d47ff8c4..8f0916f76 100644
--- a/VERSION
+++ b/VERSION
@@ -1,1 +1,1 @@
-0.4.4-dev
+0.5.0
diff --git a/bundle/manifests/security-profiles-operator.clusterserviceversion.yaml b/bundle/manifests/security-profiles-operator.clusterserviceversion.yaml
index ec337ec9b..f80626888 100644
--- a/bundle/manifests/security-profiles-operator.clusterserviceversion.yaml
+++ b/bundle/manifests/security-profiles-operator.clusterserviceversion.yaml
@@ -98,11 +98,11 @@ metadata:
       ]
     capabilities: Basic Install
     categories: Security
-    olm.skipRange: '>=0.4.1 <0.4.4-dev'
+    olm.skipRange: '>=0.4.1 <0.5.0'
     operatorframework.io/suggested-namespace: security-profiles-operator
     operators.operatorframework.io/builder: operator-sdk-v1.22.2
     operators.operatorframework.io/project_layout: go.kubebuilder.io/v3
-  name: security-profiles-operator.v0.4.4-dev
+  name: security-profiles-operator.v0.5.0
   namespace: placeholder
 spec:
   apiservicedefinitions: {}
@@ -425,7 +425,7 @@ spec:
                   valueFrom:
                     fieldRef:
                       fieldPath: metadata.namespace
-                image: gcr.io/k8s-staging-sp-operator/security-profiles-operator:latest
+                image: k8s.gcr.io/security-profiles-operator/security-profiles-operator:v0.5.0
                 imagePullPolicy: Always
                 name: security-profiles-operator
                 resources:
@@ -499,4 +499,4 @@ spec:
     name: rbac-proxy
   - image: quay.io/security-profiles-operator/selinuxd
     name: selinuxd
-  version: 0.4.4-dev
+  version: 0.5.0
diff --git a/dependencies.yaml b/dependencies.yaml
index 663feb058..dfb5967c3 100644
--- a/dependencies.yaml
+++ b/dependencies.yaml
@@ -172,7 +172,7 @@ dependencies:
       match: BOM_VERSION
 
   - name: spo-current
-    version: 0.4.4-dev
+    version: 0.5.0
     refPaths:
     - path: VERSION
       match: ^.*
diff --git a/deploy/helm/Chart.yaml b/deploy/helm/Chart.yaml
index 631029627..5b6febfe8 100644
--- a/deploy/helm/Chart.yaml
+++ b/deploy/helm/Chart.yaml
@@ -2,5 +2,5 @@ apiVersion: v2
 name: security-profiles-operator
 description: "The Kubernetes Security Profiles Operator."
 type: application
-version: "0.4.4-dev"
-appVersion: "0.4.4-dev"
+version: "0.5.0"
+appVersion: "0.5.0"
diff --git a/deploy/kustomize-deployment/kustomization.yaml b/deploy/kustomize-deployment/kustomization.yaml
index 584f44951..cebd13c4e 100644
--- a/deploy/kustomize-deployment/kustomization.yaml
+++ b/deploy/kustomize-deployment/kustomization.yaml
@@ -4,11 +4,11 @@ kind: Kustomization
 
 images:
   - name: security-profiles-operator
-    newName: gcr.io/k8s-staging-sp-operator/security-profiles-operator
-    newTag: latest
+    # newName: gcr.io/k8s-staging-sp-operator/security-profiles-operator
+    # newTag: latest
     # For images to be released:
-    # newName: k8s.gcr.io/security-profiles-operator/security-profiles-operator
-    # newTag: v0.4.4
+    newName: k8s.gcr.io/security-profiles-operator/security-profiles-operator
+    newTag: v0.5.0
 
 commonLabels:
   app: security-profiles-operator
diff --git a/deploy/namespace-operator.yaml b/deploy/namespace-operator.yaml
index ab06e60af..15c8431b8 100644
--- a/deploy/namespace-operator.yaml
+++ b/deploy/namespace-operator.yaml
@@ -2922,7 +2922,7 @@ spec:
           valueFrom:
             fieldRef:
               fieldPath: metadata.namespace
-        image: gcr.io/k8s-staging-sp-operator/security-profiles-operator:latest
+        image: k8s.gcr.io/security-profiles-operator/security-profiles-operator:v0.5.0
         imagePullPolicy: Always
         name: security-profiles-operator
         resources:
diff --git a/deploy/openshift-dev.yaml b/deploy/openshift-dev.yaml
index a8e136316..b90f4b869 100644
--- a/deploy/openshift-dev.yaml
+++ b/deploy/openshift-dev.yaml
@@ -2920,7 +2920,7 @@ spec:
           valueFrom:
             fieldRef:
               fieldPath: metadata.namespace
-        image: image-registry.openshift-image-registry.svc:5000/openshift/security-profiles-operator:latest
+        image: k8s.gcr.io/security-profiles-operator/security-profiles-operator:v0.5.0
         imagePullPolicy: Always
         name: security-profiles-operator
         resources:
diff --git a/deploy/operator.yaml b/deploy/operator.yaml
index 8c3c24334..b90f4b869 100644
--- a/deploy/operator.yaml
+++ b/deploy/operator.yaml
@@ -2920,7 +2920,7 @@ spec:
           valueFrom:
             fieldRef:
               fieldPath: metadata.namespace
-        image: gcr.io/k8s-staging-sp-operator/security-profiles-operator:latest
+        image: k8s.gcr.io/security-profiles-operator/security-profiles-operator:v0.5.0
         imagePullPolicy: Always
         name: security-profiles-operator
         resources:
diff --git a/deploy/webhook-operator.yaml b/deploy/webhook-operator.yaml
index abe58c15d..03be8a534 100644
--- a/deploy/webhook-operator.yaml
+++ b/deploy/webhook-operator.yaml
@@ -2920,7 +2920,7 @@ spec:
           valueFrom:
             fieldRef:
               fieldPath: metadata.namespace
-        image: gcr.io/k8s-staging-sp-operator/security-profiles-operator:latest
+        image: k8s.gcr.io/security-profiles-operator/security-profiles-operator:v0.5.0
         imagePullPolicy: Always
         name: security-profiles-operator
         resources:
diff --git a/examples/olm/install-resources.yaml b/examples/olm/install-resources.yaml
index c75a455d8..0682f5503 100644
--- a/examples/olm/install-resources.yaml
+++ b/examples/olm/install-resources.yaml
@@ -14,7 +14,7 @@ metadata:
   namespace: olm
 spec:
   sourceType: grpc
-  image: gcr.io/k8s-staging-sp-operator/security-profiles-operator-catalog:latest
+  image: k8s.gcr.io/security-profiles-operator/security-profiles-operator-catalog:v0.5.0
 ---
 apiVersion: operators.coreos.com/v1
 kind: OperatorGroup
diff --git a/go.mod b/go.mod
index 0d7b593a7..1a549352e 100644
--- a/go.mod
+++ b/go.mod
@@ -21,7 +21,7 @@ require (
 	github.com/prometheus/client_model v0.2.0
 	github.com/seccomp/libseccomp-golang v0.9.2-0.20210429002308-3879420cc921
 	github.com/stretchr/testify v1.8.0
-	github.com/urfave/cli/v2 v2.19.2
+	github.com/urfave/cli/v2 v2.20.2
 	golang.org/x/net v0.0.0-20220909164309-bea034e7d591
 	golang.org/x/sync v0.0.0-20220907140024-f12130a52804
 	google.golang.org/grpc v1.50.1
diff --git a/go.sum b/go.sum
index f182e7627..a6d17a2df 100644
--- a/go.sum
+++ b/go.sum
@@ -1353,8 +1353,8 @@ github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtX
 github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
 github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
 github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
-github.com/urfave/cli/v2 v2.19.2 h1:eXu5089gqqiDQKSnFW+H/FhjrxRGztwSxlTsVK7IuqQ=
-github.com/urfave/cli/v2 v2.19.2/go.mod h1:1CNUng3PtjQMtRzJO4FMXBQvkGtuYRxxiR9xMa7jMwI=
+github.com/urfave/cli/v2 v2.20.2 h1:dKA0LUjznZpwmmbrc0pOgcLTEilnHeM8Av9Yng77gHM=
+github.com/urfave/cli/v2 v2.20.2/go.mod h1:1CNUng3PtjQMtRzJO4FMXBQvkGtuYRxxiR9xMa7jMwI=
 github.com/uudashr/gocognit v1.0.5/go.mod h1:wgYz0mitoKOTysqxTDMOUXg+Jb5SvtihkfmugIZYpEA=
 github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
 github.com/valyala/fasthttp v1.30.0/go.mod h1:2rsYD01CKFrjjsvFxx75KlEUNpWNBY9JWD3K/7o2Cus=
diff --git a/installation-usage.md b/installation-usage.md
index dff48c0b5..d838b3a93 100644
--- a/installation-usage.md
+++ b/installation-usage.md
@@ -158,7 +158,7 @@ kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/
 kubectl --namespace cert-manager wait --for condition=ready pod -l app.kubernetes.io/instance=cert-manager
 # Install the chart from a release URL (note: helm also allows users to
 # specify a file path instead of a URL, if desired):
-helm install security-profiles-operator https://github.com/kubernetes-sigs/security-profiles-operator/releases/download/v0.4.4-dev/security-profiles-operator-0.4.4-dev.tgz
+helm install security-profiles-operator https://github.com/kubernetes-sigs/security-profiles-operator/releases/download/v0.5.0/security-profiles-operator-0.5.0.tgz
 ```
 
 ### Installation on AKS
diff --git a/internal/pkg/manager/spod/bindata/spod.go b/internal/pkg/manager/spod/bindata/spod.go
index 50b267f4f..49b876665 100644
--- a/internal/pkg/manager/spod/bindata/spod.go
+++ b/internal/pkg/manager/spod/bindata/spod.go
@@ -45,6 +45,7 @@ var (
 	metricsCertPath                 = "/var/run/secrets/metrics"
 	metricsServerCert               = "metrics-server-cert"
 	openshiftCertAnnotation         = "service.beta.openshift.io/serving-cert-secret-name"
+	localSeccompProfilePath         = "security-profiles-operator.json"
 )
 
 const (
@@ -125,9 +126,7 @@ var Manifest = &appsv1.DaemonSet{
 		Template: corev1.PodTemplateSpec{
 			ObjectMeta: metav1.ObjectMeta{
 				Annotations: map[string]string{
-					"openshift.io/scc":             "privileged",
-					corev1.SeccompPodAnnotationKey: corev1.SeccompProfileRuntimeDefault,
-					corev1.SeccompContainerAnnotationKeyPrefix + config.OperatorName: "localhost/security-profiles-operator.json",
+					"openshift.io/scc": "privileged",
 				},
 				Labels: map[string]string{
 					"app":  config.OperatorName,
@@ -136,6 +135,11 @@ var Manifest = &appsv1.DaemonSet{
 			},
 			Spec: corev1.PodSpec{
 				ServiceAccountName: config.SPOdServiceAccount,
+				SecurityContext: &corev1.PodSecurityContext{
+					SeccompProfile: &corev1.SeccompProfile{
+						Type: corev1.SeccompProfileTypeRuntimeDefault,
+					},
+				},
 				InitContainers: []corev1.Container{
 					{
 						Name:            "non-root-enabler",
@@ -297,6 +301,10 @@ semodule -i /opt/spo-profiles/selinuxrecording.cil
 								// TODO(jaosorior): Use a more restricted selinux type
 								Type: "spc_t",
 							},
+							SeccompProfile: &corev1.SeccompProfile{
+								Type:             corev1.SeccompProfileTypeLocalhost,
+								LocalhostProfile: &localSeccompProfilePath,
+							},
 						},
 						Resources: corev1.ResourceRequirements{
 							Requests: corev1.ResourceList{
diff --git a/release.md b/release.md
index 58fdbb04b..358b19946 100644
--- a/release.md
+++ b/release.md
@@ -13,17 +13,21 @@ The first PR targets this repository and:
 
 - bumps the [`VERSION`](VERSION) file to the target version
 - changes the `images` `newName`/`newTag` fields of
-  [./deploy/base/kustomization.yaml](deploy/base/kustomization.yaml) from
-  `gcr.io/k8s-staging-sp-operator/security-profiles-operator` to
+  [./deploy/kustomize-deployment/kustomization.yaml](deploy/kustomize-deployment/kustomization.yaml)
+  from `gcr.io/k8s-staging-sp-operator/security-profiles-operator` to
   `k8s.gcr.io/security-profiles-operator/security-profiles-operator` (`newName`) and the
   corresponding tag (`newTag`). After that the make target `make bundle`
   has to be run and the changes have to be committed.
-- changes the tag in the same way in the OLM example manifest at
+- changes the `image` in the `CatalogSource` in the same way at
   [./examples/olm/install-resources.yaml](/examples/olm/install-resources.yaml)
 - changes [`hack/ci/e2e-olm.sh`](/hack/ci/e2e-olm.sh) to sed
-  `"s#k8s.gcr.io/security-profiles-operator/security-profiles-operator-catalog:v0.4.3#${CATALOG_IMG}#g"`
+  `"s#k8s.gcr.io/security-profiles-operator/security-profiles-operator-catalog:v0.0.0#${CATALOG_IMG}#g"`
   instead of
   `"s#gcr.io/k8s-staging-sp-operator/security-profiles-operator-catalog:latest#${CATALOG_IMG}#g"`
+  (please note to change the version `v0.0.0` to the upcoming release)
+- updates [./dependencies.yaml](./dependencies.yaml) `spo-current` version as
+  well as its linked files. Run `make verify-dependencies` to verify the
+  results.
 
 After this PR has been merged, we have to watch out the successful build of the
 container image via the automatically triggered
@@ -64,9 +68,9 @@ After that, another PR against this repository has to be created, which:
 - bumps the [`VERSION`](VERSION) file to the next minor version, but now including the
   suffix `-dev`, for example `1.0.0-dev`.
 - changes the `images` `newName`/`newTag` fields in
-  [./deploy/base/kustomization.yaml](deploy/base/kustomization.yaml) back to
-  `gcr.io/k8s-staging-sp-operator/security-profiles-operator` (`newName`) and `latest`
-  (`newTag`) and runc `make bundle`
+  [./deploy/kustomize-deployment/kustomization.yaml](deploy/kustomize-deployment/kustomization.yaml)
+  back to `gcr.io/k8s-staging-sp-operator/security-profiles-operator`
+  (`newName`) and `latest` (`newTag`) and runc `make bundle`
 - changes the tag in the same way in the OLM example manifest at
   [./examples/olm/install-resources.yaml](/examples/olm/install-resources.yaml)
 - reverts the changes to [`hack/ci/e2e-olm.sh`](/hack/ci/e2e-olm.sh)
diff --git a/vendor/github.com/urfave/cli/v2/app.go b/vendor/github.com/urfave/cli/v2/app.go
index 0ae3f5247..24704e8f7 100644
--- a/vendor/github.com/urfave/cli/v2/app.go
+++ b/vendor/github.com/urfave/cli/v2/app.go
@@ -7,7 +7,6 @@ import (
 	"io"
 	"os"
 	"path/filepath"
-	"reflect"
 	"sort"
 	"time"
 )
@@ -112,6 +111,8 @@ type App struct {
 	Suggest bool
 
 	didSetup bool
+
+	rootCommand *Command
 }
 
 type SuggestFlagFunc func(flags []Flag, provided string, hideHelp bool) string
@@ -197,9 +198,11 @@ func (a *App) Setup() {
 	var newCommands []*Command
 
 	for _, c := range a.Commands {
-		if c.HelpName == "" {
-			c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name)
+		cname := c.Name
+		if c.HelpName != "" {
+			cname = c.HelpName
 		}
+		c.HelpName = fmt.Sprintf("%s %s", a.HelpName, cname)
 
 		c.flagCategories = newFlagCategoriesFromFlags(c.Flags)
 		newCommands = append(newCommands, c)
@@ -240,6 +243,31 @@ func (a *App) Setup() {
 	}
 }
 
+func (a *App) newRootCommand() *Command {
+	return &Command{
+		Name:                   a.Name,
+		Usage:                  a.Usage,
+		UsageText:              a.UsageText,
+		Description:            a.Description,
+		ArgsUsage:              a.ArgsUsage,
+		BashComplete:           a.BashComplete,
+		Before:                 a.Before,
+		After:                  a.After,
+		Action:                 a.Action,
+		OnUsageError:           a.OnUsageError,
+		Subcommands:            a.Commands,
+		Flags:                  a.Flags,
+		flagCategories:         a.flagCategories,
+		HideHelp:               a.HideHelp,
+		HideHelpCommand:        a.HideHelpCommand,
+		UseShortOptionHandling: a.UseShortOptionHandling,
+		HelpName:               a.HelpName,
+		CustomHelpTemplate:     a.CustomAppHelpTemplate,
+		categories:             a.categories,
+		isRoot:                 true,
+	}
+}
+
 func (a *App) newFlagSet() (*flag.FlagSet, error) {
 	return flagSet(a.Name, a.Flags)
 }
@@ -268,136 +296,20 @@ func (a *App) RunContext(ctx context.Context, arguments []string) (err error) {
 	// always appends the completion flag at the end of the command
 	shellComplete, arguments := checkShellCompleteFlag(a, arguments)
 
-	set, err := a.newFlagSet()
-	if err != nil {
-		return err
-	}
-
-	err = parseIter(set, a, arguments[1:], shellComplete)
-	nerr := normalizeFlags(a.Flags, set)
-	cCtx := NewContext(a, set, &Context{Context: ctx})
-	if nerr != nil {
-		_, _ = fmt.Fprintln(a.Writer, nerr)
-		if !a.HideHelp {
-			_ = ShowAppHelp(cCtx)
-		}
-		return nerr
-	}
+	cCtx := NewContext(a, nil, &Context{Context: ctx})
 	cCtx.shellComplete = shellComplete
 
-	if checkCompletions(cCtx) {
-		return nil
-	}
-
-	if err != nil {
-		if a.OnUsageError != nil {
-			err := a.OnUsageError(cCtx, err, false)
-			a.handleExitCoder(cCtx, err)
-			return err
-		}
-		_, _ = fmt.Fprintf(a.Writer, "%s %s\n\n", "Incorrect Usage.", err.Error())
-		if a.Suggest {
-			if suggestion, err := a.suggestFlagFromError(err, ""); err == nil {
-				fmt.Fprintf(a.Writer, suggestion)
-			}
-		}
-		if !a.HideHelp {
-			_ = ShowAppHelp(cCtx)
-		}
-		return err
-	}
-
-	if a.After != nil && !cCtx.shellComplete {
-		defer func() {
-			if afterErr := a.After(cCtx); afterErr != nil {
-				if err != nil {
-					err = newMultiError(err, afterErr)
-				} else {
-					err = afterErr
-				}
-			}
-		}()
-	}
-
-	if !a.HideHelp && checkHelp(cCtx) {
-		_ = ShowAppHelp(cCtx)
-		return nil
-	}
+	a.rootCommand = a.newRootCommand()
+	cCtx.Command = a.rootCommand
 
-	if !a.HideVersion && checkVersion(cCtx) {
-		ShowVersion(cCtx)
-		return nil
-	}
-
-	cerr := cCtx.checkRequiredFlags(a.Flags)
-	if cerr != nil {
-		_ = ShowAppHelp(cCtx)
-		return cerr
-	}
-
-	if a.Before != nil && !cCtx.shellComplete {
-		beforeErr := a.Before(cCtx)
-		if beforeErr != nil {
-			a.handleExitCoder(cCtx, beforeErr)
-			err = beforeErr
-			return err
-		}
-	}
-
-	if err = runFlagActions(cCtx, a.Flags); err != nil {
-		return err
-	}
-
-	var c *Command
-	args := cCtx.Args()
-	if args.Present() {
-		name := args.First()
-		if a.validCommandName(name) {
-			c = a.Command(name)
-		} else {
-			hasDefault := a.DefaultCommand != ""
-			isFlagName := checkStringSliceIncludes(name, cCtx.FlagNames())
-
-			var (
-				isDefaultSubcommand   = false
-				defaultHasSubcommands = false
-			)
-
-			if hasDefault {
-				dc := a.Command(a.DefaultCommand)
-				defaultHasSubcommands = len(dc.Subcommands) > 0
-				for _, dcSub := range dc.Subcommands {
-					if checkStringSliceIncludes(name, dcSub.Names()) {
-						isDefaultSubcommand = true
-						break
-					}
-				}
-			}
-
-			if isFlagName || (hasDefault && (defaultHasSubcommands && isDefaultSubcommand)) {
-				argsWithDefault := a.argsWithDefaultCommand(args)
-				if !reflect.DeepEqual(args, argsWithDefault) {
-					c = a.Command(argsWithDefault.First())
-				}
-			}
-		}
-	} else if a.DefaultCommand != "" {
-		c = a.Command(a.DefaultCommand)
-	}
-
-	if c != nil {
-		return c.Run(cCtx)
-	}
-
-	if a.Action == nil {
-		a.Action = helpCommand.Action
-	}
-
-	// Run default Action
-	err = a.Action(cCtx)
+	return a.rootCommand.Run(cCtx, arguments...)
+}
 
-	a.handleExitCoder(cCtx, err)
-	return err
+// This is a stub function to keep public API unchanged from old code
+//
+// Deprecated: use App.Run or App.RunContext
+func (a *App) RunAsSubcommand(ctx *Context) (err error) {
+	return a.RunContext(ctx.Context, ctx.Args().Slice())
 }
 
 func (a *App) suggestFlagFromError(err error, command string) (string, error) {
@@ -407,15 +319,17 @@ func (a *App) suggestFlagFromError(err error, command string) (string, error) {
 	}
 
 	flags := a.Flags
+	hideHelp := a.HideHelp
 	if command != "" {
 		cmd := a.Command(command)
 		if cmd == nil {
 			return "", err
 		}
 		flags = cmd.Flags
+		hideHelp = hideHelp || cmd.HideHelp
 	}
 
-	suggestion := SuggestFlag(flags, flag, a.HideHelp)
+	suggestion := SuggestFlag(flags, flag, hideHelp)
 	if len(suggestion) == 0 {
 		return "", err
 	}
@@ -435,120 +349,6 @@ func (a *App) RunAndExitOnError() {
 	}
 }
 
-// RunAsSubcommand invokes the subcommand given the context, parses ctx.Args() to
-// generate command-specific flags
-func (a *App) RunAsSubcommand(ctx *Context) (err error) {
-	// Setup also handles HideHelp and HideHelpCommand
-	a.Setup()
-
-	var newCmds []*Command
-	for _, c := range a.Commands {
-		if c.HelpName == "" {
-			c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name)
-		}
-		newCmds = append(newCmds, c)
-	}
-	a.Commands = newCmds
-
-	set, err := a.newFlagSet()
-	if err != nil {
-		return err
-	}
-
-	err = parseIter(set, a, ctx.Args().Tail(), ctx.shellComplete)
-	nerr := normalizeFlags(a.Flags, set)
-	cCtx := NewContext(a, set, ctx)
-
-	if nerr != nil {
-		_, _ = fmt.Fprintln(a.Writer, nerr)
-		_, _ = fmt.Fprintln(a.Writer)
-		if len(a.Commands) > 0 {
-			_ = ShowSubcommandHelp(cCtx)
-		} else {
-			_ = ShowCommandHelp(ctx, cCtx.Args().First())
-		}
-		return nerr
-	}
-
-	if checkCompletions(cCtx) {
-		return nil
-	}
-
-	if err != nil {
-		if a.OnUsageError != nil {
-			err = a.OnUsageError(cCtx, err, true)
-			a.handleExitCoder(cCtx, err)
-			return err
-		}
-		_, _ = fmt.Fprintf(a.Writer, "%s %s\n\n", "Incorrect Usage.", err.Error())
-		if a.Suggest {
-			if suggestion, err := a.suggestFlagFromError(err, cCtx.Command.Name); err == nil {
-				fmt.Fprintf(a.Writer, suggestion)
-			}
-		}
-		_ = ShowSubcommandHelp(cCtx)
-		return err
-	}
-
-	if len(a.Commands) > 0 {
-		if checkSubcommandHelp(cCtx) {
-			return nil
-		}
-	} else {
-		if checkCommandHelp(ctx, cCtx.Args().First()) {
-			return nil
-		}
-	}
-
-	cerr := cCtx.checkRequiredFlags(a.Flags)
-	if cerr != nil {
-		_ = ShowSubcommandHelp(cCtx)
-		return cerr
-	}
-
-	if a.After != nil && !cCtx.shellComplete {
-		defer func() {
-			afterErr := a.After(cCtx)
-			if afterErr != nil {
-				a.handleExitCoder(cCtx, err)
-				if err != nil {
-					err = newMultiError(err, afterErr)
-				} else {
-					err = afterErr
-				}
-			}
-		}()
-	}
-
-	if a.Before != nil && !cCtx.shellComplete {
-		beforeErr := a.Before(cCtx)
-		if beforeErr != nil {
-			a.handleExitCoder(cCtx, beforeErr)
-			err = beforeErr
-			return err
-		}
-	}
-
-	if err = runFlagActions(cCtx, a.Flags); err != nil {
-		return err
-	}
-
-	args := cCtx.Args()
-	if args.Present() {
-		name := args.First()
-		c := a.Command(name)
-		if c != nil {
-			return c.Run(cCtx)
-		}
-	}
-
-	// Run default Action
-	err = a.Action(cCtx)
-
-	a.handleExitCoder(cCtx, err)
-	return err
-}
-
 // Command returns the named command on App. Returns nil if the command does not exist
 func (a *App) Command(name string) *Command {
 	for _, c := range a.Commands {
diff --git a/vendor/github.com/urfave/cli/v2/cli.go b/vendor/github.com/urfave/cli/v2/cli.go
index b3b864cf5..28ad0582b 100644
--- a/vendor/github.com/urfave/cli/v2/cli.go
+++ b/vendor/github.com/urfave/cli/v2/cli.go
@@ -22,4 +22,4 @@
 //	}
 package cli
 
-//go:generate go run cmd/urfave-cli-genflags/main.go
+//go:generate make -C cmd/urfave-cli-genflags run
diff --git a/vendor/github.com/urfave/cli/v2/command.go b/vendor/github.com/urfave/cli/v2/command.go
index 037ebc52c..a63048dbd 100644
--- a/vendor/github.com/urfave/cli/v2/command.go
+++ b/vendor/github.com/urfave/cli/v2/command.go
@@ -3,6 +3,7 @@ package cli
 import (
 	"flag"
 	"fmt"
+	"reflect"
 	"sort"
 	"strings"
 )
@@ -62,6 +63,12 @@ type Command struct {
 	// cli.go uses text/template to render templates. You can
 	// render custom help text by setting this variable.
 	CustomHelpTemplate string
+
+	// categories contains the categorized commands and is populated on app startup
+	categories CommandCategories
+
+	// if this is a root "special" command
+	isRoot bool
 }
 
 type Commands []*Command
@@ -89,10 +96,21 @@ func (c *Command) FullName() string {
 	return strings.Join(c.commandNamePath, " ")
 }
 
-// Run invokes the command given the context, parses ctx.Args() to generate command-specific flags
-func (c *Command) Run(ctx *Context) (err error) {
-	if len(c.Subcommands) > 0 {
-		return c.startApp(ctx)
+func (cmd *Command) Command(name string) *Command {
+	for _, c := range cmd.Subcommands {
+		if c.HasName(name) {
+			return c
+		}
+	}
+
+	return nil
+}
+
+func (c *Command) setup(ctx *Context) {
+	if c.Command(helpCommand.Name) == nil && !c.HideHelp {
+		if !c.HideHelpCommand {
+			c.Subcommands = append(c.Subcommands, helpCommand)
+		}
 	}
 
 	if !c.HideHelp && HelpFlag != nil {
@@ -104,46 +122,72 @@ func (c *Command) Run(ctx *Context) (err error) {
 		c.UseShortOptionHandling = true
 	}
 
-	set, err := c.parseFlags(ctx.Args(), ctx.shellComplete)
+	c.categories = newCommandCategories()
+	for _, command := range c.Subcommands {
+		c.categories.AddCommand(command.Category, command)
+	}
+	sort.Sort(c.categories.(*commandCategories))
 
-	cCtx := NewContext(ctx.App, set, ctx)
-	cCtx.Command = c
-	if checkCommandCompletions(cCtx, c.Name) {
+	var newCmds []*Command
+	for _, scmd := range c.Subcommands {
+		if scmd.HelpName == "" {
+			scmd.HelpName = fmt.Sprintf("%s %s", c.HelpName, scmd.Name)
+		}
+		newCmds = append(newCmds, scmd)
+	}
+	c.Subcommands = newCmds
+}
+
+func (c *Command) Run(cCtx *Context, arguments ...string) (err error) {
+
+	if !c.isRoot {
+		c.setup(cCtx)
+	}
+
+	a := args(arguments)
+	set, err := c.parseFlags(&a, cCtx.shellComplete)
+	cCtx.flagSet = set
+
+	if c.isRoot {
+		if checkCompletions(cCtx) {
+			return nil
+		}
+	} else if checkCommandCompletions(cCtx, c.Name) {
 		return nil
 	}
 
 	if err != nil {
 		if c.OnUsageError != nil {
-			err = c.OnUsageError(cCtx, err, false)
+			err = c.OnUsageError(cCtx, err, !c.isRoot)
 			cCtx.App.handleExitCoder(cCtx, err)
 			return err
 		}
-		_, _ = fmt.Fprintln(cCtx.App.Writer, "Incorrect Usage:", err.Error())
-		_, _ = fmt.Fprintln(cCtx.App.Writer)
-		if ctx.App.Suggest {
-			if suggestion, err := ctx.App.suggestFlagFromError(err, c.Name); err == nil {
-				fmt.Fprintf(cCtx.App.Writer, suggestion)
+		_, _ = fmt.Fprintf(cCtx.App.Writer, "%s %s\n\n", "Incorrect Usage:", err.Error())
+		if cCtx.App.Suggest {
+			if suggestion, err := c.suggestFlagFromError(err, ""); err == nil {
+				fmt.Fprintf(cCtx.App.Writer, "%s", suggestion)
 			}
 		}
 		if !c.HideHelp {
-			_ = ShowCommandHelp(cCtx, c.Name)
+			if c.isRoot {
+				_ = ShowAppHelp(cCtx)
+			} else {
+				_ = ShowCommandHelp(cCtx.parentContext, c.Name)
+			}
 		}
 		return err
 	}
 
-	if checkCommandHelp(cCtx, c.Name) {
-		return nil
+	if checkHelp(cCtx) {
+		return helpCommand.Action(cCtx)
 	}
 
-	cerr := cCtx.checkRequiredFlags(c.Flags)
-	if cerr != nil {
-		if !c.HideHelp {
-			_ = ShowCommandHelp(cCtx, c.Name)
-		}
-		return cerr
+	if c.isRoot && !cCtx.App.HideVersion && checkVersion(cCtx) {
+		ShowVersion(cCtx)
+		return nil
 	}
 
-	if c.After != nil {
+	if c.After != nil && !cCtx.shellComplete {
 		defer func() {
 			afterErr := c.After(cCtx)
 			if afterErr != nil {
@@ -157,10 +201,17 @@ func (c *Command) Run(ctx *Context) (err error) {
 		}()
 	}
 
-	if c.Before != nil {
-		err = c.Before(cCtx)
-		if err != nil {
-			cCtx.App.handleExitCoder(cCtx, err)
+	cerr := cCtx.checkRequiredFlags(c.Flags)
+	if cerr != nil {
+		_ = ShowSubcommandHelp(cCtx)
+		return cerr
+	}
+
+	if c.Before != nil && !cCtx.shellComplete {
+		beforeErr := c.Before(cCtx)
+		if beforeErr != nil {
+			cCtx.App.handleExitCoder(cCtx, beforeErr)
+			err = beforeErr
 			return err
 		}
 	}
@@ -169,16 +220,57 @@ func (c *Command) Run(ctx *Context) (err error) {
 		return err
 	}
 
+	var cmd *Command
+	args := cCtx.Args()
+	if args.Present() {
+		name := args.First()
+		cmd = c.Command(name)
+		if cmd == nil {
+			hasDefault := cCtx.App.DefaultCommand != ""
+			isFlagName := checkStringSliceIncludes(name, cCtx.FlagNames())
+
+			var (
+				isDefaultSubcommand   = false
+				defaultHasSubcommands = false
+			)
+
+			if hasDefault {
+				dc := cCtx.App.Command(cCtx.App.DefaultCommand)
+				defaultHasSubcommands = len(dc.Subcommands) > 0
+				for _, dcSub := range dc.Subcommands {
+					if checkStringSliceIncludes(name, dcSub.Names()) {
+						isDefaultSubcommand = true
+						break
+					}
+				}
+			}
+
+			if isFlagName || (hasDefault && (defaultHasSubcommands && isDefaultSubcommand)) {
+				argsWithDefault := cCtx.App.argsWithDefaultCommand(args)
+				if !reflect.DeepEqual(args, argsWithDefault) {
+					cmd = cCtx.App.rootCommand.Command(argsWithDefault.First())
+				}
+			}
+		}
+	} else if cCtx.App.DefaultCommand != "" {
+		if dc := cCtx.App.Command(cCtx.App.DefaultCommand); dc != c {
+			cmd = dc
+		}
+	}
+
+	if cmd != nil {
+		newcCtx := NewContext(cCtx.App, nil, cCtx)
+		newcCtx.Command = cmd
+		return cmd.Run(newcCtx, cCtx.Args().Slice()...)
+	}
+
 	if c.Action == nil {
 		c.Action = helpCommand.Action
 	}
 
-	cCtx.Command = c
 	err = c.Action(cCtx)
 
-	if err != nil {
-		cCtx.App.handleExitCoder(cCtx, err)
-	}
+	cCtx.App.handleExitCoder(cCtx, err)
 	return err
 }
 
@@ -190,6 +282,31 @@ func (c *Command) useShortOptionHandling() bool {
 	return c.UseShortOptionHandling
 }
 
+func (c *Command) suggestFlagFromError(err error, command string) (string, error) {
+	flag, parseErr := flagFromError(err)
+	if parseErr != nil {
+		return "", err
+	}
+
+	flags := c.Flags
+	hideHelp := c.HideHelp
+	if command != "" {
+		cmd := c.Command(command)
+		if cmd == nil {
+			return "", err
+		}
+		flags = cmd.Flags
+		hideHelp = hideHelp || cmd.HideHelp
+	}
+
+	suggestion := SuggestFlag(flags, flag, hideHelp)
+	if len(suggestion) == 0 {
+		return "", err
+	}
+
+	return fmt.Sprintf(SuggestDidYouMeanTemplate, suggestion) + "\n\n", nil
+}
+
 func (c *Command) parseFlags(args Args, shellComplete bool) (*flag.FlagSet, error) {
 	set, err := c.newFlagSet()
 	if err != nil {
@@ -228,71 +345,21 @@ func (c *Command) HasName(name string) bool {
 	return false
 }
 
-func (c *Command) startApp(ctx *Context) error {
-	app := &App{
-		Metadata: ctx.App.Metadata,
-		Name:     fmt.Sprintf("%s %s", ctx.App.Name, c.Name),
-	}
-
-	if c.HelpName == "" {
-		app.HelpName = c.HelpName
-	} else {
-		app.HelpName = app.Name
-	}
-
-	app.Usage = c.Usage
-	app.UsageText = c.UsageText
-	app.Description = c.Description
-	app.ArgsUsage = c.ArgsUsage
-
-	// set CommandNotFound
-	app.CommandNotFound = ctx.App.CommandNotFound
-	app.CustomAppHelpTemplate = c.CustomHelpTemplate
-
-	// set the flags and commands
-	app.Commands = c.Subcommands
-	app.Flags = c.Flags
-	app.HideHelp = c.HideHelp
-	app.HideHelpCommand = c.HideHelpCommand
-
-	app.Version = ctx.App.Version
-	app.HideVersion = true
-	app.Compiled = ctx.App.Compiled
-	app.Reader = ctx.App.Reader
-	app.Writer = ctx.App.Writer
-	app.ErrWriter = ctx.App.ErrWriter
-	app.ExitErrHandler = ctx.App.ExitErrHandler
-	app.UseShortOptionHandling = ctx.App.UseShortOptionHandling
-	app.Suggest = ctx.App.Suggest
-
-	app.categories = newCommandCategories()
-	for _, command := range c.Subcommands {
-		app.categories.AddCommand(command.Category, command)
-	}
-
-	sort.Sort(app.categories.(*commandCategories))
-
-	// bash completion
-	app.EnableBashCompletion = ctx.App.EnableBashCompletion
-	if c.BashComplete != nil {
-		app.BashComplete = c.BashComplete
-	}
-
-	// set the actions
-	app.Before = c.Before
-	app.After = c.After
-	if c.Action != nil {
-		app.Action = c.Action
-	} else {
-		app.Action = helpCommand.Action
-	}
-	app.OnUsageError = c.OnUsageError
-
-	for index, cc := range app.Commands {
-		app.Commands[index].commandNamePath = []string{c.Name, cc.Name}
+// VisibleCategories returns a slice of categories and commands that are
+// Hidden=false
+func (c *Command) VisibleCategories() []CommandCategory {
+	ret := []CommandCategory{}
+	for _, category := range c.categories.Categories() {
+		if visible := func() CommandCategory {
+			if len(category.VisibleCommands()) > 0 {
+				return category
+			}
+			return nil
+		}(); visible != nil {
+			ret = append(ret, visible)
+		}
 	}
-
-	return app.RunAsSubcommand(ctx)
+	return ret
 }
 
 // VisibleCommands returns a slice of the Commands with Hidden=false
diff --git a/vendor/github.com/urfave/cli/v2/flag_bool.go b/vendor/github.com/urfave/cli/v2/flag_bool.go
index 0be27e3aa..f64d1cd92 100644
--- a/vendor/github.com/urfave/cli/v2/flag_bool.go
+++ b/vendor/github.com/urfave/cli/v2/flag_bool.go
@@ -84,7 +84,7 @@ func (f *BoolFlag) GetDefaultText() string {
 	if f.DefaultText != "" {
 		return f.DefaultText
 	}
-	return fmt.Sprintf("%v", f.Value)
+	return fmt.Sprintf("%v", f.defaultValue)
 }
 
 // GetEnvVars returns the env vars for this flag
@@ -103,6 +103,9 @@ func (f *BoolFlag) RunAction(c *Context) error {
 
 // Apply populates the flag given the flag set and environment
 func (f *BoolFlag) Apply(set *flag.FlagSet) error {
+	// set default value so that environment wont be able to overwrite it
+	f.defaultValue = f.Value
+
 	if val, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found {
 		if val != "" {
 			valBool, err := strconv.ParseBool(val)
diff --git a/vendor/github.com/urfave/cli/v2/flag_duration.go b/vendor/github.com/urfave/cli/v2/flag_duration.go
index 31db4102e..eac4cb833 100644
--- a/vendor/github.com/urfave/cli/v2/flag_duration.go
+++ b/vendor/github.com/urfave/cli/v2/flag_duration.go
@@ -32,7 +32,7 @@ func (f *DurationFlag) GetDefaultText() string {
 	if f.DefaultText != "" {
 		return f.DefaultText
 	}
-	return f.GetValue()
+	return f.defaultValue.String()
 }
 
 // GetEnvVars returns the env vars for this flag
@@ -42,6 +42,9 @@ func (f *DurationFlag) GetEnvVars() []string {
 
 // Apply populates the flag given the flag set and environment
 func (f *DurationFlag) Apply(set *flag.FlagSet) error {
+	// set default value so that environment wont be able to overwrite it
+	f.defaultValue = f.Value
+
 	if val, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found {
 		if val != "" {
 			valDuration, err := time.ParseDuration(val)
diff --git a/vendor/github.com/urfave/cli/v2/flag_generic.go b/vendor/github.com/urfave/cli/v2/flag_generic.go
index 358bd966e..4f9ac0a7f 100644
--- a/vendor/github.com/urfave/cli/v2/flag_generic.go
+++ b/vendor/github.com/urfave/cli/v2/flag_generic.go
@@ -11,6 +11,19 @@ type Generic interface {
 	String() string
 }
 
+type stringGeneric struct {
+	value string
+}
+
+func (s *stringGeneric) Set(value string) error {
+	s.value = value
+	return nil
+}
+
+func (s *stringGeneric) String() string {
+	return s.value
+}
+
 // TakesValue returns true of the flag takes a value, otherwise false
 func (f *GenericFlag) TakesValue() bool {
 	return true
@@ -40,7 +53,10 @@ func (f *GenericFlag) GetDefaultText() string {
 	if f.DefaultText != "" {
 		return f.DefaultText
 	}
-	return f.GetValue()
+	if f.defaultValue != nil {
+		return f.defaultValue.String()
+	}
+	return ""
 }
 
 // GetEnvVars returns the env vars for this flag
@@ -51,6 +67,11 @@ func (f *GenericFlag) GetEnvVars() []string {
 // Apply takes the flagset and calls Set on the generic flag with the value
 // provided by the user for parsing by the flag
 func (f *GenericFlag) Apply(set *flag.FlagSet) error {
+	// set default value so that environment wont be able to overwrite it
+	if f.Value != nil {
+		f.defaultValue = &stringGeneric{value: f.Value.String()}
+	}
+
 	if val, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found {
 		if val != "" {
 			if err := f.Value.Set(val); err != nil {
diff --git a/vendor/github.com/urfave/cli/v2/flag_int.go b/vendor/github.com/urfave/cli/v2/flag_int.go
index af98e936f..d681270a2 100644
--- a/vendor/github.com/urfave/cli/v2/flag_int.go
+++ b/vendor/github.com/urfave/cli/v2/flag_int.go
@@ -32,7 +32,7 @@ func (f *IntFlag) GetDefaultText() string {
 	if f.DefaultText != "" {
 		return f.DefaultText
 	}
-	return f.GetValue()
+	return fmt.Sprintf("%d", f.defaultValue)
 }
 
 // GetEnvVars returns the env vars for this flag
@@ -42,6 +42,9 @@ func (f *IntFlag) GetEnvVars() []string {
 
 // Apply populates the flag given the flag set and environment
 func (f *IntFlag) Apply(set *flag.FlagSet) error {
+	// set default value so that environment wont be able to overwrite it
+	f.defaultValue = f.Value
+
 	if val, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found {
 		if val != "" {
 			valInt, err := strconv.ParseInt(val, f.Base, 64)
diff --git a/vendor/github.com/urfave/cli/v2/flag_int64.go b/vendor/github.com/urfave/cli/v2/flag_int64.go
index ebe46d21f..6f8c8d27d 100644
--- a/vendor/github.com/urfave/cli/v2/flag_int64.go
+++ b/vendor/github.com/urfave/cli/v2/flag_int64.go
@@ -32,7 +32,7 @@ func (f *Int64Flag) GetDefaultText() string {
 	if f.DefaultText != "" {
 		return f.DefaultText
 	}
-	return f.GetValue()
+	return fmt.Sprintf("%d", f.defaultValue)
 }
 
 // GetEnvVars returns the env vars for this flag
@@ -42,6 +42,9 @@ func (f *Int64Flag) GetEnvVars() []string {
 
 // Apply populates the flag given the flag set and environment
 func (f *Int64Flag) Apply(set *flag.FlagSet) error {
+	// set default value so that environment wont be able to overwrite it
+	f.defaultValue = f.Value
+
 	if val, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found {
 		if val != "" {
 			valInt, err := strconv.ParseInt(val, f.Base, 64)
diff --git a/vendor/github.com/urfave/cli/v2/flag_path.go b/vendor/github.com/urfave/cli/v2/flag_path.go
index 911819db9..6434d3224 100644
--- a/vendor/github.com/urfave/cli/v2/flag_path.go
+++ b/vendor/github.com/urfave/cli/v2/flag_path.go
@@ -33,10 +33,10 @@ func (f *PathFlag) GetDefaultText() string {
 	if f.DefaultText != "" {
 		return f.DefaultText
 	}
-	if f.Value == "" {
-		return f.Value
+	if f.defaultValue == "" {
+		return f.defaultValue
 	}
-	return fmt.Sprintf("%q", f.Value)
+	return fmt.Sprintf("%q", f.defaultValue)
 }
 
 // GetEnvVars returns the env vars for this flag
@@ -46,6 +46,9 @@ func (f *PathFlag) GetEnvVars() []string {
 
 // Apply populates the flag given the flag set and environment
 func (f *PathFlag) Apply(set *flag.FlagSet) error {
+	// set default value so that environment wont be able to overwrite it
+	f.defaultValue = f.Value
+
 	if val, _, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found {
 		f.Value = val
 		f.HasBeenSet = true
diff --git a/vendor/github.com/urfave/cli/v2/flag_string.go b/vendor/github.com/urfave/cli/v2/flag_string.go
index b7163ba6f..3050086e8 100644
--- a/vendor/github.com/urfave/cli/v2/flag_string.go
+++ b/vendor/github.com/urfave/cli/v2/flag_string.go
@@ -31,10 +31,10 @@ func (f *StringFlag) GetDefaultText() string {
 	if f.DefaultText != "" {
 		return f.DefaultText
 	}
-	if f.Value == "" {
-		return f.Value
+	if f.defaultValue == "" {
+		return f.defaultValue
 	}
-	return fmt.Sprintf("%q", f.Value)
+	return fmt.Sprintf("%q", f.defaultValue)
 }
 
 // GetEnvVars returns the env vars for this flag
@@ -44,6 +44,9 @@ func (f *StringFlag) GetEnvVars() []string {
 
 // Apply populates the flag given the flag set and environment
 func (f *StringFlag) Apply(set *flag.FlagSet) error {
+	// set default value so that environment wont be able to overwrite it
+	f.defaultValue = f.Value
+
 	if val, _, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found {
 		f.Value = val
 		f.HasBeenSet = true
diff --git a/vendor/github.com/urfave/cli/v2/flag_timestamp.go b/vendor/github.com/urfave/cli/v2/flag_timestamp.go
index 17bc8d757..fa0671fe4 100644
--- a/vendor/github.com/urfave/cli/v2/flag_timestamp.go
+++ b/vendor/github.com/urfave/cli/v2/flag_timestamp.go
@@ -72,6 +72,25 @@ func (t *Timestamp) Get() interface{} {
 	return *t
 }
 
+// clone timestamp
+func (t *Timestamp) clone() *Timestamp {
+	tc := &Timestamp{
+		timestamp:  nil,
+		hasBeenSet: t.hasBeenSet,
+		layout:     t.layout,
+		location:   nil,
+	}
+	if t.timestamp != nil {
+		tts := *t.timestamp
+		tc.timestamp = &tts
+	}
+	if t.location != nil {
+		loc := *t.location
+		tc.location = &loc
+	}
+	return tc
+}
+
 // TakesValue returns true of the flag takes a value, otherwise false
 func (f *TimestampFlag) TakesValue() bool {
 	return true
@@ -101,7 +120,11 @@ func (f *TimestampFlag) GetDefaultText() string {
 	if f.DefaultText != "" {
 		return f.DefaultText
 	}
-	return f.GetValue()
+	if f.defaultValue != nil && f.defaultValue.timestamp != nil {
+		return f.defaultValue.timestamp.String()
+	}
+
+	return ""
 }
 
 // GetEnvVars returns the env vars for this flag
@@ -120,6 +143,8 @@ func (f *TimestampFlag) Apply(set *flag.FlagSet) error {
 	f.Value.SetLayout(f.Layout)
 	f.Value.SetLocation(f.Timezone)
 
+	f.defaultValue = f.Value.clone()
+
 	if f.Destination != nil {
 		f.Destination.SetLayout(f.Layout)
 		f.Destination.SetLocation(f.Timezone)
diff --git a/vendor/github.com/urfave/cli/v2/flag_uint.go b/vendor/github.com/urfave/cli/v2/flag_uint.go
index f9acb6d06..d11aa0a89 100644
--- a/vendor/github.com/urfave/cli/v2/flag_uint.go
+++ b/vendor/github.com/urfave/cli/v2/flag_uint.go
@@ -23,6 +23,9 @@ func (f *UintFlag) GetCategory() string {
 
 // Apply populates the flag given the flag set and environment
 func (f *UintFlag) Apply(set *flag.FlagSet) error {
+	// set default value so that environment wont be able to overwrite it
+	f.defaultValue = f.Value
+
 	if val, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found {
 		if val != "" {
 			valInt, err := strconv.ParseUint(val, f.Base, 64)
@@ -66,7 +69,7 @@ func (f *UintFlag) GetDefaultText() string {
 	if f.DefaultText != "" {
 		return f.DefaultText
 	}
-	return f.GetValue()
+	return fmt.Sprintf("%d", f.defaultValue)
 }
 
 // GetEnvVars returns the env vars for this flag
diff --git a/vendor/github.com/urfave/cli/v2/flag_uint64.go b/vendor/github.com/urfave/cli/v2/flag_uint64.go
index 09590d735..ea73100a9 100644
--- a/vendor/github.com/urfave/cli/v2/flag_uint64.go
+++ b/vendor/github.com/urfave/cli/v2/flag_uint64.go
@@ -23,6 +23,9 @@ func (f *Uint64Flag) GetCategory() string {
 
 // Apply populates the flag given the flag set and environment
 func (f *Uint64Flag) Apply(set *flag.FlagSet) error {
+	// set default value so that environment wont be able to overwrite it
+	f.defaultValue = f.Value
+
 	if val, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found {
 		if val != "" {
 			valInt, err := strconv.ParseUint(val, f.Base, 64)
@@ -66,7 +69,7 @@ func (f *Uint64Flag) GetDefaultText() string {
 	if f.DefaultText != "" {
 		return f.DefaultText
 	}
-	return f.GetValue()
+	return fmt.Sprintf("%d", f.defaultValue)
 }
 
 // GetEnvVars returns the env vars for this flag
diff --git a/vendor/github.com/urfave/cli/v2/godoc-current.txt b/vendor/github.com/urfave/cli/v2/godoc-current.txt
index b6e3d4300..80344eced 100644
--- a/vendor/github.com/urfave/cli/v2/godoc-current.txt
+++ b/vendor/github.com/urfave/cli/v2/godoc-current.txt
@@ -136,7 +136,7 @@ var SubcommandHelpTemplate = `NAME:
    {{template "helpNameTemplate" .}}
 
 USAGE:
-   {{if .UsageText}}{{wrap .UsageText 3}}{{else}}{{.HelpName}} command{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Description}}
+   {{if .UsageText}}{{wrap .UsageText 3}}{{else}}{{.HelpName}} {{if .VisibleFlags}}command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Description}}
 
 DESCRIPTION:
    {{template "descriptionTemplate" .}}{{end}}{{if .VisibleCommands}}
@@ -348,8 +348,9 @@ func (a *App) RunAndExitOnError()
     code in the cli.ExitCoder
 
 func (a *App) RunAsSubcommand(ctx *Context) (err error)
-    RunAsSubcommand invokes the subcommand given the context, parses ctx.Args()
-    to generate command-specific flags
+    This is a stub function to keep public API unchanged from old code
+
+    Deprecated: use App.Run or App.RunContext
 
 func (a *App) RunContext(ctx context.Context, arguments []string) (err error)
     RunContext is like Run except it takes a Context that will be passed to
@@ -446,6 +447,7 @@ type BoolFlag struct {
 	Count *int
 
 	Action func(*Context, bool) error
+	// Has unexported fields.
 }
     BoolFlag is a flag with type bool
 
@@ -553,10 +555,13 @@ type Command struct {
 	// cli.go uses text/template to render templates. You can
 	// render custom help text by setting this variable.
 	CustomHelpTemplate string
+
 	// Has unexported fields.
 }
     Command is a subcommand for a cli.App.
 
+func (cmd *Command) Command(name string) *Command
+
 func (c *Command) FullName() string
     FullName returns the full name of the command. For subcommands this ensures
     that parent commands are part of the command path
@@ -567,9 +572,11 @@ func (c *Command) HasName(name string) bool
 func (c *Command) Names() []string
     Names returns the names including short names and aliases.
 
-func (c *Command) Run(ctx *Context) (err error)
-    Run invokes the command given the context, parses ctx.Args() to generate
-    command-specific flags
+func (c *Command) Run(cCtx *Context, arguments ...string) (err error)
+
+func (c *Command) VisibleCategories() []CommandCategory
+    VisibleCategories returns a slice of categories and commands that are
+    Hidden=false
 
 func (c *Command) VisibleCommands() []*Command
     VisibleCommands returns a slice of the Commands with Hidden=false
@@ -769,6 +776,7 @@ type DurationFlag struct {
 	EnvVars []string
 
 	Action func(*Context, time.Duration) error
+	// Has unexported fields.
 }
     DurationFlag is a flag with type time.Duration
 
@@ -947,6 +955,7 @@ type Float64Flag struct {
 	EnvVars []string
 
 	Action func(*Context, float64) error
+	// Has unexported fields.
 }
     Float64Flag is a flag with type float64
 
@@ -1035,6 +1044,7 @@ type Float64SliceFlag struct {
 	EnvVars []string
 
 	Action func(*Context, []float64) error
+	// Has unexported fields.
 }
     Float64SliceFlag is a flag with type *Float64Slice
 
@@ -1117,6 +1127,7 @@ type GenericFlag struct {
 	TakesFile bool
 
 	Action func(*Context, interface{}) error
+	// Has unexported fields.
 }
     GenericFlag is a flag with type Generic
 
@@ -1185,6 +1196,7 @@ type Int64Flag struct {
 	Base int
 
 	Action func(*Context, int64) error
+	// Has unexported fields.
 }
     Int64Flag is a flag with type int64
 
@@ -1273,6 +1285,7 @@ type Int64SliceFlag struct {
 	EnvVars []string
 
 	Action func(*Context, []int64) error
+	// Has unexported fields.
 }
     Int64SliceFlag is a flag with type *Int64Slice
 
@@ -1349,6 +1362,7 @@ type IntFlag struct {
 	Base int
 
 	Action func(*Context, int) error
+	// Has unexported fields.
 }
     IntFlag is a flag with type int
 
@@ -1441,6 +1455,7 @@ type IntSliceFlag struct {
 	EnvVars []string
 
 	Action func(*Context, []int) error
+	// Has unexported fields.
 }
     IntSliceFlag is a flag with type *IntSlice
 
@@ -1551,6 +1566,7 @@ type PathFlag struct {
 	TakesFile bool
 
 	Action func(*Context, Path) error
+	// Has unexported fields.
 }
     PathFlag is a flag with type Path
 
@@ -1693,6 +1709,7 @@ type StringFlag struct {
 	TakesFile bool
 
 	Action func(*Context, string) error
+	// Has unexported fields.
 }
     StringFlag is a flag with type string
 
@@ -1783,6 +1800,7 @@ type StringSliceFlag struct {
 	TakesFile bool
 
 	Action func(*Context, []string) error
+	// Has unexported fields.
 }
     StringSliceFlag is a flag with type *StringSlice
 
@@ -1894,6 +1912,7 @@ type TimestampFlag struct {
 	Timezone *time.Location
 
 	Action func(*Context, *time.Time) error
+	// Has unexported fields.
 }
     TimestampFlag is a flag with type *Timestamp
 
@@ -1961,6 +1980,7 @@ type Uint64Flag struct {
 	Base int
 
 	Action func(*Context, uint64) error
+	// Has unexported fields.
 }
     Uint64Flag is a flag with type uint64
 
@@ -2049,6 +2069,7 @@ type Uint64SliceFlag struct {
 	EnvVars []string
 
 	Action func(*Context, []uint64) error
+	// Has unexported fields.
 }
     Uint64SliceFlag is a flag with type *Uint64Slice
 
@@ -2116,6 +2137,7 @@ type UintFlag struct {
 	Base int
 
 	Action func(*Context, uint) error
+	// Has unexported fields.
 }
     UintFlag is a flag with type uint
 
@@ -2208,6 +2230,7 @@ type UintSliceFlag struct {
 	EnvVars []string
 
 	Action func(*Context, []uint) error
+	// Has unexported fields.
 }
     UintSliceFlag is a flag with type *UintSlice
 
diff --git a/vendor/github.com/urfave/cli/v2/help.go b/vendor/github.com/urfave/cli/v2/help.go
index 293016562..466ff3479 100644
--- a/vendor/github.com/urfave/cli/v2/help.go
+++ b/vendor/github.com/urfave/cli/v2/help.go
@@ -68,6 +68,15 @@ var helpCommand = &Command{
 		}
 
 		// Case 3, 5
+		if (len(cCtx.Command.Subcommands) == 1 && !cCtx.Command.HideHelp) ||
+			(len(cCtx.Command.Subcommands) == 0 && cCtx.Command.HideHelp) {
+			templ := cCtx.Command.CustomHelpTemplate
+			if templ == "" {
+				templ = CommandHelpTemplate
+			}
+			HelpPrinter(cCtx.App.Writer, templ, cCtx.Command)
+			return nil
+		}
 		return ShowSubcommandHelp(cCtx)
 	},
 }
@@ -230,13 +239,12 @@ func ShowCommandHelpAndExit(c *Context, command string, code int) {
 
 // ShowCommandHelp prints help for the given command
 func ShowCommandHelp(ctx *Context, command string) error {
-	// show the subcommand help for a command with subcommands
-	if command == "" {
-		HelpPrinter(ctx.App.Writer, SubcommandHelpTemplate, ctx.App)
-		return nil
-	}
 
-	for _, c := range ctx.App.Commands {
+	commands := ctx.App.Commands
+	if ctx.Command.Subcommands != nil {
+		commands = ctx.Command.Subcommands
+	}
+	for _, c := range commands {
 		if c.HasName(command) {
 			if !ctx.App.HideHelpCommand && !c.HasName(helpName) && len(c.Subcommands) != 0 {
 				c.Subcommands = append(c.Subcommands, helpCommandDontUse)
@@ -262,7 +270,7 @@ func ShowCommandHelp(ctx *Context, command string) error {
 	if ctx.App.CommandNotFound == nil {
 		errMsg := fmt.Sprintf("No help topic for '%v'", command)
 		if ctx.App.Suggest {
-			if suggestion := SuggestCommand(ctx.App.Commands, command); suggestion != "" {
+			if suggestion := SuggestCommand(ctx.Command.Subcommands, command); suggestion != "" {
 				errMsg += ". " + suggestion
 			}
 		}
@@ -285,11 +293,8 @@ func ShowSubcommandHelp(cCtx *Context) error {
 		return nil
 	}
 
-	if cCtx.Command != nil {
-		return ShowCommandHelp(cCtx, cCtx.Command.Name)
-	}
-
-	return ShowCommandHelp(cCtx, "")
+	HelpPrinter(cCtx.App.Writer, SubcommandHelpTemplate, cCtx.Command)
+	return nil
 }
 
 // ShowVersion prints the version number of the App
@@ -401,8 +406,10 @@ func checkHelp(cCtx *Context) bool {
 	for _, name := range HelpFlag.Names() {
 		if cCtx.Bool(name) {
 			found = true
+			break
 		}
 	}
+
 	return found
 }
 
diff --git a/vendor/github.com/urfave/cli/v2/template.go b/vendor/github.com/urfave/cli/v2/template.go
index 5c2a62e89..b565ba61e 100644
--- a/vendor/github.com/urfave/cli/v2/template.go
+++ b/vendor/github.com/urfave/cli/v2/template.go
@@ -83,7 +83,7 @@ var SubcommandHelpTemplate = `NAME:
    {{template "helpNameTemplate" .}}
 
 USAGE:
-   {{if .UsageText}}{{wrap .UsageText 3}}{{else}}{{.HelpName}} command{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Description}}
+   {{if .UsageText}}{{wrap .UsageText 3}}{{else}}{{.HelpName}} {{if .VisibleFlags}}command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Description}}
 
 DESCRIPTION:
    {{template "descriptionTemplate" .}}{{end}}{{if .VisibleCommands}}
diff --git a/vendor/github.com/urfave/cli/v2/zz_generated.flags.go b/vendor/github.com/urfave/cli/v2/zz_generated.flags.go
index 0309a2868..7d0a267f7 100644
--- a/vendor/github.com/urfave/cli/v2/zz_generated.flags.go
+++ b/vendor/github.com/urfave/cli/v2/zz_generated.flags.go
@@ -23,6 +23,8 @@ type Float64SliceFlag struct {
 	Aliases []string
 	EnvVars []string
 
+	defaultValue *Float64Slice
+
 	Action func(*Context, []float64) error
 }
 
@@ -65,6 +67,8 @@ type GenericFlag struct {
 	Aliases []string
 	EnvVars []string
 
+	defaultValue Generic
+
 	TakesFile bool
 
 	Action func(*Context, interface{}) error
@@ -114,6 +118,8 @@ type Int64SliceFlag struct {
 	Aliases []string
 	EnvVars []string
 
+	defaultValue *Int64Slice
+
 	Action func(*Context, []int64) error
 }
 
@@ -156,6 +162,8 @@ type IntSliceFlag struct {
 	Aliases []string
 	EnvVars []string
 
+	defaultValue *IntSlice
+
 	Action func(*Context, []int) error
 }
 
@@ -198,6 +206,8 @@ type PathFlag struct {
 	Aliases []string
 	EnvVars []string
 
+	defaultValue Path
+
 	TakesFile bool
 
 	Action func(*Context, Path) error
@@ -247,6 +257,8 @@ type StringSliceFlag struct {
 	Aliases []string
 	EnvVars []string
 
+	defaultValue *StringSlice
+
 	TakesFile bool
 
 	Action func(*Context, []string) error
@@ -291,6 +303,8 @@ type TimestampFlag struct {
 	Aliases []string
 	EnvVars []string
 
+	defaultValue *Timestamp
+
 	Layout string
 
 	Timezone *time.Location
@@ -342,6 +356,8 @@ type Uint64SliceFlag struct {
 	Aliases []string
 	EnvVars []string
 
+	defaultValue *Uint64Slice
+
 	Action func(*Context, []uint64) error
 }
 
@@ -384,6 +400,8 @@ type UintSliceFlag struct {
 	Aliases []string
 	EnvVars []string
 
+	defaultValue *UintSlice
+
 	Action func(*Context, []uint) error
 }
 
@@ -426,6 +444,8 @@ type BoolFlag struct {
 	Aliases []string
 	EnvVars []string
 
+	defaultValue bool
+
 	Count *int
 
 	Action func(*Context, bool) error
@@ -475,6 +495,8 @@ type Float64Flag struct {
 	Aliases []string
 	EnvVars []string
 
+	defaultValue float64
+
 	Action func(*Context, float64) error
 }
 
@@ -522,6 +544,8 @@ type IntFlag struct {
 	Aliases []string
 	EnvVars []string
 
+	defaultValue int
+
 	Base int
 
 	Action func(*Context, int) error
@@ -571,6 +595,8 @@ type Int64Flag struct {
 	Aliases []string
 	EnvVars []string
 
+	defaultValue int64
+
 	Base int
 
 	Action func(*Context, int64) error
@@ -620,6 +646,8 @@ type StringFlag struct {
 	Aliases []string
 	EnvVars []string
 
+	defaultValue string
+
 	TakesFile bool
 
 	Action func(*Context, string) error
@@ -669,6 +697,8 @@ type DurationFlag struct {
 	Aliases []string
 	EnvVars []string
 
+	defaultValue time.Duration
+
 	Action func(*Context, time.Duration) error
 }
 
@@ -716,6 +746,8 @@ type UintFlag struct {
 	Aliases []string
 	EnvVars []string
 
+	defaultValue uint
+
 	Base int
 
 	Action func(*Context, uint) error
@@ -765,6 +797,8 @@ type Uint64Flag struct {
 	Aliases []string
 	EnvVars []string
 
+	defaultValue uint64
+
 	Base int
 
 	Action func(*Context, uint64) error
diff --git a/vendor/modules.txt b/vendor/modules.txt
index bdb981d8c..9e0c4a307 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -566,7 +566,7 @@ github.com/spf13/pflag
 github.com/stretchr/testify/assert
 github.com/stretchr/testify/require
 github.com/stretchr/testify/suite
-# github.com/urfave/cli/v2 v2.19.2
+# github.com/urfave/cli/v2 v2.20.2
 ## explicit; go 1.18
 github.com/urfave/cli/v2
 # github.com/vbatts/tar-split v0.11.2


Test patch:
diff --git a/hack/ci/e2e-olm.sh b/hack/ci/e2e-olm.sh
index 4dcb02c25..f60d6b832 100755
--- a/hack/ci/e2e-olm.sh
+++ b/hack/ci/e2e-olm.sh
@@ -31,10 +31,8 @@ function build_and_push_packages() {
     OPERATOR_MANIFEST=deploy/operator-ci.yaml
 
     # Create a manifest with local image
-    pushd deploy/base
-    kustomize edit set image security-profiles-operator=$IMG
-    popd
-    kustomize build --reorder=none deploy/overlays/cluster -o ${OPERATOR_MANIFEST}
+    cp deploy/operator.yaml ${OPERATOR_MANIFEST}
+    sed -i "s#k8s.gcr.io/security-profiles-operator/security-profiles-operator.*\$#${IMG}#" ${OPERATOR_MANIFEST}
 
     # this is a kludge, we need to make sure kustomize can be overwritten
     rm -f build/kustomize
@@ -62,7 +60,7 @@ function deploy_spo() {
     kubectl -ncert-manager wait --for condition=ready pod -l app.kubernetes.io/instance=cert-manager
 
     # let's roll..
-    sed -i "s#gcr.io/k8s-staging-sp-operator/security-profiles-operator-catalog:latest#${CATALOG_IMG}#g" examples/olm/install-resources.yaml
+    sed -i "s#k8s.gcr.io/security-profiles-operator/security-profiles-operator-catalog:v0.5.0#${CATALOG_IMG}#g" examples/olm/install-resources.yaml
     kubectl create -f examples/olm/install-resources.yaml
 }