forked from ilysenko/codex-desktop-linux
-
Notifications
You must be signed in to change notification settings - Fork 0
207 lines (184 loc) · 9.31 KB
/
Copy pathupdate-codex-hash.yml
File metadata and controls
207 lines (184 loc) · 9.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
name: Update Nix upstream hashes
run-name: Nix refresh ${{ inputs.expected_main_sha }}:${{ inputs.expected_dmg_sha256 }}
on:
workflow_dispatch:
inputs:
expected_main_sha:
description: Main commit selected by the DMG campaign watcher
required: true
type: string
expected_dmg_sha256:
description: Raw SHA256 of the DMG selected by the campaign watcher
required: true
type: string
permissions:
actions: write
contents: write
pull-requests: write
concurrency:
group: update-nix-upstream-hashes
cancel-in-progress: false
jobs:
update-hash:
runs-on: ubuntu-latest
timeout-minutes: 90
env:
NIX_CONFIG: experimental-features = nix-command flakes
CACHIX_CACHE_NAME: codex-desktop-linux
CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }}
NIX_VERIFY_OUTPUTS: |
.#codex-desktop
.#codex-desktop-computer-use-ui
.#codex-desktop-remote-mobile-control
.#codex-desktop-computer-use-ui-remote-mobile-control
.#checks.x86_64-linux.watchdog-linux-features
.#installer
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
with:
fetch-depth: 0
ref: ${{ inputs.expected_main_sha }}
- name: Deduplicate an already materialized campaign
id: dedupe
env:
EXPECTED_MAIN_SHA: ${{ inputs.expected_main_sha }}
EXPECTED_DMG_SHA256: ${{ inputs.expected_dmg_sha256 }}
REFRESH_BRANCH: codex/nix-upstream-refresh
run: |
set -euo pipefail
echo "skip_refresh=false" >> "$GITHUB_OUTPUT"
checked_out_sha="$(git rev-parse HEAD)"
if [ -n "$EXPECTED_MAIN_SHA" ] && [ "$checked_out_sha" != "$EXPECTED_MAIN_SHA" ]; then
echo "Expected main $EXPECTED_MAIN_SHA, but workflow checked out $checked_out_sha." >&2
exit 1
fi
refresh_branch_available=false
if git fetch origin "$REFRESH_BRANCH:refs/remotes/origin/$REFRESH_BRANCH"; then
refresh_branch_available=true
fi
if [ -z "$EXPECTED_MAIN_SHA" ] || [ -z "$EXPECTED_DMG_SHA256" ] \
|| [ "$refresh_branch_available" != "true" ]; then
exit 0
fi
source_main="$(git log -1 --format='%(trailers:key=Source-Main-SHA,valueonly)' "origin/$REFRESH_BRANCH" | tr -d '[:space:]')"
dmg_sha="$(git log -1 --format='%(trailers:key=Upstream-DMG-SHA256,valueonly)' "origin/$REFRESH_BRANCH" | tr -d '[:space:]')"
if [ "$source_main" = "$EXPECTED_MAIN_SHA" ] && [ "$dmg_sha" = "$EXPECTED_DMG_SHA256" ]; then
echo "Campaign $EXPECTED_MAIN_SHA:$EXPECTED_DMG_SHA256 is already present on $REFRESH_BRANCH."
echo "skip_refresh=true" >> "$GITHUB_OUTPUT"
fi
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
if: steps.dedupe.outputs.skip_refresh != 'true'
with:
node-version: 24
- uses: cachix/install-nix-action@630ae543ea3a38a9a4166f03376c02c50f408342 # v31
if: steps.dedupe.outputs.skip_refresh != 'true'
- name: Configure Cachix for hash refresh builds
if: steps.dedupe.outputs.skip_refresh != 'true' && env.CACHIX_AUTH_TOKEN != ''
uses: cachix/cachix-action@5f2d7c5294214f71b873db4b969586b980625e71 # v17
with:
name: ${{ env.CACHIX_CACHE_NAME }}
authToken: ${{ env.CACHIX_AUTH_TOKEN }}
- name: Install validation dependencies
if: steps.dedupe.outputs.skip_refresh != 'true'
run: |
set -euo pipefail
sudo apt-get update
sudo apt-get install -y p7zip-full
- name: Refresh Nix upstream hash
if: steps.dedupe.outputs.skip_refresh != 'true'
env:
EXPECTED_DMG_SHA256: ${{ inputs.expected_dmg_sha256 }}
NIX_COMPARE_REF: origin/codex/nix-upstream-refresh
run: |
set -euo pipefail
scripts/ci/update-nix-hashes.sh
if [ -n "$EXPECTED_DMG_SHA256" ]; then
actual_dmg_sha256="$(sha256sum /tmp/Codex.dmg | awk '{print $1}')"
if [ "$actual_dmg_sha256" != "$EXPECTED_DMG_SHA256" ]; then
echo "Expected DMG $EXPECTED_DMG_SHA256, but downloaded $actual_dmg_sha256." >&2
exit 1
fi
fi
- name: Reconcile refreshed hashes pull request and exact-head CI
env:
GH_TOKEN: ${{ github.token }}
REFRESH_BRANCH: codex/nix-upstream-refresh
SKIP_REFRESH: ${{ steps.dedupe.outputs.skip_refresh }}
EXPECTED_MAIN_SHA: ${{ inputs.expected_main_sha }}
run: |
set -euo pipefail
pin_paths=(flake.nix nix/native-modules/package.json nix/native-modules/package-lock.json)
if [ "$SKIP_REFRESH" = "true" ]; then
git checkout -B "$REFRESH_BRANCH" "origin/$REFRESH_BRANCH"
elif git diff --quiet -- "${pin_paths[@]}"; then
echo "Nix pins unchanged, nothing to do."
exit 0
else
CODEX_DMG_HASH="$(scripts/ci/update-nix-hashes.sh read-flake-hash 'codexDmg = pkgs.fetchurl {' 'hash = ')"
CODEX_VERSION="$(scripts/ci/update-nix-hashes.sh read-flake-string codexVersion)"
DMG_SHA256="$(sha256sum /tmp/Codex.dmg | awk '{print $1}')"
git config user.name "codex-dmg-hash-bot"
git config user.email "actions@github.com"
git checkout -B "$REFRESH_BRANCH"
git add "${pin_paths[@]}"
# GITHUB_TOKEN already suppresses branch push workflows. Do not add
# a skip marker: squash merges copy it to main and suppress Cachix.
git commit \
-m "fix(nix): refresh upstream Nix pins${CODEX_VERSION:+ for $CODEX_VERSION}" \
-m "Refreshed Codex.dmg SRI hash to $CODEX_DMG_HASH and synced codexVersion / electronVersion / native-module pins to the current upstream DMG." \
-m "Verified all ChatGPT Desktop Nix package outputs against the refreshed DMG." \
-m "Source-Main-SHA: $EXPECTED_MAIN_SHA" \
-m "Upstream-DMG-SHA256: $DMG_SHA256"
git push --force-with-lease origin "$REFRESH_BRANCH"
fi
CODEX_DMG_HASH="$(scripts/ci/update-nix-hashes.sh read-flake-hash 'codexDmg = pkgs.fetchurl {' 'hash = ')"
CODEX_VERSION="$(scripts/ci/update-nix-hashes.sh read-flake-string codexVersion)"
APPCAST_VERSION="$(scripts/ci/update-nix-hashes.sh read-appcast-version 2>/dev/null || true)"
if [ -n "$APPCAST_VERSION" ] && [ "$APPCAST_VERSION" != "$CODEX_VERSION" ]; then
APPCAST_NOTE="- warning: Sparkle appcast currently advertises \`$APPCAST_VERSION\`, while current \`Codex.dmg\` contains \`$CODEX_VERSION\`; this PR follows the verified DMG payload."
elif [ -n "$APPCAST_VERSION" ]; then
APPCAST_NOTE="- Sparkle appcast also advertises \`$APPCAST_VERSION\`."
else
APPCAST_NOTE="- Sparkle appcast version could not be read during PR creation; pins follow the verified DMG payload."
fi
pr_body="$RUNNER_TEMP/nix-refresh-pr-body.md"
cat >"$pr_body" <<EOF
## Summary
- refresh Codex.dmg hash and upstream version pins to the current upstream DMG
- update Electron fixed-output hashes when electronVersion changes
- regenerate nix/native-modules/package-lock.json when native module pins change
$APPCAST_NOTE
## Validation
- this workflow verified all ChatGPT Desktop Nix package outputs before opening the PR
- refreshed Codex.dmg SRI hash: \`$CODEX_DMG_HASH\`
EOF
pr_url="$(gh pr list --repo "$GITHUB_REPOSITORY" --base main --head "$REFRESH_BRANCH" --state open --json url --jq '.[0].url // ""')"
if [ -z "$pr_url" ]; then
pr_url="$(gh pr create \
--repo "$GITHUB_REPOSITORY" \
--base main \
--head "$REFRESH_BRANCH" \
--title "fix(nix): refresh upstream Nix pins${CODEX_VERSION:+ for $CODEX_VERSION}" \
--body-file "$pr_body")"
else
gh pr edit "$pr_url" \
--title "fix(nix): refresh upstream Nix pins${CODEX_VERSION:+ for $CODEX_VERSION}" \
--body-file "$pr_body"
fi
echo "Opened or updated refresh PR: $pr_url"
# Branch pushes made with GITHUB_TOKEN do not trigger normal push/PR
# workflows. Dispatch CI explicitly so required checks attach to the
# bot branch head SHA and the PR can satisfy the repository ruleset.
# A serialized duplicate run adopts the existing exact-head CI rather
# than creating a second copy of the same matrix.
refresh_head="$(git rev-parse HEAD)"
exact_head_runs="$(
gh run list --repo "$GITHUB_REPOSITORY" --workflow ci.yml --branch "$REFRESH_BRANCH" \
--limit 20 --json headSha \
| python3 -c 'import json, sys; head=sys.argv[1]; print(sum(run.get("headSha") == head for run in json.load(sys.stdin)))' "$refresh_head"
)"
if [ "$exact_head_runs" -eq 0 ]; then
gh workflow run ci.yml --repo "$GITHUB_REPOSITORY" --ref "$REFRESH_BRANCH"
else
echo "Exact-head CI already exists for $refresh_head; skipping duplicate dispatch."
fi