@indigoai-us/hq-cli 5.47.9 → 5.47.11
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/commands/members.js +38 -2
- package/dist/commands/run.js +34 -5
- package/dist/commands/secrets.d.ts +35 -1
- package/dist/commands/secrets.js +346 -22
- package/dist/run/hq-plugin.d.ts +4 -11
- package/dist/run/hq-plugin.js +22 -5
- package/dist/utils/integrity.d.ts +4 -0
- package/dist/utils/integrity.js +11 -7
- package/dist/utils/secrets-cache.d.ts +2 -1
- package/dist/utils/secrets-cache.js +42 -14
- package/package.json +1 -1
- package/src/commands/members.test.ts +92 -1
- package/src/commands/members.ts +61 -0
- package/src/commands/run.env-local.test.ts +5 -1
- package/src/commands/run.ts +40 -9
- package/src/commands/secrets.test.ts +394 -4
- package/src/commands/secrets.ts +574 -37
- package/src/run/hq-plugin.test.ts +31 -0
- package/src/run/hq-plugin.ts +33 -7
- package/src/utils/integrity.ts +13 -8
- package/src/utils/secrets-cache.ts +45 -11
package/dist/commands/members.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
|
|
2
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
2
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="40f5379c-742e-5cd5-aba2-931856dc7dd3")}catch(e){}}();
|
|
3
3
|
import chalk from "chalk";
|
|
4
4
|
import { ensureCognitoToken } from "../utils/cognito-session.js";
|
|
5
5
|
import { vaultApiFetch, getCompanyUid } from "../utils/vault-api.js";
|
|
6
6
|
const EMAIL_PATTERN = /^[^\s]+@[^\s]+$/;
|
|
7
7
|
const PERSON_UID_PATTERN = /^prs_[A-Za-z0-9_-]+$/;
|
|
8
8
|
export const VALID_ROLES = new Set(["owner", "admin", "member", "guest"]);
|
|
9
|
+
const VALID_MEMBER_SET_ROLES = new Set(["admin", "member"]);
|
|
9
10
|
export function detectTarget(target) {
|
|
10
11
|
if (EMAIL_PATTERN.test(target)) {
|
|
11
12
|
return { type: "email", value: target.trim().toLowerCase() };
|
|
@@ -250,11 +251,46 @@ export async function revokeInvite(token, tokenOrKey, companyUid) {
|
|
|
250
251
|
throw new InviteHttpError(res.status, err.message ?? err.error ?? res.statusText, err.code);
|
|
251
252
|
}
|
|
252
253
|
}
|
|
254
|
+
async function setMemberRole(token, companyUid, membershipKey, newRole) {
|
|
255
|
+
if (!VALID_MEMBER_SET_ROLES.has(newRole)) {
|
|
256
|
+
throw new Error(`Invalid role '${newRole}': must be one of admin, member`);
|
|
257
|
+
}
|
|
258
|
+
const res = await vaultApiFetch({
|
|
259
|
+
token,
|
|
260
|
+
path: "/membership/role",
|
|
261
|
+
method: "POST",
|
|
262
|
+
body: { companyUid, membershipKey, newRole },
|
|
263
|
+
});
|
|
264
|
+
if (!res.ok) {
|
|
265
|
+
const err = (await res.json().catch(() => ({})));
|
|
266
|
+
throw new InviteHttpError(res.status, err.message ?? err.error ?? res.statusText, err.code);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
253
269
|
export function registerMembersCommand(program) {
|
|
254
270
|
const members = program
|
|
255
271
|
.command("members")
|
|
256
272
|
.description("Manage company memberships and invites")
|
|
257
273
|
.option("--company <slug>", "Company slug (resolves to companyUid)");
|
|
274
|
+
members
|
|
275
|
+
.command("set-role <membershipKey> <role>")
|
|
276
|
+
.description("Change a member or agent role to admin or member")
|
|
277
|
+
.action(async (membershipKey, role) => {
|
|
278
|
+
try {
|
|
279
|
+
const token = await ensureCognitoToken();
|
|
280
|
+
const companySlug = members.opts().company;
|
|
281
|
+
const companyUid = await getCompanyUid(token, companySlug);
|
|
282
|
+
await setMemberRole(token, companyUid, membershipKey, role);
|
|
283
|
+
console.log(chalk.green(`Updated role for '${membershipKey}' to ${role}`));
|
|
284
|
+
}
|
|
285
|
+
catch (err) {
|
|
286
|
+
if (err instanceof InviteHttpError) {
|
|
287
|
+
console.error(chalk.red(err.message));
|
|
288
|
+
process.exit(1);
|
|
289
|
+
}
|
|
290
|
+
console.error(chalk.red("Error:"), err instanceof Error ? err.message : String(err));
|
|
291
|
+
process.exit(1);
|
|
292
|
+
}
|
|
293
|
+
});
|
|
258
294
|
members
|
|
259
295
|
.command("invite <target>")
|
|
260
296
|
.description("Invite a person to the company by email or personUid (sends an invitation email by default)")
|
|
@@ -461,4 +497,4 @@ export function registerMembersCommand(program) {
|
|
|
461
497
|
});
|
|
462
498
|
}
|
|
463
499
|
//# sourceMappingURL=members.js.map
|
|
464
|
-
//# debugId=
|
|
500
|
+
//# debugId=40f5379c-742e-5cd5-aba2-931856dc7dd3
|
package/dist/commands/run.js
CHANGED
|
@@ -1,19 +1,36 @@
|
|
|
1
1
|
|
|
2
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
2
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="26bb7e02-3864-5c66-8232-3abc8fc17dc1")}catch(e){}}();
|
|
3
3
|
import { spawn } from 'node:child_process';
|
|
4
4
|
import * as path from 'node:path';
|
|
5
5
|
import * as fs from 'node:fs';
|
|
6
6
|
import { internal } from 'varlock';
|
|
7
7
|
import { ensureCognitoToken } from '../utils/cognito-session.js';
|
|
8
|
+
import { computeSha256 } from '../utils/integrity.js';
|
|
8
9
|
import { vaultApiFetch, getCompanyUid } from '../utils/vault-api.js';
|
|
9
10
|
import { discoverSchemas } from '../run/discover-schemas.js';
|
|
10
11
|
import { installHqPlugin, prewarmHqSecrets } from '../run/hq-plugin.js';
|
|
12
|
+
async function buildRunUsage(scriptPath) {
|
|
13
|
+
if (!scriptPath) {
|
|
14
|
+
return undefined;
|
|
15
|
+
}
|
|
16
|
+
const resolvedPath = path.resolve(scriptPath);
|
|
17
|
+
return {
|
|
18
|
+
channel: 'run',
|
|
19
|
+
script: {
|
|
20
|
+
scriptId: resolvedPath,
|
|
21
|
+
path: resolvedPath,
|
|
22
|
+
sha256: await computeSha256(resolvedPath),
|
|
23
|
+
attestationLevel: 'self-asserted-hash',
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
}
|
|
11
27
|
export function registerRunCommand(program) {
|
|
12
28
|
program
|
|
13
29
|
.command('run')
|
|
14
30
|
.description('Load secrets from .env.schema and run a command with them injected')
|
|
15
31
|
.option('--company <slug>', 'Company slug (overrides @hqCompany in schema)')
|
|
16
32
|
.option('--schema <path>', 'Explicit schema path (skips walk-up discovery)')
|
|
33
|
+
.option('--script <path>', 'Attach local script identity for script-locked secrets')
|
|
17
34
|
.option('--check', 'Resolve schema and validate vars without executing the command')
|
|
18
35
|
.allowUnknownOption(true)
|
|
19
36
|
.action(async (opts) => {
|
|
@@ -53,22 +70,34 @@ export function registerRunCommand(program) {
|
|
|
53
70
|
}
|
|
54
71
|
const token = await ensureCognitoToken();
|
|
55
72
|
const uid = await getCompanyUid(token, slug);
|
|
56
|
-
const
|
|
73
|
+
const usage = await buildRunUsage(opts.script);
|
|
74
|
+
const fetchBatch = async (companyUid, names, requestUsage) => {
|
|
57
75
|
const res = await vaultApiFetch({
|
|
58
76
|
token,
|
|
59
77
|
path: `/secrets/${encodeURIComponent(companyUid)}/load`,
|
|
60
78
|
method: 'POST',
|
|
61
|
-
body: { names },
|
|
79
|
+
body: requestUsage ? { names, usage: requestUsage } : { names },
|
|
62
80
|
});
|
|
63
81
|
if (!res.ok) {
|
|
64
82
|
const body = await res.json().catch(() => ({}));
|
|
65
|
-
|
|
83
|
+
const message = typeof body.message === 'string'
|
|
84
|
+
? body.message
|
|
85
|
+
: typeof body.error === 'string'
|
|
86
|
+
? body.error
|
|
87
|
+
: res.statusText;
|
|
88
|
+
if (res.status >= 400 &&
|
|
89
|
+
res.status < 500 &&
|
|
90
|
+
typeof body.code === 'string') {
|
|
91
|
+
throw new Error(message);
|
|
92
|
+
}
|
|
93
|
+
throw new Error(`Failed to batch-load secrets: ${message}`);
|
|
66
94
|
}
|
|
67
95
|
return res.json();
|
|
68
96
|
};
|
|
69
97
|
const pluginOpts = {
|
|
70
98
|
companyOverride: opts.company,
|
|
71
99
|
resolveCompanyUid: async () => uid,
|
|
100
|
+
usage,
|
|
72
101
|
fetchBatch,
|
|
73
102
|
};
|
|
74
103
|
// LAST entry = highest precedence; .env.local files trail .env.schema files so any .env.local beats any schema regardless of depth.
|
|
@@ -116,4 +145,4 @@ export function registerRunCommand(program) {
|
|
|
116
145
|
});
|
|
117
146
|
}
|
|
118
147
|
//# sourceMappingURL=run.js.map
|
|
119
|
-
//# debugId=
|
|
148
|
+
//# debugId=26bb7e02-3864-5c66-8232-3abc8fc17dc1
|
|
@@ -2,6 +2,40 @@ import { Command } from "commander";
|
|
|
2
2
|
import { vaultApiFetch, getCompanyUid, getEntityUid } from "../utils/vault-api.js";
|
|
3
3
|
export type { VaultApiOptions } from "../utils/vault-api.js";
|
|
4
4
|
export { vaultApiFetch, getCompanyUid, getEntityUid };
|
|
5
|
-
export
|
|
5
|
+
export type SecretTier = "standard" | "sensitive" | "nuclear";
|
|
6
|
+
export type SecretScriptLockMode = "off" | "enforced";
|
|
7
|
+
export type SecretUsageChannel = "run" | "exec" | "env" | "reveal" | "submit-link";
|
|
8
|
+
export interface SecretScriptUsage {
|
|
9
|
+
scriptId: string;
|
|
10
|
+
path: string;
|
|
11
|
+
sha256: string;
|
|
12
|
+
attestationLevel: string;
|
|
13
|
+
}
|
|
14
|
+
export interface SecretUsage {
|
|
15
|
+
channel: SecretUsageChannel;
|
|
16
|
+
reason?: string;
|
|
17
|
+
script?: SecretScriptUsage;
|
|
18
|
+
}
|
|
19
|
+
export interface SecretMetadata {
|
|
20
|
+
tier?: SecretTier;
|
|
21
|
+
scriptLock?: {
|
|
22
|
+
mode?: SecretScriptLockMode;
|
|
23
|
+
requiredAttestation?: string;
|
|
24
|
+
};
|
|
25
|
+
cacheTtlMs?: number;
|
|
26
|
+
}
|
|
27
|
+
export interface SecretLoadSuccessRow extends SecretMetadata {
|
|
28
|
+
name: string;
|
|
29
|
+
value?: string;
|
|
30
|
+
}
|
|
31
|
+
export interface SecretLoadResponse {
|
|
32
|
+
secrets: SecretLoadSuccessRow[];
|
|
33
|
+
errors: Array<{
|
|
34
|
+
name: string;
|
|
35
|
+
code: string;
|
|
36
|
+
message?: string;
|
|
37
|
+
}>;
|
|
38
|
+
}
|
|
39
|
+
export declare function loadRevealedSecrets(token: string, companyUid: string, keys: string[], usage?: SecretUsage): Promise<Map<string, string>>;
|
|
6
40
|
export declare function registerSecretsCommand(program: Command): void;
|
|
7
41
|
//# sourceMappingURL=secrets.d.ts.map
|