agentaudit 3.12.6 → 3.12.7

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.
Files changed (2) hide show
  1. package/cli.mjs +125 -7
  2. package/package.json +1 -1
package/cli.mjs CHANGED
@@ -15,7 +15,8 @@
15
15
  * activity Your recent audits & findings
16
16
  * search <query> Search packages in registry
17
17
  * model [name|reset] Configure LLM provider + model
18
- * setup Log in to agentaudit.dev (for report uploads)
18
+ * login Sign in with GitHub (opens browser, auto-creates API key)
19
+ * setup Manual login — paste an API key from agentaudit.dev
19
20
  * status Show current config + auth status
20
21
  * profile Your profile — rank, points, audit stats
21
22
  * help [command] Show help
@@ -579,6 +580,117 @@ async function setupCommand() {
579
580
  console.log();
580
581
  }
581
582
 
583
+ // ── Login via GitHub Device Flow ─────────────────────────
584
+
585
+ async function loginCommand() {
586
+ console.log(` ${c.bold}AgentAudit Login${c.reset}`);
587
+ console.log(` ${c.dim}Sign in with GitHub to upload audit reports${c.reset}`);
588
+ console.log();
589
+
590
+ const existing = loadCredentials();
591
+ if (existing) {
592
+ console.log(` ${icons.safe} Already logged in as ${c.bold}${existing.agent_name}${c.reset}`);
593
+ console.log(` ${c.dim}Key: ${existing.api_key.slice(0, 12)}...${c.reset}`);
594
+ console.log();
595
+ const answer = await askQuestion(` Re-authenticate? ${c.dim}(y/N)${c.reset} `);
596
+ if (answer.toLowerCase() !== 'y') {
597
+ console.log(` ${c.dim}Keeping existing login.${c.reset}`);
598
+ return;
599
+ }
600
+ console.log();
601
+ }
602
+
603
+ // Step 1: Start device flow
604
+ process.stdout.write(` Starting login flow...`);
605
+ let deviceData;
606
+ try {
607
+ const res = await fetch(`${REGISTRY_URL}/api/auth/device`, {
608
+ method: 'POST',
609
+ headers: { 'Content-Type': 'application/json' },
610
+ signal: AbortSignal.timeout(10_000),
611
+ });
612
+ deviceData = await res.json();
613
+ if (!res.ok || !deviceData.device_code) {
614
+ console.log(` ${c.red}failed${c.reset}`);
615
+ console.log(` ${c.red}${deviceData.error || 'Could not start login flow'}${c.reset}`);
616
+ console.log(` ${c.dim}Fallback: run ${c.cyan}agentaudit setup${c.dim} to paste an API key manually${c.reset}`);
617
+ return;
618
+ }
619
+ console.log(` ${c.green}ok${c.reset}`);
620
+ } catch (err) {
621
+ console.log(` ${c.red}failed${c.reset}`);
622
+ console.log(` ${c.red}Could not reach ${REGISTRY_URL}${c.reset}`);
623
+ console.log(` ${c.dim}Fallback: run ${c.cyan}agentaudit setup${c.dim} to paste an API key manually${c.reset}`);
624
+ return;
625
+ }
626
+
627
+ // Step 2: Open browser
628
+ const verifyUrl = deviceData.verification_url;
629
+ console.log();
630
+ console.log(` ${c.bold}Open this URL in your browser:${c.reset}`);
631
+ console.log(` ${c.cyan}${verifyUrl}${c.reset}`);
632
+ console.log();
633
+
634
+ // Try to auto-open browser
635
+ try {
636
+ const openCmd = process.platform === 'darwin' ? 'open' : process.platform === 'win32' ? 'start' : 'xdg-open';
637
+ const { exec } = await import('child_process');
638
+ exec(`${openCmd} "${verifyUrl}"`);
639
+ console.log(` ${c.dim}(Browser should open automatically)${c.reset}`);
640
+ } catch {}
641
+
642
+ // Step 3: Poll for authorization
643
+ console.log(` ${c.dim}Waiting for GitHub authorization...${c.reset}`);
644
+ console.log();
645
+
646
+ const interval = (deviceData.interval || 5) * 1000;
647
+ const maxAttempts = Math.ceil((deviceData.expires_in || 900) / (interval / 1000));
648
+
649
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
650
+ await new Promise(r => setTimeout(r, interval));
651
+
652
+ try {
653
+ const res = await fetch(`${REGISTRY_URL}/api/auth/device?device_code=${deviceData.device_code}`, {
654
+ signal: AbortSignal.timeout(10_000),
655
+ });
656
+ const data = await res.json();
657
+
658
+ if (res.ok && data.api_key) {
659
+ // Success!
660
+ saveCredentials({ api_key: data.api_key, agent_name: data.agent_name });
661
+ console.log(` ${c.green}${icons.safe} Logged in as ${c.bold}${data.agent_name}${c.reset}`);
662
+ console.log(` ${c.dim}Key saved to: ${USER_CRED_FILE}${c.reset}`);
663
+ console.log();
664
+ console.log(` ${c.bold}Ready!${c.reset} You can now:`);
665
+ console.log(` ${c.dim}•${c.reset} Audit packages: ${c.cyan}agentaudit audit <repo-url>${c.reset}`);
666
+ console.log(` ${c.dim}•${c.reset} Quick scan: ${c.cyan}agentaudit scan <repo-url>${c.reset}`);
667
+ console.log(` ${c.dim}•${c.reset} Check registry: ${c.cyan}agentaudit check <name>${c.reset}`);
668
+ console.log();
669
+ return;
670
+ }
671
+
672
+ if (data.error === 'authorization_pending') {
673
+ process.stdout.write(`\r ${c.dim}Waiting... (${attempt + 1}/${maxAttempts})${c.reset} `);
674
+ continue;
675
+ }
676
+
677
+ if (data.error === 'expired_token') {
678
+ console.log(`\n ${c.red}Login expired. Run ${c.cyan}agentaudit login${c.red} again.${c.reset}`);
679
+ return;
680
+ }
681
+
682
+ // Unknown error
683
+ console.log(`\n ${c.red}${data.error || 'Unknown error'}${c.reset}`);
684
+ return;
685
+ } catch {
686
+ // Network error during poll — continue trying
687
+ continue;
688
+ }
689
+ }
690
+
691
+ console.log(`\n ${c.red}Login timed out. Run ${c.cyan}agentaudit login${c.red} again.${c.reset}`);
692
+ }
693
+
582
694
  // ── Helpers ──────────────────────────────────────────────
583
695
 
584
696
  function validateGitUrl(url) {
@@ -3126,7 +3238,7 @@ async function auditRepo(url) {
3126
3238
  for (const { report } of reports) await uploadReport(report, creds);
3127
3239
  console.log(` ${c.dim}Reports: ${REGISTRY_URL}/packages/${slug}${c.reset}`);
3128
3240
  } else if (!noUpload && !creds) {
3129
- console.log(` ${c.dim}Run ${c.cyan}agentaudit setup${c.dim} to upload reports to agentaudit.dev${c.reset}`);
3241
+ console.log(` ${c.dim}Run ${c.cyan}agentaudit login${c.dim} to upload reports to agentaudit.dev${c.reset}`);
3130
3242
  }
3131
3243
 
3132
3244
  console.log();
@@ -3265,11 +3377,11 @@ async function auditRepo(url) {
3265
3377
  console.log(` ${c.dim}Report: ${REGISTRY_URL}/packages/${slug}${c.reset}`);
3266
3378
  } else {
3267
3379
  console.log(` ${c.red}invalid key${c.reset}`);
3268
- console.log(` ${c.dim}Run ${c.cyan}agentaudit setup${c.dim} to configure.${c.reset}`);
3380
+ console.log(` ${c.dim}Run ${c.cyan}agentaudit login${c.dim} to sign in.${c.reset}`);
3269
3381
  }
3270
3382
  }
3271
3383
  } else {
3272
- console.log(` ${c.dim}Run ${c.cyan}agentaudit setup${c.dim} to configure your API key and upload reports${c.reset}`);
3384
+ console.log(` ${c.dim}Run ${c.cyan}agentaudit login${c.dim} to sign in and upload reports${c.reset}`);
3273
3385
  }
3274
3386
 
3275
3387
  console.log();
@@ -3370,7 +3482,7 @@ function renderOverviewTab(data, width) {
3370
3482
  profileLines.push(sevParts.join(' ') || `${c.dim}no findings yet${c.reset}`);
3371
3483
  } else {
3372
3484
  profileLines.push(`${c.dim}Not logged in${c.reset}`);
3373
- profileLines.push(`${c.dim}Run ${c.cyan}agentaudit setup${c.dim} to create account${c.reset}`);
3485
+ profileLines.push(`${c.dim}Run ${c.cyan}agentaudit login${c.dim} to sign in${c.reset}`);
3374
3486
  }
3375
3487
 
3376
3488
  // Registry box
@@ -3591,7 +3703,7 @@ async function activityCommand(args) {
3591
3703
  } else {
3592
3704
  banner();
3593
3705
  console.log(` ${c.yellow}Not logged in${c.reset}`);
3594
- console.log(` ${c.dim}Run ${c.cyan}agentaudit setup${c.dim} to create an account${c.reset}`);
3706
+ console.log(` ${c.dim}Run ${c.cyan}agentaudit login${c.dim} to sign in${c.reset}`);
3595
3707
  }
3596
3708
  return;
3597
3709
  }
@@ -4467,7 +4579,8 @@ async function main() {
4467
4579
  console.log();
4468
4580
  console.log(` ${c.bold}CONFIGURATION${c.reset}`);
4469
4581
  console.log(` ${c.cyan}model${c.reset} Configure LLM provider + model`);
4470
- console.log(` ${c.cyan}setup${c.reset} Log in to agentaudit.dev (for report uploads)`);
4582
+ console.log(` ${c.cyan}login${c.reset} Sign in with GitHub (opens browser)`);
4583
+ console.log(` ${c.cyan}setup${c.reset} Manual login — paste API key`);
4471
4584
  console.log(` ${c.cyan}status${c.reset} Show current config + auth status`);
4472
4585
  console.log(` ${c.cyan}profile${c.reset} Your profile — rank, points, audit stats`);
4473
4586
  console.log();
@@ -4626,6 +4739,11 @@ async function main() {
4626
4739
  return;
4627
4740
  }
4628
4741
 
4742
+ if (command === 'login') {
4743
+ await loginCommand();
4744
+ return;
4745
+ }
4746
+
4629
4747
  if (command === 'status' || command === 'whoami') {
4630
4748
  // ── Status / diagnostic overview ──
4631
4749
  const config = loadLlmConfig();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentaudit",
3
- "version": "3.12.6",
3
+ "version": "3.12.7",
4
4
  "description": "Security scanner for AI packages — MCP server + CLI",
5
5
  "type": "module",
6
6
  "bin": {