webmcp-cli 1.2.2 → 1.2.3
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/analysis/form-to-tool-mapper.d.ts +61 -0
- package/dist/analysis/form-to-tool-mapper.js +360 -0
- package/dist/analysis/form-to-tool-mapper.js.map +1 -0
- package/dist/analysis/index.d.ts +84 -0
- package/dist/analysis/index.js +81 -0
- package/dist/analysis/index.js.map +1 -0
- package/dist/analysis/missing-tool-analyzer.d.ts +35 -0
- package/dist/analysis/missing-tool-analyzer.js +617 -0
- package/dist/analysis/missing-tool-analyzer.js.map +1 -0
- package/dist/audit/run-multi-page-audit.d.ts +34 -0
- package/dist/audit/run-multi-page-audit.js +233 -0
- package/dist/audit/run-multi-page-audit.js.map +1 -0
- package/dist/cli/commands/potential.d.ts +8 -0
- package/dist/cli/commands/potential.js +323 -0
- package/dist/cli/commands/potential.js.map +1 -0
- package/dist/cli/commands/report.d.ts +12 -0
- package/dist/cli/commands/report.js +89 -0
- package/dist/cli/commands/report.js.map +1 -0
- package/dist/cli/index.js +35 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/config/defaults.d.ts +36 -0
- package/dist/config/defaults.js +33 -0
- package/dist/config/defaults.js.map +1 -0
- package/dist/config/index.d.ts +7 -0
- package/dist/config/index.js +7 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/loader.d.ts +22 -0
- package/dist/config/loader.js +91 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/schema.d.ts +280 -0
- package/dist/config/schema.js +42 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/core/types/audit.d.ts +1 -1
- package/dist/core/types/index.d.ts +1 -0
- package/dist/core/types/index.js +1 -0
- package/dist/core/types/index.js.map +1 -1
- package/dist/core/types/recon.d.ts +265 -0
- package/dist/core/types/recon.js +5 -0
- package/dist/core/types/recon.js.map +1 -0
- package/dist/core/types/rule.d.ts +1 -1
- package/dist/core/types/rule.js +7 -5
- package/dist/core/types/rule.js.map +1 -1
- package/dist/crawler/depth-crawler.d.ts +29 -0
- package/dist/crawler/depth-crawler.js +212 -0
- package/dist/crawler/depth-crawler.js.map +1 -0
- package/dist/crawler/index.d.ts +2 -0
- package/dist/crawler/index.js +3 -0
- package/dist/crawler/index.js.map +1 -0
- package/dist/crawler/link-extractor.d.ts +1 -0
- package/dist/crawler/link-extractor.js +49 -0
- package/dist/crawler/link-extractor.js.map +1 -0
- package/dist/generators/index.d.ts +10 -0
- package/dist/generators/index.js +8 -0
- package/dist/generators/index.js.map +1 -0
- package/dist/generators/report-html.d.ts +12 -0
- package/dist/generators/report-html.js +470 -0
- package/dist/generators/report-html.js.map +1 -0
- package/dist/generators/report-json.d.ts +95 -0
- package/dist/generators/report-json.js +144 -0
- package/dist/generators/report-json.js.map +1 -0
- package/dist/generators/report-manager.d.ts +31 -0
- package/dist/generators/report-manager.js +208 -0
- package/dist/generators/report-manager.js.map +1 -0
- package/dist/generators/tool-code-generator.d.ts +31 -0
- package/dist/generators/tool-code-generator.js +201 -0
- package/dist/generators/tool-code-generator.js.map +1 -0
- package/dist/potential/ai-recommender.d.ts +33 -0
- package/dist/potential/ai-recommender.js +414 -0
- package/dist/potential/ai-recommender.js.map +1 -0
- package/dist/potential/analyzer.d.ts +32 -0
- package/dist/potential/analyzer.js +383 -0
- package/dist/potential/analyzer.js.map +1 -0
- package/dist/potential/index.d.ts +3 -0
- package/dist/potential/index.js +4 -0
- package/dist/potential/index.js.map +1 -0
- package/dist/potential/prompts.d.ts +20 -0
- package/dist/potential/prompts.js +42 -0
- package/dist/potential/prompts.js.map +1 -0
- package/dist/potential/types.d.ts +40 -0
- package/dist/potential/types.js +2 -0
- package/dist/potential/types.js.map +1 -0
- package/dist/recon/index.d.ts +20 -0
- package/dist/recon/index.js +143 -0
- package/dist/recon/index.js.map +1 -0
- package/dist/recon/manifest.d.ts +16 -0
- package/dist/recon/manifest.js +108 -0
- package/dist/recon/manifest.js.map +1 -0
- package/dist/recon/meta-extractor.d.ts +11 -0
- package/dist/recon/meta-extractor.js +276 -0
- package/dist/recon/meta-extractor.js.map +1 -0
- package/dist/recon/robots.d.ts +16 -0
- package/dist/recon/robots.js +158 -0
- package/dist/recon/robots.js.map +1 -0
- package/dist/recon/route-discovery.d.ts +25 -0
- package/dist/recon/route-discovery.js +303 -0
- package/dist/recon/route-discovery.js.map +1 -0
- package/dist/recon/sitemap.d.ts +12 -0
- package/dist/recon/sitemap.js +177 -0
- package/dist/recon/sitemap.js.map +1 -0
- package/dist/rules/accessibility/AXE-001.d.ts +9 -0
- package/dist/rules/accessibility/AXE-001.js +109 -0
- package/dist/rules/accessibility/AXE-001.js.map +1 -0
- package/dist/rules/accessibility/AXE-002.d.ts +8 -0
- package/dist/rules/accessibility/AXE-002.js +85 -0
- package/dist/rules/accessibility/AXE-002.js.map +1 -0
- package/dist/rules/accessibility/AXE-003.d.ts +8 -0
- package/dist/rules/accessibility/AXE-003.js +94 -0
- package/dist/rules/accessibility/AXE-003.js.map +1 -0
- package/dist/rules/accessibility/AXE-004.d.ts +8 -0
- package/dist/rules/accessibility/AXE-004.js +101 -0
- package/dist/rules/accessibility/AXE-004.js.map +1 -0
- package/dist/rules/accessibility/AXE-005.d.ts +9 -0
- package/dist/rules/accessibility/AXE-005.js +89 -0
- package/dist/rules/accessibility/AXE-005.js.map +1 -0
- package/dist/rules/best-practices/BP-004.d.ts +9 -0
- package/dist/rules/best-practices/BP-004.js +96 -0
- package/dist/rules/best-practices/BP-004.js.map +1 -0
- package/dist/rules/best-practices/BP-005.d.ts +8 -0
- package/dist/rules/best-practices/BP-005.js +94 -0
- package/dist/rules/best-practices/BP-005.js.map +1 -0
- package/dist/rules/best-practices/BP-006.d.ts +8 -0
- package/dist/rules/best-practices/BP-006.js +80 -0
- package/dist/rules/best-practices/BP-006.js.map +1 -0
- package/dist/rules/best-practices/BP-007.d.ts +8 -0
- package/dist/rules/best-practices/BP-007.js +92 -0
- package/dist/rules/best-practices/BP-007.js.map +1 -0
- package/dist/rules/best-practices/BP-008.d.ts +12 -0
- package/dist/rules/best-practices/BP-008.js +86 -0
- package/dist/rules/best-practices/BP-008.js.map +1 -0
- package/dist/rules/best-practices/BP-009.d.ts +9 -0
- package/dist/rules/best-practices/BP-009.js +77 -0
- package/dist/rules/best-practices/BP-009.js.map +1 -0
- package/dist/rules/best-practices/BP-010.d.ts +8 -0
- package/dist/rules/best-practices/BP-010.js +85 -0
- package/dist/rules/best-practices/BP-010.js.map +1 -0
- package/dist/rules/coverage/COV-002.d.ts +8 -0
- package/dist/rules/coverage/COV-002.js +68 -0
- package/dist/rules/coverage/COV-002.js.map +1 -0
- package/dist/rules/coverage/COV-003.d.ts +8 -0
- package/dist/rules/coverage/COV-003.js +68 -0
- package/dist/rules/coverage/COV-003.js.map +1 -0
- package/dist/rules/coverage/COV-004.d.ts +8 -0
- package/dist/rules/coverage/COV-004.js +89 -0
- package/dist/rules/coverage/COV-004.js.map +1 -0
- package/dist/rules/coverage/COV-005.d.ts +8 -0
- package/dist/rules/coverage/COV-005.js +67 -0
- package/dist/rules/coverage/COV-005.js.map +1 -0
- package/dist/rules/coverage/COV-006.d.ts +9 -0
- package/dist/rules/coverage/COV-006.js +76 -0
- package/dist/rules/coverage/COV-006.js.map +1 -0
- package/dist/rules/coverage/COV-007.d.ts +8 -0
- package/dist/rules/coverage/COV-007.js +67 -0
- package/dist/rules/coverage/COV-007.js.map +1 -0
- package/dist/rules/coverage/COV-008.d.ts +9 -0
- package/dist/rules/coverage/COV-008.js +87 -0
- package/dist/rules/coverage/COV-008.js.map +1 -0
- package/dist/rules/coverage/COV-009.d.ts +8 -0
- package/dist/rules/coverage/COV-009.js +73 -0
- package/dist/rules/coverage/COV-009.js.map +1 -0
- package/dist/rules/coverage/COV-010.d.ts +9 -0
- package/dist/rules/coverage/COV-010.js +82 -0
- package/dist/rules/coverage/COV-010.js.map +1 -0
- package/dist/rules/description/DESC-001.d.ts +9 -0
- package/dist/rules/description/DESC-001.js +88 -0
- package/dist/rules/description/DESC-001.js.map +1 -0
- package/dist/rules/description/DESC-002.d.ts +10 -0
- package/dist/rules/description/DESC-002.js +99 -0
- package/dist/rules/description/DESC-002.js.map +1 -0
- package/dist/rules/description/DESC-006.d.ts +9 -0
- package/dist/rules/description/DESC-006.js +78 -0
- package/dist/rules/description/DESC-006.js.map +1 -0
- package/dist/rules/description/DESC-007.d.ts +9 -0
- package/dist/rules/description/DESC-007.js +70 -0
- package/dist/rules/description/DESC-007.js.map +1 -0
- package/dist/rules/description/DESC-008.d.ts +9 -0
- package/dist/rules/description/DESC-008.js +70 -0
- package/dist/rules/description/DESC-008.js.map +1 -0
- package/dist/rules/description/DESC-009.d.ts +8 -0
- package/dist/rules/description/DESC-009.js +55 -0
- package/dist/rules/description/DESC-009.js.map +1 -0
- package/dist/rules/description/DESC-010.d.ts +9 -0
- package/dist/rules/description/DESC-010.js +92 -0
- package/dist/rules/description/DESC-010.js.map +1 -0
- package/dist/rules/description/DESC-011.d.ts +9 -0
- package/dist/rules/description/DESC-011.js +81 -0
- package/dist/rules/description/DESC-011.js.map +1 -0
- package/dist/rules/description/DESC-012.d.ts +9 -0
- package/dist/rules/description/DESC-012.js +98 -0
- package/dist/rules/description/DESC-012.js.map +1 -0
- package/dist/rules/implementation/IMP-002.d.ts +9 -0
- package/dist/rules/implementation/IMP-002.js +59 -0
- package/dist/rules/implementation/IMP-002.js.map +1 -0
- package/dist/rules/implementation/IMP-006.d.ts +9 -0
- package/dist/rules/implementation/IMP-006.js +48 -0
- package/dist/rules/implementation/IMP-006.js.map +1 -0
- package/dist/rules/implementation/IMP-008.d.ts +9 -0
- package/dist/rules/implementation/IMP-008.js +46 -0
- package/dist/rules/implementation/IMP-008.js.map +1 -0
- package/dist/rules/implementation/IMP-009.d.ts +9 -0
- package/dist/rules/implementation/IMP-009.js +48 -0
- package/dist/rules/implementation/IMP-009.js.map +1 -0
- package/dist/rules/implementation/IMP-010.d.ts +9 -0
- package/dist/rules/implementation/IMP-010.js +66 -0
- package/dist/rules/implementation/IMP-010.js.map +1 -0
- package/dist/rules/implementation/IMP-011.d.ts +9 -0
- package/dist/rules/implementation/IMP-011.js +82 -0
- package/dist/rules/implementation/IMP-011.js.map +1 -0
- package/dist/rules/implementation/IMP-012.d.ts +9 -0
- package/dist/rules/implementation/IMP-012.js +88 -0
- package/dist/rules/implementation/IMP-012.js.map +1 -0
- package/dist/rules/implementation/IMP-014.d.ts +9 -0
- package/dist/rules/implementation/IMP-014.js +58 -0
- package/dist/rules/implementation/IMP-014.js.map +1 -0
- package/dist/rules/implementation/IMP-015.d.ts +9 -0
- package/dist/rules/implementation/IMP-015.js +64 -0
- package/dist/rules/implementation/IMP-015.js.map +1 -0
- package/dist/rules/implementation/IMP-016.d.ts +9 -0
- package/dist/rules/implementation/IMP-016.js +52 -0
- package/dist/rules/implementation/IMP-016.js.map +1 -0
- package/dist/rules/implementation/IMP-017.d.ts +8 -0
- package/dist/rules/implementation/IMP-017.js +51 -0
- package/dist/rules/implementation/IMP-017.js.map +1 -0
- package/dist/rules/implementation/IMP-018.d.ts +8 -0
- package/dist/rules/implementation/IMP-018.js +52 -0
- package/dist/rules/implementation/IMP-018.js.map +1 -0
- package/dist/rules/implementation/IMP-019.d.ts +8 -0
- package/dist/rules/implementation/IMP-019.js +53 -0
- package/dist/rules/implementation/IMP-019.js.map +1 -0
- package/dist/rules/implementation/IMP-020.d.ts +9 -0
- package/dist/rules/implementation/IMP-020.js +62 -0
- package/dist/rules/implementation/IMP-020.js.map +1 -0
- package/dist/rules/implementation/IMP-021.d.ts +8 -0
- package/dist/rules/implementation/IMP-021.js +64 -0
- package/dist/rules/implementation/IMP-021.js.map +1 -0
- package/dist/rules/implementation/IMP-022.d.ts +8 -0
- package/dist/rules/implementation/IMP-022.js +70 -0
- package/dist/rules/implementation/IMP-022.js.map +1 -0
- package/dist/rules/index.d.ts +73 -6
- package/dist/rules/index.js +141 -6
- package/dist/rules/index.js.map +1 -1
- package/dist/rules/schema/SCHEMA-004.d.ts +9 -0
- package/dist/rules/schema/SCHEMA-004.js +57 -0
- package/dist/rules/schema/SCHEMA-004.js.map +1 -0
- package/dist/rules/schema/SCHEMA-005.d.ts +9 -0
- package/dist/rules/schema/SCHEMA-005.js +61 -0
- package/dist/rules/schema/SCHEMA-005.js.map +1 -0
- package/dist/rules/schema/SCHEMA-006.d.ts +10 -0
- package/dist/rules/schema/SCHEMA-006.js +85 -0
- package/dist/rules/schema/SCHEMA-006.js.map +1 -0
- package/dist/rules/schema/SCHEMA-007.d.ts +9 -0
- package/dist/rules/schema/SCHEMA-007.js +73 -0
- package/dist/rules/schema/SCHEMA-007.js.map +1 -0
- package/dist/rules/schema/SCHEMA-008.d.ts +9 -0
- package/dist/rules/schema/SCHEMA-008.js +70 -0
- package/dist/rules/schema/SCHEMA-008.js.map +1 -0
- package/dist/rules/schema/SCHEMA-009.d.ts +10 -0
- package/dist/rules/schema/SCHEMA-009.js +80 -0
- package/dist/rules/schema/SCHEMA-009.js.map +1 -0
- package/dist/rules/schema/SCHEMA-010.d.ts +9 -0
- package/dist/rules/schema/SCHEMA-010.js +96 -0
- package/dist/rules/schema/SCHEMA-010.js.map +1 -0
- package/dist/rules/schema/SCHEMA-012.d.ts +9 -0
- package/dist/rules/schema/SCHEMA-012.js +65 -0
- package/dist/rules/schema/SCHEMA-012.js.map +1 -0
- package/dist/rules/security/SEC-002.d.ts +8 -0
- package/dist/rules/security/SEC-002.js +81 -0
- package/dist/rules/security/SEC-002.js.map +1 -0
- package/dist/rules/security/SEC-003.d.ts +8 -0
- package/dist/rules/security/SEC-003.js +85 -0
- package/dist/rules/security/SEC-003.js.map +1 -0
- package/dist/rules/security/SEC-004.d.ts +9 -0
- package/dist/rules/security/SEC-004.js +87 -0
- package/dist/rules/security/SEC-004.js.map +1 -0
- package/dist/rules/security/SEC-005.d.ts +8 -0
- package/dist/rules/security/SEC-005.js +87 -0
- package/dist/rules/security/SEC-005.js.map +1 -0
- package/dist/rules/security/SEC-006.d.ts +10 -0
- package/dist/rules/security/SEC-006.js +108 -0
- package/dist/rules/security/SEC-006.js.map +1 -0
- package/dist/rules/security/SEC-007.d.ts +9 -0
- package/dist/rules/security/SEC-007.js +108 -0
- package/dist/rules/security/SEC-007.js.map +1 -0
- package/dist/rules/security/SEC-008.d.ts +8 -0
- package/dist/rules/security/SEC-008.js +109 -0
- package/dist/rules/security/SEC-008.js.map +1 -0
- package/dist/rules/security/SEC-009.d.ts +9 -0
- package/dist/rules/security/SEC-009.js +93 -0
- package/dist/rules/security/SEC-009.js.map +1 -0
- package/dist/rules/security/SEC-010.d.ts +8 -0
- package/dist/rules/security/SEC-010.js +78 -0
- package/dist/rules/security/SEC-010.js.map +1 -0
- package/dist/rules/security/SEC-011.d.ts +8 -0
- package/dist/rules/security/SEC-011.js +93 -0
- package/dist/rules/security/SEC-011.js.map +1 -0
- package/dist/rules/security/SEC-012.d.ts +8 -0
- package/dist/rules/security/SEC-012.js +79 -0
- package/dist/rules/security/SEC-012.js.map +1 -0
- package/dist/rules/security/SEC-013.d.ts +9 -0
- package/dist/rules/security/SEC-013.js +107 -0
- package/dist/rules/security/SEC-013.js.map +1 -0
- package/dist/scoring/calculator.js +1 -0
- package/dist/scoring/calculator.js.map +1 -1
- package/dist/ui/ink/components/AIRecommendationCard.d.ts +11 -0
- package/dist/ui/ink/components/AIRecommendationCard.js +23 -0
- package/dist/ui/ink/components/AIRecommendationCard.js.map +1 -0
- package/dist/ui/ink/components/OpportunityList.d.ts +10 -0
- package/dist/ui/ink/components/OpportunityList.js +48 -0
- package/dist/ui/ink/components/OpportunityList.js.map +1 -0
- package/dist/ui/ink/components/PotentialPageCard.d.ts +13 -0
- package/dist/ui/ink/components/PotentialPageCard.js +43 -0
- package/dist/ui/ink/components/PotentialPageCard.js.map +1 -0
- package/dist/ui/ink/components/PotentialProgress.d.ts +16 -0
- package/dist/ui/ink/components/PotentialProgress.js +44 -0
- package/dist/ui/ink/components/PotentialProgress.js.map +1 -0
- package/dist/ui/ink/components/PotentialSummary.d.ts +10 -0
- package/dist/ui/ink/components/PotentialSummary.js +86 -0
- package/dist/ui/ink/components/PotentialSummary.js.map +1 -0
- package/dist/ui/ink/components/SuggestionCard.d.ts +34 -0
- package/dist/ui/ink/components/SuggestionCard.js +36 -0
- package/dist/ui/ink/components/SuggestionCard.js.map +1 -0
- package/dist/ui/ink/components/views/MultiPageCrawlView.d.ts +21 -0
- package/dist/ui/ink/components/views/MultiPageCrawlView.js +55 -0
- package/dist/ui/ink/components/views/MultiPageCrawlView.js.map +1 -0
- package/dist/ui/ink/components/views/PotentialView.d.ts +18 -0
- package/dist/ui/ink/components/views/PotentialView.js +74 -0
- package/dist/ui/ink/components/views/PotentialView.js.map +1 -0
- package/dist/ui/ink/components/views/ReconView.d.ts +22 -0
- package/dist/ui/ink/components/views/ReconView.js +30 -0
- package/dist/ui/ink/components/views/ReconView.js.map +1 -0
- package/package.json +2 -1
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SCHEMA-007: Enum Values Described
|
|
3
|
+
*
|
|
4
|
+
* Checks that enum properties use oneOf with title/const for clear options
|
|
5
|
+
* rather than bare enum arrays without descriptions.
|
|
6
|
+
*/
|
|
7
|
+
import { createRuleResult } from '../runner.js';
|
|
8
|
+
export const SCHEMA_007 = {
|
|
9
|
+
id: 'SCHEMA-007',
|
|
10
|
+
category: 'schema',
|
|
11
|
+
name: 'Enum Values Described',
|
|
12
|
+
description: 'Enum properties should use oneOf with title/const for clear options',
|
|
13
|
+
severity: 'info',
|
|
14
|
+
maxScore: 3,
|
|
15
|
+
async check(context) {
|
|
16
|
+
if (context.tools.length === 0) {
|
|
17
|
+
return createRuleResult('SCHEMA-007', 3, {
|
|
18
|
+
passed: true,
|
|
19
|
+
score: 3,
|
|
20
|
+
message: 'No tools detected (rule not applicable)',
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
const violations = [];
|
|
24
|
+
let enumCount = 0;
|
|
25
|
+
for (const tool of context.tools) {
|
|
26
|
+
if (!tool.inputSchema?.properties)
|
|
27
|
+
continue;
|
|
28
|
+
for (const [paramName, paramDef] of Object.entries(tool.inputSchema.properties)) {
|
|
29
|
+
if (!paramDef.enum || paramDef.enum.length <= 1)
|
|
30
|
+
continue;
|
|
31
|
+
enumCount++;
|
|
32
|
+
// Check if there's a corresponding oneOf with titles
|
|
33
|
+
if (!paramDef.oneOf) {
|
|
34
|
+
violations.push({ tool: tool.name, param: paramName });
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
const allHaveTitles = paramDef.oneOf.every((opt) => opt['title'] || opt['description']);
|
|
38
|
+
if (!allHaveTitles) {
|
|
39
|
+
violations.push({ tool: tool.name, param: paramName });
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (enumCount === 0) {
|
|
45
|
+
return createRuleResult('SCHEMA-007', 3, {
|
|
46
|
+
passed: true,
|
|
47
|
+
score: 3,
|
|
48
|
+
message: 'No enum properties found to check',
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
if (violations.length === 0) {
|
|
52
|
+
return createRuleResult('SCHEMA-007', 3, {
|
|
53
|
+
passed: true,
|
|
54
|
+
score: 3,
|
|
55
|
+
message: 'All enum properties have descriptive oneOf options',
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
return createRuleResult('SCHEMA-007', 3, {
|
|
59
|
+
passed: false,
|
|
60
|
+
score: Math.max(0, 3 - violations.length),
|
|
61
|
+
message: `${violations.length} enum property/properties lack descriptive oneOf options`,
|
|
62
|
+
details: violations.map((v) => `Property "${v.param}" in tool "${v.tool}" uses bare enum without oneOf titles`),
|
|
63
|
+
suggestions: [
|
|
64
|
+
'Replace bare enum with oneOf containing title and const',
|
|
65
|
+
'Example: { "oneOf": [{ "const": "economy", "title": "Economy (cheapest fare)" }] }',
|
|
66
|
+
'Descriptive options help agents make correct selections',
|
|
67
|
+
],
|
|
68
|
+
affectedTools: [...new Set(violations.map((v) => v.tool))],
|
|
69
|
+
});
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
export default SCHEMA_007;
|
|
73
|
+
//# sourceMappingURL=SCHEMA-007.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SCHEMA-007.js","sourceRoot":"","sources":["../../../src/rules/schema/SCHEMA-007.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SCHEMA-008: Number Has Bounds
|
|
3
|
+
*
|
|
4
|
+
* Checks that number properties have minimum/maximum constraints.
|
|
5
|
+
* Bounds help agents provide valid values.
|
|
6
|
+
*/
|
|
7
|
+
import type { Rule } from '../../core/types/rule.js';
|
|
8
|
+
export declare const SCHEMA_008: Rule;
|
|
9
|
+
export default SCHEMA_008;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SCHEMA-008: Number Has Bounds
|
|
3
|
+
*
|
|
4
|
+
* Checks that number properties have minimum/maximum constraints.
|
|
5
|
+
* Bounds help agents provide valid values.
|
|
6
|
+
*/
|
|
7
|
+
import { createRuleResult } from '../runner.js';
|
|
8
|
+
export const SCHEMA_008 = {
|
|
9
|
+
id: 'SCHEMA-008',
|
|
10
|
+
category: 'schema',
|
|
11
|
+
name: 'Number Has Bounds',
|
|
12
|
+
description: 'Number properties should have minimum/maximum constraints',
|
|
13
|
+
severity: 'warning',
|
|
14
|
+
maxScore: 5,
|
|
15
|
+
async check(context) {
|
|
16
|
+
if (context.tools.length === 0) {
|
|
17
|
+
return createRuleResult('SCHEMA-008', 5, {
|
|
18
|
+
passed: true,
|
|
19
|
+
score: 5,
|
|
20
|
+
message: 'No tools detected (rule not applicable)',
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
const violations = [];
|
|
24
|
+
let numberParamCount = 0;
|
|
25
|
+
for (const tool of context.tools) {
|
|
26
|
+
if (!tool.inputSchema?.properties)
|
|
27
|
+
continue;
|
|
28
|
+
for (const [paramName, paramDef] of Object.entries(tool.inputSchema.properties)) {
|
|
29
|
+
if (paramDef.type !== 'number' && paramDef.type !== 'integer') {
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
numberParamCount++;
|
|
33
|
+
const hasBounds = paramDef.minimum !== undefined ||
|
|
34
|
+
paramDef.maximum !== undefined ||
|
|
35
|
+
paramDef.enum !== undefined;
|
|
36
|
+
if (!hasBounds) {
|
|
37
|
+
violations.push({ tool: tool.name, param: paramName });
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (numberParamCount === 0) {
|
|
42
|
+
return createRuleResult('SCHEMA-008', 5, {
|
|
43
|
+
passed: true,
|
|
44
|
+
score: 5,
|
|
45
|
+
message: 'No number properties found to check',
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
if (violations.length === 0) {
|
|
49
|
+
return createRuleResult('SCHEMA-008', 5, {
|
|
50
|
+
passed: true,
|
|
51
|
+
score: 5,
|
|
52
|
+
message: 'All number properties have bounds',
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
return createRuleResult('SCHEMA-008', 5, {
|
|
56
|
+
passed: false,
|
|
57
|
+
score: Math.max(0, 5 - violations.length * 2),
|
|
58
|
+
message: `${violations.length} number property/properties lack bounds`,
|
|
59
|
+
details: violations.map((v) => `Property "${v.param}" in tool "${v.tool}" has no minimum/maximum`),
|
|
60
|
+
suggestions: [
|
|
61
|
+
'Add minimum and/or maximum to number properties',
|
|
62
|
+
'Example: { "type": "number", "minimum": 1, "maximum": 10 }',
|
|
63
|
+
'Bounds prevent agents from providing out-of-range values',
|
|
64
|
+
],
|
|
65
|
+
affectedTools: [...new Set(violations.map((v) => v.tool))],
|
|
66
|
+
});
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
export default SCHEMA_008;
|
|
70
|
+
//# sourceMappingURL=SCHEMA-008.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SCHEMA-008.js","sourceRoot":"","sources":["../../../src/rules/schema/SCHEMA-008.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAEhD,MAAM,CAAC,MAAM,UAAU,GAAS;IAC9B,EAAE,EAAE,YAAY;IAChB,QAAQ,EAAE,QAAQ;IAClB,IAAI,EAAE,mBAAmB;IACzB,WAAW,EAAE,2DAA2D;IACxE,QAAQ,EAAE,SAAS;IACnB,QAAQ,EAAE,CAAC;IAEX,KAAK,CAAC,KAAK,CAAC,OAAoB;QAC9B,IAAI,OAAO,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC/B,OAAO,gBAAgB,CAAC,YAAY,EAAE,CAAC,EAAE;gBACvC,MAAM,EAAE,IAAI;gBACZ,KAAK,EAAE,CAAC;gBACR,OAAO,EAAE,yCAAyC;aACnD,CAAC,CAAC;QACL,CAAC;QAED,MAAM,UAAU,GAAsC,EAAE,CAAC;QACzD,IAAI,gBAAgB,GAAG,CAAC,CAAC;QAEzB,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;YACjC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,UAAU;gBAAE,SAAS;YAE5C,KAAK,MAAM,CAAC,SAAS,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAChD,IAAI,CAAC,WAAW,CAAC,UAAU,CAC5B,EAAE,CAAC;gBACF,IAAI,QAAQ,CAAC,IAAI,KAAK,QAAQ,IAAI,QAAQ,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;oBAC9D,SAAS;gBACX,CAAC;gBACD,gBAAgB,EAAE,CAAC;gBAEnB,MAAM,SAAS,GACb,QAAQ,CAAC,OAAO,KAAK,SAAS;oBAC9B,QAAQ,CAAC,OAAO,KAAK,SAAS;oBAC9B,QAAQ,CAAC,IAAI,KAAK,SAAS,CAAC;gBAE9B,IAAI,CAAC,SAAS,EAAE,CAAC;oBACf,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;gBACzD,CAAC;YACH,CAAC;QACH,CAAC;QAED,IAAI,gBAAgB,KAAK,CAAC,EAAE,CAAC;YAC3B,OAAO,gBAAgB,CAAC,YAAY,EAAE,CAAC,EAAE;gBACvC,MAAM,EAAE,IAAI;gBACZ,KAAK,EAAE,CAAC;gBACR,OAAO,EAAE,qCAAqC;aAC/C,CAAC,CAAC;QACL,CAAC;QAED,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC5B,OAAO,gBAAgB,CAAC,YAAY,EAAE,CAAC,EAAE;gBACvC,MAAM,EAAE,IAAI;gBACZ,KAAK,EAAE,CAAC;gBACR,OAAO,EAAE,mCAAmC;aAC7C,CAAC,CAAC;QACL,CAAC;QAED,OAAO,gBAAgB,CAAC,YAAY,EAAE,CAAC,EAAE;YACvC,MAAM,EAAE,KAAK;YACb,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC;YAC7C,OAAO,EAAE,GAAG,UAAU,CAAC,MAAM,yCAAyC;YACtE,OAAO,EAAE,UAAU,CAAC,GAAG,CACrB,CAAC,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,CAAC,KAAK,cAAc,CAAC,CAAC,IAAI,0BAA0B,CAC1E;YACD,WAAW,EAAE;gBACX,iDAAiD;gBACjD,4DAA4D;gBAC5D,0DAA0D;aAC3D;YACD,aAAa,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;SAC3D,CAAC,CAAC;IACL,CAAC;CACF,CAAC;AAEF,eAAe,UAAU,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SCHEMA-009: String Has Format
|
|
3
|
+
*
|
|
4
|
+
* Checks that string properties use format hints where applicable.
|
|
5
|
+
* Heuristic: if the parameter name suggests a specific format (email, date, url),
|
|
6
|
+
* the schema should declare it.
|
|
7
|
+
*/
|
|
8
|
+
import type { Rule } from '../../core/types/rule.js';
|
|
9
|
+
export declare const SCHEMA_009: Rule;
|
|
10
|
+
export default SCHEMA_009;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SCHEMA-009: String Has Format
|
|
3
|
+
*
|
|
4
|
+
* Checks that string properties use format hints where applicable.
|
|
5
|
+
* Heuristic: if the parameter name suggests a specific format (email, date, url),
|
|
6
|
+
* the schema should declare it.
|
|
7
|
+
*/
|
|
8
|
+
import { createRuleResult } from '../runner.js';
|
|
9
|
+
const FORMAT_HINTS = [
|
|
10
|
+
{ namePattern: /email/i, expectedFormat: 'email' },
|
|
11
|
+
{ namePattern: /\burl\b|uri|href|link/i, expectedFormat: 'uri' },
|
|
12
|
+
{ namePattern: /\bdate\b/i, expectedFormat: 'date or date-time' },
|
|
13
|
+
{ namePattern: /\bdate[_-]?time\b|timestamp/i, expectedFormat: 'date-time' },
|
|
14
|
+
{ namePattern: /\btime\b$/i, expectedFormat: 'time' },
|
|
15
|
+
{ namePattern: /\bipv4\b|ip[_-]?address/i, expectedFormat: 'ipv4' },
|
|
16
|
+
{ namePattern: /\bipv6\b/i, expectedFormat: 'ipv6' },
|
|
17
|
+
{ namePattern: /\buuid\b|guid/i, expectedFormat: 'uuid' },
|
|
18
|
+
{ namePattern: /\bhostname\b/i, expectedFormat: 'hostname' },
|
|
19
|
+
];
|
|
20
|
+
export const SCHEMA_009 = {
|
|
21
|
+
id: 'SCHEMA-009',
|
|
22
|
+
category: 'schema',
|
|
23
|
+
name: 'String Has Format',
|
|
24
|
+
description: 'String properties should use format hints where applicable',
|
|
25
|
+
severity: 'info',
|
|
26
|
+
maxScore: 3,
|
|
27
|
+
async check(context) {
|
|
28
|
+
if (context.tools.length === 0) {
|
|
29
|
+
return createRuleResult('SCHEMA-009', 3, {
|
|
30
|
+
passed: true,
|
|
31
|
+
score: 3,
|
|
32
|
+
message: 'No tools detected (rule not applicable)',
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
const violations = [];
|
|
36
|
+
for (const tool of context.tools) {
|
|
37
|
+
if (!tool.inputSchema?.properties)
|
|
38
|
+
continue;
|
|
39
|
+
for (const [paramName, paramDef] of Object.entries(tool.inputSchema.properties)) {
|
|
40
|
+
if (paramDef.type !== 'string')
|
|
41
|
+
continue;
|
|
42
|
+
if (paramDef.format)
|
|
43
|
+
continue; // Already has format
|
|
44
|
+
if (paramDef.enum || paramDef.oneOf)
|
|
45
|
+
continue; // Enum, no format needed
|
|
46
|
+
for (const { namePattern, expectedFormat } of FORMAT_HINTS) {
|
|
47
|
+
if (namePattern.test(paramName)) {
|
|
48
|
+
violations.push({
|
|
49
|
+
tool: tool.name,
|
|
50
|
+
param: paramName,
|
|
51
|
+
format: expectedFormat,
|
|
52
|
+
});
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (violations.length === 0) {
|
|
59
|
+
return createRuleResult('SCHEMA-009', 3, {
|
|
60
|
+
passed: true,
|
|
61
|
+
score: 3,
|
|
62
|
+
message: 'String properties use format hints where applicable',
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
return createRuleResult('SCHEMA-009', 3, {
|
|
66
|
+
passed: false,
|
|
67
|
+
score: Math.max(0, 3 - violations.length),
|
|
68
|
+
message: `${violations.length} string property/properties could benefit from format hints`,
|
|
69
|
+
details: violations.map((v) => `Property "${v.param}" in tool "${v.tool}" should use format: "${v.format}"`),
|
|
70
|
+
suggestions: [
|
|
71
|
+
'Use JSON Schema format keyword for well-known string types',
|
|
72
|
+
'Supported formats: email, uri, date, date-time, time, ipv4, ipv6, uuid, hostname',
|
|
73
|
+
'Example: { "type": "string", "format": "email" }',
|
|
74
|
+
],
|
|
75
|
+
affectedTools: [...new Set(violations.map((v) => v.tool))],
|
|
76
|
+
});
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
export default SCHEMA_009;
|
|
80
|
+
//# sourceMappingURL=SCHEMA-009.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SCHEMA-009.js","sourceRoot":"","sources":["../../../src/rules/schema/SCHEMA-009.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SCHEMA-010: No Excessive Nesting
|
|
3
|
+
*
|
|
4
|
+
* Checks that schema nesting depth doesn't exceed 3 levels.
|
|
5
|
+
* Deeply nested schemas are harder for agents to reason about.
|
|
6
|
+
*/
|
|
7
|
+
import type { Rule } from '../../core/types/rule.js';
|
|
8
|
+
export declare const SCHEMA_010: Rule;
|
|
9
|
+
export default SCHEMA_010;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SCHEMA-010: No Excessive Nesting
|
|
3
|
+
*
|
|
4
|
+
* Checks that schema nesting depth doesn't exceed 3 levels.
|
|
5
|
+
* Deeply nested schemas are harder for agents to reason about.
|
|
6
|
+
*/
|
|
7
|
+
import { createRuleResult } from '../runner.js';
|
|
8
|
+
const MAX_NESTING_DEPTH = 3;
|
|
9
|
+
function measureDepth(schema, current) {
|
|
10
|
+
let maxDepth = current;
|
|
11
|
+
if (schema.properties) {
|
|
12
|
+
for (const prop of Object.values(schema.properties)) {
|
|
13
|
+
const childDepth = measureDepth(prop, current + 1);
|
|
14
|
+
if (childDepth > maxDepth) {
|
|
15
|
+
maxDepth = childDepth;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
if (schema.items) {
|
|
20
|
+
const itemDepth = measureDepth(schema.items, current + 1);
|
|
21
|
+
if (itemDepth > maxDepth) {
|
|
22
|
+
maxDepth = itemDepth;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (schema.oneOf) {
|
|
26
|
+
for (const option of schema.oneOf) {
|
|
27
|
+
const optionDepth = measureDepth(option, current + 1);
|
|
28
|
+
if (optionDepth > maxDepth) {
|
|
29
|
+
maxDepth = optionDepth;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
if (schema.anyOf) {
|
|
34
|
+
for (const option of schema.anyOf) {
|
|
35
|
+
const optionDepth = measureDepth(option, current + 1);
|
|
36
|
+
if (optionDepth > maxDepth) {
|
|
37
|
+
maxDepth = optionDepth;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (schema.additionalProperties &&
|
|
42
|
+
typeof schema.additionalProperties === 'object') {
|
|
43
|
+
const apDepth = measureDepth(schema.additionalProperties, current + 1);
|
|
44
|
+
if (apDepth > maxDepth) {
|
|
45
|
+
maxDepth = apDepth;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return maxDepth;
|
|
49
|
+
}
|
|
50
|
+
export const SCHEMA_010 = {
|
|
51
|
+
id: 'SCHEMA-010',
|
|
52
|
+
category: 'schema',
|
|
53
|
+
name: 'No Excessive Nesting',
|
|
54
|
+
description: `Schema nesting depth should not exceed ${MAX_NESTING_DEPTH} levels`,
|
|
55
|
+
severity: 'warning',
|
|
56
|
+
maxScore: 5,
|
|
57
|
+
async check(context) {
|
|
58
|
+
if (context.tools.length === 0) {
|
|
59
|
+
return createRuleResult('SCHEMA-010', 5, {
|
|
60
|
+
passed: true,
|
|
61
|
+
score: 5,
|
|
62
|
+
message: 'No tools detected (rule not applicable)',
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
const violations = [];
|
|
66
|
+
for (const tool of context.tools) {
|
|
67
|
+
if (!tool.inputSchema?.properties)
|
|
68
|
+
continue;
|
|
69
|
+
const depth = measureDepth(tool.inputSchema, 0);
|
|
70
|
+
if (depth > MAX_NESTING_DEPTH) {
|
|
71
|
+
violations.push({ name: tool.name, depth });
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (violations.length === 0) {
|
|
75
|
+
return createRuleResult('SCHEMA-010', 5, {
|
|
76
|
+
passed: true,
|
|
77
|
+
score: 5,
|
|
78
|
+
message: `All schemas have acceptable nesting depth (≤${MAX_NESTING_DEPTH})`,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
return createRuleResult('SCHEMA-010', 5, {
|
|
82
|
+
passed: false,
|
|
83
|
+
score: Math.max(0, 5 - violations.length * 2),
|
|
84
|
+
message: `${violations.length} tool(s) have excessively nested schemas`,
|
|
85
|
+
details: violations.map((v) => `Tool "${v.name}" has nesting depth of ${v.depth} (max: ${MAX_NESTING_DEPTH})`),
|
|
86
|
+
suggestions: [
|
|
87
|
+
'Flatten nested objects into top-level parameters where possible',
|
|
88
|
+
'Use separate tools for complex nested operations',
|
|
89
|
+
'Deeply nested schemas are harder for agents to fill correctly',
|
|
90
|
+
],
|
|
91
|
+
affectedTools: violations.map((v) => v.name),
|
|
92
|
+
});
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
export default SCHEMA_010;
|
|
96
|
+
//# sourceMappingURL=SCHEMA-010.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SCHEMA-010.js","sourceRoot":"","sources":["../../../src/rules/schema/SCHEMA-010.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SCHEMA-012: No Duplicate Params
|
|
3
|
+
*
|
|
4
|
+
* Checks that there are no duplicate parameter names (case-insensitive)
|
|
5
|
+
* within a single tool's schema.
|
|
6
|
+
*/
|
|
7
|
+
import type { Rule } from '../../core/types/rule.js';
|
|
8
|
+
export declare const SCHEMA_012: Rule;
|
|
9
|
+
export default SCHEMA_012;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SCHEMA-012: No Duplicate Params
|
|
3
|
+
*
|
|
4
|
+
* Checks that there are no duplicate parameter names (case-insensitive)
|
|
5
|
+
* within a single tool's schema.
|
|
6
|
+
*/
|
|
7
|
+
import { createRuleResult } from '../runner.js';
|
|
8
|
+
export const SCHEMA_012 = {
|
|
9
|
+
id: 'SCHEMA-012',
|
|
10
|
+
category: 'schema',
|
|
11
|
+
name: 'No Duplicate Params',
|
|
12
|
+
description: 'No duplicate parameter names (case-insensitive)',
|
|
13
|
+
severity: 'critical',
|
|
14
|
+
maxScore: 10,
|
|
15
|
+
async check(context) {
|
|
16
|
+
if (context.tools.length === 0) {
|
|
17
|
+
return createRuleResult('SCHEMA-012', 10, {
|
|
18
|
+
passed: true,
|
|
19
|
+
score: 10,
|
|
20
|
+
message: 'No tools detected (rule not applicable)',
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
const violations = [];
|
|
24
|
+
for (const tool of context.tools) {
|
|
25
|
+
if (!tool.inputSchema?.properties)
|
|
26
|
+
continue;
|
|
27
|
+
const paramNames = Object.keys(tool.inputSchema.properties);
|
|
28
|
+
const lowerNames = new Map();
|
|
29
|
+
for (const name of paramNames) {
|
|
30
|
+
const lower = name.toLowerCase();
|
|
31
|
+
const existing = lowerNames.get(lower) ?? [];
|
|
32
|
+
existing.push(name);
|
|
33
|
+
lowerNames.set(lower, existing);
|
|
34
|
+
}
|
|
35
|
+
const duplicates = Array.from(lowerNames.values()).filter((names) => names.length > 1);
|
|
36
|
+
if (duplicates.length > 0) {
|
|
37
|
+
violations.push({
|
|
38
|
+
tool: tool.name,
|
|
39
|
+
params: duplicates.map((d) => d.join(', ')),
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (violations.length === 0) {
|
|
44
|
+
return createRuleResult('SCHEMA-012', 10, {
|
|
45
|
+
passed: true,
|
|
46
|
+
score: 10,
|
|
47
|
+
message: 'No duplicate parameter names found',
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
return createRuleResult('SCHEMA-012', 10, {
|
|
51
|
+
passed: false,
|
|
52
|
+
score: Math.max(0, 10 - violations.length * 5),
|
|
53
|
+
message: `${violations.length} tool(s) have duplicate parameter names`,
|
|
54
|
+
details: violations.flatMap((v) => v.params.map((p) => `Tool "${v.tool}" has case-insensitive duplicate params: ${p}`)),
|
|
55
|
+
suggestions: [
|
|
56
|
+
'Ensure all parameter names are unique (case-insensitive)',
|
|
57
|
+
'Use distinct, descriptive names for each parameter',
|
|
58
|
+
'Example: use "departure_city" and "arrival_city" instead of "City" and "city"',
|
|
59
|
+
],
|
|
60
|
+
affectedTools: violations.map((v) => v.tool),
|
|
61
|
+
});
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
export default SCHEMA_012;
|
|
65
|
+
//# sourceMappingURL=SCHEMA-012.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SCHEMA-012.js","sourceRoot":"","sources":["../../../src/rules/schema/SCHEMA-012.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SEC-002: No Parameter Description Injection
|
|
3
|
+
*
|
|
4
|
+
* Checks that parameter descriptions don't contain injection patterns
|
|
5
|
+
* such as prompt injection, SQL injection, or script injection.
|
|
6
|
+
*/
|
|
7
|
+
import type { Rule } from '../../core/types/rule.js';
|
|
8
|
+
export declare const SEC_002: Rule;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SEC-002: No Parameter Description Injection
|
|
3
|
+
*
|
|
4
|
+
* Checks that parameter descriptions don't contain injection patterns
|
|
5
|
+
* such as prompt injection, SQL injection, or script injection.
|
|
6
|
+
*/
|
|
7
|
+
import { createRuleResult } from '../runner.js';
|
|
8
|
+
const INJECTION_PATTERNS = [
|
|
9
|
+
/ignore\s+(all\s+)?previous\s+instructions/i,
|
|
10
|
+
/you\s+are\s+now/i,
|
|
11
|
+
/system\s*:\s*/i,
|
|
12
|
+
/\bDROP\s+TABLE\b/i,
|
|
13
|
+
/\bUNION\s+SELECT\b/i,
|
|
14
|
+
/['"];\s*--/,
|
|
15
|
+
/<script[\s>]/i,
|
|
16
|
+
/javascript\s*:/i,
|
|
17
|
+
/on\w+\s*=/i,
|
|
18
|
+
/\bexec\s*\(/i,
|
|
19
|
+
/\beval\s*\(/i,
|
|
20
|
+
/\{\{.*\}\}/,
|
|
21
|
+
/\$\{.*\}/,
|
|
22
|
+
/<%.*%>/,
|
|
23
|
+
];
|
|
24
|
+
export const SEC_002 = {
|
|
25
|
+
id: 'SEC-002',
|
|
26
|
+
category: 'security',
|
|
27
|
+
name: 'No Parameter Description Injection',
|
|
28
|
+
description: 'Parameter descriptions must not contain injection patterns',
|
|
29
|
+
severity: 'critical',
|
|
30
|
+
maxScore: 10,
|
|
31
|
+
async check(context) {
|
|
32
|
+
const tools = context.tools;
|
|
33
|
+
if (tools.length === 0) {
|
|
34
|
+
return createRuleResult('SEC-002', 10, {
|
|
35
|
+
passed: true,
|
|
36
|
+
score: 10,
|
|
37
|
+
message: 'No tools detected (rule not applicable)',
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
const violations = [];
|
|
41
|
+
for (const tool of tools) {
|
|
42
|
+
const schema = tool.inputSchema;
|
|
43
|
+
if (!schema?.properties)
|
|
44
|
+
continue;
|
|
45
|
+
for (const [paramName, prop] of Object.entries(schema.properties)) {
|
|
46
|
+
const desc = prop.description ?? '';
|
|
47
|
+
for (const pattern of INJECTION_PATTERNS) {
|
|
48
|
+
if (pattern.test(desc)) {
|
|
49
|
+
violations.push({
|
|
50
|
+
tool: tool.name,
|
|
51
|
+
param: paramName,
|
|
52
|
+
pattern: pattern.source,
|
|
53
|
+
});
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (violations.length === 0) {
|
|
60
|
+
return createRuleResult('SEC-002', 10, {
|
|
61
|
+
passed: true,
|
|
62
|
+
score: 10,
|
|
63
|
+
message: 'No injection patterns found in parameter descriptions',
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
const penalty = violations.length * 5;
|
|
67
|
+
const score = Math.max(0, 10 - penalty);
|
|
68
|
+
return createRuleResult('SEC-002', 10, {
|
|
69
|
+
passed: false,
|
|
70
|
+
score,
|
|
71
|
+
message: `${violations.length} parameter(s) contain injection patterns`,
|
|
72
|
+
details: violations.map((v) => `Tool "${v.tool}" param "${v.param}" matches injection pattern: ${v.pattern}`),
|
|
73
|
+
suggestions: [
|
|
74
|
+
'Remove any prompt injection, SQL injection, or XSS patterns from parameter descriptions',
|
|
75
|
+
'Descriptions should be plain, informative text only',
|
|
76
|
+
],
|
|
77
|
+
affectedTools: [...new Set(violations.map((v) => v.tool))],
|
|
78
|
+
});
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
//# sourceMappingURL=SEC-002.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SEC-002.js","sourceRoot":"","sources":["../../../src/rules/security/SEC-002.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAEhD,MAAM,kBAAkB,GAAG;IACzB,4CAA4C;IAC5C,kBAAkB;IAClB,gBAAgB;IAChB,mBAAmB;IACnB,qBAAqB;IACrB,YAAY;IACZ,eAAe;IACf,iBAAiB;IACjB,YAAY;IACZ,cAAc;IACd,cAAc;IACd,YAAY;IACZ,UAAU;IACV,QAAQ;CACT,CAAC;AAEF,MAAM,CAAC,MAAM,OAAO,GAAS;IAC3B,EAAE,EAAE,SAAS;IACb,QAAQ,EAAE,UAAU;IACpB,IAAI,EAAE,oCAAoC;IAC1C,WAAW,EAAE,4DAA4D;IACzE,QAAQ,EAAE,UAAU;IACpB,QAAQ,EAAE,EAAE;IAEZ,KAAK,CAAC,KAAK,CAAC,OAAoB;QAC9B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAE5B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,OAAO,gBAAgB,CAAC,SAAS,EAAE,EAAE,EAAE;gBACrC,MAAM,EAAE,IAAI;gBACZ,KAAK,EAAE,EAAE;gBACT,OAAO,EAAE,yCAAyC;aACnD,CAAC,CAAC;QACL,CAAC;QAED,MAAM,UAAU,GAAuD,EAAE,CAAC;QAE1E,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC;YAChC,IAAI,CAAC,MAAM,EAAE,UAAU;gBAAE,SAAS;YAElC,KAAK,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC;gBAClE,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,IAAI,EAAE,CAAC;gBACpC,KAAK,MAAM,OAAO,IAAI,kBAAkB,EAAE,CAAC;oBACzC,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;wBACvB,UAAU,CAAC,IAAI,CAAC;4BACd,IAAI,EAAE,IAAI,CAAC,IAAI;4BACf,KAAK,EAAE,SAAS;4BAChB,OAAO,EAAE,OAAO,CAAC,MAAM;yBACxB,CAAC,CAAC;wBACH,MAAM;oBACR,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAED,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC5B,OAAO,gBAAgB,CAAC,SAAS,EAAE,EAAE,EAAE;gBACrC,MAAM,EAAE,IAAI;gBACZ,KAAK,EAAE,EAAE;gBACT,OAAO,EAAE,uDAAuD;aACjE,CAAC,CAAC;QACL,CAAC;QAED,MAAM,OAAO,GAAG,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC;QACtC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,GAAG,OAAO,CAAC,CAAC;QAExC,OAAO,gBAAgB,CAAC,SAAS,EAAE,EAAE,EAAE;YACrC,MAAM,EAAE,KAAK;YACb,KAAK;YACL,OAAO,EAAE,GAAG,UAAU,CAAC,MAAM,0CAA0C;YACvE,OAAO,EAAE,UAAU,CAAC,GAAG,CACrB,CAAC,CAAC,EAAE,EAAE,CACJ,SAAS,CAAC,CAAC,IAAI,YAAY,CAAC,CAAC,KAAK,gCAAgC,CAAC,CAAC,OAAO,EAAE,CAChF;YACD,WAAW,EAAE;gBACX,yFAAyF;gBACzF,qDAAqD;aACtD;YACD,aAAa,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;SAC3D,CAAC,CAAC;IACL,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SEC-003: Output Sanitization
|
|
3
|
+
*
|
|
4
|
+
* Checks that execute functions sanitize user-generated content
|
|
5
|
+
* in return values to prevent XSS or injection through tool outputs.
|
|
6
|
+
*/
|
|
7
|
+
import type { Rule } from '../../core/types/rule.js';
|
|
8
|
+
export declare const SEC_003: Rule;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SEC-003: Output Sanitization
|
|
3
|
+
*
|
|
4
|
+
* Checks that execute functions sanitize user-generated content
|
|
5
|
+
* in return values to prevent XSS or injection through tool outputs.
|
|
6
|
+
*/
|
|
7
|
+
import { createRuleResult } from '../runner.js';
|
|
8
|
+
const SANITIZATION_PATTERNS = [
|
|
9
|
+
/escapeHtml/i,
|
|
10
|
+
/sanitize/i,
|
|
11
|
+
/DOMPurify/i,
|
|
12
|
+
/textContent/,
|
|
13
|
+
/innerText/,
|
|
14
|
+
/encodeURIComponent/,
|
|
15
|
+
/encodeURI\b/,
|
|
16
|
+
/htmlEncode/i,
|
|
17
|
+
/stripTags/i,
|
|
18
|
+
/createTextNode/,
|
|
19
|
+
];
|
|
20
|
+
const USER_CONTENT_PATTERNS = [
|
|
21
|
+
/innerHTML/,
|
|
22
|
+
/\.html\s*\(/,
|
|
23
|
+
/document\.write/,
|
|
24
|
+
/insertAdjacentHTML/,
|
|
25
|
+
/outerHTML\s*=/,
|
|
26
|
+
];
|
|
27
|
+
export const SEC_003 = {
|
|
28
|
+
id: 'SEC-003',
|
|
29
|
+
category: 'security',
|
|
30
|
+
name: 'Output Sanitization',
|
|
31
|
+
description: 'Execute functions should sanitize user-generated content in return values',
|
|
32
|
+
severity: 'warning',
|
|
33
|
+
maxScore: 8,
|
|
34
|
+
async check(context) {
|
|
35
|
+
const tools = context.tools;
|
|
36
|
+
if (tools.length === 0) {
|
|
37
|
+
return createRuleResult('SEC-003', 8, {
|
|
38
|
+
passed: true,
|
|
39
|
+
score: 8,
|
|
40
|
+
message: 'No tools detected (rule not applicable)',
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
const toolsWithExecute = tools.filter((t) => t.executeSource && t.executeSource.length > 0);
|
|
44
|
+
if (toolsWithExecute.length === 0) {
|
|
45
|
+
return createRuleResult('SEC-003', 8, {
|
|
46
|
+
passed: true,
|
|
47
|
+
score: 8,
|
|
48
|
+
message: 'No execute functions available for analysis',
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
const violations = [];
|
|
52
|
+
for (const tool of toolsWithExecute) {
|
|
53
|
+
const src = tool.executeSource ?? '';
|
|
54
|
+
const usesUnsafeOutput = USER_CONTENT_PATTERNS.some((p) => p.test(src));
|
|
55
|
+
if (!usesUnsafeOutput)
|
|
56
|
+
continue;
|
|
57
|
+
const hasSanitization = SANITIZATION_PATTERNS.some((p) => p.test(src));
|
|
58
|
+
if (!hasSanitization) {
|
|
59
|
+
violations.push(tool.name);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (violations.length === 0) {
|
|
63
|
+
return createRuleResult('SEC-003', 8, {
|
|
64
|
+
passed: true,
|
|
65
|
+
score: 8,
|
|
66
|
+
message: 'Execute functions properly sanitize user-generated content',
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
const penalty = violations.length * 4;
|
|
70
|
+
const score = Math.max(0, 8 - penalty);
|
|
71
|
+
return createRuleResult('SEC-003', 8, {
|
|
72
|
+
passed: false,
|
|
73
|
+
score,
|
|
74
|
+
message: `${violations.length} tool(s) may return unsanitized user content`,
|
|
75
|
+
details: violations.map((name) => `Tool "${name}" uses innerHTML/document.write but lacks sanitization`),
|
|
76
|
+
suggestions: [
|
|
77
|
+
'Use textContent instead of innerHTML when inserting user data',
|
|
78
|
+
'Apply DOMPurify or escapeHtml() before returning HTML content',
|
|
79
|
+
'Use encodeURIComponent() for URL parameters in output',
|
|
80
|
+
],
|
|
81
|
+
affectedTools: violations,
|
|
82
|
+
});
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
//# sourceMappingURL=SEC-003.js.map
|