@seekrit/cli 2.6.0 → 2.7.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 +331 -9
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1752,6 +1752,229 @@ function prettyJsonOrRaw(value) {
|
|
|
1752
1752
|
const inspection = inspectJsonValue(value);
|
|
1753
1753
|
return inspection.kind === "json" ? inspection.pretty : value;
|
|
1754
1754
|
}
|
|
1755
|
+
// ../../packages/core/src/managed-providers/aws-cache.ts
|
|
1756
|
+
const cacheRegionSchema = z$1.string().regex(/^[a-z]{2}(?:-[a-z]+)+-\d$/);
|
|
1757
|
+
const cacheGroupSchema = z$1.string().min(1).max(128).regex(/^[a-zA-Z][a-zA-Z0-9-]*$/);
|
|
1758
|
+
const cacheAccessSchema = z$1.string().min(1).max(4096).refine((value) => /^on(?:\s|$)/.test(value) && !/(?:^|\s)(?:nopass|resetpass|[>#<])/.test(value), "ACL must enable the user and must not contain password directives");
|
|
1759
|
+
// ../../packages/core/src/managed-providers/common.ts
|
|
1760
|
+
const managedEndpointSchema = z$1.string().url().max(2048).refine((value) => {
|
|
1761
|
+
try {
|
|
1762
|
+
const url = new URL(value);
|
|
1763
|
+
url.port = "";
|
|
1764
|
+
return connectUrlSchema.safeParse(url.toString()).success;
|
|
1765
|
+
} catch {
|
|
1766
|
+
return false;
|
|
1767
|
+
}
|
|
1768
|
+
}, "use a public HTTPS endpoint without embedded credentials, query, or fragment");
|
|
1769
|
+
const managedTtlSchema = z$1.number().int().min(60).max(604800).optional();
|
|
1770
|
+
const nameSchema$1 = z$1.string().min(1).max(128).regex(/^[a-zA-Z_][a-zA-Z0-9_-]*$/);
|
|
1771
|
+
// ../../packages/core/src/managed-providers/memorydb.ts
|
|
1772
|
+
const memorydbTargetConfigSchema = z$1.object({
|
|
1773
|
+
provider: z$1.literal("memorydb"),
|
|
1774
|
+
executor: z$1.literal("in_do"),
|
|
1775
|
+
region: cacheRegionSchema,
|
|
1776
|
+
aclName: cacheGroupSchema,
|
|
1777
|
+
accessString: cacheAccessSchema,
|
|
1778
|
+
maxTtlSeconds: managedTtlSchema
|
|
1779
|
+
}).strict();
|
|
1780
|
+
// ../../packages/core/src/managed-providers/elasticache.ts
|
|
1781
|
+
const elasticacheTargetConfigSchema = z$1.object({
|
|
1782
|
+
provider: z$1.literal("elasticache"),
|
|
1783
|
+
executor: z$1.literal("in_do"),
|
|
1784
|
+
region: cacheRegionSchema,
|
|
1785
|
+
userGroupId: cacheGroupSchema,
|
|
1786
|
+
engine: z$1.enum(["redis", "valkey"]).default("redis"),
|
|
1787
|
+
accessString: cacheAccessSchema,
|
|
1788
|
+
maxTtlSeconds: managedTtlSchema
|
|
1789
|
+
}).strict();
|
|
1790
|
+
// ../../packages/core/src/managed-providers/snowflake.ts
|
|
1791
|
+
const identifier = z$1.string().regex(/^[a-zA-Z_][a-zA-Z0-9_$]{0,254}$/).transform((value) => value.toUpperCase());
|
|
1792
|
+
const snowflakeTargetConfigSchema = z$1.object({
|
|
1793
|
+
provider: z$1.literal("snowflake"),
|
|
1794
|
+
executor: z$1.literal("in_do"),
|
|
1795
|
+
account: z$1.string().min(1).max(200).regex(/^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)*$/i),
|
|
1796
|
+
adminRole: identifier.default("USERADMIN"),
|
|
1797
|
+
roles: z$1.array(identifier).min(1).max(50),
|
|
1798
|
+
warehouse: identifier.optional(),
|
|
1799
|
+
networkPolicy: identifier.optional(),
|
|
1800
|
+
maxTtlSeconds: managedTtlSchema
|
|
1801
|
+
}).strict();
|
|
1802
|
+
// ../../packages/core/src/managed-providers/couchbase.ts
|
|
1803
|
+
const resourceName = z$1.string().min(1).max(255);
|
|
1804
|
+
const access = z$1.object({
|
|
1805
|
+
privileges: z$1.array(z$1.enum(["data_reader", "data_writer"])).min(1).max(2),
|
|
1806
|
+
resources: z$1.object({ buckets: z$1.array(z$1.object({
|
|
1807
|
+
name: resourceName,
|
|
1808
|
+
scopes: z$1.array(z$1.object({
|
|
1809
|
+
name: resourceName,
|
|
1810
|
+
collections: z$1.array(resourceName).min(1).max(100).optional()
|
|
1811
|
+
}).strict()).min(1).max(100).optional()
|
|
1812
|
+
}).strict()).min(1).max(100) }).strict()
|
|
1813
|
+
}).strict();
|
|
1814
|
+
const couchbaseTargetConfigSchema = z$1.object({
|
|
1815
|
+
provider: z$1.literal("couchbase"),
|
|
1816
|
+
executor: z$1.literal("in_do"),
|
|
1817
|
+
organizationId: z$1.string().uuid(),
|
|
1818
|
+
projectId: z$1.string().uuid(),
|
|
1819
|
+
clusterId: z$1.string().uuid(),
|
|
1820
|
+
credentialType: z$1.enum(["basic", "advanced"]).default("basic"),
|
|
1821
|
+
access: z$1.array(access).min(1).max(100).optional(),
|
|
1822
|
+
userRoles: z$1.array(resourceName).min(1).max(100).optional(),
|
|
1823
|
+
maxTtlSeconds: managedTtlSchema
|
|
1824
|
+
}).strict().superRefine((value, ctx) => {
|
|
1825
|
+
if (value.credentialType === "basic" ? !value.access || !!value.userRoles : !value.userRoles || !!value.access) ctx.addIssue({
|
|
1826
|
+
code: "custom",
|
|
1827
|
+
message: "basic credentials require access only; advanced credentials require userRoles only"
|
|
1828
|
+
});
|
|
1829
|
+
});
|
|
1830
|
+
// ../../packages/core/src/managed-providers/mongodb-atlas.ts
|
|
1831
|
+
const mongoAtlasTargetConfigSchema = z$1.object({
|
|
1832
|
+
provider: z$1.literal("mongodb-atlas"),
|
|
1833
|
+
executor: z$1.literal("in_do"),
|
|
1834
|
+
projectId: z$1.string().regex(/^[a-f0-9]{24}$/),
|
|
1835
|
+
roles: z$1.array(z$1.object({
|
|
1836
|
+
roleName: z$1.string().min(1).max(128),
|
|
1837
|
+
databaseName: z$1.string().min(1).max(64),
|
|
1838
|
+
collectionName: z$1.string().min(1).max(128).optional()
|
|
1839
|
+
}).strict()).min(1).max(100),
|
|
1840
|
+
clusters: z$1.array(z$1.string().min(1).max(64)).min(1).max(100),
|
|
1841
|
+
maxTtlSeconds: managedTtlSchema
|
|
1842
|
+
}).strict();
|
|
1843
|
+
// ../../packages/core/src/managed-providers/milvus.ts
|
|
1844
|
+
const milvusTargetConfigSchema = z$1.object({
|
|
1845
|
+
provider: z$1.literal("milvus"),
|
|
1846
|
+
executor: z$1.literal("in_do"),
|
|
1847
|
+
endpoint: managedEndpointSchema,
|
|
1848
|
+
roles: z$1.array(z$1.string().regex(/^[a-zA-Z][a-zA-Z0-9_]{0,127}$/)).min(1).max(50),
|
|
1849
|
+
maxTtlSeconds: managedTtlSchema
|
|
1850
|
+
}).strict();
|
|
1851
|
+
// ../../packages/core/src/managed-providers/rabbitmq.ts
|
|
1852
|
+
const rabbitmqTargetConfigSchema = z$1.object({
|
|
1853
|
+
provider: z$1.literal("rabbitmq"),
|
|
1854
|
+
executor: z$1.literal("in_do"),
|
|
1855
|
+
endpoint: managedEndpointSchema,
|
|
1856
|
+
vhost: z$1.string().min(1).max(255),
|
|
1857
|
+
configure: z$1.string().max(2048).default("^$"),
|
|
1858
|
+
write: z$1.string().max(2048).default("^$"),
|
|
1859
|
+
read: z$1.string().max(2048).default("^$"),
|
|
1860
|
+
maxTtlSeconds: managedTtlSchema
|
|
1861
|
+
}).strict();
|
|
1862
|
+
// ../../packages/core/src/managed-providers/clickhouse.ts
|
|
1863
|
+
const clickhouseTargetConfigSchema = z$1.object({
|
|
1864
|
+
provider: z$1.literal("clickhouse"),
|
|
1865
|
+
executor: z$1.literal("in_do"),
|
|
1866
|
+
endpoint: managedEndpointSchema,
|
|
1867
|
+
roles: z$1.array(nameSchema$1).min(1).max(50),
|
|
1868
|
+
database: nameSchema$1.optional(),
|
|
1869
|
+
cluster: nameSchema$1.optional(),
|
|
1870
|
+
maxTtlSeconds: managedTtlSchema
|
|
1871
|
+
}).strict();
|
|
1872
|
+
// ../../packages/core/src/managed-providers/elasticsearch.ts
|
|
1873
|
+
const role = z$1.object({
|
|
1874
|
+
cluster: z$1.array(z$1.string().min(1).max(100)).max(100).default([]),
|
|
1875
|
+
indices: z$1.array(z$1.object({
|
|
1876
|
+
names: z$1.array(z$1.string().min(1).max(256)).min(1).max(100),
|
|
1877
|
+
privileges: z$1.array(z$1.string().min(1).max(100)).min(1).max(100),
|
|
1878
|
+
allow_restricted_indices: z$1.literal(false).optional()
|
|
1879
|
+
}).strict()).max(100).default([])
|
|
1880
|
+
}).strict();
|
|
1881
|
+
const elasticsearchTargetConfigSchema = z$1.object({
|
|
1882
|
+
provider: z$1.literal("elasticsearch"),
|
|
1883
|
+
executor: z$1.literal("in_do"),
|
|
1884
|
+
endpoint: managedEndpointSchema,
|
|
1885
|
+
credentialType: z$1.enum(["user", "api_key"]).default("user"),
|
|
1886
|
+
roles: z$1.array(z$1.string().min(1).max(128)).min(1).max(100).optional(),
|
|
1887
|
+
roleDescriptors: z$1.record(z$1.string().min(1).max(128), role).refine((value) => Object.keys(value).length > 0 && Object.keys(value).length <= 20, "supply explicit key permissions").optional(),
|
|
1888
|
+
maxTtlSeconds: managedTtlSchema
|
|
1889
|
+
}).strict().superRefine((value, ctx) => {
|
|
1890
|
+
if (value.credentialType === "user" && !value.roles?.length) ctx.addIssue({
|
|
1891
|
+
code: "custom",
|
|
1892
|
+
path: ["roles"],
|
|
1893
|
+
message: "select at least one user role"
|
|
1894
|
+
});
|
|
1895
|
+
if (value.credentialType === "api_key" && !value.roleDescriptors) ctx.addIssue({
|
|
1896
|
+
code: "custom",
|
|
1897
|
+
path: ["roleDescriptors"],
|
|
1898
|
+
message: "supply explicit key permissions"
|
|
1899
|
+
});
|
|
1900
|
+
});
|
|
1901
|
+
// ../../packages/core/src/managed-leases.ts
|
|
1902
|
+
/** Providers whose credential is generated by the broker or upstream service. */
|
|
1903
|
+
const MANAGED_LEASE_KINDS = [
|
|
1904
|
+
"openrouter",
|
|
1905
|
+
"tailscale",
|
|
1906
|
+
"elasticsearch",
|
|
1907
|
+
"clickhouse",
|
|
1908
|
+
"rabbitmq",
|
|
1909
|
+
"milvus",
|
|
1910
|
+
"mongodb-atlas",
|
|
1911
|
+
"couchbase",
|
|
1912
|
+
"snowflake",
|
|
1913
|
+
"elasticache",
|
|
1914
|
+
"memorydb"
|
|
1915
|
+
];
|
|
1916
|
+
const openRouterTargetConfigSchema = z$1.object({
|
|
1917
|
+
provider: z$1.literal("openrouter"),
|
|
1918
|
+
executor: z$1.literal("in_do"),
|
|
1919
|
+
workspaceId: z$1.string().uuid().optional(),
|
|
1920
|
+
creditLimit: z$1.number().finite().nonnegative(),
|
|
1921
|
+
limitReset: z$1.enum([
|
|
1922
|
+
"daily",
|
|
1923
|
+
"weekly",
|
|
1924
|
+
"monthly"
|
|
1925
|
+
]).optional(),
|
|
1926
|
+
includeByokInLimit: z$1.boolean().optional(),
|
|
1927
|
+
maxTtlSeconds: z$1.number().int().min(60).max(604800).optional()
|
|
1928
|
+
}).strict();
|
|
1929
|
+
const tailscaleTargetConfigSchema = z$1.object({
|
|
1930
|
+
provider: z$1.literal("tailscale"),
|
|
1931
|
+
executor: z$1.literal("in_do"),
|
|
1932
|
+
tailnet: z$1.string().min(1).max(253).regex(/^[a-zA-Z0-9@._-]+$/),
|
|
1933
|
+
credentialType: z$1.enum([
|
|
1934
|
+
"auth",
|
|
1935
|
+
"client",
|
|
1936
|
+
"federated"
|
|
1937
|
+
]),
|
|
1938
|
+
tags: z$1.array(z$1.string().regex(/^tag:[a-zA-Z0-9_-]+$/)).max(100).default([]),
|
|
1939
|
+
reusable: z$1.boolean().default(false),
|
|
1940
|
+
ephemeral: z$1.boolean().default(true),
|
|
1941
|
+
preauthorized: z$1.boolean().default(false),
|
|
1942
|
+
scopes: z$1.array(z$1.string().min(1).max(128)).max(100).default([]),
|
|
1943
|
+
issuer: z$1.string().url().optional(),
|
|
1944
|
+
audience: z$1.string().min(1).max(2048).optional(),
|
|
1945
|
+
subject: z$1.string().min(1).max(2048).optional(),
|
|
1946
|
+
maxTtlSeconds: z$1.number().int().min(60).max(604800).optional()
|
|
1947
|
+
}).strict().superRefine((value, ctx) => {
|
|
1948
|
+
if (value.credentialType !== "auth" && !value.scopes.length) ctx.addIssue({
|
|
1949
|
+
code: "custom",
|
|
1950
|
+
path: ["scopes"],
|
|
1951
|
+
message: "select at least one scope"
|
|
1952
|
+
});
|
|
1953
|
+
if (value.credentialType === "federated" && (!value.issuer?.startsWith("https://") || !value.audience || !value.subject)) ctx.addIssue({
|
|
1954
|
+
code: "custom",
|
|
1955
|
+
path: ["issuer"],
|
|
1956
|
+
message: "federation requires HTTPS issuer, audience, and subject"
|
|
1957
|
+
});
|
|
1958
|
+
});
|
|
1959
|
+
const managedTargetConfigSchema = z$1.discriminatedUnion("provider", [
|
|
1960
|
+
clickhouseTargetConfigSchema,
|
|
1961
|
+
rabbitmqTargetConfigSchema,
|
|
1962
|
+
milvusTargetConfigSchema,
|
|
1963
|
+
mongoAtlasTargetConfigSchema,
|
|
1964
|
+
couchbaseTargetConfigSchema,
|
|
1965
|
+
snowflakeTargetConfigSchema,
|
|
1966
|
+
elasticacheTargetConfigSchema,
|
|
1967
|
+
memorydbTargetConfigSchema,
|
|
1968
|
+
openRouterTargetConfigSchema,
|
|
1969
|
+
tailscaleTargetConfigSchema,
|
|
1970
|
+
elasticsearchTargetConfigSchema
|
|
1971
|
+
]);
|
|
1972
|
+
function isManagedLeaseKind(value) {
|
|
1973
|
+
return MANAGED_LEASE_KINDS.includes(value);
|
|
1974
|
+
}
|
|
1975
|
+
function isManagedTarget(value) {
|
|
1976
|
+
return isManagedLeaseKind(value.provider);
|
|
1977
|
+
}
|
|
1755
1978
|
z$1.enum([
|
|
1756
1979
|
"postgres",
|
|
1757
1980
|
"mysql",
|
|
@@ -1759,7 +1982,8 @@ z$1.enum([
|
|
|
1759
1982
|
"redis",
|
|
1760
1983
|
"aws",
|
|
1761
1984
|
"gcp",
|
|
1762
|
-
"mongodb"
|
|
1985
|
+
"mongodb",
|
|
1986
|
+
...MANAGED_LEASE_KINDS
|
|
1763
1987
|
]);
|
|
1764
1988
|
const executorModeSchema = z$1.enum(["in_do", "remote"]);
|
|
1765
1989
|
/**
|
|
@@ -1994,7 +2218,8 @@ const leaseTargetConfigSchema = z$1.discriminatedUnion("provider", [
|
|
|
1994
2218
|
sshTargetConfigSchema,
|
|
1995
2219
|
awsTargetConfigSchema,
|
|
1996
2220
|
gcpTargetConfigSchema,
|
|
1997
|
-
mongoTargetConfigSchema
|
|
2221
|
+
mongoTargetConfigSchema,
|
|
2222
|
+
...managedTargetConfigSchema.options
|
|
1998
2223
|
]);
|
|
1999
2224
|
z$1.object({
|
|
2000
2225
|
name: z$1.string().trim().min(1).max(128),
|
|
@@ -2100,6 +2325,18 @@ const mintMongoLeaseSchema = z$1.object({
|
|
|
2100
2325
|
recipientPublicKey: p256PublicKeyJwkSchema,
|
|
2101
2326
|
ttlSeconds: ttlSecondsSchema
|
|
2102
2327
|
});
|
|
2328
|
+
const mintManagedLeaseSchema = z$1.object({
|
|
2329
|
+
provider: z$1.enum(MANAGED_LEASE_KINDS),
|
|
2330
|
+
targetId: z$1.string().min(1),
|
|
2331
|
+
recipientPublicKey: p256PublicKeyJwkSchema.refine((value) => {
|
|
2332
|
+
try {
|
|
2333
|
+
return !("d" in JSON.parse(value));
|
|
2334
|
+
} catch {
|
|
2335
|
+
return false;
|
|
2336
|
+
}
|
|
2337
|
+
}, "send only a public key"),
|
|
2338
|
+
ttlSeconds: ttlSecondsSchema
|
|
2339
|
+
});
|
|
2103
2340
|
z$1.discriminatedUnion("provider", [
|
|
2104
2341
|
mintPostgresLeaseSchema,
|
|
2105
2342
|
mintMysqlLeaseSchema,
|
|
@@ -2107,9 +2344,9 @@ z$1.discriminatedUnion("provider", [
|
|
|
2107
2344
|
mintSshLeaseSchema,
|
|
2108
2345
|
mintAwsLeaseSchema,
|
|
2109
2346
|
mintGcpLeaseSchema,
|
|
2110
|
-
mintMongoLeaseSchema
|
|
2347
|
+
mintMongoLeaseSchema,
|
|
2348
|
+
mintManagedLeaseSchema
|
|
2111
2349
|
]);
|
|
2112
|
-
// ../../packages/core/src/providers/aws.ts
|
|
2113
2350
|
/**
|
|
2114
2351
|
* The one-time IAM setup an admin performs so seekrit can assume the target
|
|
2115
2352
|
* role. Analogue of `sshHostSetupInstructions` / `postgresGroupBootstrapSql` —
|
|
@@ -2136,7 +2373,6 @@ function awsTrustPolicyInstructions(config) {
|
|
|
2136
2373
|
`# on ${config.roleArn}. seekrit only ever calls AssumeRole on this role.`
|
|
2137
2374
|
].join("\n");
|
|
2138
2375
|
}
|
|
2139
|
-
// ../../packages/core/src/providers/gcp.ts
|
|
2140
2376
|
/**
|
|
2141
2377
|
* The one-time IAM setup an admin performs so seekrit can impersonate the target
|
|
2142
2378
|
* service account. Analogue of `awsTrustPolicyInstructions` — printed for the
|
|
@@ -2158,7 +2394,6 @@ function gcpSetupInstructions(config) {
|
|
|
2158
2394
|
"gcloud services enable iamcredentials.googleapis.com"
|
|
2159
2395
|
].join("\n");
|
|
2160
2396
|
}
|
|
2161
|
-
// ../../packages/core/src/providers/mongodb.ts
|
|
2162
2397
|
/**
|
|
2163
2398
|
* The one-time setup an admin performs so seekrit can provision users: create a
|
|
2164
2399
|
* dedicated provisioning user with `userAdmin` on the target database (or
|
|
@@ -2183,7 +2418,6 @@ function mongoAdminSetupInstructions(config) {
|
|
|
2183
2418
|
`// --uri "mongodb://seekrit_provisioner:<pwd>@${config.connection.host}:${config.connection.port}/?authSource=${authSource}"`
|
|
2184
2419
|
].join("\n");
|
|
2185
2420
|
}
|
|
2186
|
-
// ../../packages/core/src/providers/postgres.ts
|
|
2187
2421
|
/**
|
|
2188
2422
|
* The one-time setup SQL an admin runs to create the shared group role that a
|
|
2189
2423
|
* read-only / read-write target's leased credentials inherit. Idempotent (safe
|
|
@@ -2214,7 +2448,6 @@ function postgresGroupBootstrapSql(config) {
|
|
|
2214
2448
|
if (config.accessLevel === "readwrite") lines.push(`GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA "${schema}" TO ${group};`, `ALTER DEFAULT PRIVILEGES IN SCHEMA "${schema}" GRANT USAGE, SELECT ON SEQUENCES TO ${group};`);
|
|
2215
2449
|
return lines.join("\n");
|
|
2216
2450
|
}
|
|
2217
|
-
// ../../packages/core/src/providers/ssh.ts
|
|
2218
2451
|
/**
|
|
2219
2452
|
* The one-time host setup an admin runs so a target's certificates are accepted.
|
|
2220
2453
|
* Analogue of `postgresGroupBootstrapSql` — displayed for the admin to run, not
|
|
@@ -5052,6 +5285,19 @@ async function decryptDataKey(material, wrapped) {
|
|
|
5052
5285
|
throw new SeekritCryptoError("DECRYPT_FAILED", "data key unwrap failed: wrong key or tampered blob");
|
|
5053
5286
|
}
|
|
5054
5287
|
}
|
|
5288
|
+
// ../../packages/crypto/src/managed-credential.ts
|
|
5289
|
+
const generateCredentialRecipientKeyPair = generateKeyPair;
|
|
5290
|
+
/** Only called on the consumer; the API receives the wrapped bytes. */
|
|
5291
|
+
async function unwrapManagedCredential(wrapped, privateKeyJwk) {
|
|
5292
|
+
const bytes = await unwrapDek(wrapped, await importPrivateKey(privateKeyJwk));
|
|
5293
|
+
try {
|
|
5294
|
+
const result = JSON.parse(new TextDecoder().decode(bytes));
|
|
5295
|
+
if (!result || typeof result !== "object" || Array.isArray(result) || !Object.values(result).every((value) => typeof value === "string")) throw new Error();
|
|
5296
|
+
return result;
|
|
5297
|
+
} catch {
|
|
5298
|
+
throw new SeekritCryptoError("DECRYPT_FAILED", "invalid managed credential");
|
|
5299
|
+
}
|
|
5300
|
+
}
|
|
5055
5301
|
// ../../packages/crypto/src/random.ts
|
|
5056
5302
|
const ALPHABETS = {
|
|
5057
5303
|
alphanumeric: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
|
|
@@ -5894,7 +6140,7 @@ async function createAgentTaskToken() {
|
|
|
5894
6140
|
};
|
|
5895
6141
|
}
|
|
5896
6142
|
// package.json
|
|
5897
|
-
var version = "2.
|
|
6143
|
+
var version = "2.7.0";
|
|
5898
6144
|
// ../../packages/api-client/src/index.ts
|
|
5899
6145
|
/**
|
|
5900
6146
|
* The proposer's note travels as a header, not a body field: an unprotected
|
|
@@ -12619,6 +12865,81 @@ function registerDoctorCommand(program) {
|
|
|
12619
12865
|
if (checks.some((c) => c.status === "fail")) process.exitCode = 1;
|
|
12620
12866
|
});
|
|
12621
12867
|
}
|
|
12868
|
+
// src/dynamic.ts
|
|
12869
|
+
function dynamicTtl(value) {
|
|
12870
|
+
const match = /^(\d+)([smhd]?)$/.exec(value);
|
|
12871
|
+
if (!match) throw new Error("invalid TTL (use 15m, 1h, or 1d)");
|
|
12872
|
+
const seconds = Number(match[1]) * ({
|
|
12873
|
+
s: 1,
|
|
12874
|
+
m: 60,
|
|
12875
|
+
h: 3600,
|
|
12876
|
+
d: 86400
|
|
12877
|
+
}[match[2] || "s"] ?? 1);
|
|
12878
|
+
if (!Number.isSafeInteger(seconds) || seconds < 60 || seconds > 604800) throw new Error("TTL must be 1 minute–7 days");
|
|
12879
|
+
return seconds;
|
|
12880
|
+
}
|
|
12881
|
+
function registerDynamicCommands(program) {
|
|
12882
|
+
const dynamic = program.command("dynamic").description("manage provider-issued temporary credentials");
|
|
12883
|
+
const targets = dynamic.command("target").description("manage dynamic credential targets");
|
|
12884
|
+
targets.command("add").requiredOption("--name <name>", "target name").requiredOption("--config <file>", "non-secret provider configuration JSON").option("--org <slug>", "organization").description("register a target; read its admin credential from stdin and encrypt it locally").action(async (options) => {
|
|
12885
|
+
const config = managedTargetConfigSchema.parse(JSON.parse(readFileSync(options.config, "utf8")));
|
|
12886
|
+
if (process.stdin.isTTY) fail("pipe the admin credential on stdin");
|
|
12887
|
+
const secret = (await readStdin()).trim();
|
|
12888
|
+
if (!secret) fail("admin credential is empty");
|
|
12889
|
+
const ctx = buildContext();
|
|
12890
|
+
const org = await resolveOrg(ctx, options.org);
|
|
12891
|
+
const { publicKeyJwk } = await ctx.client.getLeaseBrokerKey(org.id);
|
|
12892
|
+
const wrappedAdminSecret = await wrapDek(new TextEncoder().encode(secret), publicKeyJwk);
|
|
12893
|
+
const { target } = await ctx.client.registerLeaseTarget(org.id, {
|
|
12894
|
+
name: options.name,
|
|
12895
|
+
config,
|
|
12896
|
+
wrappedAdminSecret
|
|
12897
|
+
});
|
|
12898
|
+
console.log(JSON.stringify(target));
|
|
12899
|
+
});
|
|
12900
|
+
targets.command("list").option("--org <slug>", "organization").action(async (options) => {
|
|
12901
|
+
const ctx = buildContext();
|
|
12902
|
+
const org = await resolveOrg(ctx, options.org);
|
|
12903
|
+
const { targets } = await ctx.client.listLeaseTargets(org.id);
|
|
12904
|
+
console.log(JSON.stringify(targets.filter((target) => isManagedTarget(target))));
|
|
12905
|
+
});
|
|
12906
|
+
dynamic.command("lease <target>").option("--ttl <duration>", "credential lifetime", "1h").option("--org <slug>", "organization").description("mint and decrypt a credential locally; outputs JSON once").action(async (reference, options) => {
|
|
12907
|
+
const ttlSeconds = dynamicTtl(options.ttl);
|
|
12908
|
+
const ctx = buildContext();
|
|
12909
|
+
const org = await resolveOrg(ctx, options.org);
|
|
12910
|
+
const { targets } = await ctx.client.listLeaseTargets(org.id);
|
|
12911
|
+
const matches = targets.filter((target) => target.id === reference || target.name === reference);
|
|
12912
|
+
if (matches.length !== 1) fail("target must identify exactly one registered target");
|
|
12913
|
+
const target = matches[0];
|
|
12914
|
+
if (!target) fail("target not found");
|
|
12915
|
+
const config = managedTargetConfigSchema.parse(target.config);
|
|
12916
|
+
const recipient = await generateCredentialRecipientKeyPair();
|
|
12917
|
+
const result = await ctx.client.mintLease(org.id, {
|
|
12918
|
+
provider: config.provider,
|
|
12919
|
+
targetId: target.id,
|
|
12920
|
+
recipientPublicKey: recipient.publicKeyJwk,
|
|
12921
|
+
ttlSeconds
|
|
12922
|
+
});
|
|
12923
|
+
try {
|
|
12924
|
+
const credential = await unwrapManagedCredential(result.credential.wrappedCredential, recipient.privateKeyJwk);
|
|
12925
|
+
console.log(JSON.stringify({
|
|
12926
|
+
leaseId: result.lease.id,
|
|
12927
|
+
expiresAt: result.credential.expiresAt,
|
|
12928
|
+
credential
|
|
12929
|
+
}));
|
|
12930
|
+
} catch (error) {
|
|
12931
|
+
await ctx.client.revokeLease(org.id, result.lease.id);
|
|
12932
|
+
throw error;
|
|
12933
|
+
}
|
|
12934
|
+
});
|
|
12935
|
+
dynamic.command("revoke <leaseId>").option("--org <slug>", "organization").option("-y, --yes", "skip the confirmation prompt").description("revoke a temporary credential now").action(async (leaseId, options) => {
|
|
12936
|
+
await confirmDestructive(options.yes, `Revoke temporary credential ${leaseId}?`);
|
|
12937
|
+
const ctx = buildContext();
|
|
12938
|
+
const org = await resolveOrg(ctx, options.org);
|
|
12939
|
+
await ctx.client.revokeLease(org.id, leaseId);
|
|
12940
|
+
console.log(JSON.stringify({ revoked: leaseId }));
|
|
12941
|
+
});
|
|
12942
|
+
}
|
|
12622
12943
|
// src/gcp.ts
|
|
12623
12944
|
/**
|
|
12624
12945
|
* `seekrit gcp` — temporary GCP credentials via IAM Credentials
|
|
@@ -18475,6 +18796,7 @@ registerHermesCommands(program);
|
|
|
18475
18796
|
registerSshCommands(program);
|
|
18476
18797
|
registerAwsCommands(program);
|
|
18477
18798
|
registerGcpCommands(program);
|
|
18799
|
+
registerDynamicCommands(program);
|
|
18478
18800
|
registerIdentityCommands(program);
|
|
18479
18801
|
registerMongoCommands(program);
|
|
18480
18802
|
registerKmsCommands(program);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@seekrit/cli",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.7.0",
|
|
4
4
|
"description": "CLI for seekrit (https://seekrit.dev), a zero-knowledge secrets manager and credential broker for AI agents — inject decrypted secrets into any command.",
|
|
5
5
|
"homepage": "https://seekrit.dev/docs/guides/cli",
|
|
6
6
|
"keywords": [
|