@centient/secrets 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.
- package/dist/cli/messages.d.ts +60 -0
- package/dist/cli/messages.d.ts.map +1 -0
- package/dist/cli/messages.js +63 -0
- package/dist/cli/messages.js.map +1 -0
- package/dist/cli/secrets-cli.d.ts +38 -0
- package/dist/cli/secrets-cli.d.ts.map +1 -0
- package/dist/cli/secrets-cli.js +532 -0
- package/dist/cli/secrets-cli.js.map +1 -0
- package/dist/crypto/vault-common.d.ts +63 -0
- package/dist/crypto/vault-common.d.ts.map +1 -0
- package/dist/crypto/vault-common.js +180 -0
- package/dist/crypto/vault-common.js.map +1 -0
- package/dist/environment/EnvironmentManager.d.ts +171 -0
- package/dist/environment/EnvironmentManager.d.ts.map +1 -0
- package/dist/environment/EnvironmentManager.js +604 -0
- package/dist/environment/EnvironmentManager.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/platform/agent-detect.d.ts +15 -0
- package/dist/platform/agent-detect.d.ts.map +1 -0
- package/dist/platform/agent-detect.js +22 -0
- package/dist/platform/agent-detect.js.map +1 -0
- package/dist/platform/platform.d.ts +51 -0
- package/dist/platform/platform.d.ts.map +1 -0
- package/dist/platform/platform.js +141 -0
- package/dist/platform/platform.js.map +1 -0
- package/dist/vault/types.d.ts +54 -0
- package/dist/vault/types.d.ts.map +1 -0
- package/dist/vault/types.js +12 -0
- package/dist/vault/types.js.map +1 -0
- package/dist/vault/vault-env.d.ts +58 -0
- package/dist/vault/vault-env.d.ts.map +1 -0
- package/dist/vault/vault-env.js +73 -0
- package/dist/vault/vault-env.js.map +1 -0
- package/dist/vault/vault-gpg.d.ts +40 -0
- package/dist/vault/vault-gpg.d.ts.map +1 -0
- package/dist/vault/vault-gpg.js +149 -0
- package/dist/vault/vault-gpg.js.map +1 -0
- package/dist/vault/vault-libsecret.d.ts +51 -0
- package/dist/vault/vault-libsecret.d.ts.map +1 -0
- package/dist/vault/vault-libsecret.js +115 -0
- package/dist/vault/vault-libsecret.js.map +1 -0
- package/dist/vault/vault-utils.d.ts +12 -0
- package/dist/vault/vault-utils.d.ts.map +1 -0
- package/dist/vault/vault-utils.js +16 -0
- package/dist/vault/vault-utils.js.map +1 -0
- package/dist/vault/vault-windows.d.ts +71 -0
- package/dist/vault/vault-windows.d.ts.map +1 -0
- package/dist/vault/vault-windows.js +186 -0
- package/dist/vault/vault-windows.js.map +1 -0
- package/dist/vault/vault.d.ts +53 -0
- package/dist/vault/vault.d.ts.map +1 -0
- package/dist/vault/vault.js +132 -0
- package/dist/vault/vault.js.map +1 -0
- package/package.json +37 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Environment Detection
|
|
3
|
+
*
|
|
4
|
+
* Detects whether the process is running inside an AI agent session
|
|
5
|
+
* (Claude Code, MCP context, etc.). Auth commands that require human
|
|
6
|
+
* interaction are blocked in these environments.
|
|
7
|
+
*
|
|
8
|
+
* Shared by: vault.ts, cli, secrets-cli.ts
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Returns true if the current process appears to be running inside an
|
|
12
|
+
* AI agent environment (Claude Code, MCP subprocess, etc.).
|
|
13
|
+
*/
|
|
14
|
+
export declare function isAgentEnvironment(): boolean;
|
|
15
|
+
//# sourceMappingURL=agent-detect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-detect.d.ts","sourceRoot":"","sources":["../../src/platform/agent-detect.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,OAAO,CAS5C"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Environment Detection
|
|
3
|
+
*
|
|
4
|
+
* Detects whether the process is running inside an AI agent session
|
|
5
|
+
* (Claude Code, MCP context, etc.). Auth commands that require human
|
|
6
|
+
* interaction are blocked in these environments.
|
|
7
|
+
*
|
|
8
|
+
* Shared by: vault.ts, cli, secrets-cli.ts
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Returns true if the current process appears to be running inside an
|
|
12
|
+
* AI agent environment (Claude Code, MCP subprocess, etc.).
|
|
13
|
+
*/
|
|
14
|
+
export function isAgentEnvironment() {
|
|
15
|
+
return !!(process.env["CLAUDE_PROJECT_DIR"] ||
|
|
16
|
+
process.env["MCP_CONTEXT"] ||
|
|
17
|
+
process.env["CLAUDE_CODE_SESSION"] ||
|
|
18
|
+
process.env["CLAUDE_CODE_ENTRY_POINT"] ||
|
|
19
|
+
process.env["ANTHROPIC_API_KEY_SOURCE"] ||
|
|
20
|
+
process.env["MCP_SERVER_NAME"]);
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=agent-detect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-detect.js","sourceRoot":"","sources":["../../src/platform/agent-detect.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;;GAGG;AACH,MAAM,UAAU,kBAAkB;IAChC,OAAO,CAAC,CAAC,CACP,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC;QACjC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;QAC1B,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC;QAClC,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC;QACtC,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC;QACvC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAC/B,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth Platform — Capability Detection
|
|
3
|
+
*
|
|
4
|
+
* Detects terminal/platform capabilities for rendering decisions.
|
|
5
|
+
* All functions are pure (no side effects beyond reading process.env / process.stdout).
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Returns true if stdout is a TTY (interactive terminal).
|
|
9
|
+
* Spinner, colour, and unicode output should only be used when this is true.
|
|
10
|
+
*/
|
|
11
|
+
export declare function isTTY(): boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Returns true if the terminal likely supports Unicode characters.
|
|
14
|
+
* Detection is based on LANG or LC_ALL containing "UTF-8" (case-insensitive).
|
|
15
|
+
* Falls back to false when environment variables are absent.
|
|
16
|
+
*/
|
|
17
|
+
export declare function canUnicode(): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Returns true if running in a headless environment (no display server).
|
|
20
|
+
*
|
|
21
|
+
* On Linux: checks for absence of DISPLAY and WAYLAND_DISPLAY and
|
|
22
|
+
* XDG_CURRENT_DESKTOP env vars.
|
|
23
|
+
* On macOS: always returns false (macOS always has a window server available
|
|
24
|
+
* even in SSH sessions with X11 forwarding disabled).
|
|
25
|
+
* In CI environments: treats CI=true as headless.
|
|
26
|
+
*/
|
|
27
|
+
export declare function isHeadless(): boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Returns true if the system has a browser launcher available.
|
|
30
|
+
*
|
|
31
|
+
* macOS: checks for `open` (always present).
|
|
32
|
+
* Linux: checks for `xdg-open` via `which`.
|
|
33
|
+
* Other: returns false.
|
|
34
|
+
*/
|
|
35
|
+
export declare function canLaunchBrowser(): boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Returns true if the process is running in a known CI environment.
|
|
38
|
+
* Checks standard CI environment variables used by common CI platforms.
|
|
39
|
+
*/
|
|
40
|
+
export declare function isCIEnvironment(): boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Returns true if the process is running inside a Docker or containerd container.
|
|
43
|
+
* Checks /proc/1/cgroup for container markers and /.dockerenv existence.
|
|
44
|
+
*/
|
|
45
|
+
export declare function isDockerContainer(): boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Returns true if the process is running inside an SSH session.
|
|
48
|
+
* Checks SSH_CONNECTION and SSH_CLIENT environment variables.
|
|
49
|
+
*/
|
|
50
|
+
export declare function isSSHSession(): boolean;
|
|
51
|
+
//# sourceMappingURL=platform.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform.d.ts","sourceRoot":"","sources":["../../src/platform/platform.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AASH;;;GAGG;AACH,wBAAgB,KAAK,IAAI,OAAO,CAE/B;AAMD;;;;GAIG;AACH,wBAAgB,UAAU,IAAI,OAAO,CASpC;AAMD;;;;;;;;GAQG;AACH,wBAAgB,UAAU,IAAI,OAAO,CAiBpC;AAMD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CAkB1C;AAMD;;;GAGG;AACH,wBAAgB,eAAe,IAAI,OAAO,CASzC;AAMD;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,CAe3C;AAMD;;;GAGG;AACH,wBAAgB,YAAY,IAAI,OAAO,CAEtC"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth Platform — Capability Detection
|
|
3
|
+
*
|
|
4
|
+
* Detects terminal/platform capabilities for rendering decisions.
|
|
5
|
+
* All functions are pure (no side effects beyond reading process.env / process.stdout).
|
|
6
|
+
*/
|
|
7
|
+
import { existsSync, readFileSync } from "fs";
|
|
8
|
+
import { execSync } from "child_process";
|
|
9
|
+
// =============================================================================
|
|
10
|
+
// TTY detection
|
|
11
|
+
// =============================================================================
|
|
12
|
+
/**
|
|
13
|
+
* Returns true if stdout is a TTY (interactive terminal).
|
|
14
|
+
* Spinner, colour, and unicode output should only be used when this is true.
|
|
15
|
+
*/
|
|
16
|
+
export function isTTY() {
|
|
17
|
+
return process.stdout.isTTY === true;
|
|
18
|
+
}
|
|
19
|
+
// =============================================================================
|
|
20
|
+
// Unicode detection
|
|
21
|
+
// =============================================================================
|
|
22
|
+
/**
|
|
23
|
+
* Returns true if the terminal likely supports Unicode characters.
|
|
24
|
+
* Detection is based on LANG or LC_ALL containing "UTF-8" (case-insensitive).
|
|
25
|
+
* Falls back to false when environment variables are absent.
|
|
26
|
+
*/
|
|
27
|
+
export function canUnicode() {
|
|
28
|
+
const lang = process.env["LANG"] ?? "";
|
|
29
|
+
const lcAll = process.env["LC_ALL"] ?? "";
|
|
30
|
+
const lcCtype = process.env["LC_CTYPE"] ?? "";
|
|
31
|
+
return (/utf-?8/i.test(lang) ||
|
|
32
|
+
/utf-?8/i.test(lcAll) ||
|
|
33
|
+
/utf-?8/i.test(lcCtype));
|
|
34
|
+
}
|
|
35
|
+
// =============================================================================
|
|
36
|
+
// Headless detection
|
|
37
|
+
// =============================================================================
|
|
38
|
+
/**
|
|
39
|
+
* Returns true if running in a headless environment (no display server).
|
|
40
|
+
*
|
|
41
|
+
* On Linux: checks for absence of DISPLAY and WAYLAND_DISPLAY and
|
|
42
|
+
* XDG_CURRENT_DESKTOP env vars.
|
|
43
|
+
* On macOS: always returns false (macOS always has a window server available
|
|
44
|
+
* even in SSH sessions with X11 forwarding disabled).
|
|
45
|
+
* In CI environments: treats CI=true as headless.
|
|
46
|
+
*/
|
|
47
|
+
export function isHeadless() {
|
|
48
|
+
// Explicit CI flag
|
|
49
|
+
if (process.env["CI"] === "true" || process.env["CI"] === "1")
|
|
50
|
+
return true;
|
|
51
|
+
// macOS has a window server; treat as non-headless unless CI
|
|
52
|
+
if (process.platform === "darwin")
|
|
53
|
+
return false;
|
|
54
|
+
// Linux: headless if no display server variables are set
|
|
55
|
+
if (process.platform === "linux") {
|
|
56
|
+
const hasDisplay = Boolean(process.env["DISPLAY"]);
|
|
57
|
+
const hasWayland = Boolean(process.env["WAYLAND_DISPLAY"]);
|
|
58
|
+
const hasDesktop = Boolean(process.env["XDG_CURRENT_DESKTOP"]);
|
|
59
|
+
return !hasDisplay && !hasWayland && !hasDesktop;
|
|
60
|
+
}
|
|
61
|
+
// Unknown platform — assume headless for safety
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
// =============================================================================
|
|
65
|
+
// Browser launch detection
|
|
66
|
+
// =============================================================================
|
|
67
|
+
/**
|
|
68
|
+
* Returns true if the system has a browser launcher available.
|
|
69
|
+
*
|
|
70
|
+
* macOS: checks for `open` (always present).
|
|
71
|
+
* Linux: checks for `xdg-open` via `which`.
|
|
72
|
+
* Other: returns false.
|
|
73
|
+
*/
|
|
74
|
+
export function canLaunchBrowser() {
|
|
75
|
+
if (isHeadless())
|
|
76
|
+
return false;
|
|
77
|
+
try {
|
|
78
|
+
if (process.platform === "darwin") {
|
|
79
|
+
execSync("which open", { stdio: "pipe" });
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
if (process.platform === "linux") {
|
|
83
|
+
execSync("which xdg-open", { stdio: "pipe" });
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
// `which` returned non-zero — tool not found
|
|
89
|
+
}
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
// =============================================================================
|
|
93
|
+
// CI environment detection
|
|
94
|
+
// =============================================================================
|
|
95
|
+
/**
|
|
96
|
+
* Returns true if the process is running in a known CI environment.
|
|
97
|
+
* Checks standard CI environment variables used by common CI platforms.
|
|
98
|
+
*/
|
|
99
|
+
export function isCIEnvironment() {
|
|
100
|
+
return !!(process.env["CI"] ||
|
|
101
|
+
process.env["GITHUB_ACTIONS"] ||
|
|
102
|
+
process.env["GITLAB_CI"] ||
|
|
103
|
+
process.env["CIRCLECI"] ||
|
|
104
|
+
process.env["TRAVIS"] ||
|
|
105
|
+
process.env["BUILDKITE"]);
|
|
106
|
+
}
|
|
107
|
+
// =============================================================================
|
|
108
|
+
// Docker/container detection
|
|
109
|
+
// =============================================================================
|
|
110
|
+
/**
|
|
111
|
+
* Returns true if the process is running inside a Docker or containerd container.
|
|
112
|
+
* Checks /proc/1/cgroup for container markers and /.dockerenv existence.
|
|
113
|
+
*/
|
|
114
|
+
export function isDockerContainer() {
|
|
115
|
+
// Check for /.dockerenv (Docker-specific file)
|
|
116
|
+
if (existsSync("/.dockerenv"))
|
|
117
|
+
return true;
|
|
118
|
+
// Check /proc/1/cgroup for docker or containerd markers (Linux only)
|
|
119
|
+
if (process.platform === "linux") {
|
|
120
|
+
try {
|
|
121
|
+
const cgroup = readFileSync("/proc/1/cgroup", "utf8");
|
|
122
|
+
if (/docker|containerd/.test(cgroup))
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
// /proc/1/cgroup not readable — not a concern on non-Linux
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
// =============================================================================
|
|
132
|
+
// SSH session detection
|
|
133
|
+
// =============================================================================
|
|
134
|
+
/**
|
|
135
|
+
* Returns true if the process is running inside an SSH session.
|
|
136
|
+
* Checks SSH_CONNECTION and SSH_CLIENT environment variables.
|
|
137
|
+
*/
|
|
138
|
+
export function isSSHSession() {
|
|
139
|
+
return !!(process.env["SSH_CONNECTION"] || process.env["SSH_CLIENT"]);
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=platform.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform.js","sourceRoot":"","sources":["../../src/platform/platform.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth Module — Shared Type Definitions
|
|
3
|
+
*/
|
|
4
|
+
export interface TokenValidationResult {
|
|
5
|
+
valid: boolean;
|
|
6
|
+
status: "valid" | "expiring_soon" | "expired";
|
|
7
|
+
expiresAt: Date | null;
|
|
8
|
+
remainingMs: number;
|
|
9
|
+
formattedRemaining: string;
|
|
10
|
+
}
|
|
11
|
+
export interface DeviceFlowConfig {
|
|
12
|
+
/** Base URL for the auth API (e.g. https://api.engram.ai) */
|
|
13
|
+
baseUrl: string;
|
|
14
|
+
/** OAuth client ID */
|
|
15
|
+
clientId?: string;
|
|
16
|
+
/** Poll timeout in seconds (default: 300) */
|
|
17
|
+
timeoutSeconds?: number;
|
|
18
|
+
}
|
|
19
|
+
export interface DeviceFlowResult {
|
|
20
|
+
accessToken: string;
|
|
21
|
+
refreshToken: string;
|
|
22
|
+
expiresAt: Date;
|
|
23
|
+
}
|
|
24
|
+
export type DeviceFlowErrorCode = "access_denied" | "expired_token" | "network_error" | "timeout" | "unknown";
|
|
25
|
+
export declare class DeviceFlowError extends Error {
|
|
26
|
+
readonly code: DeviceFlowErrorCode;
|
|
27
|
+
constructor(code: DeviceFlowErrorCode, message: string);
|
|
28
|
+
}
|
|
29
|
+
export interface SpinnerHandle {
|
|
30
|
+
/** Update the spinner message */
|
|
31
|
+
update(message: string): void;
|
|
32
|
+
/** Stop the spinner and optionally print a final line */
|
|
33
|
+
stop(finalMessage?: string): void;
|
|
34
|
+
}
|
|
35
|
+
export interface CountdownHandle {
|
|
36
|
+
/** Cancel the countdown early */
|
|
37
|
+
cancel(): void;
|
|
38
|
+
}
|
|
39
|
+
export type VaultType = "keychain" | "windows" | "libsecret" | "gpg" | "env" | "unknown";
|
|
40
|
+
export interface StoredCredentialMeta {
|
|
41
|
+
source: "device-flow" | "api-key" | "env";
|
|
42
|
+
storedAt: string;
|
|
43
|
+
refreshToken?: string;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Common interface implemented by all vault backends.
|
|
47
|
+
* Backends must implement store/retrieve/delete plus a static detect() method.
|
|
48
|
+
*/
|
|
49
|
+
export interface VaultBackend {
|
|
50
|
+
store(key: string, value: string): boolean;
|
|
51
|
+
retrieve(key: string): string | null;
|
|
52
|
+
delete(key: string): boolean;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/vault/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,OAAO,GAAG,eAAe,GAAG,SAAS,CAAC;IAC9C,SAAS,EAAE,IAAI,GAAG,IAAI,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAMD,MAAM,WAAW,gBAAgB;IAC/B,6DAA6D;IAC7D,OAAO,EAAE,MAAM,CAAC;IAChB,sBAAsB;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6CAA6C;IAC7C,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,IAAI,CAAC;CACjB;AAED,MAAM,MAAM,mBAAmB,GAC3B,eAAe,GACf,eAAe,GACf,eAAe,GACf,SAAS,GACT,SAAS,CAAC;AAEd,qBAAa,eAAgB,SAAQ,KAAK;aAEtB,IAAI,EAAE,mBAAmB;gBAAzB,IAAI,EAAE,mBAAmB,EACzC,OAAO,EAAE,MAAM;CAKlB;AAMD,MAAM,WAAW,aAAa;IAC5B,iCAAiC;IACjC,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,yDAAyD;IACzD,IAAI,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACnC;AAED,MAAM,WAAW,eAAe;IAC9B,iCAAiC;IACjC,MAAM,IAAI,IAAI,CAAC;CAChB;AAMD,MAAM,MAAM,SAAS,GAAG,UAAU,GAAG,SAAS,GAAG,WAAW,GAAG,KAAK,GAAG,KAAK,GAAG,SAAS,CAAC;AAEzF,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,aAAa,GAAG,SAAS,GAAG,KAAK,CAAC;IAC1C,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;IAC3C,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IACrC,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CAC9B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/vault/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAwCH,MAAM,OAAO,eAAgB,SAAQ,KAAK;IAEtB;IADlB,YACkB,IAAyB,EACzC,OAAe;QAEf,KAAK,CAAC,OAAO,CAAC,CAAC;QAHC,SAAI,GAAJ,IAAI,CAAqB;QAIzC,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;IAChC,CAAC;CACF"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth Vault — Environment Variable Fallback Backend
|
|
3
|
+
*
|
|
4
|
+
* Last-resort vault backend that reads credentials from environment variables.
|
|
5
|
+
* Reads/writes nothing to disk. Suitable for CI/headless environments where no
|
|
6
|
+
* secure credential store (libsecret, GPG, macOS Keychain) is available.
|
|
7
|
+
*
|
|
8
|
+
* Implements the VaultBackend interface:
|
|
9
|
+
* store(key, value): boolean — always returns false (env vars are read-only)
|
|
10
|
+
* retrieve(key): string|null — returns ENGRAM_API_KEY for 'auth-token', null otherwise
|
|
11
|
+
* delete(key): boolean — always returns true (no-op; nothing to delete)
|
|
12
|
+
* static detect(): boolean — always returns true (last-resort fallback)
|
|
13
|
+
*/
|
|
14
|
+
import type { VaultBackend } from "./types.js";
|
|
15
|
+
/**
|
|
16
|
+
* Environment-variable-only vault backend.
|
|
17
|
+
*
|
|
18
|
+
* This is the last-resort fallback when no OS-level secure credential store is
|
|
19
|
+
* available. It surfaces `ENGRAM_API_KEY` as the `auth-token` credential and
|
|
20
|
+
* rejects all write attempts with a warning on stderr.
|
|
21
|
+
*/
|
|
22
|
+
export declare class EnvVault implements VaultBackend {
|
|
23
|
+
/**
|
|
24
|
+
* Detection probe — always returns true so that EnvVault is always
|
|
25
|
+
* available as a last-resort fallback.
|
|
26
|
+
*/
|
|
27
|
+
static detect(): boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Attempt to store a credential.
|
|
30
|
+
*
|
|
31
|
+
* Environment variables cannot be written from within a process, so this
|
|
32
|
+
* always fails. A warning is emitted to stderr explaining how to configure
|
|
33
|
+
* persistent storage.
|
|
34
|
+
*
|
|
35
|
+
* @returns false — storage is never performed
|
|
36
|
+
*/
|
|
37
|
+
store(_key: string, _value: string): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Retrieve a credential from the environment.
|
|
40
|
+
*
|
|
41
|
+
* - `'auth-token'` -> `process.env["ENGRAM_API_KEY"] ?? null`
|
|
42
|
+
* - `'refresh-token'` -> `null` (refresh tokens are not available in env mode)
|
|
43
|
+
* - any other key -> `null`
|
|
44
|
+
*
|
|
45
|
+
* @param key - Logical credential key
|
|
46
|
+
* @returns The credential value, or null if unavailable
|
|
47
|
+
*/
|
|
48
|
+
retrieve(key: string): string | null;
|
|
49
|
+
/**
|
|
50
|
+
* Delete a credential.
|
|
51
|
+
*
|
|
52
|
+
* No-op: there is nothing stored in this backend to delete.
|
|
53
|
+
*
|
|
54
|
+
* @returns true — always succeeds (nothing to remove)
|
|
55
|
+
*/
|
|
56
|
+
delete(_key: string): boolean;
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=vault-env.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vault-env.d.ts","sourceRoot":"","sources":["../../src/vault/vault-env.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAM/C;;;;;;GAMG;AACH,qBAAa,QAAS,YAAW,YAAY;IAC3C;;;OAGG;IACH,MAAM,CAAC,MAAM,IAAI,OAAO;IAIxB;;;;;;;;OAQG;IACH,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO;IAK5C;;;;;;;;;OASG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAOpC;;;;;;OAMG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;CAG9B"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth Vault — Environment Variable Fallback Backend
|
|
3
|
+
*
|
|
4
|
+
* Last-resort vault backend that reads credentials from environment variables.
|
|
5
|
+
* Reads/writes nothing to disk. Suitable for CI/headless environments where no
|
|
6
|
+
* secure credential store (libsecret, GPG, macOS Keychain) is available.
|
|
7
|
+
*
|
|
8
|
+
* Implements the VaultBackend interface:
|
|
9
|
+
* store(key, value): boolean — always returns false (env vars are read-only)
|
|
10
|
+
* retrieve(key): string|null — returns ENGRAM_API_KEY for 'auth-token', null otherwise
|
|
11
|
+
* delete(key): boolean — always returns true (no-op; nothing to delete)
|
|
12
|
+
* static detect(): boolean — always returns true (last-resort fallback)
|
|
13
|
+
*/
|
|
14
|
+
import { AUTH_MESSAGES } from "../cli/messages.js";
|
|
15
|
+
// =============================================================================
|
|
16
|
+
// EnvVault implementation
|
|
17
|
+
// =============================================================================
|
|
18
|
+
/**
|
|
19
|
+
* Environment-variable-only vault backend.
|
|
20
|
+
*
|
|
21
|
+
* This is the last-resort fallback when no OS-level secure credential store is
|
|
22
|
+
* available. It surfaces `ENGRAM_API_KEY` as the `auth-token` credential and
|
|
23
|
+
* rejects all write attempts with a warning on stderr.
|
|
24
|
+
*/
|
|
25
|
+
export class EnvVault {
|
|
26
|
+
/**
|
|
27
|
+
* Detection probe — always returns true so that EnvVault is always
|
|
28
|
+
* available as a last-resort fallback.
|
|
29
|
+
*/
|
|
30
|
+
static detect() {
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Attempt to store a credential.
|
|
35
|
+
*
|
|
36
|
+
* Environment variables cannot be written from within a process, so this
|
|
37
|
+
* always fails. A warning is emitted to stderr explaining how to configure
|
|
38
|
+
* persistent storage.
|
|
39
|
+
*
|
|
40
|
+
* @returns false — storage is never performed
|
|
41
|
+
*/
|
|
42
|
+
store(_key, _value) {
|
|
43
|
+
process.stderr.write(AUTH_MESSAGES.warning.envVaultNoStorage + "\n");
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Retrieve a credential from the environment.
|
|
48
|
+
*
|
|
49
|
+
* - `'auth-token'` -> `process.env["ENGRAM_API_KEY"] ?? null`
|
|
50
|
+
* - `'refresh-token'` -> `null` (refresh tokens are not available in env mode)
|
|
51
|
+
* - any other key -> `null`
|
|
52
|
+
*
|
|
53
|
+
* @param key - Logical credential key
|
|
54
|
+
* @returns The credential value, or null if unavailable
|
|
55
|
+
*/
|
|
56
|
+
retrieve(key) {
|
|
57
|
+
if (key === "auth-token") {
|
|
58
|
+
return process.env["ENGRAM_API_KEY"] ?? null;
|
|
59
|
+
}
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Delete a credential.
|
|
64
|
+
*
|
|
65
|
+
* No-op: there is nothing stored in this backend to delete.
|
|
66
|
+
*
|
|
67
|
+
* @returns true — always succeeds (nothing to remove)
|
|
68
|
+
*/
|
|
69
|
+
delete(_key) {
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=vault-env.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vault-env.js","sourceRoot":"","sources":["../../src/vault/vault-env.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGnD,gFAAgF;AAChF,0BAA0B;AAC1B,gFAAgF;AAEhF;;;;;;GAMG;AACH,MAAM,OAAO,QAAQ;IACnB;;;OAGG;IACH,MAAM,CAAC,MAAM;QACX,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;;;;;OAQG;IACH,KAAK,CAAC,IAAY,EAAE,MAAc;QAChC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC;QACrE,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;;;;;;;;OASG;IACH,QAAQ,CAAC,GAAW;QAClB,IAAI,GAAG,KAAK,YAAY,EAAE,CAAC;YACzB,OAAO,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,IAAI,IAAI,CAAC;QAC/C,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;;;OAMG;IACH,MAAM,CAAC,IAAY;QACjB,OAAO,IAAI,CAAC;IACd,CAAC;CACF"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth Vault — GPG Backend
|
|
3
|
+
*
|
|
4
|
+
* Implements the VaultBackend interface using GPG-encrypted files stored at
|
|
5
|
+
* ~/.centient/auth/credentials-<key>.gpg. Falls back gracefully when GPG is
|
|
6
|
+
* not installed or no keys are configured.
|
|
7
|
+
*
|
|
8
|
+
* Error handling: all methods return false/null on failure — never throw.
|
|
9
|
+
*/
|
|
10
|
+
import type { VaultBackend } from "./types.js";
|
|
11
|
+
/**
|
|
12
|
+
* Vault backend that stores credentials as GPG-encrypted files.
|
|
13
|
+
*
|
|
14
|
+
* Use `GpgVault.detect()` before instantiating to verify availability.
|
|
15
|
+
*/
|
|
16
|
+
export declare class GpgVault implements VaultBackend {
|
|
17
|
+
/**
|
|
18
|
+
* Returns true if GPG is installed and at least one public key is available.
|
|
19
|
+
*/
|
|
20
|
+
static detect(): boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Encrypts and stores `value` under `key` using the first available GPG key.
|
|
23
|
+
*
|
|
24
|
+
* @returns true on success, false if GPG is unavailable or encryption fails
|
|
25
|
+
*/
|
|
26
|
+
store(key: string, value: string): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Decrypts and returns the stored credential for `key`.
|
|
29
|
+
*
|
|
30
|
+
* @returns the plaintext credential, or null if not found / decryption fails
|
|
31
|
+
*/
|
|
32
|
+
retrieve(key: string): string | null;
|
|
33
|
+
/**
|
|
34
|
+
* Deletes the GPG-encrypted credential file for `key`.
|
|
35
|
+
*
|
|
36
|
+
* @returns true if the file was deleted or did not exist, false on unexpected error
|
|
37
|
+
*/
|
|
38
|
+
delete(key: string): boolean;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=vault-gpg.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vault-gpg.d.ts","sourceRoot":"","sources":["../../src/vault/vault-gpg.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAOH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AA4D/C;;;;GAIG;AACH,qBAAa,QAAS,YAAW,YAAY;IAC3C;;OAEG;IACH,MAAM,CAAC,MAAM,IAAI,OAAO;IASxB;;;;OAIG;IACH,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO;IAuB1C;;;;OAIG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAkBpC;;;;OAIG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;CAkB7B"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth Vault — GPG Backend
|
|
3
|
+
*
|
|
4
|
+
* Implements the VaultBackend interface using GPG-encrypted files stored at
|
|
5
|
+
* ~/.centient/auth/credentials-<key>.gpg. Falls back gracefully when GPG is
|
|
6
|
+
* not installed or no keys are configured.
|
|
7
|
+
*
|
|
8
|
+
* Error handling: all methods return false/null on failure — never throw.
|
|
9
|
+
*/
|
|
10
|
+
import { execFileSync } from "child_process";
|
|
11
|
+
import { mkdirSync, unlinkSync } from "fs";
|
|
12
|
+
import { homedir } from "os";
|
|
13
|
+
import { join } from "path";
|
|
14
|
+
import { isValidKey } from "./vault-utils.js";
|
|
15
|
+
// =============================================================================
|
|
16
|
+
// Constants
|
|
17
|
+
// =============================================================================
|
|
18
|
+
const AUTH_DIR = join(homedir(), ".centient", "auth");
|
|
19
|
+
// =============================================================================
|
|
20
|
+
// Helpers
|
|
21
|
+
// =============================================================================
|
|
22
|
+
/**
|
|
23
|
+
* Returns the path to the GPG-encrypted credential file for the given key.
|
|
24
|
+
*/
|
|
25
|
+
function credentialPath(key) {
|
|
26
|
+
return join(AUTH_DIR, `credentials-${key}.gpg`);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Ensures ~/.centient/auth/ exists.
|
|
30
|
+
*/
|
|
31
|
+
function ensureAuthDir() {
|
|
32
|
+
mkdirSync(AUTH_DIR, { recursive: true });
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Parses `gpg --list-keys --with-colons` output and returns the fingerprint
|
|
36
|
+
* of the first available public key, or null if none found.
|
|
37
|
+
*/
|
|
38
|
+
function getFirstGpgKeyId() {
|
|
39
|
+
try {
|
|
40
|
+
const output = execFileSync("gpg", ["--list-keys", "--with-colons"], { encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] });
|
|
41
|
+
const lines = output.split("\n");
|
|
42
|
+
for (const line of lines) {
|
|
43
|
+
if (line.startsWith("fpr:")) {
|
|
44
|
+
// fpr lines have the fingerprint in the 10th colon-delimited field (index 9)
|
|
45
|
+
const parts = line.split(":");
|
|
46
|
+
const fingerprint = parts[9];
|
|
47
|
+
if (!fingerprint || !/^[0-9A-Fa-f]{40}$/.test(fingerprint.trim()))
|
|
48
|
+
continue;
|
|
49
|
+
if (fingerprint && fingerprint.trim().length > 0) {
|
|
50
|
+
return fingerprint.trim();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// =============================================================================
|
|
61
|
+
// GpgVault
|
|
62
|
+
// =============================================================================
|
|
63
|
+
/**
|
|
64
|
+
* Vault backend that stores credentials as GPG-encrypted files.
|
|
65
|
+
*
|
|
66
|
+
* Use `GpgVault.detect()` before instantiating to verify availability.
|
|
67
|
+
*/
|
|
68
|
+
export class GpgVault {
|
|
69
|
+
/**
|
|
70
|
+
* Returns true if GPG is installed and at least one public key is available.
|
|
71
|
+
*/
|
|
72
|
+
static detect() {
|
|
73
|
+
try {
|
|
74
|
+
execFileSync("which", ["gpg"], { stdio: ["pipe", "pipe", "pipe"] });
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
return getFirstGpgKeyId() !== null;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Encrypts and stores `value` under `key` using the first available GPG key.
|
|
83
|
+
*
|
|
84
|
+
* @returns true on success, false if GPG is unavailable or encryption fails
|
|
85
|
+
*/
|
|
86
|
+
store(key, value) {
|
|
87
|
+
if (!isValidKey(key))
|
|
88
|
+
return false;
|
|
89
|
+
try {
|
|
90
|
+
const keyId = getFirstGpgKeyId();
|
|
91
|
+
if (keyId === null)
|
|
92
|
+
return false;
|
|
93
|
+
ensureAuthDir();
|
|
94
|
+
const outPath = credentialPath(key);
|
|
95
|
+
execFileSync("gpg", ["--batch", "--yes", "-e", "-r", keyId, "-o", outPath], {
|
|
96
|
+
input: value,
|
|
97
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
98
|
+
});
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Decrypts and returns the stored credential for `key`.
|
|
107
|
+
*
|
|
108
|
+
* @returns the plaintext credential, or null if not found / decryption fails
|
|
109
|
+
*/
|
|
110
|
+
retrieve(key) {
|
|
111
|
+
if (!isValidKey(key))
|
|
112
|
+
return null;
|
|
113
|
+
try {
|
|
114
|
+
const filePath = credentialPath(key);
|
|
115
|
+
const result = execFileSync("gpg", ["--batch", "--quiet", "-d", filePath], {
|
|
116
|
+
encoding: "utf8",
|
|
117
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
118
|
+
});
|
|
119
|
+
return result ?? null;
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Deletes the GPG-encrypted credential file for `key`.
|
|
127
|
+
*
|
|
128
|
+
* @returns true if the file was deleted or did not exist, false on unexpected error
|
|
129
|
+
*/
|
|
130
|
+
delete(key) {
|
|
131
|
+
if (!isValidKey(key))
|
|
132
|
+
return false;
|
|
133
|
+
try {
|
|
134
|
+
unlinkSync(credentialPath(key));
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
catch (err) {
|
|
138
|
+
// ENOENT means file did not exist — treat as success
|
|
139
|
+
if (err !== null &&
|
|
140
|
+
typeof err === "object" &&
|
|
141
|
+
"code" in err &&
|
|
142
|
+
err.code === "ENOENT") {
|
|
143
|
+
return true;
|
|
144
|
+
}
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=vault-gpg.js.map
|