@aicqtools/guardrail 1.0.0-alpha.5 → 1.0.0-alpha.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/matcher/yaml-rule.d.ts +5 -2
- package/dist/matcher/yaml-rule.d.ts.map +1 -1
- package/dist/matcher/yaml-rule.js +7 -5
- package/dist/matcher/yaml-rule.js.map +1 -1
- package/dist/rules-default/no-direct-anthropic.yaml +6 -0
- package/dist/rules-default/no-direct-openai.yaml +8 -0
- package/dist/rules-default/no-magic-number.d.ts.map +1 -1
- package/dist/rules-default/no-magic-number.js +109 -9
- package/dist/rules-default/no-magic-number.js.map +1 -1
- package/dist/rules-default/no-process-env-leak.d.ts.map +1 -1
- package/dist/rules-default/no-process-env-leak.js +5 -2
- package/dist/rules-default/no-process-env-leak.js.map +1 -1
- package/dist/runner/apply-rule-config.d.ts +26 -0
- package/dist/runner/apply-rule-config.d.ts.map +1 -0
- package/dist/runner/apply-rule-config.js +52 -0
- package/dist/runner/apply-rule-config.js.map +1 -0
- package/dist/runner/index.d.ts +3 -1
- package/dist/runner/index.d.ts.map +1 -1
- package/dist/runner/index.js +2 -1
- package/dist/runner/index.js.map +1 -1
- package/dist/runner/run-file.d.ts.map +1 -1
- package/dist/runner/run-file.js +13 -1
- package/dist/runner/run-file.js.map +1 -1
- package/dist/runner/run-project.d.ts +12 -0
- package/dist/runner/run-project.d.ts.map +1 -1
- package/dist/runner/run-project.js +40 -2
- package/dist/runner/run-project.js.map +1 -1
- package/dist/runner/run-rule.d.ts.map +1 -1
- package/dist/runner/run-rule.js +17 -0
- package/dist/runner/run-rule.js.map +1 -1
- package/dist/runner/suppressions.d.ts +37 -0
- package/dist/runner/suppressions.d.ts.map +1 -0
- package/dist/runner/suppressions.js +127 -0
- package/dist/runner/suppressions.js.map +1 -0
- package/dist/suggest/analyze.d.ts +10 -0
- package/dist/suggest/analyze.d.ts.map +1 -0
- package/dist/suggest/analyze.js +193 -0
- package/dist/suggest/analyze.js.map +1 -0
- package/dist/suggest/format.d.ts +13 -0
- package/dist/suggest/format.d.ts.map +1 -0
- package/dist/suggest/format.js +120 -0
- package/dist/suggest/format.js.map +1 -0
- package/dist/suggest/index.d.ts +5 -0
- package/dist/suggest/index.d.ts.map +1 -0
- package/dist/suggest/index.js +4 -0
- package/dist/suggest/index.js.map +1 -0
- package/dist/suggest/mine.d.ts +11 -0
- package/dist/suggest/mine.d.ts.map +1 -0
- package/dist/suggest/mine.js +207 -0
- package/dist/suggest/mine.js.map +1 -0
- package/dist/suggest/types.d.ts +74 -0
- package/dist/suggest/types.d.ts.map +1 -0
- package/dist/suggest/types.js +2 -0
- package/dist/suggest/types.js.map +1 -0
- package/package.json +5 -3
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import fastGlob from 'fast-glob';
|
|
3
|
+
import Parser from 'tree-sitter';
|
|
4
|
+
import { detectLanguage, loadLanguage, parseSource } from '@aicqtools/core';
|
|
5
|
+
import { traverse } from '../matcher/traverse.js';
|
|
6
|
+
import { resolveIgnores } from '../runner/run-project.js';
|
|
7
|
+
const DEFAULT_MIN_COUNT = 5;
|
|
8
|
+
const DEFAULT_TOP = 10;
|
|
9
|
+
const MAX_FILES = 5000;
|
|
10
|
+
const MAX_SAMPLES = 2;
|
|
11
|
+
const IDENTIFIER_RE = /^[A-Za-z_$][\w$]*$/;
|
|
12
|
+
/**
|
|
13
|
+
* Common stdlib / global names whose `new X()` and `X.method()` invocations are universal
|
|
14
|
+
* patterns — they would generate noisy, useless draft rules ("don't construct Map", "don't
|
|
15
|
+
* call JSON.parse"). Dropping them keeps `--patterns` output focused on genuinely
|
|
16
|
+
* project-specific shapes.
|
|
17
|
+
*/
|
|
18
|
+
const STDLIB_BLOCKLIST = new Set([
|
|
19
|
+
'Array', 'Object', 'Map', 'Set', 'WeakMap', 'WeakSet', 'Date', 'Promise', 'RegExp',
|
|
20
|
+
'Error', 'TypeError', 'RangeError', 'SyntaxError',
|
|
21
|
+
'JSON', 'console', 'Math', 'process', 'Buffer', 'Symbol', 'Number', 'String', 'Boolean',
|
|
22
|
+
'Function', 'URL', 'URLSearchParams',
|
|
23
|
+
]);
|
|
24
|
+
/**
|
|
25
|
+
* Approach B (early prototype) — mine the AST for frequently-occurring
|
|
26
|
+
* `new X(...)` / `obj.method(...)` shapes and turn the top ones into draft
|
|
27
|
+
* tree-sitter pattern rules. `severity` is conservatively `info` and the
|
|
28
|
+
* `message`/`messageKo` are TODO placeholders — these are seeds a human edits,
|
|
29
|
+
* not finished rules. Every generated query is compiled against the language
|
|
30
|
+
* grammar before it is emitted; ones that don't compile are dropped.
|
|
31
|
+
*/
|
|
32
|
+
export async function minePatterns(opts) {
|
|
33
|
+
const minCount = Math.max(1, opts.minCount ?? DEFAULT_MIN_COUNT);
|
|
34
|
+
const top = Math.max(1, opts.top ?? DEFAULT_TOP);
|
|
35
|
+
const ignore = await resolveIgnores(opts.cwd, opts.exclude, opts.respectGitignore ?? false);
|
|
36
|
+
const files = (await fastGlob([...opts.include], {
|
|
37
|
+
cwd: opts.cwd,
|
|
38
|
+
ignore,
|
|
39
|
+
absolute: true,
|
|
40
|
+
onlyFiles: true,
|
|
41
|
+
dot: false,
|
|
42
|
+
})).slice(0, MAX_FILES);
|
|
43
|
+
const buckets = new Map();
|
|
44
|
+
for (const file of files) {
|
|
45
|
+
const language = detectLanguage(file);
|
|
46
|
+
if (!language)
|
|
47
|
+
continue;
|
|
48
|
+
let tree;
|
|
49
|
+
let source;
|
|
50
|
+
try {
|
|
51
|
+
source = await readFile(file, 'utf-8');
|
|
52
|
+
tree = parseSource(language, source);
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
continue; // per-file isolation — a broken file must not abort mining
|
|
56
|
+
}
|
|
57
|
+
const textOf = (node) => source.slice(node.startIndex, node.endIndex);
|
|
58
|
+
try {
|
|
59
|
+
traverse(tree.rootNode, (node) => {
|
|
60
|
+
const sig = extractSignature(node, language, textOf);
|
|
61
|
+
if (!sig)
|
|
62
|
+
return;
|
|
63
|
+
const key = `${language}::${sig.signature}`;
|
|
64
|
+
let bucket = buckets.get(key);
|
|
65
|
+
if (!bucket) {
|
|
66
|
+
bucket = {
|
|
67
|
+
signature: sig.signature,
|
|
68
|
+
language,
|
|
69
|
+
kind: sig.kind,
|
|
70
|
+
parts: sig.parts,
|
|
71
|
+
count: 0,
|
|
72
|
+
files: new Set(),
|
|
73
|
+
samples: [],
|
|
74
|
+
};
|
|
75
|
+
buckets.set(key, bucket);
|
|
76
|
+
}
|
|
77
|
+
bucket.count += 1;
|
|
78
|
+
bucket.files.add(file);
|
|
79
|
+
if (bucket.samples.length < MAX_SAMPLES) {
|
|
80
|
+
bucket.samples.push({
|
|
81
|
+
file,
|
|
82
|
+
line: node.startPosition.row + 1,
|
|
83
|
+
column: node.startPosition.column + 1,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
const candidates = [...buckets.values()]
|
|
93
|
+
.filter((b) => b.count >= minCount)
|
|
94
|
+
.sort((a, b) => b.count - a.count || a.signature.localeCompare(b.signature));
|
|
95
|
+
const drafts = [];
|
|
96
|
+
for (const bucket of candidates) {
|
|
97
|
+
if (drafts.length >= top)
|
|
98
|
+
break;
|
|
99
|
+
const query = buildQuery(bucket);
|
|
100
|
+
if (!query || !queryCompiles(query, bucket.language))
|
|
101
|
+
continue;
|
|
102
|
+
drafts.push(makeDraft(bucket, query));
|
|
103
|
+
}
|
|
104
|
+
return drafts;
|
|
105
|
+
}
|
|
106
|
+
function extractSignature(node, language, textOf) {
|
|
107
|
+
if (language === 'python') {
|
|
108
|
+
if (node.type !== 'call')
|
|
109
|
+
return null;
|
|
110
|
+
const fn = node.childForFieldName('function');
|
|
111
|
+
if (!fn || fn.type !== 'attribute')
|
|
112
|
+
return null;
|
|
113
|
+
const obj = fn.childForFieldName('object');
|
|
114
|
+
const attr = fn.childForFieldName('attribute');
|
|
115
|
+
if (!obj || obj.type !== 'identifier' || !attr || attr.type !== 'identifier')
|
|
116
|
+
return null;
|
|
117
|
+
const o = textOf(obj);
|
|
118
|
+
const a = textOf(attr);
|
|
119
|
+
if (!IDENTIFIER_RE.test(o) || !IDENTIFIER_RE.test(a))
|
|
120
|
+
return null;
|
|
121
|
+
if (STDLIB_BLOCKLIST.has(o))
|
|
122
|
+
return null;
|
|
123
|
+
return { signature: `call:${o}.${a}`, kind: 'call', parts: [o, a] };
|
|
124
|
+
}
|
|
125
|
+
// typescript / tsx / javascript
|
|
126
|
+
if (node.type === 'new_expression') {
|
|
127
|
+
const ctor = node.childForFieldName('constructor');
|
|
128
|
+
if (!ctor || ctor.type !== 'identifier')
|
|
129
|
+
return null;
|
|
130
|
+
const name = textOf(ctor);
|
|
131
|
+
if (!IDENTIFIER_RE.test(name))
|
|
132
|
+
return null;
|
|
133
|
+
if (STDLIB_BLOCKLIST.has(name))
|
|
134
|
+
return null;
|
|
135
|
+
return { signature: `new:${name}`, kind: 'new', parts: [name] };
|
|
136
|
+
}
|
|
137
|
+
if (node.type === 'call_expression') {
|
|
138
|
+
const fn = node.childForFieldName('function');
|
|
139
|
+
if (!fn || fn.type !== 'member_expression')
|
|
140
|
+
return null;
|
|
141
|
+
const obj = fn.childForFieldName('object');
|
|
142
|
+
const prop = fn.childForFieldName('property');
|
|
143
|
+
if (!obj || obj.type !== 'identifier' || !prop || prop.type !== 'property_identifier')
|
|
144
|
+
return null;
|
|
145
|
+
const o = textOf(obj);
|
|
146
|
+
const p = textOf(prop);
|
|
147
|
+
if (!IDENTIFIER_RE.test(o) || !IDENTIFIER_RE.test(p))
|
|
148
|
+
return null;
|
|
149
|
+
if (STDLIB_BLOCKLIST.has(o))
|
|
150
|
+
return null;
|
|
151
|
+
return { signature: `call:${o}.${p}`, kind: 'call', parts: [o, p] };
|
|
152
|
+
}
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
function buildQuery(bucket) {
|
|
156
|
+
if (bucket.kind === 'new') {
|
|
157
|
+
const name = bucket.parts[0];
|
|
158
|
+
if (!name)
|
|
159
|
+
return null;
|
|
160
|
+
return `(new_expression\n constructor: (identifier) @ctor\n (#eq? @ctor "${name}"))`;
|
|
161
|
+
}
|
|
162
|
+
const [obj, prop] = bucket.parts;
|
|
163
|
+
if (!obj || !prop)
|
|
164
|
+
return null;
|
|
165
|
+
if (bucket.language === 'python') {
|
|
166
|
+
return (`(call\n` +
|
|
167
|
+
` function: (attribute\n` +
|
|
168
|
+
` object: (identifier) @obj\n` +
|
|
169
|
+
` attribute: (identifier) @attr)\n` +
|
|
170
|
+
` (#eq? @obj "${obj}")\n` +
|
|
171
|
+
` (#eq? @attr "${prop}"))`);
|
|
172
|
+
}
|
|
173
|
+
return (`(call_expression\n` +
|
|
174
|
+
` function: (member_expression\n` +
|
|
175
|
+
` object: (identifier) @obj\n` +
|
|
176
|
+
` property: (property_identifier) @prop)\n` +
|
|
177
|
+
` (#eq? @obj "${obj}")\n` +
|
|
178
|
+
` (#eq? @prop "${prop}"))`);
|
|
179
|
+
}
|
|
180
|
+
function queryCompiles(query, language) {
|
|
181
|
+
try {
|
|
182
|
+
// eslint-disable-next-line no-new
|
|
183
|
+
new Parser.Query(loadLanguage(language), query);
|
|
184
|
+
return true;
|
|
185
|
+
}
|
|
186
|
+
catch {
|
|
187
|
+
return false;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
function makeDraft(bucket, query) {
|
|
191
|
+
const slug = bucket.signature
|
|
192
|
+
.toLowerCase()
|
|
193
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
194
|
+
.replace(/^-+|-+$/g, '');
|
|
195
|
+
const filesN = bucket.files.size;
|
|
196
|
+
const fileWord = (n, en) => (en ? `file${n === 1 ? '' : 's'}` : '개');
|
|
197
|
+
return {
|
|
198
|
+
id: `suggested-${slug}`,
|
|
199
|
+
language: bucket.language,
|
|
200
|
+
severity: 'info',
|
|
201
|
+
message: `TODO: explain why \`${bucket.signature}\` warrants a project rule — auto-suggested, ${bucket.count} occurrences across ${filesN} ${fileWord(filesN, true)}.`,
|
|
202
|
+
messageKo: `TODO: \`${bucket.signature}\` 사용을 프로젝트 룰로 만들 이유를 설명하세요 — 자동 제안, 파일 ${filesN}${fileWord(filesN, false)}에서 ${bucket.count}회.`,
|
|
203
|
+
query,
|
|
204
|
+
meta: { count: bucket.count, files: filesN, sampleLocations: bucket.samples },
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
//# sourceMappingURL=mine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mine.js","sourceRoot":"","sources":["../../src/suggest/mine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { FileCache, Language, Severity } from '@aicqtools/core';
|
|
2
|
+
import type { Rule } from '@aicqtools/rule-sdk';
|
|
3
|
+
export interface SuggestSampleLocation {
|
|
4
|
+
readonly file: string;
|
|
5
|
+
readonly line: number;
|
|
6
|
+
readonly column: number;
|
|
7
|
+
}
|
|
8
|
+
export interface RuleSuggestion {
|
|
9
|
+
readonly ruleId: string;
|
|
10
|
+
readonly hits: number;
|
|
11
|
+
readonly severity: Severity;
|
|
12
|
+
readonly message: string;
|
|
13
|
+
readonly messageKo?: string;
|
|
14
|
+
readonly docs?: string;
|
|
15
|
+
readonly sampleLocations: readonly SuggestSampleLocation[];
|
|
16
|
+
readonly stackMatch?: boolean;
|
|
17
|
+
/**
|
|
18
|
+
* True when this rule is highly likely to dominate noise budgets in the suggested config:
|
|
19
|
+
* either it has substantially more hits than the next rule in the ranking, or it's an
|
|
20
|
+
* info-severity rule whose hit count exceeds the absolute "obviously noisy" threshold.
|
|
21
|
+
* Computed by `analyzeRepo`; consumed by both the text reporter (for a flag) and the
|
|
22
|
+
* YAML config-snippet builder (to emit such rules as commented-out lines).
|
|
23
|
+
*/
|
|
24
|
+
readonly noisy?: boolean;
|
|
25
|
+
}
|
|
26
|
+
export type DependencySource = 'package.json' | 'requirements.txt';
|
|
27
|
+
export interface DetectedDependency {
|
|
28
|
+
readonly name: string;
|
|
29
|
+
readonly source: DependencySource;
|
|
30
|
+
}
|
|
31
|
+
export interface PatternRuleDraft {
|
|
32
|
+
readonly id: string;
|
|
33
|
+
readonly language: Language;
|
|
34
|
+
readonly severity: 'info';
|
|
35
|
+
readonly message: string;
|
|
36
|
+
readonly messageKo: string;
|
|
37
|
+
readonly query: string;
|
|
38
|
+
readonly meta: {
|
|
39
|
+
readonly count: number;
|
|
40
|
+
readonly files: number;
|
|
41
|
+
readonly sampleLocations: readonly SuggestSampleLocation[];
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
export interface RuleSuggestionReport {
|
|
45
|
+
readonly filesScanned: number;
|
|
46
|
+
readonly languagesPresent: readonly Language[];
|
|
47
|
+
readonly durationMs: number;
|
|
48
|
+
readonly suggestions: readonly RuleSuggestion[];
|
|
49
|
+
readonly detectedDependencies: readonly DetectedDependency[];
|
|
50
|
+
/** A paste-ready `aicq.config.yaml` fragment that enables the suggested rules. */
|
|
51
|
+
readonly configSnippet: string;
|
|
52
|
+
readonly patternDrafts?: readonly PatternRuleDraft[];
|
|
53
|
+
}
|
|
54
|
+
export interface AnalyzeRepoOptions {
|
|
55
|
+
readonly cwd: string;
|
|
56
|
+
readonly include: readonly string[];
|
|
57
|
+
readonly exclude: readonly string[];
|
|
58
|
+
readonly rules: readonly Rule[];
|
|
59
|
+
readonly cache?: FileCache;
|
|
60
|
+
readonly top?: number;
|
|
61
|
+
readonly minHits?: number;
|
|
62
|
+
/** Mirror of `AicqConfig.respectGitignore`. Default false. */
|
|
63
|
+
readonly respectGitignore?: boolean;
|
|
64
|
+
}
|
|
65
|
+
export interface MinePatternsOptions {
|
|
66
|
+
readonly cwd: string;
|
|
67
|
+
readonly include: readonly string[];
|
|
68
|
+
readonly exclude: readonly string[];
|
|
69
|
+
readonly minCount?: number;
|
|
70
|
+
readonly top?: number;
|
|
71
|
+
/** Mirror of `AicqConfig.respectGitignore`. Default false. */
|
|
72
|
+
readonly respectGitignore?: boolean;
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/suggest/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/suggest/types.ts"],"names":[],"mappings":""}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aicqtools/guardrail",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.7",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Deterministic AI code guardrail engine — 37 built-in rules, hybrid YAML/function DSL, MCP server, .cursorrules sync, sqlite cache.",
|
|
6
6
|
"keywords": [
|
|
@@ -42,10 +42,11 @@
|
|
|
42
42
|
"dependencies": {
|
|
43
43
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
44
44
|
"fast-glob": "^3.3.2",
|
|
45
|
+
"micromatch": "^4.0.8",
|
|
45
46
|
"yaml": "^2.6.1",
|
|
46
47
|
"zod": "^3.23.8",
|
|
47
|
-
"@aicqtools/core": "1.0.0-alpha.
|
|
48
|
-
"@aicqtools/rule-sdk": "1.0.0-alpha.
|
|
48
|
+
"@aicqtools/core": "1.0.0-alpha.7",
|
|
49
|
+
"@aicqtools/rule-sdk": "1.0.0-alpha.7"
|
|
49
50
|
},
|
|
50
51
|
"peerDependencies": {
|
|
51
52
|
"tree-sitter": "~0.22.4"
|
|
@@ -56,6 +57,7 @@
|
|
|
56
57
|
}
|
|
57
58
|
},
|
|
58
59
|
"devDependencies": {
|
|
60
|
+
"@types/micromatch": "^4.0.9",
|
|
59
61
|
"@types/node": "^22.10.0",
|
|
60
62
|
"typescript": "^5.7.2",
|
|
61
63
|
"vitest": "^2.1.8"
|