Sfoglia il codice sorgente

fix(ci): drop jq dependency and only sign tag-triggered releases

  * Generate the SLSA v1 provenance predicate with `python3` (preinstalled
    on every standard GitHub-hosted runner) instead of `jq`. Removes an
    implicit toolchain dependency that could silently break on minimal or
    container-based runners, and `json.dumps` handles escaping of any
    future non-trivial values cleanly.
  * Gate the release-workflow signing step on `github.event_name == 'push'`.
    A `workflow_dispatch` invocation produces a non-tag `GITHUB_REF`, which
    Fulcio would embed into the certificate identity, breaking the
    `refs/tags/vX.Y.Z` verification pattern documented in SECURITY.md.
    Manual re-runs now produce an unsigned image — the correct behaviour,
    since the canonical release path is a tag push.

Signed-off-by: Warwick Peatey <warwick@automatic.systems>
Assisted-by: Claude Code
Warwick Peatey 2 mesi fa
parent
commit
1574560730

+ 39 - 34
.github/actions/sign-image/action.yaml

@@ -62,41 +62,46 @@ runs:
         run: |
           set -euo pipefail
           RESOLVED_GIT_COMMIT="$(git rev-parse HEAD)"
-          jq -n \
-            --arg workflow_ref   "${GITHUB_REF}"                                 \
-            --arg repo_url       "https://github.com/${GITHUB_REPOSITORY}"       \
-            --arg workflow_path  "${WORKFLOW_PATH}"                              \
-            --arg source_uri     "git+https://github.com/${GITHUB_REPOSITORY}@${RESOLVED_GIT_COMMIT}" \
-            --arg git_commit     "${RESOLVED_GIT_COMMIT}"                        \
-            --arg builder_id     "https://github.com/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}" \
-            --arg invocation_id  "https://github.com/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}/attempts/${GITHUB_RUN_ATTEMPT}" \
-            --arg started_on     "${STARTED_ON}" \
-            '{
-              buildDefinition: {
-                buildType: "https://github.com/opencost/opencost/build/workflow@v1",
-                externalParameters: {
-                  workflow: {
-                    ref: $workflow_ref,
-                    repository: $repo_url,
-                    path: $workflow_path
-                  }
-                },
-                internalParameters: {},
-                resolvedDependencies: [
-                  {
-                    uri: $source_uri,
-                    digest: { gitCommit: $git_commit }
-                  }
-                ]
+          export RESOLVED_GIT_COMMIT
+          python3 - <<'PY' > predicate.json
+          import json
+          import os
+
+          repo = os.environ["GITHUB_REPOSITORY"]
+          commit = os.environ["RESOLVED_GIT_COMMIT"]
+          run_id = os.environ["GITHUB_RUN_ID"]
+          run_attempt = os.environ["GITHUB_RUN_ATTEMPT"]
+
+          predicate = {
+              "buildDefinition": {
+                  "buildType": "https://github.com/opencost/opencost/build/workflow@v1",
+                  "externalParameters": {
+                      "workflow": {
+                          "ref": os.environ["GITHUB_REF"],
+                          "repository": f"https://github.com/{repo}",
+                          "path": os.environ["WORKFLOW_PATH"],
+                      }
+                  },
+                  "internalParameters": {},
+                  "resolvedDependencies": [
+                      {
+                          "uri": f"git+https://github.com/{repo}@{commit}",
+                          "digest": {"gitCommit": commit},
+                      }
+                  ],
+              },
+              "runDetails": {
+                  "builder": {
+                      "id": f"https://github.com/{repo}/actions/runs/{run_id}",
+                  },
+                  "metadata": {
+                      "invocationId": f"https://github.com/{repo}/actions/runs/{run_id}/attempts/{run_attempt}",
+                      "startedOn": os.environ["STARTED_ON"],
+                  },
               },
-              runDetails: {
-                builder: { id: $builder_id },
-                metadata: {
-                  invocationId: $invocation_id,
-                  startedOn: $started_on
-                }
-              }
-            }' > predicate.json
+          }
+          print(json.dumps(predicate, indent=2))
+          PY
 
       - name: Attest SLSA provenance with cosign
         shell: bash

+ 4 - 0
.github/workflows/build-and-publish-release.yml

@@ -114,6 +114,10 @@ jobs:
           crane copy "$IMAGE_TAG" "$IMAGE_TAG_VERSION"
 
       - name: Sign image and attest SLSA provenance
+        # Only sign tag-triggered releases; workflow_dispatch runs produce a
+        # non-tag GITHUB_REF, so the Fulcio certificate identity would not
+        # match the `refs/tags/vX.Y.Z` pattern documented in SECURITY.md.
+        if: github.event_name == 'push'
         uses: ./.github/actions/sign-image
         with:
           image: ${{ steps.tags.outputs.IMAGE_TAG_VERSION }}