Skip to content

Commit b256946

Browse files
authored
Merge branch 'main' into feat/eol-archive-repos
2 parents 4f829ce + f9c520c commit b256946

13 files changed

Lines changed: 542 additions & 205 deletions

File tree

.github/workflows/apiserver.yml

Lines changed: 0 additions & 137 deletions
This file was deleted.

.github/workflows/code-reviews.yml

Lines changed: 0 additions & 49 deletions
This file was deleted.

.github/workflows/deploy.yml

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
# Security checklists:
2+
# https://aquilax.ai/blog/github-actions-security-hardening
3+
# https://www.wiz.io/blog/github-actions-security-guide
4+
5+
name: Deploy
6+
7+
on:
8+
workflow_dispatch:
9+
inputs:
10+
run_id:
11+
description: "Test and build workflow run ID to deploy"
12+
required: true
13+
# zizmor: ignore[dangerous-triggers] Only triggered via default branch
14+
workflow_run:
15+
workflows:
16+
- Test and build
17+
branches:
18+
- main
19+
types:
20+
- completed
21+
22+
permissions:
23+
contents: read
24+
25+
concurrency:
26+
group: ci-${{ github.workflow }}-${{ github.ref }}
27+
28+
jobs:
29+
validate:
30+
runs-on: ubuntu-24.04
31+
timeout-minutes: 2
32+
if: github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success'
33+
outputs:
34+
build_run_id: ${{ steps.resolve-run-id.outputs.run_id }}
35+
build_skipped: ${{ steps.validate-run-id.outputs.build_skipped }}
36+
build_head_sha: ${{ steps.validate-run-id.outputs.build_head_sha }}
37+
build_run_number: ${{ steps.validate-run-id.outputs.build_run_number }}
38+
build_url: ${{ steps.validate-run-id.outputs.build_url }}
39+
steps:
40+
- name: Resolve run ID
41+
id: resolve-run-id
42+
run: echo "run_id=$RESULT" >> "$GITHUB_OUTPUT"
43+
env:
44+
RESULT: ${{ github.event_name == 'workflow_run' && github.event.workflow_run.id || github.event.inputs.run_id }}
45+
46+
- name: Validate run ID
47+
id: validate-run-id
48+
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
49+
env:
50+
RUN_ID: ${{ steps.resolve-run-id.outputs.run_id }}
51+
EXPECTED_WORKFLOW_NAME: Test and build
52+
EXPECTED_BRANCH: main
53+
EXPECTED_JOB_NAME: apiserver-build
54+
with:
55+
script: |
56+
const runId = Number(process.env.RUN_ID);
57+
if (!Number.isInteger(runId) || runId <= 0) {
58+
core.setFailed(`Invalid run_id: ${process.env.RUN_ID}`);
59+
return;
60+
}
61+
62+
const { owner, repo } = context.repo;
63+
const run = (
64+
await github.rest.actions.getWorkflowRun({
65+
owner,
66+
repo,
67+
run_id: runId
68+
})
69+
).data;
70+
71+
if (run.name !== process.env.EXPECTED_WORKFLOW_NAME) {
72+
core.setFailed(
73+
`run_id ${runId} is for workflow '${run.name}', expected '${process.env.EXPECTED_WORKFLOW_NAME}'`
74+
);
75+
return;
76+
}
77+
78+
if (run.head_branch !== process.env.EXPECTED_BRANCH) {
79+
core.setFailed(
80+
`run_id ${runId} is on branch '${run.head_branch}', expected '${process.env.EXPECTED_BRANCH}'`
81+
);
82+
return;
83+
}
84+
85+
if (run.conclusion !== 'success') {
86+
core.setFailed(
87+
`run_id ${runId} has conclusion '${run.conclusion}', expected 'success'`
88+
);
89+
return;
90+
}
91+
92+
if (run.head_repository?.full_name !== `${owner}/${repo}`) {
93+
core.setFailed(
94+
`run_id ${runId} belongs to '${run.head_repository?.full_name}', expected '${owner}/${repo}'`
95+
);
96+
return;
97+
}
98+
99+
const jobs = await github.paginate(github.rest.actions.listJobsForWorkflowRun, {
100+
owner,
101+
repo,
102+
run_id: runId,
103+
per_page: 100,
104+
});
105+
106+
const buildJob = jobs.find((job) => job.name === process.env.EXPECTED_JOB_NAME);
107+
if (!buildJob) {
108+
core.setFailed(
109+
`run_id ${runId} does not contain expected job '${process.env.EXPECTED_JOB_NAME}'`
110+
);
111+
return;
112+
}
113+
114+
if (buildJob.conclusion === 'skipped') {
115+
core.setOutput('build_skipped', 'true');
116+
core.info(`job '${process.env.EXPECTED_JOB_NAME}' in run_id ${runId} was skipped; nothing to deploy`);
117+
return;
118+
}
119+
120+
if (buildJob.conclusion !== 'success') {
121+
core.setFailed(
122+
`job '${process.env.EXPECTED_JOB_NAME}' in run_id ${runId} has conclusion '${buildJob.conclusion}', expected 'success'`
123+
);
124+
return;
125+
}
126+
127+
core.setOutput('build_skipped', 'false');
128+
core.setOutput('build_head_sha', run.head_sha);
129+
core.setOutput('build_run_number', String(run.run_number));
130+
core.setOutput('build_url', run.html_url);
131+
132+
deploy-apiserver:
133+
runs-on: ubuntu-24.04
134+
timeout-minutes: 15
135+
needs: validate
136+
environment: deploy
137+
if: needs.validate.outputs.build_skipped == 'false'
138+
permissions:
139+
contents: write
140+
id-token: write
141+
steps:
142+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
143+
with:
144+
persist-credentials: true
145+
ref: ${{ needs.validate.outputs.build_head_sha }}
146+
147+
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
148+
with:
149+
name: apiserver
150+
run-id: ${{ needs.validate.outputs.build_run_id }}
151+
github-token: ${{ secrets.GITHUB_TOKEN }}
152+
153+
- name: Create tag
154+
run: |
155+
{
156+
git show -s --format=%B "$BUILD_HEAD_SHA"
157+
echo
158+
echo "Deploy run: $GITHUB_RUN_ID"
159+
echo "Build run: $BUILD_RUN_ID"
160+
echo "Build number: $BUILD_RUN_NUMBER"
161+
echo "Build URL: $BUILD_URL"
162+
echo "Build SHA: $BUILD_HEAD_SHA"
163+
} > tag-message.txt
164+
165+
git config user.name "github-actions[bot]"
166+
git config user.email "github-actions[bot]@users.noreply.github.com"
167+
git tag -a apiserver-"$GITHUB_RUN_NUMBER" -F tag-message.txt "$BUILD_HEAD_SHA"
168+
env:
169+
BUILD_RUN_ID: ${{ needs.validate.outputs.build_run_id }}
170+
BUILD_RUN_NUMBER: ${{ needs.validate.outputs.build_run_number }}
171+
BUILD_URL: ${{ needs.validate.outputs.build_url }}
172+
BUILD_HEAD_SHA: ${{ needs.validate.outputs.build_head_sha }}
173+
174+
- name: Push tag
175+
run: git push origin apiserver-"$GITHUB_RUN_NUMBER"
176+
177+
- name: Create release
178+
run: >
179+
gh release create
180+
apiserver-"$GITHUB_RUN_NUMBER"
181+
apiserver-*.tar.zst
182+
--title "apiserver v$GITHUB_RUN_NUMBER"
183+
--notes-from-tag
184+
--verify-tag
185+
env:
186+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
187+
188+
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
189+
id: get-id-token
190+
with:
191+
script: |
192+
const fs = require('fs');
193+
const token = await core.getIDToken('backend.fullstaqruby.org');
194+
fs.writeFileSync(
195+
process.env.GITHUB_OUTPUT,
196+
`id_token<<EOF\n${token}\nEOF\n`,
197+
{ flag: 'a' }
198+
);
199+
200+
- name: Deploy
201+
run: >
202+
curl -fL --no-progress-meter -X POST -H "Authorization: Bearer $TOKEN"
203+
https://apt.fullstaqruby.org/admin/upgrade_apiserver
204+
env:
205+
TOKEN: ${{ steps.get-id-token.outputs.id_token }}

0 commit comments

Comments
 (0)