From 662aec27193c3399c66a82093bf1cd38b93331f4 Mon Sep 17 00:00:00 2001 From: Ralph Bean Date: Thu, 9 Oct 2025 10:29:36 -0400 Subject: [PATCH 1/7] feat: add verify-source task for SLSA source verification This task verifies the SLSA source level of a git commit by checking for a Verification Summary Attestation (VSA) stored as a git note. Unlike git-clone, this task does not clone the repository - it only performs verification using the sourcetool verifycommit command. The task accepts a repository URL and commit SHA as parameters and outputs the achieved SLSA source level and test results. Includes tests for both positive (with VSA) and negative (without VSA) cases. Assisted-by: Claude Code Signed-off-by: Ralph Bean --- CODEOWNERS | 3 + renovate.json | 6 + task/verify-source/0.1/README.md | 22 +++ .../0.1/tests/test-verify-source-no-vsa.yaml | 68 +++++++++ .../tests/test-verify-source-with-vsa.yaml | 61 ++++++++ task/verify-source/0.1/verify-source.yaml | 131 ++++++++++++++++++ 6 files changed, 291 insertions(+) create mode 100644 task/verify-source/0.1/README.md create mode 100644 task/verify-source/0.1/tests/test-verify-source-no-vsa.yaml create mode 100644 task/verify-source/0.1/tests/test-verify-source-with-vsa.yaml create mode 100644 task/verify-source/0.1/verify-source.yaml diff --git a/CODEOWNERS b/CODEOWNERS index 7e1a8b50f8..707bf10969 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -128,6 +128,9 @@ # renovate groupName=oci-run-script /task/run-script-oci-ta @konflux-ci/build-maintainers @Zokormazo @arewm +# renovate groupName=verify-source +/task/run-script-oci-ta @arewm @ralphbean + # These are auto-generated and often require changes when tasks change. # Allow anyone with write access to approve the changes. /pipelines/*/README.md diff --git a/renovate.json b/renovate.json index 55acd43237..a98b1ed017 100644 --- a/renovate.json +++ b/renovate.json @@ -240,6 +240,12 @@ "task/run-script-oci-ta/**" ] }, + { + "groupName": "verify-source", + "matchFileNames": [ + "task/verify-source/**" + ] + }, { "groupName": "mobster", "matchFileNames": [ diff --git a/task/verify-source/0.1/README.md b/task/verify-source/0.1/README.md new file mode 100644 index 0000000000..11000f9e9b --- /dev/null +++ b/task/verify-source/0.1/README.md @@ -0,0 +1,22 @@ +# verify-source task + +The verify-source Task verifies the SLSA source level of a git commit +by checking for a Verification Summary Attestation (VSA) stored as a +git note. This task does not explicitly clone the repository - it performs +the verification using the sourcetool verifycommit command. + + +## Parameters +|name|description|default value|required| +|---|---|---|---| +|url|Repository URL to verify.||true| +|revision|Commit SHA to verify.||true| + +## Results +|name|description| +|---|---| +|SLSA_SOURCE_LEVEL_ACHIEVED|The SLSA source level achieved by this commit| +|TEST_OUTPUT|JSON formatted test results for SLSA verification| + + +## Additional info diff --git a/task/verify-source/0.1/tests/test-verify-source-no-vsa.yaml b/task/verify-source/0.1/tests/test-verify-source-no-vsa.yaml new file mode 100644 index 0000000000..1990d84bef --- /dev/null +++ b/task/verify-source/0.1/tests/test-verify-source-no-vsa.yaml @@ -0,0 +1,68 @@ +--- +apiVersion: tekton.dev/v1 +kind: Pipeline +metadata: + name: test-verify-source-no-vsa +spec: + description: | + Test the verify-source task with a repository that has no VSA + tasks: + - name: run-task + taskRef: + name: verify-source + params: + - name: url + value: https://github.com/kelseyhightower/nocode + - name: revision + value: ed6c73fc16578ec53ea374585df2b965ce9f4a31 + - name: check-result + params: + - name: SLSA_SOURCE_LEVEL_ACHIEVED + value: $(tasks.run-task.results.SLSA_SOURCE_LEVEL_ACHIEVED) + - name: TEST_OUTPUT + value: $(tasks.run-task.results.TEST_OUTPUT) + taskSpec: + params: + - name: SLSA_SOURCE_LEVEL_ACHIEVED + - name: TEST_OUTPUT + steps: + - name: check-result + env: + - name: SLSA_LEVEL_ACHIEVED + value: $(params.SLSA_SOURCE_LEVEL_ACHIEVED) + - name: TEST_OUTPUT + value: $(params.TEST_OUTPUT) + image: quay.io/konflux-ci/appstudio-utils:1610c1fc4cfc9c9053dbefc1146904a4df6659ef@sha256:90ac97b811073cb99a23232c15a08082b586c702b85da6200cf54ef505e3c50c + script: | + #!/usr/bin/env sh + set -eux + + # Strip trailing newlines from results + LEVEL=$(echo "$SLSA_LEVEL_ACHIEVED" | tr -d '\n') + OUTPUT=$(echo "$TEST_OUTPUT" | tr -d '\n') + + echo "SLSA_SOURCE_LEVEL_ACHIEVED: $LEVEL" + echo "TEST_OUTPUT: $OUTPUT" + + # For repos without VSA, verify SLSA level is 1 (baseline) + if [ "$LEVEL" != "SLSA_SOURCE_LEVEL_1" ]; then + echo "ERROR: Expected SLSA_SOURCE_LEVEL_1 for repo without VSA, got: $LEVEL" + exit 1 + fi + + # Verify that TEST_OUTPUT is non-empty + if [ -z "$OUTPUT" ]; then + echo "ERROR: TEST_OUTPUT is empty" + exit 1 + fi + + # Verify that there is at least one warning (no VSA found) + WARNINGS=$(echo "$OUTPUT" | grep -o '"warnings": [0-9]*' | grep -o '[0-9]*' || echo "0") + if [ "$WARNINGS" -eq 0 ]; then + echo "ERROR: Expected at least one warning for repo without VSA" + exit 1 + fi + + echo "SUCCESS: No-VSA verification test passed - correctly identified repo without VSA" + runAfter: + - run-task diff --git a/task/verify-source/0.1/tests/test-verify-source-with-vsa.yaml b/task/verify-source/0.1/tests/test-verify-source-with-vsa.yaml new file mode 100644 index 0000000000..f54b0a39c4 --- /dev/null +++ b/task/verify-source/0.1/tests/test-verify-source-with-vsa.yaml @@ -0,0 +1,61 @@ +--- +apiVersion: tekton.dev/v1 +kind: Pipeline +metadata: + name: test-verify-source-with-vsa +spec: + description: | + Test the verify-source task with SLSA source verification + tasks: + - name: run-task + taskRef: + name: verify-source + params: + - name: url + value: https://github.com/slsa-framework/source-tool + - name: revision + value: 134593d9158efd253e979e2e8d87b939945d091e + - name: check-result + params: + - name: SLSA_SOURCE_LEVEL_ACHIEVED + value: $(tasks.run-task.results.SLSA_SOURCE_LEVEL_ACHIEVED) + - name: TEST_OUTPUT + value: $(tasks.run-task.results.TEST_OUTPUT) + taskSpec: + params: + - name: SLSA_SOURCE_LEVEL_ACHIEVED + - name: TEST_OUTPUT + steps: + - name: check-result + env: + - name: SLSA_LEVEL_ACHIEVED + value: $(params.SLSA_SOURCE_LEVEL_ACHIEVED) + - name: TEST_OUTPUT + value: $(params.TEST_OUTPUT) + image: quay.io/konflux-ci/appstudio-utils:1610c1fc4cfc9c9053dbefc1146904a4df6659ef@sha256:90ac97b811073cb99a23232c15a08082b586c702b85da6200cf54ef505e3c50c + script: | + #!/usr/bin/env sh + set -eux + + # Strip trailing newlines from results + LEVEL=$(echo "$SLSA_LEVEL_ACHIEVED" | tr -d '\n') + OUTPUT=$(echo "$TEST_OUTPUT" | tr -d '\n') + + echo "SLSA_SOURCE_LEVEL_ACHIEVED: $LEVEL" + echo "TEST_OUTPUT: $OUTPUT" + + # Verify that SLSA level is 3 (extracted from VSA) + if [ "$LEVEL" != "SLSA_SOURCE_LEVEL_3" ]; then + echo "ERROR: Expected SLSA_SOURCE_LEVEL_3 from slsa-framework/source-tool repo VSA, got: $LEVEL" + exit 1 + fi + + # Verify that TEST_OUTPUT is non-empty + if [ -z "$OUTPUT" ]; then + echo "ERROR: TEST_OUTPUT is empty" + exit 1 + fi + + echo "SUCCESS: SLSA verification test passed" + runAfter: + - run-task diff --git a/task/verify-source/0.1/verify-source.yaml b/task/verify-source/0.1/verify-source.yaml new file mode 100644 index 0000000000..6542cd583d --- /dev/null +++ b/task/verify-source/0.1/verify-source.yaml @@ -0,0 +1,131 @@ +--- +apiVersion: tekton.dev/v1 +kind: Task +metadata: + name: verify-source + annotations: + tekton.dev/pipelines.minVersion: 0.21.0 + tekton.dev/tags: security, slsa + labels: + app.kubernetes.io/version: "0.1" +spec: + description: | + The verify-source Task verifies the SLSA source level of a git commit + by checking for a Verification Summary Attestation (VSA) stored as a + git note. This task does not explicitly clone the repository - it performs + the verification using the sourcetool verifycommit command. + params: + - name: url + description: Repository URL to verify. + type: string + - name: revision + description: Commit SHA to verify. + type: string + results: + - name: SLSA_SOURCE_LEVEL_ACHIEVED + description: The SLSA source level achieved by this commit + - name: TEST_OUTPUT + description: JSON formatted test results for SLSA verification + steps: + - name: slsa-verify + image: quay.io/konflux-ci/git-clone@sha256:bd303d16e9d9b01622d69deff77c583ebdea36611b15dc243da658d93763e8de + env: + - name: PARAM_URL + value: $(params.url) + - name: PARAM_REVISION + value: $(params.revision) + script: | + #!/usr/bin/env bash + set -euo pipefail + + # Initialize variables + REPO_URL="${PARAM_URL}" + COMMIT_SHA="${PARAM_REVISION}" + + # Extract repository information + REPO_HOST=$(echo "$REPO_URL" | awk -F/ '{print $3}') + REPO_OWNER=$(echo "$REPO_URL" | awk -F/ '{print $4}') + REPO_NAME=$(echo "$REPO_URL" | awk -F/ '{print $5}' | sed 's/\.git$//') + + echo "=== SLSA Source Verification ===" + echo "Repository: $REPO_HOST/$REPO_OWNER/$REPO_NAME" + echo "Commit: $COMMIT_SHA" + + # Initialize test results + VERIFICATION_RESULT="PASSED" + ACHIEVED_LEVEL="SLSA_SOURCE_LEVEL_1" + SUCCESSES=0 + FAILURES=0 + WARNINGS=0 + TESTS=() + + # Attempt to verify with source-tool + echo "Running SLSA source verification..." + + # Try to verify the commit using source-tool + # Note: sourcetool returns exit code 0 even on failure, so we check output + VERIFICATION_LOG=$(mktemp) + sourcetool verifycommit \ + --commit "$COMMIT_SHA" \ + --owner "$REPO_OWNER" \ + --repo "$REPO_NAME" 2>&1 | tee "$VERIFICATION_LOG" + + if grep -q "FAILED:" "$VERIFICATION_LOG"; then + echo "Source-tool verification failed - no VSA found in repository" + WARNINGS=$((WARNINGS + 1)) + TESTS+=('{"name":"source-tool-execution","result":"WARNING"}') + # Fallback to basic level 1 + ACHIEVED_LEVEL="SLSA_SOURCE_LEVEL_1" + else + echo "Source-tool verification PASSED - VSA found in repository" + SUCCESSES=$((SUCCESSES + 1)) + TESTS+=('{"name":"source-tool-execution","result":"PASSED"}') + + # Extract the actual SLSA level from sourcetool output + # Format: "SUCCESS: commit ... verified with [SLSA_SOURCE_LEVEL_3 TAG_HYGIENE]" + EXTRACTED_LEVEL=$(grep -oP '\[SLSA_SOURCE_LEVEL_\d+' "$VERIFICATION_LOG" | sed 's/\[//') + + if [ -n "$EXTRACTED_LEVEL" ]; then + ACHIEVED_LEVEL="$EXTRACTED_LEVEL" + echo "Extracted SLSA level from VSA: $ACHIEVED_LEVEL" + else + # Fallback if we can't parse the level + # Any repo is SLSA Source L1 if it exists in source control + ACHIEVED_LEVEL="SLSA_SOURCE_LEVEL_1" + echo "Could not extract SLSA level, defaulting to: $ACHIEVED_LEVEL" + fi + fi + + SUCCESSES=$((SUCCESSES + 1)) + TESTS+=('{"name":"slsa-level-determination","result":"PASSED"}') + + # Generate test output JSON + TESTS_JSON=$(printf '%s\n' "${TESTS[@]}" | paste -sd ',' -) + + TEST_OUTPUT=$( + cat <"$(results.SLSA_SOURCE_LEVEL_ACHIEVED.path)" + echo "$TEST_OUTPUT" >"$(results.TEST_OUTPUT.path)" + + echo "=== SLSA Verification Summary ===" + echo "Result: $VERIFICATION_RESULT" + echo "Achieved Level: $ACHIEVED_LEVEL" + echo "Successes: $SUCCESSES, Failures: $FAILURES, Warnings: $WARNINGS" + + # Clean up + rm -f "$VERIFICATION_LOG" + securityContext: + runAsUser: 0 From 3ace5123ad666d02639e9d8c7d58bb3bb804feb3 Mon Sep 17 00:00:00 2001 From: Ralph Bean Date: Thu, 9 Oct 2025 11:45:27 -0400 Subject: [PATCH 2/7] fix: add POC warning and fix CODEOWNERS for verify-source - Add warning to task description noting that source-tool is a proof-of-concept, not production-ready - Mention GitHub-only support and potential rate limiting - Fix CODEOWNERS entry from /task/run-script-oci-ta to /task/verify-source Assisted-by: Claude Code Signed-off-by: Ralph Bean --- CODEOWNERS | 2 +- task/verify-source/0.1/README.md | 5 +++++ task/verify-source/0.1/verify-source.yaml | 5 +++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/CODEOWNERS b/CODEOWNERS index 707bf10969..7c0d85bdf2 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -129,7 +129,7 @@ /task/run-script-oci-ta @konflux-ci/build-maintainers @Zokormazo @arewm # renovate groupName=verify-source -/task/run-script-oci-ta @arewm @ralphbean +/task/verify-source @arewm @ralphbean # These are auto-generated and often require changes when tasks change. # Allow anyone with write access to approve the changes. diff --git a/task/verify-source/0.1/README.md b/task/verify-source/0.1/README.md index 11000f9e9b..84945694fd 100644 --- a/task/verify-source/0.1/README.md +++ b/task/verify-source/0.1/README.md @@ -5,6 +5,11 @@ by checking for a Verification Summary Attestation (VSA) stored as a git note. This task does not explicitly clone the repository - it performs the verification using the sourcetool verifycommit command. +WARNING: This task uses source-tool (https://github.com/slsa-framework/source-tool) +which is currently a proof-of-concept and under active development. It should +not be used in production environments. Additionally, it currently only supports +GitHub repositories and may encounter API rate limits without authentication. + ## Parameters |name|description|default value|required| diff --git a/task/verify-source/0.1/verify-source.yaml b/task/verify-source/0.1/verify-source.yaml index 6542cd583d..b8e6a23dff 100644 --- a/task/verify-source/0.1/verify-source.yaml +++ b/task/verify-source/0.1/verify-source.yaml @@ -14,6 +14,11 @@ spec: by checking for a Verification Summary Attestation (VSA) stored as a git note. This task does not explicitly clone the repository - it performs the verification using the sourcetool verifycommit command. + + WARNING: This task uses source-tool (https://github.com/slsa-framework/source-tool) + which is currently a proof-of-concept and under active development. It should + not be used in production environments. Additionally, it currently only supports + GitHub repositories and may encounter API rate limits without authentication. params: - name: url description: Repository URL to verify. From 22c2542efdccc581c5c88bbb5e7374d0df30a70c Mon Sep 17 00:00:00 2001 From: Ralph Bean Date: Thu, 9 Oct 2025 11:52:21 -0400 Subject: [PATCH 3/7] feat: add GitHub token support to verify-source task Add optional basic-auth workspace to provide GitHub authentication token to avoid API rate limits. The task looks for a 'token' file in the workspace and passes it to sourcetool via --github_token. Includes documentation and examples in the README showing how to create a secret and use it with the task. Assisted-by: Claude Code Signed-off-by: Ralph Bean --- task/verify-source/0.1/README.md | 38 +++++++++++++++++++++++ task/verify-source/0.1/verify-source.yaml | 34 +++++++++++++++++--- 2 files changed, 68 insertions(+), 4 deletions(-) diff --git a/task/verify-source/0.1/README.md b/task/verify-source/0.1/README.md index 84945694fd..f1d36727c3 100644 --- a/task/verify-source/0.1/README.md +++ b/task/verify-source/0.1/README.md @@ -23,5 +23,43 @@ GitHub repositories and may encounter API rate limits without authentication. |SLSA_SOURCE_LEVEL_ACHIEVED|The SLSA source level achieved by this commit| |TEST_OUTPUT|JSON formatted test results for SLSA verification| +## Workspaces +|name|description|optional| +|---|---|---| +|basic-auth|A Workspace containing a token file for GitHub API authentication. The workspace should contain a file named 'token' with a GitHub personal access token or other authentication token. This is used to avoid rate limiting when accessing the GitHub API. Binding a Secret to this Workspace is strongly recommended over other volume types. |true| ## Additional info + +### GitHub Authentication + +To avoid GitHub API rate limits, you can provide a GitHub token via the `basic-auth` workspace. + +**Create a secret with your GitHub token:** + +```bash +kubectl create secret generic github-token \ + --from-literal=token=ghp_yourTokenHere +``` + +**Use the secret in your pipeline:** + +```yaml +apiVersion: tekton.dev/v1 +kind: TaskRun +metadata: + name: verify-source-example +spec: + taskRef: + name: verify-source + params: + - name: url + value: https://github.com/slsa-framework/source-tool + - name: revision + value: 134593d9158efd253e979e2e8d87b939945d091e + workspaces: + - name: basic-auth + secret: + secretName: github-token +``` + +The task will automatically detect the `token` file in the workspace and use it for GitHub API authentication. diff --git a/task/verify-source/0.1/verify-source.yaml b/task/verify-source/0.1/verify-source.yaml index b8e6a23dff..2a40543c76 100644 --- a/task/verify-source/0.1/verify-source.yaml +++ b/task/verify-source/0.1/verify-source.yaml @@ -31,6 +31,15 @@ spec: description: The SLSA source level achieved by this commit - name: TEST_OUTPUT description: JSON formatted test results for SLSA verification + workspaces: + - name: basic-auth + description: | + A Workspace containing a token file for GitHub API authentication. + The workspace should contain a file named 'token' with a GitHub + personal access token or other authentication token. This is used + to avoid rate limiting when accessing the GitHub API. Binding a + Secret to this Workspace is strongly recommended over other volume types. + optional: true steps: - name: slsa-verify image: quay.io/konflux-ci/git-clone@sha256:bd303d16e9d9b01622d69deff77c583ebdea36611b15dc243da658d93763e8de @@ -39,6 +48,10 @@ spec: value: $(params.url) - name: PARAM_REVISION value: $(params.revision) + - 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 bash set -euo pipefail @@ -52,6 +65,15 @@ spec: REPO_OWNER=$(echo "$REPO_URL" | awk -F/ '{print $4}') REPO_NAME=$(echo "$REPO_URL" | awk -F/ '{print $5}' | sed 's/\.git$//') + # Check for GitHub token in workspace + GITHUB_TOKEN="" + if [ "${WORKSPACE_BASIC_AUTH_DIRECTORY_BOUND}" = "true" ]; then + if [ -f "${WORKSPACE_BASIC_AUTH_DIRECTORY_PATH}/token" ]; then + GITHUB_TOKEN=$(cat "${WORKSPACE_BASIC_AUTH_DIRECTORY_PATH}/token") + echo "Using GitHub token from workspace for authentication" + fi + fi + echo "=== SLSA Source Verification ===" echo "Repository: $REPO_HOST/$REPO_OWNER/$REPO_NAME" echo "Commit: $COMMIT_SHA" @@ -70,10 +92,14 @@ spec: # Try to verify the commit using source-tool # Note: sourcetool returns exit code 0 even on failure, so we check output VERIFICATION_LOG=$(mktemp) - sourcetool verifycommit \ - --commit "$COMMIT_SHA" \ - --owner "$REPO_OWNER" \ - --repo "$REPO_NAME" 2>&1 | tee "$VERIFICATION_LOG" + + # Build sourcetool command with optional token + SOURCETOOL_CMD="sourcetool verifycommit --commit $COMMIT_SHA --owner $REPO_OWNER --repo $REPO_NAME" + if [ -n "$GITHUB_TOKEN" ]; then + SOURCETOOL_CMD="$SOURCETOOL_CMD --github_token $GITHUB_TOKEN" + fi + + eval "$SOURCETOOL_CMD" 2>&1 | tee "$VERIFICATION_LOG" if grep -q "FAILED:" "$VERIFICATION_LOG"; then echo "Source-tool verification failed - no VSA found in repository" From 4099f1249f27b8ceb8696aecb07ae3ab2c603907 Mon Sep 17 00:00:00 2001 From: Ralph Bean Date: Thu, 9 Oct 2025 12:38:52 -0400 Subject: [PATCH 4/7] refactor: use env vars for token auth in verify-source Instead of passing tokens as command-line arguments (which may be logged), the task now sets environment variables (GITHUB_TOKEN or GITLAB_TOKEN) based on the repository host. This allows sourcetool to passively pick up the credentials without exposing them in logs. Changes: - Detect repo host and set appropriate env var (GITHUB_TOKEN/GITLAB_TOKEN) - Remove command-line flag approach - Update task description to mention GitLab support - Update workspace description for both GitHub and GitLab - Update README with examples for both platforms Assisted-by: Claude Code Signed-off-by: Ralph Bean --- task/verify-source/0.1/README.md | 25 +++++++----- task/verify-source/0.1/verify-source.yaml | 48 ++++++++++++++--------- 2 files changed, 45 insertions(+), 28 deletions(-) diff --git a/task/verify-source/0.1/README.md b/task/verify-source/0.1/README.md index f1d36727c3..5bfecbb00b 100644 --- a/task/verify-source/0.1/README.md +++ b/task/verify-source/0.1/README.md @@ -7,8 +7,8 @@ the verification using the sourcetool verifycommit command. WARNING: This task uses source-tool (https://github.com/slsa-framework/source-tool) which is currently a proof-of-concept and under active development. It should -not be used in production environments. Additionally, it currently only supports -GitHub repositories and may encounter API rate limits without authentication. +not be used in production environments. It supports GitHub and GitLab repositories, +and may encounter API rate limits without authentication. ## Parameters @@ -26,19 +26,24 @@ GitHub repositories and may encounter API rate limits without authentication. ## Workspaces |name|description|optional| |---|---|---| -|basic-auth|A Workspace containing a token file for GitHub API authentication. The workspace should contain a file named 'token' with a GitHub personal access token or other authentication token. This is used to avoid rate limiting when accessing the GitHub API. Binding a Secret to this Workspace is strongly recommended over other volume types. |true| +|basic-auth|A Workspace containing a token file for API authentication. The workspace should contain a file named 'token' with a GitHub personal access token, GitLab personal access token, or other authentication token. The task will automatically set the appropriate environment variable (GITHUB_TOKEN or GITLAB_TOKEN) based on the repository host. This is used to avoid rate limiting when accessing the API. Binding a Secret to this Workspace is strongly recommended over other volume types. |true| ## Additional info -### GitHub Authentication +### API Authentication -To avoid GitHub API rate limits, you can provide a GitHub token via the `basic-auth` workspace. +To avoid API rate limits, you can provide an authentication token via the `basic-auth` workspace. The task automatically detects the repository host and sets the appropriate environment variable (`GITHUB_TOKEN` for GitHub, `GITLAB_TOKEN` for GitLab). -**Create a secret with your GitHub token:** +**Create a secret with your token:** ```bash -kubectl create secret generic github-token \ - --from-literal=token=ghp_yourTokenHere +# For GitHub +kubectl create secret generic git-token \ + --from-literal=token=ghp_yourGitHubTokenHere + +# For GitLab +kubectl create secret generic git-token \ + --from-literal=token=glpat-yourGitLabTokenHere ``` **Use the secret in your pipeline:** @@ -59,7 +64,7 @@ spec: workspaces: - name: basic-auth secret: - secretName: github-token + secretName: git-token ``` -The task will automatically detect the `token` file in the workspace and use it for GitHub API authentication. +The task will automatically detect the `token` file in the workspace and set the appropriate environment variable based on the repository URL. diff --git a/task/verify-source/0.1/verify-source.yaml b/task/verify-source/0.1/verify-source.yaml index 2a40543c76..16dd8748f2 100644 --- a/task/verify-source/0.1/verify-source.yaml +++ b/task/verify-source/0.1/verify-source.yaml @@ -17,8 +17,8 @@ spec: WARNING: This task uses source-tool (https://github.com/slsa-framework/source-tool) which is currently a proof-of-concept and under active development. It should - not be used in production environments. Additionally, it currently only supports - GitHub repositories and may encounter API rate limits without authentication. + not be used in production environments. It supports GitHub and GitLab repositories, + and may encounter API rate limits without authentication. params: - name: url description: Repository URL to verify. @@ -34,11 +34,14 @@ spec: workspaces: - name: basic-auth description: | - A Workspace containing a token file for GitHub API authentication. + A Workspace containing a token file for API authentication. The workspace should contain a file named 'token' with a GitHub - personal access token or other authentication token. This is used - to avoid rate limiting when accessing the GitHub API. Binding a - Secret to this Workspace is strongly recommended over other volume types. + personal access token, GitLab personal access token, or other + authentication token. The task will automatically set the appropriate + environment variable (GITHUB_TOKEN or GITLAB_TOKEN) based on the + repository host. This is used to avoid rate limiting when accessing + the API. Binding a Secret to this Workspace is strongly recommended + over other volume types. optional: true steps: - name: slsa-verify @@ -65,12 +68,25 @@ spec: REPO_OWNER=$(echo "$REPO_URL" | awk -F/ '{print $4}') REPO_NAME=$(echo "$REPO_URL" | awk -F/ '{print $5}' | sed 's/\.git$//') - # Check for GitHub token in workspace - GITHUB_TOKEN="" + # Check for token in workspace and set appropriate environment variable if [ "${WORKSPACE_BASIC_AUTH_DIRECTORY_BOUND}" = "true" ]; then if [ -f "${WORKSPACE_BASIC_AUTH_DIRECTORY_PATH}/token" ]; then - GITHUB_TOKEN=$(cat "${WORKSPACE_BASIC_AUTH_DIRECTORY_PATH}/token") - echo "Using GitHub token from workspace for authentication" + TOKEN=$(cat "${WORKSPACE_BASIC_AUTH_DIRECTORY_PATH}/token") + + # Set appropriate environment variable based on repo host + case "$REPO_HOST" in + *github.com) + export GITHUB_TOKEN="$TOKEN" + echo "Using GitHub token from workspace for authentication" + ;; + *gitlab.com|*gitlab.*) + export GITLAB_TOKEN="$TOKEN" + echo "Using GitLab token from workspace for authentication" + ;; + *) + echo "Warning: Unknown host $REPO_HOST, token authentication may not work" + ;; + esac fi fi @@ -92,14 +108,10 @@ spec: # Try to verify the commit using source-tool # Note: sourcetool returns exit code 0 even on failure, so we check output VERIFICATION_LOG=$(mktemp) - - # Build sourcetool command with optional token - SOURCETOOL_CMD="sourcetool verifycommit --commit $COMMIT_SHA --owner $REPO_OWNER --repo $REPO_NAME" - if [ -n "$GITHUB_TOKEN" ]; then - SOURCETOOL_CMD="$SOURCETOOL_CMD --github_token $GITHUB_TOKEN" - fi - - eval "$SOURCETOOL_CMD" 2>&1 | tee "$VERIFICATION_LOG" + sourcetool verifycommit \ + --commit "$COMMIT_SHA" \ + --owner "$REPO_OWNER" \ + --repo "$REPO_NAME" 2>&1 | tee "$VERIFICATION_LOG" if grep -q "FAILED:" "$VERIFICATION_LOG"; then echo "Source-tool verification failed - no VSA found in repository" From 999cf218f626835e7ddf4e9be3359a52f0fa8d04 Mon Sep 17 00:00:00 2001 From: Ralph Bean Date: Thu, 9 Oct 2025 14:57:15 -0400 Subject: [PATCH 5/7] refactor: rename sourcetool to source-tool in verify-source Update all references from sourcetool to source-tool to match the correct command name throughout the verify-source task. Assisted-by: Claude Code Signed-off-by: Ralph Bean --- task/verify-source/0.1/README.md | 2 +- task/verify-source/0.1/verify-source.yaml | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/task/verify-source/0.1/README.md b/task/verify-source/0.1/README.md index 5bfecbb00b..1083687bc6 100644 --- a/task/verify-source/0.1/README.md +++ b/task/verify-source/0.1/README.md @@ -3,7 +3,7 @@ The verify-source Task verifies the SLSA source level of a git commit by checking for a Verification Summary Attestation (VSA) stored as a git note. This task does not explicitly clone the repository - it performs -the verification using the sourcetool verifycommit command. +the verification using the source-tool verifycommit command. WARNING: This task uses source-tool (https://github.com/slsa-framework/source-tool) which is currently a proof-of-concept and under active development. It should diff --git a/task/verify-source/0.1/verify-source.yaml b/task/verify-source/0.1/verify-source.yaml index 16dd8748f2..c3854bbfd3 100644 --- a/task/verify-source/0.1/verify-source.yaml +++ b/task/verify-source/0.1/verify-source.yaml @@ -13,7 +13,7 @@ spec: The verify-source Task verifies the SLSA source level of a git commit by checking for a Verification Summary Attestation (VSA) stored as a git note. This task does not explicitly clone the repository - it performs - the verification using the sourcetool verifycommit command. + the verification using the source-tool verifycommit command. WARNING: This task uses source-tool (https://github.com/slsa-framework/source-tool) which is currently a proof-of-concept and under active development. It should @@ -106,9 +106,9 @@ spec: echo "Running SLSA source verification..." # Try to verify the commit using source-tool - # Note: sourcetool returns exit code 0 even on failure, so we check output + # Note: source-tool returns exit code 0 even on failure, so we check output VERIFICATION_LOG=$(mktemp) - sourcetool verifycommit \ + source-tool verifycommit \ --commit "$COMMIT_SHA" \ --owner "$REPO_OWNER" \ --repo "$REPO_NAME" 2>&1 | tee "$VERIFICATION_LOG" @@ -124,7 +124,7 @@ spec: SUCCESSES=$((SUCCESSES + 1)) TESTS+=('{"name":"source-tool-execution","result":"PASSED"}') - # Extract the actual SLSA level from sourcetool output + # Extract the actual SLSA level from source-tool output # Format: "SUCCESS: commit ... verified with [SLSA_SOURCE_LEVEL_3 TAG_HYGIENE]" EXTRACTED_LEVEL=$(grep -oP '\[SLSA_SOURCE_LEVEL_\d+' "$VERIFICATION_LOG" | sed 's/\[//') From 901f833dad7b9e18e49d0e34156c90c839e0515f Mon Sep 17 00:00:00 2001 From: Ralph Bean Date: Thu, 9 Oct 2025 15:59:47 -0400 Subject: [PATCH 6/7] refactor: parse VSA directly instead of log output Update verify-source task to fetch git notes and parse the VSA JSON directly to extract SLSA source level, instead of relying on parsing source-tool command output. This approach is more reliable and maintainable. The task now: - Fetches git notes (refs/notes/commits) from the repository - Parses the VSA JSON structure - Decodes the base64 payload to extract verifiedLevels Assisted-by: Claude Code Signed-off-by: Ralph Bean --- task/verify-source/0.1/README.md | 11 ++- task/verify-source/0.1/verify-source.yaml | 110 +++++++++++++++------- 2 files changed, 80 insertions(+), 41 deletions(-) diff --git a/task/verify-source/0.1/README.md b/task/verify-source/0.1/README.md index 1083687bc6..7ed2783c20 100644 --- a/task/verify-source/0.1/README.md +++ b/task/verify-source/0.1/README.md @@ -2,12 +2,13 @@ The verify-source Task verifies the SLSA source level of a git commit by checking for a Verification Summary Attestation (VSA) stored as a -git note. This task does not explicitly clone the repository - it performs -the verification using the source-tool verifycommit command. +git note. The task fetches git notes from the repository and parses +the VSA to extract the verified SLSA source level. -WARNING: This task uses source-tool (https://github.com/slsa-framework/source-tool) -which is currently a proof-of-concept and under active development. It should -not be used in production environments. It supports GitHub and GitLab repositories, +WARNING: This task relies on VSAs generated by source-tool +(https://github.com/slsa-framework/source-tool) which is currently a +proof-of-concept and under active development. It should not be used in +production environments. It supports GitHub and GitLab repositories, and may encounter API rate limits without authentication. diff --git a/task/verify-source/0.1/verify-source.yaml b/task/verify-source/0.1/verify-source.yaml index c3854bbfd3..459b1c13d0 100644 --- a/task/verify-source/0.1/verify-source.yaml +++ b/task/verify-source/0.1/verify-source.yaml @@ -12,12 +12,13 @@ spec: description: | The verify-source Task verifies the SLSA source level of a git commit by checking for a Verification Summary Attestation (VSA) stored as a - git note. This task does not explicitly clone the repository - it performs - the verification using the source-tool verifycommit command. + git note. The task fetches git notes from the repository and parses + the VSA to extract the verified SLSA source level. - WARNING: This task uses source-tool (https://github.com/slsa-framework/source-tool) - which is currently a proof-of-concept and under active development. It should - not be used in production environments. It supports GitHub and GitLab repositories, + WARNING: This task relies on VSAs generated by source-tool + (https://github.com/slsa-framework/source-tool) which is currently a + proof-of-concept and under active development. It should not be used in + production environments. It supports GitHub and GitLab repositories, and may encounter API rate limits without authentication. params: - name: url @@ -102,43 +103,83 @@ spec: WARNINGS=0 TESTS=() - # Attempt to verify with source-tool + # Attempt to verify with source-tool and fetch VSA echo "Running SLSA source verification..." - # Try to verify the commit using source-tool - # Note: source-tool returns exit code 0 even on failure, so we check output - VERIFICATION_LOG=$(mktemp) - source-tool verifycommit \ - --commit "$COMMIT_SHA" \ - --owner "$REPO_OWNER" \ - --repo "$REPO_NAME" 2>&1 | tee "$VERIFICATION_LOG" + # Create a temporary directory for git operations + TEMP_DIR=$(mktemp -d) + cd "$TEMP_DIR" - if grep -q "FAILED:" "$VERIFICATION_LOG"; then - echo "Source-tool verification failed - no VSA found in repository" - WARNINGS=$((WARNINGS + 1)) - TESTS+=('{"name":"source-tool-execution","result":"WARNING"}') - # Fallback to basic level 1 - ACHIEVED_LEVEL="SLSA_SOURCE_LEVEL_1" - else - echo "Source-tool verification PASSED - VSA found in repository" - SUCCESSES=$((SUCCESSES + 1)) - TESTS+=('{"name":"source-tool-execution","result":"PASSED"}') + # Initialize a bare repository and fetch only the notes + git init --bare repo.git + cd repo.git - # Extract the actual SLSA level from source-tool output - # Format: "SUCCESS: commit ... verified with [SLSA_SOURCE_LEVEL_3 TAG_HYGIENE]" - EXTRACTED_LEVEL=$(grep -oP '\[SLSA_SOURCE_LEVEL_\d+' "$VERIFICATION_LOG" | sed 's/\[//') + # Fetch the git notes containing VSAs + # Note: We only fetch notes, not the entire repository + if git fetch "$REPO_URL" 'refs/notes/commits:refs/notes/commits' 2>&1; then + echo "Successfully fetched git notes from repository" - if [ -n "$EXTRACTED_LEVEL" ]; then - ACHIEVED_LEVEL="$EXTRACTED_LEVEL" - echo "Extracted SLSA level from VSA: $ACHIEVED_LEVEL" - else - # Fallback if we can't parse the level - # Any repo is SLSA Source L1 if it exists in source control + # Try to get the VSA for this commit + VSA_NOTE=$(git notes --ref=commits show "$COMMIT_SHA" 2>/dev/null || echo "") + + if [ -z "$VSA_NOTE" ]; then + echo "No VSA found in git notes for this commit" + WARNINGS=$((WARNINGS + 1)) + TESTS+=('{"name":"vsa-fetch","result":"WARNING"}') + # Fallback to basic level 1 ACHIEVED_LEVEL="SLSA_SOURCE_LEVEL_1" - echo "Could not extract SLSA level, defaulting to: $ACHIEVED_LEVEL" + else + echo "VSA found in git notes" + SUCCESSES=$((SUCCESSES + 1)) + TESTS+=('{"name":"vsa-fetch","result":"PASSED"}') + + # Parse the VSA to extract the SLSA level + # VSA note contains two JSON objects - the second one has the actual VSA + # Extract the second JSON object and decode its payload using bash tools + VSA_JSON=$(echo "$VSA_NOTE" | tail -1) + + # Extract the base64 payload from dsseEnvelope.payload field + PAYLOAD_B64=$(echo "$VSA_JSON" | grep -o '"payload":"[^"]*"' | sed 's/"payload":"//;s/"$//') + + if [ -n "$PAYLOAD_B64" ]; then + # Decode the payload + DECODED_PAYLOAD=$(echo "$PAYLOAD_B64" | base64 -d 2>/dev/null || echo "") + + if [ -n "$DECODED_PAYLOAD" ]; then + # Extract verifiedLevels array - look for "verifiedLevels":["SLSA_SOURCE_LEVEL_X"] + EXTRACTED_LEVEL=$(echo "$DECODED_PAYLOAD" | \ + grep -o '"verifiedLevels":\["[^"]*"' | \ + sed 's/"verifiedLevels":\["\([^"]*\)"/\1/') + + if [ -n "$EXTRACTED_LEVEL" ]; then + ACHIEVED_LEVEL="$EXTRACTED_LEVEL" + echo "Extracted SLSA level from VSA: $ACHIEVED_LEVEL" + else + # Fallback if we can't parse the level + ACHIEVED_LEVEL="SLSA_SOURCE_LEVEL_1" + echo "Could not parse SLSA level from VSA, defaulting to: $ACHIEVED_LEVEL" + fi + else + ACHIEVED_LEVEL="SLSA_SOURCE_LEVEL_1" + echo "Could not decode VSA payload, defaulting to: $ACHIEVED_LEVEL" + fi + else + ACHIEVED_LEVEL="SLSA_SOURCE_LEVEL_1" + echo "Could not extract payload from VSA, defaulting to: $ACHIEVED_LEVEL" + fi fi + else + echo "Failed to fetch git notes from repository" + WARNINGS=$((WARNINGS + 1)) + TESTS+=('{"name":"vsa-fetch","result":"WARNING"}') + # Fallback to basic level 1 + ACHIEVED_LEVEL="SLSA_SOURCE_LEVEL_1" fi + # Clean up temp directory + cd / + rm -rf "$TEMP_DIR" + SUCCESSES=$((SUCCESSES + 1)) TESTS+=('{"name":"slsa-level-determination","result":"PASSED"}') @@ -167,8 +208,5 @@ spec: echo "Result: $VERIFICATION_RESULT" echo "Achieved Level: $ACHIEVED_LEVEL" echo "Successes: $SUCCESSES, Failures: $FAILURES, Warnings: $WARNINGS" - - # Clean up - rm -f "$VERIFICATION_LOG" securityContext: runAsUser: 0 From c786f52d9f345fbde326865294390876f9db5716 Mon Sep 17 00:00:00 2001 From: Ralph Bean Date: Thu, 9 Oct 2025 16:09:13 -0400 Subject: [PATCH 7/7] refactor: simplify VSA parsing script Reduce deep nesting in the verification script: - Inverted git fetch condition for early exit - Flattened VSA parsing by chaining operations linearly - Removed redundant SLSA_SOURCE_LEVEL_1 fallback assignments (already set as default at initialization) - Consolidated cleanup commands This reduces nesting from 5-6 levels down to 2-3 levels max, making the code more readable and maintainable. Tests pass: both with-vsa and no-vsa scenarios work correctly. Assisted-by: Claude Code Signed-off-by: Ralph Bean --- task/verify-source/0.1/verify-source.yaml | 67 +++++++---------------- 1 file changed, 21 insertions(+), 46 deletions(-) diff --git a/task/verify-source/0.1/verify-source.yaml b/task/verify-source/0.1/verify-source.yaml index 459b1c13d0..ffdf7e0797 100644 --- a/task/verify-source/0.1/verify-source.yaml +++ b/task/verify-source/0.1/verify-source.yaml @@ -103,20 +103,22 @@ spec: WARNINGS=0 TESTS=() - # Attempt to verify with source-tool and fetch VSA + # Attempt to fetch and parse VSA from git notes echo "Running SLSA source verification..." # Create a temporary directory for git operations TEMP_DIR=$(mktemp -d) cd "$TEMP_DIR" - - # Initialize a bare repository and fetch only the notes git init --bare repo.git cd repo.git - # Fetch the git notes containing VSAs - # Note: We only fetch notes, not the entire repository - if git fetch "$REPO_URL" 'refs/notes/commits:refs/notes/commits' 2>&1; then + # Fetch the git notes containing VSAs (only notes, not the entire repository) + if ! git fetch "$REPO_URL" 'refs/notes/commits:refs/notes/commits' 2>&1; then + echo "Failed to fetch git notes from repository" + WARNINGS=$((WARNINGS + 1)) + TESTS+=('{"name":"vsa-fetch","result":"WARNING"}') + cd / && rm -rf "$TEMP_DIR" + else echo "Successfully fetched git notes from repository" # Try to get the VSA for this commit @@ -126,8 +128,6 @@ spec: echo "No VSA found in git notes for this commit" WARNINGS=$((WARNINGS + 1)) TESTS+=('{"name":"vsa-fetch","result":"WARNING"}') - # Fallback to basic level 1 - ACHIEVED_LEVEL="SLSA_SOURCE_LEVEL_1" else echo "VSA found in git notes" SUCCESSES=$((SUCCESSES + 1)) @@ -135,50 +135,25 @@ spec: # Parse the VSA to extract the SLSA level # VSA note contains two JSON objects - the second one has the actual VSA - # Extract the second JSON object and decode its payload using bash tools + # Extract and decode the payload, then parse verifiedLevels field VSA_JSON=$(echo "$VSA_NOTE" | tail -1) - - # Extract the base64 payload from dsseEnvelope.payload field PAYLOAD_B64=$(echo "$VSA_JSON" | grep -o '"payload":"[^"]*"' | sed 's/"payload":"//;s/"$//') - - if [ -n "$PAYLOAD_B64" ]; then - # Decode the payload - DECODED_PAYLOAD=$(echo "$PAYLOAD_B64" | base64 -d 2>/dev/null || echo "") - - if [ -n "$DECODED_PAYLOAD" ]; then - # Extract verifiedLevels array - look for "verifiedLevels":["SLSA_SOURCE_LEVEL_X"] - EXTRACTED_LEVEL=$(echo "$DECODED_PAYLOAD" | \ - grep -o '"verifiedLevels":\["[^"]*"' | \ - sed 's/"verifiedLevels":\["\([^"]*\)"/\1/') - - if [ -n "$EXTRACTED_LEVEL" ]; then - ACHIEVED_LEVEL="$EXTRACTED_LEVEL" - echo "Extracted SLSA level from VSA: $ACHIEVED_LEVEL" - else - # Fallback if we can't parse the level - ACHIEVED_LEVEL="SLSA_SOURCE_LEVEL_1" - echo "Could not parse SLSA level from VSA, defaulting to: $ACHIEVED_LEVEL" - fi - else - ACHIEVED_LEVEL="SLSA_SOURCE_LEVEL_1" - echo "Could not decode VSA payload, defaulting to: $ACHIEVED_LEVEL" - fi + DECODED_PAYLOAD=$(echo "$PAYLOAD_B64" | base64 -d 2>/dev/null || echo "") + EXTRACTED_LEVEL=$(echo "$DECODED_PAYLOAD" | \ + grep -o '"verifiedLevels":\["[^"]*"' | \ + sed 's/"verifiedLevels":\["\([^"]*\)"/\1/') + + if [ -n "$EXTRACTED_LEVEL" ]; then + ACHIEVED_LEVEL="$EXTRACTED_LEVEL" + echo "Extracted SLSA level from VSA: $ACHIEVED_LEVEL" else - ACHIEVED_LEVEL="SLSA_SOURCE_LEVEL_1" - echo "Could not extract payload from VSA, defaulting to: $ACHIEVED_LEVEL" + echo "Could not parse SLSA level from VSA, using default: $ACHIEVED_LEVEL" fi fi - else - echo "Failed to fetch git notes from repository" - WARNINGS=$((WARNINGS + 1)) - TESTS+=('{"name":"vsa-fetch","result":"WARNING"}') - # Fallback to basic level 1 - ACHIEVED_LEVEL="SLSA_SOURCE_LEVEL_1" - fi - # Clean up temp directory - cd / - rm -rf "$TEMP_DIR" + # Clean up temp directory + cd / && rm -rf "$TEMP_DIR" + fi SUCCESSES=$((SUCCESSES + 1)) TESTS+=('{"name":"slsa-level-determination","result":"PASSED"}')