@mp-lb/arcnet 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -1
- package/dist/createCli.d.ts.map +1 -1
- package/dist/createCli.js +3 -1
- package/dist/createCli.js.map +1 -1
- package/dist/secrets/createSecretsCommands.d.ts.map +1 -1
- package/dist/secrets/createSecretsCommands.js +9 -2
- package/dist/secrets/createSecretsCommands.js.map +1 -1
- package/dist/secrets/loadSecrets.d.ts +1 -1
- package/dist/secrets/loadSecrets.d.ts.map +1 -1
- package/dist/secrets/loadSecrets.js +25 -7
- package/dist/secrets/loadSecrets.js.map +1 -1
- package/dist/secrets/withDeploymentSecrets.d.ts +1 -1
- package/dist/secrets/withDeploymentSecrets.d.ts.map +1 -1
- package/dist/secrets/withDeploymentSecrets.js +6 -2
- package/dist/secrets/withDeploymentSecrets.js.map +1 -1
- package/docs/public/commands.md +11 -0
- package/docs/public/llms-full.txt +16 -1
- package/package.json +1 -1
- package/src/createCli.ts +12 -1
- package/src/secrets/createSecretsCommands.ts +18 -1
- package/src/secrets/loadSecrets.ts +23 -7
- package/src/secrets/withDeploymentSecrets.ts +7 -1
package/README.md
CHANGED
|
@@ -21,6 +21,8 @@ Zap Arc remains the pinned Terraform engine dependency. Environment bootstrap, h
|
|
|
21
21
|
|
|
22
22
|
`arcnet secrets add` attaches an existing Forum encrypted JSON file. `arcnet secrets init` creates one. Both register a file-specific decryption key in the selected GitHub repository, save an encrypted snapshot, and generate a validation workflow. Setup prompts for your Forum encryption password locally; it never prints the password or recipient key. Use `--existing-key` when the GitHub secret already exists. The local `fm` and `gh` CLIs must be authenticated; the selected Forum parent directory must exist.
|
|
23
23
|
|
|
24
|
+
Use `/projects/<project-slug>/secrets.json.enc` for project files in the company Forum store.
|
|
25
|
+
|
|
24
26
|
The project keeps only `.arcnet/secrets.json`, encrypted snapshots under `.arcnet/secrets/`, and workflow references. Sources merge left to right, with later values winning. Each source names its own key environment variable. JSON must be an object; unused structured values are allowed, while selected environment values must be nonempty strings. Consumer mappings select and rename fields; an array of source names accepts aliases only when their values agree.
|
|
25
27
|
|
|
26
28
|
```json
|
|
@@ -29,7 +31,7 @@ The project keeps only `.arcnet/secrets.json`, encrypted snapshots under `.arcne
|
|
|
29
31
|
"repository": "example/hello-world",
|
|
30
32
|
"sources": [
|
|
31
33
|
{ "name": "standard", "store": "example/company", "path": "/admin/standard.json.enc", "keyEnv": "STANDARD_SECRETS_KEY" },
|
|
32
|
-
{ "name": "project", "store": "example/company", "path": "/
|
|
34
|
+
{ "name": "project", "store": "example/company", "path": "/projects/hello-world/secrets.json.enc", "keyEnv": "PROJECT_SECRETS_KEY" }
|
|
33
35
|
],
|
|
34
36
|
"consumers": {
|
|
35
37
|
"publish": { "NODE_AUTH_TOKEN": ["NPM_TOKEN", "NODE_AUTH_TOKEN"] },
|
|
@@ -44,6 +46,8 @@ For live loading, omit a snapshot or select `--live`: the installed `fm` CLI fet
|
|
|
44
46
|
|
|
45
47
|
`arcnet env check` reports source names and selected key names, never values. `arcnet env export` explicitly emits selected plaintext JSON. `arcnet env run` gives a subprocess only the selected values and a small execution environment; it removes file keys, isolates temporary HOME/cache paths, and withholds subprocess output. Keep npm publishing mappings scoped to publishing credentials. The command reference documents the exact options.
|
|
46
48
|
|
|
49
|
+
For the first local Terraform plan and deploy, GitHub's file keys cannot be read back. Run `arcnet plan --password` or `arcnet deploy --password` in your terminal: ArcNet prompts once for your Forum encryption password and decrypts the reviewed snapshots locally. `arcnet env check --password` validates them the same way. CI still uses the independent file keys and rejects password mode.
|
|
50
|
+
|
|
47
51
|
When `.arcnet/secrets.json` exists, deployment commands automatically load it. The `deploy` consumer selects operator credentials; Terraform application values are selected using the existing service env lists in `zap.yaml`. No duplicated application map is required. Offline project checks remain offline. Secrets commands in GitHub Actions require the configured repository's main branch.
|
|
48
52
|
|
|
49
53
|
Provisioning modifies Forum and GitHub separately. A failed GitHub upload leaves an unused Forum recipient; rerun `secrets add` to create/upload another and remove the unused recipient later. If upload succeeded but snapshot/config writing failed, attach the file with `--existing-key`. Existing sources are not silently rotated on reruns. Provision while nobody else is editing that file: the current fm write interface does not offer atomic revision-conditional writes, though ArcNet checks identity/revision before updating and refuses occupied init paths. GitHub secret names are repository-scoped; environment-level overrides take precedence in jobs that use an environment.
|
package/dist/createCli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createCli.d.ts","sourceRoot":"","sources":["../src/createCli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAcpC,eAAO,MAAM,SAAS,
|
|
1
|
+
{"version":3,"file":"createCli.d.ts","sourceRoot":"","sources":["../src/createCli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAcpC,eAAO,MAAM,SAAS,eA4HrB,CAAC"}
|
package/dist/createCli.js
CHANGED
|
@@ -53,6 +53,8 @@ export const createCli = () => {
|
|
|
53
53
|
create: "Create one explicitly approved Vercel project.",
|
|
54
54
|
})) {
|
|
55
55
|
const command = cli.command(name).description(description);
|
|
56
|
+
if (name === "plan" || name === "deploy")
|
|
57
|
+
command.option("--password", "Prompt for the Forum encryption password locally instead of using file keys");
|
|
56
58
|
if (name === "create")
|
|
57
59
|
command.argument("<site>", "Configured site name");
|
|
58
60
|
command.action(async (site) => {
|
|
@@ -70,7 +72,7 @@ export const createCli = () => {
|
|
|
70
72
|
};
|
|
71
73
|
output(await (name === "check" || (name === "plan" && mode === "vercel")
|
|
72
74
|
? execute()
|
|
73
|
-
: withDeploymentSecrets(root, mode, execute)));
|
|
75
|
+
: withDeploymentSecrets(root, mode, execute, Boolean(command.opts().password), Boolean(cli.opts().noninteractive))));
|
|
74
76
|
});
|
|
75
77
|
}
|
|
76
78
|
cli
|
package/dist/createCli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createCli.js","sourceRoot":"","sources":["../src/createCli.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"createCli.js","sourceRoot":"","sources":["../src/createCli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACrE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAC3E,OAAO,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAE3E,MAAM,CAAC,MAAM,SAAS,GAAG,GAAG,EAAE;IAC5B,MAAM,GAAG,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC;SAC9B,WAAW,CAAC,qCAAqC,CAAC;SAClD,OAAO,CAAC,cAAc,CAAC;SACvB,MAAM,CAAC,oBAAoB,EAAE,qBAAqB,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC;SAClE,MAAM,CAAC,QAAQ,EAAE,wBAAwB,CAAC;SAC1C,MAAM,CAAC,SAAS,EAAE,qCAAqC,CAAC;SACxD,MAAM,CACL,kBAAkB,EAClB,uDAAuD,CACxD,CAAC;IAEJ,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,EAAE;QACzB,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK;YACrC,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG,CAAC,MAAe,EAAE,EAAE;QACjC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC;IAChE,CAAC,CAAC;IAEF,qBAAqB,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IAEnC,GAAG;SACA,OAAO,CAAC,SAAS,CAAC;SAClB,WAAW,CAAC,qCAAqC,CAAC;SAClD,MAAM,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC;IAErD,MAAM,OAAO,GAAG,kBAAkB,EAAE,CAAC;IACrC,OAAO,CAAC,MAAM,CAAC,GAAG,EAAE,CAClB,MAAM,CAAC;QACL,GAAG,KAAK,CACN,OAAO,CAAC,IAAI,CAAC,MAAM,CACjB,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE;YACjC,MAAM,GAAG,GAAG,MAAM,CAAC,aAAa,EAAE,CAAC;YACnC,IAAI,OAAO,CAAC,oBAAoB,CAAC,GAAG,CAAC,KAAK,KAAK;gBAAE,OAAO,EAAE,CAAC;YAC3D,MAAM,KAAK,GAAY,OAAO,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC;YAC3C,OAAO,KAAK,KAAK,IAAI;gBACnB,CAAC,CAAC,CAAC,MAAM,CAAC,IAAK,CAAC;gBAChB,CAAC,CAAC,CAAC,MAAM,CAAC,IAAK,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QACpC,CAAC,CAAC,CACH,EACD,YAAY,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,CAC9B;KACF,CAAC,CACH,CAAC;IAEF,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IAExB,KAAK,MAAM,CAAC,IAAI,EAAE,WAAW,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC;QAC/C,KAAK,EAAE,yCAAyC;QAChD,IAAI,EAAE,8EAA8E;QACpF,MAAM,EAAE,8BAA8B;QACtC,OAAO,EAAE,wCAAwC;QACjD,OAAO,EAAE,mDAAmD;QAC5D,MAAM,EAAE,gDAAgD;KACzD,CAAC,EAAE,CAAC;QACH,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC;QAC3D,IAAI,IAAI,KAAK,MAAM,IAAI,IAAI,KAAK,QAAQ;YACtC,OAAO,CAAC,MAAM,CACZ,YAAY,EACZ,6EAA6E,CAC9E,CAAC;QACJ,IAAI,IAAI,KAAK,QAAQ;YAAE,OAAO,CAAC,QAAQ,CAAC,QAAQ,EAAE,sBAAsB,CAAC,CAAC;QAC1E,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,IAAa,EAAE,EAAE;YACrC,MAAM,IAAI,GAAG,YAAY,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC;YAE3C,MAAM,IAAI,GAAG,CAAC;iBACX,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC;iBACvC,KAAK,CACJ,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,sBAAsB,CAAC,EAAE,MAAM,CAAC,CAAC,CACrE,CAAC,IAAI,CAAC;YAET,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC;YAE7D,MAAM,OAAO,GAAG,KAAK,IAAI,EAAE;gBACzB,IAAI,IAAI,KAAK,QAAQ;oBACnB,OAAO,SAAS,CACd,IAAI,EACJ,IAAI,EACJ,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,EAC3C,OAAO,CACR,CAAC;gBACJ,IAAI,IAAI,KAAK,OAAO,IAAI,IAAI,KAAK,MAAM,IAAI,IAAI,KAAK,QAAQ;oBAC1D,OAAO,YAAY,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;gBAC3C,MAAM,IAAI,KAAK,CACb,GAAG,IAAI,kDAAkD,CAC1D,CAAC;YACJ,CAAC,CAAC;YAEF,MAAM,CACJ,MAAM,CAAC,IAAI,KAAK,OAAO,IAAI,CAAC,IAAI,KAAK,MAAM,IAAI,IAAI,KAAK,QAAQ,CAAC;gBAC/D,CAAC,CAAC,OAAO,EAAE;gBACX,CAAC,CAAC,qBAAqB,CACnB,IAAI,EACJ,IAAI,EACJ,OAAO,EACP,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,EAChC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,cAAc,CAAC,CACnC,CAAC,CACP,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC;IAED,GAAG;SACA,OAAO,CAAC,IAAI,CAAC;SACb,WAAW,CACV,gEAAgE,CACjE;SACA,MAAM,CAAC,GAAG,EAAE;QACX,MAAM,OAAO,GAAG,SAAS,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;QACzD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa;YAC5B,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;QACnE,cAAc,CACZ,OAAO,CAAC,GAAG,CAAC,aAAa,EACzB,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC;aACpB,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,IAAI,KAAK,IAAI,CAAC;aAC1C,IAAI,CAAC,EAAE,CAAC,CACZ,CAAC;QAEF,MAAM,CAAC,OAAO,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;IAEL,OAAO,GAAG,CAAC;AACb,CAAC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createSecretsCommands.d.ts","sourceRoot":"","sources":["../../src/secrets/createSecretsCommands.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"createSecretsCommands.d.ts","sourceRoot":"","sources":["../../src/secrets/createSecretsCommands.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAWpC,eAAO,MAAM,qBAAqB,GAChC,KAAK,OAAO,EACZ,QAAQ,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,SAgMjC,CAAC"}
|
|
@@ -6,6 +6,7 @@ import { runWithSecrets } from "./runWithSecrets.js";
|
|
|
6
6
|
import { selectSecrets } from "./selectSecrets.js";
|
|
7
7
|
import { syncSecrets } from "./syncSecrets.js";
|
|
8
8
|
import { writeSecretsWorkflow } from "./writeSecretsWorkflow.js";
|
|
9
|
+
import { promptPassword } from "./promptPassword.js";
|
|
9
10
|
export const createSecretsCommands = (cli, output) => {
|
|
10
11
|
const env = cli
|
|
11
12
|
.command("env")
|
|
@@ -20,7 +21,8 @@ export const createSecretsCommands = (cli, output) => {
|
|
|
20
21
|
}[action])
|
|
21
22
|
.option("--config <file>", "Secrets source configuration", ".arcnet/secrets.json")
|
|
22
23
|
.option("--consumer <name>", "Named mapping in the secrets configuration")
|
|
23
|
-
.option("--live", "Fetch current ciphertext through the installed fm CLI instead of snapshots")
|
|
24
|
+
.option("--live", "Fetch current ciphertext through the installed fm CLI instead of snapshots")
|
|
25
|
+
.option("--password", "Prompt for the Forum encryption password locally instead of using file keys");
|
|
24
26
|
if (action === "run")
|
|
25
27
|
command.argument("<command...>", "Executable and arguments after --");
|
|
26
28
|
command.action(async (...args) => {
|
|
@@ -31,9 +33,14 @@ export const createSecretsCommands = (cli, output) => {
|
|
|
31
33
|
(process.env.GITHUB_REPOSITORY !== config.repository ||
|
|
32
34
|
process.env.GITHUB_REF !== "refs/heads/main"))
|
|
33
35
|
throw new Error("Secrets commands in CI require the configured repository main branch.");
|
|
36
|
+
if (options.password && process.env.GITHUB_ACTIONS === "true")
|
|
37
|
+
throw new Error("Password decryption is local-only; CI must use file keys.");
|
|
34
38
|
if (action !== "check" && !options.consumer)
|
|
35
39
|
throw new Error("Choose --consumer to explicitly select output keys.");
|
|
36
|
-
const
|
|
40
|
+
const password = options.password
|
|
41
|
+
? await promptPassword(Boolean(cli.opts().noninteractive))
|
|
42
|
+
: undefined;
|
|
43
|
+
const values = await loadSecrets(config, root, process.env, options.live, password);
|
|
37
44
|
const names = options.consumer
|
|
38
45
|
? [options.consumer]
|
|
39
46
|
: Object.keys(config.consumers);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createSecretsCommands.js","sourceRoot":"","sources":["../../src/secrets/createSecretsCommands.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAyB,MAAM,sBAAsB,CAAC;AAC9E,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"createSecretsCommands.js","sourceRoot":"","sources":["../../src/secrets/createSecretsCommands.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { SecretsConfig } from "./config.js";
|
|
2
|
-
export declare const loadSecrets: (config: SecretsConfig, root: string, environment?: NodeJS.ProcessEnv, live?: boolean) => Promise<Record<string, unknown>>;
|
|
2
|
+
export declare const loadSecrets: (config: SecretsConfig, root: string, environment?: NodeJS.ProcessEnv, live?: boolean, password?: string) => Promise<Record<string, unknown>>;
|
|
3
3
|
//# sourceMappingURL=loadSecrets.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loadSecrets.d.ts","sourceRoot":"","sources":["../../src/secrets/loadSecrets.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"loadSecrets.d.ts","sourceRoot":"","sources":["../../src/secrets/loadSecrets.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAIjD,eAAO,MAAM,WAAW,GACtB,QAAQ,aAAa,EACrB,MAAM,MAAM,EACZ,+BAAyB,EACzB,cAAY,EACZ,WAAW,MAAM,qCAqDlB,CAAC"}
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import { decryptForumEncryptedFileText } from "@mp-lb/forum-secrets";
|
|
2
2
|
import { createHash } from "node:crypto";
|
|
3
|
-
import { readFileSync } from "node:fs";
|
|
3
|
+
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import { join } from "node:path";
|
|
4
6
|
import { safeTargetPath } from "../safeTargetPath.js";
|
|
5
7
|
import { readRemoteSource } from "./readRemoteSource.js";
|
|
6
|
-
|
|
8
|
+
import { secretCommand } from "./secretCommand.js";
|
|
9
|
+
export const loadSecrets = async (config, root, environment = process.env, live = false, password) => {
|
|
7
10
|
let values = {};
|
|
8
11
|
for (const source of config.sources) {
|
|
9
12
|
const key = environment[source.keyEnv];
|
|
10
|
-
if (!key)
|
|
13
|
+
if (!key && !password)
|
|
11
14
|
throw new Error(`Missing decryption credential: ${source.keyEnv}.`);
|
|
12
15
|
try {
|
|
13
16
|
const text = !live && source.snapshot
|
|
@@ -18,10 +21,25 @@ export const loadSecrets = async (config, root, environment = process.env, live
|
|
|
18
21
|
createHash("sha256").update(text).digest("hex") !==
|
|
19
22
|
source.snapshot.sha256)
|
|
20
23
|
throw new Error("Snapshot integrity mismatch");
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
let plaintext;
|
|
25
|
+
if (password) {
|
|
26
|
+
const temporary = mkdtempSync(join(tmpdir(), "arcnet-decrypt-"));
|
|
27
|
+
try {
|
|
28
|
+
const file = join(temporary, "source.json.enc");
|
|
29
|
+
writeFileSync(file, text, { mode: 0o600 });
|
|
30
|
+
plaintext = secretCommand("fm", ["decrypt", "--file", file], root, undefined, { ...environment, DOCTRINE_ENCRYPTION_PASSWORD: password });
|
|
31
|
+
}
|
|
32
|
+
finally {
|
|
33
|
+
rmSync(temporary, { recursive: true, force: true });
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
plaintext = await decryptForumEncryptedFileText({
|
|
38
|
+
encryptedText: text,
|
|
39
|
+
recipientSecret: key,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
const decoded = JSON.parse(plaintext);
|
|
25
43
|
if (!decoded || Array.isArray(decoded) || typeof decoded !== "object")
|
|
26
44
|
throw new Error("Not an object");
|
|
27
45
|
values = { ...values, ...decoded };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loadSecrets.js","sourceRoot":"","sources":["../../src/secrets/loadSecrets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,6BAA6B,EAAE,MAAM,sBAAsB,CAAC;AACrE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"loadSecrets.js","sourceRoot":"","sources":["../../src/secrets/loadSecrets.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const withDeploymentSecrets: <T>(root: string, mode: string | undefined, action: () => T | Promise<T
|
|
1
|
+
export declare const withDeploymentSecrets: <T>(root: string, mode: string | undefined, action: () => T | Promise<T>, usePassword?: boolean, noninteractive?: boolean) => Promise<T>;
|
|
2
2
|
//# sourceMappingURL=withDeploymentSecrets.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"withDeploymentSecrets.d.ts","sourceRoot":"","sources":["../../src/secrets/withDeploymentSecrets.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"withDeploymentSecrets.d.ts","sourceRoot":"","sources":["../../src/secrets/withDeploymentSecrets.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,qBAAqB,GAAU,CAAC,EAC3C,MAAM,MAAM,EACZ,MAAM,MAAM,GAAG,SAAS,EACxB,QAAQ,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,EAC5B,qBAAmB,EACnB,wBAAsB,KACrB,OAAO,CAAC,CAAC,CAoEX,CAAC"}
|
|
@@ -4,7 +4,8 @@ import { parse } from "yaml";
|
|
|
4
4
|
import { readSecretsConfig } from "./config.js";
|
|
5
5
|
import { loadSecrets } from "./loadSecrets.js";
|
|
6
6
|
import { selectSecrets } from "./selectSecrets.js";
|
|
7
|
-
|
|
7
|
+
import { promptPassword } from "./promptPassword.js";
|
|
8
|
+
export const withDeploymentSecrets = async (root, mode, action, usePassword = false, noninteractive = false) => {
|
|
8
9
|
if (!existsSync(join(root, ".arcnet/secrets.json")))
|
|
9
10
|
return action();
|
|
10
11
|
const config = readSecretsConfig(root);
|
|
@@ -12,7 +13,10 @@ export const withDeploymentSecrets = async (root, mode, action) => {
|
|
|
12
13
|
(process.env.GITHUB_REPOSITORY !== config.repository ||
|
|
13
14
|
process.env.GITHUB_REF !== "refs/heads/main"))
|
|
14
15
|
throw new Error("Secrets commands in CI require the configured repository main branch.");
|
|
15
|
-
|
|
16
|
+
if (usePassword && process.env.GITHUB_ACTIONS === "true")
|
|
17
|
+
throw new Error("Password decryption is local-only; CI must use file keys.");
|
|
18
|
+
const password = usePassword ? await promptPassword(noninteractive) : undefined;
|
|
19
|
+
const pool = await loadSecrets(config, root, process.env, false, password);
|
|
16
20
|
const selected = selectSecrets(pool, config, "deploy");
|
|
17
21
|
if (mode !== "vercel") {
|
|
18
22
|
const manifest = parse(readFileSync(join(root, "zap.yaml"), "utf8"));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"withDeploymentSecrets.js","sourceRoot":"","sources":["../../src/secrets/withDeploymentSecrets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"withDeploymentSecrets.js","sourceRoot":"","sources":["../../src/secrets/withDeploymentSecrets.ts"],"names":[],"mappings":"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"}
|
package/docs/public/commands.md
CHANGED
|
@@ -25,6 +25,7 @@ Validate decryption and mappings; report key names only.
|
|
|
25
25
|
| `--config <file>` | Secrets source configuration |
|
|
26
26
|
| `--consumer <name>` | Named mapping in the secrets configuration |
|
|
27
27
|
| `--live` | Fetch current ciphertext through the installed fm CLI instead of snapshots |
|
|
28
|
+
| `--password` | Prompt for the Forum encryption password locally instead of using file keys |
|
|
28
29
|
|
|
29
30
|
### `arcnet env export`
|
|
30
31
|
|
|
@@ -35,6 +36,7 @@ Write selected plaintext JSON to stdout for an explicit pipeline.
|
|
|
35
36
|
| `--config <file>` | Secrets source configuration |
|
|
36
37
|
| `--consumer <name>` | Named mapping in the secrets configuration |
|
|
37
38
|
| `--live` | Fetch current ciphertext through the installed fm CLI instead of snapshots |
|
|
39
|
+
| `--password` | Prompt for the Forum encryption password locally instead of using file keys |
|
|
38
40
|
|
|
39
41
|
### `arcnet env run <command...>`
|
|
40
42
|
|
|
@@ -45,6 +47,7 @@ Run a command with selected keys only; withhold child output.
|
|
|
45
47
|
| `--config <file>` | Secrets source configuration |
|
|
46
48
|
| `--consumer <name>` | Named mapping in the secrets configuration |
|
|
47
49
|
| `--live` | Fetch current ciphertext through the installed fm CLI instead of snapshots |
|
|
50
|
+
| `--password` | Prompt for the Forum encryption password locally instead of using file keys |
|
|
48
51
|
|
|
49
52
|
## `arcnet secrets`
|
|
50
53
|
|
|
@@ -111,10 +114,18 @@ Validate project configuration offline.
|
|
|
111
114
|
|
|
112
115
|
Plan deployment (Terraform contacts providers; static Vercel stays offline).
|
|
113
116
|
|
|
117
|
+
| Option | Description |
|
|
118
|
+
| --- | --- |
|
|
119
|
+
| `--password` | Prompt for the Forum encryption password locally instead of using file keys |
|
|
120
|
+
|
|
114
121
|
## `arcnet deploy`
|
|
115
122
|
|
|
116
123
|
Deploy the approved project.
|
|
117
124
|
|
|
125
|
+
| Option | Description |
|
|
126
|
+
| --- | --- |
|
|
127
|
+
| `--password` | Prompt for the Forum encryption password locally instead of using file keys |
|
|
128
|
+
|
|
118
129
|
## `arcnet preview`
|
|
119
130
|
|
|
120
131
|
Deploy static Vercel sites to preview.
|
|
@@ -21,6 +21,8 @@ Zap Arc remains the pinned Terraform engine dependency. Environment bootstrap, h
|
|
|
21
21
|
|
|
22
22
|
`arcnet secrets add` attaches an existing Forum encrypted JSON file. `arcnet secrets init` creates one. Both register a file-specific decryption key in the selected GitHub repository, save an encrypted snapshot, and generate a validation workflow. Setup prompts for your Forum encryption password locally; it never prints the password or recipient key. Use `--existing-key` when the GitHub secret already exists. The local `fm` and `gh` CLIs must be authenticated; the selected Forum parent directory must exist.
|
|
23
23
|
|
|
24
|
+
Use `/projects/<project-slug>/secrets.json.enc` for project files in the company Forum store.
|
|
25
|
+
|
|
24
26
|
The project keeps only `.arcnet/secrets.json`, encrypted snapshots under `.arcnet/secrets/`, and workflow references. Sources merge left to right, with later values winning. Each source names its own key environment variable. JSON must be an object; unused structured values are allowed, while selected environment values must be nonempty strings. Consumer mappings select and rename fields; an array of source names accepts aliases only when their values agree.
|
|
25
27
|
|
|
26
28
|
```json
|
|
@@ -29,7 +31,7 @@ The project keeps only `.arcnet/secrets.json`, encrypted snapshots under `.arcne
|
|
|
29
31
|
"repository": "example/hello-world",
|
|
30
32
|
"sources": [
|
|
31
33
|
{ "name": "standard", "store": "example/company", "path": "/admin/standard.json.enc", "keyEnv": "STANDARD_SECRETS_KEY" },
|
|
32
|
-
{ "name": "project", "store": "example/company", "path": "/
|
|
34
|
+
{ "name": "project", "store": "example/company", "path": "/projects/hello-world/secrets.json.enc", "keyEnv": "PROJECT_SECRETS_KEY" }
|
|
33
35
|
],
|
|
34
36
|
"consumers": {
|
|
35
37
|
"publish": { "NODE_AUTH_TOKEN": ["NPM_TOKEN", "NODE_AUTH_TOKEN"] },
|
|
@@ -44,6 +46,8 @@ For live loading, omit a snapshot or select `--live`: the installed `fm` CLI fet
|
|
|
44
46
|
|
|
45
47
|
`arcnet env check` reports source names and selected key names, never values. `arcnet env export` explicitly emits selected plaintext JSON. `arcnet env run` gives a subprocess only the selected values and a small execution environment; it removes file keys, isolates temporary HOME/cache paths, and withholds subprocess output. Keep npm publishing mappings scoped to publishing credentials. The command reference documents the exact options.
|
|
46
48
|
|
|
49
|
+
For the first local Terraform plan and deploy, GitHub's file keys cannot be read back. Run `arcnet plan --password` or `arcnet deploy --password` in your terminal: ArcNet prompts once for your Forum encryption password and decrypts the reviewed snapshots locally. `arcnet env check --password` validates them the same way. CI still uses the independent file keys and rejects password mode.
|
|
50
|
+
|
|
47
51
|
When `.arcnet/secrets.json` exists, deployment commands automatically load it. The `deploy` consumer selects operator credentials; Terraform application values are selected using the existing service env lists in `zap.yaml`. No duplicated application map is required. Offline project checks remain offline. Secrets commands in GitHub Actions require the configured repository's main branch.
|
|
48
52
|
|
|
49
53
|
Provisioning modifies Forum and GitHub separately. A failed GitHub upload leaves an unused Forum recipient; rerun `secrets add` to create/upload another and remove the unused recipient later. If upload succeeded but snapshot/config writing failed, attach the file with `--existing-key`. Existing sources are not silently rotated on reruns. Provision while nobody else is editing that file: the current fm write interface does not offer atomic revision-conditional writes, though ArcNet checks identity/revision before updating and refuses occupied init paths. GitHub secret names are repository-scoped; environment-level overrides take precedence in jobs that use an environment.
|
|
@@ -75,6 +79,7 @@ Validate decryption and mappings; report key names only.
|
|
|
75
79
|
| `--config <file>` | Secrets source configuration |
|
|
76
80
|
| `--consumer <name>` | Named mapping in the secrets configuration |
|
|
77
81
|
| `--live` | Fetch current ciphertext through the installed fm CLI instead of snapshots |
|
|
82
|
+
| `--password` | Prompt for the Forum encryption password locally instead of using file keys |
|
|
78
83
|
|
|
79
84
|
### `arcnet env export`
|
|
80
85
|
|
|
@@ -85,6 +90,7 @@ Write selected plaintext JSON to stdout for an explicit pipeline.
|
|
|
85
90
|
| `--config <file>` | Secrets source configuration |
|
|
86
91
|
| `--consumer <name>` | Named mapping in the secrets configuration |
|
|
87
92
|
| `--live` | Fetch current ciphertext through the installed fm CLI instead of snapshots |
|
|
93
|
+
| `--password` | Prompt for the Forum encryption password locally instead of using file keys |
|
|
88
94
|
|
|
89
95
|
### `arcnet env run <command...>`
|
|
90
96
|
|
|
@@ -95,6 +101,7 @@ Run a command with selected keys only; withhold child output.
|
|
|
95
101
|
| `--config <file>` | Secrets source configuration |
|
|
96
102
|
| `--consumer <name>` | Named mapping in the secrets configuration |
|
|
97
103
|
| `--live` | Fetch current ciphertext through the installed fm CLI instead of snapshots |
|
|
104
|
+
| `--password` | Prompt for the Forum encryption password locally instead of using file keys |
|
|
98
105
|
|
|
99
106
|
## `arcnet secrets`
|
|
100
107
|
|
|
@@ -161,10 +168,18 @@ Validate project configuration offline.
|
|
|
161
168
|
|
|
162
169
|
Plan deployment (Terraform contacts providers; static Vercel stays offline).
|
|
163
170
|
|
|
171
|
+
| Option | Description |
|
|
172
|
+
| --- | --- |
|
|
173
|
+
| `--password` | Prompt for the Forum encryption password locally instead of using file keys |
|
|
174
|
+
|
|
164
175
|
## `arcnet deploy`
|
|
165
176
|
|
|
166
177
|
Deploy the approved project.
|
|
167
178
|
|
|
179
|
+
| Option | Description |
|
|
180
|
+
| --- | --- |
|
|
181
|
+
| `--password` | Prompt for the Forum encryption password locally instead of using file keys |
|
|
182
|
+
|
|
168
183
|
## `arcnet preview`
|
|
169
184
|
|
|
170
185
|
Deploy static Vercel sites to preview.
|
package/package.json
CHANGED
package/src/createCli.ts
CHANGED
|
@@ -70,6 +70,11 @@ export const createCli = () => {
|
|
|
70
70
|
create: "Create one explicitly approved Vercel project.",
|
|
71
71
|
})) {
|
|
72
72
|
const command = cli.command(name).description(description);
|
|
73
|
+
if (name === "plan" || name === "deploy")
|
|
74
|
+
command.option(
|
|
75
|
+
"--password",
|
|
76
|
+
"Prompt for the Forum encryption password locally instead of using file keys",
|
|
77
|
+
);
|
|
73
78
|
if (name === "create") command.argument("<site>", "Configured site name");
|
|
74
79
|
command.action(async (site: unknown) => {
|
|
75
80
|
const root = realpathSync(cli.opts().root);
|
|
@@ -100,7 +105,13 @@ export const createCli = () => {
|
|
|
100
105
|
output(
|
|
101
106
|
await (name === "check" || (name === "plan" && mode === "vercel")
|
|
102
107
|
? execute()
|
|
103
|
-
: withDeploymentSecrets(
|
|
108
|
+
: withDeploymentSecrets(
|
|
109
|
+
root,
|
|
110
|
+
mode,
|
|
111
|
+
execute,
|
|
112
|
+
Boolean(command.opts().password),
|
|
113
|
+
Boolean(cli.opts().noninteractive),
|
|
114
|
+
)),
|
|
104
115
|
);
|
|
105
116
|
});
|
|
106
117
|
}
|
|
@@ -7,6 +7,7 @@ import { runWithSecrets } from "./runWithSecrets.js";
|
|
|
7
7
|
import { selectSecrets } from "./selectSecrets.js";
|
|
8
8
|
import { syncSecrets } from "./syncSecrets.js";
|
|
9
9
|
import { writeSecretsWorkflow } from "./writeSecretsWorkflow.js";
|
|
10
|
+
import { promptPassword } from "./promptPassword.js";
|
|
10
11
|
|
|
11
12
|
export const createSecretsCommands = (
|
|
12
13
|
cli: Command,
|
|
@@ -38,6 +39,10 @@ export const createSecretsCommands = (
|
|
|
38
39
|
.option(
|
|
39
40
|
"--live",
|
|
40
41
|
"Fetch current ciphertext through the installed fm CLI instead of snapshots",
|
|
42
|
+
)
|
|
43
|
+
.option(
|
|
44
|
+
"--password",
|
|
45
|
+
"Prompt for the Forum encryption password locally instead of using file keys",
|
|
41
46
|
);
|
|
42
47
|
|
|
43
48
|
if (action === "run")
|
|
@@ -47,6 +52,7 @@ export const createSecretsCommands = (
|
|
|
47
52
|
config: string;
|
|
48
53
|
consumer?: string;
|
|
49
54
|
live?: boolean;
|
|
55
|
+
password?: boolean;
|
|
50
56
|
}>();
|
|
51
57
|
|
|
52
58
|
const root = realpathSync(cli.opts().root);
|
|
@@ -59,9 +65,20 @@ export const createSecretsCommands = (
|
|
|
59
65
|
throw new Error(
|
|
60
66
|
"Secrets commands in CI require the configured repository main branch.",
|
|
61
67
|
);
|
|
68
|
+
if (options.password && process.env.GITHUB_ACTIONS === "true")
|
|
69
|
+
throw new Error("Password decryption is local-only; CI must use file keys.");
|
|
62
70
|
if (action !== "check" && !options.consumer)
|
|
63
71
|
throw new Error("Choose --consumer to explicitly select output keys.");
|
|
64
|
-
const
|
|
72
|
+
const password = options.password
|
|
73
|
+
? await promptPassword(Boolean(cli.opts().noninteractive))
|
|
74
|
+
: undefined;
|
|
75
|
+
const values = await loadSecrets(
|
|
76
|
+
config,
|
|
77
|
+
root,
|
|
78
|
+
process.env,
|
|
79
|
+
options.live,
|
|
80
|
+
password,
|
|
81
|
+
);
|
|
65
82
|
|
|
66
83
|
const names = options.consumer
|
|
67
84
|
? [options.consumer]
|
|
@@ -1,21 +1,25 @@
|
|
|
1
1
|
import { decryptForumEncryptedFileText } from "@mp-lb/forum-secrets";
|
|
2
2
|
import { createHash } from "node:crypto";
|
|
3
|
-
import { readFileSync } from "node:fs";
|
|
3
|
+
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import { join } from "node:path";
|
|
4
6
|
import { safeTargetPath } from "../safeTargetPath.js";
|
|
5
7
|
import type { SecretsConfig } from "./config.js";
|
|
6
8
|
import { readRemoteSource } from "./readRemoteSource.js";
|
|
9
|
+
import { secretCommand } from "./secretCommand.js";
|
|
7
10
|
|
|
8
11
|
export const loadSecrets = async (
|
|
9
12
|
config: SecretsConfig,
|
|
10
13
|
root: string,
|
|
11
14
|
environment = process.env,
|
|
12
15
|
live = false,
|
|
16
|
+
password?: string,
|
|
13
17
|
) => {
|
|
14
18
|
let values: Record<string, unknown> = {};
|
|
15
19
|
|
|
16
20
|
for (const source of config.sources) {
|
|
17
21
|
const key = environment[source.keyEnv];
|
|
18
|
-
if (!key)
|
|
22
|
+
if (!key && !password)
|
|
19
23
|
throw new Error(`Missing decryption credential: ${source.keyEnv}.`);
|
|
20
24
|
|
|
21
25
|
try {
|
|
@@ -32,12 +36,24 @@ export const loadSecrets = async (
|
|
|
32
36
|
)
|
|
33
37
|
throw new Error("Snapshot integrity mismatch");
|
|
34
38
|
|
|
35
|
-
|
|
36
|
-
|
|
39
|
+
let plaintext: string;
|
|
40
|
+
if (password) {
|
|
41
|
+
const temporary = mkdtempSync(join(tmpdir(), "arcnet-decrypt-"));
|
|
42
|
+
try {
|
|
43
|
+
const file = join(temporary, "source.json.enc");
|
|
44
|
+
writeFileSync(file, text, { mode: 0o600 });
|
|
45
|
+
plaintext = secretCommand("fm", ["decrypt", "--file", file], root,
|
|
46
|
+
undefined, { ...environment, DOCTRINE_ENCRYPTION_PASSWORD: password });
|
|
47
|
+
} finally {
|
|
48
|
+
rmSync(temporary, { recursive: true, force: true });
|
|
49
|
+
}
|
|
50
|
+
} else {
|
|
51
|
+
plaintext = await decryptForumEncryptedFileText({
|
|
37
52
|
encryptedText: text,
|
|
38
|
-
recipientSecret: key
|
|
39
|
-
})
|
|
40
|
-
|
|
53
|
+
recipientSecret: key!,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
const decoded: unknown = JSON.parse(plaintext);
|
|
41
57
|
|
|
42
58
|
if (!decoded || Array.isArray(decoded) || typeof decoded !== "object")
|
|
43
59
|
throw new Error("Not an object");
|
|
@@ -4,11 +4,14 @@ import { parse } from "yaml";
|
|
|
4
4
|
import { readSecretsConfig } from "./config.js";
|
|
5
5
|
import { loadSecrets } from "./loadSecrets.js";
|
|
6
6
|
import { selectSecrets } from "./selectSecrets.js";
|
|
7
|
+
import { promptPassword } from "./promptPassword.js";
|
|
7
8
|
|
|
8
9
|
export const withDeploymentSecrets = async <T>(
|
|
9
10
|
root: string,
|
|
10
11
|
mode: string | undefined,
|
|
11
12
|
action: () => T | Promise<T>,
|
|
13
|
+
usePassword = false,
|
|
14
|
+
noninteractive = false,
|
|
12
15
|
): Promise<T> => {
|
|
13
16
|
if (!existsSync(join(root, ".arcnet/secrets.json"))) return action();
|
|
14
17
|
const config = readSecretsConfig(root);
|
|
@@ -20,7 +23,10 @@ export const withDeploymentSecrets = async <T>(
|
|
|
20
23
|
throw new Error(
|
|
21
24
|
"Secrets commands in CI require the configured repository main branch.",
|
|
22
25
|
);
|
|
23
|
-
|
|
26
|
+
if (usePassword && process.env.GITHUB_ACTIONS === "true")
|
|
27
|
+
throw new Error("Password decryption is local-only; CI must use file keys.");
|
|
28
|
+
const password = usePassword ? await promptPassword(noninteractive) : undefined;
|
|
29
|
+
const pool = await loadSecrets(config, root, process.env, false, password);
|
|
24
30
|
const selected = selectSecrets(pool, config, "deploy");
|
|
25
31
|
|
|
26
32
|
if (mode !== "vercel") {
|