@skrr-ai/cli 0.1.25 → 0.1.27
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.js +29 -5
- package/dist/commands/code/install.js +13 -0
- package/dist/commands/harnesses/leases/billing.d.ts +9 -6
- package/dist/commands/harnesses/leases/billing.js +19 -24
- package/dist/commands/machines/dedicated/attach.d.ts +28 -0
- package/dist/commands/machines/dedicated/attach.js +76 -0
- package/dist/commands/machines/dedicated/catalog.d.ts +17 -0
- package/dist/commands/machines/dedicated/catalog.js +75 -0
- package/dist/commands/machines/dedicated/cp.d.ts +22 -0
- package/dist/commands/machines/dedicated/cp.js +76 -0
- package/dist/commands/machines/dedicated/create.d.ts +6 -2
- package/dist/commands/machines/dedicated/create.js +29 -20
- package/dist/commands/machines/dedicated/current.d.ts +19 -0
- package/dist/commands/machines/dedicated/current.js +49 -0
- package/dist/commands/machines/dedicated/destroy.d.ts +6 -2
- package/dist/commands/machines/dedicated/destroy.js +43 -25
- package/dist/commands/machines/dedicated/exec.d.ts +32 -0
- package/dist/commands/machines/dedicated/exec.js +122 -0
- package/dist/commands/machines/dedicated/grow.d.ts +6 -2
- package/dist/commands/machines/dedicated/grow.js +16 -20
- package/dist/commands/machines/dedicated/health-check.d.ts +2 -2
- package/dist/commands/machines/dedicated/health-check.js +18 -15
- package/dist/commands/machines/dedicated/incident-close.d.ts +3 -2
- package/dist/commands/machines/dedicated/incident-close.js +13 -15
- package/dist/commands/machines/dedicated/index.js +39 -16
- package/dist/commands/machines/dedicated/list.d.ts +2 -2
- package/dist/commands/machines/dedicated/list.js +28 -17
- package/dist/commands/machines/dedicated/restart.d.ts +5 -2
- package/dist/commands/machines/dedicated/restart.js +10 -20
- package/dist/commands/machines/dedicated/restore.d.ts +26 -0
- package/dist/commands/machines/dedicated/restore.js +64 -0
- package/dist/commands/machines/dedicated/show.d.ts +2 -2
- package/dist/commands/machines/dedicated/show.js +30 -31
- package/dist/commands/machines/dedicated/sign-in.d.ts +19 -0
- package/dist/commands/machines/dedicated/sign-in.js +49 -0
- package/dist/commands/machines/dedicated/snapshot.d.ts +5 -2
- package/dist/commands/machines/dedicated/snapshot.js +13 -20
- package/dist/commands/machines/dedicated/spending-limit.d.ts +22 -0
- package/dist/commands/machines/dedicated/spending-limit.js +51 -0
- package/dist/commands/machines/dedicated/start.d.ts +5 -2
- package/dist/commands/machines/dedicated/start.js +10 -20
- package/dist/commands/machines/dedicated/stop.d.ts +5 -2
- package/dist/commands/machines/dedicated/stop.js +10 -20
- package/dist/commands/machines/dedicated/terminal.d.ts +22 -0
- package/dist/commands/machines/dedicated/terminal.js +42 -0
- package/dist/commands/tasks/list.js +27 -0
- package/dist/lib/daemonBroker.d.ts +8 -0
- package/dist/lib/daemonBroker.js +2 -2
- package/dist/lib/dedicated-copy.d.ts +22 -0
- package/dist/lib/dedicated-copy.js +115 -0
- package/dist/lib/dedicated-exec.d.ts +80 -0
- package/dist/lib/dedicated-exec.js +271 -0
- package/dist/lib/dedicated-lease-command.d.ts +59 -0
- package/dist/lib/dedicated-lease-command.js +181 -0
- package/dist/lib/dedicated-machines.d.ts +337 -12
- package/dist/lib/dedicated-machines.js +502 -25
- package/dist/lib/dedicated-terminal.d.ts +89 -0
- package/dist/lib/dedicated-terminal.js +275 -0
- package/dist/lib/dedicated-wait.d.ts +72 -0
- package/dist/lib/dedicated-wait.js +195 -0
- package/dist/lib/edge-error-page.d.ts +49 -0
- package/dist/lib/edge-error-page.js +120 -0
- package/dist/lib/harnesses.d.ts +15 -1
- package/dist/lib/harnesses.js +20 -2
- package/dist/lib/hosted-machines.js +7 -0
- package/dist/lib/node-adapter.js +1 -1
- package/dist/lib/sky-code.d.ts +30 -1
- package/dist/lib/sky-code.js +44 -2
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.d.ts +1 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.js +2 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/spawnEnv.d.ts +10 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/spawnEnv.js +17 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.d.ts +1 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.js +1 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/spawnEnv.d.ts +10 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/spawnEnv.js +16 -0
- package/dist/node_modules/@skrr-ai/auth-core/package.json +1 -1
- package/dist/node_modules/@skrr-ai/data-provider/index.js +2625 -2608
- package/oclif.manifest.json +27851 -26936
- package/package.json +1 -1
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* edge-error-page.ts — say what an HTML error page from the EDGE means, instead
|
|
4
|
+
* of printing it.
|
|
5
|
+
*
|
|
6
|
+
* Every API route answers in JSON. An HTML page in an error response therefore
|
|
7
|
+
* did not come from the API: it is CloudFront, its web application firewall, or
|
|
8
|
+
* a load balancer answering in the API's place. Printed as-is it is a screen of
|
|
9
|
+
* markup whose one useful line ("Request blocked", a request id) is buried, and
|
|
10
|
+
* treated as an API answer it is misleading in a specific way — a 403 reads as
|
|
11
|
+
* "you lack permission", and CloudFront's 504 page tells the reader to "try again
|
|
12
|
+
* later", which for a write that is still running repeats it.
|
|
13
|
+
*
|
|
14
|
+
* Both happened to `skrr machines dedicated exec` (OSK-8700, OSK-8705): a shell
|
|
15
|
+
* command containing `http://10.0.0.10/` came back as CloudFront's raw
|
|
16
|
+
* "403 ERROR / Request blocked" page, and a command running past 60 seconds as
|
|
17
|
+
* its raw 504 page while it kept running on the machine.
|
|
18
|
+
*
|
|
19
|
+
* General on purpose: nothing here knows which command asked.
|
|
20
|
+
*/
|
|
21
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
+
exports.isHtmlErrorPage = isHtmlErrorPage;
|
|
23
|
+
exports.describeEdgeErrorPage = describeEdgeErrorPage;
|
|
24
|
+
const HTML_START = /^\s*(<!doctype html\b|<html\b)/i;
|
|
25
|
+
const EDGE_MARK = /Generated by cloudfront|The request could not be satisfied/i;
|
|
26
|
+
const REQUEST_ID = /Request ID:\s*([A-Za-z0-9_=-]{8,128})/i;
|
|
27
|
+
const MARKUP = /<(html|head|body|title|h1|pre)\b/i;
|
|
28
|
+
function isJson(body) {
|
|
29
|
+
const trimmed = body.trim();
|
|
30
|
+
if (!trimmed.startsWith('{') && !trimmed.startsWith('['))
|
|
31
|
+
return false;
|
|
32
|
+
try {
|
|
33
|
+
JSON.parse(trimmed);
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* True when an error response body is an HTML page rather than an API answer.
|
|
42
|
+
*
|
|
43
|
+
* A JSON body is never a page, whatever its text says: an API refusal that
|
|
44
|
+
* quotes "The request could not be satisfied" or an HTML fragment in its message
|
|
45
|
+
* must keep its own words (the base command's handler already gates on "no JSON
|
|
46
|
+
* body"; this makes every caller agree). The CloudFront wording counts only
|
|
47
|
+
* inside markup, never on its own.
|
|
48
|
+
*/
|
|
49
|
+
function isHtmlErrorPage(body) {
|
|
50
|
+
if (typeof body !== 'string' || !body || isJson(body))
|
|
51
|
+
return false;
|
|
52
|
+
return HTML_START.test(body) || (MARKUP.test(body) && EDGE_MARK.test(body));
|
|
53
|
+
}
|
|
54
|
+
function readOnly(method) {
|
|
55
|
+
const upper = (method || 'GET').toUpperCase();
|
|
56
|
+
return upper === 'GET' || upper === 'HEAD' || upper === 'OPTIONS';
|
|
57
|
+
}
|
|
58
|
+
function where(host) {
|
|
59
|
+
return host ? ` (${host})` : '';
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Describe an HTML error page, or return null when the body is not one (a JSON
|
|
63
|
+
* refusal from the API must keep its own words).
|
|
64
|
+
*/
|
|
65
|
+
function describeEdgeErrorPage(input) {
|
|
66
|
+
const { body, method, host } = input;
|
|
67
|
+
const status = Number(input.status) || 0;
|
|
68
|
+
if (!isHtmlErrorPage(body))
|
|
69
|
+
return null;
|
|
70
|
+
const requestId = REQUEST_ID.exec(String(body))?.[1];
|
|
71
|
+
const quote = requestId ? ` Edge request id: ${requestId} — quote it when reporting this.` : '';
|
|
72
|
+
const writeOutcome = readOnly(method)
|
|
73
|
+
? 'This request changed nothing; retry shortly.'
|
|
74
|
+
: 'For a write, the request may still have been carried out, or may still be running — check before sending it again.';
|
|
75
|
+
if (status === 403) {
|
|
76
|
+
return {
|
|
77
|
+
status,
|
|
78
|
+
code: 'EDGE_REQUEST_BLOCKED',
|
|
79
|
+
...(requestId ? { requestId } : {}),
|
|
80
|
+
message: `The request was blocked at the edge before it reached the API${where(host)}: a web ` +
|
|
81
|
+
'application firewall rule matched something in it. This is not a problem with your ' +
|
|
82
|
+
'account or permissions. Content that resembles an attack can be enough — a URL with an ' +
|
|
83
|
+
'IP address, a relative path (../), markup or SQL, even inside a command or a document — ' +
|
|
84
|
+
'and sending the same request again will be blocked again.' +
|
|
85
|
+
quote,
|
|
86
|
+
retryable: false,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
if (status === 504) {
|
|
90
|
+
return {
|
|
91
|
+
status,
|
|
92
|
+
code: 'EDGE_GATEWAY_TIMEOUT',
|
|
93
|
+
...(requestId ? { requestId } : {}),
|
|
94
|
+
message: `The edge stopped waiting for the API${where(host)} and answered HTTP 504. ` +
|
|
95
|
+
writeOutcome +
|
|
96
|
+
quote,
|
|
97
|
+
retryable: readOnly(method),
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
if (status === 502 || status === 503) {
|
|
101
|
+
return {
|
|
102
|
+
status,
|
|
103
|
+
code: 'EDGE_ORIGIN_UNAVAILABLE',
|
|
104
|
+
...(requestId ? { requestId } : {}),
|
|
105
|
+
message: `The edge could not get an answer from the API${where(host)} (HTTP ${status}). ` +
|
|
106
|
+
writeOutcome +
|
|
107
|
+
quote,
|
|
108
|
+
retryable: readOnly(method),
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
return {
|
|
112
|
+
status,
|
|
113
|
+
code: 'EDGE_ERROR_PAGE',
|
|
114
|
+
...(requestId ? { requestId } : {}),
|
|
115
|
+
message: `The request did not get an API response: something in front of the API${where(host)} ` +
|
|
116
|
+
`answered HTTP ${status || 'error'} with an HTML page.` +
|
|
117
|
+
quote,
|
|
118
|
+
retryable: false,
|
|
119
|
+
};
|
|
120
|
+
}
|
package/dist/lib/harnesses.d.ts
CHANGED
|
@@ -50,6 +50,12 @@ export interface Harness {
|
|
|
50
50
|
version?: number;
|
|
51
51
|
claudeEngine?: 'cli' | 'sdk';
|
|
52
52
|
lastSeenAt?: string;
|
|
53
|
+
/**
|
|
54
|
+
* Registration metadata. A managed machine's rows carry `machineProduct` and
|
|
55
|
+
* `machineLeaseId`, which is the only link from a lease to the harness rows its
|
|
56
|
+
* daemon registered — the lease payload names no daemon.
|
|
57
|
+
*/
|
|
58
|
+
metadata?: Record<string, unknown>;
|
|
53
59
|
}
|
|
54
60
|
/**
|
|
55
61
|
* One open lease, as `/api/machines/leases` actually returns it.
|
|
@@ -105,7 +111,15 @@ export interface HarnessLease {
|
|
|
105
111
|
createdAt?: string;
|
|
106
112
|
updatedAt?: string;
|
|
107
113
|
}
|
|
108
|
-
/**
|
|
114
|
+
/**
|
|
115
|
+
* Every action `POST /api/machines/leases/:id/actions/:action` accepts —
|
|
116
|
+
* `MACHINE_LEASE_ACTIONS` in MachineLeaseService. Which of them a given lease
|
|
117
|
+
* supports is its product's `lifecycleCapabilities`, decided by the server.
|
|
118
|
+
*
|
|
119
|
+
* `start`, `stop`, `restart` and `snapshot` were missing, so this command
|
|
120
|
+
* refused every Dedicated Runtime lifecycle verb at argument parsing — before
|
|
121
|
+
* the server that accepts them was asked — while claiming to mirror its set.
|
|
122
|
+
*/
|
|
109
123
|
export declare const HARNESS_LEASE_ACTIONS: string[];
|
|
110
124
|
/** `user` (the default) or `workspace`. */
|
|
111
125
|
export type HarnessDefaultScope = 'user' | 'workspace';
|
package/dist/lib/harnesses.js
CHANGED
|
@@ -23,8 +23,26 @@ exports.releaseHarnessLease = releaseHarnessLease;
|
|
|
23
23
|
exports.performHarnessLeaseAction = performHarnessLeaseAction;
|
|
24
24
|
exports.setHarnessLeaseBilling = setHarnessLeaseBilling;
|
|
25
25
|
const api_fetch_1 = require("./api-fetch");
|
|
26
|
-
/**
|
|
27
|
-
|
|
26
|
+
/**
|
|
27
|
+
* Every action `POST /api/machines/leases/:id/actions/:action` accepts —
|
|
28
|
+
* `MACHINE_LEASE_ACTIONS` in MachineLeaseService. Which of them a given lease
|
|
29
|
+
* supports is its product's `lifecycleCapabilities`, decided by the server.
|
|
30
|
+
*
|
|
31
|
+
* `start`, `stop`, `restart` and `snapshot` were missing, so this command
|
|
32
|
+
* refused every Dedicated Runtime lifecycle verb at argument parsing — before
|
|
33
|
+
* the server that accepts them was asked — while claiming to mirror its set.
|
|
34
|
+
*/
|
|
35
|
+
exports.HARNESS_LEASE_ACTIONS = [
|
|
36
|
+
'pause',
|
|
37
|
+
'resume',
|
|
38
|
+
'start',
|
|
39
|
+
'stop',
|
|
40
|
+
'restart',
|
|
41
|
+
'snapshot',
|
|
42
|
+
'destroy',
|
|
43
|
+
'terminate',
|
|
44
|
+
'health-check',
|
|
45
|
+
];
|
|
28
46
|
// ── Fleet reads ────────────────────────────────────────────────────────────
|
|
29
47
|
async function listHarnesses(filters = {}) {
|
|
30
48
|
const params = new URLSearchParams();
|
|
@@ -25,6 +25,7 @@ exports.execHostedMachine = execHostedMachine;
|
|
|
25
25
|
exports.waitForHostedMachineReady = waitForHostedMachineReady;
|
|
26
26
|
exports.offlineForLabel = offlineForLabel;
|
|
27
27
|
const api_fetch_1 = require("./api-fetch");
|
|
28
|
+
const edge_error_page_1 = require("./edge-error-page");
|
|
28
29
|
function curateHostedMachineList(response) {
|
|
29
30
|
return {
|
|
30
31
|
object: 'list',
|
|
@@ -148,6 +149,12 @@ function formatHostedMachineApiError(err) {
|
|
|
148
149
|
if (err.status === 401) {
|
|
149
150
|
return null;
|
|
150
151
|
}
|
|
152
|
+
// An HTML page is the edge answering in the API's place; describe it rather
|
|
153
|
+
// than printing its markup (OSK-8700).
|
|
154
|
+
const edge = (0, edge_error_page_1.describeEdgeErrorPage)({ status: err.status, body: err.body, method: err.method });
|
|
155
|
+
if (edge) {
|
|
156
|
+
return edge.message;
|
|
157
|
+
}
|
|
151
158
|
try {
|
|
152
159
|
const parsed = JSON.parse(err.body);
|
|
153
160
|
return parsed.message || parsed.error || parsed.code || null;
|
package/dist/lib/node-adapter.js
CHANGED
|
@@ -277,7 +277,7 @@ function createNodeAdapter(opts = {}) {
|
|
|
277
277
|
const accessToken = outcome.outcome.accessToken;
|
|
278
278
|
setAdapterCredentialOverride({
|
|
279
279
|
token: accessToken,
|
|
280
|
-
source: 'keychain',
|
|
280
|
+
source: outcome.outcome.storedIn === 'keychain' ? 'keychain' : 'file',
|
|
281
281
|
kind: (0, auth_core_1.classifyTokenKind)(accessToken),
|
|
282
282
|
});
|
|
283
283
|
onTokenRefresh?.(accessToken, outcome.outcome.refreshToken);
|
package/dist/lib/sky-code.d.ts
CHANGED
|
@@ -94,6 +94,32 @@ export declare function resolveEngine(env?: NodeJS.ProcessEnv): EngineResolution
|
|
|
94
94
|
* into a mode the user did not ask for.
|
|
95
95
|
*/
|
|
96
96
|
export declare function buildEngineArgs(subcommand: string | null, passthrough: readonly string[]): string[];
|
|
97
|
+
/**
|
|
98
|
+
* The uid the Dedicated Runtime workload exec wrapper stamps into everything it
|
|
99
|
+
* launches (`infrastructure/packer/files/skrr-workload-exec.c`). Mirrors the
|
|
100
|
+
* daemon's `DEDICATED_WORKLOAD_UID_ENV`.
|
|
101
|
+
*/
|
|
102
|
+
export declare const DEDICATED_WORKLOAD_UID_ENV = "SKRR_WORKLOAD_UID";
|
|
103
|
+
/**
|
|
104
|
+
* True when this process is tenant code on a Dedicated Runtime guest: a
|
|
105
|
+
* terminal, `skrr machines dedicated exec`, an agent's Bash, or an engine
|
|
106
|
+
* session the daemon launched.
|
|
107
|
+
*
|
|
108
|
+
* The variable alone is not enough — anyone can export it — so the process must
|
|
109
|
+
* also BE that uid, the same two-part test the daemon applies. Getting it wrong
|
|
110
|
+
* only changes which message is printed; nothing is authorized by it.
|
|
111
|
+
*/
|
|
112
|
+
export declare function isDedicatedRuntimeWorkload(env?: NodeJS.ProcessEnv, getuid?: (() => number) | undefined): boolean;
|
|
113
|
+
/**
|
|
114
|
+
* Why nothing installs an engine on a Dedicated Runtime.
|
|
115
|
+
*
|
|
116
|
+
* The daemon there installs into its own 0700 home, which the workload identity
|
|
117
|
+
* that runs every engine cannot enter, so both the daemon and the control plane
|
|
118
|
+
* refuse (`DEDICATED_RUNTIME_ENGINE_SHIPS_WITH_IMAGE`). A build in the user's
|
|
119
|
+
* own HOME would run in this terminal but never in a session the daemon starts,
|
|
120
|
+
* so it is not offered either.
|
|
121
|
+
*/
|
|
122
|
+
export declare const DEDICATED_RUNTIME_ENGINE_MESSAGE = "On a Dedicated Runtime, coding engines ship with the machine image. They cannot be installed on a running machine; a newer engine arrives with a newer image.";
|
|
97
123
|
/**
|
|
98
124
|
* Message shown when no engine is installed.
|
|
99
125
|
*
|
|
@@ -116,8 +142,11 @@ export declare function buildEngineArgs(subcommand: string | null, passthrough:
|
|
|
116
142
|
* Keep this in step with what actually ships. An install instruction that does
|
|
117
143
|
* not work is worse than none: it moves the failure from "I could not find how
|
|
118
144
|
* to install it" to "I did what it said and it broke".
|
|
145
|
+
*
|
|
146
|
+
* That is exactly why a Dedicated Runtime gets different text: every route
|
|
147
|
+
* below fails there (see {@link DEDICATED_RUNTIME_ENGINE_MESSAGE}).
|
|
119
148
|
*/
|
|
120
|
-
export declare function notInstalledMessage(): string;
|
|
149
|
+
export declare function notInstalledMessage(env?: NodeJS.ProcessEnv): string;
|
|
121
150
|
/**
|
|
122
151
|
* Spawn the engine with stdio inherited, resolving with its exit code.
|
|
123
152
|
*
|
package/dist/lib/sky-code.js
CHANGED
|
@@ -17,13 +17,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
17
17
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
18
18
|
};
|
|
19
19
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
-
exports.ENGINE_PATH_ENV = void 0;
|
|
20
|
+
exports.DEDICATED_RUNTIME_ENGINE_MESSAGE = exports.DEDICATED_WORKLOAD_UID_ENV = exports.ENGINE_PATH_ENV = void 0;
|
|
21
21
|
exports.engineHome = engineHome;
|
|
22
22
|
exports.skyCodeInstructionHome = skyCodeInstructionHome;
|
|
23
23
|
exports.managedEnginePath = managedEnginePath;
|
|
24
24
|
exports.legacyManagedEnginePath = legacyManagedEnginePath;
|
|
25
25
|
exports.resolveEngine = resolveEngine;
|
|
26
26
|
exports.buildEngineArgs = buildEngineArgs;
|
|
27
|
+
exports.isDedicatedRuntimeWorkload = isDedicatedRuntimeWorkload;
|
|
27
28
|
exports.notInstalledMessage = notInstalledMessage;
|
|
28
29
|
exports.inheritedProviderCredentials = inheritedProviderCredentials;
|
|
29
30
|
exports.hasProviderCredential = hasProviderCredential;
|
|
@@ -204,6 +205,35 @@ function resolveEngine(env = process.env) {
|
|
|
204
205
|
function buildEngineArgs(subcommand, passthrough) {
|
|
205
206
|
return subcommand === null ? [...passthrough] : [subcommand, ...passthrough];
|
|
206
207
|
}
|
|
208
|
+
/**
|
|
209
|
+
* The uid the Dedicated Runtime workload exec wrapper stamps into everything it
|
|
210
|
+
* launches (`infrastructure/packer/files/skrr-workload-exec.c`). Mirrors the
|
|
211
|
+
* daemon's `DEDICATED_WORKLOAD_UID_ENV`.
|
|
212
|
+
*/
|
|
213
|
+
exports.DEDICATED_WORKLOAD_UID_ENV = 'SKRR_WORKLOAD_UID';
|
|
214
|
+
/**
|
|
215
|
+
* True when this process is tenant code on a Dedicated Runtime guest: a
|
|
216
|
+
* terminal, `skrr machines dedicated exec`, an agent's Bash, or an engine
|
|
217
|
+
* session the daemon launched.
|
|
218
|
+
*
|
|
219
|
+
* The variable alone is not enough — anyone can export it — so the process must
|
|
220
|
+
* also BE that uid, the same two-part test the daemon applies. Getting it wrong
|
|
221
|
+
* only changes which message is printed; nothing is authorized by it.
|
|
222
|
+
*/
|
|
223
|
+
function isDedicatedRuntimeWorkload(env = process.env, getuid = process.getuid?.bind(process)) {
|
|
224
|
+
const uid = Number(env[exports.DEDICATED_WORKLOAD_UID_ENV]);
|
|
225
|
+
return Number.isInteger(uid) && uid > 0 && typeof getuid === 'function' && getuid() === uid;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Why nothing installs an engine on a Dedicated Runtime.
|
|
229
|
+
*
|
|
230
|
+
* The daemon there installs into its own 0700 home, which the workload identity
|
|
231
|
+
* that runs every engine cannot enter, so both the daemon and the control plane
|
|
232
|
+
* refuse (`DEDICATED_RUNTIME_ENGINE_SHIPS_WITH_IMAGE`). A build in the user's
|
|
233
|
+
* own HOME would run in this terminal but never in a session the daemon starts,
|
|
234
|
+
* so it is not offered either.
|
|
235
|
+
*/
|
|
236
|
+
exports.DEDICATED_RUNTIME_ENGINE_MESSAGE = 'On a Dedicated Runtime, coding engines ship with the machine image. They cannot be installed on a running machine; a newer engine arrives with a newer image.';
|
|
207
237
|
/**
|
|
208
238
|
* Message shown when no engine is installed.
|
|
209
239
|
*
|
|
@@ -226,8 +256,20 @@ function buildEngineArgs(subcommand, passthrough) {
|
|
|
226
256
|
* Keep this in step with what actually ships. An install instruction that does
|
|
227
257
|
* not work is worse than none: it moves the failure from "I could not find how
|
|
228
258
|
* to install it" to "I did what it said and it broke".
|
|
259
|
+
*
|
|
260
|
+
* That is exactly why a Dedicated Runtime gets different text: every route
|
|
261
|
+
* below fails there (see {@link DEDICATED_RUNTIME_ENGINE_MESSAGE}).
|
|
229
262
|
*/
|
|
230
|
-
function notInstalledMessage() {
|
|
263
|
+
function notInstalledMessage(env = process.env) {
|
|
264
|
+
if (isDedicatedRuntimeWorkload(env)) {
|
|
265
|
+
return [
|
|
266
|
+
'The skrr Code engine (`sky-code`) is not on this machine.',
|
|
267
|
+
'',
|
|
268
|
+
exports.DEDICATED_RUNTIME_ENGINE_MESSAGE,
|
|
269
|
+
'This machine was built from an image without it; it arrives when the',
|
|
270
|
+
"machine's image is replaced. `claude` and `codex` are on the image now.",
|
|
271
|
+
].join('\n');
|
|
272
|
+
}
|
|
231
273
|
return [
|
|
232
274
|
'The skrr Code engine (`sky-code`) is not installed on this machine.',
|
|
233
275
|
'',
|
|
@@ -32,7 +32,7 @@ export { initDeviceIdentity, resetDeviceIdentity, signServerRequest, enrollWithS
|
|
|
32
32
|
export { ensureMachineDaemonId, legacyDaemonUuids, __resetCachedDaemonIdForTest, } from './machineId.js';
|
|
33
33
|
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
34
|
export { HARNESS_TIERS, getHarnessTier, credentialPolicyForTier, tierPermitsConfiguredAutoMode, type HarnessTrustTier, type CredentialDeliveryPolicy, type CredentialMode, } from './harnessTrust.js';
|
|
35
|
-
export { sanitizeSpawnEnv, SENSITIVE_ENV_VARS, SENSITIVE_ENV_PREFIXES, SENSITIVE_ENV_SUFFIXES, SENSITIVE_ENV_PREFIX_EXCEPTIONS, } from './spawnEnv.js';
|
|
35
|
+
export { sanitizeSpawnEnv, SENSITIVE_ENV_VARS, SENSITIVE_ENV_PREFIXES, SENSITIVE_ENV_SUFFIXES, SENSITIVE_ENV_NAME_TOKENS, SENSITIVE_ENV_PREFIX_EXCEPTIONS, } from './spawnEnv.js';
|
|
36
36
|
export { CONFIG_DIR_NAME, LEGACY_CONFIG_DIR_NAMES, NATIVE_ID_PREFIX, LEGACY_NATIVE_ID_PREFIXES, DEFAULT_BINARY_NAME, } from './localIdentity.js';
|
|
37
37
|
export { findLegacyLocalState, describeLegacyState, type LegacyStateFinding, type LegacyStateReport, } from './legacyStatePreflight.js';
|
|
38
38
|
export { DEFAULT_SKY_CODE_CHANNEL, DEFAULT_SKY_CODE_FEED_BASE, SKY_CODE_CHANNELS, SKY_CODE_CHANNEL_ENV, SKY_CODE_MANIFEST_FILE, isSkyCodeChannel, resolveChannelManifestUrl, resolveSkyCodeChannel, skyCodeChannelPrefix, skyCodeFeedBase, SKY_CODE_FEED_BASE_ENV, type SkyCodeChannel, } from './skyCodeChannels.js';
|
|
@@ -11,7 +11,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
11
11
|
exports.challenge = exports.generateVerifier = exports.invalidateHeadersHelperCache = exports.runHeadersHelper = exports.SENTINEL_TRIGGERING_FAILURES = exports.__resetAuthHelperFailureReasonForTest = exports.getLastAuthHelperFailureReason = exports.getDefaultHelperTtlMs = exports.invokeAuthHelper = exports.AuthHelperUnavailableError = exports.AuthHelperUntrustedError = exports.CI_TOKEN_PREFIX = exports.classifyTokenKind = exports.invalidateAuthHelperCache = exports.__resetCredentialResolverForTest = exports.CREDENTIAL_PRECEDENCE = exports.CredentialResolver = exports.__setFdReaderForTest = exports.readAuthFromFd = exports.createRefreshScheduler = exports.UNKNOWN_401_BUDGET = exports.__resetUnknown401StreaksForTest = exports.__refreshDiagnostics = exports.installLockExitHandlers = exports.clearReauthState = exports.needsReauthState = exports.persistReauthState = exports.withAuthLock = exports.revokeDaemonRefreshSession = exports.refreshDaemonToken = exports.classifyRefreshResponse = exports.EXIT_NEEDS_REAUTH = exports.formatReauthMessage = exports.handleMidStreamAuthExpiry = exports.isAuthExpiredSseEvent = exports.decodeJwtPayload = exports.decodeJwtExpiry = exports.TransientAuthFailure = exports.PermanentAuthFailure = exports.emitAuthTelemetry = exports.getAuthBinaryName = exports.getAuthKillSwitches = exports.getAuthConfigDir = exports.getAuthLogger = exports.configureAuthCore = exports.OAUTH_CLI_SCOPE = exports.isDaemonScope = exports.VALID_DAEMON_SCOPE_SET = exports.ALL_DAEMON_SCOPES = exports.SCOPES = void 0;
|
|
12
12
|
exports.tokenHash = exports.publicJwkFromX = exports.normalizeHtu = exports.jwkThumbprint = exports.generateDeviceKeyPair = exports.buildDeviceProof = exports.zeroizeKekCaches = exports.WindowsKek = exports.registerZeroizeHook = exports.MacosKek = exports.LinuxKek = exports.KekUnavailableError = exports.UnavailableKek = exports.InMemoryKek = exports.getKekStrategy = exports.__setKekStrategyForTest = exports.credEnvelopeWrap = exports.credEnvelopeUnwrap = exports.credEnvelopeSerialize = exports.credSealBuffer = exports.credOpenBuffer = exports.CRED_KEY_LEN = exports.isCredEnvelopeString = exports.generateDek = exports.CRED_ENVELOPE_MAGIC = exports.credEnvelopeEncrypt = exports.credEnvelopeDeserialize = exports.credEnvelopeDecrypt = exports.buildCredentialAad = exports.isValidRecoveryCode = exports.normalizeRecoveryCode = exports.parseRecoveryCode = exports.formatRecoveryCode = exports.MAX_TTL_DAYS = exports.MIN_TTL_DAYS = exports.parseTtlDays = exports.LoginExchangeError = exports.LoginInitError = exports.loginWithLocalhost = exports.LocalCallbackMalformedError = exports.LocalCallbackDeniedError = exports.LocalCallbackStateMismatchError = exports.LocalCallbackTimeoutError = exports.LocalCallbackBindError = exports.LocalCallbackError = exports.DEFAULT_LOGIN_TIMEOUT_MS = exports.startLocalCallback = exports.verifyChallenge = exports.safeEqual = exports.generateState = void 0;
|
|
13
13
|
exports.getHarnessTier = exports.HARNESS_TIERS = exports.pairUint8ArrayToBase64Url = exports.pairUint8ArrayToBase64 = exports.parsePairUrl = exports.parsePairPlaintext = exports.parsePairBundle = exports.openPairBundleBase64 = exports.generatePairKeyPair = exports.buildPairUrl = exports.buildPairAad = exports.pairBase64UrlToUint8Array = exports.pairBase64ToUint8Array = exports.assemblePairBundleBase64 = exports.PairBundleError = exports.PAIR_SECRET_LEN = exports.PAIR_PUBKEY_LEN = exports.PAIR_NONCE_LEN = exports.PAIR_BUNDLE_MAX_BASE64_LEN = exports.PAIR_AAD_MAX_LEN = exports.PAIR_AAD_PREFIX = exports.__resetCachedDaemonIdForTest = exports.legacyDaemonUuids = exports.ensureMachineDaemonId = exports.__getDeviceIdentityStateForTest = exports.__setDeviceIdentityStateForTest = exports.__enrollmentBackoffPathForTest = exports.__enrollmentMarkerPathForTest = exports.__privateKeyPathForTest = exports.__publicKeyPathForTest = exports.describeDeviceIdentityState = exports.getDevicePublicKey = exports.isDeviceIdentityActive = exports.clearEnrollmentMarker = exports.enrollWithServer = exports.signServerRequest = exports.resetDeviceIdentity = exports.initDeviceIdentity = exports.__resetShutdownGuardForTest = exports.__getCredEnvelopeStateForTest = exports.__setCredEnvelopeStateForTest = exports.__wrappedDekFilePathForTest = exports.maybeDecryptOnRead = exports.maybeEncryptForWrite = exports.describeCredEnvelopeState = exports.isCredEnvelopeActive = exports.shutdownCredEnvelope = exports.resetCredEnvelope = exports.initCredEnvelope = exports.verifyDeviceProof = void 0;
|
|
14
|
-
exports.isConfigRootOverridden = exports.configRootPath = exports.resolveConfigRoot = exports.verifyManifest = exports.verifyArtifact = exports.getDeltaFor = exports.buildManifestMessage = exports.buildArtifactMessage = exports.MAX_SIGS = exports.OVERSKY_RELEASE_PUBLIC_KEYS = exports.SKY_CODE_FEED_BASE_ENV = exports.skyCodeFeedBase = exports.skyCodeChannelPrefix = exports.resolveSkyCodeChannel = exports.resolveChannelManifestUrl = exports.isSkyCodeChannel = exports.SKY_CODE_MANIFEST_FILE = exports.SKY_CODE_CHANNEL_ENV = exports.SKY_CODE_CHANNELS = exports.DEFAULT_SKY_CODE_FEED_BASE = exports.DEFAULT_SKY_CODE_CHANNEL = exports.describeLegacyState = exports.findLegacyLocalState = exports.DEFAULT_BINARY_NAME = exports.LEGACY_NATIVE_ID_PREFIXES = exports.NATIVE_ID_PREFIX = exports.LEGACY_CONFIG_DIR_NAMES = exports.CONFIG_DIR_NAME = exports.SENSITIVE_ENV_PREFIX_EXCEPTIONS = exports.SENSITIVE_ENV_SUFFIXES = exports.SENSITIVE_ENV_PREFIXES = exports.SENSITIVE_ENV_VARS = exports.sanitizeSpawnEnv = exports.tierPermitsConfiguredAutoMode = exports.credentialPolicyForTier = void 0;
|
|
14
|
+
exports.isConfigRootOverridden = exports.configRootPath = exports.resolveConfigRoot = exports.verifyManifest = exports.verifyArtifact = exports.getDeltaFor = exports.buildManifestMessage = exports.buildArtifactMessage = exports.MAX_SIGS = exports.OVERSKY_RELEASE_PUBLIC_KEYS = exports.SKY_CODE_FEED_BASE_ENV = exports.skyCodeFeedBase = exports.skyCodeChannelPrefix = exports.resolveSkyCodeChannel = exports.resolveChannelManifestUrl = exports.isSkyCodeChannel = exports.SKY_CODE_MANIFEST_FILE = exports.SKY_CODE_CHANNEL_ENV = exports.SKY_CODE_CHANNELS = exports.DEFAULT_SKY_CODE_FEED_BASE = exports.DEFAULT_SKY_CODE_CHANNEL = exports.describeLegacyState = exports.findLegacyLocalState = exports.DEFAULT_BINARY_NAME = exports.LEGACY_NATIVE_ID_PREFIXES = exports.NATIVE_ID_PREFIX = exports.LEGACY_CONFIG_DIR_NAMES = exports.CONFIG_DIR_NAME = exports.SENSITIVE_ENV_PREFIX_EXCEPTIONS = exports.SENSITIVE_ENV_NAME_TOKENS = exports.SENSITIVE_ENV_SUFFIXES = exports.SENSITIVE_ENV_PREFIXES = exports.SENSITIVE_ENV_VARS = exports.sanitizeSpawnEnv = exports.tierPermitsConfiguredAutoMode = exports.credentialPolicyForTier = void 0;
|
|
15
15
|
// Daemon scope vocabulary — single source of truth for non-Mongoose tiers
|
|
16
16
|
// (daemon, desktop, cli). Schema-bound canonical lives in
|
|
17
17
|
// `@skrr-ai/data-schemas/common/daemonScopes`; the two are kept byte-equal
|
|
@@ -289,6 +289,7 @@ Object.defineProperty(exports, "sanitizeSpawnEnv", { enumerable: true, get: func
|
|
|
289
289
|
Object.defineProperty(exports, "SENSITIVE_ENV_VARS", { enumerable: true, get: function () { return spawnEnv_js_1.SENSITIVE_ENV_VARS; } });
|
|
290
290
|
Object.defineProperty(exports, "SENSITIVE_ENV_PREFIXES", { enumerable: true, get: function () { return spawnEnv_js_1.SENSITIVE_ENV_PREFIXES; } });
|
|
291
291
|
Object.defineProperty(exports, "SENSITIVE_ENV_SUFFIXES", { enumerable: true, get: function () { return spawnEnv_js_1.SENSITIVE_ENV_SUFFIXES; } });
|
|
292
|
+
Object.defineProperty(exports, "SENSITIVE_ENV_NAME_TOKENS", { enumerable: true, get: function () { return spawnEnv_js_1.SENSITIVE_ENV_NAME_TOKENS; } });
|
|
292
293
|
Object.defineProperty(exports, "SENSITIVE_ENV_PREFIX_EXCEPTIONS", { enumerable: true, get: function () { return spawnEnv_js_1.SENSITIVE_ENV_PREFIX_EXCEPTIONS; } });
|
|
293
294
|
/* Local-machine identity — the names this product leaves on a disk. Exported so
|
|
294
295
|
the CLI, daemon and Desktop share one definition instead of 47 literals. */
|
|
@@ -65,6 +65,16 @@ export declare const SENSITIVE_ENV_PREFIXES: readonly string[];
|
|
|
65
65
|
* per-request allow-list, never by ambient inheritance.
|
|
66
66
|
*/
|
|
67
67
|
export declare const SENSITIVE_ENV_SUFFIXES: readonly string[];
|
|
68
|
+
/**
|
|
69
|
+
* Credential-shaped name TOKENS: an underscore-delimited segment anywhere in
|
|
70
|
+
* the name, not only at its end. Rotation slots put the qualifier AFTER the
|
|
71
|
+
* credential word — `SKRR_EDGE_ORIGIN_SECRET_SECONDARY`,
|
|
72
|
+
* `SCHEDULER_SIGNING_SECRET_PREVIOUS` — which every suffix above misses, so a
|
|
73
|
+
* second copy of a live secret would ride into a harness while the first was
|
|
74
|
+
* stripped. Whole-segment matching keeps `SECRETS_MANAGER_REGION` and
|
|
75
|
+
* `SECRETARY` untouched.
|
|
76
|
+
*/
|
|
77
|
+
export declare const SENSITIVE_ENV_NAME_TOKENS: readonly string[];
|
|
68
78
|
/** Specific OVERSKY_ vars to keep (the prefix sweep is broad on purpose). */
|
|
69
79
|
export declare const SENSITIVE_ENV_PREFIX_EXCEPTIONS: ReadonlySet<string>;
|
|
70
80
|
/**
|
|
@@ -40,7 +40,7 @@
|
|
|
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_SUFFIXES = exports.SENSITIVE_ENV_PREFIXES = exports.SENSITIVE_ENV_VARS = void 0;
|
|
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;
|
|
44
44
|
exports.sanitizeSpawnEnv = sanitizeSpawnEnv;
|
|
45
45
|
/**
|
|
46
46
|
* Env vars that must NEVER reach a spawned subprocess.
|
|
@@ -110,6 +110,16 @@ exports.SENSITIVE_ENV_SUFFIXES = [
|
|
|
110
110
|
'_PASSWORD',
|
|
111
111
|
'_CREDENTIALS',
|
|
112
112
|
];
|
|
113
|
+
/**
|
|
114
|
+
* Credential-shaped name TOKENS: an underscore-delimited segment anywhere in
|
|
115
|
+
* the name, not only at its end. Rotation slots put the qualifier AFTER the
|
|
116
|
+
* credential word — `SKRR_EDGE_ORIGIN_SECRET_SECONDARY`,
|
|
117
|
+
* `SCHEDULER_SIGNING_SECRET_PREVIOUS` — which every suffix above misses, so a
|
|
118
|
+
* second copy of a live secret would ride into a harness while the first was
|
|
119
|
+
* stripped. Whole-segment matching keeps `SECRETS_MANAGER_REGION` and
|
|
120
|
+
* `SECRETARY` untouched.
|
|
121
|
+
*/
|
|
122
|
+
exports.SENSITIVE_ENV_NAME_TOKENS = ['SECRET'];
|
|
113
123
|
/** Specific OVERSKY_ vars to keep (the prefix sweep is broad on purpose). */
|
|
114
124
|
exports.SENSITIVE_ENV_PREFIX_EXCEPTIONS = new Set([
|
|
115
125
|
// Headless flag is read by spawned tools to know they're inside the daemon —
|
|
@@ -145,6 +155,12 @@ function sanitizeSpawnEnv(env) {
|
|
|
145
155
|
if (!stripped && exports.SENSITIVE_ENV_SUFFIXES.some((suffix) => key.endsWith(suffix))) {
|
|
146
156
|
stripped = true;
|
|
147
157
|
}
|
|
158
|
+
if (!stripped) {
|
|
159
|
+
const segments = key.split('_');
|
|
160
|
+
if (exports.SENSITIVE_ENV_NAME_TOKENS.some((token) => segments.includes(token))) {
|
|
161
|
+
stripped = true;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
148
164
|
if (stripped)
|
|
149
165
|
continue;
|
|
150
166
|
out[key] = value;
|
|
@@ -32,7 +32,7 @@ export { initDeviceIdentity, resetDeviceIdentity, signServerRequest, enrollWithS
|
|
|
32
32
|
export { ensureMachineDaemonId, legacyDaemonUuids, __resetCachedDaemonIdForTest, } from './machineId.js';
|
|
33
33
|
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
34
|
export { HARNESS_TIERS, getHarnessTier, credentialPolicyForTier, tierPermitsConfiguredAutoMode, type HarnessTrustTier, type CredentialDeliveryPolicy, type CredentialMode, } from './harnessTrust.js';
|
|
35
|
-
export { sanitizeSpawnEnv, SENSITIVE_ENV_VARS, SENSITIVE_ENV_PREFIXES, SENSITIVE_ENV_SUFFIXES, SENSITIVE_ENV_PREFIX_EXCEPTIONS, } from './spawnEnv.js';
|
|
35
|
+
export { sanitizeSpawnEnv, SENSITIVE_ENV_VARS, SENSITIVE_ENV_PREFIXES, SENSITIVE_ENV_SUFFIXES, SENSITIVE_ENV_NAME_TOKENS, SENSITIVE_ENV_PREFIX_EXCEPTIONS, } from './spawnEnv.js';
|
|
36
36
|
export { CONFIG_DIR_NAME, LEGACY_CONFIG_DIR_NAMES, NATIVE_ID_PREFIX, LEGACY_NATIVE_ID_PREFIXES, DEFAULT_BINARY_NAME, } from './localIdentity.js';
|
|
37
37
|
export { findLegacyLocalState, describeLegacyState, type LegacyStateFinding, type LegacyStateReport, } from './legacyStatePreflight.js';
|
|
38
38
|
export { DEFAULT_SKY_CODE_CHANNEL, DEFAULT_SKY_CODE_FEED_BASE, SKY_CODE_CHANNELS, SKY_CODE_CHANNEL_ENV, SKY_CODE_MANIFEST_FILE, isSkyCodeChannel, resolveChannelManifestUrl, resolveSkyCodeChannel, skyCodeChannelPrefix, skyCodeFeedBase, SKY_CODE_FEED_BASE_ENV, type SkyCodeChannel, } from './skyCodeChannels.js';
|
|
@@ -135,7 +135,7 @@ export { HARNESS_TIERS, getHarnessTier, credentialPolicyForTier, tierPermitsConf
|
|
|
135
135
|
// spawns the SAME engine and did not). `daemon/src/env-sanitize.ts` re-exports
|
|
136
136
|
// these so its own importers are unchanged, and keeps `filterCustomEnv` — that
|
|
137
137
|
// governs SERVER-PROVIDED env, which no other process is handed.
|
|
138
|
-
export { sanitizeSpawnEnv, SENSITIVE_ENV_VARS, SENSITIVE_ENV_PREFIXES, SENSITIVE_ENV_SUFFIXES, SENSITIVE_ENV_PREFIX_EXCEPTIONS, } from './spawnEnv.js';
|
|
138
|
+
export { sanitizeSpawnEnv, SENSITIVE_ENV_VARS, SENSITIVE_ENV_PREFIXES, SENSITIVE_ENV_SUFFIXES, SENSITIVE_ENV_NAME_TOKENS, SENSITIVE_ENV_PREFIX_EXCEPTIONS, } from './spawnEnv.js';
|
|
139
139
|
/* Local-machine identity — the names this product leaves on a disk. Exported so
|
|
140
140
|
the CLI, daemon and Desktop share one definition instead of 47 literals. */
|
|
141
141
|
export { CONFIG_DIR_NAME, LEGACY_CONFIG_DIR_NAMES, NATIVE_ID_PREFIX, LEGACY_NATIVE_ID_PREFIXES, DEFAULT_BINARY_NAME, } from './localIdentity.js';
|
|
@@ -65,6 +65,16 @@ export declare const SENSITIVE_ENV_PREFIXES: readonly string[];
|
|
|
65
65
|
* per-request allow-list, never by ambient inheritance.
|
|
66
66
|
*/
|
|
67
67
|
export declare const SENSITIVE_ENV_SUFFIXES: readonly string[];
|
|
68
|
+
/**
|
|
69
|
+
* Credential-shaped name TOKENS: an underscore-delimited segment anywhere in
|
|
70
|
+
* the name, not only at its end. Rotation slots put the qualifier AFTER the
|
|
71
|
+
* credential word — `SKRR_EDGE_ORIGIN_SECRET_SECONDARY`,
|
|
72
|
+
* `SCHEDULER_SIGNING_SECRET_PREVIOUS` — which every suffix above misses, so a
|
|
73
|
+
* second copy of a live secret would ride into a harness while the first was
|
|
74
|
+
* stripped. Whole-segment matching keeps `SECRETS_MANAGER_REGION` and
|
|
75
|
+
* `SECRETARY` untouched.
|
|
76
|
+
*/
|
|
77
|
+
export declare const SENSITIVE_ENV_NAME_TOKENS: readonly string[];
|
|
68
78
|
/** Specific OVERSKY_ vars to keep (the prefix sweep is broad on purpose). */
|
|
69
79
|
export declare const SENSITIVE_ENV_PREFIX_EXCEPTIONS: ReadonlySet<string>;
|
|
70
80
|
/**
|
|
@@ -106,6 +106,16 @@ export const SENSITIVE_ENV_SUFFIXES = [
|
|
|
106
106
|
'_PASSWORD',
|
|
107
107
|
'_CREDENTIALS',
|
|
108
108
|
];
|
|
109
|
+
/**
|
|
110
|
+
* Credential-shaped name TOKENS: an underscore-delimited segment anywhere in
|
|
111
|
+
* the name, not only at its end. Rotation slots put the qualifier AFTER the
|
|
112
|
+
* credential word — `SKRR_EDGE_ORIGIN_SECRET_SECONDARY`,
|
|
113
|
+
* `SCHEDULER_SIGNING_SECRET_PREVIOUS` — which every suffix above misses, so a
|
|
114
|
+
* second copy of a live secret would ride into a harness while the first was
|
|
115
|
+
* stripped. Whole-segment matching keeps `SECRETS_MANAGER_REGION` and
|
|
116
|
+
* `SECRETARY` untouched.
|
|
117
|
+
*/
|
|
118
|
+
export const SENSITIVE_ENV_NAME_TOKENS = ['SECRET'];
|
|
109
119
|
/** Specific OVERSKY_ vars to keep (the prefix sweep is broad on purpose). */
|
|
110
120
|
export const SENSITIVE_ENV_PREFIX_EXCEPTIONS = new Set([
|
|
111
121
|
// Headless flag is read by spawned tools to know they're inside the daemon —
|
|
@@ -141,6 +151,12 @@ export function sanitizeSpawnEnv(env) {
|
|
|
141
151
|
if (!stripped && SENSITIVE_ENV_SUFFIXES.some((suffix) => key.endsWith(suffix))) {
|
|
142
152
|
stripped = true;
|
|
143
153
|
}
|
|
154
|
+
if (!stripped) {
|
|
155
|
+
const segments = key.split('_');
|
|
156
|
+
if (SENSITIVE_ENV_NAME_TOKENS.some((token) => segments.includes(token))) {
|
|
157
|
+
stripped = true;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
144
160
|
if (stripped)
|
|
145
161
|
continue;
|
|
146
162
|
out[key] = value;
|