@seekrit/cli 0.36.0 → 0.37.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 +71 -5
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -1520,7 +1520,8 @@ const SYNC_PROVIDER_KINDS = [
1520
1520
  "cloudflare-secrets-store",
1521
1521
  "railway",
1522
1522
  "aws-secrets-manager",
1523
- "aws-parameter-store"
1523
+ "aws-parameter-store",
1524
+ "render"
1524
1525
  ];
1525
1526
  z.enum(SYNC_PROVIDER_KINDS);
1526
1527
  /**
@@ -1646,6 +1647,17 @@ const awsParameterStoreConnectionConfigSchema = z.object({
1646
1647
  region: awsRegionSchema,
1647
1648
  accessKeyId: awsAccessKeyIdSchema
1648
1649
  });
1650
+ /**
1651
+ * Render account scope — deliberately empty.
1652
+ *
1653
+ * Like Railway's, and unlike Vercel (which 403s team-owned resources without
1654
+ * `teamId`) or Cloudflare (whose every endpoint is account-scoped): a Render
1655
+ * API key is issued to a user, and every endpoint seekrit calls addresses its
1656
+ * resource by id — `srv-…`, `crn-…`, `evg-…`. There is nothing to scope, so
1657
+ * nothing is stored. The connection's `name` is what tells an operator which Render
1658
+ * workspace it belongs to.
1659
+ */
1660
+ const renderConnectionConfigSchema = z.object({ provider: z.literal("render") });
1649
1661
  const syncConnectionConfigSchema = z.discriminatedUnion("provider", [
1650
1662
  vercelConnectionConfigSchema,
1651
1663
  cloudflareWorkersConnectionConfigSchema,
@@ -1653,7 +1665,8 @@ const syncConnectionConfigSchema = z.discriminatedUnion("provider", [
1653
1665
  cloudflareSecretsStoreConnectionConfigSchema,
1654
1666
  railwayConnectionConfigSchema,
1655
1667
  awsSecretsManagerConnectionConfigSchema,
1656
- awsParameterStoreConnectionConfigSchema
1668
+ awsParameterStoreConnectionConfigSchema,
1669
+ renderConnectionConfigSchema
1657
1670
  ]);
1658
1671
  /** Vercel's three deployment targets. A binding writes to one or more. */
1659
1672
  const VERCEL_TARGETS = [
@@ -1820,6 +1833,40 @@ const awsParameterStoreDestinationSchema = z.object({
1820
1833
  tier: z.enum(AWS_PARAMETER_TIERS).default("Standard"),
1821
1834
  kmsKeyId: awsKmsKeyIdSchema.optional()
1822
1835
  });
1836
+ /**
1837
+ * Render resource ids are `<prefix>-<slug>`, and the two prefixes below are the
1838
+ * documented ones: `srv-` for every service type, `crn-` for cron jobs, `evg-`
1839
+ * for an environment group.
1840
+ *
1841
+ * The patterns reject the *other* kind's prefix rather than requiring their own.
1842
+ * The mistake worth catching is pasting an env-group id into the service field
1843
+ * (or the reverse) — which is otherwise a 404 hours later inside an alarm, with
1844
+ * nobody watching. Requiring the positive prefix would also reject a valid id
1845
+ * the day Render introduces a new resource prefix, which is not our call to
1846
+ * make.
1847
+ */
1848
+ const renderServiceIdSchema = z.string().trim().regex(/^(?!evg-)[A-Za-z0-9_-]{1,64}$/, "must be a Render service ID (`srv-…` or `crn-…`), not an environment group");
1849
+ const renderEnvGroupIdSchema = z.string().trim().regex(/^(?!srv-|crn-)[A-Za-z0-9_-]{1,64}$/, "must be a Render environment group ID (`evg-…`), not a service");
1850
+ /** Environment variables set directly on one service. */
1851
+ const renderServiceDestinationSchema = z.object({
1852
+ provider: z.literal("render"),
1853
+ kind: z.literal("service"),
1854
+ /** Service id (`srv-…`, or `crn-…` for a cron job), from its dashboard URL. */
1855
+ serviceId: renderServiceIdSchema
1856
+ });
1857
+ /**
1858
+ * Environment variables in a shared environment group. Every service linked to
1859
+ * the group sees them, which is the point — and the reason a group binding is
1860
+ * worth thinking about twice: its blast radius is the link list, not one
1861
+ * service.
1862
+ */
1863
+ const renderEnvGroupDestinationSchema = z.object({
1864
+ provider: z.literal("render"),
1865
+ kind: z.literal("env-group"),
1866
+ /** Environment group id (`evg-…`), from its dashboard URL. */
1867
+ envGroupId: renderEnvGroupIdSchema
1868
+ });
1869
+ const renderDestinationSchema = z.discriminatedUnion("kind", [renderServiceDestinationSchema, renderEnvGroupDestinationSchema]);
1823
1870
  const syncDestinationSchema = z.discriminatedUnion("provider", [
1824
1871
  vercelDestinationSchema,
1825
1872
  cloudflareWorkersDestinationSchema,
@@ -1827,7 +1874,8 @@ const syncDestinationSchema = z.discriminatedUnion("provider", [
1827
1874
  cloudflareSecretsStoreDestinationSchema,
1828
1875
  railwayDestinationSchema,
1829
1876
  awsSecretsManagerDestinationSchema,
1830
- awsParameterStoreDestinationSchema
1877
+ awsParameterStoreDestinationSchema,
1878
+ renderDestinationSchema
1831
1879
  ]);
1832
1880
  /**
1833
1881
  * How seekrit secret names become destination key names. Applied in order:
@@ -3032,7 +3080,7 @@ function isCliSessionToken(value) {
3032
3080
  }
3033
3081
  //#endregion
3034
3082
  //#region package.json
3035
- var version = "0.36.0";
3083
+ var version = "0.37.0";
3036
3084
  //#endregion
3037
3085
  //#region ../../packages/api-client/src/index.ts
3038
3086
  var SeekritApiError = class extends Error {
@@ -6896,6 +6944,7 @@ function buildConfig(provider, options) {
6896
6944
  region: options.region,
6897
6945
  accessKeyId: options.accessKeyId
6898
6946
  };
6947
+ case "render": return { provider: "render" };
6899
6948
  }
6900
6949
  }
6901
6950
  /** Where inside the platform a binding writes. */
@@ -6969,6 +7018,22 @@ function buildDestination(provider, options) {
6969
7018
  tier: assertMember(options.tier, AWS_PARAMETER_TIERS, "--tier", "Standard"),
6970
7019
  ...options.kmsKeyId ? { kmsKeyId: options.kmsKeyId } : {}
6971
7020
  };
7021
+ case "render": {
7022
+ const serviceId = options.service?.trim();
7023
+ const envGroupId = options.envGroup?.trim();
7024
+ if (serviceId && envGroupId) fail("pass --service or --env-group for render, not both — a binding writes to one");
7025
+ if (serviceId) return {
7026
+ provider: "render",
7027
+ kind: "service",
7028
+ serviceId
7029
+ };
7030
+ if (envGroupId) return {
7031
+ provider: "render",
7032
+ kind: "env-group",
7033
+ envGroupId
7034
+ };
7035
+ return fail("--service (srv-…, or crn-… for a cron job) or --env-group (evg-…) is required for render");
7036
+ }
6972
7037
  }
6973
7038
  }
6974
7039
  /** One-line description of a destination, for list output. */
@@ -6981,6 +7046,7 @@ function describeDestination(destination) {
6981
7046
  case "railway": return `${destination.projectId} / ${destination.environmentId} (${destination.serviceId ? `service ${destination.serviceId}` : "shared"})`;
6982
7047
  case "aws-secrets-manager": return destination.layout === "json-bundle" ? `${destination.secretName} (json bundle)` : `${destination.pathPrefix ?? ""}* (secret per name)`;
6983
7048
  case "aws-parameter-store": return `${destination.path}* (${destination.type})`;
7049
+ case "render": return destination.kind === "service" ? destination.serviceId : `env group ${destination.envGroupId}`;
6984
7050
  }
6985
7051
  }
6986
7052
  /**
@@ -6988,7 +7054,7 @@ function describeDestination(destination) {
6988
7054
  * into accepting different ways of naming the same destination.
6989
7055
  */
6990
7056
  function destinationOptions(command) {
6991
- return command.option("--project <id>", "vercel: project id or name · cloudflare-pages: project name").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)").option("--skip-deploys", "railway: stage values without triggering a redeploy").option("--path <path>", "aws-parameter-store: hierarchy, e.g. /prod/storefront/ · aws-secrets-manager: 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");
7057
+ return command.option("--project <id>", "vercel: project id or name · cloudflare-pages: project name").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: 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-…)");
6992
7058
  }
6993
7059
  /** Find a connection by id or name — nobody keeps `syc_…` ids in their head. */
6994
7060
  async function resolveConnection(ctx, orgId, ref) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seekrit/cli",
3
- "version": "0.36.0",
3
+ "version": "0.37.0",
4
4
  "description": "End-to-end encrypted secrets manager CLI — inject decrypted secrets into any command.",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -28,8 +28,8 @@
28
28
  "tsdown": "^0.22.3",
29
29
  "vitest": "^4.1.9",
30
30
  "@seekrit/api-client": "0.0.1",
31
- "@seekrit/core": "0.0.1",
32
- "@seekrit/crypto": "0.0.1"
31
+ "@seekrit/crypto": "0.0.1",
32
+ "@seekrit/core": "0.0.1"
33
33
  },
34
34
  "scripts": {
35
35
  "build": "tsdown",