@seekrit/cli 0.35.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.
- package/dist/index.js +240 -10
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -669,7 +669,7 @@ const redisSha256VerifierSchema = z.string().regex(/^[0-9a-f]{64}$/, "must be a
|
|
|
669
669
|
*/
|
|
670
670
|
const awsRoleArnSchema = z.string().regex(/^arn:aws(?:-us-gov|-cn)?:iam::\d{12}:role\/[\w+=,.@/-]{1,512}$/, "must be an IAM role ARN (arn:aws:iam::<account>:role/<name>)");
|
|
671
671
|
/** An AWS region id, e.g. `us-east-1`, `eu-west-2`, `us-gov-west-1`. */
|
|
672
|
-
const awsRegionSchema = z.string().regex(/^[a-z]{2}(?:-[a-z]+)+-\d$/, "must be an AWS region id (e.g. us-east-1)");
|
|
672
|
+
const awsRegionSchema$1 = z.string().regex(/^[a-z]{2}(?:-[a-z]+)+-\d$/, "must be an AWS region id (e.g. us-east-1)");
|
|
673
673
|
/**
|
|
674
674
|
* An STS external id — the shared string a role's trust policy can require so a
|
|
675
675
|
* confused-deputy can't assume it. AWS allows a broad charset; we keep to the
|
|
@@ -811,7 +811,7 @@ const awsTargetConfigSchema = z.object({
|
|
|
811
811
|
provider: z.literal("aws"),
|
|
812
812
|
executor: z.literal("in_do"),
|
|
813
813
|
roleArn: awsRoleArnSchema,
|
|
814
|
-
region: awsRegionSchema,
|
|
814
|
+
region: awsRegionSchema$1,
|
|
815
815
|
externalId: awsExternalIdSchema.optional(),
|
|
816
816
|
sessionPolicy: z.string().min(1).max(4e3).optional(),
|
|
817
817
|
maxTtlSeconds: z.number().int().min(900).max(AWS_MAX_TTL_SECONDS).optional()
|
|
@@ -1518,7 +1518,10 @@ const SYNC_PROVIDER_KINDS = [
|
|
|
1518
1518
|
"cloudflare-workers",
|
|
1519
1519
|
"cloudflare-pages",
|
|
1520
1520
|
"cloudflare-secrets-store",
|
|
1521
|
-
"railway"
|
|
1521
|
+
"railway",
|
|
1522
|
+
"aws-secrets-manager",
|
|
1523
|
+
"aws-parameter-store",
|
|
1524
|
+
"render"
|
|
1522
1525
|
];
|
|
1523
1526
|
z.enum(SYNC_PROVIDER_KINDS);
|
|
1524
1527
|
/**
|
|
@@ -1600,12 +1603,70 @@ const railwayConnectionConfigSchema = z.object({
|
|
|
1600
1603
|
provider: z.literal("railway"),
|
|
1601
1604
|
tokenKind: z.enum(RAILWAY_TOKEN_KINDS).default("account")
|
|
1602
1605
|
});
|
|
1606
|
+
/**
|
|
1607
|
+
* An AWS region id (`us-east-1`, `eu-central-1`, `us-gov-west-1`).
|
|
1608
|
+
*
|
|
1609
|
+
* Validated by shape rather than against a list, because AWS adds regions
|
|
1610
|
+
* faster than we ship. The endpoint host is built from this string, so a typo
|
|
1611
|
+
* would otherwise surface as a DNS failure inside an alarm with nobody
|
|
1612
|
+
* watching — which is a much worse place to learn about it than this form.
|
|
1613
|
+
*/
|
|
1614
|
+
const awsRegionSchema = z.string().trim().regex(/^[a-z]{2}(-[a-z]+)+-\d$/, "must be an AWS region ID, e.g. us-east-1");
|
|
1615
|
+
/**
|
|
1616
|
+
* The IAM access key id seekrit signs with.
|
|
1617
|
+
*
|
|
1618
|
+
* This lives in `config` — the *non-secret* half — on purpose: an access key id
|
|
1619
|
+
* is an identifier, not a credential. It appears in CloudTrail, in the IAM
|
|
1620
|
+
* console, and in the `Authorization` header of every signed request; only the
|
|
1621
|
+
* **secret access key** is secret, and that is what gets wrapped to the
|
|
1622
|
+
* connection's public key. Keeping the id here also lets the dashboard say
|
|
1623
|
+
* which key a connection is using, which is the first thing you want to know
|
|
1624
|
+
* when a connection starts failing after a key rotation.
|
|
1625
|
+
*
|
|
1626
|
+
* Long-lived IAM user keys only. `ASIA…` session credentials from STS expire
|
|
1627
|
+
* within hours, and a sync connection has to keep working unattended.
|
|
1628
|
+
*/
|
|
1629
|
+
const awsAccessKeyIdSchema = z.string().trim().regex(/^[A-Z0-9]{16,128}$/, "must be an AWS access key ID, e.g. AKIAIOSFODNN7EXAMPLE");
|
|
1630
|
+
/**
|
|
1631
|
+
* AWS account scope, shared by both AWS providers: which region to call and
|
|
1632
|
+
* which key to sign with. There is no account id — every endpoint seekrit calls
|
|
1633
|
+
* is reached through the regional host and authorizes off the signature, so the
|
|
1634
|
+
* account is whichever one the key belongs to.
|
|
1635
|
+
*
|
|
1636
|
+
* Two providers rather than one `aws` with a mode field, for the same reason
|
|
1637
|
+
* the three Cloudflare kinds are separate: different APIs, different
|
|
1638
|
+
* destinations, different IAM actions.
|
|
1639
|
+
*/
|
|
1640
|
+
const awsSecretsManagerConnectionConfigSchema = z.object({
|
|
1641
|
+
provider: z.literal("aws-secrets-manager"),
|
|
1642
|
+
region: awsRegionSchema,
|
|
1643
|
+
accessKeyId: awsAccessKeyIdSchema
|
|
1644
|
+
});
|
|
1645
|
+
const awsParameterStoreConnectionConfigSchema = z.object({
|
|
1646
|
+
provider: z.literal("aws-parameter-store"),
|
|
1647
|
+
region: awsRegionSchema,
|
|
1648
|
+
accessKeyId: awsAccessKeyIdSchema
|
|
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") });
|
|
1603
1661
|
const syncConnectionConfigSchema = z.discriminatedUnion("provider", [
|
|
1604
1662
|
vercelConnectionConfigSchema,
|
|
1605
1663
|
cloudflareWorkersConnectionConfigSchema,
|
|
1606
1664
|
cloudflarePagesConnectionConfigSchema,
|
|
1607
1665
|
cloudflareSecretsStoreConnectionConfigSchema,
|
|
1608
|
-
railwayConnectionConfigSchema
|
|
1666
|
+
railwayConnectionConfigSchema,
|
|
1667
|
+
awsSecretsManagerConnectionConfigSchema,
|
|
1668
|
+
awsParameterStoreConnectionConfigSchema,
|
|
1669
|
+
renderConnectionConfigSchema
|
|
1609
1670
|
]);
|
|
1610
1671
|
/** Vercel's three deployment targets. A binding writes to one or more. */
|
|
1611
1672
|
const VERCEL_TARGETS = [
|
|
@@ -1696,12 +1757,125 @@ const railwayDestinationSchema = z.object({
|
|
|
1696
1757
|
*/
|
|
1697
1758
|
skipDeploys: z.boolean().optional()
|
|
1698
1759
|
});
|
|
1760
|
+
/**
|
|
1761
|
+
* A customer-managed KMS key to encrypt with, as a key id, ARN, or alias
|
|
1762
|
+
* (`alias/seekrit`). Omitted means the AWS-managed default for that service
|
|
1763
|
+
* (`aws/secretsmanager`, `aws/ssm`), which is what most accounts want.
|
|
1764
|
+
*
|
|
1765
|
+
* Deliberately loose: a KMS key can be named five different ways, half of them
|
|
1766
|
+
* cross-account ARNs, and rejecting a valid one here would be worse than
|
|
1767
|
+
* letting KMS give its own (very clear) error.
|
|
1768
|
+
*/
|
|
1769
|
+
const awsKmsKeyIdSchema = z.string().trim().min(1).max(2048);
|
|
1770
|
+
/**
|
|
1771
|
+
* How a binding lays its secrets out in Secrets Manager.
|
|
1772
|
+
*
|
|
1773
|
+
* - `secret-per-name` — one AWS secret per seekrit secret. The direct
|
|
1774
|
+
* translation, and what you want if consumers read secrets individually.
|
|
1775
|
+
* - `json-bundle` — every value as one JSON object in a single AWS secret. The
|
|
1776
|
+
* shape ECS task definitions and Lambda read with `secret-arn:json-key::`,
|
|
1777
|
+
* and the reason it exists is billing: Secrets Manager charges per secret per
|
|
1778
|
+
* month, so fifty names cost fifty times as much stored separately.
|
|
1779
|
+
*/
|
|
1780
|
+
const AWS_SECRETS_MANAGER_LAYOUTS = ["secret-per-name", "json-bundle"];
|
|
1781
|
+
/**
|
|
1782
|
+
* Where in Secrets Manager a binding writes.
|
|
1783
|
+
*
|
|
1784
|
+
* `pathPrefix` exists rather than reusing {@link NameTransform}'s `prefix`
|
|
1785
|
+
* because the two answer different questions: a name transform produces a
|
|
1786
|
+
* *variable name* (`[A-Za-z0-9_]`, no slashes), while this produces a
|
|
1787
|
+
* *namespace* — `prod/storefront/` — and slashes are the whole point of it.
|
|
1788
|
+
*/
|
|
1789
|
+
const awsSecretsManagerDestinationSchema = z.object({
|
|
1790
|
+
provider: z.literal("aws-secrets-manager"),
|
|
1791
|
+
layout: z.enum(AWS_SECRETS_MANAGER_LAYOUTS).default("secret-per-name"),
|
|
1792
|
+
/**
|
|
1793
|
+
* `secret-per-name` only: prepended to every secret's name, e.g.
|
|
1794
|
+
* `prod/storefront/`. Optional, but strongly advised in an account that
|
|
1795
|
+
* holds anything else — without it a binding writes at the root of a
|
|
1796
|
+
* namespace it does not own.
|
|
1797
|
+
*/
|
|
1798
|
+
pathPrefix: z.string().trim().max(400).regex(/^[A-Za-z0-9/_+=.@-]*$/, "may contain letters, digits, and / _ + = . @ -").optional(),
|
|
1799
|
+
/** `json-bundle` only: the one secret that holds every value, e.g. `prod/storefront/env`. */
|
|
1800
|
+
secretName: z.string().trim().min(1).max(512).regex(/^[A-Za-z0-9/_+=.@-]+$/, "may contain letters, digits, and / _ + = . @ -").optional(),
|
|
1801
|
+
kmsKeyId: awsKmsKeyIdSchema.optional()
|
|
1802
|
+
}).refine((d) => d.layout !== "json-bundle" || d.secretName !== void 0, {
|
|
1803
|
+
message: "a json-bundle destination needs the name of the secret to write",
|
|
1804
|
+
path: ["secretName"]
|
|
1805
|
+
});
|
|
1806
|
+
/** Parameter Store's two value types. `SecureString` is KMS-encrypted; `String` is not. */
|
|
1807
|
+
const AWS_PARAMETER_TYPES = ["SecureString", "String"];
|
|
1808
|
+
/** Parameter Store's storage tiers. Standard is free and caps values at 4KB. */
|
|
1809
|
+
const AWS_PARAMETER_TIERS = [
|
|
1810
|
+
"Standard",
|
|
1811
|
+
"Advanced",
|
|
1812
|
+
"Intelligent-Tiering"
|
|
1813
|
+
];
|
|
1814
|
+
/**
|
|
1815
|
+
* The Parameter Store hierarchy a binding owns, e.g. `/prod/storefront/`.
|
|
1816
|
+
*
|
|
1817
|
+
* A path rather than a free-form prefix because that is what the API is built
|
|
1818
|
+
* around: `GetParametersByPath` is how an application reads a whole
|
|
1819
|
+
* environment in one call, and it only works on `/`-delimited names. Leading
|
|
1820
|
+
* and trailing slashes are required so the binding's names concatenate
|
|
1821
|
+
* unambiguously — `/prod/storefront/` + `DB_URL`.
|
|
1822
|
+
*/
|
|
1823
|
+
const awsParameterStoreDestinationSchema = z.object({
|
|
1824
|
+
provider: z.literal("aws-parameter-store"),
|
|
1825
|
+
/** Must start and end with `/`. `aws`/`ssm` are reserved by AWS as the first segment. */
|
|
1826
|
+
path: z.string().trim().max(1011).regex(/^\/([A-Za-z0-9_.-]+\/)*$/, "must be a parameter path like /prod/storefront/"),
|
|
1827
|
+
type: z.enum(AWS_PARAMETER_TYPES).default("SecureString"),
|
|
1828
|
+
/**
|
|
1829
|
+
* Standard caps a value at 4KB and costs nothing; Advanced raises that to 8KB
|
|
1830
|
+
* and is billed per parameter per month. `Intelligent-Tiering` lets AWS pick,
|
|
1831
|
+
* upgrading only the parameters that need it.
|
|
1832
|
+
*/
|
|
1833
|
+
tier: z.enum(AWS_PARAMETER_TIERS).default("Standard"),
|
|
1834
|
+
kmsKeyId: awsKmsKeyIdSchema.optional()
|
|
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]);
|
|
1699
1870
|
const syncDestinationSchema = z.discriminatedUnion("provider", [
|
|
1700
1871
|
vercelDestinationSchema,
|
|
1701
1872
|
cloudflareWorkersDestinationSchema,
|
|
1702
1873
|
cloudflarePagesDestinationSchema,
|
|
1703
1874
|
cloudflareSecretsStoreDestinationSchema,
|
|
1704
|
-
railwayDestinationSchema
|
|
1875
|
+
railwayDestinationSchema,
|
|
1876
|
+
awsSecretsManagerDestinationSchema,
|
|
1877
|
+
awsParameterStoreDestinationSchema,
|
|
1878
|
+
renderDestinationSchema
|
|
1705
1879
|
]);
|
|
1706
1880
|
/**
|
|
1707
1881
|
* How seekrit secret names become destination key names. Applied in order:
|
|
@@ -2906,7 +3080,7 @@ function isCliSessionToken(value) {
|
|
|
2906
3080
|
}
|
|
2907
3081
|
//#endregion
|
|
2908
3082
|
//#region package.json
|
|
2909
|
-
var version = "0.
|
|
3083
|
+
var version = "0.37.0";
|
|
2910
3084
|
//#endregion
|
|
2911
3085
|
//#region ../../packages/api-client/src/index.ts
|
|
2912
3086
|
var SeekritApiError = class extends Error {
|
|
@@ -6728,6 +6902,12 @@ function assertRailwayId(value, flag) {
|
|
|
6728
6902
|
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(`${flag} should be a Railway UUID, not "${id}"`);
|
|
6729
6903
|
return id;
|
|
6730
6904
|
}
|
|
6905
|
+
/** Reject a single value outside a known set, naming the choices. */
|
|
6906
|
+
function assertMember(value, allowed, flag, fallback) {
|
|
6907
|
+
if (value === void 0) return fallback;
|
|
6908
|
+
if (!allowed.includes(value)) fail(`unknown ${flag} "${value}" — one of: ${allowed.join(", ")}`);
|
|
6909
|
+
return value;
|
|
6910
|
+
}
|
|
6731
6911
|
function assertProvider(value) {
|
|
6732
6912
|
if (!SYNC_PROVIDER_KINDS.includes(value)) fail(`unknown provider "${value}" — one of: ${SYNC_PROVIDER_KINDS.join(", ")}`);
|
|
6733
6913
|
return value;
|
|
@@ -6755,6 +6935,16 @@ function buildConfig(provider, options) {
|
|
|
6755
6935
|
tokenKind
|
|
6756
6936
|
};
|
|
6757
6937
|
}
|
|
6938
|
+
case "aws-secrets-manager":
|
|
6939
|
+
case "aws-parameter-store":
|
|
6940
|
+
if (!options.region) fail(`--region is required for ${provider} — an AWS region ID, e.g. us-east-1`);
|
|
6941
|
+
if (!options.accessKeyId) fail(`--access-key-id is required for ${provider} — the IAM access key ID (AKIA…)`);
|
|
6942
|
+
return {
|
|
6943
|
+
provider,
|
|
6944
|
+
region: options.region,
|
|
6945
|
+
accessKeyId: options.accessKeyId
|
|
6946
|
+
};
|
|
6947
|
+
case "render": return { provider: "render" };
|
|
6758
6948
|
}
|
|
6759
6949
|
}
|
|
6760
6950
|
/** Where inside the platform a binding writes. */
|
|
@@ -6808,6 +6998,42 @@ function buildDestination(provider, options) {
|
|
|
6808
6998
|
...options.skipDeploys ? { skipDeploys: true } : {}
|
|
6809
6999
|
};
|
|
6810
7000
|
}
|
|
7001
|
+
case "aws-secrets-manager": {
|
|
7002
|
+
const layout = assertMember(options.layout, AWS_SECRETS_MANAGER_LAYOUTS, "--layout", "secret-per-name");
|
|
7003
|
+
if (layout === "json-bundle" && !options.secretName) fail("--secret-name is required for --layout json-bundle (the one secret to write)");
|
|
7004
|
+
return {
|
|
7005
|
+
provider: "aws-secrets-manager",
|
|
7006
|
+
layout,
|
|
7007
|
+
...options.path ? { pathPrefix: options.path } : {},
|
|
7008
|
+
...options.secretName ? { secretName: options.secretName } : {},
|
|
7009
|
+
...options.kmsKeyId ? { kmsKeyId: options.kmsKeyId } : {}
|
|
7010
|
+
};
|
|
7011
|
+
}
|
|
7012
|
+
case "aws-parameter-store":
|
|
7013
|
+
if (!options.path) fail("--path is required for aws-parameter-store, e.g. /prod/storefront/");
|
|
7014
|
+
return {
|
|
7015
|
+
provider: "aws-parameter-store",
|
|
7016
|
+
path: options.path,
|
|
7017
|
+
type: assertMember(options.paramType, AWS_PARAMETER_TYPES, "--param-type", "SecureString"),
|
|
7018
|
+
tier: assertMember(options.tier, AWS_PARAMETER_TIERS, "--tier", "Standard"),
|
|
7019
|
+
...options.kmsKeyId ? { kmsKeyId: options.kmsKeyId } : {}
|
|
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
|
+
}
|
|
6811
7037
|
}
|
|
6812
7038
|
}
|
|
6813
7039
|
/** One-line description of a destination, for list output. */
|
|
@@ -6818,6 +7044,9 @@ function describeDestination(destination) {
|
|
|
6818
7044
|
case "cloudflare-pages": return `${destination.projectName} (${destination.environments.join(", ")})`;
|
|
6819
7045
|
case "cloudflare-secrets-store": return `store ${destination.storeId} (${destination.scopes.join(", ")})`;
|
|
6820
7046
|
case "railway": return `${destination.projectId} / ${destination.environmentId} (${destination.serviceId ? `service ${destination.serviceId}` : "shared"})`;
|
|
7047
|
+
case "aws-secrets-manager": return destination.layout === "json-bundle" ? `${destination.secretName} (json bundle)` : `${destination.pathPrefix ?? ""}* (secret per name)`;
|
|
7048
|
+
case "aws-parameter-store": return `${destination.path}* (${destination.type})`;
|
|
7049
|
+
case "render": return destination.kind === "service" ? destination.serviceId : `env group ${destination.envGroupId}`;
|
|
6821
7050
|
}
|
|
6822
7051
|
}
|
|
6823
7052
|
/**
|
|
@@ -6825,7 +7054,7 @@ function describeDestination(destination) {
|
|
|
6825
7054
|
* into accepting different ways of naming the same destination.
|
|
6826
7055
|
*/
|
|
6827
7056
|
function destinationOptions(command) {
|
|
6828
|
-
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");
|
|
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-…)");
|
|
6829
7058
|
}
|
|
6830
7059
|
/** Find a connection by id or name — nobody keeps `syc_…` ids in their head. */
|
|
6831
7060
|
async function resolveConnection(ctx, orgId, ref) {
|
|
@@ -6849,12 +7078,13 @@ function registerSyncCommands(program) {
|
|
|
6849
7078
|
col("id", (c) => c.id)
|
|
6850
7079
|
], "no connections — add one with `seekrit sync connect`"));
|
|
6851
7080
|
});
|
|
6852
|
-
sync.command("connect").description("register a destination account (reads its API token from stdin)").option("--org <slug>").requiredOption("--name <name>", "what to call this account, e.g. acme-vercel").option("--provider <kind>", SYNC_PROVIDER_KINDS.join(" | "), "vercel").option("--team-id <id>", "vercel: Team id (omit for a personal account)").option("--token-kind <kind>", `railway: ${RAILWAY_TOKEN_KINDS.join(" | ")}`, "account").option("--account-id <id>", "cloudflare: account ID (32 hex, from the dashboard sidebar)").action(async (options) => {
|
|
7081
|
+
sync.command("connect").description("register a destination account (reads its API token from stdin)").option("--org <slug>").requiredOption("--name <name>", "what to call this account, e.g. acme-vercel").option("--provider <kind>", SYNC_PROVIDER_KINDS.join(" | "), "vercel").option("--team-id <id>", "vercel: Team id (omit for a personal account)").option("--token-kind <kind>", `railway: ${RAILWAY_TOKEN_KINDS.join(" | ")}`, "account").option("--account-id <id>", "cloudflare: account ID (32 hex, from the dashboard sidebar)").option("--region <region>", "aws: region ID, e.g. us-east-1").option("--access-key-id <id>", "aws: IAM access key ID (the secret key is read from stdin)").action(async (options) => {
|
|
6853
7082
|
const provider = assertProvider(options.provider);
|
|
6854
7083
|
const ctx = buildContext();
|
|
6855
7084
|
const ref = await resolveOrg(ctx, options.org);
|
|
6856
|
-
const
|
|
6857
|
-
|
|
7085
|
+
const noun = provider.startsWith("aws-") ? "secret access key" : "API token";
|
|
7086
|
+
const credential = (process.stdin.isTTY ? await promptHidden(`${provider} ${noun}: `) : await readStdin()).trim();
|
|
7087
|
+
if (!credential) fail(`no ${noun} given`);
|
|
6858
7088
|
const id = randomId("syc");
|
|
6859
7089
|
const { publicKeyJwk } = await ctx.client.getSyncConnectionKey(ref.id, id);
|
|
6860
7090
|
const created = await ctx.client.createSyncConnection(ref.id, {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@seekrit/cli",
|
|
3
|
-
"version": "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": {
|
|
@@ -27,9 +27,9 @@
|
|
|
27
27
|
"@types/node": "^26.1.0",
|
|
28
28
|
"tsdown": "^0.22.3",
|
|
29
29
|
"vitest": "^4.1.9",
|
|
30
|
-
"@seekrit/core": "0.0.1",
|
|
31
30
|
"@seekrit/api-client": "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",
|