@skrr-ai/cli 0.1.80 → 0.1.82
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 +20 -0
- package/dist/base-command.js +151 -7
- package/dist/commands/agents/visibility.d.ts +14 -0
- package/dist/commands/agents/visibility.js +52 -0
- package/dist/commands/create-token.d.ts +0 -1
- package/dist/commands/create-token.js +3 -1
- package/dist/commands/followups/checkin.js +1 -1
- package/dist/commands/list-tokens.d.ts +0 -1
- package/dist/commands/list-tokens.js +1 -1
- package/dist/commands/login.js +10 -0
- package/dist/commands/logout.js +4 -0
- package/dist/commands/machines/dedicated/ssh-proxy.js +1 -0
- package/dist/commands/revoke-token.d.ts +0 -1
- package/dist/commands/revoke-token.js +1 -1
- package/dist/commands/store/follow.d.ts +1 -0
- package/dist/commands/store/follow.js +7 -1
- package/dist/commands/store/follows/list.d.ts +11 -0
- package/dist/commands/store/follows/list.js +29 -0
- package/dist/commands/store/follows/remove.d.ts +16 -0
- package/dist/commands/store/follows/remove.js +37 -0
- package/dist/commands/store/installs.js +6 -1
- package/dist/commands/store/publishers/profile/draft.d.ts +17 -0
- package/dist/commands/store/publishers/profile/draft.js +54 -0
- package/dist/commands/store/publishers/profile/handle.d.ts +14 -0
- package/dist/commands/store/publishers/profile/handle.js +39 -0
- package/dist/commands/store/publishers/profile/hide.d.ts +12 -0
- package/dist/commands/store/publishers/profile/hide.js +39 -0
- package/dist/commands/store/publishers/profile/preview.d.ts +11 -0
- package/dist/commands/store/publishers/profile/preview.js +39 -0
- package/dist/commands/store/publishers/profile/publish.d.ts +12 -0
- package/dist/commands/store/publishers/profile/publish.js +41 -0
- package/dist/commands/store/publishers/profile/restore.d.ts +15 -0
- package/dist/commands/store/publishers/profile/restore.js +49 -0
- package/dist/commands/store/publishers/profile/revisions.d.ts +11 -0
- package/dist/commands/store/publishers/profile/revisions.js +30 -0
- package/dist/commands/store/publishers/profile/show.d.ts +11 -0
- package/dist/commands/store/publishers/profile/show.js +39 -0
- package/dist/commands/store/review.d.ts +26 -0
- package/dist/commands/store/review.js +93 -0
- package/dist/commands/store/reviews.d.ts +29 -0
- package/dist/commands/store/reviews.js +170 -0
- package/dist/commands/store/tip.d.ts +20 -0
- package/dist/commands/store/tip.js +57 -0
- package/dist/commands/tokens/create.d.ts +28 -0
- package/dist/commands/tokens/create.js +136 -0
- package/dist/commands/tokens/list.d.ts +11 -0
- package/dist/commands/tokens/list.js +53 -0
- package/dist/commands/tokens/revoke.d.ts +14 -0
- package/dist/commands/tokens/revoke.js +42 -0
- package/dist/lib/access-tokens.d.ts +59 -0
- package/dist/lib/access-tokens.js +50 -0
- package/dist/lib/auth-core-init.d.ts +6 -0
- package/dist/lib/auth-core-init.js +28 -6
- package/dist/lib/auth-storage.d.ts +5 -0
- package/dist/lib/auth-storage.js +8 -0
- package/dist/lib/config.d.ts +8 -0
- package/dist/lib/credential-resolver.d.ts +1 -1
- package/dist/lib/credential-resolver.js +15 -3
- package/dist/lib/daemonBroker.d.ts +48 -2
- package/dist/lib/daemonBroker.js +193 -15
- package/dist/lib/daemonBrokerRefusal.d.ts +14 -0
- package/dist/lib/daemonBrokerRefusal.js +18 -1
- package/dist/lib/dedicated-ssh.d.ts +9 -0
- package/dist/lib/dedicated-ssh.js +232 -63
- package/dist/lib/harness-context.d.ts +8 -0
- package/dist/lib/harness-context.js +55 -0
- package/dist/lib/login.js +4 -1
- package/dist/lib/node-adapter.js +2 -2
- package/dist/lib/publisher-profile-flags.d.ts +19 -0
- package/dist/lib/publisher-profile-flags.js +48 -0
- package/dist/lib/refresh.d.ts +1 -1
- package/dist/lib/refresh.js +10 -1
- package/dist/lib/ssh-ordered-bytes.d.ts +8 -0
- package/dist/lib/ssh-ordered-bytes.js +31 -0
- package/dist/lib/usd-micros.d.ts +9 -0
- package/dist/lib/usd-micros.js +21 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/credentialResolver.d.ts +22 -3
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/credentialResolver.js +29 -5
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/deviceIdentityBridge.d.ts +7 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/deviceIdentityBridge.js +7 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.d.ts +2 -2
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.js +9 -5
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/spawnEnv.d.ts +25 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/spawnEnv.js +35 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/credentialResolver.d.ts +22 -3
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/credentialResolver.js +27 -4
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/deviceIdentityBridge.d.ts +7 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/deviceIdentityBridge.js +7 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.d.ts +2 -2
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.js +2 -2
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/spawnEnv.d.ts +25 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/spawnEnv.js +33 -0
- package/dist/node_modules/@skrr-ai/auth-core/package.json +1 -1
- package/dist/node_modules/@skrr-ai/data-provider/index.js +4302 -4249
- package/oclif.manifest.json +41314 -39972
- package/package.json +28 -4
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SshOrderedBytes = void 0;
|
|
4
|
+
/** A bounded receiver for a retryable SSH byte stream. One frame may be
|
|
5
|
+
* outstanding. A lost acknowledgment may repeat that exact frame, never its
|
|
6
|
+
* bytes; an overlapping, changed, or skipped frame is a stream error. */
|
|
7
|
+
class SshOrderedBytes {
|
|
8
|
+
nextOffset = 0;
|
|
9
|
+
last;
|
|
10
|
+
receive(offset, bytes, write) {
|
|
11
|
+
if (!Number.isSafeInteger(offset) || offset < 0 || bytes.length < 1 || bytes.length > 16 * 1024 ||
|
|
12
|
+
!Number.isSafeInteger(offset + bytes.length)) {
|
|
13
|
+
return Promise.reject(new Error('invalid SSH stream frame'));
|
|
14
|
+
}
|
|
15
|
+
if (this.last?.offset === offset) {
|
|
16
|
+
return this.last.bytes.equals(bytes)
|
|
17
|
+
? this.last.written
|
|
18
|
+
: Promise.reject(new Error('changed SSH stream replay'));
|
|
19
|
+
}
|
|
20
|
+
if (offset !== this.nextOffset)
|
|
21
|
+
return Promise.reject(new Error('SSH stream offset mismatch'));
|
|
22
|
+
const retained = Buffer.from(bytes);
|
|
23
|
+
const written = Promise.resolve().then(() => write(retained)).then(() => {
|
|
24
|
+
this.nextOffset = offset + retained.length;
|
|
25
|
+
return this.nextOffset;
|
|
26
|
+
});
|
|
27
|
+
this.last = { offset, bytes: retained, written };
|
|
28
|
+
return written;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
exports.SshOrderedBytes = SshOrderedBytes;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse a user-typed USD amount ("5", "2.50") into integer micros.
|
|
3
|
+
*
|
|
4
|
+
* Integer arithmetic on the decimal STRING, never `Number(x) * 1e6`: binary
|
|
5
|
+
* floating point turns 0.29 into 289999.99… and a money path that truncates
|
|
6
|
+
* that charges a micro less — or, rounded the other way, a micro more.
|
|
7
|
+
* Returns null for anything that is not a positive amount with ≤ 2 decimals.
|
|
8
|
+
*/
|
|
9
|
+
export declare function usdToMicros(amount: string): number | null;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.usdToMicros = usdToMicros;
|
|
4
|
+
/**
|
|
5
|
+
* Parse a user-typed USD amount ("5", "2.50") into integer micros.
|
|
6
|
+
*
|
|
7
|
+
* Integer arithmetic on the decimal STRING, never `Number(x) * 1e6`: binary
|
|
8
|
+
* floating point turns 0.29 into 289999.99… and a money path that truncates
|
|
9
|
+
* that charges a micro less — or, rounded the other way, a micro more.
|
|
10
|
+
* Returns null for anything that is not a positive amount with ≤ 2 decimals.
|
|
11
|
+
*/
|
|
12
|
+
function usdToMicros(amount) {
|
|
13
|
+
const trimmed = amount.trim();
|
|
14
|
+
if (!/^\d+(\.\d{1,2})?$/.test(trimmed))
|
|
15
|
+
return null;
|
|
16
|
+
const [whole, frac = ''] = trimmed.split('.');
|
|
17
|
+
const cents = Number(whole) * 100 + Number(frac.padEnd(2, '0'));
|
|
18
|
+
if (!Number.isSafeInteger(cents) || cents <= 0)
|
|
19
|
+
return null;
|
|
20
|
+
return cents * 10_000;
|
|
21
|
+
}
|
|
@@ -13,8 +13,11 @@
|
|
|
13
13
|
* Precedence (high → low):
|
|
14
14
|
*
|
|
15
15
|
* 1. flag — `--token <jwt>` CLI flag (debugging)
|
|
16
|
-
* 2. env-token — `OVERSKY_TOKEN`
|
|
17
|
-
*
|
|
16
|
+
* 2. env-token — `OVERSKY_TOKEN` (CI / static). The CLI also reads
|
|
17
|
+
* `SKRR_TOKEN` via `envTokenNames`; `OVERSKY_TOKEN` wins
|
|
18
|
+
* when both are set, matching the CLI config overlay. A
|
|
19
|
+
* personal access token (`osk_pat_*`) is the credential
|
|
20
|
+
* CI should put here.
|
|
18
21
|
* 3. auth-helper — `OVERSKY_AUTH_HELPER` script output (rotating
|
|
19
22
|
* creds — Vault, AWS SM, internal SSO proxy)
|
|
20
23
|
* 4. fd-handoff — `OVERSKY_AUTH_FD` parent→child IPC (Electron
|
|
@@ -64,6 +67,12 @@ export interface CredentialResolverOptions {
|
|
|
64
67
|
* string to use that value directly.
|
|
65
68
|
*/
|
|
66
69
|
envTokenOverride?: string | null;
|
|
70
|
+
/**
|
|
71
|
+
* Environment variables read by the env-token slot, in precedence order.
|
|
72
|
+
* Defaults to `['OVERSKY_TOKEN']`. The CLI passes
|
|
73
|
+
* `['OVERSKY_TOKEN', 'SKRR_TOKEN']` (OSK-13208).
|
|
74
|
+
*/
|
|
75
|
+
envTokenNames?: readonly string[];
|
|
67
76
|
/** Test/explicit override for `OVERSKY_AUTH_HELPER` env. Same semantics. */
|
|
68
77
|
authHelperPathOverride?: string | null;
|
|
69
78
|
/**
|
|
@@ -143,6 +152,8 @@ export interface AuthHelperSentinelInfo {
|
|
|
143
152
|
* (POST /api/daemons/token), MUST NOT schedule refresh,
|
|
144
153
|
* and on auth failure exits 75 with a CI-specific error
|
|
145
154
|
* rather than writing needs-reauth.json.
|
|
155
|
+
* - 'pat' — personal access token (`osk_pat_*`, OSK-13208): a static
|
|
156
|
+
* bearer used AS the user by the CLI. Never refreshed.
|
|
146
157
|
* - 'install' — short-lived web-minted JWT with `scope=daemon-install`.
|
|
147
158
|
* The daemon exchanges it through the same /api/daemons/token
|
|
148
159
|
* bootstrap path, persists only the returned daemon
|
|
@@ -157,9 +168,17 @@ export interface AuthHelperSentinelInfo {
|
|
|
157
168
|
* The kill switch `OVERSKY_DISABLE_CI_TOKEN_RESOLVER=1` forces every token to
|
|
158
169
|
* `'standard'` for triage purposes.
|
|
159
170
|
*/
|
|
160
|
-
export type TokenKind = 'standard' | 'ci' | 'install';
|
|
171
|
+
export type TokenKind = 'standard' | 'ci' | 'install' | 'pat';
|
|
161
172
|
/** CI-token plaintext prefix; mirrors api/server/services/Auth/daemonCiTokens.js. */
|
|
162
173
|
export declare const CI_TOKEN_PREFIX = "osk_ci_";
|
|
174
|
+
/** Personal-access-token prefix; mirrors api/server/services/Auth/personalAccessTokens.js. */
|
|
175
|
+
export declare const PERSONAL_ACCESS_TOKEN_PREFIX = "osk_pat_";
|
|
176
|
+
/**
|
|
177
|
+
* True for a kind whose token is static by construction: never refreshed,
|
|
178
|
+
* never rotated into a store. Like `TokenKind` itself this selects a local
|
|
179
|
+
* code path and grants nothing.
|
|
180
|
+
*/
|
|
181
|
+
export declare function isStaticTokenKind(kind: TokenKind): boolean;
|
|
163
182
|
/**
|
|
164
183
|
* Classify a token by local shape. Pure function; safe to call on any string
|
|
165
184
|
* (including `null`-coerced empty). Returns `'standard'` for empty input
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.CredentialResolver = exports.AuthHelperUntrustedError = exports.AuthHelperUnavailableError = exports.CI_TOKEN_PREFIX = exports.CREDENTIAL_PRECEDENCE = void 0;
|
|
3
|
+
exports.CredentialResolver = exports.AuthHelperUntrustedError = exports.AuthHelperUnavailableError = exports.PERSONAL_ACCESS_TOKEN_PREFIX = exports.CI_TOKEN_PREFIX = exports.CREDENTIAL_PRECEDENCE = void 0;
|
|
4
|
+
exports.isStaticTokenKind = isStaticTokenKind;
|
|
4
5
|
exports.classifyTokenKind = classifyTokenKind;
|
|
5
6
|
exports.__resetCredentialResolverForTest = __resetCredentialResolverForTest;
|
|
6
7
|
exports.invalidateAuthHelperCache = invalidateAuthHelperCache;
|
|
@@ -19,8 +20,11 @@ exports.invalidateAuthHelperCache = invalidateAuthHelperCache;
|
|
|
19
20
|
* Precedence (high → low):
|
|
20
21
|
*
|
|
21
22
|
* 1. flag — `--token <jwt>` CLI flag (debugging)
|
|
22
|
-
* 2. env-token — `OVERSKY_TOKEN`
|
|
23
|
-
*
|
|
23
|
+
* 2. env-token — `OVERSKY_TOKEN` (CI / static). The CLI also reads
|
|
24
|
+
* `SKRR_TOKEN` via `envTokenNames`; `OVERSKY_TOKEN` wins
|
|
25
|
+
* when both are set, matching the CLI config overlay. A
|
|
26
|
+
* personal access token (`osk_pat_*`) is the credential
|
|
27
|
+
* CI should put here.
|
|
24
28
|
* 3. auth-helper — `OVERSKY_AUTH_HELPER` script output (rotating
|
|
25
29
|
* creds — Vault, AWS SM, internal SSO proxy)
|
|
26
30
|
* 4. fd-handoff — `OVERSKY_AUTH_FD` parent→child IPC (Electron
|
|
@@ -68,6 +72,16 @@ exports.CREDENTIAL_PRECEDENCE = [
|
|
|
68
72
|
];
|
|
69
73
|
/** CI-token plaintext prefix; mirrors api/server/services/Auth/daemonCiTokens.js. */
|
|
70
74
|
exports.CI_TOKEN_PREFIX = 'osk_ci_';
|
|
75
|
+
/** Personal-access-token prefix; mirrors api/server/services/Auth/personalAccessTokens.js. */
|
|
76
|
+
exports.PERSONAL_ACCESS_TOKEN_PREFIX = 'osk_pat_';
|
|
77
|
+
/**
|
|
78
|
+
* True for a kind whose token is static by construction: never refreshed,
|
|
79
|
+
* never rotated into a store. Like `TokenKind` itself this selects a local
|
|
80
|
+
* code path and grants nothing.
|
|
81
|
+
*/
|
|
82
|
+
function isStaticTokenKind(kind) {
|
|
83
|
+
return kind === 'ci' || kind === 'pat';
|
|
84
|
+
}
|
|
71
85
|
/**
|
|
72
86
|
* Classify a token by local shape. Pure function; safe to call on any string
|
|
73
87
|
* (including `null`-coerced empty). Returns `'standard'` for empty input
|
|
@@ -103,6 +117,8 @@ function classifyTokenKind(token) {
|
|
|
103
117
|
return 'standard';
|
|
104
118
|
if (token.startsWith(exports.CI_TOKEN_PREFIX))
|
|
105
119
|
return 'ci';
|
|
120
|
+
if (token.startsWith(exports.PERSONAL_ACCESS_TOKEN_PREFIX))
|
|
121
|
+
return 'pat';
|
|
106
122
|
const payload = (0, jwtUtils_js_1.decodeJwtPayload)(token);
|
|
107
123
|
if (payload &&
|
|
108
124
|
typeof payload === 'object' &&
|
|
@@ -260,8 +276,16 @@ class CredentialResolver {
|
|
|
260
276
|
if (typeof this.opts.envTokenOverride === 'string') {
|
|
261
277
|
return this.opts.envTokenOverride.length > 0 ? this.opts.envTokenOverride : null;
|
|
262
278
|
}
|
|
263
|
-
|
|
264
|
-
|
|
279
|
+
// `OVERSKY_TOKEN` first (retained by decision, docs/product/skrr-env-inventory.md),
|
|
280
|
+
// then any renamed spelling the caller opted into (`SKRR_TOKEN` for the CLI,
|
|
281
|
+
// OSK-13208). The daemon does not opt in: a CI job that sets `SKRR_TOKEN`
|
|
282
|
+
// for `skrr` must not have a co-located `skrrd` silently adopt it.
|
|
283
|
+
for (const name of this.opts.envTokenNames ?? ['OVERSKY_TOKEN']) {
|
|
284
|
+
const v = process.env[name];
|
|
285
|
+
if (typeof v === 'string' && v.length > 0)
|
|
286
|
+
return v;
|
|
287
|
+
}
|
|
288
|
+
return null;
|
|
265
289
|
}
|
|
266
290
|
async tryResolveAuthHelper() {
|
|
267
291
|
let helperPath;
|
|
@@ -38,7 +38,13 @@ export declare function describeDeviceKeySplit(profile: string): {
|
|
|
38
38
|
* Order:
|
|
39
39
|
* 1. Try to load existing keypair from disk.
|
|
40
40
|
* - Success → state = active.
|
|
41
|
-
* -
|
|
41
|
+
* - No key material at all (first install) → step 2.
|
|
42
|
+
* - Key material present but unloadable (corruption, decrypt failure,
|
|
43
|
+
* public/private mismatch) → disabled+unreadable_key and a
|
|
44
|
+
* `recovery_required` event, UNLESS `recoverUnreadable` is set. Only
|
|
45
|
+
* an explicit interactive login sets it, because that login proves and
|
|
46
|
+
* re-pins the new key; replacing it on ordinary boot would sign the
|
|
47
|
+
* next refresh with a key the server never pinned.
|
|
42
48
|
* 2. Generate fresh keypair and persist. Failure to persist is a hard
|
|
43
49
|
* error landing in disabled+persist_failed.
|
|
44
50
|
*/
|
|
@@ -355,7 +355,13 @@ async function consolidateDeviceIdentity(profile) {
|
|
|
355
355
|
* Order:
|
|
356
356
|
* 1. Try to load existing keypair from disk.
|
|
357
357
|
* - Success → state = active.
|
|
358
|
-
* -
|
|
358
|
+
* - No key material at all (first install) → step 2.
|
|
359
|
+
* - Key material present but unloadable (corruption, decrypt failure,
|
|
360
|
+
* public/private mismatch) → disabled+unreadable_key and a
|
|
361
|
+
* `recovery_required` event, UNLESS `recoverUnreadable` is set. Only
|
|
362
|
+
* an explicit interactive login sets it, because that login proves and
|
|
363
|
+
* re-pins the new key; replacing it on ordinary boot would sign the
|
|
364
|
+
* next refresh with a key the server never pinned.
|
|
359
365
|
* 2. Generate fresh keypair and persist. Failure to persist is a hard
|
|
360
366
|
* error landing in disabled+persist_failed.
|
|
361
367
|
*/
|
|
@@ -16,7 +16,7 @@ export { classifyRefreshResponse, type RefreshResponseShape, type ClassifiedRefr
|
|
|
16
16
|
export { refreshDaemonToken, revokeDaemonRefreshSession, withAuthLock, persistReauthState, needsReauthState, clearReauthState, installLockExitHandlers, __refreshDiagnostics, __resetUnknown401StreaksForTest, UNKNOWN_401_BUDGET, } from './refresh.js';
|
|
17
17
|
export { createRefreshScheduler, type RefreshScheduler, type RefreshSchedulerOptions, } from './refreshScheduler.js';
|
|
18
18
|
export { readAuthFromFd, __setFdReaderForTest, type FdAuthPayload } from './fdToken.js';
|
|
19
|
-
export { CredentialResolver, CREDENTIAL_PRECEDENCE, __resetCredentialResolverForTest, invalidateAuthHelperCache, classifyTokenKind, CI_TOKEN_PREFIX, AuthHelperUntrustedError, AuthHelperUnavailableError, type CredentialSource, type CredentialStoreMode, type CredentialResolverOptions, type ResolvedCredential, type TokenKind, type HelperTrustDecision, type AuthHelperBlockedInfo, type AuthHelperSentinelInfo, } from './credentialResolver.js';
|
|
19
|
+
export { CredentialResolver, CREDENTIAL_PRECEDENCE, __resetCredentialResolverForTest, invalidateAuthHelperCache, classifyTokenKind, CI_TOKEN_PREFIX, PERSONAL_ACCESS_TOKEN_PREFIX, isStaticTokenKind, AuthHelperUntrustedError, AuthHelperUnavailableError, type CredentialSource, type CredentialStoreMode, type CredentialResolverOptions, type ResolvedCredential, type TokenKind, type HelperTrustDecision, type AuthHelperBlockedInfo, type AuthHelperSentinelInfo, } from './credentialResolver.js';
|
|
20
20
|
export { invokeAuthHelper, getDefaultHelperTtlMs, getLastAuthHelperFailureReason, __resetAuthHelperFailureReasonForTest, SENTINEL_TRIGGERING_FAILURES, type HelperResult, type InvokeAuthHelperOptions, type AuthHelperFailureReason, } from './authHelper.js';
|
|
21
21
|
export { runHeadersHelper, invalidateHeadersHelperCache, type RunHeadersHelperOptions, } from './headers-helper.js';
|
|
22
22
|
export { generateVerifier, challenge, generateState, safeEqual, verifyChallenge, type PkceChallengeMethod, } from './pkce.js';
|
|
@@ -35,7 +35,7 @@ export { ensureMachineDaemonId, legacyDaemonUuids, __resetCachedDaemonIdForTest,
|
|
|
35
35
|
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';
|
|
36
36
|
export { HARNESS_TIERS, getHarnessTier, credentialPolicyForTier, tierPermitsConfiguredAutoMode, type HarnessTrustTier, type CredentialDeliveryPolicy, type CredentialMode, } from './harnessTrust.js';
|
|
37
37
|
export { HARNESSES_LOADING_CLAUDE_SKILLS_LAYOUT, claudeSkillsLayoutEvidence, harnessLoadsClaudeSkillsLayout, } from './harnessSkillLayout.js';
|
|
38
|
-
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 { sanitizeSpawnEnv, SENSITIVE_ENV_VARS, SENSITIVE_ENV_PREFIXES, SENSITIVE_ENV_SUFFIXES, SENSITIVE_ENV_NAME_TOKENS, SENSITIVE_ENV_PREFIX_EXCEPTIONS, DAEMON_CHILD_ENV, isDaemonChildEnv, LOOPBACK_NO_PROXY_HOSTS, envHasProxy, withLoopbackNoProxy, } from './spawnEnv.js';
|
|
39
39
|
export { loopbackFetch, assertLoopbackHttpUrl, isLoopbackHostname, isLoopbackAddress, LoopbackTargetRefusedError, LOOPBACK_DEFAULT_MAX_BODY_BYTES, type LoopbackFetch, type LoopbackFetchInit, } from './loopbackHttp.js';
|
|
40
40
|
export { CONFIG_DIR_NAME, LEGACY_CONFIG_DIR_NAMES, NATIVE_ID_PREFIX, LEGACY_NATIVE_ID_PREFIXES, DEFAULT_BINARY_NAME, } from './localIdentity.js';
|
|
41
41
|
export { findLegacyLocalState, describeLegacyState, type LegacyStateFinding, type LegacyStateReport, } from './legacyStatePreflight.js';
|
|
@@ -22,11 +22,11 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
22
22
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
23
23
|
};
|
|
24
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
-
exports.
|
|
26
|
-
exports.
|
|
27
|
-
exports.
|
|
28
|
-
exports.
|
|
29
|
-
exports.consolidateProfileState = exports.profileStateFilePathsToClear = exports.profileStateFileLocations = exports.resolveProfileStateFile = exports.resolveProfileStateDir = exports.legacyProfileStateDir = exports.profileStateDir = exports.SUPERSEDED_COPY_SUFFIX = exports.SUPERSEDED_MARKER_SUFFIX = exports.PROFILES_SEGMENT = exports.isConfigRootOverridden = exports.configRootPath = exports.resolveConfigRoot = exports.verifyManifest = exports.verifyArtifact = exports.isTrustedArtifactOrigin = exports.getDeltaFor = exports.buildManifestMessage = exports.buildArtifactMessage = exports.TRUSTED_FEED_ORIGINS = exports.MAX_SIGS = exports.OVERSKY_RELEASE_PUBLIC_KEYS = exports.resolveFirstPartyHarnessChannel = exports.resolveChannelManifestUrl = exports.isFirstPartyHarnessChannel = exports.firstPartyHarnessFeedCandidates = exports.firstPartyHarnessFeedBase = exports.firstPartyHarnessChannelPrefix = exports.FIRST_PARTY_HARNESS_CHANNELS = exports.DEFAULT_FIRST_PARTY_HARNESS_CHANNEL = exports.migrateFirstPartyHarnessHome = exports.linkFirstPartyHarnessAliases = exports.firstPartyHarnessInstalledBinaryPath = exports.firstPartyHarnessHomeDir = exports.firstPartyHarnessBinDir = void 0;
|
|
25
|
+
exports.runHeadersHelper = exports.SENTINEL_TRIGGERING_FAILURES = exports.__resetAuthHelperFailureReasonForTest = exports.getLastAuthHelperFailureReason = exports.getDefaultHelperTtlMs = exports.invokeAuthHelper = exports.AuthHelperUnavailableError = exports.AuthHelperUntrustedError = exports.isStaticTokenKind = exports.PERSONAL_ACCESS_TOKEN_PREFIX = 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.reauthCommand = 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;
|
|
26
|
+
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 = exports.challenge = exports.generateVerifier = exports.invalidateHeadersHelperCache = void 0;
|
|
27
|
+
exports.ensureMachineDaemonId = exports.__resetMachineUuidCacheForTest = exports.HOSTED_RUNTIME_MACHINE_SOURCES = exports.hostedRuntimeIdOverride = exports.getMachineUuid = exports.__getDeviceIdentityStateForTest = exports.__setDeviceIdentityStateForTest = exports.__enrollmentBackoffPathForTest = exports.__enrollmentMarkerPathForTest = exports.__privateKeyPathForTest = exports.__publicKeyPathForTest = exports.describeDeviceKeySplit = 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.DEFAULT_UNREADABLE_CREDENTIAL_HINT = exports.maybeDecryptOnRead = exports.maybeEncryptForWrite = exports.splitKeyConvergencePolicy = exports.describeCredEnvelopeState = exports.hasCredEnvelopePathConflict = exports.isCredEnvelopeActive = exports.shutdownCredEnvelope = exports.resetCredEnvelope = exports.initCredEnvelope = exports.verifyDpopProof = exports.normalizeDpopHtu = exports.isJwkThumbprint = exports.isAth = exports.createDpopKey = exports.accessTokenHash = exports.DPOP_PROOF_VERIFY_UNAVAILABLE = exports.DPOP_PROOF_TYP = exports.DPOP_PROOF_REQUIRED = exports.DPOP_PROOF_INVALID = exports.DPOP_MAX_AGE_SECONDS = exports.DPOP_HEADER = exports.verifyDeviceProof = exports.tokenHash = exports.publicJwkFromX = exports.normalizeHtu = void 0;
|
|
28
|
+
exports.DEFAULT_BINARY_NAME = exports.LEGACY_NATIVE_ID_PREFIXES = exports.NATIVE_ID_PREFIX = exports.LEGACY_CONFIG_DIR_NAMES = exports.CONFIG_DIR_NAME = exports.LOOPBACK_DEFAULT_MAX_BODY_BYTES = exports.LoopbackTargetRefusedError = exports.isLoopbackAddress = exports.isLoopbackHostname = exports.assertLoopbackHttpUrl = exports.loopbackFetch = exports.withLoopbackNoProxy = exports.envHasProxy = exports.LOOPBACK_NO_PROXY_HOSTS = exports.isDaemonChildEnv = exports.DAEMON_CHILD_ENV = 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.harnessLoadsClaudeSkillsLayout = exports.claudeSkillsLayoutEvidence = exports.HARNESSES_LOADING_CLAUDE_SKILLS_LAYOUT = exports.tierPermitsConfiguredAutoMode = exports.credentialPolicyForTier = 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 = void 0;
|
|
29
|
+
exports.consolidateProfileState = exports.profileStateFilePathsToClear = exports.profileStateFileLocations = exports.resolveProfileStateFile = exports.resolveProfileStateDir = exports.legacyProfileStateDir = exports.profileStateDir = exports.SUPERSEDED_COPY_SUFFIX = exports.SUPERSEDED_MARKER_SUFFIX = exports.PROFILES_SEGMENT = exports.isConfigRootOverridden = exports.configRootPath = exports.resolveConfigRoot = exports.verifyManifest = exports.verifyArtifact = exports.isTrustedArtifactOrigin = exports.getDeltaFor = exports.buildManifestMessage = exports.buildArtifactMessage = exports.TRUSTED_FEED_ORIGINS = exports.MAX_SIGS = exports.OVERSKY_RELEASE_PUBLIC_KEYS = exports.resolveFirstPartyHarnessChannel = exports.resolveChannelManifestUrl = exports.isFirstPartyHarnessChannel = exports.firstPartyHarnessFeedCandidates = exports.firstPartyHarnessFeedBase = exports.firstPartyHarnessChannelPrefix = exports.FIRST_PARTY_HARNESS_CHANNELS = exports.DEFAULT_FIRST_PARTY_HARNESS_CHANNEL = exports.migrateFirstPartyHarnessHome = exports.linkFirstPartyHarnessAliases = exports.firstPartyHarnessInstalledBinaryPath = exports.firstPartyHarnessHomeDir = exports.firstPartyHarnessBinDir = exports.FIRST_PARTY_HARNESS_PROVENANCE_SUFFIX = exports.FIRST_PARTY_HARNESS_PREVIOUS_SUFFIX = exports.describeLegacyState = exports.findLegacyLocalState = void 0;
|
|
30
30
|
// Daemon scope vocabulary — single source of truth for non-Mongoose tiers
|
|
31
31
|
// (daemon, desktop, cli). Schema-bound canonical lives in
|
|
32
32
|
// `@skrr-ai/data-schemas/common/daemonScopes`; the two are kept byte-equal
|
|
@@ -109,6 +109,8 @@ Object.defineProperty(exports, "__resetCredentialResolverForTest", { enumerable:
|
|
|
109
109
|
Object.defineProperty(exports, "invalidateAuthHelperCache", { enumerable: true, get: function () { return credentialResolver_js_1.invalidateAuthHelperCache; } });
|
|
110
110
|
Object.defineProperty(exports, "classifyTokenKind", { enumerable: true, get: function () { return credentialResolver_js_1.classifyTokenKind; } });
|
|
111
111
|
Object.defineProperty(exports, "CI_TOKEN_PREFIX", { enumerable: true, get: function () { return credentialResolver_js_1.CI_TOKEN_PREFIX; } });
|
|
112
|
+
Object.defineProperty(exports, "PERSONAL_ACCESS_TOKEN_PREFIX", { enumerable: true, get: function () { return credentialResolver_js_1.PERSONAL_ACCESS_TOKEN_PREFIX; } });
|
|
113
|
+
Object.defineProperty(exports, "isStaticTokenKind", { enumerable: true, get: function () { return credentialResolver_js_1.isStaticTokenKind; } });
|
|
112
114
|
// L6.1 / L6.3 — fail-closed errors thrown by the auth-helper slot.
|
|
113
115
|
Object.defineProperty(exports, "AuthHelperUntrustedError", { enumerable: true, get: function () { return credentialResolver_js_1.AuthHelperUntrustedError; } });
|
|
114
116
|
Object.defineProperty(exports, "AuthHelperUnavailableError", { enumerable: true, get: function () { return credentialResolver_js_1.AuthHelperUnavailableError; } });
|
|
@@ -344,6 +346,8 @@ Object.defineProperty(exports, "SENSITIVE_ENV_PREFIXES", { enumerable: true, get
|
|
|
344
346
|
Object.defineProperty(exports, "SENSITIVE_ENV_SUFFIXES", { enumerable: true, get: function () { return spawnEnv_js_1.SENSITIVE_ENV_SUFFIXES; } });
|
|
345
347
|
Object.defineProperty(exports, "SENSITIVE_ENV_NAME_TOKENS", { enumerable: true, get: function () { return spawnEnv_js_1.SENSITIVE_ENV_NAME_TOKENS; } });
|
|
346
348
|
Object.defineProperty(exports, "SENSITIVE_ENV_PREFIX_EXCEPTIONS", { enumerable: true, get: function () { return spawnEnv_js_1.SENSITIVE_ENV_PREFIX_EXCEPTIONS; } });
|
|
349
|
+
Object.defineProperty(exports, "DAEMON_CHILD_ENV", { enumerable: true, get: function () { return spawnEnv_js_1.DAEMON_CHILD_ENV; } });
|
|
350
|
+
Object.defineProperty(exports, "isDaemonChildEnv", { enumerable: true, get: function () { return spawnEnv_js_1.isDaemonChildEnv; } });
|
|
347
351
|
Object.defineProperty(exports, "LOOPBACK_NO_PROXY_HOSTS", { enumerable: true, get: function () { return spawnEnv_js_1.LOOPBACK_NO_PROXY_HOSTS; } });
|
|
348
352
|
Object.defineProperty(exports, "envHasProxy", { enumerable: true, get: function () { return spawnEnv_js_1.envHasProxy; } });
|
|
349
353
|
Object.defineProperty(exports, "withLoopbackNoProxy", { enumerable: true, get: function () { return spawnEnv_js_1.withLoopbackNoProxy; } });
|
|
@@ -77,6 +77,31 @@ export declare const SENSITIVE_ENV_SUFFIXES: readonly string[];
|
|
|
77
77
|
export declare const SENSITIVE_ENV_NAME_TOKENS: readonly string[];
|
|
78
78
|
/** Specific names to keep — the prefix sweeps are broad on purpose. */
|
|
79
79
|
export declare const SENSITIVE_ENV_PREFIX_EXCEPTIONS: ReadonlySet<string>;
|
|
80
|
+
/**
|
|
81
|
+
* OSK-13254 — the marker the daemon stamps on every agent- or tool-driven child
|
|
82
|
+
* (`daemon/src/env-sanitize.ts`, `daemon/src/terminal/agent-terminal-env.ts`).
|
|
83
|
+
*
|
|
84
|
+
* A `skrr` that sees it is a borrower: it redeems short-lived tokens from the
|
|
85
|
+
* daemon's loopback broker, never adopts a CLI refresh session of its own, and
|
|
86
|
+
* never reads the person's stored one (`cli/src/lib/harness-context.ts`). A
|
|
87
|
+
* person's own terminal — including the web terminal, which is a human surface
|
|
88
|
+
* (`humanTerminalEnv`) — does not carry it.
|
|
89
|
+
*
|
|
90
|
+
* The marker can only take authority away, so a process that forges it hurts
|
|
91
|
+
* nobody but itself. On a laptop it is POLICY, not a boundary: a same-uid child
|
|
92
|
+
* that deletes it can do whatever the person's own shell can. Where a uid
|
|
93
|
+
* boundary exists (Dedicated Runtime, identity-split Hosted Machines), the
|
|
94
|
+
* guest descriptor already offers only the access-token mode, so a durable CLI
|
|
95
|
+
* family cannot be minted there whatever the environment says.
|
|
96
|
+
*/
|
|
97
|
+
export declare const DAEMON_CHILD_ENV = "SKRR_DAEMON_CHILD";
|
|
98
|
+
/**
|
|
99
|
+
* True when `env` carries the daemon-child marker with ANY non-empty value.
|
|
100
|
+
* Deliberately no "0 means off": the marker only narrows authority, so the
|
|
101
|
+
* one value that could switch it off is the one a request-carried environment
|
|
102
|
+
* would forge.
|
|
103
|
+
*/
|
|
104
|
+
export declare function isDaemonChildEnv(env: Readonly<Record<string, string | undefined>>): boolean;
|
|
80
105
|
/**
|
|
81
106
|
* Build a sanitized snapshot of the parent's own env for a spawned
|
|
82
107
|
* child, stripping credentials and library-injection vectors while
|
|
@@ -40,7 +40,8 @@
|
|
|
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.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;
|
|
43
|
+
exports.LOOPBACK_NO_PROXY_HOSTS = exports.DAEMON_CHILD_ENV = 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
|
+
exports.isDaemonChildEnv = isDaemonChildEnv;
|
|
44
45
|
exports.sanitizeSpawnEnv = sanitizeSpawnEnv;
|
|
45
46
|
exports.envHasProxy = envHasProxy;
|
|
46
47
|
exports.withLoopbackNoProxy = withLoopbackNoProxy;
|
|
@@ -154,7 +155,40 @@ exports.SENSITIVE_ENV_PREFIX_EXCEPTIONS = new Set([
|
|
|
154
155
|
// engine) must keep it to detect they already run as the workload uid. Not
|
|
155
156
|
// a secret — it authorizes nothing without the matching real uid.
|
|
156
157
|
'SKRR_WORKLOAD_UID',
|
|
158
|
+
// OSK-13254 — "this process descends from a skrrd agent/tool spawn". It only
|
|
159
|
+
// ever REMOVES authority (a `skrr` that sees it borrows from the daemon and
|
|
160
|
+
// never reads or writes a stored CLI session), so it must survive every later
|
|
161
|
+
// re-sanitization: a Bash tool that runs `skrr code`, whose engine runs `skrr`,
|
|
162
|
+
// is still the agent's process. See `DAEMON_CHILD_ENV` below.
|
|
163
|
+
'SKRR_DAEMON_CHILD',
|
|
157
164
|
]);
|
|
165
|
+
/**
|
|
166
|
+
* OSK-13254 — the marker the daemon stamps on every agent- or tool-driven child
|
|
167
|
+
* (`daemon/src/env-sanitize.ts`, `daemon/src/terminal/agent-terminal-env.ts`).
|
|
168
|
+
*
|
|
169
|
+
* A `skrr` that sees it is a borrower: it redeems short-lived tokens from the
|
|
170
|
+
* daemon's loopback broker, never adopts a CLI refresh session of its own, and
|
|
171
|
+
* never reads the person's stored one (`cli/src/lib/harness-context.ts`). A
|
|
172
|
+
* person's own terminal — including the web terminal, which is a human surface
|
|
173
|
+
* (`humanTerminalEnv`) — does not carry it.
|
|
174
|
+
*
|
|
175
|
+
* The marker can only take authority away, so a process that forges it hurts
|
|
176
|
+
* nobody but itself. On a laptop it is POLICY, not a boundary: a same-uid child
|
|
177
|
+
* that deletes it can do whatever the person's own shell can. Where a uid
|
|
178
|
+
* boundary exists (Dedicated Runtime, identity-split Hosted Machines), the
|
|
179
|
+
* guest descriptor already offers only the access-token mode, so a durable CLI
|
|
180
|
+
* family cannot be minted there whatever the environment says.
|
|
181
|
+
*/
|
|
182
|
+
exports.DAEMON_CHILD_ENV = 'SKRR_DAEMON_CHILD';
|
|
183
|
+
/**
|
|
184
|
+
* True when `env` carries the daemon-child marker with ANY non-empty value.
|
|
185
|
+
* Deliberately no "0 means off": the marker only narrows authority, so the
|
|
186
|
+
* one value that could switch it off is the one a request-carried environment
|
|
187
|
+
* would forge.
|
|
188
|
+
*/
|
|
189
|
+
function isDaemonChildEnv(env) {
|
|
190
|
+
return Boolean(env[exports.DAEMON_CHILD_ENV]?.trim());
|
|
191
|
+
}
|
|
158
192
|
/**
|
|
159
193
|
* Build a sanitized snapshot of the parent's own env for a spawned
|
|
160
194
|
* child, stripping credentials and library-injection vectors while
|
|
@@ -13,8 +13,11 @@
|
|
|
13
13
|
* Precedence (high → low):
|
|
14
14
|
*
|
|
15
15
|
* 1. flag — `--token <jwt>` CLI flag (debugging)
|
|
16
|
-
* 2. env-token — `OVERSKY_TOKEN`
|
|
17
|
-
*
|
|
16
|
+
* 2. env-token — `OVERSKY_TOKEN` (CI / static). The CLI also reads
|
|
17
|
+
* `SKRR_TOKEN` via `envTokenNames`; `OVERSKY_TOKEN` wins
|
|
18
|
+
* when both are set, matching the CLI config overlay. A
|
|
19
|
+
* personal access token (`osk_pat_*`) is the credential
|
|
20
|
+
* CI should put here.
|
|
18
21
|
* 3. auth-helper — `OVERSKY_AUTH_HELPER` script output (rotating
|
|
19
22
|
* creds — Vault, AWS SM, internal SSO proxy)
|
|
20
23
|
* 4. fd-handoff — `OVERSKY_AUTH_FD` parent→child IPC (Electron
|
|
@@ -64,6 +67,12 @@ export interface CredentialResolverOptions {
|
|
|
64
67
|
* string to use that value directly.
|
|
65
68
|
*/
|
|
66
69
|
envTokenOverride?: string | null;
|
|
70
|
+
/**
|
|
71
|
+
* Environment variables read by the env-token slot, in precedence order.
|
|
72
|
+
* Defaults to `['OVERSKY_TOKEN']`. The CLI passes
|
|
73
|
+
* `['OVERSKY_TOKEN', 'SKRR_TOKEN']` (OSK-13208).
|
|
74
|
+
*/
|
|
75
|
+
envTokenNames?: readonly string[];
|
|
67
76
|
/** Test/explicit override for `OVERSKY_AUTH_HELPER` env. Same semantics. */
|
|
68
77
|
authHelperPathOverride?: string | null;
|
|
69
78
|
/**
|
|
@@ -143,6 +152,8 @@ export interface AuthHelperSentinelInfo {
|
|
|
143
152
|
* (POST /api/daemons/token), MUST NOT schedule refresh,
|
|
144
153
|
* and on auth failure exits 75 with a CI-specific error
|
|
145
154
|
* rather than writing needs-reauth.json.
|
|
155
|
+
* - 'pat' — personal access token (`osk_pat_*`, OSK-13208): a static
|
|
156
|
+
* bearer used AS the user by the CLI. Never refreshed.
|
|
146
157
|
* - 'install' — short-lived web-minted JWT with `scope=daemon-install`.
|
|
147
158
|
* The daemon exchanges it through the same /api/daemons/token
|
|
148
159
|
* bootstrap path, persists only the returned daemon
|
|
@@ -157,9 +168,17 @@ export interface AuthHelperSentinelInfo {
|
|
|
157
168
|
* The kill switch `OVERSKY_DISABLE_CI_TOKEN_RESOLVER=1` forces every token to
|
|
158
169
|
* `'standard'` for triage purposes.
|
|
159
170
|
*/
|
|
160
|
-
export type TokenKind = 'standard' | 'ci' | 'install';
|
|
171
|
+
export type TokenKind = 'standard' | 'ci' | 'install' | 'pat';
|
|
161
172
|
/** CI-token plaintext prefix; mirrors api/server/services/Auth/daemonCiTokens.js. */
|
|
162
173
|
export declare const CI_TOKEN_PREFIX = "osk_ci_";
|
|
174
|
+
/** Personal-access-token prefix; mirrors api/server/services/Auth/personalAccessTokens.js. */
|
|
175
|
+
export declare const PERSONAL_ACCESS_TOKEN_PREFIX = "osk_pat_";
|
|
176
|
+
/**
|
|
177
|
+
* True for a kind whose token is static by construction: never refreshed,
|
|
178
|
+
* never rotated into a store. Like `TokenKind` itself this selects a local
|
|
179
|
+
* code path and grants nothing.
|
|
180
|
+
*/
|
|
181
|
+
export declare function isStaticTokenKind(kind: TokenKind): boolean;
|
|
163
182
|
/**
|
|
164
183
|
* Classify a token by local shape. Pure function; safe to call on any string
|
|
165
184
|
* (including `null`-coerced empty). Returns `'standard'` for empty input
|
|
@@ -13,8 +13,11 @@
|
|
|
13
13
|
* Precedence (high → low):
|
|
14
14
|
*
|
|
15
15
|
* 1. flag — `--token <jwt>` CLI flag (debugging)
|
|
16
|
-
* 2. env-token — `OVERSKY_TOKEN`
|
|
17
|
-
*
|
|
16
|
+
* 2. env-token — `OVERSKY_TOKEN` (CI / static). The CLI also reads
|
|
17
|
+
* `SKRR_TOKEN` via `envTokenNames`; `OVERSKY_TOKEN` wins
|
|
18
|
+
* when both are set, matching the CLI config overlay. A
|
|
19
|
+
* personal access token (`osk_pat_*`) is the credential
|
|
20
|
+
* CI should put here.
|
|
18
21
|
* 3. auth-helper — `OVERSKY_AUTH_HELPER` script output (rotating
|
|
19
22
|
* creds — Vault, AWS SM, internal SSO proxy)
|
|
20
23
|
* 4. fd-handoff — `OVERSKY_AUTH_FD` parent→child IPC (Electron
|
|
@@ -62,6 +65,16 @@ export const CREDENTIAL_PRECEDENCE = [
|
|
|
62
65
|
];
|
|
63
66
|
/** CI-token plaintext prefix; mirrors api/server/services/Auth/daemonCiTokens.js. */
|
|
64
67
|
export const CI_TOKEN_PREFIX = 'osk_ci_';
|
|
68
|
+
/** Personal-access-token prefix; mirrors api/server/services/Auth/personalAccessTokens.js. */
|
|
69
|
+
export const PERSONAL_ACCESS_TOKEN_PREFIX = 'osk_pat_';
|
|
70
|
+
/**
|
|
71
|
+
* True for a kind whose token is static by construction: never refreshed,
|
|
72
|
+
* never rotated into a store. Like `TokenKind` itself this selects a local
|
|
73
|
+
* code path and grants nothing.
|
|
74
|
+
*/
|
|
75
|
+
export function isStaticTokenKind(kind) {
|
|
76
|
+
return kind === 'ci' || kind === 'pat';
|
|
77
|
+
}
|
|
65
78
|
/**
|
|
66
79
|
* Classify a token by local shape. Pure function; safe to call on any string
|
|
67
80
|
* (including `null`-coerced empty). Returns `'standard'` for empty input
|
|
@@ -97,6 +110,8 @@ export function classifyTokenKind(token) {
|
|
|
97
110
|
return 'standard';
|
|
98
111
|
if (token.startsWith(CI_TOKEN_PREFIX))
|
|
99
112
|
return 'ci';
|
|
113
|
+
if (token.startsWith(PERSONAL_ACCESS_TOKEN_PREFIX))
|
|
114
|
+
return 'pat';
|
|
100
115
|
const payload = decodeJwtPayload(token);
|
|
101
116
|
if (payload &&
|
|
102
117
|
typeof payload === 'object' &&
|
|
@@ -252,8 +267,16 @@ export class CredentialResolver {
|
|
|
252
267
|
if (typeof this.opts.envTokenOverride === 'string') {
|
|
253
268
|
return this.opts.envTokenOverride.length > 0 ? this.opts.envTokenOverride : null;
|
|
254
269
|
}
|
|
255
|
-
|
|
256
|
-
|
|
270
|
+
// `OVERSKY_TOKEN` first (retained by decision, docs/product/skrr-env-inventory.md),
|
|
271
|
+
// then any renamed spelling the caller opted into (`SKRR_TOKEN` for the CLI,
|
|
272
|
+
// OSK-13208). The daemon does not opt in: a CI job that sets `SKRR_TOKEN`
|
|
273
|
+
// for `skrr` must not have a co-located `skrrd` silently adopt it.
|
|
274
|
+
for (const name of this.opts.envTokenNames ?? ['OVERSKY_TOKEN']) {
|
|
275
|
+
const v = process.env[name];
|
|
276
|
+
if (typeof v === 'string' && v.length > 0)
|
|
277
|
+
return v;
|
|
278
|
+
}
|
|
279
|
+
return null;
|
|
257
280
|
}
|
|
258
281
|
async tryResolveAuthHelper() {
|
|
259
282
|
let helperPath;
|
|
@@ -38,7 +38,13 @@ export declare function describeDeviceKeySplit(profile: string): {
|
|
|
38
38
|
* Order:
|
|
39
39
|
* 1. Try to load existing keypair from disk.
|
|
40
40
|
* - Success → state = active.
|
|
41
|
-
* -
|
|
41
|
+
* - No key material at all (first install) → step 2.
|
|
42
|
+
* - Key material present but unloadable (corruption, decrypt failure,
|
|
43
|
+
* public/private mismatch) → disabled+unreadable_key and a
|
|
44
|
+
* `recovery_required` event, UNLESS `recoverUnreadable` is set. Only
|
|
45
|
+
* an explicit interactive login sets it, because that login proves and
|
|
46
|
+
* re-pins the new key; replacing it on ordinary boot would sign the
|
|
47
|
+
* next refresh with a key the server never pinned.
|
|
42
48
|
* 2. Generate fresh keypair and persist. Failure to persist is a hard
|
|
43
49
|
* error landing in disabled+persist_failed.
|
|
44
50
|
*/
|
|
@@ -335,7 +335,13 @@ async function consolidateDeviceIdentity(profile) {
|
|
|
335
335
|
* Order:
|
|
336
336
|
* 1. Try to load existing keypair from disk.
|
|
337
337
|
* - Success → state = active.
|
|
338
|
-
* -
|
|
338
|
+
* - No key material at all (first install) → step 2.
|
|
339
|
+
* - Key material present but unloadable (corruption, decrypt failure,
|
|
340
|
+
* public/private mismatch) → disabled+unreadable_key and a
|
|
341
|
+
* `recovery_required` event, UNLESS `recoverUnreadable` is set. Only
|
|
342
|
+
* an explicit interactive login sets it, because that login proves and
|
|
343
|
+
* re-pins the new key; replacing it on ordinary boot would sign the
|
|
344
|
+
* next refresh with a key the server never pinned.
|
|
339
345
|
* 2. Generate fresh keypair and persist. Failure to persist is a hard
|
|
340
346
|
* error landing in disabled+persist_failed.
|
|
341
347
|
*/
|
|
@@ -16,7 +16,7 @@ export { classifyRefreshResponse, type RefreshResponseShape, type ClassifiedRefr
|
|
|
16
16
|
export { refreshDaemonToken, revokeDaemonRefreshSession, withAuthLock, persistReauthState, needsReauthState, clearReauthState, installLockExitHandlers, __refreshDiagnostics, __resetUnknown401StreaksForTest, UNKNOWN_401_BUDGET, } from './refresh.js';
|
|
17
17
|
export { createRefreshScheduler, type RefreshScheduler, type RefreshSchedulerOptions, } from './refreshScheduler.js';
|
|
18
18
|
export { readAuthFromFd, __setFdReaderForTest, type FdAuthPayload } from './fdToken.js';
|
|
19
|
-
export { CredentialResolver, CREDENTIAL_PRECEDENCE, __resetCredentialResolverForTest, invalidateAuthHelperCache, classifyTokenKind, CI_TOKEN_PREFIX, AuthHelperUntrustedError, AuthHelperUnavailableError, type CredentialSource, type CredentialStoreMode, type CredentialResolverOptions, type ResolvedCredential, type TokenKind, type HelperTrustDecision, type AuthHelperBlockedInfo, type AuthHelperSentinelInfo, } from './credentialResolver.js';
|
|
19
|
+
export { CredentialResolver, CREDENTIAL_PRECEDENCE, __resetCredentialResolverForTest, invalidateAuthHelperCache, classifyTokenKind, CI_TOKEN_PREFIX, PERSONAL_ACCESS_TOKEN_PREFIX, isStaticTokenKind, AuthHelperUntrustedError, AuthHelperUnavailableError, type CredentialSource, type CredentialStoreMode, type CredentialResolverOptions, type ResolvedCredential, type TokenKind, type HelperTrustDecision, type AuthHelperBlockedInfo, type AuthHelperSentinelInfo, } from './credentialResolver.js';
|
|
20
20
|
export { invokeAuthHelper, getDefaultHelperTtlMs, getLastAuthHelperFailureReason, __resetAuthHelperFailureReasonForTest, SENTINEL_TRIGGERING_FAILURES, type HelperResult, type InvokeAuthHelperOptions, type AuthHelperFailureReason, } from './authHelper.js';
|
|
21
21
|
export { runHeadersHelper, invalidateHeadersHelperCache, type RunHeadersHelperOptions, } from './headers-helper.js';
|
|
22
22
|
export { generateVerifier, challenge, generateState, safeEqual, verifyChallenge, type PkceChallengeMethod, } from './pkce.js';
|
|
@@ -35,7 +35,7 @@ export { ensureMachineDaemonId, legacyDaemonUuids, __resetCachedDaemonIdForTest,
|
|
|
35
35
|
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';
|
|
36
36
|
export { HARNESS_TIERS, getHarnessTier, credentialPolicyForTier, tierPermitsConfiguredAutoMode, type HarnessTrustTier, type CredentialDeliveryPolicy, type CredentialMode, } from './harnessTrust.js';
|
|
37
37
|
export { HARNESSES_LOADING_CLAUDE_SKILLS_LAYOUT, claudeSkillsLayoutEvidence, harnessLoadsClaudeSkillsLayout, } from './harnessSkillLayout.js';
|
|
38
|
-
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 { sanitizeSpawnEnv, SENSITIVE_ENV_VARS, SENSITIVE_ENV_PREFIXES, SENSITIVE_ENV_SUFFIXES, SENSITIVE_ENV_NAME_TOKENS, SENSITIVE_ENV_PREFIX_EXCEPTIONS, DAEMON_CHILD_ENV, isDaemonChildEnv, LOOPBACK_NO_PROXY_HOSTS, envHasProxy, withLoopbackNoProxy, } from './spawnEnv.js';
|
|
39
39
|
export { loopbackFetch, assertLoopbackHttpUrl, isLoopbackHostname, isLoopbackAddress, LoopbackTargetRefusedError, LOOPBACK_DEFAULT_MAX_BODY_BYTES, type LoopbackFetch, type LoopbackFetchInit, } from './loopbackHttp.js';
|
|
40
40
|
export { CONFIG_DIR_NAME, LEGACY_CONFIG_DIR_NAMES, NATIVE_ID_PREFIX, LEGACY_NATIVE_ID_PREFIXES, DEFAULT_BINARY_NAME, } from './localIdentity.js';
|
|
41
41
|
export { findLegacyLocalState, describeLegacyState, type LegacyStateFinding, type LegacyStateReport, } from './legacyStatePreflight.js';
|
|
@@ -51,7 +51,7 @@ export { CredentialResolver, CREDENTIAL_PRECEDENCE, __resetCredentialResolverFor
|
|
|
51
51
|
// H3-6 — public seam 401 handlers call to bust the helper cache so
|
|
52
52
|
// the next resolve re-invokes OVERSKY_AUTH_HELPER immediately
|
|
53
53
|
// instead of serving the stale cached token for up to its TTL.
|
|
54
|
-
invalidateAuthHelperCache, classifyTokenKind, CI_TOKEN_PREFIX,
|
|
54
|
+
invalidateAuthHelperCache, classifyTokenKind, CI_TOKEN_PREFIX, PERSONAL_ACCESS_TOKEN_PREFIX, isStaticTokenKind,
|
|
55
55
|
// L6.1 / L6.3 — fail-closed errors thrown by the auth-helper slot.
|
|
56
56
|
AuthHelperUntrustedError, AuthHelperUnavailableError, } from './credentialResolver.js';
|
|
57
57
|
// Auth helper — invocation contract for OVERSKY_AUTH_HELPER
|
|
@@ -149,7 +149,7 @@ export { HARNESSES_LOADING_CLAUDE_SKILLS_LAYOUT, claudeSkillsLayoutEvidence, har
|
|
|
149
149
|
// spawns the SAME engine and did not). `daemon/src/env-sanitize.ts` re-exports
|
|
150
150
|
// these so its own importers are unchanged, and keeps `filterCustomEnv` — that
|
|
151
151
|
// governs SERVER-PROVIDED env, which no other process is handed.
|
|
152
|
-
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';
|
|
152
|
+
export { sanitizeSpawnEnv, SENSITIVE_ENV_VARS, SENSITIVE_ENV_PREFIXES, SENSITIVE_ENV_SUFFIXES, SENSITIVE_ENV_NAME_TOKENS, SENSITIVE_ENV_PREFIX_EXCEPTIONS, DAEMON_CHILD_ENV, isDaemonChildEnv, LOOPBACK_NO_PROXY_HOSTS, envHasProxy, withLoopbackNoProxy, } from './spawnEnv.js';
|
|
153
153
|
// OSK-12134 — the one proxy-free client for loopback HTTP. Bun's fetch (and
|
|
154
154
|
// Node's under NODE_USE_ENV_PROXY) sends 127.0.0.1 requests to HTTP_PROXY,
|
|
155
155
|
// credentials and all; every loopback caller goes through this instead.
|
|
@@ -77,6 +77,31 @@ export declare const SENSITIVE_ENV_SUFFIXES: readonly string[];
|
|
|
77
77
|
export declare const SENSITIVE_ENV_NAME_TOKENS: readonly string[];
|
|
78
78
|
/** Specific names to keep — the prefix sweeps are broad on purpose. */
|
|
79
79
|
export declare const SENSITIVE_ENV_PREFIX_EXCEPTIONS: ReadonlySet<string>;
|
|
80
|
+
/**
|
|
81
|
+
* OSK-13254 — the marker the daemon stamps on every agent- or tool-driven child
|
|
82
|
+
* (`daemon/src/env-sanitize.ts`, `daemon/src/terminal/agent-terminal-env.ts`).
|
|
83
|
+
*
|
|
84
|
+
* A `skrr` that sees it is a borrower: it redeems short-lived tokens from the
|
|
85
|
+
* daemon's loopback broker, never adopts a CLI refresh session of its own, and
|
|
86
|
+
* never reads the person's stored one (`cli/src/lib/harness-context.ts`). A
|
|
87
|
+
* person's own terminal — including the web terminal, which is a human surface
|
|
88
|
+
* (`humanTerminalEnv`) — does not carry it.
|
|
89
|
+
*
|
|
90
|
+
* The marker can only take authority away, so a process that forges it hurts
|
|
91
|
+
* nobody but itself. On a laptop it is POLICY, not a boundary: a same-uid child
|
|
92
|
+
* that deletes it can do whatever the person's own shell can. Where a uid
|
|
93
|
+
* boundary exists (Dedicated Runtime, identity-split Hosted Machines), the
|
|
94
|
+
* guest descriptor already offers only the access-token mode, so a durable CLI
|
|
95
|
+
* family cannot be minted there whatever the environment says.
|
|
96
|
+
*/
|
|
97
|
+
export declare const DAEMON_CHILD_ENV = "SKRR_DAEMON_CHILD";
|
|
98
|
+
/**
|
|
99
|
+
* True when `env` carries the daemon-child marker with ANY non-empty value.
|
|
100
|
+
* Deliberately no "0 means off": the marker only narrows authority, so the
|
|
101
|
+
* one value that could switch it off is the one a request-carried environment
|
|
102
|
+
* would forge.
|
|
103
|
+
*/
|
|
104
|
+
export declare function isDaemonChildEnv(env: Readonly<Record<string, string | undefined>>): boolean;
|
|
80
105
|
/**
|
|
81
106
|
* Build a sanitized snapshot of the parent's own env for a spawned
|
|
82
107
|
* child, stripping credentials and library-injection vectors while
|