envpkt 0.13.0 → 0.13.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +111 -82
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -662,6 +662,17 @@ const formatError = (error) => {
|
|
|
662
662
|
case "AgeNotFound": return `${RED}Error:${RESET} age CLI not found: ${error.message}`;
|
|
663
663
|
case "DecryptFailed": return `${RED}Error:${RESET} Decrypt failed: ${error.message}`;
|
|
664
664
|
case "IdentityNotFound": return `${RED}Error:${RESET} Identity file not found: ${error.path}`;
|
|
665
|
+
case "SealKeyUnavailable": {
|
|
666
|
+
const e = error;
|
|
667
|
+
return [
|
|
668
|
+
`${RED}Error:${RESET} ${e.sealedKeys.length} sealed secret(s) can't be decrypted — no age key found.`,
|
|
669
|
+
`${DIM}Searched (in order):${RESET}`,
|
|
670
|
+
e.searched.map((l) => ` • ${l}`).join("\n"),
|
|
671
|
+
`${DIM}Fix one:${RESET}`,
|
|
672
|
+
` • Restore your key to ~/.envpkt/age-key.txt (or set ENVPKT_AGE_KEY_FILE / ENVPKT_AGE_KEY)`,
|
|
673
|
+
` • Re-provision from source: envpkt seal --edit <KEY>`
|
|
674
|
+
].join("\n");
|
|
675
|
+
}
|
|
665
676
|
case "AuditFailed": return `${RED}Error:${RESET} Audit failed: ${error.message}`;
|
|
666
677
|
case "CatalogNotFound": return `${RED}Error:${RESET} Catalog not found: ${error.path}`;
|
|
667
678
|
case "CatalogLoadError": return `${RED}Error:${RESET} Catalog load error: ${error.message}`;
|
|
@@ -2886,12 +2897,11 @@ const runEnvExport = (options) => {
|
|
|
2886
2897
|
console.error(formatError(err));
|
|
2887
2898
|
process.exit(2);
|
|
2888
2899
|
}, (boot) => {
|
|
2889
|
-
emitWarnings(boot);
|
|
2900
|
+
if (!options.track) emitWarnings(boot);
|
|
2890
2901
|
const scope = loadConfig(boot.configPath).fold(() => "exec", (config) => config.scope ?? "exec");
|
|
2902
|
+
const gateSecrets = options.track === true && scope !== "shell";
|
|
2891
2903
|
const entries = collectEmitEntries(boot);
|
|
2892
|
-
const emit =
|
|
2893
|
-
const withheld = entries.length - emit.length;
|
|
2894
|
-
if (withheld > 0) console.error(`${DIM}${withheld} secret(s) withheld (scope="${scope}") — use \`envpkt exec\` or set top-level scope="shell".${RESET}`);
|
|
2904
|
+
const emit = gateSecrets ? entries.filter((e) => !e.secret) : entries;
|
|
2895
2905
|
emit.forEach(({ name, value }) => {
|
|
2896
2906
|
console.log(options.track ? `_ENVPKT_HAD_${name}=\${${name}+1}; _ENVPKT_PREV_${name}="\${${name}-}"; export ${name}='${shellEscape(value)}'` : `export ${name}='${shellEscape(value)}'`);
|
|
2897
2907
|
});
|
|
@@ -3291,6 +3301,8 @@ const runFleet = (options) => {
|
|
|
3291
3301
|
//#endregion
|
|
3292
3302
|
//#region src/cli/commands/init.ts
|
|
3293
3303
|
const CONFIG_FILENAME = "envpkt.toml";
|
|
3304
|
+
/** Resolve the top-level `scope` to scaffold: explicit --scope wins; --global implies "shell". */
|
|
3305
|
+
const resolveInitScope = (options) => options.scope ?? (options.global ? "shell" : void 0);
|
|
3294
3306
|
const todayIso = () => (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
3295
3307
|
const generateSecretBlock = (key, service) => {
|
|
3296
3308
|
return `[secret.${key}]
|
|
@@ -3315,6 +3327,8 @@ const generateTemplate = (options, fnoxKeys) => {
|
|
|
3315
3327
|
lines.push(`#:schema https://raw.githubusercontent.com/jordanburke/envpkt/main/schemas/envpkt.schema.json`);
|
|
3316
3328
|
lines.push(``);
|
|
3317
3329
|
lines.push(`version = 1`);
|
|
3330
|
+
const scope = resolveInitScope(options);
|
|
3331
|
+
if (scope) lines.push(`scope = "${scope}" # shell = secrets load ambiently on cd/eval; exec = only via envpkt exec`);
|
|
3318
3332
|
lines.push(``);
|
|
3319
3333
|
if (options.catalog) {
|
|
3320
3334
|
lines.push(`catalog = "${options.catalog}"`);
|
|
@@ -3373,6 +3387,10 @@ const formatConfigError = (err) => {
|
|
|
3373
3387
|
};
|
|
3374
3388
|
const runInit = (dir, options) => {
|
|
3375
3389
|
const outPath = join(dir, CONFIG_FILENAME);
|
|
3390
|
+
if (options.scope !== void 0 && options.scope !== "shell" && options.scope !== "exec") {
|
|
3391
|
+
console.error(`${RED}Error:${RESET} --scope must be "shell" or "exec" (got "${options.scope}")`);
|
|
3392
|
+
process.exit(1);
|
|
3393
|
+
}
|
|
3376
3394
|
if (existsSync(outPath) && !options.force) {
|
|
3377
3395
|
console.error(`${RED}Error:${RESET} ${CONFIG_FILENAME} already exists. Use --force to overwrite.`);
|
|
3378
3396
|
process.exit(1);
|
|
@@ -4636,85 +4654,96 @@ const registerSecretCommands = (program) => {
|
|
|
4636
4654
|
};
|
|
4637
4655
|
//#endregion
|
|
4638
4656
|
//#region src/cli/commands/shell-hook.ts
|
|
4639
|
-
const
|
|
4640
|
-
#
|
|
4641
|
-
# prior
|
|
4642
|
-
_envpkt_restore() {
|
|
4643
|
-
[[ -n "$_ENVPKT_INJECTED" ]] || return
|
|
4644
|
-
local k had prev
|
|
4645
|
-
for k in
|
|
4646
|
-
had
|
|
4647
|
-
prev
|
|
4648
|
-
if [[ -n "
|
|
4649
|
-
export "$k
|
|
4650
|
-
else
|
|
4651
|
-
unset "$k"
|
|
4652
|
-
fi
|
|
4653
|
-
unset "$had" "$prev"
|
|
4654
|
-
done
|
|
4655
|
-
unset _ENVPKT_INJECTED
|
|
4656
|
-
}
|
|
4657
|
-
|
|
4658
|
-
_envpkt_chpwd() {
|
|
4659
|
-
local cfg
|
|
4660
|
-
cfg
|
|
4661
|
-
[[ "$cfg" == "$_ENVPKT_DIR" ]] && return
|
|
4662
|
-
_envpkt_restore
|
|
4663
|
-
_ENVPKT_DIR
|
|
4664
|
-
[[ -z "$cfg" ]] && return
|
|
4665
|
-
eval "$(envpkt env export --track
|
|
4666
|
-
envpkt audit --format minimal 2>/dev/null
|
|
4667
|
-
}
|
|
4668
|
-
|
|
4669
|
-
autoload -Uz add-zsh-hook
|
|
4670
|
-
add-zsh-hook chpwd _envpkt_chpwd
|
|
4671
|
-
_envpkt_chpwd
|
|
4672
|
-
|
|
4673
|
-
|
|
4674
|
-
|
|
4675
|
-
#
|
|
4676
|
-
|
|
4677
|
-
|
|
4678
|
-
|
|
4679
|
-
|
|
4680
|
-
|
|
4681
|
-
|
|
4682
|
-
|
|
4683
|
-
|
|
4684
|
-
|
|
4685
|
-
|
|
4686
|
-
|
|
4687
|
-
|
|
4688
|
-
|
|
4689
|
-
|
|
4690
|
-
|
|
4691
|
-
|
|
4692
|
-
|
|
4693
|
-
|
|
4694
|
-
|
|
4695
|
-
|
|
4696
|
-
cfg
|
|
4697
|
-
|
|
4698
|
-
|
|
4699
|
-
|
|
4700
|
-
|
|
4701
|
-
|
|
4702
|
-
envpkt
|
|
4703
|
-
|
|
4704
|
-
|
|
4705
|
-
|
|
4706
|
-
|
|
4707
|
-
|
|
4708
|
-
|
|
4709
|
-
_envpkt_prompt
|
|
4710
|
-
|
|
4711
|
-
|
|
4657
|
+
const zshHook = (audit) => [
|
|
4658
|
+
"# envpkt shell hook — add to ~/.zshrc: eval \"$(envpkt shell-hook zsh)\"",
|
|
4659
|
+
"# Loads the current directory package on cd, restores the prior env on leave, warns on health.",
|
|
4660
|
+
"_envpkt_restore() {",
|
|
4661
|
+
" [[ -n \"$_ENVPKT_INJECTED\" ]] || return",
|
|
4662
|
+
" local k had prev",
|
|
4663
|
+
" for k in ${(s: :)_ENVPKT_INJECTED}; do",
|
|
4664
|
+
" had=\"_ENVPKT_HAD_$k\"",
|
|
4665
|
+
" prev=\"_ENVPKT_PREV_$k\"",
|
|
4666
|
+
" if [[ -n \"${(P)had}\" ]]; then",
|
|
4667
|
+
" export \"$k=${(P)prev}\"",
|
|
4668
|
+
" else",
|
|
4669
|
+
" unset \"$k\"",
|
|
4670
|
+
" fi",
|
|
4671
|
+
" unset \"$had\" \"$prev\"",
|
|
4672
|
+
" done",
|
|
4673
|
+
" unset _ENVPKT_INJECTED",
|
|
4674
|
+
"}",
|
|
4675
|
+
"",
|
|
4676
|
+
"_envpkt_chpwd() {",
|
|
4677
|
+
" local cfg",
|
|
4678
|
+
" cfg=\"$(envpkt config-path 2>/dev/null)\"",
|
|
4679
|
+
" [[ \"$cfg\" == \"$_ENVPKT_DIR\" ]] && return",
|
|
4680
|
+
" _envpkt_restore",
|
|
4681
|
+
" _ENVPKT_DIR=\"$cfg\"",
|
|
4682
|
+
" [[ -z \"$cfg\" ]] && return",
|
|
4683
|
+
" eval \"$(envpkt env export --track)\"",
|
|
4684
|
+
...audit ? [" envpkt audit --format minimal 2>/dev/null"] : [],
|
|
4685
|
+
"}",
|
|
4686
|
+
"",
|
|
4687
|
+
"autoload -Uz add-zsh-hook",
|
|
4688
|
+
"add-zsh-hook chpwd _envpkt_chpwd",
|
|
4689
|
+
"_envpkt_chpwd",
|
|
4690
|
+
""
|
|
4691
|
+
].join("\n");
|
|
4692
|
+
const bashHook = (audit) => [
|
|
4693
|
+
"# envpkt shell hook — add to ~/.bashrc: eval \"$(envpkt shell-hook bash)\"",
|
|
4694
|
+
"# Loads the current directory package on cd, restores the prior env on leave, warns on health.",
|
|
4695
|
+
"_envpkt_restore() {",
|
|
4696
|
+
" [ -n \"$_ENVPKT_INJECTED\" ] || return",
|
|
4697
|
+
" local k had prev",
|
|
4698
|
+
" for k in $_ENVPKT_INJECTED; do",
|
|
4699
|
+
" had=\"_ENVPKT_HAD_$k\"",
|
|
4700
|
+
" prev=\"_ENVPKT_PREV_$k\"",
|
|
4701
|
+
" if [ -n \"${!had}\" ]; then",
|
|
4702
|
+
" export \"$k=${!prev}\"",
|
|
4703
|
+
" else",
|
|
4704
|
+
" unset \"$k\"",
|
|
4705
|
+
" fi",
|
|
4706
|
+
" unset \"$had\" \"$prev\"",
|
|
4707
|
+
" done",
|
|
4708
|
+
" unset _ENVPKT_INJECTED",
|
|
4709
|
+
"}",
|
|
4710
|
+
"",
|
|
4711
|
+
"_envpkt_prompt() {",
|
|
4712
|
+
" [ \"$PWD\" = \"$_ENVPKT_PWD\" ] && return",
|
|
4713
|
+
" _ENVPKT_PWD=\"$PWD\"",
|
|
4714
|
+
" local cfg",
|
|
4715
|
+
" cfg=\"$(envpkt config-path 2>/dev/null)\"",
|
|
4716
|
+
" [ \"$cfg\" = \"$_ENVPKT_DIR\" ] && return",
|
|
4717
|
+
" _envpkt_restore",
|
|
4718
|
+
" _ENVPKT_DIR=\"$cfg\"",
|
|
4719
|
+
" [ -z \"$cfg\" ] && return",
|
|
4720
|
+
" eval \"$(envpkt env export --track)\"",
|
|
4721
|
+
...audit ? [" envpkt audit --format minimal 2>/dev/null"] : [],
|
|
4722
|
+
"}",
|
|
4723
|
+
"",
|
|
4724
|
+
"# Register on PROMPT_COMMAND, handling both the string and (bash 5.1+) array forms.",
|
|
4725
|
+
"if [[ \"$(declare -p PROMPT_COMMAND 2>/dev/null)\" == \"declare -a\"* ]]; then",
|
|
4726
|
+
" case \" ${PROMPT_COMMAND[*]} \" in",
|
|
4727
|
+
" *\" _envpkt_prompt \"*) ;;",
|
|
4728
|
+
" *) PROMPT_COMMAND+=(_envpkt_prompt) ;;",
|
|
4729
|
+
" esac",
|
|
4730
|
+
"else",
|
|
4731
|
+
" case \"$PROMPT_COMMAND\" in",
|
|
4732
|
+
" *_envpkt_prompt*) ;;",
|
|
4733
|
+
" *) PROMPT_COMMAND=\"_envpkt_prompt${PROMPT_COMMAND:+;$PROMPT_COMMAND}\" ;;",
|
|
4734
|
+
" esac",
|
|
4735
|
+
"fi",
|
|
4736
|
+
"_envpkt_prompt",
|
|
4737
|
+
""
|
|
4738
|
+
].join("\n");
|
|
4739
|
+
const runShellHook = (shell, options) => {
|
|
4740
|
+
const audit = options?.audit !== false;
|
|
4712
4741
|
switch (shell) {
|
|
4713
4742
|
case "zsh":
|
|
4714
|
-
console.log(
|
|
4743
|
+
console.log(zshHook(audit));
|
|
4715
4744
|
break;
|
|
4716
4745
|
case "bash":
|
|
4717
|
-
console.log(
|
|
4746
|
+
console.log(bashHook(audit));
|
|
4718
4747
|
break;
|
|
4719
4748
|
default:
|
|
4720
4749
|
console.error(`${RED}Error:${RESET} Unsupported shell: ${shell}. Use "zsh" or "bash".`);
|
|
@@ -5011,7 +5040,7 @@ program.name("envpkt").description("Credential lifecycle and fleet management fo
|
|
|
5011
5040
|
const pkgPath = findPkgJson(dirname(fileURLToPath(import.meta.url)));
|
|
5012
5041
|
return pkgPath ? JSON.parse(readFileSync(pkgPath, "utf-8")).version : "0.0.0";
|
|
5013
5042
|
})());
|
|
5014
|
-
program.command("init").description("Initialize a new envpkt.toml in the current directory").option("--from-fnox [path]", "Scaffold from fnox.toml (optionally specify path)").option("--catalog <path>", "Path to shared secret catalog").option("--identity", "Include [identity] section").option("--name <name>", "Identity name (requires --identity)").option("--capabilities <caps>", "Comma-separated capabilities (requires --identity)").option("--expires <date>", "Credential expiration YYYY-MM-DD (requires --identity)").option("--force", "Overwrite existing envpkt.toml").action((options) => {
|
|
5043
|
+
program.command("init").description("Initialize a new envpkt.toml in the current directory").option("--from-fnox [path]", "Scaffold from fnox.toml (optionally specify path)").option("--catalog <path>", "Path to shared secret catalog").option("--identity", "Include [identity] section").option("--name <name>", "Identity name (requires --identity)").option("--capabilities <caps>", "Comma-separated capabilities (requires --identity)").option("--expires <date>", "Credential expiration YYYY-MM-DD (requires --identity)").option("--scope <scope>", "Top-level scope: \"shell\" (secrets load ambiently) or \"exec\" (only via envpkt exec)").option("--global", "Scaffold a global/ambient package (implies scope = \"shell\")").option("--force", "Overwrite existing envpkt.toml").action((options) => {
|
|
5015
5044
|
runInit(process.cwd(), options);
|
|
5016
5045
|
});
|
|
5017
5046
|
program.command("keygen").description("Generate an age keypair for sealing secrets — run this before `seal` if you don't have a key yet").option("-c, --config <path>", "Path to envpkt.toml (updates identity.recipient if found)").option("-o, --output <path>", "Output path for identity file (default: ~/.envpkt/<project>-key.txt)").option("--global", "Write key to the shared default path (~/.envpkt/age-key.txt) instead of a project-specific one").action((options) => {
|
|
@@ -5052,8 +5081,8 @@ program.command("upgrade").description("Upgrade envpkt to the latest version (np
|
|
|
5052
5081
|
program.command("config-path").description("Print the envpkt.toml path resolved for the current directory (empty if none). Resolve-only — no decryption.").option("-c, --config <path>", "Path to envpkt.toml").action((options) => {
|
|
5053
5082
|
runConfigPath(options);
|
|
5054
5083
|
});
|
|
5055
|
-
program.command("shell-hook").description("Output shell
|
|
5056
|
-
runShellHook(shell);
|
|
5084
|
+
program.command("shell-hook").description("Output a shell hook that loads a project's credentials on cd and restores them on leave").argument("<shell>", "Shell type: zsh | bash").option("--no-audit", "Omit the credential-health audit line from the emitted hook").action((shell, options) => {
|
|
5085
|
+
runShellHook(shell, options);
|
|
5057
5086
|
});
|
|
5058
5087
|
program.parse();
|
|
5059
5088
|
//#endregion
|