@kernlang/review 3.3.9 → 3.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/call-graph.d.ts +10 -0
- package/dist/call-graph.js +138 -9
- package/dist/call-graph.js.map +1 -1
- package/dist/concept-rules/auth-drift.js +2 -0
- package/dist/concept-rules/auth-drift.js.map +1 -1
- package/dist/concept-rules/auth-propagation-drift.js +2 -0
- package/dist/concept-rules/auth-propagation-drift.js.map +1 -1
- package/dist/concept-rules/body-shape-drift.d.ts +1 -1
- package/dist/concept-rules/body-shape-drift.js +5 -3
- package/dist/concept-rules/body-shape-drift.js.map +1 -1
- package/dist/concept-rules/contract-drift.js +3 -1
- package/dist/concept-rules/contract-drift.js.map +1 -1
- package/dist/concept-rules/contract-method-drift.js +2 -0
- package/dist/concept-rules/contract-method-drift.js.map +1 -1
- package/dist/concept-rules/index.js +2 -33
- package/dist/concept-rules/index.js.map +1 -1
- package/dist/concept-rules/request-validation-drift.js +3 -0
- package/dist/concept-rules/request-validation-drift.js.map +1 -1
- package/dist/concept-rules/root-cause.d.ts +4 -0
- package/dist/concept-rules/root-cause.js +31 -0
- package/dist/concept-rules/root-cause.js.map +1 -0
- package/dist/concept-rules/unbounded-collection-query.js +2 -0
- package/dist/concept-rules/unbounded-collection-query.js.map +1 -1
- package/dist/concept-rules/unhandled-api-error-shape.js +2 -0
- package/dist/concept-rules/unhandled-api-error-shape.js.map +1 -1
- package/dist/default-export.d.ts +41 -0
- package/dist/default-export.js +76 -0
- package/dist/default-export.js.map +1 -0
- package/dist/eval.d.ts +67 -0
- package/dist/eval.js +177 -0
- package/dist/eval.js.map +1 -0
- package/dist/file-context.js +32 -13
- package/dist/file-context.js.map +1 -1
- package/dist/file-role.d.ts +6 -0
- package/dist/file-role.js +27 -0
- package/dist/file-role.js.map +1 -1
- package/dist/framework-seeds.d.ts +46 -0
- package/dist/framework-seeds.js +245 -0
- package/dist/framework-seeds.js.map +1 -0
- package/dist/git-env.d.ts +1 -0
- package/dist/git-env.js +25 -0
- package/dist/git-env.js.map +1 -0
- package/dist/graph.js +246 -21
- package/dist/graph.js.map +1 -1
- package/dist/index.d.ts +10 -2
- package/dist/index.js +200 -56
- package/dist/index.js.map +1 -1
- package/dist/mappers/ts-concepts.js +87 -20
- package/dist/mappers/ts-concepts.js.map +1 -1
- package/dist/path-canonical.d.ts +34 -0
- package/dist/path-canonical.js +85 -0
- package/dist/path-canonical.js.map +1 -0
- package/dist/policy.d.ts +22 -0
- package/dist/policy.js +47 -0
- package/dist/policy.js.map +1 -0
- package/dist/project-context.d.ts +135 -0
- package/dist/project-context.js +563 -0
- package/dist/project-context.js.map +1 -0
- package/dist/public-api.d.ts +21 -0
- package/dist/public-api.js +17 -2
- package/dist/public-api.js.map +1 -1
- package/dist/reporter.js +22 -0
- package/dist/reporter.js.map +1 -1
- package/dist/rule-quality.d.ts +58 -0
- package/dist/rule-quality.js +357 -0
- package/dist/rule-quality.js.map +1 -0
- package/dist/rules/dead-code.d.ts +2 -2
- package/dist/rules/dead-code.js +88 -4
- package/dist/rules/dead-code.js.map +1 -1
- package/dist/rules/index.d.ts +22 -0
- package/dist/rules/index.js +32 -0
- package/dist/rules/index.js.map +1 -1
- package/dist/rules/kern-source.d.ts +4 -0
- package/dist/rules/kern-source.js +183 -0
- package/dist/rules/kern-source.js.map +1 -1
- package/dist/rules/react.js +52 -3
- package/dist/rules/react.js.map +1 -1
- package/dist/rules/suggest-kern-primitive.js +0 -1
- package/dist/rules/suggest-kern-primitive.js.map +1 -1
- package/dist/semantic-diff.js +2 -0
- package/dist/semantic-diff.js.map +1 -1
- package/dist/suppression/apply-suppression.js +2 -0
- package/dist/suppression/apply-suppression.js.map +1 -1
- package/dist/suppression/parse-directives.d.ts +13 -5
- package/dist/suppression/parse-directives.js +62 -8
- package/dist/suppression/parse-directives.js.map +1 -1
- package/dist/suppression/types.d.ts +9 -0
- package/dist/suppression/types.js +6 -1
- package/dist/suppression/types.js.map +1 -1
- package/dist/taint-crossfile.js +15 -8
- package/dist/taint-crossfile.js.map +1 -1
- package/dist/telemetry.d.ts +126 -0
- package/dist/telemetry.js +303 -0
- package/dist/telemetry.js.map +1 -0
- package/dist/types.d.ts +165 -1
- package/dist/types.js.map +1 -1
- package/package.json +4 -3
package/dist/policy.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ReviewConfig, ReviewPolicy } from './types.js';
|
|
2
|
+
export interface ReviewPolicyProfile {
|
|
3
|
+
policy: ReviewPolicy;
|
|
4
|
+
crossStackMode: 'guard' | 'audit';
|
|
5
|
+
minConfidence: number;
|
|
6
|
+
maxErrors?: number;
|
|
7
|
+
maxWarnings?: number;
|
|
8
|
+
strict?: false | 'inline' | 'all';
|
|
9
|
+
strictParse?: boolean;
|
|
10
|
+
description: string;
|
|
11
|
+
}
|
|
12
|
+
export interface ReviewPolicyExplicitOptions {
|
|
13
|
+
crossStackMode?: boolean;
|
|
14
|
+
minConfidence?: boolean;
|
|
15
|
+
maxErrors?: boolean;
|
|
16
|
+
maxWarnings?: boolean;
|
|
17
|
+
strict?: boolean;
|
|
18
|
+
strictParse?: boolean;
|
|
19
|
+
}
|
|
20
|
+
export declare function getReviewPolicyProfile(policy: ReviewPolicy): ReviewPolicyProfile;
|
|
21
|
+
export declare function inferReviewPolicy(config?: Pick<ReviewConfig, 'policy' | 'crossStackMode'>): ReviewPolicy;
|
|
22
|
+
export declare function applyReviewPolicyDefaults(config: ReviewConfig, explicit?: ReviewPolicyExplicitOptions): ReviewConfig;
|
package/dist/policy.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
const REVIEW_POLICY_PROFILES = {
|
|
2
|
+
guard: {
|
|
3
|
+
policy: 'guard',
|
|
4
|
+
crossStackMode: 'guard',
|
|
5
|
+
minConfidence: 0,
|
|
6
|
+
description: 'Low-noise review posture for local guardrails and PR feedback.',
|
|
7
|
+
},
|
|
8
|
+
ci: {
|
|
9
|
+
policy: 'ci',
|
|
10
|
+
crossStackMode: 'guard',
|
|
11
|
+
minConfidence: 0.75,
|
|
12
|
+
maxErrors: 0,
|
|
13
|
+
maxWarnings: 0,
|
|
14
|
+
strict: 'inline',
|
|
15
|
+
strictParse: true,
|
|
16
|
+
description: 'Strict CI posture: high-confidence findings only, no warnings by default, strict parsing.',
|
|
17
|
+
},
|
|
18
|
+
audit: {
|
|
19
|
+
policy: 'audit',
|
|
20
|
+
crossStackMode: 'audit',
|
|
21
|
+
minConfidence: 0,
|
|
22
|
+
description: 'Broad exploratory posture for local investigations and rule calibration.',
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
export function getReviewPolicyProfile(policy) {
|
|
26
|
+
return REVIEW_POLICY_PROFILES[policy];
|
|
27
|
+
}
|
|
28
|
+
export function inferReviewPolicy(config) {
|
|
29
|
+
if (config?.policy)
|
|
30
|
+
return config.policy;
|
|
31
|
+
return config?.crossStackMode === 'audit' ? 'audit' : 'guard';
|
|
32
|
+
}
|
|
33
|
+
export function applyReviewPolicyDefaults(config, explicit = {}) {
|
|
34
|
+
const policy = inferReviewPolicy(config);
|
|
35
|
+
const profile = getReviewPolicyProfile(policy);
|
|
36
|
+
return {
|
|
37
|
+
...config,
|
|
38
|
+
policy,
|
|
39
|
+
crossStackMode: explicit.crossStackMode ? config.crossStackMode : profile.crossStackMode,
|
|
40
|
+
minConfidence: explicit.minConfidence ? config.minConfidence : profile.minConfidence,
|
|
41
|
+
maxErrors: explicit.maxErrors ? config.maxErrors : (profile.maxErrors ?? config.maxErrors),
|
|
42
|
+
maxWarnings: explicit.maxWarnings ? config.maxWarnings : (profile.maxWarnings ?? config.maxWarnings),
|
|
43
|
+
strict: explicit.strict ? config.strict : (profile.strict ?? config.strict),
|
|
44
|
+
strictParse: explicit.strictParse ? config.strictParse : (profile.strictParse ?? config.strictParse),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy.js","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"AAsBA,MAAM,sBAAsB,GAA8C;IACxE,KAAK,EAAE;QACL,MAAM,EAAE,OAAO;QACf,cAAc,EAAE,OAAO;QACvB,aAAa,EAAE,CAAC;QAChB,WAAW,EAAE,gEAAgE;KAC9E;IACD,EAAE,EAAE;QACF,MAAM,EAAE,IAAI;QACZ,cAAc,EAAE,OAAO;QACvB,aAAa,EAAE,IAAI;QACnB,SAAS,EAAE,CAAC;QACZ,WAAW,EAAE,CAAC;QACd,MAAM,EAAE,QAAQ;QAChB,WAAW,EAAE,IAAI;QACjB,WAAW,EAAE,2FAA2F;KACzG;IACD,KAAK,EAAE;QACL,MAAM,EAAE,OAAO;QACf,cAAc,EAAE,OAAO;QACvB,aAAa,EAAE,CAAC;QAChB,WAAW,EAAE,0EAA0E;KACxF;CACF,CAAC;AAEF,MAAM,UAAU,sBAAsB,CAAC,MAAoB;IACzD,OAAO,sBAAsB,CAAC,MAAM,CAAC,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,MAAwD;IACxF,IAAI,MAAM,EAAE,MAAM;QAAE,OAAO,MAAM,CAAC,MAAM,CAAC;IACzC,OAAO,MAAM,EAAE,cAAc,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;AAChE,CAAC;AAED,MAAM,UAAU,yBAAyB,CACvC,MAAoB,EACpB,WAAwC,EAAE;IAE1C,MAAM,MAAM,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;IACzC,MAAM,OAAO,GAAG,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAE/C,OAAO;QACL,GAAG,MAAM;QACT,MAAM;QACN,cAAc,EAAE,QAAQ,CAAC,cAAc,CAAC,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,OAAO,CAAC,cAAc;QACxF,aAAa,EAAE,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa;QACpF,SAAS,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,IAAI,MAAM,CAAC,SAAS,CAAC;QAC1F,WAAW,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,IAAI,MAAM,CAAC,WAAW,CAAC;QACpG,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC;QAC3E,WAAW,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,IAAI,MAAM,CAAC,WAAW,CAAC;KACrG,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project-Context — repo-level signals for the review pipeline.
|
|
3
|
+
*
|
|
4
|
+
* Reads project configs (tsconfig.json, package.json) and .gitignore so rules
|
|
5
|
+
* can gate on what the user already enforces elsewhere. Designed to be SAFE on
|
|
6
|
+
* adversarial inputs:
|
|
7
|
+
*
|
|
8
|
+
* - **JSON-only.** No executable config readers (no eslint.config.js eval).
|
|
9
|
+
* Phase 2 may add YAML/TOML but only via safeLoad; never `require()` of a
|
|
10
|
+
* user-controlled file.
|
|
11
|
+
* - **Realpath containment.** Any path resolved from a config (extends, etc.)
|
|
12
|
+
* must live under the project root after `realpathSync` — otherwise it is
|
|
13
|
+
* ignored. Defends against `extends: '../../../etc/passwd'` and symlink
|
|
14
|
+
* traversal attacks surfaced by the Phase 1 red-team.
|
|
15
|
+
* - **Content-hash cache.** Cache key is hashed file content + extends chain
|
|
16
|
+
* (reuses the cache.ts pattern). mtime is unsound on second-resolution
|
|
17
|
+
* filesystems and on TOCTOU windows where bytes change but mtime does not.
|
|
18
|
+
* - **LRU eviction.** Max 128 cached project roots — defense against the
|
|
19
|
+
* long-running Guard bot accumulating per-PR worktree paths until OOM.
|
|
20
|
+
* - **Pattern-length cap on .gitignore.** Discards any individual pattern
|
|
21
|
+
* longer than 256 chars. Defense against ReDoS via crafted negation +
|
|
22
|
+
* quantifier patterns from the red-team.
|
|
23
|
+
*/
|
|
24
|
+
/** What `getProjectContext` returns. Extended in later phases. */
|
|
25
|
+
export interface ProjectContext {
|
|
26
|
+
/** Absolute, realpath-resolved project root. */
|
|
27
|
+
root: string;
|
|
28
|
+
/** Parsed root package.json — restricted to fields we care about. */
|
|
29
|
+
packageJson?: ProjectPackageJson;
|
|
30
|
+
/** Parsed tsconfig (top-level only — extends chain is hashed but not deep-merged here). */
|
|
31
|
+
tsconfig?: ProjectTsconfig;
|
|
32
|
+
/** Compiled .gitignore matchers, in walk order (root first, deeper later). */
|
|
33
|
+
gitignore: GitignoreMatchers;
|
|
34
|
+
/**
|
|
35
|
+
* External linter configurations — used to demote kern findings that overlap
|
|
36
|
+
* with rules the project already enforces. Phase 2 is intentionally limited
|
|
37
|
+
* to JSON-only readers: `.eslintrc.json`, `package.json` `eslintConfig`, and
|
|
38
|
+
* `biome.json`. `eslint.config.js` is **never** evaluated (RCE risk surfaced
|
|
39
|
+
* by Phase 1 red-team). Per-file `overrides` resolution requires the async
|
|
40
|
+
* ESLint API and is left to callers via a future pre-warm path.
|
|
41
|
+
*/
|
|
42
|
+
external: ExternalLinterConfig;
|
|
43
|
+
/**
|
|
44
|
+
* Set of POSIX-relative paths that `git ls-files` reports as tracked. A file
|
|
45
|
+
* being tracked overrides .gitignore for skip-list purposes — published
|
|
46
|
+
* artifacts (e.g. packages/sdk/dist/client.gen.ts) get reviewed even when
|
|
47
|
+
* the directory matches `.gitignore`. Empty set if not a git repo.
|
|
48
|
+
*/
|
|
49
|
+
gitTrackedFiles: Set<string>;
|
|
50
|
+
/**
|
|
51
|
+
* Stable hash of every config input that contributed to this context. Used as
|
|
52
|
+
* the cache key; if any config file changes, the hash changes and the entry
|
|
53
|
+
* is recomputed.
|
|
54
|
+
*/
|
|
55
|
+
contentHash: string;
|
|
56
|
+
}
|
|
57
|
+
export interface ProjectPackageJson {
|
|
58
|
+
name?: string;
|
|
59
|
+
type?: 'module' | 'commonjs';
|
|
60
|
+
workspaces?: string[];
|
|
61
|
+
bin?: Record<string, string> | string;
|
|
62
|
+
exports?: unknown;
|
|
63
|
+
private?: boolean;
|
|
64
|
+
}
|
|
65
|
+
export interface ProjectTsconfig {
|
|
66
|
+
/** True iff `compilerOptions.strict === true` is set on the resolved config. */
|
|
67
|
+
strict?: boolean;
|
|
68
|
+
/** Per-flag — overrides composite `strict`. Future phases dial confidence per flag. */
|
|
69
|
+
strictNullChecks?: boolean;
|
|
70
|
+
noImplicitAny?: boolean;
|
|
71
|
+
noUnusedLocals?: boolean;
|
|
72
|
+
noUnusedParameters?: boolean;
|
|
73
|
+
}
|
|
74
|
+
/** External linter rule IDs that are enabled at error/warn. */
|
|
75
|
+
export interface ExternalLinterConfig {
|
|
76
|
+
/** Rule IDs from `.eslintrc.json` / `package.json` eslintConfig that are at error or warn. */
|
|
77
|
+
eslintEnabledRules: Set<string>;
|
|
78
|
+
/** Rule IDs from `biome.json` linter.rules that are at error or warn. */
|
|
79
|
+
biomeEnabledRules: Set<string>;
|
|
80
|
+
}
|
|
81
|
+
/** Compiled gitignore matchers. Use `isPathIgnored` to query. */
|
|
82
|
+
export interface GitignoreMatchers {
|
|
83
|
+
/** Patterns from the project root's .gitignore, in declaration order. */
|
|
84
|
+
rootPatterns: GitignorePattern[];
|
|
85
|
+
}
|
|
86
|
+
export interface GitignorePattern {
|
|
87
|
+
/** Original line as written, post-trim. */
|
|
88
|
+
raw: string;
|
|
89
|
+
/** Compiled regex. Pattern-length capped at 256 to avoid ReDoS. */
|
|
90
|
+
regex: RegExp;
|
|
91
|
+
/** Negation rule (`!foo`) — re-includes a previously-ignored path. */
|
|
92
|
+
negate: boolean;
|
|
93
|
+
/** Pattern is anchored to repo root (no slash in middle of pattern). */
|
|
94
|
+
matchDirsOnly: boolean;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Walk up from a starting directory looking for the nearest `package.json`.
|
|
98
|
+
* Returns undefined if none is found before the filesystem root. Used by
|
|
99
|
+
* per-file review entry points that need a project context but only have a
|
|
100
|
+
* file path.
|
|
101
|
+
*/
|
|
102
|
+
export declare function findProjectRoot(startDir: string): string | undefined;
|
|
103
|
+
/**
|
|
104
|
+
* Get the project context for a project root. Cached by content hash —
|
|
105
|
+
* a config file edit invalidates the entry on next call.
|
|
106
|
+
*/
|
|
107
|
+
export declare function getProjectContext(projectRoot: string): ProjectContext;
|
|
108
|
+
/** Test-only: clear cache between tests. */
|
|
109
|
+
export declare function _resetProjectContextCache(): void;
|
|
110
|
+
/** Test-only: report current cache size. */
|
|
111
|
+
export declare function _projectContextCacheSize(): number;
|
|
112
|
+
/**
|
|
113
|
+
* Returns true iff the file is matched by the project's .gitignore. Use
|
|
114
|
+
* `isReviewable` for the full skip-list semantics — this is the gitignore
|
|
115
|
+
* predicate alone.
|
|
116
|
+
*/
|
|
117
|
+
export declare function isPathIgnored(filePath: string, ctx: ProjectContext): boolean;
|
|
118
|
+
/**
|
|
119
|
+
* Per-flag tsconfig strictness — phase 2.3 from the red-team. The composite
|
|
120
|
+
* `strict: true` is shorthand for several flags; users frequently enable
|
|
121
|
+
* `strictNullChecks` alone without the umbrella. Rules should query the
|
|
122
|
+
* specific flag they depend on, not `strict`, so that `strict:false` does
|
|
123
|
+
* not over-debuff a finding whose underlying guarantee is in fact present.
|
|
124
|
+
*/
|
|
125
|
+
export declare function isStrictFlagEffective(flag: keyof Required<ProjectTsconfig>, ctx: ProjectContext): boolean;
|
|
126
|
+
/**
|
|
127
|
+
* The full skip-list predicate. A file is reviewable iff it is NOT
|
|
128
|
+
* (gitignored AND not git-tracked).
|
|
129
|
+
*
|
|
130
|
+
* This is the Phase 1 red-team's finding #4 fix: a tracked artifact that lives
|
|
131
|
+
* inside a gitignored directory (the classic `packages/sdk/dist/client.gen.ts`
|
|
132
|
+
* case) must remain reviewable. Suppression-by-skip-list is reserved for
|
|
133
|
+
* truly-untracked outputs.
|
|
134
|
+
*/
|
|
135
|
+
export declare function isReviewable(filePath: string, ctx: ProjectContext): boolean;
|