@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.
Files changed (93) hide show
  1. package/README.md +66 -5
  2. package/dist/args.d.ts +16 -0
  3. package/dist/args.js +72 -0
  4. package/dist/build-stamp.d.ts +13 -0
  5. package/dist/build-stamp.js +76 -0
  6. package/dist/build-stamp.json +4 -0
  7. package/dist/caller-resolution.d.ts +222 -0
  8. package/dist/caller-resolution.js +1198 -0
  9. package/dist/cli.js +249 -17
  10. package/dist/contract.d.ts +25 -7
  11. package/dist/contract.js +52 -7
  12. package/dist/coverage-cli.js +8 -0
  13. package/dist/coverage.d.ts +1 -1
  14. package/dist/coverage.js +2 -2
  15. package/dist/detectors/oracle-axis1.d.ts +5 -3
  16. package/dist/detectors/oracle-axis1.js +28 -18
  17. package/dist/detectors/oracle-axis2.d.ts +6 -0
  18. package/dist/detectors/oracle-axis2.js +37 -22
  19. package/dist/detectors/predicates.d.ts +3 -0
  20. package/dist/detectors/predicates.js +93 -19
  21. package/dist/detectors/shared.js +8 -7
  22. package/dist/detectors/source/_ast.d.ts +92 -0
  23. package/dist/detectors/source/_ast.js +353 -0
  24. package/dist/detectors/source/_scan.js +4 -3
  25. package/dist/detectors/source/backfill.js +71 -18
  26. package/dist/detectors/source/contract.js +21 -13
  27. package/dist/detectors/source/cross-tenant-write.d.ts +46 -0
  28. package/dist/detectors/source/cross-tenant-write.js +1408 -0
  29. package/dist/detectors/source/guard-helper-flow.d.ts +134 -0
  30. package/dist/detectors/source/guard-helper-flow.js +1216 -0
  31. package/dist/detectors/source/identity-by-id.d.ts +80 -0
  32. package/dist/detectors/source/identity-by-id.js +1783 -0
  33. package/dist/detectors/source/identity.d.ts +58 -2
  34. package/dist/detectors/source/identity.js +1158 -28
  35. package/dist/detectors/source/isolation.d.ts +11 -1
  36. package/dist/detectors/source/isolation.js +106 -25
  37. package/dist/detectors/source/jobs.js +178 -4
  38. package/dist/detectors/source/lifecycle.js +14 -2
  39. package/dist/detectors/source/local-identity.d.ts +26 -0
  40. package/dist/detectors/source/local-identity.js +661 -0
  41. package/dist/detectors/source/package-principal.d.ts +9 -0
  42. package/dist/detectors/source/package-principal.js +177 -0
  43. package/dist/detectors/source/r6-shapes.d.ts +20 -0
  44. package/dist/detectors/source/r6-shapes.js +285 -0
  45. package/dist/detectors/source/readbudget.d.ts +1 -0
  46. package/dist/detectors/source/readbudget.js +358 -4
  47. package/dist/detectors/source/recipient-by-id.d.ts +40 -0
  48. package/dist/detectors/source/recipient-by-id.js +1108 -0
  49. package/dist/detectors/source/refusal.d.ts +14 -0
  50. package/dist/detectors/source/refusal.js +75 -2
  51. package/dist/detectors/source/security.d.ts +16 -0
  52. package/dist/detectors/source/security.js +680 -33
  53. package/dist/detectors/source/write-isolation.d.ts +8 -1
  54. package/dist/detectors/source/write-isolation.js +64 -30
  55. package/dist/detectors/source/writesafety.js +27 -14
  56. package/dist/detectors/standard/_doc.d.ts +1 -1
  57. package/dist/detectors/standard/_doc.js +5 -4
  58. package/dist/detectors/standard/r41-frontier.js +3 -2
  59. package/dist/detectors/standard/r46-returns-validator.d.ts +8 -0
  60. package/dist/detectors/standard/r46-returns-validator.js +48 -16
  61. package/dist/detectors/structural.d.ts +6 -7
  62. package/dist/detectors/structural.js +84 -48
  63. package/dist/not-checkable.d.ts +1 -1
  64. package/dist/not-checkable.js +11 -0
  65. package/dist/oracle.d.ts +92 -3
  66. package/dist/oracle.js +229 -12
  67. package/dist/registry.d.ts +8 -1
  68. package/dist/registry.js +74 -8
  69. package/dist/report.d.ts +11 -1
  70. package/dist/report.js +15 -2
  71. package/dist/rule-class.d.ts +85 -0
  72. package/dist/rule-class.js +218 -0
  73. package/dist/state-rank.d.ts +5 -0
  74. package/dist/state-rank.js +9 -0
  75. package/dist/tally.d.ts +13 -5
  76. package/dist/tally.js +15 -13
  77. package/dist/target.d.ts +32 -0
  78. package/dist/target.js +173 -0
  79. package/dist/violation-count.d.ts +48 -0
  80. package/dist/violation-count.js +94 -0
  81. package/fixtures/backend-standard-2825122.md +722 -0
  82. package/fixtures/backend-standard-4dcd3e0.md +722 -0
  83. package/fixtures/cr1-classes/_generated/api.d.ts +24 -0
  84. package/fixtures/cr1-classes/surface.ts +206 -0
  85. package/fixtures/cr1-empty/nothing.ts +1 -0
  86. package/fixtures/cr1-refusal-on-resolved/_generated/api.d.ts +24 -0
  87. package/fixtures/cr1-refusal-on-resolved/doors.ts +180 -0
  88. package/fixtures/cr1-refusal-on-resolved/lib/auth.ts +104 -0
  89. package/fixtures/r34-vp-auth-30e821b/auth-805-812.ts.txt +8 -0
  90. package/fixtures/r34-vp-auth-30e821b/auth-878-890.ts.txt +13 -0
  91. package/fixtures/rule-classes-2825122.json +228 -0
  92. package/fixtures/vp-writer-tier-1e4ab36.csv +55 -0
  93. 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.cnj.push({
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. The human half is owed: refuse (R-16), add a tighter index, or declare a bound (R-30)? Never a silent green`,
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;