@gate-forge/pack-playwright 0.1.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 (140) hide show
  1. package/LICENSE +202 -0
  2. package/bin/gateforge-witness.js +40 -0
  3. package/dist/attestation/proxy.d.ts +40 -0
  4. package/dist/attestation/proxy.d.ts.map +1 -0
  5. package/dist/attestation/proxy.js +78 -0
  6. package/dist/attestation/proxy.js.map +1 -0
  7. package/dist/constants.d.ts +130 -0
  8. package/dist/constants.d.ts.map +1 -0
  9. package/dist/constants.js +138 -0
  10. package/dist/constants.js.map +1 -0
  11. package/dist/discovery/adapters.d.ts +167 -0
  12. package/dist/discovery/adapters.d.ts.map +1 -0
  13. package/dist/discovery/adapters.js +276 -0
  14. package/dist/discovery/adapters.js.map +1 -0
  15. package/dist/discovery/discover.d.ts +57 -0
  16. package/dist/discovery/discover.d.ts.map +1 -0
  17. package/dist/discovery/discover.js +544 -0
  18. package/dist/discovery/discover.js.map +1 -0
  19. package/dist/discovery/index.d.ts +15 -0
  20. package/dist/discovery/index.d.ts.map +1 -0
  21. package/dist/discovery/index.js +15 -0
  22. package/dist/discovery/index.js.map +1 -0
  23. package/dist/discovery/inference.d.ts +63 -0
  24. package/dist/discovery/inference.d.ts.map +1 -0
  25. package/dist/discovery/inference.js +173 -0
  26. package/dist/discovery/inference.js.map +1 -0
  27. package/dist/discovery/pytest-adapter.d.ts +205 -0
  28. package/dist/discovery/pytest-adapter.d.ts.map +1 -0
  29. package/dist/discovery/pytest-adapter.js +548 -0
  30. package/dist/discovery/pytest-adapter.js.map +1 -0
  31. package/dist/discovery/reconcile.d.ts +106 -0
  32. package/dist/discovery/reconcile.d.ts.map +1 -0
  33. package/dist/discovery/reconcile.js +268 -0
  34. package/dist/discovery/reconcile.js.map +1 -0
  35. package/dist/discovery/runner-env.d.ts +80 -0
  36. package/dist/discovery/runner-env.d.ts.map +1 -0
  37. package/dist/discovery/runner-env.js +139 -0
  38. package/dist/discovery/runner-env.js.map +1 -0
  39. package/dist/discovery/static-discovery.d.ts +121 -0
  40. package/dist/discovery/static-discovery.d.ts.map +1 -0
  41. package/dist/discovery/static-discovery.js +1028 -0
  42. package/dist/discovery/static-discovery.js.map +1 -0
  43. package/dist/discovery/supervised-run.d.ts +110 -0
  44. package/dist/discovery/supervised-run.d.ts.map +1 -0
  45. package/dist/discovery/supervised-run.js +328 -0
  46. package/dist/discovery/supervised-run.js.map +1 -0
  47. package/dist/discovery/trusted-config.d.ts +103 -0
  48. package/dist/discovery/trusted-config.d.ts.map +1 -0
  49. package/dist/discovery/trusted-config.js +117 -0
  50. package/dist/discovery/trusted-config.js.map +1 -0
  51. package/dist/fixture/evidence.d.ts +191 -0
  52. package/dist/fixture/evidence.d.ts.map +1 -0
  53. package/dist/fixture/evidence.js +366 -0
  54. package/dist/fixture/evidence.js.map +1 -0
  55. package/dist/fixture/fixture.d.ts +37 -0
  56. package/dist/fixture/fixture.d.ts.map +1 -0
  57. package/dist/fixture/fixture.js +38 -0
  58. package/dist/fixture/fixture.js.map +1 -0
  59. package/dist/fixture/witness-client.d.ts +164 -0
  60. package/dist/fixture/witness-client.d.ts.map +1 -0
  61. package/dist/fixture/witness-client.js +253 -0
  62. package/dist/fixture/witness-client.js.map +1 -0
  63. package/dist/index.d.ts +64 -0
  64. package/dist/index.d.ts.map +1 -0
  65. package/dist/index.js +55 -0
  66. package/dist/index.js.map +1 -0
  67. package/dist/json.d.ts +16 -0
  68. package/dist/json.d.ts.map +1 -0
  69. package/dist/json.js +21 -0
  70. package/dist/json.js.map +1 -0
  71. package/dist/reporter/ledger.d.ts +105 -0
  72. package/dist/reporter/ledger.d.ts.map +1 -0
  73. package/dist/reporter/ledger.js +197 -0
  74. package/dist/reporter/ledger.js.map +1 -0
  75. package/dist/reporter/reporter.cjs +105 -0
  76. package/dist/reporter/reporter.cjs.map +1 -0
  77. package/dist/reporter/reporter.d.cts +35 -0
  78. package/dist/reporter/reporter.d.cts.map +1 -0
  79. package/dist/reporter/reporter.d.ts +167 -0
  80. package/dist/reporter/reporter.d.ts.map +1 -0
  81. package/dist/reporter/reporter.js +673 -0
  82. package/dist/reporter/reporter.js.map +1 -0
  83. package/dist/setup.d.ts +49 -0
  84. package/dist/setup.d.ts.map +1 -0
  85. package/dist/setup.js +167 -0
  86. package/dist/setup.js.map +1 -0
  87. package/dist/supervisor/client.d.ts +73 -0
  88. package/dist/supervisor/client.d.ts.map +1 -0
  89. package/dist/supervisor/client.js +164 -0
  90. package/dist/supervisor/client.js.map +1 -0
  91. package/dist/supervisor/drain.d.ts +45 -0
  92. package/dist/supervisor/drain.d.ts.map +1 -0
  93. package/dist/supervisor/drain.js +235 -0
  94. package/dist/supervisor/drain.js.map +1 -0
  95. package/dist/supervisor/index.d.ts +16 -0
  96. package/dist/supervisor/index.d.ts.map +1 -0
  97. package/dist/supervisor/index.js +13 -0
  98. package/dist/supervisor/index.js.map +1 -0
  99. package/dist/supervisor/spool.d.ts +137 -0
  100. package/dist/supervisor/spool.d.ts.map +1 -0
  101. package/dist/supervisor/spool.js +263 -0
  102. package/dist/supervisor/spool.js.map +1 -0
  103. package/dist/surface.d.ts +134 -0
  104. package/dist/surface.d.ts.map +1 -0
  105. package/dist/surface.js +139 -0
  106. package/dist/surface.js.map +1 -0
  107. package/dist/witness/adapter-registry.d.ts +38 -0
  108. package/dist/witness/adapter-registry.d.ts.map +1 -0
  109. package/dist/witness/adapter-registry.js +158 -0
  110. package/dist/witness/adapter-registry.js.map +1 -0
  111. package/dist/witness/bin.d.ts +21 -0
  112. package/dist/witness/bin.d.ts.map +1 -0
  113. package/dist/witness/bin.js +172 -0
  114. package/dist/witness/bin.js.map +1 -0
  115. package/dist/witness/browser.d.ts +173 -0
  116. package/dist/witness/browser.d.ts.map +1 -0
  117. package/dist/witness/browser.js +580 -0
  118. package/dist/witness/browser.js.map +1 -0
  119. package/dist/witness/classifications.d.ts +42 -0
  120. package/dist/witness/classifications.d.ts.map +1 -0
  121. package/dist/witness/classifications.js +87 -0
  122. package/dist/witness/classifications.js.map +1 -0
  123. package/dist/witness/env-attestation.d.ts +98 -0
  124. package/dist/witness/env-attestation.d.ts.map +1 -0
  125. package/dist/witness/env-attestation.js +202 -0
  126. package/dist/witness/env-attestation.js.map +1 -0
  127. package/dist/witness/loopback-pins.d.ts +79 -0
  128. package/dist/witness/loopback-pins.d.ts.map +1 -0
  129. package/dist/witness/loopback-pins.js +244 -0
  130. package/dist/witness/loopback-pins.js.map +1 -0
  131. package/dist/witness/server.d.ts +34 -0
  132. package/dist/witness/server.d.ts.map +1 -0
  133. package/dist/witness/server.js +2539 -0
  134. package/dist/witness/server.js.map +1 -0
  135. package/dist/witness/types.d.ts +643 -0
  136. package/dist/witness/types.d.ts.map +1 -0
  137. package/dist/witness/types.js +2 -0
  138. package/dist/witness/types.js.map +1 -0
  139. package/package.json +64 -0
  140. package/python/gateforge_persistence_intents.py +100 -0
@@ -0,0 +1,158 @@
1
+ /**
2
+ * Adapter loading + registry (pin #8, plan §5.4).
3
+ *
4
+ * Reviewed evidence adapters load from `.gateforge/adapters/<name>.mjs`
5
+ * at WITNESS START (engine-side — the test process never imports them).
6
+ * Default export contract:
7
+ *
8
+ * ```js
9
+ * export default {
10
+ * read: async (ctx, id) => body | null, // GET-only; ctx.get(path) is the transport
11
+ * normalize: (body) => ({ entityId, fields }), // stamped from the RESPONSE, never caller args
12
+ * deletion: 'hard' | 'archive',
13
+ * environmentFingerprint: '…', // must match the target's marker header
14
+ * baseUrl: 'http://…', // optional override of the witness adapter base
15
+ * probeServer: async (ctx, subject) => ({ found, fields }), // optional: the
16
+ * // SERVER-WITNESSED persistence channel probe — executed
17
+ * // ONLY in this trusted witness process
18
+ * };
19
+ * ```
20
+ *
21
+ * The registry loads fail-closed: a missing/invalid module, a missing
22
+ * `read`/`normalize`/`deletion`/`environmentFingerprint`, an unknown
23
+ * deletion value, or a duplicate name aborts witness startup with an
24
+ * actionable diagnostic naming the file. The registry is frozen after
25
+ * load — there is no registration path a test could reach (invariant 6,
26
+ * GF-11 "registration path does not exist").
27
+ */
28
+ import { readdirSync } from 'node:fs';
29
+ import { join } from 'node:path';
30
+ import { pathToFileURL } from 'node:url';
31
+ /**
32
+ * Loads every `.mjs` adapter in `dir` into a frozen registry.
33
+ *
34
+ * Args:
35
+ * dir: the configured adapters directory (absolute).
36
+ *
37
+ * Returns:
38
+ * Map<string, EvidenceAdapter>: keyed by the file basename sans `.mjs`.
39
+ *
40
+ * Throws:
41
+ * AdapterRegistryError: fail-closed load problems — unreadable dir,
42
+ * unimportable module, or a module missing any contract member.
43
+ */
44
+ export async function loadAdapters(dir) {
45
+ const registry = new Map();
46
+ let entries;
47
+ try {
48
+ entries = readdirSync(dir);
49
+ }
50
+ catch (error) {
51
+ if (error.code === 'ENOENT') {
52
+ // No adapters directory at all: the registry stays empty; the
53
+ // witness then answers 400 for every persistence request (a run
54
+ // with persistence obligations and no adapters is misconfigured).
55
+ return registry;
56
+ }
57
+ throw new AdapterRegistryError(`cannot read adapters directory '${dir}': ${error.message}`);
58
+ }
59
+ for (const entry of entries.sort()) {
60
+ if (!entry.endsWith('.mjs'))
61
+ continue;
62
+ const name = entry.slice(0, -'.mjs'.length);
63
+ if (registry.has(name)) {
64
+ throw new AdapterRegistryError(`duplicate adapter '${name}' (multiple '${entry}' files is a config error)`);
65
+ }
66
+ const module = await importAdapter(dir, entry, name);
67
+ const adapter = validateAdapter(module, name);
68
+ registry.set(name, adapter);
69
+ }
70
+ return Object.freeze(registry);
71
+ }
72
+ /** Imports one adapter module; import errors carry an actionable message. */
73
+ async function importAdapter(dir, entry, name) {
74
+ try {
75
+ const loaded = (await import(pathToFileURL(join(dir, entry)).href));
76
+ return loaded.default;
77
+ }
78
+ catch (error) {
79
+ throw new AdapterRegistryError(`adapter '${name}' (${join(dir, entry)}) could not be imported: ` +
80
+ `${error instanceof Error ? error.message : String(error)}`);
81
+ }
82
+ }
83
+ /**
84
+ * Validates one adapter module against the pin-#8 contract.
85
+ *
86
+ * Args:
87
+ * module: the default export of the adapter file.
88
+ * name: adapter name, used in diagnostics.
89
+ *
90
+ * Returns:
91
+ * EvidenceAdapter: the validated adapter.
92
+ *
93
+ * Throws:
94
+ * AdapterRegistryError: when any required member is missing or shaped
95
+ * wrong. Optional `baseUrl` (a string) overrides the witness's
96
+ * configured adapter base for this adapter.
97
+ */
98
+ export function validateAdapter(module, name) {
99
+ if (typeof module !== 'object' || module === null) {
100
+ throw new AdapterRegistryError(`adapter '${name}' must default-export an object {read, normalize, deletion, environmentFingerprint}`);
101
+ }
102
+ const adapter = module;
103
+ const problems = [];
104
+ if (typeof adapter['read'] !== 'function')
105
+ problems.push('read must be an async function (ctx, id)');
106
+ if (typeof adapter['normalize'] !== 'function')
107
+ problems.push('normalize must be a function (body) => {entityId, fields}');
108
+ if (adapter['deletion'] !== 'hard' && adapter['deletion'] !== 'archive') {
109
+ problems.push("deletion must be 'hard' or 'archive'");
110
+ }
111
+ if (typeof adapter['environmentFingerprint'] !== 'string') {
112
+ problems.push('environmentFingerprint must be a string');
113
+ }
114
+ if (adapter['baseUrl'] !== undefined &&
115
+ (typeof adapter['baseUrl'] !== 'string' || adapter['baseUrl'].length === 0)) {
116
+ problems.push('baseUrl must be a non-empty string when present');
117
+ }
118
+ if (adapter['list'] !== undefined && typeof adapter['list'] !== 'function') {
119
+ problems.push('list must be a function (ctx) => entity[] when present');
120
+ }
121
+ // Server probe (server-witnessed persistence channel): OPTIONAL — an
122
+ // adapter without it simply cannot serve the channel and every server
123
+ // intent for the resource resolves to a typed
124
+ // SERVER_PROBE_UNAVAILABLE failure. A PRESENT but malformed export is
125
+ // a contract violation caught here at load, fail-closed, not at
126
+ // intent time.
127
+ if (adapter['probeServer'] !== undefined && typeof adapter['probeServer'] !== 'function') {
128
+ problems.push('probeServer must be an async function (ctx, subject) => {found, fields} when present');
129
+ }
130
+ if (problems.length > 0) {
131
+ throw new AdapterRegistryError(`adapter '${name}' violates the adapter contract: ${problems.join('; ')}`);
132
+ }
133
+ return {
134
+ read: adapter['read'],
135
+ normalize: adapter['normalize'],
136
+ deletion: adapter['deletion'],
137
+ environmentFingerprint: adapter['environmentFingerprint'],
138
+ baseUrl: adapter['baseUrl'],
139
+ ...(adapter['list'] !== undefined
140
+ ? { list: adapter['list'] }
141
+ : {}),
142
+ ...(adapter['probeServer'] !== undefined
143
+ ? { probeServer: adapter['probeServer'] }
144
+ : {}),
145
+ };
146
+ }
147
+ /** Fail-closed adapter-loading error (witness startup aborts). */
148
+ export class AdapterRegistryError extends Error {
149
+ constructor(message) {
150
+ super(message);
151
+ this.name = 'AdapterRegistryError';
152
+ }
153
+ }
154
+ /** The transport the witness hands to adapter `read` calls (GET-only). */
155
+ export function makeAdapterContext(baseUrl, resourceId, get, headers) {
156
+ return Object.freeze({ baseUrl, resourceId, get, ...(headers ? { headers } : {}) });
157
+ }
158
+ //# sourceMappingURL=adapter-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter-registry.js","sourceRoot":"","sources":["../../src/witness/adapter-registry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import type { WitnessHandle } from './types.js';
2
+ /** One-line usage (the header comment above is the long form). */
3
+ export declare const WITNESS_BIN_USAGE: string;
4
+ /**
5
+ * Reads env + argv and starts the witness.
6
+ *
7
+ * Args:
8
+ * argv: CLI flags (see the module header; `--help` prints usage and
9
+ * returns a never-started handle).
10
+ * env: process environment.
11
+ *
12
+ * Returns:
13
+ * WitnessHandle once listening (or a handle with an empty `url` for
14
+ * `--help`; the wrapper skips its URL banner in that case).
15
+ *
16
+ * Throws:
17
+ * WitnessStartupError / AttestationError / AdapterRegistryError:
18
+ * fail-closed startup problems (exit 2 via the wrapper).
19
+ */
20
+ export declare function main(argv: readonly string[], env: NodeJS.ProcessEnv): Promise<WitnessHandle>;
21
+ //# sourceMappingURL=bin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../../src/witness/bin.ts"],"names":[],"mappings":"AA0DA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,kEAAkE;AAClE,eAAO,MAAM,iBAAiB,QAKK,CAAC;AAkFpC;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,IAAI,CACxB,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,GAAG,EAAE,MAAM,CAAC,UAAU,GACrB,OAAO,CAAC,aAAa,CAAC,CAiCxB"}
@@ -0,0 +1,172 @@
1
+ /**
2
+ * Witness process entry (`gateforge-witness`): derives configuration
3
+ * from CLI flags and the environment and starts the loopback witness
4
+ * service.
5
+ *
6
+ * Usage (every flag has an env fallback; the flag wins when both are
7
+ * given):
8
+ *
9
+ * gateforge-witness [--help]
10
+ * [--proxy-target <url>] start the observation proxy against
11
+ * this loopback base URL (ADR 0004 D7)
12
+ * [--mount-path <prefix>] browser-facing mount prefix the proxy
13
+ * strips before forwarding AND recording
14
+ * (e.g. /api; requires --proxy-target)
15
+ * [--state-dir <dir>] manifest append at shutdown
16
+ * [--classifications <path>] classifications YAML input
17
+ * [--adapters-dir <dir>] reviewed adapters (default .gateforge/adapters)
18
+ * [--target-base-url <url>] attestation subject (GF-10, loopback)
19
+ * [--target-fingerprint <m>] expected marker (GF-13)
20
+ * [--adapter-base-url <url>] default adapter read base
21
+ *
22
+ * Env surface:
23
+ * GATEFORGE_RUN_ID, GATEFORGE_RUN_TOKEN (required; CLI contract)
24
+ * GATEFORGE_PROXY_TARGET, GATEFORGE_MOUNT_PATH (observation proxy)
25
+ * GATEFORGE_STATE_DIR (manifest append at shutdown)
26
+ * GATEFORGE_ADAPTERS_DIR (default .gateforge/adapters)
27
+ * GATEFORGE_CLASSIFICATIONS (classifications YAML path)
28
+ * GATEFORGE_TARGET_BASE_URL (attestation subject, GF-10)
29
+ * GATEFORGE_TARGET_FINGERPRINT (expected marker, GF-13)
30
+ * GATEFORGE_ADAPTER_BASE_URL (default adapter read base)
31
+ * GATEFORGE_WITNESS_VERIFIER_KEY (attestation verifier key)
32
+ *
33
+ * SECRETS NEVER TRAVEL ON ARGV (a process's cmdline is world-readable
34
+ * via /proc — the same rule `gateforge test-gates` applies): the run
35
+ * id/token are env-only (set by 'gateforge test-gates'), and the
36
+ * verifier key is read from GATEFORGE_WITNESS_VERIFIER_KEY only. With a
37
+ * verifier key the witness serves the MAC-attested ledger surface;
38
+ * without one it stays unauthenticated and downstream evaluation fails
39
+ * closed.
40
+ *
41
+ * The wrapper prints `GATEFORGE_WITNESS_URL=<url>` once listening — and
42
+ * `GATEFORGE_WITNESS_PROXY_URL=<url>` when an observation proxy is
43
+ * active; the process serves until SIGTERM/SIGINT.
44
+ */
45
+ import { startWitness, WitnessStartupError } from './server.js';
46
+ import { ENV_ADAPTER_BASE_URL, ENV_ADAPTERS_DIR, ENV_CLASSIFICATIONS, ENV_MOUNT_PATH, ENV_PROXY_TARGET, ENV_RUN_ID, ENV_RUN_TOKEN, ENV_STATE_DIR, ENV_TARGET_BASE_URL, ENV_TARGET_FINGERPRINT, ENV_WITNESS_VERIFIER_KEY, } from '../constants.js';
47
+ /** One-line usage (the header comment above is the long form). */
48
+ export const WITNESS_BIN_USAGE = 'usage: gateforge-witness [--proxy-target <url>] [--mount-path <prefix>] ' +
49
+ '[--state-dir <dir>] [--classifications <path>] [--adapters-dir <dir>] ' +
50
+ '[--target-base-url <url>] [--target-fingerprint <marker>] [--adapter-base-url <url>] ' +
51
+ '(run id/token via GATEFORGE_RUN_ID/GATEFORGE_RUN_TOKEN; verifier key via ' +
52
+ 'GATEFORGE_WITNESS_VERIFIER_KEY)';
53
+ /** Flags this bin accepts (values; `--help` is handled separately). */
54
+ const VALUE_FLAGS = new Set([
55
+ 'proxy-target',
56
+ 'mount-path',
57
+ 'state-dir',
58
+ 'classifications',
59
+ 'adapters-dir',
60
+ 'target-base-url',
61
+ 'target-fingerprint',
62
+ 'adapter-base-url',
63
+ 'adapter-read-authorization',
64
+ ]);
65
+ /**
66
+ * Parses the bin argv (`--flag value` and `--flag=value` shapes).
67
+ * Unknown flags and missing values fail closed with the usage line —
68
+ * a mis-wired harness must never silently start a half-configured
69
+ * witness.
70
+ *
71
+ * Args:
72
+ * argv: arguments after node/script.
73
+ *
74
+ * Returns:
75
+ * WitnessBinFlags: parsed flag values.
76
+ *
77
+ * Throws:
78
+ * WitnessStartupError: on any malformed argv.
79
+ */
80
+ function parseFlags(argv) {
81
+ const values = new Map();
82
+ for (let index = 0; index < argv.length; index += 1) {
83
+ const token = argv[index] ?? '';
84
+ if (!token.startsWith('--')) {
85
+ throw new WitnessStartupError(`unexpected argument '${token}'\n${WITNESS_BIN_USAGE}`);
86
+ }
87
+ const body = token.slice(2);
88
+ const eq = body.indexOf('=');
89
+ const name = eq >= 0 ? body.slice(0, eq) : body;
90
+ if (name.length === 0) {
91
+ throw new WitnessStartupError(`invalid flag '${token}'\n${WITNESS_BIN_USAGE}`);
92
+ }
93
+ if (name === 'help') {
94
+ continue; // handled by the caller before parsing matters
95
+ }
96
+ if (!VALUE_FLAGS.has(name)) {
97
+ throw new WitnessStartupError(`unknown flag '--${name}'\n${WITNESS_BIN_USAGE}`);
98
+ }
99
+ let value = eq >= 0 ? body.slice(eq + 1) : undefined;
100
+ if (value === undefined) {
101
+ const next = argv[index + 1];
102
+ if (next === undefined || next.startsWith('--')) {
103
+ throw new WitnessStartupError(`flag '--${name}' requires a value\n${WITNESS_BIN_USAGE}`);
104
+ }
105
+ value = next;
106
+ index += 1;
107
+ }
108
+ if (values.has(name)) {
109
+ throw new WitnessStartupError(`flag '--${name}' may only be given once\n${WITNESS_BIN_USAGE}`);
110
+ }
111
+ values.set(name, value);
112
+ }
113
+ return { values };
114
+ }
115
+ /** Flag value or its env fallback (undefined when neither is set). */
116
+ function flagOrEnv(flags, name, envValue) {
117
+ const fromFlags = flags.values.get(name);
118
+ if (fromFlags !== undefined && fromFlags !== '')
119
+ return fromFlags;
120
+ if (envValue !== undefined && envValue !== '')
121
+ return envValue;
122
+ return undefined;
123
+ }
124
+ /**
125
+ * Reads env + argv and starts the witness.
126
+ *
127
+ * Args:
128
+ * argv: CLI flags (see the module header; `--help` prints usage and
129
+ * returns a never-started handle).
130
+ * env: process environment.
131
+ *
132
+ * Returns:
133
+ * WitnessHandle once listening (or a handle with an empty `url` for
134
+ * `--help`; the wrapper skips its URL banner in that case).
135
+ *
136
+ * Throws:
137
+ * WitnessStartupError / AttestationError / AdapterRegistryError:
138
+ * fail-closed startup problems (exit 2 via the wrapper).
139
+ */
140
+ export async function main(argv, env) {
141
+ if (argv.includes('--help') || argv.includes('-h')) {
142
+ process.stdout.write(`${WITNESS_BIN_USAGE}\n`);
143
+ return Object.freeze({ url: '', proxyUrl: null, stop: async () => { } });
144
+ }
145
+ const flags = parseFlags(argv);
146
+ const runId = env[ENV_RUN_ID];
147
+ const token = env[ENV_RUN_TOKEN];
148
+ if (runId === undefined || runId === '') {
149
+ throw new WitnessStartupError(`${ENV_RUN_ID} is required (set by 'gateforge test-gates')`);
150
+ }
151
+ if (token === undefined || token === '') {
152
+ throw new WitnessStartupError(`${ENV_RUN_TOKEN} is required (set by 'gateforge test-gates')`);
153
+ }
154
+ // Environment-only, deliberately absent from argv (world-readable
155
+ // /proc cmdline): the suite must never see the verifier key either way.
156
+ const verifierKey = env[ENV_WITNESS_VERIFIER_KEY] ?? null;
157
+ return startWitness({
158
+ runId,
159
+ token,
160
+ proxyTarget: flagOrEnv(flags, 'proxy-target', env[ENV_PROXY_TARGET]),
161
+ mountPath: flagOrEnv(flags, 'mount-path', env[ENV_MOUNT_PATH]),
162
+ stateDir: flagOrEnv(flags, 'state-dir', env[ENV_STATE_DIR]),
163
+ classificationsPath: flagOrEnv(flags, 'classifications', env[ENV_CLASSIFICATIONS]),
164
+ adaptersDir: flagOrEnv(flags, 'adapters-dir', env[ENV_ADAPTERS_DIR] ?? '.gateforge/adapters'),
165
+ targetBaseUrl: flagOrEnv(flags, 'target-base-url', env[ENV_TARGET_BASE_URL]),
166
+ targetFingerprint: flagOrEnv(flags, 'target-fingerprint', env[ENV_TARGET_FINGERPRINT]),
167
+ adapterBaseUrl: flagOrEnv(flags, 'adapter-base-url', env[ENV_ADAPTER_BASE_URL]),
168
+ adapterReadAuthorization: flagOrEnv(flags, 'adapter-read-authorization', env['GATEFORGE_ADAPTER_READ_AUTHORIZATION']) ?? null,
169
+ verifierKey,
170
+ });
171
+ }
172
+ //# sourceMappingURL=bin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.js","sourceRoot":"","sources":["../../src/witness/bin.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,173 @@
1
+ /**
2
+ * The engine-owned browser (plan Phase 1 item 4): Chromium contexts the
3
+ * WITNESS process creates and drives itself — one isolated context per
4
+ * supervisor-opened test session, closed when the session seals.
5
+ *
6
+ * Test code NEVER touches these pages: the worker holds no handle, no
7
+ * URL, and no capability over them. The engine executes the constrained
8
+ * surface operations (create/read/update/archive) with the
9
+ * consumer-declared locators, and observes each step itself:
10
+ * - the rendered control it clicked and the values it typed;
11
+ * - the actual application request the action caused (captured from the
12
+ * engine page's own network, app-origin only);
13
+ * - the resulting navigation and the rendered row/form it read back.
14
+ *
15
+ * Forgery resistance (why this channel is proof):
16
+ * - fabricated DOM (`page.evaluate` in the worker page) is irrelevant:
17
+ * the engine reads its OWN page;
18
+ * - mocked responses (`page.route` in the worker) are irrelevant: the
19
+ * worker cannot route the engine's traffic;
20
+ * - direct API/Node mutations bypass the engine page entirely: no
21
+ * engine action runs, so no engine-observed action/visible records
22
+ * exist for them — invented suite-submitted records never satisfy;
23
+ * - HTTP-200-while-error: the engine asserts the rendered status
24
+ * itself (created/archived values) AND captures the app response
25
+ * status — a displayed error fails the action fail-closed.
26
+ *
27
+ * Surface selectors are LOCATORS, never proof: a lying descriptor only
28
+ * makes the engine fail to find elements (fail closed).
29
+ */
30
+ import { type Browser, type Page } from 'playwright';
31
+ import { type SurfaceDescriptor } from '../surface.js';
32
+ /** The UI operations the engine can perform (constrained subset). */
33
+ export type EngineOperation = 'create' | 'read' | 'update' | 'delete';
34
+ /** One app-origin exchange the engine captured during an action. */
35
+ export interface EngineCapturedExchange {
36
+ /** Uppercase method (GET, POST, ...). */
37
+ method: string;
38
+ /** Canonical observed path (query/fragment stripped). */
39
+ path: string;
40
+ /** Response status the app answered. */
41
+ status: number;
42
+ /** Response body bytes (bounded snapshot for hashing). */
43
+ body: Buffer;
44
+ }
45
+ /** What the engine observed performing one action. */
46
+ export interface EngineActionObservation {
47
+ /** Entity id OBSERVED from the rendered list (never declared). */
48
+ entityId: string;
49
+ /** The exact input values the engine typed (exact-value echo source). */
50
+ enteredFields: Record<string, string>;
51
+ /** The rendered fields the engine read back after the action. */
52
+ renderedFields: Record<string, string>;
53
+ /** App-origin exchanges captured inside the action window. */
54
+ exchanges: EngineCapturedExchange[];
55
+ /** Engine-side pre-observation marker (filled by the witness layer). */
56
+ preObservationId?: string;
57
+ }
58
+ /** Fail-closed engine browser error (surfaced as 409/503 downstream). */
59
+ export declare class EngineBrowserError extends Error {
60
+ constructor(message: string);
61
+ }
62
+ /** The browser launcher the engine drives (default: pinned Chromium). */
63
+ export interface EngineBrowserLauncher {
64
+ launch(options?: Record<string, unknown>): Promise<Browser>;
65
+ }
66
+ /**
67
+ * Owns the engine Chromium instance and its per-session contexts.
68
+ *
69
+ * Args:
70
+ * launcher: browser launcher (default: the pinned Chromium). Tests
71
+ * inject a failing launcher to prove the fail-closed path; the
72
+ * driving and observation below stay engine code regardless of
73
+ * which executable launches.
74
+ */
75
+ export declare class EngineBrowserManager {
76
+ private readonly launcher;
77
+ private browser;
78
+ private launching;
79
+ private readonly sessions;
80
+ /**
81
+ * Pinned `--host-resolver-rules` value binding every attested hostname
82
+ * to its startup-approved loopback IPs. Set once at witness startup
83
+ * (before any launch); the browser is then incapable of resolving
84
+ * those names anywhere but loopback, regardless of later DNS changes.
85
+ */
86
+ private dnsPinRules;
87
+ constructor(launcher?: EngineBrowserLauncher);
88
+ /**
89
+ * Installs the DNS pin rules for the next (first) launch.
90
+ *
91
+ * Args:
92
+ * rules: the `--host-resolver-rules` value, or null when nothing is
93
+ * pinned (plain launch, previous behavior).
94
+ *
95
+ * Throws:
96
+ * EngineBrowserError: when the browser already launched — pins must
97
+ * precede every navigation (fail closed, never silently unbound).
98
+ */
99
+ setDnsPinRules(rules: string | null): void;
100
+ /**
101
+ * Returns the engine page for one session, creating the isolated
102
+ * context on first use.
103
+ *
104
+ * Args:
105
+ * sessionId: the supervisor-opened session the context belongs to.
106
+ *
107
+ * Returns:
108
+ * Promise<Page>: the session's engine-owned page.
109
+ *
110
+ * Throws:
111
+ * EngineBrowserError: when Chromium cannot launch (fail closed —
112
+ * the capability is honestly unavailable at runtime).
113
+ */
114
+ pageFor(sessionId: string): Promise<Page>;
115
+ /**
116
+ * Closes and forgets one session's engine context (session seal).
117
+ * Late engine calls for the session then recreate nothing — callers
118
+ * must refuse sealed sessions before driving (they do: every browser
119
+ * endpoint requires an OPEN session first).
120
+ *
121
+ * Args:
122
+ * sessionId: the sealed session.
123
+ */
124
+ closeSession(sessionId: string): Promise<void>;
125
+ /** Closes every engine context and the browser (witness stop). */
126
+ closeAll(): Promise<void>;
127
+ /** Lazy Chromium launch (single flight; fail closed with the cause). */
128
+ private ensureBrowser;
129
+ }
130
+ /**
131
+ * Drives one constrained surface operation on the engine page and
132
+ * observes every step itself.
133
+ *
134
+ * Args:
135
+ * page: the session's engine-owned page.
136
+ * appBase: loopback app base the engine navigates (validated upstream).
137
+ * surface: the validated consumer descriptor (locators only).
138
+ * operation: the constrained operation to perform.
139
+ * input: entered fields (create/update) and/or the target entity id.
140
+ *
141
+ * Returns:
142
+ * Promise<EngineActionObservation>: the engine's own observation —
143
+ * observed entity id, entered + rendered fields, captured exchanges.
144
+ *
145
+ * Throws:
146
+ * EngineBrowserError: fail-closed on every untrusted outcome —
147
+ * missing rows, ambiguous creation, wrong rendered status, no
148
+ * application request, or an application error status.
149
+ */
150
+ export declare function driveEngineAction(page: Page, appBase: string, surface: SurfaceDescriptor, operation: EngineOperation, input: {
151
+ fields?: Record<string, string>;
152
+ entityId?: string;
153
+ }): Promise<EngineActionObservation>;
154
+ /**
155
+ * Re-reads the rendered result for one entity on the engine page
156
+ * (the `visible.confirm` counterpart): row read for mutations, form
157
+ * read for reads.
158
+ *
159
+ * Args:
160
+ * page: the session's engine-owned page.
161
+ * appBase: loopback app base.
162
+ * surface: the validated consumer descriptor.
163
+ * operation: the original action (decides row vs form readback).
164
+ * entityId: the engine-observed entity id.
165
+ *
166
+ * Returns:
167
+ * Promise<Record<string, string>>: the rendered fields.
168
+ *
169
+ * Throws:
170
+ * EngineBrowserError: when the UI no longer exposes the entity.
171
+ */
172
+ export declare function readEngineVisible(page: Page, appBase: string, surface: SurfaceDescriptor, operation: EngineOperation, entityId: string): Promise<Record<string, string>>;
173
+ //# sourceMappingURL=browser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../../src/witness/browser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,OAAO,EAAY,KAAK,OAAO,EAAqC,KAAK,IAAI,EAAiB,MAAM,YAAY,CAAC;AACjH,OAAO,EAGL,KAAK,iBAAiB,EACvB,MAAM,eAAe,CAAC;AAEvB,qEAAqE;AACrE,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAEtE,oEAAoE;AACpE,MAAM,WAAW,sBAAsB;IACrC,yCAAyC;IACzC,MAAM,EAAE,MAAM,CAAC;IACf,yDAAyD;IACzD,IAAI,EAAE,MAAM,CAAC;IACb,wCAAwC;IACxC,MAAM,EAAE,MAAM,CAAC;IACf,0DAA0D;IAC1D,IAAI,EAAE,MAAM,CAAC;CACd;AAED,sDAAsD;AACtD,MAAM,WAAW,uBAAuB;IACtC,kEAAkE;IAClE,QAAQ,EAAE,MAAM,CAAC;IACjB,yEAAyE;IACzE,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,iEAAiE;IACjE,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,8DAA8D;IAC9D,SAAS,EAAE,sBAAsB,EAAE,CAAC;IACpC,wEAAwE;IACxE,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,yEAAyE;AACzE,qBAAa,kBAAmB,SAAQ,KAAK;gBAC/B,OAAO,EAAE,MAAM;CAI5B;AAED,yEAAyE;AACzE,MAAM,WAAW,qBAAqB;IACpC,MAAM,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC7D;AAKD;;;;;;;;GAQG;AACH,qBAAa,oBAAoB;IAYnB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAXrC,OAAO,CAAC,OAAO,CAAwB;IACvC,OAAO,CAAC,SAAS,CAAiC;IAClD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA8D;IACvF;;;;;OAKG;IACH,OAAO,CAAC,WAAW,CAAuB;gBAEb,QAAQ,GAAE,qBAAgC;IAEvE;;;;;;;;;;OAUG;IACH,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAS1C;;;;;;;;;;;;;OAaG;IACG,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAU/C;;;;;;;;OAQG;IACG,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOpD,kEAAkE;IAC5D,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAU/B,wEAAwE;YAC1D,aAAa;CAuB5B;AAgND;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,iBAAiB,EAC1B,SAAS,EAAE,eAAe,EAC1B,KAAK,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GAC5D,OAAO,CAAC,uBAAuB,CAAC,CAWlC;AAkLD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,iBAAiB,EAC1B,SAAS,EAAE,eAAe,EAC1B,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAmBjC"}