@skrr-ai/cli 0.1.50 → 0.1.52
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/base-command.d.ts +7 -0
- package/dist/base-command.js +95 -8
- package/dist/commands/agents/chat.d.ts +14 -0
- package/dist/commands/agents/chat.js +37 -1
- package/dist/commands/agents/create.js +8 -4
- package/dist/commands/agents/show.d.ts +9 -0
- package/dist/commands/agents/show.js +53 -0
- package/dist/commands/agents/update.d.ts +32 -0
- package/dist/commands/agents/update.js +81 -9
- package/dist/commands/balance/show.d.ts +34 -0
- package/dist/commands/balance/show.js +92 -2
- package/dist/commands/commitments/doctor.d.ts +1 -0
- package/dist/commands/commitments/doctor.js +19 -4
- package/dist/commands/commitments/effective-policy.js +15 -1
- package/dist/commands/commitments/next-tick.js +12 -2
- package/dist/commands/commitments/preflight.js +10 -0
- package/dist/commands/commitments/show.js +11 -1
- package/dist/commands/context.js +2 -1
- package/dist/commands/daemon/config.d.ts +15 -0
- package/dist/commands/daemon/config.js +53 -0
- package/dist/commands/daemon/index.js +1 -0
- package/dist/commands/daemon/status.js +15 -1
- package/dist/commands/doctor.js +8 -1
- package/dist/commands/harnesses/models.d.ts +54 -0
- package/dist/commands/harnesses/models.js +100 -7
- package/dist/commands/harnesses/show.d.ts +11 -0
- package/dist/commands/harnesses/show.js +35 -0
- package/dist/commands/harnesses/update.d.ts +28 -1
- package/dist/commands/harnesses/update.js +73 -10
- package/dist/commands/login.d.ts +2 -1
- package/dist/commands/login.js +26 -7
- package/dist/commands/logout.js +3 -0
- package/dist/commands/machines/dedicated/show.js +25 -2
- package/dist/commands/outbox/list.d.ts +12 -1
- package/dist/commands/outbox/list.js +31 -2
- package/dist/commands/revoke-daemon.js +9 -0
- package/dist/commands/spaces/create.d.ts +1 -0
- package/dist/commands/spaces/create.js +17 -0
- package/dist/commands/spaces/show.js +5 -0
- package/dist/commands/spaces/update.d.ts +1 -0
- package/dist/commands/spaces/update.js +16 -0
- package/dist/commands/tasks/create.d.ts +6 -0
- package/dist/commands/tasks/create.js +31 -6
- package/dist/commands/tasks/show.js +45 -0
- package/dist/commands/tasks/start.d.ts +14 -0
- package/dist/commands/tasks/start.js +31 -1
- package/dist/commands/tasks/update.d.ts +1 -0
- package/dist/commands/tasks/update.js +29 -1
- package/dist/commands/tasks/upsert.d.ts +1 -0
- package/dist/commands/tasks/upsert.js +16 -0
- package/dist/commands/whoami.js +5 -3
- package/dist/lib/agent-config.d.ts +2 -0
- package/dist/lib/agent-config.js +14 -10
- package/dist/lib/agentic-stream.d.ts +88 -1
- package/dist/lib/agentic-stream.js +330 -9
- package/dist/lib/auth-core-init.d.ts +2 -10
- package/dist/lib/auth-core-init.js +20 -67
- package/dist/lib/auth-failure.d.ts +33 -0
- package/dist/lib/auth-failure.js +68 -0
- package/dist/lib/auth-storage.d.ts +24 -0
- package/dist/lib/auth-storage.js +342 -11
- package/dist/lib/cli-id.d.ts +22 -0
- package/dist/lib/cli-id.js +56 -0
- package/dist/lib/cli-identity.d.ts +49 -0
- package/dist/lib/cli-identity.js +159 -0
- package/dist/lib/commitments.d.ts +25 -1
- package/dist/lib/commitments.js +46 -1
- package/dist/lib/config.d.ts +17 -0
- package/dist/lib/config.js +15 -3
- package/dist/lib/daemonBroker.d.ts +37 -1
- package/dist/lib/daemonBroker.js +146 -22
- package/dist/lib/daemonBrokerRefusal.d.ts +51 -0
- package/dist/lib/daemonBrokerRefusal.js +127 -0
- package/dist/lib/dedicated-machines.d.ts +33 -2
- package/dist/lib/dedicated-machines.js +50 -1
- package/dist/lib/delegated-cli.js +20 -1
- package/dist/lib/exec-runtime-binary.d.ts +3 -1
- package/dist/lib/exec-runtime-binary.js +4 -2
- package/dist/lib/first-party-harness-broker.js +10 -5
- package/dist/lib/harnesses.d.ts +10 -0
- package/dist/lib/keychain.d.ts +39 -0
- package/dist/lib/keychain.js +228 -39
- package/dist/lib/label-ref.d.ts +34 -0
- package/dist/lib/label-ref.js +68 -1
- package/dist/lib/live-runtime-binary.d.ts +40 -0
- package/dist/lib/live-runtime-binary.js +193 -0
- package/dist/lib/login.d.ts +23 -0
- package/dist/lib/login.js +67 -21
- package/dist/lib/message-intent.js +3 -1
- package/dist/lib/oauthLogin.js +2 -8
- package/dist/lib/refresh.js +6 -2
- package/dist/lib/tasks.d.ts +20 -0
- package/dist/lib/tasks.js +87 -8
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/credentialEnvelopeBridge.d.ts +2 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/credentialEnvelopeBridge.js +26 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/daemonToolApproval.d.ts +28 -4
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/daemonToolApproval.js +23 -5
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/deviceIdentityBridge.js +41 -3
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.d.ts +3 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.js +25 -3
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/loopbackHttp.d.ts +32 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/loopbackHttp.js +268 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/machineId.d.ts +2 -2
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/machineId.js +11 -10
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/machineUuid.d.ts +36 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/machineUuid.js +156 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/refresh.d.ts +8 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/refresh.js +8 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/spawnEnv.d.ts +22 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/spawnEnv.js +61 -2
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/credentialEnvelopeBridge.d.ts +2 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/credentialEnvelopeBridge.js +25 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/daemonToolApproval.d.ts +28 -4
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/daemonToolApproval.js +22 -4
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/deviceIdentityBridge.js +41 -3
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.d.ts +3 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.js +10 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/loopbackHttp.d.ts +32 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/loopbackHttp.js +257 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/machineId.d.ts +2 -2
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/machineId.js +11 -10
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/machineUuid.d.ts +36 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/machineUuid.js +147 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/refresh.d.ts +8 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/refresh.js +8 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/spawnEnv.d.ts +22 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/spawnEnv.js +58 -1
- package/dist/node_modules/@skrr-ai/auth-core/package.json +21 -1
- package/dist/node_modules/@skrr-ai/data-provider/index.js +3139 -3097
- package/oclif.manifest.json +28591 -28438
- package/package.json +1 -1
|
@@ -23,11 +23,13 @@ exports.__resetCachedDaemonIdForTest = __resetCachedDaemonIdForTest;
|
|
|
23
23
|
* directory survives), and a user whose machineUuid changes can
|
|
24
24
|
* still be re-anchored via the legacy-id list.
|
|
25
25
|
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
26
|
+
* This id is NOT the `machineUuid` the server keys Daemon rows on. That
|
|
27
|
+
* is the hardware id from `getMachineUuid()` (`machineUuid.ts`), and the
|
|
28
|
+
* two must never be substituted for each other on the wire: OSK-12063
|
|
29
|
+
* was the CLI sending this id as `machineUuid` on device-key enrollment,
|
|
30
|
+
* which matched no Daemon row and 404'd forever. The fallback used when
|
|
31
|
+
* this file cannot be persisted is supplied by the consumer via the
|
|
32
|
+
* `machineUuidFallback` parameter (the daemon passes `getMachineUuid`).
|
|
31
33
|
*/
|
|
32
34
|
const node_crypto_1 = __importDefault(require("node:crypto"));
|
|
33
35
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
@@ -108,9 +110,8 @@ function writeDaemonIdFile(target, id) {
|
|
|
108
110
|
* SHA-256 of `os.hostname()` + `os.platform()` — better than just
|
|
109
111
|
* hostname (includes platform) but worse than a true hardware UUID.
|
|
110
112
|
*
|
|
111
|
-
* The daemon overrides this with
|
|
112
|
-
* (`
|
|
113
|
-
* no native deps for OS UUIDs and so accepts this default.
|
|
113
|
+
* The daemon overrides this with the hardware detector
|
|
114
|
+
* (`getMachineUuid()`, `machineUuid.ts`).
|
|
114
115
|
*/
|
|
115
116
|
function defaultMachineUuidFallback() {
|
|
116
117
|
const host = node_os_1.default.hostname() || 'unknown-host';
|
|
@@ -129,8 +130,8 @@ function defaultMachineUuidFallback() {
|
|
|
129
130
|
* with a real UUIDv7 downstream.
|
|
130
131
|
*
|
|
131
132
|
* The caller may pass `machineUuidFallback` to override the default
|
|
132
|
-
* hostname+platform fingerprint with a richer detector (e.g.
|
|
133
|
-
*
|
|
133
|
+
* hostname+platform fingerprint with a richer detector (e.g.
|
|
134
|
+
* `getMachineUuid()` from `machineUuid.ts`).
|
|
134
135
|
*/
|
|
135
136
|
function ensureMachineDaemonId(machineUuidFallback) {
|
|
136
137
|
if (cachedStableDaemonId !== null)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Daemon sources whose identity is ISSUED by the control plane rather than
|
|
3
|
+
* derived from the host: the provisioner mints the daemon id and machine uuid
|
|
4
|
+
* before the daemon exists, and every binary on the runtime must use exactly
|
|
5
|
+
* those values.
|
|
6
|
+
*
|
|
7
|
+
* `dedicated-runtime` is here because the server's generation fence parses the
|
|
8
|
+
* lease generation out of the machine uuid (`dedicated-runtime:<lease>:<gen>`).
|
|
9
|
+
* A guest that fell back to `/etc/machine-id` would register under a uuid the
|
|
10
|
+
* fence cannot read, and every dispatch to it would be refused.
|
|
11
|
+
*/
|
|
12
|
+
export declare const HOSTED_RUNTIME_MACHINE_SOURCES: ReadonlySet<string>;
|
|
13
|
+
/**
|
|
14
|
+
* The control-plane-issued value of `name` (e.g. `OVERSKY_MACHINE_UUID`), or
|
|
15
|
+
* null when this process is not on a hosted runtime or the value is absent /
|
|
16
|
+
* malformed. Only honoured under a hosted `OVERSKY_DAEMON_SOURCE`, so a stray
|
|
17
|
+
* variable on a laptop cannot rename the machine.
|
|
18
|
+
*/
|
|
19
|
+
export declare function hostedRuntimeIdOverride(name: string, env?: NodeJS.ProcessEnv): string | null;
|
|
20
|
+
/**
|
|
21
|
+
* Return a stable, machine-scoped UUID. Cached for the process lifetime.
|
|
22
|
+
*
|
|
23
|
+
* Callers should treat this as opaque: the format differs per platform
|
|
24
|
+
* (macOS IOPlatformUUID, Linux systemd machine-id, Windows MachineGuid).
|
|
25
|
+
* The guarantee is only: same machine -> same value across reboots, and the
|
|
26
|
+
* same value from every binary that calls this function.
|
|
27
|
+
*
|
|
28
|
+
* On a hosted runtime the control-plane-issued `OVERSKY_MACHINE_UUID` wins.
|
|
29
|
+
*
|
|
30
|
+
* Falls back to a deterministic hostname+username hash if the platform
|
|
31
|
+
* probe fails. This preserves server-side record continuity even on
|
|
32
|
+
* locked-down machines that refuse ioreg / registry access.
|
|
33
|
+
*/
|
|
34
|
+
export declare function getMachineUuid(): string;
|
|
35
|
+
/** @internal test seam — forget the cached value so the next call re-probes. */
|
|
36
|
+
export declare function __resetMachineUuidCacheForTest(): void;
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.HOSTED_RUNTIME_MACHINE_SOURCES = void 0;
|
|
7
|
+
exports.hostedRuntimeIdOverride = hostedRuntimeIdOverride;
|
|
8
|
+
exports.getMachineUuid = getMachineUuid;
|
|
9
|
+
exports.__resetMachineUuidCacheForTest = __resetMachineUuidCacheForTest;
|
|
10
|
+
/**
|
|
11
|
+
* machineUuid.ts — the ONE hardware machine identity sent to the server as
|
|
12
|
+
* `machineUuid`, shared by the daemon and the CLI.
|
|
13
|
+
*
|
|
14
|
+
* Server Daemon rows are keyed on this value (daemon register, device-key
|
|
15
|
+
* enrollment, token mint, pairing), so every binary on one machine must
|
|
16
|
+
* compute it identically. Until OSK-12063 the CLI sent its own UUIDv7 from
|
|
17
|
+
* `~/.skrr/daemon.id` (`ensureMachineDaemonId()`, a DIFFERENT identity) as
|
|
18
|
+
* `machineUuid` on device-key enrollment while the daemon sent the hardware
|
|
19
|
+
* UUID computed here, so every CLI enrollment matched no Daemon row, got
|
|
20
|
+
* 404 DAEMON_NOT_FOUND and backed off forever. Two implementations of one
|
|
21
|
+
* identity can only agree by being edited together; this file is the one
|
|
22
|
+
* implementation, and `daemon/src/registry-lite.ts` re-exports it.
|
|
23
|
+
*
|
|
24
|
+
* Deliberately dependency-free (node builtins only) and exposed as the
|
|
25
|
+
* `@skrr-ai/auth-core/machine-uuid` subpath: the packaged desktop imports the
|
|
26
|
+
* daemon's `registry-lite.js` directly, and loading the full auth-core index
|
|
27
|
+
* there would drag in the credential stack for a one-function need.
|
|
28
|
+
*
|
|
29
|
+
* Not to be confused with `ensureMachineDaemonId()` (`machineId.ts`), the
|
|
30
|
+
* minted per-home-dir UUIDv7 that anchors the daemon's `stableDaemonId`. That
|
|
31
|
+
* one survives an OS reinstall; this one survives a home-dir wipe. They are
|
|
32
|
+
* different facts and neither may stand in for the other on the wire.
|
|
33
|
+
*/
|
|
34
|
+
const node_crypto_1 = __importDefault(require("node:crypto"));
|
|
35
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
36
|
+
const node_os_1 = __importDefault(require("node:os"));
|
|
37
|
+
const node_child_process_1 = require("node:child_process");
|
|
38
|
+
/**
|
|
39
|
+
* Daemon sources whose identity is ISSUED by the control plane rather than
|
|
40
|
+
* derived from the host: the provisioner mints the daemon id and machine uuid
|
|
41
|
+
* before the daemon exists, and every binary on the runtime must use exactly
|
|
42
|
+
* those values.
|
|
43
|
+
*
|
|
44
|
+
* `dedicated-runtime` is here because the server's generation fence parses the
|
|
45
|
+
* lease generation out of the machine uuid (`dedicated-runtime:<lease>:<gen>`).
|
|
46
|
+
* A guest that fell back to `/etc/machine-id` would register under a uuid the
|
|
47
|
+
* fence cannot read, and every dispatch to it would be refused.
|
|
48
|
+
*/
|
|
49
|
+
exports.HOSTED_RUNTIME_MACHINE_SOURCES = new Set([
|
|
50
|
+
'hosted-machine',
|
|
51
|
+
'cloud-coding',
|
|
52
|
+
'dedicated-runtime',
|
|
53
|
+
]);
|
|
54
|
+
const HOSTED_RUNTIME_ID_RE = /^[A-Za-z0-9_.:-]{1,160}$/;
|
|
55
|
+
/**
|
|
56
|
+
* The control-plane-issued value of `name` (e.g. `OVERSKY_MACHINE_UUID`), or
|
|
57
|
+
* null when this process is not on a hosted runtime or the value is absent /
|
|
58
|
+
* malformed. Only honoured under a hosted `OVERSKY_DAEMON_SOURCE`, so a stray
|
|
59
|
+
* variable on a laptop cannot rename the machine.
|
|
60
|
+
*/
|
|
61
|
+
function hostedRuntimeIdOverride(name, env = process.env) {
|
|
62
|
+
if (!exports.HOSTED_RUNTIME_MACHINE_SOURCES.has(env.OVERSKY_DAEMON_SOURCE ?? '')) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
const value = env[name]?.trim();
|
|
66
|
+
if (!value || !HOSTED_RUNTIME_ID_RE.test(value))
|
|
67
|
+
return null;
|
|
68
|
+
return value;
|
|
69
|
+
}
|
|
70
|
+
let cachedMachineUuid = null;
|
|
71
|
+
function readMachineUuidDarwin() {
|
|
72
|
+
try {
|
|
73
|
+
const out = (0, node_child_process_1.execFileSync)('ioreg', ['-rd1', '-c', 'IOPlatformExpertDevice'], {
|
|
74
|
+
encoding: 'utf-8',
|
|
75
|
+
timeout: 2_000,
|
|
76
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
77
|
+
});
|
|
78
|
+
const match = out.match(/IOPlatformUUID"?\s*=\s*"?([0-9A-F-]{36})/i);
|
|
79
|
+
return match ? match[1].toLowerCase() : null;
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
function readMachineUuidLinux() {
|
|
86
|
+
for (const p of ['/etc/machine-id', '/var/lib/dbus/machine-id']) {
|
|
87
|
+
try {
|
|
88
|
+
const raw = node_fs_1.default.readFileSync(p, 'utf-8').trim();
|
|
89
|
+
if (raw)
|
|
90
|
+
return raw.toLowerCase();
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
// Try the next candidate.
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
function readMachineUuidWindows() {
|
|
99
|
+
try {
|
|
100
|
+
const out = (0, node_child_process_1.execFileSync)('reg', ['query', 'HKLM\\SOFTWARE\\Microsoft\\Cryptography', '/v', 'MachineGuid'], { encoding: 'utf-8', timeout: 2_000, stdio: ['ignore', 'pipe', 'ignore'] });
|
|
101
|
+
const match = out.match(/MachineGuid\s+REG_SZ\s+([0-9A-Fa-f-]{36})/);
|
|
102
|
+
return match ? match[1].toLowerCase() : null;
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Return a stable, machine-scoped UUID. Cached for the process lifetime.
|
|
110
|
+
*
|
|
111
|
+
* Callers should treat this as opaque: the format differs per platform
|
|
112
|
+
* (macOS IOPlatformUUID, Linux systemd machine-id, Windows MachineGuid).
|
|
113
|
+
* The guarantee is only: same machine -> same value across reboots, and the
|
|
114
|
+
* same value from every binary that calls this function.
|
|
115
|
+
*
|
|
116
|
+
* On a hosted runtime the control-plane-issued `OVERSKY_MACHINE_UUID` wins.
|
|
117
|
+
*
|
|
118
|
+
* Falls back to a deterministic hostname+username hash if the platform
|
|
119
|
+
* probe fails. This preserves server-side record continuity even on
|
|
120
|
+
* locked-down machines that refuse ioreg / registry access.
|
|
121
|
+
*/
|
|
122
|
+
function getMachineUuid() {
|
|
123
|
+
const hostedMachineUuid = hostedRuntimeIdOverride('OVERSKY_MACHINE_UUID');
|
|
124
|
+
if (hostedMachineUuid)
|
|
125
|
+
return hostedMachineUuid;
|
|
126
|
+
if (cachedMachineUuid !== null)
|
|
127
|
+
return cachedMachineUuid;
|
|
128
|
+
let detected = null;
|
|
129
|
+
switch (process.platform) {
|
|
130
|
+
case 'darwin':
|
|
131
|
+
detected = readMachineUuidDarwin();
|
|
132
|
+
break;
|
|
133
|
+
case 'linux':
|
|
134
|
+
detected = readMachineUuidLinux();
|
|
135
|
+
break;
|
|
136
|
+
case 'win32':
|
|
137
|
+
detected = readMachineUuidWindows();
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
if (detected) {
|
|
141
|
+
cachedMachineUuid = detected;
|
|
142
|
+
return detected;
|
|
143
|
+
}
|
|
144
|
+
const fallback = 'fallback-' +
|
|
145
|
+
node_crypto_1.default
|
|
146
|
+
.createHash('sha256')
|
|
147
|
+
.update(`${node_os_1.default.hostname()}:${node_os_1.default.userInfo().username}`)
|
|
148
|
+
.digest('hex')
|
|
149
|
+
.slice(0, 32);
|
|
150
|
+
cachedMachineUuid = fallback;
|
|
151
|
+
return fallback;
|
|
152
|
+
}
|
|
153
|
+
/** @internal test seam — forget the cached value so the next call re-probes. */
|
|
154
|
+
function __resetMachineUuidCacheForTest() {
|
|
155
|
+
cachedMachineUuid = null;
|
|
156
|
+
}
|
|
@@ -274,6 +274,14 @@ export declare function persistReauthState(state: ReauthState): void;
|
|
|
274
274
|
export declare function needsReauthState(): {
|
|
275
275
|
needed: boolean;
|
|
276
276
|
reason?: string;
|
|
277
|
+
/**
|
|
278
|
+
* The server's own words for the refusal (`Refresh token bound to a different
|
|
279
|
+
* daemon`). The code alone collapses several distinct causes into one
|
|
280
|
+
* (`REFRESH_INVALID` is also "not recognized" and "issued without a
|
|
281
|
+
* daemonId"), and a surface that names only the code cannot tell the reader
|
|
282
|
+
* which one they hit (OSK-12116).
|
|
283
|
+
*/
|
|
284
|
+
message?: string;
|
|
277
285
|
since?: number;
|
|
278
286
|
};
|
|
279
287
|
export declare function clearReauthState(): void;
|
|
@@ -969,7 +969,14 @@ function needsReauthState() {
|
|
|
969
969
|
return { needed: false };
|
|
970
970
|
const raw = node_fs_1.default.readFileSync(flagPath, 'utf-8');
|
|
971
971
|
const state = JSON.parse(raw);
|
|
972
|
-
return {
|
|
972
|
+
return {
|
|
973
|
+
needed: true,
|
|
974
|
+
reason: state.code,
|
|
975
|
+
...(typeof state.message === 'string' && state.message.length > 0
|
|
976
|
+
? { message: state.message }
|
|
977
|
+
: {}),
|
|
978
|
+
since: state.at,
|
|
979
|
+
};
|
|
973
980
|
}
|
|
974
981
|
catch {
|
|
975
982
|
return { needed: false };
|
|
@@ -84,3 +84,25 @@ export declare const SENSITIVE_ENV_PREFIX_EXCEPTIONS: ReadonlySet<string>;
|
|
|
84
84
|
* etc.) so legitimate tools keep working.
|
|
85
85
|
*/
|
|
86
86
|
export declare function sanitizeSpawnEnv(env: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
|
|
87
|
+
/**
|
|
88
|
+
* OSK-12134 — loopback names a spawned child must reach directly, never through
|
|
89
|
+
* a proxy. A harness talks to this machine constantly: the daemon's local
|
|
90
|
+
* bridges (browser, delegated CLI, message intents), the inference broker, and
|
|
91
|
+
* the engine's own loopback services (skrr Code's `session/new` reaches a local
|
|
92
|
+
* directory service and failed with "service failure" behind a shell proxy).
|
|
93
|
+
*/
|
|
94
|
+
export declare const LOOPBACK_NO_PROXY_HOSTS: readonly string[];
|
|
95
|
+
/** True when `env` names a proxy some client in the child might honour. */
|
|
96
|
+
export declare function envHasProxy(env: Readonly<Record<string, string | undefined>>): boolean;
|
|
97
|
+
/**
|
|
98
|
+
* Return `env` with the loopback hosts appended to BOTH `NO_PROXY` and
|
|
99
|
+
* `no_proxy`, when (and only when) it names a proxy. Tools disagree on which
|
|
100
|
+
* spelling they read and whether they fall back to the other, so an unset
|
|
101
|
+
* spelling is seeded from the other one before the hosts are appended —
|
|
102
|
+
* seeding only the hosts would silently drop every existing exemption for a
|
|
103
|
+
* tool that prefers the unset spelling. Existing entries keep their order.
|
|
104
|
+
*
|
|
105
|
+
* Exported for a parent that layers a proxy onto the child's env AFTER
|
|
106
|
+
* {@link sanitizeSpawnEnv}: call it again on the final map.
|
|
107
|
+
*/
|
|
108
|
+
export declare function withLoopbackNoProxy<T extends Record<string, string | undefined>>(env: T): T;
|
|
@@ -40,8 +40,10 @@
|
|
|
40
40
|
* serve that case: a deny-list with a hole is not a deny-list.
|
|
41
41
|
*/
|
|
42
42
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
43
|
-
exports.SENSITIVE_ENV_PREFIX_EXCEPTIONS = exports.SENSITIVE_ENV_NAME_TOKENS = exports.SENSITIVE_ENV_SUFFIXES = exports.SENSITIVE_ENV_PREFIXES = exports.SENSITIVE_ENV_VARS = void 0;
|
|
43
|
+
exports.LOOPBACK_NO_PROXY_HOSTS = exports.SENSITIVE_ENV_PREFIX_EXCEPTIONS = exports.SENSITIVE_ENV_NAME_TOKENS = exports.SENSITIVE_ENV_SUFFIXES = exports.SENSITIVE_ENV_PREFIXES = exports.SENSITIVE_ENV_VARS = void 0;
|
|
44
44
|
exports.sanitizeSpawnEnv = sanitizeSpawnEnv;
|
|
45
|
+
exports.envHasProxy = envHasProxy;
|
|
46
|
+
exports.withLoopbackNoProxy = withLoopbackNoProxy;
|
|
45
47
|
/**
|
|
46
48
|
* Env vars that must NEVER reach a spawned subprocess.
|
|
47
49
|
*
|
|
@@ -187,5 +189,62 @@ function sanitizeSpawnEnv(env) {
|
|
|
187
189
|
continue;
|
|
188
190
|
out[key] = value;
|
|
189
191
|
}
|
|
190
|
-
return out;
|
|
192
|
+
return withLoopbackNoProxy(out);
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* OSK-12134 — loopback names a spawned child must reach directly, never through
|
|
196
|
+
* a proxy. A harness talks to this machine constantly: the daemon's local
|
|
197
|
+
* bridges (browser, delegated CLI, message intents), the inference broker, and
|
|
198
|
+
* the engine's own loopback services (skrr Code's `session/new` reaches a local
|
|
199
|
+
* directory service and failed with "service failure" behind a shell proxy).
|
|
200
|
+
*/
|
|
201
|
+
exports.LOOPBACK_NO_PROXY_HOSTS = ['127.0.0.1', 'localhost', '::1'];
|
|
202
|
+
const PROXY_ENV_VARS = [
|
|
203
|
+
'HTTP_PROXY',
|
|
204
|
+
'http_proxy',
|
|
205
|
+
'HTTPS_PROXY',
|
|
206
|
+
'https_proxy',
|
|
207
|
+
'ALL_PROXY',
|
|
208
|
+
'all_proxy',
|
|
209
|
+
];
|
|
210
|
+
/** True when `env` names a proxy some client in the child might honour. */
|
|
211
|
+
function envHasProxy(env) {
|
|
212
|
+
return PROXY_ENV_VARS.some((name) => typeof env[name] === 'string' && env[name].trim() !== '');
|
|
213
|
+
}
|
|
214
|
+
function appendNoProxyHosts(list, hosts) {
|
|
215
|
+
const entries = list
|
|
216
|
+
.split(',')
|
|
217
|
+
.map((entry) => entry.trim().toLowerCase())
|
|
218
|
+
.filter(Boolean);
|
|
219
|
+
// `*` already exempts everything, and some clients honour it only as the
|
|
220
|
+
// entire value, so appending to it would break them.
|
|
221
|
+
if (entries.includes('*'))
|
|
222
|
+
return list;
|
|
223
|
+
const missing = hosts.filter((host) => !entries.includes(host));
|
|
224
|
+
if (missing.length === 0)
|
|
225
|
+
return list;
|
|
226
|
+
const kept = list.replace(/[\s,]+$/, '');
|
|
227
|
+
return kept ? `${kept},${missing.join(',')}` : missing.join(',');
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Return `env` with the loopback hosts appended to BOTH `NO_PROXY` and
|
|
231
|
+
* `no_proxy`, when (and only when) it names a proxy. Tools disagree on which
|
|
232
|
+
* spelling they read and whether they fall back to the other, so an unset
|
|
233
|
+
* spelling is seeded from the other one before the hosts are appended —
|
|
234
|
+
* seeding only the hosts would silently drop every existing exemption for a
|
|
235
|
+
* tool that prefers the unset spelling. Existing entries keep their order.
|
|
236
|
+
*
|
|
237
|
+
* Exported for a parent that layers a proxy onto the child's env AFTER
|
|
238
|
+
* {@link sanitizeSpawnEnv}: call it again on the final map.
|
|
239
|
+
*/
|
|
240
|
+
function withLoopbackNoProxy(env) {
|
|
241
|
+
if (!envHasProxy(env))
|
|
242
|
+
return env;
|
|
243
|
+
const upper = env.NO_PROXY?.trim() ? env.NO_PROXY : undefined;
|
|
244
|
+
const lower = env.no_proxy?.trim() ? env.no_proxy : undefined;
|
|
245
|
+
return {
|
|
246
|
+
...env,
|
|
247
|
+
NO_PROXY: appendNoProxyHosts(upper ?? lower ?? '', exports.LOOPBACK_NO_PROXY_HOSTS),
|
|
248
|
+
no_proxy: appendNoProxyHosts(lower ?? upper ?? '', exports.LOOPBACK_NO_PROXY_HOSTS),
|
|
249
|
+
};
|
|
191
250
|
}
|
|
@@ -21,6 +21,8 @@ type DisabledReason = 'kek_unavailable' | 'init_failed' | 'platform_unsupported'
|
|
|
21
21
|
export declare function __setStateForTest(next: CredEnvelopeState): CredEnvelopeState;
|
|
22
22
|
/** @internal Test seam — read state for assertions. */
|
|
23
23
|
export declare function __getStateForTest(): CredEnvelopeState;
|
|
24
|
+
/** @internal Test seam — each spec owns its warn-dedupe horizon. */
|
|
25
|
+
export declare function __clearWarnDedupeForTest(): void;
|
|
24
26
|
/**
|
|
25
27
|
* Initialize the envelope path. Idempotent — second call when state is
|
|
26
28
|
* non-uninit returns immediately.
|
|
@@ -123,7 +123,21 @@ function atomicWrite0600(target, value) {
|
|
|
123
123
|
* The event name passed in is the FULLY-QUALIFIED `cred_envelope.*` form
|
|
124
124
|
* because daemon-side telemetry consumers (`event-log.ts`, dashboards,
|
|
125
125
|
* spec assertions) key off the prefixed name. Do not strip the prefix.
|
|
126
|
+
*
|
|
127
|
+
* Identical failure warnings hit the logger only once per process.
|
|
128
|
+
* Telemetry still records every occurrence — the dedupe exists because a
|
|
129
|
+
* single unreadable envelope produced the same warning once per stored
|
|
130
|
+
* field (token, refresh token, expiry…), which read to users as three
|
|
131
|
+
* crashes rather than one stale credential (OSK-12074). The signature is
|
|
132
|
+
* event + kek identity + message, so a genuinely different failure mode
|
|
133
|
+
* still gets its own line.
|
|
126
134
|
*/
|
|
135
|
+
const warnedSignatures = new Set();
|
|
136
|
+
const MAX_WARNED_SIGNATURES = 64;
|
|
137
|
+
/** @internal Test seam — each spec owns its warn-dedupe horizon. */
|
|
138
|
+
export function __clearWarnDedupeForTest() {
|
|
139
|
+
warnedSignatures.clear();
|
|
140
|
+
}
|
|
127
141
|
function emit(eventName, success, metadata) {
|
|
128
142
|
emitAuthTelemetry({
|
|
129
143
|
timestamp: new Date().toISOString(),
|
|
@@ -132,7 +146,13 @@ function emit(eventName, success, metadata) {
|
|
|
132
146
|
metadata: { event: eventName, ...metadata },
|
|
133
147
|
});
|
|
134
148
|
if (!success) {
|
|
135
|
-
|
|
149
|
+
const signature = `${eventName}:${metadata.kekId ?? ''}:${metadata.kekKind ?? ''}:${metadata.message ?? ''}`;
|
|
150
|
+
if (!warnedSignatures.has(signature)) {
|
|
151
|
+
if (warnedSignatures.size >= MAX_WARNED_SIGNATURES)
|
|
152
|
+
warnedSignatures.clear();
|
|
153
|
+
warnedSignatures.add(signature);
|
|
154
|
+
getAuthLogger().warn(`[credEnvelope] ${eventName}`, metadata);
|
|
155
|
+
}
|
|
136
156
|
}
|
|
137
157
|
}
|
|
138
158
|
// ---------------------------------------------------------------------------
|
|
@@ -745,6 +765,10 @@ export function maybeDecryptOnRead(stored) {
|
|
|
745
765
|
kekId: _state.kekId,
|
|
746
766
|
kekKind: _state.kekKind,
|
|
747
767
|
message: err?.message ?? 'unknown',
|
|
768
|
+
// The crypto error alone reads as a crash; the actionable truth is
|
|
769
|
+
// that this stored credential is unreadable by THIS binary (usually
|
|
770
|
+
// a signing-identity or profile drift) and re-login rebuilds it.
|
|
771
|
+
hint: 'stored credential is unreadable on this machine — signing in again rebuilds it',
|
|
748
772
|
});
|
|
749
773
|
return { plaintext: null, needsMigration: false };
|
|
750
774
|
}
|
|
@@ -23,9 +23,14 @@
|
|
|
23
23
|
*
|
|
24
24
|
* What the daemon verifies is the binding, not the server's honesty: the
|
|
25
25
|
* request already arrives over the daemon's authenticated server channel, so
|
|
26
|
-
* the field IS the attestation
|
|
27
|
-
*
|
|
28
|
-
* one call cannot be replayed
|
|
26
|
+
* the field IS the attestation — it is unsigned, and `decidedBy` is a literal.
|
|
27
|
+
* What the binding buys is that the model — which authors `toolInput` —
|
|
28
|
+
* cannot mint an approval, and an approval for one call cannot be replayed
|
|
29
|
+
* onto another. The verifier also bounds the validity window itself (never
|
|
30
|
+
* trusting the issuer's `expiresAt` beyond `ATTESTED_TOOL_APPROVAL_TTL_MS`),
|
|
31
|
+
* and the daemon spends each approval once: a second delivery of the same
|
|
32
|
+
* attestation inside its window is refused as `replayed`. That ledger lives
|
|
33
|
+
* in daemon memory, so a daemon restart inside the (≤60s) window forgets it.
|
|
29
34
|
*/
|
|
30
35
|
/** Announced by a daemon that honours `attestedApproval` on daemon:tool:request. */
|
|
31
36
|
export declare const DAEMON_TOOL_ATTESTED_APPROVAL_CAPABILITY = "daemon_tool_attested_approval_v1";
|
|
@@ -89,12 +94,31 @@ export declare function mintAttestedToolApproval(args: {
|
|
|
89
94
|
now?: number;
|
|
90
95
|
ttlMs?: number;
|
|
91
96
|
}): AttestedToolApproval;
|
|
97
|
+
/**
|
|
98
|
+
* Why an attestation did not approve a call — logged by the daemon, never
|
|
99
|
+
* shown to the caller beyond "absent" vs "did not verify".
|
|
100
|
+
* - `absent` — no attestation arrived (the server did not ask anyone)
|
|
101
|
+
* - `malformed` — not the v1 shape
|
|
102
|
+
* - `expired` — past `expiresAt`, or issued implausibly far in the future
|
|
103
|
+
* - `window` — the issuer claimed a validity window longer than
|
|
104
|
+
* `ATTESTED_TOOL_APPROVAL_TTL_MS` (or an empty/negative one)
|
|
105
|
+
* - `binding` — minted for a different call (toolUseId, tool, or input)
|
|
106
|
+
* - `replayed` — this exact approval was already spent on this daemon
|
|
107
|
+
* (the ledger is the verifier's caller's, see the daemon's
|
|
108
|
+
* `permissions/attestation-ledger.ts`)
|
|
109
|
+
*/
|
|
110
|
+
export type AttestedToolApprovalRefusalReason = 'absent' | 'malformed' | 'binding' | 'expired' | 'window' | 'replayed';
|
|
92
111
|
export type AttestedToolApprovalVerdict = {
|
|
93
112
|
ok: true;
|
|
94
113
|
} | {
|
|
95
114
|
ok: false;
|
|
96
|
-
reason:
|
|
115
|
+
reason: AttestedToolApprovalRefusalReason;
|
|
97
116
|
};
|
|
117
|
+
/**
|
|
118
|
+
* Clock skew tolerated on `issuedAt`: a server clock slightly ahead of the
|
|
119
|
+
* daemon's must not refuse a fresh approval.
|
|
120
|
+
*/
|
|
121
|
+
export declare const ATTESTED_TOOL_APPROVAL_CLOCK_SKEW_MS: number;
|
|
98
122
|
/**
|
|
99
123
|
* Daemon side: verify an attestation against the call it claims to approve.
|
|
100
124
|
* Untrusted wire input — every field is checked, and any mismatch is a plain
|
|
@@ -24,9 +24,14 @@ import { createHash } from 'node:crypto';
|
|
|
24
24
|
*
|
|
25
25
|
* What the daemon verifies is the binding, not the server's honesty: the
|
|
26
26
|
* request already arrives over the daemon's authenticated server channel, so
|
|
27
|
-
* the field IS the attestation
|
|
28
|
-
*
|
|
29
|
-
* one call cannot be replayed
|
|
27
|
+
* the field IS the attestation — it is unsigned, and `decidedBy` is a literal.
|
|
28
|
+
* What the binding buys is that the model — which authors `toolInput` —
|
|
29
|
+
* cannot mint an approval, and an approval for one call cannot be replayed
|
|
30
|
+
* onto another. The verifier also bounds the validity window itself (never
|
|
31
|
+
* trusting the issuer's `expiresAt` beyond `ATTESTED_TOOL_APPROVAL_TTL_MS`),
|
|
32
|
+
* and the daemon spends each approval once: a second delivery of the same
|
|
33
|
+
* attestation inside its window is refused as `replayed`. That ledger lives
|
|
34
|
+
* in daemon memory, so a daemon restart inside the (≤60s) window forgets it.
|
|
30
35
|
*/
|
|
31
36
|
/** Announced by a daemon that honours `attestedApproval` on daemon:tool:request. */
|
|
32
37
|
export const DAEMON_TOOL_ATTESTED_APPROVAL_CAPABILITY = 'daemon_tool_attested_approval_v1';
|
|
@@ -129,6 +134,11 @@ export function mintAttestedToolApproval(args) {
|
|
|
129
134
|
expiresAt: now + (args.ttlMs ?? ATTESTED_TOOL_APPROVAL_TTL_MS),
|
|
130
135
|
};
|
|
131
136
|
}
|
|
137
|
+
/**
|
|
138
|
+
* Clock skew tolerated on `issuedAt`: a server clock slightly ahead of the
|
|
139
|
+
* daemon's must not refuse a fresh approval.
|
|
140
|
+
*/
|
|
141
|
+
export const ATTESTED_TOOL_APPROVAL_CLOCK_SKEW_MS = 30 * 1000;
|
|
132
142
|
/**
|
|
133
143
|
* Daemon side: verify an attestation against the call it claims to approve.
|
|
134
144
|
* Untrusted wire input — every field is checked, and any mismatch is a plain
|
|
@@ -152,9 +162,17 @@ export function verifyAttestedToolApproval(approval, call) {
|
|
|
152
162
|
return { ok: false, reason: 'malformed' };
|
|
153
163
|
}
|
|
154
164
|
const now = call.now ?? Date.now();
|
|
155
|
-
if (a.expiresAt <= now || a.issuedAt > now +
|
|
165
|
+
if (a.expiresAt <= now || a.issuedAt > now + ATTESTED_TOOL_APPROVAL_CLOCK_SKEW_MS) {
|
|
156
166
|
return { ok: false, reason: 'expired' };
|
|
157
167
|
}
|
|
168
|
+
// The TTL is the VERIFIER's bound, not the issuer's claim (OSK-12108): an
|
|
169
|
+
// attestation whose own window is longer than one approval may stay valid
|
|
170
|
+
// is refused whatever `expiresAt` says, so "answers one person about this
|
|
171
|
+
// call, moments ago" holds even against an issuer that set a year.
|
|
172
|
+
const window = a.expiresAt - a.issuedAt;
|
|
173
|
+
if (!(window > 0) || window > ATTESTED_TOOL_APPROVAL_TTL_MS) {
|
|
174
|
+
return { ok: false, reason: 'window' };
|
|
175
|
+
}
|
|
158
176
|
if (a.toolUseId !== call.toolUseId ||
|
|
159
177
|
a.toolName.toLowerCase() !== String(call.toolName).toLowerCase() ||
|
|
160
178
|
a.inputSha256 !== canonicalToolInputDigest(call.toolInput)) {
|
|
@@ -585,11 +585,49 @@ export async function enrollWithServer(opts) {
|
|
|
585
585
|
// Enrollment is the CLI's (JWT) job; the daemon holding an opaque
|
|
586
586
|
// token should not enroll. Guarded at the daemon call site, this is
|
|
587
587
|
// defense-in-depth for any other opaque caller.
|
|
588
|
-
// • 409
|
|
589
|
-
// for
|
|
588
|
+
// • 409 ALREADY_ENROLLED with OUR thumbprint — a concurrent binary won
|
|
589
|
+
// the enrollment race for this keypair; idempotent, nothing to do.
|
|
590
|
+
//
|
|
591
|
+
// A 409 is NOT benign when the row is pinned to a DIFFERENT key
|
|
592
|
+
// (OSK-12063). The server keeps one pin per (user, machine) row while
|
|
593
|
+
// every local profile has its own key, so a 409 can mean "every refresh
|
|
594
|
+
// this key signs will be refused with DEVICE_PROOF_THUMBPRINT_MISMATCH".
|
|
595
|
+
// The server names the pinned thumbprint (`enrolledThumbprint`) so the
|
|
596
|
+
// two cases can be told apart. An older server that omits it keeps the
|
|
597
|
+
// old reading, because there is nothing to compare. A 409
|
|
598
|
+
// ENROLLMENT_DUPLICATE_KEY — this key is pinned on another active row —
|
|
599
|
+
// is never benign either.
|
|
600
|
+
let conflictCode = null;
|
|
601
|
+
let enrolledThumbprint = null;
|
|
602
|
+
if (response.status === 409) {
|
|
603
|
+
try {
|
|
604
|
+
const parsed = JSON.parse(responseText);
|
|
605
|
+
conflictCode = typeof parsed.code === 'string' ? parsed.code : null;
|
|
606
|
+
enrolledThumbprint =
|
|
607
|
+
typeof parsed.enrolledThumbprint === 'string' ? parsed.enrolledThumbprint : null;
|
|
608
|
+
}
|
|
609
|
+
catch {
|
|
610
|
+
/* non-JSON 409 — treat as the legacy benign race */
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
const pinnedToOtherKey = response.status === 409 &&
|
|
614
|
+
enrolledThumbprint !== null &&
|
|
615
|
+
enrolledThumbprint !== keypair.thumbprint;
|
|
616
|
+
const keyPinnedElsewhere = response.status === 409 && conflictCode === 'ENROLLMENT_DUPLICATE_KEY';
|
|
590
617
|
const isBenignRejection = (response.status === 404 && responseText.includes('DAEMON_NOT_FOUND')) ||
|
|
591
618
|
(response.status === 403 && responseText.includes('OPAQUE_AUTH_REFUSED')) ||
|
|
592
|
-
response.status === 409;
|
|
619
|
+
(response.status === 409 && !pinnedToOtherKey && !keyPinnedElsewhere);
|
|
620
|
+
if (pinnedToOtherKey) {
|
|
621
|
+
emit('enrollment_key_mismatch', false, {
|
|
622
|
+
profile,
|
|
623
|
+
thumbprint: keypair.thumbprint,
|
|
624
|
+
enrolledThumbprint,
|
|
625
|
+
serverUrl,
|
|
626
|
+
message: 'this machine is registered with a different device key than this profile signs ' +
|
|
627
|
+
'with; its refreshes will be refused. An interactive daemon login (skrrd login) ' +
|
|
628
|
+
're-registers this key.',
|
|
629
|
+
}, { logLevel: 'warn' });
|
|
630
|
+
}
|
|
593
631
|
if (response.status === 404 && responseText.includes('DAEMON_NOT_FOUND')) {
|
|
594
632
|
try {
|
|
595
633
|
atomicWrite0600(backoffPath, JSON.stringify({
|
|
@@ -29,11 +29,13 @@ export { __setKekStrategyForTest, getKekStrategy, InMemoryKek, UnavailableKek, K
|
|
|
29
29
|
export { buildProof as buildDeviceProof, generateDeviceKeyPair, jwkThumbprint, normalizeHtu, publicJwkFromX, tokenHash, verifyProof as verifyDeviceProof, type DeviceKeyPair, type DeviceProofClaims, type DeviceProofHeader, type Ed25519PrivateJwk, type Ed25519PublicJwk, type VerifyFailureReason as DeviceProofVerifyFailureReason, type VerifyFailure as DeviceProofVerifyFailure, type VerifyOptions as DeviceProofVerifyOptions, type VerifySuccess as DeviceProofVerifySuccess, } from './deviceKey.js';
|
|
30
30
|
export { initCredEnvelope, resetCredEnvelope, shutdownCredEnvelope, isCredEnvelopeActive, hasCredEnvelopePathConflict, describeCredEnvelopeState, maybeEncryptForWrite, maybeDecryptOnRead, __wrappedDekFilePathForTest, __setStateForTest as __setCredEnvelopeStateForTest, __getStateForTest as __getCredEnvelopeStateForTest, __resetShutdownGuardForTest, type ReadTransformResult, } from './credentialEnvelopeBridge.js';
|
|
31
31
|
export { initDeviceIdentity, resetDeviceIdentity, signServerRequest, enrollWithServer, clearEnrollmentMarker, isDeviceIdentityActive, getDevicePublicKey, describeDeviceIdentityState, __publicKeyPathForTest, __privateKeyPathForTest, __enrollmentMarkerPathForTest, __enrollmentBackoffPathForTest, __setStateForTest as __setDeviceIdentityStateForTest, __getStateForTest as __getDeviceIdentityStateForTest, type EnrollmentResult, } from './deviceIdentityBridge.js';
|
|
32
|
+
export { getMachineUuid, hostedRuntimeIdOverride, HOSTED_RUNTIME_MACHINE_SOURCES, __resetMachineUuidCacheForTest, } from './machineUuid.js';
|
|
32
33
|
export { ensureMachineDaemonId, legacyDaemonUuids, __resetCachedDaemonIdForTest, } from './machineId.js';
|
|
33
34
|
export { PAIR_AAD_PREFIX, PAIR_AAD_MAX_LEN, PAIR_BUNDLE_MAX_BASE64_LEN, PAIR_NONCE_LEN, PAIR_PUBKEY_LEN, PAIR_SECRET_LEN, PairBundleError, assemblePairBundleBase64, base64ToUint8Array as pairBase64ToUint8Array, base64UrlToUint8Array as pairBase64UrlToUint8Array, buildPairAad, buildPairUrl, generatePairKeyPair, openPairBundleBase64, parsePairBundle, parsePairPlaintext, parsePairUrl, uint8ArrayToBase64 as pairUint8ArrayToBase64, uint8ArrayToBase64Url as pairUint8ArrayToBase64Url, type AssembleBundleOptions as PairAssembleBundleOptions, type OpenBundleOptions as PairOpenBundleOptions, type PairBundle, type PairBundleErrorCode, type PairKeyPair, type PairPlaintextV1, type PairUrlFields, } from './daemonPair.js';
|
|
34
35
|
export { HARNESS_TIERS, getHarnessTier, credentialPolicyForTier, tierPermitsConfiguredAutoMode, type HarnessTrustTier, type CredentialDeliveryPolicy, type CredentialMode, } from './harnessTrust.js';
|
|
35
36
|
export { HARNESSES_LOADING_CLAUDE_SKILLS_LAYOUT, claudeSkillsLayoutEvidence, harnessLoadsClaudeSkillsLayout, } from './harnessSkillLayout.js';
|
|
36
|
-
export { sanitizeSpawnEnv, SENSITIVE_ENV_VARS, SENSITIVE_ENV_PREFIXES, SENSITIVE_ENV_SUFFIXES, SENSITIVE_ENV_NAME_TOKENS, SENSITIVE_ENV_PREFIX_EXCEPTIONS, } from './spawnEnv.js';
|
|
37
|
+
export { sanitizeSpawnEnv, SENSITIVE_ENV_VARS, SENSITIVE_ENV_PREFIXES, SENSITIVE_ENV_SUFFIXES, SENSITIVE_ENV_NAME_TOKENS, SENSITIVE_ENV_PREFIX_EXCEPTIONS, LOOPBACK_NO_PROXY_HOSTS, envHasProxy, withLoopbackNoProxy, } from './spawnEnv.js';
|
|
38
|
+
export { loopbackFetch, assertLoopbackHttpUrl, isLoopbackHostname, isLoopbackAddress, LoopbackTargetRefusedError, LOOPBACK_DEFAULT_MAX_BODY_BYTES, type LoopbackFetch, type LoopbackFetchInit, } from './loopbackHttp.js';
|
|
37
39
|
export { CONFIG_DIR_NAME, LEGACY_CONFIG_DIR_NAMES, NATIVE_ID_PREFIX, LEGACY_NATIVE_ID_PREFIXES, DEFAULT_BINARY_NAME, } from './localIdentity.js';
|
|
38
40
|
export { findLegacyLocalState, describeLegacyState, type LegacyStateFinding, type LegacyStateReport, } from './legacyStatePreflight.js';
|
|
39
41
|
export * from './firstPartyHarness.js';
|
|
@@ -118,7 +118,12 @@ export {
|
|
|
118
118
|
initDeviceIdentity, resetDeviceIdentity, signServerRequest, enrollWithServer, clearEnrollmentMarker, isDeviceIdentityActive, getDevicePublicKey, describeDeviceIdentityState,
|
|
119
119
|
// Test seams — file path resolvers + state setters for spec files.
|
|
120
120
|
__publicKeyPathForTest, __privateKeyPathForTest, __enrollmentMarkerPathForTest, __enrollmentBackoffPathForTest, __setStateForTest as __setDeviceIdentityStateForTest, __getStateForTest as __getDeviceIdentityStateForTest, } from './deviceIdentityBridge.js';
|
|
121
|
+
// Hardware machine identity sent as `machineUuid` (IOPlatformUUID /
|
|
122
|
+
// machine-id / MachineGuid). ONE implementation for daemon and CLI —
|
|
123
|
+
// OSK-12063. Also exposed dependency-free as `@skrr-ai/auth-core/machine-uuid`.
|
|
124
|
+
export { getMachineUuid, hostedRuntimeIdOverride, HOSTED_RUNTIME_MACHINE_SOURCES, __resetMachineUuidCacheForTest, } from './machineUuid.js';
|
|
121
125
|
// Stable per-machine UUIDv7 identity persisted at <configDir>/daemon.id.
|
|
126
|
+
// NOT a `machineUuid` — see machineUuid.ts.
|
|
122
127
|
export { ensureMachineDaemonId, legacyDaemonUuids, __resetCachedDaemonIdForTest, } from './machineId.js';
|
|
123
128
|
// Tier 1 #2 — daemon QR pairing primitives. Pure crypto + AAD framing,
|
|
124
129
|
// shared between the daemon CLI orchestrator (`daemon/src/pair.ts`) and
|
|
@@ -140,7 +145,11 @@ export { HARNESSES_LOADING_CLAUDE_SKILLS_LAYOUT, claudeSkillsLayoutEvidence, har
|
|
|
140
145
|
// spawns the SAME engine and did not). `daemon/src/env-sanitize.ts` re-exports
|
|
141
146
|
// these so its own importers are unchanged, and keeps `filterCustomEnv` — that
|
|
142
147
|
// governs SERVER-PROVIDED env, which no other process is handed.
|
|
143
|
-
export { sanitizeSpawnEnv, SENSITIVE_ENV_VARS, SENSITIVE_ENV_PREFIXES, SENSITIVE_ENV_SUFFIXES, SENSITIVE_ENV_NAME_TOKENS, SENSITIVE_ENV_PREFIX_EXCEPTIONS, } from './spawnEnv.js';
|
|
148
|
+
export { sanitizeSpawnEnv, SENSITIVE_ENV_VARS, SENSITIVE_ENV_PREFIXES, SENSITIVE_ENV_SUFFIXES, SENSITIVE_ENV_NAME_TOKENS, SENSITIVE_ENV_PREFIX_EXCEPTIONS, LOOPBACK_NO_PROXY_HOSTS, envHasProxy, withLoopbackNoProxy, } from './spawnEnv.js';
|
|
149
|
+
// OSK-12134 — the one proxy-free client for loopback HTTP. Bun's fetch (and
|
|
150
|
+
// Node's under NODE_USE_ENV_PROXY) sends 127.0.0.1 requests to HTTP_PROXY,
|
|
151
|
+
// credentials and all; every loopback caller goes through this instead.
|
|
152
|
+
export { loopbackFetch, assertLoopbackHttpUrl, isLoopbackHostname, isLoopbackAddress, LoopbackTargetRefusedError, LOOPBACK_DEFAULT_MAX_BODY_BYTES, } from './loopbackHttp.js';
|
|
144
153
|
/* Local-machine identity — the names this product leaves on a disk. Exported so
|
|
145
154
|
the CLI, daemon and Desktop share one definition instead of 47 literals. */
|
|
146
155
|
export { CONFIG_DIR_NAME, LEGACY_CONFIG_DIR_NAMES, NATIVE_ID_PREFIX, LEGACY_NATIVE_ID_PREFIXES, DEFAULT_BINARY_NAME, } from './localIdentity.js';
|