@seekrit/cli 1.6.2 → 1.6.4
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
CHANGED
|
@@ -12,10 +12,10 @@ import { connect } from "node:net";
|
|
|
12
12
|
import { fileURLToPath } from "node:url";
|
|
13
13
|
import { request } from "node:http";
|
|
14
14
|
/** Default lifetime of a published bundle (7 days), in seconds. */
|
|
15
|
-
const POLICY_DEFAULT_TTL_SECONDS =
|
|
15
|
+
const POLICY_DEFAULT_TTL_SECONDS = 604800;
|
|
16
16
|
/** Bounds on a bundle's lifetime: an hour at the short end, 90 days at the long. */
|
|
17
17
|
const POLICY_MIN_TTL_SECONDS = 3600;
|
|
18
|
-
const POLICY_MAX_TTL_SECONDS =
|
|
18
|
+
const POLICY_MAX_TTL_SECONDS = 7776e3;
|
|
19
19
|
/** A bare hostname: no scheme, no port, no path, no wildcard. */
|
|
20
20
|
const policyHostSchema = z.string().trim().min(1).max(253).toLowerCase().refine((h) => !/[:/\s*]/.test(h), { message: "host must be a bare hostname (no scheme, port, path, or wildcard)" }).refine((h) => /^[a-z0-9.-]+$/.test(h), { message: "host contains invalid characters" });
|
|
21
21
|
const policyMethodSchema = z.string().trim().toUpperCase().regex(/^[A-Z]{3,10}$/, "method must be an HTTP method name");
|
|
@@ -34,7 +34,7 @@ const agentPolicyRuleSchema = z.object({
|
|
|
34
34
|
});
|
|
35
35
|
z.object({
|
|
36
36
|
/** `ap1.<body>.<signature>` — opaque to the server. */
|
|
37
|
-
bundle: z.string().min(16).max(
|
|
37
|
+
bundle: z.string().min(16).max(262144) });
|
|
38
38
|
z.object({
|
|
39
39
|
name: z.string().trim().min(1).max(120),
|
|
40
40
|
slug: z.string().trim().min(1).max(64).regex(/^[a-z0-9][a-z0-9-]*$/, "slug is lowercase letters, digits, and dashes"),
|
|
@@ -521,7 +521,7 @@ function countApplicable(proposals) {
|
|
|
521
521
|
* to bound one run; something that needs longer wants a policy change, not a
|
|
522
522
|
* longer ticket.
|
|
523
523
|
*/
|
|
524
|
-
const TASK_MAX_TTL_SECONDS =
|
|
524
|
+
const TASK_MAX_TTL_SECONDS = 43200;
|
|
525
525
|
/** An EC P-256 public JWK, for a sender-constraint proof key. */
|
|
526
526
|
const taskProofJwkSchema = z.object({
|
|
527
527
|
kty: z.literal("EC"),
|
|
@@ -707,14 +707,16 @@ async function verifyArchive(archive, options = {}) {
|
|
|
707
707
|
if (options.skipSignature) {
|
|
708
708
|
signature = "unverifiable";
|
|
709
709
|
signatureNote = "signature checking was skipped";
|
|
710
|
-
} else if (archive.signature)
|
|
711
|
-
signature
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
710
|
+
} else if (archive.signature) {
|
|
711
|
+
if (options.expectKeyId && options.expectKeyId !== archive.signature.keyId) {
|
|
712
|
+
signature = "invalid";
|
|
713
|
+
signatureNote = `signed by key ${archive.signature.keyId}, expected ${options.expectKeyId}`;
|
|
714
|
+
} else try {
|
|
715
|
+
signature = await verifySignature(archive.manifest, archive.signature) ? "valid" : "invalid";
|
|
716
|
+
} catch (err) {
|
|
717
|
+
signature = "unverifiable";
|
|
718
|
+
signatureNote = err instanceof Error ? err.message : String(err);
|
|
719
|
+
}
|
|
718
720
|
}
|
|
719
721
|
return {
|
|
720
722
|
ok: badSections.length === 0 && missingSections.length === 0 && undeclaredSections.length === 0 && manifestDigestOk && signature === "valid",
|
|
@@ -1001,7 +1003,7 @@ const SUBSCRIPTION_STATUSES = [
|
|
|
1001
1003
|
* composition (matched by slug) and have no single parent to overlay.
|
|
1002
1004
|
*/
|
|
1003
1005
|
/** Longest life a branch may be given. Bounds sprawl even if nobody cleans up. */
|
|
1004
|
-
const MAX_BRANCH_TTL_SECONDS =
|
|
1006
|
+
const MAX_BRANCH_TTL_SECONDS = 2592e3;
|
|
1005
1007
|
/**
|
|
1006
1008
|
* Parse a human TTL — `30m`, `12h`, `7d`, `2w`, or bare seconds — into seconds.
|
|
1007
1009
|
* Returns null for anything unparseable, so callers can report the input back.
|
|
@@ -1610,13 +1612,13 @@ const sshTargetConfigSchema = z.object({
|
|
|
1610
1612
|
caPublicKey: sshPublicKeySchema,
|
|
1611
1613
|
allowedPrincipals: z.array(sshPrincipalSchema).max(64).optional(),
|
|
1612
1614
|
extensions: z.array(sshExtensionSchema).max(16).optional(),
|
|
1613
|
-
maxTtlSeconds: z.number().int().min(60).max(
|
|
1615
|
+
maxTtlSeconds: z.number().int().min(60).max(604800).optional(),
|
|
1614
1616
|
connection: z.object({
|
|
1615
1617
|
host: z.string().min(1).optional(),
|
|
1616
1618
|
user: sshPrincipalSchema.optional()
|
|
1617
1619
|
}).optional()
|
|
1618
1620
|
});
|
|
1619
|
-
const AWS_MAX_TTL_SECONDS =
|
|
1621
|
+
const AWS_MAX_TTL_SECONDS = 43200;
|
|
1620
1622
|
const awsTargetConfigSchema = z.object({
|
|
1621
1623
|
provider: z.literal("aws"),
|
|
1622
1624
|
executor: z.literal("in_do"),
|
|
@@ -1626,7 +1628,7 @@ const awsTargetConfigSchema = z.object({
|
|
|
1626
1628
|
sessionPolicy: z.string().min(1).max(4e3).optional(),
|
|
1627
1629
|
maxTtlSeconds: z.number().int().min(900).max(AWS_MAX_TTL_SECONDS).optional()
|
|
1628
1630
|
});
|
|
1629
|
-
const GCP_MAX_TTL_SECONDS =
|
|
1631
|
+
const GCP_MAX_TTL_SECONDS = 43200;
|
|
1630
1632
|
const gcpTargetConfigSchema = z.object({
|
|
1631
1633
|
provider: z.literal("gcp"),
|
|
1632
1634
|
executor: z.literal("in_do"),
|
|
@@ -1643,7 +1645,7 @@ const mongoTargetConfigSchema = z.object({
|
|
|
1643
1645
|
authSource: mongoDatabaseNameSchema.optional(),
|
|
1644
1646
|
roles: z.array(mongoRoleSchema).min(1).max(32).optional(),
|
|
1645
1647
|
tls: z.boolean().optional(),
|
|
1646
|
-
maxTtlSeconds: z.number().int().min(60).max(
|
|
1648
|
+
maxTtlSeconds: z.number().int().min(60).max(604800).optional()
|
|
1647
1649
|
});
|
|
1648
1650
|
const leaseTargetConfigSchema = z.discriminatedUnion("provider", [
|
|
1649
1651
|
postgresTargetConfigSchema,
|
|
@@ -1665,7 +1667,7 @@ z.object({
|
|
|
1665
1667
|
wrappedAdminSecret: z.string().min(1)
|
|
1666
1668
|
});
|
|
1667
1669
|
/** Requested lease lifetime, shared by all providers. */
|
|
1668
|
-
const ttlSecondsSchema = z.number().int().min(60).max(
|
|
1670
|
+
const ttlSecondsSchema = z.number().int().min(60).max(604800);
|
|
1669
1671
|
/**
|
|
1670
1672
|
* Client → API: mint a Postgres lease. The client generates the password and
|
|
1671
1673
|
* its SCRAM verifier locally and sends only the verifier — the plaintext
|
|
@@ -2376,7 +2378,7 @@ const rotationAlphabetSchema = z.enum([
|
|
|
2376
2378
|
"base64url",
|
|
2377
2379
|
"printable"
|
|
2378
2380
|
]);
|
|
2379
|
-
const rotationIntervalSchema = z.number().int().min(300).max(
|
|
2381
|
+
const rotationIntervalSchema = z.number().int().min(300).max(31536e3);
|
|
2380
2382
|
/**
|
|
2381
2383
|
* A database user name we are willing to *re-key*. Deliberately more permissive
|
|
2382
2384
|
* than the lease providers' name schemas — those name accounts seekrit creates,
|
|
@@ -5053,7 +5055,7 @@ async function createAgentTaskToken() {
|
|
|
5053
5055
|
}
|
|
5054
5056
|
//#endregion
|
|
5055
5057
|
//#region package.json
|
|
5056
|
-
var version = "1.6.
|
|
5058
|
+
var version = "1.6.4";
|
|
5057
5059
|
//#endregion
|
|
5058
5060
|
//#region ../../packages/api-client/src/index.ts
|
|
5059
5061
|
var SeekritApiError = class extends Error {
|
|
@@ -7063,7 +7065,7 @@ function registerPolicyCommands(policy) {
|
|
|
7063
7065
|
const KEY_DOMAIN = "seekrit-lkg-cache-v1";
|
|
7064
7066
|
const TOKEN_DOMAIN = "seekrit-token-fp-v1";
|
|
7065
7067
|
/** 24h: long enough to ride out an outage, short enough to bound the tail. */
|
|
7066
|
-
const DEFAULT_MAX_AGE_MS =
|
|
7068
|
+
const DEFAULT_MAX_AGE_MS = 864e5;
|
|
7067
7069
|
/**
|
|
7068
7070
|
* Derive the key for one resolve request. Overrides are sorted, so flag order
|
|
7069
7071
|
* never splits the cache. Byte-for-byte identical to `CacheKey::new` in
|
|
@@ -9126,8 +9128,12 @@ function envLabel(archive, env) {
|
|
|
9126
9128
|
}
|
|
9127
9129
|
/** Filesystem path for an environment's output file, mirroring its label. */
|
|
9128
9130
|
function envPath(archive, env, extension) {
|
|
9129
|
-
if (env.groupId)
|
|
9130
|
-
|
|
9131
|
+
if (env.groupId) {
|
|
9132
|
+
const group = archive.data.groups.find((g) => g.id === env.groupId);
|
|
9133
|
+
return join("groups", group?.slug ?? env.groupId, `${env.slug}.${extension}`);
|
|
9134
|
+
}
|
|
9135
|
+
const app = archive.data.applications.find((a) => a.id === env.applicationId);
|
|
9136
|
+
return join("apps", app?.slug ?? env.applicationId ?? "unknown", `${env.slug}.${extension}`);
|
|
9131
9137
|
}
|
|
9132
9138
|
/**
|
|
9133
9139
|
* Recover a private key to open the archive with, from (in order) a service
|
|
@@ -9545,7 +9551,7 @@ function registerAwsCommands(program) {
|
|
|
9545
9551
|
const cfg = t.config;
|
|
9546
9552
|
if (cfg.provider !== "aws") fail(`"${t.name}" is not an aws target (see \`seekrit pg\`)`);
|
|
9547
9553
|
const ttlSeconds = parseTtlSeconds$6(options.ttl);
|
|
9548
|
-
if (ttlSeconds < 900) fail(`--ttl must be at least
|
|
9554
|
+
if (ttlSeconds < 900) fail(`--ttl must be at least 15m (STS minimum)`);
|
|
9549
9555
|
const recipient = await generateAwsRecipientKeyPair();
|
|
9550
9556
|
const { aws: leased } = await ctx.client.mintLease(org.id, {
|
|
9551
9557
|
provider: "aws",
|
|
@@ -11951,11 +11957,12 @@ function checkPlugin(pluginDir, opts = {}) {
|
|
|
11951
11957
|
detail: fingerprintOk ? String(fingerprintBody?.version ?? "") : (fingerprint.stderr || fingerprint.stdout || "no output").trim()
|
|
11952
11958
|
});
|
|
11953
11959
|
if (!fingerprintOk) return steps;
|
|
11954
|
-
const
|
|
11960
|
+
const argv = opts.config ? [
|
|
11955
11961
|
"--config",
|
|
11956
11962
|
opts.config,
|
|
11957
11963
|
"fetch"
|
|
11958
|
-
] : ["fetch"]
|
|
11964
|
+
] : ["fetch"];
|
|
11965
|
+
const fetch = spawnSync(bin, [...argv, opts.path ?? ""], {
|
|
11959
11966
|
encoding: "utf8",
|
|
11960
11967
|
timeout: 6e4,
|
|
11961
11968
|
env: {
|
|
@@ -15525,7 +15532,7 @@ registerKmsCommands(program);
|
|
|
15525
15532
|
registerRotationCommands(program);
|
|
15526
15533
|
registerRecoveryCommands(program);
|
|
15527
15534
|
program.command("mcp").description("run an MCP server over stdio so AI agents can drive seekrit").action(async () => {
|
|
15528
|
-
const { runMcpServer } = await import("./mcp-
|
|
15535
|
+
const { runMcpServer } = await import("./mcp-BvXwiGRv.js");
|
|
15529
15536
|
await runMcpServer();
|
|
15530
15537
|
});
|
|
15531
15538
|
registerAuditCommands(program);
|
|
@@ -438,7 +438,8 @@ async function runMcpServer(options = {}) {
|
|
|
438
438
|
const k = await kmsResolveKey(ctx, orgRef.id, key);
|
|
439
439
|
if (k.purpose !== "sign") throw new Error(`${k.name} is a ${k.purpose} key`);
|
|
440
440
|
const { material, currentVersion } = await kmsRecoverMaterial(ctx, orgRef.id, k.id);
|
|
441
|
-
|
|
441
|
+
const privateKey = await importSigningKey(material);
|
|
442
|
+
return { signature: await signMessage(privateKey, {
|
|
442
443
|
keyId: k.id,
|
|
443
444
|
version: currentVersion
|
|
444
445
|
}, message) };
|
|
@@ -527,7 +528,8 @@ async function runMcpServer(options = {}) {
|
|
|
527
528
|
const { apps } = await ctx.client.listApps(orgRef.id);
|
|
528
529
|
const appRow = apps.find((a) => a.slug === app || a.id === app);
|
|
529
530
|
if (!appRow) throw new Error(`no app "${app}" in ${orgRef.slug}`);
|
|
530
|
-
const
|
|
531
|
+
const dek = generateDek();
|
|
532
|
+
const wrappedDek = await wrapDek(dek, await principalPublicKeyJwk(ctx));
|
|
531
533
|
return (await ctx.client.createEnv(orgRef.id, appRow.id, {
|
|
532
534
|
name,
|
|
533
535
|
slug,
|
|
@@ -594,7 +596,8 @@ async function runMcpServer(options = {}) {
|
|
|
594
596
|
org,
|
|
595
597
|
group
|
|
596
598
|
});
|
|
597
|
-
const
|
|
599
|
+
const dek = generateDek();
|
|
600
|
+
const wrappedDek = await wrapDek(dek, await principalPublicKeyJwk(ctx));
|
|
598
601
|
return (await ctx.client.createGroupEnv(g.orgId, g.id, {
|
|
599
602
|
name,
|
|
600
603
|
slug,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@seekrit/cli",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.4",
|
|
4
4
|
"description": "End-to-end encrypted secrets manager CLI — inject decrypted secrets into any command.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
|
@@ -27,8 +27,8 @@
|
|
|
27
27
|
"zod": "^4.6.2"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
|
-
"@types/node": "^26.1
|
|
31
|
-
"tsdown": "^0.
|
|
30
|
+
"@types/node": "^26.5.1",
|
|
31
|
+
"tsdown": "^0.23.0",
|
|
32
32
|
"vitest": "^4.1.11",
|
|
33
33
|
"@seekrit/api-client": "0.0.1",
|
|
34
34
|
"@seekrit/core": "0.0.1",
|