diff --git a/.github/workflows/checkton.yaml b/.github/workflows/checkton.yaml
index d1d30ea46a..3a1ec1421c 100644
--- a/.github/workflows/checkton.yaml
+++ b/.github/workflows/checkton.yaml
@@ -21,6 +21,7 @@ jobs:
# Set to false when re-enabling SARIF uploads
fail-on-findings: true
find-copies-harder: true
+ exclude-regex: ^ta-generator
# Currently, code scanning alerts annoyingly stay open even if you fix them.
# Don't upload SARIF until https://github.com/orgs/community/discussions/132787 is resolved.
diff --git a/.github/workflows/go-ci.yaml b/.github/workflows/go-ci.yaml
index 8dfbd553aa..7c15c3ff77 100644
--- a/.github/workflows/go-ci.yaml
+++ b/.github/workflows/go-ci.yaml
@@ -6,27 +6,39 @@ jobs:
lint:
name: Lint
runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ path:
+ - task-generator
+ - ta-generator
steps:
- uses: actions/checkout@9a9194f87191a7e9055e3e9b95b8cfb13023bb08
- uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32
with:
- go-version-file: './task-generator/go.mod'
+ go-version-file: './${{matrix.path}}/go.mod'
+ cache-dependency-path: './${{matrix.path}}/go.sum'
- name: golangci-lint
uses: golangci/golangci-lint-action@e13590484647602042886c51e2a8e43a670a22b7
with:
- working-directory: task-generator
+ working-directory: ${{matrix.path}}
args: "--timeout=10m --build-tags='normal periodic'"
go:
name: Check sources
runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ path:
+ - task-generator
+ - ta-generator
steps:
- uses: actions/checkout@9a9194f87191a7e9055e3e9b95b8cfb13023bb08
- name: Install Go
uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32
with:
- go-version-file: './task-generator/go.mod'
+ go-version-file: './${{matrix.path}}/go.mod'
+ cache-dependency-path: './${{matrix.path}}/go.sum'
- name: Check go mod status
- working-directory: task-generator
+ working-directory: ${{matrix.path}}
run: |
go mod tidy
if [[ ! -z $(git status -s) ]]
@@ -36,7 +48,7 @@ jobs:
exit 1
fi
- name: Check format
- working-directory: task-generator
+ working-directory: ${{matrix.path}}
run: |
go fmt ./...
@@ -46,21 +58,31 @@ jobs:
git --no-pager diff
exit 1
fi
+ - name: Tests
+ working-directory: ${{matrix.path}}
+ run: |
+ go test ./...
security_scan:
name: Security scan
runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ path:
+ - task-generator
+ - ta-generator
steps:
- uses: actions/checkout@9a9194f87191a7e9055e3e9b95b8cfb13023bb08
- uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32
with:
- go-version-file: './task-generator/go.mod'
+ go-version-file: './${{matrix.path}}/go.mod'
+ cache-dependency-path: './${{matrix.path}}/go.sum'
# https://github.com/securego/gosec/blob/12be14859bc7d4b956b71bef0b443694aa519d8a/README.md#integrating-with-code-scanning
- name: Run Gosec Security Scanner
uses: securego/gosec@master
with:
# we let the report trigger content trigger a failure using the GitHub Security features.
- args: '-tags normal,periodic -no-fail -fmt sarif -out results.sarif ./...'
+ args: '-tags normal,periodic -no-fail -fmt sarif -out results.sarif ${{matrix.path}}/...'
- name: Upload SARIF file
uses: github/codeql-action/upload-sarif@9c646c24a4c8410122b0d6a1311088e9377eea95
with:
diff --git a/hack/generate-ta-tasks.sh b/hack/generate-ta-tasks.sh
index 40fc6d2ecf..e5d4c6a5ac 100755
--- a/hack/generate-ta-tasks.sh
+++ b/hack/generate-ta-tasks.sh
@@ -1,29 +1,23 @@
#!/usr/bin/env bash
set -o errexit
+set -o errtrace
set -o nounset
set -o pipefail
set -o posix
shopt -s globstar nullglob
+command -v go &> /dev/null || { echo Please install golang to run this tool; exit 1; }
+[[ "$(go env GOVERSION)" == @(go1|go1.[1-9]+(|.*|rc*|beta*)|go1.1[0-9]+(|.*|rc*|beta*)|go1.20*) ]] && { echo Please install golang 1.21.0 or newer; exit 1; }
+
HACK_DIR="$(realpath "$(dirname "${BASH_SOURCE[0]}")")"
ROOT_DIR="$(git rev-parse --show-toplevel)"
TASK_DIR="$(realpath "${ROOT_DIR}/task")"
-if ! command -v tash &> /dev/null; then
- echo INFO: tash command is not available will download and use the latest version
- tash_dir="$(mktemp -d)"
- trap 'rm -rf ${tash_dir}' EXIT
- tash_url=https://github.com/enterprise-contract/hacks/releases/download/latest/tash
- echo INFO: downloading from ${tash_url} to "${tash_dir}"
- curl --no-progress-meter --location --output "${tash_dir}/tash" "${tash_url}"
- echo INFO: SHA256: "$(sha256sum "${tash_dir}/tash")"
- chmod +x "${tash_dir}/tash"
- tash() {
- "${tash_dir}/tash" "$@"
- }
-fi
+tash() {
+ go run -C "${ROOT_DIR}/ta-generator/" github.com/konflux-ci/build-definitions/ta-generator "$@"
+}
declare -i changes=0
emit() {
@@ -44,7 +38,8 @@ fi
cd "${TASK_DIR}"
for recipe_path in **/recipe.yaml; do
task_path="${recipe_path%/recipe.yaml}/$(basename "${recipe_path%/*/*}").yaml"
- cat <<< "$(tash "${recipe_path}")" > "${task_path}"
+ sponge=$(tash "${TASK_DIR}/${recipe_path}")
+ echo "${sponge}" > "${task_path}"
readme_path="${recipe_path%/recipe.yaml}/README.md"
"${HACK_DIR}/generate-readme.sh" "${task_path}" > "${readme_path}"
if ! git diff --quiet HEAD "${task_path}"; then
diff --git a/ta-generator/README.md b/ta-generator/README.md
new file mode 100644
index 0000000000..bd39ab7c22
--- /dev/null
+++ b/ta-generator/README.md
@@ -0,0 +1,17 @@
+# Trusted Artifacts variants generator
+
+## Description and usage
+
+The code in here will process a set of directions in `recipe.yaml` file and
+based on that and a set of builtin conventions generate the Tekton Task
+definition in YAML format.
+
+Usage (from this directory):
+
+ go run . path/to/recipe.yaml
+
+The generated Trusted Artifacts Task is provided on the standard output.
+
+## Development
+
+To build the tool executable run `go build`, to run the tests run `go test`.
diff --git a/ta-generator/expect.go b/ta-generator/expect.go
new file mode 100644
index 0000000000..114caaacd5
--- /dev/null
+++ b/ta-generator/expect.go
@@ -0,0 +1,22 @@
+package main
+
+import (
+ "fmt"
+ "os"
+)
+
+func expect(err error) {
+ if err == nil {
+ return
+ }
+ fmt.Fprint(os.Stderr, err)
+ os.Exit(1)
+}
+
+func expectValue[T any](val T, err error) T {
+ if err != nil {
+ expect(err)
+ }
+
+ return val
+}
diff --git a/ta-generator/go.mod b/ta-generator/go.mod
new file mode 100644
index 0000000000..8b70d3967c
--- /dev/null
+++ b/ta-generator/go.mod
@@ -0,0 +1,91 @@
+module github.com/konflux-ci/build-definitions/ta-generator
+
+go 1.22.3
+
+require (
+ github.com/google/go-cmp v0.6.0
+ github.com/google/go-containerregistry v0.19.1
+ github.com/tektoncd/pipeline v0.60.1
+ github.com/zregvart/tkn-fmt v0.0.0-20240613172239-ba04662da674
+ k8s.io/api v0.30.1
+ mvdan.cc/sh/v3 v3.8.0
+ sigs.k8s.io/yaml v1.4.0
+)
+
+require (
+ contrib.go.opencensus.io/exporter/ocagent v0.7.1-0.20200907061046-05415f1de66d // indirect
+ contrib.go.opencensus.io/exporter/prometheus v0.4.2 // indirect
+ github.com/antlr4-go/antlr/v4 v4.13.1 // indirect
+ github.com/beorn7/perks v1.0.1 // indirect
+ github.com/blendle/zapdriver v1.3.1 // indirect
+ github.com/braydonk/yaml v0.7.0 // indirect
+ github.com/census-instrumentation/opencensus-proto v0.4.1 // indirect
+ github.com/cespare/xxhash/v2 v2.3.0 // indirect
+ github.com/containerd/stargz-snapshotter/estargz v0.14.3 // indirect
+ github.com/davecgh/go-spew v1.1.1 // indirect
+ github.com/docker/cli v24.0.7+incompatible // indirect
+ github.com/docker/distribution v2.8.2+incompatible // indirect
+ github.com/docker/docker v26.0.0+incompatible // indirect
+ github.com/docker/docker-credential-helpers v0.7.0 // indirect
+ github.com/emicklei/go-restful/v3 v3.12.1 // indirect
+ github.com/evanphx/json-patch/v5 v5.9.0 // indirect
+ github.com/go-kit/log v0.2.1 // indirect
+ github.com/go-logfmt/logfmt v0.6.0 // indirect
+ github.com/go-logr/logr v1.4.2 // indirect
+ github.com/go-openapi/jsonpointer v0.21.0 // indirect
+ github.com/go-openapi/jsonreference v0.21.0 // indirect
+ github.com/go-openapi/swag v0.23.0 // indirect
+ github.com/gogo/protobuf v1.3.2 // indirect
+ github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
+ github.com/golang/protobuf v1.5.4 // indirect
+ github.com/google/cel-go v0.20.1 // indirect
+ github.com/google/gnostic-models v0.6.8 // indirect
+ github.com/google/gofuzz v1.2.0 // indirect
+ github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect
+ github.com/josharian/intern v1.0.0 // indirect
+ github.com/json-iterator/go v1.1.12 // indirect
+ github.com/klauspost/compress v1.16.6 // indirect
+ github.com/mailru/easyjson v0.7.7 // indirect
+ github.com/mitchellh/go-homedir v1.1.0 // indirect
+ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
+ github.com/modern-go/reflect2 v1.0.2 // indirect
+ github.com/opencontainers/go-digest v1.0.0 // indirect
+ github.com/opencontainers/image-spec v1.1.0 // indirect
+ github.com/pkg/errors v0.9.1 // indirect
+ github.com/prometheus/client_golang v1.19.1 // indirect
+ github.com/prometheus/client_model v0.6.1 // indirect
+ github.com/prometheus/common v0.54.0 // indirect
+ github.com/prometheus/procfs v0.15.1 // indirect
+ github.com/prometheus/statsd_exporter v0.26.1 // indirect
+ github.com/sirupsen/logrus v1.9.3 // indirect
+ github.com/stoewer/go-strcase v1.3.0 // indirect
+ github.com/vbatts/tar-split v0.11.3 // indirect
+ go.opencensus.io v0.24.0 // indirect
+ go.uber.org/multierr v1.11.0 // indirect
+ go.uber.org/zap v1.27.0 // indirect
+ golang.org/x/exp v0.0.0-20240604190554-fc45aab8b7f8 // indirect
+ golang.org/x/net v0.26.0 // indirect
+ golang.org/x/oauth2 v0.21.0 // indirect
+ golang.org/x/sync v0.7.0 // indirect
+ golang.org/x/sys v0.21.0 // indirect
+ golang.org/x/term v0.21.0 // indirect
+ golang.org/x/text v0.16.0 // indirect
+ golang.org/x/time v0.5.0 // indirect
+ gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
+ google.golang.org/api v0.183.0 // indirect
+ google.golang.org/genproto/googleapis/api v0.0.0-20240604185151-ef581f913117 // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 // indirect
+ google.golang.org/grpc v1.64.0 // indirect
+ google.golang.org/protobuf v1.34.1 // indirect
+ gopkg.in/inf.v0 v0.9.1 // indirect
+ gopkg.in/yaml.v2 v2.4.0 // indirect
+ gopkg.in/yaml.v3 v3.0.1 // indirect
+ k8s.io/apimachinery v0.30.1 // indirect
+ k8s.io/client-go v0.30.1 // indirect
+ k8s.io/klog/v2 v2.120.1 // indirect
+ k8s.io/kube-openapi v0.0.0-20240521193020-835d969ad83a // indirect
+ k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0 // indirect
+ knative.dev/pkg v0.0.0-20240604134003-58135c2c0694 // indirect
+ sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
+ sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
+)
diff --git a/ta-generator/go.sum b/ta-generator/go.sum
new file mode 100644
index 0000000000..095fac6cab
--- /dev/null
+++ b/ta-generator/go.sum
@@ -0,0 +1,722 @@
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
+cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
+cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
+cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
+cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
+cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
+cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
+cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
+cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
+cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
+cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
+cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
+cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
+cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
+cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
+cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
+cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
+cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
+cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
+cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
+cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
+cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
+cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
+cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
+cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
+cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
+cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
+cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
+cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
+cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
+contrib.go.opencensus.io/exporter/ocagent v0.7.1-0.20200907061046-05415f1de66d h1:LblfooH1lKOpp1hIhukktmSAxFkqMPFk9KR6iZ0MJNI=
+contrib.go.opencensus.io/exporter/ocagent v0.7.1-0.20200907061046-05415f1de66d/go.mod h1:IshRmMJBhDfFj5Y67nVhMYTTIze91RUeT73ipWKs/GY=
+contrib.go.opencensus.io/exporter/prometheus v0.4.2 h1:sqfsYl5GIY/L570iT+l93ehxaWJs2/OwXtiWwew3oAg=
+contrib.go.opencensus.io/exporter/prometheus v0.4.2/go.mod h1:dvEHbiKmgvbr5pjaF9fpw1KeYcjrnC1J8B+JKjsZyRQ=
+dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
+github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
+github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
+github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
+github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
+github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ=
+github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw=
+github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
+github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
+github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
+github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
+github.com/blendle/zapdriver v1.3.1 h1:C3dydBOWYRiOk+B8X9IVZ5IOe+7cl+tGOexN4QqHfpE=
+github.com/blendle/zapdriver v1.3.1/go.mod h1:mdXfREi6u5MArG4j9fewC+FGnXaBR+T4Ox4J2u4eHCc=
+github.com/braydonk/yaml v0.7.0 h1:ySkqO7r0MGoCNhiRJqE0Xe9yhINMyvOAB3nFjgyJn2k=
+github.com/braydonk/yaml v0.7.0/go.mod h1:hcm3h581tudlirk8XEUPDBAimBPbmnL0Y45hCRl47N4=
+github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/census-instrumentation/opencensus-proto v0.4.1 h1:iKLQ0xPNFxR/2hzXZMrBo8f1j86j5WHzznCCQxV/b8g=
+github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw=
+github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
+github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
+github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
+github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/cloudevents/sdk-go/v2 v2.15.2 h1:54+I5xQEnI73RBhWHxbI1XJcqOFOVJN85vb41+8mHUc=
+github.com/cloudevents/sdk-go/v2 v2.15.2/go.mod h1:lL7kSWAE/V8VI4Wh0jbL2v/jvqsm6tjmaQBSvxcv4uE=
+github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
+github.com/containerd/stargz-snapshotter/estargz v0.14.3 h1:OqlDCK3ZVUO6C3B/5FSkDwbkEETK84kQgEeFwDC+62k=
+github.com/containerd/stargz-snapshotter/estargz v0.14.3/go.mod h1:KY//uOCIkSuNAHhJogcZtrNHdKrA99/FCCRjE3HD36o=
+github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/docker/cli v24.0.7+incompatible h1:wa/nIwYFW7BVTGa7SWPVyyXU9lgORqUb1xfI36MSkFg=
+github.com/docker/cli v24.0.7+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
+github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8=
+github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
+github.com/docker/docker v26.0.0+incompatible h1:Ng2qi+gdKADUa/VM+6b6YaY2nlZhk/lVJiKR/2bMudU=
+github.com/docker/docker v26.0.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
+github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A=
+github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0=
+github.com/emicklei/go-restful/v3 v3.12.1 h1:PJMDIM/ak7btuL8Ex0iYET9hxM3CI2sjZtzpL63nKAU=
+github.com/emicklei/go-restful/v3 v3.12.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
+github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
+github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84=
+github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
+github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg=
+github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ=
+github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
+github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
+github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
+github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
+github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
+github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU=
+github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
+github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
+github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
+github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
+github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
+github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
+github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
+github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
+github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
+github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
+github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
+github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
+github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
+github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
+github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
+github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
+github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
+github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
+github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
+github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
+github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
+github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
+github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
+github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
+github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
+github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
+github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
+github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
+github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
+github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
+github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/cel-go v0.20.1 h1:nDx9r8S3L4pE61eDdt8igGj8rf5kjYR3ILxWIpWNi84=
+github.com/google/cel-go v0.20.1/go.mod h1:kWcIzTsPX0zmQ+H3TirHstLLf9ep5QTsZBN9u4dOYLg=
+github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
+github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
+github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/go-containerregistry v0.19.1 h1:yMQ62Al6/V0Z7CqIrrS1iYoA5/oQCm88DeNujc7C1KY=
+github.com/google/go-containerregistry v0.19.1/go.mod h1:YCMFNQeeXeLF+dnhhWkqDItx/JSkH01j1Kis4PsjzFI=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
+github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
+github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
+github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 h1:k7nVchz72niMH6YLQNvHSdIE7iqsQxK1P41mySCvssg=
+github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
+github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
+github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
+github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
+github.com/grpc-ecosystem/grpc-gateway v1.14.6/go.mod h1:zdiPV4Yse/1gnckTHtghG4GkDEdKCRJduHpTxT3/jcw=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k=
+github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
+github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
+github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
+github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c=
+github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
+github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
+github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk=
+github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg=
+github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
+github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
+github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
+github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
+github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
+github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
+github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
+github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
+github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
+github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8=
+github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
+github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/klauspost/compress v1.16.6 h1:91SKEy4K37vkp255cJ8QesJhjyRO0hn9i9G0GoUwLsk=
+github.com/klauspost/compress v1.16.6/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
+github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
+github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
+github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
+github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
+github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
+github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
+github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
+github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/onsi/ginkgo/v2 v2.17.2 h1:7eMhcy3GimbsA3hEnVKdw/PQM9XN9krpKVXsZdph0/g=
+github.com/onsi/ginkgo/v2 v2.17.2/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc=
+github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk=
+github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0=
+github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
+github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
+github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
+github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
+github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
+github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
+github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
+github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
+github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
+github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ=
+github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
+github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
+github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
+github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
+github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
+github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
+github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
+github.com/prometheus/common v0.35.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA=
+github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA=
+github.com/prometheus/common v0.54.0 h1:ZlZy0BgJhTwVZUn7dLOkwCZHUkrAqd3WYtcFCWnM1D8=
+github.com/prometheus/common v0.54.0/go.mod h1:/TQgMJP5CuVYveyT7n/0Ix8yLNNXy9yRSkhnLTHPDIQ=
+github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
+github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
+github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
+github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4=
+github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
+github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
+github.com/prometheus/statsd_exporter v0.22.7/go.mod h1:N/TevpjkIh9ccs6nuzY3jQn9dFqnUakOjnEuMPJJJnI=
+github.com/prometheus/statsd_exporter v0.26.1 h1:ucbIAdPmwAUcA+dU+Opok8Qt81Aw8HanlO+2N/Wjv7w=
+github.com/prometheus/statsd_exporter v0.26.1/go.mod h1:XlDdjAmRmx3JVvPPYuFNUg+Ynyb5kR69iPPkQjxXFMk=
+github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
+github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
+github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
+github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
+github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
+github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
+github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
+github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
+github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
+github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs=
+github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
+github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/stvp/go-udp-testing v0.0.0-20201019212854-469649b16807/go.mod h1:7jxmlfBCDBXRzr0eAQJ48XC1hBu1np4CS5+cHEYfwpc=
+github.com/tektoncd/pipeline v0.60.1 h1:SRQ0p3LXBMtG4jcLBVmhENjrQIevah9CSo3jEvKpZDk=
+github.com/tektoncd/pipeline v0.60.1/go.mod h1:7bCvVXxBB06Ee7GVqYp+UKgUN5IadFvvH9wdLds5jZE=
+github.com/urfave/cli v1.22.12/go.mod h1:sSBEIC79qR6OvcmsD4U3KABeOTxDqQtdDnaFuUN30b8=
+github.com/vbatts/tar-split v0.11.3 h1:hLFqsOLQ1SsppQNTMpkpPXClLDfC2A3Zgy9OUU+RVck=
+github.com/vbatts/tar-split v0.11.3/go.mod h1:9QlHN18E+fEH7RdG+QAJJcuya3rqT7eXSTY7wGrAokY=
+github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/zregvart/tkn-fmt v0.0.0-20240613172239-ba04662da674 h1:yspt7cxlsDwWUWUjqbA75dyloOGacbnzHWO55CMsq9k=
+github.com/zregvart/tkn-fmt v0.0.0-20240613172239-ba04662da674/go.mod h1:t7139snuK35qgYLly1CaLLVZy6UCkz/KmN/AevOJi+k=
+go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
+go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
+go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
+go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
+go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
+go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
+go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
+go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
+go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
+go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
+go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
+go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
+go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
+golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
+golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
+golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
+golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
+golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
+golang.org/x/exp v0.0.0-20240604190554-fc45aab8b7f8 h1:LoYXNGAShUG3m/ehNk4iFctuhGX/+R1ZpfJ4/ia80JM=
+golang.org/x/exp v0.0.0-20240604190554-fc45aab8b7f8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI=
+golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
+golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
+golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
+golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
+golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
+golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
+golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
+golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
+golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
+golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
+golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
+golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
+golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs=
+golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
+golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220708085239-5a0f0661e09d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220906165534-d0df966e6959/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
+golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA=
+golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
+golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
+golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
+golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
+golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
+golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
+golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
+golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
+golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw=
+gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
+google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
+google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
+google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
+google.golang.org/api v0.25.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
+google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
+google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
+google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
+google.golang.org/api v0.183.0 h1:PNMeRDwo1pJdgNcFQ9GstuLe/noWKIc89pRWRLMvLwE=
+google.golang.org/api v0.183.0/go.mod h1:q43adC5/pHoSZTx5h2mSmdF7NcyfW9JuDyIOJAgS9ZQ=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
+google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
+google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
+google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
+google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
+google.golang.org/genproto v0.0.0-20200527145253-8367513e4ece/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
+google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
+google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto/googleapis/api v0.0.0-20240604185151-ef581f913117 h1:+rdxYoE3E5htTEWIe15GlN6IfvbURM//Jt0mmkmm6ZU=
+google.golang.org/genproto/googleapis/api v0.0.0-20240604185151-ef581f913117/go.mod h1:OimBR/bc1wPO9iV4NC2bpyjy3VnAwZh5EBPQdtaE5oo=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 h1:1GBuWVLM/KMVUv1t1En5Gs+gFZCNd360GGb4sSxtrhU=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
+google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
+google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
+google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
+google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
+google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
+google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
+google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
+google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY=
+google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg=
+google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
+google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
+google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
+google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
+google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
+google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
+google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
+google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
+gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
+gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
+gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
+gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0=
+gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
+honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
+honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
+k8s.io/api v0.30.1 h1:kCm/6mADMdbAxmIh0LBjS54nQBE+U4KmbCfIkF5CpJY=
+k8s.io/api v0.30.1/go.mod h1:ddbN2C0+0DIiPntan/bye3SW3PdwLa11/0yqwvuRrJM=
+k8s.io/apimachinery v0.30.1 h1:ZQStsEfo4n65yAdlGTfP/uSHMQSoYzU/oeEbkmF7P2U=
+k8s.io/apimachinery v0.30.1/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc=
+k8s.io/client-go v0.30.1 h1:uC/Ir6A3R46wdkgCV3vbLyNOYyCJ8oZnjtJGKfytl/Q=
+k8s.io/client-go v0.30.1/go.mod h1:wrAqLNs2trwiCH/wxxmT/x3hKVH9PuV0GGW0oDoHVqc=
+k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw=
+k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
+k8s.io/kube-openapi v0.0.0-20240521193020-835d969ad83a h1:zD1uj3Jf+mD4zmA7W+goE5TxDkI7OGJjBNBzq5fJtLA=
+k8s.io/kube-openapi v0.0.0-20240521193020-835d969ad83a/go.mod h1:UxDHUPsUwTOOxSU+oXURfFBcAS6JwiRXTYqYwfuGowc=
+k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0 h1:jgGTlFYnhF1PM1Ax/lAlxUPE+KfCIXHaathvJg1C3ak=
+k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
+knative.dev/pkg v0.0.0-20240604134003-58135c2c0694 h1:trbVXm0WFXxxjcuSCKrYHKQwRQCuDrE8T5+yqXAI1NA=
+knative.dev/pkg v0.0.0-20240604134003-58135c2c0694/go.mod h1:E5OxJHFsQiW7pL0lVJ02XEVm2QUc0ZVdSUHiarUJHrU=
+mvdan.cc/sh/v3 v3.8.0 h1:ZxuJipLZwr/HLbASonmXtcvvC9HXY9d2lXZHnKGjFc8=
+mvdan.cc/sh/v3 v3.8.0/go.mod h1:w04623xkgBVo7/IUK89E0g8hBykgEpN0vgOj3RJr6MY=
+rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
+rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
+rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
+sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
+sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
+sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4=
+sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08=
+sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
+sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
diff --git a/ta-generator/golden/buildah/base.yaml b/ta-generator/golden/buildah/base.yaml
new file mode 100644
index 0000000000..5b6d4d19af
--- /dev/null
+++ b/ta-generator/golden/buildah/base.yaml
@@ -0,0 +1,462 @@
+apiVersion: tekton.dev/v1
+kind: Task
+metadata:
+ labels:
+ app.kubernetes.io/version: "0.1"
+ build.appstudio.redhat.com/build_type: "docker"
+ annotations:
+ tekton.dev/pipelines.minVersion: "0.12.1"
+ tekton.dev/tags: "image-build, appstudio, hacbs"
+ name: buildah
+spec:
+ description: |-
+ Buildah task builds source code into a container image and pushes the image into container registry using buildah tool.
+ In addition it generates a SBOM file, injects the SBOM file into final container image and pushes the SBOM file as separate image using cosign tool.
+ When [Java dependency rebuild](https://redhat-appstudio.github.io/docs.stonesoup.io/Documentation/main/cli/proc_enabled_java_dependencies.html) is enabled it triggers rebuilds of Java artifacts.
+ When prefetch-dependencies task was activated it is using its artifacts to run build in hermetic environment.
+ params:
+ - description: Reference of the image buildah will produce.
+ name: IMAGE
+ type: string
+ - default: ""
+ description: Deprecated. Has no effect. Will be removed in the future.
+ name: BUILDER_IMAGE
+ type: string
+ - default: ./Dockerfile
+ description: Path to the Dockerfile to build.
+ name: DOCKERFILE
+ type: string
+ - default: .
+ description: Path to the directory to use as context.
+ name: CONTEXT
+ type: string
+ - default: "true"
+ description: Verify the TLS on the registry endpoint (for push/pull to a non-TLS registry)
+ name: TLSVERIFY
+ type: string
+ - description: unused, should be removed in next task version
+ name: DOCKER_AUTH
+ type: string
+ default: ""
+ - default: "false"
+ description: Determines if build will be executed without network access.
+ name: HERMETIC
+ type: string
+ - default: ""
+ description: In case it is not empty, the prefetched content should be made available to the build.
+ name: PREFETCH_INPUT
+ type: string
+ - default: ""
+ description: Delete image tag after specified time. Empty means to keep the image tag. Time values could be something like 1h, 2d, 3w for hours, days, and weeks, respectively.
+ name: IMAGE_EXPIRES_AFTER
+ type: string
+ - name: COMMIT_SHA
+ description: The image is built from this commit.
+ type: string
+ default: ""
+ - name: YUM_REPOS_D_SRC
+ description: Path in the git repository in which yum repository files are stored
+ default: repos.d
+ - name: YUM_REPOS_D_FETCHED
+ description: Path in source workspace where dynamically-fetched repos are present
+ default: fetched.repos.d
+ - name: YUM_REPOS_D_TARGET
+ description: Target path on the container in which yum repository files should be made available
+ default: /etc/yum.repos.d
+ - name: TARGET_STAGE
+ description: Target stage in Dockerfile to build. If not specified, the Dockerfile is processed entirely to (and including) its last stage.
+ type: string
+ default: ""
+ - name: ENTITLEMENT_SECRET
+ description: Name of secret which contains the entitlement certificates
+ type: string
+ default: "etc-pki-entitlement"
+ - name: BUILD_ARGS
+ description: Array of --build-arg values ("arg=value" strings)
+ type: array
+ default: []
+ - name: BUILD_ARGS_FILE
+ description: Path to a file with build arguments, see https://www.mankier.com/1/buildah-build#--build-arg-file
+ type: string
+ default: ""
+
+ results:
+ - description: Digest of the image just built
+ name: IMAGE_DIGEST
+ - description: Image repository where the built image was pushed
+ name: IMAGE_URL
+ - description: Digests of the base images used for build
+ name: BASE_IMAGES_DIGESTS
+ - name: SBOM_JAVA_COMPONENTS_COUNT
+ description: The counting of Java components by publisher in JSON format
+ type: string
+ - name: JAVA_COMMUNITY_DEPENDENCIES
+ description: The Java dependencies that came from community sources such as Maven central.
+ stepTemplate:
+ env:
+ - name: BUILDAH_FORMAT
+ value: oci
+ - name: STORAGE_DRIVER
+ value: vfs
+ - name: HERMETIC
+ value: $(params.HERMETIC)
+ - name: CONTEXT
+ value: $(params.CONTEXT)
+ - name: DOCKERFILE
+ value: $(params.DOCKERFILE)
+ - name: IMAGE
+ value: $(params.IMAGE)
+ - name: TLSVERIFY
+ value: $(params.TLSVERIFY)
+ - name: IMAGE_EXPIRES_AFTER
+ value: $(params.IMAGE_EXPIRES_AFTER)
+ - name: YUM_REPOS_D_SRC
+ value: $(params.YUM_REPOS_D_SRC)
+ - name: YUM_REPOS_D_FETCHED
+ value: $(params.YUM_REPOS_D_FETCHED)
+ - name: YUM_REPOS_D_TARGET
+ value: $(params.YUM_REPOS_D_TARGET)
+ - name: TARGET_STAGE
+ value: $(params.TARGET_STAGE)
+ - name: PARAM_BUILDER_IMAGE
+ value: $(params.BUILDER_IMAGE)
+ - name: ENTITLEMENT_SECRET
+ value: $(params.ENTITLEMENT_SECRET)
+ - name: BUILD_ARGS_FILE
+ value: $(params.BUILD_ARGS_FILE)
+
+ steps:
+ - image: quay.io/redhat-appstudio/buildah:v1.31.0@sha256:34f12c7b72ec2c28f1ded0c494b428df4791c909f1f174dd21b8ed6a57cf5ddb
+ name: build
+ computeResources:
+ limits:
+ memory: 4Gi
+ requests:
+ memory: 512Mi
+ cpu: 250m
+ env:
+ - name: COMMIT_SHA
+ value: $(params.COMMIT_SHA)
+ args:
+ - $(params.BUILD_ARGS[*])
+ script: |
+ if [ -n "${PARAM_BUILDER_IMAGE}" ]; then
+ echo "WARNING: provided deprecated BUILDER_IMAGE parameter has no effect."
+ fi
+
+ SOURCE_CODE_DIR=source
+ if [ -e "$SOURCE_CODE_DIR/$CONTEXT/$DOCKERFILE" ]; then
+ dockerfile_path="$(pwd)/$SOURCE_CODE_DIR/$CONTEXT/$DOCKERFILE"
+ elif [ -e "$SOURCE_CODE_DIR/$DOCKERFILE" ]; then
+ dockerfile_path="$(pwd)/$SOURCE_CODE_DIR/$DOCKERFILE"
+ elif echo "$DOCKERFILE" | grep -q "^https\?://"; then
+ echo "Fetch Dockerfile from $DOCKERFILE"
+ dockerfile_path=$(mktemp --suffix=-Dockerfile)
+ http_code=$(curl -s -L -w "%{http_code}" --output "$dockerfile_path" "$DOCKERFILE")
+ if [ $http_code != 200 ]; then
+ echo "No Dockerfile is fetched. Server responds $http_code"
+ exit 1
+ fi
+ http_code=$(curl -s -L -w "%{http_code}" --output "$dockerfile_path.dockerignore.tmp" "$DOCKERFILE.dockerignore")
+ if [ $http_code = 200 ]; then
+ echo "Fetched .dockerignore from $DOCKERFILE.dockerignore"
+ mv "$dockerfile_path.dockerignore.tmp" $SOURCE_CODE_DIR/$CONTEXT/.dockerignore
+ fi
+ else
+ echo "Cannot find Dockerfile $DOCKERFILE"
+ exit 1
+ fi
+ if [ -n "$JVM_BUILD_WORKSPACE_ARTIFACT_CACHE_PORT_80_TCP_ADDR" ] && grep -q '^\s*RUN \(./\)\?mvn' "$dockerfile_path"; then
+ sed -i -e "s|^\s*RUN \(\(./\)\?mvn\)\(.*\)|RUN echo \"mirror.defaulthttp://$JVM_BUILD_WORKSPACE_ARTIFACT_CACHE_PORT_80_TCP_ADDR/v1/cache/default/0/*\" > /tmp/settings.yaml; \1 -s /tmp/settings.yaml \3|g" "$dockerfile_path"
+ touch /var/lib/containers/java
+ fi
+
+ # Fixing group permission on /var/lib/containers
+ chown root:root /var/lib/containers
+
+ sed -i 's/^\s*short-name-mode\s*=\s*.*/short-name-mode = "disabled"/' /etc/containers/registries.conf
+
+ # Setting new namespace to run buildah - 2^32-2
+ echo 'root:1:4294967294' | tee -a /etc/subuid >> /etc/subgid
+
+ BUILDAH_ARGS=()
+
+ BASE_IMAGES=$(grep -i '^\s*FROM' "$dockerfile_path" | sed 's/--platform=\S*//' | awk '{print $2}')
+ if [ "${HERMETIC}" == "true" ]; then
+ BUILDAH_ARGS+=("--pull=never")
+ UNSHARE_ARGS="--net"
+ for image in $BASE_IMAGES; do
+ if [ "${image}" != "scratch" ]; then
+ unshare -Ufp --keep-caps -r --map-users 1,1,65536 --map-groups 1,1,65536 -- buildah pull $image
+ fi
+ done
+ echo "Build will be executed with network isolation"
+ fi
+
+ if [ -n "${TARGET_STAGE}" ]; then
+ BUILDAH_ARGS+=("--target=${TARGET_STAGE}")
+ fi
+
+ if [ -n "${BUILD_ARGS_FILE}" ]; then
+ BUILDAH_ARGS+=("--build-arg-file=$(pwd)/$SOURCE_CODE_DIR/${BUILD_ARGS_FILE}")
+ fi
+
+ for build_arg in "$@"; do
+ BUILDAH_ARGS+=("--build-arg=$build_arg")
+ done
+
+ if [ -d "$(workspaces.source.path)/cachi2" ]; then
+ cp -r "$(workspaces.source.path)/cachi2" /tmp/
+ chmod -R go+rwX /tmp/cachi2
+ VOLUME_MOUNTS="--volume /tmp/cachi2:/cachi2"
+ sed -i 's|^\s*run |RUN . /cachi2/cachi2.env \&\& \\\n |i' "$dockerfile_path"
+ echo "Prefetched content will be made available"
+
+ prefetched_repo_for_my_arch="/tmp/cachi2/output/deps/rpm/$(uname -m)/repos.d/cachi2.repo"
+ if [ -f "$prefetched_repo_for_my_arch" ]; then
+ echo "Adding $prefetched_repo_for_my_arch to $YUM_REPOS_D_FETCHED"
+ mkdir -p "$YUM_REPOS_D_FETCHED"
+ cp --no-clobber "$prefetched_repo_for_my_arch" "$YUM_REPOS_D_FETCHED"
+ fi
+ fi
+
+ # if yum repofiles stored in git, copy them to mount point outside the source dir
+ if [ -d "${SOURCE_CODE_DIR}/${YUM_REPOS_D_SRC}" ]; then
+ mkdir -p ${YUM_REPOS_D_FETCHED}
+ cp -r ${SOURCE_CODE_DIR}/${YUM_REPOS_D_SRC}/* ${YUM_REPOS_D_FETCHED}
+ fi
+
+ # if anything in the repofiles mount point (either fetched or from git), mount it
+ if [ -d "${YUM_REPOS_D_FETCHED}" ]; then
+ chmod -R go+rwX ${YUM_REPOS_D_FETCHED}
+ mount_point=$(realpath ${YUM_REPOS_D_FETCHED})
+ VOLUME_MOUNTS="${VOLUME_MOUNTS} --volume ${mount_point}:${YUM_REPOS_D_TARGET}"
+ fi
+
+ LABELS=(
+ "--label" "build-date=$(date -u +'%Y-%m-%dT%H:%M:%S')"
+ "--label" "architecture=$(uname -m)"
+ "--label" "vcs-type=git"
+ )
+ [ -n "$COMMIT_SHA" ] && LABELS+=("--label" "vcs-ref=$COMMIT_SHA")
+ [ -n "$IMAGE_EXPIRES_AFTER" ] && LABELS+=("--label" "quay.expires-after=$IMAGE_EXPIRES_AFTER")
+
+ ENTITLEMENT_PATH="/entitlement"
+ if [ -d "$ENTITLEMENT_PATH" ]; then
+ cp -r --preserve=mode "$ENTITLEMENT_PATH" /tmp/entitlement
+ VOLUME_MOUNTS="${VOLUME_MOUNTS} --volume /tmp/entitlement:/etc/pki/entitlement"
+ echo "Adding the entitlement to the build"
+ fi
+
+ unshare -Uf $UNSHARE_ARGS --keep-caps -r --map-users 1,1,65536 --map-groups 1,1,65536 -w ${SOURCE_CODE_DIR}/$CONTEXT -- buildah build \
+ $VOLUME_MOUNTS \
+ "${BUILDAH_ARGS[@]}" \
+ "${LABELS[@]}" \
+ --tls-verify=$TLSVERIFY --no-cache \
+ --ulimit nofile=4096:4096 \
+ -f "$dockerfile_path" -t $IMAGE .
+
+ container=$(buildah from --pull-never $IMAGE)
+ buildah mount $container | tee /workspace/container_path
+ echo $container > /workspace/container_name
+
+ # Save the SBOM produced by Cachi2 so it can be merged into the final SBOM later
+ if [ -d "$(workspaces.source.path)/cachi2" ]; then
+ cp /tmp/cachi2/output/bom.json ./sbom-cachi2.json
+ fi
+
+ # Expose base image digests
+ for image in $BASE_IMAGES; do
+ if [ "${image}" != "scratch" ]; then
+ buildah images --format '{{ .Name }}:{{ .Tag }}@{{ .Digest }}' --filter reference="$image" >> $(results.BASE_IMAGES_DIGESTS.path)
+ fi
+ done
+
+ # Needed to generate base images SBOM
+ echo "$BASE_IMAGES" > $(workspaces.source.path)/base_images_from_dockerfile
+
+ securityContext:
+ capabilities:
+ add:
+ - SETFCAP
+ volumeMounts:
+ - mountPath: /var/lib/containers
+ name: varlibcontainers
+ - mountPath: "/entitlement"
+ name: etc-pki-entitlement
+ workingDir: $(workspaces.source.path)
+
+ - name: sbom-syft-generate
+ image: quay.io/redhat-appstudio/syft:v0.105.1@sha256:1910b829997650c696881e5fc2fc654ddf3184c27edb1b2024e9cb2ba51ac431
+ # Respect Syft configuration if the user has it in the root of their repository
+ # (need to set the workdir, see https://github.com/anchore/syft/issues/2465)
+ workingDir: $(workspaces.source.path)/source
+ script: |
+ echo "Running syft on the source directory"
+ syft dir:$(workspaces.source.path)/source --output cyclonedx-json=$(workspaces.source.path)/sbom-source.json
+ find $(cat /workspace/container_path) -xtype l -delete
+ echo "Running syft on the image filesystem"
+ syft dir:$(cat /workspace/container_path) --output cyclonedx-json=$(workspaces.source.path)/sbom-image.json
+ volumeMounts:
+ - mountPath: /var/lib/containers
+ name: varlibcontainers
+ - name: analyse-dependencies-java-sbom
+ image: quay.io/redhat-appstudio/hacbs-jvm-build-request-processor:127ee0c223a2b56a9bd20a6f2eaeed3bd6015f77
+ script: |
+ if [ -f /var/lib/containers/java ]; then
+ /opt/jboss/container/java/run/run-java.sh analyse-dependencies path $(cat /workspace/container_path) -s $(workspaces.source.path)/sbom-image.json --task-run-name $(context.taskRun.name) --publishers $(results.SBOM_JAVA_COMPONENTS_COUNT.path)
+ sed -i 's/^/ /' $(results.SBOM_JAVA_COMPONENTS_COUNT.path) # Workaround for SRVKP-2875
+ else
+ touch $(results.JAVA_COMMUNITY_DEPENDENCIES.path)
+ fi
+ volumeMounts:
+ - mountPath: /var/lib/containers
+ name: varlibcontainers
+ securityContext:
+ runAsUser: 0
+
+ - name: merge-syft-sboms
+ image: registry.access.redhat.com/ubi9/python-39:1-172.1712567222@sha256:c96f839e927c52990143df4efb2872946fcd5de9e1ed2014947bb2cf3084c27a
+ script: |
+ #!/bin/python3
+ import json
+
+ # load SBOMs
+ with open("./sbom-image.json") as f:
+ image_sbom = json.load(f)
+
+ with open("./sbom-source.json") as f:
+ source_sbom = json.load(f)
+
+ # fetch unique components from available SBOMs
+ def get_identifier(component):
+ return component["name"] + '@' + component.get("version", "")
+
+ image_sbom_components = image_sbom.get("components", [])
+ existing_components = [get_identifier(component) for component in image_sbom_components]
+
+ source_sbom_components = source_sbom.get("components", [])
+ for component in source_sbom_components:
+ if get_identifier(component) not in existing_components:
+ image_sbom_components.append(component)
+ existing_components.append(get_identifier(component))
+
+ image_sbom_components.sort(key=lambda c: get_identifier(c))
+
+ # write the CycloneDX unified SBOM
+ with open("./sbom-cyclonedx.json", "w") as f:
+ json.dump(image_sbom, f, indent=4)
+ workingDir: $(workspaces.source.path)
+ securityContext:
+ runAsUser: 0
+
+ - name: merge-cachi2-sbom
+ image: quay.io/redhat-appstudio/cachi2:0.7.0@sha256:1fc772aa3636fd0b43d62120d832e5913843e028e8cac42814b487c3a0a32bd8
+ script: |
+ if [ -d "$(workspaces.source.path)/cachi2" ]; then
+ echo "Merging contents of sbom-cachi2.json into sbom-cyclonedx.json"
+ /src/utils/merge_syft_sbom.py sbom-cachi2.json sbom-cyclonedx.json > sbom-temp.json
+ mv sbom-temp.json sbom-cyclonedx.json
+ else
+ echo "Skipping step since no Cachi2 SBOM was produced"
+ fi
+ workingDir: $(workspaces.source.path)
+ securityContext:
+ runAsUser: 0
+
+ - name: create-purl-sbom
+ image: registry.access.redhat.com/ubi9/python-39:1-172.1712567222@sha256:c96f839e927c52990143df4efb2872946fcd5de9e1ed2014947bb2cf3084c27a
+ script: |
+ #!/bin/python3
+ import json
+
+ with open("./sbom-cyclonedx.json") as f:
+ cyclonedx_sbom = json.load(f)
+
+ purls = [{"purl": component["purl"]} for component in cyclonedx_sbom.get("components", []) if "purl" in component]
+ purl_content = {"image_contents": {"dependencies": purls}}
+
+ with open("sbom-purl.json", "w") as output_file:
+ json.dump(purl_content, output_file, indent=4)
+ workingDir: $(workspaces.source.path)
+ securityContext:
+ runAsUser: 0
+
+ - name: create-base-images-sbom
+ image: quay.io/redhat-appstudio/base-images-sbom-script@sha256:667669e3def018f9dbb8eaf8868887a40bc07842221e9a98f6787edcff021840
+ env:
+ - name: BASE_IMAGES_DIGESTS_PATH
+ value: $(results.BASE_IMAGES_DIGESTS.path)
+ script: |
+ python3 /app/base_images_sbom_script.py --sbom=sbom-cyclonedx.json --base-images-from-dockerfile=base_images_from_dockerfile --base-images-digests=$BASE_IMAGES_DIGESTS_PATH
+ workingDir: $(workspaces.source.path)
+ securityContext:
+ runAsUser: 0
+
+ - name: inject-sbom-and-push
+ image: quay.io/redhat-appstudio/buildah:v1.31.0@sha256:34f12c7b72ec2c28f1ded0c494b428df4791c909f1f174dd21b8ed6a57cf5ddb
+ computeResources: {}
+ script: |
+ if [ -n "${PARAM_BUILDER_IMAGE}" ]; then
+ echo "WARNING: provided deprecated BUILDER_IMAGE parameter has no effect."
+ fi
+
+ base_image_name=$(buildah inspect --format '{{ index .ImageAnnotations "org.opencontainers.image.base.name"}}' $IMAGE | cut -f1 -d'@')
+ base_image_digest=$(buildah inspect --format '{{ index .ImageAnnotations "org.opencontainers.image.base.digest"}}' $IMAGE)
+ container=$(buildah from --pull-never $IMAGE)
+ buildah copy $container sbom-cyclonedx.json sbom-purl.json /root/buildinfo/content_manifests/
+ buildah config -a org.opencontainers.image.base.name=${base_image_name} -a org.opencontainers.image.base.digest=${base_image_digest} $container
+ buildah commit $container $IMAGE
+
+ status=-1
+ max_run=5
+ sleep_sec=10
+ for run in $(seq 1 $max_run); do
+ status=0
+ [ "$run" -gt 1 ] && sleep $sleep_sec
+ echo "Pushing sbom image to registry"
+ buildah push \
+ --tls-verify=$TLSVERIFY \
+ --digestfile $(workspaces.source.path)/image-digest $IMAGE \
+ docker://$IMAGE && break || status=$?
+ done
+ if [ "$status" -ne 0 ]; then
+ echo "Failed to push sbom image to registry after ${max_run} tries"
+ exit 1
+ fi
+
+ cat "$(workspaces.source.path)"/image-digest | tee $(results.IMAGE_DIGEST.path)
+ echo -n "$IMAGE" | tee $(results.IMAGE_URL.path)
+
+ securityContext:
+ runAsUser: 0
+ capabilities:
+ add:
+ - SETFCAP
+ volumeMounts:
+ - mountPath: /var/lib/containers
+ name: varlibcontainers
+ workingDir: $(workspaces.source.path)
+
+ - name: upload-sbom
+ image: quay.io/redhat-appstudio/cosign:v2.1.1@sha256:c883d6f8d39148f2cea71bff4622d196d89df3e510f36c140c097b932f0dd5d5
+ args:
+ - attach
+ - sbom
+ - --sbom
+ - sbom-cyclonedx.json
+ - --type
+ - cyclonedx
+ - $(params.IMAGE)
+ workingDir: $(workspaces.source.path)
+
+ volumes:
+ - name: varlibcontainers
+ emptyDir: {}
+ - name: etc-pki-entitlement
+ secret:
+ secretName: $(params.ENTITLEMENT_SECRET)
+ optional: true
+ workspaces:
+ - name: source
+ description: Workspace containing the source code to build.
diff --git a/ta-generator/golden/buildah/recipe.yaml b/ta-generator/golden/buildah/recipe.yaml
new file mode 100644
index 0000000000..aef4e83882
--- /dev/null
+++ b/ta-generator/golden/buildah/recipe.yaml
@@ -0,0 +1,17 @@
+---
+removeParams:
+ - BUILDER_IMAGE
+add:
+ - use-source
+ - use-cachi2
+removeWorkspaces:
+ - source
+replacements:
+ workspaces.source.path: /var/workdir
+regexReplacements:
+ "/workspace(/.*)": /var/workdir$1
+description: |-
+ Buildah task builds source code into a container image and pushes the image into container registry using buildah tool.
+ In addition it generates a SBOM file, injects the SBOM file into final container image and pushes the SBOM file as separate image using cosign tool.
+ When [Java dependency rebuild](https://redhat-appstudio.github.io/docs.stonesoup.io/Documentation/main/cli/proc_enabled_java_dependencies.html) is enabled it triggers rebuilds of Java artifacts.
+ When prefetch-dependencies task was activated it is using its artifacts to run build in hermetic environment.
diff --git a/ta-generator/golden/buildah/ta.yaml b/ta-generator/golden/buildah/ta.yaml
new file mode 100644
index 0000000000..ca29e30f1d
--- /dev/null
+++ b/ta-generator/golden/buildah/ta.yaml
@@ -0,0 +1,461 @@
+---
+apiVersion: tekton.dev/v1
+kind: Task
+metadata:
+ labels:
+ app.kubernetes.io/version: "0.1"
+ build.appstudio.redhat.com/build_type: "docker"
+ annotations:
+ tekton.dev/pipelines.minVersion: "0.12.1"
+ tekton.dev/tags: "image-build, appstudio, hacbs"
+ name: buildah-oci-ta
+spec:
+ description: |-
+ Buildah task builds source code into a container image and pushes the image into container registry using buildah tool.
+ In addition it generates a SBOM file, injects the SBOM file into final container image and pushes the SBOM file as separate image using cosign tool.
+ When [Java dependency rebuild](https://redhat-appstudio.github.io/docs.stonesoup.io/Documentation/main/cli/proc_enabled_java_dependencies.html) is enabled it triggers rebuilds of Java artifacts.
+ When prefetch-dependencies task was activated it is using its artifacts to run build in hermetic environment.
+ params:
+ - description: Reference of the image buildah will produce.
+ name: IMAGE
+ type: string
+ - description: The Trusted Artifact URI pointing to the artifact with the application source code.
+ name: SOURCE_ARTIFACT
+ type: string
+ - description: The Trusted Artifact URI pointing to the artifact with the prefetched dependencies.
+ name: CACHI2_ARTIFACT
+ type: string
+ default: ""
+ - default: ./Dockerfile
+ description: Path to the Dockerfile to build.
+ name: DOCKERFILE
+ type: string
+ - default: .
+ description: Path to the directory to use as context.
+ name: CONTEXT
+ type: string
+ - default: "true"
+ description: Verify the TLS on the registry endpoint (for push/pull to a non-TLS registry)
+ name: TLSVERIFY
+ type: string
+ - description: unused, should be removed in next task version
+ name: DOCKER_AUTH
+ type: string
+ default: ""
+ - default: "false"
+ description: Determines if build will be executed without network access.
+ name: HERMETIC
+ type: string
+ - default: ""
+ description: In case it is not empty, the prefetched content should be made available to the build.
+ name: PREFETCH_INPUT
+ type: string
+ - default: ""
+ description: Delete image tag after specified time. Empty means to keep the image tag. Time values could be something like 1h, 2d, 3w for hours, days, and weeks, respectively.
+ name: IMAGE_EXPIRES_AFTER
+ type: string
+ - name: COMMIT_SHA
+ description: The image is built from this commit.
+ type: string
+ default: ""
+ - name: YUM_REPOS_D_SRC
+ description: Path in the git repository in which yum repository files are stored
+ default: repos.d
+ - name: YUM_REPOS_D_FETCHED
+ description: Path in source workspace where dynamically-fetched repos are present
+ default: fetched.repos.d
+ - name: YUM_REPOS_D_TARGET
+ description: Target path on the container in which yum repository files should be made available
+ default: /etc/yum.repos.d
+ - name: TARGET_STAGE
+ description: Target stage in Dockerfile to build. If not specified, the Dockerfile is processed entirely to (and including) its last stage.
+ type: string
+ default: ""
+ - name: ENTITLEMENT_SECRET
+ description: Name of secret which contains the entitlement certificates
+ type: string
+ default: "etc-pki-entitlement"
+ - name: BUILD_ARGS
+ description: Array of --build-arg values ("arg=value" strings)
+ type: array
+ default: []
+ - name: BUILD_ARGS_FILE
+ description: Path to a file with build arguments, see https://www.mankier.com/1/buildah-build#--build-arg-file
+ type: string
+ default: ""
+
+ results:
+ - description: Digest of the image just built
+ name: IMAGE_DIGEST
+ - description: Image repository where the built image was pushed
+ name: IMAGE_URL
+ - description: Digests of the base images used for build
+ name: BASE_IMAGES_DIGESTS
+ - name: SBOM_JAVA_COMPONENTS_COUNT
+ description: The counting of Java components by publisher in JSON format
+ type: string
+ - name: JAVA_COMMUNITY_DEPENDENCIES
+ description: The Java dependencies that came from community sources such as Maven central.
+ stepTemplate:
+ env:
+ - name: BUILDAH_FORMAT
+ value: oci
+ - name: STORAGE_DRIVER
+ value: vfs
+ - name: HERMETIC
+ value: $(params.HERMETIC)
+ - name: CONTEXT
+ value: $(params.CONTEXT)
+ - name: DOCKERFILE
+ value: $(params.DOCKERFILE)
+ - name: IMAGE
+ value: $(params.IMAGE)
+ - name: TLSVERIFY
+ value: $(params.TLSVERIFY)
+ - name: IMAGE_EXPIRES_AFTER
+ value: $(params.IMAGE_EXPIRES_AFTER)
+ - name: YUM_REPOS_D_SRC
+ value: $(params.YUM_REPOS_D_SRC)
+ - name: YUM_REPOS_D_FETCHED
+ value: $(params.YUM_REPOS_D_FETCHED)
+ - name: YUM_REPOS_D_TARGET
+ value: $(params.YUM_REPOS_D_TARGET)
+ - name: TARGET_STAGE
+ value: $(params.TARGET_STAGE)
+ - name: ENTITLEMENT_SECRET
+ value: $(params.ENTITLEMENT_SECRET)
+ - name: BUILD_ARGS_FILE
+ value: $(params.BUILD_ARGS_FILE)
+ volumeMounts:
+ - mountPath: /var/workdir
+ name: workdir
+ steps:
+ - image: quay.io/redhat-appstudio/build-trusted-artifacts:latest@sha256:resolved
+ name: use-trusted-artifact
+ args:
+ - use
+ - $(params.SOURCE_ARTIFACT)=/var/workdir/source
+ - $(params.CACHI2_ARTIFACT)=/var/workdir/cachi2
+ - image: quay.io/redhat-appstudio/buildah:v1.31.0@sha256:34f12c7b72ec2c28f1ded0c494b428df4791c909f1f174dd21b8ed6a57cf5ddb
+ name: build
+ computeResources:
+ limits:
+ memory: 4Gi
+ requests:
+ memory: 512Mi
+ cpu: 250m
+ env:
+ - name: COMMIT_SHA
+ value: $(params.COMMIT_SHA)
+ args:
+ - $(params.BUILD_ARGS[*])
+ script: |
+ SOURCE_CODE_DIR=source
+ if [ -e "$SOURCE_CODE_DIR/$CONTEXT/$DOCKERFILE" ]; then
+ dockerfile_path="$(pwd)/$SOURCE_CODE_DIR/$CONTEXT/$DOCKERFILE"
+ elif [ -e "$SOURCE_CODE_DIR/$DOCKERFILE" ]; then
+ dockerfile_path="$(pwd)/$SOURCE_CODE_DIR/$DOCKERFILE"
+ elif echo "$DOCKERFILE" | grep -q "^https\?://"; then
+ echo "Fetch Dockerfile from $DOCKERFILE"
+ dockerfile_path=$(mktemp --suffix=-Dockerfile)
+ http_code=$(curl -s -L -w "%{http_code}" --output "$dockerfile_path" "$DOCKERFILE")
+ if [ $http_code != 200 ]; then
+ echo "No Dockerfile is fetched. Server responds $http_code"
+ exit 1
+ fi
+ http_code=$(curl -s -L -w "%{http_code}" --output "$dockerfile_path.dockerignore.tmp" "$DOCKERFILE.dockerignore")
+ if [ $http_code = 200 ]; then
+ echo "Fetched .dockerignore from $DOCKERFILE.dockerignore"
+ mv "$dockerfile_path.dockerignore.tmp" $SOURCE_CODE_DIR/$CONTEXT/.dockerignore
+ fi
+ else
+ echo "Cannot find Dockerfile $DOCKERFILE"
+ exit 1
+ fi
+ if [ -n "$JVM_BUILD_WORKSPACE_ARTIFACT_CACHE_PORT_80_TCP_ADDR" ] && grep -q '^\s*RUN \(./\)\?mvn' "$dockerfile_path"; then
+ sed -i -e "s|^\s*RUN \(\(./\)\?mvn\)\(.*\)|RUN echo \"mirror.defaulthttp://$JVM_BUILD_WORKSPACE_ARTIFACT_CACHE_PORT_80_TCP_ADDR/v1/cache/default/0/*\" > /tmp/settings.yaml; \1 -s /tmp/settings.yaml \3|g" "$dockerfile_path"
+ touch /var/lib/containers/java
+ fi
+
+ # Fixing group permission on /var/lib/containers
+ chown root:root /var/lib/containers
+
+ sed -i 's/^\s*short-name-mode\s*=\s*.*/short-name-mode = "disabled"/' /etc/containers/registries.conf
+
+ # Setting new namespace to run buildah - 2^32-2
+ echo 'root:1:4294967294' | tee -a /etc/subuid >> /etc/subgid
+
+ BUILDAH_ARGS=()
+
+ BASE_IMAGES=$(grep -i '^\s*FROM' "$dockerfile_path" | sed 's/--platform=\S*//' | awk '{print $2}')
+ if [ "${HERMETIC}" == "true" ]; then
+ BUILDAH_ARGS+=("--pull=never")
+ UNSHARE_ARGS="--net"
+ for image in $BASE_IMAGES; do
+ if [ "${image}" != "scratch" ]; then
+ unshare -Ufp --keep-caps -r --map-users 1,1,65536 --map-groups 1,1,65536 -- buildah pull $image
+ fi
+ done
+ echo "Build will be executed with network isolation"
+ fi
+
+ if [ -n "${TARGET_STAGE}" ]; then
+ BUILDAH_ARGS+=("--target=${TARGET_STAGE}")
+ fi
+
+ if [ -n "${BUILD_ARGS_FILE}" ]; then
+ BUILDAH_ARGS+=("--build-arg-file=$(pwd)/$SOURCE_CODE_DIR/${BUILD_ARGS_FILE}")
+ fi
+
+ for build_arg in "$@"; do
+ BUILDAH_ARGS+=("--build-arg=$build_arg")
+ done
+
+ if [ -d "/var/workdir/cachi2" ]; then
+ cp -r "/var/workdir/cachi2" /tmp/
+ chmod -R go+rwX /tmp/cachi2
+ VOLUME_MOUNTS="--volume /tmp/cachi2:/cachi2"
+ sed -i 's|^\s*run |RUN . /cachi2/cachi2.env \&\& \\\n |i' "$dockerfile_path"
+ echo "Prefetched content will be made available"
+
+ prefetched_repo_for_my_arch="/tmp/cachi2/output/deps/rpm/$(uname -m)/repos.d/cachi2.repo"
+ if [ -f "$prefetched_repo_for_my_arch" ]; then
+ echo "Adding $prefetched_repo_for_my_arch to $YUM_REPOS_D_FETCHED"
+ mkdir -p "$YUM_REPOS_D_FETCHED"
+ cp --no-clobber "$prefetched_repo_for_my_arch" "$YUM_REPOS_D_FETCHED"
+ fi
+ fi
+
+ # if yum repofiles stored in git, copy them to mount point outside the source dir
+ if [ -d "${SOURCE_CODE_DIR}/${YUM_REPOS_D_SRC}" ]; then
+ mkdir -p ${YUM_REPOS_D_FETCHED}
+ cp -r ${SOURCE_CODE_DIR}/${YUM_REPOS_D_SRC}/* ${YUM_REPOS_D_FETCHED}
+ fi
+
+ # if anything in the repofiles mount point (either fetched or from git), mount it
+ if [ -d "${YUM_REPOS_D_FETCHED}" ]; then
+ chmod -R go+rwX ${YUM_REPOS_D_FETCHED}
+ mount_point=$(realpath ${YUM_REPOS_D_FETCHED})
+ VOLUME_MOUNTS="${VOLUME_MOUNTS} --volume ${mount_point}:${YUM_REPOS_D_TARGET}"
+ fi
+
+ LABELS=(
+ "--label" "build-date=$(date -u +'%Y-%m-%dT%H:%M:%S')"
+ "--label" "architecture=$(uname -m)"
+ "--label" "vcs-type=git"
+ )
+ [ -n "$COMMIT_SHA" ] && LABELS+=("--label" "vcs-ref=$COMMIT_SHA")
+ [ -n "$IMAGE_EXPIRES_AFTER" ] && LABELS+=("--label" "quay.expires-after=$IMAGE_EXPIRES_AFTER")
+
+ ENTITLEMENT_PATH="/entitlement"
+ if [ -d "$ENTITLEMENT_PATH" ]; then
+ cp -r --preserve=mode "$ENTITLEMENT_PATH" /tmp/entitlement
+ VOLUME_MOUNTS="${VOLUME_MOUNTS} --volume /tmp/entitlement:/etc/pki/entitlement"
+ echo "Adding the entitlement to the build"
+ fi
+
+ unshare -Uf $UNSHARE_ARGS --keep-caps -r --map-users 1,1,65536 --map-groups 1,1,65536 -w ${SOURCE_CODE_DIR}/$CONTEXT -- buildah build \
+ $VOLUME_MOUNTS \
+ "${BUILDAH_ARGS[@]}" \
+ "${LABELS[@]}" \
+ --tls-verify=$TLSVERIFY --no-cache \
+ --ulimit nofile=4096:4096 \
+ -f "$dockerfile_path" -t $IMAGE .
+
+ container=$(buildah from --pull-never $IMAGE)
+ buildah mount $container | tee /var/workdir/container_path
+ echo $container > /var/workdir/container_name
+
+ # Save the SBOM produced by Cachi2 so it can be merged into the final SBOM later
+ if [ -d "/var/workdir/cachi2" ]; then
+ cp /tmp/cachi2/output/bom.json ./sbom-cachi2.json
+ fi
+
+ # Expose base image digests
+ for image in $BASE_IMAGES; do
+ if [ "${image}" != "scratch" ]; then
+ buildah images --format '{{ .Name }}:{{ .Tag }}@{{ .Digest }}' --filter reference="$image" >> $(results.BASE_IMAGES_DIGESTS.path)
+ fi
+ done
+
+ # Needed to generate base images SBOM
+ echo "$BASE_IMAGES" > /var/workdir/base_images_from_dockerfile
+
+ securityContext:
+ capabilities:
+ add:
+ - SETFCAP
+ volumeMounts:
+ - mountPath: /var/lib/containers
+ name: varlibcontainers
+ - mountPath: "/entitlement"
+ name: etc-pki-entitlement
+ workingDir: /var/workdir
+
+ - name: sbom-syft-generate
+ image: quay.io/redhat-appstudio/syft:v0.105.1@sha256:1910b829997650c696881e5fc2fc654ddf3184c27edb1b2024e9cb2ba51ac431
+ workingDir: /var/workdir/source
+ script: |
+ echo "Running syft on the source directory"
+ syft dir:/var/workdir/source --output cyclonedx-json=/var/workdir/sbom-source.json
+ find $(cat /var/workdir/container_path) -xtype l -delete
+ echo "Running syft on the image filesystem"
+ syft dir:$(cat /var/workdir/container_path) --output cyclonedx-json=/var/workdir/sbom-image.json
+ volumeMounts:
+ - mountPath: /var/lib/containers
+ name: varlibcontainers
+ - name: analyse-dependencies-java-sbom
+ image: quay.io/redhat-appstudio/hacbs-jvm-build-request-processor:127ee0c223a2b56a9bd20a6f2eaeed3bd6015f77
+ script: |
+ if [ -f /var/lib/containers/java ]; then
+ /opt/jboss/container/java/run/run-java.sh analyse-dependencies path $(cat /var/workdir/container_path) -s /var/workdir/sbom-image.json --task-run-name $(context.taskRun.name) --publishers $(results.SBOM_JAVA_COMPONENTS_COUNT.path)
+ sed -i 's/^/ /' $(results.SBOM_JAVA_COMPONENTS_COUNT.path) # Workaround for SRVKP-2875
+ else
+ touch $(results.JAVA_COMMUNITY_DEPENDENCIES.path)
+ fi
+ volumeMounts:
+ - mountPath: /var/lib/containers
+ name: varlibcontainers
+ securityContext:
+ runAsUser: 0
+
+ - name: merge-syft-sboms
+ image: registry.access.redhat.com/ubi9/python-39:1-172.1712567222@sha256:c96f839e927c52990143df4efb2872946fcd5de9e1ed2014947bb2cf3084c27a
+ script: |
+ #!/bin/python3
+ import json
+
+ # load SBOMs
+ with open("./sbom-image.json") as f:
+ image_sbom = json.load(f)
+
+ with open("./sbom-source.json") as f:
+ source_sbom = json.load(f)
+
+ # fetch unique components from available SBOMs
+ def get_identifier(component):
+ return component["name"] + '@' + component.get("version", "")
+
+ image_sbom_components = image_sbom.get("components", [])
+ existing_components = [get_identifier(component) for component in image_sbom_components]
+
+ source_sbom_components = source_sbom.get("components", [])
+ for component in source_sbom_components:
+ if get_identifier(component) not in existing_components:
+ image_sbom_components.append(component)
+ existing_components.append(get_identifier(component))
+
+ image_sbom_components.sort(key=lambda c: get_identifier(c))
+
+ # write the CycloneDX unified SBOM
+ with open("./sbom-cyclonedx.json", "w") as f:
+ json.dump(image_sbom, f, indent=4)
+ workingDir: /var/workdir
+ securityContext:
+ runAsUser: 0
+
+ - name: merge-cachi2-sbom
+ image: quay.io/redhat-appstudio/cachi2:0.7.0@sha256:1fc772aa3636fd0b43d62120d832e5913843e028e8cac42814b487c3a0a32bd8
+ script: |
+ if [ -d "/var/workdir/cachi2" ]; then
+ echo "Merging contents of sbom-cachi2.json into sbom-cyclonedx.json"
+ /src/utils/merge_syft_sbom.py sbom-cachi2.json sbom-cyclonedx.json > sbom-temp.json
+ mv sbom-temp.json sbom-cyclonedx.json
+ else
+ echo "Skipping step since no Cachi2 SBOM was produced"
+ fi
+ workingDir: /var/workdir
+ securityContext:
+ runAsUser: 0
+
+ - name: create-purl-sbom
+ image: registry.access.redhat.com/ubi9/python-39:1-172.1712567222@sha256:c96f839e927c52990143df4efb2872946fcd5de9e1ed2014947bb2cf3084c27a
+ script: |
+ #!/bin/python3
+ import json
+
+ with open("./sbom-cyclonedx.json") as f:
+ cyclonedx_sbom = json.load(f)
+
+ purls = [{"purl": component["purl"]} for component in cyclonedx_sbom.get("components", []) if "purl" in component]
+ purl_content = {"image_contents": {"dependencies": purls}}
+
+ with open("sbom-purl.json", "w") as output_file:
+ json.dump(purl_content, output_file, indent=4)
+ workingDir: /var/workdir
+ securityContext:
+ runAsUser: 0
+
+ - name: create-base-images-sbom
+ image: quay.io/redhat-appstudio/base-images-sbom-script@sha256:667669e3def018f9dbb8eaf8868887a40bc07842221e9a98f6787edcff021840
+ env:
+ - name: BASE_IMAGES_DIGESTS_PATH
+ value: $(results.BASE_IMAGES_DIGESTS.path)
+ script: |
+ python3 /app/base_images_sbom_script.py --sbom=sbom-cyclonedx.json --base-images-from-dockerfile=base_images_from_dockerfile --base-images-digests=$BASE_IMAGES_DIGESTS_PATH
+ workingDir: /var/workdir
+ securityContext:
+ runAsUser: 0
+
+ - name: inject-sbom-and-push
+ image: quay.io/redhat-appstudio/buildah:v1.31.0@sha256:34f12c7b72ec2c28f1ded0c494b428df4791c909f1f174dd21b8ed6a57cf5ddb
+ computeResources: {}
+ script: |
+ base_image_name=$(buildah inspect --format '{{ index .ImageAnnotations "org.opencontainers.image.base.name"}}' $IMAGE | cut -f1 -d'@')
+ base_image_digest=$(buildah inspect --format '{{ index .ImageAnnotations "org.opencontainers.image.base.digest"}}' $IMAGE)
+ container=$(buildah from --pull-never $IMAGE)
+ buildah copy $container sbom-cyclonedx.json sbom-purl.json /root/buildinfo/content_manifests/
+ buildah config -a org.opencontainers.image.base.name=${base_image_name} -a org.opencontainers.image.base.digest=${base_image_digest} $container
+ buildah commit $container $IMAGE
+
+ status=-1
+ max_run=5
+ sleep_sec=10
+ for run in $(seq 1 $max_run); do
+ status=0
+ [ "$run" -gt 1 ] && sleep $sleep_sec
+ echo "Pushing sbom image to registry"
+ buildah push \
+ --tls-verify=$TLSVERIFY \
+ --digestfile /var/workdir/image-digest $IMAGE \
+ docker://$IMAGE && break || status=$?
+ done
+ if [ "$status" -ne 0 ]; then
+ echo "Failed to push sbom image to registry after ${max_run} tries"
+ exit 1
+ fi
+
+ cat "/var/workdir"/image-digest | tee $(results.IMAGE_DIGEST.path)
+ echo -n "$IMAGE" | tee $(results.IMAGE_URL.path)
+
+ securityContext:
+ runAsUser: 0
+ capabilities:
+ add:
+ - SETFCAP
+ volumeMounts:
+ - mountPath: /var/lib/containers
+ name: varlibcontainers
+ workingDir: /var/workdir
+
+ - name: upload-sbom
+ image: quay.io/redhat-appstudio/cosign:v2.1.1@sha256:c883d6f8d39148f2cea71bff4622d196d89df3e510f36c140c097b932f0dd5d5
+ args:
+ - attach
+ - sbom
+ - --sbom
+ - sbom-cyclonedx.json
+ - --type
+ - cyclonedx
+ - $(params.IMAGE)
+ workingDir: /var/workdir
+
+ volumes:
+ - name: varlibcontainers
+ emptyDir: {}
+ - name: workdir
+ emptyDir: {}
+ - name: etc-pki-entitlement
+ secret:
+ secretName: $(params.ENTITLEMENT_SECRET)
+ optional: true
diff --git a/ta-generator/golden/git-clone/base.yaml b/ta-generator/golden/git-clone/base.yaml
new file mode 100644
index 0000000000..70817c33bc
--- /dev/null
+++ b/ta-generator/golden/git-clone/base.yaml
@@ -0,0 +1,313 @@
+---
+apiVersion: tekton.dev/v1
+kind: Task
+metadata:
+ name: git-clone
+ annotations:
+ tekton.dev/categories: Git
+ tekton.dev/displayName: git clone
+ tekton.dev/pipelines.minVersion: 0.21.0
+ tekton.dev/platforms: linux/amd64,linux/s390x,linux/ppc64le,linux/arm64
+ tekton.dev/tags: git
+ labels:
+ app.kubernetes.io/version: "0.1"
+spec:
+ description: |-
+ The git-clone Task will clone a repo from the provided url into the output Workspace. By default the repo will be cloned into the root of your Workspace.
+ params:
+ - description: Repository URL to clone from.
+ name: url
+ type: string
+ - default: ""
+ description: Revision to checkout. (branch, tag, sha, ref, etc...)
+ name: revision
+ type: string
+ - default: ""
+ description: Refspec to fetch before checking out revision.
+ name: refspec
+ type: string
+ - default: "true"
+ description: Initialize and fetch git submodules.
+ name: submodules
+ type: string
+ - default: "1"
+ description: Perform a shallow clone, fetching only the most recent
+ N commits.
+ name: depth
+ type: string
+ - default: "true"
+ description: Set the `http.sslVerify` global git config. Setting
+ this to `false` is not advised unless you are sure that you trust
+ your git remote.
+ name: sslVerify
+ type: string
+ - default: "source"
+ description: Subdirectory inside the `output` Workspace to clone
+ the repo into.
+ name: subdirectory
+ type: string
+ - default: ""
+ description: Define the directory patterns to match or exclude when
+ performing a sparse checkout.
+ name: sparseCheckoutDirectories
+ type: string
+ - default: "true"
+ description: Clean out the contents of the destination directory
+ if it already exists before cloning.
+ name: deleteExisting
+ type: string
+ - default: ""
+ description: HTTP proxy server for non-SSL requests.
+ name: httpProxy
+ type: string
+ - default: ""
+ description: HTTPS proxy server for SSL requests.
+ name: httpsProxy
+ type: string
+ - default: ""
+ description: Opt out of proxying HTTP/HTTPS requests.
+ name: noProxy
+ type: string
+ - default: "false"
+ description: Log the commands that are executed during `git-clone`'s
+ operation.
+ name: verbose
+ type: string
+ - default: ""
+ description: Deprecated. Has no effect. Will be removed in the future.
+ name: gitInitImage
+ type: string
+ - default: /tekton/home
+ description: |
+ Absolute path to the user's home directory. Set this explicitly if you are running the image as a non-root user.
+ name: userHome
+ type: string
+ - default: "true"
+ description: |
+ Check symlinks in the repo. If they're pointing outside of the repo, the build will fail.
+ name: enableSymlinkCheck
+ type: string
+ - default: "false"
+ description: Fetch all tags for the repo.
+ name: fetchTags
+ type: string
+ - name: caTrustConfigMapName
+ type: string
+ description: The name of the ConfigMap to read CA bundle data from.
+ default: trusted-ca
+ - name: caTrustConfigMapKey
+ type: string
+ description: The name of the key in the ConfigMap that contains
+ the CA bundle data.
+ default: ca-bundle.crt
+ results:
+ - description: The precise commit SHA that was fetched by this Task.
+ name: commit
+ - description: The precise URL that was fetched by this Task.
+ name: url
+ volumes:
+ - name: trusted-ca
+ configMap:
+ name: $(params.caTrustConfigMapName)
+ items:
+ - key: $(params.caTrustConfigMapKey)
+ path: ca-bundle.crt
+ optional: true
+ workspaces:
+ - description: The git repo will be cloned onto the volume backing
+ this Workspace.
+ name: output
+ - description: |
+ A .ssh directory with private key, known_hosts, config, etc. Copied to
+ the user's home before git commands are executed. Used to authenticate
+ with the git remote when performing the clone. Binding a Secret to this
+ Workspace is strongly recommended over other volume types.
+ name: ssh-directory
+ optional: true
+ - description: |
+ A Workspace containing a .gitconfig and .git-credentials file or username and password.
+ These will be copied to the user's home before any git commands are run. Any
+ other files in this Workspace are ignored. It is strongly recommended
+ to use ssh-directory over basic-auth whenever possible and to bind a
+ Secret to this Workspace over other volume types.
+ name: basic-auth
+ optional: true
+ steps:
+ - name: clone
+ image: registry.redhat.io/openshift-pipelines/pipelines-git-init-rhel8:v1.8.2-8@sha256:a538c423e7a11aae6ae582a411fdb090936458075f99af4ce5add038bb6983e8
+ volumeMounts:
+ - name: trusted-ca
+ mountPath: /mnt/trusted-ca
+ readOnly: true
+ env:
+ - name: HOME
+ value: $(params.userHome)
+ - name: PARAM_URL
+ value: $(params.url)
+ - name: PARAM_REVISION
+ value: $(params.revision)
+ - name: PARAM_REFSPEC
+ value: $(params.refspec)
+ - name: PARAM_SUBMODULES
+ value: $(params.submodules)
+ - name: PARAM_DEPTH
+ value: $(params.depth)
+ - name: PARAM_SSL_VERIFY
+ value: $(params.sslVerify)
+ - name: PARAM_SUBDIRECTORY
+ value: $(params.subdirectory)
+ - name: PARAM_DELETE_EXISTING
+ value: $(params.deleteExisting)
+ - name: PARAM_HTTP_PROXY
+ value: $(params.httpProxy)
+ - name: PARAM_HTTPS_PROXY
+ value: $(params.httpsProxy)
+ - name: PARAM_NO_PROXY
+ value: $(params.noProxy)
+ - name: PARAM_VERBOSE
+ value: $(params.verbose)
+ - name: PARAM_SPARSE_CHECKOUT_DIRECTORIES
+ value: $(params.sparseCheckoutDirectories)
+ - name: PARAM_USER_HOME
+ value: $(params.userHome)
+ - name: PARAM_FETCH_TAGS
+ value: $(params.fetchTags)
+ - name: PARAM_GIT_INIT_IMAGE
+ value: $(params.gitInitImage)
+ - name: WORKSPACE_OUTPUT_PATH
+ value: $(workspaces.output.path)
+ - name: WORKSPACE_SSH_DIRECTORY_BOUND
+ value: $(workspaces.ssh-directory.bound)
+ - name: WORKSPACE_SSH_DIRECTORY_PATH
+ value: $(workspaces.ssh-directory.path)
+ - name: WORKSPACE_BASIC_AUTH_DIRECTORY_BOUND
+ value: $(workspaces.basic-auth.bound)
+ - name: WORKSPACE_BASIC_AUTH_DIRECTORY_PATH
+ value: $(workspaces.basic-auth.path)
+ script: |
+ #!/usr/bin/env sh
+ set -eu
+
+ if [ "${PARAM_VERBOSE}" = "true" ]; then
+ set -x
+ fi
+
+ if [ -n "${PARAM_GIT_INIT_IMAGE}" ]; then
+ echo "WARNING: provided deprecated gitInitImage parameter has no effect."
+ fi
+
+ if [ "${WORKSPACE_BASIC_AUTH_DIRECTORY_BOUND}" = "true" ]; then
+ if [ -f "${WORKSPACE_BASIC_AUTH_DIRECTORY_PATH}/.git-credentials" ] && [ -f "${WORKSPACE_BASIC_AUTH_DIRECTORY_PATH}/.gitconfig" ]; then
+ cp "${WORKSPACE_BASIC_AUTH_DIRECTORY_PATH}/.git-credentials" "${PARAM_USER_HOME}/.git-credentials"
+ cp "${WORKSPACE_BASIC_AUTH_DIRECTORY_PATH}/.gitconfig" "${PARAM_USER_HOME}/.gitconfig"
+ # Compatibility with kubernetes.io/basic-auth secrets
+ elif [ -f "${WORKSPACE_BASIC_AUTH_DIRECTORY_PATH}/username" ] && [ -f "${WORKSPACE_BASIC_AUTH_DIRECTORY_PATH}/password" ]; then
+ HOSTNAME=$(echo $PARAM_URL | awk -F/ '{print $3}')
+ echo "https://$(cat ${WORKSPACE_BASIC_AUTH_DIRECTORY_PATH}/username):$(cat ${WORKSPACE_BASIC_AUTH_DIRECTORY_PATH}/password)@$HOSTNAME" >"${PARAM_USER_HOME}/.git-credentials"
+ echo -e "[credential \"https://$HOSTNAME\"]\n helper = store" >"${PARAM_USER_HOME}/.gitconfig"
+ else
+ echo "Unknown basic-auth workspace format"
+ exit 1
+ fi
+ chmod 400 "${PARAM_USER_HOME}/.git-credentials"
+ chmod 400 "${PARAM_USER_HOME}/.gitconfig"
+ fi
+
+ # Should be called after the gitconfig is copied from the repository secret
+ ca_bundle=/mnt/trusted-ca/ca-bundle.crt
+ if [ -f "$ca_bundle" ]; then
+ echo "INFO: Using mounted CA bundle: $ca_bundle"
+ git config --global http.sslCAInfo "$ca_bundle"
+ fi
+
+ if [ "${WORKSPACE_SSH_DIRECTORY_BOUND}" = "true" ]; then
+ cp -R "${WORKSPACE_SSH_DIRECTORY_PATH}" "${PARAM_USER_HOME}"/.ssh
+ chmod 700 "${PARAM_USER_HOME}"/.ssh
+ chmod -R 400 "${PARAM_USER_HOME}"/.ssh/*
+ fi
+
+ CHECKOUT_DIR="${WORKSPACE_OUTPUT_PATH}/${PARAM_SUBDIRECTORY}"
+
+ cleandir() {
+ # Delete any existing contents of the repo directory if it exists.
+ #
+ # We don't just "rm -rf ${CHECKOUT_DIR}" because ${CHECKOUT_DIR} might be "/"
+ # or the root of a mounted volume.
+ if [ -d "${CHECKOUT_DIR}" ]; then
+ # Delete non-hidden files and directories
+ rm -rf "${CHECKOUT_DIR:?}"/*
+ # Delete files and directories starting with . but excluding ..
+ rm -rf "${CHECKOUT_DIR}"/.[!.]*
+ # Delete files and directories starting with .. plus any other character
+ rm -rf "${CHECKOUT_DIR}"/..?*
+ fi
+ }
+
+ if [ "${PARAM_DELETE_EXISTING}" = "true" ]; then
+ cleandir
+ fi
+
+ test -z "${PARAM_HTTP_PROXY}" || export HTTP_PROXY="${PARAM_HTTP_PROXY}"
+ test -z "${PARAM_HTTPS_PROXY}" || export HTTPS_PROXY="${PARAM_HTTPS_PROXY}"
+ test -z "${PARAM_NO_PROXY}" || export NO_PROXY="${PARAM_NO_PROXY}"
+
+ /ko-app/git-init \
+ -url="${PARAM_URL}" \
+ -revision="${PARAM_REVISION}" \
+ -refspec="${PARAM_REFSPEC}" \
+ -path="${CHECKOUT_DIR}" \
+ -sslVerify="${PARAM_SSL_VERIFY}" \
+ -submodules="${PARAM_SUBMODULES}" \
+ -depth="${PARAM_DEPTH}" \
+ -sparseCheckoutDirectories="${PARAM_SPARSE_CHECKOUT_DIRECTORIES}"
+ cd "${CHECKOUT_DIR}"
+ RESULT_SHA="$(git rev-parse HEAD)"
+ EXIT_CODE="$?"
+ if [ "${EXIT_CODE}" != 0 ]; then
+ exit "${EXIT_CODE}"
+ fi
+ printf "%s" "${RESULT_SHA}" >"$(results.commit.path)"
+ printf "%s" "${PARAM_URL}" >"$(results.url.path)"
+
+ if [ "${PARAM_FETCH_TAGS}" = "true" ]; then
+ echo "Fetching tags"
+ git fetch --tags
+ fi
+ computeResources: {}
+ securityContext:
+ runAsUser: 0
+ - name: symlink-check
+ image: registry.redhat.io/ubi9:9.2-696@sha256:089bd3b82a78ac45c0eed231bb58bfb43bfcd0560d9bba240fc6355502c92976
+ # per https://kubernetes.io/docs/concepts/containers/images/#imagepullpolicy-defaulting
+ # the cluster will set imagePullPolicy to IfNotPresent
+ env:
+ - name: PARAM_ENABLE_SYMLINK_CHECK
+ value: $(params.enableSymlinkCheck)
+ - name: PARAM_SUBDIRECTORY
+ value: $(params.subdirectory)
+ - name: WORKSPACE_OUTPUT_PATH
+ value: $(workspaces.output.path)
+ script: |
+ #!/usr/bin/env bash
+ set -euo pipefail
+
+ CHECKOUT_DIR="${WORKSPACE_OUTPUT_PATH}/${PARAM_SUBDIRECTORY}"
+ check_symlinks() {
+ FOUND_SYMLINK_POINTING_OUTSIDE_OF_REPO=false
+ while read symlink; do
+ target=$(readlink -f "$symlink")
+ if ! [[ "$target" =~ ^$CHECKOUT_DIR ]]; then
+ echo "The cloned repository contains symlink pointing outside of the cloned repository: $symlink"
+ FOUND_SYMLINK_POINTING_OUTSIDE_OF_REPO=true
+ fi
+ done < <(find $CHECKOUT_DIR -type l -print)
+ if [ "$FOUND_SYMLINK_POINTING_OUTSIDE_OF_REPO" = true ]; then
+ return 1
+ fi
+ }
+
+ if [ "${PARAM_ENABLE_SYMLINK_CHECK}" = "true" ]; then
+ echo "Running symlink check"
+ check_symlinks
+ fi
+ computeResources: {}
diff --git a/ta-generator/golden/git-clone/recipe.yaml b/ta-generator/golden/git-clone/recipe.yaml
new file mode 100644
index 0000000000..7f5ed5b512
--- /dev/null
+++ b/ta-generator/golden/git-clone/recipe.yaml
@@ -0,0 +1,14 @@
+---
+removeParams:
+ - gitInitImage
+ - deleteExisting
+ - subdirectory
+addEnvironment:
+ - name: CHECKOUT_DIR
+ value: /var/workdir/source
+add:
+ - create-source
+removeWorkspaces:
+ - output
+description: The git-clone-oci-ta Task will clone a repo from the provided url and store it as a trusted
+ artifact in the provided OCI repository.
diff --git a/ta-generator/golden/git-clone/ta.yaml b/ta-generator/golden/git-clone/ta.yaml
new file mode 100644
index 0000000000..40c71aa88e
--- /dev/null
+++ b/ta-generator/golden/git-clone/ta.yaml
@@ -0,0 +1,292 @@
+---
+apiVersion: tekton.dev/v1
+kind: Task
+metadata:
+ labels:
+ app.kubernetes.io/version: "0.1"
+ annotations:
+ tekton.dev/categories: Git
+ tekton.dev/displayName: git clone oci trusted artifacts
+ tekton.dev/pipelines.minVersion: 0.21.0
+ tekton.dev/platforms: linux/amd64,linux/s390x,linux/ppc64le,linux/arm64
+ tekton.dev/tags: git
+ name: git-clone-oci-ta
+spec:
+ description: >-
+ The git-clone-oci-ta Task will clone a repo from the provided url and store it as a trusted
+ artifact in the provided OCI repository.
+ params:
+ - description: Repository URL to clone from.
+ name: url
+ type: string
+ - default: ""
+ description: Revision to checkout. (branch, tag, sha, ref, etc...)
+ name: revision
+ type: string
+ - default: ""
+ description: Refspec to fetch before checking out revision.
+ name: refspec
+ type: string
+ - default: "true"
+ description: Initialize and fetch git submodules.
+ name: submodules
+ type: string
+ - default: "1"
+ description: Perform a shallow clone, fetching only the most recent N commits.
+ name: depth
+ type: string
+ - default: "true"
+ description: Set the `http.sslVerify` global git config. Setting this to `false` is not advised unless you are sure that you trust your git remote.
+ name: sslVerify
+ type: string
+ - default: ""
+ description: Define the directory patterns to match or exclude when performing a sparse checkout.
+ name: sparseCheckoutDirectories
+ type: string
+ - default: ""
+ description: HTTP proxy server for non-SSL requests.
+ name: httpProxy
+ type: string
+ - default: ""
+ description: HTTPS proxy server for SSL requests.
+ name: httpsProxy
+ type: string
+ - default: ""
+ description: Opt out of proxying HTTP/HTTPS requests.
+ name: noProxy
+ type: string
+ - default: "false"
+ description: Log the commands that are executed during `git-clone`'s operation.
+ name: verbose
+ type: string
+ - default: /tekton/home
+ description: |
+ Absolute path to the user's home directory. Set this explicitly if you are running the image as a non-root user.
+ name: userHome
+ type: string
+ - default: "true"
+ description: |
+ Check symlinks in the repo. If they're pointing outside of the repo, the build will fail.
+ name: enableSymlinkCheck
+ type: string
+ - default: "false"
+ description: Fetch all tags for the repo.
+ name: fetchTags
+ type: string
+ - name: caTrustConfigMapName
+ type: string
+ description: The name of the ConfigMap to read CA bundle data from.
+ default: trusted-ca
+ - name: caTrustConfigMapKey
+ type: string
+ description: The name of the key in the ConfigMap that contains the CA bundle data.
+ default: ca-bundle.crt
+ - name: ociStorage
+ type: string
+ description: The OCI repository where the Trusted Artifacts are stored.
+ - name: ociArtifactExpiresAfter
+ type: string
+ description: >-
+ Expiration date for the trusted artifacts created in the OCI repository. An empty string means
+ the artifacts do not expire.
+ default: ""
+
+ results:
+ - description: The precise commit SHA that was fetched by this Task.
+ name: commit
+ - description: The precise URL that was fetched by this Task.
+ name: url
+ - description: The Trusted Artifact URI pointing to the artifact with the application source code.
+ name: SOURCE_ARTIFACT
+ type: string
+ steps:
+ - name: clone
+ env:
+ - name: HOME
+ value: $(params.userHome)
+ - name: PARAM_URL
+ value: $(params.url)
+ - name: PARAM_REVISION
+ value: $(params.revision)
+ - name: PARAM_REFSPEC
+ value: $(params.refspec)
+ - name: PARAM_SUBMODULES
+ value: $(params.submodules)
+ - name: PARAM_DEPTH
+ value: $(params.depth)
+ - name: PARAM_SSL_VERIFY
+ value: $(params.sslVerify)
+ - name: PARAM_HTTP_PROXY
+ value: $(params.httpProxy)
+ - name: PARAM_HTTPS_PROXY
+ value: $(params.httpsProxy)
+ - name: PARAM_NO_PROXY
+ value: $(params.noProxy)
+ - name: PARAM_VERBOSE
+ value: $(params.verbose)
+ - name: PARAM_SPARSE_CHECKOUT_DIRECTORIES
+ value: $(params.sparseCheckoutDirectories)
+ - name: PARAM_USER_HOME
+ value: $(params.userHome)
+ - name: PARAM_FETCH_TAGS
+ value: $(params.fetchTags)
+ - name: WORKSPACE_SSH_DIRECTORY_BOUND
+ value: $(workspaces.ssh-directory.bound)
+ - name: WORKSPACE_SSH_DIRECTORY_PATH
+ value: $(workspaces.ssh-directory.path)
+ - name: WORKSPACE_BASIC_AUTH_DIRECTORY_BOUND
+ value: $(workspaces.basic-auth.bound)
+ - name: WORKSPACE_BASIC_AUTH_DIRECTORY_PATH
+ value: $(workspaces.basic-auth.path)
+ - name: CHECKOUT_DIR
+ value: /var/workdir/source
+ image: registry.redhat.io/openshift-pipelines/pipelines-git-init-rhel8:v1.8.2-8@sha256:a538c423e7a11aae6ae582a411fdb090936458075f99af4ce5add038bb6983e8
+ computeResources: {}
+ securityContext:
+ runAsUser: 0
+ volumeMounts:
+ - name: trusted-ca
+ mountPath: /mnt/trusted-ca
+ readOnly: true
+ - name: workdir
+ mountPath: /var/workdir
+ script: |
+ #!/usr/bin/env sh
+ set -eu
+
+ if [ "${PARAM_VERBOSE}" = "true" ] ; then
+ set -x
+ fi
+
+ if [ "${WORKSPACE_BASIC_AUTH_DIRECTORY_BOUND}" = "true" ] ; then
+ if [ -f "${WORKSPACE_BASIC_AUTH_DIRECTORY_PATH}/.git-credentials" ] && [ -f "${WORKSPACE_BASIC_AUTH_DIRECTORY_PATH}/.gitconfig" ]; then
+ cp "${WORKSPACE_BASIC_AUTH_DIRECTORY_PATH}/.git-credentials" "${PARAM_USER_HOME}/.git-credentials"
+ cp "${WORKSPACE_BASIC_AUTH_DIRECTORY_PATH}/.gitconfig" "${PARAM_USER_HOME}/.gitconfig"
+ # Compatibility with kubernetes.io/basic-auth secrets
+ elif [ -f "${WORKSPACE_BASIC_AUTH_DIRECTORY_PATH}/username" ] && [ -f "${WORKSPACE_BASIC_AUTH_DIRECTORY_PATH}/password" ]; then
+ HOSTNAME=$(echo $PARAM_URL | awk -F/ '{print $3}')
+ echo "https://$(cat ${WORKSPACE_BASIC_AUTH_DIRECTORY_PATH}/username):$(cat ${WORKSPACE_BASIC_AUTH_DIRECTORY_PATH}/password)@$HOSTNAME" > "${PARAM_USER_HOME}/.git-credentials"
+ echo -e "[credential \"https://$HOSTNAME\"]\n helper = store" > "${PARAM_USER_HOME}/.gitconfig"
+ else
+ echo "Unknown basic-auth workspace format"
+ exit 1
+ fi
+ chmod 400 "${PARAM_USER_HOME}/.git-credentials"
+ chmod 400 "${PARAM_USER_HOME}/.gitconfig"
+ fi
+
+ # Should be called after the gitconfig is copied from the repository secret
+ ca_bundle=/mnt/trusted-ca/ca-bundle.crt
+ if [ -f "$ca_bundle" ]; then
+ echo "INFO: Using mounted CA bundle: $ca_bundle"
+ git config --global http.sslCAInfo "$ca_bundle"
+ fi
+
+ if [ "${WORKSPACE_SSH_DIRECTORY_BOUND}" = "true" ] ; then
+ cp -R "${WORKSPACE_SSH_DIRECTORY_PATH}" "${PARAM_USER_HOME}"/.ssh
+ chmod 700 "${PARAM_USER_HOME}"/.ssh
+ chmod -R 400 "${PARAM_USER_HOME}"/.ssh/*
+ fi
+
+ test -z "${PARAM_HTTP_PROXY}" || export HTTP_PROXY="${PARAM_HTTP_PROXY}"
+ test -z "${PARAM_HTTPS_PROXY}" || export HTTPS_PROXY="${PARAM_HTTPS_PROXY}"
+ test -z "${PARAM_NO_PROXY}" || export NO_PROXY="${PARAM_NO_PROXY}"
+
+ /ko-app/git-init \
+ -url="${PARAM_URL}" \
+ -revision="${PARAM_REVISION}" \
+ -refspec="${PARAM_REFSPEC}" \
+ -path="${CHECKOUT_DIR}" \
+ -sslVerify="${PARAM_SSL_VERIFY}" \
+ -submodules="${PARAM_SUBMODULES}" \
+ -depth="${PARAM_DEPTH}" \
+ -sparseCheckoutDirectories="${PARAM_SPARSE_CHECKOUT_DIRECTORIES}"
+ cd "${CHECKOUT_DIR}"
+ RESULT_SHA="$(git rev-parse HEAD)"
+ EXIT_CODE="$?"
+ if [ "${EXIT_CODE}" != 0 ] ; then
+ exit "${EXIT_CODE}"
+ fi
+ printf "%s" "${RESULT_SHA}" > "$(results.commit.path)"
+ printf "%s" "${PARAM_URL}" > "$(results.url.path)"
+
+ if [ "${PARAM_FETCH_TAGS}" = "true" ] ; then
+ echo "Fetching tags"
+ git fetch --tags
+ fi
+
+ - name: symlink-check
+ image: registry.redhat.io/ubi9:9.2-696@sha256:089bd3b82a78ac45c0eed231bb58bfb43bfcd0560d9bba240fc6355502c92976
+ env:
+ - name: PARAM_ENABLE_SYMLINK_CHECK
+ value: $(params.enableSymlinkCheck)
+ - name: CHECKOUT_DIR
+ value: /var/workdir/source
+ volumeMounts:
+ - name: workdir
+ mountPath: /var/workdir
+ computeResources: {}
+ script: |
+ #!/usr/bin/env bash
+ set -euo pipefail
+
+ check_symlinks() {
+ FOUND_SYMLINK_POINTING_OUTSIDE_OF_REPO=false
+ while read symlink
+ do
+ target=$(readlink -f "$symlink")
+ if ! [[ "$target" =~ ^$CHECKOUT_DIR ]]; then
+ echo "The cloned repository contains symlink pointing outside of the cloned repository: $symlink"
+ FOUND_SYMLINK_POINTING_OUTSIDE_OF_REPO=true
+ fi
+ done < <(find $CHECKOUT_DIR -type l -print)
+ if [ "$FOUND_SYMLINK_POINTING_OUTSIDE_OF_REPO" = true ] ; then
+ return 1
+ fi
+ }
+
+ if [ "${PARAM_ENABLE_SYMLINK_CHECK}" = "true" ] ; then
+ echo "Running symlink check"
+ check_symlinks
+ fi
+
+ - name: create-trusted-artifact
+ image: quay.io/redhat-appstudio/build-trusted-artifacts:latest@sha256:existing
+ env:
+ - name: IMAGE_EXPIRES_AFTER
+ value: $(params.ociArtifactExpiresAfter)
+ volumeMounts:
+ - name: workdir
+ mountPath: /var/workdir
+ args:
+ - create
+ - --store
+ - $(params.ociStorage)
+ - $(results.SOURCE_ARTIFACT.path)=/var/workdir/source
+
+ workspaces:
+ - description: |
+ A .ssh directory with private key, known_hosts, config, etc. Copied to
+ the user's home before git commands are executed. Used to authenticate
+ with the git remote when performing the clone. Binding a Secret to this
+ Workspace is strongly recommended over other volume types.
+ name: ssh-directory
+ optional: true
+ - description: |
+ A Workspace containing a .gitconfig and .git-credentials file or username and password.
+ These will be copied to the user's home before any git commands are run. Any
+ other files in this Workspace are ignored. It is strongly recommended
+ to use ssh-directory over basic-auth whenever possible and to bind a
+ Secret to this Workspace over other volume types.
+ name: basic-auth
+ optional: true
+ volumes:
+ - name: workdir
+ emptyDir: {}
+ - name: trusted-ca
+ configMap:
+ name: $(params.caTrustConfigMapName)
+ items:
+ - key: $(params.caTrustConfigMapKey)
+ path: ca-bundle.crt
+ optional: true
diff --git a/ta-generator/golden/prefetch-dependencies/base.yaml b/ta-generator/golden/prefetch-dependencies/base.yaml
new file mode 100644
index 0000000000..0161463fb2
--- /dev/null
+++ b/ta-generator/golden/prefetch-dependencies/base.yaml
@@ -0,0 +1,122 @@
+apiVersion: tekton.dev/v1
+kind: Task
+metadata:
+ labels:
+ app.kubernetes.io/version: "0.1"
+ annotations:
+ tekton.dev/pipelines.minVersion: "0.12.1"
+ tekton.dev/tags: "image-build, hacbs"
+ name: prefetch-dependencies
+spec:
+ description: |-
+ Task that uses Cachi2 to prefetch build dependencies.
+ See docs at https://github.com/containerbuildsystem/cachi2#basic-usage.
+ params:
+ - description: Configures project packages that will have their dependencies prefetched.
+ name: input
+ - description: >
+ Enable in-development package managers. WARNING: the behavior may change at any time without
+ notice. Use at your own risk.
+ name: dev-package-managers
+ default: "false"
+ - description: Set cachi2 log level (debug, info, warning, error)
+ name: log-level
+ default: "info"
+ - name: caTrustConfigMapName
+ type: string
+ description: The name of the ConfigMap to read CA bundle data from.
+ default: trusted-ca
+ - name: caTrustConfigMapKey
+ type: string
+ description: The name of the key in the ConfigMap that contains the CA bundle data.
+ default: ca-bundle.crt
+ steps:
+ - image: quay.io/redhat-appstudio/cachi2:0.7.0@sha256:1fc772aa3636fd0b43d62120d832e5913843e028e8cac42814b487c3a0a32bd8
+ # per https://kubernetes.io/docs/concepts/containers/images/#imagepullpolicy-defaulting
+ # the cluster will set imagePullPolicy to IfNotPresent
+ name: prefetch-dependencies
+ env:
+ - name: INPUT
+ value: $(params.input)
+ - name: DEV_PACKAGE_MANAGERS
+ value: $(params.dev-package-managers)
+ - name: LOG_LEVEL
+ value: $(params.log-level)
+ - name: WORKSPACE_GIT_AUTH_BOUND
+ value: $(workspaces.git-basic-auth.bound)
+ - name: WORKSPACE_GIT_AUTH_PATH
+ value: $(workspaces.git-basic-auth.path)
+ volumeMounts:
+ - name: trusted-ca
+ mountPath: /mnt/trusted-ca
+ readOnly: true
+ script: |
+ if [ -z "${INPUT}" ]
+ then
+ # Confirm input was provided though it's likely the whole task would be skipped if it wasn't
+ echo "No prefetch will be performed because no input was provided for cachi2 fetch-deps"
+ exit 0
+ fi
+
+ if [ "$DEV_PACKAGE_MANAGERS" = "true" ]; then
+ dev_pacman_flag=--dev-package-managers
+ else
+ dev_pacman_flag=""
+ fi
+
+ # Copied from https://github.com/konflux-ci/build-definitions/blob/main/task/git-clone/0.1/git-clone.yaml
+ if [ "${WORKSPACE_GIT_AUTH_BOUND}" = "true" ] ; then
+ if [ -f "${WORKSPACE_GIT_AUTH_PATH}/.git-credentials" ] && [ -f "${WORKSPACE_GIT_AUTH_PATH}/.gitconfig" ]; then
+ cp "${WORKSPACE_GIT_AUTH_PATH}/.git-credentials" "${HOME}/.git-credentials"
+ cp "${WORKSPACE_GIT_AUTH_PATH}/.gitconfig" "${HOME}/.gitconfig"
+ # Compatibility with kubernetes.io/basic-auth secrets
+ elif [ -f "${WORKSPACE_GIT_AUTH_PATH}/username" ] && [ -f "${WORKSPACE_GIT_AUTH_PATH}/password" ]; then
+ HOSTNAME=$(cd "$(workspaces.source.path)/source" && git remote get-url origin | awk -F/ '{print $3}')
+ echo "https://$(cat ${WORKSPACE_GIT_AUTH_PATH}/username):$(cat ${WORKSPACE_GIT_AUTH_PATH}/password)@$HOSTNAME" > "${HOME}/.git-credentials"
+ echo -e "[credential \"https://$HOSTNAME\"]\n helper = store" > "${HOME}/.gitconfig"
+ else
+ echo "Unknown git-basic-auth workspace format"
+ exit 1
+ fi
+ chmod 400 "${HOME}/.git-credentials"
+ chmod 400 "${HOME}/.gitconfig"
+ fi
+
+ ca_bundle=/mnt/trusted-ca/ca-bundle.crt
+ if [ -f "$ca_bundle" ]; then
+ echo "INFO: Using mounted CA bundle: $ca_bundle"
+ cp -vf $ca_bundle /etc/pki/ca-trust/source/anchors
+ update-ca-trust
+ fi
+
+ cachi2 --log-level="$LOG_LEVEL" fetch-deps \
+ $dev_pacman_flag \
+ --source=$(workspaces.source.path)/source \
+ --output=$(workspaces.source.path)/cachi2/output \
+ "${INPUT}"
+
+ cachi2 --log-level="$LOG_LEVEL" generate-env $(workspaces.source.path)/cachi2/output \
+ --format env \
+ --for-output-dir=/cachi2/output \
+ --output $(workspaces.source.path)/cachi2/cachi2.env
+
+ cachi2 --log-level="$LOG_LEVEL" inject-files $(workspaces.source.path)/cachi2/output \
+ --for-output-dir=/cachi2/output
+ workspaces:
+ - name: source
+ description: Workspace with the source code, cachi2 artifacts will be stored on the workspace as well
+ - name: git-basic-auth
+ description: |
+ A Workspace containing a .gitconfig and .git-credentials file or username and password.
+ These will be copied to the user's home before any cachi2 commands are run. Any
+ other files in this Workspace are ignored. It is strongly recommended
+ to bind a Secret to this Workspace over other volume types.
+ optional: true
+ volumes:
+ - name: trusted-ca
+ configMap:
+ name: $(params.caTrustConfigMapName)
+ items:
+ - key: $(params.caTrustConfigMapKey)
+ path: ca-bundle.crt
+ optional: true
diff --git a/ta-generator/golden/prefetch-dependencies/recipe.yaml b/ta-generator/golden/prefetch-dependencies/recipe.yaml
new file mode 100644
index 0000000000..61c40b7382
--- /dev/null
+++ b/ta-generator/golden/prefetch-dependencies/recipe.yaml
@@ -0,0 +1,33 @@
+---
+add:
+ - use-source
+ - create-source
+ - create-cachi2
+additionalSteps:
+ - at: 0
+ name: skip-ta
+ image: registry.access.redhat.com/ubi9/ubi-minimal:9.3-1612@sha256:119ac25920c8bb50c8b5fd75dcbca369bf7d1f702b82f3d39663307890f0bf26
+ env:
+ - name: INPUT
+ value: $(params.input)
+ - name: SOURCE_ARTIFACT
+ value: $(params.SOURCE_ARTIFACT)
+ script: |
+ if [ -z "${INPUT}" ]; then
+ mkdir -p /var/workdir/source
+ mkdir -p /var/workdir/cachi2
+ echo "true" > /var/workdir/source/.skip-trusted-artifacts
+ echo "true" > /var/workdir/cachi2/.skip-trusted-artifacts
+ echo -n "${SOURCE_ARTIFACT}" > $(results.SOURCE_ARTIFACT.path)
+ echo -n "" > $(results.CACHI2_ARTIFACT.path)
+ fi
+description: |-
+ Task that uses Cachi2 to prefetch build dependencies. The fetched dependencies and the
+ application source code are stored as a trusted artifact in the provided OCI repository.
+ For additional info on Cachi2, see docs at
+ https://github.com/containerbuildsystem/cachi2#basic-usage.
+preferStepTemplate: true
+removeWorkspaces:
+ - source
+replacements:
+ workspaces.source.path: /var/workdir
diff --git a/ta-generator/golden/prefetch-dependencies/ta.yaml b/ta-generator/golden/prefetch-dependencies/ta.yaml
new file mode 100644
index 0000000000..cc100cda23
--- /dev/null
+++ b/ta-generator/golden/prefetch-dependencies/ta.yaml
@@ -0,0 +1,178 @@
+---
+apiVersion: tekton.dev/v1
+kind: Task
+metadata:
+ labels:
+ app.kubernetes.io/version: "0.1"
+ annotations:
+ tekton.dev/pipelines.minVersion: "0.12.1"
+ tekton.dev/tags: "image-build, hacbs"
+ name: prefetch-dependencies-oci-ta
+spec:
+ description: |-
+ Task that uses Cachi2 to prefetch build dependencies. The fetched dependencies and the
+ application source code are stored as a trusted artifact in the provided OCI repository.
+ For additional info on Cachi2, see docs at
+ https://github.com/containerbuildsystem/cachi2#basic-usage.
+ params:
+ - description: Configures project packages that will have their dependencies prefetched.
+ name: input
+ - description: The Trusted Artifact URI pointing to the artifact with the application source code.
+ name: SOURCE_ARTIFACT
+ type: string
+ - description: The OCI repository where the Trusted Artifacts are stored.
+ name: ociStorage
+ type: string
+ - description: >-
+ Expiration date for the trusted artifacts created in the OCI repository. An empty string means
+ the artifacts do not expire.
+ name: ociArtifactExpiresAfter
+ type: string
+ default: ""
+ - description: >
+ Enable in-development package managers. WARNING: the behavior may change at any time without
+ notice. Use at your own risk.
+ name: dev-package-managers
+ default: "false"
+ - description: Set cachi2 log level (debug, info, warning, error)
+ name: log-level
+ default: "info"
+ - name: caTrustConfigMapName
+ type: string
+ description: The name of the ConfigMap to read CA bundle data from.
+ default: trusted-ca
+ - name: caTrustConfigMapKey
+ type: string
+ description: The name of the key in the ConfigMap that contains the CA bundle data.
+ default: ca-bundle.crt
+ results:
+ - description: The Trusted Artifact URI pointing to the artifact with the application source code.
+ name: SOURCE_ARTIFACT
+ type: string
+ - description: The Trusted Artifact URI pointing to the artifact with the prefetched dependencies.
+ name: CACHI2_ARTIFACT
+ type: string
+ stepTemplate:
+ volumeMounts:
+ - mountPath: /var/workdir
+ name: workdir
+ steps:
+ - name: skip-ta
+ image: registry.access.redhat.com/ubi9/ubi-minimal:9.3-1612@sha256:119ac25920c8bb50c8b5fd75dcbca369bf7d1f702b82f3d39663307890f0bf26
+ env:
+ - name: INPUT
+ value: $(params.input)
+ - name: SOURCE_ARTIFACT
+ value: $(params.SOURCE_ARTIFACT)
+ script: |
+ if [ -z "${INPUT}" ]; then
+ mkdir -p /var/workdir/source
+ mkdir -p /var/workdir/cachi2
+ echo "true" > /var/workdir/source/.skip-trusted-artifacts
+ echo "true" > /var/workdir/cachi2/.skip-trusted-artifacts
+ echo -n "${SOURCE_ARTIFACT}" > $(results.SOURCE_ARTIFACT.path)
+ echo -n "" > $(results.CACHI2_ARTIFACT.path)
+ fi
+ - image: quay.io/redhat-appstudio/build-trusted-artifacts:latest@sha256:placeholder
+ name: use-trusted-artifact
+ args:
+ - use
+ - $(params.SOURCE_ARTIFACT)=/var/workdir/source
+ - image: quay.io/redhat-appstudio/cachi2:0.7.0@sha256:1fc772aa3636fd0b43d62120d832e5913843e028e8cac42814b487c3a0a32bd8
+ name: prefetch-dependencies
+ env:
+ - name: INPUT
+ value: $(params.input)
+ - name: DEV_PACKAGE_MANAGERS
+ value: $(params.dev-package-managers)
+ - name: LOG_LEVEL
+ value: $(params.log-level)
+ - name: WORKSPACE_GIT_AUTH_BOUND
+ value: $(workspaces.git-basic-auth.bound)
+ - name: WORKSPACE_GIT_AUTH_PATH
+ value: $(workspaces.git-basic-auth.path)
+ volumeMounts:
+ - name: trusted-ca
+ mountPath: /mnt/trusted-ca
+ readOnly: true
+ script: |
+ if [ -z "${INPUT}" ]
+ then
+ # Confirm input was provided though it's likely the whole task would be skipped if it wasn't
+ echo "No prefetch will be performed because no input was provided for cachi2 fetch-deps"
+ exit 0
+ fi
+
+ if [ "$DEV_PACKAGE_MANAGERS" = "true" ]; then
+ dev_pacman_flag=--dev-package-managers
+ else
+ dev_pacman_flag=""
+ fi
+
+ # Copied from https://github.com/konflux-ci/build-definitions/blob/main/task/git-clone/0.1/git-clone.yaml
+ if [ "${WORKSPACE_GIT_AUTH_BOUND}" = "true" ] ; then
+ if [ -f "${WORKSPACE_GIT_AUTH_PATH}/.git-credentials" ] && [ -f "${WORKSPACE_GIT_AUTH_PATH}/.gitconfig" ]; then
+ cp "${WORKSPACE_GIT_AUTH_PATH}/.git-credentials" "${HOME}/.git-credentials"
+ cp "${WORKSPACE_GIT_AUTH_PATH}/.gitconfig" "${HOME}/.gitconfig"
+ # Compatibility with kubernetes.io/basic-auth secrets
+ elif [ -f "${WORKSPACE_GIT_AUTH_PATH}/username" ] && [ -f "${WORKSPACE_GIT_AUTH_PATH}/password" ]; then
+ HOSTNAME=$(cd "/var/workdir/source" && git remote get-url origin | awk -F/ '{print $3}')
+ echo "https://$(cat ${WORKSPACE_GIT_AUTH_PATH}/username):$(cat ${WORKSPACE_GIT_AUTH_PATH}/password)@$HOSTNAME" > "${HOME}/.git-credentials"
+ echo -e "[credential \"https://$HOSTNAME\"]\n helper = store" > "${HOME}/.gitconfig"
+ else
+ echo "Unknown git-basic-auth workspace format"
+ exit 1
+ fi
+ chmod 400 "${HOME}/.git-credentials"
+ chmod 400 "${HOME}/.gitconfig"
+ fi
+
+ ca_bundle=/mnt/trusted-ca/ca-bundle.crt
+ if [ -f "$ca_bundle" ]; then
+ echo "INFO: Using mounted CA bundle: $ca_bundle"
+ cp -vf $ca_bundle /etc/pki/ca-trust/source/anchors
+ update-ca-trust
+ fi
+
+ cachi2 --log-level="$LOG_LEVEL" fetch-deps \
+ $dev_pacman_flag \
+ --source=/var/workdir/source \
+ --output=/var/workdir/cachi2/output \
+ "${INPUT}"
+
+ cachi2 --log-level="$LOG_LEVEL" generate-env /var/workdir/cachi2/output \
+ --format env \
+ --for-output-dir=/cachi2/output \
+ --output /var/workdir/cachi2/cachi2.env
+
+ cachi2 --log-level="$LOG_LEVEL" inject-files /var/workdir/cachi2/output \
+ --for-output-dir=/cachi2/output
+ - image: quay.io/redhat-appstudio/build-trusted-artifacts:latest@sha256:placeholder
+ name: create-trusted-artifact
+ env:
+ - name: IMAGE_EXPIRES_AFTER
+ value: $(params.ociArtifactExpiresAfter)
+ args:
+ - create
+ - --store
+ - $(params.ociStorage)
+ - $(results.SOURCE_ARTIFACT.path)=/var/workdir/source
+ - $(results.CACHI2_ARTIFACT.path)=/var/workdir/cachi2
+ workspaces:
+ - name: git-basic-auth
+ description: |
+ A Workspace containing a .gitconfig and .git-credentials file or username and password.
+ These will be copied to the user's home before any cachi2 commands are run. Any
+ other files in this Workspace are ignored. It is strongly recommended
+ to bind a Secret to this Workspace over other volume types.
+ optional: true
+ volumes:
+ - name: workdir
+ emptyDir: {}
+ - name: trusted-ca
+ configMap:
+ name: $(params.caTrustConfigMapName)
+ items:
+ - key: $(params.caTrustConfigMapKey)
+ path: ca-bundle.crt
+ optional: true
diff --git a/ta-generator/golden/sast-snyk-check/base.yaml b/ta-generator/golden/sast-snyk-check/base.yaml
new file mode 100644
index 0000000000..8894d28492
--- /dev/null
+++ b/ta-generator/golden/sast-snyk-check/base.yaml
@@ -0,0 +1,88 @@
+apiVersion: tekton.dev/v1
+kind: Task
+metadata:
+ labels:
+ app.kubernetes.io/version: "0.1"
+ annotations:
+ tekton.dev/pipelines.minVersion: "0.12.1"
+ tekton.dev/tags: "appstudio, hacbs"
+ name: sast-snyk-check
+spec:
+ description: >-
+ Scans source code for security vulnerabilities, including common issues such as SQL injection, cross-site scripting (XSS), and code injection attacks using Snyk Code, a Static Application Security Testing (SAST) tool.
+ results:
+ - description: Tekton task test output.
+ name: TEST_OUTPUT
+ params:
+ - name: SNYK_SECRET
+ description: Name of secret which contains Snyk token.
+ default: snyk-secret
+ - name: ARGS
+ type: string
+ description: Append arguments.
+ default: "--all-projects --exclude=test*,vendor,deps"
+ volumes:
+ - name: snyk-secret
+ secret:
+ secretName: $(params.SNYK_SECRET)
+ optional: true
+ steps:
+ - name: sast-snyk-check
+ image: quay.io/redhat-appstudio/konflux-test:v1.4.0@sha256:54d49b37c9a2e280d42961a57e4f7a16c171d6b065559f1329b548db85300bea
+ # per https://kubernetes.io/docs/concepts/containers/images/#imagepullpolicy-defaulting
+ # the cluster will set imagePullPolicy to IfNotPresent
+ workingDir: $(workspaces.workspace.path)/hacbs/$(context.task.name)
+ volumeMounts:
+ - name: snyk-secret
+ mountPath: "/etc/secrets"
+ readOnly: true
+ env:
+ - name: SNYK_SECRET
+ value: $(params.SNYK_SECRET)
+ - name: ARGS
+ value: $(params.ARGS)
+ script: |
+ #!/usr/bin/env bash
+ set -euo pipefail
+ . /utils.sh
+ trap 'handle_error $(results.TEST_OUTPUT.path)' EXIT
+
+ SNYK_TOKEN_PATH="/etc/secrets/snyk_token"
+
+ if [ -f "${SNYK_TOKEN_PATH}" ] && [ -s "${SNYK_TOKEN_PATH}" ]; then
+ # SNYK token is provided
+ SNYK_TOKEN="$(cat ${SNYK_TOKEN_PATH})"
+ export SNYK_TOKEN
+ else
+ to_enable_snyk='[here](https://redhat-appstudio.github.io/docs.appstudio.io/Documentation/main/how-to-guides/testing_applications/enable_snyk_check_for_a_product/)'
+ note="Task $(context.task.name) skipped: If you wish to use the Snyk code SAST task, please create a secret name snyk-secret with the key "snyk_token" containing the Snyk token by following the steps given ${to_enable_snyk}"
+ TEST_OUTPUT=$(make_result_json -r SKIPPED -t "$note")
+ echo "${TEST_OUTPUT}" | tee "$(results.TEST_OUTPUT.path)"
+ exit 0
+ fi
+
+ SNYK_EXIT_CODE=0
+ SOURCE_CODE_DIR=$(workspaces.workspace.path)/source
+ snyk code test $ARGS $SOURCE_CODE_DIR --sarif-file-output=sast_snyk_check_out.json 1>&2>> stdout.txt || SNYK_EXIT_CODE=$?
+ test_not_skipped=0
+ SKIP_MSG="We found 0 supported files"
+ grep -q "$SKIP_MSG" stdout.txt || test_not_skipped=$?
+
+ if [[ "$SNYK_EXIT_CODE" -eq 0 ]] || [[ "$SNYK_EXIT_CODE" -eq 1 ]]; then
+ cat sast_snyk_check_out.json
+ TEST_OUTPUT=
+ parse_test_output $(context.task.name) sarif sast_snyk_check_out.json || true
+
+ # When the test is skipped, the "SNYK_EXIT_CODE" is 3 and it can also be 3 in some other situation
+ elif [[ "$test_not_skipped" -eq 0 ]]; then
+ note="Task $(context.task.name) success: Snyk code test found zero supported files."
+ ERROR_OUTPUT=$(make_result_json -r SUCCESS -t "$note")
+ else
+ echo "sast-snyk-check test failed because of the following issues:"
+ cat stdout.txt
+ note="Task $(context.task.name) failed: For details, check Tekton task log."
+ ERROR_OUTPUT=$(make_result_json -r ERROR -t "$note")
+ fi
+ echo "${TEST_OUTPUT:-${ERROR_OUTPUT}}" | tee $(results.TEST_OUTPUT.path)
+ workspaces:
+ - name: workspace
diff --git a/ta-generator/golden/sast-snyk-check/recipe.yaml b/ta-generator/golden/sast-snyk-check/recipe.yaml
new file mode 100644
index 0000000000..3ac22ef99b
--- /dev/null
+++ b/ta-generator/golden/sast-snyk-check/recipe.yaml
@@ -0,0 +1,27 @@
+---
+add:
+ - use-source
+description: >-
+ Scans source code for security vulnerabilities, including common issues such as SQL injection,
+ cross-site scripting (XSS), and code injection attacks using Snyk Code, a Static Application
+ Security Testing (SAST) tool.
+
+
+ Follow the steps given
+ [here](https://redhat-appstudio.github.io/docs.appstudio.io/Documentation/main/how-to-guides/testing_applications/enable_snyk_check_for_a_product/)
+ to obtain a snyk-token and to enable the snyk task in a Pipeline.
+
+
+ The snyk binary used in this Task comes from a container image defined in
+ https://github.com/konflux-ci/konflux-test
+
+
+ See https://snyk.io/product/snyk-code/ and https://snyk.io/ for more information about the snyk
+ tool.
+preferStepTemplate: true
+removeWorkspaces:
+ - workspace
+replacements:
+ workspaces.workspace.path: /var/workdir
+regexReplacements:
+ hacbs/\$\(context.task.name\): source
diff --git a/ta-generator/golden/sast-snyk-check/ta.yaml b/ta-generator/golden/sast-snyk-check/ta.yaml
new file mode 100644
index 0000000000..66e8e98490
--- /dev/null
+++ b/ta-generator/golden/sast-snyk-check/ta.yaml
@@ -0,0 +1,114 @@
+---
+apiVersion: tekton.dev/v1
+kind: Task
+metadata:
+ labels:
+ app.kubernetes.io/version: "0.1"
+ annotations:
+ tekton.dev/pipelines.minVersion: "0.12.1"
+ tekton.dev/tags: "appstudio, hacbs"
+ name: sast-snyk-check-oci-ta
+spec:
+ description: >-
+ Scans source code for security vulnerabilities, including common issues such as SQL injection,
+ cross-site scripting (XSS), and code injection attacks using Snyk Code, a Static Application
+ Security Testing (SAST) tool.
+
+
+ Follow the steps given
+ [here](https://redhat-appstudio.github.io/docs.appstudio.io/Documentation/main/how-to-guides/testing_applications/enable_snyk_check_for_a_product/)
+ to obtain a snyk-token and to enable the snyk task in a Pipeline.
+
+
+ The snyk binary used in this Task comes from a container image defined in
+ https://github.com/konflux-ci/konflux-test
+
+
+ See https://snyk.io/product/snyk-code/ and https://snyk.io/ for more information about the snyk
+ tool.
+ results:
+ - description: Tekton task test output.
+ name: TEST_OUTPUT
+ params:
+ - name: SOURCE_ARTIFACT
+ type: string
+ description: The Trusted Artifact URI pointing to the artifact with the application source code.
+ - name: SNYK_SECRET
+ description: Name of secret which contains Snyk token.
+ default: snyk-secret
+ - name: ARGS
+ type: string
+ description: Append arguments.
+ default: "--all-projects --exclude=test*,vendor,deps"
+ volumes:
+ - name: snyk-secret
+ secret:
+ secretName: $(params.SNYK_SECRET)
+ optional: true
+ - name: workdir
+ emptyDir: {}
+ stepTemplate:
+ volumeMounts:
+ - mountPath: /var/workdir
+ name: workdir
+ steps:
+ - name: use-trusted-artifact
+ image: quay.io/redhat-appstudio/build-trusted-artifacts:latest@sha256:placeholder
+ args:
+ - use
+ - $(params.SOURCE_ARTIFACT)=/var/workdir/source
+ - name: sast-snyk-check
+ image: quay.io/redhat-appstudio/konflux-test:v1.4.0@sha256:54d49b37c9a2e280d42961a57e4f7a16c171d6b065559f1329b548db85300bea
+ workingDir: /var/workdir/source
+ volumeMounts:
+ - name: snyk-secret
+ mountPath: "/etc/secrets"
+ readOnly: true
+ env:
+ - name: SNYK_SECRET
+ value: $(params.SNYK_SECRET)
+ - name: ARGS
+ value: $(params.ARGS)
+ script: |
+ #!/usr/bin/env bash
+ set -euo pipefail
+ . /utils.sh
+ trap 'handle_error $(results.TEST_OUTPUT.path)' EXIT
+
+ SNYK_TOKEN_PATH="/etc/secrets/snyk_token"
+
+ if [ -f "${SNYK_TOKEN_PATH}" ] && [ -s "${SNYK_TOKEN_PATH}" ]; then
+ # SNYK token is provided
+ SNYK_TOKEN="$(cat ${SNYK_TOKEN_PATH})"
+ export SNYK_TOKEN
+ else
+ to_enable_snyk='[here](https://redhat-appstudio.github.io/docs.appstudio.io/Documentation/main/how-to-guides/testing_applications/enable_snyk_check_for_a_product/)'
+ note="Task $(context.task.name) skipped: If you wish to use the Snyk code SAST task, please create a secret name snyk-secret with the key "snyk_token" containing the Snyk token by following the steps given ${to_enable_snyk}"
+ TEST_OUTPUT=$(make_result_json -r SKIPPED -t "$note")
+ echo "${TEST_OUTPUT}" | tee "$(results.TEST_OUTPUT.path)"
+ exit 0
+ fi
+
+ SNYK_EXIT_CODE=0
+ SOURCE_CODE_DIR=/var/workdir/source
+ snyk code test $ARGS $SOURCE_CODE_DIR --sarif-file-output=sast_snyk_check_out.json 1>&2>> stdout.txt || SNYK_EXIT_CODE=$?
+ test_not_skipped=0
+ SKIP_MSG="We found 0 supported files"
+ grep -q "$SKIP_MSG" stdout.txt || test_not_skipped=$?
+
+ if [[ "$SNYK_EXIT_CODE" -eq 0 ]] || [[ "$SNYK_EXIT_CODE" -eq 1 ]]; then
+ cat sast_snyk_check_out.json
+ TEST_OUTPUT=
+ parse_test_output $(context.task.name) sarif sast_snyk_check_out.json || true
+
+ # When the test is skipped, the "SNYK_EXIT_CODE" is 3 and it can also be 3 in some other situation
+ elif [[ "$test_not_skipped" -eq 0 ]]; then
+ note="Task $(context.task.name) success: Snyk code test found zero supported files."
+ ERROR_OUTPUT=$(make_result_json -r SUCCESS -t "$note")
+ else
+ echo "sast-snyk-check test failed because of the following issues:"
+ cat stdout.txt
+ note="Task $(context.task.name) failed: For details, check Tekton task log."
+ ERROR_OUTPUT=$(make_result_json -r ERROR -t "$note")
+ fi
+ echo "${TEST_OUTPUT:-${ERROR_OUTPUT}}" | tee $(results.TEST_OUTPUT.path)
diff --git a/ta-generator/golden/source-build/base.yaml b/ta-generator/golden/source-build/base.yaml
new file mode 100644
index 0000000000..e24ad9a0ac
--- /dev/null
+++ b/ta-generator/golden/source-build/base.yaml
@@ -0,0 +1,161 @@
+---
+apiVersion: tekton.dev/v1
+kind: Task
+metadata:
+ name: source-build
+ labels:
+ app.kubernetes.io/version: "0.1"
+ annotations:
+ tekton.dev/pipelines.minVersion: "0.12.1"
+ tekton.dev/tags: "konflux"
+spec:
+ description: Source image build.
+ params:
+ - name: BINARY_IMAGE
+ description: Binary image name from which to generate the source image name.
+ type: string
+ - name: BASE_IMAGES
+ description: >-
+ By default, the task inspects the SBOM of the binary image to find the base image.
+ With this parameter, you can override that behavior and pass the base image directly.
+ The value should be a newline-separated list of images, in the same order as the FROM
+ instructions specified in a multistage Dockerfile.
+ type: string
+ default: ""
+ results:
+ - name: BUILD_RESULT
+ description: Build result.
+ - name: SOURCE_IMAGE_URL
+ description: The source image url.
+ - name: SOURCE_IMAGE_DIGEST
+ description: The source image digest.
+ workspaces:
+ - name: workspace
+ description: The workspace where source code is included.
+ volumes:
+ - name: source-build-work-place
+ emptyDir: {}
+ stepTemplate:
+ env:
+ - name: BINARY_IMAGE
+ value: "$(params.BINARY_IMAGE)"
+ - name: BASE_IMAGES_FILE
+ value: /var/source-build/base-images.txt
+ volumeMounts:
+ - name: source-build-work-place
+ mountPath: /var/source-build
+ steps:
+ - name: get-base-images
+ image: quay.io/konflux-ci/appstudio-utils:ab6b0b8e40e440158e7288c73aff1cf83a2cc8a9@sha256:24179f0efd06c65d16868c2d7eb82573cce8e43533de6cea14fec3b7446e0b14
+ env:
+ - name: BASE_IMAGES
+ value: "$(params.BASE_IMAGES)"
+ script: |
+ #!/usr/bin/env bash
+ set -euo pipefail
+
+ if [[ -n "$BASE_IMAGES" ]]; then
+ echo "BASE_IMAGES param received:"
+ printf "%s" "$BASE_IMAGES" | tee "$BASE_IMAGES_FILE"
+ exit
+ fi
+
+ echo "BASE_IMAGES param is empty, inspecting the SBOM instead"
+
+ raw_inspect=$(skopeo inspect --raw "docker://$BINARY_IMAGE")
+ if manifest_digest=$(jq -e -r '.manifests[0].digest' <<< "$raw_inspect"); then
+ # The BINARY_IMAGE is an index image, each manifest in the list has its own SBOM.
+ # We're gonna assume the base images are the same or similar enough in all the SBOMs.
+ echo "BINARY_IMAGE ($BINARY_IMAGE) is a manifest list, picking an arbitrary image from the list"
+ image_without_digest=${BINARY_IMAGE%@*}
+ image_without_tag=${image_without_digest%:*}
+ image=${image_without_tag}@${manifest_digest}
+ else
+ # The image is a single manifest
+ image=$BINARY_IMAGE
+ fi
+
+ for i in {1..5}; do
+ echo "Downloading SBOM for $image (attempt $i)"
+ sbom=$(cosign download sbom "$image") && break
+ [[ "$i" -lt 5 ]] && sleep 1
+ done
+
+ if [[ -z "$sbom" ]]; then
+ echo "Failed to download SBOM after 5 attempts. Proceeding anyway."
+ echo "WARNING: the source image will not include sources for the base image."
+ exit 0
+ fi
+
+ echo -n "Looking for base image in SBOM"
+ echo " (.formulation[].components[] with 'konflux:container:is_base_image' property)"
+ # Note: the SBOM should contain at most one image with the is_base_image property - the
+ # base image for the last FROM instruction. That is the only base image we care about.
+ jq -r '
+ .formulation[]?
+ | .components[]?
+ | select(any(.properties[]?; .name == "konflux:container:is_base_image"))
+ | (.purl | capture("^pkg:oci/.*?@(?.*?:[a-f0-9]*)")) as $matched
+ | .name + "@" + $matched.digest
+ ' <<< "$sbom" | tee "$BASE_IMAGES_FILE"
+
+ - name: build
+ image: quay.io/konflux-ci/source-container-build:9ad131acf5154d2f280b7b46a1abc543952d325c@sha256:94271c32e4578208ac90308695d2b625d4e932d65f0cdd116b200c39228f5ece
+ # per https://kubernetes.io/docs/concepts/containers/images/#imagepullpolicy-defaulting
+ # the cluster will set imagePullPolicy to IfNotPresent
+ computeResources:
+ limits:
+ memory: 2Gi
+ requests:
+ memory: 512Mi
+ cpu: 250m
+ workingDir: "/var/source-build"
+ securityContext:
+ runAsUser: 0
+ capabilities:
+ add:
+ - SETFCAP
+ env:
+ - name: SOURCE_DIR
+ value: "$(workspaces.workspace.path)/source"
+ - name: RESULT_FILE
+ value: "$(results.BUILD_RESULT.path)"
+ - name: CACHI2_ARTIFACTS_DIR
+ value: "$(workspaces.workspace.path)/cachi2"
+ - name: RESULT_SOURCE_IMAGE_URL
+ value: "$(results.SOURCE_IMAGE_URL.path)"
+ - name: RESULT_SOURCE_IMAGE_DIGEST
+ value: "$(results.SOURCE_IMAGE_DIGEST.path)"
+ - name: WS_BUILD_RESULT_FILE
+ value: "$(workspaces.workspace.path)/source_build_result.json"
+ script: |
+ #!/usr/bin/env bash
+ set -euo pipefail
+
+ app_dir=/opt/source_build
+ registry_allowlist="
+ registry.access.redhat.com
+ registry.redhat.io
+ "
+
+ ## This is needed for the builds performed by the rpm-ostree task
+ ## otherwise, we can see this error:
+ ## "fatal: detected dubious ownership in repository at '/workspace/workspace/source'"
+ ##
+ git config --global --add safe.directory $SOURCE_DIR
+
+ base_images=$(if [[ -f "$BASE_IMAGES_FILE" ]]; then cat "$BASE_IMAGES_FILE"; fi)
+
+ ${app_dir}/appenv/bin/python3 ${app_dir}/source_build.py \
+ --output-binary-image "$BINARY_IMAGE" \
+ --workspace /var/source-build \
+ --source-dir "$SOURCE_DIR" \
+ --base-images "$base_images" \
+ --write-result-to "$RESULT_FILE" \
+ --cachi2-artifacts-dir "$CACHI2_ARTIFACTS_DIR" \
+ --registry-allowlist="$registry_allowlist"
+
+ cat "$RESULT_FILE" | jq -j ".image_url" >"$RESULT_SOURCE_IMAGE_URL"
+ cat "$RESULT_FILE" | jq -j ".image_digest" >"$RESULT_SOURCE_IMAGE_DIGEST"
+
+ cp "$RESULT_FILE" "$WS_BUILD_RESULT_FILE"
diff --git a/ta-generator/golden/source-build/recipe.yaml b/ta-generator/golden/source-build/recipe.yaml
new file mode 100644
index 0000000000..f9d27410ba
--- /dev/null
+++ b/ta-generator/golden/source-build/recipe.yaml
@@ -0,0 +1,14 @@
+---
+add:
+ - use-source
+ - use-cachi2
+removeWorkspaces:
+ - workspace
+removeVolumes:
+ - source-build-work-place
+regexReplacements:
+ \/var\/source-build: /var/workdir
+ \/workspace\/workspace: /var/workdir
+preferStepTemplate: true
+replacements:
+ workspaces.workspace.path: /var/workdir
diff --git a/ta-generator/golden/source-build/ta.yaml b/ta-generator/golden/source-build/ta.yaml
new file mode 100644
index 0000000000..efea0e4ebb
--- /dev/null
+++ b/ta-generator/golden/source-build/ta.yaml
@@ -0,0 +1,171 @@
+---
+apiVersion: tekton.dev/v1
+kind: Task
+metadata:
+ name: source-build-oci-ta
+ annotations:
+ tekton.dev/pipelines.minVersion: 0.12.1
+ tekton.dev/tags: konflux
+ labels:
+ app.kubernetes.io/version: "0.1"
+spec:
+ description: Source image build.
+ params:
+ - name: BASE_IMAGES
+ description: By default, the task inspects the SBOM of the binary image
+ to find the base image. With this parameter, you can override that
+ behavior and pass the base image directly. The value should be a newline-separated
+ list of images, in the same order as the FROM instructions specified
+ in a multistage Dockerfile.
+ type: string
+ default: ""
+ - name: BINARY_IMAGE
+ description: Binary image name from which to generate the source image
+ name.
+ type: string
+ - name: CACHI2_ARTIFACT
+ description: The Trusted Artifact URI pointing to the artifact with
+ the prefetched dependencies.
+ type: string
+ default: ""
+ - name: SOURCE_ARTIFACT
+ description: The Trusted Artifact URI pointing to the artifact with
+ the application source code.
+ type: string
+ results:
+ - name: BUILD_RESULT
+ description: Build result.
+ - name: SOURCE_IMAGE_DIGEST
+ description: The source image digest.
+ - name: SOURCE_IMAGE_URL
+ description: The source image url.
+ volumes:
+ - name: workdir
+ emptyDir: {}
+ stepTemplate:
+ env:
+ - name: BASE_IMAGES_FILE
+ value: /var/workdir/base-images.txt
+ - name: BINARY_IMAGE
+ value: $(params.BINARY_IMAGE)
+ volumeMounts:
+ - mountPath: /var/workdir
+ name: workdir
+ steps:
+ - name: use-trusted-artifact
+ image: quay.io/redhat-appstudio/build-trusted-artifacts:latest@sha256:placeholder
+ args:
+ - use
+ - $(params.SOURCE_ARTIFACT)=/var/workdir/source
+ - $(params.CACHI2_ARTIFACT)=/var/workdir/cachi2
+ - name: get-base-images
+ image: quay.io/konflux-ci/appstudio-utils:ab6b0b8e40e440158e7288c73aff1cf83a2cc8a9@sha256:24179f0efd06c65d16868c2d7eb82573cce8e43533de6cea14fec3b7446e0b14
+ env:
+ - name: BASE_IMAGES
+ value: $(params.BASE_IMAGES)
+ script: |
+ #!/usr/bin/env bash
+ set -euo pipefail
+
+ if [[ -n "$BASE_IMAGES" ]]; then
+ echo "BASE_IMAGES param received:"
+ printf "%s" "$BASE_IMAGES" | tee "$BASE_IMAGES_FILE"
+ exit
+ fi
+
+ echo "BASE_IMAGES param is empty, inspecting the SBOM instead"
+
+ raw_inspect=$(skopeo inspect --raw "docker://$BINARY_IMAGE")
+ if manifest_digest=$(jq -e -r '.manifests[0].digest' <<<"$raw_inspect"); then
+ # The BINARY_IMAGE is an index image, each manifest in the list has its own SBOM.
+ # We're gonna assume the base images are the same or similar enough in all the SBOMs.
+ echo "BINARY_IMAGE ($BINARY_IMAGE) is a manifest list, picking an arbitrary image from the list"
+ image_without_digest=${BINARY_IMAGE%@*}
+ image_without_tag=${image_without_digest%:*}
+ image=${image_without_tag}@${manifest_digest}
+ else
+ # The image is a single manifest
+ image=$BINARY_IMAGE
+ fi
+
+ for i in {1..5}; do
+ echo "Downloading SBOM for $image (attempt $i)"
+ sbom=$(cosign download sbom "$image") && break
+ [[ "$i" -lt 5 ]] && sleep 1
+ done
+
+ if [[ -z "$sbom" ]]; then
+ echo "Failed to download SBOM after 5 attempts. Proceeding anyway."
+ echo "WARNING: the source image will not include sources for the base image."
+ exit 0
+ fi
+
+ echo -n "Looking for base image in SBOM"
+ echo " (.formulation[].components[] with 'konflux:container:is_base_image' property)"
+ # Note: the SBOM should contain at most one image with the is_base_image property - the
+ # base image for the last FROM instruction. That is the only base image we care about.
+ jq -r '
+ .formulation[]?
+ | .components[]?
+ | select(any(.properties[]?; .name == "konflux:container:is_base_image"))
+ | (.purl | capture("^pkg:oci/.*?@(?.*?:[a-f0-9]*)")) as $matched
+ | .name + "@" + $matched.digest
+ ' <<<"$sbom" | tee "$BASE_IMAGES_FILE"
+ - name: build
+ image: quay.io/konflux-ci/source-container-build:9ad131acf5154d2f280b7b46a1abc543952d325c@sha256:94271c32e4578208ac90308695d2b625d4e932d65f0cdd116b200c39228f5ece
+ workingDir: /var/workdir
+ env:
+ - name: SOURCE_DIR
+ value: /var/workdir/source
+ - name: RESULT_FILE
+ value: $(results.BUILD_RESULT.path)
+ - name: CACHI2_ARTIFACTS_DIR
+ value: /var/workdir/cachi2
+ - name: RESULT_SOURCE_IMAGE_URL
+ value: $(results.SOURCE_IMAGE_URL.path)
+ - name: RESULT_SOURCE_IMAGE_DIGEST
+ value: $(results.SOURCE_IMAGE_DIGEST.path)
+ - name: WS_BUILD_RESULT_FILE
+ value: /var/workdir/source_build_result.json
+ script: |
+ #!/usr/bin/env bash
+ set -euo pipefail
+
+ app_dir=/opt/source_build
+ registry_allowlist="
+ registry.access.redhat.com
+ registry.redhat.io
+ "
+
+ ## This is needed for the builds performed by the rpm-ostree task
+ ## otherwise, we can see this error:
+ ## "fatal: detected dubious ownership in repository at '/var/workdir/source'"
+ ##
+ git config --global --add safe.directory $SOURCE_DIR
+
+ base_images=$(if [[ -f "$BASE_IMAGES_FILE" ]]; then cat "$BASE_IMAGES_FILE"; fi)
+
+ ${app_dir}/appenv/bin/python3 ${app_dir}/source_build.py \
+ --output-binary-image "$BINARY_IMAGE" \
+ --workspace /var/workdir \
+ --source-dir "$SOURCE_DIR" \
+ --base-images "$base_images" \
+ --write-result-to "$RESULT_FILE" \
+ --cachi2-artifacts-dir "$CACHI2_ARTIFACTS_DIR" \
+ --registry-allowlist="$registry_allowlist"
+
+ cat "$RESULT_FILE" | jq -j ".image_url" >"$RESULT_SOURCE_IMAGE_URL"
+ cat "$RESULT_FILE" | jq -j ".image_digest" >"$RESULT_SOURCE_IMAGE_DIGEST"
+
+ cp "$RESULT_FILE" "$WS_BUILD_RESULT_FILE"
+ computeResources:
+ limits:
+ memory: 2Gi
+ requests:
+ cpu: 250m
+ memory: 512Mi
+ securityContext:
+ capabilities:
+ add:
+ - SETFCAP
+ runAsUser: 0
diff --git a/ta-generator/main.go b/ta-generator/main.go
new file mode 100644
index 0000000000..06ab310fc6
--- /dev/null
+++ b/ta-generator/main.go
@@ -0,0 +1,39 @@
+package main
+
+import (
+ "fmt"
+ "os"
+ "path"
+ "strings"
+)
+
+func main() {
+ if len(os.Args) != 2 {
+ fmt.Fprintf(os.Stderr, "Usage: %s path/to/recipe.yaml\n", os.Args[0])
+ os.Exit(1)
+ }
+
+ recipePath := os.Args[1]
+
+ recipe := expectValue(readRecipe(recipePath))
+
+ task := expectValue(readTask(recipe.Base))
+
+ taDir := path.Dir(recipePath)
+
+ taTaskPath := path.Join(taDir, path.Base(path.Dir(taDir))+".yaml")
+
+ if _, err := os.Stat(taTaskPath); err == nil {
+ existing := expectValue(readTask(taTaskPath))
+ for _, step := range existing.Spec.Steps {
+ if strings.Contains(step.Image, "/build-trusted-artifacts:") {
+ image = step.Image
+ break
+ }
+ }
+ }
+
+ expect(perform(task, recipe))
+
+ expect(writeTask(task, os.Stdout))
+}
diff --git a/ta-generator/main_test.go b/ta-generator/main_test.go
new file mode 100644
index 0000000000..a990cf471c
--- /dev/null
+++ b/ta-generator/main_test.go
@@ -0,0 +1,81 @@
+package main
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "os"
+ "path"
+ "testing"
+
+ "github.com/google/go-cmp/cmp"
+ "github.com/zregvart/tkn-fmt/format"
+)
+
+func TestGolden(t *testing.T) {
+ dirs, err := os.ReadDir("golden")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ resolveImage = func() string {
+ return "quay.io/redhat-appstudio/build-trusted-artifacts:latest@sha256:resolved"
+ }
+
+ for _, dir := range dirs {
+ t.Run(dir.Name(), func(t *testing.T) {
+ task, err := readTask(path.Join("golden", dir.Name(), "base.yaml"))
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ recipe, err := readRecipe(path.Join("golden", dir.Name(), "recipe.yaml"))
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ switch dir.Name() {
+ case "buildah":
+ image = "" // force resolve
+ case "git-clone":
+ image = "quay.io/redhat-appstudio/build-trusted-artifacts:latest@sha256:existing" // use existing
+ default:
+ image = "quay.io/redhat-appstudio/build-trusted-artifacts:latest@sha256:placeholder"
+ }
+
+ if err := perform(task, recipe); err != nil {
+ t.Fatal(err)
+ }
+
+ got := bytes.Buffer{}
+ if err := writeTask(task, &got); err != nil {
+ t.Fatal(err)
+ }
+
+ ta, err := os.Open(path.Join("golden", dir.Name(), "ta.yaml"))
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ golden := bytes.Buffer{}
+ if err := format.Format(ta, &golden); err != nil {
+ t.Fatal(err)
+ }
+
+ expected := golden.String()
+
+ if diff := cmp.Diff(expected, got.String()); diff != "" {
+ failure := fmt.Errorf("%s mismatch (-want +got):\n%s", dir.Name(), diff)
+ if err := os.WriteFile(path.Join(path.Join("golden", dir.Name(), "got")), got.Bytes(), 0644); err != nil {
+ failure = errors.Join(failure, err)
+ }
+ if err := os.WriteFile(path.Join(path.Join("golden", dir.Name(), "expected")), golden.Bytes(), 0644); err != nil {
+ failure = errors.Join(failure, err)
+ }
+
+ t.Error(failure)
+
+ }
+ })
+ }
+}
diff --git a/ta-generator/recipe.go b/ta-generator/recipe.go
new file mode 100644
index 0000000000..2d2691d3dd
--- /dev/null
+++ b/ta-generator/recipe.go
@@ -0,0 +1,67 @@
+package main
+
+import (
+ "os"
+ "path/filepath"
+ "slices"
+ "sort"
+
+ pipeline "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1"
+ core "k8s.io/api/core/v1"
+ "sigs.k8s.io/yaml"
+)
+
+type AdditionalStep struct {
+ pipeline.Step
+ At int `json:"at"`
+}
+
+type Recipe struct {
+ Add []string `json:"add"`
+ AddEnvironment []core.EnvVar `json:"addEnvironment"`
+ AdditionalSteps []AdditionalStep `json:"additionalSteps"`
+ AddParams pipeline.ParamSpecs `json:"addParams"`
+ AddResult []pipeline.TaskResult `json:"addResult"`
+ AddVolume []core.Volume `json:"addVolume"`
+ AddVolumeMount []core.VolumeMount `json:"addVolumeMount"`
+ Base string `json:"base"`
+ Description string `json:"description"`
+ DisplaySuffix string `json:"displaySuffix"`
+ PreferStepTemplate bool `json:"preferStepTemplate"`
+ RegexReplacements map[string]string `json:"regexReplacements"`
+ RemoveParams []string `json:"removeParams"`
+ RemoveVolumes []string `json:"removeVolumes"`
+ RemoveWorkspaces []string `json:"removeWorkspaces"`
+ Replacements map[string]string `json:"replacements"`
+ Suffix string `json:"suffix"`
+ createCachi2 bool
+ createSource bool
+ useCachi2 bool
+ useSource bool
+}
+
+func readRecipe(path string) (*Recipe, error) {
+ b := expectValue(os.ReadFile(path)) // #nosec G304 -- the file is passed in by the user, this is expected
+
+ // with defaults
+ recipe := Recipe{
+ Suffix: "-oci-ta",
+ DisplaySuffix: " oci trusted artifacts",
+ }
+
+ if err := yaml.Unmarshal(b, &recipe); err != nil {
+ return nil, err
+ }
+
+ sort.Strings(recipe.Add)
+ _, recipe.createCachi2 = slices.BinarySearch(recipe.Add, "create-cachi2")
+ _, recipe.createSource = slices.BinarySearch(recipe.Add, "create-source")
+ _, recipe.useCachi2 = slices.BinarySearch(recipe.Add, "use-cachi2")
+ _, recipe.useSource = slices.BinarySearch(recipe.Add, "use-source")
+
+ if !filepath.IsAbs(recipe.Base) {
+ recipe.Base = filepath.Join(filepath.Dir(path), recipe.Base)
+ }
+
+ return &recipe, nil
+}
diff --git a/ta-generator/shell.go b/ta-generator/shell.go
new file mode 100644
index 0000000000..df8abb7752
--- /dev/null
+++ b/ta-generator/shell.go
@@ -0,0 +1,136 @@
+package main
+
+import (
+ "regexp"
+ "slices"
+ "sort"
+ "strings"
+
+ "mvdan.cc/sh/v3/fileutil"
+ "mvdan.cc/sh/v3/syntax"
+)
+
+var (
+ parser = syntax.NewParser(syntax.KeepComments(true))
+ printer = syntax.NewPrinter(syntax.KeepPadding(true), syntax.Indent(2))
+)
+
+func removeEnvUse(f *syntax.File, name string) []*syntax.Stmt {
+ modified := make([]*syntax.Stmt, 0, len(f.Stmts))
+ syntax.Walk(f, func(node syntax.Node) bool {
+ if p, ok := node.(*syntax.ParamExp); ok {
+ // parameter expansion, e.g. ${name}
+ if p.Param.Value == name {
+ // remove every line starting from the line where the ${name} was used
+ start := p.Param.Pos().Line()
+
+ var end uint = 0
+ for _, s := range f.Stmts {
+ line := s.Pos().Line()
+ if line == start {
+ if ifstmt, ok := s.Cmd.(*syntax.IfClause); ok {
+ // if the if statement is at the start line, remove
+ // the lines till the corresponding `fi` statement
+ end = ifstmt.FiPos.Line()
+ }
+ if assign, ok := s.Cmd.(*syntax.CallExpr); ok {
+ // remove the whole assignment
+ end = assign.End().Line()
+ }
+ }
+
+ if line < start || (line > end || end == 0) {
+ // add only the lines that are not in the start-end segment
+ modified = append(modified, s)
+ }
+ }
+ }
+ }
+
+ return true
+ })
+
+ if len(modified) == 0 {
+ // if the environment variable is not found, the modified slice will be empty
+ return f.Stmts
+ }
+
+ return modified
+}
+
+func removeUnusedFunctions(f *syntax.File) []*syntax.Stmt {
+ used := make([]string, 0, 10) // includes used functions and other calls (echo, printf...)
+ syntax.Walk(f, func(node syntax.Node) bool {
+ if c, ok := node.(*syntax.CallExpr); ok && len(c.Args) > 0 {
+ // first argument of a call statement is the name
+ used = append(used, c.Args[0].Lit())
+ }
+
+ return true
+ })
+
+ sort.Strings(used)
+
+ forRemoval := make([]struct{ start, end uint }, 0, 10)
+ syntax.Walk(f, func(node syntax.Node) bool {
+ if fn, ok := node.(*syntax.FuncDecl); ok {
+ if _, found := slices.BinarySearch(used, fn.Name.Value); !found {
+ // we found a function declared and unused
+ forRemoval = append(forRemoval, struct{ start, end uint }{fn.Pos().Line(), fn.End().Line()})
+ }
+ }
+ return true
+ })
+
+ modified := make([]*syntax.Stmt, 0, len(f.Stmts))
+ for _, s := range f.Stmts {
+ line := s.Position.Line()
+ remove := false
+ for _, r := range forRemoval {
+ if remove = line >= r.start && line <= r.end; remove {
+ // found lines comprising a unused function declaration
+ break
+ }
+ }
+
+ if !remove {
+ modified = append(modified, s)
+ }
+ }
+
+ return modified
+}
+
+func replaceLiterals(f *syntax.File, rx map[*regexp.Regexp]string) []*syntax.Stmt {
+ syntax.Walk(f, func(n syntax.Node) bool {
+ if l, ok := n.(*syntax.Lit); ok {
+ l.Value = applyRegexReplacements(l.Value, rx)
+ }
+ if s, ok := n.(*syntax.Stmt); ok {
+ for i := range s.Comments {
+ s.Comments[i].Text = applyRegexReplacements(s.Comments[i].Text, rx)
+ }
+ }
+ return true
+ })
+
+ return f.Stmts
+}
+
+func isShell(script string) bool {
+ if script == "" {
+ return false
+ }
+
+ // fileutil.Shebang returns "" if the shebang is not shell
+ if shebang := fileutil.Shebang([]byte(script)); shebang != "" {
+ return true
+ }
+
+ // folk don't add shebangs so missing one defaults to shell
+ if !strings.HasPrefix(script, "#!") {
+ return true
+ }
+
+ return false
+}
diff --git a/ta-generator/ta.go b/ta-generator/ta.go
new file mode 100644
index 0000000000..19e1c5760a
--- /dev/null
+++ b/ta-generator/ta.go
@@ -0,0 +1,350 @@
+package main
+
+import (
+ "bytes"
+ "fmt"
+ "regexp"
+ "slices"
+ "strings"
+
+ "github.com/google/go-containerregistry/pkg/authn"
+ "github.com/google/go-containerregistry/pkg/name"
+ "github.com/google/go-containerregistry/pkg/v1/remote"
+ pipeline "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1"
+ core "k8s.io/api/core/v1"
+)
+
+var (
+ image = ""
+
+ resolveImage = func() string {
+ ref := name.MustParseReference("quay.io/redhat-appstudio/build-trusted-artifacts:latest")
+
+ desc, err := remote.Head(ref, remote.WithAuthFromKeychain(authn.DefaultKeychain))
+ if err != nil {
+ panic(err)
+ }
+
+ return "quay.io/redhat-appstudio/build-trusted-artifacts:latest@" + desc.Digest.String()
+ }
+)
+
+func ensureImage() {
+ if image != "" {
+ return
+ }
+
+ image = resolveImage()
+}
+
+func perform(task *pipeline.Task, recipe *Recipe) error {
+ ensureImage()
+
+ sourceResult := pipeline.TaskResult{
+ Name: "SOURCE_ARTIFACT",
+ Description: "The Trusted Artifact URI pointing to the artifact with the application source code.",
+ Type: pipeline.ResultsTypeString,
+ }
+
+ cachi2Result := pipeline.TaskResult{
+ Name: "CACHI2_ARTIFACT",
+ Description: "The Trusted Artifact URI pointing to the artifact with the prefetched dependencies.",
+ Type: pipeline.ResultsTypeString,
+ }
+
+ useSourceParam := pipeline.ParamSpec{
+ Name: "SOURCE_ARTIFACT",
+ Type: pipeline.ParamTypeString,
+ Description: "The Trusted Artifact URI pointing to the artifact with the application source code.",
+ }
+
+ useCachi2Param := pipeline.ParamSpec{
+ Name: "CACHI2_ARTIFACT",
+ Type: pipeline.ParamTypeString,
+ Description: "The Trusted Artifact URI pointing to the artifact with the prefetched dependencies.",
+ Default: &pipeline.ParamValue{Type: pipeline.ParamTypeString, StringVal: ""},
+ }
+
+ createParams := pipeline.ParamSpecs{
+ {
+ Name: "ociStorage",
+ Description: "The OCI repository where the Trusted Artifacts are stored.",
+ Type: pipeline.ParamTypeString,
+ },
+ {
+ Name: "ociArtifactExpiresAfter",
+ Description: "Expiration date for the trusted artifacts created in the OCI repository. An empty string means the artifacts do not expire.",
+ Type: pipeline.ParamTypeString,
+ Default: &pipeline.ParamValue{Type: pipeline.ParamTypeString, StringVal: ""},
+ },
+ }
+
+ task.Name += recipe.Suffix
+
+ if recipe.Description != "" {
+ task.Spec.Description = recipe.Description
+ }
+
+ if _, ok := task.Annotations["tekton.dev/displayName"]; ok {
+ task.Annotations["tekton.dev/displayName"] += recipe.DisplaySuffix
+ }
+
+ task.Spec.Params = slices.DeleteFunc(task.Spec.Params, func(ps pipeline.ParamSpec) bool {
+ for _, rm := range recipe.RemoveParams {
+ if ps.Name == rm {
+ return true
+ }
+ }
+
+ return false
+ })
+
+ task.Spec.Workspaces = slices.DeleteFunc(task.Spec.Workspaces, func(wd pipeline.WorkspaceDeclaration) bool {
+ for _, rm := range recipe.RemoveWorkspaces {
+ if wd.Name == rm {
+ return true
+ }
+ }
+ return false
+ })
+ if len(task.Spec.Workspaces) == 0 {
+ task.Spec.Workspaces = nil
+ }
+
+ task.Spec.Volumes = slices.DeleteFunc(task.Spec.Volumes, func(v core.Volume) bool {
+ for _, rm := range recipe.RemoveVolumes {
+ if v.Name == rm {
+ return true
+ }
+ }
+ return false
+ })
+
+ task.Spec.Params = append(task.Spec.Params, recipe.AddParams...)
+
+ if recipe.useSource {
+ task.Spec.Params = append(task.Spec.Params, useSourceParam)
+ }
+
+ if recipe.useCachi2 {
+ task.Spec.Params = append(task.Spec.Params, useCachi2Param)
+ }
+
+ if recipe.createSource || recipe.createCachi2 {
+ task.Spec.Params = append(task.Spec.Params, createParams...)
+ }
+
+ if len(recipe.AddResult) == 0 {
+ if recipe.createSource {
+ recipe.AddResult = append(recipe.AddResult, sourceResult)
+ }
+ if recipe.createCachi2 {
+ recipe.AddResult = append(recipe.AddResult, cachi2Result)
+ }
+ }
+ task.Spec.Results = append(task.Spec.Results, recipe.AddResult...)
+
+ if len(recipe.AddVolume) == 0 {
+ recipe.AddVolume = []core.Volume{{
+ Name: "workdir",
+ VolumeSource: core.VolumeSource{
+ EmptyDir: &core.EmptyDirVolumeSource{},
+ },
+ }}
+ }
+ task.Spec.Volumes = append(task.Spec.Volumes, recipe.AddVolume...)
+
+ workdirVolumeMount := core.VolumeMount{
+ Name: "workdir",
+ MountPath: "/var/workdir",
+ }
+ if len(recipe.AddVolumeMount) == 0 {
+ recipe.AddVolumeMount = []core.VolumeMount{workdirVolumeMount}
+ }
+
+ removeEnv := func(env *[]string) func(core.EnvVar) bool {
+ return func(e core.EnvVar) bool {
+ for _, rm := range recipe.RemoveParams {
+ if strings.Contains(e.Value, "$(params."+rm+")") {
+ *env = append(*env, e.Name)
+ return true
+ }
+ }
+
+ for _, rm := range recipe.RemoveWorkspaces {
+ if strings.Contains(e.Value, "$(workspaces."+rm+".path)") {
+ *env = append(*env, e.Name)
+ return true
+ }
+ }
+
+ return false
+ }
+ }
+
+ rx := map[*regexp.Regexp]string{}
+ for old, new := range recipe.RegexReplacements {
+ ex, err := regexp.Compile(old)
+ if err != nil {
+ panic(err)
+ }
+ rx[ex] = new
+ }
+
+ templateEnv := make([]string, 0, 5)
+ if task.Spec.StepTemplate != nil || recipe.PreferStepTemplate {
+ if task.Spec.StepTemplate == nil {
+ task.Spec.StepTemplate = &pipeline.StepTemplate{}
+ }
+ task.Spec.StepTemplate.VolumeMounts = slices.DeleteFunc(task.Spec.StepTemplate.VolumeMounts, func(vm core.VolumeMount) bool {
+ for _, rm := range recipe.RemoveWorkspaces {
+ if vm.Name == rm {
+ return true
+ }
+ }
+
+ for _, rm := range recipe.RemoveVolumes {
+ if vm.Name == rm {
+ return true
+ }
+ }
+
+ return false
+ })
+
+ task.Spec.StepTemplate.VolumeMounts = append(task.Spec.StepTemplate.VolumeMounts, recipe.AddVolumeMount...)
+
+ task.Spec.StepTemplate.Env = slices.DeleteFunc(task.Spec.StepTemplate.Env, removeEnv(&templateEnv))
+
+ for i := range task.Spec.StepTemplate.Env {
+ task.Spec.StepTemplate.Env[i].Value = applyReplacements(task.Spec.StepTemplate.Env[i].Value, recipe.Replacements)
+ task.Spec.StepTemplate.Env[i].Value = applyRegexReplacements(task.Spec.StepTemplate.Env[i].Value, rx)
+ }
+
+ task.Spec.StepTemplate.WorkingDir = applyReplacements(task.Spec.StepTemplate.WorkingDir, recipe.Replacements)
+ task.Spec.StepTemplate.WorkingDir = applyRegexReplacements(task.Spec.StepTemplate.WorkingDir, rx)
+ }
+
+ for i := range task.Spec.Steps {
+ env := make([]string, 0, 5)
+
+ for j := range task.Spec.Steps[i].Env {
+ task.Spec.Steps[i].Env[j].Value = applyReplacements(task.Spec.Steps[i].Env[j].Value, recipe.Replacements)
+ task.Spec.Steps[i].Env[j].Value = applyRegexReplacements(task.Spec.Steps[i].Env[j].Value, rx)
+ }
+
+ task.Spec.Steps[i].Env = slices.DeleteFunc(task.Spec.Steps[i].Env, removeEnv(&env))
+
+ task.Spec.Steps[i].Env = append(task.Spec.Steps[i].Env, recipe.AddEnvironment...)
+
+ if task.Spec.StepTemplate == nil {
+ task.Spec.Steps[i].VolumeMounts = append(task.Spec.Steps[i].VolumeMounts, recipe.AddVolumeMount...)
+ }
+
+ task.Spec.Steps[i].VolumeMounts = slices.DeleteFunc(task.Spec.Steps[i].VolumeMounts, func(vm core.VolumeMount) bool {
+ for _, rm := range recipe.RemoveVolumes {
+ if vm.Name == rm {
+ return true
+ }
+ }
+
+ return false
+ })
+
+ if len(task.Spec.Steps[i].VolumeMounts) == 0 {
+ task.Spec.Steps[i].VolumeMounts = nil
+ }
+
+ task.Spec.Steps[i].WorkingDir = applyReplacements(task.Spec.Steps[i].WorkingDir, recipe.Replacements)
+ task.Spec.Steps[i].WorkingDir = applyRegexReplacements(task.Spec.Steps[i].WorkingDir, rx)
+
+ if !isShell(task.Spec.Steps[i].Script) {
+ continue
+ }
+
+ if len(recipe.Replacements) > 0 {
+ task.Spec.Steps[i].Script = applyReplacements(task.Spec.Steps[i].Script, recipe.Replacements)
+ }
+
+ r := strings.NewReader(task.Spec.Steps[i].Script)
+ f, err := parser.Parse(r, task.Spec.Steps[i].Name+"_script.sh")
+ if err != nil {
+ return err
+ }
+
+ for _, rm := range templateEnv {
+ f.Stmts = removeEnvUse(f, rm)
+ }
+ for _, rm := range env {
+ f.Stmts = removeEnvUse(f, rm)
+ }
+ if len(recipe.RegexReplacements) > 0 {
+ f.Stmts = replaceLiterals(f, rx)
+ }
+
+ f.Stmts = removeUnusedFunctions(f)
+
+ buf := bytes.Buffer{}
+ if err := printer.Print(&buf, f); err != nil {
+ return err
+ }
+
+ task.Spec.Steps[i].Script = buf.String()
+ }
+
+ if recipe.useSource || recipe.useCachi2 {
+ args := []string{"use"}
+
+ if recipe.useSource {
+ args = append(args, fmt.Sprintf("$(params.SOURCE_ARTIFACT)=/var/workdir/%s", "source"))
+ }
+
+ if recipe.useCachi2 {
+ args = append(args, fmt.Sprintf("$(params.CACHI2_ARTIFACT)=/var/workdir/%s", "cachi2"))
+ }
+
+ task.Spec.Steps = append([]pipeline.Step{{
+ Name: "use-trusted-artifact",
+ Image: image,
+ Args: args,
+ }}, task.Spec.Steps...)
+ }
+ if recipe.createSource || recipe.createCachi2 {
+ args := []string{
+ "create",
+ "--store",
+ "$(params.ociStorage)",
+ }
+
+ if recipe.createSource {
+ args = append(args, "$(results.SOURCE_ARTIFACT.path)=/var/workdir/source")
+ }
+
+ if recipe.createCachi2 {
+ args = append(args, "$(results.CACHI2_ARTIFACT.path)=/var/workdir/cachi2")
+ }
+
+ create := pipeline.Step{
+ Name: "create-trusted-artifact",
+ Image: image,
+ Env: []core.EnvVar{
+ {
+ Name: "IMAGE_EXPIRES_AFTER",
+ Value: "$(params.ociArtifactExpiresAfter)",
+ },
+ },
+ Args: args,
+ }
+
+ if task.Spec.StepTemplate == nil && !recipe.PreferStepTemplate {
+ create.VolumeMounts = []core.VolumeMount{workdirVolumeMount}
+ }
+ task.Spec.Steps = append(task.Spec.Steps, create)
+ }
+
+ for _, additional := range recipe.AdditionalSteps {
+ task.Spec.Steps = slices.Insert(task.Spec.Steps, additional.At, additional.Step)
+ }
+
+ return nil
+}
diff --git a/ta-generator/tekton.go b/ta-generator/tekton.go
new file mode 100644
index 0000000000..a99b183a74
--- /dev/null
+++ b/ta-generator/tekton.go
@@ -0,0 +1,47 @@
+package main
+
+import (
+ "bytes"
+ "io"
+ "os"
+ "regexp"
+
+ pipeline "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1"
+ "github.com/tektoncd/pipeline/pkg/substitution"
+ "github.com/zregvart/tkn-fmt/format"
+ "sigs.k8s.io/yaml"
+)
+
+func readTask(path string) (*pipeline.Task, error) {
+ b := expectValue(os.ReadFile(path)) // #nosec G304 -- we want to read the file as Task, nothing to worry about here
+ b = bytes.TrimLeft(b, "---\n")
+ task := pipeline.Task{}
+ return &task, yaml.Unmarshal(b, &task)
+}
+
+func writeTask(task *pipeline.Task, writer io.Writer) error {
+ if c, ok := writer.(io.Closer); ok {
+ defer c.Close()
+ }
+
+ b, err := yaml.Marshal(task)
+ if err != nil {
+ return err
+ }
+
+ buf := bytes.NewBuffer(b)
+
+ return format.Format(buf, writer)
+}
+
+func applyReplacements(in string, replacements map[string]string) string {
+ return substitution.ApplyReplacements(in, replacements)
+}
+
+func applyRegexReplacements(in string, replacements map[*regexp.Regexp]string) string {
+ out := in
+ for ex, new := range replacements {
+ out = ex.ReplaceAllString(out, new)
+ }
+ return out
+}