@seekrit/cli 0.21.0 → 0.23.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
CHANGED
|
@@ -1976,7 +1976,7 @@ function isServiceToken(value) {
|
|
|
1976
1976
|
}
|
|
1977
1977
|
//#endregion
|
|
1978
1978
|
//#region package.json
|
|
1979
|
-
var version = "0.
|
|
1979
|
+
var version = "0.23.0";
|
|
1980
1980
|
//#endregion
|
|
1981
1981
|
//#region ../../packages/api-client/src/index.ts
|
|
1982
1982
|
var SeekritApiError = class extends Error {
|
|
@@ -1993,13 +1993,16 @@ var SeekritClient = class {
|
|
|
1993
1993
|
baseUrl;
|
|
1994
1994
|
auth;
|
|
1995
1995
|
fetchImpl;
|
|
1996
|
+
client;
|
|
1996
1997
|
constructor(options) {
|
|
1997
1998
|
this.baseUrl = options.baseUrl.replace(/\/$/, "");
|
|
1998
1999
|
this.auth = options.auth;
|
|
1999
2000
|
this.fetchImpl = options.fetch ?? ((...args) => fetch(...args));
|
|
2001
|
+
this.client = options.client;
|
|
2000
2002
|
}
|
|
2001
2003
|
async request(method, path, body) {
|
|
2002
2004
|
const headers = { accept: "application/json" };
|
|
2005
|
+
if (this.client) headers["x-seekrit-client"] = this.client;
|
|
2003
2006
|
if (this.auth.type === "bearer") headers.authorization = `Bearer ${this.auth.token}`;
|
|
2004
2007
|
else if (this.auth.type === "dynamic") {
|
|
2005
2008
|
const token = await this.auth.getToken();
|
|
@@ -2430,6 +2433,8 @@ async function readStdin() {
|
|
|
2430
2433
|
}
|
|
2431
2434
|
//#endregion
|
|
2432
2435
|
//#region src/context.ts
|
|
2436
|
+
/** Sent as `x-seekrit-client` so the API attributes usage to the CLI (analytics). */
|
|
2437
|
+
const CLI_CLIENT = `cli/${version}`;
|
|
2433
2438
|
/**
|
|
2434
2439
|
* Build the client context from configured credentials, or return null when
|
|
2435
2440
|
* none are set. `seekrit run` uses this to degrade to a plain launcher instead
|
|
@@ -2460,7 +2465,8 @@ function tryBuildContext(dotenvVars = {}) {
|
|
|
2460
2465
|
return {
|
|
2461
2466
|
client: new SeekritClient({
|
|
2462
2467
|
baseUrl: apiUrl,
|
|
2463
|
-
auth
|
|
2468
|
+
auth,
|
|
2469
|
+
client: CLI_CLIENT
|
|
2464
2470
|
}),
|
|
2465
2471
|
auth
|
|
2466
2472
|
};
|
|
@@ -3232,7 +3238,8 @@ async function mintAdminToken(apiUrl, creds) {
|
|
|
3232
3238
|
type: "m2m",
|
|
3233
3239
|
clientId: creds.clientId,
|
|
3234
3240
|
clientSecret: creds.clientSecret
|
|
3235
|
-
}
|
|
3241
|
+
},
|
|
3242
|
+
client: `cli/${version}`
|
|
3236
3243
|
});
|
|
3237
3244
|
const { orgs } = await client.listOrgs();
|
|
3238
3245
|
const org = orgs[0];
|
|
@@ -4716,7 +4723,7 @@ registerMongoCommands(program);
|
|
|
4716
4723
|
registerKmsCommands(program);
|
|
4717
4724
|
registerRecoveryCommands(program);
|
|
4718
4725
|
program.command("mcp").description("run an MCP server over stdio so AI agents can drive seekrit").action(async () => {
|
|
4719
|
-
const { runMcpServer } = await import("./mcp-
|
|
4726
|
+
const { runMcpServer } = await import("./mcp-CbNXG37n.js");
|
|
4720
4727
|
await runMcpServer();
|
|
4721
4728
|
});
|
|
4722
4729
|
program.command("audit").description("show the org audit trail").option("--org <slug>").option("--limit <n>", "entries to fetch", "50").action(async (options) => {
|
|
@@ -26,6 +26,74 @@ function errText(err) {
|
|
|
26
26
|
isError: true
|
|
27
27
|
};
|
|
28
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* Short primer surfaced as the MCP server `instructions`. Most clients show
|
|
31
|
+
* this to the model on connect, so it has to orient an agent that lands here
|
|
32
|
+
* with zero context in a few lines.
|
|
33
|
+
*/
|
|
34
|
+
function serverInstructions() {
|
|
35
|
+
return [
|
|
36
|
+
"seekrit is a zero-knowledge secrets manager. This is the LOCAL CRYPTO plane —",
|
|
37
|
+
"it runs on this machine, next to your key, so it's the one server that can",
|
|
38
|
+
"actually read or write a secret VALUE (everything else can only see structure).",
|
|
39
|
+
"",
|
|
40
|
+
"Auth comes from SEEKRIT_TOKEN (a skt_… token), SEEKRIT_CLIENT_ID +",
|
|
41
|
+
"SEEKRIT_CLIENT_SECRET (machine credentials — an admin token is minted and",
|
|
42
|
+
"cached automatically on first use), or the config saved by `seekrit login`.",
|
|
43
|
+
"Decrypting under a user session (not a token) additionally needs",
|
|
44
|
+
"SEEKRIT_PASSPHRASE set in this server's env — there's no TTY to prompt on.",
|
|
45
|
+
"",
|
|
46
|
+
"Model: org → apps/groups → environments → secrets. Call `whoami` first, then",
|
|
47
|
+
"`get_started` for the recommended end-to-end recipe. Prefer `run_command` over",
|
|
48
|
+
"`get_secret reveal:true` — it injects secrets into a subprocess so plaintext",
|
|
49
|
+
"never enters your context or the transcript."
|
|
50
|
+
].join("\n");
|
|
51
|
+
}
|
|
52
|
+
/** The `get_started` tool body: the recommended first-project flow end to end. */
|
|
53
|
+
function getStartedText() {
|
|
54
|
+
return [
|
|
55
|
+
"# Standing up a project with seekrit (agent, end to end)",
|
|
56
|
+
"",
|
|
57
|
+
"This server is the crypto plane — every step below runs locally, next to your",
|
|
58
|
+
"key, so secret values never leave this machine.",
|
|
59
|
+
"",
|
|
60
|
+
"## 1. Confirm identity",
|
|
61
|
+
"`whoami` — see who you're authenticated as and which orgs you can reach. If it",
|
|
62
|
+
"fails, check SEEKRIT_TOKEN / SEEKRIT_CLIENT_ID+SEEKRIT_CLIENT_SECRET / saved",
|
|
63
|
+
"login in this server's env.",
|
|
64
|
+
"",
|
|
65
|
+
"## 2. Provision structure",
|
|
66
|
+
"- `create_org` (user session only — a service token can't own one) if you",
|
|
67
|
+
" don't have one yet, otherwise skip to the next step.",
|
|
68
|
+
"- `create_app` — an application to hold environments.",
|
|
69
|
+
"- `create_env` — generates the data key on this machine and grants it to you.",
|
|
70
|
+
"- `create_group` + `compose_group` (optional) — a reusable secret bag layered",
|
|
71
|
+
" under one or more app environments.",
|
|
72
|
+
"",
|
|
73
|
+
"## 3. Store secrets",
|
|
74
|
+
"- `set_secret` — encrypts a value locally and stores the ciphertext.",
|
|
75
|
+
"- `list_secrets` — confirm names + versions (never returns values).",
|
|
76
|
+
"",
|
|
77
|
+
"## 4. Use secrets without exposing them",
|
|
78
|
+
"- `run_command -- <cmd>` — inject secrets into a subprocess; prefer this.",
|
|
79
|
+
"- `export_env` — materialize a `.env` file when a tool needs one on disk.",
|
|
80
|
+
"- `get_secret reveal:true` — only when the value itself is what's needed.",
|
|
81
|
+
"",
|
|
82
|
+
"## 5. Propagate access",
|
|
83
|
+
"- `create_token` bound to an app+env — a runtime credential for CI/another",
|
|
84
|
+
" agent to decrypt with (pass `admin:true` instead for a provisioning token).",
|
|
85
|
+
"- `grant_env` — give another member or token access to an env's data key.",
|
|
86
|
+
"- `configure_project` — link a directory to an org/app (writes seekrit.json)",
|
|
87
|
+
" so a bound token can infer its target without flags.",
|
|
88
|
+
"",
|
|
89
|
+
"## 6. Verify",
|
|
90
|
+
"`audit` — every write, grant, and revocation is recorded; read it back.",
|
|
91
|
+
"",
|
|
92
|
+
"Also available: `kms_*` (client-side managed encrypt/sign keys) and",
|
|
93
|
+
"`create_pg_lease`/`create_mysql_lease` (short-lived database credentials whose",
|
|
94
|
+
"password is generated here and never stored anywhere in plaintext)."
|
|
95
|
+
].join("\n");
|
|
96
|
+
}
|
|
29
97
|
/** Build the client context or throw a friendly, agent-readable error. */
|
|
30
98
|
function getCtx() {
|
|
31
99
|
const ctx = tryBuildContext();
|
|
@@ -121,7 +189,7 @@ async function runMcpServer(options = {}) {
|
|
|
121
189
|
const server = new McpServer({
|
|
122
190
|
name: "seekrit",
|
|
123
191
|
version: options.version ?? version
|
|
124
|
-
});
|
|
192
|
+
}, { instructions: serverInstructions() });
|
|
125
193
|
/** Register a tool whose handler returns data (serialized) or throws (→ isError). */
|
|
126
194
|
const tool = (name, description, shape, handler) => {
|
|
127
195
|
server.registerTool(name, {
|
|
@@ -135,6 +203,15 @@ async function runMcpServer(options = {}) {
|
|
|
135
203
|
}
|
|
136
204
|
}));
|
|
137
205
|
};
|
|
206
|
+
server.registerTool("get_started", {
|
|
207
|
+
description: "The recommended first-project recipe: provision structure, store secrets, and use them without exposing values. Call this before doing anything else.",
|
|
208
|
+
inputSchema: {},
|
|
209
|
+
annotations: {
|
|
210
|
+
title: "get_started",
|
|
211
|
+
readOnlyHint: true,
|
|
212
|
+
openWorldHint: false
|
|
213
|
+
}
|
|
214
|
+
}, async () => jsonText(getStartedText()));
|
|
138
215
|
tool("whoami", "Show the authenticated identity, its role, and accessible orgs.", {}, async () => {
|
|
139
216
|
const ctx = getCtx();
|
|
140
217
|
if (isTokenAuth(ctx) && ctx.auth.type === "bearer") {
|