@verax-ai/body 0.3.0 → 0.4.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/README.md +7 -2
- package/dist/approve-cli.d.ts +22 -1
- package/dist/approve-cli.js +209 -22
- package/dist/auth.d.ts +9 -1
- package/dist/auth.js +12 -2
- package/dist/body-log.d.ts +14 -0
- package/dist/body-log.js +61 -0
- package/dist/cli.d.ts +23 -1
- package/dist/cli.js +227 -94
- package/dist/config.d.ts +26 -0
- package/dist/config.js +47 -0
- package/dist/demo.d.ts +2 -0
- package/dist/demo.js +8 -2
- package/dist/desktop-parent.d.ts +19 -0
- package/dist/desktop-parent.js +44 -0
- package/dist/desktop.d.ts +140 -11
- package/dist/desktop.js +931 -103
- package/dist/doctor.d.ts +2 -0
- package/dist/doctor.js +94 -11
- package/dist/health-extras.d.ts +4 -0
- package/dist/health-extras.js +14 -0
- package/dist/init-local.d.ts +25 -1
- package/dist/init-local.js +151 -54
- package/dist/install.d.ts +745 -0
- package/dist/install.js +5738 -0
- package/dist/keys.d.ts +6 -0
- package/dist/keys.js +43 -20
- package/dist/main.js +11 -1
- package/dist/no-bypass-scan.js +3 -2
- package/dist/reconcile-cli.js +3 -1
- package/dist/server.d.ts +14 -1
- package/dist/server.js +125 -3
- package/dist/tools/audit.d.ts +5 -2
- package/dist/tools/audit.js +12 -2
- package/dist/tools/memory.js +41 -6
- package/dist/tools/message.js +38 -9
- package/dist/unlock.d.ts +5 -2
- package/dist/unlock.js +6 -1
- package/dist/verify-cli.js +135 -15
- package/dist/wiring.js +1 -1
- package/dist/witness.js +154 -24
- package/package.json +7 -3
package/dist/desktop.d.ts
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
import { type ChildProcess } from "node:child_process";
|
|
2
|
+
import { type Server } from "node:net";
|
|
3
|
+
/** One stderr line when this state has no enrolled operator. */
|
|
4
|
+
export declare const DESKTOP_PASSKEY_HINT = "the panel reads the ledger after a passkey sign-in; run verax operator enroll\n";
|
|
5
|
+
/**
|
|
6
|
+
* The credentials file is written only when an operator enrolls. Its presence
|
|
7
|
+
* is the whole answer; a missing file means the panel's audit doors will
|
|
8
|
+
* refuse the session that has no passkey.
|
|
9
|
+
*/
|
|
10
|
+
export declare function desktopPasskeyHint(stateDir: string): string | null;
|
|
1
11
|
export declare function resolveRepoRoot(): string;
|
|
2
12
|
export declare const DESKTOP_CLONE_ONLY = "verax desktop runs from a clone of github.com/verax-ai/verax; it is not in the npm package\n";
|
|
3
13
|
export declare function desktopCloneError(root: string): string | null;
|
|
@@ -16,10 +26,48 @@ export type DesktopOpts = {
|
|
|
16
26
|
* and reopening it showed the previous app, with no sign that it was stale.
|
|
17
27
|
*/
|
|
18
28
|
export declare function panelBuildNeeded(distIndex: string, sourceRoots: readonly string[]): boolean;
|
|
19
|
-
|
|
29
|
+
/** UNC share or a Win32 device path (`\\?\`, `\\.\`, `\\?\UNC\`, `//host`): all start with two separators. */
|
|
30
|
+
export declare function desktopStateUncOrDevice(stateDir: string): boolean;
|
|
31
|
+
export declare function parseDesktopArgs(argv: string[], platform?: NodeJS.Platform): DesktopOpts | {
|
|
20
32
|
error: string;
|
|
21
33
|
};
|
|
22
34
|
export declare function portOpen(port: number, host?: string): Promise<boolean>;
|
|
35
|
+
/**
|
|
36
|
+
* Bind 127.0.0.1 and [::1], then close both. True only when this process held
|
|
37
|
+
* 127.0.0.1 and [::1] was free or this host has no IPv6 loopback. A connect
|
|
38
|
+
* probe is not this: whoever is already listening would answer it.
|
|
39
|
+
*/
|
|
40
|
+
export declare function desktopPortFree(port: number): Promise<boolean>;
|
|
41
|
+
/** True when a socket can bind [::1]. False when the host has no IPv6 loopback. */
|
|
42
|
+
export declare function ipv6LoopbackAvailable(): Promise<boolean>;
|
|
43
|
+
/**
|
|
44
|
+
* Hold `[::1]:port` and pipe each accepted socket to `127.0.0.1:port`.
|
|
45
|
+
* `unsupported` means this host cannot bind the IPv6 loopback.
|
|
46
|
+
*/
|
|
47
|
+
export declare function forwardIpv6Loopback(port: number): Promise<{
|
|
48
|
+
ok: true;
|
|
49
|
+
server: Server;
|
|
50
|
+
} | {
|
|
51
|
+
ok: false;
|
|
52
|
+
reason: "busy" | "unsupported";
|
|
53
|
+
}>;
|
|
54
|
+
export declare function desktopPortBusyLine(name: DesktopChildName, port: number, ipv6?: boolean): string;
|
|
55
|
+
/** JWKS document the dev issuer rewrites under the state directory on every start. */
|
|
56
|
+
export declare function issuerJwksPinPath(stateDir: string): string;
|
|
57
|
+
/** Drop a file left by an earlier run. A missing file is the state we want. */
|
|
58
|
+
export declare function discardStaleFile(file: string): void;
|
|
59
|
+
/**
|
|
60
|
+
* The pin is the file the issuer just wrote. Compact JSON, or a throw when
|
|
61
|
+
* it is not a key set. Nothing is fetched.
|
|
62
|
+
*/
|
|
63
|
+
export declare function readIssuerJwksPin(stateDir: string): string;
|
|
64
|
+
export declare function issuerReadyLine(port: number): string;
|
|
65
|
+
export declare function bodyReadyLine(port: number): string;
|
|
66
|
+
export declare function panelReadyLine(port: number): string;
|
|
67
|
+
export declare function childStillAlive(child: {
|
|
68
|
+
exitCode: number | null;
|
|
69
|
+
signalCode: NodeJS.Signals | null;
|
|
70
|
+
}): boolean;
|
|
23
71
|
/** GET /healthz on the loopback port; true only for a 200. */
|
|
24
72
|
export declare function healthzUp(port: number): Promise<boolean>;
|
|
25
73
|
export type DesktopMode = {
|
|
@@ -30,26 +78,107 @@ export type DesktopMode = {
|
|
|
30
78
|
} | {
|
|
31
79
|
error: "desktop-body-locked";
|
|
32
80
|
pid: number;
|
|
81
|
+
lockPort: number | null;
|
|
33
82
|
};
|
|
83
|
+
/** Pid listening on 127.0.0.1:`port`, or null when the tool names nobody or more than one pid. */
|
|
84
|
+
export declare function loopbackListenPid(port: number, platform?: NodeJS.Platform): number | null;
|
|
34
85
|
/**
|
|
35
86
|
* One ledger, one body. The desktop used to build its own issuer and body on
|
|
36
87
|
* every open, which on a machine whose body starts at logon put the window on
|
|
37
88
|
* a second, empty ledger: the panel looked broken while the real decisions sat
|
|
38
|
-
* in the directory the lock names. So the lock is read first.
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
|
|
45
|
-
|
|
89
|
+
* in the directory the lock names. So the lock is read first. A live lock that
|
|
90
|
+
* records this port, whose pid is the listener on 127.0.0.1 there, is
|
|
91
|
+
* `attach`. 0.4.0 does not join that body: `runDesktop` stops before it
|
|
92
|
+
* claims a port or starts a child. A later release may join again, once that
|
|
93
|
+
* body is supervised. A 200 from /healthz is not the check. Any other live
|
|
94
|
+
* lock stops the desktop: `desktop-body-locked:<pid>:<port or unknown>`. A
|
|
95
|
+
* lock with no port is that stop until the body is started again. A dead or
|
|
96
|
+
* unreadable lock is left for `verax unlock`, which is only for a dead lock.
|
|
97
|
+
*/
|
|
98
|
+
export declare function desktopMode(stateDir: string, bodyPort: number, listenerPid?: (port: number) => number | null): Promise<DesktopMode>;
|
|
99
|
+
export type DesktopChildName = "issuer" | "body" | "panel";
|
|
100
|
+
export type SupervisedChild = {
|
|
101
|
+
name: DesktopChildName;
|
|
102
|
+
/** Registers the listener invoked when this child exits. May run it immediately if it already has. */
|
|
103
|
+
onExit: (listener: () => void) => void;
|
|
104
|
+
};
|
|
105
|
+
/**
|
|
106
|
+
* The first of the issuer, the body or the panel to exit stops the rest.
|
|
107
|
+
* A later exit does not stop again. `stillWatching` is false once this run
|
|
108
|
+
* is shutting down on purpose, so those exits are not a child failure.
|
|
109
|
+
*/
|
|
110
|
+
export declare function superviseDesktopChildren(children: readonly SupervisedChild[], stopAll: () => void, stillWatching?: () => boolean): Promise<DesktopChildName>;
|
|
111
|
+
export declare function desktopChildExitedLine(name: DesktopChildName): string;
|
|
112
|
+
export type DesktopSpawnName = DesktopChildName | "browser";
|
|
113
|
+
/**
|
|
114
|
+
* Stand-in for `process` so a test can emit SIGHUP, SIGBREAK, an uncaught
|
|
115
|
+
* exception, or `exit` without signalling this process. `platform` chooses
|
|
116
|
+
* SIGHUP (anything but win32) or SIGBREAK (win32).
|
|
117
|
+
*/
|
|
118
|
+
export type DesktopSignalHost = {
|
|
119
|
+
once: (event: string, listener: () => void) => void;
|
|
120
|
+
on: (event: string, listener: () => void) => void;
|
|
121
|
+
removeListener: (event: string, listener: () => void) => void;
|
|
122
|
+
exit: (code: number) => void;
|
|
123
|
+
platform?: NodeJS.Platform;
|
|
124
|
+
};
|
|
125
|
+
/** Test seam. Production leaves this unset and spawns the real children. */
|
|
126
|
+
export type DesktopHooks = {
|
|
127
|
+
spawn?: (name: DesktopSpawnName, cmd: string, args: string[], env: NodeJS.ProcessEnv, cwd: string) => ChildProcess;
|
|
128
|
+
/** Caps issuer, body, and panel readiness waits. The CLI uses the built-in budgets. */
|
|
129
|
+
readyMs?: number;
|
|
130
|
+
/** Replaces the listener-pid lookup. */
|
|
131
|
+
listenerPid?: (port: number) => number | null;
|
|
132
|
+
/** Replaces the Windows owner ACL call on the state directory and the browser profile. */
|
|
133
|
+
restrictOwner?: (dir: string) => void;
|
|
134
|
+
/** Replaces `process.platform` for the directory owner check. */
|
|
135
|
+
platform?: NodeJS.Platform;
|
|
136
|
+
/** Replaces the Windows owner-SID and invoking-SID lookup. */
|
|
137
|
+
windowsDirectoryOwner?: (dir: string) => {
|
|
138
|
+
ownerSid?: string;
|
|
139
|
+
invokingSid?: string;
|
|
140
|
+
};
|
|
141
|
+
/** Replaces the Windows DACL read. The text is the SDDL `windowsUserCanWrite` already judges. */
|
|
142
|
+
windowsDirectoryDacl?: (dir: string) => string;
|
|
143
|
+
/**
|
|
144
|
+
* Replaces the ancestor DACL read. When set, each ancestor is judged with
|
|
145
|
+
* `windowsUserCanWrite(..., { ancestor: true })`. When a leaf owner or leaf
|
|
146
|
+
* DACL hook is set and this is not, ancestors are not read from the machine.
|
|
147
|
+
*/
|
|
148
|
+
windowsAncestorDacl?: (dir: string) => string;
|
|
149
|
+
/** Replaces `killTree` for the children this run started. */
|
|
150
|
+
kill?: (pid: number | undefined) => void;
|
|
151
|
+
/** Called with the capped stdout/stderr kept for one child. */
|
|
152
|
+
childOutput?: (name: DesktopSpawnName, stored: string) => void;
|
|
153
|
+
/** Replaces `process` for stop handlers. Production uses this process. */
|
|
154
|
+
signals?: DesktopSignalHost;
|
|
155
|
+
};
|
|
156
|
+
/**
|
|
157
|
+
* The account SIDs in place of the `LA` / `LG` aliases, so the built-in
|
|
158
|
+
* Administrator's own entry compares equal to its SID (a GitHub Windows
|
|
159
|
+
* runner runs as that account). An alias with no SID given is left, and the
|
|
160
|
+
* judge treats it as someone else.
|
|
161
|
+
*/
|
|
162
|
+
export declare function expandLocalAccountAliases(sddl: string, sids: {
|
|
163
|
+
LA?: string;
|
|
164
|
+
LG?: string;
|
|
165
|
+
}): string;
|
|
166
|
+
/** Last bytes kept from a child so a long log cannot grow without a bound. */
|
|
167
|
+
export declare const DESKTOP_CHILD_OUTPUT_CAP: number;
|
|
168
|
+
/** Keep the tail. A ready line at the end of a large chunk stays inside the cap. */
|
|
169
|
+
export declare function rememberChildOutput(current: string, chunk: string, cap?: number): string;
|
|
170
|
+
/** Synchronous: `spawnSync` on Windows, `process.kill` elsewhere. An `exit` handler can call it. */
|
|
46
171
|
export declare function killTree(pid: number | undefined): void;
|
|
172
|
+
/** Comma-separated origins. An origin already listed is not added again. */
|
|
173
|
+
export declare function mergeAllowedOrigin(existing: string | undefined, origin: string): string;
|
|
47
174
|
/** The panel's redirect is its own origin, so the issuer has to be told which port
|
|
48
|
-
* this run put it on: the allow-list default only holds 5173 and 4173.
|
|
175
|
+
* this run put it on: the allow-list default only holds 5173 and 4173.
|
|
176
|
+
* The passkey ceremony runs on the issuer (`/authorize` and `/enroll`), so the
|
|
177
|
+
* RP ID and RP origins name that origin unless the operator already set them. */
|
|
49
178
|
export declare function issuerEnv(base: NodeJS.ProcessEnv, opts: {
|
|
50
179
|
stateDir: string;
|
|
51
180
|
issuerPort: number;
|
|
52
181
|
panelPort: number;
|
|
53
182
|
}, audience: string, issuerUrl: string): NodeJS.ProcessEnv;
|
|
54
|
-
export declare function runDesktop(opts: DesktopOpts, writeErr?: (s: string) => void): Promise<number>;
|
|
183
|
+
export declare function runDesktop(opts: DesktopOpts, writeErr?: (s: string) => void, hooks?: DesktopHooks): Promise<number>;
|
|
55
184
|
export declare function desktopMain(argv: string[]): Promise<number>;
|