11name : apt-indices-refresh
22
3- # Weekly freshness loop for golden apt indices. Pack production stamps each
3+ # Weekly freshness reminder for golden apt indices. Pack production stamps each
44# bake (marker in the image, `apt_indices` in provenance.json); this job
5- # compares the published pack's stamp against the versions.toml policy and
6- # dispatches a rebuild when stale. Nothing runs on the Preloop pool — the
7- # bake itself executes in release-golden on hosted runners .
5+ # compares the published pack's stamp against the versions.toml policy. When
6+ # stale, it opens a draft PR asking an operator to rebuild on a host with enough
7+ # disk. The schedule never dispatches the hosted golden bake .
88on :
99 schedule :
10- # Monday 04:00 UTC: at most one rebake per week when indices rot past policy.
10+ # Monday 04:00 UTC: at most one reminder per week when indices exceed policy.
1111 - cron : " 0 4 * * 1"
1212 workflow_dispatch :
1313
1414permissions :
15- contents : read
16- actions : write
15+ contents : write
16+ pull-requests : write
1717
1818jobs :
1919 check :
20- name : Rebuild goldens past index policy
20+ name : Open draft PR when golden apt indices are stale
2121 runs-on : ubuntu-latest
2222 timeout-minutes : 10
2323 steps :
@@ -26,35 +26,115 @@ jobs:
2626 persist-credentials : false
2727 sparse-checkout : versions.toml
2828
29- - name : Rebuild when the published pack is stale
29+ - name : Check published index freshness
30+ id : freshness
3031 env :
3132 GH_TOKEN : ${{ secrets.GITHUB_TOKEN }}
3233 run : |
3334 set -euo pipefail
3435 MAX_AGE_DAYS="$(grep '^apt_indices_max_age_days' versions.toml | cut -d'"' -f2)"
3536 test -n "$MAX_AGE_DAYS"
36- TAG="$(gh release view --json tagName --jq .tagName)"
37+ TAG="$(gh release view --repo "$GITHUB_REPOSITORY" -- json tagName --jq .tagName)"
3738 echo "policy: ${MAX_AGE_DAYS}d; latest release: $TAG"
38- # A pack predating the stamp feature has no provenance field and
39- # reads as infinitely stale: the first run self-heals by rebuilding.
39+ rm -rf /tmp/apt-prov
4040 if gh release download "$TAG" \
4141 --pattern 'preloop-ubuntu-24.04-x86_64.provenance.json' \
42- --dir /tmp/apt-prov --clobber >/dev/null 2>&1; then
42+ --dir /tmp/apt-prov \
43+ --clobber \
44+ --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
4345 STAMP="$(python3 -c 'import json; print(json.load(open("/tmp/apt-prov/preloop-ubuntu-24.04-x86_64.provenance.json")).get("apt_indices", {}).get("baked_at", ""))')"
4446 else
4547 echo "no provenance asset; treating pack as stale"
4648 STAMP=""
4749 fi
4850 if [ -z "$STAMP" ]; then
49- echo "stale (no stamp); dispatching golden rebuild"
50- gh workflow run release-golden --ref main
51+ {
52+ echo "stale=true"
53+ echo "stamp=missing"
54+ echo "age_days=unknown"
55+ } >> "$GITHUB_OUTPUT"
5156 exit 0
5257 fi
5358 AGE_DAYS="$(( ($(date -u +%s) - $(date -u -d "$STAMP" +%s)) / 86400 ))"
5459 echo "indices baked $STAMP (${AGE_DAYS}d old)"
60+ {
61+ echo "stamp=$STAMP"
62+ echo "age_days=$AGE_DAYS"
63+ } >> "$GITHUB_OUTPUT"
5564 if [ "$AGE_DAYS" -gt "$MAX_AGE_DAYS" ]; then
56- echo "stale; dispatching golden rebuild"
57- gh workflow run release-golden --ref main
65+ echo "stale=true" >> "$GITHUB_OUTPUT"
5866 else
67+ echo "stale=false" >> "$GITHUB_OUTPUT"
5968 echo "fresh; nothing to do"
6069 fi
70+
71+ - name : Open manual rebuild reminder
72+ if : steps.freshness.outputs.stale == 'true'
73+ env :
74+ GH_TOKEN : ${{ secrets.GITHUB_TOKEN }}
75+ APT_INDEX_STAMP : ${{ steps.freshness.outputs.stamp }}
76+ APT_INDEX_AGE_DAYS : ${{ steps.freshness.outputs.age_days }}
77+ run : |
78+ set -euo pipefail
79+ REQUESTED_AT="$(date -u +%F)"
80+ BRANCH="chore/golden-apt-refresh-${REQUESTED_AT}"
81+ EXISTING_URL="$(gh pr list \
82+ --repo "$GITHUB_REPOSITORY" \
83+ --state open \
84+ --head "$BRANCH" \
85+ --json url \
86+ --jq '.[0].url // empty')"
87+ if [ -n "$EXISTING_URL" ]; then
88+ echo "rebuild reminder already open: $EXISTING_URL"
89+ exit 0
90+ fi
91+
92+ git config user.name "github-actions[bot]"
93+ git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
94+ git switch -c "$BRANCH"
95+ awk -v marker="# Golden rebuild requested ${REQUESTED_AT}: apt indices ${APT_INDEX_STAMP} (${APT_INDEX_AGE_DAYS}d old)." '
96+ /^# Golden rebuild requested / { next }
97+ /^apt_indices_max_age_days = / { print marker }
98+ { print }
99+ ' versions.toml > versions.toml.tmp
100+ mv versions.toml.tmp versions.toml
101+ git add versions.toml
102+ git commit -m "chore(golden): request apt index refresh [skip ci]"
103+ gh auth setup-git
104+ git fetch origin "$BRANCH" || true
105+ git push --force-with-lease origin "HEAD:refs/heads/$BRANCH"
106+
107+ BODY="$RUNNER_TEMP/golden-refresh-pr.md"
108+ cat > "$BODY" <<EOF
109+ ## Manual golden rebuild required
110+
111+ The published x86_64 golden reports apt indices baked at
112+ **${APT_INDEX_STAMP}** (${APT_INDEX_AGE_DAYS} days old), beyond the
113+ policy in versions.toml.
114+
115+ This draft PR is a reminder only; do not merge it.
116+
117+ 1. On the x86_64 Linux host with KVM and sufficient disk, run
118+ scripts/build-golden-x86_64.sh from current main.
119+ 2. Publish the payload, checksum, bundle, signatures, and provenance
120+ sidecars to the current release.
121+ 3. Confirm the published provenance has a fresh apt_indices.baked_at.
122+ 4. Close this draft PR.
123+ EOF
124+
125+ if ! gh pr create \
126+ --repo "$GITHUB_REPOSITORY" \
127+ --draft \
128+ --base main \
129+ --head "$BRANCH" \
130+ --title "chore(golden): rebuild stale apt indices [skip preloop]" \
131+ --body-file "$BODY"; then
132+ EXISTING_URL="$(gh pr list \
133+ --repo "$GITHUB_REPOSITORY" \
134+ --state open \
135+ --head "$BRANCH" \
136+ --json url \
137+ --jq '.[0].url // empty')"
138+ test -n "$EXISTING_URL"
139+ echo "concurrent reminder already opened: $EXISTING_URL"
140+ fi
0 commit comments