@aicqtools/guardrail 1.0.0-alpha.11 → 1.0.0-alpha.16
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/docs/render-rule-md.d.ts.map +1 -1
- package/dist/docs/render-rule-md.js +80 -0
- package/dist/docs/render-rule-md.js.map +1 -1
- package/dist/rules-default/camelcase-migration-column.d.ts.map +1 -1
- package/dist/rules-default/camelcase-migration-column.js +26 -2
- package/dist/rules-default/camelcase-migration-column.js.map +1 -1
- package/dist/rules-default/mask-pii-in-ai-prompt.d.ts.map +1 -1
- package/dist/rules-default/mask-pii-in-ai-prompt.js +44 -7
- package/dist/rules-default/mask-pii-in-ai-prompt.js.map +1 -1
- package/dist/rules-default/no-console-log.d.ts +6 -0
- package/dist/rules-default/no-console-log.d.ts.map +1 -1
- package/dist/rules-default/no-console-log.js +24 -3
- package/dist/rules-default/no-console-log.js.map +1 -1
- package/dist/rules-default/no-empty-catch.d.ts +15 -0
- package/dist/rules-default/no-empty-catch.d.ts.map +1 -1
- package/dist/rules-default/no-empty-catch.js +44 -3
- package/dist/rules-default/no-empty-catch.js.map +1 -1
- package/dist/rules-default/no-fstring-sql.d.ts.map +1 -1
- package/dist/rules-default/no-fstring-sql.js +51 -2
- package/dist/rules-default/no-fstring-sql.js.map +1 -1
- package/dist/rules-default/no-magic-number.d.ts +1 -0
- package/dist/rules-default/no-magic-number.d.ts.map +1 -1
- package/dist/rules-default/no-magic-number.js +26 -5
- package/dist/rules-default/no-magic-number.js.map +1 -1
- package/dist/runner/apply-rule-config.d.ts +43 -12
- package/dist/runner/apply-rule-config.d.ts.map +1 -1
- package/dist/runner/apply-rule-config.js +115 -41
- package/dist/runner/apply-rule-config.js.map +1 -1
- package/dist/runner/context.d.ts +7 -0
- package/dist/runner/context.d.ts.map +1 -1
- package/dist/runner/context.js +2 -0
- package/dist/runner/context.js.map +1 -1
- package/dist/runner/index.d.ts +4 -2
- 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/resolve-rule-options.d.ts +28 -0
- package/dist/runner/resolve-rule-options.d.ts.map +1 -0
- package/dist/runner/resolve-rule-options.js +27 -0
- package/dist/runner/resolve-rule-options.js.map +1 -0
- package/dist/runner/run-file.d.ts +10 -2
- package/dist/runner/run-file.d.ts.map +1 -1
- package/dist/runner/run-file.js +14 -4
- package/dist/runner/run-file.js.map +1 -1
- package/dist/runner/run-project.d.ts +14 -0
- package/dist/runner/run-project.d.ts.map +1 -1
- package/dist/runner/run-project.js +22 -5
- package/dist/runner/run-project.js.map +1 -1
- package/dist/suggest/analyze.js +3 -0
- package/dist/suggest/analyze.js.map +1 -1
- package/dist/suggest/format.d.ts.map +1 -1
- package/dist/suggest/format.js +9 -0
- package/dist/suggest/format.js.map +1 -1
- package/dist/suggest/types.d.ts +7 -0
- package/dist/suggest/types.d.ts.map +1 -1
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render-rule-md.d.ts","sourceRoot":"","sources":["../../src/docs/render-rule-md.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"render-rule-md.d.ts","sourceRoot":"","sources":["../../src/docs/render-rule-md.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAuHhD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,GAAG,IAAI,GAAG,MAAM,CAwF1E;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,EAAE,MAAM,EAAE,IAAI,GAAG,IAAI,GAAG,MAAM,CAYpF"}
|
|
@@ -17,6 +17,84 @@ function ruleKindLabel(rule, locale) {
|
|
|
17
17
|
return locale === 'ko' ? 'YAML 패턴' : 'YAML pattern';
|
|
18
18
|
return locale === 'ko' ? 'JS/TS 함수' : 'JS/TS function';
|
|
19
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* Alpha.14 — render the rule's `options` zod schema as a markdown table. Best-effort
|
|
22
|
+
* introspection: works for `z.object({ key: z.array(z.string()).default(...) })` shapes and
|
|
23
|
+
* similar. Anything we can't introspect cleanly falls back to "see source for shape".
|
|
24
|
+
*/
|
|
25
|
+
function describeZodType(schema) {
|
|
26
|
+
const def = schema._def;
|
|
27
|
+
switch (def?.typeName) {
|
|
28
|
+
case 'ZodString':
|
|
29
|
+
return 'string';
|
|
30
|
+
case 'ZodNumber':
|
|
31
|
+
return 'number';
|
|
32
|
+
case 'ZodBoolean':
|
|
33
|
+
return 'boolean';
|
|
34
|
+
case 'ZodArray': {
|
|
35
|
+
const inner = def.type;
|
|
36
|
+
return inner ? `array<${describeZodType(inner)}>` : 'array';
|
|
37
|
+
}
|
|
38
|
+
case 'ZodDefault': {
|
|
39
|
+
const inner = def.innerType;
|
|
40
|
+
return inner ? describeZodType(inner) : 'unknown';
|
|
41
|
+
}
|
|
42
|
+
case 'ZodOptional': {
|
|
43
|
+
const inner = def.innerType;
|
|
44
|
+
return inner ? `${describeZodType(inner)}?` : 'unknown?';
|
|
45
|
+
}
|
|
46
|
+
case 'ZodEnum': {
|
|
47
|
+
const values = def.values;
|
|
48
|
+
return values ? values.map((v) => `'${v}'`).join(' | ') : 'enum';
|
|
49
|
+
}
|
|
50
|
+
case 'ZodUnion':
|
|
51
|
+
return 'union';
|
|
52
|
+
case 'ZodObject':
|
|
53
|
+
return 'object';
|
|
54
|
+
default:
|
|
55
|
+
return 'unknown';
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function renderOptionsTable(schema, defaults, locale) {
|
|
59
|
+
const def = schema._def;
|
|
60
|
+
if (def?.typeName !== 'ZodObject' || typeof def.shape !== 'function') {
|
|
61
|
+
return locale === 'ko' ? '_옵션 스키마 구조 확인은 룰 소스를 참고하세요._' : '_See rule source for option schema shape._';
|
|
62
|
+
}
|
|
63
|
+
const shape = def.shape();
|
|
64
|
+
const keys = Object.keys(shape);
|
|
65
|
+
if (keys.length === 0)
|
|
66
|
+
return null;
|
|
67
|
+
const header = locale === 'ko'
|
|
68
|
+
? '| 키 | 타입 | 기본값 |\n|----|------|--------|'
|
|
69
|
+
: '| Key | Type | Default |\n|-----|------|---------|';
|
|
70
|
+
const rows = keys.map((key) => {
|
|
71
|
+
const fieldSchema = shape[key];
|
|
72
|
+
const type = describeZodType(fieldSchema);
|
|
73
|
+
const def = defaults[key];
|
|
74
|
+
const defaultStr = def === undefined ? '—' : '`' + JSON.stringify(def) + '`';
|
|
75
|
+
return `| \`${key}\` | \`${type}\` | ${defaultStr} |`;
|
|
76
|
+
});
|
|
77
|
+
return [header, ...rows].join('\n');
|
|
78
|
+
}
|
|
79
|
+
function renderOptionsSection(rule, locale) {
|
|
80
|
+
if (!rule.options)
|
|
81
|
+
return [];
|
|
82
|
+
const heading = locale === 'ko' ? '## 옵션 (alpha.14)' : '## Options (alpha.14)';
|
|
83
|
+
const intro = locale === 'ko'
|
|
84
|
+
? '`aicq.config.yaml`에서 `rules.<룰 id>.options`로 재정의 가능. 잘못된 키/타입은 stderr 경고 후 기본값으로 복귀.'
|
|
85
|
+
: 'Override under `rules.<rule id>.options` in `aicq.config.yaml`. Invalid keys/types trigger a stderr warning and fall back to defaults.';
|
|
86
|
+
const table = renderOptionsTable(rule.options.schema, rule.options.defaults, locale);
|
|
87
|
+
const lines = [heading, '', intro, ''];
|
|
88
|
+
if (table)
|
|
89
|
+
lines.push(table, '');
|
|
90
|
+
const example = locale === 'ko' ? '예시:' : 'Example:';
|
|
91
|
+
lines.push(example, '', '```yaml', 'modules:', ' guardrail:', ' rules:', ` ${rule.id}:`, ' options:');
|
|
92
|
+
for (const [k, v] of Object.entries(rule.options.defaults)) {
|
|
93
|
+
lines.push(` ${k}: ${JSON.stringify(v)}`);
|
|
94
|
+
}
|
|
95
|
+
lines.push('```', '');
|
|
96
|
+
return lines;
|
|
97
|
+
}
|
|
20
98
|
export function renderRuleMarkdown(rule, locale) {
|
|
21
99
|
const messages = locale === 'ko' && rule.messageKo ? rule.messageKo : rule.message;
|
|
22
100
|
const severityLabel = locale === 'ko' ? SEVERITY_LABEL_KO[rule.severity] : SEVERITY_LABEL_EN[rule.severity];
|
|
@@ -33,6 +111,7 @@ export function renderRuleMarkdown(rule, locale) {
|
|
|
33
111
|
'',
|
|
34
112
|
messages,
|
|
35
113
|
'',
|
|
114
|
+
...renderOptionsSection(rule, 'ko'),
|
|
36
115
|
'## 위반 예시',
|
|
37
116
|
'',
|
|
38
117
|
'```typescript',
|
|
@@ -73,6 +152,7 @@ export function renderRuleMarkdown(rule, locale) {
|
|
|
73
152
|
'',
|
|
74
153
|
messages,
|
|
75
154
|
'',
|
|
155
|
+
...renderOptionsSection(rule, 'en'),
|
|
76
156
|
'## Violation example',
|
|
77
157
|
'',
|
|
78
158
|
'```typescript',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render-rule-md.js","sourceRoot":"","sources":["../../src/docs/render-rule-md.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"render-rule-md.js","sourceRoot":"","sources":["../../src/docs/render-rule-md.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"camelcase-migration-column.d.ts","sourceRoot":"","sources":["../../src/rules-default/camelcase-migration-column.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"camelcase-migration-column.d.ts","sourceRoot":"","sources":["../../src/rules-default/camelcase-migration-column.ts"],"names":[],"mappings":";AAuCA,wBAwCG"}
|
|
@@ -1,6 +1,22 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
1
2
|
import { defineRule } from '@aicqtools/rule-sdk';
|
|
2
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Default Sequelize migration functions whose first object-shaped argument we scan for
|
|
5
|
+
* snake_case column keys. Alpha.16 promotes this to `options.migrationFunctions` so users
|
|
6
|
+
* on Knex / TypeORM / custom ORMs can swap in their own function names (e.g. Knex
|
|
7
|
+
* `['create_table', 'add_column']`). Default keeps alpha.15 behavior bit-for-bit identical.
|
|
8
|
+
*/
|
|
9
|
+
const DEFAULT_MIGRATION_FUNCTIONS = [
|
|
10
|
+
'createTable',
|
|
11
|
+
'addColumn',
|
|
12
|
+
'changeColumn',
|
|
13
|
+
];
|
|
3
14
|
const SNAKE_CASE_PATTERN = /^[a-z][a-z0-9]*(_[a-z0-9]+)+$/;
|
|
15
|
+
const optionsSchema = z
|
|
16
|
+
.object({
|
|
17
|
+
migrationFunctions: z.array(z.string()).default([...DEFAULT_MIGRATION_FUNCTIONS]),
|
|
18
|
+
})
|
|
19
|
+
.strict();
|
|
4
20
|
function findColumnDefObject(callNode) {
|
|
5
21
|
const args = callNode.childForFieldName('arguments');
|
|
6
22
|
if (!args)
|
|
@@ -20,6 +36,10 @@ export default defineRule({
|
|
|
20
36
|
message: 'Sequelize migration column should use camelCase to match model attribute (avoid `underscored: true` divergence).',
|
|
21
37
|
messageKo: 'Sequelize 마이그레이션 컬럼명은 모델과 일치하도록 camelCase 사용 (snake_case는 underscored 옵션 충돌 위험).',
|
|
22
38
|
docs: 'https://github.com/aicqtools/aicqtools/blob/main/docs/rules/camelcase-migration-column.md',
|
|
39
|
+
options: {
|
|
40
|
+
schema: optionsSchema,
|
|
41
|
+
defaults: { migrationFunctions: [...DEFAULT_MIGRATION_FUNCTIONS] },
|
|
42
|
+
},
|
|
23
43
|
visitors: {
|
|
24
44
|
call_expression(node, ctx) {
|
|
25
45
|
const fn = node.childForFieldName('function');
|
|
@@ -32,7 +52,11 @@ export default defineRule({
|
|
|
32
52
|
// Only inside `queryInterface.createTable(...)` etc.
|
|
33
53
|
if (ctx.textOf(obj) !== 'queryInterface')
|
|
34
54
|
return;
|
|
35
|
-
|
|
55
|
+
const opts = ctx.options ?? {
|
|
56
|
+
migrationFunctions: DEFAULT_MIGRATION_FUNCTIONS,
|
|
57
|
+
};
|
|
58
|
+
const fnSet = new Set(opts.migrationFunctions);
|
|
59
|
+
if (!fnSet.has(ctx.textOf(prop)))
|
|
36
60
|
return;
|
|
37
61
|
const colObj = findColumnDefObject(node);
|
|
38
62
|
if (!colObj)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"camelcase-migration-column.js","sourceRoot":"","sources":["../../src/rules-default/camelcase-migration-column.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEjD,MAAM,
|
|
1
|
+
{"version":3,"file":"camelcase-migration-column.js","sourceRoot":"","sources":["../../src/rules-default/camelcase-migration-column.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEjD;;;;;GAKG;AACH,MAAM,2BAA2B,GAAsB;IACrD,aAAa;IACb,WAAW;IACX,cAAc;CACN,CAAC;AAEX,MAAM,kBAAkB,GAAG,+BAA+B,CAAC;AAE3D,MAAM,aAAa,GAAG,CAAC;KACpB,MAAM,CAAC;IACN,kBAAkB,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,2BAA2B,CAAC,CAAC;CAClF,CAAC;KACD,MAAM,EAAE,CAAC;AAMZ,SAAS,mBAAmB,CAAC,QAA2B;IACtD,MAAM,IAAI,GAAG,QAAQ,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAC;IACrD,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IACvB,sGAAsG;IACtG,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC,EAAE,EAAE,CAAC;QAC9C,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QAC/B,IAAI,GAAG,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,GAAG,CAAC;IAC/C,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,eAAe,UAAU,CAAC;IACxB,EAAE,EAAE,4BAA4B;IAChC,QAAQ,EAAE,CAAC,YAAY,EAAE,YAAY,CAAC;IACtC,QAAQ,EAAE,SAAS;IACnB,OAAO,EAAE,kHAAkH;IAC3H,SAAS,EAAE,kFAAkF;IAC7F,IAAI,EAAE,2FAA2F;IACjG,OAAO,EAAE;QACP,MAAM,EAAE,aAAa;QACrB,QAAQ,EAAE,EAAE,kBAAkB,EAAE,CAAC,GAAG,2BAA2B,CAAC,EAAE;KACnE;IACD,QAAQ,EAAE;QACR,eAAe,CAAC,IAAI,EAAE,GAAG;YACvB,MAAM,EAAE,GAAG,IAAI,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC;YAC9C,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,IAAI,KAAK,mBAAmB;gBAAE,OAAO;YACnD,MAAM,IAAI,GAAG,EAAE,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC;YAC9C,MAAM,GAAG,GAAG,EAAE,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC;YAC3C,IAAI,CAAC,IAAI,IAAI,CAAC,GAAG;gBAAE,OAAO;YAC1B,qDAAqD;YACrD,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,gBAAgB;gBAAE,OAAO;YACjD,MAAM,IAAI,GAAI,GAAG,CAAC,OAAuD,IAAI;gBAC3E,kBAAkB,EAAE,2BAA2B;aAChD,CAAC;YACF,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;YAC/C,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;gBAAE,OAAO;YACzC,MAAM,MAAM,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAC;YACzC,IAAI,CAAC,MAAM;gBAAE,OAAO;YACpB,0CAA0C;YAC1C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,eAAe,EAAE,CAAC,EAAE,EAAE,CAAC;gBAChD,MAAM,IAAI,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;gBAClC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM;oBAAE,SAAS;gBAC5C,MAAM,GAAG,GAAG,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC;gBAC1C,IAAI,CAAC,GAAG;oBAAE,SAAS;gBACnB,MAAM,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;gBACrD,IAAI,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;oBACrC,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;gBAC5B,CAAC;YACH,CAAC;QACH,CAAC;KACF;CACF,CAAC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mask-pii-in-ai-prompt.d.ts","sourceRoot":"","sources":["../../src/rules-default/mask-pii-in-ai-prompt.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"mask-pii-in-ai-prompt.d.ts","sourceRoot":"","sources":["../../src/rules-default/mask-pii-in-ai-prompt.ts"],"names":[],"mappings":";AAuDA,wBA4BG"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
1
2
|
import { defineRule } from '@aicqtools/rule-sdk';
|
|
2
3
|
/**
|
|
3
4
|
* FSC AI guideline: personal information (RRN, card number) must be masked
|
|
@@ -5,14 +6,40 @@ import { defineRule } from '@aicqtools/rule-sdk';
|
|
|
5
6
|
* (\d{6}-\d{7}) or 16-digit card numbers in string/template arguments of
|
|
6
7
|
* AI SDK calls.
|
|
7
8
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
9
|
+
* Alpha.16: `options.piiPatterns: string[]` (regex source array) — default is the alpha.15
|
|
10
|
+
* RRN + card-number pair. Users can extend (passport numbers, account numbers) or replace
|
|
11
|
+
* the set. The AI SDK call pattern (`AI_CALL`) stays a fixed default this cycle — exposing
|
|
12
|
+
* it as an option is deferred to a future release.
|
|
13
|
+
*
|
|
14
|
+
* Limitation: false negatives if PII enters via interpolated variables; false positives if a
|
|
15
|
+
* legitimate test fixture contains a digit run. User-supplied regex source strings are not
|
|
16
|
+
* safety-checked (catastrophic backtracking is the user's responsibility).
|
|
10
17
|
*/
|
|
11
|
-
const
|
|
12
|
-
|
|
18
|
+
const DEFAULT_PII_PATTERNS = [
|
|
19
|
+
'\\b\\d{6}-\\d{7}\\b',
|
|
20
|
+
'\\b(?:\\d[ -]?){15,16}\\b',
|
|
21
|
+
];
|
|
13
22
|
const AI_CALL = /\b(openai|anthropic|aiClient)\.\w+/;
|
|
14
|
-
|
|
15
|
-
|
|
23
|
+
const optionsSchema = z
|
|
24
|
+
.object({
|
|
25
|
+
piiPatterns: z.array(z.string()).default([...DEFAULT_PII_PATTERNS]),
|
|
26
|
+
})
|
|
27
|
+
.strict();
|
|
28
|
+
// Module-scope compile cache — when the same source array repeats across calls (common case:
|
|
29
|
+
// one `applyRuleConfig` per run), we skip the `new RegExp` cost. Reference equality on the
|
|
30
|
+
// source array key is sufficient for resolve-rule-options call patterns.
|
|
31
|
+
let cachedSource = null;
|
|
32
|
+
let cachedCompiled = null;
|
|
33
|
+
function compilePiiPatterns(source) {
|
|
34
|
+
if (cachedSource === source && cachedCompiled !== null)
|
|
35
|
+
return cachedCompiled;
|
|
36
|
+
const compiled = source.map((s) => new RegExp(s));
|
|
37
|
+
cachedSource = source;
|
|
38
|
+
cachedCompiled = compiled;
|
|
39
|
+
return compiled;
|
|
40
|
+
}
|
|
41
|
+
function inspectArgsString(text, patterns) {
|
|
42
|
+
return patterns.some((re) => re.test(text));
|
|
16
43
|
}
|
|
17
44
|
export default defineRule({
|
|
18
45
|
id: 'mask-pii-in-ai-prompt',
|
|
@@ -21,6 +48,10 @@ export default defineRule({
|
|
|
21
48
|
message: 'AI prompt contains unmasked PII (Korean RRN or card number) — mask before sending (FSC AI guideline — privacy protection).',
|
|
22
49
|
messageKo: 'AI 프롬프트에 마스킹되지 않은 개인정보(주민번호/카드번호)가 포함되어 있습니다 — AI 호출 전 마스킹 필수 (금감원 AI 가이드라인 — 개인정보 보호).',
|
|
23
50
|
docs: 'https://github.com/aicqtools/aicqtools/blob/main/docs/rules/mask-pii-in-ai-prompt.md',
|
|
51
|
+
options: {
|
|
52
|
+
schema: optionsSchema,
|
|
53
|
+
defaults: { piiPatterns: [...DEFAULT_PII_PATTERNS] },
|
|
54
|
+
},
|
|
24
55
|
visitors: {
|
|
25
56
|
call_expression(node, ctx) {
|
|
26
57
|
const fnNode = node.childForFieldName('function');
|
|
@@ -33,7 +64,13 @@ export default defineRule({
|
|
|
33
64
|
if (!args)
|
|
34
65
|
return;
|
|
35
66
|
const argsText = ctx.textOf(args);
|
|
36
|
-
|
|
67
|
+
const opts = ctx.options ?? {
|
|
68
|
+
piiPatterns: DEFAULT_PII_PATTERNS,
|
|
69
|
+
};
|
|
70
|
+
if (opts.piiPatterns.length === 0)
|
|
71
|
+
return;
|
|
72
|
+
const compiled = compilePiiPatterns(opts.piiPatterns);
|
|
73
|
+
if (inspectArgsString(argsText, compiled))
|
|
37
74
|
ctx.report({ node });
|
|
38
75
|
},
|
|
39
76
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mask-pii-in-ai-prompt.js","sourceRoot":"","sources":["../../src/rules-default/mask-pii-in-ai-prompt.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAGjD
|
|
1
|
+
{"version":3,"file":"mask-pii-in-ai-prompt.js","sourceRoot":"","sources":["../../src/rules-default/mask-pii-in-ai-prompt.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAGjD;;;;;;;;;;;;;;GAcG;AACH,MAAM,oBAAoB,GAAsB;IAC9C,qBAAqB;IACrB,2BAA2B;CACnB,CAAC;AAEX,MAAM,OAAO,GAAG,oCAAoC,CAAC;AAErD,MAAM,aAAa,GAAG,CAAC;KACpB,MAAM,CAAC;IACN,WAAW,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,oBAAoB,CAAC,CAAC;CACpE,CAAC;KACD,MAAM,EAAE,CAAC;AAMZ,6FAA6F;AAC7F,2FAA2F;AAC3F,yEAAyE;AACzE,IAAI,YAAY,GAA6B,IAAI,CAAC;AAClD,IAAI,cAAc,GAA6B,IAAI,CAAC;AAEpD,SAAS,kBAAkB,CAAC,MAAyB;IACnD,IAAI,YAAY,KAAK,MAAM,IAAI,cAAc,KAAK,IAAI;QAAE,OAAO,cAAc,CAAC;IAC9E,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IAClD,YAAY,GAAG,MAAM,CAAC;IACtB,cAAc,GAAG,QAAQ,CAAC;IAC1B,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,iBAAiB,CAAC,IAAY,EAAE,QAA2B;IAClE,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;AAC9C,CAAC;AAED,eAAe,UAAU,CAAC;IACxB,EAAE,EAAE,uBAAuB;IAC3B,QAAQ,EAAE,CAAC,YAAY,EAAE,KAAK,CAAC;IAC/B,QAAQ,EAAE,OAAO;IACjB,OAAO,EAAE,4HAA4H;IACrI,SAAS,EAAE,yFAAyF;IACpG,IAAI,EAAE,sFAAsF;IAC5F,OAAO,EAAE;QACP,MAAM,EAAE,aAAa;QACrB,QAAQ,EAAE,EAAE,WAAW,EAAE,CAAC,GAAG,oBAAoB,CAAC,EAAE;KACrD;IACD,QAAQ,EAAE;QACR,eAAe,CAAC,IAAuB,EAAE,GAAgB;YACvD,MAAM,MAAM,GAAG,IAAI,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC;YAClD,IAAI,CAAC,MAAM;gBAAE,OAAO;YACpB,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YAClC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC;gBAAE,OAAO;YAClC,MAAM,IAAI,GAAG,IAAI,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAC;YACjD,IAAI,CAAC,IAAI;gBAAE,OAAO;YAClB,MAAM,QAAQ,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAClC,MAAM,IAAI,GAAI,GAAG,CAAC,OAAgD,IAAI;gBACpE,WAAW,EAAE,oBAAoB;aAClC,CAAC;YACF,IAAI,IAAI,CAAC,WAAW,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO;YAC1C,MAAM,QAAQ,GAAG,kBAAkB,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YACtD,IAAI,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,CAAC;gBAAE,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;QAClE,CAAC;KACF;CACF,CAAC,CAAC"}
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skip build/utility script directories where `console.log` is the intended I/O channel
|
|
3
|
+
* (`scripts/`, `tools/`, `bin/` — same convention as alpha.8's `seeders/`+`migrations/`
|
|
4
|
+
* skip for `no-magic-number`). The rule continues to fire in application source.
|
|
5
|
+
*/
|
|
6
|
+
export declare const SKIP_FILE_RE: RegExp;
|
|
1
7
|
declare const _default: import("@aicqtools/rule-sdk").FunctionRule;
|
|
2
8
|
export default _default;
|
|
3
9
|
//# sourceMappingURL=no-console-log.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"no-console-log.d.ts","sourceRoot":"","sources":["../../src/rules-default/no-console-log.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"no-console-log.d.ts","sourceRoot":"","sources":["../../src/rules-default/no-console-log.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,eAAO,MAAM,YAAY,QAAkC,CAAC;;AAmB5D,wBAwBG"}
|
|
@@ -1,25 +1,46 @@
|
|
|
1
1
|
import { defineRule } from '@aicqtools/rule-sdk';
|
|
2
|
+
import { z } from 'zod';
|
|
2
3
|
/**
|
|
3
4
|
* Skip build/utility script directories where `console.log` is the intended I/O channel
|
|
4
5
|
* (`scripts/`, `tools/`, `bin/` — same convention as alpha.8's `seeders/`+`migrations/`
|
|
5
6
|
* skip for `no-magic-number`). The rule continues to fire in application source.
|
|
6
7
|
*/
|
|
7
|
-
const SKIP_FILE_RE = /[/\\](scripts|tools|bin)[/\\]/;
|
|
8
|
+
export const SKIP_FILE_RE = /[/\\](scripts|tools|bin)[/\\]/;
|
|
9
|
+
/**
|
|
10
|
+
* Default detection set — alpha.13 behavior was "flag `console.log` only". Alpha.15 promotes
|
|
11
|
+
* this to a configurable allowlist via `options.flagMethods` so users can extend detection to
|
|
12
|
+
* `console.debug`, `console.warn`, etc. (or shrink to `[]` for an intentional mute).
|
|
13
|
+
*/
|
|
14
|
+
const DEFAULT_FLAG_METHODS = ['log'];
|
|
15
|
+
const optionsSchema = z
|
|
16
|
+
.object({
|
|
17
|
+
flagMethods: z.array(z.string()).default([...DEFAULT_FLAG_METHODS]),
|
|
18
|
+
})
|
|
19
|
+
.strict();
|
|
8
20
|
export default defineRule({
|
|
9
21
|
id: 'no-console-log',
|
|
10
22
|
language: ['typescript', 'javascript', 'tsx'],
|
|
11
23
|
severity: 'warning',
|
|
12
24
|
message: 'Avoid console.log in production code.',
|
|
13
25
|
messageKo: '운영 코드에서 console.log 사용을 피하세요.',
|
|
26
|
+
skipPatterns: [SKIP_FILE_RE],
|
|
27
|
+
options: {
|
|
28
|
+
schema: optionsSchema,
|
|
29
|
+
defaults: { flagMethods: [...DEFAULT_FLAG_METHODS] },
|
|
30
|
+
},
|
|
14
31
|
visitors: {
|
|
15
32
|
call_expression(node, ctx) {
|
|
16
|
-
if (SKIP_FILE_RE.test(ctx.filePath))
|
|
33
|
+
if (!ctx.skipBuiltinSkips && SKIP_FILE_RE.test(ctx.filePath))
|
|
17
34
|
return;
|
|
18
35
|
const fn = node.childForFieldName('function');
|
|
19
36
|
if (!fn)
|
|
20
37
|
return;
|
|
21
38
|
const text = ctx.textOf(fn);
|
|
22
|
-
|
|
39
|
+
const opts = ctx.options ?? {
|
|
40
|
+
flagMethods: DEFAULT_FLAG_METHODS,
|
|
41
|
+
};
|
|
42
|
+
const flagged = new Set(opts.flagMethods.map((m) => 'console.' + m));
|
|
43
|
+
if (flagged.has(text))
|
|
23
44
|
ctx.report({ node });
|
|
24
45
|
},
|
|
25
46
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"no-console-log.js","sourceRoot":"","sources":["../../src/rules-default/no-console-log.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"no-console-log.js","sourceRoot":"","sources":["../../src/rules-default/no-console-log.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;GAIG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,+BAA+B,CAAC;AAE5D;;;;GAIG;AACH,MAAM,oBAAoB,GAAsB,CAAC,KAAK,CAAU,CAAC;AAEjE,MAAM,aAAa,GAAG,CAAC;KACpB,MAAM,CAAC;IACN,WAAW,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,oBAAoB,CAAC,CAAC;CACpE,CAAC;KACD,MAAM,EAAE,CAAC;AAMZ,eAAe,UAAU,CAAC;IACxB,EAAE,EAAE,gBAAgB;IACpB,QAAQ,EAAE,CAAC,YAAY,EAAE,YAAY,EAAE,KAAK,CAAC;IAC7C,QAAQ,EAAE,SAAS;IACnB,OAAO,EAAE,uCAAuC;IAChD,SAAS,EAAE,+BAA+B;IAC1C,YAAY,EAAE,CAAC,YAAY,CAAC;IAC5B,OAAO,EAAE;QACP,MAAM,EAAE,aAAa;QACrB,QAAQ,EAAE,EAAE,WAAW,EAAE,CAAC,GAAG,oBAAoB,CAAC,EAAE;KACrD;IACD,QAAQ,EAAE;QACR,eAAe,CAAC,IAAI,EAAE,GAAG;YACvB,IAAI,CAAC,GAAG,CAAC,gBAAgB,IAAI,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC;gBAAE,OAAO;YACrE,MAAM,EAAE,GAAG,IAAI,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC;YAC9C,IAAI,CAAC,EAAE;gBAAE,OAAO;YAChB,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAC5B,MAAM,IAAI,GAAI,GAAG,CAAC,OAA2C,IAAI;gBAC/D,WAAW,EAAE,oBAAoB;aAClC,CAAC;YACF,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC;YACrE,IAAI,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;gBAAE,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9C,CAAC;KACF;CACF,CAAC,CAAC"}
|
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Forbids empty catch blocks. At minimum, log or rethrow.
|
|
3
|
+
* Catches the silent-failure anti-pattern that masks bugs.
|
|
4
|
+
*
|
|
5
|
+
* Skip: Capacitor's `native-bridge.{js,ts}` and PWA `service-worker.{js,ts}` regularly
|
|
6
|
+
* swallow exceptions on purpose (the bridge/SW must never crash the host). The rule still
|
|
7
|
+
* fires elsewhere on the same files via other lints.
|
|
8
|
+
*
|
|
9
|
+
* Alpha.15: `SKIP_FILE_RE`'s pattern is promoted to a configurable option
|
|
10
|
+
* (`options.skipFilePatterns`) so users can extend / replace the skip set. The named export
|
|
11
|
+
* is preserved for the alpha.12 meta-vs-code equality guard — `skipPatterns: [SKIP_FILE_RE]`
|
|
12
|
+
* reflects the built-in default only. If the user overrides `skipFilePatterns`, runtime
|
|
13
|
+
* matching diverges from the meta (intentional — `aicq rules suggest` keeps showing defaults).
|
|
14
|
+
*/
|
|
15
|
+
export declare const SKIP_FILE_RE: RegExp;
|
|
1
16
|
declare const _default: import("@aicqtools/rule-sdk").FunctionRule;
|
|
2
17
|
export default _default;
|
|
3
18
|
//# sourceMappingURL=no-empty-catch.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"no-empty-catch.d.ts","sourceRoot":"","sources":["../../src/rules-default/no-empty-catch.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"no-empty-catch.d.ts","sourceRoot":"","sources":["../../src/rules-default/no-empty-catch.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,YAAY,QAAkD,CAAC;;AA8B5E,wBAmCG"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { defineRule } from '@aicqtools/rule-sdk';
|
|
2
|
+
import { z } from 'zod';
|
|
2
3
|
/**
|
|
3
4
|
* Forbids empty catch blocks. At minimum, log or rethrow.
|
|
4
5
|
* Catches the silent-failure anti-pattern that masks bugs.
|
|
@@ -6,18 +7,58 @@ import { defineRule } from '@aicqtools/rule-sdk';
|
|
|
6
7
|
* Skip: Capacitor's `native-bridge.{js,ts}` and PWA `service-worker.{js,ts}` regularly
|
|
7
8
|
* swallow exceptions on purpose (the bridge/SW must never crash the host). The rule still
|
|
8
9
|
* fires elsewhere on the same files via other lints.
|
|
10
|
+
*
|
|
11
|
+
* Alpha.15: `SKIP_FILE_RE`'s pattern is promoted to a configurable option
|
|
12
|
+
* (`options.skipFilePatterns`) so users can extend / replace the skip set. The named export
|
|
13
|
+
* is preserved for the alpha.12 meta-vs-code equality guard — `skipPatterns: [SKIP_FILE_RE]`
|
|
14
|
+
* reflects the built-in default only. If the user overrides `skipFilePatterns`, runtime
|
|
15
|
+
* matching diverges from the meta (intentional — `aicq rules suggest` keeps showing defaults).
|
|
9
16
|
*/
|
|
10
|
-
const SKIP_FILE_RE = /[/\\](native-bridge|service-worker)\.[jt]sx?$/;
|
|
17
|
+
export const SKIP_FILE_RE = /[/\\](native-bridge|service-worker)\.[jt]sx?$/;
|
|
18
|
+
const DEFAULT_SKIP_PATTERNS = [
|
|
19
|
+
'[/\\\\](native-bridge|service-worker)\\.[jt]sx?$',
|
|
20
|
+
];
|
|
21
|
+
const optionsSchema = z
|
|
22
|
+
.object({
|
|
23
|
+
skipFilePatterns: z.array(z.string()).default([...DEFAULT_SKIP_PATTERNS]),
|
|
24
|
+
})
|
|
25
|
+
.strict();
|
|
26
|
+
// Module-scope compile cache — when the same option source array repeats across calls (the
|
|
27
|
+
// common case: one `applyRuleConfig` per run), we skip the `new RegExp` cost. Cache invalidates
|
|
28
|
+
// when source array reference changes (good enough for the resolve-rule-options call pattern).
|
|
29
|
+
let cachedSource = null;
|
|
30
|
+
let cachedCompiled = null;
|
|
31
|
+
function compileSkipPatterns(source) {
|
|
32
|
+
if (cachedSource === source && cachedCompiled !== null)
|
|
33
|
+
return cachedCompiled;
|
|
34
|
+
const compiled = source.map((s) => new RegExp(s));
|
|
35
|
+
cachedSource = source;
|
|
36
|
+
cachedCompiled = compiled;
|
|
37
|
+
return compiled;
|
|
38
|
+
}
|
|
11
39
|
export default defineRule({
|
|
12
40
|
id: 'no-empty-catch',
|
|
13
41
|
language: ['typescript', 'javascript', 'tsx'],
|
|
14
42
|
severity: 'error',
|
|
15
43
|
message: 'catch block must not be empty — log or rethrow.',
|
|
16
44
|
messageKo: 'catch 블록은 비어 있을 수 없습니다 — log하거나 rethrow하세요.',
|
|
45
|
+
skipPatterns: [SKIP_FILE_RE],
|
|
46
|
+
options: {
|
|
47
|
+
schema: optionsSchema,
|
|
48
|
+
defaults: { skipFilePatterns: [...DEFAULT_SKIP_PATTERNS] },
|
|
49
|
+
},
|
|
17
50
|
visitors: {
|
|
18
51
|
catch_clause(node, ctx) {
|
|
19
|
-
|
|
20
|
-
|
|
52
|
+
// Alpha.13 escape hatch: `skipBuiltinSkips=true` bypasses BOTH the built-in skip and any
|
|
53
|
+
// user-supplied `skipFilePatterns` (global short-circuit, plan decision #4).
|
|
54
|
+
if (!ctx.skipBuiltinSkips) {
|
|
55
|
+
const opts = ctx.options ?? {
|
|
56
|
+
skipFilePatterns: DEFAULT_SKIP_PATTERNS,
|
|
57
|
+
};
|
|
58
|
+
const compiled = compileSkipPatterns(opts.skipFilePatterns);
|
|
59
|
+
if (compiled.some((re) => re.test(ctx.filePath)))
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
21
62
|
const body = node.childForFieldName('body');
|
|
22
63
|
if (!body)
|
|
23
64
|
return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"no-empty-catch.js","sourceRoot":"","sources":["../../src/rules-default/no-empty-catch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"no-empty-catch.js","sourceRoot":"","sources":["../../src/rules-default/no-empty-catch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,+CAA+C,CAAC;AAE5E,MAAM,qBAAqB,GAAsB;IAC/C,kDAAkD;CAC1C,CAAC;AAEX,MAAM,aAAa,GAAG,CAAC;KACpB,MAAM,CAAC;IACN,gBAAgB,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,qBAAqB,CAAC,CAAC;CAC1E,CAAC;KACD,MAAM,EAAE,CAAC;AAMZ,2FAA2F;AAC3F,gGAAgG;AAChG,+FAA+F;AAC/F,IAAI,YAAY,GAA6B,IAAI,CAAC;AAClD,IAAI,cAAc,GAA6B,IAAI,CAAC;AAEpD,SAAS,mBAAmB,CAAC,MAAyB;IACpD,IAAI,YAAY,KAAK,MAAM,IAAI,cAAc,KAAK,IAAI;QAAE,OAAO,cAAc,CAAC;IAC9E,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IAClD,YAAY,GAAG,MAAM,CAAC;IACtB,cAAc,GAAG,QAAQ,CAAC;IAC1B,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,eAAe,UAAU,CAAC;IACxB,EAAE,EAAE,gBAAgB;IACpB,QAAQ,EAAE,CAAC,YAAY,EAAE,YAAY,EAAE,KAAK,CAAC;IAC7C,QAAQ,EAAE,OAAO;IACjB,OAAO,EAAE,iDAAiD;IAC1D,SAAS,EAAE,6CAA6C;IACxD,YAAY,EAAE,CAAC,YAAY,CAAC;IAC5B,OAAO,EAAE;QACP,MAAM,EAAE,aAAa;QACrB,QAAQ,EAAE,EAAE,gBAAgB,EAAE,CAAC,GAAG,qBAAqB,CAAC,EAAE;KAC3D;IACD,QAAQ,EAAE;QACR,YAAY,CAAC,IAAI,EAAE,GAAG;YACpB,yFAAyF;YACzF,6EAA6E;YAC7E,IAAI,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;gBAC1B,MAAM,IAAI,GAAI,GAAG,CAAC,OAA2C,IAAI;oBAC/D,gBAAgB,EAAE,qBAAqB;iBACxC,CAAC;gBACF,MAAM,QAAQ,GAAG,mBAAmB,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;gBAC5D,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;oBAAE,OAAO;YAC3D,CAAC;YACD,MAAM,IAAI,GAAG,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC;YAC5C,IAAI,CAAC,IAAI;gBAAE,OAAO;YAClB,IAAI,OAAO,GAAG,KAAK,CAAC;YACpB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC9C,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;gBACjC,IAAI,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;oBACtC,OAAO,GAAG,IAAI,CAAC;oBACf,MAAM;gBACR,CAAC;YACH,CAAC;YACD,IAAI,CAAC,OAAO;gBAAE,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;QACrC,CAAC;KACF;CACF,CAAC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"no-fstring-sql.d.ts","sourceRoot":"","sources":["../../src/rules-default/no-fstring-sql.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"no-fstring-sql.d.ts","sourceRoot":"","sources":["../../src/rules-default/no-fstring-sql.ts"],"names":[],"mappings":";AAkDA,wBA0BG"}
|
|
@@ -1,18 +1,67 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
1
2
|
import { defineRule } from '@aicqtools/rule-sdk';
|
|
2
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Default SQL keywords flagged inside Python f-strings. Alpha.16 exposes this list as
|
|
5
|
+
* `options.sqlKeywords` so projects can shrink it (e.g. `['SELECT']` only) or extend it
|
|
6
|
+
* (e.g. add `'CREATE TABLE'`). Default keeps alpha.15 behavior bit-for-bit identical.
|
|
7
|
+
*
|
|
8
|
+
* Multi-token keywords like `'CREATE TABLE'` work via `\b(...)\b` with the literal space
|
|
9
|
+
* preserved — note that double spaces or newlines between tokens won't match, and meta
|
|
10
|
+
* characters are escaped via `escapeRegex` to keep user-supplied keywords safe.
|
|
11
|
+
*/
|
|
12
|
+
const DEFAULT_SQL_KEYWORDS = [
|
|
13
|
+
'SELECT',
|
|
14
|
+
'INSERT',
|
|
15
|
+
'UPDATE',
|
|
16
|
+
'DELETE',
|
|
17
|
+
'FROM',
|
|
18
|
+
'WHERE',
|
|
19
|
+
'JOIN',
|
|
20
|
+
'VALUES',
|
|
21
|
+
];
|
|
22
|
+
const optionsSchema = z
|
|
23
|
+
.object({
|
|
24
|
+
sqlKeywords: z.array(z.string()).default([...DEFAULT_SQL_KEYWORDS]),
|
|
25
|
+
})
|
|
26
|
+
.strict();
|
|
27
|
+
function escapeRegex(s) {
|
|
28
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
29
|
+
}
|
|
30
|
+
// Module-scope compile cache — keyed by source array reference equality (same trade-off as
|
|
31
|
+
// alpha.15 `no-empty-catch.compileSkipPatterns`).
|
|
32
|
+
let cachedSource = null;
|
|
33
|
+
let cachedPattern = null;
|
|
34
|
+
function compileSqlKeywordPattern(source) {
|
|
35
|
+
if (cachedSource === source && cachedPattern !== null)
|
|
36
|
+
return cachedPattern;
|
|
37
|
+
const pattern = new RegExp('\\b(' + source.map(escapeRegex).join('|') + ')\\b', 'i');
|
|
38
|
+
cachedSource = source;
|
|
39
|
+
cachedPattern = pattern;
|
|
40
|
+
return pattern;
|
|
41
|
+
}
|
|
3
42
|
export default defineRule({
|
|
4
43
|
id: 'no-fstring-sql',
|
|
5
44
|
language: 'python',
|
|
6
45
|
severity: 'error',
|
|
7
46
|
message: 'SQL inside f-string is a SQL injection vector — use parameterized queries.',
|
|
8
47
|
messageKo: 'f-string으로 SQL 조합은 SQL 주입 위험 — 파라미터 바인딩을 사용하세요.',
|
|
48
|
+
options: {
|
|
49
|
+
schema: optionsSchema,
|
|
50
|
+
defaults: { sqlKeywords: [...DEFAULT_SQL_KEYWORDS] },
|
|
51
|
+
},
|
|
9
52
|
visitors: {
|
|
10
53
|
string(node, ctx) {
|
|
11
54
|
const text = ctx.textOf(node);
|
|
12
55
|
// Python f-string starts with f" or f' (or rf", fr", etc.)
|
|
13
56
|
if (!/^[a-zA-Z]*[fF][a-zA-Z]*['"]/.test(text))
|
|
14
57
|
return;
|
|
15
|
-
|
|
58
|
+
const opts = ctx.options ?? {
|
|
59
|
+
sqlKeywords: DEFAULT_SQL_KEYWORDS,
|
|
60
|
+
};
|
|
61
|
+
if (opts.sqlKeywords.length === 0)
|
|
62
|
+
return;
|
|
63
|
+
const pattern = compileSqlKeywordPattern(opts.sqlKeywords);
|
|
64
|
+
if (!pattern.test(text))
|
|
16
65
|
return;
|
|
17
66
|
// Has interpolation `{...}`?
|
|
18
67
|
if (!/\{[^{}]+\}/.test(text))
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"no-fstring-sql.js","sourceRoot":"","sources":["../../src/rules-default/no-fstring-sql.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEjD,MAAM,
|
|
1
|
+
{"version":3,"file":"no-fstring-sql.js","sourceRoot":"","sources":["../../src/rules-default/no-fstring-sql.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEjD;;;;;;;;GAQG;AACH,MAAM,oBAAoB,GAAsB;IAC9C,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,MAAM;IACN,OAAO;IACP,MAAM;IACN,QAAQ;CACA,CAAC;AAEX,MAAM,aAAa,GAAG,CAAC;KACpB,MAAM,CAAC;IACN,WAAW,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,oBAAoB,CAAC,CAAC;CACpE,CAAC;KACD,MAAM,EAAE,CAAC;AAMZ,SAAS,WAAW,CAAC,CAAS;IAC5B,OAAO,CAAC,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;AAClD,CAAC;AAED,2FAA2F;AAC3F,kDAAkD;AAClD,IAAI,YAAY,GAA6B,IAAI,CAAC;AAClD,IAAI,aAAa,GAAkB,IAAI,CAAC;AAExC,SAAS,wBAAwB,CAAC,MAAyB;IACzD,IAAI,YAAY,KAAK,MAAM,IAAI,aAAa,KAAK,IAAI;QAAE,OAAO,aAAa,CAAC;IAC5E,MAAM,OAAO,GAAG,IAAI,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,EAAE,GAAG,CAAC,CAAC;IACrF,YAAY,GAAG,MAAM,CAAC;IACtB,aAAa,GAAG,OAAO,CAAC;IACxB,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,eAAe,UAAU,CAAC;IACxB,EAAE,EAAE,gBAAgB;IACpB,QAAQ,EAAE,QAAQ;IAClB,QAAQ,EAAE,OAAO;IACjB,OAAO,EAAE,4EAA4E;IACrF,SAAS,EAAE,iDAAiD;IAC5D,OAAO,EAAE;QACP,MAAM,EAAE,aAAa;QACrB,QAAQ,EAAE,EAAE,WAAW,EAAE,CAAC,GAAG,oBAAoB,CAAC,EAAE;KACrD;IACD,QAAQ,EAAE;QACR,MAAM,CAAC,IAAI,EAAE,GAAG;YACd,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAC9B,2DAA2D;YAC3D,IAAI,CAAC,6BAA6B,CAAC,IAAI,CAAC,IAAI,CAAC;gBAAE,OAAO;YACtD,MAAM,IAAI,GAAI,GAAG,CAAC,OAA2C,IAAI;gBAC/D,WAAW,EAAE,oBAAoB;aAClC,CAAC;YACF,IAAI,IAAI,CAAC,WAAW,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO;YAC1C,MAAM,OAAO,GAAG,wBAAwB,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YAC3D,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;gBAAE,OAAO;YAChC,6BAA6B;YAC7B,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC;gBAAE,OAAO;YACrC,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;QACvB,CAAC;KACF;CACF,CAAC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"no-magic-number.d.ts","sourceRoot":"","sources":["../../src/rules-default/no-magic-number.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"no-magic-number.d.ts","sourceRoot":"","sources":["../../src/rules-default/no-magic-number.ts"],"names":[],"mappings":"AAiDA,eAAO,MAAM,YAAY,QAA0M,CAAC;;AA6FpO,wBA0BG"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
1
2
|
import { defineRule } from '@aicqtools/rule-sdk';
|
|
2
3
|
/**
|
|
3
4
|
* `no-magic-number` — info-severity rule that flags numeric literals appearing inline in
|
|
@@ -24,10 +25,21 @@ import { defineRule } from '@aicqtools/rule-sdk';
|
|
|
24
25
|
* Allowed-numbers default extended to common-sense values: powers of two, common bases,
|
|
25
26
|
* time/clock constants, etc.
|
|
26
27
|
*/
|
|
27
|
-
|
|
28
|
+
/**
|
|
29
|
+
* Default allowed-number literals. Common-sense values: -2..2, base-10 / base-16 / base-2,
|
|
30
|
+
* time/clock constants. Alpha.14 exposes this list as `options.allowedNumbers` so users can
|
|
31
|
+
* extend (`['0', '1', '-1', '2', '60', '3600', '86400']` for time-heavy projects) or shrink
|
|
32
|
+
* the allow-list per project.
|
|
33
|
+
*/
|
|
34
|
+
const DEFAULT_ALLOWED_NUMBERS = [
|
|
28
35
|
'0', '1', '-1', '2', '-2', '10', '16', '24', '60', '100', '1000', '1024',
|
|
29
|
-
]
|
|
30
|
-
const
|
|
36
|
+
];
|
|
37
|
+
const optionsSchema = z
|
|
38
|
+
.object({
|
|
39
|
+
allowedNumbers: z.array(z.string()).default([...DEFAULT_ALLOWED_NUMBERS]),
|
|
40
|
+
})
|
|
41
|
+
.strict();
|
|
42
|
+
export const SKIP_FILE_RE = /(\.test\.|\.spec\.|__tests__|fixtures|\.config\.|\.polyfill\.|[/\\]polyfills[/\\]|[/\\]seeders[/\\]|[/\\]migrations[/\\]|[/\\](scripts|tools|bin)[/\\]|[/\\](native-bridge|service-worker)\.[jt]sx?$)/;
|
|
31
43
|
// Callee names whose numeric args are almost always intentional, not magic numbers.
|
|
32
44
|
// Matched on the leaf identifier (last name segment) — covers both `parseInt(...)` and
|
|
33
45
|
// `Number.parseInt(...)` / `globalThis.setTimeout(...)`.
|
|
@@ -125,12 +137,21 @@ export default defineRule({
|
|
|
125
137
|
severity: 'info',
|
|
126
138
|
message: 'Magic number — extract to a named constant for clarity.',
|
|
127
139
|
messageKo: '매직 넘버 — 명명된 상수로 추출해 의미를 명확히 하세요.',
|
|
140
|
+
skipPatterns: [SKIP_FILE_RE],
|
|
141
|
+
options: {
|
|
142
|
+
schema: optionsSchema,
|
|
143
|
+
defaults: { allowedNumbers: [...DEFAULT_ALLOWED_NUMBERS] },
|
|
144
|
+
},
|
|
128
145
|
visitors: {
|
|
129
146
|
number(node, ctx) {
|
|
130
|
-
if (isInSkippedFile(ctx.filePath))
|
|
147
|
+
if (!ctx.skipBuiltinSkips && isInSkippedFile(ctx.filePath))
|
|
131
148
|
return;
|
|
149
|
+
const opts = ctx.options ?? {
|
|
150
|
+
allowedNumbers: DEFAULT_ALLOWED_NUMBERS,
|
|
151
|
+
};
|
|
152
|
+
const allowed = new Set(opts.allowedNumbers);
|
|
132
153
|
const text = ctx.textOf(node);
|
|
133
|
-
if (
|
|
154
|
+
if (allowed.has(text))
|
|
134
155
|
return;
|
|
135
156
|
if (hasSkippableAncestor(node))
|
|
136
157
|
return;
|