humanish 0.47.0 → 0.49.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/README.md +13 -3
- package/dist/actor-contract.d.ts +14 -0
- package/dist/actor-contract.js.map +1 -1
- package/dist/computer-use-actor.d.ts +3 -7
- package/dist/computer-use.d.ts +4 -7
- package/dist/computer-use.js +39 -3
- package/dist/computer-use.js.map +1 -1
- package/dist/concurrent-shared-world-lab.js +2 -1
- package/dist/concurrent-shared-world-lab.js.map +1 -1
- package/dist/cua-actor-lab.js +4 -7
- package/dist/cua-actor-lab.js.map +1 -1
- package/dist/key-resolution.d.ts +67 -0
- package/dist/key-resolution.js +373 -0
- package/dist/key-resolution.js.map +1 -0
- package/dist/observer-app.html +5 -5
- package/dist/openai-responses-cu.d.ts +1 -1
- package/dist/openai-responses-cu.js +8 -2
- package/dist/openai-responses-cu.js.map +1 -1
- package/dist/pricing.d.ts +20 -0
- package/dist/pricing.js +109 -17
- package/dist/pricing.js.map +1 -1
- package/dist/program.d.ts +4 -1
- package/dist/program.js +164 -8
- package/dist/program.js.map +1 -1
- package/dist/run.js +24 -0
- package/dist/run.js.map +1 -1
- package/dist/scripted-browser-lab.js +2 -1
- package/dist/scripted-browser-lab.js.map +1 -1
- package/dist/shared-world-lab.js +2 -1
- package/dist/shared-world-lab.js.map +1 -1
- package/docs/contracts/schemas.md +16 -7
- package/docs/goals/current.md +19 -10
- package/docs/ramp/README.md +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
export declare const KEY_RESOLUTION_SCHEMA = "humanish.key-resolution.v1";
|
|
2
|
+
/** The ONLY names implicit discovery may fill (and `humanish keys set` may store). Everything
|
|
3
|
+
* else in an overlay/store file is ignored-and-named: a repo-planted NODE_OPTIONS/LD_PRELOAD
|
|
4
|
+
* must never enter process env off a file the operator did not explicitly pass (an explicit
|
|
5
|
+
* --env-file remains the operator's own full-file load). Red-team finding, #436. */
|
|
6
|
+
export declare const KNOWN_PROVIDER_KEYS: readonly ["OPENAI_API_KEY", "ANTHROPIC_API_KEY", "E2B_API_KEY", "GH_TOKEN", "GITHUB_TOKEN", "CODEX_API_KEY"];
|
|
7
|
+
/** `humanish keys set <vendor>` aliases; a raw ENV_NAME is also accepted. */
|
|
8
|
+
export declare const KEY_VENDOR_ALIASES: Record<string, string>;
|
|
9
|
+
export interface ResolvedKeyFill {
|
|
10
|
+
name: string;
|
|
11
|
+
/** Human-readable source label (a path or command name) — never a value. */
|
|
12
|
+
source: string;
|
|
13
|
+
}
|
|
14
|
+
export interface KeyResolutionDeps {
|
|
15
|
+
/** Injectable for tests: run `gh auth token`-style probes. Resolves to trimmed single-line
|
|
16
|
+
* stdout, or null on any failure (missing binary, non-zero exit, empty/multi-line output). */
|
|
17
|
+
execText?: (command: string, args: string[], timeoutMs: number) => Promise<string | null>;
|
|
18
|
+
homeDir?: string;
|
|
19
|
+
}
|
|
20
|
+
export declare const PROJECT_OVERLAY_RELATIVE: string;
|
|
21
|
+
export declare function userKeyStorePath(env: NodeJS.ProcessEnv, deps?: KeyResolutionDeps): string;
|
|
22
|
+
/**
|
|
23
|
+
* Fill missing provider keys into `env` from the discovery chain, announcing each fill as
|
|
24
|
+
* `NAME from SOURCE`. Returns the fills. Opt-out: HUMANISH_STRICT_KEYS=1 returns [] untouched.
|
|
25
|
+
*/
|
|
26
|
+
export declare function discoverProviderKeys(args: {
|
|
27
|
+
cwd: string;
|
|
28
|
+
env: NodeJS.ProcessEnv;
|
|
29
|
+
announce: (line: string) => void;
|
|
30
|
+
deps?: KeyResolutionDeps;
|
|
31
|
+
}): Promise<ResolvedKeyFill[]>;
|
|
32
|
+
export interface KeySourceProbe {
|
|
33
|
+
name: string;
|
|
34
|
+
/** The source that supplies the key right now, or null when missing everywhere. */
|
|
35
|
+
source: string | null;
|
|
36
|
+
/** The command/path that would fill it when missing. */
|
|
37
|
+
hint: string;
|
|
38
|
+
}
|
|
39
|
+
/** The nearest fill instruction for a missing key — used by doctor rows and appended to
|
|
40
|
+
* *_KEYS_MISSING errors so the failure names the fix, not just the absence (#436). */
|
|
41
|
+
export declare function missingKeyHint(name: string): string;
|
|
42
|
+
/** One shared suffix for *_KEYS_MISSING messages: where discovery looked, and what fills each
|
|
43
|
+
* missing key. Pure text; never values. */
|
|
44
|
+
export declare function describeMissingKeys(names: string[], env: NodeJS.ProcessEnv): string;
|
|
45
|
+
/**
|
|
46
|
+
* Non-mutating probe for doctor: report, per key, the source that currently supplies it.
|
|
47
|
+
* Runs the same chain against a scratch copy of env so nothing observable changes.
|
|
48
|
+
*/
|
|
49
|
+
export declare function probeKeySources(names: readonly string[], args: {
|
|
50
|
+
cwd: string;
|
|
51
|
+
env: NodeJS.ProcessEnv;
|
|
52
|
+
deps?: KeyResolutionDeps;
|
|
53
|
+
}): Promise<KeySourceProbe[]>;
|
|
54
|
+
/** Resolve a `humanish keys set` target: a vendor alias or a raw env name. Null = invalid. */
|
|
55
|
+
export declare function resolveKeyName(vendorOrName: string): string | null;
|
|
56
|
+
/** Write one key into the user store (0700 dir, 0600 file). Only allowlisted provider names
|
|
57
|
+
* are storable (the store feeds implicit discovery — an arbitrary-name store would be an env
|
|
58
|
+
* injection vector with extra steps). The value must be a single non-empty line that
|
|
59
|
+
* round-trips the store's own parser byte-identically, and the write refuses symlinks at the
|
|
60
|
+
* file AND its parent directory (red-team findings). */
|
|
61
|
+
export declare function setUserKey(name: string, value: string, env: NodeJS.ProcessEnv, deps?: KeyResolutionDeps): {
|
|
62
|
+
path: string;
|
|
63
|
+
};
|
|
64
|
+
/** Remove one key from the user store. Returns whether it was present. */
|
|
65
|
+
export declare function unsetUserKey(name: string, env: NodeJS.ProcessEnv, deps?: KeyResolutionDeps): boolean;
|
|
66
|
+
/** The names (never values) currently in the user store. */
|
|
67
|
+
export declare function listUserKeys(env: NodeJS.ProcessEnv, deps?: KeyResolutionDeps): string[];
|
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
// Provider-key discovery (#436): resolve the keys a live run needs through each vendor's
|
|
2
|
+
// native chain instead of demanding a per-repo --env-file that operators hand-copy keys into.
|
|
3
|
+
//
|
|
4
|
+
// The chain, per key, FILL-ONLY (a rung never overrides anything already present):
|
|
5
|
+
// 1. process env — including whatever --env-file just loaded (explicit always wins);
|
|
6
|
+
// 2. `.humanish/local/provider.env` — the project-local overlay this CLI's own --help
|
|
7
|
+
// examples document;
|
|
8
|
+
// 3. the OWNING vendor's native store, where one exists:
|
|
9
|
+
// E2B_API_KEY <- ~/.e2b/config.json (written by `e2b auth login`);
|
|
10
|
+
// GH_TOKEN <- `gh auth token` (the gh CLI's credential chain);
|
|
11
|
+
// 4. the humanish user-level store `$XDG_CONFIG_HOME/humanish/keys.env`, written only by
|
|
12
|
+
// `humanish keys set` (0600, prompted or --stdin) — the fallback for vendors that ship
|
|
13
|
+
// no machine chain of their own (OpenAI, Anthropic).
|
|
14
|
+
//
|
|
15
|
+
// Every fill is ANNOUNCED by key name + source, never by value. The subject app's own
|
|
16
|
+
// `.env`/`.env.local` are NEVER read — those hold product credentials, a different class
|
|
17
|
+
// (#11); this module only reads humanish-owned files and vendor-owned stores.
|
|
18
|
+
// `HUMANISH_STRICT_KEYS=1` disables every rung below process env (the pre-#436 behavior).
|
|
19
|
+
import { spawn } from "node:child_process";
|
|
20
|
+
import { chmodSync, closeSync, constants as fsConstants, existsSync, ftruncateSync, lstatSync, mkdirSync, openSync, readFileSync, writeSync } from "node:fs";
|
|
21
|
+
import { homedir } from "node:os";
|
|
22
|
+
import path from "node:path";
|
|
23
|
+
import { loadEnvFile } from "./env-file.js";
|
|
24
|
+
export const KEY_RESOLUTION_SCHEMA = "humanish.key-resolution.v1";
|
|
25
|
+
/** The ONLY names implicit discovery may fill (and `humanish keys set` may store). Everything
|
|
26
|
+
* else in an overlay/store file is ignored-and-named: a repo-planted NODE_OPTIONS/LD_PRELOAD
|
|
27
|
+
* must never enter process env off a file the operator did not explicitly pass (an explicit
|
|
28
|
+
* --env-file remains the operator's own full-file load). Red-team finding, #436. */
|
|
29
|
+
export const KNOWN_PROVIDER_KEYS = [
|
|
30
|
+
"OPENAI_API_KEY",
|
|
31
|
+
"ANTHROPIC_API_KEY",
|
|
32
|
+
"E2B_API_KEY",
|
|
33
|
+
"GH_TOKEN",
|
|
34
|
+
"GITHUB_TOKEN",
|
|
35
|
+
"CODEX_API_KEY"
|
|
36
|
+
];
|
|
37
|
+
const PROVIDER_KEY_SET = new Set(KNOWN_PROVIDER_KEYS);
|
|
38
|
+
/** `humanish keys set <vendor>` aliases; a raw ENV_NAME is also accepted. */
|
|
39
|
+
export const KEY_VENDOR_ALIASES = {
|
|
40
|
+
openai: "OPENAI_API_KEY",
|
|
41
|
+
e2b: "E2B_API_KEY",
|
|
42
|
+
anthropic: "ANTHROPIC_API_KEY",
|
|
43
|
+
github: "GH_TOKEN"
|
|
44
|
+
};
|
|
45
|
+
export const PROJECT_OVERLAY_RELATIVE = path.join(".humanish", "local", "provider.env");
|
|
46
|
+
export function userKeyStorePath(env, deps = {}) {
|
|
47
|
+
const home = deps.homeDir ?? homedir();
|
|
48
|
+
const declared = env.XDG_CONFIG_HOME?.trim();
|
|
49
|
+
// The XDG spec: a relative XDG_CONFIG_HOME MUST be ignored. Honoring one would make the
|
|
50
|
+
// key store cwd-relative — `humanish keys set` would write a secret into the current repo.
|
|
51
|
+
const configHome = declared !== undefined && declared !== "" && path.isAbsolute(declared) ? declared : path.join(home, ".config");
|
|
52
|
+
return path.join(configHome, "humanish", "keys.env");
|
|
53
|
+
}
|
|
54
|
+
function e2bConfigPath(deps) {
|
|
55
|
+
return path.join(deps.homeDir ?? homedir(), ".e2b", "config.json");
|
|
56
|
+
}
|
|
57
|
+
/** Default exec: bounded, quiet, stdin closed; null on ANY failure. Never throws. */
|
|
58
|
+
function defaultExecText(command, args, timeoutMs) {
|
|
59
|
+
return new Promise((resolve) => {
|
|
60
|
+
let child;
|
|
61
|
+
try {
|
|
62
|
+
child = spawn(command, args, { stdio: ["ignore", "pipe", "ignore"] });
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
resolve(null);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
let out = "";
|
|
69
|
+
let settled = false;
|
|
70
|
+
const settle = (value) => {
|
|
71
|
+
if (!settled) {
|
|
72
|
+
settled = true;
|
|
73
|
+
resolve(value);
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
const timer = setTimeout(() => {
|
|
77
|
+
try {
|
|
78
|
+
child.kill();
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
// best effort
|
|
82
|
+
}
|
|
83
|
+
settle(null);
|
|
84
|
+
}, timeoutMs);
|
|
85
|
+
timer.unref?.();
|
|
86
|
+
child.stdout?.on("data", (chunk) => {
|
|
87
|
+
out += chunk.toString("utf8");
|
|
88
|
+
});
|
|
89
|
+
child.on("error", () => settle(null));
|
|
90
|
+
child.on("close", (code) => {
|
|
91
|
+
clearTimeout(timer);
|
|
92
|
+
if (code !== 0) {
|
|
93
|
+
settle(null);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
const trimmed = out.trim();
|
|
97
|
+
settle(trimmed.length > 0 && !trimmed.includes("\n") ? trimmed : null);
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
/** Read the E2B team key from the e2b CLI's own config. Defensive on shape: accept the
|
|
102
|
+
* documented `teamApiKey`, fall back to `apiKey`; anything else is a miss, never an error. */
|
|
103
|
+
function readE2bConfigKey(deps) {
|
|
104
|
+
try {
|
|
105
|
+
const raw = readFileSync(e2bConfigPath(deps), "utf8");
|
|
106
|
+
const parsed = JSON.parse(raw);
|
|
107
|
+
if (parsed === null || typeof parsed !== "object")
|
|
108
|
+
return null;
|
|
109
|
+
const record = parsed;
|
|
110
|
+
for (const field of ["teamApiKey", "apiKey"]) {
|
|
111
|
+
const value = record[field];
|
|
112
|
+
if (typeof value === "string" && value.trim().length > 0)
|
|
113
|
+
return value.trim();
|
|
114
|
+
}
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/** Refuse to READ a store through a symlink: a repo-local overlay that is secretly a link to
|
|
122
|
+
* an unrelated file is exactly the retargeting shape the artifact paths refuse elsewhere. */
|
|
123
|
+
function isRegularFile(filePath) {
|
|
124
|
+
try {
|
|
125
|
+
return lstatSync(filePath).isFile();
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Fill missing provider keys into `env` from the discovery chain, announcing each fill as
|
|
133
|
+
* `NAME from SOURCE`. Returns the fills. Opt-out: HUMANISH_STRICT_KEYS=1 returns [] untouched.
|
|
134
|
+
*/
|
|
135
|
+
export async function discoverProviderKeys(args) {
|
|
136
|
+
const { cwd, env, announce } = args;
|
|
137
|
+
const deps = args.deps ?? {};
|
|
138
|
+
if (env.HUMANISH_STRICT_KEYS?.trim() === "1")
|
|
139
|
+
return [];
|
|
140
|
+
const fills = [];
|
|
141
|
+
const ignored = [];
|
|
142
|
+
// Fill-only means PRESENCE wins, including an explicitly-set empty value: an operator who
|
|
143
|
+
// exported OPENAI_API_KEY="" said "off", and a rung that "fixes" that has overridden them
|
|
144
|
+
// (red-team finding). Only a truly-unset name is fillable.
|
|
145
|
+
const fillable = (name) => env[name] === undefined;
|
|
146
|
+
const fill = (name, value, source) => {
|
|
147
|
+
env[name] = value;
|
|
148
|
+
fills.push({ name, source });
|
|
149
|
+
};
|
|
150
|
+
// Rung 2: the documented project-local overlay. Parsed ATOMICALLY against a scratch env so a
|
|
151
|
+
// file loadEnvFile rejects can never half-apply (red-team finding: earlier lines used to land
|
|
152
|
+
// in env unannounced before the parse error aborted). Only allowlisted provider names cross
|
|
153
|
+
// from the file into the real env.
|
|
154
|
+
const overlayPath = path.resolve(cwd, PROJECT_OVERLAY_RELATIVE);
|
|
155
|
+
if (isRegularFile(overlayPath) && !dirIsSymlink(overlayPath)) {
|
|
156
|
+
const scratch = {};
|
|
157
|
+
const overlay = await loadEnvFile(cwd, PROJECT_OVERLAY_RELATIVE, scratch);
|
|
158
|
+
if (overlay.ok) {
|
|
159
|
+
for (const name of overlay.loaded) {
|
|
160
|
+
const value = scratch[name];
|
|
161
|
+
if (value === undefined || !fillable(name))
|
|
162
|
+
continue;
|
|
163
|
+
if (!PROVIDER_KEY_SET.has(name)) {
|
|
164
|
+
ignored.push(`${name} (${PROJECT_OVERLAY_RELATIVE})`);
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
fill(name, value, PROJECT_OVERLAY_RELATIVE);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
// Rung 3a: the e2b CLI's own login store.
|
|
172
|
+
if (fillable("E2B_API_KEY")) {
|
|
173
|
+
const teamKey = readE2bConfigKey(deps);
|
|
174
|
+
if (teamKey !== null)
|
|
175
|
+
fill("E2B_API_KEY", teamKey, "~/.e2b/config.json (e2b auth login)");
|
|
176
|
+
}
|
|
177
|
+
// Rung 3b: the gh CLI's credential chain. Only consulted when NEITHER GitHub env name is
|
|
178
|
+
// present; fills GH_TOKEN (the name humanish reads first).
|
|
179
|
+
if (fillable("GH_TOKEN") && fillable("GITHUB_TOKEN")) {
|
|
180
|
+
const exec = deps.execText ?? defaultExecText;
|
|
181
|
+
const token = await exec("gh", ["auth", "token"], 3_000);
|
|
182
|
+
if (token !== null)
|
|
183
|
+
fill("GH_TOKEN", token, "gh auth token");
|
|
184
|
+
}
|
|
185
|
+
// Rung 4: the humanish user-level store — read with the SAME lenient parser `keys set`/`list`
|
|
186
|
+
// use, so one hand-mangled line degrades to that line alone instead of silently voiding the
|
|
187
|
+
// whole store (red-team finding: the strict parser disagreed with the store's own reader).
|
|
188
|
+
const storePath = userKeyStorePath(env, deps);
|
|
189
|
+
if (isRegularFile(storePath) && !dirIsSymlink(storePath)) {
|
|
190
|
+
for (const [name, value] of readStoreEntries(storePath)) {
|
|
191
|
+
if (!fillable(name))
|
|
192
|
+
continue;
|
|
193
|
+
if (!PROVIDER_KEY_SET.has(name)) {
|
|
194
|
+
ignored.push(`${name} (${storeLabel(env, deps)})`);
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
fill(name, value, storeLabel(env, deps));
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
for (const fill_ of fills)
|
|
201
|
+
announce(`humanish keys: ${fill_.name} from ${fill_.source}`);
|
|
202
|
+
for (const name of ignored)
|
|
203
|
+
announce(`humanish keys: ignored non-provider name ${name} — implicit discovery fills provider keys only; pass the file via --env-file to load everything in it`);
|
|
204
|
+
return fills;
|
|
205
|
+
}
|
|
206
|
+
/** True when the file's PARENT directory is (or traverses) a symlink at its last component —
|
|
207
|
+
* the dir-level retarget that defeats a file-level lstat check (red-team finding). */
|
|
208
|
+
function dirIsSymlink(filePath) {
|
|
209
|
+
try {
|
|
210
|
+
return lstatSync(path.dirname(filePath)).isSymbolicLink();
|
|
211
|
+
}
|
|
212
|
+
catch {
|
|
213
|
+
return false;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
function storeLabel(env, deps) {
|
|
217
|
+
const home = deps.homeDir ?? homedir();
|
|
218
|
+
return userKeyStorePath(env, deps).replace(home, "~");
|
|
219
|
+
}
|
|
220
|
+
/** The nearest fill instruction for a missing key — used by doctor rows and appended to
|
|
221
|
+
* *_KEYS_MISSING errors so the failure names the fix, not just the absence (#436). */
|
|
222
|
+
export function missingKeyHint(name) {
|
|
223
|
+
switch (name) {
|
|
224
|
+
case "E2B_API_KEY":
|
|
225
|
+
return "run `e2b auth login`, or `humanish keys set e2b`";
|
|
226
|
+
case "GH_TOKEN":
|
|
227
|
+
case "GITHUB_TOKEN":
|
|
228
|
+
return "run `gh auth login`, or `humanish keys set github`";
|
|
229
|
+
case "OPENAI_API_KEY":
|
|
230
|
+
return "run `humanish keys set openai`";
|
|
231
|
+
case "ANTHROPIC_API_KEY":
|
|
232
|
+
return "run `humanish keys set anthropic`";
|
|
233
|
+
default:
|
|
234
|
+
return `run \`humanish keys set ${name}\``;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
/** One shared suffix for *_KEYS_MISSING messages: where discovery looked, and what fills each
|
|
238
|
+
* missing key. Pure text; never values. */
|
|
239
|
+
export function describeMissingKeys(names, env) {
|
|
240
|
+
const hints = names.map((name) => `${name}: ${missingKeyHint(name)}`).join("; ");
|
|
241
|
+
const strict = env.HUMANISH_STRICT_KEYS?.trim() === "1";
|
|
242
|
+
const chain = strict
|
|
243
|
+
? "key discovery is disabled (HUMANISH_STRICT_KEYS=1); only process env and --env-file are read"
|
|
244
|
+
: `also checked ${PROJECT_OVERLAY_RELATIVE}, ~/.e2b/config.json, gh auth token, and ${path.join("~", ".config", "humanish", "keys.env")}`;
|
|
245
|
+
return `${chain}. Fill: ${hints}.`;
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Non-mutating probe for doctor: report, per key, the source that currently supplies it.
|
|
249
|
+
* Runs the same chain against a scratch copy of env so nothing observable changes.
|
|
250
|
+
*/
|
|
251
|
+
export async function probeKeySources(names, args) {
|
|
252
|
+
const scratch = { ...args.env };
|
|
253
|
+
const fills = await discoverProviderKeys({
|
|
254
|
+
cwd: args.cwd,
|
|
255
|
+
env: scratch,
|
|
256
|
+
announce: () => { },
|
|
257
|
+
...(args.deps === undefined ? {} : { deps: args.deps })
|
|
258
|
+
});
|
|
259
|
+
const bySource = new Map(fills.map((fill) => [fill.name, fill.source]));
|
|
260
|
+
return names.map((name) => {
|
|
261
|
+
const inEnv = args.env[name] !== undefined && args.env[name]?.trim() !== "";
|
|
262
|
+
// GH_TOKEN and GITHUB_TOKEN are one credential with two spellings; a doctor row that says
|
|
263
|
+
// "missing" while GITHUB_TOKEN sits in the env would be wrong (red-team nit).
|
|
264
|
+
const aliasInEnv = name === "GH_TOKEN" && args.env.GITHUB_TOKEN !== undefined && args.env.GITHUB_TOKEN.trim() !== "";
|
|
265
|
+
const source = inEnv ? "process env" : aliasInEnv ? "process env (GITHUB_TOKEN)" : (bySource.get(name) ?? null);
|
|
266
|
+
return { name, source, hint: missingKeyHint(name) };
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
const ENV_NAME = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
270
|
+
/** Resolve a `humanish keys set` target: a vendor alias or a raw env name. Null = invalid. */
|
|
271
|
+
export function resolveKeyName(vendorOrName) {
|
|
272
|
+
const alias = KEY_VENDOR_ALIASES[vendorOrName.toLowerCase()];
|
|
273
|
+
if (alias !== undefined)
|
|
274
|
+
return alias;
|
|
275
|
+
return ENV_NAME.test(vendorOrName) ? vendorOrName : null;
|
|
276
|
+
}
|
|
277
|
+
/** Write one key into the user store (0700 dir, 0600 file). Only allowlisted provider names
|
|
278
|
+
* are storable (the store feeds implicit discovery — an arbitrary-name store would be an env
|
|
279
|
+
* injection vector with extra steps). The value must be a single non-empty line that
|
|
280
|
+
* round-trips the store's own parser byte-identically, and the write refuses symlinks at the
|
|
281
|
+
* file AND its parent directory (red-team findings). */
|
|
282
|
+
export function setUserKey(name, value, env, deps = {}) {
|
|
283
|
+
const trimmed = value.trim();
|
|
284
|
+
if (trimmed.length === 0 || /\r|\n/.test(trimmed)) {
|
|
285
|
+
throw new Error("The key value must be a single non-empty line.");
|
|
286
|
+
}
|
|
287
|
+
if (!ENV_NAME.test(name)) {
|
|
288
|
+
throw new Error(`Not a valid env name: ${name}`);
|
|
289
|
+
}
|
|
290
|
+
if (!PROVIDER_KEY_SET.has(name)) {
|
|
291
|
+
throw new Error(`The store holds provider keys only (${[...PROVIDER_KEY_SET].join(", ")}). For anything else, use an explicit --env-file.`);
|
|
292
|
+
}
|
|
293
|
+
const storePath = userKeyStorePath(env, deps);
|
|
294
|
+
const dir = path.dirname(storePath);
|
|
295
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
296
|
+
if (lstatSync(dir).isSymbolicLink()) {
|
|
297
|
+
throw new Error(`Refusing to write through a symlinked store directory: ${dir}`);
|
|
298
|
+
}
|
|
299
|
+
if (existsSync(storePath) && !lstatSync(storePath).isFile()) {
|
|
300
|
+
throw new Error(`Refusing to write the store: ${storePath} is not a regular file.`);
|
|
301
|
+
}
|
|
302
|
+
const entries = readStoreEntries(storePath);
|
|
303
|
+
entries.set(name, trimmed);
|
|
304
|
+
// The written line must read back byte-identically through the store's own parser: a value
|
|
305
|
+
// that parses differently (an embedded '#', a leading quote the env parser would strip)
|
|
306
|
+
// would silently resolve to a DIFFERENT secret on the next run.
|
|
307
|
+
const roundTrip = parseStoreLine(`${name}=${trimmed}`);
|
|
308
|
+
if (roundTrip === null || roundTrip[0] !== name || roundTrip[1] !== trimmed) {
|
|
309
|
+
throw new Error("The value does not round-trip the store format (avoid leading quotes and '#'); pass it via --env-file instead.");
|
|
310
|
+
}
|
|
311
|
+
writeStore(storePath, entries);
|
|
312
|
+
return { path: storePath };
|
|
313
|
+
}
|
|
314
|
+
/** Remove one key from the user store. Returns whether it was present. */
|
|
315
|
+
export function unsetUserKey(name, env, deps = {}) {
|
|
316
|
+
const storePath = userKeyStorePath(env, deps);
|
|
317
|
+
if (!isRegularFile(storePath) || dirIsSymlink(storePath))
|
|
318
|
+
return false;
|
|
319
|
+
const entries = readStoreEntries(storePath);
|
|
320
|
+
const had = entries.delete(name);
|
|
321
|
+
if (had)
|
|
322
|
+
writeStore(storePath, entries);
|
|
323
|
+
return had;
|
|
324
|
+
}
|
|
325
|
+
/** The names (never values) currently in the user store. */
|
|
326
|
+
export function listUserKeys(env, deps = {}) {
|
|
327
|
+
const storePath = userKeyStorePath(env, deps);
|
|
328
|
+
if (!isRegularFile(storePath) || dirIsSymlink(storePath))
|
|
329
|
+
return [];
|
|
330
|
+
return [...readStoreEntries(storePath).keys()];
|
|
331
|
+
}
|
|
332
|
+
function readStoreEntries(storePath) {
|
|
333
|
+
const entries = new Map();
|
|
334
|
+
if (!existsSync(storePath))
|
|
335
|
+
return entries;
|
|
336
|
+
const text = readFileSync(storePath, "utf8");
|
|
337
|
+
for (const line of text.split(/\r?\n/)) {
|
|
338
|
+
const parsed = parseStoreLine(line);
|
|
339
|
+
if (parsed !== null)
|
|
340
|
+
entries.set(parsed[0], parsed[1]);
|
|
341
|
+
}
|
|
342
|
+
return entries;
|
|
343
|
+
}
|
|
344
|
+
function writeStore(storePath, entries) {
|
|
345
|
+
const body = [...entries.entries()].map(([name, value]) => `${name}=${value}`).join("\n");
|
|
346
|
+
const text = body.length > 0 ? `${body}\n` : "";
|
|
347
|
+
// O_NOFOLLOW: a symlinked keys.env must never carry the write to its target (red-team
|
|
348
|
+
// reproduced writing a secret through the link into an attacker-chosen file).
|
|
349
|
+
const fd = openSync(storePath, fsConstants.O_WRONLY | fsConstants.O_CREAT | fsConstants.O_NOFOLLOW, 0o600);
|
|
350
|
+
try {
|
|
351
|
+
ftruncateSync(fd, 0);
|
|
352
|
+
writeSync(fd, text, 0, "utf8");
|
|
353
|
+
}
|
|
354
|
+
finally {
|
|
355
|
+
closeSync(fd);
|
|
356
|
+
}
|
|
357
|
+
// mkdir/open modes are masked by umask; enforce the final bits explicitly.
|
|
358
|
+
chmodSync(storePath, 0o600);
|
|
359
|
+
}
|
|
360
|
+
/** The store's line grammar, shared by read and the set-time round-trip check. */
|
|
361
|
+
function parseStoreLine(line) {
|
|
362
|
+
const trimmed = line.trim();
|
|
363
|
+
if (trimmed === "" || trimmed.startsWith("#"))
|
|
364
|
+
return null;
|
|
365
|
+
const separator = trimmed.indexOf("=");
|
|
366
|
+
if (separator <= 0)
|
|
367
|
+
return null;
|
|
368
|
+
const name = trimmed.slice(0, separator).trim();
|
|
369
|
+
if (!ENV_NAME.test(name))
|
|
370
|
+
return null;
|
|
371
|
+
return [name, trimmed.slice(separator + 1).trim()];
|
|
372
|
+
}
|
|
373
|
+
//# sourceMappingURL=key-resolution.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"key-resolution.js","sourceRoot":"","sources":["../src/key-resolution.ts"],"names":[],"mappings":"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"}
|