Skip to content
Merged
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
17 changes: 11 additions & 6 deletions .github/workflows/update-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
# bundle and schema to the draft (draft-first because published
# releases freeze their assets),
# 4. confirms origin's refs and the draft's assets before the managed
# publish stage attests every asset (attestation.jsonl; public
# publish stage attests every asset (attestation.json; public
# repositories only, by fleet policy) and flips the release live.
# When the draft is published, GitHub binds it to the existing
# vX.Y.Z tag, so the release lands on the packaged commit.
Expand All @@ -38,7 +38,7 @@
# Finish a dead run by re-running its FAILED jobs. The same steps by hand
# (<merge sha> is the draft release's target commitish; a hand-packaged
# commit carries no workflow-run trailer, and a hand-finished release no
# attestation.jsonl - both need the workflow's identity):
# attestation.json - both need the workflow's identity):
# git checkout <merge sha>
# bun install --frozen-lockfile --ignore-scripts && bun run build
# TAG=vX.Y.Z GITHUB_SHA=<merge sha> bun .github/scripts/release-pipeline.ts package
Expand Down Expand Up @@ -159,16 +159,21 @@ jobs:
run: GITHUB_SHA="$SOURCE_SHA" bun .github/scripts/release-pipeline.ts verify
# Publishing freezes the asset list, so an incomplete one must stop
# the pipeline here, while the release is still a draft (v2.0.0
# shipped assetless exactly this way). attestation.jsonl is the
# managed publish stage's asset: attached after this job, replaced on
# its reruns - ignore it rather than racing it.
# shipped assetless exactly this way). attestation.json is the managed
# publish stage's asset, attached after this job and replaced on its
# reruns, so the check ignores it. A legacy attestation.jsonl (the
# name before the template renamed it) is stale provenance that stage
# no longer cleans up, so it is deleted here before the check.
- name: Confirm the release carries both packaged assets
env:
GH_TOKEN: ${{ github.token }}
TAG: ${{ inputs.tag }}
run: |
if gh release view "$TAG" --json assets --jq '.assets[].name' | grep -qx 'attestation.jsonl'; then
gh release delete-asset "$TAG" attestation.jsonl --yes
fi
assets="$(gh release view "$TAG" --json assets \
--jq '[.assets[].name | select(. != "attestation.jsonl")] | sort | join(" ")')"
--jq '[.assets[].name | select(. != "attestation.json")] | sort | join(" ")')"
expected="index.js settings.schema.json"
if [ "$assets" != "$expected" ]; then
echo "::error::release $TAG carries assets [$assets], expected [$expected]; re-run package-release before anything publishes."
Expand Down
2 changes: 1 addition & 1 deletion SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ This action holds a repository-admin token and writes repository settings, so th
- Settings escalation. A crafted settings file should never be able to touch a repository or setting it does not declare, nor bypass the preflight barrier or the required-sections policy.
- Supply chain. Every ref a `uses:` pin can name - the `vX.Y.Z` release tags and the moving major - points at a packaged commit parented on the audited release commit, produced by the release workflow run named in its provenance message; main carries no executable bundle. The release-tags ruleset freezes version tags for everything except deliberate repository-admin action (the bypass exists for repair; the release workflow itself never moves a version tag, reruns verify the existing one byte-for-byte instead). A packaged commit whose bundle a rebuild of its parent's src/ does not reproduce is a vulnerability. The release pipeline also attests every release asset (`lib/index.js` and `lib/settings.schema.json`) in one build-provenance attestation while the repository is public (GitHub offers no attestations elsewhere): fetch either from the `vX.Y.Z` tag or the release assets, then check it with `gh attestation verify
<artifact> -R vivswan/github-settings-as-code` (add
`--signer-workflow vivswan/github-settings-as-code/.github/workflows/release.yml` to also pin the producing workflow), or without the attestations API via `--bundle` against the `attestation.jsonl` release asset. A release finished by hand carries no attestation at all, and its packaged commit no workflow-run trailer: both need the workflow's OIDC identity.
`--signer-workflow vivswan/github-settings-as-code/.github/workflows/release.yml` to also pin the producing workflow), or without the attestations API via `--bundle` against the `attestation.json` release asset. A release finished by hand carries no attestation at all, and its packaged commit no workflow-run trailer: both need the workflow's OIDC identity.

Fixes ship in the next release and are not backported; upgrade the `uses:` pin to pick them up.

Expand Down
Loading