ReviewOS

also looking at this

stacks/drone

test: retain execution lifetime failure observations

#62
Draft chris wants to merge codex/execution-lifetime-observations into main
10 files +174 -64

Review threads live on the whole diff, not on one commit, so none are shown here - a thread's line means something in the branch's final form, and painting it into an intermediate step would put it on code it is not about.

.github/workflows/ci.ymlmodified+13-0
Changes to .github/workflows/ci.yml
@@ -58,6 +58,19 @@ jobs:
5858 env:
5959 RUNTIME_HOST_FILE_LIMIT_EVIDENCE: ${{ runner.temp }}/runtime-host-file-limit-full-evidence
6060 RUNTIME_MAINTENANCE_EVIDENCE: ${{ runner.temp }}/runtime-maintenance-full-evidence
61 EXECUTION_LIFETIME_EVIDENCE: ${{ runner.temp }}/execution-lifetime-failures
62 - uses: actions/upload-artifact@v4
63 if: always()
64 with:
65 name: execution-lifetime-failure-evidence
66 if-no-files-found: ignore
67 retention-days: 7
68 path: |
69 ${{ runner.temp }}/execution-lifetime-failures/*/fixture.stdout
70 ${{ runner.temp }}/execution-lifetime-failures/*/fixture.stderr
71 ${{ runner.temp }}/execution-lifetime-failures/*/lifecycle.json
72 ${{ runner.temp }}/execution-lifetime-failures/*/access.sqlite*
73 ${{ runner.temp }}/execution-lifetime-failures/*/bunfig.toml
6174 - uses: actions/upload-artifact@v4
6275 if: always()
6376 with:
docs/public-safety-execution.mdmodified+7-2
Changes to docs/public-safety-execution.md
@@ -123,8 +123,13 @@ exit code and signal separately from whether its own watchdog fired or cleanup
123123requested a kill. Elapsed time includes process work and output handling, not
124124just a native check. Failed cases retain their private temporary directory,
125125stdout, stderr and lifecycle receipt when storage permits. A fixed warning
126reports an unavailable receipt if that write fails. Successful cases remove
127their temporary files as before.
126identifies each unavailable evidence file if its write fails; this does not
127replace the captured child diagnostics or its original test verdict. Successful
128cases remove their temporary files as before. CI sets `EXECUTION_LIFETIME_EVIDENCE`
129to an owned runner directory and retains the failed synthetic database, process
130configuration and captured diagnostics for seven days, using explicit file
131patterns that exclude linked dependencies. No account tokens, scope identifiers or recording contents are included
132in the scalar phase and lifecycle observations.
128133
129134These observations support [the unresolved Mac failure](https://github.com/stacksjs/drone/issues/60);
130135they do not establish its cause or repair it. The production authority-check
tests/unit/public-safety-execution-lifetime.test.tsmodified+14-8
Changes to tests/unit/public-safety-execution-lifetime.test.ts
@@ -1,13 +1,20 @@
11import { expect, test } from 'bun:test'
2import { mkdtemp, rm, writeFile } from 'node:fs/promises'
2import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises'
33import { tmpdir } from 'node:os'
4import { join } from 'node:path'
4import { join, resolve } from 'node:path'
55
66for (const mode of ['completed', 'canceled', 'quarantine']) test(`native execution lifetime ${mode}`, async () => {
7 const root = await mkdtemp(join(tmpdir(), 'drone-incident-access-execution-lifetime-'))
7 const evidence = process.env.EXECUTION_LIFETIME_EVIDENCE
8 if (evidence) await mkdir(resolve(evidence), { recursive: true, mode: 0o700 })
9 const root = await mkdtemp(join(evidence ? resolve(evidence) : tmpdir(), 'drone-incident-access-execution-lifetime-'))
810 let child: ReturnType<typeof Bun.spawn> | undefined
911 const began = performance.now()
1012 let deadlineFired = false, cleanupKill = false, completed = false
13 let stdoutWritten = false, stderrWritten = false
14 const retain = async (artifact: 'fixture.stdout' | 'fixture.stderr' | 'lifecycle.json', value: string) => {
15 try { await writeFile(join(root, artifact), value, { mode: 0o600, flag: 'wx' }); return true }
16 catch { console.error('LIFETIME_FIXTURE_EVIDENCE_UNAVAILABLE', JSON.stringify({ mode, artifact })); return false }
17 }
1118 try {
1219 const config = join(root, 'bunfig.toml'); await writeFile(config, 'preload=[]\n[install]\nauto="disable"\n')
1320 const running = child = Bun.spawn([process.execPath, '--no-install', `--config=${config}`, '--no-env-file', `${import.meta.dir}/../fixtures/public-safety-access/execution-lifetime.ts`, mode], { cwd: root, env: { APP_ENV: 'test', APP_DEBUG: 'false', NODE_ENV: 'test', DB_CONNECTION: 'sqlite', DB_DATABASE_PATH: join(root, 'access.sqlite') }, stdin: 'ignore', stdout: 'pipe', stderr: 'pipe' })
@@ -19,10 +26,10 @@ for (const mode of ['completed', 'canceled', 'quarantine']) test(`native executi
1926 }, 90000)
2027 try {
2128 const [code, stdout, stderr] = await Promise.all([running.exited, new Response(running.stdout).text(), new Response(running.stderr).text()])
22 await writeFile(join(root, 'fixture.stdout'), stdout, { mode: 0o600 })
23 await writeFile(join(root, 'fixture.stderr'), stderr, { mode: 0o600 })
2429 // eslint-disable-next-line no-console
2530 for (const line of stdout.split('\n')) if (line.startsWith('{"oracle":')) console.log(line)
31 stdoutWritten = await retain('fixture.stdout', stdout)
32 stderrWritten = await retain('fixture.stderr', stderr)
2633 expect(code, `${stdout}\n${stderr}`).toBe(0)
2734 expect(stdout).toContain(`PASS native execution lifetime ${mode}`)
2835 completed = true
@@ -31,10 +38,9 @@ for (const mode of ['completed', 'canceled', 'quarantine']) test(`native executi
3138 }
3239 finally {
3340 if (child?.exitCode === null) { cleanupKill = true; child.kill('SIGKILL'); await child.exited }
34 const lifecycle = { mode, pid: child?.pid ?? null, exitCode: child?.exitCode ?? null, signal: child?.signalCode ?? null, timeoutMs: 90000, deadlineFired, cleanupKill, elapsedMs: performance.now() - began, completed }
41 const lifecycle = { mode, pid: child?.pid ?? null, exitCode: child?.exitCode ?? null, signal: child?.signalCode ?? null, timeoutMs: 90000, deadlineFired, cleanupKill, elapsedMs: performance.now() - began, stdoutWritten, stderrWritten, completed }
3542 console.log(JSON.stringify({ oracle: 'lifetime-fixture-exit', ...lifecycle }))
36 try { await writeFile(join(root, 'lifecycle.json'), JSON.stringify(lifecycle, null, 2), { mode: 0o600 }) }
37 catch { console.error('LIFETIME_FIXTURE_EVIDENCE_UNAVAILABLE', JSON.stringify({ mode })) }
43 await retain('lifecycle.json', JSON.stringify(lifecycle, null, 2))
3844 if (completed) await rm(root, { recursive: true, force: true })
3945 else console.error('LIFETIME_FIXTURE_RETAINED', root)
4046 }