@kernlang/review 3.3.8 → 3.3.9
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/cache.js +1 -1
- package/dist/concept-rules/auth-propagation-drift.d.ts +10 -0
- package/dist/concept-rules/auth-propagation-drift.js +83 -0
- package/dist/concept-rules/auth-propagation-drift.js.map +1 -0
- package/dist/concept-rules/body-shape-drift.d.ts +32 -0
- package/dist/concept-rules/body-shape-drift.js +96 -0
- package/dist/concept-rules/body-shape-drift.js.map +1 -0
- package/dist/concept-rules/cross-stack-utils.d.ts +24 -0
- package/dist/concept-rules/cross-stack-utils.js +123 -29
- package/dist/concept-rules/cross-stack-utils.js.map +1 -1
- package/dist/concept-rules/index.d.ts +4 -2
- package/dist/concept-rules/index.js +53 -3
- package/dist/concept-rules/index.js.map +1 -1
- package/dist/concept-rules/mutation-without-idempotency.d.ts +10 -0
- package/dist/concept-rules/mutation-without-idempotency.js +47 -0
- package/dist/concept-rules/mutation-without-idempotency.js.map +1 -0
- package/dist/concept-rules/request-validation-drift.d.ts +11 -0
- package/dist/concept-rules/request-validation-drift.js +96 -0
- package/dist/concept-rules/request-validation-drift.js.map +1 -0
- package/dist/concept-rules/unbounded-collection-query.d.ts +10 -0
- package/dist/concept-rules/unbounded-collection-query.js +56 -0
- package/dist/concept-rules/unbounded-collection-query.js.map +1 -0
- package/dist/concept-rules/unhandled-api-error-shape.d.ts +10 -0
- package/dist/concept-rules/unhandled-api-error-shape.js +57 -0
- package/dist/concept-rules/unhandled-api-error-shape.js.map +1 -0
- package/dist/external-tools.js +52 -3
- package/dist/external-tools.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +136 -62
- package/dist/index.js.map +1 -1
- package/dist/mappers/ts-concepts.js +663 -1
- package/dist/mappers/ts-concepts.js.map +1 -1
- package/dist/python-fallback.d.ts +2 -0
- package/dist/python-fallback.js +506 -0
- package/dist/python-fallback.js.map +1 -0
- package/dist/reporter.js +84 -1
- package/dist/reporter.js.map +1 -1
- package/dist/rules/base.js +21 -3
- package/dist/rules/base.js.map +1 -1
- package/dist/rules/index.js +40 -0
- package/dist/rules/index.js.map +1 -1
- package/dist/rules/kern-source.js +1 -0
- package/dist/rules/kern-source.js.map +1 -1
- package/dist/types.d.ts +7 -1
- package/dist/types.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule: mutation-without-idempotency
|
|
3
|
+
*
|
|
4
|
+
* Backend rule — fires on mutating HTTP routes that perform a DB write without
|
|
5
|
+
* visible idempotency, transaction, unique/upsert, or duplicate-protection
|
|
6
|
+
* evidence.
|
|
7
|
+
*/
|
|
8
|
+
import { createFingerprint } from '../types.js';
|
|
9
|
+
import { API_PATH_RE } from './cross-stack-utils.js';
|
|
10
|
+
const GUARD_MUTATING_METHODS = new Set(['POST']);
|
|
11
|
+
const AUDIT_MUTATING_METHODS = new Set(['POST', 'PATCH', 'DELETE']);
|
|
12
|
+
export function mutationWithoutIdempotency(ctx) {
|
|
13
|
+
const findings = [];
|
|
14
|
+
for (const node of ctx.concepts.nodes) {
|
|
15
|
+
if (node.kind !== 'entrypoint' || node.payload.kind !== 'entrypoint' || node.payload.subtype !== 'route')
|
|
16
|
+
continue;
|
|
17
|
+
const method = node.payload.httpMethod?.toUpperCase();
|
|
18
|
+
const mutatingMethods = ctx.crossStackMode === 'audit' ? AUDIT_MUTATING_METHODS : GUARD_MUTATING_METHODS;
|
|
19
|
+
if (!method || !mutatingMethods.has(method))
|
|
20
|
+
continue;
|
|
21
|
+
if (!API_PATH_RE.test(node.payload.name))
|
|
22
|
+
continue;
|
|
23
|
+
if (ctx.crossStackMode !== 'audit' && routeHasPathParam(node.payload.name))
|
|
24
|
+
continue;
|
|
25
|
+
if (node.payload.hasDbWrite !== true)
|
|
26
|
+
continue;
|
|
27
|
+
if (node.payload.hasIdempotencyProtection === true)
|
|
28
|
+
continue;
|
|
29
|
+
findings.push({
|
|
30
|
+
source: 'kern',
|
|
31
|
+
ruleId: 'mutation-without-idempotency',
|
|
32
|
+
severity: 'warning',
|
|
33
|
+
category: 'bug',
|
|
34
|
+
message: `Mutating route \`${method} ${node.payload.name}\` writes to the database without visible idempotency key, transaction, unique guard, upsert, or duplicate-protection evidence. Retries or double-submits can create duplicate side effects.`,
|
|
35
|
+
primarySpan: node.primarySpan,
|
|
36
|
+
fingerprint: createFingerprint('mutation-without-idempotency', node.primarySpan.startLine, node.primarySpan.startCol),
|
|
37
|
+
confidence: node.confidence * 0.75,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
return findings;
|
|
41
|
+
}
|
|
42
|
+
function routeHasPathParam(path) {
|
|
43
|
+
return path
|
|
44
|
+
.split('/')
|
|
45
|
+
.some((segment) => segment.startsWith(':') || (segment.startsWith('{') && segment.endsWith('}')));
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=mutation-without-idempotency.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mutation-without-idempotency.js","sourceRoot":"","sources":["../../src/concept-rules/mutation-without-idempotency.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAGrD,MAAM,sBAAsB,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AACjD,MAAM,sBAAsB,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;AAEpE,MAAM,UAAU,0BAA0B,CAAC,GAAuB;IAChE,MAAM,QAAQ,GAAoB,EAAE,CAAC;IAErC,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;QACtC,IAAI,IAAI,CAAC,IAAI,KAAK,YAAY,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,YAAY,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,KAAK,OAAO;YAAE,SAAS;QACnH,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,WAAW,EAAE,CAAC;QACtD,MAAM,eAAe,GAAG,GAAG,CAAC,cAAc,KAAK,OAAO,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,sBAAsB,CAAC;QACzG,IAAI,CAAC,MAAM,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC;YAAE,SAAS;QACtD,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;YAAE,SAAS;QACnD,IAAI,GAAG,CAAC,cAAc,KAAK,OAAO,IAAI,iBAAiB,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;YAAE,SAAS;QACrF,IAAI,IAAI,CAAC,OAAO,CAAC,UAAU,KAAK,IAAI;YAAE,SAAS;QAC/C,IAAI,IAAI,CAAC,OAAO,CAAC,wBAAwB,KAAK,IAAI;YAAE,SAAS;QAE7D,QAAQ,CAAC,IAAI,CAAC;YACZ,MAAM,EAAE,MAAM;YACd,MAAM,EAAE,8BAA8B;YACtC,QAAQ,EAAE,SAAS;YACnB,QAAQ,EAAE,KAAK;YACf,OAAO,EAAE,oBAAoB,MAAM,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,8LAA8L;YACtP,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,WAAW,EAAE,iBAAiB,CAC5B,8BAA8B,EAC9B,IAAI,CAAC,WAAW,CAAC,SAAS,EAC1B,IAAI,CAAC,WAAW,CAAC,QAAQ,CAC1B;YACD,UAAU,EAAE,IAAI,CAAC,UAAU,GAAG,IAAI;SACnC,CAAC,CAAC;IACL,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,iBAAiB,CAAC,IAAY;IACrC,OAAO,IAAI;SACR,KAAK,CAAC,GAAG,CAAC;SACV,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACtG,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule: request-validation-drift
|
|
3
|
+
*
|
|
4
|
+
* Cross-stack/backend rule:
|
|
5
|
+
* - client sends fields outside the backend's resolved validation schema;
|
|
6
|
+
* - or a mutating backend route reads body fields and writes to DB with no
|
|
7
|
+
* visible body validation.
|
|
8
|
+
*/
|
|
9
|
+
import type { ReviewFinding } from '../types.js';
|
|
10
|
+
import type { ConceptRuleContext } from './index.js';
|
|
11
|
+
export declare function requestValidationDrift(ctx: ConceptRuleContext): ReviewFinding[];
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule: request-validation-drift
|
|
3
|
+
*
|
|
4
|
+
* Cross-stack/backend rule:
|
|
5
|
+
* - client sends fields outside the backend's resolved validation schema;
|
|
6
|
+
* - or a mutating backend route reads body fields and writes to DB with no
|
|
7
|
+
* visible body validation.
|
|
8
|
+
*/
|
|
9
|
+
import { createFingerprint } from '../types.js';
|
|
10
|
+
import { API_PATH_RE, CROSS_STACK_HEURISTIC_CONFIDENCE, collectRoutesAcrossGraph, findHighConfidenceRouteForMethod, findMatchingRouteForMethod, normalizeClientUrl, } from './cross-stack-utils.js';
|
|
11
|
+
const GUARD_BODY_METHODS = new Set(['POST']);
|
|
12
|
+
const AUDIT_BODY_METHODS = new Set(['POST', 'PUT', 'PATCH']);
|
|
13
|
+
export function requestValidationDrift(ctx) {
|
|
14
|
+
const findings = [];
|
|
15
|
+
findings.push(...backendUnvalidatedBodyFindings(ctx));
|
|
16
|
+
findings.push(...clientExtraFieldFindings(ctx));
|
|
17
|
+
return findings;
|
|
18
|
+
}
|
|
19
|
+
function backendUnvalidatedBodyFindings(ctx) {
|
|
20
|
+
const findings = [];
|
|
21
|
+
for (const node of ctx.concepts.nodes) {
|
|
22
|
+
if (node.kind !== 'entrypoint' || node.payload.kind !== 'entrypoint' || node.payload.subtype !== 'route')
|
|
23
|
+
continue;
|
|
24
|
+
const method = node.payload.httpMethod?.toUpperCase();
|
|
25
|
+
const bodyMethods = ctx.crossStackMode === 'audit' ? AUDIT_BODY_METHODS : GUARD_BODY_METHODS;
|
|
26
|
+
if (!method || !bodyMethods.has(method))
|
|
27
|
+
continue;
|
|
28
|
+
if (!API_PATH_RE.test(node.payload.name))
|
|
29
|
+
continue;
|
|
30
|
+
if (node.payload.hasDbWrite !== true)
|
|
31
|
+
continue;
|
|
32
|
+
if (node.payload.bodyFieldsResolved !== true || !node.payload.bodyFields || node.payload.bodyFields.length === 0) {
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
if (node.payload.hasBodyValidation === true)
|
|
36
|
+
continue;
|
|
37
|
+
const fields = node.payload.bodyFields.map((field) => `\`${field}\``).join(', ');
|
|
38
|
+
findings.push({
|
|
39
|
+
source: 'kern',
|
|
40
|
+
ruleId: 'request-validation-drift',
|
|
41
|
+
severity: 'warning',
|
|
42
|
+
category: 'bug',
|
|
43
|
+
message: `Route \`${method} ${node.payload.name}\` reads request body fields ${fields} and writes to the database without visible request-body validation.`,
|
|
44
|
+
primarySpan: node.primarySpan,
|
|
45
|
+
fingerprint: createFingerprint('request-validation-drift', node.primarySpan.startLine, node.primarySpan.startCol),
|
|
46
|
+
confidence: node.confidence * 0.8,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
return findings;
|
|
50
|
+
}
|
|
51
|
+
function clientExtraFieldFindings(ctx) {
|
|
52
|
+
if (!ctx.allConcepts || ctx.allConcepts.size === 0)
|
|
53
|
+
return [];
|
|
54
|
+
const serverRoutes = collectRoutesAcrossGraph(ctx.allConcepts);
|
|
55
|
+
if (serverRoutes.length === 0)
|
|
56
|
+
return [];
|
|
57
|
+
const findings = [];
|
|
58
|
+
const localConcepts = ctx.allConcepts.get(ctx.filePath) ?? ctx.concepts;
|
|
59
|
+
for (const node of localConcepts.nodes) {
|
|
60
|
+
if (node.kind !== 'effect' || node.payload.kind !== 'effect' || node.payload.subtype !== 'network')
|
|
61
|
+
continue;
|
|
62
|
+
if (node.payload.sentFieldsResolved !== true || !node.payload.sentFields)
|
|
63
|
+
continue;
|
|
64
|
+
const target = node.payload.target;
|
|
65
|
+
if (typeof target !== 'string')
|
|
66
|
+
continue;
|
|
67
|
+
const normalized = normalizeClientUrl(target);
|
|
68
|
+
if (!normalized)
|
|
69
|
+
continue;
|
|
70
|
+
const route = ctx.crossStackMode === 'audit'
|
|
71
|
+
? findMatchingRouteForMethod(normalized, node.payload.method, serverRoutes)
|
|
72
|
+
: findHighConfidenceRouteForMethod(normalized, node.payload.method, serverRoutes);
|
|
73
|
+
if (route?.node?.payload.kind !== 'entrypoint')
|
|
74
|
+
continue;
|
|
75
|
+
if (route.node.payload.bodyValidationResolved !== true || !route.node.payload.validatedBodyFields)
|
|
76
|
+
continue;
|
|
77
|
+
const validated = new Set(route.node.payload.validatedBodyFields);
|
|
78
|
+
const extra = node.payload.sentFields.filter((field) => !validated.has(field));
|
|
79
|
+
if (extra.length === 0)
|
|
80
|
+
continue;
|
|
81
|
+
const fieldList = extra.map((field) => `\`${field}\``).join(', ');
|
|
82
|
+
findings.push({
|
|
83
|
+
source: 'kern',
|
|
84
|
+
ruleId: 'request-validation-drift',
|
|
85
|
+
severity: 'warning',
|
|
86
|
+
category: 'bug',
|
|
87
|
+
message: `Client sends ${fieldList} to \`${target}\`, but the matching backend validation schema does not accept ${extra.length === 1 ? 'that field' : 'those fields'}. Remove the extra payload data or update the backend schema intentionally.`,
|
|
88
|
+
primarySpan: node.primarySpan,
|
|
89
|
+
relatedSpans: [route.node.primarySpan],
|
|
90
|
+
fingerprint: createFingerprint('request-validation-drift', node.primarySpan.startLine, node.primarySpan.startCol),
|
|
91
|
+
confidence: node.confidence * CROSS_STACK_HEURISTIC_CONFIDENCE,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
return findings;
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=request-validation-drift.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request-validation-drift.js","sourceRoot":"","sources":["../../src/concept-rules/request-validation-drift.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule: unbounded-collection-query
|
|
3
|
+
*
|
|
4
|
+
* Cross-stack rule — fires when a client calls a list endpoint without
|
|
5
|
+
* page/cursor/limit parameters and the matching server route appears to return
|
|
6
|
+
* a DB-backed collection without a bound.
|
|
7
|
+
*/
|
|
8
|
+
import type { ReviewFinding } from '../types.js';
|
|
9
|
+
import type { ConceptRuleContext } from './index.js';
|
|
10
|
+
export declare function unboundedCollectionQuery(ctx: ConceptRuleContext): ReviewFinding[];
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule: unbounded-collection-query
|
|
3
|
+
*
|
|
4
|
+
* Cross-stack rule — fires when a client calls a list endpoint without
|
|
5
|
+
* page/cursor/limit parameters and the matching server route appears to return
|
|
6
|
+
* a DB-backed collection without a bound.
|
|
7
|
+
*/
|
|
8
|
+
import { createFingerprint } from '../types.js';
|
|
9
|
+
import { CROSS_STACK_HEURISTIC_CONFIDENCE, collectRoutesAcrossGraph, findHighConfidenceRouteForMethod, findMatchingRouteForMethod, normalizeClientUrl, } from './cross-stack-utils.js';
|
|
10
|
+
const PAGINATION_QUERY_PARAMS = new Set(['limit', 'take', 'page', 'pageSize', 'perPage', 'cursor', 'offset', 'skip']);
|
|
11
|
+
export function unboundedCollectionQuery(ctx) {
|
|
12
|
+
if (!ctx.allConcepts || ctx.allConcepts.size === 0)
|
|
13
|
+
return [];
|
|
14
|
+
const serverRoutes = collectRoutesAcrossGraph(ctx.allConcepts);
|
|
15
|
+
if (serverRoutes.length === 0)
|
|
16
|
+
return [];
|
|
17
|
+
const findings = [];
|
|
18
|
+
const localConcepts = ctx.allConcepts.get(ctx.filePath) ?? ctx.concepts;
|
|
19
|
+
for (const node of localConcepts.nodes) {
|
|
20
|
+
if (node.kind !== 'effect' || node.payload.kind !== 'effect' || node.payload.subtype !== 'network')
|
|
21
|
+
continue;
|
|
22
|
+
if (node.payload.queryParamsResolved !== true)
|
|
23
|
+
continue;
|
|
24
|
+
if (hasPaginationParam(node.payload.queryParams ?? []))
|
|
25
|
+
continue;
|
|
26
|
+
const target = node.payload.target;
|
|
27
|
+
if (typeof target !== 'string')
|
|
28
|
+
continue;
|
|
29
|
+
const normalized = normalizeClientUrl(target);
|
|
30
|
+
if (!normalized)
|
|
31
|
+
continue;
|
|
32
|
+
const route = ctx.crossStackMode === 'audit'
|
|
33
|
+
? findMatchingRouteForMethod(normalized, node.payload.method, serverRoutes)
|
|
34
|
+
: findHighConfidenceRouteForMethod(normalized, node.payload.method, serverRoutes);
|
|
35
|
+
if (route?.node?.payload.kind !== 'entrypoint')
|
|
36
|
+
continue;
|
|
37
|
+
if (route.node.payload.hasUnboundedCollectionQuery !== true)
|
|
38
|
+
continue;
|
|
39
|
+
findings.push({
|
|
40
|
+
source: 'kern',
|
|
41
|
+
ruleId: 'unbounded-collection-query',
|
|
42
|
+
severity: 'warning',
|
|
43
|
+
category: 'bug',
|
|
44
|
+
message: `Client calls list endpoint \`${target}\` without page/cursor/limit parameters, and the matching server route appears to return an unbounded DB collection. Add pagination on both sides before this endpoint grows.`,
|
|
45
|
+
primarySpan: node.primarySpan,
|
|
46
|
+
relatedSpans: [route.node.primarySpan],
|
|
47
|
+
fingerprint: createFingerprint('unbounded-collection-query', node.primarySpan.startLine, node.primarySpan.startCol),
|
|
48
|
+
confidence: node.confidence * CROSS_STACK_HEURISTIC_CONFIDENCE,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
return findings;
|
|
52
|
+
}
|
|
53
|
+
function hasPaginationParam(params) {
|
|
54
|
+
return params.some((param) => PAGINATION_QUERY_PARAMS.has(param));
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=unbounded-collection-query.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unbounded-collection-query.js","sourceRoot":"","sources":["../../src/concept-rules/unbounded-collection-query.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule: unhandled-api-error-shape
|
|
3
|
+
*
|
|
4
|
+
* Cross-stack rule — fires when a client calls a matching project API route
|
|
5
|
+
* without a visible error path while the backend route can explicitly return
|
|
6
|
+
* an error status such as 401/403/404/422/500.
|
|
7
|
+
*/
|
|
8
|
+
import type { ReviewFinding } from '../types.js';
|
|
9
|
+
import type { ConceptRuleContext } from './index.js';
|
|
10
|
+
export declare function unhandledApiErrorShape(ctx: ConceptRuleContext): ReviewFinding[];
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule: unhandled-api-error-shape
|
|
3
|
+
*
|
|
4
|
+
* Cross-stack rule — fires when a client calls a matching project API route
|
|
5
|
+
* without a visible error path while the backend route can explicitly return
|
|
6
|
+
* an error status such as 401/403/404/422/500.
|
|
7
|
+
*/
|
|
8
|
+
import { createFingerprint } from '../types.js';
|
|
9
|
+
import { CROSS_STACK_EXACT_CONFIDENCE, collectRoutesAcrossGraph, findHighConfidenceRouteForMethod, findMatchingRouteForMethod, normalizeClientUrl, } from './cross-stack-utils.js';
|
|
10
|
+
const ERROR_STATUS_CODES = new Set([401, 403, 404, 422, 500]);
|
|
11
|
+
export function unhandledApiErrorShape(ctx) {
|
|
12
|
+
if (!ctx.allConcepts || ctx.allConcepts.size === 0)
|
|
13
|
+
return [];
|
|
14
|
+
const serverRoutes = collectRoutesAcrossGraph(ctx.allConcepts);
|
|
15
|
+
if (serverRoutes.length === 0)
|
|
16
|
+
return [];
|
|
17
|
+
const findings = [];
|
|
18
|
+
const localConcepts = ctx.allConcepts.get(ctx.filePath) ?? ctx.concepts;
|
|
19
|
+
for (const node of localConcepts.nodes) {
|
|
20
|
+
if (node.kind !== 'effect' || node.payload.kind !== 'effect' || node.payload.subtype !== 'network')
|
|
21
|
+
continue;
|
|
22
|
+
if (node.payload.handlesApiErrors !== false)
|
|
23
|
+
continue;
|
|
24
|
+
const target = node.payload.target;
|
|
25
|
+
if (typeof target !== 'string')
|
|
26
|
+
continue;
|
|
27
|
+
const normalized = normalizeClientUrl(target);
|
|
28
|
+
if (!normalized)
|
|
29
|
+
continue;
|
|
30
|
+
if (!isRawFetchEffect(node.evidence))
|
|
31
|
+
continue;
|
|
32
|
+
const route = ctx.crossStackMode === 'audit'
|
|
33
|
+
? findMatchingRouteForMethod(normalized, node.payload.method, serverRoutes)
|
|
34
|
+
: findHighConfidenceRouteForMethod(normalized, node.payload.method, serverRoutes);
|
|
35
|
+
const statusCodes = route?.node?.payload.kind === 'entrypoint' ? route.node.payload.errorStatusCodes : undefined;
|
|
36
|
+
const relevantCodes = (statusCodes ?? []).filter((code) => ERROR_STATUS_CODES.has(code));
|
|
37
|
+
if (relevantCodes.length === 0)
|
|
38
|
+
continue;
|
|
39
|
+
const codeList = relevantCodes.join('/');
|
|
40
|
+
findings.push({
|
|
41
|
+
source: 'kern',
|
|
42
|
+
ruleId: 'unhandled-api-error-shape',
|
|
43
|
+
severity: 'warning',
|
|
44
|
+
category: 'bug',
|
|
45
|
+
message: `Client calls \`${target}\` with only the success path handled, but the matching server route can return ${codeList}. Add a \`response.ok\`/status branch, catch path, or error UI for the API error shape.`,
|
|
46
|
+
primarySpan: node.primarySpan,
|
|
47
|
+
relatedSpans: route?.node ? [route.node.primarySpan] : undefined,
|
|
48
|
+
fingerprint: createFingerprint('unhandled-api-error-shape', node.primarySpan.startLine, node.primarySpan.startCol),
|
|
49
|
+
confidence: node.confidence * CROSS_STACK_EXACT_CONFIDENCE,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
return findings;
|
|
53
|
+
}
|
|
54
|
+
function isRawFetchEffect(evidence) {
|
|
55
|
+
return /^\s*(?:await\s+)?fetch\s*\(/.test(evidence);
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=unhandled-api-error-shape.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unhandled-api-error-shape.js","sourceRoot":"","sources":["../../src/concept-rules/unhandled-api-error-shape.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EACL,4BAA4B,EAC5B,wBAAwB,EACxB,gCAAgC,EAChC,0BAA0B,EAC1B,kBAAkB,GACnB,MAAM,wBAAwB,CAAC;AAGhC,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;AAE9D,MAAM,UAAU,sBAAsB,CAAC,GAAuB;IAC5D,IAAI,CAAC,GAAG,CAAC,WAAW,IAAI,GAAG,CAAC,WAAW,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAE9D,MAAM,YAAY,GAAG,wBAAwB,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAC/D,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAEzC,MAAM,QAAQ,GAAoB,EAAE,CAAC;IACrC,MAAM,aAAa,GAAG,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC;IAExE,KAAK,MAAM,IAAI,IAAI,aAAa,CAAC,KAAK,EAAE,CAAC;QACvC,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,KAAK,SAAS;YAAE,SAAS;QAC7G,IAAI,IAAI,CAAC,OAAO,CAAC,gBAAgB,KAAK,KAAK;YAAE,SAAS;QACtD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;QACnC,IAAI,OAAO,MAAM,KAAK,QAAQ;YAAE,SAAS;QACzC,MAAM,UAAU,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;QAC9C,IAAI,CAAC,UAAU;YAAE,SAAS;QAC1B,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,QAAQ,CAAC;YAAE,SAAS;QAE/C,MAAM,KAAK,GACT,GAAG,CAAC,cAAc,KAAK,OAAO;YAC5B,CAAC,CAAC,0BAA0B,CAAC,UAAU,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,YAAY,CAAC;YAC3E,CAAC,CAAC,gCAAgC,CAAC,UAAU,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;QACtF,MAAM,WAAW,GAAG,KAAK,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,KAAK,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC,SAAS,CAAC;QACjH,MAAM,aAAa,GAAG,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,kBAAkB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;QACzF,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC;YAAE,SAAS;QAEzC,MAAM,QAAQ,GAAG,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACzC,QAAQ,CAAC,IAAI,CAAC;YACZ,MAAM,EAAE,MAAM;YACd,MAAM,EAAE,2BAA2B;YACnC,QAAQ,EAAE,SAAS;YACnB,QAAQ,EAAE,KAAK;YACf,OAAO,EAAE,kBAAkB,MAAM,mFAAmF,QAAQ,yFAAyF;YACrN,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,YAAY,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,SAAS;YAChE,WAAW,EAAE,iBAAiB,CAC5B,2BAA2B,EAC3B,IAAI,CAAC,WAAW,CAAC,SAAS,EAC1B,IAAI,CAAC,WAAW,CAAC,QAAQ,CAC1B;YACD,UAAU,EAAE,IAAI,CAAC,UAAU,GAAG,4BAA4B;SAC3D,CAAC,CAAC;IACL,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,gBAAgB,CAAC,QAAgB;IACxC,OAAO,6BAA6B,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AACtD,CAAC"}
|
package/dist/external-tools.js
CHANGED
|
@@ -6,9 +6,17 @@
|
|
|
6
6
|
*
|
|
7
7
|
* Phase 3 of the review pipeline.
|
|
8
8
|
*/
|
|
9
|
+
import { existsSync } from 'fs';
|
|
10
|
+
import { dirname, resolve } from 'path';
|
|
9
11
|
import { createProject } from './inferrer.js';
|
|
10
12
|
import { debugDetail } from './review-health.js';
|
|
11
13
|
import { createFingerprint } from './types.js';
|
|
14
|
+
function optionalPackageName(...parts) {
|
|
15
|
+
return parts.join('');
|
|
16
|
+
}
|
|
17
|
+
function importOptionalModule(specifier) {
|
|
18
|
+
return import(specifier);
|
|
19
|
+
}
|
|
12
20
|
/**
|
|
13
21
|
* Node-style error check — used to distinguish "optional peer dep missing" (quietly skip)
|
|
14
22
|
* from "the peer dep is installed but failed to load" (surface as degraded-mode health note).
|
|
@@ -35,10 +43,10 @@ function isModuleNotFound(err) {
|
|
|
35
43
|
export async function runESLint(filePaths, cwd, health) {
|
|
36
44
|
// Dynamic import — ESLint is an optional peer dep. MODULE_NOT_FOUND at this step means
|
|
37
45
|
// "not installed" (quiet skip); anything else is a real load failure worth surfacing.
|
|
38
|
-
const eslintModuleName = '
|
|
46
|
+
const eslintModuleName = optionalPackageName('es', 'lint');
|
|
39
47
|
let ESLint;
|
|
40
48
|
try {
|
|
41
|
-
const eslintModule = (await
|
|
49
|
+
const eslintModule = (await importOptionalModule(eslintModuleName));
|
|
42
50
|
ESLint = eslintModule.ESLint || eslintModule.default?.ESLint;
|
|
43
51
|
}
|
|
44
52
|
catch (err) {
|
|
@@ -163,7 +171,8 @@ export function runTSCDiagnostics(project, options = {}, health) {
|
|
|
163
171
|
// both point at the same user-side remedy, both are environmental from review's POV.)
|
|
164
172
|
const isLoadingNoise = code === 6059 || code === 6307;
|
|
165
173
|
const isEnvironmentalNoise = code === 2792 || code === 17004 || code === 2580 || code === 2591;
|
|
166
|
-
if (
|
|
174
|
+
if (options.downgradeProjectLoadingErrors &&
|
|
175
|
+
(isLoadingNoise || isEnvironmentalNoise || isReviewModeModuleResolutionNoise(code, messageStr, filePath))) {
|
|
167
176
|
continue;
|
|
168
177
|
}
|
|
169
178
|
findings.push({
|
|
@@ -191,6 +200,46 @@ export function runTSCDiagnostics(project, options = {}, health) {
|
|
|
191
200
|
}
|
|
192
201
|
return findings;
|
|
193
202
|
}
|
|
203
|
+
function isReviewModeModuleResolutionNoise(code, message, importerFilePath) {
|
|
204
|
+
if (code !== 2307)
|
|
205
|
+
return false;
|
|
206
|
+
const specifier = extractMissingModuleSpecifier(message);
|
|
207
|
+
if (!specifier)
|
|
208
|
+
return false;
|
|
209
|
+
// KERN-generated facades are commonly imported as `.js` from TS source and
|
|
210
|
+
// materialized by `kern compile`. In guard mode, a missing generated facade is
|
|
211
|
+
// pipeline ordering noise unless the explicit lint/typecheck phase says
|
|
212
|
+
// otherwise.
|
|
213
|
+
if (isGeneratedModuleSpecifier(specifier))
|
|
214
|
+
return true;
|
|
215
|
+
// Bare package misses (`vitest`, `ai`, etc.) are dependency-install or workspace
|
|
216
|
+
// context failures in review mode. The explicit `--lint` tsc path still reports
|
|
217
|
+
// them as real compiler errors.
|
|
218
|
+
if (isBareModuleSpecifier(specifier))
|
|
219
|
+
return true;
|
|
220
|
+
// TS ESM commonly imports `./foo.js` while the source file is `foo.ts`. If the
|
|
221
|
+
// corresponding TS source exists, this is a moduleResolution mismatch in
|
|
222
|
+
// review's ad-hoc Project, not a code bug.
|
|
223
|
+
return isTsBackedJsSpecifier(specifier, importerFilePath);
|
|
224
|
+
}
|
|
225
|
+
function extractMissingModuleSpecifier(message) {
|
|
226
|
+
const match = message.match(/Cannot find module ['"]([^'"]+)['"]/);
|
|
227
|
+
return match?.[1];
|
|
228
|
+
}
|
|
229
|
+
function isGeneratedModuleSpecifier(specifier) {
|
|
230
|
+
const normalized = specifier.replace(/\\/g, '/');
|
|
231
|
+
return /(?:^|\/)generated\//.test(normalized) || /(?:^|\/)__generated__\//.test(normalized);
|
|
232
|
+
}
|
|
233
|
+
function isBareModuleSpecifier(specifier) {
|
|
234
|
+
return !specifier.startsWith('.') && !specifier.startsWith('/') && !/^[A-Za-z]:[\\/]/.test(specifier);
|
|
235
|
+
}
|
|
236
|
+
function isTsBackedJsSpecifier(specifier, importerFilePath) {
|
|
237
|
+
if (!specifier.startsWith('.') || !/\.(?:mjs|cjs|js|jsx)$/.test(specifier))
|
|
238
|
+
return false;
|
|
239
|
+
const resolved = resolve(dirname(importerFilePath), specifier);
|
|
240
|
+
const withoutJsExt = resolved.replace(/\.(?:mjs|cjs|js|jsx)$/, '');
|
|
241
|
+
return ['.ts', '.tsx', '.mts', '.cts', '.d.ts'].some((ext) => existsSync(`${withoutJsExt}${ext}`));
|
|
242
|
+
}
|
|
194
243
|
// ── tsc Diagnostics from file paths ───────────────────────────────────
|
|
195
244
|
/**
|
|
196
245
|
* Run TypeScript compiler diagnostics from file paths (no pre-existing Project).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"external-tools.js","sourceRoot":"","sources":["../src/external-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;
|
|
1
|
+
{"version":3,"file":"external-tools.js","sourceRoot":"","sources":["../src/external-tools.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
*
|
|
9
9
|
* v2: Unified ReviewFinding pipeline. All findings merged into single array.
|
|
10
10
|
*/
|
|
11
|
+
import type { ConceptMap } from '@kernlang/core';
|
|
11
12
|
import type { GraphOptions } from './types.js';
|
|
12
13
|
import type { ReviewConfig, ReviewReport } from './types.js';
|
|
13
14
|
export type { CallGraph, CallSite, FunctionNode } from './call-graph.js';
|
|
@@ -93,7 +94,7 @@ export declare function isReviewableFile(filePath: string): boolean;
|
|
|
93
94
|
* review pipeline — no rule evaluation, no import-graph resolution, no
|
|
94
95
|
* health aggregation.
|
|
95
96
|
*/
|
|
96
|
-
export declare function extractConceptsForGraph(filePaths: string[]): Map<string,
|
|
97
|
+
export declare function extractConceptsForGraph(filePaths: string[]): Map<string, ConceptMap>;
|
|
97
98
|
/**
|
|
98
99
|
* Review a single file. Auto-detects language from extension.
|
|
99
100
|
* Uses a filesystem-backed ts-morph Project for type-aware analysis.
|