mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-11-14 02:29:33 +01:00
ci(desktop): a rebuild by hand takes only a Codeman release tag on master
A dispatch with -f tag=<any tag> built that tag, and sign then ran the tag's sign-macos.sh with the Developer ID key unlocked and the notary login in its environment. Nothing checked the tag: xterm-zerolag-input@0.1.7 would have put Codeman.dmg on that package's release, and a tag on a commit that never reached master would have run unreviewed scripts with the secrets. build and sign now each check their own checkout before anything else runs: the tag must read codeman@x.y.z (or aicodeman@x.y.z, which a failed rename leaves) and GitHub's compare of master with the checked-out commit must say behind or identical. The check is inline, since a script from the checkout would be the tag's own code. Release's own call (a push, not a dispatch) and the branch dry run are unchanged. The header says why a master-only Environment would not close this path, and release.yml's macos-app job now says that any permission a called job asks for must be granted there too, or Release fails at startup. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
d5273347c3
commit
ea23445ad7
3 files changed
+69
-3
No files matched your search
@@ -12,7 +12,15 @@ name: macOS app
|
||||
# gh workflow run desktop-dmg.yml --ref <branch> # dry run of a branch that carries this file
|
||||
# gh workflow run desktop-dmg.yml -f tag=codeman@1.50.0 # rebuild that tag, replace its Codeman.dmg
|
||||
# Only a run on master (or Release itself) attaches anything; every run leaves
|
||||
# the signed Codeman.dmg as an artifact on its run page.
|
||||
# the signed Codeman.dmg as an artifact on its run page. A rebuild takes only a
|
||||
# Codeman release tag whose commit is on master ("Check the tag", in build and
|
||||
# in sign).
|
||||
#
|
||||
# A dispatch runs its ref's copy of this file with the secrets, as every
|
||||
# repository secret reaches anyone with write access. A GitHub Environment
|
||||
# limited to master would not narrow the rebuild path (the job's ref is master
|
||||
# while it runs the tag's scripts) and would refuse the branch dry run above;
|
||||
# the tag check is what keeps a rebuild on master's history.
|
||||
#
|
||||
# Three jobs, so no job that holds a secret runs code from a crate:
|
||||
# - build runs cargo, and with it the build script of every crate in
|
||||
@@ -79,6 +87,36 @@ jobs:
|
||||
ref: ${{ env.BUILD_REF }}
|
||||
persist-credentials: false
|
||||
|
||||
# A rebuild by hand builds the tag it names, and sign then runs that tag's
|
||||
# scripts with the Developer ID key unlocked. So the tag must be a Codeman
|
||||
# release (another package's tag would put Codeman.dmg on its release), and
|
||||
# its commit must be on master's history, where those scripts were reviewed.
|
||||
# aicodeman@ is the tag a failed rename leaves (Release's retag step).
|
||||
# A tag can move between jobs, so build and sign each check their own
|
||||
# checkout. Inline on purpose: a script from the checkout would be the
|
||||
# tag's own code. Kept the same as the step in sign.
|
||||
- name: Check the tag
|
||||
if: github.event_name == 'workflow_dispatch' && inputs.tag != ''
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
TAG: ${{ inputs.tag }}
|
||||
run: |
|
||||
TAG_RE='^(ai)?codeman@[0-9]+\.[0-9]+\.[0-9]+$'
|
||||
if ! [[ $TAG =~ $TAG_RE ]]; then
|
||||
echo "::error::The tag input is not a Codeman release tag (codeman@x.y.z)"
|
||||
exit 1
|
||||
fi
|
||||
SHA=$(git rev-parse HEAD)
|
||||
# behind: an ancestor of master's tip; identical: the tip itself.
|
||||
STATUS=$(gh api "repos/$GITHUB_REPOSITORY/compare/master...$SHA" --jq .status)
|
||||
case "$STATUS" in
|
||||
behind | identical) echo "$TAG ($SHA) is on master's history" ;;
|
||||
*)
|
||||
echo "::error::$TAG ($SHA) is not on master's history (compare says $STATUS)"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
- name: Rust toolchain
|
||||
run: |
|
||||
rustup toolchain install "$RUST_TOOLCHAIN" --profile minimal \
|
||||
@@ -151,6 +189,30 @@ jobs:
|
||||
ref: ${{ env.BUILD_REF }}
|
||||
persist-credentials: false
|
||||
|
||||
# The same check as in build, on this job's own checkout, before anything
|
||||
# here touches a secret. Kept the same as the step in build.
|
||||
- name: Check the tag
|
||||
if: github.event_name == 'workflow_dispatch' && inputs.tag != ''
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
TAG: ${{ inputs.tag }}
|
||||
run: |
|
||||
TAG_RE='^(ai)?codeman@[0-9]+\.[0-9]+\.[0-9]+$'
|
||||
if ! [[ $TAG =~ $TAG_RE ]]; then
|
||||
echo "::error::The tag input is not a Codeman release tag (codeman@x.y.z)"
|
||||
exit 1
|
||||
fi
|
||||
SHA=$(git rev-parse HEAD)
|
||||
# behind: an ancestor of master's tip; identical: the tip itself.
|
||||
STATUS=$(gh api "repos/$GITHUB_REPOSITORY/compare/master...$SHA" --jq .status)
|
||||
case "$STATUS" in
|
||||
behind | identical) echo "$TAG ($SHA) is on master's history" ;;
|
||||
*)
|
||||
echo "::error::$TAG ($SHA) is not on master's history (compare says $STATUS)"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
- name: Download the unsigned app
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
|
||||
@@ -145,8 +145,12 @@ jobs:
|
||||
name: macOS app
|
||||
needs: release
|
||||
if: needs.release.outputs.codeman_version != ''
|
||||
# The ceiling for the called jobs; only its attach job asks for write. A job in
|
||||
# desktop-dmg.yml that asks for a permission not granted here (id-token or
|
||||
# attestations for a provenance attestation, say) makes GitHub refuse this
|
||||
# whole Release run at startup, npm publish included: widen both together.
|
||||
permissions:
|
||||
contents: write # the ceiling for the called jobs; only its attach job asks for write
|
||||
contents: write
|
||||
uses: ./.github/workflows/desktop-dmg.yml
|
||||
with:
|
||||
tag: codeman@${{ needs.release.outputs.codeman_version }}
|
||||
|
||||
Reference in new issue
Block a user