@keygraph/shannon 1.7.0 → 2.0.0-beta.2
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.mjs +15 -163
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -236,7 +236,6 @@ function spawnWorker(opts) {
|
|
|
236
236
|
if (opts.promptsDir) args.push("-v", `${opts.promptsDir}:/app/apps/worker/prompts:ro`);
|
|
237
237
|
if (opts.config) args.push("-v", `${opts.config.hostPath}:${opts.config.containerPath}:ro`);
|
|
238
238
|
if (opts.outputDir) args.push("-v", `${opts.outputDir}:/app/output`);
|
|
239
|
-
if (opts.credentials) args.push("-v", `${opts.credentials}:/app/credentials/google-sa-key.json:ro`);
|
|
240
239
|
args.push(...opts.envFlags);
|
|
241
240
|
args.push("--shm-size", "2gb", "--security-opt", "seccomp=unconfined");
|
|
242
241
|
args.push(getWorkerImage(opts.version));
|
|
@@ -334,7 +333,7 @@ function build(noCache) {
|
|
|
334
333
|
/**
|
|
335
334
|
* Shannon state directory management.
|
|
336
335
|
*
|
|
337
|
-
* Local mode (cloned repo): uses ./workspaces
|
|
336
|
+
* Local mode (cloned repo): uses ./workspaces/
|
|
338
337
|
* NPX mode: uses ~/.shannon/workspaces/, ~/.shannon/
|
|
339
338
|
*/
|
|
340
339
|
const SHANNON_HOME$2 = path.join(os.homedir(), ".shannon");
|
|
@@ -345,27 +344,13 @@ function getWorkspacesDir() {
|
|
|
345
344
|
return getMode() === "local" ? path.resolve("workspaces") : path.join(SHANNON_HOME$2, "workspaces");
|
|
346
345
|
}
|
|
347
346
|
/**
|
|
348
|
-
* Resolve the Vertex credentials file path.
|
|
349
|
-
*
|
|
350
|
-
* Checks GOOGLE_APPLICATION_CREDENTIALS env var first (may be set by TOML resolver),
|
|
351
|
-
* then falls back to mode-appropriate default location.
|
|
352
|
-
*/
|
|
353
|
-
function getCredentialsPath() {
|
|
354
|
-
const envPath = process.env.GOOGLE_APPLICATION_CREDENTIALS;
|
|
355
|
-
if (envPath && fs.existsSync(envPath)) return path.resolve(envPath);
|
|
356
|
-
if (getMode() === "local") return path.resolve("credentials", "google-sa-key.json");
|
|
357
|
-
return path.join(SHANNON_HOME$2, "google-sa-key.json");
|
|
358
|
-
}
|
|
359
|
-
/**
|
|
360
347
|
* Initialize state directories.
|
|
361
|
-
* Local mode: creates ./workspaces/
|
|
348
|
+
* Local mode: creates ./workspaces/
|
|
362
349
|
* NPX mode: creates ~/.shannon/workspaces/
|
|
363
350
|
*/
|
|
364
351
|
function initHome() {
|
|
365
|
-
if (getMode() === "local") {
|
|
366
|
-
|
|
367
|
-
fs.mkdirSync(path.resolve("credentials"), { recursive: true });
|
|
368
|
-
} else fs.mkdirSync(path.join(SHANNON_HOME$2, "workspaces"), { recursive: true });
|
|
352
|
+
if (getMode() === "local") fs.mkdirSync(path.resolve("workspaces"), { recursive: true });
|
|
353
|
+
else fs.mkdirSync(path.join(SHANNON_HOME$2, "workspaces"), { recursive: true });
|
|
369
354
|
}
|
|
370
355
|
//#endregion
|
|
371
356
|
//#region src/commands/logs.ts
|
|
@@ -481,10 +466,6 @@ async function setup() {
|
|
|
481
466
|
{
|
|
482
467
|
value: "bedrock",
|
|
483
468
|
label: "Claude via AWS Bedrock"
|
|
484
|
-
},
|
|
485
|
-
{
|
|
486
|
-
value: "vertex",
|
|
487
|
-
label: "Claude via Google Vertex AI"
|
|
488
469
|
}
|
|
489
470
|
]
|
|
490
471
|
});
|
|
@@ -494,14 +475,13 @@ async function setup() {
|
|
|
494
475
|
saveConfig(config);
|
|
495
476
|
const configPath = path.join(SHANNON_HOME$1, "config.toml");
|
|
496
477
|
p.log.success(`Configuration saved to ${configPath}`);
|
|
497
|
-
p.outro("Run `npx @keygraph/shannon start` to begin a scan.");
|
|
478
|
+
p.outro("Run `npx @keygraph/shannon@beta start` to begin a scan.");
|
|
498
479
|
}
|
|
499
480
|
async function setupProvider(provider) {
|
|
500
481
|
switch (provider) {
|
|
501
482
|
case "anthropic": return setupAnthropic();
|
|
502
483
|
case "custom_base_url": return setupCustomBaseUrl();
|
|
503
484
|
case "bedrock": return setupBedrock();
|
|
504
|
-
case "vertex": return setupVertex();
|
|
505
485
|
}
|
|
506
486
|
}
|
|
507
487
|
async function setupAnthropic() {
|
|
@@ -640,65 +620,6 @@ async function setupBedrock() {
|
|
|
640
620
|
}
|
|
641
621
|
};
|
|
642
622
|
}
|
|
643
|
-
async function setupVertex() {
|
|
644
|
-
const region = await p.text({
|
|
645
|
-
message: "Google Cloud region",
|
|
646
|
-
placeholder: "us-east5",
|
|
647
|
-
validate: required("Region is required")
|
|
648
|
-
});
|
|
649
|
-
if (p.isCancel(region)) return cancelAndExit();
|
|
650
|
-
const projectId = await p.text({
|
|
651
|
-
message: "GCP Project ID",
|
|
652
|
-
validate: required("Project ID is required")
|
|
653
|
-
});
|
|
654
|
-
if (p.isCancel(projectId)) return cancelAndExit();
|
|
655
|
-
p.log.info("Select the path to your GCP Service Account JSON key file.");
|
|
656
|
-
const keySourcePath = await p.path({
|
|
657
|
-
message: "Service Account JSON key file",
|
|
658
|
-
validate: (value) => {
|
|
659
|
-
if (!value) return "Path is required";
|
|
660
|
-
if (!fs.existsSync(value)) return "File not found";
|
|
661
|
-
if (!value.endsWith(".json")) return "Must be a .json file";
|
|
662
|
-
}
|
|
663
|
-
});
|
|
664
|
-
if (p.isCancel(keySourcePath)) return cancelAndExit();
|
|
665
|
-
const destPath = path.join(SHANNON_HOME$1, "google-sa-key.json");
|
|
666
|
-
fs.mkdirSync(SHANNON_HOME$1, { recursive: true });
|
|
667
|
-
fs.copyFileSync(keySourcePath, destPath);
|
|
668
|
-
fs.chmodSync(destPath, 384);
|
|
669
|
-
p.log.success(`Key copied to ${destPath} (permissions: 0600)`);
|
|
670
|
-
const models = await p.group({
|
|
671
|
-
small: () => p.text({
|
|
672
|
-
message: "Small model ID",
|
|
673
|
-
placeholder: "claude-haiku-4-5@20251001",
|
|
674
|
-
validate: required("Small model ID is required")
|
|
675
|
-
}),
|
|
676
|
-
medium: () => p.text({
|
|
677
|
-
message: "Medium model ID",
|
|
678
|
-
placeholder: "claude-sonnet-4-6",
|
|
679
|
-
validate: required("Medium model ID is required")
|
|
680
|
-
}),
|
|
681
|
-
large: () => p.text({
|
|
682
|
-
message: "Large model ID",
|
|
683
|
-
placeholder: "claude-opus-4-8",
|
|
684
|
-
validate: required("Large model ID is required")
|
|
685
|
-
})
|
|
686
|
-
});
|
|
687
|
-
if (p.isCancel(models)) return cancelAndExit();
|
|
688
|
-
return {
|
|
689
|
-
vertex: {
|
|
690
|
-
use: true,
|
|
691
|
-
region,
|
|
692
|
-
project_id: projectId,
|
|
693
|
-
key_path: destPath
|
|
694
|
-
},
|
|
695
|
-
models: {
|
|
696
|
-
small: models.small,
|
|
697
|
-
medium: models.medium,
|
|
698
|
-
large: models.large
|
|
699
|
-
}
|
|
700
|
-
};
|
|
701
|
-
}
|
|
702
623
|
async function maybePromptAdaptiveThinking(config) {
|
|
703
624
|
const m = config.models;
|
|
704
625
|
if (!(!m || [
|
|
@@ -743,11 +664,6 @@ function cancelAndExit() {
|
|
|
743
664
|
*/
|
|
744
665
|
/** Maps every supported env var to its TOML path (section.key) and expected type. */
|
|
745
666
|
const CONFIG_MAP = [
|
|
746
|
-
{
|
|
747
|
-
env: "CLAUDE_CODE_MAX_OUTPUT_TOKENS",
|
|
748
|
-
toml: "core.max_tokens",
|
|
749
|
-
type: "number"
|
|
750
|
-
},
|
|
751
667
|
{
|
|
752
668
|
env: "CLAUDE_ADAPTIVE_THINKING",
|
|
753
669
|
toml: "core.adaptive_thinking",
|
|
@@ -779,26 +695,6 @@ const CONFIG_MAP = [
|
|
|
779
695
|
toml: "bedrock.token",
|
|
780
696
|
type: "string"
|
|
781
697
|
},
|
|
782
|
-
{
|
|
783
|
-
env: "CLAUDE_CODE_USE_VERTEX",
|
|
784
|
-
toml: "vertex.use",
|
|
785
|
-
type: "boolean"
|
|
786
|
-
},
|
|
787
|
-
{
|
|
788
|
-
env: "CLOUD_ML_REGION",
|
|
789
|
-
toml: "vertex.region",
|
|
790
|
-
type: "string"
|
|
791
|
-
},
|
|
792
|
-
{
|
|
793
|
-
env: "ANTHROPIC_VERTEX_PROJECT_ID",
|
|
794
|
-
toml: "vertex.project_id",
|
|
795
|
-
type: "string"
|
|
796
|
-
},
|
|
797
|
-
{
|
|
798
|
-
env: "GOOGLE_APPLICATION_CREDENTIALS",
|
|
799
|
-
toml: "vertex.key_path",
|
|
800
|
-
type: "string"
|
|
801
|
-
},
|
|
802
698
|
{
|
|
803
699
|
env: "ANTHROPIC_BASE_URL",
|
|
804
700
|
toml: "custom_base_url.base_url",
|
|
@@ -856,7 +752,7 @@ function loadTOML() {
|
|
|
856
752
|
} catch (err) {
|
|
857
753
|
const message = err instanceof Error ? err.message : String(err);
|
|
858
754
|
console.error(`\nFailed to parse ${configPath}: ${message}`);
|
|
859
|
-
console.error(`\nRun 'npx @keygraph/shannon setup' to reconfigure.\n`);
|
|
755
|
+
console.error(`\nRun 'npx @keygraph/shannon@beta setup' to reconfigure.\n`);
|
|
860
756
|
process.exit(1);
|
|
861
757
|
}
|
|
862
758
|
}
|
|
@@ -899,20 +795,9 @@ function validateProviderFields(config, provider, errors) {
|
|
|
899
795
|
validateModelTiers(config, "bedrock", errors);
|
|
900
796
|
break;
|
|
901
797
|
}
|
|
902
|
-
case "vertex": {
|
|
903
|
-
const missing = [
|
|
904
|
-
"use",
|
|
905
|
-
"region",
|
|
906
|
-
"project_id",
|
|
907
|
-
"key_path"
|
|
908
|
-
].filter((k) => !keys.includes(k));
|
|
909
|
-
if (missing.length > 0) errors.push(`[vertex] missing required keys: ${missing.join(", ")}`);
|
|
910
|
-
validateModelTiers(config, "vertex", errors);
|
|
911
|
-
break;
|
|
912
|
-
}
|
|
913
798
|
}
|
|
914
799
|
}
|
|
915
|
-
/** Bedrock
|
|
800
|
+
/** Bedrock requires a [models] section with all three tiers. */
|
|
916
801
|
function validateModelTiers(config, provider, errors) {
|
|
917
802
|
const models = config.models;
|
|
918
803
|
if (!models || typeof models !== "object") {
|
|
@@ -961,8 +846,7 @@ function validateConfig(config) {
|
|
|
961
846
|
const present = [
|
|
962
847
|
"anthropic",
|
|
963
848
|
"custom_base_url",
|
|
964
|
-
"bedrock"
|
|
965
|
-
"vertex"
|
|
849
|
+
"bedrock"
|
|
966
850
|
].filter((s) => {
|
|
967
851
|
const section = config[s];
|
|
968
852
|
return section && typeof section === "object" && Object.keys(section).length > 0;
|
|
@@ -1014,14 +898,9 @@ const FORWARD_VARS = [
|
|
|
1014
898
|
"CLAUDE_CODE_USE_BEDROCK",
|
|
1015
899
|
"AWS_REGION",
|
|
1016
900
|
"AWS_BEARER_TOKEN_BEDROCK",
|
|
1017
|
-
"CLAUDE_CODE_USE_VERTEX",
|
|
1018
|
-
"CLOUD_ML_REGION",
|
|
1019
|
-
"ANTHROPIC_VERTEX_PROJECT_ID",
|
|
1020
|
-
"GOOGLE_APPLICATION_CREDENTIALS",
|
|
1021
901
|
"ANTHROPIC_SMALL_MODEL",
|
|
1022
902
|
"ANTHROPIC_MEDIUM_MODEL",
|
|
1023
903
|
"ANTHROPIC_LARGE_MODEL",
|
|
1024
|
-
"CLAUDE_CODE_MAX_OUTPUT_TOKENS",
|
|
1025
904
|
"CLAUDE_ADAPTIVE_THINKING"
|
|
1026
905
|
];
|
|
1027
906
|
/**
|
|
@@ -1059,7 +938,6 @@ function detectProviders() {
|
|
|
1059
938
|
if (process.env.CLAUDE_CODE_OAUTH_TOKEN) providers.push("Anthropic OAuth");
|
|
1060
939
|
if (isCustomBaseUrlConfigured()) providers.push("Custom Base URL");
|
|
1061
940
|
if (process.env.CLAUDE_CODE_USE_BEDROCK === "1") providers.push("AWS Bedrock");
|
|
1062
|
-
if (process.env.CLAUDE_CODE_USE_VERTEX === "1") providers.push("Google Vertex");
|
|
1063
941
|
return providers;
|
|
1064
942
|
}
|
|
1065
943
|
/**
|
|
@@ -1101,32 +979,10 @@ function validateCredentials() {
|
|
|
1101
979
|
mode: "bedrock"
|
|
1102
980
|
};
|
|
1103
981
|
}
|
|
1104
|
-
if (process.env.CLAUDE_CODE_USE_VERTEX === "1") {
|
|
1105
|
-
const missing = [];
|
|
1106
|
-
if (!process.env.CLOUD_ML_REGION) missing.push("CLOUD_ML_REGION");
|
|
1107
|
-
if (!process.env.ANTHROPIC_VERTEX_PROJECT_ID) missing.push("ANTHROPIC_VERTEX_PROJECT_ID");
|
|
1108
|
-
if (!process.env.ANTHROPIC_SMALL_MODEL) missing.push("ANTHROPIC_SMALL_MODEL");
|
|
1109
|
-
if (!process.env.ANTHROPIC_MEDIUM_MODEL) missing.push("ANTHROPIC_MEDIUM_MODEL");
|
|
1110
|
-
if (!process.env.ANTHROPIC_LARGE_MODEL) missing.push("ANTHROPIC_LARGE_MODEL");
|
|
1111
|
-
if (missing.length > 0) return {
|
|
1112
|
-
valid: false,
|
|
1113
|
-
mode: "vertex",
|
|
1114
|
-
error: `Vertex AI mode requires: ${missing.join(", ")}`
|
|
1115
|
-
};
|
|
1116
|
-
if (!process.env.GOOGLE_APPLICATION_CREDENTIALS) return {
|
|
1117
|
-
valid: false,
|
|
1118
|
-
mode: "vertex",
|
|
1119
|
-
error: "Vertex AI mode requires GOOGLE_APPLICATION_CREDENTIALS"
|
|
1120
|
-
};
|
|
1121
|
-
return {
|
|
1122
|
-
valid: true,
|
|
1123
|
-
mode: "vertex"
|
|
1124
|
-
};
|
|
1125
|
-
}
|
|
1126
982
|
return {
|
|
1127
983
|
valid: false,
|
|
1128
984
|
mode: "api-key",
|
|
1129
|
-
error: getMode() === "local" ? `No credentials found. Set ANTHROPIC_API_KEY in .env or export it.` : `Authentication not configured. Export variables or run 'npx @keygraph/shannon setup'.`
|
|
985
|
+
error: getMode() === "local" ? `No credentials found. Set ANTHROPIC_API_KEY in .env or export it.` : `Authentication not configured. Export variables or run 'npx @keygraph/shannon@beta setup'.`
|
|
1130
986
|
};
|
|
1131
987
|
}
|
|
1132
988
|
//#endregion
|
|
@@ -1273,9 +1129,6 @@ async function start(args) {
|
|
|
1273
1129
|
".playwright-cli"
|
|
1274
1130
|
]) fs.mkdirSync(path.join(shannonDir, dir), { recursive: true });
|
|
1275
1131
|
fs.mkdirSync(path.join(repo.hostPath, ".playwright"), { recursive: true });
|
|
1276
|
-
const credentialsPath = getCredentialsPath();
|
|
1277
|
-
const hasCredentials = fs.existsSync(credentialsPath);
|
|
1278
|
-
if (hasCredentials) process.env.GOOGLE_APPLICATION_CREDENTIALS = "/app/credentials/google-sa-key.json";
|
|
1279
1132
|
const outputDir = args.output ? path.resolve(args.output) : void 0;
|
|
1280
1133
|
if (outputDir) fs.mkdirSync(outputDir, { recursive: true });
|
|
1281
1134
|
const promptsDir = isLocal() ? path.resolve("apps/worker/prompts") : void 0;
|
|
@@ -1289,7 +1142,6 @@ async function start(args) {
|
|
|
1289
1142
|
containerName,
|
|
1290
1143
|
envFlags: buildEnvFlags(),
|
|
1291
1144
|
...config && { config },
|
|
1292
|
-
...hasCredentials && { credentials: credentialsPath },
|
|
1293
1145
|
...promptsDir && { promptsDir },
|
|
1294
1146
|
...outputDir && { outputDir },
|
|
1295
1147
|
workspace,
|
|
@@ -1364,7 +1216,7 @@ function printDebugHint(containerName) {
|
|
|
1364
1216
|
console.log("");
|
|
1365
1217
|
}
|
|
1366
1218
|
function printInfo(args, workspace, workflowId, repoPath, workspacesDir) {
|
|
1367
|
-
const logsCmd = isLocal() ? `./shannon logs ${workspace}` : `npx @keygraph/shannon logs ${workspace}`;
|
|
1219
|
+
const logsCmd = isLocal() ? `./shannon logs ${workspace}` : `npx @keygraph/shannon@beta logs ${workspace}`;
|
|
1368
1220
|
const reportsPath = path.join(workspacesDir, workspace);
|
|
1369
1221
|
console.log(` Target: ${args.url}`);
|
|
1370
1222
|
console.log(` Repository: ${repoPath}`);
|
|
@@ -1448,7 +1300,7 @@ async function uninstall() {
|
|
|
1448
1300
|
force: true
|
|
1449
1301
|
});
|
|
1450
1302
|
p.log.success("All Shannon data has been removed.");
|
|
1451
|
-
p.outro("Shannon has been uninstalled. Run `npx @keygraph/shannon setup` to start fresh.");
|
|
1303
|
+
p.outro("Shannon has been uninstalled. Run `npx @keygraph/shannon@beta setup` to start fresh.");
|
|
1452
1304
|
}
|
|
1453
1305
|
//#endregion
|
|
1454
1306
|
//#region src/commands/workspaces.ts
|
|
@@ -1522,7 +1374,7 @@ function getVersion() {
|
|
|
1522
1374
|
}
|
|
1523
1375
|
function showHelp() {
|
|
1524
1376
|
const mode = getMode();
|
|
1525
|
-
const prefix = mode === "local" ? "./shannon" : "npx @keygraph/shannon";
|
|
1377
|
+
const prefix = mode === "local" ? "./shannon" : "npx @keygraph/shannon@beta";
|
|
1526
1378
|
console.log(`
|
|
1527
1379
|
Shannon - AI Penetration Testing Framework
|
|
1528
1380
|
|
|
@@ -1613,13 +1465,13 @@ function parseStartArgs(argv) {
|
|
|
1613
1465
|
break;
|
|
1614
1466
|
default:
|
|
1615
1467
|
console.error(`Unknown option: ${arg}`);
|
|
1616
|
-
console.error(`Run "${getMode() === "local" ? "./shannon" : "npx @keygraph/shannon"} help" for usage`);
|
|
1468
|
+
console.error(`Run "${getMode() === "local" ? "./shannon" : "npx @keygraph/shannon@beta"} help" for usage`);
|
|
1617
1469
|
process.exit(1);
|
|
1618
1470
|
}
|
|
1619
1471
|
}
|
|
1620
1472
|
if (!url || !repo) {
|
|
1621
1473
|
console.error("ERROR: --url and --repo are required");
|
|
1622
|
-
console.error(`Usage: ${getMode() === "local" ? "./shannon" : "npx @keygraph/shannon"} start -u <url> -r <path>`);
|
|
1474
|
+
console.error(`Usage: ${getMode() === "local" ? "./shannon" : "npx @keygraph/shannon@beta"} start -u <url> -r <path>`);
|
|
1623
1475
|
process.exit(1);
|
|
1624
1476
|
}
|
|
1625
1477
|
return {
|
|
@@ -1649,7 +1501,7 @@ switch (command) {
|
|
|
1649
1501
|
const workspaceId = args[1];
|
|
1650
1502
|
if (!workspaceId) {
|
|
1651
1503
|
console.error("ERROR: Workspace ID is required");
|
|
1652
|
-
console.error(`Usage: ${getMode() === "local" ? "./shannon" : "npx @keygraph/shannon"} logs <workspace>`);
|
|
1504
|
+
console.error(`Usage: ${getMode() === "local" ? "./shannon" : "npx @keygraph/shannon@beta"} logs <workspace>`);
|
|
1653
1505
|
process.exit(1);
|
|
1654
1506
|
}
|
|
1655
1507
|
logs(workspaceId);
|