@miller-tech/uap 1.141.0 → 1.143.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.tsbuildinfo +1 -1
- package/dist/bin/cli.js +2 -0
- package/dist/bin/cli.js.map +1 -1
- package/dist/browser/web-browser.d.ts +4 -0
- package/dist/browser/web-browser.d.ts.map +1 -1
- package/dist/browser/web-browser.js +20 -0
- package/dist/browser/web-browser.js.map +1 -1
- package/dist/cli/deliver.d.ts.map +1 -1
- package/dist/cli/deliver.js +45 -1
- package/dist/cli/deliver.js.map +1 -1
- package/dist/cli/guided-setup.d.ts.map +1 -1
- package/dist/cli/guided-setup.js +49 -0
- package/dist/cli/guided-setup.js.map +1 -1
- package/dist/cli/policy-select.d.ts +46 -0
- package/dist/cli/policy-select.d.ts.map +1 -0
- package/dist/cli/policy-select.js +135 -0
- package/dist/cli/policy-select.js.map +1 -0
- package/dist/cli/policy.d.ts +15 -0
- package/dist/cli/policy.d.ts.map +1 -1
- package/dist/cli/policy.js +77 -2
- package/dist/cli/policy.js.map +1 -1
- package/dist/cli/verify.d.ts +3 -0
- package/dist/cli/verify.d.ts.map +1 -1
- package/dist/cli/verify.js +7 -0
- package/dist/cli/verify.js.map +1 -1
- package/dist/cli/wizard-config.d.ts +4 -0
- package/dist/cli/wizard-config.d.ts.map +1 -1
- package/dist/cli/wizard-config.js +1 -1
- package/dist/cli/wizard-config.js.map +1 -1
- package/dist/config/settings-registry.d.ts.map +1 -1
- package/dist/config/settings-registry.js +10 -0
- package/dist/config/settings-registry.js.map +1 -1
- package/dist/delivery/acceptance-judge.d.ts.map +1 -1
- package/dist/delivery/acceptance-judge.js +16 -0
- package/dist/delivery/acceptance-judge.js.map +1 -1
- package/dist/delivery/user-paths.d.ts +85 -0
- package/dist/delivery/user-paths.d.ts.map +1 -0
- package/dist/delivery/user-paths.js +179 -0
- package/dist/delivery/user-paths.js.map +1 -0
- package/dist/delivery/user-validation.d.ts +89 -0
- package/dist/delivery/user-validation.d.ts.map +1 -0
- package/dist/delivery/user-validation.js +516 -0
- package/dist/delivery/user-validation.js.map +1 -0
- package/dist/delivery/verifier-ladder.d.ts +7 -1
- package/dist/delivery/verifier-ladder.d.ts.map +1 -1
- package/dist/delivery/verifier-ladder.js +9 -2
- package/dist/delivery/verifier-ladder.js.map +1 -1
- package/dist/types/config.d.ts +8 -0
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/config.js +6 -0
- package/dist/types/config.js.map +1 -1
- package/package.json +1 -1
- package/src/policies/enforcers/__pycache__/_common.cpython-312.pyc +0 -0
- package/src/policies/enforcers/enforcement_self_protect.py +1 -0
- package/templates/hooks/pre-tool-use-bash.sh +30 -0
- package/templates/hooks/uap-policy-gate.sh +1 -1
- package/tools/agents/scripts/__pycache__/toolcall_path_normalizer.cpython-312.pyc +0 -0
|
@@ -0,0 +1,516 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* user-validation: exercise the delivered artifact through the SAME CLIENT a
|
|
3
|
+
* real user would use, and refuse DELIVERED until the critical paths pass.
|
|
4
|
+
*
|
|
5
|
+
* - browser paths: headless Chromium (cloakbrowser via WebBrowser) — real DOM
|
|
6
|
+
* interaction with console-error capture. `curl 200` does not count.
|
|
7
|
+
* - http paths: real HTTP requests against the actually-started server.
|
|
8
|
+
* - cli paths: the built artifact spawned with real argv.
|
|
9
|
+
*
|
|
10
|
+
* The runner interprets the declarative manifest (user-paths.ts); the model
|
|
11
|
+
* never supplies harness code. Results land in agents/data/validation/latest.json
|
|
12
|
+
* with a sha256 recorded in-process (getTrustedReportHash) so the acceptance
|
|
13
|
+
* judge's runtime note can refuse a report the runner did not itself write —
|
|
14
|
+
* the same anti-fabrication stance as the gate-integrity guard (integrity.ts).
|
|
15
|
+
*
|
|
16
|
+
* Availability follows the deploy-dev precedent: a missing browser marks
|
|
17
|
+
* browser paths skipped (rung non-blocking) rather than failing delivery on an
|
|
18
|
+
* environment gap — but the skip is loud in the report and the judge note.
|
|
19
|
+
*/
|
|
20
|
+
import { spawn, spawnSync } from 'node:child_process';
|
|
21
|
+
import { createHash } from 'node:crypto';
|
|
22
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
23
|
+
import { join } from 'node:path';
|
|
24
|
+
import { startStaticServer } from './execution-gate.js';
|
|
25
|
+
import { loadUserPaths, USER_PATHS_FILE, } from './user-paths.js';
|
|
26
|
+
export const VALIDATION_REPORT_FILE = join('agents', 'data', 'validation', 'latest.json');
|
|
27
|
+
export const USER_VALIDATION_RUNG_ID = 'user-validation';
|
|
28
|
+
/* ------------------------------------------------------------------ trust */
|
|
29
|
+
let trustedReportHash = null;
|
|
30
|
+
export function sha256Text(text) {
|
|
31
|
+
return createHash('sha256').update(text, 'utf8').digest('hex');
|
|
32
|
+
}
|
|
33
|
+
/** Hash of the report THIS process last wrote via the runner. A report on
|
|
34
|
+
* disk whose hash differs was not produced by the sanctioned runner this run
|
|
35
|
+
* and must not be trusted for the "ALL PASSED" judge note. */
|
|
36
|
+
export function getTrustedReportHash() {
|
|
37
|
+
return trustedReportHash;
|
|
38
|
+
}
|
|
39
|
+
/** Test seam. */
|
|
40
|
+
export function resetTrustedReportHash() {
|
|
41
|
+
trustedReportHash = null;
|
|
42
|
+
}
|
|
43
|
+
/* ------------------------------------------------------- mode resolution */
|
|
44
|
+
/**
|
|
45
|
+
* delivery.userValidation resolution — ON BY DEFAULT ('block').
|
|
46
|
+
* Precedence: explicit config value > env downgrade > default.
|
|
47
|
+
* UAP_USER_VALIDATION=0 downgrades block→advisory (never to off): the
|
|
48
|
+
* operator out-of-band switch is the config file, and the env var is on the
|
|
49
|
+
* self-protect blocklist so the model cannot persist it.
|
|
50
|
+
*/
|
|
51
|
+
export function resolveUserValidationMode(configValue, env = process.env) {
|
|
52
|
+
const cfg = typeof configValue === 'string' ? configValue.toLowerCase() : configValue;
|
|
53
|
+
let mode = cfg === 'off' || cfg === false ? 'off'
|
|
54
|
+
: cfg === 'advisory' ? 'advisory'
|
|
55
|
+
: 'block';
|
|
56
|
+
if (mode === 'block' && env.UAP_USER_VALIDATION === '0')
|
|
57
|
+
mode = 'advisory';
|
|
58
|
+
return mode;
|
|
59
|
+
}
|
|
60
|
+
async function loadBrowser() {
|
|
61
|
+
try {
|
|
62
|
+
const { WebBrowser } = await import('../browser/web-browser.js');
|
|
63
|
+
const b = new WebBrowser();
|
|
64
|
+
await b.launch({ headless: true });
|
|
65
|
+
return b;
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
function stepLabel(step) {
|
|
72
|
+
const [k] = Object.keys(step);
|
|
73
|
+
const v = step[k];
|
|
74
|
+
return `${k}:${typeof v === 'object' ? JSON.stringify(v) : String(v)}`.slice(0, 160);
|
|
75
|
+
}
|
|
76
|
+
async function runBrowserPath(path, browser, ctx) {
|
|
77
|
+
const steps = [];
|
|
78
|
+
const screenshots = [];
|
|
79
|
+
browser.clearErrors();
|
|
80
|
+
let failed = false;
|
|
81
|
+
for (const [i, step] of path.steps.entries()) {
|
|
82
|
+
if (failed)
|
|
83
|
+
break;
|
|
84
|
+
const label = stepLabel(step);
|
|
85
|
+
try {
|
|
86
|
+
if (step.goto !== undefined) {
|
|
87
|
+
const target = /^https?:/.test(step.goto) ? step.goto : `${ctx.baseUrl}${step.goto.startsWith('/') ? '' : '/'}${step.goto}`;
|
|
88
|
+
const status = await browser.goto(target);
|
|
89
|
+
const ok = status.startsWith('2') || status.startsWith('3');
|
|
90
|
+
steps.push({ step: label, ok, observed: `HTTP ${status}` });
|
|
91
|
+
failed = !ok;
|
|
92
|
+
}
|
|
93
|
+
else if (step.click !== undefined) {
|
|
94
|
+
await browser.click(step.click);
|
|
95
|
+
steps.push({ step: label, ok: true, observed: 'clicked' });
|
|
96
|
+
}
|
|
97
|
+
else if (step.fill !== undefined) {
|
|
98
|
+
await browser.fill(step.fill.selector, step.fill.value);
|
|
99
|
+
steps.push({ step: label, ok: true, observed: 'filled' });
|
|
100
|
+
}
|
|
101
|
+
else if (step.press !== undefined) {
|
|
102
|
+
await browser.press(step.press);
|
|
103
|
+
steps.push({ step: label, ok: true, observed: 'pressed' });
|
|
104
|
+
}
|
|
105
|
+
else if (step.wait_ms !== undefined) {
|
|
106
|
+
await new Promise((r) => setTimeout(r, Math.min(step.wait_ms ?? 0, 15_000)));
|
|
107
|
+
steps.push({ step: label, ok: true, observed: 'waited' });
|
|
108
|
+
}
|
|
109
|
+
else if (step.expect_visible !== undefined) {
|
|
110
|
+
const vis = await browser.isVisible(step.expect_visible);
|
|
111
|
+
steps.push({ step: label, ok: vis, observed: vis ? 'visible' : 'NOT visible' });
|
|
112
|
+
failed = !vis;
|
|
113
|
+
}
|
|
114
|
+
else if (step.expect_text !== undefined) {
|
|
115
|
+
const text = await browser.getText(step.expect_text.selector);
|
|
116
|
+
let ok = true;
|
|
117
|
+
if (step.expect_text.contains !== undefined)
|
|
118
|
+
ok = text.includes(step.expect_text.contains);
|
|
119
|
+
if (ok && step.expect_text.not_empty)
|
|
120
|
+
ok = text.trim().length > 0;
|
|
121
|
+
steps.push({ step: label, ok, observed: `text="${text.slice(0, 120)}"` });
|
|
122
|
+
failed = !ok;
|
|
123
|
+
}
|
|
124
|
+
else if (step.expect_no_console_errors !== undefined) {
|
|
125
|
+
const errs = browser.getErrors().filter((e) => e.kind === 'pageerror' || e.kind === 'console');
|
|
126
|
+
const ok = errs.length === 0;
|
|
127
|
+
steps.push({ step: label, ok, observed: ok ? 'no errors' : errs.map((e) => e.message).join(' | ').slice(0, 300) });
|
|
128
|
+
failed = !ok;
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
steps.push({ step: label, ok: false, observed: `step not valid for browser client` });
|
|
132
|
+
failed = true;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
catch (e) {
|
|
136
|
+
steps.push({ step: label, ok: false, observed: `error: ${e instanceof Error ? e.message : String(e)}`.slice(0, 300) });
|
|
137
|
+
failed = true;
|
|
138
|
+
}
|
|
139
|
+
// Screenshot after each interaction step (evidence trail), best-effort.
|
|
140
|
+
try {
|
|
141
|
+
const shot = join(ctx.shotsDir, `${path.id}-${i}.png`);
|
|
142
|
+
await browser.screenshot(shot);
|
|
143
|
+
screenshots.push(shot);
|
|
144
|
+
}
|
|
145
|
+
catch { /* headless screenshot unavailable — evidence degrades */ }
|
|
146
|
+
}
|
|
147
|
+
return { id: path.id, rule: path.rule, client: 'browser', status: failed ? 'fail' : 'pass', steps, screenshots };
|
|
148
|
+
}
|
|
149
|
+
async function runHttpPath(path, ctx) {
|
|
150
|
+
const steps = [];
|
|
151
|
+
let failed = false;
|
|
152
|
+
let lastStatus = 0;
|
|
153
|
+
let lastBody = '';
|
|
154
|
+
for (const step of path.steps) {
|
|
155
|
+
if (failed)
|
|
156
|
+
break;
|
|
157
|
+
const label = stepLabel(step);
|
|
158
|
+
try {
|
|
159
|
+
if (step.request !== undefined) {
|
|
160
|
+
const url = `${ctx.baseUrl}${step.request.path.startsWith('/') ? '' : '/'}${step.request.path}`;
|
|
161
|
+
const controller = new AbortController();
|
|
162
|
+
const timer = setTimeout(() => controller.abort(), ctx.timeoutMs);
|
|
163
|
+
try {
|
|
164
|
+
const res = await fetch(url, {
|
|
165
|
+
method: step.request.method,
|
|
166
|
+
headers: { ...(step.request.json !== undefined ? { 'content-type': 'application/json' } : {}), ...step.request.headers },
|
|
167
|
+
body: step.request.json !== undefined ? JSON.stringify(step.request.json) : undefined,
|
|
168
|
+
signal: controller.signal,
|
|
169
|
+
});
|
|
170
|
+
lastStatus = res.status;
|
|
171
|
+
lastBody = await res.text();
|
|
172
|
+
}
|
|
173
|
+
finally {
|
|
174
|
+
clearTimeout(timer);
|
|
175
|
+
}
|
|
176
|
+
steps.push({ step: label, ok: true, observed: `HTTP ${lastStatus} ${lastBody.slice(0, 160)}` });
|
|
177
|
+
}
|
|
178
|
+
else if (step.expect_status !== undefined) {
|
|
179
|
+
const ok = lastStatus === step.expect_status;
|
|
180
|
+
steps.push({ step: label, ok, observed: `HTTP ${lastStatus}` });
|
|
181
|
+
failed = !ok;
|
|
182
|
+
}
|
|
183
|
+
else if (step.expect_json_contains !== undefined) {
|
|
184
|
+
let ok = false;
|
|
185
|
+
let observed = lastBody.slice(0, 160);
|
|
186
|
+
try {
|
|
187
|
+
const body = JSON.parse(lastBody);
|
|
188
|
+
ok = jsonContains(body, step.expect_json_contains);
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
observed = `non-JSON body: ${observed}`;
|
|
192
|
+
}
|
|
193
|
+
steps.push({ step: label, ok, observed });
|
|
194
|
+
failed = !ok;
|
|
195
|
+
}
|
|
196
|
+
else if (step.expect_body_matches !== undefined) {
|
|
197
|
+
const ok = new RegExp(step.expect_body_matches).test(lastBody);
|
|
198
|
+
steps.push({ step: label, ok, observed: lastBody.slice(0, 160) });
|
|
199
|
+
failed = !ok;
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
steps.push({ step: label, ok: false, observed: 'step not valid for http client' });
|
|
203
|
+
failed = true;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
catch (e) {
|
|
207
|
+
steps.push({ step: label, ok: false, observed: `error: ${e instanceof Error ? e.message : String(e)}`.slice(0, 300) });
|
|
208
|
+
failed = true;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
return { id: path.id, rule: path.rule, client: 'http', status: failed ? 'fail' : 'pass', steps, screenshots: [] };
|
|
212
|
+
}
|
|
213
|
+
/** Deep subset match: every key/value in `expected` appears in `actual`
|
|
214
|
+
* (arrays: some element matches). */
|
|
215
|
+
export function jsonContains(actual, expected) {
|
|
216
|
+
if (expected === null || typeof expected !== 'object')
|
|
217
|
+
return actual === expected;
|
|
218
|
+
if (Array.isArray(expected)) {
|
|
219
|
+
return expected.every((e) => Array.isArray(actual) && actual.some((a) => jsonContains(a, e)));
|
|
220
|
+
}
|
|
221
|
+
if (Array.isArray(actual))
|
|
222
|
+
return actual.some((a) => jsonContains(a, expected));
|
|
223
|
+
if (typeof actual !== 'object' || actual === null)
|
|
224
|
+
return false;
|
|
225
|
+
return Object.entries(expected).every(([k, v]) => jsonContains(actual[k], v));
|
|
226
|
+
}
|
|
227
|
+
function runCliPath(path, ctx) {
|
|
228
|
+
const steps = [];
|
|
229
|
+
let failed = false;
|
|
230
|
+
let lastExit = null;
|
|
231
|
+
let lastStdout = '';
|
|
232
|
+
let lastStderr = '';
|
|
233
|
+
for (const step of path.steps) {
|
|
234
|
+
if (failed)
|
|
235
|
+
break;
|
|
236
|
+
const label = stepLabel(step);
|
|
237
|
+
try {
|
|
238
|
+
if (step.run !== undefined) {
|
|
239
|
+
const [cmd, ...rest] = step.run.argv;
|
|
240
|
+
const r = spawnSync(cmd, rest, {
|
|
241
|
+
cwd: ctx.projectRoot,
|
|
242
|
+
timeout: Math.min(step.run.timeoutMs ?? ctx.timeoutMs, 120_000),
|
|
243
|
+
input: step.run.stdin,
|
|
244
|
+
encoding: 'utf8',
|
|
245
|
+
shell: false,
|
|
246
|
+
});
|
|
247
|
+
lastExit = r.status;
|
|
248
|
+
lastStdout = r.stdout ?? '';
|
|
249
|
+
lastStderr = r.stderr ?? '';
|
|
250
|
+
steps.push({ step: label, ok: true, observed: `exit=${String(lastExit)} stdout=${lastStdout.slice(0, 120)}` });
|
|
251
|
+
}
|
|
252
|
+
else if (step.expect_exit !== undefined) {
|
|
253
|
+
const ok = lastExit === step.expect_exit;
|
|
254
|
+
steps.push({ step: label, ok, observed: `exit=${String(lastExit)}` });
|
|
255
|
+
failed = !ok;
|
|
256
|
+
}
|
|
257
|
+
else if (step.expect_stdout_matches !== undefined) {
|
|
258
|
+
const ok = new RegExp(step.expect_stdout_matches).test(lastStdout);
|
|
259
|
+
steps.push({ step: label, ok, observed: lastStdout.slice(0, 160) });
|
|
260
|
+
failed = !ok;
|
|
261
|
+
}
|
|
262
|
+
else if (step.expect_stderr_matches !== undefined) {
|
|
263
|
+
const ok = new RegExp(step.expect_stderr_matches).test(lastStderr);
|
|
264
|
+
steps.push({ step: label, ok, observed: lastStderr.slice(0, 160) });
|
|
265
|
+
failed = !ok;
|
|
266
|
+
}
|
|
267
|
+
else {
|
|
268
|
+
steps.push({ step: label, ok: false, observed: 'step not valid for cli client' });
|
|
269
|
+
failed = true;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
catch (e) {
|
|
273
|
+
steps.push({ step: label, ok: false, observed: `error: ${e instanceof Error ? e.message : String(e)}`.slice(0, 300) });
|
|
274
|
+
failed = true;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
return { id: path.id, rule: path.rule, client: 'cli', status: failed ? 'fail' : 'pass', steps, screenshots: [] };
|
|
278
|
+
}
|
|
279
|
+
async function startManifestServer(srv, projectRoot) {
|
|
280
|
+
const child = spawn(srv.command, srv.args ?? [], {
|
|
281
|
+
cwd: projectRoot,
|
|
282
|
+
env: { ...process.env, ...srv.env },
|
|
283
|
+
stdio: 'ignore',
|
|
284
|
+
detached: false,
|
|
285
|
+
});
|
|
286
|
+
const baseUrl = `http://127.0.0.1:${srv.port}`;
|
|
287
|
+
const deadline = Date.now() + (srv.readyTimeoutMs ?? 30_000);
|
|
288
|
+
const readyUrl = `${baseUrl}${srv.readyPath ?? '/'}`;
|
|
289
|
+
while (Date.now() < deadline) {
|
|
290
|
+
if (child.exitCode !== null)
|
|
291
|
+
return null; // died during bring-up
|
|
292
|
+
try {
|
|
293
|
+
await fetch(readyUrl, { signal: AbortSignal.timeout(1_000) });
|
|
294
|
+
return { baseUrl, close: () => { try {
|
|
295
|
+
child.kill();
|
|
296
|
+
}
|
|
297
|
+
catch { /* already gone */ } } };
|
|
298
|
+
}
|
|
299
|
+
catch {
|
|
300
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
try {
|
|
304
|
+
child.kill();
|
|
305
|
+
}
|
|
306
|
+
catch { /* already gone */ }
|
|
307
|
+
return null;
|
|
308
|
+
}
|
|
309
|
+
export async function runUserValidation(projectRoot, opts = {}) {
|
|
310
|
+
const startedAt = new Date().toISOString();
|
|
311
|
+
const timeoutMs = opts.timeoutMs ?? 20_000;
|
|
312
|
+
const loaded = loadUserPaths(projectRoot);
|
|
313
|
+
const finish = (report) => {
|
|
314
|
+
const full = { ...report, startedAt, finishedAt: new Date().toISOString() };
|
|
315
|
+
try {
|
|
316
|
+
const file = join(projectRoot, VALIDATION_REPORT_FILE);
|
|
317
|
+
mkdirSync(join(projectRoot, 'agents', 'data', 'validation'), { recursive: true });
|
|
318
|
+
const text = JSON.stringify(full, null, 2) + '\n';
|
|
319
|
+
writeFileSync(file, text, 'utf8');
|
|
320
|
+
trustedReportHash = sha256Text(text);
|
|
321
|
+
}
|
|
322
|
+
catch {
|
|
323
|
+
trustedReportHash = null; // report unwritable — note stays untrusted
|
|
324
|
+
}
|
|
325
|
+
return full;
|
|
326
|
+
};
|
|
327
|
+
if (!loaded) {
|
|
328
|
+
return finish({
|
|
329
|
+
version: 1, manifestHash: null, results: [], verdict: 'na',
|
|
330
|
+
naReason: `no ${USER_PATHS_FILE} manifest`, browserAvailable: false,
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
if (!loaded.ok || !loaded.manifest) {
|
|
334
|
+
return finish({
|
|
335
|
+
version: 1, manifestHash: null,
|
|
336
|
+
results: [{
|
|
337
|
+
id: 'manifest', rule: 'manifest must be valid', client: 'cli', status: 'fail',
|
|
338
|
+
steps: loaded.errors.map((e) => ({ step: 'validate', ok: false, observed: e })), screenshots: [],
|
|
339
|
+
}],
|
|
340
|
+
verdict: 'fail', browserAvailable: false,
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
const manifest = loaded.manifest;
|
|
344
|
+
const manifestHash = sha256Text(JSON.stringify(manifest));
|
|
345
|
+
if (manifest.paths.length === 0) {
|
|
346
|
+
return finish({
|
|
347
|
+
version: 1, manifestHash, results: [], verdict: 'na',
|
|
348
|
+
naReason: 'manifest has no paths', browserAvailable: false,
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
const shotsDir = join(projectRoot, 'agents', 'data', 'validation', 'shots');
|
|
352
|
+
mkdirSync(shotsDir, { recursive: true });
|
|
353
|
+
const needsBrowser = manifest.paths.some((p) => p.client === 'browser');
|
|
354
|
+
const needsServer = manifest.paths.some((p) => p.client === 'http') || manifest.server !== undefined;
|
|
355
|
+
let managed = null;
|
|
356
|
+
let staticServer = null;
|
|
357
|
+
let browser = null;
|
|
358
|
+
const results = [];
|
|
359
|
+
try {
|
|
360
|
+
if (needsServer && manifest.server) {
|
|
361
|
+
managed = await startManifestServer(manifest.server, projectRoot);
|
|
362
|
+
}
|
|
363
|
+
if (needsBrowser) {
|
|
364
|
+
browser = await (opts.browserLoader ?? loadBrowser)();
|
|
365
|
+
if (!managed && !staticServer) {
|
|
366
|
+
try {
|
|
367
|
+
staticServer = await startStaticServer(projectRoot);
|
|
368
|
+
}
|
|
369
|
+
catch {
|
|
370
|
+
staticServer = null;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
for (const path of manifest.paths) {
|
|
375
|
+
if (path.client === 'browser') {
|
|
376
|
+
if (!browser) {
|
|
377
|
+
results.push({
|
|
378
|
+
id: path.id, rule: path.rule, client: 'browser', status: 'skipped',
|
|
379
|
+
steps: [{ step: 'launch-browser', ok: false, observed: 'headless browser unavailable in this environment' }],
|
|
380
|
+
screenshots: [],
|
|
381
|
+
});
|
|
382
|
+
continue;
|
|
383
|
+
}
|
|
384
|
+
const base = managed?.baseUrl ?? staticServer?.url ?? null;
|
|
385
|
+
results.push(await runBrowserPath(path, browser, { projectRoot, baseUrl: base, shotsDir, timeoutMs }));
|
|
386
|
+
}
|
|
387
|
+
else if (path.client === 'http') {
|
|
388
|
+
if (!managed) {
|
|
389
|
+
results.push({
|
|
390
|
+
id: path.id, rule: path.rule, client: 'http', status: 'fail',
|
|
391
|
+
steps: [{ step: 'server', ok: false, observed: manifest.server ? 'server failed to become ready' : `http paths need a "server" entry in ${USER_PATHS_FILE}` }],
|
|
392
|
+
screenshots: [],
|
|
393
|
+
});
|
|
394
|
+
continue;
|
|
395
|
+
}
|
|
396
|
+
results.push(await runHttpPath(path, { projectRoot, baseUrl: managed.baseUrl, shotsDir, timeoutMs }));
|
|
397
|
+
}
|
|
398
|
+
else {
|
|
399
|
+
results.push(runCliPath(path, { projectRoot, baseUrl: null, shotsDir, timeoutMs }));
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
finally {
|
|
404
|
+
try {
|
|
405
|
+
await browser?.close();
|
|
406
|
+
}
|
|
407
|
+
catch { /* already closed */ }
|
|
408
|
+
managed?.close();
|
|
409
|
+
staticServer?.close();
|
|
410
|
+
}
|
|
411
|
+
const anyFail = results.some((r) => r.status === 'fail');
|
|
412
|
+
const allSkipped = results.length > 0 && results.every((r) => r.status === 'skipped');
|
|
413
|
+
return finish({
|
|
414
|
+
version: 1, manifestHash, results,
|
|
415
|
+
verdict: anyFail ? 'fail' : allSkipped ? 'na' : 'pass',
|
|
416
|
+
naReason: allSkipped ? 'all paths skipped (browser unavailable)' : undefined,
|
|
417
|
+
browserAvailable: browser !== null,
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
/* --------------------------------------------------------- ladder wiring */
|
|
421
|
+
/** Synthesize the terminal user-validation rung. `required` mirrors the
|
|
422
|
+
* resolved mode: block ⇒ required, advisory ⇒ optional. */
|
|
423
|
+
export function synthesizeUserValidationRung(mode) {
|
|
424
|
+
if (mode === 'off')
|
|
425
|
+
return null;
|
|
426
|
+
return {
|
|
427
|
+
id: USER_VALIDATION_RUNG_ID,
|
|
428
|
+
name: `User-path validation (real client${mode === 'advisory' ? ', advisory' : ''})`,
|
|
429
|
+
command: 'user-validation', // executed in-process by the injected runner
|
|
430
|
+
args: [],
|
|
431
|
+
required: mode === 'block',
|
|
432
|
+
timeoutMs: 300_000,
|
|
433
|
+
tier: 'final',
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
/**
|
|
437
|
+
* LadderRunFn for the 'final' tier: runs the validation in-process (never
|
|
438
|
+
* spawning model-writable code) and maps the report onto rung results.
|
|
439
|
+
* Skipped-not-failed when every path was environment-skipped, mirroring the
|
|
440
|
+
* deploy-dev docker-unavailable behavior.
|
|
441
|
+
*/
|
|
442
|
+
export function createUserValidationRunner(runOpts = {}) {
|
|
443
|
+
return async (rungs, projectRoot) => {
|
|
444
|
+
const rung = rungs.find((r) => r.id === USER_VALIDATION_RUNG_ID) ?? rungs[0];
|
|
445
|
+
const started = Date.now();
|
|
446
|
+
const report = await runUserValidation(projectRoot, runOpts);
|
|
447
|
+
const failedPaths = report.results.filter((r) => r.status === 'fail');
|
|
448
|
+
const passed = report.verdict === 'pass' || report.verdict === 'na';
|
|
449
|
+
const skipped = report.verdict === 'na';
|
|
450
|
+
const detail = report.results
|
|
451
|
+
.map((r) => `${r.status.toUpperCase()} ${r.id}: ${r.rule}${r.status === 'fail' ? ` — ${r.steps.find((s) => !s.ok)?.step ?? ''} → ${r.steps.find((s) => !s.ok)?.observed ?? ''}` : ''}`)
|
|
452
|
+
.join('\n');
|
|
453
|
+
const result = {
|
|
454
|
+
id: rung.id,
|
|
455
|
+
name: rung.name,
|
|
456
|
+
// NA counts as passed (skipped-not-failed, the deploy-dev precedent):
|
|
457
|
+
// a required rung with no applicable paths must not fail the aggregate.
|
|
458
|
+
passed,
|
|
459
|
+
skipped,
|
|
460
|
+
exitCode: passed ? 0 : 1,
|
|
461
|
+
durationMs: Date.now() - started,
|
|
462
|
+
outputTail: (report.verdict === 'na' ? `NA: ${report.naReason ?? ''}\n` : '') +
|
|
463
|
+
detail +
|
|
464
|
+
(passed
|
|
465
|
+
? ''
|
|
466
|
+
: `\nThe artifact does not work for a real user on these journeys. Fix the artifact so they pass; the manifest is ${USER_PATHS_FILE}.`),
|
|
467
|
+
};
|
|
468
|
+
return {
|
|
469
|
+
passed: passed || !rung.required,
|
|
470
|
+
score: passed ? 1 : Math.max(0, 1 - failedPaths.length / Math.max(1, report.results.length)),
|
|
471
|
+
results: [result],
|
|
472
|
+
feedback: passed
|
|
473
|
+
? ''
|
|
474
|
+
: `User-path validation FAILED — the artifact does not work for a real user:\n${detail}\nFix the artifact so these journeys pass; the manifest is ${USER_PATHS_FILE}.`,
|
|
475
|
+
};
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
/**
|
|
479
|
+
* Build the acceptance-judge runtime note from the on-disk report, refusing
|
|
480
|
+
* to vouch for a report the in-process runner did not write (hash mismatch ⇒
|
|
481
|
+
* fabricated/stale ⇒ say so to the judge instead of staying silent).
|
|
482
|
+
*/
|
|
483
|
+
export function buildUserPathsNote(projectRoot) {
|
|
484
|
+
const file = join(projectRoot, VALIDATION_REPORT_FILE);
|
|
485
|
+
if (!existsSync(file))
|
|
486
|
+
return null;
|
|
487
|
+
let text;
|
|
488
|
+
try {
|
|
489
|
+
text = readFileSync(file, 'utf8');
|
|
490
|
+
}
|
|
491
|
+
catch {
|
|
492
|
+
return null;
|
|
493
|
+
}
|
|
494
|
+
const trusted = trustedReportHash !== null && sha256Text(text) === trustedReportHash;
|
|
495
|
+
if (!trusted) {
|
|
496
|
+
return {
|
|
497
|
+
note: 'A user-validation report exists but was NOT produced by the sanctioned runner this run — treat it as unverified.',
|
|
498
|
+
trusted: false,
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
try {
|
|
502
|
+
const report = JSON.parse(text);
|
|
503
|
+
if (report.verdict === 'pass') {
|
|
504
|
+
return { note: `User-path validation ALL PASSED (${report.results.length} real-client journeys) — treat user-facing requirements covered by these paths as objectively verified.`, trusted: true };
|
|
505
|
+
}
|
|
506
|
+
if (report.verdict === 'fail') {
|
|
507
|
+
const failed = report.results.filter((r) => r.status === 'fail').map((r) => `${r.id} (${r.rule})`).join('; ');
|
|
508
|
+
return { note: `User-path validation FAILED: ${failed} — the artifact does not work for a real user on these journeys.`, trusted: true };
|
|
509
|
+
}
|
|
510
|
+
return { note: `User-path validation: not applicable (${report.naReason ?? 'no user-facing surface'}).`, trusted: true };
|
|
511
|
+
}
|
|
512
|
+
catch {
|
|
513
|
+
return null;
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
//# sourceMappingURL=user-validation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"user-validation.js","sourceRoot":"","sources":["../../src/delivery/user-validation.ts"],"names":[],"mappings":"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"}
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
* `ci`/`deploy-staging`/`deploy-prod` bands are NEVER run locally — they are
|
|
18
18
|
* consumed after commit via the CI watcher (see ci-watcher.ts).
|
|
19
19
|
*/
|
|
20
|
-
export type GateTier = 'fast' | 'runtime' | 'integration' | 'deploy-dev' | 'ci' | 'deploy-staging' | 'deploy-prod';
|
|
20
|
+
export type GateTier = 'fast' | 'runtime' | 'integration' | 'deploy-dev' | 'final' | 'ci' | 'deploy-staging' | 'deploy-prod';
|
|
21
21
|
/** Cheap → expensive promotion order. */
|
|
22
22
|
export declare const TIER_ORDER: GateTier[];
|
|
23
23
|
export interface GateRung {
|
|
@@ -211,6 +211,12 @@ export interface TieredLadderOptions extends LadderOptions {
|
|
|
211
211
|
* which simply spawns the smoke command without managing a compose stack.
|
|
212
212
|
*/
|
|
213
213
|
deployDevRunner?: LadderRunFn;
|
|
214
|
+
/**
|
|
215
|
+
* Specialized runner for the terminal `final` tier (user-path validation
|
|
216
|
+
* against the real client). When absent, `final` rungs fall back to
|
|
217
|
+
* {@link runner}, which would spawn their command verbatim.
|
|
218
|
+
*/
|
|
219
|
+
userValidationRunner?: LadderRunFn;
|
|
214
220
|
}
|
|
215
221
|
/**
|
|
216
222
|
* Cheap-first tiered ladder. Runs the cheapest tier first and only promotes to
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"verifier-ladder.d.ts","sourceRoot":"","sources":["../../src/delivery/verifier-ladder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAOH;;;;;;GAMG;AACH,MAAM,MAAM,QAAQ,GAChB,MAAM,GACN,SAAS,GACT,aAAa,GACb,YAAY,GACZ,IAAI,GACJ,gBAAgB,GAChB,aAAa,CAAC;AAElB,yCAAyC;AACzC,eAAO,MAAM,UAAU,EAAE,QAAQ,
|
|
1
|
+
{"version":3,"file":"verifier-ladder.d.ts","sourceRoot":"","sources":["../../src/delivery/verifier-ladder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAOH;;;;;;GAMG;AACH,MAAM,MAAM,QAAQ,GAChB,MAAM,GACN,SAAS,GACT,aAAa,GACb,YAAY,GACZ,OAAO,GACP,IAAI,GACJ,gBAAgB,GAChB,aAAa,CAAC;AAElB,yCAAyC;AACzC,eAAO,MAAM,UAAU,EAAE,QAAQ,EAShC,CAAC;AAEF,MAAM,WAAW,QAAQ;IACvB,mEAAmE;IACnE,EAAE,EAAE,MAAM,CAAC;IACX,4CAA4C;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,iDAAiD;IACjD,OAAO,EAAE,MAAM,CAAC;IAChB,gCAAgC;IAChC,IAAI,EAAE,MAAM,EAAE,CAAC;IACf;;;;OAIG;IACH,QAAQ,EAAE,OAAO,CAAC;IAClB,uCAAuC;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB;;;;OAIG;IACH,QAAQ,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,EAAE,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAClE;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED,8EAA8E;AAC9E,wBAAgB,MAAM,CAAC,IAAI,EAAE,QAAQ,GAAG,QAAQ,CAE/C;AAED,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,SAAS,GAAG,QAAQ,GAAG,aAAa,CAAC;AAE9E,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,2EAA2E;IAC3E,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,mEAAmE;IACnE,aAAa,CAAC,EAAE,iBAAiB,CAAC;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,qEAAqE;IACrE,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,2CAA2C;IAC3C,MAAM,EAAE,OAAO,CAAC;IAChB,4EAA4E;IAC5E,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,sDAAsD;IACtD,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,gFAAgF;IAChF,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,gFAAgF;IAChF,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAGD,eAAO,MAAM,kBAAkB,OAAQ,CAAC;AAMxC,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGlD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,GAAE,MAA2B,GAAG,QAAQ,EAAE,CAsGnG;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC/B,SAAS,GAAE,MAA2B,GACrC,QAAQ,EAAE,CAoDZ;AAgCD;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC/B,SAAS,GAAE,MAA2B,GACrC,QAAQ,GAAG,IAAI,CAkDjB;AAED,4EAA4E;AAC5E,eAAO,MAAM,sBAAsB,2DAAsD,CAAC;AAE1F,MAAM,WAAW,mBAAmB;IAClC,0EAA0E;IAC1E,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,uEAAuE;IACvE,OAAO,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACjE,wCAAwC;IACxC,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,QAAQ,EAAE,EACjB,WAAW,EAAE,MAAM,EACnB,SAAS,GAAE,MAA2B,GACrC,mBAAmB,CAYrB;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,GAAE,MAA2B,GAAG,QAAQ,EAAE,CA0CxG;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CA+BxE;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,GAAE,MAA2B,GAAG,QAAQ,EAAE,CA8DzG;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAInE;AAED,2DAA2D;AAC3D,wBAAgB,OAAO,CAAC,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,GAAE,MAA2B,GAAG,UAAU,CAiD/G;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,UAAU,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,MAAM,CAoC/E;AAED,kEAAkE;AAClE,wBAAgB,SAAS,CACvB,KAAK,EAAE,QAAQ,EAAE,EACjB,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,aAAkB,GAC1B,YAAY,CA8Cd;AAED,yEAAyE;AACzE,MAAM,MAAM,WAAW,GAAG,CACxB,KAAK,EAAE,QAAQ,EAAE,EACjB,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE,aAAa,KACpB,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;AAE1C,MAAM,WAAW,mBAAoB,SAAQ,aAAa;IACxD;;;;OAIG;IACH,OAAO,CAAC,EAAE,QAAQ,CAAC;IACnB;;;;OAIG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB;;;;OAIG;IACH,eAAe,CAAC,EAAE,WAAW,CAAC;IAC9B;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,WAAW,CAAC;CACpC;AAYD;;;;;;GAMG;AACH,wBAAsB,eAAe,CACnC,KAAK,EAAE,QAAQ,EAAE,EACjB,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,YAAY,CAAC,CA6EvB"}
|
|
@@ -20,6 +20,7 @@ export const TIER_ORDER = [
|
|
|
20
20
|
'runtime',
|
|
21
21
|
'integration',
|
|
22
22
|
'deploy-dev',
|
|
23
|
+
'final',
|
|
23
24
|
'ci',
|
|
24
25
|
'deploy-staging',
|
|
25
26
|
'deploy-prod',
|
|
@@ -657,7 +658,11 @@ export async function runTieredLadder(rungs, projectRoot, options = {}) {
|
|
|
657
658
|
const tierRungs = byTier.get(tier);
|
|
658
659
|
if (!tierRungs || tierRungs.length === 0)
|
|
659
660
|
continue;
|
|
660
|
-
|
|
661
|
+
// 'final' is an epilogue tier: always in scope when its rung was
|
|
662
|
+
// synthesized (config-gated upstream), regardless of the cost ceiling —
|
|
663
|
+
// it must not drag integration/deploy-dev into scope, and promotion
|
|
664
|
+
// still guarantees it only runs when every cheaper in-scope tier passed.
|
|
665
|
+
const eligible = tier === 'final' || TIER_ORDER.indexOf(tier) <= maxIdx;
|
|
661
666
|
if (!eligible) {
|
|
662
667
|
// Above maxTier — verified remotely, never run locally.
|
|
663
668
|
for (const rung of tierRungs)
|
|
@@ -671,7 +676,9 @@ export async function runTieredLadder(rungs, projectRoot, options = {}) {
|
|
|
671
676
|
results.push(skippedRung(rung));
|
|
672
677
|
continue;
|
|
673
678
|
}
|
|
674
|
-
const useRunner = tier === 'deploy-dev' && options.deployDevRunner ? options.deployDevRunner
|
|
679
|
+
const useRunner = tier === 'deploy-dev' && options.deployDevRunner ? options.deployDevRunner
|
|
680
|
+
: tier === 'final' && options.userValidationRunner ? options.userValidationRunner
|
|
681
|
+
: runner;
|
|
675
682
|
const tierResult = await useRunner(tierRungs, projectRoot, innerOptions);
|
|
676
683
|
results.push(...tierResult.results);
|
|
677
684
|
if (!tierResult.passed)
|