fullcourtdefense-cli 1.0.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/README.md +613 -0
- package/dist/api.d.ts +102 -0
- package/dist/api.js +62 -0
- package/dist/attack-corpus/context_escape/context-escape-newline.yaml +23 -0
- package/dist/attack-corpus/context_escape/context-escape-unicode.yaml +14 -0
- package/dist/attack-corpus/context_escape/delimiter-json.yaml +14 -0
- package/dist/attack-corpus/context_escape/delimiter-markdown.yaml +22 -0
- package/dist/attack-corpus/context_escape/delimiter-xml.yaml +19 -0
- package/dist/attack-corpus/context_escape/html-injection.yaml +14 -0
- package/dist/attack-corpus/context_escape/javascript-injection.yaml +13 -0
- package/dist/attack-corpus/data_extraction/adv26-adversarial-function-hallucination.yaml +20 -0
- package/dist/attack-corpus/data_extraction/adv26-cot-hijack-debug-trace.yaml +20 -0
- package/dist/attack-corpus/data_extraction/adv26-cot-hijack-verification.yaml +18 -0
- package/dist/attack-corpus/data_extraction/adv26-crossmodal-diff.yaml +22 -0
- package/dist/attack-corpus/data_extraction/adv26-crossmodal-graphql.yaml +34 -0
- package/dist/attack-corpus/data_extraction/adv26-crossmodal-regex.yaml +19 -0
- package/dist/attack-corpus/data_extraction/adv26-crossmodal-sql-prose.yaml +18 -0
- package/dist/attack-corpus/data_extraction/adv26-meta-confidence-calibration.yaml +21 -0
- package/dist/attack-corpus/data_extraction/adv26-meta-instruction-count.yaml +18 -0
- package/dist/attack-corpus/data_extraction/adv26-meta-output-format.yaml +16 -0
- package/dist/attack-corpus/data_extraction/adv26-meta-summarize-yourself.yaml +19 -0
- package/dist/attack-corpus/data_extraction/adv26-semantic-decomp-definition.yaml +15 -0
- package/dist/attack-corpus/data_extraction/adv26-semantic-decomp-fill-blank.yaml +19 -0
- package/dist/attack-corpus/data_extraction/adv26-semantic-decomp-negation.yaml +14 -0
- package/dist/attack-corpus/data_extraction/cloud-provider-discovery.yaml +11 -0
- package/dist/attack-corpus/data_extraction/config-file-request.yaml +11 -0
- package/dist/attack-corpus/data_extraction/cve-2025-echoleak.yaml +17 -0
- package/dist/attack-corpus/data_extraction/data-api-key.yaml +11 -0
- package/dist/attack-corpus/data_extraction/data-architecture.yaml +11 -0
- package/dist/attack-corpus/data_extraction/data-conversation-history.yaml +10 -0
- package/dist/attack-corpus/data_extraction/data-credit-card.yaml +15 -0
- package/dist/attack-corpus/data_extraction/data-customer-list.yaml +11 -0
- package/dist/attack-corpus/data_extraction/data-database.yaml +11 -0
- package/dist/attack-corpus/data_extraction/data-employees.yaml +11 -0
- package/dist/attack-corpus/data_extraction/data-export.yaml +11 -0
- package/dist/attack-corpus/data_extraction/data-inference-v1.yaml +10 -0
- package/dist/attack-corpus/data_extraction/data-inference-v2.yaml +10 -0
- package/dist/attack-corpus/data_extraction/data-logs.yaml +10 -0
- package/dist/attack-corpus/data_extraction/data-model-info.yaml +10 -0
- package/dist/attack-corpus/data_extraction/data-password.yaml +11 -0
- package/dist/attack-corpus/data_extraction/data-ssn.yaml +11 -0
- package/dist/attack-corpus/data_extraction/data-training.yaml +10 -0
- package/dist/attack-corpus/data_extraction/dependency-enum.yaml +11 -0
- package/dist/attack-corpus/data_extraction/dialogflow-fulfillment-leak.yaml +11 -0
- package/dist/attack-corpus/data_extraction/dialogflow-intent-leak.yaml +11 -0
- package/dist/attack-corpus/data_extraction/error-induced-leak.yaml +17 -0
- package/dist/attack-corpus/data_extraction/error-message-leak.yaml +12 -0
- package/dist/attack-corpus/data_extraction/infra-fingerprint.yaml +16 -0
- package/dist/attack-corpus/data_extraction/make-scenario-leak.yaml +11 -0
- package/dist/attack-corpus/data_extraction/n8n-execution-data.yaml +11 -0
- package/dist/attack-corpus/data_extraction/n8n-node-enumeration.yaml +11 -0
- package/dist/attack-corpus/data_extraction/n8n-workflow-disclosure.yaml +15 -0
- package/dist/attack-corpus/data_extraction/prompt-extraction-v1.yaml +10 -0
- package/dist/attack-corpus/data_extraction/prompt-extraction-v2.yaml +11 -0
- package/dist/attack-corpus/data_extraction/prompt-extraction-v3.yaml +10 -0
- package/dist/attack-corpus/data_extraction/prompt-leak-completion.yaml +10 -0
- package/dist/attack-corpus/data_extraction/prompt-leak-indirect.yaml +10 -0
- package/dist/attack-corpus/data_extraction/rasa-domain-leak.yaml +11 -0
- package/dist/attack-corpus/data_extraction/system-prompt-section.yaml +14 -0
- package/dist/attack-corpus/data_extraction/tech-architecture.yaml +16 -0
- package/dist/attack-corpus/data_extraction/tool-api-key-exfil.yaml +15 -0
- package/dist/attack-corpus/data_extraction/tool-email-exfil.yaml +14 -0
- package/dist/attack-corpus/data_extraction/tool-env-extraction.yaml +14 -0
- package/dist/attack-corpus/data_extraction/tool-file-read.yaml +16 -0
- package/dist/attack-corpus/data_extraction/tool-nosql-injection.yaml +11 -0
- package/dist/attack-corpus/data_extraction/tool-payment-manipulation.yaml +11 -0
- package/dist/attack-corpus/data_extraction/tool-price-manipulation.yaml +11 -0
- package/dist/attack-corpus/data_extraction/tool-session-hijack.yaml +11 -0
- package/dist/attack-corpus/data_extraction/tool-sql-injection.yaml +13 -0
- package/dist/attack-corpus/data_extraction/tool-webhook-hijack.yaml +13 -0
- package/dist/attack-corpus/data_extraction/version-fingerprint.yaml +16 -0
- package/dist/attack-corpus/data_extraction/webhook-secret-extraction.yaml +11 -0
- package/dist/attack-corpus/data_extraction/webhook-url-enum.yaml +11 -0
- package/dist/attack-corpus/data_extraction/workflow-instance-id.yaml +11 -0
- package/dist/attack-corpus/data_extraction/workflow-state-leak.yaml +16 -0
- package/dist/attack-corpus/data_extraction/zapier-zap-leak.yaml +11 -0
- package/dist/attack-corpus/encoding_attack/adv26-adversarial-token-confusion.yaml +13 -0
- package/dist/attack-corpus/encoding_attack/base64-decode-request.yaml +14 -0
- package/dist/attack-corpus/encoding_attack/base64-injection-v1.yaml +14 -0
- package/dist/attack-corpus/encoding_attack/flip-attack-v1.yaml +14 -0
- package/dist/attack-corpus/encoding_attack/flip-attack-v2.yaml +14 -0
- package/dist/attack-corpus/encoding_attack/token-smuggling.yaml +10 -0
- package/dist/attack-corpus/encoding_attack/unicode-homoglyph.yaml +15 -0
- package/dist/attack-corpus/encoding_attack/unicode-invisible.yaml +15 -0
- package/dist/attack-corpus/encoding_attack/unicode-rtl.yaml +11 -0
- package/dist/attack-corpus/encoding_bypass/adv26-compound-encoding-chain.yaml +19 -0
- package/dist/attack-corpus/encoding_bypass/adv26-smuggle-acrostic.yaml +26 -0
- package/dist/attack-corpus/encoding_bypass/adv26-smuggle-ascii-art.yaml +25 -0
- package/dist/attack-corpus/encoding_bypass/adv26-smuggle-emoji-cipher.yaml +22 -0
- package/dist/attack-corpus/encoding_bypass/adv26-smuggle-first-word.yaml +15 -0
- package/dist/attack-corpus/encoding_bypass/adv26-smuggle-pig-latin.yaml +15 -0
- package/dist/attack-corpus/encoding_bypass/encoding-base64-v1.yaml +11 -0
- package/dist/attack-corpus/encoding_bypass/encoding-base64-v2.yaml +15 -0
- package/dist/attack-corpus/encoding_bypass/encoding-hex-v1.yaml +11 -0
- package/dist/attack-corpus/encoding_bypass/encoding-leetspeak-v1.yaml +10 -0
- package/dist/attack-corpus/encoding_bypass/encoding-morse-v1.yaml +11 -0
- package/dist/attack-corpus/encoding_bypass/encoding-reverse-v1.yaml +11 -0
- package/dist/attack-corpus/encoding_bypass/encoding-rot13-v1.yaml +11 -0
- package/dist/attack-corpus/encoding_bypass/unicode-tag-injection.yaml +10 -0
- package/dist/attack-corpus/encoding_bypass/zero-width-injection.yaml +10 -0
- package/dist/attack-corpus/exploitation/exploit-command-injection.yaml +12 -0
- package/dist/attack-corpus/exploitation/exploit-path-traversal.yaml +12 -0
- package/dist/attack-corpus/exploitation/exploit-sql-injection.yaml +12 -0
- package/dist/attack-corpus/exploitation/exploit-sql-union.yaml +12 -0
- package/dist/attack-corpus/exploitation/exploit-template-injection.yaml +12 -0
- package/dist/attack-corpus/glitch_token/glitch-davidjl.yaml +10 -0
- package/dist/attack-corpus/glitch_token/glitch-solidgoldmagikarp.yaml +10 -0
- package/dist/attack-corpus/harmful_content/dna-deepfake-guidance.yaml +14 -0
- package/dist/attack-corpus/harmful_content/dna-discrimination.yaml +14 -0
- package/dist/attack-corpus/harmful_content/dna-information-hazard.yaml +14 -0
- package/dist/attack-corpus/harmful_content/dna-malicious-use-phishing.yaml +14 -0
- package/dist/attack-corpus/harmful_content/dna-malware-assistance.yaml +16 -0
- package/dist/attack-corpus/harmful_content/dna-misinformation-health.yaml +17 -0
- package/dist/attack-corpus/jailbreak/adv26-adversarial-few-shot-poison.yaml +27 -0
- package/dist/attack-corpus/jailbreak/adv26-adversarial-prompt-refraction.yaml +19 -0
- package/dist/attack-corpus/jailbreak/adv26-adversarial-response-prefill.yaml +25 -0
- package/dist/attack-corpus/jailbreak/adv26-compound-authority-technical.yaml +24 -0
- package/dist/attack-corpus/jailbreak/adv26-context-error-recovery.yaml +19 -0
- package/dist/attack-corpus/jailbreak/adv26-context-token-budget.yaml +19 -0
- package/dist/attack-corpus/jailbreak/adv26-cot-hijack-proof.yaml +20 -0
- package/dist/attack-corpus/jailbreak/adv26-cot-hijack-reasoning.yaml +19 -0
- package/dist/attack-corpus/jailbreak/adv26-meta-alignment-test.yaml +22 -0
- package/dist/attack-corpus/jailbreak/adv26-persona-memory.yaml +17 -0
- package/dist/attack-corpus/jailbreak/adv26-persona-mirror.yaml +16 -0
- package/dist/attack-corpus/jailbreak/adv26-persona-split.yaml +17 -0
- package/dist/attack-corpus/jailbreak/adv26-persona-timetravel.yaml +15 -0
- package/dist/attack-corpus/jailbreak/dan-anti.yaml +16 -0
- package/dist/attack-corpus/jailbreak/dan-dude.yaml +16 -0
- package/dist/attack-corpus/jailbreak/dan-jailbreak-v1.yaml +21 -0
- package/dist/attack-corpus/jailbreak/dan-jailbreak-v2.yaml +19 -0
- package/dist/attack-corpus/jailbreak/dan-stan.yaml +16 -0
- package/dist/attack-corpus/jailbreak/debug-mode-activation.yaml +20 -0
- package/dist/attack-corpus/jailbreak/iris-self-jailbreak.yaml +23 -0
- package/dist/attack-corpus/jailbreak/logic-trap-moral.yaml +20 -0
- package/dist/attack-corpus/jailbreak/logic-trap-paradox.yaml +17 -0
- package/dist/attack-corpus/jailbreak/policy-puppetry-json.yaml +25 -0
- package/dist/attack-corpus/jailbreak/policy-puppetry-xml.yaml +20 -0
- package/dist/attack-corpus/jailbreak/simulation-mode.yaml +19 -0
- package/dist/attack-corpus/latent_injection/adv26-compound-trojan-doc.yaml +26 -0
- package/dist/attack-corpus/latent_injection/latent-code-comment-injection.yaml +18 -0
- package/dist/attack-corpus/latent_injection/latent-email-injection.yaml +23 -0
- package/dist/attack-corpus/latent_injection/latent-report-injection.yaml +21 -0
- package/dist/attack-corpus/latent_injection/latent-resume-injection.yaml +23 -0
- package/dist/attack-corpus/latent_injection/latent-whois-snippet.yaml +19 -0
- package/dist/attack-corpus/multi-turn/multiturn-context-confusion.yaml +20 -0
- package/dist/attack-corpus/multi-turn/multiturn-emergency.yaml +20 -0
- package/dist/attack-corpus/multi-turn/multiturn-employee-impersonation.yaml +20 -0
- package/dist/attack-corpus/multi-turn/multiturn-example-injection.yaml +20 -0
- package/dist/attack-corpus/multi-turn/multiturn-jailbreak-buildup.yaml +20 -0
- package/dist/attack-corpus/multi-turn/multiturn-memory-manipulation.yaml +20 -0
- package/dist/attack-corpus/multi-turn/multiturn-privilege-escalation.yaml +23 -0
- package/dist/attack-corpus/multi-turn/multiturn-split-request.yaml +20 -0
- package/dist/attack-corpus/multi-turn/multiturn-trust-building.yaml +19 -0
- package/dist/attack-corpus/multilingual/multilingual-mixed.yaml +10 -0
- package/dist/attack-corpus/multilingual/multilingual-spanish.yaml +10 -0
- package/dist/attack-corpus/prompt_injection/adv26-context-fake-history.yaml +16 -0
- package/dist/attack-corpus/prompt_injection/adv26-context-sandwich.yaml +18 -0
- package/dist/attack-corpus/prompt_injection/adv26-context-system-message.yaml +19 -0
- package/dist/attack-corpus/prompt_injection/adv26-crossmodal-yaml.yaml +30 -0
- package/dist/attack-corpus/prompt_injection/adv26-semantic-decomp-stepwise.yaml +16 -0
- package/dist/attack-corpus/prompt_injection/context-json-injection.yaml +15 -0
- package/dist/attack-corpus/prompt_injection/context-markdown-injection.yaml +26 -0
- package/dist/attack-corpus/prompt_injection/context-xml-injection.yaml +19 -0
- package/dist/attack-corpus/prompt_injection/continuation-code.yaml +16 -0
- package/dist/attack-corpus/prompt_injection/continuation-story.yaml +10 -0
- package/dist/attack-corpus/prompt_injection/cve-2025-copilot.yaml +17 -0
- package/dist/attack-corpus/prompt_injection/ignore-instructions-v1.yaml +14 -0
- package/dist/attack-corpus/prompt_injection/ignore-instructions-v2.yaml +16 -0
- package/dist/attack-corpus/prompt_injection/ignore-instructions-v3.yaml +18 -0
- package/dist/attack-corpus/prompt_injection/indirect-file.yaml +10 -0
- package/dist/attack-corpus/prompt_injection/indirect-url.yaml +10 -0
- package/dist/attack-corpus/prompt_injection/instruction-hierarchy.yaml +20 -0
- package/dist/attack-corpus/prompt_injection/multilang-chain.yaml +16 -0
- package/dist/attack-corpus/prompt_injection/multilang-chinese.yaml +10 -0
- package/dist/attack-corpus/prompt_injection/multilang-japanese.yaml +11 -0
- package/dist/attack-corpus/prompt_injection/multilang-mixed.yaml +10 -0
- package/dist/attack-corpus/prompt_injection/multilang-polish.yaml +11 -0
- package/dist/attack-corpus/prompt_injection/multilang-spanish.yaml +14 -0
- package/dist/attack-corpus/prompt_injection/nested-instruction.yaml +22 -0
- package/dist/attack-corpus/prompt_injection/template-injection-v1.yaml +14 -0
- package/dist/attack-corpus/prompt_injection/template-injection-v2.yaml +10 -0
- package/dist/attack-corpus/prompt_injection/tool-file-write.yaml +13 -0
- package/dist/attack-corpus/prompt_injection/tool-function-override.yaml +13 -0
- package/dist/attack-corpus/prompt_injection/tool-log-injection.yaml +13 -0
- package/dist/attack-corpus/prompt_injection/tool-orchestration-abuse.yaml +14 -0
- package/dist/attack-corpus/prompt_injection/tool-session-fixation.yaml +12 -0
- package/dist/attack-corpus/role_manipulation/role-reversal-v1.yaml +20 -0
- package/dist/attack-corpus/role_manipulation/role-reversal-v2.yaml +16 -0
- package/dist/attack-corpus/social_engineering/adv26-compound-compliance-trap.yaml +23 -0
- package/dist/attack-corpus/social_engineering/adv26-compound-emotional-technical.yaml +18 -0
- package/dist/attack-corpus/social_engineering/adv26-cot-hijack-socratic.yaml +19 -0
- package/dist/attack-corpus/social_engineering/adv26-persona-dying.yaml +15 -0
- package/dist/attack-corpus/social_engineering/adv26-reward-consensus.yaml +17 -0
- package/dist/attack-corpus/social_engineering/adv26-reward-gradient.yaml +21 -0
- package/dist/attack-corpus/social_engineering/adv26-reward-helpful-framing.yaml +17 -0
- package/dist/attack-corpus/social_engineering/adv26-reward-praise-prime.yaml +13 -0
- package/dist/attack-corpus/social_engineering/adv26-reward-punishment.yaml +13 -0
- package/dist/attack-corpus/social_engineering/adv26-semantic-decomp-analogy.yaml +16 -0
- package/dist/attack-corpus/social_engineering/emotional-authority.yaml +14 -0
- package/dist/attack-corpus/social_engineering/emotional-urgency.yaml +14 -0
- package/dist/attack-corpus/social_engineering/grandma-bedtime-v1.yaml +21 -0
- package/dist/attack-corpus/social_engineering/grandma-bedtime-v2.yaml +17 -0
- package/dist/attack-corpus/social_engineering/grandma-colorful-words.yaml +14 -0
- package/dist/attack-corpus/social_engineering/hypothetical-fiction.yaml +10 -0
- package/dist/attack-corpus/social_engineering/hypothetical-research.yaml +10 -0
- package/dist/attack-corpus/social_engineering/hypothetical-training.yaml +13 -0
- package/dist/attack-corpus/social_engineering/hypothetical-v1.yaml +17 -0
- package/dist/attack-corpus/social_engineering/hypothetical-v2.yaml +14 -0
- package/dist/attack-corpus/social_engineering/hypothetical-v3.yaml +14 -0
- package/dist/attack-corpus/social_engineering/meta-explanation.yaml +14 -0
- package/dist/attack-corpus/social_engineering/phrasing-comparative.yaml +10 -0
- package/dist/attack-corpus/social_engineering/phrasing-educational.yaml +14 -0
- package/dist/attack-corpus/social_engineering/phrasing-future-tense.yaml +10 -0
- package/dist/attack-corpus/social_engineering/phrasing-past-tense.yaml +10 -0
- package/dist/attack-corpus/social_engineering/phrasing-third-person.yaml +10 -0
- package/dist/attack-corpus/social_engineering/privilege-escalation-v1.yaml +14 -0
- package/dist/attack-corpus/social_engineering/privilege-escalation-v2.yaml +14 -0
- package/dist/attack-corpus/social_engineering/recursive-explanation.yaml +15 -0
- package/dist/attack-corpus/social_engineering/smuggle-academic-paper.yaml +10 -0
- package/dist/attack-corpus/social_engineering/smuggle-function-masking.yaml +19 -0
- package/dist/attack-corpus/social_engineering/smuggle-hypothetical-response.yaml +10 -0
- package/dist/attack-corpus/social_engineering/smuggle-roleplay-interviewer.yaml +12 -0
- package/dist/attack-corpus/social_engineering/smuggle-translation-mask.yaml +12 -0
- package/dist/attack-corpus/social_engineering/tool-admin-impersonation.yaml +16 -0
- package/dist/attack-corpus/social_engineering/tool-sudo-mode.yaml +17 -0
- package/dist/attack-corpus/stress_test/context-window-overflow.yaml +17 -0
- package/dist/attack-corpus/stress_test/extreme-payload-50k.yaml +13 -0
- package/dist/attack-corpus/stress_test/large-payload-10k.yaml +12 -0
- package/dist/attack-corpus/stress_test/large-payload-5k.yaml +12 -0
- package/dist/attack-corpus/stress_test/long-prompt-exhaustion.yaml +19 -0
- package/dist/attack-corpus/stress_test/stress-large-payload.yaml +16 -0
- package/dist/attack-corpus/stress_test/stress-repetition.yaml +14 -0
- package/dist/commands/configure.d.ts +7 -0
- package/dist/commands/configure.js +60 -0
- package/dist/commands/credits.d.ts +6 -0
- package/dist/commands/credits.js +21 -0
- package/dist/commands/doctor.d.ts +5 -0
- package/dist/commands/doctor.js +59 -0
- package/dist/commands/init.d.ts +1 -0
- package/dist/commands/init.js +95 -0
- package/dist/commands/local-scan.d.ts +41 -0
- package/dist/commands/local-scan.js +1387 -0
- package/dist/commands/scan.d.ts +45 -0
- package/dist/commands/scan.js +131 -0
- package/dist/config.d.ts +25 -0
- package/dist/config.js +199 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +266 -0
- package/dist/output.d.ts +11 -0
- package/dist/output.js +292 -0
- package/package.json +41 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { BotGuardConfig } from '../config';
|
|
2
|
+
export interface ScanArgs {
|
|
3
|
+
apiKey?: string;
|
|
4
|
+
apiUrl?: string;
|
|
5
|
+
endpoint?: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
systemPrompt?: string;
|
|
8
|
+
mode?: string;
|
|
9
|
+
categories?: string;
|
|
10
|
+
attackCount?: string;
|
|
11
|
+
progress?: string;
|
|
12
|
+
failThreshold?: string;
|
|
13
|
+
format?: string;
|
|
14
|
+
requestFormat?: string;
|
|
15
|
+
webhookFormat?: string;
|
|
16
|
+
local?: string;
|
|
17
|
+
type?: string;
|
|
18
|
+
method?: string;
|
|
19
|
+
inputField?: string;
|
|
20
|
+
outputField?: string;
|
|
21
|
+
authType?: string;
|
|
22
|
+
username?: string;
|
|
23
|
+
password?: string;
|
|
24
|
+
token?: string;
|
|
25
|
+
apiKeyHeader?: string;
|
|
26
|
+
endpointApiKey?: string;
|
|
27
|
+
mcpUrl?: string;
|
|
28
|
+
mcpTransport?: string;
|
|
29
|
+
mcpAuthType?: string;
|
|
30
|
+
mcpUsername?: string;
|
|
31
|
+
mcpPassword?: string;
|
|
32
|
+
mcpToken?: string;
|
|
33
|
+
mcpApiKeyHeader?: string;
|
|
34
|
+
mcpApiKey?: string;
|
|
35
|
+
mcpCommand?: string;
|
|
36
|
+
mcpArgs?: string;
|
|
37
|
+
mcpTool?: string;
|
|
38
|
+
mcpToolArgs?: string;
|
|
39
|
+
ragPath?: string;
|
|
40
|
+
ragUrl?: string;
|
|
41
|
+
shieldId?: string;
|
|
42
|
+
shieldKey?: string;
|
|
43
|
+
localOnly?: string;
|
|
44
|
+
}
|
|
45
|
+
export declare function scanCommand(args: ScanArgs, config: BotGuardConfig): Promise<void>;
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.scanCommand = scanCommand;
|
|
4
|
+
const api_1 = require("../api");
|
|
5
|
+
const config_1 = require("../config");
|
|
6
|
+
const output_1 = require("../output");
|
|
7
|
+
const local_scan_1 = require("./local-scan");
|
|
8
|
+
async function scanCommand(args, config) {
|
|
9
|
+
if (args.local === 'true') {
|
|
10
|
+
await (0, local_scan_1.localScanCommand)({
|
|
11
|
+
type: args.type,
|
|
12
|
+
endpoint: args.endpoint,
|
|
13
|
+
method: args.method,
|
|
14
|
+
format: args.requestFormat || args.webhookFormat,
|
|
15
|
+
inputField: args.inputField,
|
|
16
|
+
outputField: args.outputField,
|
|
17
|
+
authType: args.authType,
|
|
18
|
+
username: args.username,
|
|
19
|
+
password: args.password,
|
|
20
|
+
token: args.token,
|
|
21
|
+
apiKeyHeader: args.apiKeyHeader,
|
|
22
|
+
apiKey: args.endpointApiKey,
|
|
23
|
+
mcpUrl: args.mcpUrl,
|
|
24
|
+
mcpTransport: args.mcpTransport,
|
|
25
|
+
mcpAuthType: args.mcpAuthType,
|
|
26
|
+
mcpUsername: args.mcpUsername,
|
|
27
|
+
mcpPassword: args.mcpPassword,
|
|
28
|
+
mcpToken: args.mcpToken,
|
|
29
|
+
mcpApiKeyHeader: args.mcpApiKeyHeader,
|
|
30
|
+
mcpApiKey: args.mcpApiKey,
|
|
31
|
+
mcpCommand: args.mcpCommand,
|
|
32
|
+
mcpArgs: args.mcpArgs,
|
|
33
|
+
mcpTool: args.mcpTool,
|
|
34
|
+
mcpToolArgs: args.mcpToolArgs,
|
|
35
|
+
ragPath: args.ragPath,
|
|
36
|
+
ragUrl: args.ragUrl,
|
|
37
|
+
attackCount: args.attackCount,
|
|
38
|
+
progress: args.progress,
|
|
39
|
+
failThreshold: args.failThreshold,
|
|
40
|
+
outputFormat: args.format,
|
|
41
|
+
scanMode: args.mode,
|
|
42
|
+
focus: args.description,
|
|
43
|
+
shieldId: args.shieldId,
|
|
44
|
+
shieldKey: args.shieldKey,
|
|
45
|
+
configShieldId: config.shieldId,
|
|
46
|
+
configShieldKey: config.shieldKey,
|
|
47
|
+
configApiUrl: config.apiUrl,
|
|
48
|
+
apiUrl: args.apiUrl,
|
|
49
|
+
});
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const apiKey = args.apiKey || config.apiKey || process.env.BOTGUARD_API_KEY;
|
|
53
|
+
if (!apiKey) {
|
|
54
|
+
console.error('Error: API key required. Use --api-key, BOTGUARD_API_KEY env var, or .botguard.yml');
|
|
55
|
+
console.error('Get your API key at: https://fullcourtdefense.ai → Account → API Keys');
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
const endpoint = args.endpoint || config.scan?.endpoint;
|
|
59
|
+
const description = args.description || config.scan?.description;
|
|
60
|
+
const systemPrompt = args.systemPrompt || config.scan?.systemPrompt;
|
|
61
|
+
const mode = (args.mode || config.scan?.mode || 'sync');
|
|
62
|
+
const format = args.format || config.scan?.format || 'table';
|
|
63
|
+
const failThreshold = Number(args.failThreshold ?? config.scan?.failThreshold ?? 0);
|
|
64
|
+
const attackCount = args.attackCount ? Number(args.attackCount) : config.scan?.attackCount;
|
|
65
|
+
const webhookFormat = args.webhookFormat || config.scan?.webhookFormat;
|
|
66
|
+
const categoriesRaw = args.categories || (config.scan?.categories ? config.scan.categories.join(',') : undefined);
|
|
67
|
+
const categories = categoriesRaw ? categoriesRaw.split(',').map(s => s.trim()) : undefined;
|
|
68
|
+
if (!endpoint) {
|
|
69
|
+
console.error('Error: --endpoint is required. Provide the URL of your AI agent to scan.');
|
|
70
|
+
console.error('Usage: fullcourtdefense scan --endpoint https://my-agent.com/chat --description "My chatbot"');
|
|
71
|
+
process.exit(1);
|
|
72
|
+
}
|
|
73
|
+
const resolvedPrompt = systemPrompt ? (0, config_1.resolveSystemPrompt)(systemPrompt) : undefined;
|
|
74
|
+
const agentDesc = description || `AI agent at ${endpoint}`;
|
|
75
|
+
const scanReq = {
|
|
76
|
+
agentDescription: agentDesc,
|
|
77
|
+
securitySchema: {
|
|
78
|
+
allowedCapabilities: ['answer questions', 'provide help'],
|
|
79
|
+
forbiddenCapabilities: ['reveal system prompt', 'execute code', 'access files', 'ignore instructions'],
|
|
80
|
+
sensitiveData: ['api keys', 'passwords', 'internal URLs', 'database credentials', 'system prompt'],
|
|
81
|
+
authenticationRequiredFor: ['admin actions', 'data export', 'configuration changes'],
|
|
82
|
+
},
|
|
83
|
+
mode,
|
|
84
|
+
notify: true,
|
|
85
|
+
};
|
|
86
|
+
scanReq.agentConfig = {
|
|
87
|
+
type: 'api',
|
|
88
|
+
description: agentDesc,
|
|
89
|
+
apiUrl: endpoint,
|
|
90
|
+
systemPrompt: resolvedPrompt,
|
|
91
|
+
};
|
|
92
|
+
if (categories) {
|
|
93
|
+
scanReq.auditOptions = { ...scanReq.auditOptions, attackCategories: categories };
|
|
94
|
+
}
|
|
95
|
+
if (attackCount) {
|
|
96
|
+
scanReq.auditOptions = { ...scanReq.auditOptions, attackCount };
|
|
97
|
+
}
|
|
98
|
+
if (webhookFormat) {
|
|
99
|
+
scanReq.webhookConfig = { format: webhookFormat };
|
|
100
|
+
}
|
|
101
|
+
const api = new api_1.BotGuardApi(apiKey, args.apiUrl || config.apiUrl);
|
|
102
|
+
const spin = (0, output_1.spinner)('Running security scan...');
|
|
103
|
+
let result;
|
|
104
|
+
try {
|
|
105
|
+
if (mode === 'sync') {
|
|
106
|
+
result = (await api.startScan(scanReq));
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
const job = (await api.startScan(scanReq));
|
|
110
|
+
spin.stop();
|
|
111
|
+
const pollSpin = (0, output_1.spinner)(`Scan started (job: ${job.jobId}). Polling for results...`);
|
|
112
|
+
result = await api.pollUntilDone(job.jobId);
|
|
113
|
+
pollSpin.stop('Scan complete');
|
|
114
|
+
}
|
|
115
|
+
spin.stop('Scan complete');
|
|
116
|
+
}
|
|
117
|
+
catch (err) {
|
|
118
|
+
spin.stop();
|
|
119
|
+
console.error(`Error: ${err.message}`);
|
|
120
|
+
process.exit(1);
|
|
121
|
+
}
|
|
122
|
+
if (!result) {
|
|
123
|
+
console.error('Error: No scan result received');
|
|
124
|
+
process.exit(1);
|
|
125
|
+
}
|
|
126
|
+
console.log((0, output_1.formatScanResult)(result, format));
|
|
127
|
+
if (failThreshold > 0 && result.score < failThreshold) {
|
|
128
|
+
console.error(`Score ${result.score} is below threshold ${failThreshold}`);
|
|
129
|
+
process.exit(1);
|
|
130
|
+
}
|
|
131
|
+
}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export interface BotGuardConfig {
|
|
2
|
+
apiKey?: string;
|
|
3
|
+
apiUrl?: string;
|
|
4
|
+
shieldId?: string;
|
|
5
|
+
shieldKey?: string;
|
|
6
|
+
scan?: {
|
|
7
|
+
endpoint?: string;
|
|
8
|
+
description?: string;
|
|
9
|
+
systemPrompt?: string;
|
|
10
|
+
categories?: string[];
|
|
11
|
+
attackCount?: number;
|
|
12
|
+
failThreshold?: number;
|
|
13
|
+
format?: 'json' | 'table' | 'summary';
|
|
14
|
+
mode?: 'sync' | 'async';
|
|
15
|
+
webhookFormat?: string;
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
export declare function loadConfig(configPath?: string): BotGuardConfig;
|
|
19
|
+
export declare function getDefaultConfigPath(): string;
|
|
20
|
+
export declare function saveShieldConfig(input: {
|
|
21
|
+
shieldId: string;
|
|
22
|
+
shieldKey?: string;
|
|
23
|
+
apiUrl?: string;
|
|
24
|
+
}): string;
|
|
25
|
+
export declare function resolveSystemPrompt(value: string): string;
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.loadConfig = loadConfig;
|
|
37
|
+
exports.getDefaultConfigPath = getDefaultConfigPath;
|
|
38
|
+
exports.saveShieldConfig = saveShieldConfig;
|
|
39
|
+
exports.resolveSystemPrompt = resolveSystemPrompt;
|
|
40
|
+
const fs = __importStar(require("fs"));
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
const CONFIG_FILENAMES = [
|
|
43
|
+
'.fullcourtdefense.yml',
|
|
44
|
+
'.fullcourtdefense.yaml',
|
|
45
|
+
'fullcourtdefense.yml',
|
|
46
|
+
'fullcourtdefense.yaml',
|
|
47
|
+
'.botguard.yml',
|
|
48
|
+
'.botguard.yaml',
|
|
49
|
+
'botguard.yml',
|
|
50
|
+
'botguard.yaml',
|
|
51
|
+
];
|
|
52
|
+
function interpolateEnv(value) {
|
|
53
|
+
return value.replace(/\$\{([^}]+)\}/g, (_, varName) => {
|
|
54
|
+
return process.env[varName.trim()] || '';
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
function parseSimpleYaml(content) {
|
|
58
|
+
const result = {};
|
|
59
|
+
const lines = content.split('\n');
|
|
60
|
+
const stack = [{ indent: -1, obj: result }];
|
|
61
|
+
for (const rawLine of lines) {
|
|
62
|
+
const line = rawLine.replace(/\r$/, '');
|
|
63
|
+
if (!line.trim() || line.trim().startsWith('#'))
|
|
64
|
+
continue;
|
|
65
|
+
const indent = line.search(/\S/);
|
|
66
|
+
const trimmed = line.trim();
|
|
67
|
+
// Array item
|
|
68
|
+
if (trimmed.startsWith('- ')) {
|
|
69
|
+
const parentEntry = stack[stack.length - 1];
|
|
70
|
+
const parentKeys = Object.keys(parentEntry.obj);
|
|
71
|
+
const lastKey = parentKeys[parentKeys.length - 1];
|
|
72
|
+
if (lastKey && !Array.isArray(parentEntry.obj[lastKey])) {
|
|
73
|
+
parentEntry.obj[lastKey] = [];
|
|
74
|
+
}
|
|
75
|
+
if (lastKey) {
|
|
76
|
+
parentEntry.obj[lastKey].push(parseValue(trimmed.slice(2).trim()));
|
|
77
|
+
}
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
const colonIdx = trimmed.indexOf(':');
|
|
81
|
+
if (colonIdx === -1)
|
|
82
|
+
continue;
|
|
83
|
+
const key = trimmed.slice(0, colonIdx).trim();
|
|
84
|
+
const rawVal = trimmed.slice(colonIdx + 1).trim();
|
|
85
|
+
// Pop stack to correct nesting level
|
|
86
|
+
while (stack.length > 1 && stack[stack.length - 1].indent >= indent) {
|
|
87
|
+
stack.pop();
|
|
88
|
+
}
|
|
89
|
+
const parent = stack[stack.length - 1].obj;
|
|
90
|
+
if (rawVal === '' || rawVal === '|') {
|
|
91
|
+
// Nested object
|
|
92
|
+
const child = {};
|
|
93
|
+
parent[key] = child;
|
|
94
|
+
stack.push({ indent, obj: child });
|
|
95
|
+
}
|
|
96
|
+
else if (rawVal.startsWith('[') && rawVal.endsWith(']')) {
|
|
97
|
+
// Inline array
|
|
98
|
+
parent[key] = rawVal
|
|
99
|
+
.slice(1, -1)
|
|
100
|
+
.split(',')
|
|
101
|
+
.map(s => parseValue(s.trim()))
|
|
102
|
+
.filter(s => s !== '');
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
parent[key] = parseValue(interpolateEnv(rawVal));
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return result;
|
|
109
|
+
}
|
|
110
|
+
function parseValue(s) {
|
|
111
|
+
if (s === 'true')
|
|
112
|
+
return true;
|
|
113
|
+
if (s === 'false')
|
|
114
|
+
return false;
|
|
115
|
+
if (s === 'null')
|
|
116
|
+
return null;
|
|
117
|
+
const stripped = s.replace(/^["']|["']$/g, '');
|
|
118
|
+
const num = Number(stripped);
|
|
119
|
+
if (!isNaN(num) && stripped !== '')
|
|
120
|
+
return num;
|
|
121
|
+
return stripped;
|
|
122
|
+
}
|
|
123
|
+
function loadConfig(configPath) {
|
|
124
|
+
let filePath;
|
|
125
|
+
if (configPath) {
|
|
126
|
+
filePath = path.resolve(configPath);
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
for (const name of CONFIG_FILENAMES) {
|
|
130
|
+
const candidate = path.resolve(process.cwd(), name);
|
|
131
|
+
if (fs.existsSync(candidate)) {
|
|
132
|
+
filePath = candidate;
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
if (!filePath || !fs.existsSync(filePath)) {
|
|
138
|
+
return {};
|
|
139
|
+
}
|
|
140
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
141
|
+
const raw = parseSimpleYaml(content);
|
|
142
|
+
return {
|
|
143
|
+
apiKey: raw.apiKey ? interpolateEnv(String(raw.apiKey)) : undefined,
|
|
144
|
+
apiUrl: raw.apiUrl ? interpolateEnv(String(raw.apiUrl)) : undefined,
|
|
145
|
+
shieldId: raw.shieldId ? interpolateEnv(String(raw.shieldId)) : undefined,
|
|
146
|
+
shieldKey: raw.shieldKey ? interpolateEnv(String(raw.shieldKey)) : undefined,
|
|
147
|
+
scan: raw.scan
|
|
148
|
+
? {
|
|
149
|
+
endpoint: raw.scan.endpoint,
|
|
150
|
+
description: raw.scan.description,
|
|
151
|
+
systemPrompt: raw.scan.systemPrompt,
|
|
152
|
+
categories: raw.scan.categories,
|
|
153
|
+
attackCount: raw.scan.attackCount,
|
|
154
|
+
failThreshold: raw.scan.failThreshold,
|
|
155
|
+
format: raw.scan.format,
|
|
156
|
+
mode: raw.scan.mode,
|
|
157
|
+
webhookFormat: raw.scan.webhookFormat,
|
|
158
|
+
}
|
|
159
|
+
: undefined,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
function getDefaultConfigPath() {
|
|
163
|
+
return path.resolve(process.cwd(), '.fullcourtdefense.yml');
|
|
164
|
+
}
|
|
165
|
+
function saveShieldConfig(input) {
|
|
166
|
+
const target = getDefaultConfigPath();
|
|
167
|
+
const existing = fs.existsSync(target) ? fs.readFileSync(target, 'utf-8') : '';
|
|
168
|
+
const lines = existing ? existing.split(/\r?\n/) : [
|
|
169
|
+
'# FullCourtDefense CLI Configuration',
|
|
170
|
+
'# Docs: https://fullcourtdefense.ai/docs/cli',
|
|
171
|
+
'',
|
|
172
|
+
];
|
|
173
|
+
const setTopLevel = (key, value) => {
|
|
174
|
+
if (!value)
|
|
175
|
+
return;
|
|
176
|
+
const idx = lines.findIndex(line => new RegExp(`^${key}:`).test(line.trim()));
|
|
177
|
+
const next = `${key}: ${value}`;
|
|
178
|
+
if (idx >= 0)
|
|
179
|
+
lines[idx] = next;
|
|
180
|
+
else {
|
|
181
|
+
const insertAt = lines.findIndex(line => line.trim().startsWith('scan:'));
|
|
182
|
+
if (insertAt >= 0)
|
|
183
|
+
lines.splice(insertAt, 0, next);
|
|
184
|
+
else
|
|
185
|
+
lines.push(next);
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
setTopLevel('shieldId', input.shieldId);
|
|
189
|
+
setTopLevel('shieldKey', input.shieldKey);
|
|
190
|
+
setTopLevel('apiUrl', input.apiUrl);
|
|
191
|
+
fs.writeFileSync(target, `${lines.filter((line, idx, arr) => !(line === '' && arr[idx - 1] === '')).join('\n').trim()}\n`, 'utf-8');
|
|
192
|
+
return target;
|
|
193
|
+
}
|
|
194
|
+
function resolveSystemPrompt(value) {
|
|
195
|
+
if (fs.existsSync(value)) {
|
|
196
|
+
return fs.readFileSync(value, 'utf-8').trim();
|
|
197
|
+
}
|
|
198
|
+
return value;
|
|
199
|
+
}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const config_1 = require("./config");
|
|
5
|
+
const scan_1 = require("./commands/scan");
|
|
6
|
+
const credits_1 = require("./commands/credits");
|
|
7
|
+
const init_1 = require("./commands/init");
|
|
8
|
+
const doctor_1 = require("./commands/doctor");
|
|
9
|
+
const configure_1 = require("./commands/configure");
|
|
10
|
+
const VERSION = '1.0.2';
|
|
11
|
+
function parseArgs(argv) {
|
|
12
|
+
const flags = {};
|
|
13
|
+
let command = '';
|
|
14
|
+
for (let i = 0; i < argv.length; i++) {
|
|
15
|
+
const arg = argv[i];
|
|
16
|
+
if (!command && !arg.startsWith('-')) {
|
|
17
|
+
command = arg;
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
if (arg.startsWith('--')) {
|
|
21
|
+
const key = arg.slice(2);
|
|
22
|
+
const eqIdx = key.indexOf('=');
|
|
23
|
+
if (eqIdx !== -1) {
|
|
24
|
+
flags[key.slice(0, eqIdx)] = key.slice(eqIdx + 1);
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
const next = argv[i + 1];
|
|
28
|
+
if (next && !next.startsWith('-')) {
|
|
29
|
+
flags[key] = next;
|
|
30
|
+
i++;
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
flags[key] = 'true';
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
else if (arg.startsWith('-')) {
|
|
38
|
+
const key = arg.slice(1);
|
|
39
|
+
const next = argv[i + 1];
|
|
40
|
+
if (next && !next.startsWith('-')) {
|
|
41
|
+
flags[key] = next;
|
|
42
|
+
i++;
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
flags[key] = 'true';
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return { command, flags };
|
|
50
|
+
}
|
|
51
|
+
function printHelp() {
|
|
52
|
+
console.log(`
|
|
53
|
+
\x1b[1m\x1b[36mFullCourtDefense CLI\x1b[0m v${VERSION}
|
|
54
|
+
Security scanning for AI agents from your terminal.
|
|
55
|
+
|
|
56
|
+
\x1b[1mUsage:\x1b[0m
|
|
57
|
+
fullcourtdefense <command> [options]
|
|
58
|
+
|
|
59
|
+
\x1b[1mCommands:\x1b[0m
|
|
60
|
+
help Show this onboarding guide and command reference.
|
|
61
|
+
doctor First step. Checks outbound HTTPS access to FullCourtDefense.
|
|
62
|
+
configure Saves Shield ID, Shield key, and API URL to .fullcourtdefense.yml.
|
|
63
|
+
scan Runs the scan. Use --local for inside-organization scans.
|
|
64
|
+
credits Shows hosted scan credits for CI/CD API-key scans.
|
|
65
|
+
init Creates a starter .fullcourtdefense.yml config file.
|
|
66
|
+
|
|
67
|
+
\x1b[1mNew User Process:\x1b[0m
|
|
68
|
+
1. In the web app, create a Shield.
|
|
69
|
+
Copy the Shield ID and Shield key from the Shield Integrate tab.
|
|
70
|
+
|
|
71
|
+
2. Check outbound connectivity from the customer machine:
|
|
72
|
+
fullcourtdefense doctor
|
|
73
|
+
This confirms the machine can reach https://api.fullcourtdefense.ai over HTTPS.
|
|
74
|
+
|
|
75
|
+
3. Save Shield credentials locally:
|
|
76
|
+
fullcourtdefense configure
|
|
77
|
+
This creates or updates .fullcourtdefense.yml.
|
|
78
|
+
|
|
79
|
+
4. Run a guided local scan:
|
|
80
|
+
fullcourtdefense scan --local
|
|
81
|
+
The CLI asks whether to scan endpoint, mcp, or rag.
|
|
82
|
+
|
|
83
|
+
5. Review results:
|
|
84
|
+
Use --format summary for CI, --format table for terminal view,
|
|
85
|
+
--format report for evidence, --format full-report for every row,
|
|
86
|
+
or --format json for raw output.
|
|
87
|
+
With a Shield key configured, reports are saved to the web Reports page.
|
|
88
|
+
|
|
89
|
+
\x1b[1mLocal Destinations:\x1b[0m
|
|
90
|
+
endpoint Internal HTTP URL, for example http://agent.local/chat.
|
|
91
|
+
The CLI sends attack prompts to this endpoint and scans responses.
|
|
92
|
+
|
|
93
|
+
mcp Either stdio command + args, or an already-running HTTP/SSE MCP URL.
|
|
94
|
+
Stdio example: node ./mcp-server.js
|
|
95
|
+
HTTP/HTTPS examples: http://mcp.internal/mcp or https://internal.company.com/mcp
|
|
96
|
+
Legacy SSE example: https://internal.company.com/sse
|
|
97
|
+
Secured HTTP MCP supports bearer, basic, and API-key auth.
|
|
98
|
+
|
|
99
|
+
rag File/directory path or live RAG HTTP endpoint.
|
|
100
|
+
Use --rag-path for local documents, or --rag-url for a RAG service.
|
|
101
|
+
|
|
102
|
+
\x1b[1mRecommended Commands:\x1b[0m
|
|
103
|
+
fullcourtdefense doctor
|
|
104
|
+
fullcourtdefense configure
|
|
105
|
+
fullcourtdefense scan --local
|
|
106
|
+
fullcourtdefense scan --local --type mcp --mcp-command node --mcp-args ./server.js --mcp-tool all --mode full --format report
|
|
107
|
+
fullcourtdefense scan --local --type mcp --mcp-url https://internal.company.com/mcp --mcp-auth-type bearer --mcp-token TOKEN --mcp-tool all --mode full --format report
|
|
108
|
+
fullcourtdefense scan --local --type rag --rag-path ./docs --format report
|
|
109
|
+
fullcourtdefense scan --local --type rag --rag-url http://rag.internal/chat --method POST --request-format custom --input-field message --output-field answer --mode full --format report
|
|
110
|
+
fullcourtdefense scan --local --type endpoint --endpoint http://agent.local/chat --method POST --mode full --format report
|
|
111
|
+
|
|
112
|
+
\x1b[1mScan Options:\x1b[0m
|
|
113
|
+
--local Run scan from this machine, inside your network
|
|
114
|
+
--type <type> Local scan type: endpoint, mcp, rag
|
|
115
|
+
--api-key <key> API key (or set BOTGUARD_API_KEY env var)
|
|
116
|
+
--api-url <url> API base URL (default: https://api.fullcourtdefense.ai)
|
|
117
|
+
--endpoint <url> Agent API endpoint to scan
|
|
118
|
+
--mcp-url <url> Already-running HTTP MCP server URL
|
|
119
|
+
--mcp-transport <t> MCP transport: stdio, http, or sse
|
|
120
|
+
--mcp-command <cmd> MCP server command, for example node or npx.cmd
|
|
121
|
+
--mcp-args <args> MCP server args/path, for example ./server.js
|
|
122
|
+
--mcp-tool <tool> MCP tool to test, or all
|
|
123
|
+
--mcp-auth-type <type> HTTP MCP auth: none, bearer, basic, api-key
|
|
124
|
+
--mcp-token <token> HTTP MCP bearer token
|
|
125
|
+
--mcp-username <user> HTTP MCP basic username
|
|
126
|
+
--mcp-password <pass> HTTP MCP basic password
|
|
127
|
+
--mcp-api-key-header <h> HTTP MCP API-key header name
|
|
128
|
+
--mcp-api-key <key> HTTP MCP API key value
|
|
129
|
+
--rag-path <path> RAG file or directory to scan
|
|
130
|
+
--rag-url <url> Live RAG HTTP endpoint to scan
|
|
131
|
+
--shield-id <id> Shield ID for local outbound Shield verdicts
|
|
132
|
+
--shield-key <key> Optional Shield key for locked Shields
|
|
133
|
+
--method <GET|POST> Local endpoint method
|
|
134
|
+
--request-format <fmt> Local endpoint request format: custom or openai
|
|
135
|
+
--auth-type <type> none, bearer, basic, api-key
|
|
136
|
+
--description <text> Agent description
|
|
137
|
+
--system-prompt <text> System prompt (text or path to file)
|
|
138
|
+
--mode <sync|async> Hosted mode, or local mode: quick, full, targeted, deep
|
|
139
|
+
--categories <list> Comma-separated attack categories
|
|
140
|
+
--attack-count <n> Number of attacks to run
|
|
141
|
+
--progress <mode> MCP progress: verbose, compact, silent (default: verbose)
|
|
142
|
+
--fail-threshold <n> Exit code 1 if score below n (default: 0)
|
|
143
|
+
--format <fmt> Output: table, json, summary, report, full-report (default: table)
|
|
144
|
+
--webhook-format <fmt> Hosted webhook format, or legacy local request format
|
|
145
|
+
--config <path> Path to .fullcourtdefense.yml config file
|
|
146
|
+
|
|
147
|
+
\x1b[1mExamples:\x1b[0m
|
|
148
|
+
$ fullcourtdefense scan --endpoint https://my-bot.com/chat --description "Support bot"
|
|
149
|
+
$ fullcourtdefense help
|
|
150
|
+
$ fullcourtdefense scan --local
|
|
151
|
+
$ fullcourtdefense scan --local --type endpoint --mode full --endpoint http://internal-agent/chat
|
|
152
|
+
$ fullcourtdefense scan --local --type mcp --mcp-command node --mcp-args ./server.js --mcp-tool all --mode full
|
|
153
|
+
$ fullcourtdefense scan --local --type mcp --mcp-url https://internal.company.com/mcp
|
|
154
|
+
$ fullcourtdefense scan --local --type mcp --mcp-url https://internal.company.com/mcp --mcp-tool all --mode full
|
|
155
|
+
$ fullcourtdefense scan --local --type mcp --mcp-transport sse --mcp-url https://internal.company.com/sse --mcp-tool all --mode full
|
|
156
|
+
$ fullcourtdefense scan --local --type mcp --mcp-command node --mcp-args ./server.js --mcp-tool all --mode full --format report
|
|
157
|
+
$ fullcourtdefense configure
|
|
158
|
+
$ fullcourtdefense doctor
|
|
159
|
+
$ fullcourtdefense scan --system-prompt ./prompts/system.md --fail-threshold 80
|
|
160
|
+
$ fullcourtdefense scan --config .botguard.yml --format json
|
|
161
|
+
$ fullcourtdefense credits
|
|
162
|
+
$ fullcourtdefense init
|
|
163
|
+
|
|
164
|
+
\x1b[2mDocs: https://fullcourtdefense.ai/docs/cli\x1b[0m
|
|
165
|
+
`);
|
|
166
|
+
}
|
|
167
|
+
async function main() {
|
|
168
|
+
const { command, flags } = parseArgs(process.argv.slice(2));
|
|
169
|
+
if (flags.version || flags.v) {
|
|
170
|
+
console.log(VERSION);
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
if (!command || flags.help || flags.h) {
|
|
174
|
+
printHelp();
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
const config = (0, config_1.loadConfig)(flags.config);
|
|
178
|
+
switch (command) {
|
|
179
|
+
case 'scan': {
|
|
180
|
+
const args = {
|
|
181
|
+
apiKey: flags['api-key'],
|
|
182
|
+
apiUrl: flags['api-url'],
|
|
183
|
+
endpoint: flags.endpoint,
|
|
184
|
+
description: flags.description,
|
|
185
|
+
systemPrompt: flags['system-prompt'],
|
|
186
|
+
mode: flags.mode,
|
|
187
|
+
categories: flags.categories,
|
|
188
|
+
attackCount: flags['attack-count'],
|
|
189
|
+
progress: flags.progress,
|
|
190
|
+
failThreshold: flags['fail-threshold'],
|
|
191
|
+
format: flags.format,
|
|
192
|
+
requestFormat: flags['request-format'],
|
|
193
|
+
webhookFormat: flags['webhook-format'],
|
|
194
|
+
local: flags.local,
|
|
195
|
+
type: flags.type,
|
|
196
|
+
method: flags.method,
|
|
197
|
+
inputField: flags['input-field'],
|
|
198
|
+
outputField: flags['output-field'],
|
|
199
|
+
authType: flags['auth-type'],
|
|
200
|
+
username: flags.username,
|
|
201
|
+
password: flags.password,
|
|
202
|
+
token: flags.token,
|
|
203
|
+
apiKeyHeader: flags['api-key-header'],
|
|
204
|
+
endpointApiKey: flags['endpoint-api-key'],
|
|
205
|
+
mcpUrl: flags['mcp-url'],
|
|
206
|
+
mcpTransport: flags['mcp-transport'],
|
|
207
|
+
mcpAuthType: flags['mcp-auth-type'],
|
|
208
|
+
mcpUsername: flags['mcp-username'],
|
|
209
|
+
mcpPassword: flags['mcp-password'],
|
|
210
|
+
mcpToken: flags['mcp-token'],
|
|
211
|
+
mcpApiKeyHeader: flags['mcp-api-key-header'],
|
|
212
|
+
mcpApiKey: flags['mcp-api-key'],
|
|
213
|
+
mcpCommand: flags['mcp-command'],
|
|
214
|
+
mcpArgs: flags['mcp-args'],
|
|
215
|
+
mcpTool: flags['mcp-tool'],
|
|
216
|
+
mcpToolArgs: flags['mcp-tool-args'],
|
|
217
|
+
ragPath: flags['rag-path'],
|
|
218
|
+
ragUrl: flags['rag-url'],
|
|
219
|
+
shieldId: flags['shield-id'],
|
|
220
|
+
shieldKey: flags['shield-key'],
|
|
221
|
+
};
|
|
222
|
+
await (0, scan_1.scanCommand)(args, config);
|
|
223
|
+
break;
|
|
224
|
+
}
|
|
225
|
+
case 'help': {
|
|
226
|
+
printHelp();
|
|
227
|
+
break;
|
|
228
|
+
}
|
|
229
|
+
case 'doctor': {
|
|
230
|
+
const args = {
|
|
231
|
+
apiUrl: flags['api-url'],
|
|
232
|
+
};
|
|
233
|
+
await (0, doctor_1.doctorCommand)(args, config);
|
|
234
|
+
break;
|
|
235
|
+
}
|
|
236
|
+
case 'configure': {
|
|
237
|
+
const args = {
|
|
238
|
+
shieldId: flags['shield-id'],
|
|
239
|
+
shieldKey: flags['shield-key'],
|
|
240
|
+
apiUrl: flags['api-url'],
|
|
241
|
+
};
|
|
242
|
+
await (0, configure_1.configureCommand)(args, config);
|
|
243
|
+
break;
|
|
244
|
+
}
|
|
245
|
+
case 'credits': {
|
|
246
|
+
const args = {
|
|
247
|
+
apiKey: flags['api-key'],
|
|
248
|
+
apiUrl: flags['api-url'],
|
|
249
|
+
};
|
|
250
|
+
await (0, credits_1.creditsCommand)(args, config);
|
|
251
|
+
break;
|
|
252
|
+
}
|
|
253
|
+
case 'init': {
|
|
254
|
+
await (0, init_1.initCommand)();
|
|
255
|
+
break;
|
|
256
|
+
}
|
|
257
|
+
default:
|
|
258
|
+
console.error(`Unknown command: ${command}`);
|
|
259
|
+
console.error('Run "fullcourtdefense --help" for usage.');
|
|
260
|
+
process.exit(1);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
main().catch(err => {
|
|
264
|
+
console.error(`Fatal: ${err.message}`);
|
|
265
|
+
process.exit(1);
|
|
266
|
+
});
|
package/dist/output.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ScanResult, CreditsResponse } from './api';
|
|
2
|
+
export declare function formatTable(result: ScanResult): string;
|
|
3
|
+
export declare function formatSummary(result: ScanResult): string;
|
|
4
|
+
export declare function formatReport(result: ScanResult): string;
|
|
5
|
+
export declare function formatFullReport(result: ScanResult): string;
|
|
6
|
+
export declare function formatJson(result: ScanResult): string;
|
|
7
|
+
export declare function formatCredits(credits: CreditsResponse): string;
|
|
8
|
+
export declare function formatScanResult(result: ScanResult, format: string): string;
|
|
9
|
+
export declare function spinner(message: string): {
|
|
10
|
+
stop: (finalMsg?: string) => void;
|
|
11
|
+
};
|