@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,138 @@
|
|
|
1
|
+
import { readFile, readdir } from 'node:fs/promises';
|
|
2
|
+
import { dirname, extname, join, resolve } from 'node:path';
|
|
3
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
4
|
+
import { parseYamlRule } from '../matcher/yaml-rule.js';
|
|
5
|
+
// Phase 0 (TalkUp 사례 + 기본)
|
|
6
|
+
import noConsoleLog from './no-console-log.js';
|
|
7
|
+
import noIdOverwrite from './no-id-overwrite.js';
|
|
8
|
+
import routeNeedsRateLimit from './route-needs-rate-limit.js';
|
|
9
|
+
import controllerNeedsAsyncWrapper from './controller-needs-async-wrapper.js';
|
|
10
|
+
import fkNeedsOnDelete from './fk-needs-on-delete.js';
|
|
11
|
+
import apiResponseShape from './api-response-shape.js';
|
|
12
|
+
// S3.A — TS 글로벌 추가 (function-style)
|
|
13
|
+
import noBareThrow from './no-bare-throw.js';
|
|
14
|
+
import noEmptyCatch from './no-empty-catch.js';
|
|
15
|
+
import noProcessEnvLeak from './no-process-env-leak.js';
|
|
16
|
+
import routeNeedsAuth from './route-needs-auth.js';
|
|
17
|
+
import noMagicNumber from './no-magic-number.js';
|
|
18
|
+
import noDefaultExportFromLibs from './no-default-export-from-libs.js';
|
|
19
|
+
import preferConstArray from './prefer-const-array.js';
|
|
20
|
+
import noBooleanTrap from './no-boolean-trap.js';
|
|
21
|
+
import preferNamedImports from './prefer-named-imports.js';
|
|
22
|
+
import noJsonbCircular from './no-jsonb-circular.js';
|
|
23
|
+
// S3.B — Python 글로벌 (function-style; YAML은 자동 로드됨)
|
|
24
|
+
import requestsNeedsTimeout from './requests-needs-timeout.js';
|
|
25
|
+
import noShellTrue from './no-shell-true.js';
|
|
26
|
+
import noFstringSql from './no-fstring-sql.js';
|
|
27
|
+
import noMutableDefaultArg from './no-mutable-default-arg.js';
|
|
28
|
+
import noBareExcept from './no-bare-except.js';
|
|
29
|
+
import typeHintRequiredPublic from './type-hint-required-public.js';
|
|
30
|
+
import asyncAwaitConsistency from './async-await-consistency.js';
|
|
31
|
+
import pytestFixtureNaming from './pytest-fixture-naming.js';
|
|
32
|
+
// K1 — 한국 IT 컨벤션 (Phase 1a 베타)
|
|
33
|
+
import camelcaseMigrationColumn from './camelcase-migration-column.js';
|
|
34
|
+
import enforceUtf8Encoding from './enforce-utf8-encoding.js';
|
|
35
|
+
import explicitKstTimezone from './explicit-kst-timezone.js';
|
|
36
|
+
import wonFormatThousands from './won-format-thousands.js';
|
|
37
|
+
import rfc5987KoreanFilename from './rfc5987-korean-filename.js';
|
|
38
|
+
import naverKakaoOauthWebview from './naver-kakao-oauth-webview.js';
|
|
39
|
+
import koreanCommentEncoding from './korean-comment-encoding.js';
|
|
40
|
+
// K2 — 한국 도메인 컴플라이언스 (Phase 1b 베타)
|
|
41
|
+
// 금감원 AI 가이드라인 (5)
|
|
42
|
+
import auditLogAiDecision from './audit-log-ai-decision.js';
|
|
43
|
+
import maskPiiInAiPrompt from './mask-pii-in-ai-prompt.js';
|
|
44
|
+
import trackAiModelVersion from './track-ai-model-version.js';
|
|
45
|
+
import humanOversightCheckpoint from './human-oversight-checkpoint.js';
|
|
46
|
+
import aiExplainabilityMetadata from './ai-explainability-metadata.js';
|
|
47
|
+
// PCI DSS (8)
|
|
48
|
+
import noPlainCardNumber from './no-plain-card-number.js';
|
|
49
|
+
import noCvvLogging from './no-cvv-logging.js';
|
|
50
|
+
import requireTls12Plus from './require-tls-1-2-plus.js';
|
|
51
|
+
import verifyPgResponse from './verify-pg-response.js';
|
|
52
|
+
import requireIdempotencyKey from './require-idempotency-key.js';
|
|
53
|
+
import separateRefundPermission from './separate-refund-permission.js';
|
|
54
|
+
import preserveTransactionLog from './preserve-transaction-log.js';
|
|
55
|
+
import maskCardNumber from './mask-card-number.js';
|
|
56
|
+
export const builtinFunctionRules = [
|
|
57
|
+
// Phase 0
|
|
58
|
+
noConsoleLog,
|
|
59
|
+
noIdOverwrite,
|
|
60
|
+
routeNeedsRateLimit,
|
|
61
|
+
controllerNeedsAsyncWrapper,
|
|
62
|
+
fkNeedsOnDelete,
|
|
63
|
+
apiResponseShape,
|
|
64
|
+
// S3.A TS 글로벌
|
|
65
|
+
noBareThrow,
|
|
66
|
+
noEmptyCatch,
|
|
67
|
+
noProcessEnvLeak,
|
|
68
|
+
routeNeedsAuth,
|
|
69
|
+
noMagicNumber,
|
|
70
|
+
noDefaultExportFromLibs,
|
|
71
|
+
preferConstArray,
|
|
72
|
+
noBooleanTrap,
|
|
73
|
+
preferNamedImports,
|
|
74
|
+
noJsonbCircular,
|
|
75
|
+
// S3.B Python 글로벌
|
|
76
|
+
requestsNeedsTimeout,
|
|
77
|
+
noShellTrue,
|
|
78
|
+
noFstringSql,
|
|
79
|
+
noMutableDefaultArg,
|
|
80
|
+
noBareExcept,
|
|
81
|
+
typeHintRequiredPublic,
|
|
82
|
+
asyncAwaitConsistency,
|
|
83
|
+
pytestFixtureNaming,
|
|
84
|
+
// K1 한국 IT 컨벤션
|
|
85
|
+
camelcaseMigrationColumn,
|
|
86
|
+
enforceUtf8Encoding,
|
|
87
|
+
explicitKstTimezone,
|
|
88
|
+
wonFormatThousands,
|
|
89
|
+
rfc5987KoreanFilename,
|
|
90
|
+
naverKakaoOauthWebview,
|
|
91
|
+
koreanCommentEncoding,
|
|
92
|
+
// K2 금감원 AI 가이드라인
|
|
93
|
+
auditLogAiDecision,
|
|
94
|
+
maskPiiInAiPrompt,
|
|
95
|
+
trackAiModelVersion,
|
|
96
|
+
humanOversightCheckpoint,
|
|
97
|
+
aiExplainabilityMetadata,
|
|
98
|
+
// K2 PCI DSS
|
|
99
|
+
noPlainCardNumber,
|
|
100
|
+
noCvvLogging,
|
|
101
|
+
requireTls12Plus,
|
|
102
|
+
verifyPgResponse,
|
|
103
|
+
requireIdempotencyKey,
|
|
104
|
+
separateRefundPermission,
|
|
105
|
+
preserveTransactionLog,
|
|
106
|
+
maskCardNumber,
|
|
107
|
+
];
|
|
108
|
+
export async function loadBuiltinYamlRules() {
|
|
109
|
+
const dir = dirname(fileURLToPath(import.meta.url));
|
|
110
|
+
const entries = await readdir(dir);
|
|
111
|
+
const rules = [];
|
|
112
|
+
for (const entry of entries) {
|
|
113
|
+
if (extname(entry) === '.yaml' || extname(entry) === '.yml') {
|
|
114
|
+
const content = await readFile(join(dir, entry), 'utf-8');
|
|
115
|
+
rules.push(parseYamlRule(content));
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return rules;
|
|
119
|
+
}
|
|
120
|
+
export async function loadAllBuiltinRules() {
|
|
121
|
+
const yaml = await loadBuiltinYamlRules();
|
|
122
|
+
return [...builtinFunctionRules, ...yaml];
|
|
123
|
+
}
|
|
124
|
+
export async function loadFunctionRulesFromDir(dir) {
|
|
125
|
+
const absDir = resolve(dir);
|
|
126
|
+
const entries = await readdir(absDir);
|
|
127
|
+
const rules = [];
|
|
128
|
+
for (const entry of entries) {
|
|
129
|
+
if (extname(entry) === '.ts' || extname(entry) === '.js' || extname(entry) === '.mjs') {
|
|
130
|
+
const url = pathToFileURL(join(absDir, entry)).href;
|
|
131
|
+
const mod = (await import(url));
|
|
132
|
+
if (mod.default)
|
|
133
|
+
rules.push(mod.default);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return rules;
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/rules-default/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"korean-comment-encoding.d.ts","sourceRoot":"","sources":["../../src/rules-default/korean-comment-encoding.ts"],"names":[],"mappings":";AAeA,wBAYG"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { defineRule } from '@aicqtools/rule-sdk';
|
|
2
|
+
/**
|
|
3
|
+
* Detect mojibake (broken Korean) in comments — typical sign of EUC-KR / CP949
|
|
4
|
+
* source forced through a UTF-8 decoder.
|
|
5
|
+
*
|
|
6
|
+
* Heuristic: looks for runs of `�` or characters in the CJK Compatibility
|
|
7
|
+
* range that are very rare in well-formed Korean comments. False positives
|
|
8
|
+
* possible if the file legitimately uses these chars (e.g. Japanese mixed text).
|
|
9
|
+
*
|
|
10
|
+
* Known limitation: this rule is intentionally heuristic. v1.5 will use a proper
|
|
11
|
+
* encoding detection lib (e.g. chardet) at the file-loader level.
|
|
12
|
+
*/
|
|
13
|
+
const MOJIBAKE_PATTERN = /[�]{1,}|[㈠-㉃]{2,}|[豈-]{3,}/;
|
|
14
|
+
export default defineRule({
|
|
15
|
+
id: 'korean-comment-encoding',
|
|
16
|
+
language: ['typescript', 'javascript', 'tsx', 'python'],
|
|
17
|
+
severity: 'info',
|
|
18
|
+
message: 'Comment contains potential mojibake — file may have encoding issues.',
|
|
19
|
+
messageKo: '주석에 깨진 한글로 보이는 패턴이 있습니다 — 파일 인코딩을 확인하세요.',
|
|
20
|
+
visitors: {
|
|
21
|
+
comment(node, ctx) {
|
|
22
|
+
const text = ctx.textOf(node);
|
|
23
|
+
if (MOJIBAKE_PATTERN.test(text))
|
|
24
|
+
ctx.report({ node });
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
//# sourceMappingURL=korean-comment-encoding.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"korean-comment-encoding.js","sourceRoot":"","sources":["../../src/rules-default/korean-comment-encoding.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEjD;;;;;;;;;;GAUG;AACH,MAAM,gBAAgB,GAAG,6BAA6B,CAAC;AAEvD,eAAe,UAAU,CAAC;IACxB,EAAE,EAAE,yBAAyB;IAC7B,QAAQ,EAAE,CAAC,YAAY,EAAE,YAAY,EAAE,KAAK,EAAE,QAAQ,CAAC;IACvD,QAAQ,EAAE,MAAM;IAChB,OAAO,EAAE,sEAAsE;IAC/E,SAAS,EAAE,0CAA0C;IACrD,QAAQ,EAAE;QACR,OAAO,CAAC,IAAI,EAAE,GAAG;YACf,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAC9B,IAAI,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC;gBAAE,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;QACxD,CAAC;KACF;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mask-card-number.d.ts","sourceRoot":"","sources":["../../src/rules-default/mask-card-number.ts"],"names":[],"mappings":";AAaA,wBA2BG"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { defineRule } from '@aicqtools/rule-sdk';
|
|
2
|
+
/**
|
|
3
|
+
* PCI DSS § 3.3: when a PAN is displayed it must be masked. Detect raw
|
|
4
|
+
* `cardNumber` / `card_number` references inside `JSON.stringify(...)`,
|
|
5
|
+
* template literals, or string concatenations without an accompanying
|
|
6
|
+
* mask helper (`mask`, `redact`, `truncate`).
|
|
7
|
+
*/
|
|
8
|
+
const CARD_VAR = /\b(cardNumber|card_number|pan)\b/;
|
|
9
|
+
const MASK_HELPER = /\b(mask|redact|truncate|last4|maskCard)\w*\(/;
|
|
10
|
+
export default defineRule({
|
|
11
|
+
id: 'mask-card-number',
|
|
12
|
+
language: ['typescript', 'tsx'],
|
|
13
|
+
severity: 'error',
|
|
14
|
+
message: 'Card number is rendered without masking (PCI DSS § 3.4.1 — PAN must be masked when displayed; max first 6 + last 4).',
|
|
15
|
+
messageKo: '카드번호가 마스킹 없이 표시됩니다 (PCI DSS § 3.4.1 — PAN 표시 시 마스킹 필수; 최대 앞 6자리 + 뒷 4자리).',
|
|
16
|
+
docs: 'https://github.com/aicqtools/aicqtools/blob/main/docs/rules/mask-card-number.md',
|
|
17
|
+
visitors: {
|
|
18
|
+
template_string(node, ctx) {
|
|
19
|
+
const text = ctx.textOf(node);
|
|
20
|
+
if (!CARD_VAR.test(text))
|
|
21
|
+
return;
|
|
22
|
+
if (MASK_HELPER.test(text))
|
|
23
|
+
return;
|
|
24
|
+
ctx.report({ node });
|
|
25
|
+
},
|
|
26
|
+
call_expression(node, ctx) {
|
|
27
|
+
const fn = node.childForFieldName('function');
|
|
28
|
+
if (!fn)
|
|
29
|
+
return;
|
|
30
|
+
const fnText = ctx.textOf(fn);
|
|
31
|
+
if (fnText !== 'JSON.stringify')
|
|
32
|
+
return;
|
|
33
|
+
const args = node.childForFieldName('arguments');
|
|
34
|
+
if (!args)
|
|
35
|
+
return;
|
|
36
|
+
const argsText = ctx.textOf(args);
|
|
37
|
+
if (!CARD_VAR.test(argsText))
|
|
38
|
+
return;
|
|
39
|
+
if (MASK_HELPER.test(argsText))
|
|
40
|
+
return;
|
|
41
|
+
ctx.report({ node });
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
//# sourceMappingURL=mask-card-number.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mask-card-number.js","sourceRoot":"","sources":["../../src/rules-default/mask-card-number.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAGjD;;;;;GAKG;AACH,MAAM,QAAQ,GAAG,kCAAkC,CAAC;AACpD,MAAM,WAAW,GAAG,8CAA8C,CAAC;AAEnE,eAAe,UAAU,CAAC;IACxB,EAAE,EAAE,kBAAkB;IACtB,QAAQ,EAAE,CAAC,YAAY,EAAE,KAAK,CAAC;IAC/B,QAAQ,EAAE,OAAO;IACjB,OAAO,EAAE,sHAAsH;IAC/H,SAAS,EAAE,2EAA2E;IACtF,IAAI,EAAE,iFAAiF;IACvF,QAAQ,EAAE;QACR,eAAe,CAAC,IAAuB,EAAE,GAAgB;YACvD,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAC9B,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC;gBAAE,OAAO;YACjC,IAAI,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC;gBAAE,OAAO;YACnC,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;QACvB,CAAC;QACD,eAAe,CAAC,IAAuB,EAAE,GAAgB;YACvD,MAAM,EAAE,GAAG,IAAI,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC;YAC9C,IAAI,CAAC,EAAE;gBAAE,OAAO;YAChB,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAC9B,IAAI,MAAM,KAAK,gBAAgB;gBAAE,OAAO;YACxC,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,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC;gBAAE,OAAO;YACrC,IAAI,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC;gBAAE,OAAO;YACvC,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;QACvB,CAAC;KACF;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +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":";AAqBA,wBAmBG"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { defineRule } from '@aicqtools/rule-sdk';
|
|
2
|
+
/**
|
|
3
|
+
* FSC AI guideline: personal information (RRN, card number) must be masked
|
|
4
|
+
* before being passed to AI providers. Detect literal Korean RRN patterns
|
|
5
|
+
* (\d{6}-\d{7}) or 16-digit card numbers in string/template arguments of
|
|
6
|
+
* AI SDK calls.
|
|
7
|
+
*
|
|
8
|
+
* Limitation: false negatives if PII enters via interpolated variables;
|
|
9
|
+
* false positives if a legitimate test fixture contains a digit run.
|
|
10
|
+
*/
|
|
11
|
+
const RRN_PATTERN = /\b\d{6}-\d{7}\b/;
|
|
12
|
+
const CARD_PATTERN = /\b(?:\d[ -]?){15,16}\b/;
|
|
13
|
+
const AI_CALL = /\b(openai|anthropic|aiClient)\.\w+/;
|
|
14
|
+
function inspectArgsString(text) {
|
|
15
|
+
return RRN_PATTERN.test(text) || CARD_PATTERN.test(text);
|
|
16
|
+
}
|
|
17
|
+
export default defineRule({
|
|
18
|
+
id: 'mask-pii-in-ai-prompt',
|
|
19
|
+
language: ['typescript', 'tsx'],
|
|
20
|
+
severity: 'error',
|
|
21
|
+
message: 'AI prompt contains unmasked PII (Korean RRN or card number) — mask before sending (FSC AI guideline — privacy protection).',
|
|
22
|
+
messageKo: 'AI 프롬프트에 마스킹되지 않은 개인정보(주민번호/카드번호)가 포함되어 있습니다 — AI 호출 전 마스킹 필수 (금감원 AI 가이드라인 — 개인정보 보호).',
|
|
23
|
+
docs: 'https://github.com/aicqtools/aicqtools/blob/main/docs/rules/mask-pii-in-ai-prompt.md',
|
|
24
|
+
visitors: {
|
|
25
|
+
call_expression(node, ctx) {
|
|
26
|
+
const fnNode = node.childForFieldName('function');
|
|
27
|
+
if (!fnNode)
|
|
28
|
+
return;
|
|
29
|
+
const fnText = ctx.textOf(fnNode);
|
|
30
|
+
if (!AI_CALL.test(fnText))
|
|
31
|
+
return;
|
|
32
|
+
const args = node.childForFieldName('arguments');
|
|
33
|
+
if (!args)
|
|
34
|
+
return;
|
|
35
|
+
const argsText = ctx.textOf(args);
|
|
36
|
+
if (inspectArgsString(argsText))
|
|
37
|
+
ctx.report({ node });
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
//# sourceMappingURL=mask-pii-in-ai-prompt.js.map
|
|
@@ -0,0 +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;;;;;;;;GAQG;AACH,MAAM,WAAW,GAAG,iBAAiB,CAAC;AACtC,MAAM,YAAY,GAAG,wBAAwB,CAAC;AAC9C,MAAM,OAAO,GAAG,oCAAoC,CAAC;AAErD,SAAS,iBAAiB,CAAC,IAAY;IACrC,OAAO,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC3D,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,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,IAAI,iBAAiB,CAAC,QAAQ,CAAC;gBAAE,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;QACxD,CAAC;KACF;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"naver-kakao-oauth-webview.d.ts","sourceRoot":"","sources":["../../src/rules-default/naver-kakao-oauth-webview.ts"],"names":[],"mappings":";AAkBA,wBAoBG"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { defineRule } from '@aicqtools/rule-sdk';
|
|
2
|
+
/**
|
|
3
|
+
* Capacitor's `Browser.open()` opens an external Chrome Custom Tab on Android — but
|
|
4
|
+
* Naver/Kakao OAuth callbacks may not return to the in-app session correctly.
|
|
5
|
+
* Best practice (per soanjang's brain rule): use WebView-internal web flow instead.
|
|
6
|
+
*
|
|
7
|
+
* Known limitation: false positives if `Browser.open()` is used for non-OAuth URLs.
|
|
8
|
+
* v1.0 PoC accepts this in exchange for catching the common Capacitor mis-pattern.
|
|
9
|
+
*/
|
|
10
|
+
const KAKAO_NAVER_PATTERN = /(kakao|naver)/i;
|
|
11
|
+
function nthArgText(args, idx, textOf) {
|
|
12
|
+
const arg = args.namedChild(idx);
|
|
13
|
+
return arg ? textOf(arg) : null;
|
|
14
|
+
}
|
|
15
|
+
export default defineRule({
|
|
16
|
+
id: 'naver-kakao-oauth-webview',
|
|
17
|
+
language: ['typescript', 'javascript', 'tsx'],
|
|
18
|
+
severity: 'warning',
|
|
19
|
+
message: 'Capacitor Browser.open() with Kakao/Naver OAuth URL — use in-WebView web flow for callback continuity.',
|
|
20
|
+
messageKo: 'Capacitor Browser.open()으로 카카오/네이버 OAuth URL — 콜백 연속성을 위해 WebView 내 웹 플로우 권장.',
|
|
21
|
+
docs: 'https://github.com/aicqtools/aicqtools/blob/main/docs/rules/naver-kakao-oauth-webview.md',
|
|
22
|
+
visitors: {
|
|
23
|
+
call_expression(node, ctx) {
|
|
24
|
+
const fn = node.childForFieldName('function');
|
|
25
|
+
if (!fn)
|
|
26
|
+
return;
|
|
27
|
+
// Match `Browser.open(...)` exactly
|
|
28
|
+
if (ctx.textOf(fn) !== 'Browser.open')
|
|
29
|
+
return;
|
|
30
|
+
const args = node.childForFieldName('arguments');
|
|
31
|
+
if (!args || args.namedChildCount === 0)
|
|
32
|
+
return;
|
|
33
|
+
// Argument is usually an options object containing { url: '...' }
|
|
34
|
+
const optsText = nthArgText(args, 0, ctx.textOf) ?? '';
|
|
35
|
+
if (KAKAO_NAVER_PATTERN.test(optsText))
|
|
36
|
+
ctx.report({ node });
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
//# sourceMappingURL=naver-kakao-oauth-webview.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"naver-kakao-oauth-webview.js","sourceRoot":"","sources":["../../src/rules-default/naver-kakao-oauth-webview.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEjD;;;;;;;GAOG;AACH,MAAM,mBAAmB,GAAG,gBAAgB,CAAC;AAE7C,SAAS,UAAU,CAAC,IAAuB,EAAE,GAAW,EAAE,MAAwC;IAChG,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;IACjC,OAAO,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAClC,CAAC;AAED,eAAe,UAAU,CAAC;IACxB,EAAE,EAAE,2BAA2B;IAC/B,QAAQ,EAAE,CAAC,YAAY,EAAE,YAAY,EAAE,KAAK,CAAC;IAC7C,QAAQ,EAAE,SAAS;IACnB,OAAO,EAAE,wGAAwG;IACjH,SAAS,EAAE,+EAA+E;IAC1F,IAAI,EAAE,0FAA0F;IAChG,QAAQ,EAAE;QACR,eAAe,CAAC,IAAI,EAAE,GAAG;YACvB,MAAM,EAAE,GAAG,IAAI,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC;YAC9C,IAAI,CAAC,EAAE;gBAAE,OAAO;YAChB,oCAAoC;YACpC,IAAI,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,cAAc;gBAAE,OAAO;YAC9C,MAAM,IAAI,GAAG,IAAI,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAC;YACjD,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,eAAe,KAAK,CAAC;gBAAE,OAAO;YAChD,kEAAkE;YAClE,MAAM,QAAQ,GAAG,UAAU,CAAC,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;YACvD,IAAI,mBAAmB,CAAC,IAAI,CAAC,QAAQ,CAAC;gBAAE,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/D,CAAC;KACF;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `except:` (no exception type) catches everything including SystemExit and KeyboardInterrupt.
|
|
3
|
+
* Always specify the exception class(es) to catch.
|
|
4
|
+
*/
|
|
5
|
+
declare const _default: import("@aicqtools/rule-sdk").FunctionRule;
|
|
6
|
+
export default _default;
|
|
7
|
+
//# sourceMappingURL=no-bare-except.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-bare-except.d.ts","sourceRoot":"","sources":["../../src/rules-default/no-bare-except.ts"],"names":[],"mappings":"AAEA;;;GAGG;;AACH,wBAgBG"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { defineRule } from '@aicqtools/rule-sdk';
|
|
2
|
+
/**
|
|
3
|
+
* `except:` (no exception type) catches everything including SystemExit and KeyboardInterrupt.
|
|
4
|
+
* Always specify the exception class(es) to catch.
|
|
5
|
+
*/
|
|
6
|
+
export default defineRule({
|
|
7
|
+
id: 'no-bare-except',
|
|
8
|
+
language: 'python',
|
|
9
|
+
severity: 'error',
|
|
10
|
+
message: 'Bare `except:` catches SystemExit/KeyboardInterrupt — specify exception type(s).',
|
|
11
|
+
messageKo: 'bare `except:`는 SystemExit/KeyboardInterrupt까지 잡습니다 — 예외 타입을 명시하세요.',
|
|
12
|
+
visitors: {
|
|
13
|
+
except_clause(node, ctx) {
|
|
14
|
+
// tree-sitter-python's except_clause: `except [exception_type [as name]]: body`
|
|
15
|
+
// Bare except has no type specifier between `except` and `:`.
|
|
16
|
+
const text = ctx.textOf(node).split('\n')[0] ?? '';
|
|
17
|
+
if (/^\s*except\s*:/.test(text)) {
|
|
18
|
+
ctx.report({ node });
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
//# sourceMappingURL=no-bare-except.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-bare-except.js","sourceRoot":"","sources":["../../src/rules-default/no-bare-except.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEjD;;;GAGG;AACH,eAAe,UAAU,CAAC;IACxB,EAAE,EAAE,gBAAgB;IACpB,QAAQ,EAAE,QAAQ;IAClB,QAAQ,EAAE,OAAO;IACjB,OAAO,EAAE,kFAAkF;IAC3F,SAAS,EAAE,qEAAqE;IAChF,QAAQ,EAAE;QACR,aAAa,CAAC,IAAI,EAAE,GAAG;YACrB,gFAAgF;YAChF,8DAA8D;YAC9D,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YACnD,IAAI,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;gBAChC,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;YACvB,CAAC;QACH,CAAC;KACF;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Forbids `throw <non-Error>` (e.g. `throw "msg"`, `throw 42`, `throw {x:1}`).
|
|
3
|
+
* Errors should always be Error instances or its subclasses for stack-trace + instanceof checks.
|
|
4
|
+
*/
|
|
5
|
+
declare const _default: import("@aicqtools/rule-sdk").FunctionRule;
|
|
6
|
+
export default _default;
|
|
7
|
+
//# sourceMappingURL=no-bare-throw.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-bare-throw.d.ts","sourceRoot":"","sources":["../../src/rules-default/no-bare-throw.ts"],"names":[],"mappings":"AAEA;;;GAGG;;AACH,wBAyBG"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { defineRule } from '@aicqtools/rule-sdk';
|
|
2
|
+
/**
|
|
3
|
+
* Forbids `throw <non-Error>` (e.g. `throw "msg"`, `throw 42`, `throw {x:1}`).
|
|
4
|
+
* Errors should always be Error instances or its subclasses for stack-trace + instanceof checks.
|
|
5
|
+
*/
|
|
6
|
+
export default defineRule({
|
|
7
|
+
id: 'no-bare-throw',
|
|
8
|
+
language: ['typescript', 'javascript', 'tsx'],
|
|
9
|
+
severity: 'error',
|
|
10
|
+
message: 'Throw an Error instance, not a raw value (string/number/object).',
|
|
11
|
+
messageKo: 'raw 값 대신 Error 인스턴스를 throw 하세요 (스택 트레이스 + instanceof 검사 가능).',
|
|
12
|
+
visitors: {
|
|
13
|
+
throw_statement(node, ctx) {
|
|
14
|
+
const expr = node.namedChild(0);
|
|
15
|
+
if (!expr)
|
|
16
|
+
return;
|
|
17
|
+
// Allow: new Error(...), new <SomethingError>(...), call expressions, identifiers (assume Error var)
|
|
18
|
+
if (expr.type === 'new_expression' || expr.type === 'identifier' || expr.type === 'call_expression')
|
|
19
|
+
return;
|
|
20
|
+
// Flag: string_literal, number, true/false, object literal
|
|
21
|
+
if (expr.type === 'string' ||
|
|
22
|
+
expr.type === 'template_string' ||
|
|
23
|
+
expr.type === 'number' ||
|
|
24
|
+
expr.type === 'true' ||
|
|
25
|
+
expr.type === 'false' ||
|
|
26
|
+
expr.type === 'object') {
|
|
27
|
+
ctx.report({ node });
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
//# sourceMappingURL=no-bare-throw.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-bare-throw.js","sourceRoot":"","sources":["../../src/rules-default/no-bare-throw.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEjD;;;GAGG;AACH,eAAe,UAAU,CAAC;IACxB,EAAE,EAAE,eAAe;IACnB,QAAQ,EAAE,CAAC,YAAY,EAAE,YAAY,EAAE,KAAK,CAAC;IAC7C,QAAQ,EAAE,OAAO;IACjB,OAAO,EAAE,kEAAkE;IAC3E,SAAS,EAAE,8DAA8D;IACzE,QAAQ,EAAE;QACR,eAAe,CAAC,IAAI,EAAE,GAAG;YACvB,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;YAChC,IAAI,CAAC,IAAI;gBAAE,OAAO;YAClB,qGAAqG;YACrG,IAAI,IAAI,CAAC,IAAI,KAAK,gBAAgB,IAAI,IAAI,CAAC,IAAI,KAAK,YAAY,IAAI,IAAI,CAAC,IAAI,KAAK,iBAAiB;gBAAE,OAAO;YAC5G,2DAA2D;YAC3D,IACE,IAAI,CAAC,IAAI,KAAK,QAAQ;gBACtB,IAAI,CAAC,IAAI,KAAK,iBAAiB;gBAC/B,IAAI,CAAC,IAAI,KAAK,QAAQ;gBACtB,IAAI,CAAC,IAAI,KAAK,MAAM;gBACpB,IAAI,CAAC,IAAI,KAAK,OAAO;gBACrB,IAAI,CAAC,IAAI,KAAK,QAAQ,EACtB,CAAC;gBACD,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;YACvB,CAAC;QACH,CAAC;KACF;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Functions with a single boolean argument force callers to write
|
|
3
|
+
* `doThing(true)` whose meaning is unclear at the call site. Use an
|
|
4
|
+
* options object instead (e.g. `doThing({ silent: true })`).
|
|
5
|
+
*/
|
|
6
|
+
declare const _default: import("@aicqtools/rule-sdk").FunctionRule;
|
|
7
|
+
export default _default;
|
|
8
|
+
//# sourceMappingURL=no-boolean-trap.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-boolean-trap.d.ts","sourceRoot":"","sources":["../../src/rules-default/no-boolean-trap.ts"],"names":[],"mappings":"AAEA;;;;GAIG;;AACH,wBAqBG"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { defineRule } from '@aicqtools/rule-sdk';
|
|
2
|
+
/**
|
|
3
|
+
* Functions with a single boolean argument force callers to write
|
|
4
|
+
* `doThing(true)` whose meaning is unclear at the call site. Use an
|
|
5
|
+
* options object instead (e.g. `doThing({ silent: true })`).
|
|
6
|
+
*/
|
|
7
|
+
export default defineRule({
|
|
8
|
+
id: 'no-boolean-trap',
|
|
9
|
+
language: ['typescript', 'javascript', 'tsx'],
|
|
10
|
+
severity: 'info',
|
|
11
|
+
message: 'Boolean-only function argument is opaque at call sites — prefer an options object.',
|
|
12
|
+
messageKo: '함수 인자에 boolean 단독은 호출부에서 의미가 불분명합니다 — 옵션 객체를 권장합니다.',
|
|
13
|
+
visitors: {
|
|
14
|
+
function_declaration(node, ctx) {
|
|
15
|
+
const params = node.childForFieldName('parameters');
|
|
16
|
+
if (!params)
|
|
17
|
+
return;
|
|
18
|
+
if (params.namedChildCount !== 1)
|
|
19
|
+
return;
|
|
20
|
+
const onlyParam = params.namedChild(0);
|
|
21
|
+
if (!onlyParam)
|
|
22
|
+
return;
|
|
23
|
+
const text = ctx.textOf(onlyParam);
|
|
24
|
+
// Skip object/array type literals (e.g. `opts: { silent: boolean }`)
|
|
25
|
+
if (text.includes('{') || text.includes('['))
|
|
26
|
+
return;
|
|
27
|
+
if (/:\s*boolean(\s|$|=)/.test(text)) {
|
|
28
|
+
ctx.report({ node: onlyParam });
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
//# sourceMappingURL=no-boolean-trap.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-boolean-trap.js","sourceRoot":"","sources":["../../src/rules-default/no-boolean-trap.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEjD;;;;GAIG;AACH,eAAe,UAAU,CAAC;IACxB,EAAE,EAAE,iBAAiB;IACrB,QAAQ,EAAE,CAAC,YAAY,EAAE,YAAY,EAAE,KAAK,CAAC;IAC7C,QAAQ,EAAE,MAAM;IAChB,OAAO,EAAE,oFAAoF;IAC7F,SAAS,EAAE,qDAAqD;IAChE,QAAQ,EAAE;QACR,oBAAoB,CAAC,IAAI,EAAE,GAAG;YAC5B,MAAM,MAAM,GAAG,IAAI,CAAC,iBAAiB,CAAC,YAAY,CAAC,CAAC;YACpD,IAAI,CAAC,MAAM;gBAAE,OAAO;YACpB,IAAI,MAAM,CAAC,eAAe,KAAK,CAAC;gBAAE,OAAO;YACzC,MAAM,SAAS,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;YACvC,IAAI,CAAC,SAAS;gBAAE,OAAO;YACvB,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;YACnC,qEAAqE;YACrE,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;gBAAE,OAAO;YACrD,IAAI,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;gBACrC,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;YAClC,CAAC;QACH,CAAC;KACF;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-console-log.d.ts","sourceRoot":"","sources":["../../src/rules-default/no-console-log.ts"],"names":[],"mappings":";AAEA,wBAcG"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { defineRule } from '@aicqtools/rule-sdk';
|
|
2
|
+
export default defineRule({
|
|
3
|
+
id: 'no-console-log',
|
|
4
|
+
language: ['typescript', 'javascript', 'tsx'],
|
|
5
|
+
severity: 'warning',
|
|
6
|
+
message: 'Avoid console.log in production code.',
|
|
7
|
+
messageKo: '운영 코드에서 console.log 사용을 피하세요.',
|
|
8
|
+
visitors: {
|
|
9
|
+
call_expression(node, ctx) {
|
|
10
|
+
const fn = node.childForFieldName('function');
|
|
11
|
+
if (!fn)
|
|
12
|
+
return;
|
|
13
|
+
const text = ctx.textOf(fn);
|
|
14
|
+
if (text === 'console.log')
|
|
15
|
+
ctx.report({ node });
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
//# sourceMappingURL=no-console-log.js.map
|
|
@@ -0,0 +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;AAEjD,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,QAAQ,EAAE;QACR,eAAe,CAAC,IAAI,EAAE,GAAG;YACvB,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,IAAI,IAAI,KAAK,aAAa;gBAAE,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;QACnD,CAAC;KACF;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-cvv-logging.d.ts","sourceRoot":"","sources":["../../src/rules-default/no-cvv-logging.ts"],"names":[],"mappings":";AAeA,wBAmBG"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { defineRule } from '@aicqtools/rule-sdk';
|
|
2
|
+
/**
|
|
3
|
+
* PCI DSS § 3.2: CVV/CVC must never be persisted or logged. Detect
|
|
4
|
+
* `console.log` / `logger.*` / `winston.*` / `pino.*` calls whose
|
|
5
|
+
* arguments reference a `cvv` / `cvc` identifier.
|
|
6
|
+
*
|
|
7
|
+
* Limitation: false positive when a variable is named `cvc` for unrelated
|
|
8
|
+
* reasons.
|
|
9
|
+
*/
|
|
10
|
+
const LOGGER_FN = /^(console\.(log|info|warn|error|debug)|(logger|winston|pino|log)\.\w+)$/;
|
|
11
|
+
const CVV_PATTERN = /\b(cvv|cvc|cvv2|cardSecurityCode)\b/i;
|
|
12
|
+
export default defineRule({
|
|
13
|
+
id: 'no-cvv-logging',
|
|
14
|
+
language: ['typescript', 'tsx'],
|
|
15
|
+
severity: 'error',
|
|
16
|
+
message: 'CVV/CVC must not appear in log output (PCI DSS § 3.3.1 — sensitive authentication data must not be stored after authorization).',
|
|
17
|
+
messageKo: 'CVV/CVC를 로그에 기록할 수 없습니다 (PCI DSS § 3.3.1 — 인증 후 민감 인증 데이터 저장 금지).',
|
|
18
|
+
docs: 'https://github.com/aicqtools/aicqtools/blob/main/docs/rules/no-cvv-logging.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 (!LOGGER_FN.test(fnText))
|
|
26
|
+
return;
|
|
27
|
+
const args = node.childForFieldName('arguments');
|
|
28
|
+
if (!args)
|
|
29
|
+
return;
|
|
30
|
+
const argsText = ctx.textOf(args);
|
|
31
|
+
if (CVV_PATTERN.test(argsText))
|
|
32
|
+
ctx.report({ node });
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
//# sourceMappingURL=no-cvv-logging.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-cvv-logging.js","sourceRoot":"","sources":["../../src/rules-default/no-cvv-logging.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAGjD;;;;;;;GAOG;AACH,MAAM,SAAS,GAAG,yEAAyE,CAAC;AAC5F,MAAM,WAAW,GAAG,sCAAsC,CAAC;AAE3D,eAAe,UAAU,CAAC;IACxB,EAAE,EAAE,gBAAgB;IACpB,QAAQ,EAAE,CAAC,YAAY,EAAE,KAAK,CAAC;IAC/B,QAAQ,EAAE,OAAO;IACjB,OAAO,EAAE,iIAAiI;IAC1I,SAAS,EAAE,mEAAmE;IAC9E,IAAI,EAAE,+EAA+E;IACrF,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,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC;gBAAE,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;QACvD,CAAC;KACF;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inside a `libs/` or `packages/` directory, prefer named exports for tree-shaking
|
|
3
|
+
* and clearer intent. `export default` makes refactoring/renaming harder across consumers.
|
|
4
|
+
*/
|
|
5
|
+
declare const _default: import("@aicqtools/rule-sdk").FunctionRule;
|
|
6
|
+
export default _default;
|
|
7
|
+
//# sourceMappingURL=no-default-export-from-libs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-default-export-from-libs.d.ts","sourceRoot":"","sources":["../../src/rules-default/no-default-export-from-libs.ts"],"names":[],"mappings":"AAEA;;;GAGG;;AACH,wBAgBG"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { defineRule } from '@aicqtools/rule-sdk';
|
|
2
|
+
/**
|
|
3
|
+
* Inside a `libs/` or `packages/` directory, prefer named exports for tree-shaking
|
|
4
|
+
* and clearer intent. `export default` makes refactoring/renaming harder across consumers.
|
|
5
|
+
*/
|
|
6
|
+
export default defineRule({
|
|
7
|
+
id: 'no-default-export-from-libs',
|
|
8
|
+
language: ['typescript', 'javascript', 'tsx'],
|
|
9
|
+
severity: 'warning',
|
|
10
|
+
message: 'Use named exports from libraries (default exports hinder tree-shaking and renames).',
|
|
11
|
+
messageKo: '라이브러리는 named export를 사용하세요 (default export는 tree-shaking·이름 변경에 불리).',
|
|
12
|
+
visitors: {
|
|
13
|
+
export_statement(node, ctx) {
|
|
14
|
+
// Only flag `export default ...` patterns inside lib/package directories
|
|
15
|
+
if (!/(^|[/\\])(libs?|packages)[/\\]/.test(ctx.filePath))
|
|
16
|
+
return;
|
|
17
|
+
const text = ctx.textOf(node);
|
|
18
|
+
if (text.startsWith('export default ')) {
|
|
19
|
+
ctx.report({ node });
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
//# sourceMappingURL=no-default-export-from-libs.js.map
|