@vantageos/backend-doctor 0.1.14 → 0.3.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/README.md +66 -5
- package/dist/args.d.ts +16 -0
- package/dist/args.js +72 -0
- package/dist/build-stamp.d.ts +13 -0
- package/dist/build-stamp.js +76 -0
- package/dist/build-stamp.json +4 -0
- package/dist/caller-resolution.d.ts +222 -0
- package/dist/caller-resolution.js +1198 -0
- package/dist/cli.js +249 -17
- package/dist/contract.d.ts +25 -7
- package/dist/contract.js +52 -7
- package/dist/coverage-cli.js +8 -0
- package/dist/coverage.d.ts +1 -1
- package/dist/coverage.js +2 -2
- package/dist/detectors/oracle-axis1.d.ts +5 -3
- package/dist/detectors/oracle-axis1.js +28 -18
- package/dist/detectors/oracle-axis2.d.ts +6 -0
- package/dist/detectors/oracle-axis2.js +37 -22
- package/dist/detectors/predicates.d.ts +3 -0
- package/dist/detectors/predicates.js +93 -19
- package/dist/detectors/shared.js +8 -7
- package/dist/detectors/source/_ast.d.ts +92 -0
- package/dist/detectors/source/_ast.js +353 -0
- package/dist/detectors/source/_scan.js +4 -3
- package/dist/detectors/source/backfill.js +71 -18
- package/dist/detectors/source/contract.js +21 -13
- package/dist/detectors/source/cross-tenant-write.d.ts +46 -0
- package/dist/detectors/source/cross-tenant-write.js +1408 -0
- package/dist/detectors/source/guard-helper-flow.d.ts +134 -0
- package/dist/detectors/source/guard-helper-flow.js +1216 -0
- package/dist/detectors/source/identity-by-id.d.ts +80 -0
- package/dist/detectors/source/identity-by-id.js +1783 -0
- package/dist/detectors/source/identity.d.ts +58 -2
- package/dist/detectors/source/identity.js +1158 -28
- package/dist/detectors/source/isolation.d.ts +11 -1
- package/dist/detectors/source/isolation.js +106 -25
- package/dist/detectors/source/jobs.js +178 -4
- package/dist/detectors/source/lifecycle.js +14 -2
- package/dist/detectors/source/local-identity.d.ts +26 -0
- package/dist/detectors/source/local-identity.js +661 -0
- package/dist/detectors/source/package-principal.d.ts +9 -0
- package/dist/detectors/source/package-principal.js +177 -0
- package/dist/detectors/source/r6-shapes.d.ts +20 -0
- package/dist/detectors/source/r6-shapes.js +285 -0
- package/dist/detectors/source/readbudget.d.ts +1 -0
- package/dist/detectors/source/readbudget.js +358 -4
- package/dist/detectors/source/recipient-by-id.d.ts +40 -0
- package/dist/detectors/source/recipient-by-id.js +1108 -0
- package/dist/detectors/source/refusal.d.ts +14 -0
- package/dist/detectors/source/refusal.js +75 -2
- package/dist/detectors/source/security.d.ts +16 -0
- package/dist/detectors/source/security.js +680 -33
- package/dist/detectors/source/write-isolation.d.ts +8 -1
- package/dist/detectors/source/write-isolation.js +64 -30
- package/dist/detectors/source/writesafety.js +27 -14
- package/dist/detectors/standard/_doc.d.ts +1 -1
- package/dist/detectors/standard/_doc.js +5 -4
- package/dist/detectors/standard/r41-frontier.js +3 -2
- package/dist/detectors/standard/r46-returns-validator.d.ts +8 -0
- package/dist/detectors/standard/r46-returns-validator.js +48 -16
- package/dist/detectors/structural.d.ts +6 -7
- package/dist/detectors/structural.js +84 -48
- package/dist/not-checkable.d.ts +1 -1
- package/dist/not-checkable.js +11 -0
- package/dist/oracle.d.ts +92 -3
- package/dist/oracle.js +229 -12
- package/dist/registry.d.ts +8 -1
- package/dist/registry.js +74 -8
- package/dist/report.d.ts +11 -1
- package/dist/report.js +15 -2
- package/dist/rule-class.d.ts +85 -0
- package/dist/rule-class.js +218 -0
- package/dist/state-rank.d.ts +5 -0
- package/dist/state-rank.js +9 -0
- package/dist/tally.d.ts +13 -5
- package/dist/tally.js +15 -13
- package/dist/target.d.ts +32 -0
- package/dist/target.js +173 -0
- package/dist/violation-count.d.ts +48 -0
- package/dist/violation-count.js +94 -0
- package/fixtures/backend-standard-2825122.md +722 -0
- package/fixtures/backend-standard-4dcd3e0.md +722 -0
- package/fixtures/cr1-classes/_generated/api.d.ts +24 -0
- package/fixtures/cr1-classes/surface.ts +206 -0
- package/fixtures/cr1-empty/nothing.ts +1 -0
- package/fixtures/cr1-refusal-on-resolved/_generated/api.d.ts +24 -0
- package/fixtures/cr1-refusal-on-resolved/doors.ts +180 -0
- package/fixtures/cr1-refusal-on-resolved/lib/auth.ts +104 -0
- package/fixtures/r34-vp-auth-30e821b/auth-805-812.ts.txt +8 -0
- package/fixtures/r34-vp-auth-30e821b/auth-878-890.ts.txt +13 -0
- package/fixtures/rule-classes-2825122.json +228 -0
- package/fixtures/vp-writer-tier-1e4ab36.csv +55 -0
- package/package.json +2 -2
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
import type { Detector } from "../../engine-types.js";
|
|
2
2
|
import { type Scan, type SourceDetectorEntry, type SrcFile } from "./_scan.js";
|
|
3
|
+
/**
|
|
4
|
+
* The text of every comment in `src`, read by a LEXER rather than by line shape
|
|
5
|
+
* (Argus REVISE, PR #32 @6b2b6ad). A trailing `// …` after code and a bare line
|
|
6
|
+
* inside a block comment are comments; a line inside a string or a template
|
|
7
|
+
* literal is data, even when it starts with `//`. Five states: code, line
|
|
8
|
+
* comment, block comment, a `'`/`"` string, a template literal.
|
|
9
|
+
*
|
|
10
|
+
* Declared limit: a regex literal containing a quote or a backtick (`/"/`,
|
|
11
|
+
* `` /`/ ``) is read as opening a string. A `'`/`"` state closes at the end of
|
|
12
|
+
* its line, so the damage stays on that line; a backtick state does not close
|
|
13
|
+
* at a newline, so a regex literal holding a backtick hides every comment up to
|
|
14
|
+
* the next backtick. Rare in a handler body; named here, not hidden.
|
|
15
|
+
*/
|
|
16
|
+
export declare function commentsOf(src: string): string;
|
|
3
17
|
export declare function scanR47(files: SrcFile[]): Scan;
|
|
4
18
|
export declare const R47: Detector;
|
|
5
19
|
/** In the form the orchestrator spreads into REGISTRY. */
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { hasJustificationTokenInText } from "../oracle-axis2.js";
|
|
1
2
|
import { code, emptyScan, isJudgeable, SOURCE_STANDARD_PIN, srcDetector, } from "./_scan.js";
|
|
2
3
|
// a read-only query opener — the function class R-47 governs.
|
|
3
4
|
const QUERY_OPEN = /\b(?:internalQuery|query)\s*\(/;
|
|
@@ -55,6 +56,62 @@ function queryBlock(lines, i) {
|
|
|
55
56
|
}
|
|
56
57
|
return { lines: body, unterminated: seenOpen };
|
|
57
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* The text of every comment in `src`, read by a LEXER rather than by line shape
|
|
61
|
+
* (Argus REVISE, PR #32 @6b2b6ad). A trailing `// …` after code and a bare line
|
|
62
|
+
* inside a block comment are comments; a line inside a string or a template
|
|
63
|
+
* literal is data, even when it starts with `//`. Five states: code, line
|
|
64
|
+
* comment, block comment, a `'`/`"` string, a template literal.
|
|
65
|
+
*
|
|
66
|
+
* Declared limit: a regex literal containing a quote or a backtick (`/"/`,
|
|
67
|
+
* `` /`/ ``) is read as opening a string. A `'`/`"` state closes at the end of
|
|
68
|
+
* its line, so the damage stays on that line; a backtick state does not close
|
|
69
|
+
* at a newline, so a regex literal holding a backtick hides every comment up to
|
|
70
|
+
* the next backtick. Rare in a handler body; named here, not hidden.
|
|
71
|
+
*/
|
|
72
|
+
export function commentsOf(src) {
|
|
73
|
+
let out = "";
|
|
74
|
+
let state = "code";
|
|
75
|
+
for (let i = 0; i < src.length; i++) {
|
|
76
|
+
const c = src[i];
|
|
77
|
+
const next = src[i + 1];
|
|
78
|
+
if (state === "code") {
|
|
79
|
+
if (c === "/" && next === "/") {
|
|
80
|
+
state = "line";
|
|
81
|
+
i++;
|
|
82
|
+
}
|
|
83
|
+
else if (c === "/" && next === "*") {
|
|
84
|
+
state = "block";
|
|
85
|
+
i++;
|
|
86
|
+
}
|
|
87
|
+
else if (c === "'" || c === '"' || c === "`") {
|
|
88
|
+
state = c;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
else if (state === "line") {
|
|
92
|
+
out += c;
|
|
93
|
+
if (c === "\n")
|
|
94
|
+
state = "code";
|
|
95
|
+
}
|
|
96
|
+
else if (state === "block") {
|
|
97
|
+
if (c === "*" && next === "/") {
|
|
98
|
+
state = "code";
|
|
99
|
+
i++;
|
|
100
|
+
out += "\n";
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
out += c;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
else if (c === "\\") {
|
|
107
|
+
i++;
|
|
108
|
+
}
|
|
109
|
+
else if (c === state || (c === "\n" && state !== "`")) {
|
|
110
|
+
state = "code";
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return out;
|
|
114
|
+
}
|
|
58
115
|
export function scanR47(files) {
|
|
59
116
|
const scan = emptyScan();
|
|
60
117
|
for (const f of files) {
|
|
@@ -86,6 +143,11 @@ export function scanR47(files) {
|
|
|
86
143
|
.map((l) => l.raw)
|
|
87
144
|
.join("\n");
|
|
88
145
|
const hasRefusal = REFUSAL.test(blockText);
|
|
146
|
+
// The justification token is a WRITTEN RECORD, so it is read from the
|
|
147
|
+
// handler's COMMENTS only, found by a lexer (`commentsOf`), never by line
|
|
148
|
+
// shape. A string or template literal is executing data and never
|
|
149
|
+
// justifies (Argus REVISE, PR #32 @515ca1f and @6b2b6ad).
|
|
150
|
+
const commentText = commentsOf(block.lines.map((l) => l.raw).join("\n"));
|
|
89
151
|
for (const st of statements(block.lines)) {
|
|
90
152
|
const isUnbounded = COLLECT.test(st.text) && !BOUNDED.test(st.text);
|
|
91
153
|
if (!isUnbounded)
|
|
@@ -106,11 +168,22 @@ export function scanR47(files) {
|
|
|
106
168
|
note: `${fn}: wide non-index-bounded scan on "${table}" but the handler carries a REFUSAL path (R-16 error contract naming the narrowing args) — the correct R-47 behaviour (the tasks.list SCAN_CAP_EXCEEDED shape)`,
|
|
107
169
|
});
|
|
108
170
|
}
|
|
171
|
+
else if (hasJustificationTokenInText(commentText)) {
|
|
172
|
+
// judgement retired (task k179jnhx, §23): flagged — no refusal path;
|
|
173
|
+
// the enclosing handler's written JUSTIFIÉ:/JUSTIFIED: token IS the
|
|
174
|
+
// accepted remedy record (refuse / tighter index / declared bound),
|
|
175
|
+
// decided by presence, never a person's opinion of which is right.
|
|
176
|
+
scan.conform.push({
|
|
177
|
+
rel: f.rel,
|
|
178
|
+
n: st.n,
|
|
179
|
+
note: `${fn}: wide, non-index-bounded \`.query("${table}").collect()\` with NO refusal path, but the handler carries a written JUSTIFIÉ:/JUSTIFIED: token — accepted, not silently passed`,
|
|
180
|
+
});
|
|
181
|
+
}
|
|
109
182
|
else {
|
|
110
|
-
scan.
|
|
183
|
+
scan.violate.push({
|
|
111
184
|
rel: f.rel,
|
|
112
185
|
n: st.n,
|
|
113
|
-
note: `${fn}: wide, non-index-bounded \`.query("${table}").collect()\` in a query with NO refusal path — the read cap can truncate it BEFORE any filter runs, returning a fraction indistinguishable from a full match.
|
|
186
|
+
note: `${fn}: wide, non-index-bounded \`.query("${table}").collect()\` in a query with NO refusal path and no written JUSTIFIÉ:/JUSTIFIED: token — the read cap can truncate it BEFORE any filter runs, returning a fraction indistinguishable from a full match. Owes a fix (refuse (R-16) / tighter index / declared bound (R-30)) or a recorded justification`,
|
|
114
187
|
});
|
|
115
188
|
}
|
|
116
189
|
}
|
|
@@ -25,6 +25,22 @@ export declare function scanR22(files: SrcFile[]): Scan;
|
|
|
25
25
|
export declare function scanR33(files: SrcFile[]): Scan;
|
|
26
26
|
export declare function scanR34(files: SrcFile[]): Scan;
|
|
27
27
|
export declare function scanR35(files: SrcFile[]): Scan;
|
|
28
|
+
/**
|
|
29
|
+
* The directories R-36 searches, nearest first: the scanned root, then each
|
|
30
|
+
* ancestor up to and INCLUDING the git root (the first ancestor holding `.git`).
|
|
31
|
+
*
|
|
32
|
+
* The misread this closes: the documented invocation points the doctor at
|
|
33
|
+
* `<repo>/convex`, while the lockfile and `.github/workflows` are REPOSITORY
|
|
34
|
+
* artifacts living at the repo root. Reading only `tree.root` reported "no lockfile
|
|
35
|
+
* — dependencies are not pinned" on a repository with a committed `bun.lock`.
|
|
36
|
+
*
|
|
37
|
+
* The walk stops at the git root and never goes above it: a lockfile in some
|
|
38
|
+
* unrelated parent directory (a home directory, a monorepo host that is not this
|
|
39
|
+
* repository) does not pin this repository's dependencies. With no `.git` ancestor
|
|
40
|
+
* at all, only the scanned root itself is read (the pre-fix behaviour) — the walk
|
|
41
|
+
* is never widened on a guess.
|
|
42
|
+
*/
|
|
43
|
+
export declare function r36SearchDirs(root: string): string[];
|
|
28
44
|
export declare function evalR36(root: string): Scan;
|
|
29
45
|
export declare const R21: Detector;
|
|
30
46
|
export declare const R22: Detector;
|