@gate-forge/pack-playwright 0.7.0 → 0.8.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.
Files changed (200) hide show
  1. package/README.md +31 -0
  2. package/dist/constants.d.ts +13 -140
  3. package/dist/constants.d.ts.map +1 -1
  4. package/dist/constants.js +13 -148
  5. package/dist/constants.js.map +1 -1
  6. package/dist/cypress/plugin.d.ts +53 -0
  7. package/dist/cypress/plugin.d.ts.map +1 -0
  8. package/dist/cypress/plugin.js +369 -0
  9. package/dist/cypress/plugin.js.map +1 -0
  10. package/dist/cypress/spec-scan.d.ts +39 -0
  11. package/dist/cypress/spec-scan.d.ts.map +1 -0
  12. package/dist/cypress/spec-scan.js +301 -0
  13. package/dist/cypress/spec-scan.js.map +1 -0
  14. package/dist/diagnosis.d.ts +39 -0
  15. package/dist/diagnosis.d.ts.map +1 -0
  16. package/dist/diagnosis.js +63 -0
  17. package/dist/diagnosis.js.map +1 -0
  18. package/dist/discovery/adapter-projection.d.ts +13 -0
  19. package/dist/discovery/adapter-projection.d.ts.map +1 -0
  20. package/dist/discovery/adapter-projection.js +84 -0
  21. package/dist/discovery/adapter-projection.js.map +1 -0
  22. package/dist/discovery/config-locations.d.ts +5 -0
  23. package/dist/discovery/config-locations.d.ts.map +1 -0
  24. package/dist/discovery/config-locations.js +19 -0
  25. package/dist/discovery/config-locations.js.map +1 -0
  26. package/dist/discovery/cypress-runner-adapter.d.ts +112 -0
  27. package/dist/discovery/cypress-runner-adapter.d.ts.map +1 -0
  28. package/dist/discovery/cypress-runner-adapter.js +501 -0
  29. package/dist/discovery/cypress-runner-adapter.js.map +1 -0
  30. package/dist/discovery/discover.d.ts +53 -1
  31. package/dist/discovery/discover.d.ts.map +1 -1
  32. package/dist/discovery/discover.js +100 -3
  33. package/dist/discovery/discover.js.map +1 -1
  34. package/dist/discovery/git-ignore.d.ts +13 -0
  35. package/dist/discovery/git-ignore.d.ts.map +1 -0
  36. package/dist/discovery/git-ignore.js +62 -0
  37. package/dist/discovery/git-ignore.js.map +1 -0
  38. package/dist/discovery/index.d.ts +9 -0
  39. package/dist/discovery/index.d.ts.map +1 -1
  40. package/dist/discovery/index.js +9 -0
  41. package/dist/discovery/index.js.map +1 -1
  42. package/dist/discovery/playwright-runner-adapter.d.ts +108 -0
  43. package/dist/discovery/playwright-runner-adapter.d.ts.map +1 -0
  44. package/dist/discovery/playwright-runner-adapter.js +185 -0
  45. package/dist/discovery/playwright-runner-adapter.js.map +1 -0
  46. package/dist/discovery/prepare-barrier.d.ts +522 -0
  47. package/dist/discovery/prepare-barrier.d.ts.map +1 -0
  48. package/dist/discovery/prepare-barrier.js +739 -0
  49. package/dist/discovery/prepare-barrier.js.map +1 -0
  50. package/dist/discovery/pytest-adapter.d.ts.map +1 -1
  51. package/dist/discovery/pytest-adapter.js +6 -2
  52. package/dist/discovery/pytest-adapter.js.map +1 -1
  53. package/dist/discovery/pytest-runner-adapter.d.ts +124 -0
  54. package/dist/discovery/pytest-runner-adapter.d.ts.map +1 -0
  55. package/dist/discovery/pytest-runner-adapter.js +454 -0
  56. package/dist/discovery/pytest-runner-adapter.js.map +1 -0
  57. package/dist/discovery/reconcile.d.ts +80 -11
  58. package/dist/discovery/reconcile.d.ts.map +1 -1
  59. package/dist/discovery/reconcile.js +395 -78
  60. package/dist/discovery/reconcile.js.map +1 -1
  61. package/dist/discovery/runner-env.d.ts +88 -2
  62. package/dist/discovery/runner-env.d.ts.map +1 -1
  63. package/dist/discovery/runner-env.js +142 -4
  64. package/dist/discovery/runner-env.js.map +1 -1
  65. package/dist/discovery/static-discovery.d.ts +38 -3
  66. package/dist/discovery/static-discovery.d.ts.map +1 -1
  67. package/dist/discovery/static-discovery.js +454 -15
  68. package/dist/discovery/static-discovery.js.map +1 -1
  69. package/dist/discovery/supervised-run.d.ts +199 -10
  70. package/dist/discovery/supervised-run.d.ts.map +1 -1
  71. package/dist/discovery/supervised-run.js +350 -39
  72. package/dist/discovery/supervised-run.js.map +1 -1
  73. package/dist/discovery/trusted-config.d.ts +180 -6
  74. package/dist/discovery/trusted-config.d.ts.map +1 -1
  75. package/dist/discovery/trusted-config.js +279 -10
  76. package/dist/discovery/trusted-config.js.map +1 -1
  77. package/dist/discovery/vitest-runner-adapter.d.ts +172 -0
  78. package/dist/discovery/vitest-runner-adapter.d.ts.map +1 -0
  79. package/dist/discovery/vitest-runner-adapter.js +607 -0
  80. package/dist/discovery/vitest-runner-adapter.js.map +1 -0
  81. package/dist/fixture/consumer-runner.d.ts +4 -0
  82. package/dist/fixture/consumer-runner.d.ts.map +1 -0
  83. package/dist/fixture/consumer-runner.js +38 -0
  84. package/dist/fixture/consumer-runner.js.map +1 -0
  85. package/dist/fixture/evidence.d.ts +27 -0
  86. package/dist/fixture/evidence.d.ts.map +1 -1
  87. package/dist/fixture/evidence.js +12 -0
  88. package/dist/fixture/evidence.js.map +1 -1
  89. package/dist/fixture/fixture.d.ts +2 -1
  90. package/dist/fixture/fixture.d.ts.map +1 -1
  91. package/dist/fixture/fixture.js +1 -17
  92. package/dist/fixture/fixture.js.map +1 -1
  93. package/dist/fixture/witness-client.d.ts +6 -174
  94. package/dist/fixture/witness-client.d.ts.map +1 -1
  95. package/dist/fixture/witness-client.js +6 -267
  96. package/dist/fixture/witness-client.js.map +1 -1
  97. package/dist/index.d.ts +9 -6
  98. package/dist/index.d.ts.map +1 -1
  99. package/dist/index.js +5 -4
  100. package/dist/index.js.map +1 -1
  101. package/dist/json.d.ts +6 -12
  102. package/dist/json.d.ts.map +1 -1
  103. package/dist/json.js +6 -17
  104. package/dist/json.js.map +1 -1
  105. package/dist/reporter/project-graph-reporter.d.ts +92 -0
  106. package/dist/reporter/project-graph-reporter.d.ts.map +1 -0
  107. package/dist/reporter/project-graph-reporter.js +92 -0
  108. package/dist/reporter/project-graph-reporter.js.map +1 -0
  109. package/dist/reporter/reporter.cjs.map +1 -1
  110. package/dist/reporter/reporter.d.ts +93 -4
  111. package/dist/reporter/reporter.d.ts.map +1 -1
  112. package/dist/reporter/reporter.js +174 -18
  113. package/dist/reporter/reporter.js.map +1 -1
  114. package/dist/runner-claims.d.ts +13 -0
  115. package/dist/runner-claims.d.ts.map +1 -0
  116. package/dist/runner-claims.js +46 -0
  117. package/dist/runner-claims.js.map +1 -0
  118. package/dist/runner-resolution.d.ts +3 -0
  119. package/dist/runner-resolution.d.ts.map +1 -0
  120. package/dist/runner-resolution.js +14 -0
  121. package/dist/runner-resolution.js.map +1 -0
  122. package/dist/supervisor/client.d.ts +23 -1
  123. package/dist/supervisor/client.d.ts.map +1 -1
  124. package/dist/supervisor/client.js +49 -0
  125. package/dist/supervisor/client.js.map +1 -1
  126. package/dist/supervisor/drain.d.ts +65 -0
  127. package/dist/supervisor/drain.d.ts.map +1 -1
  128. package/dist/supervisor/drain.js +353 -9
  129. package/dist/supervisor/drain.js.map +1 -1
  130. package/dist/supervisor/index.d.ts +7 -3
  131. package/dist/supervisor/index.d.ts.map +1 -1
  132. package/dist/supervisor/index.js +7 -3
  133. package/dist/supervisor/index.js.map +1 -1
  134. package/dist/supervisor/spool.d.ts +65 -2
  135. package/dist/supervisor/spool.d.ts.map +1 -1
  136. package/dist/supervisor/spool.js +47 -0
  137. package/dist/supervisor/spool.js.map +1 -1
  138. package/dist/surface.d.ts +6 -207
  139. package/dist/surface.d.ts.map +1 -1
  140. package/dist/surface.js +6 -264
  141. package/dist/surface.js.map +1 -1
  142. package/dist/vitest/index.d.ts +23 -0
  143. package/dist/vitest/index.d.ts.map +1 -0
  144. package/dist/vitest/index.js +356 -0
  145. package/dist/vitest/index.js.map +1 -0
  146. package/dist/vitest/reporter.d.ts +83 -0
  147. package/dist/vitest/reporter.d.ts.map +1 -0
  148. package/dist/vitest/reporter.js +211 -0
  149. package/dist/vitest/reporter.js.map +1 -0
  150. package/dist/vitest/worker-slot.d.ts +36 -0
  151. package/dist/vitest/worker-slot.d.ts.map +1 -0
  152. package/dist/vitest/worker-slot.js +51 -0
  153. package/dist/vitest/worker-slot.js.map +1 -0
  154. package/dist/witness/adapter-registry.d.ts +6 -50
  155. package/dist/witness/adapter-registry.d.ts.map +1 -1
  156. package/dist/witness/adapter-registry.js +6 -257
  157. package/dist/witness/adapter-registry.js.map +1 -1
  158. package/dist/witness/behavior-request.d.ts +6 -76
  159. package/dist/witness/behavior-request.d.ts.map +1 -1
  160. package/dist/witness/behavior-request.js +6 -273
  161. package/dist/witness/behavior-request.js.map +1 -1
  162. package/dist/witness/behavior.d.ts +6 -48
  163. package/dist/witness/behavior.d.ts.map +1 -1
  164. package/dist/witness/behavior.js +6 -114
  165. package/dist/witness/behavior.js.map +1 -1
  166. package/dist/witness/bin.d.ts +6 -17
  167. package/dist/witness/bin.d.ts.map +1 -1
  168. package/dist/witness/bin.js +6 -168
  169. package/dist/witness/bin.js.map +1 -1
  170. package/dist/witness/browser.d.ts +14 -206
  171. package/dist/witness/browser.d.ts.map +1 -1
  172. package/dist/witness/browser.js +15 -654
  173. package/dist/witness/browser.js.map +1 -1
  174. package/dist/witness/classifications.d.ts +6 -38
  175. package/dist/witness/classifications.d.ts.map +1 -1
  176. package/dist/witness/classifications.js +6 -83
  177. package/dist/witness/classifications.js.map +1 -1
  178. package/dist/witness/env-attestation.d.ts +6 -94
  179. package/dist/witness/env-attestation.d.ts.map +1 -1
  180. package/dist/witness/env-attestation.js +6 -198
  181. package/dist/witness/env-attestation.js.map +1 -1
  182. package/dist/witness/fixture-provider.d.ts +6 -82
  183. package/dist/witness/fixture-provider.d.ts.map +1 -1
  184. package/dist/witness/fixture-provider.js +6 -105
  185. package/dist/witness/fixture-provider.js.map +1 -1
  186. package/dist/witness/loopback-pins.d.ts +6 -75
  187. package/dist/witness/loopback-pins.d.ts.map +1 -1
  188. package/dist/witness/loopback-pins.js +6 -240
  189. package/dist/witness/loopback-pins.js.map +1 -1
  190. package/dist/witness/server.d.ts +8 -26
  191. package/dist/witness/server.d.ts.map +1 -1
  192. package/dist/witness/server.js +24 -3761
  193. package/dist/witness/server.js.map +1 -1
  194. package/dist/witness/types.d.ts +6 -882
  195. package/dist/witness/types.d.ts.map +1 -1
  196. package/dist/witness/types.js +9 -1
  197. package/dist/witness/types.js.map +1 -1
  198. package/examples/overlay-proof.spec.js +75 -0
  199. package/package.json +8 -2
  200. package/python/gateforge_pytest_plugin.py +462 -0
@@ -0,0 +1,522 @@
1
+ /**
2
+ * The GLOBAL native preparation freeze barrier (contract: "ONE native
3
+ * process, ONE GLOBAL prepared snapshot").
4
+ *
5
+ * Why this exists. A Playwright config's prerequisite (`setup`) projects
6
+ * produce their artifacts — the saved `playwright/.auth/user.json` of the
7
+ * standard auth pattern above all — WHILE the behavioral projects are
8
+ * already scheduled to run. Gateforge's candidate freeze, on the other
9
+ * hand, is taken BEFORE the runner starts, so a run whose setup writes
10
+ * generated bytes into the workspace always ends with a candidate tree
11
+ * that no longer equals the frozen one, and no receipt is ever sealed.
12
+ * That is the honest failure this module removes — not by excluding the
13
+ * generated bytes (that would weaken every binding), but by taking ONE
14
+ * prepared snapshot AFTER the whole prerequisite stage and BEFORE any
15
+ * body project, and then demanding the workspace stay exactly that.
16
+ *
17
+ * The shape of the barrier, and why each part exists:
18
+ *
19
+ * - ONE controller project. The engine adds a project of its own that
20
+ * depends on the FULL upstream prerequisite closure of the planned
21
+ * graph, and gives every non-prerequisite planned project that
22
+ * controller as its FIRST dependency (its own captured edges follow,
23
+ * unchanged, in their emitted order). Prerequisites keep their edges
24
+ * exactly as captured. The runner's own phase scheduler then orders
25
+ * prerequisite → controller → body inside ONE process, with the
26
+ * runner's real dependency semantics — not a second process, not a flag.
27
+ * - The controller is a real Playwright test, because the environment
28
+ * leak it has to undo happens in WORKERS: the native scheduler unions
29
+ * every dependency worker's produced environment into its dependents
30
+ * (`runner/tasks.js`), so merely emitting an empty controller project
31
+ * would hand each body the whole preparation environment.
32
+ * - A REQUEST/RELEASE handshake. The controller writes a request naming
33
+ * the exact run, invocation and per-invocation nonce; the trusted CLI
34
+ * — the only process holding supervisor credentials — validates every
35
+ * prerequisite identity against the authenticated witness execution
36
+ * trace, freezes, and answers with a SIGNED release. A request that
37
+ * never comes, an unsigned release, a release for another
38
+ * run/invocation/nonce, and a release whose bound controller spec
39
+ * bytes no longer hash to what the CLI pinned are all refusals, and a
40
+ * controller that never receives a valid release fails its own bounded
41
+ * wait instead of letting the bodies run unfrozen.
42
+ * - An ephemeral Ed25519 signature. A release is a file, and a file at
43
+ * this boundary is forgeable by any code running as the same user. The
44
+ * private key is minted per invocation and never leaves the CLI
45
+ * process — never a child environment, never a file; the controller
46
+ * receives only the public key. Same-UID modify/restore or in-process
47
+ * tampering stays OUTSIDE this boundary (this is not a filesystem
48
+ * sandbox); what the signature closes is an ordinary control-file
49
+ * forgery and any replay of an older or different release.
50
+ *
51
+ * Honesty boundary (repeated on purpose): this is a CONTROL barrier, not
52
+ * a physical one. It orders one native process, proves the prerequisites
53
+ * really passed under supervision, and proves the workspace did not move
54
+ * between the freeze and the seal. It does not make the source read-only.
55
+ */
56
+ import { type KeyObject } from 'node:crypto';
57
+ import type { ProjectScope } from './trusted-config.js';
58
+ /** The engine-owned controller project name (never a candidate project). */
59
+ export declare const FREEZE_CONTROLLER_PROJECT = "gateforge-freeze";
60
+ /**
61
+ * Directory (inside the excluded run-state dir) holding the barrier's
62
+ * handshake DOCUMENTS — the controller's request, the CLI's signed
63
+ * release and its refusal document. They are evidence about the run,
64
+ * not test-shaped files, so they stay where the CLI pins and seals
65
+ * them.
66
+ *
67
+ * The generated controller SPEC is deliberately NOT here: a `.mjs` spec
68
+ * file inside the repository is a file a consumer's own Playwright
69
+ * configuration can collect (see {@link FREEZE_CONTROL_SPEC_FILE}).
70
+ */
71
+ export declare const FREEZE_CONTROL_DIR = "native-freeze";
72
+ /**
73
+ * The generated controller spec: the ONE worker that performs the handshake.
74
+ *
75
+ * Plain ESM JavaScript under an `.mjs` name, deliberately. The runner
76
+ * decides a file's module kind from its extension first and only then from
77
+ * the nearest `package.json` `type`, and a consumer repository may sit
78
+ * under EITHER: a CommonJS/default root would have this spec `require`d,
79
+ * which turns its ESM imports into `require()` of a `file:` URL and fails
80
+ * to load at all. `.mjs` fixes the module kind on the file itself, so the
81
+ * controller's imports resolve as real ESM imports whatever the
82
+ * consumer's root package says — no manifest inspection, no install
83
+ * restriction, and no candidate module ever loaded by the CLI. The
84
+ * consequence is that the generated bytes must stay plain JavaScript:
85
+ * nothing TypeScript-only may reappear in the template below.
86
+ *
87
+ * WHERE the file is written follows from what it IS: a parseable test
88
+ * file. Inside the repository it is a candidate the consumer's own
89
+ * runner collects — a config at the repo root with no restricting
90
+ * `testDir` enumerates every parseable file below it, so an engine spec
91
+ * parked in the run-state subtree was still enumerated as a consumer
92
+ * case, by the engine's own `--list` and by the owner's `npx playwright
93
+ * test` alike. It is therefore written into a private per-run directory
94
+ * OUTSIDE the repository ({@link FreezeControl.specDir}) and removed
95
+ * once the run no longer reads it.
96
+ */
97
+ export declare const FREEZE_CONTROL_SPEC_FILE = "freeze-controller.spec.mjs";
98
+ /** The controller's request document (written by the controller worker). */
99
+ export declare const FREEZE_REQUEST_FILE = "freeze-request.json";
100
+ /** The CLI's signed release document (read by the controller worker). */
101
+ export declare const FREEZE_RELEASE_FILE = "freeze-release.json";
102
+ /**
103
+ * The trusted CLI's REFUSAL document (read by the controller worker).
104
+ *
105
+ * The handshake needs a failure channel as well as a success one, or a
106
+ * permanent refusal turns into a bounded-but-slow timeout: the trusted
107
+ * side answers "your prerequisite sealed as failed", and the controller
108
+ * should stop waiting the moment it hears that, not poll to its own long
109
+ * bound. This file is FAILURE ONLY. Nothing here can ever unblock a body
110
+ * project — only a correctly signed `FREEZE_RELEASE_FILE` does — so a
111
+ * controller that trusts this document can only ever fail earlier, never
112
+ * proceed. A forged refusal therefore costs a run its barrier, which the
113
+ * signing already guarantees; a missing one costs nothing.
114
+ */
115
+ export declare const FREEZE_REFUSAL_FILE = "freeze-refusal.json";
116
+ /**
117
+ * Environment names the runner itself owns in every worker process, and
118
+ * which the projection must therefore never touch.
119
+ *
120
+ * The reason is structural, read from the runner itself:
121
+ * `worker/workerMain.js` assigns `TEST_WORKER_INDEX` and
122
+ * `TEST_PARALLEL_INDEX` AFTER the process booted, and
123
+ * `runner/workerHost.js` spreads `FORCE_COLOR` and `DEBUG_COLORS` into
124
+ * every worker's environment at spawn. `lib/common/process.js` computes
125
+ * the produced-environment diff against the worker's OWN boot
126
+ * environment, so all four names appear in a produced diff without any
127
+ * prerequisite having written them — a subtraction reset that touched
128
+ * them would report a deletion the bodies then inherit.
129
+ *
130
+ * The reset set is otherwise derived BY SUBTRACTION — every key in the
131
+ * controller's environment or in the trusted baseline, minus these four.
132
+ * That is equivalent to a positively-owned namespace ONLY under the
133
+ * invariant below, and the invariant is the real risk: nothing in the
134
+ * run pins it, so a future change that starts injecting environment into
135
+ * workers beyond these names would be silently projected away rather
136
+ * than reported.
137
+ *
138
+ * Gateforge injects nothing into worker environment beyond the runner
139
+ * child's own baseline: `buildRunnerChildEnv` refuses run-state paths
140
+ * and signing material, and the freeze control reaches the controller
141
+ * inlined in its generated spec rather than through the environment.
142
+ * Under that invariant the worker's environment is the baseline, plus
143
+ * preparation-written keys, plus these four names — so the reset set is
144
+ * exactly the baseline keys a prerequisite overrode (restored) and the
145
+ * keys a prerequisite introduced (deleted), whatever they are named.
146
+ */
147
+ export declare const FREEZE_ENV_EXEMPT: readonly string[];
148
+ /** One armed freeze barrier (paths, identities and the pinned spec bytes). */
149
+ export interface FreezeControl {
150
+ /** Engine-owned controller project name. */
151
+ project: string;
152
+ /** The run identity (bound into request AND release). */
153
+ runId: string;
154
+ /** The invocation identity (bound into request AND release). */
155
+ invocationId: string;
156
+ /** Per-invocation random nonce; an old release can never match it. */
157
+ nonce: string;
158
+ /**
159
+ * Absolute path of the state-directory control directory: the request,
160
+ * release and refusal documents. NEVER the spec — see
161
+ * {@link FreezeControl.specDir}.
162
+ */
163
+ controlDir: string;
164
+ /**
165
+ * Absolute, symlink-RESOLVED path of the private per-run directory that
166
+ * holds the generated controller spec.
167
+ *
168
+ * It is a fresh `mkdtemp` directory under the host temporary
169
+ * directory, outside the repository, so no consumer enumeration can
170
+ * collect the spec and nothing this run generates can end up among the
171
+ * candidate's own bytes. `realpath` matters because a temporary
172
+ * directory is commonly a symlink (`/tmp` → `/private/tmp`): the
173
+ * runner reports the spec under the `testDir` it was handed and the
174
+ * reporter compares resolved paths, so both sides must name the same
175
+ * physical file. It is owner-only and holds nothing but the spec, and
176
+ * the CLI removes it ({@link removeFreezeSpecDir}) once the run has
177
+ * read the spec for the last time.
178
+ */
179
+ specDir: string;
180
+ /** Absolute path of the generated controller spec (inside `specDir`). */
181
+ specPath: string;
182
+ /** Absolute path of the request document. */
183
+ requestPath: string;
184
+ /** Absolute path of the release document. */
185
+ releasePath: string;
186
+ /**
187
+ * Absolute path of the selected install's CommonJS test module
188
+ * (`@playwright/test`'s package root, or `playwright/test`) that the
189
+ * runner this run uses, resolved from the install this run actually
190
+ * spawns. The generated controller is an ES module and this module is
191
+ * CommonJS, so it is bound through the module's default export — the
192
+ * ordinary interop for a CommonJS module, and the same file every
193
+ * body in this run executes against.
194
+ */
195
+ testModulePath: string;
196
+ /** Absolute engine module the controller imports its primitives from. */
197
+ barrierModulePath: string;
198
+ /** Absolute path of the CLI's REFUSAL document (failure channel only). */
199
+ refusalPath: string;
200
+ /** Base64 raw SPKI Ed25519 PUBLIC key (the private key never leaves the CLI). */
201
+ releasePublicKey: string;
202
+ /** How long the controller waits for a valid release before failing. */
203
+ timeoutMs: number;
204
+ /**
205
+ * The trusted runner MAIN/child environment BEFORE any project worker
206
+ * ran — the exact baseline every body worker must be projected back to.
207
+ * It is the child's OWN allowlisted environment, never the CLI's ambient
208
+ * environment and never anything secret: the worker it describes already
209
+ * runs with these very values.
210
+ */
211
+ baseEnv: Readonly<Record<string, string>>;
212
+ /** Environment names the projection must never touch. */
213
+ exemptEnv: readonly string[];
214
+ }
215
+ /** What the CLI hands the pack to arm one barrier. */
216
+ export interface FreezeArmInput {
217
+ /** The run identity. */
218
+ runId: string;
219
+ /** The invocation identity. */
220
+ invocationId: string;
221
+ /** Per-invocation random nonce. */
222
+ nonce: string;
223
+ /**
224
+ * Absolute run-state dir. The barrier's handshake DOCUMENTS live in
225
+ * its excluded subtree; the generated spec does not (it is written
226
+ * outside the repository).
227
+ */
228
+ stateDir: string;
229
+ /** Absolute path of the selected install's CommonJS test module. */
230
+ testModulePath: string;
231
+ /** Base64 raw SPKI Ed25519 public key for the release signature. */
232
+ releasePublicKey: string;
233
+ /** The trusted runner child's baseline environment. */
234
+ baseEnv: Readonly<Record<string, string>>;
235
+ /** How long the controller waits for a valid release. */
236
+ timeoutMs: number;
237
+ }
238
+ /** The armed barrier plus the sha256 of the exact spec bytes written. */
239
+ export interface ArmedFreezeControl {
240
+ control: FreezeControl;
241
+ /** sha256 hex of the controller spec file the CLI pinned in memory. */
242
+ specDigest: string;
243
+ }
244
+ /** The signed release payload (exactly what the signature covers). */
245
+ export interface FreezeReleasePayload {
246
+ schemaVersion: 1;
247
+ project: string;
248
+ runId: string;
249
+ invocationId: string;
250
+ nonce: string;
251
+ /** The prepared candidate tree the freeze produced. */
252
+ preparedTreeId: string;
253
+ /** sha256 of the controller spec bytes the CLI pinned before the run. */
254
+ specDigest: string;
255
+ /** ISO timestamp of the freeze (diagnostic; inside the signature). */
256
+ sealedAt: string;
257
+ }
258
+ /** The signed release document the CLI writes and the controller reads. */
259
+ export interface FreezeReleaseDocument {
260
+ schemaVersion: 1;
261
+ payload: FreezeReleasePayload;
262
+ /** Base64 Ed25519 signature over `canonicalFreezeJson(payload)`. */
263
+ signature: string;
264
+ }
265
+ /** One controller request (written by the controller worker). */
266
+ export interface FreezeRequest {
267
+ schemaVersion: 1;
268
+ project: string;
269
+ runId: string;
270
+ invocationId: string;
271
+ nonce: string;
272
+ /** ISO timestamp the controller asked (diagnostic). */
273
+ requestedAt: string;
274
+ }
275
+ /**
276
+ * Deterministic canonical JSON: object keys sorted, no insignificant
277
+ * whitespace. The CLI signs exactly these bytes and the controller
278
+ * verifies exactly these bytes, so neither side may depend on a property
279
+ * order or a serializer default.
280
+ *
281
+ * @param value: any JSON-compatible value.
282
+ *
283
+ * @returns
284
+ * string: the canonical form.
285
+ */
286
+ export declare function canonicalFreezeJson(value: unknown): string;
287
+ /** One ephemeral per-invocation Ed25519 release-signing key pair. */
288
+ export interface FreezeSigningKeyPair {
289
+ /** The public key object (verification only). */
290
+ publicKey: KeyObject;
291
+ /** The same public key as base64 raw SPKI, for the control data. */
292
+ publicKeyBase64: string;
293
+ /** The private key — CLI memory only, never a file or an environment. */
294
+ privateKey: KeyObject;
295
+ }
296
+ /**
297
+ * Mints one ephemeral Ed25519 key pair for the release signature. The
298
+ * private key is returned to the CLI and NEVER written anywhere: not the
299
+ * trusted config, not the run state, not a child environment.
300
+ *
301
+ * @returns
302
+ * FreezeSigningKeyPair: the pair, with the public key already
303
+ * base64-encoded as raw SPKI.
304
+ */
305
+ export declare function mintFreezeSigningKeyPair(): FreezeSigningKeyPair;
306
+ /**
307
+ * Signs one release payload with the invocation's ephemeral private key.
308
+ *
309
+ * @param privateKey: the ephemeral key (CLI memory only).
310
+ * @param payload: the payload to sign.
311
+ *
312
+ * @returns
313
+ * FreezeReleaseDocument: the document the controller verifies.
314
+ */
315
+ export declare function signFreezeRelease(privateKey: KeyObject, payload: FreezeReleasePayload): FreezeReleaseDocument;
316
+ /**
317
+ * Verifies one release document against the pinned public key and the
318
+ * exact identities the controller itself was armed with.
319
+ *
320
+ * A release passes only when ALL of these hold: the document shape, the
321
+ * Ed25519 signature under the pinned key, the controller project name, the
322
+ * run, the invocation, the per-invocation nonce, and the sha256 of the
323
+ * controller's OWN current spec bytes. The last check is what makes a
324
+ * replaced control file detectable rather than trusted.
325
+ *
326
+ * @param document: the parsed release document.
327
+ * @param publicKeyBase64: the pinned base64 raw SPKI public key.
328
+ * @param expected: the identities and spec digest the controller was armed with.
329
+ *
330
+ * @returns
331
+ * {ok: true, payload} | {ok: false, reason}: the verified payload, or the
332
+ * single plain reason the release was refused.
333
+ */
334
+ export declare function verifyFreezeRelease(document: unknown, publicKeyBase64: string, expected: {
335
+ project: string;
336
+ runId: string;
337
+ invocationId: string;
338
+ nonce: string;
339
+ specDigest: string;
340
+ }): {
341
+ ok: true;
342
+ payload: FreezeReleasePayload;
343
+ } | {
344
+ ok: false;
345
+ reason: string;
346
+ };
347
+ /**
348
+ * What ONE baseline projection changed, reported by name.
349
+ *
350
+ * Both lists are sorted; their ORDER is a diagnostic convenience, not a
351
+ * contract — the contract is their membership.
352
+ */
353
+ export interface BaselineEnvProjection {
354
+ /** Names the trusted baseline OWNS, given their baseline value back. */
355
+ restored: string[];
356
+ /** Names the trusted baseline never owned, removed from the worker. */
357
+ deleted: string[];
358
+ }
359
+ /**
360
+ * Projects one worker environment back to the trusted baseline the runner
361
+ * child started with.
362
+ *
363
+ * The native scheduler unions every dependency worker's produced
364
+ * environment into its dependents, so a body worker inherits whatever a
365
+ * prerequisite worker assigned — including a deleted key, which the
366
+ * scheduler carries as `undefined` and Node then simply omits from the
367
+ * child. This restores exactly that difference: every name the trusted
368
+ * baseline OWNS goes back to its own value, and every name the baseline
369
+ * never owned is removed. The keys Playwright's own worker bootstrap
370
+ * writes ({@link FREEZE_ENV_EXEMPT}) are left alone — they are the
371
+ * runner's, not a prerequisite's.
372
+ *
373
+ * Both sides are read by OWN membership, never through an inherited
374
+ * lookup, because the names at stake are ordinary environment names the
375
+ * runner itself spawns workers with: `constructor`, `toString` and
376
+ * `__proto__` are each a property every plain object inherits, so a
377
+ * baseline read as `base[key]` reports those as owned values of `Object`,
378
+ * `Object.prototype.toString` and `Object.prototype` itself and hands
379
+ * the body worker that instead of deleting what a prerequisite
380
+ * introduced. No prefix restriction avoids that, and none is acceptable.
381
+ *
382
+ * The restore side is therefore a `defineProperty`, not an assignment:
383
+ * on an ordinary object an assignment to `__proto__` does not create an
384
+ * own key at all — the inherited accessor swallows it — so a baseline
385
+ * name a prerequisite deleted could never be put back.
386
+ *
387
+ * @param current: the controller worker's own environment (mutated in place).
388
+ * @param base: the trusted runner child's baseline environment.
389
+ * @param exempt: names the projection must not touch.
390
+ *
391
+ * @returns
392
+ * BaselineEnvProjection: what the projection changed, sorted, for the
393
+ * controller's own diagnostic.
394
+ */
395
+ export declare function projectBaselineEnv(current: Record<string, string | undefined>, base: Readonly<Record<string, string>>, exempt?: readonly string[]): BaselineEnvProjection;
396
+ /**
397
+ * Resolves the engine barrier module the generated controller imports.
398
+ * Absolute and pack-relative for the same reason the trusted reporter
399
+ * entry is: a generated worker spec must load an ENGINE file by absolute
400
+ * path, never a candidate-relative one. Resolves from both the `src/` and
401
+ * the `dist/` layout.
402
+ *
403
+ * @param fromModule: module URL to resolve the pack from (default: this file).
404
+ *
405
+ * @returns
406
+ * string: absolute `<pack>/dist|src/discovery/prepare-barrier.js` path.
407
+ */
408
+ export declare function barrierModulePath(fromModule?: string): string;
409
+ /**
410
+ * The controller worker's own bytes.
411
+ *
412
+ * The generated spec imports the ENGINE barrier module by absolute path so
413
+ * the canonical payload form, the signature verification and the
414
+ * environment projection are ONE implementation on both sides — never a
415
+ * second copy that can drift from the one the CLI signed.
416
+ *
417
+ * The armed control reaches the worker as a JSON document bound through
418
+ * `JSON.parse`, never as an object literal inlined in these bytes: the
419
+ * baseline is a map of ordinary environment NAMES, so a name like
420
+ * `__proto__` has to arrive as an own key, and a value has to arrive
421
+ * escaped. `JSON.parse` is the one binding that gives both — it creates
422
+ * data properties — while a literal would be re-read by the JavaScript
423
+ * parser: a backtick or a `${` in a value would end the literal, and
424
+ * `__proto__:` in a literal is a PROTOTYPE assignment, not a key.
425
+ *
426
+ * @param control: the armed control (paths and pinned identities).
427
+ *
428
+ * @returns
429
+ * string: the generated plain-ESM JavaScript source of the controller spec.
430
+ */
431
+ export declare function freezeControllerSpecSource(control: FreezeControl): string;
432
+ /**
433
+ * Writes the controller spec and returns the armed barrier plus the sha256
434
+ * of the exact bytes written. The spec is GENERATED engine code and the
435
+ * only worker that performs the handshake, and its bytes are pinned in
436
+ * CLI memory for the whole run; because it is a parseable test file it is
437
+ * written OUTSIDE the repository, into a private per-run directory
438
+ * ({@link FreezeControl.specDir}), while the handshake documents stay in
439
+ * the excluded run-state subtree.
440
+ *
441
+ * @param input: the identities, paths, public key and baseline environment.
442
+ *
443
+ * @returns
444
+ * ArmedFreezeControl: the control (with absolute paths) and its spec digest.
445
+ */
446
+ export declare function armFreezeControl(input: FreezeArmInput): ArmedFreezeControl;
447
+ /**
448
+ * Removes the private per-run directory holding the generated controller
449
+ * spec, and with it the generated engine file itself.
450
+ *
451
+ * The CLI calls this once the spec has been read for the LAST time — the
452
+ * final pinned-digest check — and on every path that never reaches that
453
+ * check, so no generated spec outlives the run that produced it and no
454
+ * consumer enumeration can ever see one. Idempotent: a second call, or a
455
+ * call for a directory something else already removed, removes nothing.
456
+ *
457
+ * @param control: the armed control.
458
+ */
459
+ export declare function removeFreezeSpecDir(control: FreezeControl): void;
460
+ /**
461
+ * Writes the trusted side's REFUSAL document for one handshake. It is
462
+ * failure-only by construction: no code path in the controller treats
463
+ * its presence as permission to continue, so a refusal can only shorten a
464
+ * wait, never satisfy one.
465
+ *
466
+ * @param control: the armed control.
467
+ * @param reason: the plain refusal text the controller surfaces.
468
+ */
469
+ export declare function writeFreezeRefusal(control: FreezeControl, reason: string): void;
470
+ /**
471
+ * Reads the controller's request document, or null when it is absent or
472
+ * unusable. An absent request is ordinary (the controller has not asked
473
+ * yet); a MALFORMED one is a refusal the trusted side reports.
474
+ *
475
+ * @param path: absolute request document path.
476
+ *
477
+ * @returns
478
+ * FreezeRequest | null: the parsed request, or null.
479
+ */
480
+ export declare function readFreezeRequest(path: string): FreezeRequest | null;
481
+ /**
482
+ * Rewrites the planned project scopes into the freeze-aware shape the
483
+ * synthesized config emits.
484
+ *
485
+ * The rules, in the order they matter:
486
+ *
487
+ * - The engine's controller project is appended as one more scope. It
488
+ collects its generated spec from its OWN `testDir` — the private
489
+ per-run directory outside the repository the spec was written into,
490
+ which the consumer's own configuration can never collect — and
491
+ depends on the FULL upstream prerequisite closure the trusted CLI
492
+ classified, so the runner's own scheduler runs every prerequisite,
493
+ then the controller, then any body.
494
+ * - A PREREQUISITE keeps its captured edges exactly as they were. Its
495
+ rows are the native cases that must execute genuinely and exactly
496
+ once, and re-ordering them would change what the run proves.
497
+ * - Every other project gets the controller as its FIRST dependency,
498
+ followed by its own captured edges in their original emitted order.
499
+ Placement is not an ordering statement — the runner's phase scheduler
500
+ is topological (`runner/tasks.js`: a project joins the earliest phase
501
+ in which every dependency is already processed), so a body runs after
502
+ the controller either way. Placement IS an environment-merge
503
+ statement: a project's extra environment is the union over
504
+ `project.deps` in emitted order (`tasks.js:341-347`), later entries
505
+ winning, so where the controller lands decides what a body starts
506
+ with. FIRST is the contract's placement, emitted explicitly rather
507
+ than by inserting into a sorted array (a sort would move the
508
+ controller behind any prerequisite that sorts before it);
509
+ `trusted-config.ts` re-asserts it when it emits the final list. Whether
510
+ FIRST or LAST is what the environment projection actually needs is
511
+ under live measurement by the native environment probe; this is the
512
+ contract's ordering until that measurement says otherwise.
513
+ * @param control: the armed controller (its project name, dir and spec).
514
+ * @param scopes: the planned project scopes, unchanged in every other way.
515
+ * @param prerequisiteProjects: the CLI's upstream-closure classification.
516
+ *
517
+ * @returns
518
+ * ProjectScope[]: the scopes to synthesize — the planned scopes in
519
+ * place, plus the controller appended.
520
+ */
521
+ export declare function freezeProjectScopes(control: FreezeControl, scopes: readonly ProjectScope[], prerequisiteProjects: readonly string[]): ProjectScope[];
522
+ //# sourceMappingURL=prepare-barrier.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prepare-barrier.d.ts","sourceRoot":"","sources":["../../src/discovery/prepare-barrier.ts"],"names":[],"mappings":"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"}