@simonfestl/husky-cli 1.30.0 → 1.31.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.
@@ -6,6 +6,27 @@ const API_KEY_ROLES = [
6
6
  "admin", "supervisor", "worker", "reviewer", "support",
7
7
  "purchasing", "ops", "e2e_agent", "pr_agent"
8
8
  ];
9
+ /**
10
+ * Fetch VM Identity Token from GCP Metadata Server
11
+ * This token is cryptographically signed by Google and proves the caller is running on a specific GCP VM.
12
+ * Returns null if not running on GCP or metadata server is unavailable.
13
+ */
14
+ async function getVMIdentityToken(audience = "husky-api") {
15
+ try {
16
+ const url = `http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity?audience=${audience}`;
17
+ const res = await fetch(url, {
18
+ headers: { "Metadata-Flavor": "Google" },
19
+ signal: AbortSignal.timeout(3000), // 3 second timeout
20
+ });
21
+ if (res.ok) {
22
+ return (await res.text()).trim();
23
+ }
24
+ }
25
+ catch {
26
+ // Not on GCP or metadata server unavailable - this is expected for local development
27
+ }
28
+ return null;
29
+ }
9
30
  export const authCommand = new Command("auth")
10
31
  .description("Manage API keys and authentication");
11
32
  authCommand
@@ -250,7 +271,8 @@ authCommand
250
271
  authCommand
251
272
  .command("login")
252
273
  .description("Create a session token for this agent")
253
- .requiredOption("--agent <name>", "Agent name (must be registered in Firestore)")
274
+ .requiredOption("--agent <name>", "Agent name or alias (must be registered in Firestore)")
275
+ .option("--force", "Clear existing session before creating new one")
254
276
  .option("--json", "Output as JSON")
255
277
  .action(async (options) => {
256
278
  try {
@@ -259,14 +281,26 @@ authCommand
259
281
  console.error("API not configured. Run: husky config set api-url <url> && husky config set api-key <key>");
260
282
  process.exit(1);
261
283
  }
284
+ // Clear existing session if --force flag is set
285
+ if (options.force) {
286
+ clearSessionConfig();
287
+ clearPermissionsCache();
288
+ }
289
+ // Try to get VM Identity Token from GCP Metadata Server
290
+ // This will be null on local development machines
291
+ const vmIdentityToken = await getVMIdentityToken();
262
292
  const url = new URL("/api/auth/session", config.apiUrl);
293
+ const requestBody = { agent: options.agent };
294
+ if (vmIdentityToken) {
295
+ requestBody.vmIdentityToken = vmIdentityToken;
296
+ }
263
297
  const res = await fetch(url.toString(), {
264
298
  method: "POST",
265
299
  headers: {
266
300
  "x-api-key": config.apiKey,
267
301
  "Content-Type": "application/json",
268
302
  },
269
- body: JSON.stringify({ agent: options.agent }),
303
+ body: JSON.stringify(requestBody),
270
304
  });
271
305
  if (!res.ok) {
272
306
  const error = await res.json().catch(() => ({ error: res.statusText }));
@@ -401,14 +435,20 @@ authCommand
401
435
  console.error("No agent specified and no active session. Use: husky auth refresh --agent <name>");
402
436
  process.exit(1);
403
437
  }
438
+ // Try to get VM Identity Token from GCP Metadata Server
439
+ const vmIdentityToken = await getVMIdentityToken();
404
440
  const url = new URL("/api/auth/session", config.apiUrl);
441
+ const requestBody = { agent: agentName };
442
+ if (vmIdentityToken) {
443
+ requestBody.vmIdentityToken = vmIdentityToken;
444
+ }
405
445
  const res = await fetch(url.toString(), {
406
446
  method: "POST",
407
447
  headers: {
408
448
  "x-api-key": config.apiKey,
409
449
  "Content-Type": "application/json",
410
450
  },
411
- body: JSON.stringify({ agent: agentName }),
451
+ body: JSON.stringify(requestBody),
412
452
  });
413
453
  if (!res.ok) {
414
454
  const error = await res.json().catch(() => ({ error: res.statusText }));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simonfestl/husky-cli",
3
- "version": "1.30.0",
3
+ "version": "1.31.0",
4
4
  "description": "CLI for Huskyv0 Task Orchestration with Claude Agent SDK",
5
5
  "type": "module",
6
6
  "bin": {