diff --git a/.github/workflows/image-lane.yml b/.github/workflows/image-lane.yml index ad14785..84c0700 100644 --- a/.github/workflows/image-lane.yml +++ b/.github/workflows/image-lane.yml @@ -59,6 +59,13 @@ on: and refuses anything else, so mutable names like `latest` cannot be published. required: true type: string + source-sha: + description: >- + Exact source commit to build when a verified commit dispatches the lane after main has moved. + Empty uses the triggering commit. The checkout and evidence use this same revision. + required: false + type: string + default: "" lane-ref: description: >- Optional ref of this lane repository to check out for the lane's own tooling. Leave empty to use @@ -248,7 +255,7 @@ jobs: # Pinned to the exact built source SHA, not the moving ref tip. - uses: actions/checkout@v4 with: - ref: ${{ github.sha }} + ref: ${{ inputs.source-sha || github.sha }} persist-credentials: false - name: Check out this lane @@ -293,7 +300,7 @@ jobs: LANE_PLATFORMS: ${{ inputs.platforms }} LANE_DOCKERFILE: ${{ inputs.dockerfile }} LANE_CONTEXT: ${{ inputs.context }} - LANE_SOURCE_SHA: ${{ github.sha }} + LANE_SOURCE_SHA: ${{ inputs.source-sha || github.sha }} LANE_RUN_ID: ${{ github.run_id }} LANE_RUN_ATTEMPT: ${{ github.run_attempt }} LANE_EVIDENCE_TAG_PREFIX: ${{ inputs.evidence-tag-prefix }} diff --git a/README.md b/README.md index 819ae4f..915e64a 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,11 @@ Reusable workflows are in [.github/workflows](.github/workflows); the CI fast-pa [disarm-auto-merge-on-push](docs/disarm-automerge-on-push.md) clears an arm predating a new push without dequeuing an entry already on that head. +The image lane accepts `source-sha` for post-verification dispatches. Pass the +verified commit both as `source-sha` and `tag`; checkout and build evidence bind +that commit even when the dispatch runs after `main` advances. An omitted +`source-sha` keeps the triggering commit as the source. + ## Repository settings Company repositories delete a pull request's head branch when it merges diff --git a/tests/test_image_lane_tools.py b/tests/test_image_lane_tools.py index 5ed9155..f3ab84c 100644 --- a/tests/test_image_lane_tools.py +++ b/tests/test_image_lane_tools.py @@ -41,6 +41,16 @@ def segment(value: dict) -> str: return f"{segment({'alg': 'ES256'})}.{segment(claims)}.signature" +class ImageLaneSourceContractTests(unittest.TestCase): + def test_dispatched_source_binds_checkout_and_evidence(self) -> None: + workflow = (ROOT / ".github/workflows/image-lane.yml").read_text() + source = "${{ inputs.source-sha || github.sha }}" + self.assertIn(" source-sha:\n", workflow) + self.assertIn(f" ref: {source}\n", workflow) + self.assertIn(f" LANE_SOURCE_SHA: {source}\n", workflow) + self.assertNotIn(" LANE_SOURCE_SHA: ${{ github.sha }}", workflow) + + class SplitImageReferenceTests(unittest.TestCase): def test_splits_host_and_repository(self) -> None: