@kevinrabun/judges 3.47.0 → 3.48.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +56 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/audit-trail.d.ts +18 -0
- package/dist/commands/audit-trail.d.ts.map +1 -0
- package/dist/commands/audit-trail.js +155 -0
- package/dist/commands/audit-trail.js.map +1 -0
- package/dist/commands/auto-fix.d.ts +18 -0
- package/dist/commands/auto-fix.d.ts.map +1 -0
- package/dist/commands/auto-fix.js +241 -0
- package/dist/commands/auto-fix.js.map +1 -0
- package/dist/commands/dep-correlate.d.ts +9 -0
- package/dist/commands/dep-correlate.d.ts.map +1 -0
- package/dist/commands/dep-correlate.js +208 -0
- package/dist/commands/dep-correlate.js.map +1 -0
- package/dist/commands/doc-gen.d.ts +8 -0
- package/dist/commands/doc-gen.d.ts.map +1 -0
- package/dist/commands/doc-gen.js +209 -0
- package/dist/commands/doc-gen.js.map +1 -0
- package/dist/commands/judge-author.d.ts +8 -0
- package/dist/commands/judge-author.d.ts.map +1 -0
- package/dist/commands/judge-author.js +261 -0
- package/dist/commands/judge-author.js.map +1 -0
- package/dist/commands/pattern-registry.d.ts +23 -0
- package/dist/commands/pattern-registry.d.ts.map +1 -0
- package/dist/commands/pattern-registry.js +227 -0
- package/dist/commands/pattern-registry.js.map +1 -0
- package/dist/commands/perf-hotspot.d.ts +8 -0
- package/dist/commands/perf-hotspot.d.ts.map +1 -0
- package/dist/commands/perf-hotspot.js +274 -0
- package/dist/commands/perf-hotspot.js.map +1 -0
- package/dist/commands/security-maturity.d.ts +8 -0
- package/dist/commands/security-maturity.d.ts.map +1 -0
- package/dist/commands/security-maturity.js +313 -0
- package/dist/commands/security-maturity.js.map +1 -0
- package/package.json +1 -1
- package/server.json +2 -2
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Documentation generation — generates security documentation
|
|
3
|
+
* from Judges findings history and configuration.
|
|
4
|
+
*
|
|
5
|
+
* All output is local markdown files.
|
|
6
|
+
*/
|
|
7
|
+
import { existsSync, readFileSync, mkdirSync, writeFileSync } from "fs";
|
|
8
|
+
import { join } from "path";
|
|
9
|
+
// ─── Helpers ────────────────────────────────────────────────────────────────
|
|
10
|
+
function loadJsonSafe(path, fallback) {
|
|
11
|
+
if (!existsSync(path))
|
|
12
|
+
return fallback;
|
|
13
|
+
try {
|
|
14
|
+
return JSON.parse(readFileSync(path, "utf-8"));
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return fallback;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function generatePolicyDoc() {
|
|
21
|
+
const sections = [];
|
|
22
|
+
// Header
|
|
23
|
+
sections.push({
|
|
24
|
+
title: "Security Review Policy",
|
|
25
|
+
content: `# Security Review Policy\n\n_Generated by Judges on ${new Date().toISOString().split("T")[0]}_\n\n## Overview\n\nThis document outlines the security review policy enforced by the Judges automated code review system.\n`,
|
|
26
|
+
});
|
|
27
|
+
// Configuration
|
|
28
|
+
const configPath = ".judgesrc";
|
|
29
|
+
if (existsSync(configPath)) {
|
|
30
|
+
try {
|
|
31
|
+
const config = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
32
|
+
let content = `## Configuration\n\n`;
|
|
33
|
+
if (config.preset)
|
|
34
|
+
content += `- **Preset:** ${config.preset}\n`;
|
|
35
|
+
if (config.minSeverity)
|
|
36
|
+
content += `- **Minimum Severity:** ${config.minSeverity}\n`;
|
|
37
|
+
if (config.disabledJudges?.length)
|
|
38
|
+
content += `- **Disabled Judges:** ${config.disabledJudges.join(", ")}\n`;
|
|
39
|
+
if (config.disabledRules?.length)
|
|
40
|
+
content += `- **Disabled Rules:** ${config.disabledRules.join(", ")}\n`;
|
|
41
|
+
content += `\n`;
|
|
42
|
+
sections.push({ title: "Configuration", content });
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
// skip
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
// Suppressions
|
|
49
|
+
const supps = loadJsonSafe(".judges-suppressions.json", { suppressions: [] });
|
|
50
|
+
if (supps.suppressions && supps.suppressions.length > 0) {
|
|
51
|
+
let content = `## Approved Suppressions\n\n| Rule | Reason | Approved By |\n|------|--------|-------------|\n`;
|
|
52
|
+
for (const s of supps.suppressions) {
|
|
53
|
+
content += `| ${s.ruleId || "—"} | ${s.reason || "—"} | ${s.approvedBy || "—"} |\n`;
|
|
54
|
+
}
|
|
55
|
+
content += `\n`;
|
|
56
|
+
sections.push({ title: "Suppressions", content });
|
|
57
|
+
}
|
|
58
|
+
// Quality gates
|
|
59
|
+
const gate = loadJsonSafe(join(".judges-quality-gate", "policy.json"), {});
|
|
60
|
+
if (Object.keys(gate).length > 0) {
|
|
61
|
+
let content = `## Quality Gate Policy\n\n`;
|
|
62
|
+
for (const [key, val] of Object.entries(gate)) {
|
|
63
|
+
content += `- **${key}:** ${JSON.stringify(val)}\n`;
|
|
64
|
+
}
|
|
65
|
+
content += `\n`;
|
|
66
|
+
sections.push({ title: "Quality Gate", content });
|
|
67
|
+
}
|
|
68
|
+
return sections;
|
|
69
|
+
}
|
|
70
|
+
function generateRemediationGuide() {
|
|
71
|
+
const sections = [];
|
|
72
|
+
sections.push({
|
|
73
|
+
title: "Remediation Guide",
|
|
74
|
+
content: `# Security Remediation Guide\n\n_Generated by Judges on ${new Date().toISOString().split("T")[0]}_\n\nThis guide covers common security findings and how to fix them.\n\n`,
|
|
75
|
+
});
|
|
76
|
+
const guides = [
|
|
77
|
+
{
|
|
78
|
+
rule: "SQL Injection",
|
|
79
|
+
fix: "Use parameterized queries or prepared statements. Never concatenate user input into SQL strings.",
|
|
80
|
+
example: "db.query('SELECT * FROM users WHERE id = ?', [userId])",
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
rule: "Cross-Site Scripting (XSS)",
|
|
84
|
+
fix: "Sanitize and encode all user-provided output. Use framework-provided escaping (e.g., React auto-escapes).",
|
|
85
|
+
example: "const safe = DOMPurify.sanitize(userInput)",
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
rule: "Command Injection",
|
|
89
|
+
fix: "Use parameterized APIs or allowlists instead of shell execution with user input.",
|
|
90
|
+
example: "execFile('git', ['log', '--oneline'], callback)",
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
rule: "Hardcoded Secrets",
|
|
94
|
+
fix: "Move secrets to environment variables or a secrets manager. Never commit credentials.",
|
|
95
|
+
example: "const apiKey = process.env.API_KEY",
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
rule: "Insecure Cryptography",
|
|
99
|
+
fix: "Use strong algorithms (AES-256-GCM, SHA-256+). Avoid MD5, SHA-1, DES, RC4.",
|
|
100
|
+
example: "crypto.createCipheriv('aes-256-gcm', key, iv)",
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
rule: "Path Traversal",
|
|
104
|
+
fix: "Validate and normalize file paths. Use allowlists for permitted directories.",
|
|
105
|
+
example: "const safePath = path.resolve(baseDir, path.basename(userInput))",
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
rule: "SSRF",
|
|
109
|
+
fix: "Validate and allowlist URLs. Block internal IP ranges. Use URL parsing.",
|
|
110
|
+
example: "const url = new URL(userInput); if (!ALLOWED_HOSTS.has(url.hostname)) throw new Error()",
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
rule: "Missing Authentication",
|
|
114
|
+
fix: "Require authentication on all sensitive endpoints. Use middleware for consistent enforcement.",
|
|
115
|
+
example: "app.use('/api', authMiddleware)",
|
|
116
|
+
},
|
|
117
|
+
];
|
|
118
|
+
let content = "";
|
|
119
|
+
for (const g of guides) {
|
|
120
|
+
content += `## ${g.rule}\n\n**Fix:** ${g.fix}\n\n\`\`\`\n${g.example}\n\`\`\`\n\n---\n\n`;
|
|
121
|
+
}
|
|
122
|
+
sections.push({ title: "Remediation Details", content });
|
|
123
|
+
return sections;
|
|
124
|
+
}
|
|
125
|
+
function generateTeamPlaybook() {
|
|
126
|
+
const sections = [];
|
|
127
|
+
sections.push({
|
|
128
|
+
title: "Team Security Playbook",
|
|
129
|
+
content: `# Team Security Playbook\n\n_Generated by Judges on ${new Date().toISOString().split("T")[0]}_\n\n## Workflow\n\n1. **Pre-commit**: Run \`judges review\` locally before pushing code\n2. **CI Pipeline**: Configure \`judges ci-template\` for automated PR checks\n3. **Triage**: Use \`judges auto-triage\` to prioritize critical findings\n4. **Review**: Assign findings using \`judges assign-findings\`\n5. **Track**: Monitor progress with \`judges burndown\`\n6. **Report**: Generate digests with \`judges digest\`\n\n`,
|
|
130
|
+
});
|
|
131
|
+
sections.push({
|
|
132
|
+
title: "Escalation Procedures",
|
|
133
|
+
content: `## Escalation Procedures\n\n| Severity | SLA | Action |\n|----------|-----|--------|\n| Critical | 4 hours | Notify security lead, create incident ticket |\n| High | 24 hours | Assign to code owner, block PR merge |\n| Medium | 1 week | Assign to team backlog |\n| Low | 1 sprint | Track in burndown |\n\n`,
|
|
134
|
+
});
|
|
135
|
+
sections.push({
|
|
136
|
+
title: "Metrics",
|
|
137
|
+
content: `## Key Metrics\n\n- **Mean Time to Remediate (MTTR)**: Track via \`judges sla-track\`\n- **False Positive Rate**: Tune via \`judges noise-advisor\`\n- **Coverage**: Monitor via \`judges coverage-map\`\n- **Team Score**: View via \`judges team-leaderboard\`\n- **Security Maturity**: Assess via \`judges security-maturity\`\n\n`,
|
|
138
|
+
});
|
|
139
|
+
return sections;
|
|
140
|
+
}
|
|
141
|
+
// ─── CLI ────────────────────────────────────────────────────────────────────
|
|
142
|
+
const STORE = ".judges-docs";
|
|
143
|
+
export function runDocGen(argv) {
|
|
144
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
145
|
+
console.log(`
|
|
146
|
+
judges doc-gen — Generate security documentation
|
|
147
|
+
|
|
148
|
+
Usage:
|
|
149
|
+
judges doc-gen --policy
|
|
150
|
+
judges doc-gen --remediation
|
|
151
|
+
judges doc-gen --playbook
|
|
152
|
+
judges doc-gen --all
|
|
153
|
+
|
|
154
|
+
Options:
|
|
155
|
+
--policy Generate security review policy document
|
|
156
|
+
--remediation Generate remediation guide
|
|
157
|
+
--playbook Generate team security playbook
|
|
158
|
+
--all Generate all documents
|
|
159
|
+
--output <dir> Output directory (default: .judges-docs)
|
|
160
|
+
--format json JSON output
|
|
161
|
+
--help, -h Show this help
|
|
162
|
+
`);
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
|
|
166
|
+
const outputDir = argv.find((_a, i) => argv[i - 1] === "--output") || STORE;
|
|
167
|
+
const genPolicy = argv.includes("--policy") || argv.includes("--all");
|
|
168
|
+
const genRemediation = argv.includes("--remediation") || argv.includes("--all");
|
|
169
|
+
const genPlaybook = argv.includes("--playbook") || argv.includes("--all");
|
|
170
|
+
if (!genPolicy && !genRemediation && !genPlaybook) {
|
|
171
|
+
console.log(" Specify --policy, --remediation, --playbook, or --all. Use --help for details.");
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
if (!existsSync(outputDir))
|
|
175
|
+
mkdirSync(outputDir, { recursive: true });
|
|
176
|
+
const generated = [];
|
|
177
|
+
if (genPolicy) {
|
|
178
|
+
const sections = generatePolicyDoc();
|
|
179
|
+
const content = sections.map((s) => s.content).join("\n");
|
|
180
|
+
const outPath = join(outputDir, "security-policy.md");
|
|
181
|
+
writeFileSync(outPath, content);
|
|
182
|
+
generated.push(outPath);
|
|
183
|
+
}
|
|
184
|
+
if (genRemediation) {
|
|
185
|
+
const sections = generateRemediationGuide();
|
|
186
|
+
const content = sections.map((s) => s.content).join("\n");
|
|
187
|
+
const outPath = join(outputDir, "remediation-guide.md");
|
|
188
|
+
writeFileSync(outPath, content);
|
|
189
|
+
generated.push(outPath);
|
|
190
|
+
}
|
|
191
|
+
if (genPlaybook) {
|
|
192
|
+
const sections = generateTeamPlaybook();
|
|
193
|
+
const content = sections.map((s) => s.content).join("\n");
|
|
194
|
+
const outPath = join(outputDir, "team-playbook.md");
|
|
195
|
+
writeFileSync(outPath, content);
|
|
196
|
+
generated.push(outPath);
|
|
197
|
+
}
|
|
198
|
+
if (format === "json") {
|
|
199
|
+
console.log(JSON.stringify({ generated, outputDir, timestamp: new Date().toISOString() }, null, 2));
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
console.log(`\n Documentation Generated\n ──────────────────────────`);
|
|
203
|
+
for (const g of generated) {
|
|
204
|
+
console.log(` ✅ ${g}`);
|
|
205
|
+
}
|
|
206
|
+
console.log(`\n Output directory: ${outputDir}\n`);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
//# sourceMappingURL=doc-gen.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doc-gen.js","sourceRoot":"","sources":["../../src/commands/doc-gen.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"judge-author.d.ts","sourceRoot":"","sources":["../../src/commands/judge-author.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA2JH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CA6InD"}
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom judge authoring toolkit — scaffolds, validates,
|
|
3
|
+
* and tests new judge definitions.
|
|
4
|
+
*
|
|
5
|
+
* All data stored locally.
|
|
6
|
+
*/
|
|
7
|
+
import { existsSync, readFileSync, mkdirSync, writeFileSync } from "fs";
|
|
8
|
+
import { join } from "path";
|
|
9
|
+
import { defaultRegistry } from "../judge-registry.js";
|
|
10
|
+
// ─── Scaffold ───────────────────────────────────────────────────────────────
|
|
11
|
+
function scaffoldJudge(id, opts) {
|
|
12
|
+
return {
|
|
13
|
+
id,
|
|
14
|
+
name: opts.name || id.replace(/-/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()),
|
|
15
|
+
description: `Custom judge: ${id}`,
|
|
16
|
+
category: opts.category || "custom",
|
|
17
|
+
severity: opts.severity || "medium",
|
|
18
|
+
rules: [
|
|
19
|
+
{
|
|
20
|
+
id: `${id}-001`,
|
|
21
|
+
pattern: "TODO: define pattern",
|
|
22
|
+
message: "TODO: describe what this rule detects",
|
|
23
|
+
severity: opts.severity || "medium",
|
|
24
|
+
},
|
|
25
|
+
],
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function generateJudgeFile(scaffold) {
|
|
29
|
+
return `/**
|
|
30
|
+
* ${scaffold.name}
|
|
31
|
+
*
|
|
32
|
+
* ${scaffold.description}
|
|
33
|
+
* Category: ${scaffold.category}
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
import type { Finding } from "../types.js";
|
|
37
|
+
|
|
38
|
+
export const judgeId = "${scaffold.id}";
|
|
39
|
+
export const judgeName = "${scaffold.name}";
|
|
40
|
+
export const judgeDescription = "${scaffold.description}";
|
|
41
|
+
export const judgeCategory = "${scaffold.category}";
|
|
42
|
+
|
|
43
|
+
interface Rule {
|
|
44
|
+
id: string;
|
|
45
|
+
pattern: RegExp;
|
|
46
|
+
message: string;
|
|
47
|
+
severity: string;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const rules: Rule[] = [
|
|
51
|
+
${scaffold.rules
|
|
52
|
+
.map((r) => ` {
|
|
53
|
+
id: "${r.id}",
|
|
54
|
+
pattern: /${r.pattern.replace(/\//g, "\\/")}/g,
|
|
55
|
+
message: "${r.message}",
|
|
56
|
+
severity: "${r.severity}",
|
|
57
|
+
},`)
|
|
58
|
+
.join("\n")}
|
|
59
|
+
];
|
|
60
|
+
|
|
61
|
+
export function evaluate(code: string, _filename: string): Finding[] {
|
|
62
|
+
const findings: Finding[] = [];
|
|
63
|
+
const lines = code.split("\\n");
|
|
64
|
+
|
|
65
|
+
for (const rule of rules) {
|
|
66
|
+
for (let i = 0; i < lines.length; i++) {
|
|
67
|
+
if (rule.pattern.test(lines[i])) {
|
|
68
|
+
findings.push({
|
|
69
|
+
ruleId: rule.id,
|
|
70
|
+
severity: rule.severity as Finding["severity"],
|
|
71
|
+
title: rule.message,
|
|
72
|
+
description: \`Detected by custom judge \${judgeId} at line \${i + 1}\`,
|
|
73
|
+
lineNumbers: [i + 1],
|
|
74
|
+
recommendation: "Review and fix the detected pattern",
|
|
75
|
+
});
|
|
76
|
+
rule.pattern.lastIndex = 0; // reset global regex
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return findings;
|
|
82
|
+
}
|
|
83
|
+
`;
|
|
84
|
+
}
|
|
85
|
+
// ─── Validation ─────────────────────────────────────────────────────────────
|
|
86
|
+
function validateJudge(path) {
|
|
87
|
+
const errors = [];
|
|
88
|
+
const warnings = [];
|
|
89
|
+
if (!existsSync(path)) {
|
|
90
|
+
return { valid: false, errors: [`File not found: ${path}`], warnings: [] };
|
|
91
|
+
}
|
|
92
|
+
let content;
|
|
93
|
+
try {
|
|
94
|
+
content = readFileSync(path, "utf-8");
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
return { valid: false, errors: [`Cannot read file: ${path}`], warnings: [] };
|
|
98
|
+
}
|
|
99
|
+
// Check for required exports
|
|
100
|
+
if (!content.includes("export const judgeId"))
|
|
101
|
+
errors.push("Missing 'export const judgeId'");
|
|
102
|
+
if (!content.includes("export const judgeName"))
|
|
103
|
+
errors.push("Missing 'export const judgeName'");
|
|
104
|
+
if (!content.includes("export function evaluate"))
|
|
105
|
+
errors.push("Missing 'export function evaluate'");
|
|
106
|
+
// Check for Finding type
|
|
107
|
+
if (!content.includes("Finding"))
|
|
108
|
+
warnings.push("No reference to Finding type — ensure findings match expected shape");
|
|
109
|
+
// Check for severity values
|
|
110
|
+
const validSeverities = ["critical", "high", "medium", "low", "info"];
|
|
111
|
+
const sevMatches = content.match(/severity:\s*["'](\w+)["']/g) || [];
|
|
112
|
+
for (const m of sevMatches) {
|
|
113
|
+
const val = m.match(/["'](\w+)["']/)?.[1];
|
|
114
|
+
if (val && !validSeverities.includes(val)) {
|
|
115
|
+
errors.push(`Invalid severity '${val}' — must be: ${validSeverities.join(", ")}`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
// Check for rule IDs
|
|
119
|
+
const ruleIds = content.match(/id:\s*["']([^"']+)["']/g) || [];
|
|
120
|
+
if (ruleIds.length === 0)
|
|
121
|
+
warnings.push("No rule IDs found — each rule should have a unique id");
|
|
122
|
+
return { valid: errors.length === 0, errors, warnings };
|
|
123
|
+
}
|
|
124
|
+
// ─── CLI ────────────────────────────────────────────────────────────────────
|
|
125
|
+
const STORE = ".judges-custom";
|
|
126
|
+
export function runJudgeAuthor(argv) {
|
|
127
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
128
|
+
console.log(`
|
|
129
|
+
judges judge-author — Custom judge authoring toolkit
|
|
130
|
+
|
|
131
|
+
Usage:
|
|
132
|
+
judges judge-author --scaffold <id>
|
|
133
|
+
judges judge-author --validate <file>
|
|
134
|
+
judges judge-author --list
|
|
135
|
+
judges judge-author --test <file> --code <sample>
|
|
136
|
+
|
|
137
|
+
Options:
|
|
138
|
+
--scaffold <id> Generate a new judge scaffold
|
|
139
|
+
--name <name> Judge display name
|
|
140
|
+
--category <cat> Category (default: custom)
|
|
141
|
+
--severity <sev> Default severity (default: medium)
|
|
142
|
+
--validate <file> Validate judge file structure
|
|
143
|
+
--list List existing custom judges
|
|
144
|
+
--test <file> Test a judge against sample code
|
|
145
|
+
--code <sample> Sample code file to test against
|
|
146
|
+
--output <dir> Output directory (default: .judges-custom)
|
|
147
|
+
--format json JSON output
|
|
148
|
+
--help, -h Show this help
|
|
149
|
+
`);
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
|
|
153
|
+
// List existing judges
|
|
154
|
+
if (argv.includes("--list")) {
|
|
155
|
+
const builtin = defaultRegistry.getJudges();
|
|
156
|
+
const customDir = STORE;
|
|
157
|
+
let customCount = 0;
|
|
158
|
+
if (existsSync(customDir)) {
|
|
159
|
+
try {
|
|
160
|
+
const { readdirSync } = require("fs");
|
|
161
|
+
customCount = readdirSync(customDir).filter((f) => f.endsWith(".ts") || f.endsWith(".json")).length;
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
/* skip */
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
if (format === "json") {
|
|
168
|
+
console.log(JSON.stringify({ builtin: builtin.length, custom: customCount, judges: builtin.map((j) => j.id) }, null, 2));
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
console.log(`\n Judges Registry\n ──────────────────────────`);
|
|
172
|
+
console.log(` Built-in: ${builtin.length}`);
|
|
173
|
+
console.log(` Custom: ${customCount}`);
|
|
174
|
+
console.log(`\n Built-in judges:`);
|
|
175
|
+
for (const j of builtin) {
|
|
176
|
+
console.log(` ${j.id}`);
|
|
177
|
+
}
|
|
178
|
+
console.log("");
|
|
179
|
+
}
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
// Scaffold
|
|
183
|
+
const scaffoldId = argv.find((_a, i) => argv[i - 1] === "--scaffold");
|
|
184
|
+
if (scaffoldId) {
|
|
185
|
+
const name = argv.find((_a, i) => argv[i - 1] === "--name");
|
|
186
|
+
const category = argv.find((_a, i) => argv[i - 1] === "--category");
|
|
187
|
+
const severity = argv.find((_a, i) => argv[i - 1] === "--severity");
|
|
188
|
+
const outputDir = argv.find((_a, i) => argv[i - 1] === "--output") || STORE;
|
|
189
|
+
const scaffold = scaffoldJudge(scaffoldId, {
|
|
190
|
+
name: name || undefined,
|
|
191
|
+
category: category || undefined,
|
|
192
|
+
severity: severity || undefined,
|
|
193
|
+
});
|
|
194
|
+
const code = generateJudgeFile(scaffold);
|
|
195
|
+
if (!existsSync(outputDir))
|
|
196
|
+
mkdirSync(outputDir, { recursive: true });
|
|
197
|
+
const outPath = join(outputDir, `${scaffoldId}.ts`);
|
|
198
|
+
writeFileSync(outPath, code);
|
|
199
|
+
// Also write the JSON definition
|
|
200
|
+
const jsonPath = join(outputDir, `${scaffoldId}.json`);
|
|
201
|
+
writeFileSync(jsonPath, JSON.stringify(scaffold, null, 2));
|
|
202
|
+
if (format === "json") {
|
|
203
|
+
console.log(JSON.stringify({ scaffold, files: [outPath, jsonPath] }, null, 2));
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
console.log(`\n Judge Scaffolded: ${scaffoldId}\n ──────────────────────────`);
|
|
207
|
+
console.log(` TypeScript: ${outPath}`);
|
|
208
|
+
console.log(` Definition: ${jsonPath}`);
|
|
209
|
+
console.log(`\n Next steps:`);
|
|
210
|
+
console.log(` 1. Edit ${outPath} to add detection patterns`);
|
|
211
|
+
console.log(` 2. Validate with: judges judge-author --validate ${outPath}`);
|
|
212
|
+
console.log(` 3. Test with: judges judge-author --test ${outPath} --code sample.ts\n`);
|
|
213
|
+
}
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
// Validate
|
|
217
|
+
const validatePath = argv.find((_a, i) => argv[i - 1] === "--validate");
|
|
218
|
+
if (validatePath) {
|
|
219
|
+
const result = validateJudge(validatePath);
|
|
220
|
+
if (format === "json") {
|
|
221
|
+
console.log(JSON.stringify(result, null, 2));
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
console.log(`\n Validation: ${validatePath}`);
|
|
225
|
+
console.log(` Status: ${result.valid ? "✅ Valid" : "❌ Invalid"}\n ──────────────────────────`);
|
|
226
|
+
for (const e of result.errors)
|
|
227
|
+
console.log(` ❌ ${e}`);
|
|
228
|
+
for (const w of result.warnings)
|
|
229
|
+
console.log(` ⚠️ ${w}`);
|
|
230
|
+
if (result.valid && result.warnings.length === 0)
|
|
231
|
+
console.log(` All checks passed`);
|
|
232
|
+
console.log("");
|
|
233
|
+
}
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
// Test
|
|
237
|
+
const testPath = argv.find((_a, i) => argv[i - 1] === "--test");
|
|
238
|
+
const codePath = argv.find((_a, i) => argv[i - 1] === "--code");
|
|
239
|
+
if (testPath) {
|
|
240
|
+
if (!codePath || !existsSync(codePath)) {
|
|
241
|
+
console.error(" Provide --code <file> with a sample code file to test against.");
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
// Validate first
|
|
245
|
+
const validation = validateJudge(testPath);
|
|
246
|
+
if (!validation.valid) {
|
|
247
|
+
console.error(" Judge file has validation errors. Fix errors before testing.");
|
|
248
|
+
for (const e of validation.errors)
|
|
249
|
+
console.error(` ❌ ${e}`);
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
console.log(`\n Testing ${testPath} against ${codePath}`);
|
|
253
|
+
console.log(` (Note: full testing requires loading the judge module at runtime)\n`);
|
|
254
|
+
console.log(` Validation: ✅ Passed`);
|
|
255
|
+
console.log(` Structure: ✅ Valid`);
|
|
256
|
+
console.log(`\n To run a full test, import and call the evaluate() function directly.\n`);
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
console.log(" Use --scaffold, --validate, --list, or --test. Run --help for details.");
|
|
260
|
+
}
|
|
261
|
+
//# sourceMappingURL=judge-author.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"judge-author.js","sourceRoot":"","sources":["../../src/commands/judge-author.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,IAAI,CAAC;AACxE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAwBvD,+EAA+E;AAE/E,SAAS,aAAa,CAAC,EAAU,EAAE,IAA6D;IAC9F,OAAO;QACL,EAAE;QACF,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;QACjF,WAAW,EAAE,iBAAiB,EAAE,EAAE;QAClC,QAAQ,EAAE,IAAI,CAAC,QAAQ,IAAI,QAAQ;QACnC,QAAQ,EAAE,IAAI,CAAC,QAAQ,IAAI,QAAQ;QACnC,KAAK,EAAE;YACL;gBACE,EAAE,EAAE,GAAG,EAAE,MAAM;gBACf,OAAO,EAAE,sBAAsB;gBAC/B,OAAO,EAAE,uCAAuC;gBAChD,QAAQ,EAAE,IAAI,CAAC,QAAQ,IAAI,QAAQ;aACpC;SACF;KACF,CAAC;AACJ,CAAC;AAED,SAAS,iBAAiB,CAAC,QAAuB;IAChD,OAAO;KACJ,QAAQ,CAAC,IAAI;;KAEb,QAAQ,CAAC,WAAW;eACV,QAAQ,CAAC,QAAQ;;;;;0BAKN,QAAQ,CAAC,EAAE;4BACT,QAAQ,CAAC,IAAI;mCACN,QAAQ,CAAC,WAAW;gCACvB,QAAQ,CAAC,QAAQ;;;;;;;;;;EAU/C,QAAQ,CAAC,KAAK;SACb,GAAG,CACF,CAAC,CAAC,EAAE,EAAE,CAAC;WACA,CAAC,CAAC,EAAE;gBACC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC;gBAC/B,CAAC,CAAC,OAAO;iBACR,CAAC,CAAC,QAAQ;KACtB,CACF;SACA,IAAI,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;CAyBZ,CAAC;AACF,CAAC;AAED,+EAA+E;AAE/E,SAAS,aAAa,CAAC,IAAY;IACjC,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,MAAM,QAAQ,GAAa,EAAE,CAAC;IAE9B,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACtB,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,mBAAmB,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;IAC7E,CAAC;IAED,IAAI,OAAe,CAAC;IACpB,IAAI,CAAC;QACH,OAAO,GAAG,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,qBAAqB,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;IAC/E,CAAC;IAED,6BAA6B;IAC7B,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAC;QAAE,MAAM,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAC;IAC7F,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAC;QAAE,MAAM,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC;IACjG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,0BAA0B,CAAC;QAAE,MAAM,CAAC,IAAI,CAAC,oCAAoC,CAAC,CAAC;IAErG,yBAAyB;IACzB,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC;QAC9B,QAAQ,CAAC,IAAI,CAAC,qEAAqE,CAAC,CAAC;IAEvF,4BAA4B;IAC5B,MAAM,eAAe,GAAG,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;IACtE,MAAM,UAAU,GAAG,OAAO,CAAC,KAAK,CAAC,4BAA4B,CAAC,IAAI,EAAE,CAAC;IACrE,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;QAC3B,MAAM,GAAG,GAAG,CAAC,CAAC,KAAK,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC1C,IAAI,GAAG,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAC1C,MAAM,CAAC,IAAI,CAAC,qBAAqB,GAAG,gBAAgB,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACpF,CAAC;IACH,CAAC;IAED,qBAAqB;IACrB,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,yBAAyB,CAAC,IAAI,EAAE,CAAC;IAC/D,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,QAAQ,CAAC,IAAI,CAAC,uDAAuD,CAAC,CAAC;IAEjG,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;AAC1D,CAAC;AAED,+EAA+E;AAE/E,MAAM,KAAK,GAAG,gBAAgB,CAAC;AAE/B,MAAM,UAAU,cAAc,CAAC,IAAc;IAC3C,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACnD,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;;CAqBf,CAAC,CAAC;QACC,OAAO;IACT,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,EAAU,EAAE,CAAS,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,UAAU,CAAC,IAAI,MAAM,CAAC;IAE1F,uBAAuB;IACvB,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC5B,MAAM,OAAO,GAAG,eAAe,CAAC,SAAS,EAAE,CAAC;QAC5C,MAAM,SAAS,GAAG,KAAK,CAAC;QACxB,IAAI,WAAW,GAAG,CAAC,CAAC;QAEpB,IAAI,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAC1B,IAAI,CAAC;gBACH,MAAM,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;gBACtC,WAAW,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC;YAC9G,CAAC;YAAC,MAAM,CAAC;gBACP,UAAU;YACZ,CAAC;QACH,CAAC;QAED,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;YACtB,OAAO,CAAC,GAAG,CACT,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAC5G,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,mDAAmD,CAAC,CAAC;YACjE,OAAO,CAAC,GAAG,CAAC,iBAAiB,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;YAC/C,OAAO,CAAC,GAAG,CAAC,iBAAiB,WAAW,EAAE,CAAC,CAAC;YAC5C,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;YACpC,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;gBACxB,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC7B,CAAC;YACD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAClB,CAAC;QACD,OAAO;IACT,CAAC;IAED,WAAW;IACX,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,EAAU,EAAE,CAAS,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,YAAY,CAAC,CAAC;IACtF,IAAI,UAAU,EAAE,CAAC;QACf,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,EAAU,EAAE,CAAS,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,QAAQ,CAAC,CAAC;QAC5E,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,EAAU,EAAE,CAAS,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,YAAY,CAAC,CAAC;QACpF,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,EAAU,EAAE,CAAS,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,YAAY,CAAC,CAAC;QACpF,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,EAAU,EAAE,CAAS,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,UAAU,CAAC,IAAI,KAAK,CAAC;QAE5F,MAAM,QAAQ,GAAG,aAAa,CAAC,UAAU,EAAE;YACzC,IAAI,EAAE,IAAI,IAAI,SAAS;YACvB,QAAQ,EAAE,QAAQ,IAAI,SAAS;YAC/B,QAAQ,EAAE,QAAQ,IAAI,SAAS;SAChC,CAAC,CAAC;QACH,MAAM,IAAI,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAC;QAEzC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;YAAE,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACtE,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,EAAE,GAAG,UAAU,KAAK,CAAC,CAAC;QACpD,aAAa,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QAE7B,iCAAiC;QACjC,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,EAAE,GAAG,UAAU,OAAO,CAAC,CAAC;QACvD,aAAa,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAE3D,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;YACtB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,OAAO,EAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QACjF,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,yBAAyB,UAAU,gCAAgC,CAAC,CAAC;YACjF,OAAO,CAAC,GAAG,CAAC,mBAAmB,OAAO,EAAE,CAAC,CAAC;YAC1C,OAAO,CAAC,GAAG,CAAC,mBAAmB,QAAQ,EAAE,CAAC,CAAC;YAC3C,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;YAC/B,OAAO,CAAC,GAAG,CAAC,eAAe,OAAO,4BAA4B,CAAC,CAAC;YAChE,OAAO,CAAC,GAAG,CAAC,wDAAwD,OAAO,EAAE,CAAC,CAAC;YAC/E,OAAO,CAAC,GAAG,CAAC,gDAAgD,OAAO,qBAAqB,CAAC,CAAC;QAC5F,CAAC;QACD,OAAO;IACT,CAAC;IAED,WAAW;IACX,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,EAAU,EAAE,CAAS,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,YAAY,CAAC,CAAC;IACxF,IAAI,YAAY,EAAE,CAAC;QACjB,MAAM,MAAM,GAAG,aAAa,CAAC,YAAY,CAAC,CAAC;QAE3C,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;YACtB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAC/C,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,mBAAmB,YAAY,EAAE,CAAC,CAAC;YAC/C,OAAO,CAAC,GAAG,CAAC,aAAa,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,gCAAgC,CAAC,CAAC;YACjG,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM;gBAAE,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;YACzD,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,QAAQ;gBAAE,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;YAC7D,IAAI,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;YACvF,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAClB,CAAC;QACD,OAAO;IACT,CAAC;IAED,OAAO;IACP,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,EAAU,EAAE,CAAS,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,QAAQ,CAAC,CAAC;IAChF,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,EAAU,EAAE,CAAS,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,QAAQ,CAAC,CAAC;IAChF,IAAI,QAAQ,EAAE,CAAC;QACb,IAAI,CAAC,QAAQ,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YACvC,OAAO,CAAC,KAAK,CAAC,kEAAkE,CAAC,CAAC;YAClF,OAAO;QACT,CAAC;QACD,iBAAiB;QACjB,MAAM,UAAU,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;QAC3C,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;YACtB,OAAO,CAAC,KAAK,CAAC,gEAAgE,CAAC,CAAC;YAChF,KAAK,MAAM,CAAC,IAAI,UAAU,CAAC,MAAM;gBAAE,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;YAC/D,OAAO;QACT,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,eAAe,QAAQ,YAAY,QAAQ,EAAE,CAAC,CAAC;QAC3D,OAAO,CAAC,GAAG,CAAC,uEAAuE,CAAC,CAAC;QACrF,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC;QACtC,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;QACrC,OAAO,CAAC,GAAG,CAAC,6EAA6E,CAAC,CAAC;QAC3F,OAAO;IACT,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,0EAA0E,CAAC,CAAC;AAC1F,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pattern registry — team knowledge sharing via a local
|
|
3
|
+
* repository of security patterns and anti-patterns.
|
|
4
|
+
*
|
|
5
|
+
* All data stays in .judges-patterns/ directory.
|
|
6
|
+
*/
|
|
7
|
+
interface SecurityPattern {
|
|
8
|
+
id: string;
|
|
9
|
+
title: string;
|
|
10
|
+
category: string;
|
|
11
|
+
type: "pattern" | "anti-pattern";
|
|
12
|
+
language: string;
|
|
13
|
+
description: string;
|
|
14
|
+
example: string;
|
|
15
|
+
fix?: string;
|
|
16
|
+
author: string;
|
|
17
|
+
tags: string[];
|
|
18
|
+
createdAt: string;
|
|
19
|
+
}
|
|
20
|
+
export declare function addPattern(pattern: Omit<SecurityPattern, "id" | "createdAt">): SecurityPattern;
|
|
21
|
+
export declare function runPatternRegistry(argv: string[]): void;
|
|
22
|
+
export {};
|
|
23
|
+
//# sourceMappingURL=pattern-registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pattern-registry.d.ts","sourceRoot":"","sources":["../../src/commands/pattern-registry.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH,UAAU,eAAe;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,SAAS,GAAG,cAAc,CAAC;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB;AAsFD,wBAAgB,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,eAAe,EAAE,IAAI,GAAG,WAAW,CAAC,GAAG,eAAe,CAU9F;AAID,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAoIvD"}
|