getmyenv 0.5.3 → 0.6.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 +57 -13
- package/dist/bin.js +1 -24
- package/dist/bin.js.map +1 -1
- package/dist/cli.d.ts +10 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +179 -106
- package/dist/cli.js.map +1 -1
- package/dist/commands/backup.d.ts +2 -1
- package/dist/commands/backup.d.ts.map +1 -1
- package/dist/commands/backup.js +15 -19
- package/dist/commands/backup.js.map +1 -1
- package/dist/commands/claim.d.ts +2 -1
- package/dist/commands/claim.d.ts.map +1 -1
- package/dist/commands/claim.js +114 -80
- package/dist/commands/claim.js.map +1 -1
- package/dist/commands/context.d.ts +11 -0
- package/dist/commands/context.d.ts.map +1 -0
- package/dist/commands/context.js +53 -0
- package/dist/commands/context.js.map +1 -0
- package/dist/commands/export.d.ts +11 -0
- package/dist/commands/export.d.ts.map +1 -0
- package/dist/commands/export.js +67 -0
- package/dist/commands/export.js.map +1 -0
- package/dist/commands/guest.d.ts +9 -3
- package/dist/commands/guest.d.ts.map +1 -1
- package/dist/commands/guest.js +32 -28
- package/dist/commands/guest.js.map +1 -1
- package/dist/commands/import.d.ts +26 -0
- package/dist/commands/import.d.ts.map +1 -0
- package/dist/commands/import.js +168 -0
- package/dist/commands/import.js.map +1 -0
- package/dist/commands/lock.d.ts +5 -0
- package/dist/commands/lock.d.ts.map +1 -0
- package/dist/commands/lock.js +18 -0
- package/dist/commands/lock.js.map +1 -0
- package/dist/commands/ls.d.ts +6 -0
- package/dist/commands/ls.d.ts.map +1 -0
- package/dist/commands/ls.js +37 -0
- package/dist/commands/ls.js.map +1 -0
- package/dist/commands/restore.d.ts +7 -2
- package/dist/commands/restore.d.ts.map +1 -1
- package/dist/commands/restore.js +57 -49
- package/dist/commands/restore.js.map +1 -1
- package/dist/commands/run.d.ts +7 -5
- package/dist/commands/run.d.ts.map +1 -1
- package/dist/commands/run.js +98 -187
- package/dist/commands/run.js.map +1 -1
- package/dist/commands/set.d.ts +16 -0
- package/dist/commands/set.d.ts.map +1 -0
- package/dist/commands/set.js +111 -0
- package/dist/commands/set.js.map +1 -0
- package/dist/commands/start.d.ts +16 -0
- package/dist/commands/start.d.ts.map +1 -0
- package/dist/commands/start.js +118 -0
- package/dist/commands/start.js.map +1 -0
- package/dist/commands/status.d.ts +5 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +40 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/unlink.d.ts +9 -0
- package/dist/commands/unlink.d.ts.map +1 -0
- package/dist/commands/unlink.js +70 -0
- package/dist/commands/unlink.js.map +1 -0
- package/dist/lib/api-url.d.ts +12 -0
- package/dist/lib/api-url.d.ts.map +1 -1
- package/dist/lib/api-url.js +32 -0
- package/dist/lib/api-url.js.map +1 -1
- package/dist/lib/api.d.ts +35 -23
- package/dist/lib/api.d.ts.map +1 -1
- package/dist/lib/api.js +23 -59
- package/dist/lib/api.js.map +1 -1
- package/dist/lib/authorize.d.ts +13 -6
- package/dist/lib/authorize.d.ts.map +1 -1
- package/dist/lib/authorize.js +68 -61
- package/dist/lib/authorize.js.map +1 -1
- package/dist/lib/bootstrap.d.ts +18 -15
- package/dist/lib/bootstrap.d.ts.map +1 -1
- package/dist/lib/bootstrap.js +59 -69
- package/dist/lib/bootstrap.js.map +1 -1
- package/dist/lib/confirm.js +4 -4
- package/dist/lib/confirm.js.map +1 -1
- package/dist/lib/context.d.ts +12 -0
- package/dist/lib/context.d.ts.map +1 -0
- package/dist/lib/context.js +43 -0
- package/dist/lib/context.js.map +1 -0
- package/dist/lib/credentials.d.ts +8 -13
- package/dist/lib/credentials.d.ts.map +1 -1
- package/dist/lib/credentials.js +2 -9
- package/dist/lib/credentials.js.map +1 -1
- package/dist/lib/fs.d.ts +26 -40
- package/dist/lib/fs.d.ts.map +1 -1
- package/dist/lib/fs.js +112 -326
- package/dist/lib/fs.js.map +1 -1
- package/dist/lib/guest-key.d.ts +2 -5
- package/dist/lib/guest-key.d.ts.map +1 -1
- package/dist/lib/guest-key.js +9 -2
- package/dist/lib/guest-key.js.map +1 -1
- package/dist/lib/identity.d.ts +9 -11
- package/dist/lib/identity.d.ts.map +1 -1
- package/dist/lib/identity.js +34 -24
- package/dist/lib/identity.js.map +1 -1
- package/dist/lib/keychain.d.ts +21 -0
- package/dist/lib/keychain.d.ts.map +1 -0
- package/dist/lib/keychain.js +124 -0
- package/dist/lib/keychain.js.map +1 -0
- package/dist/lib/pek.d.ts +15 -24
- package/dist/lib/pek.d.ts.map +1 -1
- package/dist/lib/pek.js +30 -54
- package/dist/lib/pek.js.map +1 -1
- package/dist/lib/run-env.d.ts +50 -0
- package/dist/lib/run-env.d.ts.map +1 -0
- package/dist/lib/run-env.js +114 -0
- package/dist/lib/run-env.js.map +1 -0
- package/dist/lib/unlock.d.ts +24 -0
- package/dist/lib/unlock.d.ts.map +1 -0
- package/dist/lib/unlock.js +87 -0
- package/dist/lib/unlock.js.map +1 -0
- package/dist/lib/update-check.d.ts +4 -2
- package/dist/lib/update-check.d.ts.map +1 -1
- package/dist/lib/update-check.js +54 -68
- package/dist/lib/update-check.js.map +1 -1
- package/dist/lib/upload.d.ts +21 -0
- package/dist/lib/upload.d.ts.map +1 -0
- package/dist/lib/upload.js +53 -0
- package/dist/lib/upload.js.map +1 -0
- package/package.json +5 -3
- package/dist/commands/delete.d.ts +0 -6
- package/dist/commands/delete.d.ts.map +0 -1
- package/dist/commands/delete.js +0 -55
- package/dist/commands/delete.js.map +0 -1
- package/dist/commands/link.d.ts +0 -16
- package/dist/commands/link.d.ts.map +0 -1
- package/dist/commands/link.js +0 -142
- package/dist/commands/link.js.map +0 -1
- package/dist/commands/pull.d.ts +0 -15
- package/dist/commands/pull.d.ts.map +0 -1
- package/dist/commands/pull.js +0 -155
- package/dist/commands/pull.js.map +0 -1
- package/dist/commands/push.d.ts +0 -15
- package/dist/commands/push.d.ts.map +0 -1
- package/dist/commands/push.js +0 -261
- package/dist/commands/push.js.map +0 -1
- package/dist/commands/remove.d.ts +0 -11
- package/dist/commands/remove.d.ts.map +0 -1
- package/dist/commands/remove.js +0 -39
- package/dist/commands/remove.js.map +0 -1
- package/dist/commands/token.d.ts +0 -14
- package/dist/commands/token.d.ts.map +0 -1
- package/dist/commands/token.js +0 -132
- package/dist/commands/token.js.map +0 -1
- package/dist/commands/whoami.d.ts +0 -6
- package/dist/commands/whoami.d.ts.map +0 -1
- package/dist/commands/whoami.js +0 -46
- package/dist/commands/whoami.js.map +0 -1
- package/dist/lib/env-name.d.ts +0 -3
- package/dist/lib/env-name.d.ts.map +0 -1
- package/dist/lib/env-name.js +0 -5
- package/dist/lib/env-name.js.map +0 -1
- package/dist/lib/guest-key.test.d.ts +0 -2
- package/dist/lib/guest-key.test.d.ts.map +0 -1
- package/dist/lib/guest-key.test.js.map +0 -1
package/dist/lib/guest-key.d.ts
CHANGED
|
@@ -10,10 +10,7 @@ export type ResolveVaultPasswordOpts = {
|
|
|
10
10
|
*/
|
|
11
11
|
create?: boolean;
|
|
12
12
|
};
|
|
13
|
-
/**
|
|
14
|
-
|
|
15
|
-
* Use that silently so guest → push → run needs no Vault password prompt.
|
|
16
|
-
* Claimed / human projects still prompt for the Vault password.
|
|
17
|
-
*/
|
|
13
|
+
/** Password already read from stdin by the command (for example `set --stdin`). */
|
|
14
|
+
export declare function presetVaultPassword(password: string): void;
|
|
18
15
|
export declare function resolveVaultPassword(opts: ResolveVaultPasswordOpts): Promise<string>;
|
|
19
16
|
//# sourceMappingURL=guest-key.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"guest-key.d.ts","sourceRoot":"","sources":["../../src/lib/guest-key.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,wBAAwB,GAAG;IACrC,wCAAwC;IACxC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,4DAA4D;IAC5D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,CAAC;
|
|
1
|
+
{"version":3,"file":"guest-key.d.ts","sourceRoot":"","sources":["../../src/lib/guest-key.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,wBAAwB,GAAG;IACrC,wCAAwC;IACxC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,4DAA4D;IAC5D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,CAAC;AASF,mFAAmF;AACnF,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAE1D;AAED,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,wBAAwB,GAC7B,OAAO,CAAC,MAAM,CAAC,CAuCjB"}
|
package/dist/lib/guest-key.js
CHANGED
|
@@ -1,16 +1,23 @@
|
|
|
1
1
|
import { promptHidden, readClaimFile } from "./fs.js";
|
|
2
2
|
/**
|
|
3
3
|
* Guest projects wrap the PEK with the passphrase in claim.json.
|
|
4
|
-
* Use that silently so guest
|
|
4
|
+
* Use that silently so guest, set and run need no Vault password prompt.
|
|
5
5
|
* Claimed / human projects still prompt for the Vault password.
|
|
6
6
|
*/
|
|
7
|
+
let presetPassword = null;
|
|
8
|
+
/** Password already read from stdin by the command (for example `set --stdin`). */
|
|
9
|
+
export function presetVaultPassword(password) {
|
|
10
|
+
presetPassword = password;
|
|
11
|
+
}
|
|
7
12
|
export async function resolveVaultPassword(opts) {
|
|
13
|
+
if (!opts.isGuest && presetPassword)
|
|
14
|
+
return presetPassword;
|
|
8
15
|
if (opts.isGuest) {
|
|
9
16
|
const claim = readClaimFile();
|
|
10
17
|
if (claim?.passphrase) {
|
|
11
18
|
return claim.passphrase;
|
|
12
19
|
}
|
|
13
|
-
throw new Error("Guest project is missing .getmyenv/claim.json. Restore it
|
|
20
|
+
throw new Error("Guest project is missing .getmyenv/claim.json. Restore it from your repo or a copy.");
|
|
14
21
|
}
|
|
15
22
|
if (opts.create) {
|
|
16
23
|
const password = await promptHidden("New Vault password (hidden): ", {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"guest-key.js","sourceRoot":"","sources":["../../src/lib/guest-key.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAetD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,IAA8B;IAE9B,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;QACjB,MAAM,KAAK,GAAG,aAAa,EAAE,CAAC;QAC9B,IAAI,KAAK,EAAE,UAAU,EAAE,CAAC;YACtB,OAAO,KAAK,CAAC,UAAU,CAAC;QAC1B,CAAC;QACD,MAAM,IAAI,KAAK,CACb,
|
|
1
|
+
{"version":3,"file":"guest-key.js","sourceRoot":"","sources":["../../src/lib/guest-key.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAetD;;;;GAIG;AACH,IAAI,cAAc,GAAkB,IAAI,CAAC;AAEzC,mFAAmF;AACnF,MAAM,UAAU,mBAAmB,CAAC,QAAgB;IAClD,cAAc,GAAG,QAAQ,CAAC;AAC5B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,IAA8B;IAE9B,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,cAAc;QAAE,OAAO,cAAc,CAAC;IAC3D,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;QACjB,MAAM,KAAK,GAAG,aAAa,EAAE,CAAC;QAC9B,IAAI,KAAK,EAAE,UAAU,EAAE,CAAC;YACtB,OAAO,KAAK,CAAC,UAAU,CAAC;QAC1B,CAAC;QACD,MAAM,IAAI,KAAK,CACb,qFAAqF,CACtF,CAAC;IACJ,CAAC;IAED,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAChB,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,+BAA+B,EAAE;YACnE,UAAU,EAAE,IAAI,CAAC,kBAAkB;SACpC,CAAC,CAAC;QACH,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;QAC9C,CAAC;QACD,IAAI,IAAI,CAAC,kBAAkB,EAAE,CAAC;YAC5B,OAAO,QAAQ,CAAC;QAClB,CAAC;QACD,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,mCAAmC,CAAC,CAAC;QACxE,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;QAC9C,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,YAAY,CACjC,IAAI,CAAC,MAAM,IAAI,2BAA2B,EAC1C;QACE,UAAU,EAAE,IAAI,CAAC,kBAAkB;KACpC,CACF,CAAC;IACF,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;IAC9C,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
package/dist/lib/identity.d.ts
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
import { type
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
export declare function
|
|
10
|
-
export declare function saveGrant(grant: StoredGrant): void;
|
|
11
|
-
export declare function clearGrant(projectId: string, environmentId: string): void;
|
|
1
|
+
import { type MachineKeypair } from "@getmyenv/crypto";
|
|
2
|
+
import { type MachineProof } from "@getmyenv/shared";
|
|
3
|
+
/**
|
|
4
|
+
* Machine identity per project, stored in the OS user config (never the repo).
|
|
5
|
+
* It identifies this machine for locked contexts. It does not decrypt values.
|
|
6
|
+
*/
|
|
7
|
+
export declare function loadOrCreateIdentity(projectId: string): MachineKeypair;
|
|
8
|
+
export declare function machineLabel(): string;
|
|
9
|
+
export declare function signMachineProof(projectId: string, contextSlug: string): MachineProof;
|
|
12
10
|
//# sourceMappingURL=identity.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../../src/lib/identity.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../../src/lib/identity.ts"],"names":[],"mappings":"AAGA,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAuB,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAG1E;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,cAAc,CAiBtE;AAED,wBAAgB,YAAY,IAAI,MAAM,CAKrC;AAED,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,GAClB,YAAY,CAed"}
|
package/dist/lib/identity.js
CHANGED
|
@@ -1,38 +1,48 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
|
+
import os from "node:os";
|
|
2
3
|
import path from "node:path";
|
|
3
|
-
import {
|
|
4
|
+
import { generateMachineIdentity, signAccessRequest, } from "@getmyenv/crypto";
|
|
5
|
+
import { machineProofMessage } from "@getmyenv/shared";
|
|
4
6
|
import { getConfigDir } from "./fs.js";
|
|
7
|
+
/**
|
|
8
|
+
* Machine identity per project, stored in the OS user config (never the repo).
|
|
9
|
+
* It identifies this machine for locked contexts. It does not decrypt values.
|
|
10
|
+
*/
|
|
5
11
|
export function loadOrCreateIdentity(projectId) {
|
|
6
|
-
const dir = path.join(getConfigDir(), "
|
|
12
|
+
const dir = path.join(getConfigDir(), "machines");
|
|
7
13
|
fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
8
14
|
const file = path.join(dir, `${projectId}.json`);
|
|
9
15
|
if (fs.existsSync(file)) {
|
|
10
|
-
|
|
16
|
+
try {
|
|
17
|
+
const data = JSON.parse(fs.readFileSync(file, "utf8"));
|
|
18
|
+
if (typeof data.publicKey === "string" && typeof data.privateKey === "string") {
|
|
19
|
+
return { publicKey: data.publicKey, privateKey: data.privateKey };
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
/* regenerate below */
|
|
24
|
+
}
|
|
11
25
|
}
|
|
12
|
-
const identity =
|
|
26
|
+
const identity = generateMachineIdentity();
|
|
13
27
|
fs.writeFileSync(file, JSON.stringify(identity, null, 2), { mode: 0o600 });
|
|
14
28
|
return identity;
|
|
15
29
|
}
|
|
16
|
-
export function
|
|
17
|
-
const
|
|
18
|
-
if (
|
|
19
|
-
return
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
fs.unlinkSync(file);
|
|
23
|
-
return null;
|
|
24
|
-
}
|
|
25
|
-
return grant;
|
|
26
|
-
}
|
|
27
|
-
export function saveGrant(grant) {
|
|
28
|
-
const dir = path.join(getConfigDir(), "grants");
|
|
29
|
-
fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
30
|
-
const file = path.join(dir, `${grant.projectId}-${grant.environmentId}.json`);
|
|
31
|
-
fs.writeFileSync(file, JSON.stringify(grant, null, 2), { mode: 0o600 });
|
|
30
|
+
export function machineLabel() {
|
|
31
|
+
const fromEnv = process.env.GETMYENV_MACHINE_LABEL?.trim();
|
|
32
|
+
if (fromEnv)
|
|
33
|
+
return fromEnv.slice(0, 120);
|
|
34
|
+
const user = process.env.USERNAME ?? process.env.USER ?? "user";
|
|
35
|
+
return `${user}@${os.hostname()}`.slice(0, 120);
|
|
32
36
|
}
|
|
33
|
-
export function
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
+
export function signMachineProof(projectId, contextSlug) {
|
|
38
|
+
const identity = loadOrCreateIdentity(projectId);
|
|
39
|
+
const timestamp = String(Date.now());
|
|
40
|
+
const message = machineProofMessage(projectId, contextSlug, identity.publicKey, timestamp);
|
|
41
|
+
return {
|
|
42
|
+
publicKey: identity.publicKey,
|
|
43
|
+
label: machineLabel(),
|
|
44
|
+
signature: signAccessRequest(identity.privateKey, message),
|
|
45
|
+
timestamp,
|
|
46
|
+
};
|
|
37
47
|
}
|
|
38
48
|
//# sourceMappingURL=identity.js.map
|
package/dist/lib/identity.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"identity.js","sourceRoot":"","sources":["../../src/lib/identity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EACL,
|
|
1
|
+
{"version":3,"file":"identity.js","sourceRoot":"","sources":["../../src/lib/identity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EACL,uBAAuB,EACvB,iBAAiB,GAElB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,mBAAmB,EAAqB,MAAM,kBAAkB,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,SAAiB;IACpD,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,UAAU,CAAC,CAAC;IAClD,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACpD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,OAAO,CAAC,CAAC;IACjD,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACxB,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAA4B,CAAC;YAClF,IAAI,OAAO,IAAI,CAAC,SAAS,KAAK,QAAQ,IAAI,OAAO,IAAI,CAAC,UAAU,KAAK,QAAQ,EAAE,CAAC;gBAC9E,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC;YACpE,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,sBAAsB;QACxB,CAAC;IACH,CAAC;IACD,MAAM,QAAQ,GAAG,uBAAuB,EAAE,CAAC;IAC3C,EAAE,CAAC,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC3E,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,sBAAsB,EAAE,IAAI,EAAE,CAAC;IAC3D,IAAI,OAAO;QAAE,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAC1C,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,MAAM,CAAC;IAChE,OAAO,GAAG,IAAI,IAAI,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AAClD,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC9B,SAAiB,EACjB,WAAmB;IAEnB,MAAM,QAAQ,GAAG,oBAAoB,CAAC,SAAS,CAAC,CAAC;IACjD,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IACrC,MAAM,OAAO,GAAG,mBAAmB,CACjC,SAAS,EACT,WAAW,EACX,QAAQ,CAAC,SAAS,EAClB,SAAS,CACV,CAAC;IACF,OAAO;QACL,SAAS,EAAE,QAAQ,CAAC,SAAS;QAC7B,KAAK,EAAE,YAAY,EAAE;QACrB,SAAS,EAAE,iBAAiB,CAAC,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;QAC1D,SAAS;KACV,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export declare const KEYCHAIN_TTL_MS: number;
|
|
2
|
+
type KeyringEntry = {
|
|
3
|
+
getPassword(): string | null;
|
|
4
|
+
setPassword(password: string): void;
|
|
5
|
+
deletePassword(): boolean;
|
|
6
|
+
};
|
|
7
|
+
export type KeyringFactory = (service: string, account: string) => KeyringEntry;
|
|
8
|
+
/** Tests swap in an in-memory keyring. `null` means no keyring available. */
|
|
9
|
+
export declare function setKeyringForTests(factory: KeyringFactory | null | undefined): void;
|
|
10
|
+
/** Off with `GETMYENV_KEYCHAIN=0` or in CI (`CI` set to anything but `false` or `0`). */
|
|
11
|
+
export declare function keychainEnabled(env?: NodeJS.ProcessEnv): boolean;
|
|
12
|
+
/** One keychain entry per server origin and project, so staging and production keys never mix. */
|
|
13
|
+
export declare function keychainAccount(apiUrl: string, projectId: string): string;
|
|
14
|
+
/** The cached key, only if it has not expired and matches the server's wrapped key. */
|
|
15
|
+
export declare function readCachedPek(account: string, wrappedRaw: string, now?: number): Promise<Uint8Array | null>;
|
|
16
|
+
/** Returns false when no keychain is available; the CLI then keeps asking. */
|
|
17
|
+
export declare function storeCachedPek(account: string, wrappedRaw: string, pek: Uint8Array, now?: number): Promise<boolean>;
|
|
18
|
+
/** True when an entry was removed. False when there was none or no keychain is available. */
|
|
19
|
+
export declare function clearCachedPek(account: string): Promise<boolean>;
|
|
20
|
+
export {};
|
|
21
|
+
//# sourceMappingURL=keychain.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keychain.d.ts","sourceRoot":"","sources":["../../src/lib/keychain.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,eAAe,QAAqB,CAAC;AAElD,KAAK,YAAY,GAAG;IAClB,WAAW,IAAI,MAAM,GAAG,IAAI,CAAC;IAC7B,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,cAAc,IAAI,OAAO,CAAC;CAC3B,CAAC;AACF,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,YAAY,CAAC;AAMhF,6EAA6E;AAC7E,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI,GAAG,SAAS,GAAG,IAAI,CAEnF;AAYD,yFAAyF;AACzF,wBAAgB,eAAe,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAK7E;AAED,kGAAkG;AAClG,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAQzE;AAgBD,uFAAuF;AACvF,wBAAsB,aAAa,CACjC,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,GAAG,SAAa,GACf,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CA2B5B;AAED,8EAA8E;AAC9E,wBAAsB,cAAc,CAClC,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,GAAG,EAAE,UAAU,EACf,GAAG,SAAa,GACf,OAAO,CAAC,OAAO,CAAC,CAclB;AAED,6FAA6F;AAC7F,wBAAsB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAItE"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
/**
|
|
3
|
+
* The unlocked project key, remembered in the OS keychain (macOS Keychain,
|
|
4
|
+
* Windows Credential Manager, Linux Secret Service) for a few hours so `run`
|
|
5
|
+
* on an open context does not ask for the Vault password every time.
|
|
6
|
+
* Never the Vault password itself.
|
|
7
|
+
*/
|
|
8
|
+
const SERVICE = "getmyenv";
|
|
9
|
+
export const KEYCHAIN_TTL_MS = 8 * 60 * 60 * 1000;
|
|
10
|
+
let factoryOverride;
|
|
11
|
+
/** Tests swap in an in-memory keyring. `null` means no keyring available. */
|
|
12
|
+
export function setKeyringForTests(factory) {
|
|
13
|
+
factoryOverride = factory;
|
|
14
|
+
}
|
|
15
|
+
async function loadFactory() {
|
|
16
|
+
if (factoryOverride !== undefined)
|
|
17
|
+
return factoryOverride;
|
|
18
|
+
try {
|
|
19
|
+
const { Entry } = await import("@napi-rs/keyring");
|
|
20
|
+
return (service, account) => new Entry(service, account);
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/** Off with `GETMYENV_KEYCHAIN=0` or in CI (`CI` set to anything but `false` or `0`). */
|
|
27
|
+
export function keychainEnabled(env = process.env) {
|
|
28
|
+
if (env.GETMYENV_KEYCHAIN === "0")
|
|
29
|
+
return false;
|
|
30
|
+
const ci = env.CI?.trim().toLowerCase();
|
|
31
|
+
if (ci && ci !== "false" && ci !== "0")
|
|
32
|
+
return false;
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
/** One keychain entry per server origin and project, so staging and production keys never mix. */
|
|
36
|
+
export function keychainAccount(apiUrl, projectId) {
|
|
37
|
+
let origin = apiUrl;
|
|
38
|
+
try {
|
|
39
|
+
origin = new URL(apiUrl).origin;
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
/* keep as given */
|
|
43
|
+
}
|
|
44
|
+
return `${origin}|project:${projectId}`;
|
|
45
|
+
}
|
|
46
|
+
function hashWrapped(wrappedRaw) {
|
|
47
|
+
return createHash("sha256").update(wrappedRaw).digest("hex");
|
|
48
|
+
}
|
|
49
|
+
async function entryFor(account) {
|
|
50
|
+
const factory = await loadFactory();
|
|
51
|
+
if (!factory)
|
|
52
|
+
return null;
|
|
53
|
+
try {
|
|
54
|
+
return factory(SERVICE, account);
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/** The cached key, only if it has not expired and matches the server's wrapped key. */
|
|
61
|
+
export async function readCachedPek(account, wrappedRaw, now = Date.now()) {
|
|
62
|
+
const entry = await entryFor(account);
|
|
63
|
+
if (!entry)
|
|
64
|
+
return null;
|
|
65
|
+
let raw;
|
|
66
|
+
try {
|
|
67
|
+
raw = entry.getPassword();
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
if (!raw)
|
|
73
|
+
return null;
|
|
74
|
+
let stored;
|
|
75
|
+
try {
|
|
76
|
+
stored = JSON.parse(raw);
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
safeDelete(entry);
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
if (typeof stored.pek !== "string" ||
|
|
83
|
+
stored.wrappedHash !== hashWrapped(wrappedRaw) ||
|
|
84
|
+
typeof stored.expiresAt !== "number" ||
|
|
85
|
+
stored.expiresAt <= now) {
|
|
86
|
+
safeDelete(entry);
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
return new Uint8Array(Buffer.from(stored.pek, "base64"));
|
|
90
|
+
}
|
|
91
|
+
/** Returns false when no keychain is available; the CLI then keeps asking. */
|
|
92
|
+
export async function storeCachedPek(account, wrappedRaw, pek, now = Date.now()) {
|
|
93
|
+
const entry = await entryFor(account);
|
|
94
|
+
if (!entry)
|
|
95
|
+
return false;
|
|
96
|
+
const stored = {
|
|
97
|
+
pek: Buffer.from(pek).toString("base64"),
|
|
98
|
+
wrappedHash: hashWrapped(wrappedRaw),
|
|
99
|
+
expiresAt: now + KEYCHAIN_TTL_MS,
|
|
100
|
+
};
|
|
101
|
+
try {
|
|
102
|
+
entry.setPassword(JSON.stringify(stored));
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
/** True when an entry was removed. False when there was none or no keychain is available. */
|
|
110
|
+
export async function clearCachedPek(account) {
|
|
111
|
+
const entry = await entryFor(account);
|
|
112
|
+
if (!entry)
|
|
113
|
+
return false;
|
|
114
|
+
return safeDelete(entry);
|
|
115
|
+
}
|
|
116
|
+
function safeDelete(entry) {
|
|
117
|
+
try {
|
|
118
|
+
return entry.deletePassword();
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=keychain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keychain.js","sourceRoot":"","sources":["../../src/lib/keychain.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/pek.d.ts
CHANGED
|
@@ -1,36 +1,27 @@
|
|
|
1
|
-
import type { CliScope } from "./credentials.js";
|
|
2
|
-
export declare function wrappedKeyPath(cwd?: string): string;
|
|
3
|
-
/** Remove cached wrapped PEK for this folder (getmyenv delete). */
|
|
4
|
-
export declare function clearWrappedKey(cwd?: string): boolean;
|
|
5
|
-
/** True when `.getmyenv/wrapped-key.json` exists (development cache). */
|
|
6
|
-
export declare function hasLocalWrappedKey(cwd?: string): boolean;
|
|
7
|
-
/** Write development wrapped-key cache (guest + push). */
|
|
8
|
-
export declare function writeCachedWrappedKey(wrappedRaw: string, cwd?: string): void;
|
|
9
1
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
2
|
+
* `.getmyenv/key.json` (gitignored): the wrapped project key, cached for open
|
|
3
|
+
* contexts. It is useless without the Vault password. Locked reads never
|
|
4
|
+
* read or write it.
|
|
5
|
+
*/
|
|
6
|
+
export declare function keyFilePath(cwd?: string): string;
|
|
7
|
+
export declare function clearCachedKey(cwd?: string): boolean;
|
|
8
|
+
export declare function hasCachedKey(cwd?: string): boolean;
|
|
9
|
+
export declare function writeCachedKey(wrappedRaw: string, cwd?: string): void;
|
|
10
|
+
/**
|
|
11
|
+
* Unwrap the project key.
|
|
12
|
+
* - `wrapped` from the server wins over the cache (it may have been rewrapped).
|
|
13
|
+
* - `cache: true` (open contexts) reads and refreshes key.json.
|
|
14
|
+
* - `allowCreate` makes a new project key when none exists yet.
|
|
13
15
|
*/
|
|
14
16
|
export declare function loadPek(opts: {
|
|
15
17
|
password: string;
|
|
16
|
-
|
|
17
|
-
/** Server or previously known wrapped key (required for production). */
|
|
18
|
+
cache: boolean;
|
|
18
19
|
wrapped?: unknown;
|
|
19
|
-
/** Allow creating a new wrapped key when none exists (push / first upload). */
|
|
20
20
|
allowCreate?: boolean;
|
|
21
21
|
cwd?: string;
|
|
22
22
|
}): Promise<{
|
|
23
23
|
pek: Uint8Array;
|
|
24
24
|
wrappedRaw: string;
|
|
25
|
+
created: boolean;
|
|
25
26
|
}>;
|
|
26
|
-
/**
|
|
27
|
-
* Unwrap a known wrapped key (e.g. from export / grant).
|
|
28
|
-
* Writes development cache only; production never caches.
|
|
29
|
-
*/
|
|
30
|
-
export declare function unwrapPek(opts: {
|
|
31
|
-
password: string;
|
|
32
|
-
scope: CliScope;
|
|
33
|
-
wrapped: unknown;
|
|
34
|
-
cwd?: string;
|
|
35
|
-
}): Promise<Uint8Array>;
|
|
36
27
|
//# sourceMappingURL=pek.d.ts.map
|
package/dist/lib/pek.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pek.d.ts","sourceRoot":"","sources":["../../src/lib/pek.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"pek.d.ts","sourceRoot":"","sources":["../../src/lib/pek.ts"],"names":[],"mappings":"AAUA;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,GAAG,SAAgB,GAAG,MAAM,CAEvD;AAED,wBAAgB,cAAc,CAAC,GAAG,SAAgB,GAAG,OAAO,CAK3D;AAQD,wBAAgB,YAAY,CAAC,GAAG,SAAgB,GAAG,OAAO,CAEzD;AAED,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,SAAgB,GAAG,IAAI,CAI5E;AAOD;;;;;GAKG;AACH,wBAAsB,OAAO,CAAC,IAAI,EAAE;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,GAAG,OAAO,CAAC;IAAE,GAAG,EAAE,UAAU,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC,CAoBrE"}
|
package/dist/lib/pek.js
CHANGED
|
@@ -2,88 +2,64 @@ import fs from "node:fs";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { createWrappedProjectKey, parseWrappedKey, serializeWrappedKey, unwrapProjectKey, } from "@getmyenv/crypto";
|
|
4
4
|
import { getGetenvDir } from "./fs.js";
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
/**
|
|
6
|
+
* `.getmyenv/key.json` (gitignored): the wrapped project key, cached for open
|
|
7
|
+
* contexts. It is useless without the Vault password. Locked reads never
|
|
8
|
+
* read or write it.
|
|
9
|
+
*/
|
|
10
|
+
export function keyFilePath(cwd = process.cwd()) {
|
|
11
|
+
return path.join(getGetenvDir(cwd), "key.json");
|
|
7
12
|
}
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const file = wrappedKeyPath(cwd);
|
|
13
|
+
export function clearCachedKey(cwd = process.cwd()) {
|
|
14
|
+
const file = keyFilePath(cwd);
|
|
11
15
|
if (!fs.existsSync(file))
|
|
12
16
|
return false;
|
|
13
17
|
fs.unlinkSync(file);
|
|
14
18
|
return true;
|
|
15
19
|
}
|
|
16
|
-
function
|
|
17
|
-
const file =
|
|
20
|
+
function readCachedKey(cwd) {
|
|
21
|
+
const file = keyFilePath(cwd);
|
|
18
22
|
if (!fs.existsSync(file))
|
|
19
23
|
return null;
|
|
20
24
|
return fs.readFileSync(file, "utf8");
|
|
21
25
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
return fs.existsSync(wrappedKeyPath(cwd));
|
|
26
|
+
export function hasCachedKey(cwd = process.cwd()) {
|
|
27
|
+
return fs.existsSync(keyFilePath(cwd));
|
|
25
28
|
}
|
|
26
|
-
function
|
|
27
|
-
const file =
|
|
28
|
-
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
29
|
+
export function writeCachedKey(wrappedRaw, cwd = process.cwd()) {
|
|
30
|
+
const file = keyFilePath(cwd);
|
|
31
|
+
fs.mkdirSync(path.dirname(file), { recursive: true, mode: 0o700 });
|
|
29
32
|
fs.writeFileSync(file, wrappedRaw, { mode: 0o600 });
|
|
30
33
|
}
|
|
31
|
-
/** Write development wrapped-key cache (guest + push). */
|
|
32
|
-
export function writeCachedWrappedKey(wrappedRaw, cwd = process.cwd()) {
|
|
33
|
-
writeCachedWrapped(wrappedRaw, cwd);
|
|
34
|
-
}
|
|
35
34
|
function normalizeWrappedRaw(wrapped) {
|
|
36
35
|
if (typeof wrapped === "string")
|
|
37
36
|
return wrapped;
|
|
38
37
|
return JSON.stringify(wrapped);
|
|
39
38
|
}
|
|
40
39
|
/**
|
|
41
|
-
*
|
|
42
|
-
* -
|
|
43
|
-
* -
|
|
40
|
+
* Unwrap the project key.
|
|
41
|
+
* - `wrapped` from the server wins over the cache (it may have been rewrapped).
|
|
42
|
+
* - `cache: true` (open contexts) reads and refreshes key.json.
|
|
43
|
+
* - `allowCreate` makes a new project key when none exists yet.
|
|
44
44
|
*/
|
|
45
45
|
export async function loadPek(opts) {
|
|
46
46
|
const cwd = opts.cwd ?? process.cwd();
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
wrappedRaw = readCachedWrapped(cwd);
|
|
51
|
-
}
|
|
52
|
-
if (!wrappedRaw && opts.wrapped != null) {
|
|
53
|
-
wrappedRaw = normalizeWrappedRaw(opts.wrapped);
|
|
54
|
-
}
|
|
47
|
+
let wrappedRaw = opts.wrapped != null ? normalizeWrappedRaw(opts.wrapped) : null;
|
|
48
|
+
if (!wrappedRaw && opts.cache)
|
|
49
|
+
wrappedRaw = readCachedKey(cwd);
|
|
55
50
|
if (!wrappedRaw) {
|
|
56
51
|
if (!opts.allowCreate) {
|
|
57
|
-
throw new Error(
|
|
58
|
-
? "No project key available. Pull or push once after unlocking with your vault password."
|
|
59
|
-
: "No local wrapped key. Push secrets first, or pass the server key.");
|
|
52
|
+
throw new Error("This project has no key yet. Set a value first: npx getmyenv set KEY");
|
|
60
53
|
}
|
|
61
54
|
const created = await createWrappedProjectKey(opts.password);
|
|
62
55
|
wrappedRaw = serializeWrappedKey(created.wrapped);
|
|
63
|
-
if (
|
|
64
|
-
|
|
65
|
-
}
|
|
66
|
-
return { pek: created.pek, wrappedRaw };
|
|
56
|
+
if (opts.cache)
|
|
57
|
+
writeCachedKey(wrappedRaw, cwd);
|
|
58
|
+
return { pek: created.pek, wrappedRaw, created: true };
|
|
67
59
|
}
|
|
68
60
|
const pek = await unwrapProjectKey(opts.password, parseWrappedKey(wrappedRaw));
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
}
|
|
73
|
-
return { pek, wrappedRaw };
|
|
74
|
-
}
|
|
75
|
-
/**
|
|
76
|
-
* Unwrap a known wrapped key (e.g. from export / grant).
|
|
77
|
-
* Writes development cache only; production never caches.
|
|
78
|
-
*/
|
|
79
|
-
export async function unwrapPek(opts) {
|
|
80
|
-
const { pek } = await loadPek({
|
|
81
|
-
password: opts.password,
|
|
82
|
-
scope: opts.scope,
|
|
83
|
-
wrapped: opts.wrapped,
|
|
84
|
-
allowCreate: false,
|
|
85
|
-
cwd: opts.cwd,
|
|
86
|
-
});
|
|
87
|
-
return pek;
|
|
61
|
+
if (opts.cache)
|
|
62
|
+
writeCachedKey(wrappedRaw, cwd);
|
|
63
|
+
return { pek, wrappedRaw, created: false };
|
|
88
64
|
}
|
|
89
65
|
//# sourceMappingURL=pek.js.map
|
package/dist/lib/pek.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pek.js","sourceRoot":"","sources":["../../src/lib/pek.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EACL,uBAAuB,EACvB,eAAe,EACf,mBAAmB,EACnB,gBAAgB,GACjB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"pek.js","sourceRoot":"","sources":["../../src/lib/pek.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure pieces of `getmyenv run`: validate and merge. Names only in any output.
|
|
3
|
+
*/
|
|
4
|
+
export type MissingKey = {
|
|
5
|
+
name: string;
|
|
6
|
+
reason: "missing" | "expired";
|
|
7
|
+
};
|
|
8
|
+
export type ParentEnv = Record<string, string | undefined>;
|
|
9
|
+
export type Origin = "context" | "context-overrides-parent" | "parent-kept" | "parent-fills-missing" | "missing";
|
|
10
|
+
export type ExplainEntry = {
|
|
11
|
+
name: string;
|
|
12
|
+
origin: Origin;
|
|
13
|
+
reason?: MissingKey["reason"];
|
|
14
|
+
};
|
|
15
|
+
export type MergeResult = {
|
|
16
|
+
env: ParentEnv;
|
|
17
|
+
/** Names set from the context. */
|
|
18
|
+
applied: string[];
|
|
19
|
+
/** Names the context replaced in the parent env. */
|
|
20
|
+
overridden: string[];
|
|
21
|
+
/** Names the parent env kept because of --keep-existing. */
|
|
22
|
+
kept: string[];
|
|
23
|
+
/** Keys missing in the context but present in the parent env. */
|
|
24
|
+
filledByParent: string[];
|
|
25
|
+
/** Keys missing in the context and absent from the parent env. */
|
|
26
|
+
unresolved: MissingKey[];
|
|
27
|
+
entries: ExplainEntry[];
|
|
28
|
+
};
|
|
29
|
+
/** The child never sees the CLI's own settings (token, API URL, config dir). */
|
|
30
|
+
export declare function withoutOwnEnv(parent: ParentEnv): ParentEnv;
|
|
31
|
+
/**
|
|
32
|
+
* Merge context values into the parent env.
|
|
33
|
+
* The context wins unless keepExisting is set. A key missing in the context is
|
|
34
|
+
* satisfied when the parent env already has it (for example from `op run`).
|
|
35
|
+
*/
|
|
36
|
+
export declare function mergeEnv(parent: ParentEnv, values: Record<string, string>, missing: MissingKey[], keepExisting: boolean): MergeResult;
|
|
37
|
+
/** Error text when keys are unresolved and --allow-missing is not set. Null when fine. */
|
|
38
|
+
export declare function validationError(result: Pick<MergeResult, "unresolved">, contextSlug: string, allowMissing: boolean): string | null;
|
|
39
|
+
/**
|
|
40
|
+
* One cmd.exe command line from argv. Windows needs the shell to find `npm.cmd`
|
|
41
|
+
* and friends, and Node does not quote args passed alongside `shell: true`.
|
|
42
|
+
* cmd expands %VAR% even inside quotes, so each % is closed out of the quotes
|
|
43
|
+
* and escaped with ^.
|
|
44
|
+
*/
|
|
45
|
+
export declare function windowsCommandLine(args: string[]): string;
|
|
46
|
+
/** Exit code for a child that ended by signal: 128 + signal number, like a shell. */
|
|
47
|
+
export declare function signalExitCode(signal: NodeJS.Signals, numbers: Record<string, number>): number;
|
|
48
|
+
/** `--explain` output. Names and origins only, never values. */
|
|
49
|
+
export declare function explainLines(result: MergeResult, contextSlug: string): string[];
|
|
50
|
+
//# sourceMappingURL=run-env.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-env.d.ts","sourceRoot":"","sources":["../../src/lib/run-env.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,MAAM,UAAU,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,SAAS,GAAG,SAAS,CAAA;CAAE,CAAC;AAEzE,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;AAE3D,MAAM,MAAM,MAAM,GACd,SAAS,GACT,0BAA0B,GAC1B,aAAa,GACb,sBAAsB,GACtB,SAAS,CAAC;AAEd,MAAM,MAAM,YAAY,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAA;CAAE,CAAC;AAE3F,MAAM,MAAM,WAAW,GAAG;IACxB,GAAG,EAAE,SAAS,CAAC;IACf,kCAAkC;IAClC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,oDAAoD;IACpD,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,4DAA4D;IAC5D,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,iEAAiE;IACjE,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,kEAAkE;IAClE,UAAU,EAAE,UAAU,EAAE,CAAC;IACzB,OAAO,EAAE,YAAY,EAAE,CAAC;CACzB,CAAC;AAEF,gFAAgF;AAChF,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,GAAG,SAAS,CAM1D;AAOD;;;;GAIG;AACH,wBAAgB,QAAQ,CACtB,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,OAAO,EAAE,UAAU,EAAE,EACrB,YAAY,EAAE,OAAO,GACpB,WAAW,CAyCb;AAED,0FAA0F;AAC1F,wBAAgB,eAAe,CAC7B,MAAM,EAAE,IAAI,CAAC,WAAW,EAAE,YAAY,CAAC,EACvC,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,OAAO,GACpB,MAAM,GAAG,IAAI,CAWf;AAWD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,CASzD;AAED,qFAAqF;AACrF,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAG9F;AAED,gEAAgE;AAChE,wBAAgB,YAAY,CAAC,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,EAAE,CAU/E"}
|