narai-primitives 2.0.0 → 2.1.1
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/config/index.d.ts +1 -0
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +1 -0
- package/dist/config/index.js.map +1 -1
- package/dist/config/policy_validation.d.ts +68 -0
- package/dist/config/policy_validation.d.ts.map +1 -0
- package/dist/config/policy_validation.js +58 -0
- package/dist/config/policy_validation.js.map +1 -0
- package/dist/config/types.d.ts +37 -19
- package/dist/config/types.d.ts.map +1 -1
- package/dist/connectors/aws/lib/aws_client.js +1 -1
- package/dist/connectors/aws/lib/aws_client.js.map +1 -1
- package/dist/connectors/confluence/index.js +1 -1
- package/dist/connectors/confluence/index.js.map +1 -1
- package/dist/connectors/confluence/lib/confluence_client.js +1 -1
- package/dist/connectors/confluence/lib/confluence_client.js.map +1 -1
- package/dist/connectors/db/connector.d.ts.map +1 -1
- package/dist/connectors/db/connector.js +4 -0
- package/dist/connectors/db/connector.js.map +1 -1
- package/dist/connectors/db/index.d.ts +1 -1
- package/dist/connectors/db/index.d.ts.map +1 -1
- package/dist/connectors/db/index.js +1 -1
- package/dist/connectors/db/index.js.map +1 -1
- package/dist/connectors/db/lib/connection.js +1 -1
- package/dist/connectors/db/lib/connection.js.map +1 -1
- package/dist/connectors/db/lib/credentials.d.ts +1 -1
- package/dist/connectors/db/lib/credentials.js +4 -4
- package/dist/connectors/db/lib/credentials.js.map +1 -1
- package/dist/connectors/db/lib/plugin_config.d.ts +28 -1
- package/dist/connectors/db/lib/plugin_config.d.ts.map +1 -1
- package/dist/connectors/db/lib/plugin_config.js +7 -1
- package/dist/connectors/db/lib/plugin_config.js.map +1 -1
- package/dist/connectors/db/lib/policy.d.ts +10 -2
- package/dist/connectors/db/lib/policy.d.ts.map +1 -1
- package/dist/connectors/db/lib/policy.js.map +1 -1
- package/dist/connectors/github/index.js +1 -1
- package/dist/connectors/github/index.js.map +1 -1
- package/dist/connectors/github/lib/github_client.js +1 -1
- package/dist/connectors/github/lib/github_client.js.map +1 -1
- package/dist/connectors/jira/index.js +1 -1
- package/dist/connectors/jira/index.js.map +1 -1
- package/dist/connectors/jira/lib/jira_client.js +1 -1
- package/dist/connectors/jira/lib/jira_client.js.map +1 -1
- package/dist/connectors/notion/index.js +1 -1
- package/dist/connectors/notion/index.js.map +1 -1
- package/dist/connectors/notion/lib/notion_client.js +1 -1
- package/dist/connectors/notion/lib/notion_client.js.map +1 -1
- package/dist/credentials/cloud_secrets.d.ts +57 -0
- package/dist/credentials/cloud_secrets.d.ts.map +1 -0
- package/dist/credentials/cloud_secrets.js +202 -0
- package/dist/credentials/cloud_secrets.js.map +1 -0
- package/dist/credentials/env_var.d.ts +24 -0
- package/dist/credentials/env_var.d.ts.map +1 -0
- package/dist/credentials/env_var.js +30 -0
- package/dist/credentials/env_var.js.map +1 -0
- package/dist/credentials/file.d.ts +73 -0
- package/dist/credentials/file.d.ts.map +1 -0
- package/dist/credentials/file.js +159 -0
- package/dist/credentials/file.js.map +1 -0
- package/dist/credentials/index.d.ts +114 -0
- package/dist/credentials/index.d.ts.map +1 -0
- package/dist/credentials/index.js +174 -0
- package/dist/credentials/index.js.map +1 -0
- package/dist/credentials/keychain.d.ts +31 -0
- package/dist/credentials/keychain.d.ts.map +1 -0
- package/dist/credentials/keychain.js +124 -0
- package/dist/credentials/keychain.js.map +1 -0
- package/dist/credentials/parse_ref.d.ts +57 -0
- package/dist/credentials/parse_ref.d.ts.map +1 -0
- package/dist/credentials/parse_ref.js +128 -0
- package/dist/credentials/parse_ref.js.map +1 -0
- package/dist/credentials/redact.d.ts +30 -0
- package/dist/credentials/redact.d.ts.map +1 -0
- package/dist/credentials/redact.js +51 -0
- package/dist/credentials/redact.js.map +1 -0
- package/dist/toolkit/agent_resolver.d.ts +22 -6
- package/dist/toolkit/agent_resolver.d.ts.map +1 -1
- package/dist/toolkit/agent_resolver.js +53 -8
- package/dist/toolkit/agent_resolver.js.map +1 -1
- package/dist/toolkit/connector.d.ts +11 -0
- package/dist/toolkit/connector.d.ts.map +1 -1
- package/dist/toolkit/connector.js.map +1 -1
- package/dist/toolkit/index.d.ts +1 -1
- package/dist/toolkit/index.js +1 -1
- package/dist/toolkit/policy/config.d.ts.map +1 -1
- package/dist/toolkit/policy/config.js +1 -2
- package/dist/toolkit/policy/config.js.map +1 -1
- package/dist/toolkit/policy/gate.d.ts +7 -5
- package/dist/toolkit/policy/gate.d.ts.map +1 -1
- package/dist/toolkit/policy/gate.js +2 -14
- package/dist/toolkit/policy/gate.js.map +1 -1
- package/dist/toolkit/policy/types.d.ts +30 -8
- package/dist/toolkit/policy/types.d.ts.map +1 -1
- package/dist/toolkit/policy/types.js +8 -2
- package/dist/toolkit/policy/types.js.map +1 -1
- package/package.json +21 -3
- package/plugins/aws-agent/.claude-plugin/plugin.json +2 -2
- package/plugins/aws-agent/README.md +2 -2
- package/plugins/aws-agent/bin/aws-agent +2 -2
- package/plugins/aws-agent/hooks/hooks.json +5 -5
- package/plugins/aws-agent/hooks/reminder.mjs +1 -1
- package/plugins/aws-agent/package.json +1 -1
- package/plugins/aws-agent/skills/aws-agent/SKILL.md +1 -1
- package/plugins/confluence-agent/.claude-plugin/plugin.json +2 -2
- package/plugins/confluence-agent/README.md +1 -1
- package/plugins/confluence-agent/bin/confluence-agent +1 -1
- package/plugins/confluence-agent/hooks/hooks.json +5 -5
- package/plugins/confluence-agent/hooks/reminder.mjs +1 -1
- package/plugins/confluence-agent/package.json +1 -1
- package/plugins/confluence-agent/skills/confluence-agent/SKILL.md +1 -1
- package/plugins/db-agent/.claude-plugin/plugin.json +4 -4
- package/plugins/db-agent/README.md +2 -2
- package/plugins/db-agent/bin/db-agent +1 -1
- package/plugins/db-agent/hooks/hooks.json +6 -6
- package/plugins/db-agent/hooks/reminder.mjs +1 -1
- package/plugins/db-agent/package.json +1 -1
- package/plugins/db-agent/skills/db-agent/SKILL.md +1 -1
- package/plugins/gcp-agent/.claude-plugin/plugin.json +2 -2
- package/plugins/gcp-agent/README.md +2 -2
- package/plugins/gcp-agent/bin/gcp-agent +2 -2
- package/plugins/gcp-agent/hooks/hooks.json +5 -5
- package/plugins/gcp-agent/hooks/reminder.mjs +1 -1
- package/plugins/gcp-agent/package.json +1 -1
- package/plugins/gcp-agent/skills/gcp-agent/SKILL.md +1 -1
- package/plugins/github-agent/.claude-plugin/plugin.json +2 -2
- package/plugins/github-agent/README.md +1 -1
- package/plugins/github-agent/bin/github-agent +1 -1
- package/plugins/github-agent/hooks/hooks.json +5 -5
- package/plugins/github-agent/hooks/reminder.mjs +1 -1
- package/plugins/github-agent/package.json +1 -1
- package/plugins/github-agent/skills/github-agent/SKILL.md +1 -1
- package/plugins/jira-agent/.claude-plugin/plugin.json +2 -2
- package/plugins/jira-agent/README.md +1 -1
- package/plugins/jira-agent/bin/jira-agent +1 -1
- package/plugins/jira-agent/hooks/hooks.json +5 -5
- package/plugins/jira-agent/hooks/reminder.mjs +1 -1
- package/plugins/jira-agent/package.json +1 -1
- package/plugins/jira-agent/skills/jira-agent/SKILL.md +1 -1
- package/plugins/notion-agent/.claude-plugin/plugin.json +2 -2
- package/plugins/notion-agent/README.md +2 -2
- package/plugins/notion-agent/bin/notion-agent +1 -1
- package/plugins/notion-agent/hooks/hooks.json +5 -5
- package/plugins/notion-agent/hooks/reminder.mjs +1 -1
- package/plugins/notion-agent/package.json +1 -1
- package/plugins/notion-agent/skills/notion-agent/SKILL.md +1 -1
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* file.ts — Plaintext secrets file credential provider.
|
|
3
|
+
*
|
|
4
|
+
* Reads a JSON file shaped like `{ "<secret-name>": "<value>", ... }`.
|
|
5
|
+
* Emits a single `console.warn` on first use to flag that secrets are
|
|
6
|
+
* stored in cleartext. Callers that need at-rest encryption should switch
|
|
7
|
+
* to the `cloud_secrets` or `keychain` provider.
|
|
8
|
+
*
|
|
9
|
+
* Future enhancement: support age/sops-encrypted files. For now the
|
|
10
|
+
* warning makes the trade-off explicit.
|
|
11
|
+
*/
|
|
12
|
+
import * as fs from "node:fs";
|
|
13
|
+
export class FileProvider {
|
|
14
|
+
_path;
|
|
15
|
+
_suppressWarning;
|
|
16
|
+
_allowLoosePermissions;
|
|
17
|
+
_cacheTtlMs;
|
|
18
|
+
_warned = false;
|
|
19
|
+
_cache = null;
|
|
20
|
+
_cacheExpiresAt = null;
|
|
21
|
+
constructor(opts) {
|
|
22
|
+
this._path = opts.path;
|
|
23
|
+
this._suppressWarning = opts.suppressWarning ?? false;
|
|
24
|
+
this._allowLoosePermissions = opts.allowLoosePermissions ?? false;
|
|
25
|
+
this._cacheTtlMs = opts.cacheTtlMs ?? Infinity;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Discard the cached JSON so the next `getSecret` re-reads from disk.
|
|
29
|
+
* Useful when callers want to invalidate the cache on demand — e.g. after
|
|
30
|
+
* rotating the file — independent of the configured TTL.
|
|
31
|
+
*/
|
|
32
|
+
clearCache() {
|
|
33
|
+
this._cache = null;
|
|
34
|
+
this._cacheExpiresAt = null;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Return the value for `name`. Two lookup strategies, in order:
|
|
38
|
+
* 1. Literal top-level key — preserves the original flat
|
|
39
|
+
* `{ "<name>": "<value>" }` contract and lets users have
|
|
40
|
+
* key names that contain dots.
|
|
41
|
+
* 2. Dot-path traversal — if the literal key doesn't resolve to a
|
|
42
|
+
* string, treat `name` as a path (e.g. `db-prod.username`) and
|
|
43
|
+
* walk the nested JSON. Returns null if any segment is missing
|
|
44
|
+
* or the leaf is not a string. Lets nested credential layouts
|
|
45
|
+
* reuse the same file/mode/warning machinery.
|
|
46
|
+
*/
|
|
47
|
+
async getSecret(name) {
|
|
48
|
+
return this.getSecretSync(name);
|
|
49
|
+
}
|
|
50
|
+
getSecretSync(name) {
|
|
51
|
+
this._warnOnce();
|
|
52
|
+
const data = this._load();
|
|
53
|
+
if (data === null)
|
|
54
|
+
return null;
|
|
55
|
+
const literal = data[name];
|
|
56
|
+
if (typeof literal === "string")
|
|
57
|
+
return literal;
|
|
58
|
+
if (name.includes(".")) {
|
|
59
|
+
const parts = name.split(".");
|
|
60
|
+
let cur = data;
|
|
61
|
+
for (const part of parts) {
|
|
62
|
+
if (cur === null || typeof cur !== "object" || Array.isArray(cur)) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
cur = cur[part];
|
|
66
|
+
}
|
|
67
|
+
if (typeof cur === "string")
|
|
68
|
+
return cur;
|
|
69
|
+
}
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
async describeSecret(name) {
|
|
73
|
+
const value = this.getSecretSync(name);
|
|
74
|
+
let lastModified;
|
|
75
|
+
try {
|
|
76
|
+
lastModified = fs.statSync(this._path).mtime;
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
// file absent or unreadable — skip
|
|
80
|
+
}
|
|
81
|
+
const out = { exists: value !== null, provider: "file" };
|
|
82
|
+
if (lastModified !== undefined)
|
|
83
|
+
out.lastModified = lastModified;
|
|
84
|
+
return out;
|
|
85
|
+
}
|
|
86
|
+
_warnOnce() {
|
|
87
|
+
if (this._warned || this._suppressWarning)
|
|
88
|
+
return;
|
|
89
|
+
this._warned = true;
|
|
90
|
+
console.warn(`[credential_providers/file] reading secrets from plaintext file ${this._path}; ` +
|
|
91
|
+
"consider using the keychain or cloud_secrets provider instead.");
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Refuse to read the file if its mode is group- or world-accessible
|
|
95
|
+
* on POSIX systems (matches the OpenSSH posture for private keys).
|
|
96
|
+
* Skipped on Windows where stat().mode does not carry Unix permission
|
|
97
|
+
* bits in a portable way.
|
|
98
|
+
*/
|
|
99
|
+
_checkFileMode() {
|
|
100
|
+
if (process.platform === "win32")
|
|
101
|
+
return;
|
|
102
|
+
if (this._allowLoosePermissions)
|
|
103
|
+
return;
|
|
104
|
+
const st = fs.statSync(this._path);
|
|
105
|
+
const insecureBits = st.mode & 0o077;
|
|
106
|
+
if (insecureBits !== 0) {
|
|
107
|
+
const octal = (st.mode & 0o777).toString(8).padStart(3, "0");
|
|
108
|
+
throw new Error(`[credential_providers/file] refusing to read ${this._path}: ` +
|
|
109
|
+
`file mode ${octal} is group- or world-accessible. ` +
|
|
110
|
+
`Run 'chmod 600 ${this._path}' to restrict to the owner.`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Parse the credentials JSON. Stores the raw nested structure so
|
|
115
|
+
* dot-path traversal can find values inside subobjects (e.g. a
|
|
116
|
+
* `db-<env>: {username, password}` layout); literal-key lookups still
|
|
117
|
+
* filter to strings in `getSecret`.
|
|
118
|
+
*
|
|
119
|
+
* Cache lifecycle: by default held forever (fast path). When `cacheTtlMs`
|
|
120
|
+
* is finite, the mode check and file read re-run after the TTL elapses —
|
|
121
|
+
* that way rotated files with new bad permissions still get caught.
|
|
122
|
+
*/
|
|
123
|
+
_load() {
|
|
124
|
+
if (this._cache !== null) {
|
|
125
|
+
if (this._cacheTtlMs === Infinity)
|
|
126
|
+
return this._cache;
|
|
127
|
+
if (this._cacheExpiresAt !== null &&
|
|
128
|
+
Date.now() < this._cacheExpiresAt) {
|
|
129
|
+
return this._cache;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
if (!fs.existsSync(this._path))
|
|
133
|
+
return null;
|
|
134
|
+
this._checkFileMode();
|
|
135
|
+
const raw = fs.readFileSync(this._path, "utf-8");
|
|
136
|
+
let parsed;
|
|
137
|
+
try {
|
|
138
|
+
parsed = JSON.parse(raw);
|
|
139
|
+
}
|
|
140
|
+
catch (err) {
|
|
141
|
+
this._cache = null;
|
|
142
|
+
this._cacheExpiresAt = null;
|
|
143
|
+
throw err;
|
|
144
|
+
}
|
|
145
|
+
if (parsed === null ||
|
|
146
|
+
typeof parsed !== "object" ||
|
|
147
|
+
Array.isArray(parsed)) {
|
|
148
|
+
this._cache = null;
|
|
149
|
+
this._cacheExpiresAt = null;
|
|
150
|
+
throw new Error(`file provider: ${this._path} did not contain a JSON object`);
|
|
151
|
+
}
|
|
152
|
+
this._cache = parsed;
|
|
153
|
+
if (this._cacheTtlMs !== Infinity) {
|
|
154
|
+
this._cacheExpiresAt = Date.now() + this._cacheTtlMs;
|
|
155
|
+
}
|
|
156
|
+
return this._cache;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
//# sourceMappingURL=file.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file.js","sourceRoot":"","sources":["../../src/credentials/file.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/** Minimal interface every secret backend satisfies. */
|
|
2
|
+
export interface CredentialProvider {
|
|
3
|
+
/** Look up a secret by logical name. Returns `null` on miss. */
|
|
4
|
+
getSecret(name: string): Promise<string | null>;
|
|
5
|
+
/**
|
|
6
|
+
* Optional synchronous lookup, for callers that cannot await (module-level
|
|
7
|
+
* config resolution, legacy synchronous dispatchers). Providers backed by
|
|
8
|
+
* sync-capable stores (`process.env`, `fs.readFileSync`) implement this;
|
|
9
|
+
* keychain and cloud providers do not because their backing APIs are
|
|
10
|
+
* async-only. Callers that need broad backend coverage should prefer
|
|
11
|
+
* `getSecret`.
|
|
12
|
+
*/
|
|
13
|
+
getSecretSync?(name: string): string | null;
|
|
14
|
+
/**
|
|
15
|
+
* Optional metadata lookup. Default built-in providers fall back to
|
|
16
|
+
* calling getSecret and reporting `{exists, provider}` only. Cloud
|
|
17
|
+
* providers may override to surface real version / lastModified data.
|
|
18
|
+
*/
|
|
19
|
+
describeSecret?(name: string): Promise<SecretMetadata | null>;
|
|
20
|
+
}
|
|
21
|
+
export interface SecretMetadata {
|
|
22
|
+
/** True when the secret exists in this backend. */
|
|
23
|
+
exists: boolean;
|
|
24
|
+
/** Backend-reported version identifier, if available. */
|
|
25
|
+
version?: string;
|
|
26
|
+
/** When the secret was last modified, if the backend tracks it. */
|
|
27
|
+
lastModified?: Date;
|
|
28
|
+
/** Which registered provider name produced this record. */
|
|
29
|
+
provider: string;
|
|
30
|
+
}
|
|
31
|
+
export interface ResolveSecretOptions {
|
|
32
|
+
/** Primary provider name. If unset, uses the first registered provider. */
|
|
33
|
+
provider?: string;
|
|
34
|
+
/**
|
|
35
|
+
* Ordered fallback provider names. Tried in order after the primary
|
|
36
|
+
* returns `null` or throws.
|
|
37
|
+
*/
|
|
38
|
+
fallback?: string[];
|
|
39
|
+
}
|
|
40
|
+
export interface ResolveSecretsOptions {
|
|
41
|
+
/** When true, any null result (miss) causes the batch to reject. */
|
|
42
|
+
strict?: boolean;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* A named registry of {@link CredentialProvider} instances plus the
|
|
46
|
+
* `resolveSecret` chain. Instantiate your own resolver for test isolation,
|
|
47
|
+
* multi-tenant setups, or any case where the module-level {@link defaultResolver}
|
|
48
|
+
* is too coarse.
|
|
49
|
+
*/
|
|
50
|
+
export declare class CredentialResolver {
|
|
51
|
+
private readonly _registry;
|
|
52
|
+
/** Register a provider under a short name (`keychain`, `env_var`, …). */
|
|
53
|
+
register(name: string, provider: CredentialProvider): void;
|
|
54
|
+
/** Look up a provider previously registered via {@link register}. */
|
|
55
|
+
get(name: string): CredentialProvider | undefined;
|
|
56
|
+
/** Drop all registered providers. */
|
|
57
|
+
clear(): void;
|
|
58
|
+
/** Return the list of currently registered provider names. */
|
|
59
|
+
list(): string[];
|
|
60
|
+
/**
|
|
61
|
+
* Resolve a secret through a primary provider and optional fallback chain.
|
|
62
|
+
*
|
|
63
|
+
* Returns `null` if no provider produces a value while at least one
|
|
64
|
+
* provider runs to completion (hit or miss). If *every* provider throws,
|
|
65
|
+
* an `AggregateError` is raised whose `.errors` array preserves each
|
|
66
|
+
* original error in the order providers were tried.
|
|
67
|
+
*/
|
|
68
|
+
resolveSecret(name: string, options?: ResolveSecretOptions): Promise<string | null>;
|
|
69
|
+
/**
|
|
70
|
+
* Resolve multiple credential references in parallel.
|
|
71
|
+
*
|
|
72
|
+
* Each entry in `specs` maps an alias to a reference string (e.g.
|
|
73
|
+
* `{db: "env:PGPASSWORD", token: "keychain:gh"}`). Every reference is
|
|
74
|
+
* parsed up front with `strict: true` so typos in config surface at
|
|
75
|
+
* batch time rather than silently returning null.
|
|
76
|
+
*
|
|
77
|
+
* Per-alias errors are collected and re-thrown as an `AggregateError`
|
|
78
|
+
* — individual errors are wrapped to include their alias name so the
|
|
79
|
+
* `.errors` array is self-describing. With `strict: true`, any null
|
|
80
|
+
* result (miss) also causes the batch to reject.
|
|
81
|
+
*/
|
|
82
|
+
resolveSecrets(specs: Record<string, string>, options?: ResolveSecretsOptions): Promise<Record<string, string | null>>;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Built-in provider short names. Matches the reference-string aliases
|
|
86
|
+
* recognized by `parseCredentialRef` (`env` → `env_var`, `cloud` →
|
|
87
|
+
* `cloud_secrets`). Consumers can iterate or narrow against this literal;
|
|
88
|
+
* the tuple is frozen so runtime mutation is rejected in strict mode.
|
|
89
|
+
*/
|
|
90
|
+
export declare const KNOWN_PROVIDERS: readonly ["env", "keychain", "file", "cloud"];
|
|
91
|
+
export type KnownProvider = (typeof KNOWN_PROVIDERS)[number];
|
|
92
|
+
/** Shared resolver used by the module-level delegators below. */
|
|
93
|
+
export declare const defaultResolver: CredentialResolver;
|
|
94
|
+
/** Register a provider on the {@link defaultResolver}. */
|
|
95
|
+
export declare const registerProvider: (name: string, provider: CredentialProvider) => void;
|
|
96
|
+
/** Look up a provider on the {@link defaultResolver}. */
|
|
97
|
+
export declare const getProvider: (name: string) => CredentialProvider | undefined;
|
|
98
|
+
/** Drop all providers from the {@link defaultResolver} (test helper). */
|
|
99
|
+
export declare const clearProviders: () => void;
|
|
100
|
+
/** List provider names registered on the {@link defaultResolver}. */
|
|
101
|
+
export declare const listProviders: () => string[];
|
|
102
|
+
/** Resolve a secret via the {@link defaultResolver}. */
|
|
103
|
+
export declare const resolveSecret: (name: string, options?: ResolveSecretOptions) => Promise<string | null>;
|
|
104
|
+
/** Resolve a batch of credential references via the {@link defaultResolver}. */
|
|
105
|
+
export declare const resolveSecrets: (specs: Record<string, string>, options?: ResolveSecretsOptions) => Promise<Record<string, string | null>>;
|
|
106
|
+
export { FileProvider } from "./file.js";
|
|
107
|
+
export { EnvVarProvider } from "./env_var.js";
|
|
108
|
+
export { KeychainProvider } from "./keychain.js";
|
|
109
|
+
export { CloudSecretsProvider } from "./cloud_secrets.js";
|
|
110
|
+
export type { CloudSecretsConfig, CloudSubProvider } from "./cloud_secrets.js";
|
|
111
|
+
export { parseCredentialRef } from "./parse_ref.js";
|
|
112
|
+
export type { CredentialRef, ParseCredentialRefOptions, } from "./parse_ref.js";
|
|
113
|
+
export { redact, redactAll } from "./redact.js";
|
|
114
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/credentials/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* credential_providers — pluggable secret-backend layer.
|
|
3
|
+
*
|
|
4
|
+
* Each provider implements {@link CredentialProvider}. A {@link CredentialResolver}
|
|
5
|
+
* instance keeps a named registry of providers and exposes `resolveSecret`,
|
|
6
|
+
* which chains providers in the given fallback order and returns the first
|
|
7
|
+
* non-null hit.
|
|
8
|
+
*
|
|
9
|
+
* A module-level {@link defaultResolver} plus thin delegators
|
|
10
|
+
* (`registerProvider`, `resolveSecret`, …) are provided so callers that only
|
|
11
|
+
* need a single global registry can keep their imports flat.
|
|
12
|
+
*/
|
|
13
|
+
import { parseCredentialRef } from "./parse_ref.js";
|
|
14
|
+
/**
|
|
15
|
+
* A named registry of {@link CredentialProvider} instances plus the
|
|
16
|
+
* `resolveSecret` chain. Instantiate your own resolver for test isolation,
|
|
17
|
+
* multi-tenant setups, or any case where the module-level {@link defaultResolver}
|
|
18
|
+
* is too coarse.
|
|
19
|
+
*/
|
|
20
|
+
export class CredentialResolver {
|
|
21
|
+
_registry = new Map();
|
|
22
|
+
/** Register a provider under a short name (`keychain`, `env_var`, …). */
|
|
23
|
+
register(name, provider) {
|
|
24
|
+
this._registry.set(name, provider);
|
|
25
|
+
}
|
|
26
|
+
/** Look up a provider previously registered via {@link register}. */
|
|
27
|
+
get(name) {
|
|
28
|
+
return this._registry.get(name);
|
|
29
|
+
}
|
|
30
|
+
/** Drop all registered providers. */
|
|
31
|
+
clear() {
|
|
32
|
+
this._registry.clear();
|
|
33
|
+
}
|
|
34
|
+
/** Return the list of currently registered provider names. */
|
|
35
|
+
list() {
|
|
36
|
+
return [...this._registry.keys()];
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Resolve a secret through a primary provider and optional fallback chain.
|
|
40
|
+
*
|
|
41
|
+
* Returns `null` if no provider produces a value while at least one
|
|
42
|
+
* provider runs to completion (hit or miss). If *every* provider throws,
|
|
43
|
+
* an `AggregateError` is raised whose `.errors` array preserves each
|
|
44
|
+
* original error in the order providers were tried.
|
|
45
|
+
*/
|
|
46
|
+
async resolveSecret(name, options = {}) {
|
|
47
|
+
const order = [];
|
|
48
|
+
if (options.provider)
|
|
49
|
+
order.push(options.provider);
|
|
50
|
+
if (options.fallback)
|
|
51
|
+
order.push(...options.fallback);
|
|
52
|
+
if (order.length === 0) {
|
|
53
|
+
// Default: iterate whatever is in the registry, insertion order.
|
|
54
|
+
order.push(...this._registry.keys());
|
|
55
|
+
}
|
|
56
|
+
const errors = [];
|
|
57
|
+
let anySuccess = false;
|
|
58
|
+
for (const providerName of order) {
|
|
59
|
+
const provider = this._registry.get(providerName);
|
|
60
|
+
if (!provider)
|
|
61
|
+
continue;
|
|
62
|
+
try {
|
|
63
|
+
const value = await provider.getSecret(name);
|
|
64
|
+
anySuccess = true;
|
|
65
|
+
if (value !== null)
|
|
66
|
+
return value;
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
errors.push(err);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (!anySuccess && errors.length > 0) {
|
|
73
|
+
throw new AggregateError(errors, `resolveSecret('${name}') failed: all ${errors.length} provider(s) threw`);
|
|
74
|
+
}
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Resolve multiple credential references in parallel.
|
|
79
|
+
*
|
|
80
|
+
* Each entry in `specs` maps an alias to a reference string (e.g.
|
|
81
|
+
* `{db: "env:PGPASSWORD", token: "keychain:gh"}`). Every reference is
|
|
82
|
+
* parsed up front with `strict: true` so typos in config surface at
|
|
83
|
+
* batch time rather than silently returning null.
|
|
84
|
+
*
|
|
85
|
+
* Per-alias errors are collected and re-thrown as an `AggregateError`
|
|
86
|
+
* — individual errors are wrapped to include their alias name so the
|
|
87
|
+
* `.errors` array is self-describing. With `strict: true`, any null
|
|
88
|
+
* result (miss) also causes the batch to reject.
|
|
89
|
+
*/
|
|
90
|
+
async resolveSecrets(specs, options = {}) {
|
|
91
|
+
const aliases = Object.keys(specs);
|
|
92
|
+
const parsed = aliases.map((alias) => ({
|
|
93
|
+
alias,
|
|
94
|
+
ref: parseCredentialRef(specs[alias], {
|
|
95
|
+
strict: true,
|
|
96
|
+
resolver: this,
|
|
97
|
+
}),
|
|
98
|
+
}));
|
|
99
|
+
const settled = await Promise.allSettled(parsed.map(({ ref }) => {
|
|
100
|
+
if (ref === null)
|
|
101
|
+
return Promise.resolve(null);
|
|
102
|
+
return this.resolveSecret(ref.key, { provider: ref.provider });
|
|
103
|
+
}));
|
|
104
|
+
const errors = [];
|
|
105
|
+
const failedAliases = [];
|
|
106
|
+
const out = {};
|
|
107
|
+
for (let i = 0; i < aliases.length; i++) {
|
|
108
|
+
const alias = aliases[i];
|
|
109
|
+
const result = settled[i];
|
|
110
|
+
if (result === undefined)
|
|
111
|
+
continue;
|
|
112
|
+
if (result.status === "rejected") {
|
|
113
|
+
const original = result.reason;
|
|
114
|
+
const origMsg = original instanceof Error
|
|
115
|
+
? original.message
|
|
116
|
+
: String(original);
|
|
117
|
+
const wrapped = new Error(`resolveSecrets: alias "${alias}" failed: ${origMsg}`);
|
|
118
|
+
errors.push(wrapped);
|
|
119
|
+
failedAliases.push(alias);
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
out[alias] = result.value;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
if (errors.length > 0) {
|
|
126
|
+
throw new AggregateError(errors, `resolveSecrets failed for: ${failedAliases.join(", ")}`);
|
|
127
|
+
}
|
|
128
|
+
if (options.strict) {
|
|
129
|
+
const missingAliases = aliases.filter((a) => out[a] === null);
|
|
130
|
+
if (missingAliases.length > 0) {
|
|
131
|
+
throw new Error(`resolveSecrets strict: aliases returned null: ${missingAliases.join(", ")}`);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return out;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Built-in provider short names. Matches the reference-string aliases
|
|
139
|
+
* recognized by `parseCredentialRef` (`env` → `env_var`, `cloud` →
|
|
140
|
+
* `cloud_secrets`). Consumers can iterate or narrow against this literal;
|
|
141
|
+
* the tuple is frozen so runtime mutation is rejected in strict mode.
|
|
142
|
+
*/
|
|
143
|
+
export const KNOWN_PROVIDERS = Object.freeze([
|
|
144
|
+
"env",
|
|
145
|
+
"keychain",
|
|
146
|
+
"file",
|
|
147
|
+
"cloud",
|
|
148
|
+
]);
|
|
149
|
+
/** Shared resolver used by the module-level delegators below. */
|
|
150
|
+
export const defaultResolver = new CredentialResolver();
|
|
151
|
+
/** Register a provider on the {@link defaultResolver}. */
|
|
152
|
+
export const registerProvider = defaultResolver.register.bind(defaultResolver);
|
|
153
|
+
/** Look up a provider on the {@link defaultResolver}. */
|
|
154
|
+
export const getProvider = defaultResolver.get.bind(defaultResolver);
|
|
155
|
+
/** Drop all providers from the {@link defaultResolver} (test helper). */
|
|
156
|
+
export const clearProviders = defaultResolver.clear.bind(defaultResolver);
|
|
157
|
+
/** List provider names registered on the {@link defaultResolver}. */
|
|
158
|
+
export const listProviders = defaultResolver.list.bind(defaultResolver);
|
|
159
|
+
/** Resolve a secret via the {@link defaultResolver}. */
|
|
160
|
+
export const resolveSecret = defaultResolver.resolveSecret.bind(defaultResolver);
|
|
161
|
+
/** Resolve a batch of credential references via the {@link defaultResolver}. */
|
|
162
|
+
export const resolveSecrets = defaultResolver.resolveSecrets.bind(defaultResolver);
|
|
163
|
+
// Re-export provider implementations so callers can import everything from
|
|
164
|
+
// `narai-primitives/credentials` directly.
|
|
165
|
+
export { FileProvider } from "./file.js";
|
|
166
|
+
export { EnvVarProvider } from "./env_var.js";
|
|
167
|
+
export { KeychainProvider } from "./keychain.js";
|
|
168
|
+
export { CloudSecretsProvider } from "./cloud_secrets.js";
|
|
169
|
+
// Reference-string grammar. Config consumers call `parseCredentialRef` on
|
|
170
|
+
// each string value to decide whether it's a literal or a reference into
|
|
171
|
+
// one of the registered providers. See `parse_ref.ts` for the grammar.
|
|
172
|
+
export { parseCredentialRef } from "./parse_ref.js";
|
|
173
|
+
export { redact, redactAll } from "./redact.js";
|
|
174
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/credentials/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { CredentialProvider, SecretMetadata } from "./index.js";
|
|
2
|
+
export interface KeychainProviderOptions {
|
|
3
|
+
/**
|
|
4
|
+
* Override the platform detection (for tests). Accepts any Node
|
|
5
|
+
* `process.platform` value.
|
|
6
|
+
*/
|
|
7
|
+
platform?: NodeJS.Platform;
|
|
8
|
+
/**
|
|
9
|
+
* macOS Keychain "account" field (optional). If given, passed as
|
|
10
|
+
* `-a <account>` to `security find-generic-password`.
|
|
11
|
+
*/
|
|
12
|
+
account?: string;
|
|
13
|
+
/**
|
|
14
|
+
* macOS Keychain "service" prefix. If set, the lookup name is
|
|
15
|
+
* `<servicePrefix>.<name>` so an application's secrets can be grouped
|
|
16
|
+
* under a single service name (e.g. `com.example.myapp`).
|
|
17
|
+
*/
|
|
18
|
+
servicePrefix?: string;
|
|
19
|
+
}
|
|
20
|
+
export declare class KeychainProvider implements CredentialProvider {
|
|
21
|
+
private readonly _platform;
|
|
22
|
+
private readonly _account;
|
|
23
|
+
private readonly _servicePrefix;
|
|
24
|
+
constructor(opts?: KeychainProviderOptions);
|
|
25
|
+
getSecret(name: string): Promise<string | null>;
|
|
26
|
+
describeSecret(name: string): Promise<SecretMetadata>;
|
|
27
|
+
private _macos;
|
|
28
|
+
private _linux;
|
|
29
|
+
private _windows;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=keychain.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keychain.d.ts","sourceRoot":"","sources":["../../src/credentials/keychain.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAErE,MAAM,WAAW,uBAAuB;IACtC;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC;IAC3B;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,qBAAa,gBAAiB,YAAW,kBAAkB;IACzD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAkB;IAC5C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqB;IAC9C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;gBAE5B,IAAI,GAAE,uBAA4B;IAMxC,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAmB/C,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAK3D,OAAO,CAAC,MAAM;IAoBd,OAAO,CAAC,MAAM;YAoBA,QAAQ;CAqBvB"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* keychain.ts — OS-native keychain provider.
|
|
3
|
+
*
|
|
4
|
+
* Backends (selected by platform):
|
|
5
|
+
* - darwin → `security find-generic-password -s "<name>" -w`
|
|
6
|
+
* - linux → `secret-tool lookup name "<name>"` (libsecret).
|
|
7
|
+
* If `secret-tool` is missing, throws a clear error.
|
|
8
|
+
* - win32 → `@napi-rs/keyring` (Windows Credential Manager via N-API).
|
|
9
|
+
* Lazy-imported; if the module is not installed, throws a
|
|
10
|
+
* clear error with the install command.
|
|
11
|
+
*/
|
|
12
|
+
import { execFileSync } from "node:child_process";
|
|
13
|
+
export class KeychainProvider {
|
|
14
|
+
_platform;
|
|
15
|
+
_account;
|
|
16
|
+
_servicePrefix;
|
|
17
|
+
constructor(opts = {}) {
|
|
18
|
+
this._platform = opts.platform ?? process.platform;
|
|
19
|
+
this._account = opts.account;
|
|
20
|
+
this._servicePrefix = opts.servicePrefix ?? "";
|
|
21
|
+
}
|
|
22
|
+
async getSecret(name) {
|
|
23
|
+
const service = this._servicePrefix
|
|
24
|
+
? `${this._servicePrefix}.${name}`
|
|
25
|
+
: name;
|
|
26
|
+
switch (this._platform) {
|
|
27
|
+
case "darwin":
|
|
28
|
+
return this._macos(service);
|
|
29
|
+
case "linux":
|
|
30
|
+
return this._linux(service);
|
|
31
|
+
case "win32":
|
|
32
|
+
return this._windows(service);
|
|
33
|
+
default:
|
|
34
|
+
throw new Error(`keychain provider unsupported on platform '${this._platform}'`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
async describeSecret(name) {
|
|
38
|
+
const value = await this.getSecret(name);
|
|
39
|
+
return { exists: value !== null, provider: "keychain" };
|
|
40
|
+
}
|
|
41
|
+
_macos(service) {
|
|
42
|
+
const args = ["find-generic-password", "-s", service, "-w"];
|
|
43
|
+
if (this._account) {
|
|
44
|
+
args.splice(1, 0, "-a", this._account);
|
|
45
|
+
}
|
|
46
|
+
try {
|
|
47
|
+
const out = execFileSync("security", args, {
|
|
48
|
+
encoding: "utf-8",
|
|
49
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
50
|
+
});
|
|
51
|
+
const trimmed = out.replace(/\n$/, "");
|
|
52
|
+
return trimmed === "" ? null : trimmed;
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
// `security` exits non-zero if the item is not found. Surface a
|
|
56
|
+
// null-miss rather than an error so the fallback chain can proceed.
|
|
57
|
+
if (_isMissingKeychainItem(err))
|
|
58
|
+
return null;
|
|
59
|
+
throw _wrapKeychainError(err, "security");
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
_linux(service) {
|
|
63
|
+
try {
|
|
64
|
+
const out = execFileSync("secret-tool", ["lookup", "name", service], {
|
|
65
|
+
encoding: "utf-8",
|
|
66
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
67
|
+
});
|
|
68
|
+
const trimmed = out.replace(/\n$/, "");
|
|
69
|
+
return trimmed === "" ? null : trimmed;
|
|
70
|
+
}
|
|
71
|
+
catch (err) {
|
|
72
|
+
if (_isCommandNotFound(err)) {
|
|
73
|
+
throw new Error("keychain provider on Linux requires `secret-tool` (libsecret). " +
|
|
74
|
+
"Install with `apt install libsecret-tools` or equivalent.");
|
|
75
|
+
}
|
|
76
|
+
if (_isMissingKeychainItem(err))
|
|
77
|
+
return null;
|
|
78
|
+
throw _wrapKeychainError(err, "secret-tool");
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
async _windows(service) {
|
|
82
|
+
const mod = await _loadOptional("@napi-rs/keyring", "npm install --save-dev @napi-rs/keyring");
|
|
83
|
+
const { Entry } = mod;
|
|
84
|
+
const entry = new Entry(service, this._account ?? "default");
|
|
85
|
+
try {
|
|
86
|
+
const pw = entry.getPassword();
|
|
87
|
+
return pw === "" || pw === null ? null : pw;
|
|
88
|
+
}
|
|
89
|
+
catch (err) {
|
|
90
|
+
const msg = err.message ?? "";
|
|
91
|
+
if (/not (found|exist)|no.*entry/i.test(msg))
|
|
92
|
+
return null;
|
|
93
|
+
throw new Error(`keychain provider on Windows: ${msg}`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
function _isMissingKeychainItem(err) {
|
|
98
|
+
const e = err;
|
|
99
|
+
// macOS `security` returns 44 for "item not found"; libsecret's
|
|
100
|
+
// `secret-tool lookup` returns 1 with empty stdout when missing.
|
|
101
|
+
return e.status === 44 || e.status === 1;
|
|
102
|
+
}
|
|
103
|
+
function _isCommandNotFound(err) {
|
|
104
|
+
const e = err;
|
|
105
|
+
return e.code === "ENOENT";
|
|
106
|
+
}
|
|
107
|
+
function _wrapKeychainError(err, command) {
|
|
108
|
+
const e = err;
|
|
109
|
+
const stderr = e.stderr instanceof Buffer ? e.stderr.toString("utf-8") : e.stderr ?? "";
|
|
110
|
+
return new Error(`keychain provider: ${command} failed (status=${e.status}): ${stderr || e.message}`);
|
|
111
|
+
}
|
|
112
|
+
async function _loadOptional(pkg, install) {
|
|
113
|
+
try {
|
|
114
|
+
return (await import(pkg));
|
|
115
|
+
}
|
|
116
|
+
catch (err) {
|
|
117
|
+
const e = err;
|
|
118
|
+
if (e.code === "ERR_MODULE_NOT_FOUND" || e.code === "MODULE_NOT_FOUND") {
|
|
119
|
+
throw new Error(`keychain provider on Windows requires '${pkg}'. Run: ${install}`);
|
|
120
|
+
}
|
|
121
|
+
throw err;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=keychain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keychain.js","sourceRoot":"","sources":["../../src/credentials/keychain.ts"],"names":[],"mappings":"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"}
|