@miller-tech/uap 1.170.1 → 1.172.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 +26 -0
- package/dist/bin/cli.js.map +1 -1
- package/dist/browser/web-browser.d.ts +17 -0
- package/dist/browser/web-browser.d.ts.map +1 -1
- package/dist/browser/web-browser.js +36 -0
- package/dist/browser/web-browser.js.map +1 -1
- package/dist/cli/interaction.d.ts +29 -0
- package/dist/cli/interaction.d.ts.map +1 -0
- package/dist/cli/interaction.js +217 -0
- package/dist/cli/interaction.js.map +1 -0
- package/dist/cli/verify.d.ts +6 -0
- package/dist/cli/verify.d.ts.map +1 -1
- package/dist/cli/verify.js +112 -7
- package/dist/cli/verify.js.map +1 -1
- package/dist/delivery/fidelity.d.ts +16 -0
- package/dist/delivery/fidelity.d.ts.map +1 -1
- package/dist/delivery/fidelity.js +7 -0
- package/dist/delivery/fidelity.js.map +1 -1
- package/dist/delivery/interaction/driver.d.ts +60 -0
- package/dist/delivery/interaction/driver.d.ts.map +1 -0
- package/dist/delivery/interaction/driver.js +18 -0
- package/dist/delivery/interaction/driver.js.map +1 -0
- package/dist/delivery/interaction/manifest.d.ts +84 -0
- package/dist/delivery/interaction/manifest.d.ts.map +1 -0
- package/dist/delivery/interaction/manifest.js +241 -0
- package/dist/delivery/interaction/manifest.js.map +1 -0
- package/dist/delivery/interaction/mine.d.ts +54 -0
- package/dist/delivery/interaction/mine.d.ts.map +1 -0
- package/dist/delivery/interaction/mine.js +218 -0
- package/dist/delivery/interaction/mine.js.map +1 -0
- package/dist/delivery/interaction/runner.d.ts +51 -0
- package/dist/delivery/interaction/runner.d.ts.map +1 -0
- package/dist/delivery/interaction/runner.js +277 -0
- package/dist/delivery/interaction/runner.js.map +1 -0
- package/dist/delivery/interaction/types.d.ts +223 -0
- package/dist/delivery/interaction/types.d.ts.map +1 -0
- package/dist/delivery/interaction/types.js +19 -0
- package/dist/delivery/interaction/types.js.map +1 -0
- package/dist/delivery/interaction/verdict.d.ts +26 -0
- package/dist/delivery/interaction/verdict.d.ts.map +1 -0
- package/dist/delivery/interaction/verdict.js +139 -0
- package/dist/delivery/interaction/verdict.js.map +1 -0
- package/dist/delivery/interaction/watchdog.d.ts +82 -0
- package/dist/delivery/interaction/watchdog.d.ts.map +1 -0
- package/dist/delivery/interaction/watchdog.js +210 -0
- package/dist/delivery/interaction/watchdog.js.map +1 -0
- package/dist/delivery/interaction/web-driver.d.ts +102 -0
- package/dist/delivery/interaction/web-driver.d.ts.map +1 -0
- package/dist/delivery/interaction/web-driver.js +306 -0
- package/dist/delivery/interaction/web-driver.js.map +1 -0
- package/dist/delivery/interaction-gate.d.ts +45 -0
- package/dist/delivery/interaction-gate.d.ts.map +1 -0
- package/dist/delivery/interaction-gate.js +248 -0
- package/dist/delivery/interaction-gate.js.map +1 -0
- package/dist/delivery/mission-acceptance.d.ts +2 -0
- package/dist/delivery/mission-acceptance.d.ts.map +1 -1
- package/dist/delivery/mission-acceptance.js +23 -0
- package/dist/delivery/mission-acceptance.js.map +1 -1
- package/dist/delivery/vision-judge.d.ts +21 -0
- package/dist/delivery/vision-judge.d.ts.map +1 -1
- package/dist/delivery/vision-judge.js +96 -0
- package/dist/delivery/vision-judge.js.map +1 -1
- package/dist/types/config.d.ts +20 -0
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/config.js +7 -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/templates/hooks/__pycache__/deliver_autoroute.cpython-312.pyc +0 -0
- package/tools/agents/scripts/__pycache__/toolcall_path_normalizer.cpython-312.pyc +0 -0
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interaction watchdog — invariants that hold for EVERY probe, checked
|
|
3
|
+
* independently of what any individual probe asserts.
|
|
4
|
+
*
|
|
5
|
+
* Probes prove the promised behaviour. The watchdog catches the failures nobody
|
|
6
|
+
* thought to write a probe for: the loop stops ticking, an uncaught error fires,
|
|
7
|
+
* a tracked number goes NaN, a collection grows without bound. Tonight's fatal
|
|
8
|
+
* defect (`player.takeDamage is not a function`) is exactly the first class —
|
|
9
|
+
* one uncaught throw, the rAF loop never rescheduled, and every later frame was
|
|
10
|
+
* a frozen copy of the last good one, which no screenshot can distinguish from a
|
|
11
|
+
* paused game.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Injected before any page script runs. Wraps requestAnimationFrame to count
|
|
15
|
+
* ticks and records uncaught errors. Deliberately defensive: a page that
|
|
16
|
+
* replaces rAF or throws during setup must not break the watchdog itself.
|
|
17
|
+
*
|
|
18
|
+
* SELF-INVOKED — `addInitScript` evaluates the string as source, so a bare
|
|
19
|
+
* function expression would construct a function and discard it. That mistake
|
|
20
|
+
* is invisible at runtime: the counters simply never appear, every sample falls
|
|
21
|
+
* back to `ticks: 0`, `everTicked` stays false and `loopAlive` is unconditionally
|
|
22
|
+
* true — the frozen-loop detection this gate exists for silently never fires.
|
|
23
|
+
* Matches RAF_INSTRUMENT in execution-gate.ts, which is self-invoked for the
|
|
24
|
+
* same reason.
|
|
25
|
+
*/
|
|
26
|
+
export const DEFAULT_WATCH_GLOBAL = '__uapWatch';
|
|
27
|
+
/**
|
|
28
|
+
* Build the init script under a caller-chosen global name.
|
|
29
|
+
*
|
|
30
|
+
* The name is randomised per run because the page can otherwise DEFEAT its own
|
|
31
|
+
* watchdog: `window.__uapWatch = {ticks: 1e9, errors: []}` forges liveness and
|
|
32
|
+
* empties the error list, and the `if (already defined) return` guard means a
|
|
33
|
+
* page that predefines the global blocks instrumentation outright. Randomising
|
|
34
|
+
* is not a security boundary — it raises the cost of a targeted forge, while
|
|
35
|
+
* the authoritative error channel remains Playwright-side, out of page reach.
|
|
36
|
+
*/
|
|
37
|
+
export function buildWatchdogInitScript(globalName = DEFAULT_WATCH_GLOBAL) {
|
|
38
|
+
return WATCHDOG_INIT_SCRIPT.split(DEFAULT_WATCH_GLOBAL).join(globalName);
|
|
39
|
+
}
|
|
40
|
+
export const WATCHDOG_INIT_SCRIPT = `(function () {
|
|
41
|
+
try {
|
|
42
|
+
if (window.__uapWatch) return;
|
|
43
|
+
var w = { ticks: 0, errors: [], startedAt: Date.now() };
|
|
44
|
+
window.__uapWatch = w;
|
|
45
|
+
var raf = window.requestAnimationFrame;
|
|
46
|
+
if (typeof raf === 'function') {
|
|
47
|
+
window.requestAnimationFrame = function (cb) {
|
|
48
|
+
return raf.call(window, function (t) {
|
|
49
|
+
w.ticks++;
|
|
50
|
+
return cb(t);
|
|
51
|
+
});
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
window.addEventListener('error', function (e) {
|
|
55
|
+
try { w.errors.push('uncaught: ' + (e && e.message ? e.message : String(e))); } catch (x) {}
|
|
56
|
+
});
|
|
57
|
+
window.addEventListener('unhandledrejection', function (e) {
|
|
58
|
+
try { w.errors.push('unhandledrejection: ' + String(e && e.reason)); } catch (x) {}
|
|
59
|
+
});
|
|
60
|
+
} catch (x) {
|
|
61
|
+
/* the watchdog must never break the page it observes */
|
|
62
|
+
}
|
|
63
|
+
})()`;
|
|
64
|
+
/**
|
|
65
|
+
* Read one watchdog sample. `watchExprs` are artifact expressions yielding
|
|
66
|
+
* numbers (collection sizes, key state fields) — the miner supplies them, and
|
|
67
|
+
* each one that goes NaN or grows without bound becomes a defect.
|
|
68
|
+
*/
|
|
69
|
+
/**
|
|
70
|
+
* NaN cannot survive the JSON transport — `JSON.stringify(NaN)` is `null`, so a
|
|
71
|
+
* corrupted field arrives indistinguishable from "not present" and the NaN check
|
|
72
|
+
* can never fire in production. Encode it explicitly and decode on the way back.
|
|
73
|
+
*/
|
|
74
|
+
export const NAN_SENTINEL = '__uap_NaN__';
|
|
75
|
+
export function watchdogSampleScript(watchExprs, globalName = DEFAULT_WATCH_GLOBAL) {
|
|
76
|
+
const entries = watchExprs
|
|
77
|
+
.map((e) => {
|
|
78
|
+
const key = JSON.stringify(e);
|
|
79
|
+
return ` try { var v = (${e}); vals[${key}] = (typeof v === 'number' && v !== v) ? ${JSON.stringify(NAN_SENTINEL)} : v; } catch (x) { vals[${key}] = null; }`;
|
|
80
|
+
})
|
|
81
|
+
.join('\n');
|
|
82
|
+
return `(function () {
|
|
83
|
+
var w = window[${JSON.stringify(globalName)}] || { ticks: 0, errors: [] };
|
|
84
|
+
var vals = {};
|
|
85
|
+
${entries}
|
|
86
|
+
return JSON.stringify({ ticks: w.ticks, errors: w.errors.slice(0, 20), values: vals });
|
|
87
|
+
})`;
|
|
88
|
+
}
|
|
89
|
+
export function parseWatchdogSample(raw) {
|
|
90
|
+
try {
|
|
91
|
+
const text = typeof raw === 'string' ? raw : JSON.stringify(raw);
|
|
92
|
+
const parsed = JSON.parse(text);
|
|
93
|
+
if (!parsed || typeof parsed !== 'object')
|
|
94
|
+
return null;
|
|
95
|
+
const values = {};
|
|
96
|
+
for (const [k, v] of Object.entries(parsed.values ?? {})) {
|
|
97
|
+
values[k] = v === NAN_SENTINEL ? Number.NaN : v;
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
ticks: Number(parsed.ticks) || 0,
|
|
101
|
+
errors: Array.isArray(parsed.errors) ? parsed.errors.map(String) : [],
|
|
102
|
+
values,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
/** Does this expression observe the SIZE of a collection (vs a counter)? */
|
|
110
|
+
export function isCollectionSize(expr) {
|
|
111
|
+
return /\.(length|size)\s*$/.test(expr) || /\.(length|size)\b/.test(expr);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Pure verdict from the observed samples. Kept free of IO so the interesting
|
|
115
|
+
* judgements are unit-testable without a browser.
|
|
116
|
+
*/
|
|
117
|
+
export function judgeWatchdog(samples, driverErrors = [], opts = {}) {
|
|
118
|
+
const minTicks = opts.minTicks ?? 1;
|
|
119
|
+
const growthFactor = opts.growthFactor ?? 20;
|
|
120
|
+
const growthFloor = opts.growthFloor ?? 500;
|
|
121
|
+
const errors = [...new Set([...samples.flatMap((s) => s.errors), ...driverErrors])];
|
|
122
|
+
const first = samples[0];
|
|
123
|
+
const last = samples[samples.length - 1];
|
|
124
|
+
const prev = samples.length >= 2 ? samples[samples.length - 2] : first;
|
|
125
|
+
// Ticks in the FINAL window: a loop that ran for two seconds and then died
|
|
126
|
+
// still has a large cumulative count, so only the last interval is evidence
|
|
127
|
+
// that it is alive NOW.
|
|
128
|
+
const ticksObserved = last && prev ? Math.max(0, last.ticks - prev.ticks) : 0;
|
|
129
|
+
// A page with no rAF at all (a form, a static doc) legitimately never ticks.
|
|
130
|
+
// Only claim the loop is dead when it demonstrably ticked earlier.
|
|
131
|
+
const everTicked = (last?.ticks ?? 0) > 0;
|
|
132
|
+
// TWO samples minimum. With one, `prev === last`, the delta is 0 by
|
|
133
|
+
// construction, and any artifact that ever ticked is declared dead — so a
|
|
134
|
+
// single dropped watchdog read would fail a perfectly healthy build. Liveness
|
|
135
|
+
// is a claim about change over time and needs two points to make.
|
|
136
|
+
const loopAlive = samples.length < 2 || !everTicked || ticksObserved >= minTicks;
|
|
137
|
+
// NaN over EVERY sample, not just the last. Judging only the final sample
|
|
138
|
+
// meant a field corrupted during any earlier probe was wiped by the next
|
|
139
|
+
// page reload and never seen — the check silently became "did the LAST probe
|
|
140
|
+
// produce NaN".
|
|
141
|
+
const nanSet = new Set();
|
|
142
|
+
for (const s of samples) {
|
|
143
|
+
for (const [key, v] of Object.entries(s.values)) {
|
|
144
|
+
if (typeof v === 'number' && Number.isNaN(v))
|
|
145
|
+
nanSet.add(key);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
const nanFields = [...nanSet];
|
|
149
|
+
// Growth compared only WITHIN a contiguous segment: across a reload the
|
|
150
|
+
// start and end points belong to different runs of the artifact, so the
|
|
151
|
+
// comparison is meaningless (and a real leak measured over one short probe
|
|
152
|
+
// never crosses the floor).
|
|
153
|
+
const growth = new Map();
|
|
154
|
+
const bySegment = new Map();
|
|
155
|
+
for (const s of samples) {
|
|
156
|
+
const seg = s.segment ?? 0;
|
|
157
|
+
if (!bySegment.has(seg))
|
|
158
|
+
bySegment.set(seg, []);
|
|
159
|
+
bySegment.get(seg).push(s);
|
|
160
|
+
}
|
|
161
|
+
for (const group of bySegment.values()) {
|
|
162
|
+
const a = group[0];
|
|
163
|
+
const b = group[group.length - 1];
|
|
164
|
+
if (!a || !b || a === b)
|
|
165
|
+
continue;
|
|
166
|
+
for (const key of Object.keys(b.values)) {
|
|
167
|
+
// Growth means "a COLLECTION grew without bound". An ordinary counter —
|
|
168
|
+
// a score, a frame number, elapsed time — is supposed to climb, and
|
|
169
|
+
// flagging it reports a leak in a working game (observed: score 0 →
|
|
170
|
+
// 38 060 reported as unbounded growth). Only size-like observations
|
|
171
|
+
// qualify; every watched value is still checked for NaN.
|
|
172
|
+
if (!isCollectionSize(key))
|
|
173
|
+
continue;
|
|
174
|
+
const start = a.values[key];
|
|
175
|
+
const end = b.values[key];
|
|
176
|
+
if (typeof start === 'number' &&
|
|
177
|
+
typeof end === 'number' &&
|
|
178
|
+
!Number.isNaN(end) &&
|
|
179
|
+
end > growthFloor &&
|
|
180
|
+
end > Math.max(1, start) * growthFactor) {
|
|
181
|
+
growth.set(key, `${key}: ${start} → ${end}`);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
const unboundedGrowth = [...growth.values()];
|
|
186
|
+
return { errors, loopAlive, ticksObserved, nanFields, unboundedGrowth };
|
|
187
|
+
}
|
|
188
|
+
/** True when the watchdog saw something that should fail the gate. */
|
|
189
|
+
export function watchdogFailed(r) {
|
|
190
|
+
return r.errors.length > 0 || !r.loopAlive || r.nanFields.length > 0 || r.unboundedGrowth.length > 0;
|
|
191
|
+
}
|
|
192
|
+
export function watchdogSummary(r) {
|
|
193
|
+
const lines = [];
|
|
194
|
+
if (r.errors.length > 0) {
|
|
195
|
+
lines.push(`✗ runtime errors (${r.errors.length}): ${r.errors.slice(0, 5).join(' | ')}`);
|
|
196
|
+
}
|
|
197
|
+
if (!r.loopAlive) {
|
|
198
|
+
lines.push(`✗ the main loop STOPPED — ${r.ticksObserved} frame(s) in the final sampling window. ` +
|
|
199
|
+
`An uncaught error inside a requestAnimationFrame callback stops the loop being ` +
|
|
200
|
+
`rescheduled; every later frame is a frozen copy of the last good one, which looks ` +
|
|
201
|
+
`identical to a working paused screen in a screenshot.`);
|
|
202
|
+
}
|
|
203
|
+
if (r.nanFields.length > 0)
|
|
204
|
+
lines.push(`✗ NaN in tracked state: ${r.nanFields.join(', ')}`);
|
|
205
|
+
if (r.unboundedGrowth.length > 0) {
|
|
206
|
+
lines.push(`✗ unbounded growth (leak): ${r.unboundedGrowth.join(', ')}`);
|
|
207
|
+
}
|
|
208
|
+
return lines.join('\n');
|
|
209
|
+
}
|
|
210
|
+
//# sourceMappingURL=watchdog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"watchdog.js","sourceRoot":"","sources":["../../../src/delivery/interaction/watchdog.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Web driver — drives a real headless browser with real pointer and key input.
|
|
3
|
+
*
|
|
4
|
+
* Deliberately uses coordinate-level mouse control rather than selector clicks:
|
|
5
|
+
* inside a <canvas> there are no elements to target, so aiming and firing only
|
|
6
|
+
* exist as pointer positions. A gate that can only click selectors cannot play a
|
|
7
|
+
* game, and "cannot play it" is indistinguishable from "it works".
|
|
8
|
+
*/
|
|
9
|
+
import { type InteractionDriver, type ReadResult } from './driver.js';
|
|
10
|
+
import type { Step } from './types.js';
|
|
11
|
+
/** The subset of WebBrowser the driver needs — keeps tests free of a browser. */
|
|
12
|
+
export interface PointerBrowser {
|
|
13
|
+
launch(opts?: Record<string, unknown>): Promise<unknown>;
|
|
14
|
+
goto(url: string): Promise<string>;
|
|
15
|
+
waitForLoadState(state?: 'load' | 'domcontentloaded' | 'networkidle'): Promise<void>;
|
|
16
|
+
addInitScript(script: string): Promise<void>;
|
|
17
|
+
evaluate<T>(script: string): Promise<T>;
|
|
18
|
+
screenshot(path: string): Promise<void>;
|
|
19
|
+
getErrors(): Array<{
|
|
20
|
+
kind: string;
|
|
21
|
+
message: string;
|
|
22
|
+
}>;
|
|
23
|
+
mouseMove(x: number, y: number): Promise<void>;
|
|
24
|
+
mouseDown(): Promise<void>;
|
|
25
|
+
mouseUp(): Promise<void>;
|
|
26
|
+
mouseClick(x: number, y: number): Promise<void>;
|
|
27
|
+
press(key: string): Promise<void>;
|
|
28
|
+
viewportSize(): Promise<{
|
|
29
|
+
width: number;
|
|
30
|
+
height: number;
|
|
31
|
+
}>;
|
|
32
|
+
close(): Promise<void>;
|
|
33
|
+
}
|
|
34
|
+
export interface WebDriverOptions {
|
|
35
|
+
projectRoot: string;
|
|
36
|
+
/** Entry html path relative to the served root (default index.html). */
|
|
37
|
+
entry?: string;
|
|
38
|
+
/** Directory that becomes the server root (default: the project root). */
|
|
39
|
+
webRoot?: string;
|
|
40
|
+
browserFactory?: () => Promise<PointerBrowser>;
|
|
41
|
+
serverFactory?: (dir: string, entry: string) => Promise<{
|
|
42
|
+
url: string;
|
|
43
|
+
close: () => void;
|
|
44
|
+
}>;
|
|
45
|
+
}
|
|
46
|
+
export declare class WebInteractionDriver implements InteractionDriver {
|
|
47
|
+
private browser;
|
|
48
|
+
private server;
|
|
49
|
+
private readonly opts;
|
|
50
|
+
/** Last pointer position, so `down`/`up` act where the pointer actually is. */
|
|
51
|
+
private pointer;
|
|
52
|
+
private launched;
|
|
53
|
+
/** Per-run instrumentation global — see buildWatchdogInitScript. */
|
|
54
|
+
private readonly watchGlobal;
|
|
55
|
+
constructor(opts: WebDriverOptions);
|
|
56
|
+
start(): Promise<void>;
|
|
57
|
+
/**
|
|
58
|
+
* Reload the entry page. Init scripts are registered on the CONTEXT, so the
|
|
59
|
+
* watchdog re-installs automatically on the fresh document.
|
|
60
|
+
*/
|
|
61
|
+
reset(): Promise<void>;
|
|
62
|
+
/** True once the browser is up — distinguishes infra failure from load failure. */
|
|
63
|
+
didLaunch(): boolean;
|
|
64
|
+
/** A probe may only navigate within the artifact's own served origin. */
|
|
65
|
+
private sameOrigin;
|
|
66
|
+
runStep(step: Step): Promise<void>;
|
|
67
|
+
/**
|
|
68
|
+
* Evaluate an observation. Wrapped in a function so `const`/`let` declared at
|
|
69
|
+
* the top level of a classic script — which live in the global LEXICAL scope
|
|
70
|
+
* and are NOT properties of `window` — are still readable. Reading these
|
|
71
|
+
* through `window.X` returns undefined, which silently turns every assertion
|
|
72
|
+
* into "undefined", so the wrapper matters.
|
|
73
|
+
*/
|
|
74
|
+
read(expr: string): Promise<unknown>;
|
|
75
|
+
/**
|
|
76
|
+
* `ok: false` means the expression THREW or named something undefined — a
|
|
77
|
+
* broken probe, reported as such rather than as a behavioural failure.
|
|
78
|
+
* `undefined` reached by a resolving expression stays `ok: true`.
|
|
79
|
+
*/
|
|
80
|
+
readDetailed(expr: string): Promise<ReadResult>;
|
|
81
|
+
inject(expr: string): Promise<void>;
|
|
82
|
+
/**
|
|
83
|
+
* GATING errors only: uncaught page exceptions.
|
|
84
|
+
*
|
|
85
|
+
* `console.error` output and failed sub-resource requests are common in
|
|
86
|
+
* working apps — a missing decorative asset or a handled-and-logged warning
|
|
87
|
+
* would otherwise hard-fail the behavioural gate. Both sibling gates already
|
|
88
|
+
* refuse to gate on them (execution-gate treats them as advisory;
|
|
89
|
+
* visual-gate filters to `pageerror`), and a gate that false-fails working
|
|
90
|
+
* builds gets switched off.
|
|
91
|
+
*/
|
|
92
|
+
errors(): string[];
|
|
93
|
+
/** Sample the watchdog under this run's private global name. */
|
|
94
|
+
watchdogSample(watchExprs: string[]): Promise<unknown>;
|
|
95
|
+
/** Non-gating observations, surfaced in the report as context. */
|
|
96
|
+
advisoryErrors(): string[];
|
|
97
|
+
capture(path: string): Promise<void>;
|
|
98
|
+
stop(): Promise<void>;
|
|
99
|
+
}
|
|
100
|
+
/** Where probe evidence (screenshots) is written. */
|
|
101
|
+
export declare function evidenceDir(projectRoot: string): string;
|
|
102
|
+
//# sourceMappingURL=web-driver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web-driver.d.ts","sourceRoot":"","sources":["../../../src/delivery/interaction/web-driver.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Web driver — drives a real headless browser with real pointer and key input.
|
|
3
|
+
*
|
|
4
|
+
* Deliberately uses coordinate-level mouse control rather than selector clicks:
|
|
5
|
+
* inside a <canvas> there are no elements to target, so aiming and firing only
|
|
6
|
+
* exist as pointer positions. A gate that can only click selectors cannot play a
|
|
7
|
+
* game, and "cannot play it" is indistinguishable from "it works".
|
|
8
|
+
*/
|
|
9
|
+
import { join } from 'node:path';
|
|
10
|
+
import { startStaticServer } from '../execution-gate.js';
|
|
11
|
+
import { buildWatchdogInitScript, watchdogSampleScript } from './watchdog.js';
|
|
12
|
+
import { delay } from './driver.js';
|
|
13
|
+
async function loadRealBrowser() {
|
|
14
|
+
const mod = await import('../../browser/web-browser.js');
|
|
15
|
+
return new mod.WebBrowser();
|
|
16
|
+
}
|
|
17
|
+
export class WebInteractionDriver {
|
|
18
|
+
browser = null;
|
|
19
|
+
server = null;
|
|
20
|
+
opts;
|
|
21
|
+
/** Last pointer position, so `down`/`up` act where the pointer actually is. */
|
|
22
|
+
pointer = { x: 0, y: 0 };
|
|
23
|
+
launched = false;
|
|
24
|
+
/** Per-run instrumentation global — see buildWatchdogInitScript. */
|
|
25
|
+
watchGlobal = `__uapWatch_${Math.random().toString(36).slice(2, 10)}`;
|
|
26
|
+
constructor(opts) {
|
|
27
|
+
this.opts = opts;
|
|
28
|
+
}
|
|
29
|
+
async start() {
|
|
30
|
+
const entry = this.opts.entry ?? 'index.html';
|
|
31
|
+
const root = this.opts.webRoot ?? this.opts.projectRoot;
|
|
32
|
+
const startServer = this.opts.serverFactory ?? startStaticServer;
|
|
33
|
+
this.server = await startServer(root, entry);
|
|
34
|
+
this.browser = this.opts.browserFactory
|
|
35
|
+
? await this.opts.browserFactory()
|
|
36
|
+
: await loadRealBrowser();
|
|
37
|
+
await this.browser.launch({ headless: true });
|
|
38
|
+
// MUST precede goto: the watchdog wraps requestAnimationFrame before the
|
|
39
|
+
// page's own scripts capture a reference to it.
|
|
40
|
+
await this.browser.addInitScript(buildWatchdogInitScript(this.watchGlobal));
|
|
41
|
+
// Everything above is INFRASTRUCTURE — if it fails the gate has no opinion
|
|
42
|
+
// about the artifact. Everything below is the ARTIFACT failing to load,
|
|
43
|
+
// which is a real defect and must not be laundered into "no browser
|
|
44
|
+
// available, skipping".
|
|
45
|
+
this.launched = true;
|
|
46
|
+
await this.browser.goto(this.server.url);
|
|
47
|
+
await this.browser.waitForLoadState('load');
|
|
48
|
+
const size = await this.browser.viewportSize();
|
|
49
|
+
this.pointer = { x: Math.round(size.width / 2), y: Math.round(size.height / 2) };
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Reload the entry page. Init scripts are registered on the CONTEXT, so the
|
|
53
|
+
* watchdog re-installs automatically on the fresh document.
|
|
54
|
+
*/
|
|
55
|
+
async reset() {
|
|
56
|
+
const b = this.browser;
|
|
57
|
+
if (!b || !this.server)
|
|
58
|
+
throw new Error('cannot reset: driver not started');
|
|
59
|
+
// Release a button a previous probe left held: Playwright's mouse state is
|
|
60
|
+
// browser-level and survives navigation, so a probe ending on `down`
|
|
61
|
+
// otherwise keeps firing into the next one.
|
|
62
|
+
try {
|
|
63
|
+
await b.mouseUp();
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
/* nothing was held */
|
|
67
|
+
}
|
|
68
|
+
await b.goto(this.server.url);
|
|
69
|
+
await b.waitForLoadState('load');
|
|
70
|
+
// Persisted storage survives a reload, so a save-state or "seen the
|
|
71
|
+
// tutorial" flag would carry the previous probe's writes across — exactly
|
|
72
|
+
// the leak the reload is meant to close.
|
|
73
|
+
try {
|
|
74
|
+
await b.evaluate('(function(){try{localStorage.clear();sessionStorage.clear();}catch(e){}return true;})');
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
/* storage may be unavailable (file://, blocked) */
|
|
78
|
+
}
|
|
79
|
+
const size = await b.viewportSize();
|
|
80
|
+
const cx = Math.round(size.width / 2);
|
|
81
|
+
const cy = Math.round(size.height / 2);
|
|
82
|
+
this.pointer = { x: cx, y: cy };
|
|
83
|
+
// Move the REAL cursor too — otherwise the driver believes the pointer is
|
|
84
|
+
// centred while it sits wherever the last probe left it, and coordinate-free
|
|
85
|
+
// `down`/`up` fire at the wrong place.
|
|
86
|
+
await b.mouseMove(cx, cy);
|
|
87
|
+
}
|
|
88
|
+
/** True once the browser is up — distinguishes infra failure from load failure. */
|
|
89
|
+
didLaunch() {
|
|
90
|
+
return this.launched;
|
|
91
|
+
}
|
|
92
|
+
/** A probe may only navigate within the artifact's own served origin. */
|
|
93
|
+
sameOrigin(url) {
|
|
94
|
+
if (!this.server)
|
|
95
|
+
return false;
|
|
96
|
+
try {
|
|
97
|
+
return new URL(url, this.server.url).origin === new URL(this.server.url).origin;
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
async runStep(step) {
|
|
104
|
+
const b = this.browser;
|
|
105
|
+
if (!b)
|
|
106
|
+
throw new Error('web driver not started');
|
|
107
|
+
switch (step.do) {
|
|
108
|
+
case 'goto':
|
|
109
|
+
if (step.url) {
|
|
110
|
+
// SAME-ORIGIN ONLY. The manifest is model-authored, and an unrestricted
|
|
111
|
+
// goto lets it navigate to `file:///…/.uap/proxy.env` or an attacker
|
|
112
|
+
// host — after which every `read` expression executes in THAT origin
|
|
113
|
+
// and its values flow out through the verdict feedback.
|
|
114
|
+
if (!this.sameOrigin(step.url)) {
|
|
115
|
+
throw new Error(`probe tried to navigate off-origin (${step.url}); interaction probes may only drive the artifact under test`);
|
|
116
|
+
}
|
|
117
|
+
await b.goto(step.url);
|
|
118
|
+
await b.waitForLoadState('load');
|
|
119
|
+
}
|
|
120
|
+
return;
|
|
121
|
+
case 'wait':
|
|
122
|
+
await delay(step.ms);
|
|
123
|
+
return;
|
|
124
|
+
case 'move':
|
|
125
|
+
this.pointer = { x: step.x, y: step.y };
|
|
126
|
+
await b.mouseMove(step.x, step.y);
|
|
127
|
+
return;
|
|
128
|
+
case 'down':
|
|
129
|
+
await b.mouseDown();
|
|
130
|
+
return;
|
|
131
|
+
case 'up':
|
|
132
|
+
await b.mouseUp();
|
|
133
|
+
return;
|
|
134
|
+
case 'click':
|
|
135
|
+
if (typeof step.x === 'number' && typeof step.y === 'number') {
|
|
136
|
+
this.pointer = { x: step.x, y: step.y };
|
|
137
|
+
await b.mouseClick(step.x, step.y);
|
|
138
|
+
}
|
|
139
|
+
else if (step.selector) {
|
|
140
|
+
// Selector clicks stay available for DOM UIs (menus, forms).
|
|
141
|
+
await b.evaluate(`(function(){var el=document.querySelector(${JSON.stringify(step.selector)});if(el)el.click();return true;})`);
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
await b.mouseClick(this.pointer.x, this.pointer.y);
|
|
145
|
+
}
|
|
146
|
+
return;
|
|
147
|
+
case 'aimAt': {
|
|
148
|
+
// Read-only: the same evaluation path as any observation, so the
|
|
149
|
+
// mutation guard covers it.
|
|
150
|
+
const at = await this.read(step.expr);
|
|
151
|
+
let x;
|
|
152
|
+
let y;
|
|
153
|
+
if (typeof at === 'number')
|
|
154
|
+
x = at;
|
|
155
|
+
else if (at && typeof at === 'object') {
|
|
156
|
+
const o = at;
|
|
157
|
+
if (typeof o.x === 'number')
|
|
158
|
+
x = o.x;
|
|
159
|
+
if (typeof o.y === 'number')
|
|
160
|
+
y = o.y;
|
|
161
|
+
}
|
|
162
|
+
// An expression that resolves to nothing (no target on screen) leaves
|
|
163
|
+
// the pointer where it is rather than throwing — "nothing to aim at"
|
|
164
|
+
// is a normal moment in play, not a probe failure.
|
|
165
|
+
if (typeof x !== 'number' || !Number.isFinite(x))
|
|
166
|
+
return;
|
|
167
|
+
const ty = typeof step.y === 'number' ? step.y : (y ?? this.pointer.y);
|
|
168
|
+
this.pointer = { x, y: ty };
|
|
169
|
+
await b.mouseMove(x, ty);
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
case 'key':
|
|
173
|
+
await b.press(step.key);
|
|
174
|
+
return;
|
|
175
|
+
case 'eval':
|
|
176
|
+
await this.read(step.expr);
|
|
177
|
+
return;
|
|
178
|
+
case 'inject':
|
|
179
|
+
await this.inject(step.expr);
|
|
180
|
+
return;
|
|
181
|
+
case 'repeat': {
|
|
182
|
+
// The RUNNER expands repeat blocks so every adapter gets them; this is a
|
|
183
|
+
// fallback for callers driving the driver directly (e.g. the operator).
|
|
184
|
+
const times = Math.max(0, Math.min(step.times, 10_000));
|
|
185
|
+
for (let i = 0; i < times; i++) {
|
|
186
|
+
for (const inner of step.steps)
|
|
187
|
+
await this.runStep(inner);
|
|
188
|
+
}
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
default:
|
|
192
|
+
// Unknown step kinds are ignored rather than thrown: a manifest mined by
|
|
193
|
+
// a newer version must not hard-fail an older gate.
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Evaluate an observation. Wrapped in a function so `const`/`let` declared at
|
|
199
|
+
* the top level of a classic script — which live in the global LEXICAL scope
|
|
200
|
+
* and are NOT properties of `window` — are still readable. Reading these
|
|
201
|
+
* through `window.X` returns undefined, which silently turns every assertion
|
|
202
|
+
* into "undefined", so the wrapper matters.
|
|
203
|
+
*/
|
|
204
|
+
async read(expr) {
|
|
205
|
+
return (await this.readDetailed(expr)).value;
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* `ok: false` means the expression THREW or named something undefined — a
|
|
209
|
+
* broken probe, reported as such rather than as a behavioural failure.
|
|
210
|
+
* `undefined` reached by a resolving expression stays `ok: true`.
|
|
211
|
+
*/
|
|
212
|
+
async readDetailed(expr) {
|
|
213
|
+
const b = this.browser;
|
|
214
|
+
if (!b)
|
|
215
|
+
throw new Error('web driver not started');
|
|
216
|
+
const script = `(function(){try{var v=(${expr});return JSON.stringify({ok:true,v:v===undefined?null:v,u:v===undefined});}catch(e){return JSON.stringify({ok:false,e:String(e)});}})`;
|
|
217
|
+
const raw = await b.evaluate(script);
|
|
218
|
+
try {
|
|
219
|
+
const parsed = JSON.parse(typeof raw === 'string' ? raw : JSON.stringify(raw));
|
|
220
|
+
if (!parsed.ok)
|
|
221
|
+
return { ok: false, error: parsed.e ?? 'expression threw' };
|
|
222
|
+
// An expression that resolves to `undefined` is almost always a probe
|
|
223
|
+
// naming a member the artifact does not expose (`Particles.particles`
|
|
224
|
+
// against a module that only exports functions), not a real observation.
|
|
225
|
+
if (parsed.u)
|
|
226
|
+
return { ok: false, error: `${expr} is undefined — the artifact does not expose it` };
|
|
227
|
+
return { ok: true, value: parsed.v };
|
|
228
|
+
}
|
|
229
|
+
catch {
|
|
230
|
+
return { ok: false, error: 'observation could not be serialised' };
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
async inject(expr) {
|
|
234
|
+
const b = this.browser;
|
|
235
|
+
if (!b)
|
|
236
|
+
throw new Error('web driver not started');
|
|
237
|
+
await b.evaluate(`(function(){try{${expr};}catch(e){}return true;})`);
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* GATING errors only: uncaught page exceptions.
|
|
241
|
+
*
|
|
242
|
+
* `console.error` output and failed sub-resource requests are common in
|
|
243
|
+
* working apps — a missing decorative asset or a handled-and-logged warning
|
|
244
|
+
* would otherwise hard-fail the behavioural gate. Both sibling gates already
|
|
245
|
+
* refuse to gate on them (execution-gate treats them as advisory;
|
|
246
|
+
* visual-gate filters to `pageerror`), and a gate that false-fails working
|
|
247
|
+
* builds gets switched off.
|
|
248
|
+
*/
|
|
249
|
+
errors() {
|
|
250
|
+
try {
|
|
251
|
+
return (this.browser?.getErrors() ?? [])
|
|
252
|
+
.filter((e) => e.kind === 'pageerror')
|
|
253
|
+
.map((e) => `${e.kind}: ${e.message}`);
|
|
254
|
+
}
|
|
255
|
+
catch {
|
|
256
|
+
return [];
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
/** Sample the watchdog under this run's private global name. */
|
|
260
|
+
async watchdogSample(watchExprs) {
|
|
261
|
+
return this.read(`(${watchdogSampleScript(watchExprs, this.watchGlobal)})()`);
|
|
262
|
+
}
|
|
263
|
+
/** Non-gating observations, surfaced in the report as context. */
|
|
264
|
+
advisoryErrors() {
|
|
265
|
+
try {
|
|
266
|
+
return (this.browser?.getErrors() ?? [])
|
|
267
|
+
.filter((e) => e.kind !== 'pageerror')
|
|
268
|
+
.map((e) => `${e.kind}: ${e.message}`);
|
|
269
|
+
}
|
|
270
|
+
catch {
|
|
271
|
+
return [];
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
async capture(path) {
|
|
275
|
+
try {
|
|
276
|
+
await this.browser?.screenshot(path);
|
|
277
|
+
}
|
|
278
|
+
catch {
|
|
279
|
+
/* evidence capture is best-effort */
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
async stop() {
|
|
283
|
+
// Each teardown independently guarded: a browser left alive leaks a Chromium
|
|
284
|
+
// process per gate pass, which has previously held SIGTERM'd deliver runs
|
|
285
|
+
// open for hours.
|
|
286
|
+
try {
|
|
287
|
+
await this.browser?.close();
|
|
288
|
+
}
|
|
289
|
+
catch {
|
|
290
|
+
/* ignore */
|
|
291
|
+
}
|
|
292
|
+
try {
|
|
293
|
+
this.server?.close();
|
|
294
|
+
}
|
|
295
|
+
catch {
|
|
296
|
+
/* ignore */
|
|
297
|
+
}
|
|
298
|
+
this.browser = null;
|
|
299
|
+
this.server = null;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
/** Where probe evidence (screenshots) is written. */
|
|
303
|
+
export function evidenceDir(projectRoot) {
|
|
304
|
+
return join(projectRoot, '.uap', 'interaction', 'evidence');
|
|
305
|
+
}
|
|
306
|
+
//# sourceMappingURL=web-driver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web-driver.js","sourceRoot":"","sources":["../../../src/delivery/interaction/web-driver.ts"],"names":[],"mappings":"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"}
|