@seekrit/cli 2.1.0 → 2.2.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 +163 -33
- package/dist/{mcp-DZoBFmDF.js → mcp-Dgj-7S9y.js} +16 -25
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2086,6 +2086,8 @@ const AUDIT_ACTIONS = [
|
|
|
2086
2086
|
"org.created",
|
|
2087
2087
|
"org.updated",
|
|
2088
2088
|
"org.member_added",
|
|
2089
|
+
"org.member_role_changed",
|
|
2090
|
+
"app.access_granted",
|
|
2089
2091
|
"org.member_removed",
|
|
2090
2092
|
"org.member_invited",
|
|
2091
2093
|
"org.invite_revoked",
|
|
@@ -2308,7 +2310,7 @@ const nameSchema = z.string().trim().min(1).max(128);
|
|
|
2308
2310
|
const emailSchema = z.string().trim().toLowerCase().pipe(z.email().max(320));
|
|
2309
2311
|
/** Env-var style secret name: FOO, DATABASE_URL, apiKey2 … */
|
|
2310
2312
|
const secretNameSchema = z.string().min(1).max(256).regex(/^[A-Za-z_][A-Za-z0-9_]*$/, "must be a valid environment variable name");
|
|
2311
|
-
z.enum([
|
|
2313
|
+
const orgRoleSchema = z.enum([
|
|
2312
2314
|
"owner",
|
|
2313
2315
|
"admin",
|
|
2314
2316
|
"member"
|
|
@@ -2347,7 +2349,20 @@ z.object({
|
|
|
2347
2349
|
name: nameSchema,
|
|
2348
2350
|
slug: slugSchema
|
|
2349
2351
|
});
|
|
2352
|
+
/** Compose a group into an application environment (matched by env slug). */
|
|
2353
|
+
const appAccessKeySchema = z.object({
|
|
2354
|
+
environmentId: z.string().min(1),
|
|
2355
|
+
userId: z.string().min(1),
|
|
2356
|
+
wrappedDek: z.string().min(1).max(8192)
|
|
2357
|
+
});
|
|
2358
|
+
const appAccessGrantsSchema = z.array(appAccessKeySchema).max(5e3).optional();
|
|
2350
2359
|
z.object({
|
|
2360
|
+
userId: z.string().min(1),
|
|
2361
|
+
grants: z.array(appAccessKeySchema).max(5e3)
|
|
2362
|
+
});
|
|
2363
|
+
z.object({ role: orgRoleSchema });
|
|
2364
|
+
z.object({
|
|
2365
|
+
appAccessGrants: appAccessGrantsSchema,
|
|
2351
2366
|
groupId: z.string().min(1),
|
|
2352
2367
|
/** Precedence among an env's groups (higher wins). Appended if omitted. */
|
|
2353
2368
|
position: z.number().int().min(0).optional(),
|
|
@@ -2358,6 +2373,11 @@ z.object({
|
|
|
2358
2373
|
})).optional()
|
|
2359
2374
|
});
|
|
2360
2375
|
z.object({
|
|
2376
|
+
/** Wrap the new DEK to all persistent app recipients. */
|
|
2377
|
+
userGrants: z.array(z.object({
|
|
2378
|
+
userId: z.string().min(1),
|
|
2379
|
+
wrappedDek: z.string().min(1).max(8192)
|
|
2380
|
+
})).max(5e3).optional(),
|
|
2361
2381
|
name: nameSchema,
|
|
2362
2382
|
slug: slugSchema,
|
|
2363
2383
|
/** Environment DEK wrapped to the creator's public key — created client-side. */
|
|
@@ -2419,7 +2439,23 @@ z.object({
|
|
|
2419
2439
|
/** The same DEK wrapped to each of the parent's existing grant-holders. */
|
|
2420
2440
|
grants: z.array(grantEnvironmentKeySchema).max(500).default([])
|
|
2421
2441
|
});
|
|
2442
|
+
/**
|
|
2443
|
+
* Token creation is client-driven so the server never sees the token secret:
|
|
2444
|
+
* the client generates the keypair + token string and submits only the hash
|
|
2445
|
+
* and public key.
|
|
2446
|
+
*/
|
|
2447
|
+
const environmentGrantBatchSchema = z.array(z.object({
|
|
2448
|
+
environmentId: z.string().min(1),
|
|
2449
|
+
wrappedDek: z.string().min(1).max(8192)
|
|
2450
|
+
})).max(5e3);
|
|
2451
|
+
z.object({
|
|
2452
|
+
principalType: principalTypeSchema,
|
|
2453
|
+
principalId: z.string().min(1),
|
|
2454
|
+
grants: environmentGrantBatchSchema
|
|
2455
|
+
});
|
|
2422
2456
|
z.object({
|
|
2457
|
+
/** Commit the token and all default resolve keys together, when supplied. */
|
|
2458
|
+
initialGrants: environmentGrantBatchSchema.optional(),
|
|
2423
2459
|
name: nameSchema,
|
|
2424
2460
|
tokenId: z.string().regex(/^skt_[0-9A-Za-z]+$/),
|
|
2425
2461
|
/** SHA-256 hash (base64url) of the full token string. */
|
|
@@ -5700,7 +5736,7 @@ async function createAgentTaskToken() {
|
|
|
5700
5736
|
}
|
|
5701
5737
|
//#endregion
|
|
5702
5738
|
//#region package.json
|
|
5703
|
-
var version = "2.
|
|
5739
|
+
var version = "2.2.0";
|
|
5704
5740
|
//#endregion
|
|
5705
5741
|
//#region ../../packages/api-client/src/index.ts
|
|
5706
5742
|
/**
|
|
@@ -5837,6 +5873,56 @@ var SeekritClient = class {
|
|
|
5837
5873
|
listMembers(orgId) {
|
|
5838
5874
|
return this.request("GET", `/v1/orgs/${orgId}/members`);
|
|
5839
5875
|
}
|
|
5876
|
+
updateMemberRole(orgId, userId, role) {
|
|
5877
|
+
return this.request("PATCH", `/v1/orgs/${orgId}/members/${userId}`, { role });
|
|
5878
|
+
}
|
|
5879
|
+
getAppAccess(orgId, appId) {
|
|
5880
|
+
return this.request("GET", `/v1/orgs/${orgId}/apps/${appId}/access`);
|
|
5881
|
+
}
|
|
5882
|
+
provisionAppAccess(orgId, appId, userId, grants) {
|
|
5883
|
+
return this.request("POST", `/v1/orgs/${orgId}/apps/${appId}/access`, {
|
|
5884
|
+
userId,
|
|
5885
|
+
grants
|
|
5886
|
+
});
|
|
5887
|
+
}
|
|
5888
|
+
accessRecipients(orgId, target) {
|
|
5889
|
+
const path = "appId" in target ? `apps/${target.appId}` : `groups/${target.groupId}`;
|
|
5890
|
+
return this.request("GET", `/v1/orgs/${orgId}/${path}/access-recipients`);
|
|
5891
|
+
}
|
|
5892
|
+
/** The caller owns the new DEK; only public keys and wrapped blobs cross the API. */
|
|
5893
|
+
async wrapNewEnvironmentAccess(orgId, target, dek) {
|
|
5894
|
+
const { recipients } = await this.accessRecipients(orgId, target);
|
|
5895
|
+
return Promise.all(recipients.map(async (r) => {
|
|
5896
|
+
if (!r.publicKeyJwk) throw new Error(`${r.email} must finish key setup before creating this environment`);
|
|
5897
|
+
return {
|
|
5898
|
+
userId: r.userId,
|
|
5899
|
+
wrappedDek: await wrapDek(dek, r.publicKeyJwk)
|
|
5900
|
+
};
|
|
5901
|
+
}));
|
|
5902
|
+
}
|
|
5903
|
+
async wrapGroupAppAccess(orgId, envId, groupId, getDek) {
|
|
5904
|
+
const { environment } = await this.getEnv(orgId, envId);
|
|
5905
|
+
if (!environment.applicationId) throw new Error("only app environments can compose groups");
|
|
5906
|
+
const { recipients } = await this.accessRecipients(orgId, { appId: environment.applicationId });
|
|
5907
|
+
if (!recipients.length) return [];
|
|
5908
|
+
const { environments } = await this.listGroupEnvs(orgId, groupId);
|
|
5909
|
+
const result = [];
|
|
5910
|
+
for (const env of environments) {
|
|
5911
|
+
const { grants } = await this.listEnvKeys(orgId, env.id);
|
|
5912
|
+
const missing = recipients.filter((r) => !grants.some((g) => g.principalType === "user" && g.principalId === r.userId));
|
|
5913
|
+
if (!missing.length) continue;
|
|
5914
|
+
const dek = await getDek(env.id);
|
|
5915
|
+
for (const recipient of missing) {
|
|
5916
|
+
if (!recipient.publicKeyJwk) throw new Error(`${recipient.email} must finish key setup first`);
|
|
5917
|
+
result.push({
|
|
5918
|
+
environmentId: env.id,
|
|
5919
|
+
userId: recipient.userId,
|
|
5920
|
+
wrappedDek: await wrapDek(dek, recipient.publicKeyJwk)
|
|
5921
|
+
});
|
|
5922
|
+
}
|
|
5923
|
+
}
|
|
5924
|
+
return result;
|
|
5925
|
+
}
|
|
5840
5926
|
/**
|
|
5841
5927
|
* The org-wide "require a second factor for all members" policy. `configured`
|
|
5842
5928
|
* is false when the identity provider isn't wired up (local dev), in which
|
|
@@ -6021,6 +6107,46 @@ var SeekritClient = class {
|
|
|
6021
6107
|
return this.request("POST", `/v1/orgs/${orgId}/change-requests/${id}/withdraw`);
|
|
6022
6108
|
}
|
|
6023
6109
|
/** The calling principal's wrapped DEK for this environment. */
|
|
6110
|
+
getEnvironmentKeyScope(orgId, envId) {
|
|
6111
|
+
return this.request("GET", `/v1/orgs/${orgId}/envs/${envId}/key-scope`);
|
|
6112
|
+
}
|
|
6113
|
+
async prepareComposedKeyGrants(orgId, envId, principal, getDek) {
|
|
6114
|
+
const scope = await this.getEnvironmentKeyScope(orgId, envId);
|
|
6115
|
+
const grants = [];
|
|
6116
|
+
for (const layer of scope.environments) {
|
|
6117
|
+
if (scope.grants.some((g) => g.environmentId === layer.environmentId && g.principalType === principal.principalType && g.principalId === principal.principalId)) continue;
|
|
6118
|
+
try {
|
|
6119
|
+
const dek = await getDek(layer.environmentId);
|
|
6120
|
+
grants.push({
|
|
6121
|
+
environmentId: layer.environmentId,
|
|
6122
|
+
wrappedDek: await wrapDek(dek, principal.publicKeyJwk)
|
|
6123
|
+
});
|
|
6124
|
+
} catch (error) {
|
|
6125
|
+
if (error instanceof Error && error.message === "unlock cancelled") throw error;
|
|
6126
|
+
throw new Error(`Could not prepare access to ${layer.label}: ${error instanceof Error ? error.message : "key unavailable"}. No keys were granted.`);
|
|
6127
|
+
}
|
|
6128
|
+
}
|
|
6129
|
+
return grants;
|
|
6130
|
+
}
|
|
6131
|
+
grantComposedKeys(orgId, envId, input) {
|
|
6132
|
+
return this.request("POST", `/v1/orgs/${orgId}/envs/${envId}/keys/composed`, input);
|
|
6133
|
+
}
|
|
6134
|
+
/** Sharing an application environment includes the exact layers resolve reads. */
|
|
6135
|
+
async grantEnvironmentAccess(orgId, envId, principal, getDek) {
|
|
6136
|
+
const { environment } = await this.getEnv(orgId, envId);
|
|
6137
|
+
if (environment.applicationId) {
|
|
6138
|
+
const grants = await this.prepareComposedKeyGrants(orgId, envId, principal, getDek);
|
|
6139
|
+
await this.grantComposedKeys(orgId, envId, {
|
|
6140
|
+
principalType: principal.principalType,
|
|
6141
|
+
principalId: principal.principalId,
|
|
6142
|
+
grants
|
|
6143
|
+
});
|
|
6144
|
+
} else await this.grantEnvKey(orgId, envId, {
|
|
6145
|
+
principalType: principal.principalType,
|
|
6146
|
+
principalId: principal.principalId,
|
|
6147
|
+
wrappedDek: await wrapDek(await getDek(envId), principal.publicKeyJwk)
|
|
6148
|
+
});
|
|
6149
|
+
}
|
|
6024
6150
|
getMyEnvKey(orgId, envId) {
|
|
6025
6151
|
return this.request("GET", `/v1/orgs/${orgId}/envs/${envId}/key`);
|
|
6026
6152
|
}
|
|
@@ -7154,12 +7280,11 @@ function registerAccessCommands(program) {
|
|
|
7154
7280
|
const ctx = buildContext();
|
|
7155
7281
|
const { orgId, envId, label } = await resolveEnvTarget(ctx, options);
|
|
7156
7282
|
const principal = await resolvePrincipal(ctx, orgId, options);
|
|
7157
|
-
|
|
7158
|
-
await ctx.client.grantEnvKey(orgId, envId, {
|
|
7283
|
+
await ctx.client.grantEnvironmentAccess(orgId, envId, {
|
|
7159
7284
|
principalType: principal.type,
|
|
7160
7285
|
principalId: principal.id,
|
|
7161
|
-
|
|
7162
|
-
});
|
|
7286
|
+
publicKeyJwk: principal.publicKeyJwk
|
|
7287
|
+
}, (id) => getDek(ctx, orgId, id));
|
|
7163
7288
|
console.error(`granted ${label} access to ${principal.id}`);
|
|
7164
7289
|
});
|
|
7165
7290
|
withEnvTarget(grant.command("list").alias("ls").description("list who holds a key for an environment").option("--json", "print the raw API response")).action(async (options) => {
|
|
@@ -9013,6 +9138,7 @@ function registerAppCommands(program) {
|
|
|
9013
9138
|
const wrappedDek = await wrapDek(dek, await principalPublicKeyJwk(ctx));
|
|
9014
9139
|
const recoveryWrappedDek = await recoveryWrapForNewEnv(ctx, orgRef.id, dek);
|
|
9015
9140
|
const created = await ctx.client.createEnv(orgRef.id, appRow.id, {
|
|
9141
|
+
userGrants: await ctx.client.wrapNewEnvironmentAccess(orgRef.id, { appId: appRow.id }, dek),
|
|
9016
9142
|
name: options.name,
|
|
9017
9143
|
slug: options.slug,
|
|
9018
9144
|
wrappedDek,
|
|
@@ -9038,6 +9164,7 @@ function registerAppCommands(program) {
|
|
|
9038
9164
|
});
|
|
9039
9165
|
const syncGrants = await syncGrantsForGroupLink(ctx, target.orgId, target.envId, target.envSlug, group.id);
|
|
9040
9166
|
await ctx.client.linkEnvGroup(target.orgId, target.envId, {
|
|
9167
|
+
appAccessGrants: await ctx.client.wrapGroupAppAccess(target.orgId, target.envId, group.id, (id) => getDek(ctx, target.orgId, id)),
|
|
9041
9168
|
groupId: group.id,
|
|
9042
9169
|
position: options.position === void 0 ? void 0 : Number.parseInt(options.position, 10),
|
|
9043
9170
|
syncGrants
|
|
@@ -11807,6 +11934,7 @@ function registerGroupCommands(program) {
|
|
|
11807
11934
|
const wrappedDek = await wrapDek(dek, user.publicKeyJwk);
|
|
11808
11935
|
const recoveryWrappedDek = await recoveryWrapForNewEnv(ctx, groupRef.orgId, dek);
|
|
11809
11936
|
const created = await ctx.client.createGroupEnv(groupRef.orgId, groupRef.id, {
|
|
11937
|
+
userGrants: await ctx.client.wrapNewEnvironmentAccess(groupRef.orgId, { groupId: groupRef.id }, dek),
|
|
11810
11938
|
name: options.name,
|
|
11811
11939
|
slug: options.slug,
|
|
11812
11940
|
wrappedDek,
|
|
@@ -12270,6 +12398,7 @@ async function runInit(options) {
|
|
|
12270
12398
|
const wrappedDek = await wrapDek(dek, await principalPublicKeyJwk(ctx));
|
|
12271
12399
|
const recoveryWrappedDek = await recoveryWrapForNewEnv(ctx, orgRef.id, dek);
|
|
12272
12400
|
({environment: env} = await ctx.client.createEnv(orgRef.id, app.id, {
|
|
12401
|
+
userGrants: await ctx.client.wrapNewEnvironmentAccess(orgRef.id, { appId: app.id }, dek),
|
|
12273
12402
|
name: titleCase(envSlug),
|
|
12274
12403
|
slug: envSlug,
|
|
12275
12404
|
wrappedDek,
|
|
@@ -16826,42 +16955,43 @@ token.command("create").description("create a service token (runtime, or --admin
|
|
|
16826
16955
|
if (boundToEnv && !(options.app && options.env)) fail("pass both --app and --env to bind a token to an environment");
|
|
16827
16956
|
const target = boundToEnv ? await resolveAppEnv(ctx, options) : { orgId: (await resolveOrg(ctx, options.org)).id };
|
|
16828
16957
|
const created = await createServiceToken();
|
|
16958
|
+
const granted = boundToEnv && options.grant !== false;
|
|
16959
|
+
const initialGrants = granted && "envId" in target ? await ctx.client.prepareComposedKeyGrants(target.orgId, target.envId, {
|
|
16960
|
+
principalType: "service_token",
|
|
16961
|
+
principalId: created.tokenId,
|
|
16962
|
+
publicKeyJwk: created.publicKeyJwk
|
|
16963
|
+
}, (id) => getDek(ctx, target.orgId, id)) : void 0;
|
|
16964
|
+
const extraGrants = [];
|
|
16965
|
+
if (granted) for (const [groupSlug, envSlug] of Object.entries(options.allow ?? {})) {
|
|
16966
|
+
const groupRef = await resolveGroup(ctx, {
|
|
16967
|
+
org: options.org,
|
|
16968
|
+
group: groupSlug
|
|
16969
|
+
});
|
|
16970
|
+
const { environments } = await ctx.client.listGroupEnvs(target.orgId, groupRef.id);
|
|
16971
|
+
const slice = environments.find((e) => e.slug === envSlug);
|
|
16972
|
+
if (!slice) fail(`group "${groupSlug}" has no "${envSlug}" environment`);
|
|
16973
|
+
extraGrants.push({
|
|
16974
|
+
environmentId: slice.id,
|
|
16975
|
+
wrappedDek: await wrapDek(await getDek(ctx, target.orgId, slice.id), created.publicKeyJwk)
|
|
16976
|
+
});
|
|
16977
|
+
}
|
|
16829
16978
|
await ctx.client.createToken(target.orgId, {
|
|
16830
16979
|
name: options.name,
|
|
16831
16980
|
tokenId: created.tokenId,
|
|
16832
16981
|
tokenHash: created.tokenHash,
|
|
16833
16982
|
publicKeyJwk: created.publicKeyJwk,
|
|
16834
16983
|
role,
|
|
16835
|
-
environmentId: "envId" in target ? target.envId : null
|
|
16984
|
+
environmentId: "envId" in target ? target.envId : null,
|
|
16985
|
+
initialGrants
|
|
16836
16986
|
});
|
|
16837
|
-
const
|
|
16838
|
-
|
|
16839
|
-
await ctx.client.grantEnvKey(target.orgId, envId, {
|
|
16987
|
+
for (const extra of extraGrants) try {
|
|
16988
|
+
await ctx.client.grantEnvKey(target.orgId, extra.environmentId, {
|
|
16840
16989
|
principalType: "service_token",
|
|
16841
16990
|
principalId: created.tokenId,
|
|
16842
|
-
wrappedDek:
|
|
16991
|
+
wrappedDek: extra.wrappedDek
|
|
16843
16992
|
});
|
|
16844
|
-
}
|
|
16845
|
-
|
|
16846
|
-
if (granted && "envId" in target) {
|
|
16847
|
-
await grantEnv(target.envId);
|
|
16848
|
-
const { groups } = await ctx.client.listEnvGroups(target.orgId, target.envId);
|
|
16849
|
-
for (const g of groups) {
|
|
16850
|
-
const { environments } = await ctx.client.listGroupEnvs(target.orgId, g.groupId);
|
|
16851
|
-
const slice = environments.find((e) => e.slug === target.envSlug);
|
|
16852
|
-
if (!slice) fail(`group "${g.slug}" has no "${target.envSlug}" environment — create it before granting`);
|
|
16853
|
-
await grantEnv(slice.id);
|
|
16854
|
-
}
|
|
16855
|
-
for (const [groupSlug, envSlug] of Object.entries(options.allow ?? {})) {
|
|
16856
|
-
const groupRef = await resolveGroup(ctx, {
|
|
16857
|
-
org: options.org,
|
|
16858
|
-
group: groupSlug
|
|
16859
|
-
});
|
|
16860
|
-
const { environments } = await ctx.client.listGroupEnvs(target.orgId, groupRef.id);
|
|
16861
|
-
const slice = environments.find((e) => e.slug === envSlug);
|
|
16862
|
-
if (!slice) fail(`group "${groupSlug}" has no "${envSlug}" environment`);
|
|
16863
|
-
await grantEnv(slice.id);
|
|
16864
|
-
}
|
|
16993
|
+
} catch (error) {
|
|
16994
|
+
console.error(`Token created with its default environment keys, but extra grant ${extra.environmentId} failed: ${error instanceof Error ? error.message : "unknown error"}`);
|
|
16865
16995
|
}
|
|
16866
16996
|
const scope = "appSlug" in target ? `${target.appSlug}/${target.envSlug}` : "org-scoped (admin)";
|
|
16867
16997
|
console.error(`${role} token created${granted ? " and granted" : ""} for ${scope} — save it now, it is not stored:`);
|
|
@@ -16915,7 +17045,7 @@ registerKmsCommands(program);
|
|
|
16915
17045
|
registerRotationCommands(program);
|
|
16916
17046
|
registerRecoveryCommands(program);
|
|
16917
17047
|
program.command("mcp").description("run an MCP server over stdio so AI agents can drive seekrit").action(async () => {
|
|
16918
|
-
const { runMcpServer } = await import("./mcp-
|
|
17048
|
+
const { runMcpServer } = await import("./mcp-Dgj-7S9y.js");
|
|
16919
17049
|
await runMcpServer();
|
|
16920
17050
|
});
|
|
16921
17051
|
registerAuditCommands(program);
|
|
@@ -527,7 +527,8 @@ async function runMcpServer(options = {}) {
|
|
|
527
527
|
return (await ctx.client.createEnv(orgRef.id, appRow.id, {
|
|
528
528
|
name,
|
|
529
529
|
slug,
|
|
530
|
-
wrappedDek
|
|
530
|
+
wrappedDek,
|
|
531
|
+
userGrants: await ctx.client.wrapNewEnvironmentAccess(orgRef.id, { appId: appRow.id }, dek)
|
|
531
532
|
})).environment;
|
|
532
533
|
});
|
|
533
534
|
tool("create_branch", "Fork an environment into an ephemeral branch (a per-PR / preview config). The branch inherits the parent's secrets by layering at read time — nothing is copied or re-encrypted — and holds only the values you override on it. Generates the branch's data key locally, grants it to the caller, and shares it with the parent's other readers.", { idempotent: false }, {
|
|
@@ -595,7 +596,8 @@ async function runMcpServer(options = {}) {
|
|
|
595
596
|
return (await ctx.client.createGroupEnv(g.orgId, g.id, {
|
|
596
597
|
name,
|
|
597
598
|
slug,
|
|
598
|
-
wrappedDek
|
|
599
|
+
wrappedDek,
|
|
600
|
+
userGrants: await ctx.client.wrapNewEnvironmentAccess(g.orgId, { groupId: g.id }, dek)
|
|
599
601
|
})).environment;
|
|
600
602
|
});
|
|
601
603
|
tool("compose_group", "Compose a group into an application environment (higher position wins on name clashes).", { idempotent: true }, {
|
|
@@ -617,6 +619,7 @@ async function runMcpServer(options = {}) {
|
|
|
617
619
|
});
|
|
618
620
|
const syncGrants = await syncGrantsForGroupLink(ctx, target.orgId, target.envId, target.envSlug, g.id);
|
|
619
621
|
return (await ctx.client.linkEnvGroup(target.orgId, target.envId, {
|
|
622
|
+
appAccessGrants: await ctx.client.wrapGroupAppAccess(target.orgId, target.envId, g.id, (id) => getDek(ctx, target.orgId, id)),
|
|
620
623
|
groupId: g.id,
|
|
621
624
|
position,
|
|
622
625
|
syncGrants
|
|
@@ -819,32 +822,21 @@ async function runMcpServer(options = {}) {
|
|
|
819
822
|
env
|
|
820
823
|
}) : { orgId: (await resolveOrg(ctx, org)).id };
|
|
821
824
|
const created = await createServiceToken();
|
|
825
|
+
if (boundToEnv) ensureDecryptable(ctx);
|
|
826
|
+
const initialGrants = "envId" in target ? await ctx.client.prepareComposedKeyGrants(target.orgId, target.envId, {
|
|
827
|
+
principalType: "service_token",
|
|
828
|
+
principalId: created.tokenId,
|
|
829
|
+
publicKeyJwk: created.publicKeyJwk
|
|
830
|
+
}, (id) => getDek(ctx, target.orgId, id)) : void 0;
|
|
822
831
|
await ctx.client.createToken(target.orgId, {
|
|
823
832
|
name,
|
|
824
833
|
tokenId: created.tokenId,
|
|
825
834
|
tokenHash: created.tokenHash,
|
|
826
835
|
publicKeyJwk: created.publicKeyJwk,
|
|
827
836
|
role,
|
|
828
|
-
environmentId: "envId" in target ? target.envId : null
|
|
837
|
+
environmentId: "envId" in target ? target.envId : null,
|
|
838
|
+
initialGrants
|
|
829
839
|
});
|
|
830
|
-
if (boundToEnv && "envId" in target) {
|
|
831
|
-
ensureDecryptable(ctx);
|
|
832
|
-
const grantEnv = async (envId) => {
|
|
833
|
-
const dek = await getDek(ctx, target.orgId, envId);
|
|
834
|
-
await ctx.client.grantEnvKey(target.orgId, envId, {
|
|
835
|
-
principalType: "service_token",
|
|
836
|
-
principalId: created.tokenId,
|
|
837
|
-
wrappedDek: await wrapDek(dek, created.publicKeyJwk)
|
|
838
|
-
});
|
|
839
|
-
};
|
|
840
|
-
await grantEnv(target.envId);
|
|
841
|
-
const { groups } = await ctx.client.listEnvGroups(target.orgId, target.envId);
|
|
842
|
-
for (const g of groups) {
|
|
843
|
-
const { environments } = await ctx.client.listGroupEnvs(target.orgId, g.groupId);
|
|
844
|
-
const slice = environments.find((e) => e.slug === target.envSlug);
|
|
845
|
-
if (slice) await grantEnv(slice.id);
|
|
846
|
-
}
|
|
847
|
-
}
|
|
848
840
|
return {
|
|
849
841
|
token: created.token,
|
|
850
842
|
tokenId: created.tokenId,
|
|
@@ -873,7 +865,6 @@ async function runMcpServer(options = {}) {
|
|
|
873
865
|
const ctx = getCtx();
|
|
874
866
|
ensureDecryptable(ctx);
|
|
875
867
|
const { orgId, envId, label } = await resolveEnvTarget(ctx, o);
|
|
876
|
-
const dek = await getDek(ctx, orgId, envId);
|
|
877
868
|
let principalType;
|
|
878
869
|
let principalId;
|
|
879
870
|
let publicKeyJwk;
|
|
@@ -897,11 +888,11 @@ async function runMcpServer(options = {}) {
|
|
|
897
888
|
t.publicKeyJwk
|
|
898
889
|
];
|
|
899
890
|
}
|
|
900
|
-
await ctx.client.
|
|
891
|
+
await ctx.client.grantEnvironmentAccess(orgId, envId, {
|
|
901
892
|
principalType,
|
|
902
893
|
principalId,
|
|
903
|
-
|
|
904
|
-
});
|
|
894
|
+
publicKeyJwk
|
|
895
|
+
}, (id) => getDek(ctx, orgId, id));
|
|
905
896
|
return {
|
|
906
897
|
ok: true,
|
|
907
898
|
env: label,
|
package/package.json
CHANGED