@seekrit/cli 1.7.1 → 1.9.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.
Files changed (2) hide show
  1. package/dist/index.js +203 -26
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -2560,7 +2560,9 @@ const SYNC_PROVIDER_KINDS = [
2560
2560
  "gcp-secret-manager",
2561
2561
  "langgraph-platform",
2562
2562
  "azure-key-vault",
2563
- "huggingface-spaces"
2563
+ "huggingface-spaces",
2564
+ "openai-vault",
2565
+ "claude-managed-agents"
2564
2566
  ];
2565
2567
  z.enum(SYNC_PROVIDER_KINDS);
2566
2568
  /**
@@ -2964,6 +2966,25 @@ const azureKeyVaultConnectionConfigSchema = z.object({
2964
2966
  * would invite pointing a connection at a host that silently swallows secrets.
2965
2967
  */
2966
2968
  const huggingfaceSpacesConnectionConfigSchema = z.object({ provider: z.literal("huggingface-spaces") });
2969
+ /** The wrapped credential is an OpenAI project API key with vault read/write access. */
2970
+ const openaiVaultConnectionConfigSchema = z.object({ provider: z.literal("openai-vault") });
2971
+ /**
2972
+ * Claude Managed Agents account scope — empty, for Hugging Face's reason.
2973
+ *
2974
+ * An Anthropic API key belongs to exactly one **workspace**, and vaults are
2975
+ * workspace-scoped: the key can reach every vault in its workspace and none
2976
+ * outside it. A vault ID is globally unique. So the key plus the destination is
2977
+ * the whole address, and the API's `anthropic-workspace-id` header — which
2978
+ * exists for credentials that span several workspaces — has nothing to select.
2979
+ *
2980
+ * There is no `baseUrl`, and adding one would not be enough. Bedrock, Vertex
2981
+ * AI, and Foundry do not offer Managed Agents at all. Claude Platform on AWS
2982
+ * does, at `aws-external-anthropic.{region}.api.aws` — but it authenticates
2983
+ * with SigV4 over an IAM credential, not an API key, so it is a different
2984
+ * credential shape and a different connector (one that would reuse
2985
+ * `lib/leases/aws-sigv4.ts`), not a different host for this one.
2986
+ */
2987
+ const claudeManagedAgentsConnectionConfigSchema = z.object({ provider: z.literal("claude-managed-agents") });
2967
2988
  const syncConnectionConfigSchema = z.discriminatedUnion("provider", [
2968
2989
  vercelConnectionConfigSchema,
2969
2990
  cloudflareWorkersConnectionConfigSchema,
@@ -2983,7 +3004,9 @@ const syncConnectionConfigSchema = z.discriminatedUnion("provider", [
2983
3004
  gcpSecretManagerConnectionConfigSchema,
2984
3005
  langgraphPlatformConnectionConfigSchema,
2985
3006
  azureKeyVaultConnectionConfigSchema,
2986
- huggingfaceSpacesConnectionConfigSchema
3007
+ huggingfaceSpacesConnectionConfigSchema,
3008
+ openaiVaultConnectionConfigSchema,
3009
+ claudeManagedAgentsConnectionConfigSchema
2987
3010
  ]);
2988
3011
  /** Vercel's three deployment targets. A binding writes to one or more. */
2989
3012
  const VERCEL_TARGETS = [
@@ -3808,6 +3831,91 @@ const huggingfaceSpacesDestinationSchema = z.object({
3808
3831
  /** Space ID as `owner/name`, e.g. `acme/support-demo`. */
3809
3832
  repoId: huggingfaceRepoIdSchema
3810
3833
  });
3834
+ /** One existing OpenAI vault; every credential in this binding gets the same host boundary. */
3835
+ const openaiVaultDestinationSchema = z.object({
3836
+ provider: z.literal("openai-vault"),
3837
+ vaultId: z.string().trim().regex(/^vault_[A-Za-z0-9_-]+$/, "must be an OpenAI vault ID"),
3838
+ allowedHosts: z.array(z.string().trim().toLowerCase().max(253).regex(/^(?=.{1,253}$)[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)+$/, "must be an exact hostname without scheme, port, path, or wildcard")).min(1).max(100).refine((hosts) => new Set(hosts).size === hosts.length, "hostnames must be unique")
3839
+ });
3840
+ /**
3841
+ * A vault ID as the Claude Console and API show it: `vlt_` and an opaque
3842
+ * alphanumeric tail. Held to that shape because the habitual slip — pasting the
3843
+ * vault's display name — is a 404 from inside an alarm, which says nothing
3844
+ * about which half of the address was wrong.
3845
+ */
3846
+ const claudeVaultIdSchema = z.string().trim().regex(/^vlt_[A-Za-z0-9]{1,128}$/, "must be a vault ID, e.g. vlt_01ABC… — not its display name");
3847
+ /** Ceiling on per-name host rules; a vault itself holds at most 20 credentials. */
3848
+ const CLAUDE_VAULT_MAX_HOST_RULES = 100;
3849
+ /** A hostname of two or more labels whose last label starts with a letter. */
3850
+ const CLAUDE_VAULT_HOSTNAME = /^(?:\*\.)?(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z](?:[a-z0-9-]{0,61}[a-z0-9])?$/;
3851
+ const CLAUDE_VAULT_IPV4 = /^(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}$/;
3852
+ /**
3853
+ * One host a secret's value may be substituted on, in the three forms the vault
3854
+ * API takes: a bare hostname (`api.openai.com`), a `*.`-prefixed wildcard
3855
+ * (`*.stripe.com`), or an IPv4 address.
3856
+ *
3857
+ * The API refuses URLs, ports, paths, and IPv6, so those are refused here too —
3858
+ * pasting `https://api.openai.com/v1` is the slip this exists for. Note the
3859
+ * wildcard's documented reach: `*.stripe.com` matches every subdomain of
3860
+ * `stripe.com` **but not `stripe.com` itself**, so a service reached at its apex
3861
+ * needs both entries. A bare TLD wildcard (`*.com`) is refused by shape.
3862
+ */
3863
+ const claudeVaultHostSchema = z.string().trim().toLowerCase().max(253).refine((host) => CLAUDE_VAULT_HOSTNAME.test(host) || CLAUDE_VAULT_IPV4.test(host), "must be a bare hostname (api.example.com), a *.example.com wildcard, or an IPv4 address — not a URL");
3864
+ /**
3865
+ * Where one secret's value may be substituted: a list of hosts, or the literal
3866
+ * `"unrestricted"`, which lets it reach any host the agent's *environment*
3867
+ * permits. The literal is spelled out rather than implied by an empty list, so
3868
+ * the widest setting is never something a binding arrives at by omission.
3869
+ */
3870
+ const claudeVaultHostRuleSchema = z.union([z.literal("unrestricted"), z.array(claudeVaultHostSchema).min(1).max(16)]);
3871
+ /**
3872
+ * Which parts of an outbound request a secret's placeholder is swapped in. The
3873
+ * API's own default when the field is omitted is both; seekrit's is `header`,
3874
+ * the narrower one — request bodies are often assembled from content the agent
3875
+ * is working with, and most services read an API key from a header. It is also
3876
+ * what the Claude Console creates by default, so the two agree.
3877
+ */
3878
+ const CLAUDE_VAULT_INJECTION_LOCATIONS = [
3879
+ "header",
3880
+ "body",
3881
+ "both"
3882
+ ];
3883
+ /**
3884
+ * One **Claude Managed Agents vault**, whose `environment_variable` credentials
3885
+ * a binding owns.
3886
+ *
3887
+ * Like `openai-vault`, a destination where the workload never holds the
3888
+ * plaintext either: an agent's sandbox sees an opaque placeholder in the
3889
+ * variable, and Anthropic's egress proxy swaps the real value in only on a
3890
+ * request to a host the credential names. So every name needs somewhere it is
3891
+ * allowed to go, and that is most of this shape:
3892
+ *
3893
+ * - `allowedHostsByName` — per destination name, after `nameTransform`. The
3894
+ * right tool: a Stripe key belongs on `api.stripe.com` and nowhere else.
3895
+ * - `allowedHosts` — for every name without its own rule.
3896
+ *
3897
+ * At least one must be given. A pushed name covered by neither **fails** rather
3898
+ * than going out `unrestricted` — the default-deny stance `apps/proxy` takes, so
3899
+ * a secret added to the environment later cannot silently widen where values
3900
+ * flow. Both levels apply beside the agent environment's own network policy,
3901
+ * which must also let the host through; this shape cannot see that policy.
3902
+ */
3903
+ const claudeManagedAgentsDestinationSchema = z.object({
3904
+ provider: z.literal("claude-managed-agents"),
3905
+ /** The vault's ID, e.g. `vlt_01ABC…`. */
3906
+ vaultId: claudeVaultIdSchema,
3907
+ /** Hosts for every name without its own entry in `allowedHostsByName`. */
3908
+ allowedHosts: claudeVaultHostRuleSchema.optional(),
3909
+ /** Destination name → the hosts that one value may be substituted on. */
3910
+ allowedHostsByName: z.record(secretNameSchema, claudeVaultHostRuleSchema).optional(),
3911
+ injectionLocation: z.enum(CLAUDE_VAULT_INJECTION_LOCATIONS).default("header")
3912
+ }).refine((d) => d.allowedHosts !== void 0 || Object.keys(d.allowedHostsByName ?? {}).length > 0, {
3913
+ message: "name the hosts each secret may be used on — allowedHosts for all of them, allowedHostsByName per name, or \"unrestricted\"",
3914
+ path: ["allowedHosts"]
3915
+ }).refine((d) => Object.keys(d.allowedHostsByName ?? {}).length <= CLAUDE_VAULT_MAX_HOST_RULES, {
3916
+ message: `at most ${CLAUDE_VAULT_MAX_HOST_RULES} per-name host rules`,
3917
+ path: ["allowedHostsByName"]
3918
+ });
3811
3919
  const syncDestinationSchema = z.discriminatedUnion("provider", [
3812
3920
  vercelDestinationSchema,
3813
3921
  cloudflareWorkersDestinationSchema,
@@ -3827,7 +3935,9 @@ const syncDestinationSchema = z.discriminatedUnion("provider", [
3827
3935
  gcpSecretManagerDestinationSchema,
3828
3936
  langgraphPlatformDestinationSchema,
3829
3937
  azureKeyVaultDestinationSchema,
3830
- huggingfaceSpacesDestinationSchema
3938
+ huggingfaceSpacesDestinationSchema,
3939
+ openaiVaultDestinationSchema,
3940
+ claudeManagedAgentsDestinationSchema
3831
3941
  ]);
3832
3942
  /**
3833
3943
  * How seekrit secret names become destination key names. Applied in order:
@@ -5115,7 +5225,7 @@ async function createAgentTaskToken() {
5115
5225
  }
5116
5226
  //#endregion
5117
5227
  //#region package.json
5118
- var version = "1.7.1";
5228
+ var version = "1.9.0";
5119
5229
  //#endregion
5120
5230
  //#region ../../packages/api-client/src/index.ts
5121
5231
  /**
@@ -7679,7 +7789,7 @@ async function syncGrantsForGroupLink(ctx, orgId, envId, envSlug, groupId) {
7679
7789
  //#endregion
7680
7790
  //#region src/kms.ts
7681
7791
  /** Collect a repeatable option into a list. */
7682
- function collect$8(value, acc = []) {
7792
+ function collect$9(value, acc = []) {
7683
7793
  acc.push(value);
7684
7794
  return acc;
7685
7795
  }
@@ -7747,7 +7857,7 @@ async function kmsRecoverMaterial(ctx, orgId, keyId, version) {
7747
7857
  }
7748
7858
  function registerKmsCommands(program) {
7749
7859
  const kms = program.command("kms").description("managed keys for application-layer encryption & signing (client-side)");
7750
- kms.command("create").description("create a managed key (material is generated locally and wrapped, never sent)").requiredOption("--name <name>", "org-unique key name").requiredOption("--purpose <purpose>", "encrypt | sign").option("--org <slug>", "organization slug (defaults to seekrit.json, or your only org)").option("--app <slug>", "scope the key to an application").option("--group <slug>", "scope the key to a group").option("--grant-user <email>", "also grant an org member (repeatable)", collect$8, []).option("--grant-token <tokenId>", "also grant a service token (repeatable)", collect$8, []).action(async (options) => {
7860
+ kms.command("create").description("create a managed key (material is generated locally and wrapped, never sent)").requiredOption("--name <name>", "org-unique key name").requiredOption("--purpose <purpose>", "encrypt | sign").option("--org <slug>", "organization slug (defaults to seekrit.json, or your only org)").option("--app <slug>", "scope the key to an application").option("--group <slug>", "scope the key to a group").option("--grant-user <email>", "also grant an org member (repeatable)", collect$9, []).option("--grant-token <tokenId>", "also grant a service token (repeatable)", collect$9, []).action(async (options) => {
7751
7861
  if (options.purpose !== "encrypt" && options.purpose !== "sign") fail("--purpose must be encrypt or sign");
7752
7862
  if (options.app && options.group) fail("pass at most one of --app or --group");
7753
7863
  const ctx = buildContext();
@@ -7969,7 +8079,7 @@ function registerKmsCommands(program) {
7969
8079
  //#endregion
7970
8080
  //#region src/recovery.ts
7971
8081
  /** Collect a repeatable option into a list. */
7972
- function collect$7(value, acc = []) {
8082
+ function collect$8(value, acc = []) {
7973
8083
  acc.push(value);
7974
8084
  return acc;
7975
8085
  }
@@ -8066,7 +8176,7 @@ function registerRecoveryCommands(program) {
8066
8176
  for (const cst of status.custodians) console.log(` - ${cst.label ?? cst.principalId} (${cst.principalType}, share #${cst.shareIndex})`);
8067
8177
  if (status.coverage.unprotectedEnvIds.length > 0) console.log(`${status.coverage.unprotectedEnvIds.length} environment(s) not yet protected — run \`seekrit recovery sync\``);
8068
8178
  });
8069
- recovery.command("setup").description("enable recovery: split a fresh recovery key across custodians").requiredOption("--threshold <M>", "custodians required to recover (M in M-of-N)").option("--custodian <email|skt_id>", "a recovery custodian (repeatable)", collect$7, []).option("--org <slug>", "organization slug (defaults to seekrit.json, or your only org)").action(async (options) => {
8179
+ recovery.command("setup").description("enable recovery: split a fresh recovery key across custodians").requiredOption("--threshold <M>", "custodians required to recover (M in M-of-N)").option("--custodian <email|skt_id>", "a recovery custodian (repeatable)", collect$8, []).option("--org <slug>", "organization slug (defaults to seekrit.json, or your only org)").action(async (options) => {
8070
8180
  const ctx = buildContext();
8071
8181
  const org = await resolveOrg(ctx, options.org);
8072
8182
  const config = await buildRecoveryConfig(ctx, org.id, options.threshold, options.custodian);
@@ -8084,7 +8194,7 @@ function registerRecoveryCommands(program) {
8084
8194
  const { wrapped, skipped } = await syncRecoveryGrants(ctx, (await resolveOrg(ctx, options.org)).id);
8085
8195
  console.error(`recovery-protected ${wrapped} environment(s); skipped ${skipped} you cannot decrypt`);
8086
8196
  });
8087
- recovery.command("rotate").description("rotate the recovery key (new keypair, custodians, and env re-wraps)").requiredOption("--threshold <M>", "custodians required to recover (M in M-of-N)").option("--custodian <email|skt_id>", "a recovery custodian (repeatable)", collect$7, []).option("--org <slug>", "organization slug (defaults to seekrit.json, or your only org)").action(async (options) => {
8197
+ recovery.command("rotate").description("rotate the recovery key (new keypair, custodians, and env re-wraps)").requiredOption("--threshold <M>", "custodians required to recover (M in M-of-N)").option("--custodian <email|skt_id>", "a recovery custodian (repeatable)", collect$8, []).option("--org <slug>", "organization slug (defaults to seekrit.json, or your only org)").action(async (options) => {
8088
8198
  const ctx = buildContext();
8089
8199
  const org = await resolveOrg(ctx, options.org);
8090
8200
  const config = await buildRecoveryConfig(ctx, org.id, options.threshold, options.custodian);
@@ -9227,7 +9337,7 @@ function formatSecrets(values, format) {
9227
9337
  * `buildContext()` in any of them silently breaks the promise the feature makes.
9228
9338
  */
9229
9339
  /** Collect a repeatable option into a list. */
9230
- function collect$6(value, acc = []) {
9340
+ function collect$7(value, acc = []) {
9231
9341
  acc.push(value);
9232
9342
  return acc;
9233
9343
  }
@@ -9504,7 +9614,7 @@ function registerArchiveCommands(program) {
9504
9614
  } catch {}
9505
9615
  fail("none of the recovery shares in this archive unwrap with that key");
9506
9616
  });
9507
- archive.command("decrypt <file>").description("decrypt an archive's secrets with your own key (offline)").option("-o, --out <dir>", "write one file per environment into this directory").option("--stdout", "print plaintext to stdout instead of writing files").option("--env <label>", "only this environment (app/env, group@env, slug, or id)").option("--format <format>", "dotenv | json | shell", "dotenv").option("--token <skt_…>", "decrypt as a service token instead of a passphrase").option("--key-file <path>", "decrypt with a private key JWK file").option("--share <file>", "custodian share for an offline quorum (repeatable)", collect$6).option("-y, --yes", "skip the confirmation when printing plaintext to stdout").action(async (file, options) => {
9617
+ archive.command("decrypt <file>").description("decrypt an archive's secrets with your own key (offline)").option("-o, --out <dir>", "write one file per environment into this directory").option("--stdout", "print plaintext to stdout instead of writing files").option("--env <label>", "only this environment (app/env, group@env, slug, or id)").option("--format <format>", "dotenv | json | shell", "dotenv").option("--token <skt_…>", "decrypt as a service token instead of a passphrase").option("--key-file <path>", "decrypt with a private key JWK file").option("--share <file>", "custodian share for an offline quorum (repeatable)", collect$7).option("-y, --yes", "skip the confirmation when printing plaintext to stdout").action(async (file, options) => {
9508
9618
  if (!options.out && !options.stdout) fail("choose a destination: --out <dir> to write files, or --stdout to print plaintext");
9509
9619
  if (![
9510
9620
  "dotenv",
@@ -11551,7 +11661,7 @@ function parseTtlSeconds$4(input) {
11551
11661
  }[m[2] || "s"] ?? 1);
11552
11662
  }
11553
11663
  /** Collect a repeatable option into an array. */
11554
- function collect$5(value, previous) {
11664
+ function collect$6(value, previous) {
11555
11665
  return [...previous, value];
11556
11666
  }
11557
11667
  /** Parse `readWrite@app` → { role, db } for a custom target. */
@@ -11576,7 +11686,7 @@ function resolveAdminUri(uri) {
11576
11686
  function registerMongoCommands(program) {
11577
11687
  const mongo = program.command("mongodb").description("temporary MongoDB credentials (createUser, zero-knowledge delivery)");
11578
11688
  const target = mongo.command("target").description("manage MongoDB targets");
11579
- target.command("add").description("register a MongoDB cluster to issue temporary credentials from").requiredOption("--name <name>", "display name, e.g. prod-app").requiredOption("--database <db>", "the database leased users get access to, e.g. app").option("--uri <uri>", "admin connection string (else SEEKRIT_MONGODB_ADMIN_URL)").option("--org <slug>", "organization slug (defaults to seekrit.json, or your only org)").option("--access <level>", "readonly | readwrite | custom", "readonly").option("--role <role@db>", "grant for a custom target (repeatable)", collect$5, []).option("--auth-source <db>", "authentication database (default admin)").option("--max-ttl <duration>", "clamp requested credential lifetime, e.g. 8h").option("--no-tls", "disable TLS to the cluster (TLS is on by default)").action(async (options) => {
11689
+ target.command("add").description("register a MongoDB cluster to issue temporary credentials from").requiredOption("--name <name>", "display name, e.g. prod-app").requiredOption("--database <db>", "the database leased users get access to, e.g. app").option("--uri <uri>", "admin connection string (else SEEKRIT_MONGODB_ADMIN_URL)").option("--org <slug>", "organization slug (defaults to seekrit.json, or your only org)").option("--access <level>", "readonly | readwrite | custom", "readonly").option("--role <role@db>", "grant for a custom target (repeatable)", collect$6, []).option("--auth-source <db>", "authentication database (default admin)").option("--max-ttl <duration>", "clamp requested credential lifetime, e.g. 8h").option("--no-tls", "disable TLS to the cluster (TLS is on by default)").action(async (options) => {
11580
11690
  const ctx = buildContext();
11581
11691
  const org = await resolveOrg(ctx, options.org);
11582
11692
  const adminUri = resolveAdminUri(options.uri);
@@ -11738,7 +11848,7 @@ function generateUserName$1(prefix = "tmp") {
11738
11848
  function registerMysqlCommands(program) {
11739
11849
  const mysql = program.command("mysql").description("temporary MySQL/MariaDB credentials (short-lived, zero-knowledge)");
11740
11850
  const target = mysql.command("target").description("manage provisioning targets");
11741
- target.command("add").description("register a MySQL/MariaDB server to lease credentials from").requiredOption("--name <name>", "display name, e.g. prod-db").option("--org <slug>", "organization slug (defaults to seekrit.json, or your only org)").requiredOption("--host <host>", "database host").option("--port <port>", "database port", "3306").requiredOption("--database <name>", "database to grant access to").option("--access <level>", "readonly | readwrite | custom", "readonly").option("--user-host <host>", "host part of created accounts ('name'@'<host>')", "%").option("--executor <mode>", "in_do | remote", "in_do").option("--provisioner-url <url>", "customer provisioner URL (remote executor)").option("--hmac-key <base64>", "shared HMAC key for the remote executor (or set SEEKRIT_PROVISIONER_HMAC_KEY); `seekrit provisioner keygen` mints one").option("--admin-url <url>", "in_do: admin mysql:// connection string (or set SEEKRIT_MYSQL_ADMIN_URL); wrapped locally").option("--create-statement <sql>", "custom CREATE template (repeatable)", collect$4, []).option("--revoke-statement <sql>", "custom REVOKE template (repeatable)", collect$4, []).action(async (options) => {
11851
+ target.command("add").description("register a MySQL/MariaDB server to lease credentials from").requiredOption("--name <name>", "display name, e.g. prod-db").option("--org <slug>", "organization slug (defaults to seekrit.json, or your only org)").requiredOption("--host <host>", "database host").option("--port <port>", "database port", "3306").requiredOption("--database <name>", "database to grant access to").option("--access <level>", "readonly | readwrite | custom", "readonly").option("--user-host <host>", "host part of created accounts ('name'@'<host>')", "%").option("--executor <mode>", "in_do | remote", "in_do").option("--provisioner-url <url>", "customer provisioner URL (remote executor)").option("--hmac-key <base64>", "shared HMAC key for the remote executor (or set SEEKRIT_PROVISIONER_HMAC_KEY); `seekrit provisioner keygen` mints one").option("--admin-url <url>", "in_do: admin mysql:// connection string (or set SEEKRIT_MYSQL_ADMIN_URL); wrapped locally").option("--create-statement <sql>", "custom CREATE template (repeatable)", collect$5, []).option("--revoke-statement <sql>", "custom REVOKE template (repeatable)", collect$5, []).action(async (options) => {
11742
11852
  const ctx = buildContext();
11743
11853
  const org = await resolveOrg(ctx, options.org);
11744
11854
  const executor = options.executor === "remote" ? "remote" : "in_do";
@@ -11841,7 +11951,7 @@ function registerMysqlCommands(program) {
11841
11951
  });
11842
11952
  }
11843
11953
  /** Collect a repeatable option into an array. */
11844
- function collect$4(value, acc) {
11954
+ function collect$5(value, acc) {
11845
11955
  acc.push(value);
11846
11956
  return acc;
11847
11957
  }
@@ -12293,12 +12403,12 @@ function requirePluginDir(explicit) {
12293
12403
  if (found) return found;
12294
12404
  fail("could not find the Nomad plugin directory — pass --plugin-dir <path> matching your agent's client.common_plugin_dir");
12295
12405
  }
12296
- function collect$3(value, previous = []) {
12406
+ function collect$4(value, previous = []) {
12297
12407
  return [...previous, value];
12298
12408
  }
12299
12409
  function registerNomadCommands(program) {
12300
12410
  const nomad = program.command("nomad").description("wire seekrit into Nomad as a secret provider (`seekrit nomad --help`)");
12301
- nomad.command("init").description("print the agent stanza, plugin config, and job snippet for this client").option("--plugin-dir <path>", "the agent's client.common_plugin_dir").option("--profile <name>", "profile name jobs will reference in `path`", "default").option("--token-file <path>", "where the profile's service token lives").option("--namespace <ns>", "restrict the profile to a Nomad namespace (repeatable)", collect$3).option("--job <id>", "restrict the profile to a Nomad job id (repeatable)", collect$3).option("--config <path>", "plugin config path", DEFAULT_CONFIG_PATH).option("--write", "write the plugin config file instead of printing it").option("--json", "machine-readable output").action((options) => {
12411
+ nomad.command("init").description("print the agent stanza, plugin config, and job snippet for this client").option("--plugin-dir <path>", "the agent's client.common_plugin_dir").option("--profile <name>", "profile name jobs will reference in `path`", "default").option("--token-file <path>", "where the profile's service token lives").option("--namespace <ns>", "restrict the profile to a Nomad namespace (repeatable)", collect$4).option("--job <id>", "restrict the profile to a Nomad job id (repeatable)", collect$4).option("--config <path>", "plugin config path", DEFAULT_CONFIG_PATH).option("--write", "write the plugin config file instead of printing it").option("--json", "machine-readable output").action((options) => {
12302
12412
  const pluginDir = options.pluginDir ? resolve(options.pluginDir) : detectPluginDir() ?? PLUGIN_DIR_CANDIDATES[0];
12303
12413
  const profile = options.profile ?? "default";
12304
12414
  const tokenFile = options.tokenFile ?? `/etc/seekrit/tokens/${profile}`;
@@ -13417,7 +13527,7 @@ function generateRoleName(prefix = "tmp") {
13417
13527
  function registerPgCommands(program) {
13418
13528
  const pg = program.command("pg").description("temporary Postgres credentials (short-lived, zero-knowledge)");
13419
13529
  const target = pg.command("target").description("manage provisioning targets");
13420
- target.command("add").description("register a Postgres cluster to lease credentials from").requiredOption("--name <name>", "display name, e.g. prod-db").option("--org <slug>", "organization slug (defaults to seekrit.json, or your only org)").requiredOption("--host <host>", "database host").option("--port <port>", "database port", "5432").requiredOption("--database <name>", "database to connect to").option("--access <level>", "readonly | readwrite | custom", "readonly").option("--schema <name>", "schema for preset grants", "public").option("--executor <mode>", "in_do | remote", "in_do").option("--provisioner-url <url>", "customer provisioner URL (remote executor)").option("--hmac-key <base64>", "shared HMAC key for the remote executor (or set SEEKRIT_PROVISIONER_HMAC_KEY); `seekrit provisioner keygen` mints one").option("--admin-url <url>", "in_do: admin postgres:// connection string (or set SEEKRIT_PG_ADMIN_URL); wrapped locally").option("--create-statement <sql>", "custom CREATE template (repeatable)", collect$2, []).option("--revoke-statement <sql>", "custom REVOKE template (repeatable)", collect$2, []).action(async (options) => {
13530
+ target.command("add").description("register a Postgres cluster to lease credentials from").requiredOption("--name <name>", "display name, e.g. prod-db").option("--org <slug>", "organization slug (defaults to seekrit.json, or your only org)").requiredOption("--host <host>", "database host").option("--port <port>", "database port", "5432").requiredOption("--database <name>", "database to connect to").option("--access <level>", "readonly | readwrite | custom", "readonly").option("--schema <name>", "schema for preset grants", "public").option("--executor <mode>", "in_do | remote", "in_do").option("--provisioner-url <url>", "customer provisioner URL (remote executor)").option("--hmac-key <base64>", "shared HMAC key for the remote executor (or set SEEKRIT_PROVISIONER_HMAC_KEY); `seekrit provisioner keygen` mints one").option("--admin-url <url>", "in_do: admin postgres:// connection string (or set SEEKRIT_PG_ADMIN_URL); wrapped locally").option("--create-statement <sql>", "custom CREATE template (repeatable)", collect$3, []).option("--revoke-statement <sql>", "custom REVOKE template (repeatable)", collect$3, []).action(async (options) => {
13421
13531
  const ctx = buildContext();
13422
13532
  const org = await resolveOrg(ctx, options.org);
13423
13533
  const executor = options.executor === "remote" ? "remote" : "in_do";
@@ -13533,7 +13643,7 @@ function registerPgCommands(program) {
13533
13643
  });
13534
13644
  }
13535
13645
  /** Collect a repeatable option into an array. */
13536
- function collect$2(value, acc) {
13646
+ function collect$3(value, acc) {
13537
13647
  acc.push(value);
13538
13648
  return acc;
13539
13649
  }
@@ -13968,7 +14078,7 @@ function generateUserName(prefix = "tmp") {
13968
14078
  function registerRedisCommands(program) {
13969
14079
  const redis = program.command("redis").description("temporary Redis credentials (short-lived, zero-knowledge)");
13970
14080
  const target = redis.command("target").description("manage provisioning targets");
13971
- target.command("add").description("register a Redis server to lease credentials from").requiredOption("--name <name>", "display name, e.g. prod-cache").option("--org <slug>", "organization slug (defaults to seekrit.json, or your only org)").requiredOption("--host <host>", "redis host").option("--port <port>", "redis port", "6379").option("--db <index>", "logical database index (the /<n> in the URL)").option("--access <level>", "readonly | readwrite | custom", "readonly").option("--executor <mode>", "in_do | remote", "in_do").option("--provisioner-url <url>", "customer provisioner URL (remote executor)").option("--hmac-key <base64>", "shared HMAC key for the remote executor (or set SEEKRIT_PROVISIONER_HMAC_KEY); `seekrit provisioner keygen` mints one").option("--admin-url <url>", "in_do: admin redis:// (or rediss://) connection string (or set SEEKRIT_REDIS_ADMIN_URL); wrapped locally").option("--create-statement <cmd>", "custom SETUSER template (repeatable)", collect$1, []).option("--revoke-statement <cmd>", "custom DELUSER template (repeatable)", collect$1, []).action(async (options) => {
14081
+ target.command("add").description("register a Redis server to lease credentials from").requiredOption("--name <name>", "display name, e.g. prod-cache").option("--org <slug>", "organization slug (defaults to seekrit.json, or your only org)").requiredOption("--host <host>", "redis host").option("--port <port>", "redis port", "6379").option("--db <index>", "logical database index (the /<n> in the URL)").option("--access <level>", "readonly | readwrite | custom", "readonly").option("--executor <mode>", "in_do | remote", "in_do").option("--provisioner-url <url>", "customer provisioner URL (remote executor)").option("--hmac-key <base64>", "shared HMAC key for the remote executor (or set SEEKRIT_PROVISIONER_HMAC_KEY); `seekrit provisioner keygen` mints one").option("--admin-url <url>", "in_do: admin redis:// (or rediss://) connection string (or set SEEKRIT_REDIS_ADMIN_URL); wrapped locally").option("--create-statement <cmd>", "custom SETUSER template (repeatable)", collect$2, []).option("--revoke-statement <cmd>", "custom DELUSER template (repeatable)", collect$2, []).action(async (options) => {
13972
14082
  const ctx = buildContext();
13973
14083
  const org = await resolveOrg(ctx, options.org);
13974
14084
  const executor = options.executor === "remote" ? "remote" : "in_do";
@@ -14071,7 +14181,7 @@ function registerRedisCommands(program) {
14071
14181
  });
14072
14182
  }
14073
14183
  /** Collect a repeatable option into an array. */
14074
- function collect$1(value, acc) {
14184
+ function collect$2(value, acc) {
14075
14185
  acc.push(value);
14076
14186
  return acc;
14077
14187
  }
@@ -14270,7 +14380,7 @@ function parseTtlSeconds(input) {
14270
14380
  function registerSshCommands(program) {
14271
14381
  const ssh = program.command("ssh").description("temporary SSH access (short-lived certificates, zero-knowledge)");
14272
14382
  const target = ssh.command("target").description("manage SSH CA targets");
14273
- target.command("add").description("create an SSH certificate authority to issue certs from").requiredOption("--name <name>", "display name, e.g. prod-fleet").option("--org <slug>", "organization slug (defaults to seekrit.json, or your only org)").option("--host <host>", "default host the printed ssh command connects to").option("--user <login>", "default login user (a cert principal)").option("--principal <name>", "allow-list a principal certs may request (repeatable)", collect, []).option("--extension <name>", "cert extension to grant, e.g. permit-pty (repeatable)", collect, []).option("--max-ttl <duration>", "clamp requested cert lifetime, e.g. 8h").action(async (options) => {
14383
+ target.command("add").description("create an SSH certificate authority to issue certs from").requiredOption("--name <name>", "display name, e.g. prod-fleet").option("--org <slug>", "organization slug (defaults to seekrit.json, or your only org)").option("--host <host>", "default host the printed ssh command connects to").option("--user <login>", "default login user (a cert principal)").option("--principal <name>", "allow-list a principal certs may request (repeatable)", collect$1, []).option("--extension <name>", "cert extension to grant, e.g. permit-pty (repeatable)", collect$1, []).option("--max-ttl <duration>", "clamp requested cert lifetime, e.g. 8h").action(async (options) => {
14274
14384
  const ctx = buildContext();
14275
14385
  const org = await resolveOrg(ctx, options.org);
14276
14386
  const ca = await generateSshCaKeyPair(`seekrit-ca:${options.name}`);
@@ -14326,7 +14436,7 @@ function registerSshCommands(program) {
14326
14436
  await ctx.client.deleteLeaseTarget(org.id, targetId);
14327
14437
  console.error(`deleted ${targetId}`);
14328
14438
  });
14329
- ssh.command("lease <target>").description("mint a short-lived SSH certificate; prints a ready-to-run ssh command").option("--org <slug>", "organization slug (defaults to seekrit.json, or your only org)").option("--principal <name>", "login user to request (repeatable; default from target)", collect, []).option("--ttl <duration>", "certificate lifetime, e.g. 30m, 1h, 8h", "1h").option("--out <dir>", "directory to write the key + cert (default: a temp dir)").option("--json", "print key/cert paths and the certificate as JSON").action(async (targetRef, options) => {
14439
+ ssh.command("lease <target>").description("mint a short-lived SSH certificate; prints a ready-to-run ssh command").option("--org <slug>", "organization slug (defaults to seekrit.json, or your only org)").option("--principal <name>", "login user to request (repeatable; default from target)", collect$1, []).option("--ttl <duration>", "certificate lifetime, e.g. 30m, 1h, 8h", "1h").option("--out <dir>", "directory to write the key + cert (default: a temp dir)").option("--json", "print key/cert paths and the certificate as JSON").action(async (targetRef, options) => {
14330
14440
  const ctx = buildContext();
14331
14441
  const org = await resolveOrg(ctx, options.org);
14332
14442
  const { targets } = await ctx.client.listLeaseTargets(org.id);
@@ -14382,7 +14492,7 @@ function registerSshCommands(program) {
14382
14492
  });
14383
14493
  }
14384
14494
  /** Collect a repeatable option into an array. */
14385
- function collect(value, acc) {
14495
+ function collect$1(value, acc) {
14386
14496
  acc.push(value);
14387
14497
  return acc;
14388
14498
  }
@@ -14392,6 +14502,36 @@ function collect(value, acc) {
14392
14502
  function list(raw, fallback) {
14393
14503
  return (raw ?? fallback).split(",").map((item) => item.trim()).filter(Boolean);
14394
14504
  }
14505
+ /** Accumulate a repeatable flag, in the order given. */
14506
+ function collect(value, acc = []) {
14507
+ return [...acc, value];
14508
+ }
14509
+ /**
14510
+ * One host rule as typed on the command line: a comma-separated host list, or
14511
+ * the literal `unrestricted`. The schema does the real validation; this only
14512
+ * turns the spelling into the shape it checks.
14513
+ */
14514
+ function hostRule(raw) {
14515
+ const trimmed = raw.trim();
14516
+ if (trimmed.toLowerCase() === "unrestricted") return "unrestricted";
14517
+ return list(trimmed, "");
14518
+ }
14519
+ /**
14520
+ * `--allowed-hosts-for NAME=host,host`, repeated — one per destination name.
14521
+ * A name given twice is refused rather than merged or last-wins, since either
14522
+ * reading would silently widen or narrow what the other occurrence said.
14523
+ */
14524
+ function hostRulesByName(entries) {
14525
+ const rules = {};
14526
+ for (const entry of entries ?? []) {
14527
+ const eq = entry.indexOf("=");
14528
+ const name = eq > 0 ? entry.slice(0, eq).trim() : "";
14529
+ if (!name || eq === entry.length - 1) fail(`--allowed-hosts-for takes NAME=host[,host…] (or NAME=unrestricted), not "${entry}"`);
14530
+ if (Object.hasOwn(rules, name)) fail(`--allowed-hosts-for names ${name} twice`);
14531
+ rules[name] = hostRule(entry.slice(eq + 1));
14532
+ }
14533
+ return rules;
14534
+ }
14395
14535
  /** Reject list members outside a known set, naming both the strays and the choices. */
14396
14536
  function assertMembers(values, allowed, flag) {
14397
14537
  const unknown = values.filter((v) => !allowed.includes(v));
@@ -14555,6 +14695,8 @@ function credentialNoun(provider) {
14555
14695
  if (provider === "langgraph-platform") return "LangSmith API key";
14556
14696
  if (provider === "azure-key-vault") return "client secret";
14557
14697
  if (provider === "huggingface-spaces") return "user access token";
14698
+ if (provider === "openai-vault") return "OpenAI project API key";
14699
+ if (provider === "claude-managed-agents") return "Anthropic API key";
14558
14700
  return "API token";
14559
14701
  }
14560
14702
  /**
@@ -14644,9 +14786,14 @@ function buildConfig(provider, options) {
14644
14786
  };
14645
14787
  }
14646
14788
  case "huggingface-spaces": return { provider: "huggingface-spaces" };
14789
+ case "openai-vault": return { provider: "openai-vault" };
14790
+ case "claude-managed-agents": return { provider: "claude-managed-agents" };
14647
14791
  }
14648
14792
  }
14649
- /** Where inside the platform a binding writes. */
14793
+ /**
14794
+ * Where inside the platform a binding writes. Exported for its tests: the
14795
+ * flags are the one part of a binding the API cannot see as typed.
14796
+ */
14650
14797
  function buildDestination(provider, options) {
14651
14798
  switch (provider) {
14652
14799
  case "vercel": {
@@ -14861,6 +15008,30 @@ function buildDestination(provider, options) {
14861
15008
  provider: "huggingface-spaces",
14862
15009
  repoId: assertHuggingfaceSpace(options.hfSpace)
14863
15010
  };
15011
+ case "openai-vault":
15012
+ if (!options.openaiVault) fail("--openai-vault is required for openai-vault (vault_… ID)");
15013
+ if (!options.openaiHosts) fail("--openai-hosts is required for openai-vault");
15014
+ return {
15015
+ provider: "openai-vault",
15016
+ vaultId: options.openaiVault.trim(),
15017
+ allowedHosts: list(options.openaiHosts, "")
15018
+ };
15019
+ case "claude-managed-agents": {
15020
+ if (!options.vault) fail("--vault is required for claude-managed-agents — the vault ID, e.g. vlt_01ABC…");
15021
+ const byName = hostRulesByName(options.allowedHostsFor);
15022
+ const parsed = claudeManagedAgentsDestinationSchema.safeParse({
15023
+ provider: "claude-managed-agents",
15024
+ vaultId: options.vault,
15025
+ ...options.allowedHosts !== void 0 ? { allowedHosts: hostRule(options.allowedHosts) } : {},
15026
+ ...Object.keys(byName).length > 0 ? { allowedHostsByName: byName } : {},
15027
+ injectionLocation: assertMember(options.injectionLocation, CLAUDE_VAULT_INJECTION_LOCATIONS, "--injection-location", "header")
15028
+ });
15029
+ if (!parsed.success) {
15030
+ const issue = parsed.error.issues[0];
15031
+ fail(`claude-managed-agents: ${issue?.path.length ? `${issue.path.join(".")}: ` : ""}${issue?.message ?? "invalid destination"} — pass --allowed-hosts <host,…> for every name, and/or --allowed-hosts-for NAME=<host,…> per name`);
15032
+ }
15033
+ return parsed.data;
15034
+ }
14864
15035
  }
14865
15036
  }
14866
15037
  /** One-line description of a destination, for list output. */
@@ -14884,6 +15055,12 @@ function describeDestination(destination) {
14884
15055
  case "langgraph-platform": return `deployment ${destination.deploymentId}`;
14885
15056
  case "azure-key-vault": return `${destination.vault}${destination.prefix ? ` (${destination.prefix}*)` : ""}`;
14886
15057
  case "huggingface-spaces": return `space ${destination.repoId}`;
15058
+ case "openai-vault": return `${destination.vaultId} (${destination.allowedHosts.join(", ")})`;
15059
+ case "claude-managed-agents": {
15060
+ const rules = Object.keys(destination.allowedHostsByName ?? {}).length;
15061
+ const hosts = destination.allowedHosts === void 0 ? "no default hosts" : destination.allowedHosts === "unrestricted" ? "unrestricted by default" : destination.allowedHosts.join(", ");
15062
+ return `vault ${destination.vaultId} (${hosts}${rules ? ` · ${rules} per-name` : ""} · ${destination.injectionLocation})`;
15063
+ }
14887
15064
  case "github-actions": switch (destination.kind) {
14888
15065
  case "repo": return `${destination.owner}/${destination.repo}`;
14889
15066
  case "environment": return `${destination.owner}/${destination.repo} @${destination.environment}`;
@@ -14899,7 +15076,7 @@ function describeDestination(destination) {
14899
15076
  * application whose environment the binding reads from.
14900
15077
  */
14901
15078
  function destinationOptions(command) {
14902
- return command.option("--project <id>", "vercel: project id or name · cloudflare-pages / northflank: project name or slug · bunnyshell: project ID (writes variables new environments inherit)").option("--target <list>", "vercel / cloudflare-pages: comma-separated deployment targets", "production").option("--git-branch <branch>", "vercel: restrict preview writes to one branch").option("--script <name>", "cloudflare-workers: Worker script name").option("--store-id <id>", "cloudflare-secrets-store: store ID (32 hex)").option("--scopes <list>", "cloudflare-secrets-store: comma-separated scopes", "workers").option("--railway-project <id>", "railway: project ID (a UUID)").option("--railway-environment <id>", "railway: environment ID (a UUID)").option("--service <id>", "railway: service ID (omit for the environment's shared variables) · render: service ID (srv-…, or crn-… for a cron job)").option("--skip-deploys", "railway: stage values without triggering a redeploy").option("--path <path>", "aws-parameter-store: hierarchy, e.g. /prod/storefront/ · aws-secrets-manager, azure-key-vault: name prefix").option("--layout <layout>", `aws-secrets-manager: ${AWS_SECRETS_MANAGER_LAYOUTS.join(" | ")}`).option("--secret-name <name>", "aws-secrets-manager: the secret a json-bundle writes to").option("--param-type <type>", `aws-parameter-store: ${AWS_PARAMETER_TYPES.join(" | ")}`).option("--tier <tier>", `aws-parameter-store: ${AWS_PARAMETER_TIERS.join(" | ")}`).option("--kms-key-id <id>", "aws: customer-managed KMS key id, ARN, or alias").option("--env-group <id>", "render: environment group ID (evg-…)").option("--fly-app <name>", "fly: app name, as `fly apps list` shows it").option("--secret-group <id>", "northflank: secret group ID (the slug in its URL)").option("--do-app <id>", "digitalocean: App Platform app ID (the UUID in its URL)").option("--component <name>", "digitalocean: write to one component's variables (omit for app-level)").option("--env-scope <scope>", `digitalocean: ${DIGITALOCEAN_ENV_SCOPES.join(" | ")}`).option("--heroku-app <name>", "heroku: app name, as `heroku apps` shows it (or its UUID)").option("--netlify-site <id>", "netlify: site API ID (the UUID under Project configuration)").option("--no-netlify-secret", "netlify: create readable variables instead of Netlify secrets (write-only)").option("--bunnyshell-environment <id>", "bunnyshell: environment ID (omit to write a project)").option("--no-bunnyshell-secret", "bunnyshell: create variables visible in the dashboard instead of secret ones").option("--gh-repo <owner/name>", "github-actions: repository, e.g. acme/storefront").option("--gh-environment <name>", "github-actions: write to one deployment environment's secrets (needs --gh-repo)").option("--gh-org <login>", "github-actions: write organization secrets instead of a repo's").option("--gh-visibility <v>", `github-actions org secrets: ${GITHUB_ACTIONS_VISIBILITIES.join(" | ")}`).option("--gh-repo-ids <ids>", "github-actions: comma-separated numeric repository IDs for --gh-visibility selected").option("--langgraph-deployment <id>", "langgraph-platform: deployment UUID (the one in its dashboard URL)").option("--gcp-prefix <prefix>", "gcp: prepended to every secret ID, e.g. prod-storefront-").option("--gcp-replication <policy>", `gcp: ${GCP_REPLICATION_POLICIES.join(" | ")}`, "automatic").option("--gcp-locations <list>", "gcp: regions for user-managed replication, e.g. us-east1").option("--gcp-kms-key <name>", "gcp: Cloud KMS key (projects/…/cryptoKeys/…)").option("--gcp-prune-versions", "gcp: destroy the version each push supersedes, keeping one active version").option("--vault <name>", "azure-key-vault: vault name, e.g. acme-prod").option("--hf-space <owner/name>", "huggingface-spaces: Space ID, e.g. acme/support-demo (its owner and name, not a URL)").option("--name-mode <mode>", `azure-key-vault: ${AZURE_KEY_VAULT_NAME_MODES.join(" | ")} — Key Vault stores no underscores, so DATABASE_URL becomes DATABASE-URL unless you reject instead`);
15079
+ return command.option("--project <id>", "vercel: project id or name · cloudflare-pages / northflank: project name or slug · bunnyshell: project ID (writes variables new environments inherit)").option("--target <list>", "vercel / cloudflare-pages: comma-separated deployment targets", "production").option("--git-branch <branch>", "vercel: restrict preview writes to one branch").option("--script <name>", "cloudflare-workers: Worker script name").option("--store-id <id>", "cloudflare-secrets-store: store ID (32 hex)").option("--scopes <list>", "cloudflare-secrets-store: comma-separated scopes", "workers").option("--railway-project <id>", "railway: project ID (a UUID)").option("--railway-environment <id>", "railway: environment ID (a UUID)").option("--service <id>", "railway: service ID (omit for the environment's shared variables) · render: service ID (srv-…, or crn-… for a cron job)").option("--skip-deploys", "railway: stage values without triggering a redeploy").option("--path <path>", "aws-parameter-store: hierarchy, e.g. /prod/storefront/ · aws-secrets-manager, azure-key-vault: name prefix").option("--layout <layout>", `aws-secrets-manager: ${AWS_SECRETS_MANAGER_LAYOUTS.join(" | ")}`).option("--secret-name <name>", "aws-secrets-manager: the secret a json-bundle writes to").option("--param-type <type>", `aws-parameter-store: ${AWS_PARAMETER_TYPES.join(" | ")}`).option("--tier <tier>", `aws-parameter-store: ${AWS_PARAMETER_TIERS.join(" | ")}`).option("--kms-key-id <id>", "aws: customer-managed KMS key id, ARN, or alias").option("--env-group <id>", "render: environment group ID (evg-…)").option("--fly-app <name>", "fly: app name, as `fly apps list` shows it").option("--secret-group <id>", "northflank: secret group ID (the slug in its URL)").option("--do-app <id>", "digitalocean: App Platform app ID (the UUID in its URL)").option("--component <name>", "digitalocean: write to one component's variables (omit for app-level)").option("--env-scope <scope>", `digitalocean: ${DIGITALOCEAN_ENV_SCOPES.join(" | ")}`).option("--heroku-app <name>", "heroku: app name, as `heroku apps` shows it (or its UUID)").option("--netlify-site <id>", "netlify: site API ID (the UUID under Project configuration)").option("--no-netlify-secret", "netlify: create readable variables instead of Netlify secrets (write-only)").option("--bunnyshell-environment <id>", "bunnyshell: environment ID (omit to write a project)").option("--no-bunnyshell-secret", "bunnyshell: create variables visible in the dashboard instead of secret ones").option("--gh-repo <owner/name>", "github-actions: repository, e.g. acme/storefront").option("--gh-environment <name>", "github-actions: write to one deployment environment's secrets (needs --gh-repo)").option("--gh-org <login>", "github-actions: write organization secrets instead of a repo's").option("--gh-visibility <v>", `github-actions org secrets: ${GITHUB_ACTIONS_VISIBILITIES.join(" | ")}`).option("--gh-repo-ids <ids>", "github-actions: comma-separated numeric repository IDs for --gh-visibility selected").option("--langgraph-deployment <id>", "langgraph-platform: deployment UUID (the one in its dashboard URL)").option("--gcp-prefix <prefix>", "gcp: prepended to every secret ID, e.g. prod-storefront-").option("--gcp-replication <policy>", `gcp: ${GCP_REPLICATION_POLICIES.join(" | ")}`, "automatic").option("--gcp-locations <list>", "gcp: regions for user-managed replication, e.g. us-east1").option("--gcp-kms-key <name>", "gcp: Cloud KMS key (projects/…/cryptoKeys/…)").option("--gcp-prune-versions", "gcp: destroy the version each push supersedes, keeping one active version").option("--vault <name>", "azure-key-vault: vault name, e.g. acme-prod · claude-managed-agents: vault ID (vlt_…)").option("--allowed-hosts <list>", "claude-managed-agents: hosts every secret may be used on, comma-separated (api.example.com, *.example.com, an IPv4) — or `unrestricted`").option("--allowed-hosts-for <NAME=hosts>", "claude-managed-agents: hosts for one secret, overriding --allowed-hosts (repeatable)", collect).option("--injection-location <where>", `claude-managed-agents: ${CLAUDE_VAULT_INJECTION_LOCATIONS.join(" | ")} — which parts of a request the value is substituted into (default header)`).option("--openai-vault <id>", "openai-vault: existing OpenAI Vault ID (vault_…)").option("--openai-hosts <hosts>", "openai-vault: comma-separated exact HTTPS hostnames").option("--hf-space <owner/name>", "huggingface-spaces: Space ID, e.g. acme/support-demo (its owner and name, not a URL)").option("--name-mode <mode>", `azure-key-vault: ${AZURE_KEY_VAULT_NAME_MODES.join(" | ")} — Key Vault stores no underscores, so DATABASE_URL becomes DATABASE-URL unless you reject instead`);
14903
15080
  }
14904
15081
  /** Find a connection by id or name — nobody keeps `syc_…` ids in their head. */
14905
15082
  async function resolveConnection(ctx, orgId, ref) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seekrit/cli",
3
- "version": "1.7.1",
3
+ "version": "1.9.0",
4
4
  "description": "End-to-end encrypted secrets manager CLI — inject decrypted secrets into any command.",
5
5
  "type": "module",
6
6
  "publishConfig": {