@descryy/runtime-environment-profile 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +6 -0
- package/dist/credential-store.d.ts +17 -41
- package/dist/credential-store.d.ts.map +1 -1
- package/dist/credential-store.js +34 -44
- package/dist/credential-store.js.map +1 -1
- package/dist/profile.d.ts +23 -50
- package/dist/profile.d.ts.map +1 -1
- package/dist/profile.js +16 -38
- package/dist/profile.js.map +1 -1
- package/dist/safety-gate.d.ts +7 -11
- package/dist/safety-gate.d.ts.map +1 -1
- package/dist/safety-gate.js +7 -11
- package/dist/safety-gate.js.map +1 -1
- package/package.json +7 -2
package/LICENSE
ADDED
|
@@ -1,31 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* keychain on the user's machine — not on a Descry server." This repo has
|
|
4
|
-
* no server component (`descry-core` CLAUDE.md, "Repo split"), so that
|
|
5
|
-
* guarantee is entirely a local-storage concern here.
|
|
6
|
-
*
|
|
2
|
+
* DEC-270: credentials stored locally (OS keychain), never on a server.
|
|
7
3
|
* `CredentialStore` is the seam a real OS-keychain backend (`keytar` or
|
|
8
|
-
* equivalent) plugs into later.
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* -
|
|
15
|
-
*
|
|
16
|
-
* this file), and `keytar` itself is an unmaintained native module
|
|
17
|
-
* (prebuilt binaries, no upstream releases since 2021) — exactly the
|
|
18
|
-
* "heavy new dependency added without checking existing ones" this
|
|
19
|
-
* pass was told to avoid, for a package that would need per-platform
|
|
20
|
-
* native builds to even test in CI.
|
|
21
|
-
* - `node:crypto` is already a dependency of this repo (`randomUUID` is
|
|
22
|
-
* used in `backend-observation`, `browser`, `controller`,
|
|
23
|
-
* `evidence-store`) and needs no native build step, so the interim
|
|
24
|
-
* implementation is buildable and testable everywhere `node --test`
|
|
25
|
-
* already runs.
|
|
26
|
-
* - The interface below does not leak this choice: a future
|
|
27
|
-
* `KeychainCredentialStore` satisfies the same three methods and every
|
|
28
|
-
* caller (including the safety gate) is unaffected by the swap.
|
|
4
|
+
* equivalent) plugs into later. This pass uses `EncryptedFileCredentialStore`
|
|
5
|
+
* (AES-256-GCM file store) instead, disclosed per honest-degradation
|
|
6
|
+
* (rule 7) rather than passed off as a real keychain:
|
|
7
|
+
* - `keytar` is unmaintained (no releases since 2021, native prebuilt
|
|
8
|
+
* binaries) and neither this repo nor `descry-core` already depends on it.
|
|
9
|
+
* - `node:crypto` is already used elsewhere in this repo, no native build.
|
|
10
|
+
* - The interface doesn't leak this choice — a future
|
|
11
|
+
* `KeychainCredentialStore` is a drop-in swap.
|
|
29
12
|
*/
|
|
30
13
|
export interface CredentialStore {
|
|
31
14
|
/** Stores `secret` under `credentialRef`, overwriting any existing value for that ref. */
|
|
@@ -36,22 +19,15 @@ export interface CredentialStore {
|
|
|
36
19
|
delete(credentialRef: string): Promise<void>;
|
|
37
20
|
}
|
|
38
21
|
/**
|
|
39
|
-
* AES-256-GCM file-at-rest fallback.
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
* convention, and so a ref containing characters unsafe for a filename
|
|
44
|
-
* never needs special-casing.
|
|
22
|
+
* AES-256-GCM file-at-rest fallback. Each `credentialRef` is stored under
|
|
23
|
+
* the SHA-256 hash of the ref, not the ref itself — scoping is structural
|
|
24
|
+
* (wrong ref hashes to a different, absent file) and unsafe filename
|
|
25
|
+
* characters never need special-casing.
|
|
45
26
|
*
|
|
46
|
-
* The AES key
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
* against another *process running as the same user*, which is the
|
|
51
|
-
* limitation a real OS keychain (backed by the platform's own access
|
|
52
|
-
* control / user login secret) does not have. That gap is exactly why
|
|
53
|
-
* this is documented as an interim fallback rather than the intended
|
|
54
|
-
* long-term implementation.
|
|
27
|
+
* The AES key lives in `master.key` under the store dir, both chmod'd
|
|
28
|
+
* 0o600/0o700 owner-only. This protects against other users on a shared
|
|
29
|
+
* machine, not another process running as the same user — a real OS
|
|
30
|
+
* keychain doesn't have that gap, which is why this is interim.
|
|
55
31
|
*/
|
|
56
32
|
export declare class EncryptedFileCredentialStore implements CredentialStore {
|
|
57
33
|
private readonly baseDir;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"credential-store.d.ts","sourceRoot":"","sources":["../src/credential-store.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"credential-store.d.ts","sourceRoot":"","sources":["../src/credential-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAQH,MAAM,WAAW,eAAe;IAC9B,0FAA0F;IAC1F,KAAK,CAAC,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5D,kGAAkG;IAClG,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACxD,mGAAmG;IACnG,MAAM,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9C;AAkBD;;;;;;;;;;GAUG;AACH,qBAAa,4BAA6B,YAAW,eAAe;IAClE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,UAAU,CAAgC;gBAEtC,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE;IAM7C,KAAK,CAAC,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgB3D,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IA2BvD,MAAM,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAWlD,OAAO,CAAC,SAAS;YAKH,eAAe;YAOf,uBAAuB;CAUtC"}
|
package/dist/credential-store.js
CHANGED
|
@@ -1,31 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* keychain on the user's machine — not on a Descry server." This repo has
|
|
4
|
-
* no server component (`descry-core` CLAUDE.md, "Repo split"), so that
|
|
5
|
-
* guarantee is entirely a local-storage concern here.
|
|
6
|
-
*
|
|
2
|
+
* DEC-270: credentials stored locally (OS keychain), never on a server.
|
|
7
3
|
* `CredentialStore` is the seam a real OS-keychain backend (`keytar` or
|
|
8
|
-
* equivalent) plugs into later.
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* -
|
|
15
|
-
*
|
|
16
|
-
* this file), and `keytar` itself is an unmaintained native module
|
|
17
|
-
* (prebuilt binaries, no upstream releases since 2021) — exactly the
|
|
18
|
-
* "heavy new dependency added without checking existing ones" this
|
|
19
|
-
* pass was told to avoid, for a package that would need per-platform
|
|
20
|
-
* native builds to even test in CI.
|
|
21
|
-
* - `node:crypto` is already a dependency of this repo (`randomUUID` is
|
|
22
|
-
* used in `backend-observation`, `browser`, `controller`,
|
|
23
|
-
* `evidence-store`) and needs no native build step, so the interim
|
|
24
|
-
* implementation is buildable and testable everywhere `node --test`
|
|
25
|
-
* already runs.
|
|
26
|
-
* - The interface below does not leak this choice: a future
|
|
27
|
-
* `KeychainCredentialStore` satisfies the same three methods and every
|
|
28
|
-
* caller (including the safety gate) is unaffected by the swap.
|
|
4
|
+
* equivalent) plugs into later. This pass uses `EncryptedFileCredentialStore`
|
|
5
|
+
* (AES-256-GCM file store) instead, disclosed per honest-degradation
|
|
6
|
+
* (rule 7) rather than passed off as a real keychain:
|
|
7
|
+
* - `keytar` is unmaintained (no releases since 2021, native prebuilt
|
|
8
|
+
* binaries) and neither this repo nor `descry-core` already depends on it.
|
|
9
|
+
* - `node:crypto` is already used elsewhere in this repo, no native build.
|
|
10
|
+
* - The interface doesn't leak this choice — a future
|
|
11
|
+
* `KeychainCredentialStore` is a drop-in swap.
|
|
29
12
|
*/
|
|
30
13
|
import { randomBytes, createCipheriv, createDecipheriv, createHash } from "node:crypto";
|
|
31
14
|
import { mkdir, readFile, writeFile, unlink, chmod } from "node:fs/promises";
|
|
@@ -35,23 +18,22 @@ import { join } from "node:path";
|
|
|
35
18
|
const ALGORITHM = "aes-256-gcm";
|
|
36
19
|
const KEY_BYTES = 32;
|
|
37
20
|
const IV_BYTES = 12;
|
|
21
|
+
// Pinned to 16 bytes on both cipher directions (S-1): unpinned, `setAuthTag`
|
|
22
|
+
// accepts any shorter tag and GCM authenticates against only that many
|
|
23
|
+
// bytes (a real tag's 4/8/12-byte prefix all pass). Pinning here, plus the
|
|
24
|
+
// length check in retrieve() below, is what forces full 2^128 forgery
|
|
25
|
+
// resistance instead of whatever length is present on disk.
|
|
26
|
+
const AUTH_TAG_BYTES = 16;
|
|
38
27
|
/**
|
|
39
|
-
* AES-256-GCM file-at-rest fallback.
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
* convention, and so a ref containing characters unsafe for a filename
|
|
44
|
-
* never needs special-casing.
|
|
28
|
+
* AES-256-GCM file-at-rest fallback. Each `credentialRef` is stored under
|
|
29
|
+
* the SHA-256 hash of the ref, not the ref itself — scoping is structural
|
|
30
|
+
* (wrong ref hashes to a different, absent file) and unsafe filename
|
|
31
|
+
* characters never need special-casing.
|
|
45
32
|
*
|
|
46
|
-
* The AES key
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
* against another *process running as the same user*, which is the
|
|
51
|
-
* limitation a real OS keychain (backed by the platform's own access
|
|
52
|
-
* control / user login secret) does not have. That gap is exactly why
|
|
53
|
-
* this is documented as an interim fallback rather than the intended
|
|
54
|
-
* long-term implementation.
|
|
33
|
+
* The AES key lives in `master.key` under the store dir, both chmod'd
|
|
34
|
+
* 0o600/0o700 owner-only. This protects against other users on a shared
|
|
35
|
+
* machine, not another process running as the same user — a real OS
|
|
36
|
+
* keychain doesn't have that gap, which is why this is interim.
|
|
55
37
|
*/
|
|
56
38
|
export class EncryptedFileCredentialStore {
|
|
57
39
|
baseDir;
|
|
@@ -67,7 +49,7 @@ export class EncryptedFileCredentialStore {
|
|
|
67
49
|
await mkdir(this.entriesDir, { recursive: true, mode: 0o700 });
|
|
68
50
|
const key = await this.loadOrCreateKey();
|
|
69
51
|
const iv = randomBytes(IV_BYTES);
|
|
70
|
-
const cipher = createCipheriv(ALGORITHM, key, iv);
|
|
52
|
+
const cipher = createCipheriv(ALGORITHM, key, iv, { authTagLength: AUTH_TAG_BYTES });
|
|
71
53
|
const ciphertext = Buffer.concat([cipher.update(secret, "utf8"), cipher.final()]);
|
|
72
54
|
const envelope = {
|
|
73
55
|
iv: iv.toString("base64"),
|
|
@@ -86,8 +68,16 @@ export class EncryptedFileCredentialStore {
|
|
|
86
68
|
const key = await this.loadOrCreateKey();
|
|
87
69
|
const raw = await readFile(path, "utf8");
|
|
88
70
|
const envelope = JSON.parse(raw);
|
|
89
|
-
const
|
|
90
|
-
|
|
71
|
+
const authTag = Buffer.from(envelope.authTag, "base64");
|
|
72
|
+
// Reject on length before setAuthTag/final(): anything but a full
|
|
73
|
+
// 16-byte tag (truncated, or written by a pre-S-1 build) must fail
|
|
74
|
+
// loudly rather than risk authenticating against a shortened tag.
|
|
75
|
+
if (authTag.length !== AUTH_TAG_BYTES) {
|
|
76
|
+
throw new Error(`EncryptedFileCredentialStore: refusing to decrypt "${credentialRef}" -- authTag is ${String(authTag.length)} bytes, expected exactly ${String(AUTH_TAG_BYTES)}. ` +
|
|
77
|
+
"This envelope is either tampered with or was written before authTagLength was pinned (S-1); it cannot be safely decrypted as-is.");
|
|
78
|
+
}
|
|
79
|
+
const decipher = createDecipheriv(ALGORITHM, key, Buffer.from(envelope.iv, "base64"), { authTagLength: AUTH_TAG_BYTES });
|
|
80
|
+
decipher.setAuthTag(authTag);
|
|
91
81
|
const plaintext = Buffer.concat([
|
|
92
82
|
decipher.update(Buffer.from(envelope.ciphertext, "base64")),
|
|
93
83
|
decipher.final(),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"credential-store.js","sourceRoot":"","sources":["../src/credential-store.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"credential-store.js","sourceRoot":"","sources":["../src/credential-store.ts"],"names":[],"mappings":"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"}
|
package/dist/profile.d.ts
CHANGED
|
@@ -1,38 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* DEC-266's four target kinds (local booted, local attached, remote
|
|
5
|
-
* dev/staging/preview, production).
|
|
2
|
+
* DEC-270, building on DEC-266's four target kinds (local booted, local
|
|
3
|
+
* attached, remote dev/staging/preview, production).
|
|
6
4
|
*
|
|
7
|
-
* A profile is
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* that governs what is permitted, and it is always set explicitly by the
|
|
11
|
-
* user, never guessed from the name or the URL.
|
|
5
|
+
* A profile is user-named, no fixed vocabulary — nothing here pattern-matches
|
|
6
|
+
* on `name`; `safetyLevel` alone governs what's permitted, always set
|
|
7
|
+
* explicitly by the user, never guessed from name or URL.
|
|
12
8
|
*
|
|
13
|
-
* `credentialRef` is a reference into a `CredentialStore
|
|
14
|
-
*
|
|
15
|
-
* serialize or hand to a planner without ever exposing what it points at.
|
|
9
|
+
* `credentialRef` is a reference into a `CredentialStore`, never the raw
|
|
10
|
+
* secret — safe to log, serialize, or hand to a planner.
|
|
16
11
|
*
|
|
17
|
-
* `mode
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* existed with real tests and zero callers, and there was no profile-level
|
|
21
|
-
* place for a "remote/production" target to declare where its logs live,
|
|
22
|
-
* so nothing could have called it. `mode` closes that: it is what
|
|
23
|
-
* `packages/orchestrator/src/profile-backend-observation.ts` reads to
|
|
24
|
-
* choose DEC-271's mechanism — a real `InboundProxy` for `"localBooted"`,
|
|
12
|
+
* `mode`/`remoteLogSource` (RT-197/DEC-271) name which of DEC-266's four
|
|
13
|
+
* kinds a profile is; `profile-backend-observation.ts` reads `mode` to pick
|
|
14
|
+
* DEC-271's mechanism — `InboundProxy` for `"localBooted"`,
|
|
25
15
|
* `remote-log-ingestion` for `"remote"`/`"production"`, never both.
|
|
26
16
|
*/
|
|
27
17
|
import type { RemoteLogSourceConfig } from "@descryy/runtime-remote-log-ingestion";
|
|
28
18
|
/** Set once by the user per profile. Never inferred from `name` (DEC-270's core rule). */
|
|
29
19
|
export declare const SAFETY_LEVELS: readonly ["readOnly", "write", "destructiveWithApproval"];
|
|
30
20
|
export type SafetyLevel = (typeof SAFETY_LEVELS)[number];
|
|
31
|
-
/**
|
|
32
|
-
* DEC-266's four target kinds, named as a closed union for the first time
|
|
33
|
-
* (RT-197). Set once by the user per profile, same discipline as
|
|
34
|
-
* `safetyLevel` — never inferred from `name` or `url`.
|
|
35
|
-
*/
|
|
21
|
+
/** DEC-266's four target kinds, closed union (RT-197). Never inferred, like `safetyLevel`. */
|
|
36
22
|
export declare const PROFILE_MODES: readonly ["localBooted", "localAttached", "remote", "production"];
|
|
37
23
|
export type ProfileMode = (typeof PROFILE_MODES)[number];
|
|
38
24
|
export interface EnvironmentProfile {
|
|
@@ -41,37 +27,29 @@ export interface EnvironmentProfile {
|
|
|
41
27
|
readonly url: string;
|
|
42
28
|
readonly safetyLevel: SafetyLevel;
|
|
43
29
|
/**
|
|
44
|
-
* Opaque key into a `CredentialStore` — never the raw secret
|
|
45
|
-
*
|
|
46
|
-
* `credentialRef`, so a credential entered for one is never retrievable
|
|
47
|
-
* under another's identity, even by accident (DEC-270).
|
|
30
|
+
* Opaque key into a `CredentialStore` — never the raw secret. Scoped per
|
|
31
|
+
* profile: two profiles must never share a `credentialRef` (DEC-270).
|
|
48
32
|
*/
|
|
49
33
|
readonly credentialRef: string;
|
|
50
34
|
/** Which of DEC-266's four kinds this profile targets. Governs DEC-271's mechanism choice — see this file's own header. */
|
|
51
35
|
readonly mode: ProfileMode;
|
|
52
36
|
/**
|
|
53
|
-
* DEC-271's "ask, don't guess" input for
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
* `validateProfile` rejects it on a `"localBooted"`/`"localAttached"`
|
|
58
|
-
* profile rather than silently ignoring it, because a caller that set it
|
|
59
|
-
* there believed it would be honored and it would not have been.
|
|
37
|
+
* DEC-271's "ask, don't guess" input for remote/production log location.
|
|
38
|
+
* Only meaningful for `mode: "remote"`/`"production"` — `validateProfile`
|
|
39
|
+
* rejects it on a local mode rather than silently ignoring it, since a
|
|
40
|
+
* caller that set it there expected it to be honored.
|
|
60
41
|
*
|
|
61
42
|
* `null`/absent on a remote or production profile is a real, honest
|
|
62
|
-
* state
|
|
63
|
-
*
|
|
64
|
-
* the other direction: `@descryy/runtime-remote-log-ingestion` does not
|
|
65
|
-
* import from this package.
|
|
43
|
+
* state, not an error. No reverse dependency: `runtime-remote-log-ingestion`
|
|
44
|
+
* does not import from this package.
|
|
66
45
|
*/
|
|
67
46
|
readonly remoteLogSource?: RemoteLogSourceConfig | null;
|
|
68
47
|
}
|
|
69
48
|
export type ProfileValidationError = "EMPTY_NAME" | "EMPTY_CREDENTIAL_REF" | "INVALID_URL" | "INVALID_SAFETY_LEVEL" | "INVALID_MODE" | "REMOTE_LOG_SOURCE_NOT_ALLOWED_FOR_MODE";
|
|
70
49
|
/**
|
|
71
|
-
* Structural validation only —
|
|
72
|
-
* credential exists
|
|
73
|
-
*
|
|
74
|
-
* possible (e.g. while a setup form is still being filled in).
|
|
50
|
+
* Structural validation only — doesn't reach `url` or verify the
|
|
51
|
+
* credential exists (runtime concerns), so it can run while a setup form
|
|
52
|
+
* is still being filled in.
|
|
75
53
|
*/
|
|
76
54
|
export declare function validateProfile(input: {
|
|
77
55
|
readonly name: string;
|
|
@@ -81,12 +59,7 @@ export declare function validateProfile(input: {
|
|
|
81
59
|
readonly mode: string;
|
|
82
60
|
readonly remoteLogSource?: RemoteLogSourceConfig | null;
|
|
83
61
|
}): readonly ProfileValidationError[];
|
|
84
|
-
/**
|
|
85
|
-
* Validates and constructs a profile in one step. Throws with every
|
|
86
|
-
* validation error joined, rather than the first one only, so a caller
|
|
87
|
-
* building a setup form doesn't have to fix and resubmit one field at a
|
|
88
|
-
* time.
|
|
89
|
-
*/
|
|
62
|
+
/** Throws with every validation error joined, not just the first, so a setup form can show all problems at once. */
|
|
90
63
|
export declare function createEnvironmentProfile(input: {
|
|
91
64
|
readonly name: string;
|
|
92
65
|
readonly url: string;
|
package/dist/profile.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"profile.d.ts","sourceRoot":"","sources":["../src/profile.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"profile.d.ts","sourceRoot":"","sources":["../src/profile.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAC;AAEnF,0FAA0F;AAC1F,eAAO,MAAM,aAAa,2DAA4D,CAAC;AACvF,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC;AAEzD,8FAA8F;AAC9F,eAAO,MAAM,aAAa,mEAAoE,CAAC;AAC/F,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC;AAEzD,MAAM,WAAW,kBAAkB;IACjC,gGAAgG;IAChG,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;IAClC;;;OAGG;IACH,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,2HAA2H;IAC3H,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B;;;;;;;;;OASG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,qBAAqB,GAAG,IAAI,CAAC;CACzD;AAED,MAAM,MAAM,sBAAsB,GAC9B,YAAY,GACZ,sBAAsB,GACtB,aAAa,GACb,sBAAsB,GACtB,cAAc,GACd,wCAAwC,CAAC;AAE7C;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE;IACrC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,eAAe,CAAC,EAAE,qBAAqB,GAAG,IAAI,CAAC;CACzD,GAAG,SAAS,sBAAsB,EAAE,CA2BpC;AAWD,oHAAoH;AACpH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE;IAC9C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;IAClC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,QAAQ,CAAC,eAAe,CAAC,EAAE,qBAAqB,GAAG,IAAI,CAAC;CACzD,GAAG,kBAAkB,CAarB"}
|
package/dist/profile.js
CHANGED
|
@@ -1,42 +1,27 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* DEC-266's four target kinds (local booted, local attached, remote
|
|
5
|
-
* dev/staging/preview, production).
|
|
2
|
+
* DEC-270, building on DEC-266's four target kinds (local booted, local
|
|
3
|
+
* attached, remote dev/staging/preview, production).
|
|
6
4
|
*
|
|
7
|
-
* A profile is
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* that governs what is permitted, and it is always set explicitly by the
|
|
11
|
-
* user, never guessed from the name or the URL.
|
|
5
|
+
* A profile is user-named, no fixed vocabulary — nothing here pattern-matches
|
|
6
|
+
* on `name`; `safetyLevel` alone governs what's permitted, always set
|
|
7
|
+
* explicitly by the user, never guessed from name or URL.
|
|
12
8
|
*
|
|
13
|
-
* `credentialRef` is a reference into a `CredentialStore
|
|
14
|
-
*
|
|
15
|
-
* serialize or hand to a planner without ever exposing what it points at.
|
|
9
|
+
* `credentialRef` is a reference into a `CredentialStore`, never the raw
|
|
10
|
+
* secret — safe to log, serialize, or hand to a planner.
|
|
16
11
|
*
|
|
17
|
-
* `mode
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* existed with real tests and zero callers, and there was no profile-level
|
|
21
|
-
* place for a "remote/production" target to declare where its logs live,
|
|
22
|
-
* so nothing could have called it. `mode` closes that: it is what
|
|
23
|
-
* `packages/orchestrator/src/profile-backend-observation.ts` reads to
|
|
24
|
-
* choose DEC-271's mechanism — a real `InboundProxy` for `"localBooted"`,
|
|
12
|
+
* `mode`/`remoteLogSource` (RT-197/DEC-271) name which of DEC-266's four
|
|
13
|
+
* kinds a profile is; `profile-backend-observation.ts` reads `mode` to pick
|
|
14
|
+
* DEC-271's mechanism — `InboundProxy` for `"localBooted"`,
|
|
25
15
|
* `remote-log-ingestion` for `"remote"`/`"production"`, never both.
|
|
26
16
|
*/
|
|
27
17
|
/** Set once by the user per profile. Never inferred from `name` (DEC-270's core rule). */
|
|
28
18
|
export const SAFETY_LEVELS = ["readOnly", "write", "destructiveWithApproval"];
|
|
29
|
-
/**
|
|
30
|
-
* DEC-266's four target kinds, named as a closed union for the first time
|
|
31
|
-
* (RT-197). Set once by the user per profile, same discipline as
|
|
32
|
-
* `safetyLevel` — never inferred from `name` or `url`.
|
|
33
|
-
*/
|
|
19
|
+
/** DEC-266's four target kinds, closed union (RT-197). Never inferred, like `safetyLevel`. */
|
|
34
20
|
export const PROFILE_MODES = ["localBooted", "localAttached", "remote", "production"];
|
|
35
21
|
/**
|
|
36
|
-
* Structural validation only —
|
|
37
|
-
* credential exists
|
|
38
|
-
*
|
|
39
|
-
* possible (e.g. while a setup form is still being filled in).
|
|
22
|
+
* Structural validation only — doesn't reach `url` or verify the
|
|
23
|
+
* credential exists (runtime concerns), so it can run while a setup form
|
|
24
|
+
* is still being filled in.
|
|
40
25
|
*/
|
|
41
26
|
export function validateProfile(input) {
|
|
42
27
|
const errors = [];
|
|
@@ -55,9 +40,7 @@ export function validateProfile(input) {
|
|
|
55
40
|
if (!PROFILE_MODES.includes(input.mode)) {
|
|
56
41
|
errors.push("INVALID_MODE");
|
|
57
42
|
}
|
|
58
|
-
//
|
|
59
|
-
// silently-ignored setting, not a harmless extra -- rejected rather than
|
|
60
|
-
// dropped, so the caller who set it learns it would not have been honored.
|
|
43
|
+
// Rejected rather than silently dropped -- caller learns it wouldn't be honored.
|
|
61
44
|
if (input.remoteLogSource != null &&
|
|
62
45
|
(input.mode === "localBooted" || input.mode === "localAttached")) {
|
|
63
46
|
errors.push("REMOTE_LOG_SOURCE_NOT_ALLOWED_FOR_MODE");
|
|
@@ -73,12 +56,7 @@ function isParsableUrl(url) {
|
|
|
73
56
|
return false;
|
|
74
57
|
}
|
|
75
58
|
}
|
|
76
|
-
/**
|
|
77
|
-
* Validates and constructs a profile in one step. Throws with every
|
|
78
|
-
* validation error joined, rather than the first one only, so a caller
|
|
79
|
-
* building a setup form doesn't have to fix and resubmit one field at a
|
|
80
|
-
* time.
|
|
81
|
-
*/
|
|
59
|
+
/** Throws with every validation error joined, not just the first, so a setup form can show all problems at once. */
|
|
82
60
|
export function createEnvironmentProfile(input) {
|
|
83
61
|
const errors = validateProfile(input);
|
|
84
62
|
if (errors.length > 0) {
|
package/dist/profile.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"profile.js","sourceRoot":"","sources":["../src/profile.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"profile.js","sourceRoot":"","sources":["../src/profile.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH,0FAA0F;AAC1F,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,UAAU,EAAE,OAAO,EAAE,yBAAyB,CAAU,CAAC;AAGvF,8FAA8F;AAC9F,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,aAAa,EAAE,eAAe,EAAE,QAAQ,EAAE,YAAY,CAAU,CAAC;AAoC/F;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,KAO/B;IACC,MAAM,MAAM,GAA6B,EAAE,CAAC;IAE5C,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACnC,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAC5B,CAAC;IACD,IAAI,KAAK,CAAC,aAAa,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5C,MAAM,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;IACtC,CAAC;IACD,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QAC9B,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IAC7B,CAAC;IACD,IAAI,CAAE,aAAmC,CAAC,QAAQ,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC;QACtE,MAAM,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;IACtC,CAAC;IACD,IAAI,CAAE,aAAmC,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QAC/D,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAC9B,CAAC;IACD,iFAAiF;IACjF,IACE,KAAK,CAAC,eAAe,IAAI,IAAI;QAC7B,CAAC,KAAK,CAAC,IAAI,KAAK,aAAa,IAAI,KAAK,CAAC,IAAI,KAAK,eAAe,CAAC,EAChE,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,wCAAwC,CAAC,CAAC;IACxD,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,aAAa,CAAC,GAAW;IAChC,IAAI,CAAC;QACH,KAAK,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QAClB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,oHAAoH;AACpH,MAAM,UAAU,wBAAwB,CAAC,KAOxC;IACC,MAAM,MAAM,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;IACtC,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,gCAAgC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACvE,CAAC;IACD,OAAO;QACL,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE;QACvB,GAAG,EAAE,KAAK,CAAC,GAAG;QACd,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,aAAa,EAAE,KAAK,CAAC,aAAa,CAAC,IAAI,EAAE;QACzC,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,eAAe,EAAE,KAAK,CAAC,eAAe,IAAI,IAAI;KAC/C,CAAC;AACJ,CAAC"}
|
package/dist/safety-gate.d.ts
CHANGED
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* This function does not wire itself into any caller — DEC-270 only asks
|
|
7
|
-
* that it exist and be correct; the runners that actually perform
|
|
8
|
-
* destructive actions (a different lane's work) call it before acting.
|
|
2
|
+
* DEC-270's enforcement point: destructive actions check the profile's
|
|
3
|
+
* declared safety level, never the environment's name or "not prod."
|
|
4
|
+
* Not wired to any caller here — runners that perform destructive actions
|
|
5
|
+
* (a different lane) call this before acting.
|
|
9
6
|
*/
|
|
10
7
|
import type { EnvironmentProfile } from "./profile.ts";
|
|
11
8
|
export declare const GATE_DECISIONS: readonly ["allow", "deny", "requiresApproval"];
|
|
@@ -29,10 +26,9 @@ export interface ProposedAction {
|
|
|
29
26
|
* | `write` | allow | allow | deny |
|
|
30
27
|
* | `destructiveWithApproval` | allow | allow | requiresApproval |
|
|
31
28
|
*
|
|
32
|
-
* `write` denies destructive rather than escalating
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
* is declared, not inferred or auto-upgraded.
|
|
29
|
+
* `write` denies destructive rather than escalating to approval — an
|
|
30
|
+
* owner who chose `write` did not choose `destructiveWithApproval`;
|
|
31
|
+
* DEC-270 requires the level be declared, not auto-upgraded.
|
|
36
32
|
*/
|
|
37
33
|
export declare function evaluateAction(profile: EnvironmentProfile, action: ProposedAction): GateDecision;
|
|
38
34
|
//# sourceMappingURL=safety-gate.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"safety-gate.d.ts","sourceRoot":"","sources":["../src/safety-gate.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"safety-gate.d.ts","sourceRoot":"","sources":["../src/safety-gate.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAEvD,eAAO,MAAM,cAAc,gDAAiD,CAAC;AAC7E,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC;AAE3D,MAAM,WAAW,cAAc;IAC7B,yFAAyF;IACzF,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB;;;;OAIG;IACH,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;CAC/B;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,kBAAkB,EAAE,MAAM,EAAE,cAAc,GAAG,YAAY,CAQhG"}
|
package/dist/safety-gate.js
CHANGED
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* This function does not wire itself into any caller — DEC-270 only asks
|
|
7
|
-
* that it exist and be correct; the runners that actually perform
|
|
8
|
-
* destructive actions (a different lane's work) call it before acting.
|
|
2
|
+
* DEC-270's enforcement point: destructive actions check the profile's
|
|
3
|
+
* declared safety level, never the environment's name or "not prod."
|
|
4
|
+
* Not wired to any caller here — runners that perform destructive actions
|
|
5
|
+
* (a different lane) call this before acting.
|
|
9
6
|
*/
|
|
10
7
|
export const GATE_DECISIONS = ["allow", "deny", "requiresApproval"];
|
|
11
8
|
/**
|
|
@@ -17,10 +14,9 @@ export const GATE_DECISIONS = ["allow", "deny", "requiresApproval"];
|
|
|
17
14
|
* | `write` | allow | allow | deny |
|
|
18
15
|
* | `destructiveWithApproval` | allow | allow | requiresApproval |
|
|
19
16
|
*
|
|
20
|
-
* `write` denies destructive rather than escalating
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* is declared, not inferred or auto-upgraded.
|
|
17
|
+
* `write` denies destructive rather than escalating to approval — an
|
|
18
|
+
* owner who chose `write` did not choose `destructiveWithApproval`;
|
|
19
|
+
* DEC-270 requires the level be declared, not auto-upgraded.
|
|
24
20
|
*/
|
|
25
21
|
export function evaluateAction(profile, action) {
|
|
26
22
|
if (action.destructive) {
|
package/dist/safety-gate.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"safety-gate.js","sourceRoot":"","sources":["../src/safety-gate.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"safety-gate.js","sourceRoot":"","sources":["../src/safety-gate.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,kBAAkB,CAAU,CAAC;AAc7E;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,cAAc,CAAC,OAA2B,EAAE,MAAsB;IAChF,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;QACvB,OAAO,OAAO,CAAC,WAAW,KAAK,yBAAyB,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,MAAM,CAAC;IACzF,CAAC;IACD,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QACjB,OAAO,OAAO,CAAC,WAAW,KAAK,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;IAC/D,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@descryy/runtime-environment-profile",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Environment profiles per DEC-270/DEC-266: a user-named target (local booted/attached, remote dev/staging/preview, production) carrying a declared safety level, scoped credentials, and the safety-gate enforcement point destructive actions must call before running.",
|
|
6
6
|
"license": "UNLICENSED",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/descryhq-wq/descry-runtime.git",
|
|
10
|
+
"directory": "packages/environment-profile"
|
|
11
|
+
},
|
|
7
12
|
"engines": {
|
|
8
13
|
"node": ">=22.5"
|
|
9
14
|
},
|
|
@@ -24,6 +29,6 @@
|
|
|
24
29
|
"build": "tsc -b"
|
|
25
30
|
},
|
|
26
31
|
"dependencies": {
|
|
27
|
-
"@descryy/runtime-remote-log-ingestion": "0.
|
|
32
|
+
"@descryy/runtime-remote-log-ingestion": "0.4.0"
|
|
28
33
|
}
|
|
29
34
|
}
|