@oscharko-dev/keiko-security 0.2.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.
Files changed (56) hide show
  1. package/dist/.tsbuildinfo +1 -0
  2. package/dist/errors/audit.d.ts +26 -0
  3. package/dist/errors/audit.d.ts.map +1 -0
  4. package/dist/errors/audit.js +39 -0
  5. package/dist/errors/gateway.d.ts +84 -0
  6. package/dist/errors/gateway.d.ts.map +1 -0
  7. package/dist/errors/gateway.js +95 -0
  8. package/dist/errors/harness.d.ts +22 -0
  9. package/dist/errors/harness.d.ts.map +1 -0
  10. package/dist/errors/harness.js +39 -0
  11. package/dist/errors/index.d.ts +9 -0
  12. package/dist/errors/index.d.ts.map +1 -0
  13. package/dist/errors/index.js +12 -0
  14. package/dist/errors/promptEnhancer.d.ts +38 -0
  15. package/dist/errors/promptEnhancer.d.ts.map +1 -0
  16. package/dist/errors/promptEnhancer.js +56 -0
  17. package/dist/errors/secretbox.d.ts +5 -0
  18. package/dist/errors/secretbox.d.ts.map +1 -0
  19. package/dist/errors/secretbox.js +13 -0
  20. package/dist/errors/tools.d.ts +60 -0
  21. package/dist/errors/tools.d.ts.map +1 -0
  22. package/dist/errors/tools.js +94 -0
  23. package/dist/errors/verification.d.ts +12 -0
  24. package/dist/errors/verification.d.ts.map +1 -0
  25. package/dist/errors/verification.js +21 -0
  26. package/dist/errors/workspace.d.ts +56 -0
  27. package/dist/errors/workspace.d.ts.map +1 -0
  28. package/dist/errors/workspace.js +95 -0
  29. package/dist/hashing.d.ts +4 -0
  30. package/dist/hashing.d.ts.map +1 -0
  31. package/dist/hashing.js +38 -0
  32. package/dist/index.d.ts +11 -0
  33. package/dist/index.d.ts.map +1 -0
  34. package/dist/index.js +13 -0
  35. package/dist/promptInjection.d.ts +29 -0
  36. package/dist/promptInjection.d.ts.map +1 -0
  37. package/dist/promptInjection.js +235 -0
  38. package/dist/redaction.d.ts +5 -0
  39. package/dist/redaction.d.ts.map +1 -0
  40. package/dist/redaction.js +123 -0
  41. package/dist/runid.d.ts +2 -0
  42. package/dist/runid.d.ts.map +1 -0
  43. package/dist/runid.js +29 -0
  44. package/dist/secret-vault.d.ts +33 -0
  45. package/dist/secret-vault.d.ts.map +1 -0
  46. package/dist/secret-vault.js +271 -0
  47. package/dist/secretbox.d.ts +6 -0
  48. package/dist/secretbox.d.ts.map +1 -0
  49. package/dist/secretbox.js +80 -0
  50. package/dist/secrets.d.ts +4 -0
  51. package/dist/secrets.d.ts.map +1 -0
  52. package/dist/secrets.js +34 -0
  53. package/dist/version.d.ts +2 -0
  54. package/dist/version.d.ts.map +1 -0
  55. package/dist/version.js +4 -0
  56. package/package.json +78 -0
@@ -0,0 +1,235 @@
1
+ // Authoritative prompt-injection / unsafe-content detector for the Prompt Enhancer
2
+ // (Epic #1307, Issue #1313; ADR-0044 §1/§5).
3
+ //
4
+ // ADR-0044 places the authoritative prompt-injection patterns and secret/PII detectors in
5
+ // `keiko-security`; the contracts analyzer's lexical risk cues (#1309) are a deliberately shallow
6
+ // signal only. This module is the deep detector the gateway validate stage composes over the
7
+ // contracts structural assessment: it scans UNTRUSTED text for instruction-override, system/developer
8
+ // prompt disclosure, secret-exfiltration, unsafe tool/agency requests, egress requests, and
9
+ // manipulative role-reassignment, and it detects embedded secret material by reusing `redact`.
10
+ //
11
+ // Content-free by construction (safe-error discipline, ADR-0003/ADR-0044 §5): a signal carries only a
12
+ // stable closed-vocabulary `code` and a match COUNT — never the matched text. The result is therefore
13
+ // always safe to log, persist as evidence, and surface across trust boundaries.
14
+ //
15
+ // ReDoS-safe by construction: detection is substring containment over a normalized lowercase view
16
+ // (linear, no backtracking). The only regular expressions reached are inside `redact`, which is itself
17
+ // bounded-quantifier ReDoS-safe (ADR-0002).
18
+ import { redact } from "./redaction.js";
19
+ export const PROMPT_INJECTION_SIGNAL_CODES = [
20
+ "instruction-override",
21
+ "system-prompt-disclosure",
22
+ "secret-exfiltration",
23
+ "tool-authority-request",
24
+ "egress-request",
25
+ "manipulative-framing",
26
+ "embedded-secret-material",
27
+ ];
28
+ export const isPromptInjectionSignalCode = (value) => typeof value === "string" && PROMPT_INJECTION_SIGNAL_CODES.includes(value);
29
+ // Cue tables. Lowercased substrings; each is a deeper, more comprehensive set than the contracts
30
+ // analyzer's shallow risk cues. Ordered by code for readability.
31
+ const INJECTION_RULES = [
32
+ {
33
+ code: "instruction-override",
34
+ severity: "critical",
35
+ cues: [
36
+ "ignore previous instructions",
37
+ "ignore all previous",
38
+ "ignore the above",
39
+ "ignore your instructions",
40
+ "ignore your guidelines",
41
+ "ignore all prior",
42
+ "disregard previous",
43
+ "disregard the above",
44
+ "disregard all prior",
45
+ "disregard your instructions",
46
+ "forget your instructions",
47
+ "forget all previous",
48
+ "override your instructions",
49
+ "do not follow your instructions",
50
+ "bypass your restrictions",
51
+ "ignore the safety rules",
52
+ "ignore all safety",
53
+ ],
54
+ },
55
+ {
56
+ code: "system-prompt-disclosure",
57
+ severity: "critical",
58
+ cues: [
59
+ "system prompt",
60
+ "reveal your instructions",
61
+ "show me your instructions",
62
+ "print your instructions",
63
+ "repeat the words above",
64
+ "repeat your system",
65
+ "what is your system prompt",
66
+ "reveal your prompt",
67
+ "show your prompt",
68
+ "your initial instructions",
69
+ "disclose your instructions",
70
+ "what were you told",
71
+ "the text above this line",
72
+ ],
73
+ },
74
+ {
75
+ code: "secret-exfiltration",
76
+ severity: "critical",
77
+ cues: [
78
+ "api key",
79
+ "apikey",
80
+ "secret key",
81
+ "access token",
82
+ "your password",
83
+ "the password",
84
+ "your credentials",
85
+ "environment variable",
86
+ "env var",
87
+ "process.env",
88
+ ".env file",
89
+ "private key",
90
+ "ssh key",
91
+ "reveal the secret",
92
+ "print the secret",
93
+ "show me the api",
94
+ "leak the",
95
+ "dump the secrets",
96
+ "exfiltrate the",
97
+ ],
98
+ },
99
+ {
100
+ code: "tool-authority-request",
101
+ severity: "critical",
102
+ cues: [
103
+ "run this command",
104
+ "execute this command",
105
+ "run the script",
106
+ "execute the following",
107
+ "sudo ",
108
+ "rm -rf",
109
+ "grant yourself",
110
+ "give yourself access",
111
+ "install and run",
112
+ "you have permission to run",
113
+ "act as root",
114
+ "with admin privileges",
115
+ "escalate privileges",
116
+ "deploy to production",
117
+ ],
118
+ },
119
+ {
120
+ code: "egress-request",
121
+ severity: "critical",
122
+ cues: [
123
+ "exfiltrate",
124
+ "send the data to",
125
+ "upload to",
126
+ "post to http",
127
+ "curl http",
128
+ "wget http",
129
+ "make a request to http",
130
+ "send it to my server",
131
+ "download from and run",
132
+ "email the data",
133
+ "leak to",
134
+ ],
135
+ },
136
+ {
137
+ code: "manipulative-framing",
138
+ severity: "elevated",
139
+ cues: [
140
+ "you are now ",
141
+ "pretend to be",
142
+ "pretend you are",
143
+ "act as if you have no",
144
+ "developer mode",
145
+ "jailbreak",
146
+ "dan mode",
147
+ "you must comply",
148
+ "without any restrictions",
149
+ "there are no rules",
150
+ "this is only hypothetical so",
151
+ "from now on you are",
152
+ "you are no longer",
153
+ "new system role",
154
+ "assume the role of an unrestricted",
155
+ ],
156
+ },
157
+ ];
158
+ // Inclusive code-point ranges to strip: C0 controls (excluding tab/LF/CR), DEL, C1 controls, the
159
+ // zero-width joiners/space, the BOM, and the bidi-embedding/isolate format characters used to hide
160
+ // injection markers. Tab (0x09), LF (0x0a), and CR (0x0d) are preserved by carving the C0 range.
161
+ const STRIPPABLE_CODE_POINT_RANGES = [
162
+ [0x00, 0x08],
163
+ [0x0b, 0x0c],
164
+ [0x0e, 0x1f],
165
+ [0x7f, 0x7f],
166
+ [0x80, 0x9f],
167
+ [0x200b, 0x200d],
168
+ [0x202a, 0x202e],
169
+ [0x2066, 0x2069],
170
+ [0xfeff, 0xfeff],
171
+ ];
172
+ // Strip control / zero-width / bidi code points and NFKC-normalise so unicode obfuscation cannot evade
173
+ // substring matching. Mirrors the QI promptSegmentation control stripper (code-point scan, no
174
+ // no-control-regex lint suppression needed).
175
+ function isStrippableCodePoint(codePoint) {
176
+ return STRIPPABLE_CODE_POINT_RANGES.some(([lo, hi]) => codePoint >= lo && codePoint <= hi);
177
+ }
178
+ function normalizeForDetection(input) {
179
+ let out = "";
180
+ for (const ch of input.normalize("NFKC")) {
181
+ const codePoint = ch.codePointAt(0);
182
+ if (codePoint === undefined)
183
+ continue;
184
+ if (!isStrippableCodePoint(codePoint))
185
+ out += ch;
186
+ }
187
+ return out.toLowerCase();
188
+ }
189
+ function countCueHits(haystack, cues) {
190
+ let count = 0;
191
+ for (const cue of cues) {
192
+ if (haystack.includes(cue))
193
+ count += 1;
194
+ }
195
+ return count;
196
+ }
197
+ /**
198
+ * Detect unsafe-content signals in a piece of UNTRUSTED text (raw user draft, retrieved snippet, or
199
+ * tool output). Pure and content-free: returns a stable list of `{ code, severity, matchCount }`
200
+ * signals and never echoes the matched text. ReDoS-safe (substring containment + the bounded `redact`).
201
+ *
202
+ * `embedded-secret-material` fires when the text itself contains a redactable secret shape — relevant
203
+ * both to secret-exfiltration detection and to the redaction guarantee for persisted evidence.
204
+ */
205
+ export function detectPromptInjectionSignals(untrustedText) {
206
+ if (typeof untrustedText !== "string" || untrustedText.length === 0) {
207
+ return [];
208
+ }
209
+ const normalized = normalizeForDetection(untrustedText);
210
+ const signals = [];
211
+ for (const rule of INJECTION_RULES) {
212
+ const matchCount = countCueHits(normalized, rule.cues);
213
+ if (matchCount > 0) {
214
+ signals.push({ code: rule.code, severity: rule.severity, matchCount });
215
+ }
216
+ }
217
+ if (containsRedactableSecret(untrustedText)) {
218
+ signals.push({ code: "embedded-secret-material", severity: "elevated", matchCount: 1 });
219
+ }
220
+ return signals;
221
+ }
222
+ /**
223
+ * Whether the text contains redactable secret material (a known token/key/credential shape). Reuses
224
+ * the authoritative `redact` so the detector and the redactor agree by construction. Pure.
225
+ */
226
+ export function containsRedactableSecret(text) {
227
+ return typeof text === "string" && text.length > 0 && redact(text) !== text;
228
+ }
229
+ /**
230
+ * Whether any detected signal is `critical` — an active attack attempt (override, disclosure,
231
+ * exfiltration, unsafe tool, or egress). Pure helper for callers gating on attack severity.
232
+ */
233
+ export function hasCriticalInjectionSignal(signals) {
234
+ return signals.some((signal) => signal.severity === "critical");
235
+ }
@@ -0,0 +1,5 @@
1
+ import type { AuditRedactionConfig } from "@oscharko-dev/keiko-contracts";
2
+ export declare function redact(input: string, additionalSecrets?: readonly string[]): string;
3
+ export declare function createAuditRedactor(config: AuditRedactionConfig, env: Readonly<Record<string, string | undefined>>): (input: string) => string;
4
+ export declare function deepRedactStrings(value: unknown, redactString: (input: string) => string): unknown;
5
+ //# sourceMappingURL=redaction.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redaction.d.ts","sourceRoot":"","sources":["../src/redaction.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AA2D1E,wBAAgB,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,iBAAiB,GAAE,SAAS,MAAM,EAAO,GAAG,MAAM,CAmBvF;AA6BD,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,oBAAoB,EAC5B,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,GAChD,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAO3B;AAQD,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,OAAO,EACd,YAAY,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,GACtC,OAAO,CAeT"}
@@ -0,0 +1,123 @@
1
+ // Secret redaction at the boundary. Every provider-derived string passes through
2
+ // redact() before it can reach an error message, log call, or serialised artefact.
3
+ //
4
+ // ReDoS-safe by construction: every built-in pattern is a single linear character class with one
5
+ // bounded or open quantifier (no nesting), so none can backtrack catastrophically. Caller-supplied
6
+ // literals are escaped via escapeRegExp before any RegExp is built, so no caller-controlled
7
+ // metacharacter reaches the regex engine. This keeps the CodeQL js/polynomial-redos required
8
+ // gate green (ADR-0002).
9
+ const REDACTED = "[REDACTED]";
10
+ // Bearer <token>: keep the scheme, drop the credential.
11
+ const BEARER_PATTERN = /\bBearer\s+[\w.\-+/=]+/gi;
12
+ const BASIC_AUTH_PATTERN = /\bBasic\s+[\w.\-+/=]+/gi;
13
+ // OpenAI-style keys (sk-, sk-proj-, etc.): a prefix followed by >= 16 secret chars.
14
+ const API_KEY_PATTERN = /\bsk-[A-Za-z0-9_-]{16,}/g;
15
+ // Common third-party credential shapes. Each is a single linear character class with one
16
+ // bounded/open quantifier (no nesting), so none can backtrack catastrophically — this keeps
17
+ // CodeQL js/polynomial-redos satisfied while scrubbing non-OpenAI secrets from tool output.
18
+ const GITHUB_TOKEN_PATTERN = /\bgh[pousr]_[A-Za-z0-9]{20,}/g;
19
+ const AWS_ACCESS_KEY_PATTERN = /\bAKIA[0-9A-Z]{16}\b/g;
20
+ const SLACK_TOKEN_PATTERN = /\bxox[baprs]-[A-Za-z0-9-]{10,}/g;
21
+ const GOOGLE_API_KEY_PATTERN = /\bAIza[0-9A-Za-z_-]{20,}/g;
22
+ const STRIPE_KEY_PATTERN = /\b[rs]k_(?:live|test)_[A-Za-z0-9]{16,}/g;
23
+ const PEM_PRIVATE_KEY_BLOCK_PATTERN = /-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g;
24
+ const PEM_PRIVATE_KEY_HEADER_PATTERN = /-----BEGIN [A-Z ]*PRIVATE KEY-----/g;
25
+ const GENERIC_API_KEY_HEADER_PATTERN = /\b(x-api-key\s*:\s*)[^\s"'`,;]+/gi;
26
+ const GENERIC_API_KEY_ASSIGNMENT_PATTERN = /\b(api[_-]?key\s*[=:]\s*)[^\s"'`,;&]+/gi;
27
+ // Key-name-based value redaction (Epic #532 security audit H1). Connected-folder browsing and
28
+ // grounded answers can now surface arbitrary files whose secrets do not match a known token SHAPE
29
+ // (gcloud refresh_token, service-account client_secret, generic password/secret fields, AWS secret
30
+ // access key, DB passwords). This scrubs the VALUE assigned to a well-known secret KEY in JSON
31
+ // ("client_secret": "x"), INI/env (db_password=x), or YAML (secret: x) shape — keeping the key and
32
+ // separator, dropping the value. ReDoS-safe: alternation of literals + one linear value class.
33
+ const SECRET_KEY_NAMES = "passwd|password|api_?token|token|secret_key|secret|client_secret|refresh_token|access_token|id_token|private_key|aws_secret_access_key|secret_access_key|sas_token|jwt_secret|db_password|connection_?string|credential";
34
+ const SECRET_KEY_VALUE_PATTERN = new RegExp(`(?<![A-Za-z0-9])(${SECRET_KEY_NAMES})(["']?\\s*[:=]\\s*["']?)[^\\s"'\`,;&]+`, "gi");
35
+ // scheme://user:password@host — strip the userinfo credentials from any URL or DSN. One linear
36
+ // userinfo class on each side of the ':' and bounded by '@', so no catastrophic backtracking.
37
+ const URL_CREDENTIALS_PATTERN = /\b([a-z][a-z0-9+.-]*:\/\/)[^\s:@/]+:[^\s:@/]+@/gi;
38
+ const BUILTIN_PATTERNS = [
39
+ GITHUB_TOKEN_PATTERN,
40
+ AWS_ACCESS_KEY_PATTERN,
41
+ SLACK_TOKEN_PATTERN,
42
+ GOOGLE_API_KEY_PATTERN,
43
+ STRIPE_KEY_PATTERN,
44
+ PEM_PRIVATE_KEY_BLOCK_PATTERN,
45
+ PEM_PRIVATE_KEY_HEADER_PATTERN,
46
+ ];
47
+ function escapeRegExp(value) {
48
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
49
+ }
50
+ // Strips known secret shapes and any caller-supplied literal secrets from `input`.
51
+ // `additionalSecrets` lets the caller pass exact apiKey/baseUrl/env values it holds
52
+ // so even non-standard key formats are scrubbed.
53
+ export function redact(input, additionalSecrets = []) {
54
+ let output = input
55
+ .replace(BEARER_PATTERN, `Bearer ${REDACTED}`)
56
+ .replace(BASIC_AUTH_PATTERN, `Basic ${REDACTED}`)
57
+ .replace(GENERIC_API_KEY_HEADER_PATTERN, `$1${REDACTED}`)
58
+ .replace(GENERIC_API_KEY_ASSIGNMENT_PATTERN, `$1${REDACTED}`)
59
+ .replace(SECRET_KEY_VALUE_PATTERN, `$1$2${REDACTED}`)
60
+ .replace(URL_CREDENTIALS_PATTERN, `$1${REDACTED}@`)
61
+ .replace(API_KEY_PATTERN, REDACTED);
62
+ for (const pattern of BUILTIN_PATTERNS) {
63
+ output = output.replace(pattern, REDACTED);
64
+ }
65
+ for (const secret of additionalSecrets) {
66
+ if (secret.length === 0) {
67
+ continue;
68
+ }
69
+ output = output.replace(new RegExp(escapeRegExp(secret), "g"), REDACTED);
70
+ }
71
+ return output;
72
+ }
73
+ // A literal shorter than this is too generic to scrub safely: redacting a 2-char value would
74
+ // over-redact ordinary prose. redact() itself only skips empty strings, so the floor lives here.
75
+ const MIN_LITERAL_LENGTH = 4;
76
+ // Resolves the VALUES of the named env vars (never the names), keeping only non-empty values long
77
+ // enough to be a plausible secret. The builder passes these as escaped literals to redact().
78
+ function resolveEnvValues(names, env) {
79
+ const values = [];
80
+ for (const name of names) {
81
+ const value = env[name];
82
+ if (value !== undefined && value.length >= MIN_LITERAL_LENGTH) {
83
+ values.push(value);
84
+ }
85
+ }
86
+ return values;
87
+ }
88
+ function keepLongEnough(literals) {
89
+ return literals.filter((literal) => literal.length >= MIN_LITERAL_LENGTH);
90
+ }
91
+ // Returns a function string -> string applying redact() with the union of all literal secrets
92
+ // (additionalSecrets ∪ resolved env values ∪ sensitiveLiterals). Idempotent: redact() over already-
93
+ // redacted text is a no-op on the redacted tokens (ADR-0010 D3 audit-redaction layer).
94
+ export function createAuditRedactor(config, env) {
95
+ const literals = [
96
+ ...keepLongEnough(config.additionalSecrets ?? []),
97
+ ...resolveEnvValues(config.redactEnvValues ?? [], env),
98
+ ...keepLongEnough(config.sensitiveLiterals ?? []),
99
+ ];
100
+ return (input) => redact(input, literals);
101
+ }
102
+ // Recursively re-applies a redactor to EVERY STRING LEAF of a plain-JSON value, rebuilding
103
+ // arrays/objects so the input is never mutated and the JSON structure is preserved exactly. Bounded
104
+ // by the (finite) nesting depth of an EvidenceManifest. Idempotent (redact over already-redacted
105
+ // text is a no-op), so it is safe to apply at build time AND again as defense in depth at persist
106
+ // time. This is what makes the audit builder truly redacted-by-construction even for embedded
107
+ // summaries that the audit redactor would otherwise miss.
108
+ export function deepRedactStrings(value, redactString) {
109
+ if (typeof value === "string") {
110
+ return redactString(value);
111
+ }
112
+ if (Array.isArray(value)) {
113
+ return value.map((item) => deepRedactStrings(item, redactString));
114
+ }
115
+ if (typeof value === "object" && value !== null) {
116
+ const out = {};
117
+ for (const [key, child] of Object.entries(value)) {
118
+ out[key] = deepRedactStrings(child, redactString);
119
+ }
120
+ return out;
121
+ }
122
+ return value;
123
+ }
@@ -0,0 +1,2 @@
1
+ export declare function assertValidRunId(runId: string): void;
2
+ //# sourceMappingURL=runid.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runid.d.ts","sourceRoot":"","sources":["../src/runid.ts"],"names":[],"mappings":"AAoBA,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAYpD"}
package/dist/runid.js ADDED
@@ -0,0 +1,29 @@
1
+ // PURE, bounded runId validation (ADR-0010 D4 iii). The manifest filename is ALWAYS derived from a
2
+ // validated runId, so a malicious runId cannot escape the contained base dir or overwrite an
3
+ // arbitrary file. We accept only a bounded [A-Za-z0-9._-] character set with a length cap and reject
4
+ // a leading dot (no dotfiles, no `..`). NO REGEX is used (D3 no-new-regex rule) — validation is a
5
+ // per-character class check, which is also trivially linear-time.
6
+ import { InvalidRunIdError } from "./errors/audit.js";
7
+ const MAX_RUN_ID_LENGTH = 256;
8
+ // Inclusive ASCII code-point ranges for the allowed class, plus the three allowed punctuation
9
+ // characters. A leading dot is rejected separately so `.` is allowed only in non-leading position.
10
+ function isAllowedChar(code) {
11
+ const isDigit = code >= 48 && code <= 57; // 0-9
12
+ const isUpper = code >= 65 && code <= 90; // A-Z
13
+ const isLower = code >= 97 && code <= 122; // a-z
14
+ const isPunct = code === 46 || code === 95 || code === 45; // . _ -
15
+ return isDigit || isUpper || isLower || isPunct;
16
+ }
17
+ export function assertValidRunId(runId) {
18
+ if (runId.length === 0 || runId.length > MAX_RUN_ID_LENGTH) {
19
+ throw new InvalidRunIdError(`invalid runId length: ${String(runId.length)}`);
20
+ }
21
+ if (runId.startsWith(".")) {
22
+ throw new InvalidRunIdError("runId must not start with a dot");
23
+ }
24
+ for (let i = 0; i < runId.length; i += 1) {
25
+ if (!isAllowedChar(runId.charCodeAt(i))) {
26
+ throw new InvalidRunIdError("runId contains a disallowed character");
27
+ }
28
+ }
29
+ }
@@ -0,0 +1,33 @@
1
+ export type LocalVaultKeySource = "env" | "keychain" | "keyfile";
2
+ export interface ResolvedLocalVaultKey {
3
+ readonly key: Buffer;
4
+ readonly source: LocalVaultKeySource;
5
+ }
6
+ export type LocalVaultKeychainAccess = () => Buffer | undefined;
7
+ export declare const NO_LOCAL_VAULT_KEYCHAIN: LocalVaultKeychainAccess;
8
+ export interface ResolveLocalVaultKeyOptions {
9
+ readonly env: Readonly<Record<string, string | undefined>>;
10
+ readonly vaultDir: string;
11
+ readonly envVarName: string;
12
+ readonly keychainService: string;
13
+ readonly keyfileName: string;
14
+ readonly keychainAccess?: LocalVaultKeychainAccess | undefined;
15
+ }
16
+ export interface LocalSecretVault {
17
+ readonly get: (reference: string) => string | undefined;
18
+ readonly set: (reference: string, secret: string) => void;
19
+ readonly replaceAll: (entries: ReadonlyMap<string, string>) => void;
20
+ readonly delete: (reference: string) => void;
21
+ readonly has: (reference: string) => boolean;
22
+ readonly list: () => readonly string[];
23
+ }
24
+ export interface LocalSecretVaultDeps {
25
+ readonly key: Buffer;
26
+ readonly storePath: string;
27
+ }
28
+ export type KeychainCommandRunner = (args: readonly string[]) => string;
29
+ export declare function createKeychainVaultKeyAccess(keychainService: string, runCommand?: KeychainCommandRunner): LocalVaultKeychainAccess;
30
+ export declare function resolveLocalVaultKey(options: ResolveLocalVaultKeyOptions): ResolvedLocalVaultKey;
31
+ export declare function readLocalVaultReferences(storePath: string): readonly string[];
32
+ export declare function createLocalSecretVault(deps: LocalSecretVaultDeps): LocalSecretVault;
33
+ //# sourceMappingURL=secret-vault.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secret-vault.d.ts","sourceRoot":"","sources":["../src/secret-vault.ts"],"names":[],"mappings":"AA2CA,MAAM,MAAM,mBAAmB,GAAG,KAAK,GAAG,UAAU,GAAG,SAAS,CAAC;AAEjE,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,mBAAmB,CAAC;CACtC;AAKD,MAAM,MAAM,wBAAwB,GAAG,MAAM,MAAM,GAAG,SAAS,CAAC;AAEhE,eAAO,MAAM,uBAAuB,EAAE,wBAA0C,CAAC;AAEjF,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;IAC3D,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAE1B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAE5B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IAEjC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAE7B,QAAQ,CAAC,cAAc,CAAC,EAAE,wBAAwB,GAAG,SAAS,CAAC;CAChE;AAED,MAAM,WAAW,gBAAgB;IAG/B,QAAQ,CAAC,GAAG,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IAExD,QAAQ,CAAC,GAAG,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAI1D,QAAQ,CAAC,UAAU,EAAE,CAAC,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,IAAI,CAAC;IAEpE,QAAQ,CAAC,MAAM,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7C,QAAQ,CAAC,GAAG,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC;IAE7C,QAAQ,CAAC,IAAI,EAAE,MAAM,SAAS,MAAM,EAAE,CAAC;CACxC;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAyCD,MAAM,MAAM,qBAAqB,GAAG,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,KAAK,MAAM,CAAC;AAQxE,wBAAgB,4BAA4B,CAC1C,eAAe,EAAE,MAAM,EACvB,UAAU,GAAE,qBAAoD,GAC/D,wBAAwB,CAkB1B;AAwCD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,2BAA2B,GAAG,qBAAqB,CAQhG;AAwDD,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAE7E;AAsCD,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,oBAAoB,GAAG,gBAAgB,CAmDnF"}