Skip to content

Commit 8cf5035

Browse files
authored
Verify release checkouts use tag commits (#75)
**Why** The release workflow accepts a tag input and then builds, signs, uploads, and records release metadata. The caller checkout should be tied directly to that tag so a release run cannot publish artifacts from one commit while labeling or recording them as another tag. **What this changes** - Checks out caller code from `refs/tags/${{ inputs.tag }}` in the binaries, Windows, Docker, and registry metadata jobs. - Verifies each checked-out caller repository HEAD matches the tag target before continuing. - Records the verified connector checkout commit SHA in the registry metadata instead of using `github.sha`. - Documents the release source identity invariant in the release workflow docs. This PR is stacked on #74 and should merge after it. **Validation** - Parsed `.github/workflows/release.yaml` with `yq`. - Ran `git diff --check`. - Verified all caller/connector release checkouts use `refs/tags/${{ inputs.tag }}`. - Ran `orch-cross-review` focused on annotated/lightweight tags, cross-runner behavior, registry commit recording, and regressions; no blockers were reported. - Ran a private connector release canary against this branch; the release completed successfully, including macOS, Windows, Docker, manifest publication, artifact verification, and registry recording jobs.
1 parent 9726023 commit 8cf5035

2 files changed

Lines changed: 76 additions & 1 deletion

File tree

.github/workflows/release.yaml

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,9 +177,25 @@ jobs:
177177
with:
178178
path: _caller
179179
repository: ${{ github.event.repository.full_name }}
180+
ref: refs/tags/${{ inputs.tag }}
180181
fetch-depth: 0
181182
persist-credentials: false
182183

184+
- name: Verify caller checkout matches release tag
185+
working-directory: _caller
186+
shell: bash
187+
env:
188+
RELEASE_TAG: ${{ inputs.tag }}
189+
run: |
190+
set -euo pipefail
191+
tag_commit="$(git rev-list -n 1 "refs/tags/$RELEASE_TAG")"
192+
head_commit="$(git rev-parse HEAD)"
193+
if [ "$head_commit" != "$tag_commit" ]; then
194+
echo "::error::Checked out $head_commit but refs/tags/$RELEASE_TAG resolves to $tag_commit"
195+
exit 1
196+
fi
197+
echo "Verified $RELEASE_TAG at $head_commit"
198+
183199
- name: Checkout connector workflows
184200
uses: actions/checkout@v5
185201
with:
@@ -429,9 +445,25 @@ jobs:
429445
with:
430446
path: _caller
431447
repository: ${{ github.event.repository.full_name }}
448+
ref: refs/tags/${{ inputs.tag }}
432449
fetch-depth: 0
433450
persist-credentials: false
434451

452+
- name: Verify caller checkout matches release tag
453+
working-directory: _caller
454+
shell: bash
455+
env:
456+
RELEASE_TAG: ${{ inputs.tag }}
457+
run: |
458+
set -euo pipefail
459+
tag_commit="$(git rev-list -n 1 "refs/tags/$RELEASE_TAG")"
460+
head_commit="$(git rev-parse HEAD)"
461+
if [ "$head_commit" != "$tag_commit" ]; then
462+
echo "::error::Checked out $head_commit but refs/tags/$RELEASE_TAG resolves to $tag_commit"
463+
exit 1
464+
fi
465+
echo "Verified $RELEASE_TAG at $head_commit"
466+
435467
- name: Checkout connector workflows
436468
uses: actions/checkout@v5
437469
with:
@@ -721,9 +753,25 @@ jobs:
721753
with:
722754
path: _caller
723755
repository: ${{ github.event.repository.full_name }}
756+
ref: refs/tags/${{ inputs.tag }}
724757
fetch-depth: 0
725758
persist-credentials: false
726759

760+
- name: Verify caller checkout matches release tag
761+
working-directory: _caller
762+
shell: bash
763+
env:
764+
RELEASE_TAG: ${{ inputs.tag }}
765+
run: |
766+
set -euo pipefail
767+
tag_commit="$(git rev-list -n 1 "refs/tags/$RELEASE_TAG")"
768+
head_commit="$(git rev-parse HEAD)"
769+
if [ "$head_commit" != "$tag_commit" ]; then
770+
echo "::error::Checked out $head_commit but refs/tags/$RELEASE_TAG resolves to $tag_commit"
771+
exit 1
772+
fi
773+
echo "Verified $RELEASE_TAG at $head_commit"
774+
727775
- name: Checkout connector workflows
728776
if: inputs.docker == true || inputs.lambda == true
729777
uses: actions/checkout@v5
@@ -1207,8 +1255,28 @@ jobs:
12071255
uses: actions/checkout@v5
12081256
with:
12091257
path: _connector
1258+
repository: ${{ github.event.repository.full_name }}
1259+
ref: refs/tags/${{ inputs.tag }}
1260+
fetch-depth: 0
12101261
persist-credentials: false
12111262

1263+
- name: Verify connector checkout matches release tag
1264+
id: verify-connector-checkout
1265+
working-directory: _connector
1266+
shell: bash
1267+
env:
1268+
RELEASE_TAG: ${{ inputs.tag }}
1269+
run: |
1270+
set -euo pipefail
1271+
tag_commit="$(git rev-list -n 1 "refs/tags/$RELEASE_TAG")"
1272+
head_commit="$(git rev-parse HEAD)"
1273+
if [ "$head_commit" != "$tag_commit" ]; then
1274+
echo "::error::Checked out $head_commit but refs/tags/$RELEASE_TAG resolves to $tag_commit"
1275+
exit 1
1276+
fi
1277+
echo "commit_sha=$head_commit" >> "$GITHUB_OUTPUT"
1278+
echo "Verified $RELEASE_TAG at $head_commit"
1279+
12121280
- name: Read connector documentation
12131281
id: read-docs
12141282
run: |
@@ -1288,7 +1356,7 @@ jobs:
12881356
-name "${{ github.event.repository.name }}" \
12891357
-version "${{ inputs.tag }}" \
12901358
-repository-url "https://github.com/${{ github.repository }}" \
1291-
-commit-sha "${{ github.sha }}" \
1359+
-commit-sha "${{ steps.verify-connector-checkout.outputs.commit_sha }}" \
12921360
-workflow-run-id "${{ github.run_id }}" \
12931361
-registry-url "https://dist.conductorone.com" \
12941362
$DOCS_FLAG \

docs/release-workflow.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,13 @@ Post-release validation (non-blocking):
100100

101101
## Security Properties
102102

103+
### Release Source Identity
104+
105+
Release jobs check out caller code from `refs/tags/<tag>` and verify the
106+
checked-out commit matches the tag target before building artifacts or recording
107+
registry metadata. This prevents a release run from publishing artifacts for one
108+
commit while labeling them as a different tag.
109+
103110
### Keyless Signing
104111

105112
All signatures use Sigstore's keyless signing:

0 commit comments

Comments
 (0)