@seekrit/cli 1.1.0 → 1.2.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 +104 -5
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -1907,6 +1907,8 @@ const AUDIT_ACTIONS = [
1907
1907
  "org.mfa_policy_changed",
1908
1908
  "org.exported",
1909
1909
  "user.keys_updated",
1910
+ "user.passkey_enrolled",
1911
+ "user.passkey_removed",
1910
1912
  "user.notification_prefs_updated",
1911
1913
  "app.created",
1912
1914
  "app.updated",
@@ -2151,6 +2153,16 @@ z.object({
2151
2153
  */
2152
2154
  encryptedPrivateKey: z.string().min(1)
2153
2155
  });
2156
+ z.object({
2157
+ /** Base64url WebAuthn credential id — what `allowCredentials` is built from. */
2158
+ credentialId: z.string().min(1).max(512),
2159
+ /** Human label for the device, e.g. "MacBook Touch ID". Display only. */
2160
+ label: z.string().min(1).max(64),
2161
+ /** Base64url PRF evaluation input for this credential; not a secret. */
2162
+ prfInput: z.string().min(1).max(256),
2163
+ /** The private key wrapped to this passkey's PRF output. */
2164
+ encryptedPrivateKey: z.string().min(1).max(8192).refine((v) => v.startsWith("pk2."), { message: "expected a pk2. passkey wrap" })
2165
+ });
2154
2166
  const grantEnvironmentKeySchema = z.object({
2155
2167
  principalType: principalTypeSchema,
2156
2168
  principalId: z.string().min(1),
@@ -2483,7 +2495,8 @@ const SYNC_PROVIDER_KINDS = [
2483
2495
  "github-actions",
2484
2496
  "gcp-secret-manager",
2485
2497
  "langgraph-platform",
2486
- "azure-key-vault"
2498
+ "azure-key-vault",
2499
+ "huggingface-spaces"
2487
2500
  ];
2488
2501
  z.enum(SYNC_PROVIDER_KINDS);
2489
2502
  /**
@@ -2872,6 +2885,21 @@ const azureKeyVaultConnectionConfigSchema = z.object({
2872
2885
  /** Which Azure cloud the tenant and its vaults live in. */
2873
2886
  cloud: z.enum(AZURE_CLOUDS).default("public")
2874
2887
  });
2888
+ /**
2889
+ * Hugging Face account scope — empty, as Render's and Fly's are.
2890
+ *
2891
+ * Neither half of "which account, which thing" needs stating. A Hub user access
2892
+ * token belongs to one user and carries their write access to every Space they
2893
+ * or their organizations own; a Space is addressed by `owner/name`, which is
2894
+ * globally unique. So the token plus the destination is the whole address.
2895
+ *
2896
+ * There is deliberately no `baseUrl` twin of the GitHub Enterprise Server
2897
+ * field. `HF_ENDPOINT` exists in the Python client for Hub *mirrors*, which
2898
+ * serve repository content — not the settings API this connector writes, and
2899
+ * not something a mirror is expected to accept a write on. Adding the field
2900
+ * would invite pointing a connection at a host that silently swallows secrets.
2901
+ */
2902
+ const huggingfaceSpacesConnectionConfigSchema = z.object({ provider: z.literal("huggingface-spaces") });
2875
2903
  const syncConnectionConfigSchema = z.discriminatedUnion("provider", [
2876
2904
  vercelConnectionConfigSchema,
2877
2905
  cloudflareWorkersConnectionConfigSchema,
@@ -2890,7 +2918,8 @@ const syncConnectionConfigSchema = z.discriminatedUnion("provider", [
2890
2918
  githubActionsConnectionConfigSchema,
2891
2919
  gcpSecretManagerConnectionConfigSchema,
2892
2920
  langgraphPlatformConnectionConfigSchema,
2893
- azureKeyVaultConnectionConfigSchema
2921
+ azureKeyVaultConnectionConfigSchema,
2922
+ huggingfaceSpacesConnectionConfigSchema
2894
2923
  ]);
2895
2924
  /** Vercel's three deployment targets. A binding writes to one or more. */
2896
2925
  const VERCEL_TARGETS = [
@@ -3681,6 +3710,40 @@ const azureKeyVaultDestinationSchema = z.object({
3681
3710
  /** What to do with a name Key Vault cannot store — see {@link AZURE_KEY_VAULT_NAME_MODES}. */
3682
3711
  nameMode: z.enum(AZURE_KEY_VAULT_NAME_MODES).default("dash")
3683
3712
  });
3713
+ /**
3714
+ * The Space whose secrets a binding owns, addressed the way the Hub addresses
3715
+ * every repository: `owner/name`, where `owner` is a user or an organization.
3716
+ *
3717
+ * A Space has **one** secret set, shared by every replica — there is no
3718
+ * per-target split to state, the way Vercel and Pages have one. The Hub's
3719
+ * convention is that staging and production are separate Spaces
3720
+ * (`acme/demo`, `acme/demo-staging`), so pointing at an environment means
3721
+ * naming that Space, exactly as a Fly environment means naming its own app.
3722
+ *
3723
+ * Validated by shape because the two habitual slips both fail *late*: pasting
3724
+ * the browser URL (`https://huggingface.co/spaces/acme/demo`) or the bare name
3725
+ * without its owner. Either one is a 404 from the Hub inside an alarm with
3726
+ * nobody watching, and a 404 says nothing about which half was wrong. The
3727
+ * leading character is held to alphanumeric, which is also what rejects the
3728
+ * `.` and `..` that no repository may be called.
3729
+ */
3730
+ const huggingfaceRepoIdSchema = z.string().trim().regex(/^[A-Za-z0-9][A-Za-z0-9._-]{0,95}\/[A-Za-z0-9][A-Za-z0-9._-]{0,95}$/, "must be a Space ID as owner/name, e.g. acme/support-demo — not a URL");
3731
+ /**
3732
+ * One Hugging Face **Space**, whose secrets arrive in the app's container as
3733
+ * environment variables.
3734
+ *
3735
+ * Only secrets. A Space also has *variables*, and they are not a second lane
3736
+ * seekrit could use: the Hub calls them "non-sensitive configuration values",
3737
+ * they are "publicly accessible and viewable", and they are copied into every
3738
+ * Space duplicated from this one. Writing a seekrit secret there would publish
3739
+ * it, so this connector has no variables mode — a binding that wants one is
3740
+ * asking for the wrong thing.
3741
+ */
3742
+ const huggingfaceSpacesDestinationSchema = z.object({
3743
+ provider: z.literal("huggingface-spaces"),
3744
+ /** Space ID as `owner/name`, e.g. `acme/support-demo`. */
3745
+ repoId: huggingfaceRepoIdSchema
3746
+ });
3684
3747
  const syncDestinationSchema = z.discriminatedUnion("provider", [
3685
3748
  vercelDestinationSchema,
3686
3749
  cloudflareWorkersDestinationSchema,
@@ -3699,7 +3762,8 @@ const syncDestinationSchema = z.discriminatedUnion("provider", [
3699
3762
  githubActionsDestinationSchema,
3700
3763
  gcpSecretManagerDestinationSchema,
3701
3764
  langgraphPlatformDestinationSchema,
3702
- azureKeyVaultDestinationSchema
3765
+ azureKeyVaultDestinationSchema,
3766
+ huggingfaceSpacesDestinationSchema
3703
3767
  ]);
3704
3768
  /**
3705
3769
  * How seekrit secret names become destination key names. Applied in order:
@@ -4987,7 +5051,7 @@ async function createAgentTaskToken() {
4987
5051
  }
4988
5052
  //#endregion
4989
5053
  //#region package.json
4990
- var version = "1.1.0";
5054
+ var version = "1.2.0";
4991
5055
  //#endregion
4992
5056
  //#region ../../packages/api-client/src/index.ts
4993
5057
  var SeekritApiError = class extends Error {
@@ -5060,6 +5124,22 @@ var SeekritClient = class {
5060
5124
  revokeCliSession(sessionId) {
5061
5125
  return this.request("DELETE", `/v1/me/cli-sessions/${sessionId}`);
5062
5126
  }
5127
+ /**
5128
+ * The passkeys enrolled to unlock this user's keyring, each with the `pk2.`
5129
+ * blob its PRF output decrypts. One call is everything the unlock ceremony
5130
+ * needs; the blobs are opaque without the authenticator.
5131
+ */
5132
+ listMyPasskeys() {
5133
+ return this.request("GET", "/v1/me/passkeys");
5134
+ }
5135
+ /** File a private key already wrapped, client-side, to a passkey's PRF output. */
5136
+ enrollMyPasskey(input) {
5137
+ return this.request("POST", "/v1/me/passkeys", input);
5138
+ }
5139
+ /** Stop a passkey unlocking the keyring. The key itself is untouched. */
5140
+ deleteMyPasskey(passkeyId) {
5141
+ return this.request("DELETE", `/v1/me/passkeys/${passkeyId}`);
5142
+ }
5063
5143
  /** What a pending login request is asking for — for the approval screen. */
5064
5144
  getCliLoginRequest(code) {
5065
5145
  return this.request("GET", `/v1/cli-login/${encodeURIComponent(code)}`);
@@ -12949,6 +13029,18 @@ function assertLanggraphDeploymentId(value) {
12949
13029
  if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(id)) fail(`--langgraph-deployment should be the deployment UUID from its dashboard URL, not "${id}"`);
12950
13030
  return id;
12951
13031
  }
13032
+ /**
13033
+ * A Hugging Face Space is addressed as `owner/name`. The two habitual slips are
13034
+ * pasting the browser URL and giving the bare name without its owner; the first
13035
+ * is recovered rather than refused, since a Space URL has exactly one shape.
13036
+ */
13037
+ function assertHuggingfaceSpace(value) {
13038
+ if (!value) fail("--hf-space is required for huggingface-spaces (owner/name)");
13039
+ const raw = value.trim();
13040
+ const id = raw.match(/^https?:\/\/(?:[^/]*\.)?huggingface\.co\/spaces\/([^/?#]+\/[^/?#]+)(?:[/?#]|$)/i)?.[1] ?? raw.replace(/^\/+|\/+$/g, "");
13041
+ if (!/^[A-Za-z0-9][A-Za-z0-9._-]{0,95}\/[A-Za-z0-9][A-Za-z0-9._-]{0,95}$/.test(id)) fail(`--hf-space should be the Space ID as owner/name, e.g. acme/support-demo, not "${raw}"`);
13042
+ return id;
13043
+ }
12952
13044
  /** Reject a single value outside a known set, naming the choices. */
12953
13045
  function assertMember(value, allowed, flag, fallback) {
12954
13046
  if (value === void 0) return fallback;
@@ -13075,6 +13167,7 @@ function credentialNoun(provider) {
13075
13167
  if (provider === "gcp-secret-manager") return "service-account key JSON";
13076
13168
  if (provider === "langgraph-platform") return "LangSmith API key";
13077
13169
  if (provider === "azure-key-vault") return "client secret";
13170
+ if (provider === "huggingface-spaces") return "user access token";
13078
13171
  return "API token";
13079
13172
  }
13080
13173
  /**
@@ -13163,6 +13256,7 @@ function buildConfig(provider, options) {
13163
13256
  cloud: cloud ?? "public"
13164
13257
  };
13165
13258
  }
13259
+ case "huggingface-spaces": return { provider: "huggingface-spaces" };
13166
13260
  }
13167
13261
  }
13168
13262
  /** Where inside the platform a binding writes. */
@@ -13376,6 +13470,10 @@ function buildDestination(provider, options) {
13376
13470
  nameMode: nameMode ?? "dash"
13377
13471
  };
13378
13472
  }
13473
+ case "huggingface-spaces": return {
13474
+ provider: "huggingface-spaces",
13475
+ repoId: assertHuggingfaceSpace(options.hfSpace)
13476
+ };
13379
13477
  }
13380
13478
  }
13381
13479
  /** One-line description of a destination, for list output. */
@@ -13398,6 +13496,7 @@ function describeDestination(destination) {
13398
13496
  case "gcp-secret-manager": return destination.layout === "json-bundle" ? `${destination.secretId} · json` : `${destination.idPrefix ?? ""}* · one per name`;
13399
13497
  case "langgraph-platform": return `deployment ${destination.deploymentId}`;
13400
13498
  case "azure-key-vault": return `${destination.vault}${destination.prefix ? ` (${destination.prefix}*)` : ""}`;
13499
+ case "huggingface-spaces": return `space ${destination.repoId}`;
13401
13500
  case "github-actions": switch (destination.kind) {
13402
13501
  case "repo": return `${destination.owner}/${destination.repo}`;
13403
13502
  case "environment": return `${destination.owner}/${destination.repo} @${destination.environment}`;
@@ -13413,7 +13512,7 @@ function describeDestination(destination) {
13413
13512
  * application whose environment the binding reads from.
13414
13513
  */
13415
13514
  function destinationOptions(command) {
13416
- 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("--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`);
13515
+ 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`);
13417
13516
  }
13418
13517
  /** Find a connection by id or name — nobody keeps `syc_…` ids in their head. */
13419
13518
  async function resolveConnection(ctx, orgId, ref) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seekrit/cli",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "End-to-end encrypted secrets manager CLI — inject decrypted secrets into any command.",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -31,8 +31,8 @@
31
31
  "tsdown": "^0.22.3",
32
32
  "vitest": "^4.1.9",
33
33
  "@seekrit/api-client": "0.0.1",
34
- "@seekrit/crypto": "0.0.1",
35
- "@seekrit/core": "0.0.1"
34
+ "@seekrit/core": "0.0.1",
35
+ "@seekrit/crypto": "0.0.1"
36
36
  },
37
37
  "scripts": {
38
38
  "build": "tsdown",