Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 48 additions & 3 deletions charts/supply-chain/templates/pipeline-qtodo.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
apiVersion: tekton.dev/v1beta1
apiVersion: tekton.dev/v1
kind: Pipeline
metadata:
name: qtodo-supply-chain
Expand All @@ -8,12 +8,20 @@ spec:
params:
- name: git-url
type: string
description: The URL of the public Github qtodo repository
description: The URL of the qtodo repository (public or protected)
default: {{ .Values.qtodo.repository | quote }}
- name: git-revision
type: string
description: The revision of the public Github qtodo repository
description: The revision of the qtodo repository
default: {{ .Values.qtodo.revision }}
- name: rebuild
type: string
description: Force rebuild the image even if it already exists
default: "false"
- name: skip-checks
type: string
description: Skip pre-build checks against existing image
default: "false"
- name: qtodo-build-cmd
type: string
description: The command to build the qtodo artifact
Expand Down Expand Up @@ -94,9 +102,44 @@ spec:
workspaces:
- name: qtodo-source
- name: registry-auth-config
- name: git-auth
optional: true

results:
- name: CHAINS-GIT_URL
description: The git URL used for the build (Tekton Chains provenance)
value: $(tasks.qtodo-clone-repository.results.URL)
- name: CHAINS-GIT_COMMIT
description: The git commit SHA used for the build (Tekton Chains provenance)
value: $(tasks.qtodo-clone-repository.results.COMMIT)
- name: IMAGE_URL
description: The image URL built by the pipeline (Tekton Chains provenance)
value: $(tasks.qtodo-build-image.results.IMAGE_URL)
- name: IMAGE_DIGEST
description: The image digest built by the pipeline (Tekton Chains provenance)
value: $(tasks.qtodo-build-image.results.IMAGE_DIGEST)

tasks:
- name: init
taskRef:
name: init
kind: Task
params:
- name: image-url
value: $(params.image-target)
- name: rebuild
value: $(params.rebuild)
- name: skip-checks
value: $(params.skip-checks)

- name: qtodo-clone-repository
runAfter:
- init
when:
- input: $(tasks.init.results.build)
operator: in
values:
- "true"
taskRef:
resolver: cluster
params:
Expand All @@ -114,6 +157,8 @@ spec:
workspaces:
- name: output
workspace: qtodo-source
- name: basic-auth
workspace: git-auth

- name: qtodo-build-artifact
runAfter:
Expand Down
2 changes: 1 addition & 1 deletion charts/supply-chain/templates/pipelinerun-qtodo.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ spec:
fi

cat <<'MANIFEST' | oc create -f -
apiVersion: tekton.dev/v1beta1
apiVersion: tekton.dev/v1
kind: PipelineRun
metadata:
generateName: qtodo-supply-chain-
Expand Down
5 changes: 4 additions & 1 deletion charts/supply-chain/templates/rbac/pipeline-sa.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,7 @@ metadata:
argocd.argoproj.io/compare-options: IgnoreExtraneous
argocd.argoproj.io/syncOptions: ServerSideApply=true
secrets:
- name: qtodo-registry-auth
- name: qtodo-registry-auth
{{- if .Values.git.credentials.enabled }}
- name: qtodo-git-credentials
{{- end }}
38 changes: 38 additions & 0 deletions charts/supply-chain/templates/secrets/qtodo-git-credentials.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{{- if .Values.git.credentials.enabled }}
{{- $host := .Values.git.credentials.host }}
{{- $hostBare := $host | trimPrefix "https://" | trimPrefix "http://" }}
{{- $userKey := .Values.git.credentials.usernameKey }}
{{- $passKey := .Values.git.credentials.passwordKey }}
---
apiVersion: "external-secrets.io/v1beta1"
kind: ExternalSecret
metadata:
name: qtodo-git-credentials
namespace: {{ .Release.Namespace | default .Values.global.namespace }}
spec:
refreshInterval: 15s
secretStoreRef:
name: {{ .Values.global.secretStore.name }}
kind: {{ .Values.global.secretStore.kind }}
target:
name: qtodo-git-credentials
template:
type: Opaque
metadata:
annotations:
tekton.dev/git-0: {{ $host | quote }}
data:
.gitconfig: |
[credential "{{ $host }}"]
helper = store
.git-credentials: {{ printf "https://{{ .%s }}:{{ .%s }}@%s" $userKey $passKey $hostBare | quote }}
data:
- secretKey: {{ $userKey }}
remoteRef:
key: {{ .Values.git.credentials.vaultPath }}
property: {{ $userKey }}
- secretKey: {{ $passKey }}
remoteRef:
key: {{ .Values.git.credentials.vaultPath }}
property: {{ $passKey }}
{{- end }}
2 changes: 1 addition & 1 deletion charts/supply-chain/templates/tasks/build-artifact.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
apiVersion: tekton.dev/v1beta1
apiVersion: tekton.dev/v1
kind: Task
metadata:
name: qtodo-build-artifact
Expand Down
2 changes: 1 addition & 1 deletion charts/supply-chain/templates/tasks/generate-sbom.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
apiVersion: tekton.dev/v1beta1
apiVersion: tekton.dev/v1
kind: Task
metadata:
name: qtodo-generate-sbom
Expand Down
55 changes: 55 additions & 0 deletions charts/supply-chain/templates/tasks/init.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
---
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: "supply-chain"
name: init
namespace: {{ .Values.global.namespace }}
spec:
description: >-
Initialize Pipeline Task. Determines whether the image should be built
by checking if the target image already exists in the registry.
Supports rebuild and skip-checks flags.
params:
- name: image-url
description: Image URL for build by PipelineRun
- name: rebuild
description: Rebuild the image even if it exists
default: "false"
- name: skip-checks
description: Skip checks against built image
default: "false"
results:
- name: build
description: Defines if the image in param image-url should be built
steps:
- name: init
image: {{ .Values.tasks.images.skopeo }}
computeResources:
limits:
memory: 256Mi
requests:
memory: 256Mi
cpu: 100m
env:
- name: IMAGE_URL
value: $(params.image-url)
- name: REBUILD
value: $(params.rebuild)
- name: SKIP_CHECKS
value: $(params.skip-checks)
script: |
#!/bin/bash
echo "Build Initialize: $IMAGE_URL"
echo

echo "Determine if Image Already Exists"
if [ "$REBUILD" == "true" ] || [ "$SKIP_CHECKS" == "false" ] || ! skopeo inspect --no-tags --raw "docker://$IMAGE_URL" &>/dev/null; then
echo -n "true" > $(results.build.path)
else
echo -n "false" > $(results.build.path)
fi
2 changes: 1 addition & 1 deletion charts/supply-chain/templates/tasks/restart-qtodo.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
apiVersion: tekton.dev/v1beta1
apiVersion: tekton.dev/v1
kind: Task
metadata:
name: restart-qtodo
Expand Down
2 changes: 1 addition & 1 deletion charts/supply-chain/templates/tasks/sbom-attest.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
apiVersion: tekton.dev/v1beta1
apiVersion: tekton.dev/v1
kind: Task
metadata:
name: qtodo-sbom-attestation
Expand Down
2 changes: 1 addition & 1 deletion charts/supply-chain/templates/tasks/sign-artifact.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
apiVersion: tekton.dev/v1beta1
apiVersion: tekton.dev/v1
kind: Task
metadata:
name: qtodo-sign-artifact
Expand Down
2 changes: 1 addition & 1 deletion charts/supply-chain/templates/tasks/sign-image.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
apiVersion: tekton.dev/v1beta1
apiVersion: tekton.dev/v1
kind: Task
metadata:
name: qtodo-sign-image
Expand Down
2 changes: 1 addition & 1 deletion charts/supply-chain/templates/tasks/upload-sbom.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{{- if eq .Values.rhtpa.enabled true }}
---
apiVersion: tekton.dev/v1beta1
apiVersion: tekton.dev/v1
kind: Task
metadata:
name: qtodo-upload-sbom
Expand Down
2 changes: 1 addition & 1 deletion charts/supply-chain/templates/tasks/verify-artifact.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
apiVersion: tekton.dev/v1beta1
apiVersion: tekton.dev/v1
kind: Task
metadata:
name: qtodo-verify-artifact
Expand Down
2 changes: 1 addition & 1 deletion charts/supply-chain/templates/tasks/verify-image.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
apiVersion: tekton.dev/v1beta1
apiVersion: tekton.dev/v1
kind: Task
metadata:
name: qtodo-verify-image
Expand Down
10 changes: 10 additions & 0 deletions charts/supply-chain/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,15 @@ rhtpa:
clientSecretVaultPath: "secret/data/hub/infra/rhtpa/rhtpa-oidc-cli"
clientSecretVaultKey: "client-secret"

# git credentials for protected repositories
git:
credentials:
enabled: false
host: "https://github.com"
vaultPath: "secret/data/hub/supply-chain/git-credentials"
usernameKey: "username"
passwordKey: "password"

# qtodo repository configuration
qtodo:
repository: "https://github.com/validatedpatterns-demos/qtodo.git"
Expand Down Expand Up @@ -144,3 +153,4 @@ tasks:
mandrel: "registry.redhat.io/quarkus/mandrel-for-jdk-21-rhel8:23.1-36"
syft: "registry.redhat.io/rh-syft-tech-preview/syft-rhel9:1.29.0"
rhtpa: "registry.access.redhat.com/ubi9/ubi:9.7-1764794285"
skopeo: "registry.access.redhat.com/ubi9/skopeo:9.5-1745865345@sha256:d91eb0dac7308ddfb12193368a42009509925edba80da9ffd3b82d03427dc3ed"
82 changes: 81 additions & 1 deletion docs/supply-chain.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ For the Secure Supply Chain use case, the command would be:
python3 scripts/gen-feature-variants.py --base values-hub.yaml --features supply-chain --registry-option <id>
```

If the source repository is **private** (protected), add the `protected-repos` feature:

```shell
python3 scripts/gen-feature-variants.py --base values-hub.yaml --features supply-chain,protected-repos --registry-option <id>
```

Where `<id>` is one of the options available in _Bring Your Own (BYO) Container Registry_:

1. Embedded Quay Registry
Expand Down Expand Up @@ -251,6 +257,7 @@ Once the supply-chain application has synced in ArgoCD, start the pipeline using
At the bottom we have the **workspaces**. These must be configured manually.
* For **qtodo-source**, select `PersistentVolumeClaim` and the PVC name is `qtodo-workspace-source`.
* For **registry-auth-config**, select `Secret` and the name of the secret is `qtodo-registry-auth`.
* For **git-auth** (optional, only when using protected repositories), select `Secret` and the name of the secret is `qtodo-git-credentials`.

5. Press **Start** to finish and run the pipeline.

Expand Down Expand Up @@ -278,9 +285,13 @@ spec:
- name: registry-auth-config
secret:
secretName: qtodo-registry-auth
# Uncomment for protected (private) repositories:
# - name: git-auth
# secret:
# secretName: qtodo-git-credentials
```

As was described previously, verify the values associated with the PVC storage and registry configuration.
As was described previously, verify the values associated with the PVC storage and registry configuration. If you are using a protected repository, uncomment the `git-auth` workspace.

Using the previously created definition, start a new execution of the pipeline using `oc` CLI:

Expand All @@ -307,10 +318,79 @@ oc get taskruns -n layered-zero-trust-hub -l tekton.dev/pipelineRun=<pipelinerun
oc logs -n layered-zero-trust-hub -l tekton.dev/pipelineRun=<pipelinerun-name>,tekton.dev/pipelineTask=<task-name>
```

### Protected Repositories

By default the pipeline clones the qtodo source from a **public** GitHub repository. If your source code lives in a private (protected) repository, enable the Git credentials feature so the `git-clone` task can authenticate.

#### 1. Store Git credentials in Vault

Uncomment the `git-credentials` secret in your local `~/values-secret.yaml` (copied from `values-secret.yaml.template`) and fill in your Git username and Personal Access Token (PAT):

```yaml
- name: git-credentials
vaultPrefixes:
- hub/supply-chain
fields:
- name: username
value: "your-git-username"
onMissingValue: error
- name: password
value: "your-personal-access-token"
onMissingValue: error
```

Then load the secret into Vault: `make load-secrets`.

#### 2. Enable Git credentials in the supply-chain overrides

Add the following overrides to the `supply-chain` application in `values-hub.yaml`:

```yaml
- name: git.credentials.enabled
value: "true"
- name: git.credentials.host
value: "https://github.com"
- name: git.credentials.vaultPath
value: "secret/data/hub/supply-chain/git-credentials"
```

Alternatively, if you use the `gen-feature-variants.py` script, add `protected-repos` to the features list and provide your private repository URL with `--git-repo`. The Git credential overrides and the `qtodo.repository` override are included automatically:

```shell
python3 scripts/gen-feature-variants.py \
--features supply-chain,protected-repos \
--registry-option <id> \
--git-repo https://github.com/your-org/qtodo.git
```

#### 3. Point the pipeline at your private repository

When using the generator with `--git-repo`, the `qtodo.repository` override is set automatically in the generated `values-hub.yaml`. If you are configuring manually, add this override to the `supply-chain` application:

```yaml
- name: qtodo.repository
value: "https://github.com/your-org/qtodo.git"
```

#### How it works

When `git.credentials.enabled` is `true`:

* An `ExternalSecret` (`qtodo-git-credentials`) pulls the username and PAT from Vault and creates an `Opaque` secret containing `.git-credentials` and `.gitconfig` files, annotated with `tekton.dev/git-0` pointing to the configured host.
* The pipeline ServiceAccount mounts this secret, and the `git-clone` task receives it via the optional `git-auth` / `basic-auth` workspace. When starting a PipelineRun, select `Secret` / `qtodo-git-credentials` for the **git-auth** workspace.
* The Vault policy `hub-supply-chain-jwt-secret` grants read access to `secret/data/hub/supply-chain/*` for the pipeline's SPIFFE identity.

### Init task (pre-flight image check)

The pipeline includes an `init` task that runs before `git-clone`. It uses `skopeo inspect` to check whether the target image already exists in the registry. If the image exists (and `rebuild` is not set to `"true"`), the pipeline skips the build. This avoids unnecessary rebuilds and is modeled after the [RHTAP sample pipelines](https://github.com/konflux-ci/build-definitions).

The pipeline also emits Tekton Chains provenance results (`CHAINS-GIT_URL`, `CHAINS-GIT_COMMIT`, `IMAGE_URL`, `IMAGE_DIGEST`) so that Tekton Chains can automatically generate and sign provenance attestations.

### Pipeline tasks

The pipeline we have prepared has the following steps:

* **init**. Checks whether the target image already exists in the registry. Gates the build with a `when` condition.
* **qtodo-clone-repository**. Clones the `qtodo` repository.
* **qtodo-build-artifact**. Builds an _uber-jar_ of `qtodo` application.
* **qtodo-sign-artifact**. Signs the JAR file generated during the build process.
Expand Down
Loading
Loading