mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-03 07:18:03 +01:00
fix(pregate): clear validates the remote gate receipt; test_backend run URLs are attested
`gstack-pregate clear` accepted any --run-url for a small machine's obligation. A pregate.json/remote_gate obligation now clears only with --receipt <file> holding the gate's PREGATE_REMOTE: line, validated as --remote validates it (tree equals the tested tree, tests > 0, failed = 0; shared parseRemoteReport/remoteReportProblem); a run URL is usage (exit 2) and a bad receipt is PREGATE_RECEIPT_INVALID (exit 1, obligation unchanged). A test_backend/<backend> obligation has no machine-checkable receipt: its --run-url is recorded as attested:<url> and the output says attested, not validated. Platform lanes are unchanged. Hints name the right clear form. New code PREGATE_RECEIPT_INVALID: result-codes row, troubleshooting anchor, installer-form error line, regenerated doctor components. Files (G2): lib/pregate/index.ts, lib/pregate/checks/lanes.ts, bin/gstack-pregate, lib/result-codes.ts, bin/gstack-doctor-components.sh (generated), docs/pregate.md, docs/troubleshooting.md, test/pregate-remote.test.ts. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
b235af1184
commit
1f7b003fba
8 files changed
+145
-33
No files matched your search
@@ -162,6 +162,7 @@ gstack_result_anchor() {
|
||||
PREGATE_LANE_FAILED) printf '%s' 'pregate-lane-failed' ;;
|
||||
PREGATE_INCOMPLETE) printf '%s' 'pregate-incomplete' ;;
|
||||
PREGATE_STALLED) printf '%s' 'pregate-stalled' ;;
|
||||
PREGATE_RECEIPT_INVALID) printf '%s' 'pregate-receipt-invalid' ;;
|
||||
PREGATE_STALE) printf '%s' 'pregate-stale' ;;
|
||||
PREGATE_REMOTE_UNCLEARED) printf '%s' 'pregate-remote-uncleared' ;;
|
||||
ISSUE_UNREADABLE) printf '%s' 'issue-unreadable' ;;
|
||||
|
||||
+17
-11
@@ -6,7 +6,7 @@
|
||||
* [--allow-repo-commands] [--policy-from base|head] [--out <pregate.json>]
|
||||
* [--timeout <s>] [--stall-timeout <s>] [--remote --spend-cap <usd>] [--run <id>] [--explain] [--json]
|
||||
* gstack-pregate verify [--out <pregate.json>] [--json] publication check: current tree, no fail/incomplete, obligations cleared
|
||||
* gstack-pregate clear --remote <workflow.yml/job> --run-url <url> | --bundle-lane <label> [--out <pregate.json>]
|
||||
* gstack-pregate clear --remote <workflow.yml/job> --run-url <url> | --bundle-lane <label> | --receipt <file> [--out <pregate.json>]
|
||||
* gstack-pregate lanes [--explain] the lane list and platform tiers read from .github/workflows
|
||||
* gstack-pregate validate | init [--explain] [--force] the working-tree .gstack/pregate.json
|
||||
* gstack-pregate sealed [--range <a..b>] [--remote <name>] [--base <branch>] [--json]
|
||||
@@ -29,10 +29,11 @@ import * as path from 'node:path';
|
||||
import { EXIT, exitTableHelp, formatResult, type PregateFile } from '../lib/headless-artifacts';
|
||||
import { PREGATE_CONFIG_PATH, exampleConfigJson, explainConfig, loadConfigFromHead } from '../lib/pregate/config';
|
||||
import { buildContext } from '../lib/pregate/context';
|
||||
import { CHECKS, CHECK_IDS, PREGATE_OUT_REL, PREGATE_TIER2, clearObligation, readPregateFile, renderTable, runPregate, verifyPregate, writePregateFile } from '../lib/pregate/index';
|
||||
import { CHECKS, CHECK_IDS, PREGATE_OUT_REL, PREGATE_TIER2, clearDecision, clearObligation, readPregateFile, renderTable, runPregate, verifyPregate, writePregateFile } from '../lib/pregate/index';
|
||||
import { describeLane, discoverLanes } from '../lib/pregate/workflows';
|
||||
import { REMOTE_GATE_LANE } from '../lib/pregate/checks/lanes';
|
||||
import { ensureTmpExcluded } from '../lib/restamp';
|
||||
import { resultCodeSuffix, resultLine, type ResultCodeName } from '../lib/result-codes';
|
||||
import { RESULT_CODES, resultCodeSuffix, resultLine, type ResultCodeName } from '../lib/result-codes';
|
||||
import { DEFAULT_STALL_TIMEOUT_S } from '../lib/pregate/context';
|
||||
import { cancelActive } from '../lib/pregate/supervise';
|
||||
import { defaultGh, evaluateRegate, renderRegate } from '../lib/pregate/regate';
|
||||
@@ -45,7 +46,9 @@ const HELP = `gstack-pregate — cheap checks before anything paid or remote (do
|
||||
|
||||
run (default) stage 1 mechanical preflight (${CHECKS.filter(c => c.stage === 'preflight').map(c => c.id).join(', ')}), then stage 2 test execution (${CHECKS.filter(c => c.stage === 'tests').map(c => c.id).join(', ')})
|
||||
verify publication check against ${PREGATE_OUT_REL}: current tree, no fail or incomplete, every requires-remote obligation cleared
|
||||
clear record the receipt that clears one requires-remote obligation
|
||||
clear record the receipt that clears one requires-remote obligation: pregate.json/remote_gate needs
|
||||
--receipt <file> (the gate's PREGATE_REMOTE: line, checked against the tested tree); a
|
||||
test_backend/<backend> run URL is recorded as attested, not validated
|
||||
lanes print every CI lane with its platform tier (from .github/workflows/*.yml)
|
||||
validate | init the working-tree ${PREGATE_CONFIG_PATH}
|
||||
sealed [--range <a..b>] [--remote <name>] [--base <branch>]
|
||||
@@ -88,7 +91,7 @@ function flag(args: string[], name: string): string | undefined { const i = args
|
||||
const VERB_FLAGS: Record<string, [string[], string[]]> = {
|
||||
run: [['--stage', '--only', '--base', '--policy-from', '--out', '--timeout', '--stall-timeout', '--spend-cap', '--run'], ['--allow-repo-commands', '--explain', '--json', '--remote']],
|
||||
verify: [['--out'], ['--json']],
|
||||
clear: [['--remote', '--run-url', '--bundle-lane', '--out'], []],
|
||||
clear: [['--remote', '--run-url', '--bundle-lane', '--receipt', '--out'], []],
|
||||
lanes: [[], ['--explain', '--json']],
|
||||
validate: [[], ['--json']],
|
||||
init: [[], ['--explain', '--force']],
|
||||
@@ -192,16 +195,19 @@ function cmdVerify(root: string, rest: string[], json: boolean): number {
|
||||
|
||||
function cmdClear(root: string, rest: string[]): number {
|
||||
const lane = flag(rest, '--remote');
|
||||
const receipt = flag(rest, '--run-url') ?? (flag(rest, '--bundle-lane') ? `bundle-lane:${flag(rest, '--bundle-lane')}` : undefined);
|
||||
if (!lane || !receipt) { process.stderr.write(`gstack-pregate clear: --remote <workflow.yml/job> and --run-url <url> (or --bundle-lane <label>) are required\n`); return EXIT.usage; }
|
||||
if (!lane) { process.stderr.write(`gstack-pregate clear: --remote <workflow.yml/job> with --run-url <url>, --bundle-lane <label> or (for ${REMOTE_GATE_LANE}) --receipt <file> is required\n`); return EXIT.usage; }
|
||||
const out = outPath(root, rest);
|
||||
const read = fs.existsSync(out) ? readPregateFile(out) : { file: null, errors: [] };
|
||||
if (!read.file) { process.stderr.write(resultLine('gstack-pregate clear', 'PREGATE_STALE', `${out} is missing or invalid; run gstack-pregate first`) + '\n'); return EXIT.fail; }
|
||||
let file: PregateFile;
|
||||
try { file = clearObligation(read.file, lane, receipt, `gstack-pregate clear ${new Date().toISOString()}`); }
|
||||
catch (e: any) { process.stderr.write(`gstack-pregate clear: ${e.message}\n`); return EXIT.usage; }
|
||||
const decision = clearDecision(read.file, lane, { runUrl: flag(rest, '--run-url'), bundleLane: flag(rest, '--bundle-lane'), receiptPath: flag(rest, '--receipt') });
|
||||
if ('refused' in decision) {
|
||||
if (decision.refused === 'usage') { process.stderr.write(`gstack-pregate clear: ${decision.message}\n`); return EXIT.usage; }
|
||||
process.stderr.write(`gstack-pregate clear: receipt refused — ${decision.message}; fix: ${RESULT_CODES.PREGATE_RECEIPT_INVALID.fix} ${resultCodeSuffix('PREGATE_RECEIPT_INVALID')}\n`);
|
||||
return EXIT.fail;
|
||||
}
|
||||
const file = clearObligation(read.file, lane, decision.receipt, `gstack-pregate clear ${new Date().toISOString()}`);
|
||||
writePregateFile(root, out, file);
|
||||
process.stdout.write(`PREGATE_CLEARED: ${lane} receipt=${receipt} verdict=${file.verdict}\n`);
|
||||
process.stdout.write(`PREGATE_CLEARED: ${lane} receipt=${decision.receipt} verdict=${file.verdict}${decision.attested ? ` (attested, not validated: ${lane} has no machine-checkable receipt)` : ''}\n`);
|
||||
return EXIT.ok;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user