@seekrit/cli 1.2.0 → 1.2.1
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/README.md +6 -5
- package/dist/index.js +46 -4
- package/dist/{mcp-DR-zla_u.js → mcp-BOawfW_U.js} +7 -23
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -30,11 +30,12 @@ seekrit login --token skt_…
|
|
|
30
30
|
# leaves this machine). Only needed once per account.
|
|
31
31
|
seekrit keys setup
|
|
32
32
|
|
|
33
|
-
# 3. Link the current directory to an org / app
|
|
34
|
-
#
|
|
35
|
-
seekrit init --org acme --app storefront
|
|
33
|
+
# 3. Link the current directory to an org / app. Writes seekrit.json, which is
|
|
34
|
+
# safe to commit. The environment comes from the token at runtime.
|
|
35
|
+
seekrit init --org acme --app storefront
|
|
36
36
|
|
|
37
|
-
# 4. Work with secrets
|
|
37
|
+
# 4. Work with secrets. A service token names its own environment; on a user
|
|
38
|
+
# session, add --env production.
|
|
38
39
|
seekrit secrets set DATABASE_URL 'postgres://…'
|
|
39
40
|
seekrit secrets list
|
|
40
41
|
seekrit run -- ./server # runs ./server with secrets in its env
|
|
@@ -55,7 +56,7 @@ Run `seekrit <command> --help` for full flags. The
|
|
|
55
56
|
| `login [--token \| --dev-user] [--api-url]` | Save credentials to the global config. |
|
|
56
57
|
| `whoami` | Show the authenticated identity and org membership. |
|
|
57
58
|
| `keys setup` | Generate your keypair and protect it with a passphrase. |
|
|
58
|
-
| `init --org --app
|
|
59
|
+
| `init --org --app` | Link this directory to an org/app (`seekrit.json`). The environment comes from the token. |
|
|
59
60
|
| `org create` / `app create` / `env create` | Create organizations, apps, and environments. |
|
|
60
61
|
| `secrets list` | List secret names (never values). |
|
|
61
62
|
| `secrets get <name> [--raw]` | Decrypt and print one secret value (`--raw` skips `${OTHER_SECRET}` expansion). |
|
package/dist/index.js
CHANGED
|
@@ -5051,7 +5051,7 @@ async function createAgentTaskToken() {
|
|
|
5051
5051
|
}
|
|
5052
5052
|
//#endregion
|
|
5053
5053
|
//#region package.json
|
|
5054
|
-
var version = "1.2.
|
|
5054
|
+
var version = "1.2.1";
|
|
5055
5055
|
//#endregion
|
|
5056
5056
|
//#region ../../packages/api-client/src/index.ts
|
|
5057
5057
|
var SeekritApiError = class extends Error {
|
|
@@ -6146,11 +6146,46 @@ async function resolveOrg(ctx, orgSlug) {
|
|
|
6146
6146
|
fail("specify --org (or run `seekrit init`)");
|
|
6147
6147
|
}
|
|
6148
6148
|
/**
|
|
6149
|
+
* The environment a service token is bound to.
|
|
6150
|
+
*
|
|
6151
|
+
* The binding lives on the token row, not in the token string — `GET
|
|
6152
|
+
* /v1/resolve` is where the API publishes it, and `seekrit whoami` reads it the
|
|
6153
|
+
* same way. One round trip, and it also resolves `--branch` against the bound
|
|
6154
|
+
* environment, which is the only environment a token may name a branch of.
|
|
6155
|
+
*/
|
|
6156
|
+
async function boundEnvTarget(ctx, opts) {
|
|
6157
|
+
let scope;
|
|
6158
|
+
try {
|
|
6159
|
+
({scope} = await ctx.client.resolve(opts.branch ? { branch: opts.branch } : {}));
|
|
6160
|
+
} catch (err) {
|
|
6161
|
+
fail(`specify --env — this token has no environment of its own to fall back to (${err instanceof Error ? err.message : String(err)})`);
|
|
6162
|
+
}
|
|
6163
|
+
const env = scope.branchOf ?? {
|
|
6164
|
+
envId: scope.envId,
|
|
6165
|
+
envSlug: scope.envSlug
|
|
6166
|
+
};
|
|
6167
|
+
const label = scope.branchOf ? `${scope.appSlug}/${scope.branchOf.envSlug}#${scope.envSlug}` : `${scope.appSlug}/${scope.envSlug}`;
|
|
6168
|
+
if (opts.org && opts.org !== scope.orgSlug && opts.org !== scope.orgId) fail(`this token belongs to ${scope.orgSlug}, not "${opts.org}"`);
|
|
6169
|
+
if (opts.env && opts.env !== env.envSlug && opts.env !== env.envId) fail(`this token is bound to ${scope.appSlug}/${env.envSlug}, not "${opts.env}" — add --app (or --group) to target another environment you hold a key for`);
|
|
6170
|
+
return {
|
|
6171
|
+
orgId: scope.orgId,
|
|
6172
|
+
envId: scope.envId,
|
|
6173
|
+
label
|
|
6174
|
+
};
|
|
6175
|
+
}
|
|
6176
|
+
/**
|
|
6149
6177
|
* Resolve an environment to operate on — an application env (`--app --env`,
|
|
6150
6178
|
* or the config's app + `--env`), a branch of one (`--branch`), or a group env
|
|
6151
6179
|
* (`--group --env`).
|
|
6180
|
+
*
|
|
6181
|
+
* `--env` is optional for a service token that names no `--app`/`--group`: it is
|
|
6182
|
+
* already bound to exactly one environment, so requiring the flag made every
|
|
6183
|
+
* documented one-liner (`seekrit secrets list`) fail for the CI job and the
|
|
6184
|
+
* agent that are the point of a token. The local MCP server has always inferred
|
|
6185
|
+
* it this way; this is the same rule, in one place, for both.
|
|
6152
6186
|
*/
|
|
6153
6187
|
async function resolveEnvTarget(ctx, opts) {
|
|
6188
|
+
if (!opts.app && !opts.group && isTokenAuth(ctx)) return boundEnvTarget(ctx, opts);
|
|
6154
6189
|
const org = await resolveOrg(ctx, opts.org);
|
|
6155
6190
|
if (!opts.env) fail("specify --env");
|
|
6156
6191
|
if (opts.group) {
|
|
@@ -13959,9 +13994,16 @@ function parseVersion(raw) {
|
|
|
13959
13994
|
if (!Number.isInteger(n) || n < 1) fail(`expected a positive whole number, got "${raw}"`);
|
|
13960
13995
|
return n;
|
|
13961
13996
|
}
|
|
13962
|
-
/**
|
|
13997
|
+
/**
|
|
13998
|
+
* Attach the environment-selection flags shared by every `secrets` command.
|
|
13999
|
+
*
|
|
14000
|
+
* `--env` is an ordinary option, not a required one: a service token is bound
|
|
14001
|
+
* to a single environment, so `seekrit secrets list` with nothing else on the
|
|
14002
|
+
* line is the whole invocation for CI and for agents. `resolveEnvTarget` fills
|
|
14003
|
+
* it in from the token, and still insists on it for a user session.
|
|
14004
|
+
*/
|
|
13963
14005
|
function withTarget(cmd) {
|
|
13964
|
-
return cmd.option("--org <slug>", "organization slug").option("--app <slug>", "application slug (defaults to seekrit.json)").option("--group <slug>", "target a group environment instead of an app").option("--branch <slug>", "operate on a branch of --env").
|
|
14006
|
+
return cmd.option("--org <slug>", "organization slug").option("--app <slug>", "application slug (defaults to seekrit.json)").option("--group <slug>", "target a group environment instead of an app").option("--branch <slug>", "operate on a branch of --env").option("--env <slug>", "environment slug (a service token infers its own)");
|
|
13965
14007
|
}
|
|
13966
14008
|
const secrets = program.command("secrets").description("manage secrets in an application or group environment");
|
|
13967
14009
|
withTarget(secrets.command("list").alias("ls").description("list secret names (no values)").option("--json", "print the listing as JSON (metadata only — never values)")).action(async (options) => {
|
|
@@ -14419,7 +14461,7 @@ registerKmsCommands(program);
|
|
|
14419
14461
|
registerRotationCommands(program);
|
|
14420
14462
|
registerRecoveryCommands(program);
|
|
14421
14463
|
program.command("mcp").description("run an MCP server over stdio so AI agents can drive seekrit").action(async () => {
|
|
14422
|
-
const { runMcpServer } = await import("./mcp-
|
|
14464
|
+
const { runMcpServer } = await import("./mcp-BOawfW_U.js");
|
|
14423
14465
|
await runMcpServer();
|
|
14424
14466
|
});
|
|
14425
14467
|
registerAuditCommands(program);
|
|
@@ -180,22 +180,6 @@ const targetShape = {
|
|
|
180
180
|
group: z.string().optional().describe("target a group environment instead of an app"),
|
|
181
181
|
env: z.string().optional().describe("environment slug or id (a service token infers its own)")
|
|
182
182
|
};
|
|
183
|
-
/**
|
|
184
|
-
* Resolve which environment a secret tool addresses. A service token with no
|
|
185
|
-
* explicit app/group targets its own bound environment (no flags needed);
|
|
186
|
-
* everyone else names app|group + env.
|
|
187
|
-
*/
|
|
188
|
-
async function resolveTargetEnv(ctx, o) {
|
|
189
|
-
if (isTokenAuth(ctx) && !o.app && !o.group) {
|
|
190
|
-
const { scope } = await ctx.client.resolve();
|
|
191
|
-
return {
|
|
192
|
-
orgId: scope.orgId,
|
|
193
|
-
envId: scope.envId,
|
|
194
|
-
label: `${scope.appSlug}/${scope.envSlug}`
|
|
195
|
-
};
|
|
196
|
-
}
|
|
197
|
-
return resolveEnvTarget(ctx, o);
|
|
198
|
-
}
|
|
199
183
|
async function runMcpServer(options = {}) {
|
|
200
184
|
setFailThrows(true);
|
|
201
185
|
await ensureM2mAdminToken();
|
|
@@ -476,7 +460,7 @@ async function runMcpServer(options = {}) {
|
|
|
476
460
|
});
|
|
477
461
|
tool("list_secrets", "List secret names + versions in an environment (never values).", ro, targetShape, async (o) => {
|
|
478
462
|
const ctx = getCtx();
|
|
479
|
-
const { orgId, envId } = await
|
|
463
|
+
const { orgId, envId } = await resolveEnvTarget(ctx, o);
|
|
480
464
|
const { secrets } = await ctx.client.listSecrets(orgId, envId);
|
|
481
465
|
return secrets.map((s) => ({
|
|
482
466
|
name: s.name,
|
|
@@ -665,7 +649,7 @@ async function runMcpServer(options = {}) {
|
|
|
665
649
|
}, async (o) => {
|
|
666
650
|
const ctx = getCtx();
|
|
667
651
|
ensureDecryptable(ctx);
|
|
668
|
-
const { orgId, envId } = await
|
|
652
|
+
const { orgId, envId } = await resolveEnvTarget(ctx, o);
|
|
669
653
|
await encryptAndSetSecret(ctx, orgId, envId, o.name, o.value);
|
|
670
654
|
return {
|
|
671
655
|
ok: true,
|
|
@@ -680,7 +664,7 @@ async function runMcpServer(options = {}) {
|
|
|
680
664
|
version: z.number().int().positive().optional().describe("an earlier version from list_secret_versions (default: current)")
|
|
681
665
|
}, async (o) => {
|
|
682
666
|
const ctx = getCtx();
|
|
683
|
-
const { orgId, envId } = await
|
|
667
|
+
const { orgId, envId } = await resolveEnvTarget(ctx, o);
|
|
684
668
|
if (!o.reveal) {
|
|
685
669
|
const { secrets } = await ctx.client.listSecrets(orgId, envId);
|
|
686
670
|
const row = secrets.find((s) => s.name === o.name);
|
|
@@ -715,7 +699,7 @@ async function runMcpServer(options = {}) {
|
|
|
715
699
|
limit: z.number().int().min(1).max(200).optional().describe("default 20")
|
|
716
700
|
}, async (o) => {
|
|
717
701
|
const ctx = getCtx();
|
|
718
|
-
const { orgId, envId } = await
|
|
702
|
+
const { orgId, envId } = await resolveEnvTarget(ctx, o);
|
|
719
703
|
const { versions, currentVersion } = await ctx.client.listSecretVersions(orgId, envId, o.name, { limit: o.limit ?? 20 });
|
|
720
704
|
return {
|
|
721
705
|
currentVersion,
|
|
@@ -733,7 +717,7 @@ async function runMcpServer(options = {}) {
|
|
|
733
717
|
version: z.number().int().positive()
|
|
734
718
|
}, async (o) => {
|
|
735
719
|
const ctx = getCtx();
|
|
736
|
-
const { orgId, envId } = await
|
|
720
|
+
const { orgId, envId } = await resolveEnvTarget(ctx, o);
|
|
737
721
|
const { secret, restoredFrom } = await ctx.client.restoreSecret(orgId, envId, o.name, o.version);
|
|
738
722
|
return {
|
|
739
723
|
ok: true,
|
|
@@ -747,7 +731,7 @@ async function runMcpServer(options = {}) {
|
|
|
747
731
|
name: z.string()
|
|
748
732
|
}, async (o) => {
|
|
749
733
|
const ctx = getCtx();
|
|
750
|
-
const { orgId, envId } = await
|
|
734
|
+
const { orgId, envId } = await resolveEnvTarget(ctx, o);
|
|
751
735
|
await ctx.client.deleteSecret(orgId, envId, o.name);
|
|
752
736
|
return {
|
|
753
737
|
ok: true,
|
|
@@ -870,7 +854,7 @@ async function runMcpServer(options = {}) {
|
|
|
870
854
|
if (Boolean(o.user) === Boolean(o.token)) throw new Error("pass exactly one of user or token");
|
|
871
855
|
const ctx = getCtx();
|
|
872
856
|
ensureDecryptable(ctx);
|
|
873
|
-
const { orgId, envId, label } = await
|
|
857
|
+
const { orgId, envId, label } = await resolveEnvTarget(ctx, o);
|
|
874
858
|
const dek = await getDek(ctx, orgId, envId);
|
|
875
859
|
let principalType;
|
|
876
860
|
let principalId;
|