@descryy/mcp 0.9.1 → 0.11.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/browser/auth.d.ts +76 -0
- package/dist/browser/auth.d.ts.map +1 -0
- package/dist/browser/auth.js +223 -0
- package/dist/browser/auth.js.map +1 -0
- package/dist/browser/capability-probe.d.ts +109 -0
- package/dist/browser/capability-probe.d.ts.map +1 -0
- package/dist/browser/capability-probe.js +201 -0
- package/dist/browser/capability-probe.js.map +1 -0
- package/dist/browser/driver.d.ts +342 -4
- package/dist/browser/driver.d.ts.map +1 -1
- package/dist/browser/driver.js +79 -1
- package/dist/browser/driver.js.map +1 -1
- package/dist/browser/evidence.d.ts +3 -0
- package/dist/browser/evidence.d.ts.map +1 -1
- package/dist/browser/evidence.js +6 -1
- package/dist/browser/evidence.js.map +1 -1
- package/dist/browser/fake-driver.d.ts +65 -8
- package/dist/browser/fake-driver.d.ts.map +1 -1
- package/dist/browser/fake-driver.js +235 -8
- package/dist/browser/fake-driver.js.map +1 -1
- package/dist/browser/fault-attribution.d.ts +178 -0
- package/dist/browser/fault-attribution.d.ts.map +1 -0
- package/dist/browser/fault-attribution.js +266 -0
- package/dist/browser/fault-attribution.js.map +1 -0
- package/dist/browser/identity-graph-write.d.ts +55 -0
- package/dist/browser/identity-graph-write.d.ts.map +1 -0
- package/dist/browser/identity-graph-write.js +45 -0
- package/dist/browser/identity-graph-write.js.map +1 -0
- package/dist/browser/page-probe.d.ts +81 -0
- package/dist/browser/page-probe.d.ts.map +1 -0
- package/dist/browser/page-probe.js +202 -0
- package/dist/browser/page-probe.js.map +1 -0
- package/dist/browser/playwright-driver.d.ts +79 -0
- package/dist/browser/playwright-driver.d.ts.map +1 -1
- package/dist/browser/playwright-driver.js +1138 -180
- package/dist/browser/playwright-driver.js.map +1 -1
- package/dist/browser/reach-recording-session.d.ts +44 -0
- package/dist/browser/reach-recording-session.d.ts.map +1 -0
- package/dist/browser/reach-recording-session.js +143 -0
- package/dist/browser/reach-recording-session.js.map +1 -0
- package/dist/browser/reachability.d.ts +168 -0
- package/dist/browser/reachability.d.ts.map +1 -0
- package/dist/browser/reachability.js +294 -0
- package/dist/browser/reachability.js.map +1 -0
- package/dist/browser/registry.d.ts +24 -0
- package/dist/browser/registry.d.ts.map +1 -1
- package/dist/browser/registry.js +21 -2
- package/dist/browser/registry.js.map +1 -1
- package/dist/browser/scenario-provenance.d.ts +1 -1
- package/dist/browser/scenario-provenance.d.ts.map +1 -1
- package/dist/browser/scenario-provenance.js +15 -1
- package/dist/browser/scenario-provenance.js.map +1 -1
- package/dist/browser/scenario-runner.d.ts +10 -2
- package/dist/browser/scenario-runner.d.ts.map +1 -1
- package/dist/browser/scenario-runner.js +77 -9
- package/dist/browser/scenario-runner.js.map +1 -1
- package/dist/browser/tool-support.d.ts +5 -1
- package/dist/browser/tool-support.d.ts.map +1 -1
- package/dist/browser/tool-support.js +80 -4
- package/dist/browser/tool-support.js.map +1 -1
- package/dist/browser/wait-target.d.ts +37 -0
- package/dist/browser/wait-target.d.ts.map +1 -0
- package/dist/browser/wait-target.js +54 -0
- package/dist/browser/wait-target.js.map +1 -0
- package/dist/heap.d.ts +61 -0
- package/dist/heap.d.ts.map +1 -0
- package/dist/heap.js +82 -0
- package/dist/heap.js.map +1 -0
- package/dist/heartbeat.d.ts +46 -0
- package/dist/heartbeat.d.ts.map +1 -0
- package/dist/heartbeat.js +66 -0
- package/dist/heartbeat.js.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/planner/predict-then-propose.d.ts +101 -0
- package/dist/planner/predict-then-propose.d.ts.map +1 -0
- package/dist/planner/predict-then-propose.js +88 -0
- package/dist/planner/predict-then-propose.js.map +1 -0
- package/dist/planner/propose-journey.d.ts +60 -0
- package/dist/planner/propose-journey.d.ts.map +1 -0
- package/dist/planner/propose-journey.js +96 -0
- package/dist/planner/propose-journey.js.map +1 -0
- package/dist/registry.d.ts +10 -1
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +5 -1
- package/dist/registry.js.map +1 -1
- package/dist/render.d.ts +4 -4
- package/dist/render.js +3 -3
- package/dist/scenarios/browser-run-plan-projection.d.ts +143 -0
- package/dist/scenarios/browser-run-plan-projection.d.ts.map +1 -0
- package/dist/scenarios/browser-run-plan-projection.js +228 -0
- package/dist/scenarios/browser-run-plan-projection.js.map +1 -0
- package/dist/scenarios/credential-ref.d.ts +102 -0
- package/dist/scenarios/credential-ref.d.ts.map +1 -0
- package/dist/scenarios/credential-ref.js +148 -0
- package/dist/scenarios/credential-ref.js.map +1 -0
- package/dist/scenarios/index.d.ts +4 -1
- package/dist/scenarios/index.d.ts.map +1 -1
- package/dist/scenarios/index.js +4 -1
- package/dist/scenarios/index.js.map +1 -1
- package/dist/scenarios/parse.d.ts.map +1 -1
- package/dist/scenarios/parse.js +42 -9
- package/dist/scenarios/parse.js.map +1 -1
- package/dist/scenarios/scenario.d.ts +39 -5
- package/dist/scenarios/scenario.d.ts.map +1 -1
- package/dist/scenarios/scenario.js +15 -2
- package/dist/scenarios/scenario.js.map +1 -1
- package/dist/scenarios/secret-ref.d.ts +86 -0
- package/dist/scenarios/secret-ref.d.ts.map +1 -0
- package/dist/scenarios/secret-ref.js +125 -0
- package/dist/scenarios/secret-ref.js.map +1 -0
- package/dist/server.d.ts +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +8 -4
- package/dist/server.js.map +1 -1
- package/dist/session.d.ts +19 -0
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +36 -0
- package/dist/session.js.map +1 -1
- package/dist/tools/analyze-workspace.d.ts +52 -0
- package/dist/tools/analyze-workspace.d.ts.map +1 -0
- package/dist/tools/analyze-workspace.js +207 -0
- package/dist/tools/analyze-workspace.js.map +1 -0
- package/dist/tools/analyze.d.ts +50 -4
- package/dist/tools/analyze.d.ts.map +1 -1
- package/dist/tools/analyze.js +225 -5
- package/dist/tools/analyze.js.map +1 -1
- package/dist/tools/browser-close-session.d.ts +21 -1
- package/dist/tools/browser-close-session.d.ts.map +1 -1
- package/dist/tools/browser-close-session.js +71 -7
- package/dist/tools/browser-close-session.js.map +1 -1
- package/dist/tools/browser-navigate.d.ts +1 -1
- package/dist/tools/browser-navigate.d.ts.map +1 -1
- package/dist/tools/browser-navigate.js +5 -3
- package/dist/tools/browser-navigate.js.map +1 -1
- package/dist/tools/browser-run-scenario.d.ts.map +1 -1
- package/dist/tools/browser-run-scenario.js +6 -1
- package/dist/tools/browser-run-scenario.js.map +1 -1
- package/dist/tools/browser-save-scenario.d.ts.map +1 -1
- package/dist/tools/browser-save-scenario.js +84 -4
- package/dist/tools/browser-save-scenario.js.map +1 -1
- package/dist/tools/browser-select.d.ts +20 -0
- package/dist/tools/browser-select.d.ts.map +1 -0
- package/dist/tools/browser-select.js +120 -0
- package/dist/tools/browser-select.js.map +1 -0
- package/dist/tools/browser-snapshot.d.ts +17 -1
- package/dist/tools/browser-snapshot.d.ts.map +1 -1
- package/dist/tools/browser-snapshot.js +18 -5
- package/dist/tools/browser-snapshot.js.map +1 -1
- package/dist/tools/browser-start-session.d.ts.map +1 -1
- package/dist/tools/browser-start-session.js +161 -9
- package/dist/tools/browser-start-session.js.map +1 -1
- package/dist/tools/browser-submit.d.ts +18 -0
- package/dist/tools/browser-submit.d.ts.map +1 -0
- package/dist/tools/browser-submit.js +106 -0
- package/dist/tools/browser-submit.js.map +1 -0
- package/dist/tools/browser-wait-for.d.ts +41 -0
- package/dist/tools/browser-wait-for.d.ts.map +1 -0
- package/dist/tools/browser-wait-for.js +148 -0
- package/dist/tools/browser-wait-for.js.map +1 -0
- package/dist/tools/chain.d.ts +41 -0
- package/dist/tools/chain.d.ts.map +1 -0
- package/dist/tools/chain.js +105 -0
- package/dist/tools/chain.js.map +1 -0
- package/dist/tools/draw-conclusion.d.ts +44 -0
- package/dist/tools/draw-conclusion.d.ts.map +1 -0
- package/dist/tools/draw-conclusion.js +250 -0
- package/dist/tools/draw-conclusion.js.map +1 -0
- package/dist/tools/index.d.ts +7 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +16 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/kit.d.ts +17 -0
- package/dist/tools/kit.d.ts.map +1 -1
- package/dist/tools/kit.js.map +1 -1
- package/dist/tools/observe-runtime.d.ts +17 -0
- package/dist/tools/observe-runtime.d.ts.map +1 -1
- package/dist/tools/observe-runtime.js +174 -10
- package/dist/tools/observe-runtime.js.map +1 -1
- package/dist/tools/predict-reach.d.ts +57 -0
- package/dist/tools/predict-reach.d.ts.map +1 -0
- package/dist/tools/predict-reach.js +159 -0
- package/dist/tools/predict-reach.js.map +1 -0
- package/dist/tools/propagation.d.ts +8 -3
- package/dist/tools/propagation.d.ts.map +1 -1
- package/dist/tools/propagation.js +16 -9
- package/dist/tools/propagation.js.map +1 -1
- package/dist/tools/propose-journey.d.ts +16 -0
- package/dist/tools/propose-journey.d.ts.map +1 -0
- package/dist/tools/propose-journey.js +121 -0
- package/dist/tools/propose-journey.js.map +1 -0
- package/dist/tools/runtime-journey-drive.d.ts +102 -0
- package/dist/tools/runtime-journey-drive.d.ts.map +1 -0
- package/dist/tools/runtime-journey-drive.js +247 -0
- package/dist/tools/runtime-journey-drive.js.map +1 -0
- package/dist/tools/scope.d.ts +3 -0
- package/dist/tools/scope.d.ts.map +1 -1
- package/dist/tools/scope.js +33 -6
- package/dist/tools/scope.js.map +1 -1
- package/dist/workspace-index.d.ts +164 -0
- package/dist/workspace-index.d.ts.map +1 -0
- package/dist/workspace-index.js +381 -0
- package/dist/workspace-index.js.map +1 -0
- package/package.json +32 -31
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a browser session actually reached, and what it did not. §4.1.
|
|
3
|
+
*
|
|
4
|
+
* ## The claim this module exists to make possible
|
|
5
|
+
*
|
|
6
|
+
* *"I reached 40% of your application, and here is the 60% I could not."*
|
|
7
|
+
*
|
|
8
|
+
* Everything else here serves that sentence. The browser path already reports
|
|
9
|
+
* what it saw; what it has never reported is what it **missed**, and a testing
|
|
10
|
+
* agent that cannot say that is not merely incomplete — it is misleading,
|
|
11
|
+
* because "no failures found" and "nothing was driven" render identically.
|
|
12
|
+
* `fixtures/hostile-apps/` app 11 reproduces exactly that: a CAPTCHA screen
|
|
13
|
+
* reports two interactive elements and no failures, which is true and useless.
|
|
14
|
+
*
|
|
15
|
+
* ## Coverage is not one of the five report categories
|
|
16
|
+
*
|
|
17
|
+
* Rule 6 is explicit: untested scope is a **separate axis**, reported as
|
|
18
|
+
* verification status, not folded into confirmed/strongly-supported/
|
|
19
|
+
* unconfirmed/not-analysable/unsupported. This module is on that separate axis.
|
|
20
|
+
* So every rendering of it says, in words, that it is not a verdict — and the
|
|
21
|
+
* tests assert that it still says so at 100% reach, which is the one case where
|
|
22
|
+
* a reader is most likely to hear "all clear".
|
|
23
|
+
*
|
|
24
|
+
* ## Why counting is per screen and not per snapshot
|
|
25
|
+
*
|
|
26
|
+
* Two snapshots of one screen are not twice the coverage, and a reply that was
|
|
27
|
+
* trimmed to fit a budget is not a screen that shrank. So screens are keyed by
|
|
28
|
+
* URL and the largest observation of each wins. The alternative — summing
|
|
29
|
+
* snapshots — would let an agent inflate its own coverage by asking twice.
|
|
30
|
+
*
|
|
31
|
+
* Rule 1: nothing here names a language or a framework.
|
|
32
|
+
*/
|
|
33
|
+
import { evidenceInWindow, refineAttribution, assertEveryFailureAttributed, } from "./fault-attribution.js";
|
|
34
|
+
/** Roles the port has a verb for. Anything else is enumerated and undrivable —
|
|
35
|
+
* §1.3, and a fact about the port rather than about the page.
|
|
36
|
+
*
|
|
37
|
+
* `combobox` is here because the port grew `select`. It has to be added in the
|
|
38
|
+
* same change as the verb or the gap stays reported after it is closed, which
|
|
39
|
+
* is worse than either state on its own: a caller reading "no verb for this
|
|
40
|
+
* role" would go and build the verb that already exists. The hostile corpus's
|
|
41
|
+
* harness carries the same list and moves with this one. */
|
|
42
|
+
const ROLES_WITH_A_VERB = new Set(["button", "link", "textbox", "searchbox", "combobox"]);
|
|
43
|
+
/**
|
|
44
|
+
* The risk kinds that mean **a region with controls in it was not entered at
|
|
45
|
+
* all** — as opposed to reached with something lost on the way.
|
|
46
|
+
*
|
|
47
|
+
* The line is drawn by what a caller would do about it, not by severity. A
|
|
48
|
+
* shadow root is reached and unsaveable; a same-origin frame is entered and
|
|
49
|
+
* enumerated (`fixtures/hostile-apps/` app 05 measured both of its targets
|
|
50
|
+
* driven); a tall document is unvisited until someone asks for a reveal pass.
|
|
51
|
+
* None of those is a region nobody got into, so none of them is a gate.
|
|
52
|
+
*
|
|
53
|
+
* What is: a challenge and a sign-in, which put the whole application on the
|
|
54
|
+
* far side; a cross-origin frame, which this session's consent does not cover;
|
|
55
|
+
* an overlay or an inert subtree, under which every control is enumerable,
|
|
56
|
+
* counted and impossible to operate; a canvas, whose controls have no elements
|
|
57
|
+
* to enumerate at all; and a windowed region, which no single snapshot can ever
|
|
58
|
+
* hold all of.
|
|
59
|
+
*
|
|
60
|
+
* Promoting them here rather than at each call site is deliberate: a disclosure
|
|
61
|
+
* that depends on a caller remembering to file it is a disclosure that goes
|
|
62
|
+
* missing on the path nobody tested.
|
|
63
|
+
*/
|
|
64
|
+
const GATING_RISKS = new Set([
|
|
65
|
+
"challenge",
|
|
66
|
+
"authWall",
|
|
67
|
+
"crossOriginFrame",
|
|
68
|
+
"overlay",
|
|
69
|
+
"inertSubtree",
|
|
70
|
+
"canvasRendered",
|
|
71
|
+
"virtualizedRegion",
|
|
72
|
+
]);
|
|
73
|
+
export function createReachabilityTracker() {
|
|
74
|
+
const screens = new Map();
|
|
75
|
+
const actions = [];
|
|
76
|
+
const gates = [];
|
|
77
|
+
const skipped = [];
|
|
78
|
+
let estimate = null;
|
|
79
|
+
return {
|
|
80
|
+
recordScreen(snapshot) {
|
|
81
|
+
let actionable = 0;
|
|
82
|
+
let savable = 0;
|
|
83
|
+
let noVerb = 0;
|
|
84
|
+
for (const el of snapshot.elements) {
|
|
85
|
+
if (ROLES_WITH_A_VERB.has(el.role.trim().toLowerCase()))
|
|
86
|
+
actionable += 1;
|
|
87
|
+
else
|
|
88
|
+
noVerb += 1;
|
|
89
|
+
if (el.selector !== null)
|
|
90
|
+
savable += 1;
|
|
91
|
+
}
|
|
92
|
+
// `totalElements`, never `elements.length`: a budget-trimmed reply is a
|
|
93
|
+
// shorter list, not a smaller page, and coverage measured off the list
|
|
94
|
+
// would improve every time a reply got tighter.
|
|
95
|
+
const unlisted = Math.max(0, snapshot.totalElements - snapshot.elements.length);
|
|
96
|
+
const next = {
|
|
97
|
+
seen: snapshot.totalElements,
|
|
98
|
+
actionable,
|
|
99
|
+
savable,
|
|
100
|
+
// Elements that did not fit in the reply were never classified. They
|
|
101
|
+
// are counted as seen and as having no known verb, because claiming
|
|
102
|
+
// them as actionable would be claiming something nothing looked at.
|
|
103
|
+
noVerb: noVerb + unlisted,
|
|
104
|
+
};
|
|
105
|
+
const existing = screens.get(snapshot.url);
|
|
106
|
+
if (existing === undefined || next.seen > existing.seen)
|
|
107
|
+
screens.set(snapshot.url, next);
|
|
108
|
+
},
|
|
109
|
+
recordEstimate(next) {
|
|
110
|
+
estimate = next;
|
|
111
|
+
},
|
|
112
|
+
recordAction(action) {
|
|
113
|
+
actions.push(action);
|
|
114
|
+
},
|
|
115
|
+
recordGate(gate) {
|
|
116
|
+
if (gate.reason.trim() === "") {
|
|
117
|
+
throw new Error("A gated region must carry a reason. A region recorded as unreachable with no reason is the silence " +
|
|
118
|
+
"reachability reporting exists to remove.");
|
|
119
|
+
}
|
|
120
|
+
gates.push(gate);
|
|
121
|
+
},
|
|
122
|
+
recordSkip(item) {
|
|
123
|
+
skipped.push(item);
|
|
124
|
+
},
|
|
125
|
+
refineFailures(drained, applicationOrigin) {
|
|
126
|
+
for (let index = 0; index < actions.length; index += 1) {
|
|
127
|
+
const action = actions[index];
|
|
128
|
+
if (action.succeeded)
|
|
129
|
+
continue;
|
|
130
|
+
// Only `undetermined` is open to revision — see `refineAttribution`.
|
|
131
|
+
// Checked here as well as there so a failure that already has a domain
|
|
132
|
+
// costs nothing to walk past on every later drain.
|
|
133
|
+
if (action.attribution.owner !== "undetermined")
|
|
134
|
+
continue;
|
|
135
|
+
if (action.failure === undefined || action.window === undefined)
|
|
136
|
+
continue;
|
|
137
|
+
const later = evidenceInWindow(drained, action.window, applicationOrigin);
|
|
138
|
+
if (later.pageErrors === 0 && later.failedRequests === 0)
|
|
139
|
+
continue;
|
|
140
|
+
actions[index] = { ...action, attribution: refineAttribution(action.attribution, action.failure, later) };
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
report() {
|
|
144
|
+
const perScreen = [...screens.entries()].map(([url, acc]) => ({
|
|
145
|
+
url,
|
|
146
|
+
elementsSeen: acc.seen,
|
|
147
|
+
elementsActionable: acc.actionable,
|
|
148
|
+
elementsSavable: acc.savable,
|
|
149
|
+
}));
|
|
150
|
+
const elementsSeen = perScreen.reduce((sum, s) => sum + s.elementsSeen, 0);
|
|
151
|
+
const elementsActionable = perScreen.reduce((sum, s) => sum + s.elementsActionable, 0);
|
|
152
|
+
const elementsSavable = perScreen.reduce((sum, s) => sum + s.elementsSavable, 0);
|
|
153
|
+
const noVerb = [...screens.values()].reduce((sum, s) => sum + s.noVerb, 0);
|
|
154
|
+
const blocked = noVerb === 0
|
|
155
|
+
? []
|
|
156
|
+
: [
|
|
157
|
+
{
|
|
158
|
+
reason: "noVerbForRole",
|
|
159
|
+
count: noVerb,
|
|
160
|
+
detail: "Enumerated on the page, but Descry has no verb for their role, so they were listed and never " +
|
|
161
|
+
"operated. This is a gap in Descry's browser port, not something wrong with the page.",
|
|
162
|
+
},
|
|
163
|
+
];
|
|
164
|
+
// A risk named before the run that nothing later contradicted is still a
|
|
165
|
+
// region nobody reached. Promoting it to a gate here means the disclosure
|
|
166
|
+
// does not depend on some caller remembering to file it.
|
|
167
|
+
const gatedFromEstimate = estimate === null
|
|
168
|
+
? []
|
|
169
|
+
: estimate.risks
|
|
170
|
+
.filter((risk) => GATING_RISKS.has(risk.kind))
|
|
171
|
+
.map((risk) => ({ region: risk.detail, reason: risk.effect, kind: risk.kind }));
|
|
172
|
+
const gated = [...gatedFromEstimate, ...gates];
|
|
173
|
+
// RG-12(c): every failed action in `actions` is, by the type above,
|
|
174
|
+
// already carrying a real attribution — nothing to filter, nothing
|
|
175
|
+
// that can silently fall out of the report unseen. Asserted, not just
|
|
176
|
+
// typed: a cast or a future widening of the type could still produce
|
|
177
|
+
// one from outside this module, and this is the belt for that.
|
|
178
|
+
assertEveryFailureAttributed(actions);
|
|
179
|
+
const failures = actions
|
|
180
|
+
.filter((a) => !a.succeeded)
|
|
181
|
+
.map((a) => ({ verb: a.verb, ref: a.ref, attribution: a.attribution }));
|
|
182
|
+
const wall = wallFor(estimate, perScreen.length);
|
|
183
|
+
return {
|
|
184
|
+
screens: perScreen,
|
|
185
|
+
elementsSeen,
|
|
186
|
+
elementsActionable,
|
|
187
|
+
elementsSavable,
|
|
188
|
+
blocked,
|
|
189
|
+
actionsAttempted: actions.length,
|
|
190
|
+
actionsSucceeded: actions.filter((a) => a.succeeded).length,
|
|
191
|
+
failures,
|
|
192
|
+
gated,
|
|
193
|
+
skipped,
|
|
194
|
+
estimate,
|
|
195
|
+
wall,
|
|
196
|
+
statement: statementFor(wall, perScreen.length, elementsSeen, elementsActionable, gated.length, skipped.length),
|
|
197
|
+
};
|
|
198
|
+
},
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Is the session behind a wall, and which one?
|
|
203
|
+
*
|
|
204
|
+
* A challenge is unconditional. Descry does not pass one, so however many
|
|
205
|
+
* screens a session went on to see, it did not legitimately get past that.
|
|
206
|
+
*
|
|
207
|
+
* A sign-in is conditional on the session having stayed on one screen. The
|
|
208
|
+
* evidence for the wall is a password field on the probed screen, and a session
|
|
209
|
+
* that went on to read a second screen demonstrably moved — claiming it never
|
|
210
|
+
* got in would be a false statement made from a true observation, which is the
|
|
211
|
+
* precise failure rule 2 exists to prevent. It keeps its gated region either
|
|
212
|
+
* way.
|
|
213
|
+
*
|
|
214
|
+
* An overlay is deliberately **not** a wall. The application underneath one is
|
|
215
|
+
* present and enumerated, and one dismissal reaches it; "this session did not
|
|
216
|
+
* reach the application" would overstate what a fixed banner proves. The gated
|
|
217
|
+
* region carries it instead.
|
|
218
|
+
*/
|
|
219
|
+
function wallFor(estimate, screens) {
|
|
220
|
+
if (estimate === null)
|
|
221
|
+
return null;
|
|
222
|
+
const challenge = estimate.risks.find((risk) => risk.kind === "challenge");
|
|
223
|
+
if (challenge !== undefined) {
|
|
224
|
+
return {
|
|
225
|
+
kind: "challenge",
|
|
226
|
+
detail: challenge.detail,
|
|
227
|
+
reason: "Descry does not attempt to pass a human-verification challenge, by design. Everything behind it is not " +
|
|
228
|
+
"analysable, which is a different statement from finding nothing wrong with it.",
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
const auth = estimate.risks.find((risk) => risk.kind === "authWall");
|
|
232
|
+
if (auth !== undefined && screens <= 1) {
|
|
233
|
+
return {
|
|
234
|
+
kind: "authWall",
|
|
235
|
+
detail: auth.detail,
|
|
236
|
+
reason: "The only screen this session saw is the logged-out surface. Nothing behind the sign-in was seen, so " +
|
|
237
|
+
"nothing behind it was tested. Seed an authenticated session — browser_start_session takes a " +
|
|
238
|
+
"storageState or a storageStatePath — to drive the application itself.",
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
return null;
|
|
242
|
+
}
|
|
243
|
+
/** The wall's own sentence. Written out per kind rather than assembled, because
|
|
244
|
+
* this is the one sentence in the reply that must not read as boilerplate. */
|
|
245
|
+
function wallStatement(wall, seen, screenNoun) {
|
|
246
|
+
const counted = seen === 0
|
|
247
|
+
? ""
|
|
248
|
+
: ` The ${seen} interactive element${seen === 1 ? "" : "s"} counted below are the ${screenNoun}'s own, not the application's.`;
|
|
249
|
+
return `This session did not reach the application: ${wall.reason}${counted}`;
|
|
250
|
+
}
|
|
251
|
+
function statementFor(wall, screens, seen, actionable, gates, skips) {
|
|
252
|
+
if (wall !== null) {
|
|
253
|
+
return wallStatement(wall, seen, wall.kind === "challenge" ? "challenge screen" : "sign-in screen");
|
|
254
|
+
}
|
|
255
|
+
if (screens === 0) {
|
|
256
|
+
return ("This session read no screen, so it reached none of the application. That is a statement about coverage " +
|
|
257
|
+
"and not about the application.");
|
|
258
|
+
}
|
|
259
|
+
const plural = (n, word) => `${n} ${word}${n === 1 ? "" : "s"}`;
|
|
260
|
+
const tail = [];
|
|
261
|
+
if (gates > 0)
|
|
262
|
+
tail.push(`${plural(gates, "region")} could not be entered at all`);
|
|
263
|
+
if (skips > 0)
|
|
264
|
+
tail.push(`${plural(skips, "thing")} was deliberately skipped`);
|
|
265
|
+
const suffix = tail.length === 0 ? "" : `, and ${tail.join(", ")}`;
|
|
266
|
+
return `Reached ${actionable} of ${seen} interactive elements across ${plural(screens, "screen")}${suffix}.`;
|
|
267
|
+
}
|
|
268
|
+
/** The disclosure lines. Every one of them is on the coverage axis, and the
|
|
269
|
+
* last one says so explicitly at every level of reach — including total. */
|
|
270
|
+
export function reachabilityNotes(report) {
|
|
271
|
+
const notes = [report.statement];
|
|
272
|
+
for (const blocked of report.blocked) {
|
|
273
|
+
notes.push(`${blocked.count} element${blocked.count === 1 ? " was" : "s were"} seen but not usable. ${blocked.detail}`);
|
|
274
|
+
}
|
|
275
|
+
const unsavable = report.elementsSeen - report.elementsSavable;
|
|
276
|
+
if (unsavable > 0) {
|
|
277
|
+
notes.push(`${unsavable} of the ${report.elementsSeen} elements seen have no stable selector. They can be driven in this ` +
|
|
278
|
+
"session and can never be saved to a scenario, so a flow through them cannot be replayed.");
|
|
279
|
+
}
|
|
280
|
+
for (const gate of report.gated) {
|
|
281
|
+
notes.push(`Not reached — ${gate.region}: ${gate.reason}`);
|
|
282
|
+
}
|
|
283
|
+
for (const skip of report.skipped) {
|
|
284
|
+
notes.push(`Skipped — ${skip.what}: ${skip.why}`);
|
|
285
|
+
}
|
|
286
|
+
for (const failure of report.failures) {
|
|
287
|
+
notes.push(`A ${failure.verb} failed${failure.ref === null ? "" : ` on ${failure.ref}`}. Fault: ${failure.attribution.owner}. ` +
|
|
288
|
+
`${failure.attribution.reason} ${failure.attribution.evidence}`);
|
|
289
|
+
}
|
|
290
|
+
notes.push("Reachability is coverage, not a verdict — it is a separate axis from the five report categories. Nothing here " +
|
|
291
|
+
"says the parts that were reached are correct, and nothing here says the parts that were not are broken.");
|
|
292
|
+
return notes;
|
|
293
|
+
}
|
|
294
|
+
//# sourceMappingURL=reachability.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reachability.js","sourceRoot":"","sources":["../../src/browser/reachability.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* flushed (kept, never dropped — rule 7). Per-connection, never global — a global
|
|
5
5
|
* registry would let one client guess another's browser by session id. */
|
|
6
6
|
import type { BrowserDriver, BrowserLaunchOptions, BrowserObservation, BrowserPageSession, ChromiumRefusal } from "./driver.ts";
|
|
7
|
+
import type { ReachabilityReport, ReachabilityTracker } from "./reachability.ts";
|
|
7
8
|
/** How long a session may go untouched before torn down. Starting value, not a
|
|
8
9
|
* measurement — 5 min balances agent-thinking time against leak size; matches the
|
|
9
10
|
* action handshake's token TTL deliberately. */
|
|
@@ -35,12 +36,35 @@ export interface BrowserSessionEntry {
|
|
|
35
36
|
readonly consentedOrigin: string;
|
|
36
37
|
readonly openedAt: number;
|
|
37
38
|
readonly lastUsedAt: number;
|
|
39
|
+
/** What this session has reached so far. Accumulated by the port wrapper, not
|
|
40
|
+
* by the tools — see `reach-recording-session.ts` for why that is not a
|
|
41
|
+
* convenience. */
|
|
42
|
+
readonly reach: ReachabilityTracker;
|
|
38
43
|
}
|
|
39
44
|
export interface ReapedSession {
|
|
40
45
|
readonly sessionId: string;
|
|
41
46
|
readonly reason: ReapReason;
|
|
42
47
|
readonly observation: BrowserObservation;
|
|
43
48
|
readonly at: number;
|
|
49
|
+
/**
|
|
50
|
+
* Why this session's `saveStorageStateTo` write did not happen, or null —
|
|
51
|
+
* B1.
|
|
52
|
+
*
|
|
53
|
+
* Recorded on the reap record for the same reason the final observation is:
|
|
54
|
+
* three of the four teardown paths have no reply to attach it to, and a
|
|
55
|
+
* caller who asked for a state and silently got none would only find out on
|
|
56
|
+
* the next run, when a session seeded from an absent file quietly drove the
|
|
57
|
+
* logged-out surface.
|
|
58
|
+
*/
|
|
59
|
+
readonly storageStateSaveFailure: string | null;
|
|
60
|
+
/** The session's final reachability report, taken at teardown.
|
|
61
|
+
*
|
|
62
|
+
* It rides on the reap record for the same reason `observation` does: all
|
|
63
|
+
* four teardown paths converge here, and a report that only `close()`
|
|
64
|
+
* produced would be missing from the three ways a session ends that nobody
|
|
65
|
+
* asked for. A session reaped on an idle timeout still has to be able to say
|
|
66
|
+
* what it reached. */
|
|
67
|
+
readonly reachability: ReachabilityReport;
|
|
44
68
|
}
|
|
45
69
|
export type OpenResult = {
|
|
46
70
|
readonly opened: true;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/browser/registry.ts"],"names":[],"mappings":"AAAA;;;;2EAI2E;AAE3E,OAAO,KAAK,EACV,aAAa,EACb,oBAAoB,EACpB,kBAAkB,EAClB,kBAAkB,EAClB,eAAe,EAChB,MAAM,aAAa,CAAC;AAGrB;;iDAEiD;AACjD,eAAO,MAAM,uBAAuB,QAAgB,CAAC;AAErD;;2DAE2D;AAC3D,eAAO,MAAM,oBAAoB,IAAI,CAAC;AAItC,MAAM,MAAM,UAAU,GAAG,aAAa,GAAG,kBAAkB,GAAG,SAAS,GAAG,QAAQ,CAAC;AAEnF;;6DAE6D;AAC7D,MAAM,MAAM,kBAAkB,GAAG,UAAU,GAAG,OAAO,GAAG,yBAAyB,CAAC;AAElF,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B;;4CAEwC;IACxC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,kBAAkB,CAAC;IAClC,iFAAiF;IACjF,QAAQ,CAAC,OAAO,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,WAAW,EAAE,kBAAkB,CAAA;KAAE,GAAG,IAAI,CAAC;IAC7F;;wBAEoB;IACpB,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/browser/registry.ts"],"names":[],"mappings":"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"}
|
package/dist/browser/registry.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* flushed (kept, never dropped — rule 7). Per-connection, never global — a global
|
|
5
5
|
* registry would let one client guess another's browser by session id. */
|
|
6
6
|
import { EMPTY_OBSERVATION } from "./driver.js";
|
|
7
|
+
import { withReachRecording } from "./reach-recording-session.js";
|
|
7
8
|
/** How long a session may go untouched before torn down. Starting value, not a
|
|
8
9
|
* measurement — 5 min balances agent-thinking time against leak size; matches the
|
|
9
10
|
* action handshake's token TTL deliberately. */
|
|
@@ -42,7 +43,22 @@ export function createBrowserSessionRegistry(options = {}) {
|
|
|
42
43
|
// Teardown that throws must not leave the session tracked or lose the record —
|
|
43
44
|
// the browser may be gone already; this id is now unusable and says why.
|
|
44
45
|
}
|
|
45
|
-
|
|
46
|
+
// Read after `close()`, which is when the driver performs the write.
|
|
47
|
+
const storageStateSaveFailure = session.page.storageStateSaveFailure?.() ?? null;
|
|
48
|
+
// C3. The tail no tool call ever sees: everything produced after the last
|
|
49
|
+
// drain arrives in this final observation, and three of the four teardown
|
|
50
|
+
// paths have no reply to attach it to. A failure that the page explained
|
|
51
|
+
// only in its last moments would otherwise stay `undetermined` in the one
|
|
52
|
+
// report that gets read — `reachability` below is taken immediately after.
|
|
53
|
+
session.reach.refineFailures(observation, session.consentedOrigin);
|
|
54
|
+
const record = {
|
|
55
|
+
sessionId,
|
|
56
|
+
reason,
|
|
57
|
+
observation,
|
|
58
|
+
at: now(),
|
|
59
|
+
storageStateSaveFailure,
|
|
60
|
+
reachability: session.reach.report(),
|
|
61
|
+
};
|
|
46
62
|
reapedSessions.set(sessionId, record);
|
|
47
63
|
return record;
|
|
48
64
|
}
|
|
@@ -73,9 +89,11 @@ export function createBrowserSessionRegistry(options = {}) {
|
|
|
73
89
|
return { opened: false, kind: "chromiumNotInstalled", ...refusal };
|
|
74
90
|
}
|
|
75
91
|
const at = now();
|
|
92
|
+
const recorded = withReachRecording(launch.session);
|
|
76
93
|
const session = {
|
|
77
94
|
runId: `browser-${launch.session.sessionId}`,
|
|
78
|
-
page:
|
|
95
|
+
page: recorded.page,
|
|
96
|
+
reach: recorded.reach,
|
|
79
97
|
profile: launchOptions.profile ?? null,
|
|
80
98
|
consentedOrigin: originOf(launchOptions.targetUrl),
|
|
81
99
|
openedAt: at,
|
|
@@ -131,6 +149,7 @@ function entryOf(sessionId, session) {
|
|
|
131
149
|
sessionId,
|
|
132
150
|
runId: session.runId,
|
|
133
151
|
page: session.page,
|
|
152
|
+
reach: session.reach,
|
|
134
153
|
profile: session.profile,
|
|
135
154
|
consentedOrigin: session.consentedOrigin,
|
|
136
155
|
openedAt: session.openedAt,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/browser/registry.ts"],"names":[],"mappings":"AAAA;;;;2EAI2E;AAS3E,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/browser/registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* (`browser-save-scenario.ts`) still runs today's single-snapshot check for anything this says no
|
|
11
11
|
* to, which is the fallback that still catches a fabricated or hand-edited scenario. */
|
|
12
12
|
import type { PerformedStep } from "./driver.ts";
|
|
13
|
-
import type
|
|
13
|
+
import { type ScenarioStep } from "../scenarios/index.ts";
|
|
14
14
|
/** For each of `steps`, in order: does it match an entry in `log`, without matching an earlier
|
|
15
15
|
* step to a later log entry than a later step already claimed? A greedy in-order subsequence
|
|
16
16
|
* match — each match consumes the log up to and including itself, so a match can never come
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scenario-provenance.d.ts","sourceRoot":"","sources":["../../src/browser/scenario-provenance.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;yFAUyF;AAEzF,OAAO,KAAK,EAAE,aAAa,EAAmB,MAAM,aAAa,CAAC;AAClE,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"scenario-provenance.d.ts","sourceRoot":"","sources":["../../src/browser/scenario-provenance.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;yFAUyF;AAEzF,OAAO,KAAK,EAAE,aAAa,EAAmB,MAAM,aAAa,CAAC;AAClE,OAAO,EAAgC,KAAK,YAAY,EAAyB,MAAM,uBAAuB,CAAC;AAiC/G;;;;;;;+FAO+F;AAC/F,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,SAAS,YAAY,EAAE,EAAE,GAAG,EAAE,SAAS,aAAa,EAAE,GAAG,SAAS,OAAO,EAAE,CAmBnH"}
|
|
@@ -9,11 +9,23 @@
|
|
|
9
9
|
* same relative order? It does not decide what to do with that answer — the caller
|
|
10
10
|
* (`browser-save-scenario.ts`) still runs today's single-snapshot check for anything this says no
|
|
11
11
|
* to, which is the fallback that still catches a fabricated or hand-edited scenario. */
|
|
12
|
+
import { isCredentialRef, isSecretRef } from "../scenarios/index.js";
|
|
12
13
|
function targetsEqual(performed, declared) {
|
|
13
14
|
if (performed === null || declared === null)
|
|
14
15
|
return performed === declared;
|
|
15
16
|
return performed.role === declared.role && performed.name === declared.name && performed.selector === declared.selector;
|
|
16
17
|
}
|
|
18
|
+
/** The stored value against what was actually entered. Equal, or — when the stored value is a
|
|
19
|
+
* secret reference — deliberately unequal, because replacing the literal with `${env:VAR}` is
|
|
20
|
+
* the whole point of the reference. What provenance proves is that *this element was acted on*;
|
|
21
|
+
* for `click` and `submit` there is no text to compare at all. Narrow on purpose: a literal is
|
|
22
|
+
* still compared exactly, so a hand-constructed scenario claiming text that was never typed
|
|
23
|
+
* still falls through to the fresh-snapshot check. */
|
|
24
|
+
function textMatches(stored, performed) {
|
|
25
|
+
if (stored !== null && (isSecretRef(stored) || isCredentialRef(stored)))
|
|
26
|
+
return true;
|
|
27
|
+
return stored === performed;
|
|
28
|
+
}
|
|
17
29
|
function stepMatches(step, entry) {
|
|
18
30
|
if (step.action !== entry.action)
|
|
19
31
|
return false;
|
|
@@ -21,10 +33,12 @@ function stepMatches(step, entry) {
|
|
|
21
33
|
case "navigate":
|
|
22
34
|
return step.url === entry.url;
|
|
23
35
|
case "click":
|
|
36
|
+
case "submit":
|
|
24
37
|
return targetsEqual(entry.target, step.target);
|
|
25
38
|
case "type":
|
|
26
39
|
case "fill":
|
|
27
|
-
|
|
40
|
+
case "select":
|
|
41
|
+
return targetsEqual(entry.target, step.target) && textMatches(step.text, entry.text);
|
|
28
42
|
}
|
|
29
43
|
}
|
|
30
44
|
/** For each of `steps`, in order: does it match an entry in `log`, without matching an earlier
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scenario-provenance.js","sourceRoot":"","sources":["../../src/browser/scenario-provenance.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;yFAUyF;
|
|
1
|
+
{"version":3,"file":"scenario-provenance.js","sourceRoot":"","sources":["../../src/browser/scenario-provenance.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;yFAUyF;AAGzF,OAAO,EAAE,eAAe,EAAE,WAAW,EAA4C,MAAM,uBAAuB,CAAC;AAE/G,SAAS,YAAY,CAAC,SAAiC,EAAE,QAAiC;IACxF,IAAI,SAAS,KAAK,IAAI,IAAI,QAAQ,KAAK,IAAI;QAAE,OAAO,SAAS,KAAK,QAAQ,CAAC;IAC3E,OAAO,SAAS,CAAC,IAAI,KAAK,QAAQ,CAAC,IAAI,IAAI,SAAS,CAAC,IAAI,KAAK,QAAQ,CAAC,IAAI,IAAI,SAAS,CAAC,QAAQ,KAAK,QAAQ,CAAC,QAAQ,CAAC;AAC1H,CAAC;AAED;;;;;uDAKuD;AACvD,SAAS,WAAW,CAAC,MAAqB,EAAE,SAAwB;IAClE,IAAI,MAAM,KAAK,IAAI,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,eAAe,CAAC,MAAM,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACrF,OAAO,MAAM,KAAK,SAAS,CAAC;AAC9B,CAAC;AAED,SAAS,WAAW,CAAC,IAAkB,EAAE,KAAoB;IAC3D,IAAI,IAAI,CAAC,MAAM,KAAK,KAAK,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAC/C,QAAQ,IAAI,CAAC,MAAM,EAAE,CAAC;QACpB,KAAK,UAAU;YACb,OAAO,IAAI,CAAC,GAAG,KAAK,KAAK,CAAC,GAAG,CAAC;QAChC,KAAK,OAAO,CAAC;QACb,KAAK,QAAQ;YACX,OAAO,YAAY,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QACjD,KAAK,MAAM,CAAC;QACZ,KAAK,MAAM,CAAC;QACZ,KAAK,QAAQ;YACX,OAAO,YAAY,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IACzF,CAAC;AACH,CAAC;AAED;;;;;;;+FAO+F;AAC/F,MAAM,UAAU,iBAAiB,CAAC,KAA8B,EAAE,GAA6B;IAC7F,MAAM,MAAM,GAAc,EAAE,CAAC;IAC7B,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,OAAO,GAAG,CAAC,CAAC,CAAC;QACjB,KAAK,IAAI,CAAC,GAAG,MAAM,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;YAC5C,IAAI,WAAW,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAE,CAAC,EAAE,CAAC;gBAC/B,OAAO,GAAG,CAAC,CAAC;gBACZ,MAAM;YACR,CAAC;QACH,CAAC;QACD,IAAI,OAAO,KAAK,CAAC,CAAC,EAAE,CAAC;YACnB,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClB,MAAM,GAAG,OAAO,GAAG,CAAC,CAAC;QACvB,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* error/failed request doesn't; no assertions is `unverified`; unresolvable step is
|
|
4
4
|
* neither pass nor fail. `registry.use()` and evidence draining run once per step only.
|
|
5
5
|
*/
|
|
6
|
-
import type
|
|
6
|
+
import { type CredentialStoreLike, type Scenario, type ScenarioActionKind, type ScenarioAssertionKind, type SecretEnvironment } from "../scenarios/index.ts";
|
|
7
7
|
import type { ToolContext } from "../tools/kit.ts";
|
|
8
8
|
import type { BrowserEvidenceReport } from "./evidence.ts";
|
|
9
9
|
import { type BrowserGraphWrite } from "./graph-write.ts";
|
|
@@ -60,5 +60,13 @@ export interface ScenarioReplay {
|
|
|
60
60
|
}
|
|
61
61
|
/** True when replaying this scenario would change the running application. A navigate-only scenario would not. */
|
|
62
62
|
export declare function mutates(scenario: Scenario): boolean;
|
|
63
|
-
export declare function replayScenario(ctx: ToolContext, registry: BrowserSessionRegistry, sessionId: string, scenario: Scenario
|
|
63
|
+
export declare function replayScenario(ctx: ToolContext, registry: BrowserSessionRegistry, sessionId: string, scenario: Scenario,
|
|
64
|
+
/** Where a `${env:VAR}` step resolves its value. Defaulted rather than required so every
|
|
65
|
+
* existing caller is unchanged, and injectable so a test never has to mutate the process. */
|
|
66
|
+
env?: SecretEnvironment,
|
|
67
|
+
/** Where a `${credential:NAME}` step resolves its value — "sign in as this profile" without the
|
|
68
|
+
* credential ever entering the committed file (lane A1, item 4). Undefined by default, same as
|
|
69
|
+
* every existing caller being unchanged: a scenario naming a credential reference with no store
|
|
70
|
+
* configured refuses by name rather than silently falling through to the environment resolver. */
|
|
71
|
+
credentialStore?: CredentialStoreLike | undefined): Promise<ScenarioReplay>;
|
|
64
72
|
//# sourceMappingURL=scenario-runner.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scenario-runner.d.ts","sourceRoot":"","sources":["../../src/browser/scenario-runner.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"scenario-runner.d.ts","sourceRoot":"","sources":["../../src/browser/scenario-runner.ts"],"names":[],"mappings":"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"}
|