tenseleyflow/shithub / 1baf580

Browse files

actions: document arbitrary repo smoke

Authored by mfwolffe <wolffemf@dukes.jmu.edu>
SHA
1baf5803a9a155cdfaaf91022b3c5fc9f1910519
Parents
b9f1094
Tree
21a4e6d

5 changed files

StatusFile+-
M docs/internal/runbooks/actions-runner.md 92 1
M docs/internal/runbooks/runner-deploy.md 7 0
M docs/public/user/actions.md 25 0
M internal/actions/workflow/parse_test.go 36 0
A tests/fixtures/workflows/arbitrary-repo-smoke.yml 13 0
docs/internal/runbooks/actions-runner.mdmodified
@@ -10,7 +10,7 @@ For host provisioning and the systemd/Ansible path, see
1010
 
1111
 Prereqs:
1212
 
13
-- Database migrations are current through `0057_workflow_job_secret_masks.sql`.
13
+- Database migrations are current through `0067_runner_pool_ops.sql`.
1414
 - `SHITHUB_TOTP_KEY` or `auth.totp_key_b64` is set on the web process.
1515
 - Object storage is configured if testing artifact upload.
1616
 - Docker or Podman is installed on the runner host.
@@ -175,6 +175,97 @@ Environment variables use the `SHITHUB_RUNNER_` prefix, for example
175175
 Use `--expires-in` only for tokens that your automation rotates before expiry;
176176
 the runner presents its registration token on every heartbeat.
177177
 
178
+## Arbitrary Repository Smoke
179
+
180
+Use this checklist after provisioning a shared runner pool or changing runner
181
+labels. The purpose is to prove that ordinary repositories can use the pool
182
+without repo-specific labels.
183
+
184
+Pick at least two repositories:
185
+
186
+- `mfwolffe/scratch`, the historical dogfood repo;
187
+- one additional public repository;
188
+- one private repository if one is available for the operator account.
189
+
190
+In each repository, commit this file as `.shithub/workflows/smoke.yml` on
191
+`trunk`:
192
+
193
+```yaml
194
+name: Smoke
195
+on:
196
+  push:
197
+    branches: [trunk]
198
+jobs:
199
+  green:
200
+    runs-on: ubuntu-latest
201
+    steps:
202
+      - uses: actions/checkout@v4
203
+      - name: Verify checkout
204
+        run: test -f README.md || test -f readme.md || pwd
205
+      - name: Smoke
206
+        run: printf 'shithub actions smoke passed\n'
207
+```
208
+
209
+Expected results for each repo:
210
+
211
+- the repo heading shows a green check after the push;
212
+- the Actions run page shows `Triggered via push` on `refs/heads/trunk`;
213
+- the `green` job is completed with conclusion `success`;
214
+- the checkout step logs the scoped repository URL for that repo;
215
+- the smoke step log contains `shithub actions smoke passed`;
216
+- the check run attached to the commit agrees with the workflow run state;
217
+- the downloaded or raw archived step log matches the in-page step log.
218
+
219
+Confirm the pool is shared:
220
+
221
+```sh
222
+shithubd admin runner list --output json
223
+shithubd admin runner queue --output json
224
+```
225
+
226
+The same online runner labels should satisfy both repositories. The smoke
227
+workflow must use `runs-on: ubuntu-latest`; do not add per-repo labels for this
228
+test.
229
+
230
+Unsupported-label negative test:
231
+
232
+```yaml
233
+name: Unsupported runner label
234
+on:
235
+  workflow_dispatch:
236
+jobs:
237
+  nope:
238
+    runs-on: windows-latest
239
+    steps:
240
+      - run: echo should-not-run
241
+```
242
+
243
+Trigger it manually. The run should stay queued and the run page should say
244
+`Waiting for runner with labels: windows-latest`. `shithubd admin runner queue
245
+--output json` should show one queued `windows-latest` job with zero matching
246
+runners. Cancel the run after confirming the diagnostic.
247
+
248
+Untrusted-PR secret negative test:
249
+
250
+1. Add a repo secret named `S41J_SECRET_SMOKE` with any non-production value.
251
+2. Open an untrusted pull request whose workflow prints whether that secret is
252
+   present.
253
+3. Before approval, confirm the claimed job contains no injected secrets and
254
+   logs do not contain the secret value.
255
+4. Only after explicit approval should the run be allowed through the trusted
256
+   secret path.
257
+
258
+Runner-outage negative test:
259
+
260
+1. Drain every shared runner with `shithubd admin runner drain --id <id>`.
261
+2. Push the smoke workflow to a test repo.
262
+3. Confirm the run stays queued with the requested `ubuntu-latest` label visible.
263
+4. Undrain one runner and confirm the same queued job is claimed and completes.
264
+
265
+This smoke is considered passing only when scratch and the second repository
266
+both complete from the same shared label set and the negative cases produce
267
+clear queued/secret-denied behavior.
268
+
178269
 The Ansible runner role creates the `shithub-actions` bridge, runs the
179270
 allowlist resolver at `172.30.0.1`, and installs firewall rules that
180271
 reject direct-IP egress from step containers. If you run the binary
docs/internal/runbooks/runner-deploy.mdmodified
@@ -215,6 +215,13 @@ Expected state:
215215
 Repeat with `exit 1`; the check should complete with conclusion
216216
 `failure`.
217217
 
218
+Before declaring a shared pool available to arbitrary repositories, run the
219
+[arbitrary repository smoke](./actions-runner.md#arbitrary-repository-smoke)
220
+checklist against scratch and at least one additional repository. The single
221
+repo check above proves the runner process works; the arbitrary-repo smoke
222
+proves label routing, checkout scoping, archived logs, check runs, and negative
223
+queue/secret cases across normal repositories.
224
+
218225
 Sandbox smoke checks:
219226
 
220227
 ```yaml
docs/public/user/actions.mdmodified
@@ -24,6 +24,31 @@ Commit that file as `.shithub/workflows/smoke.yml` and push to the repository.
2424
 The run appears under the repository's Actions tab and its job also appears as
2525
 a check run on matching pull requests.
2626
 
27
+## Copy-paste smoke workflow
28
+
29
+Use this workflow to confirm a normal repository can use the shared Linux pool.
30
+It runs on every push to `trunk` while Actions are enabled for the repository
31
+and a runner advertising `ubuntu-latest` is online.
32
+
33
+```yaml
34
+name: Smoke
35
+on:
36
+  push:
37
+    branches: [trunk]
38
+jobs:
39
+  green:
40
+    runs-on: ubuntu-latest
41
+    steps:
42
+      - uses: actions/checkout@v4
43
+      - name: Verify checkout
44
+        run: test -f README.md || test -f readme.md || pwd
45
+      - name: Smoke
46
+        run: printf 'shithub actions smoke passed\n'
47
+```
48
+
49
+The same file should work in any repository that is allowed by the site, org,
50
+and repo Actions policies. It should not need a repo-specific runner label.
51
+
2752
 ## What works today
2853
 
2954
 - `push`, `pull_request`, `schedule`, and `workflow_dispatch` triggers
internal/actions/workflow/parse_test.gomodified
@@ -71,6 +71,42 @@ func TestParse_CheckoutOnly(t *testing.T) {
7171
 	}
7272
 }
7373
 
74
+func TestParse_ArbitraryRepoSmoke(t *testing.T) {
75
+	t.Parallel()
76
+	w, diags, err := workflow.Parse(readFixture(t, "arbitrary-repo-smoke"))
77
+	if err != nil {
78
+		t.Fatalf("Parse: %v", err)
79
+	}
80
+	if len(diags) != 0 {
81
+		t.Fatalf("unexpected diagnostics: %v", diags)
82
+	}
83
+	if w.Name != "Smoke" {
84
+		t.Fatalf("Name = %q, want Smoke", w.Name)
85
+	}
86
+	if w.On.Push == nil || len(w.On.Push.Branches) != 1 || w.On.Push.Branches[0] != "trunk" {
87
+		t.Fatalf("push branches = %+v", w.On.Push)
88
+	}
89
+	if len(w.Jobs) != 1 {
90
+		t.Fatalf("len(Jobs) = %d", len(w.Jobs))
91
+	}
92
+	job := w.Jobs[0]
93
+	if job.Key != "green" || job.RunsOn != "ubuntu-latest" {
94
+		t.Fatalf("job = %+v", job)
95
+	}
96
+	if len(job.Steps) != 3 {
97
+		t.Fatalf("steps = %+v", job.Steps)
98
+	}
99
+	if job.Steps[0].Uses != "actions/checkout@v4" {
100
+		t.Fatalf("checkout step = %+v", job.Steps[0])
101
+	}
102
+	if job.Steps[1].Name != "Verify checkout" || !strings.Contains(job.Steps[1].Run, "README.md") {
103
+		t.Fatalf("verify step = %+v", job.Steps[1])
104
+	}
105
+	if job.Steps[2].Name != "Smoke" || !strings.Contains(job.Steps[2].Run, "shithub actions smoke passed") {
106
+		t.Fatalf("smoke step = %+v", job.Steps[2])
107
+	}
108
+}
109
+
74110
 func TestParse_MultiJob(t *testing.T) {
75111
 	t.Parallel()
76112
 	w, diags, err := workflow.Parse(readFixture(t, "multi-job"))
tests/fixtures/workflows/arbitrary-repo-smoke.ymladded
@@ -0,0 +1,13 @@
1
+name: Smoke
2
+on:
3
+  push:
4
+    branches: [trunk]
5
+jobs:
6
+  green:
7
+    runs-on: ubuntu-latest
8
+    steps:
9
+      - uses: actions/checkout@v4
10
+      - name: Verify checkout
11
+        run: test -f README.md || test -f readme.md || pwd
12
+      - name: Smoke
13
+        run: printf 'shithub actions smoke passed\n'