@aicqtools/guardrail 1.0.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/docs/build.d.ts +12 -0
- package/dist/docs/build.d.ts.map +1 -0
- package/dist/docs/build.js +23 -0
- package/dist/docs/build.js.map +1 -0
- package/dist/docs/index.d.ts +4 -0
- package/dist/docs/index.d.ts.map +1 -0
- package/dist/docs/index.js +3 -0
- package/dist/docs/index.js.map +1 -0
- package/dist/docs/render-rule-md.d.ts +4 -0
- package/dist/docs/render-rule-md.d.ts.map +1 -0
- package/dist/docs/render-rule-md.js +117 -0
- package/dist/docs/render-rule-md.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/matcher/index.d.ts +4 -0
- package/dist/matcher/index.d.ts.map +1 -0
- package/dist/matcher/index.js +3 -0
- package/dist/matcher/index.js.map +1 -0
- package/dist/matcher/traverse.d.ts +3 -0
- package/dist/matcher/traverse.d.ts.map +1 -0
- package/dist/matcher/traverse.js +9 -0
- package/dist/matcher/traverse.js.map +1 -0
- package/dist/matcher/yaml-rule.d.ts +31 -0
- package/dist/matcher/yaml-rule.d.ts.map +1 -0
- package/dist/matcher/yaml-rule.js +30 -0
- package/dist/matcher/yaml-rule.js.map +1 -0
- package/dist/mcp/handlers.d.ts +36 -0
- package/dist/mcp/handlers.d.ts.map +1 -0
- package/dist/mcp/handlers.js +32 -0
- package/dist/mcp/handlers.js.map +1 -0
- package/dist/mcp/index.d.ts +6 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +4 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/server.d.ts +9 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +53 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/stdio.d.ts +3 -0
- package/dist/mcp/stdio.d.ts.map +1 -0
- package/dist/mcp/stdio.js +8 -0
- package/dist/mcp/stdio.js.map +1 -0
- package/dist/rules-default/ai-explainability-metadata.d.ts +3 -0
- package/dist/rules-default/ai-explainability-metadata.d.ts.map +1 -0
- package/dist/rules-default/ai-explainability-metadata.js +41 -0
- package/dist/rules-default/ai-explainability-metadata.js.map +1 -0
- package/dist/rules-default/api-response-shape.d.ts +3 -0
- package/dist/rules-default/api-response-shape.d.ts.map +1 -0
- package/dist/rules-default/api-response-shape.js +52 -0
- package/dist/rules-default/api-response-shape.js.map +1 -0
- package/dist/rules-default/async-await-consistency.d.ts +3 -0
- package/dist/rules-default/async-await-consistency.d.ts.map +1 -0
- package/dist/rules-default/async-await-consistency.js +38 -0
- package/dist/rules-default/async-await-consistency.js.map +1 -0
- package/dist/rules-default/audit-log-ai-decision.d.ts +3 -0
- package/dist/rules-default/audit-log-ai-decision.d.ts.map +1 -0
- package/dist/rules-default/audit-log-ai-decision.js +33 -0
- package/dist/rules-default/audit-log-ai-decision.js.map +1 -0
- package/dist/rules-default/camelcase-migration-column.d.ts +3 -0
- package/dist/rules-default/camelcase-migration-column.d.ts.map +1 -0
- package/dist/rules-default/camelcase-migration-column.js +56 -0
- package/dist/rules-default/camelcase-migration-column.js.map +1 -0
- package/dist/rules-default/controller-needs-async-wrapper.d.ts +3 -0
- package/dist/rules-default/controller-needs-async-wrapper.d.ts.map +1 -0
- package/dist/rules-default/controller-needs-async-wrapper.js +56 -0
- package/dist/rules-default/controller-needs-async-wrapper.js.map +1 -0
- package/dist/rules-default/enforce-utf8-encoding.d.ts +10 -0
- package/dist/rules-default/enforce-utf8-encoding.d.ts.map +1 -0
- package/dist/rules-default/enforce-utf8-encoding.js +28 -0
- package/dist/rules-default/enforce-utf8-encoding.js.map +1 -0
- package/dist/rules-default/explicit-kst-timezone.d.ts +3 -0
- package/dist/rules-default/explicit-kst-timezone.d.ts.map +1 -0
- package/dist/rules-default/explicit-kst-timezone.js +49 -0
- package/dist/rules-default/explicit-kst-timezone.js.map +1 -0
- package/dist/rules-default/fk-needs-on-delete.d.ts +3 -0
- package/dist/rules-default/fk-needs-on-delete.d.ts.map +1 -0
- package/dist/rules-default/fk-needs-on-delete.js +54 -0
- package/dist/rules-default/fk-needs-on-delete.js.map +1 -0
- package/dist/rules-default/human-oversight-checkpoint.d.ts +3 -0
- package/dist/rules-default/human-oversight-checkpoint.d.ts.map +1 -0
- package/dist/rules-default/human-oversight-checkpoint.js +37 -0
- package/dist/rules-default/human-oversight-checkpoint.js.map +1 -0
- package/dist/rules-default/index.d.ts +6 -0
- package/dist/rules-default/index.d.ts.map +1 -0
- package/dist/rules-default/index.js +138 -0
- package/dist/rules-default/index.js.map +1 -0
- package/dist/rules-default/korean-comment-encoding.d.ts +3 -0
- package/dist/rules-default/korean-comment-encoding.d.ts.map +1 -0
- package/dist/rules-default/korean-comment-encoding.js +28 -0
- package/dist/rules-default/korean-comment-encoding.js.map +1 -0
- package/dist/rules-default/mask-card-number.d.ts +3 -0
- package/dist/rules-default/mask-card-number.d.ts.map +1 -0
- package/dist/rules-default/mask-card-number.js +45 -0
- package/dist/rules-default/mask-card-number.js.map +1 -0
- package/dist/rules-default/mask-pii-in-ai-prompt.d.ts +3 -0
- package/dist/rules-default/mask-pii-in-ai-prompt.d.ts.map +1 -0
- package/dist/rules-default/mask-pii-in-ai-prompt.js +41 -0
- package/dist/rules-default/mask-pii-in-ai-prompt.js.map +1 -0
- package/dist/rules-default/naver-kakao-oauth-webview.d.ts +3 -0
- package/dist/rules-default/naver-kakao-oauth-webview.d.ts.map +1 -0
- package/dist/rules-default/naver-kakao-oauth-webview.js +40 -0
- package/dist/rules-default/naver-kakao-oauth-webview.js.map +1 -0
- package/dist/rules-default/no-bare-except.d.ts +7 -0
- package/dist/rules-default/no-bare-except.d.ts.map +1 -0
- package/dist/rules-default/no-bare-except.js +23 -0
- package/dist/rules-default/no-bare-except.js.map +1 -0
- package/dist/rules-default/no-bare-throw.d.ts +7 -0
- package/dist/rules-default/no-bare-throw.d.ts.map +1 -0
- package/dist/rules-default/no-bare-throw.js +32 -0
- package/dist/rules-default/no-bare-throw.js.map +1 -0
- package/dist/rules-default/no-boolean-trap.d.ts +8 -0
- package/dist/rules-default/no-boolean-trap.d.ts.map +1 -0
- package/dist/rules-default/no-boolean-trap.js +33 -0
- package/dist/rules-default/no-boolean-trap.js.map +1 -0
- package/dist/rules-default/no-console-log.d.ts +3 -0
- package/dist/rules-default/no-console-log.d.ts.map +1 -0
- package/dist/rules-default/no-console-log.js +19 -0
- package/dist/rules-default/no-console-log.js.map +1 -0
- package/dist/rules-default/no-cvv-logging.d.ts +3 -0
- package/dist/rules-default/no-cvv-logging.d.ts.map +1 -0
- package/dist/rules-default/no-cvv-logging.js +36 -0
- package/dist/rules-default/no-cvv-logging.js.map +1 -0
- package/dist/rules-default/no-default-export-from-libs.d.ts +7 -0
- package/dist/rules-default/no-default-export-from-libs.d.ts.map +1 -0
- package/dist/rules-default/no-default-export-from-libs.js +24 -0
- package/dist/rules-default/no-default-export-from-libs.js.map +1 -0
- package/dist/rules-default/no-direct-anthropic.yaml +9 -0
- package/dist/rules-default/no-direct-openai.yaml +9 -0
- package/dist/rules-default/no-empty-catch.d.ts +7 -0
- package/dist/rules-default/no-empty-catch.d.ts.map +1 -0
- package/dist/rules-default/no-empty-catch.js +30 -0
- package/dist/rules-default/no-empty-catch.js.map +1 -0
- package/dist/rules-default/no-fstring-sql.d.ts +3 -0
- package/dist/rules-default/no-fstring-sql.d.ts.map +1 -0
- package/dist/rules-default/no-fstring-sql.js +24 -0
- package/dist/rules-default/no-fstring-sql.js.map +1 -0
- package/dist/rules-default/no-id-overwrite.d.ts +7 -0
- package/dist/rules-default/no-id-overwrite.d.ts.map +1 -0
- package/dist/rules-default/no-id-overwrite.js +26 -0
- package/dist/rules-default/no-id-overwrite.js.map +1 -0
- package/dist/rules-default/no-inline-date.yaml +9 -0
- package/dist/rules-default/no-inline-math-round.yaml +12 -0
- package/dist/rules-default/no-jsonb-circular.d.ts +3 -0
- package/dist/rules-default/no-jsonb-circular.d.ts.map +1 -0
- package/dist/rules-default/no-jsonb-circular.js +33 -0
- package/dist/rules-default/no-jsonb-circular.js.map +1 -0
- package/dist/rules-default/no-magic-number.d.ts +3 -0
- package/dist/rules-default/no-magic-number.d.ts.map +1 -0
- package/dist/rules-default/no-magic-number.js +42 -0
- package/dist/rules-default/no-magic-number.js.map +1 -0
- package/dist/rules-default/no-mutable-default-arg.d.ts +3 -0
- package/dist/rules-default/no-mutable-default-arg.d.ts.map +1 -0
- package/dist/rules-default/no-mutable-default-arg.js +30 -0
- package/dist/rules-default/no-mutable-default-arg.js.map +1 -0
- package/dist/rules-default/no-pickle.yaml +12 -0
- package/dist/rules-default/no-plain-card-number.d.ts +3 -0
- package/dist/rules-default/no-plain-card-number.d.ts.map +1 -0
- package/dist/rules-default/no-plain-card-number.js +51 -0
- package/dist/rules-default/no-plain-card-number.js.map +1 -0
- package/dist/rules-default/no-print-in-prod.yaml +9 -0
- package/dist/rules-default/no-process-env-leak.d.ts +7 -0
- package/dist/rules-default/no-process-env-leak.d.ts.map +1 -0
- package/dist/rules-default/no-process-env-leak.js +34 -0
- package/dist/rules-default/no-process-env-leak.js.map +1 -0
- package/dist/rules-default/no-shell-true.d.ts +3 -0
- package/dist/rules-default/no-shell-true.d.ts.map +1 -0
- package/dist/rules-default/no-shell-true.js +42 -0
- package/dist/rules-default/no-shell-true.js.map +1 -0
- package/dist/rules-default/prefer-const-array.d.ts +9 -0
- package/dist/rules-default/prefer-const-array.d.ts.map +1 -0
- package/dist/rules-default/prefer-const-array.js +34 -0
- package/dist/rules-default/prefer-const-array.js.map +1 -0
- package/dist/rules-default/prefer-named-imports.d.ts +8 -0
- package/dist/rules-default/prefer-named-imports.d.ts.map +1 -0
- package/dist/rules-default/prefer-named-imports.js +25 -0
- package/dist/rules-default/prefer-named-imports.js.map +1 -0
- package/dist/rules-default/preserve-transaction-log.d.ts +3 -0
- package/dist/rules-default/preserve-transaction-log.d.ts.map +1 -0
- package/dist/rules-default/preserve-transaction-log.js +33 -0
- package/dist/rules-default/preserve-transaction-log.js.map +1 -0
- package/dist/rules-default/pytest-fixture-naming.d.ts +3 -0
- package/dist/rules-default/pytest-fixture-naming.d.ts.map +1 -0
- package/dist/rules-default/pytest-fixture-naming.js +36 -0
- package/dist/rules-default/pytest-fixture-naming.js.map +1 -0
- package/dist/rules-default/requests-needs-timeout.d.ts +3 -0
- package/dist/rules-default/requests-needs-timeout.d.ts.map +1 -0
- package/dist/rules-default/requests-needs-timeout.js +43 -0
- package/dist/rules-default/requests-needs-timeout.js.map +1 -0
- package/dist/rules-default/require-idempotency-key.d.ts +3 -0
- package/dist/rules-default/require-idempotency-key.d.ts.map +1 -0
- package/dist/rules-default/require-idempotency-key.js +47 -0
- package/dist/rules-default/require-idempotency-key.js.map +1 -0
- package/dist/rules-default/require-tls-1-2-plus.d.ts +3 -0
- package/dist/rules-default/require-tls-1-2-plus.d.ts.map +1 -0
- package/dist/rules-default/require-tls-1-2-plus.js +30 -0
- package/dist/rules-default/require-tls-1-2-plus.js.map +1 -0
- package/dist/rules-default/rfc5987-korean-filename.d.ts +3 -0
- package/dist/rules-default/rfc5987-korean-filename.d.ts.map +1 -0
- package/dist/rules-default/rfc5987-korean-filename.js +32 -0
- package/dist/rules-default/rfc5987-korean-filename.js.map +1 -0
- package/dist/rules-default/route-needs-auth.d.ts +3 -0
- package/dist/rules-default/route-needs-auth.d.ts.map +1 -0
- package/dist/rules-default/route-needs-auth.js +48 -0
- package/dist/rules-default/route-needs-auth.js.map +1 -0
- package/dist/rules-default/route-needs-rate-limit.d.ts +3 -0
- package/dist/rules-default/route-needs-rate-limit.d.ts.map +1 -0
- package/dist/rules-default/route-needs-rate-limit.js +47 -0
- package/dist/rules-default/route-needs-rate-limit.js.map +1 -0
- package/dist/rules-default/separate-refund-permission.d.ts +3 -0
- package/dist/rules-default/separate-refund-permission.d.ts.map +1 -0
- package/dist/rules-default/separate-refund-permission.js +33 -0
- package/dist/rules-default/separate-refund-permission.js.map +1 -0
- package/dist/rules-default/track-ai-model-version.d.ts +3 -0
- package/dist/rules-default/track-ai-model-version.d.ts.map +1 -0
- package/dist/rules-default/track-ai-model-version.js +37 -0
- package/dist/rules-default/track-ai-model-version.js.map +1 -0
- package/dist/rules-default/type-hint-required-public.d.ts +10 -0
- package/dist/rules-default/type-hint-required-public.d.ts.map +1 -0
- package/dist/rules-default/type-hint-required-public.js +29 -0
- package/dist/rules-default/type-hint-required-public.js.map +1 -0
- package/dist/rules-default/verify-pg-response.d.ts +3 -0
- package/dist/rules-default/verify-pg-response.d.ts.map +1 -0
- package/dist/rules-default/verify-pg-response.js +37 -0
- package/dist/rules-default/verify-pg-response.js.map +1 -0
- package/dist/rules-default/won-format-thousands.d.ts +3 -0
- package/dist/rules-default/won-format-thousands.d.ts.map +1 -0
- package/dist/rules-default/won-format-thousands.js +24 -0
- package/dist/rules-default/won-format-thousands.js.map +1 -0
- package/dist/runner/context.d.ts +12 -0
- package/dist/runner/context.d.ts.map +1 -0
- package/dist/runner/context.js +34 -0
- package/dist/runner/context.js.map +1 -0
- package/dist/runner/index.d.ts +7 -0
- package/dist/runner/index.d.ts.map +1 -0
- package/dist/runner/index.js +5 -0
- package/dist/runner/index.js.map +1 -0
- package/dist/runner/ruleset-signature.d.ts +4 -0
- package/dist/runner/ruleset-signature.d.ts.map +1 -0
- package/dist/runner/ruleset-signature.js +11 -0
- package/dist/runner/ruleset-signature.js.map +1 -0
- package/dist/runner/run-file.d.ts +10 -0
- package/dist/runner/run-file.d.ts.map +1 -0
- package/dist/runner/run-file.js +20 -0
- package/dist/runner/run-file.js.map +1 -0
- package/dist/runner/run-project.d.ts +12 -0
- package/dist/runner/run-project.d.ts.map +1 -0
- package/dist/runner/run-project.js +55 -0
- package/dist/runner/run-project.js.map +1 -0
- package/dist/runner/run-rule.d.ts +5 -0
- package/dist/runner/run-rule.d.ts.map +1 -0
- package/dist/runner/run-rule.js +37 -0
- package/dist/runner/run-rule.js.map +1 -0
- package/dist/sync/index.d.ts +5 -0
- package/dist/sync/index.d.ts.map +1 -0
- package/dist/sync/index.js +3 -0
- package/dist/sync/index.js.map +1 -0
- package/dist/sync/render.d.ts +9 -0
- package/dist/sync/render.d.ts.map +1 -0
- package/dist/sync/render.js +70 -0
- package/dist/sync/render.js.map +1 -0
- package/dist/sync/sync-files.d.ts +12 -0
- package/dist/sync/sync-files.d.ts.map +1 -0
- package/dist/sync/sync-files.js +29 -0
- package/dist/sync/sync-files.js.map +1 -0
- package/package.json +62 -0
- package/scripts/copy-yaml-rules.mjs +19 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { defineRule } from '@aicqtools/rule-sdk';
|
|
2
|
+
/**
|
|
3
|
+
* `import * as X from 'module'` namespace imports prevent tree-shaking and
|
|
4
|
+
* obscure dependency analysis. Prefer named imports unless the module
|
|
5
|
+
* genuinely exports many disparate symbols (rare).
|
|
6
|
+
*/
|
|
7
|
+
export default defineRule({
|
|
8
|
+
id: 'prefer-named-imports',
|
|
9
|
+
language: ['typescript', 'javascript', 'tsx'],
|
|
10
|
+
severity: 'info',
|
|
11
|
+
message: 'Avoid `import * as X` namespace imports; use named imports for tree-shaking.',
|
|
12
|
+
messageKo: '`import * as X` 네임스페이스 import 지양 — tree-shaking을 위해 named import 권장.',
|
|
13
|
+
visitors: {
|
|
14
|
+
import_statement(node, ctx) {
|
|
15
|
+
const text = ctx.textOf(node);
|
|
16
|
+
if (/import\s+\*\s+as\s+\w+/.test(text)) {
|
|
17
|
+
// Allow type-only namespace imports (less impact on bundle)
|
|
18
|
+
if (/import\s+type\s+\*/.test(text))
|
|
19
|
+
return;
|
|
20
|
+
ctx.report({ node });
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
//# sourceMappingURL=prefer-named-imports.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prefer-named-imports.js","sourceRoot":"","sources":["../../src/rules-default/prefer-named-imports.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEjD;;;;GAIG;AACH,eAAe,UAAU,CAAC;IACxB,EAAE,EAAE,sBAAsB;IAC1B,QAAQ,EAAE,CAAC,YAAY,EAAE,YAAY,EAAE,KAAK,CAAC;IAC7C,QAAQ,EAAE,MAAM;IAChB,OAAO,EAAE,8EAA8E;IACvF,SAAS,EAAE,sEAAsE;IACjF,QAAQ,EAAE;QACR,gBAAgB,CAAC,IAAI,EAAE,GAAG;YACxB,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAC9B,IAAI,wBAAwB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;gBACxC,4DAA4D;gBAC5D,IAAI,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC;oBAAE,OAAO;gBAC5C,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;YACvB,CAAC;QACH,CAAC;KACF;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preserve-transaction-log.d.ts","sourceRoot":"","sources":["../../src/rules-default/preserve-transaction-log.ts"],"names":[],"mappings":";AAsBA,wBAWG"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { defineRule } from '@aicqtools/rule-sdk';
|
|
2
|
+
/**
|
|
3
|
+
* PCI DSS § 10: financial transactions must produce an audit trail.
|
|
4
|
+
* Detect functions named pay/charge/payment/refund that lack any logging
|
|
5
|
+
* or transaction-table write call in their body.
|
|
6
|
+
*/
|
|
7
|
+
const TX_NAME = /^(pay|charge|payment|refund|cancelRefund|issueRefund|pay\w*|charge\w*|payment\w*|refund\w*)$/;
|
|
8
|
+
const LOG_OR_AUDIT = /\b(logger|auditLog|audit|winston|pino)\.\w+|\bconsole\.(log|info|warn|error)|\b(transactions|payment_log|paymentLogs|auditLogs|tx_log)\b.*\.(insert|create|save|push)/;
|
|
9
|
+
function check(node, ctx) {
|
|
10
|
+
const name = node.childForFieldName('name');
|
|
11
|
+
if (!name)
|
|
12
|
+
return;
|
|
13
|
+
const fnName = ctx.textOf(name);
|
|
14
|
+
if (!TX_NAME.test(fnName))
|
|
15
|
+
return;
|
|
16
|
+
const text = ctx.textOf(node);
|
|
17
|
+
if (LOG_OR_AUDIT.test(text))
|
|
18
|
+
return;
|
|
19
|
+
ctx.report({ node });
|
|
20
|
+
}
|
|
21
|
+
export default defineRule({
|
|
22
|
+
id: 'preserve-transaction-log',
|
|
23
|
+
language: ['typescript', 'tsx'],
|
|
24
|
+
severity: 'error',
|
|
25
|
+
message: 'Payment/refund function does not produce an audit log entry (PCI DSS § 10.2 — implement audit logs for all access to cardholder data).',
|
|
26
|
+
messageKo: '결제/환불 함수에 감사 로그 기록이 없습니다 (PCI DSS § 10.2 — 카드 소지자 데이터 접근에 대한 감사 로그 필수).',
|
|
27
|
+
docs: 'https://github.com/aicqtools/aicqtools/blob/main/docs/rules/preserve-transaction-log.md',
|
|
28
|
+
visitors: {
|
|
29
|
+
function_declaration: check,
|
|
30
|
+
method_definition: check,
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
//# sourceMappingURL=preserve-transaction-log.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preserve-transaction-log.js","sourceRoot":"","sources":["../../src/rules-default/preserve-transaction-log.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAGjD;;;;GAIG;AACH,MAAM,OAAO,GAAG,8FAA8F,CAAC;AAC/G,MAAM,YAAY,GAAG,uKAAuK,CAAC;AAE7L,SAAS,KAAK,CAAC,IAAuB,EAAE,GAAgB;IACtD,MAAM,IAAI,GAAG,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAC5C,IAAI,CAAC,IAAI;QAAE,OAAO;IAClB,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAChC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,OAAO;IAClC,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC9B,IAAI,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO;IACpC,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;AACvB,CAAC;AAED,eAAe,UAAU,CAAC;IACxB,EAAE,EAAE,0BAA0B;IAC9B,QAAQ,EAAE,CAAC,YAAY,EAAE,KAAK,CAAC;IAC/B,QAAQ,EAAE,OAAO;IACjB,OAAO,EAAE,wIAAwI;IACjJ,SAAS,EAAE,yEAAyE;IACpF,IAAI,EAAE,yFAAyF;IAC/F,QAAQ,EAAE;QACR,oBAAoB,EAAE,KAAK;QAC3B,iBAAiB,EAAE,KAAK;KACzB;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pytest-fixture-naming.d.ts","sourceRoot":"","sources":["../../src/rules-default/pytest-fixture-naming.ts"],"names":[],"mappings":";AAgBA,wBAeG"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { defineRule } from '@aicqtools/rule-sdk';
|
|
2
|
+
function hasPytestFixtureDecorator(node, textOf) {
|
|
3
|
+
// function_definition's parent is decorated_definition when decorated
|
|
4
|
+
const parent = node.parent;
|
|
5
|
+
if (!parent || parent.type !== 'decorated_definition')
|
|
6
|
+
return false;
|
|
7
|
+
for (let i = 0; i < parent.namedChildCount; i++) {
|
|
8
|
+
const child = parent.namedChild(i);
|
|
9
|
+
if (!child || child.type !== 'decorator')
|
|
10
|
+
continue;
|
|
11
|
+
const text = textOf(child);
|
|
12
|
+
if (/@pytest\.fixture\b/.test(text) || /^@fixture\b/.test(text))
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
export default defineRule({
|
|
18
|
+
id: 'pytest-fixture-naming',
|
|
19
|
+
language: 'python',
|
|
20
|
+
severity: 'warning',
|
|
21
|
+
message: 'pytest fixture should not start with `test_` (it would be collected as a test instead).',
|
|
22
|
+
messageKo: 'pytest fixture 함수는 `test_`로 시작하면 안 됩니다 (테스트로 인식되어 버립니다).',
|
|
23
|
+
visitors: {
|
|
24
|
+
function_definition(node, ctx) {
|
|
25
|
+
const name = node.childForFieldName('name');
|
|
26
|
+
if (!name)
|
|
27
|
+
return;
|
|
28
|
+
const nameText = ctx.textOf(name);
|
|
29
|
+
if (!nameText.startsWith('test_'))
|
|
30
|
+
return;
|
|
31
|
+
if (hasPytestFixtureDecorator(node, ctx.textOf))
|
|
32
|
+
ctx.report({ node: name });
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
//# sourceMappingURL=pytest-fixture-naming.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pytest-fixture-naming.js","sourceRoot":"","sources":["../../src/rules-default/pytest-fixture-naming.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEjD,SAAS,yBAAyB,CAAC,IAAuB,EAAE,MAAwC;IAClG,sEAAsE;IACtE,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;IAC3B,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,IAAI,KAAK,sBAAsB;QAAE,OAAO,KAAK,CAAC;IACpE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,eAAe,EAAE,CAAC,EAAE,EAAE,CAAC;QAChD,MAAM,KAAK,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QACnC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW;YAAE,SAAS;QACnD,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;QAC3B,IAAI,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;IAC/E,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,eAAe,UAAU,CAAC;IACxB,EAAE,EAAE,uBAAuB;IAC3B,QAAQ,EAAE,QAAQ;IAClB,QAAQ,EAAE,SAAS;IACnB,OAAO,EAAE,yFAAyF;IAClG,SAAS,EAAE,0DAA0D;IACrE,QAAQ,EAAE;QACR,mBAAmB,CAAC,IAAI,EAAE,GAAG;YAC3B,MAAM,IAAI,GAAG,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC;YAC5C,IAAI,CAAC,IAAI;gBAAE,OAAO;YAClB,MAAM,QAAQ,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAClC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,OAAO,CAAC;gBAAE,OAAO;YAC1C,IAAI,yBAAyB,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC;gBAAE,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9E,CAAC;KACF;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"requests-needs-timeout.d.ts","sourceRoot":"","sources":["../../src/rules-default/requests-needs-timeout.ts"],"names":[],"mappings":";AAiBA,wBAoBG"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { defineRule } from '@aicqtools/rule-sdk';
|
|
2
|
+
const REQUESTS_METHODS = new Set(['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'request']);
|
|
3
|
+
function hasTimeoutKwarg(args, textOf) {
|
|
4
|
+
for (let i = 0; i < args.namedChildCount; i++) {
|
|
5
|
+
const arg = args.namedChild(i);
|
|
6
|
+
if (!arg)
|
|
7
|
+
continue;
|
|
8
|
+
if (arg.type === 'keyword_argument') {
|
|
9
|
+
const name = arg.childForFieldName('name');
|
|
10
|
+
if (name && textOf(name) === 'timeout')
|
|
11
|
+
return true;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
export default defineRule({
|
|
17
|
+
id: 'requests-needs-timeout',
|
|
18
|
+
language: 'python',
|
|
19
|
+
severity: 'error',
|
|
20
|
+
message: 'requests call missing `timeout=...` — without it the call can hang indefinitely.',
|
|
21
|
+
messageKo: 'requests 호출에 `timeout=...` 누락 — 무한 대기 위험.',
|
|
22
|
+
visitors: {
|
|
23
|
+
call(node, ctx) {
|
|
24
|
+
const fn = node.childForFieldName('function');
|
|
25
|
+
if (!fn || fn.type !== 'attribute')
|
|
26
|
+
return;
|
|
27
|
+
const obj = fn.childForFieldName('object');
|
|
28
|
+
const attr = fn.childForFieldName('attribute');
|
|
29
|
+
if (!obj || !attr)
|
|
30
|
+
return;
|
|
31
|
+
if (ctx.textOf(obj) !== 'requests')
|
|
32
|
+
return;
|
|
33
|
+
if (!REQUESTS_METHODS.has(ctx.textOf(attr)))
|
|
34
|
+
return;
|
|
35
|
+
const args = node.childForFieldName('arguments');
|
|
36
|
+
if (!args)
|
|
37
|
+
return;
|
|
38
|
+
if (!hasTimeoutKwarg(args, ctx.textOf))
|
|
39
|
+
ctx.report({ node });
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
//# sourceMappingURL=requests-needs-timeout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"requests-needs-timeout.js","sourceRoot":"","sources":["../../src/rules-default/requests-needs-timeout.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEjD,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC;AAE1G,SAAS,eAAe,CAAC,IAAuB,EAAE,MAAwC;IACxF,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,CAAC,GAAG;YAAE,SAAS;QACnB,IAAI,GAAG,CAAC,IAAI,KAAK,kBAAkB,EAAE,CAAC;YACpC,MAAM,IAAI,GAAG,GAAG,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC;YAC3C,IAAI,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,SAAS;gBAAE,OAAO,IAAI,CAAC;QACtD,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,eAAe,UAAU,CAAC;IACxB,EAAE,EAAE,wBAAwB;IAC5B,QAAQ,EAAE,QAAQ;IAClB,QAAQ,EAAE,OAAO;IACjB,OAAO,EAAE,kFAAkF;IAC3F,SAAS,EAAE,2CAA2C;IACtD,QAAQ,EAAE;QACR,IAAI,CAAC,IAAI,EAAE,GAAG;YACZ,MAAM,EAAE,GAAG,IAAI,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC;YAC9C,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,IAAI,KAAK,WAAW;gBAAE,OAAO;YAC3C,MAAM,GAAG,GAAG,EAAE,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC;YAC3C,MAAM,IAAI,GAAG,EAAE,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAC;YAC/C,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI;gBAAE,OAAO;YAC1B,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,UAAU;gBAAE,OAAO;YAC3C,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;gBAAE,OAAO;YACpD,MAAM,IAAI,GAAG,IAAI,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAC;YACjD,IAAI,CAAC,IAAI;gBAAE,OAAO;YAClB,IAAI,CAAC,eAAe,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC;gBAAE,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/D,CAAC;KACF;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"require-idempotency-key.d.ts","sourceRoot":"","sources":["../../src/rules-default/require-idempotency-key.ts"],"names":[],"mappings":";AAgBA,wBA2BG"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { defineRule } from '@aicqtools/rule-sdk';
|
|
2
|
+
/**
|
|
3
|
+
* Payment best practice: charge/pay/refund operations must include an
|
|
4
|
+
* idempotency key to prevent double-spend on retry. Detect functions whose
|
|
5
|
+
* name contains `pay` / `charge` / `payment` and which lack an
|
|
6
|
+
* `idempotencyKey` / `Idempotency-Key` reference in the body.
|
|
7
|
+
*
|
|
8
|
+
* Limitation: name-based detection — functions named differently
|
|
9
|
+
* (`processOrder`, `bill`, etc.) are not flagged.
|
|
10
|
+
*/
|
|
11
|
+
const PAYMENT_NAME = /^(pay|charge|payment|chargePayment|pay\w*|charge\w*|payment\w*|process(Pay|Payment|Charge))$/;
|
|
12
|
+
const IDEMPOTENCY = /\b(idempotency[_-]?key|idempotencyKey|Idempotency-Key)\b/i;
|
|
13
|
+
export default defineRule({
|
|
14
|
+
id: 'require-idempotency-key',
|
|
15
|
+
language: ['typescript', 'tsx'],
|
|
16
|
+
severity: 'error',
|
|
17
|
+
message: 'Payment function missing an idempotency key — required to prevent double-charge on retry (payment-domain best practice; aligns with PCI DSS § 10.2 audit trail integrity).',
|
|
18
|
+
messageKo: '결제 함수에 idempotency key 누락 — 재시도 시 중복 청구 방지 필수 (결제 도메인 권장 사항; PCI DSS § 10.2 감사 추적 무결성 정렬).',
|
|
19
|
+
docs: 'https://github.com/aicqtools/aicqtools/blob/main/docs/rules/require-idempotency-key.md',
|
|
20
|
+
visitors: {
|
|
21
|
+
function_declaration(node, ctx) {
|
|
22
|
+
const name = node.childForFieldName('name');
|
|
23
|
+
if (!name)
|
|
24
|
+
return;
|
|
25
|
+
const fnName = ctx.textOf(name);
|
|
26
|
+
if (!PAYMENT_NAME.test(fnName))
|
|
27
|
+
return;
|
|
28
|
+
const text = ctx.textOf(node);
|
|
29
|
+
if (IDEMPOTENCY.test(text))
|
|
30
|
+
return;
|
|
31
|
+
ctx.report({ node });
|
|
32
|
+
},
|
|
33
|
+
method_definition(node, ctx) {
|
|
34
|
+
const name = node.childForFieldName('name');
|
|
35
|
+
if (!name)
|
|
36
|
+
return;
|
|
37
|
+
const fnName = ctx.textOf(name);
|
|
38
|
+
if (!PAYMENT_NAME.test(fnName))
|
|
39
|
+
return;
|
|
40
|
+
const text = ctx.textOf(node);
|
|
41
|
+
if (IDEMPOTENCY.test(text))
|
|
42
|
+
return;
|
|
43
|
+
ctx.report({ node });
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
//# sourceMappingURL=require-idempotency-key.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"require-idempotency-key.js","sourceRoot":"","sources":["../../src/rules-default/require-idempotency-key.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAGjD;;;;;;;;GAQG;AACH,MAAM,YAAY,GAAG,8FAA8F,CAAC;AACpH,MAAM,WAAW,GAAG,2DAA2D,CAAC;AAEhF,eAAe,UAAU,CAAC;IACxB,EAAE,EAAE,yBAAyB;IAC7B,QAAQ,EAAE,CAAC,YAAY,EAAE,KAAK,CAAC;IAC/B,QAAQ,EAAE,OAAO;IACjB,OAAO,EAAE,4KAA4K;IACrL,SAAS,EAAE,4FAA4F;IACvG,IAAI,EAAE,wFAAwF;IAC9F,QAAQ,EAAE;QACR,oBAAoB,CAAC,IAAuB,EAAE,GAAgB;YAC5D,MAAM,IAAI,GAAG,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC;YAC5C,IAAI,CAAC,IAAI;gBAAE,OAAO;YAClB,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAChC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC;gBAAE,OAAO;YACvC,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAC9B,IAAI,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC;gBAAE,OAAO;YACnC,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;QACvB,CAAC;QACD,iBAAiB,CAAC,IAAuB,EAAE,GAAgB;YACzD,MAAM,IAAI,GAAG,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC;YAC5C,IAAI,CAAC,IAAI;gBAAE,OAAO;YAClB,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAChC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC;gBAAE,OAAO;YACvC,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAC9B,IAAI,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC;gBAAE,OAAO;YACnC,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;QACvB,CAAC;KACF;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"require-tls-1-2-plus.d.ts","sourceRoot":"","sources":["../../src/rules-default/require-tls-1-2-plus.ts"],"names":[],"mappings":";AAWA,wBAkBG"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { defineRule } from '@aicqtools/rule-sdk';
|
|
2
|
+
/**
|
|
3
|
+
* PCI DSS § 4.1: cardholder data in transit must use strong cryptography.
|
|
4
|
+
* Detect TLS configuration that explicitly allows TLSv1 / TLSv1.1 via
|
|
5
|
+
* `secureProtocol` or `minVersion` options.
|
|
6
|
+
*/
|
|
7
|
+
const FORBIDDEN_PROTO = /['"`](TLSv1(_method)?|TLSv1\.1|TLSv1_1(_method)?|SSLv\d|SSLv\d_method)['"`]/;
|
|
8
|
+
export default defineRule({
|
|
9
|
+
id: 'require-tls-1-2-plus',
|
|
10
|
+
language: ['typescript', 'tsx'],
|
|
11
|
+
severity: 'error',
|
|
12
|
+
message: 'TLS configuration allows TLS < 1.2 (PCI DSS § 4.2.1 — strong cryptography for cardholder data in transit).',
|
|
13
|
+
messageKo: 'TLS 1.2 미만 프로토콜을 허용하는 설정 (PCI DSS § 4.2.1 — 카드 소지자 데이터 전송 시 강한 암호화 필수).',
|
|
14
|
+
docs: 'https://github.com/aicqtools/aicqtools/blob/main/docs/rules/require-tls-1-2-plus.md',
|
|
15
|
+
visitors: {
|
|
16
|
+
pair(node, ctx) {
|
|
17
|
+
const key = node.childForFieldName('key');
|
|
18
|
+
const value = node.childForFieldName('value');
|
|
19
|
+
if (!key || !value)
|
|
20
|
+
return;
|
|
21
|
+
const keyText = ctx.textOf(key).replace(/^['"`]|['"`]$/g, '');
|
|
22
|
+
if (keyText !== 'secureProtocol' && keyText !== 'minVersion')
|
|
23
|
+
return;
|
|
24
|
+
const valueText = ctx.textOf(value);
|
|
25
|
+
if (FORBIDDEN_PROTO.test(valueText))
|
|
26
|
+
ctx.report({ node });
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
//# sourceMappingURL=require-tls-1-2-plus.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"require-tls-1-2-plus.js","sourceRoot":"","sources":["../../src/rules-default/require-tls-1-2-plus.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAGjD;;;;GAIG;AACH,MAAM,eAAe,GAAG,6EAA6E,CAAC;AAEtG,eAAe,UAAU,CAAC;IACxB,EAAE,EAAE,sBAAsB;IAC1B,QAAQ,EAAE,CAAC,YAAY,EAAE,KAAK,CAAC;IAC/B,QAAQ,EAAE,OAAO;IACjB,OAAO,EAAE,4GAA4G;IACrH,SAAS,EAAE,yEAAyE;IACpF,IAAI,EAAE,qFAAqF;IAC3F,QAAQ,EAAE;QACR,IAAI,CAAC,IAAuB,EAAE,GAAgB;YAC5C,MAAM,GAAG,GAAG,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC;YAC1C,MAAM,KAAK,GAAG,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;YAC9C,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK;gBAAE,OAAO;YAC3B,MAAM,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,gBAAgB,EAAE,EAAE,CAAC,CAAC;YAC9D,IAAI,OAAO,KAAK,gBAAgB,IAAI,OAAO,KAAK,YAAY;gBAAE,OAAO;YACrE,MAAM,SAAS,GAAG,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACpC,IAAI,eAAe,CAAC,IAAI,CAAC,SAAS,CAAC;gBAAE,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5D,CAAC;KACF;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rfc5987-korean-filename.d.ts","sourceRoot":"","sources":["../../src/rules-default/rfc5987-korean-filename.ts"],"names":[],"mappings":";AAcA,wBAeG"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { defineRule } from '@aicqtools/rule-sdk';
|
|
2
|
+
/**
|
|
3
|
+
* `Content-Disposition: attachment; filename="<korean>.csv"` without RFC 5987 encoding
|
|
4
|
+
* breaks Korean filenames in older browsers (esp. IE11/old Safari). Use
|
|
5
|
+
* `filename*=UTF-8''<encoded>` form.
|
|
6
|
+
*
|
|
7
|
+
* Heuristic: inspect whole call expressions (e.g. `setHeader("Content-Disposition", "...")`)
|
|
8
|
+
* so multi-arg patterns where the header name and value live in separate strings are caught.
|
|
9
|
+
*/
|
|
10
|
+
const HAS_KOREAN = /[ㄱ-힝]/;
|
|
11
|
+
const HAS_RFC5987 = /filename\*\s*=\s*UTF-8''/i;
|
|
12
|
+
const HAS_CONTENT_DISPOSITION = /Content-Disposition/i;
|
|
13
|
+
export default defineRule({
|
|
14
|
+
id: 'rfc5987-korean-filename',
|
|
15
|
+
language: ['typescript', 'javascript', 'tsx'],
|
|
16
|
+
severity: 'warning',
|
|
17
|
+
message: 'Content-Disposition with Korean filename should use RFC 5987 (`filename*=UTF-8\'\'...`).',
|
|
18
|
+
messageKo: '한글 파일명 Content-Disposition은 RFC 5987 인코딩 필요 (`filename*=UTF-8\'\'...`).',
|
|
19
|
+
visitors: {
|
|
20
|
+
call_expression(node, ctx) {
|
|
21
|
+
const text = ctx.textOf(node);
|
|
22
|
+
if (!HAS_CONTENT_DISPOSITION.test(text))
|
|
23
|
+
return;
|
|
24
|
+
if (!HAS_KOREAN.test(text))
|
|
25
|
+
return;
|
|
26
|
+
if (HAS_RFC5987.test(text))
|
|
27
|
+
return;
|
|
28
|
+
ctx.report({ node });
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
//# sourceMappingURL=rfc5987-korean-filename.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rfc5987-korean-filename.js","sourceRoot":"","sources":["../../src/rules-default/rfc5987-korean-filename.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEjD;;;;;;;GAOG;AACH,MAAM,UAAU,GAAG,OAAO,CAAC;AAC3B,MAAM,WAAW,GAAG,2BAA2B,CAAC;AAChD,MAAM,uBAAuB,GAAG,sBAAsB,CAAC;AAEvD,eAAe,UAAU,CAAC;IACxB,EAAE,EAAE,yBAAyB;IAC7B,QAAQ,EAAE,CAAC,YAAY,EAAE,YAAY,EAAE,KAAK,CAAC;IAC7C,QAAQ,EAAE,SAAS;IACnB,OAAO,EAAE,0FAA0F;IACnG,SAAS,EAAE,yEAAyE;IACpF,QAAQ,EAAE;QACR,eAAe,CAAC,IAAI,EAAE,GAAG;YACvB,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAC9B,IAAI,CAAC,uBAAuB,CAAC,IAAI,CAAC,IAAI,CAAC;gBAAE,OAAO;YAChD,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC;gBAAE,OAAO;YACnC,IAAI,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC;gBAAE,OAAO;YACnC,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;QACvB,CAAC;KACF;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route-needs-auth.d.ts","sourceRoot":"","sources":["../../src/rules-default/route-needs-auth.ts"],"names":[],"mappings":";AAkBA,wBA2BG"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { defineRule } from '@aicqtools/rule-sdk';
|
|
2
|
+
const ROUTER_METHODS = new Set(['get', 'post', 'put', 'patch', 'delete']);
|
|
3
|
+
const AUTH_PATTERN = /auth(enticate)?|requireUser|requireAuth|isAuthenticated/i;
|
|
4
|
+
// Public path patterns that don't require auth
|
|
5
|
+
const PUBLIC_PATH_PATTERN = /^["'`](\/health|\/ping|\/login|\/signup|\/auth\/|\/public\/)/;
|
|
6
|
+
function isRouterCall(callee, textOf) {
|
|
7
|
+
if (callee.type !== 'member_expression')
|
|
8
|
+
return false;
|
|
9
|
+
const obj = callee.childForFieldName('object');
|
|
10
|
+
const prop = callee.childForFieldName('property');
|
|
11
|
+
if (!obj || !prop)
|
|
12
|
+
return false;
|
|
13
|
+
const objText = textOf(obj);
|
|
14
|
+
if (objText !== 'router' && objText !== 'app')
|
|
15
|
+
return false;
|
|
16
|
+
return ROUTER_METHODS.has(textOf(prop));
|
|
17
|
+
}
|
|
18
|
+
export default defineRule({
|
|
19
|
+
id: 'route-needs-auth',
|
|
20
|
+
language: ['typescript', 'javascript', 'tsx'],
|
|
21
|
+
severity: 'error',
|
|
22
|
+
message: 'Route is missing an authentication middleware (e.g. `authenticate`, `requireAuth`).',
|
|
23
|
+
messageKo: '라우트에 인증 미들웨어가 빠졌습니다 (`authenticate` / `requireAuth` 등).',
|
|
24
|
+
visitors: {
|
|
25
|
+
call_expression(node, ctx) {
|
|
26
|
+
const callee = node.childForFieldName('function');
|
|
27
|
+
if (!callee || !isRouterCall(callee, ctx.textOf))
|
|
28
|
+
return;
|
|
29
|
+
const args = node.childForFieldName('arguments');
|
|
30
|
+
if (!args || args.namedChildCount < 2)
|
|
31
|
+
return;
|
|
32
|
+
const pathArg = args.namedChild(0);
|
|
33
|
+
if (pathArg && PUBLIC_PATH_PATTERN.test(ctx.textOf(pathArg)))
|
|
34
|
+
return;
|
|
35
|
+
let hasAuth = false;
|
|
36
|
+
for (let i = 1; i < args.namedChildCount; i++) {
|
|
37
|
+
const arg = args.namedChild(i);
|
|
38
|
+
if (arg && AUTH_PATTERN.test(ctx.textOf(arg))) {
|
|
39
|
+
hasAuth = true;
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (!hasAuth)
|
|
44
|
+
ctx.report({ node });
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
//# sourceMappingURL=route-needs-auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route-needs-auth.js","sourceRoot":"","sources":["../../src/rules-default/route-needs-auth.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEjD,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;AAC1E,MAAM,YAAY,GAAG,0DAA0D,CAAC;AAChF,+CAA+C;AAC/C,MAAM,mBAAmB,GAAG,8DAA8D,CAAC;AAE3F,SAAS,YAAY,CAAC,MAAyB,EAAE,MAAwC;IACvF,IAAI,MAAM,CAAC,IAAI,KAAK,mBAAmB;QAAE,OAAO,KAAK,CAAC;IACtD,MAAM,GAAG,GAAG,MAAM,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IAC/C,MAAM,IAAI,GAAG,MAAM,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC;IAClD,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI;QAAE,OAAO,KAAK,CAAC;IAChC,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IAC5B,IAAI,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK;QAAE,OAAO,KAAK,CAAC;IAC5D,OAAO,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;AAC1C,CAAC;AAED,eAAe,UAAU,CAAC;IACxB,EAAE,EAAE,kBAAkB;IACtB,QAAQ,EAAE,CAAC,YAAY,EAAE,YAAY,EAAE,KAAK,CAAC;IAC7C,QAAQ,EAAE,OAAO;IACjB,OAAO,EAAE,qFAAqF;IAC9F,SAAS,EAAE,yDAAyD;IACpE,QAAQ,EAAE;QACR,eAAe,CAAC,IAAI,EAAE,GAAG;YACvB,MAAM,MAAM,GAAG,IAAI,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC;YAClD,IAAI,CAAC,MAAM,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC;gBAAE,OAAO;YACzD,MAAM,IAAI,GAAG,IAAI,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAC;YACjD,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,eAAe,GAAG,CAAC;gBAAE,OAAO;YAE9C,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;YACnC,IAAI,OAAO,IAAI,mBAAmB,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;gBAAE,OAAO;YAErE,IAAI,OAAO,GAAG,KAAK,CAAC;YACpB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC9C,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;gBAC/B,IAAI,GAAG,IAAI,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;oBAC9C,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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route-needs-rate-limit.d.ts","sourceRoot":"","sources":["../../src/rules-default/route-needs-rate-limit.ts"],"names":[],"mappings":";AAqBA,wBAuBG"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { defineRule } from '@aicqtools/rule-sdk';
|
|
2
|
+
const ROUTER_METHODS = new Set(['get', 'post', 'put', 'patch', 'delete']);
|
|
3
|
+
const RATE_LIMIT_PATTERN = /rate.?limit/i;
|
|
4
|
+
function isRouterCall(callee, textOf) {
|
|
5
|
+
if (callee.type !== 'member_expression')
|
|
6
|
+
return false;
|
|
7
|
+
const obj = callee.childForFieldName('object');
|
|
8
|
+
const prop = callee.childForFieldName('property');
|
|
9
|
+
if (!obj || !prop)
|
|
10
|
+
return false;
|
|
11
|
+
const objText = textOf(obj);
|
|
12
|
+
if (objText !== 'router' && objText !== 'app')
|
|
13
|
+
return false;
|
|
14
|
+
return ROUTER_METHODS.has(textOf(prop));
|
|
15
|
+
}
|
|
16
|
+
function argHasRateLimit(arg, textOf) {
|
|
17
|
+
const text = textOf(arg);
|
|
18
|
+
return RATE_LIMIT_PATTERN.test(text);
|
|
19
|
+
}
|
|
20
|
+
export default defineRule({
|
|
21
|
+
id: 'route-needs-rate-limit',
|
|
22
|
+
language: ['typescript', 'javascript', 'tsx'],
|
|
23
|
+
severity: 'error',
|
|
24
|
+
message: 'New route is missing a rate-limit middleware.',
|
|
25
|
+
messageKo: '새 라우트에 rate-limit 미들웨어가 빠졌습니다.',
|
|
26
|
+
visitors: {
|
|
27
|
+
call_expression(node, ctx) {
|
|
28
|
+
const callee = node.childForFieldName('function');
|
|
29
|
+
if (!callee || !isRouterCall(callee, ctx.textOf))
|
|
30
|
+
return;
|
|
31
|
+
const args = node.childForFieldName('arguments');
|
|
32
|
+
if (!args)
|
|
33
|
+
return;
|
|
34
|
+
let hasRateLimit = false;
|
|
35
|
+
for (let i = 0; i < args.namedChildCount; i++) {
|
|
36
|
+
const arg = args.namedChild(i);
|
|
37
|
+
if (arg && argHasRateLimit(arg, ctx.textOf)) {
|
|
38
|
+
hasRateLimit = true;
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (!hasRateLimit)
|
|
43
|
+
ctx.report({ node });
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
//# sourceMappingURL=route-needs-rate-limit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route-needs-rate-limit.js","sourceRoot":"","sources":["../../src/rules-default/route-needs-rate-limit.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEjD,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;AAC1E,MAAM,kBAAkB,GAAG,cAAc,CAAC;AAE1C,SAAS,YAAY,CAAC,MAAyB,EAAE,MAAwC;IACvF,IAAI,MAAM,CAAC,IAAI,KAAK,mBAAmB;QAAE,OAAO,KAAK,CAAC;IACtD,MAAM,GAAG,GAAG,MAAM,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IAC/C,MAAM,IAAI,GAAG,MAAM,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC;IAClD,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI;QAAE,OAAO,KAAK,CAAC;IAChC,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IAC5B,IAAI,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK;QAAE,OAAO,KAAK,CAAC;IAC5D,OAAO,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;AAC1C,CAAC;AAED,SAAS,eAAe,CAAC,GAAsB,EAAE,MAAwC;IACvF,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IACzB,OAAO,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACvC,CAAC;AAED,eAAe,UAAU,CAAC;IACxB,EAAE,EAAE,wBAAwB;IAC5B,QAAQ,EAAE,CAAC,YAAY,EAAE,YAAY,EAAE,KAAK,CAAC;IAC7C,QAAQ,EAAE,OAAO;IACjB,OAAO,EAAE,+CAA+C;IACxD,SAAS,EAAE,gCAAgC;IAC3C,QAAQ,EAAE;QACR,eAAe,CAAC,IAAI,EAAE,GAAG;YACvB,MAAM,MAAM,GAAG,IAAI,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC;YAClD,IAAI,CAAC,MAAM,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC;gBAAE,OAAO;YACzD,MAAM,IAAI,GAAG,IAAI,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAC;YACjD,IAAI,CAAC,IAAI;gBAAE,OAAO;YAClB,IAAI,YAAY,GAAG,KAAK,CAAC;YACzB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC9C,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;gBAC/B,IAAI,GAAG,IAAI,eAAe,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;oBAC5C,YAAY,GAAG,IAAI,CAAC;oBACpB,MAAM;gBACR,CAAC;YACH,CAAC;YACD,IAAI,CAAC,YAAY;gBAAE,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1C,CAAC;KACF;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"separate-refund-permission.d.ts","sourceRoot":"","sources":["../../src/rules-default/separate-refund-permission.ts"],"names":[],"mappings":";AAsBA,wBAWG"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { defineRule } from '@aicqtools/rule-sdk';
|
|
2
|
+
/**
|
|
3
|
+
* Refund operations are highly privileged — separation of duties requires
|
|
4
|
+
* a permission check before invoking any refund logic. Detect functions
|
|
5
|
+
* named `refund*` whose body lacks a permission/role check.
|
|
6
|
+
*/
|
|
7
|
+
const REFUND_NAME = /^(refund|cancelRefund|issueRefund|refund\w*)$/;
|
|
8
|
+
const PERMISSION_CHECK = /\b(req\.user\.role|hasPermission|checkPermission|isAdmin|requireRole|allowedRoles|authGuard|RBAC|canRefund|verifyPermission)\b/i;
|
|
9
|
+
function check(node, ctx) {
|
|
10
|
+
const name = node.childForFieldName('name');
|
|
11
|
+
if (!name)
|
|
12
|
+
return;
|
|
13
|
+
const fnName = ctx.textOf(name);
|
|
14
|
+
if (!REFUND_NAME.test(fnName))
|
|
15
|
+
return;
|
|
16
|
+
const text = ctx.textOf(node);
|
|
17
|
+
if (PERMISSION_CHECK.test(text))
|
|
18
|
+
return;
|
|
19
|
+
ctx.report({ node });
|
|
20
|
+
}
|
|
21
|
+
export default defineRule({
|
|
22
|
+
id: 'separate-refund-permission',
|
|
23
|
+
language: ['typescript', 'tsx'],
|
|
24
|
+
severity: 'error',
|
|
25
|
+
message: 'Refund function lacks a permission/role check (PCI DSS § 7.2 — restrict access by business need-to-know; separation of duties).',
|
|
26
|
+
messageKo: '환불 함수에 권한 체크가 없습니다 (PCI DSS § 7.2 — 업무 필요에 따른 접근 제한; 직무 분리 원칙).',
|
|
27
|
+
docs: 'https://github.com/aicqtools/aicqtools/blob/main/docs/rules/separate-refund-permission.md',
|
|
28
|
+
visitors: {
|
|
29
|
+
function_declaration: check,
|
|
30
|
+
method_definition: check,
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
//# sourceMappingURL=separate-refund-permission.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"separate-refund-permission.js","sourceRoot":"","sources":["../../src/rules-default/separate-refund-permission.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAGjD;;;;GAIG;AACH,MAAM,WAAW,GAAG,+CAA+C,CAAC;AACpE,MAAM,gBAAgB,GAAG,iIAAiI,CAAC;AAE3J,SAAS,KAAK,CAAC,IAAuB,EAAE,GAAgB;IACtD,MAAM,IAAI,GAAG,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAC5C,IAAI,CAAC,IAAI;QAAE,OAAO;IAClB,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAChC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,OAAO;IACtC,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC9B,IAAI,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO;IACxC,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;AACvB,CAAC;AAED,eAAe,UAAU,CAAC;IACxB,EAAE,EAAE,4BAA4B;IAChC,QAAQ,EAAE,CAAC,YAAY,EAAE,KAAK,CAAC;IAC/B,QAAQ,EAAE,OAAO;IACjB,OAAO,EAAE,iIAAiI;IAC1I,SAAS,EAAE,iEAAiE;IAC5E,IAAI,EAAE,2FAA2F;IACjG,QAAQ,EAAE;QACR,oBAAoB,EAAE,KAAK;QAC3B,iBAAiB,EAAE,KAAK;KACzB;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"track-ai-model-version.d.ts","sourceRoot":"","sources":["../../src/rules-default/track-ai-model-version.ts"],"names":[],"mappings":";AAeA,wBAoBG"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { defineRule } from '@aicqtools/rule-sdk';
|
|
2
|
+
/**
|
|
3
|
+
* FSC AI guideline: AI inference calls must specify the model name explicitly
|
|
4
|
+
* so audits can trace which model produced a given decision. Detect calls to
|
|
5
|
+
* `openai.chat.completions.create()` / `anthropic.messages.create()` whose
|
|
6
|
+
* argument object lacks a `model:` property.
|
|
7
|
+
*
|
|
8
|
+
* Limitation: false negatives when the options object is built elsewhere and
|
|
9
|
+
* passed in as a variable.
|
|
10
|
+
*/
|
|
11
|
+
const TARGET_FN = /\b(openai\.chat\.completions\.create|anthropic\.messages\.create|openai\.completions\.create)$/;
|
|
12
|
+
export default defineRule({
|
|
13
|
+
id: 'track-ai-model-version',
|
|
14
|
+
language: ['typescript', 'tsx'],
|
|
15
|
+
severity: 'warning',
|
|
16
|
+
message: 'AI inference call missing explicit `model:` parameter (FSC AI guideline — model governance).',
|
|
17
|
+
messageKo: 'AI 추론 호출에 `model:` 파라미터가 명시되지 않았습니다 (금감원 AI 가이드라인 — 모델 거버넌스).',
|
|
18
|
+
docs: 'https://github.com/aicqtools/aicqtools/blob/main/docs/rules/track-ai-model-version.md',
|
|
19
|
+
visitors: {
|
|
20
|
+
call_expression(node, ctx) {
|
|
21
|
+
const fnNode = node.childForFieldName('function');
|
|
22
|
+
if (!fnNode)
|
|
23
|
+
return;
|
|
24
|
+
const fnText = ctx.textOf(fnNode);
|
|
25
|
+
if (!TARGET_FN.test(fnText))
|
|
26
|
+
return;
|
|
27
|
+
const args = node.childForFieldName('arguments');
|
|
28
|
+
if (!args)
|
|
29
|
+
return;
|
|
30
|
+
const argsText = ctx.textOf(args);
|
|
31
|
+
if (/\bmodel\s*:/.test(argsText))
|
|
32
|
+
return;
|
|
33
|
+
ctx.report({ node });
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
//# sourceMappingURL=track-ai-model-version.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"track-ai-model-version.js","sourceRoot":"","sources":["../../src/rules-default/track-ai-model-version.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAGjD;;;;;;;;GAQG;AACH,MAAM,SAAS,GAAG,gGAAgG,CAAC;AAEnH,eAAe,UAAU,CAAC;IACxB,EAAE,EAAE,wBAAwB;IAC5B,QAAQ,EAAE,CAAC,YAAY,EAAE,KAAK,CAAC;IAC/B,QAAQ,EAAE,SAAS;IACnB,OAAO,EAAE,8FAA8F;IACvG,SAAS,EAAE,+DAA+D;IAC1E,IAAI,EAAE,uFAAuF;IAC7F,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,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC;gBAAE,OAAO;YACpC,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,IAAI,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC;gBAAE,OAAO;YACzC,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;QACvB,CAAC;KACF;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public functions (not starting with `_`) should have a return type annotation.
|
|
3
|
+
* Helps catch type errors and serves as inline documentation.
|
|
4
|
+
*
|
|
5
|
+
* Heuristic: looks for `-> Type:` after parameter list. False positives possible
|
|
6
|
+
* for functions that genuinely have no useful return type, but that's rare.
|
|
7
|
+
*/
|
|
8
|
+
declare const _default: import("@aicqtools/rule-sdk").FunctionRule;
|
|
9
|
+
export default _default;
|
|
10
|
+
//# sourceMappingURL=type-hint-required-public.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"type-hint-required-public.d.ts","sourceRoot":"","sources":["../../src/rules-default/type-hint-required-public.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;;AACH,wBAgBG"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { defineRule } from '@aicqtools/rule-sdk';
|
|
2
|
+
/**
|
|
3
|
+
* Public functions (not starting with `_`) should have a return type annotation.
|
|
4
|
+
* Helps catch type errors and serves as inline documentation.
|
|
5
|
+
*
|
|
6
|
+
* Heuristic: looks for `-> Type:` after parameter list. False positives possible
|
|
7
|
+
* for functions that genuinely have no useful return type, but that's rare.
|
|
8
|
+
*/
|
|
9
|
+
export default defineRule({
|
|
10
|
+
id: 'type-hint-required-public',
|
|
11
|
+
language: 'python',
|
|
12
|
+
severity: 'info',
|
|
13
|
+
message: 'Public function is missing a return type annotation (`-> Type:`).',
|
|
14
|
+
messageKo: 'public 함수에 반환 타입 어노테이션 누락 (`-> Type:`).',
|
|
15
|
+
visitors: {
|
|
16
|
+
function_definition(node, ctx) {
|
|
17
|
+
const name = node.childForFieldName('name');
|
|
18
|
+
if (!name)
|
|
19
|
+
return;
|
|
20
|
+
const nameText = ctx.textOf(name);
|
|
21
|
+
if (nameText.startsWith('_'))
|
|
22
|
+
return;
|
|
23
|
+
const returnType = node.childForFieldName('return_type');
|
|
24
|
+
if (!returnType)
|
|
25
|
+
ctx.report({ node: name });
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
//# sourceMappingURL=type-hint-required-public.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"type-hint-required-public.js","sourceRoot":"","sources":["../../src/rules-default/type-hint-required-public.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEjD;;;;;;GAMG;AACH,eAAe,UAAU,CAAC;IACxB,EAAE,EAAE,2BAA2B;IAC/B,QAAQ,EAAE,QAAQ;IAClB,QAAQ,EAAE,MAAM;IAChB,OAAO,EAAE,mEAAmE;IAC5E,SAAS,EAAE,yCAAyC;IACpD,QAAQ,EAAE;QACR,mBAAmB,CAAC,IAAI,EAAE,GAAG;YAC3B,MAAM,IAAI,GAAG,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC;YAC5C,IAAI,CAAC,IAAI;gBAAE,OAAO;YAClB,MAAM,QAAQ,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAClC,IAAI,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC;gBAAE,OAAO;YACrC,MAAM,UAAU,GAAG,IAAI,CAAC,iBAAiB,CAAC,aAAa,CAAC,CAAC;YACzD,IAAI,CAAC,UAAU;gBAAE,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9C,CAAC;KACF;CACF,CAAC,CAAC"}
|