@rigour-labs/core 6.8.0 → 6.8.1-rc.1

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 (326) hide show
  1. package/dist/inference/cloud-provider.js +12 -2
  2. package/package.json +11 -8
  3. package/dist/brief/briefing.test.d.ts +0 -1
  4. package/dist/brief/briefing.test.js +0 -107
  5. package/dist/context/automatic-index-cache.test.d.ts +0 -1
  6. package/dist/context/automatic-index-cache.test.js +0 -30
  7. package/dist/context/automatic-index.test.d.ts +0 -1
  8. package/dist/context/automatic-index.test.js +0 -45
  9. package/dist/context/cache-engine.test.d.ts +0 -1
  10. package/dist/context/cache-engine.test.js +0 -99
  11. package/dist/context/dependency-graph.test.d.ts +0 -1
  12. package/dist/context/dependency-graph.test.js +0 -13
  13. package/dist/context/index-status.test.d.ts +0 -1
  14. package/dist/context/index-status.test.js +0 -26
  15. package/dist/context.test.d.ts +0 -1
  16. package/dist/context.test.js +0 -228
  17. package/dist/deep/agent-review.test.d.ts +0 -1
  18. package/dist/deep/agent-review.test.js +0 -53
  19. package/dist/deep/code-context.test.d.ts +0 -1
  20. package/dist/deep/code-context.test.js +0 -48
  21. package/dist/deep/code-pass.test.d.ts +0 -1
  22. package/dist/deep/code-pass.test.js +0 -112
  23. package/dist/deep/code-review-prompt.test.d.ts +0 -1
  24. package/dist/deep/code-review-prompt.test.js +0 -20
  25. package/dist/deep/code-verifier.test.d.ts +0 -1
  26. package/dist/deep/code-verifier.test.js +0 -54
  27. package/dist/deep/diff-tests/calls.test.d.ts +0 -1
  28. package/dist/deep/diff-tests/calls.test.js +0 -33
  29. package/dist/deep/diff-tests/run.test.d.ts +0 -1
  30. package/dist/deep/diff-tests/run.test.js +0 -58
  31. package/dist/deep/fact-extractor.test.d.ts +0 -1
  32. package/dist/deep/fact-extractor.test.js +0 -581
  33. package/dist/deep/parse-findings.test.d.ts +0 -1
  34. package/dist/deep/parse-findings.test.js +0 -25
  35. package/dist/deep/pr-review.test.d.ts +0 -1
  36. package/dist/deep/pr-review.test.js +0 -80
  37. package/dist/deep/prompts.test.d.ts +0 -1
  38. package/dist/deep/prompts.test.js +0 -235
  39. package/dist/deep/reference-pack.test.d.ts +0 -1
  40. package/dist/deep/reference-pack.test.js +0 -46
  41. package/dist/deep/related-changes.test.d.ts +0 -1
  42. package/dist/deep/related-changes.test.js +0 -33
  43. package/dist/deep/review-context-export.test.d.ts +0 -1
  44. package/dist/deep/review-context-export.test.js +0 -32
  45. package/dist/deep/review-tools.test.d.ts +0 -1
  46. package/dist/deep/review-tools.test.js +0 -39
  47. package/dist/deep/risk.test.d.ts +0 -1
  48. package/dist/deep/risk.test.js +0 -101
  49. package/dist/deep/verifier.test.d.ts +0 -1
  50. package/dist/deep/verifier.test.js +0 -635
  51. package/dist/discovery.test.d.ts +0 -1
  52. package/dist/discovery.test.js +0 -93
  53. package/dist/environment.test.d.ts +0 -1
  54. package/dist/environment.test.js +0 -94
  55. package/dist/firewall/firewall.test.d.ts +0 -1
  56. package/dist/firewall/firewall.test.js +0 -117
  57. package/dist/firewall/trust-boundaries.test.d.ts +0 -1
  58. package/dist/firewall/trust-boundaries.test.js +0 -64
  59. package/dist/firewall/trusted-control.test.d.ts +0 -1
  60. package/dist/firewall/trusted-control.test.js +0 -188
  61. package/dist/gates/agent-team.test.d.ts +0 -1
  62. package/dist/gates/agent-team.test.js +0 -113
  63. package/dist/gates/ast.test.d.ts +0 -1
  64. package/dist/gates/ast.test.js +0 -112
  65. package/dist/gates/checkpoint.test.d.ts +0 -1
  66. package/dist/gates/checkpoint.test.js +0 -105
  67. package/dist/gates/content.test.d.ts +0 -1
  68. package/dist/gates/content.test.js +0 -73
  69. package/dist/gates/coverage.test.d.ts +0 -1
  70. package/dist/gates/coverage.test.js +0 -53
  71. package/dist/gates/dedupe-failures.test.d.ts +0 -1
  72. package/dist/gates/dedupe-failures.test.js +0 -12
  73. package/dist/gates/deep-analysis.test.d.ts +0 -1
  74. package/dist/gates/deep-analysis.test.js +0 -86
  75. package/dist/gates/deep-intent.test.d.ts +0 -1
  76. package/dist/gates/deep-intent.test.js +0 -51
  77. package/dist/gates/deep-timeout.test.d.ts +0 -1
  78. package/dist/gates/deep-timeout.test.js +0 -10
  79. package/dist/gates/deprecated-apis.test.d.ts +0 -1
  80. package/dist/gates/deprecated-apis.test.js +0 -318
  81. package/dist/gates/deprecated-dependencies.test.d.ts +0 -1
  82. package/dist/gates/deprecated-dependencies.test.js +0 -55
  83. package/dist/gates/frontend-secret-exposure.test.d.ts +0 -1
  84. package/dist/gates/frontend-secret-exposure.test.js +0 -148
  85. package/dist/gates/hallucinated-imports/framework-modules-nuxt.test.d.ts +0 -1
  86. package/dist/gates/hallucinated-imports/framework-modules-nuxt.test.js +0 -27
  87. package/dist/gates/hallucinated-imports/js-resolver-types.test.d.ts +0 -1
  88. package/dist/gates/hallucinated-imports/js-resolver-types.test.js +0 -14
  89. package/dist/gates/hallucinated-imports-sveltekit.test.d.ts +0 -1
  90. package/dist/gates/hallucinated-imports-sveltekit.test.js +0 -132
  91. package/dist/gates/hallucinated-imports.test.d.ts +0 -1
  92. package/dist/gates/hallucinated-imports.test.js +0 -1206
  93. package/dist/gates/js-style-context.test.d.ts +0 -1
  94. package/dist/gates/js-style-context.test.js +0 -35
  95. package/dist/gates/logic-drift.test.d.ts +0 -1
  96. package/dist/gates/logic-drift.test.js +0 -52
  97. package/dist/gates/phantom-apis.test.d.ts +0 -1
  98. package/dist/gates/phantom-apis.test.js +0 -396
  99. package/dist/gates/promise-safety.test.d.ts +0 -1
  100. package/dist/gates/promise-safety.test.js +0 -34
  101. package/dist/gates/runner.test.d.ts +0 -1
  102. package/dist/gates/runner.test.js +0 -77
  103. package/dist/gates/scoped-gates.test.d.ts +0 -1
  104. package/dist/gates/scoped-gates.test.js +0 -52
  105. package/dist/gates/security-patterns-owasp.test.d.ts +0 -1
  106. package/dist/gates/security-patterns-owasp.test.js +0 -186
  107. package/dist/gates/security-patterns.test.d.ts +0 -1
  108. package/dist/gates/security-patterns.test.js +0 -194
  109. package/dist/gates/semantic-bugs.test.d.ts +0 -1
  110. package/dist/gates/semantic-bugs.test.js +0 -76
  111. package/dist/gates/side-effect-analysis.test.d.ts +0 -1
  112. package/dist/gates/side-effect-analysis.test.js +0 -162
  113. package/dist/gates/style-drift.test.d.ts +0 -1
  114. package/dist/gates/style-drift.test.js +0 -26
  115. package/dist/gates/test-quality.test.d.ts +0 -1
  116. package/dist/gates/test-quality.test.js +0 -325
  117. package/dist/gates/trusted-reviews.test.d.ts +0 -1
  118. package/dist/gates/trusted-reviews.test.js +0 -16
  119. package/dist/gates/unindexed-reads/queries.test.d.ts +0 -1
  120. package/dist/gates/unindexed-reads/queries.test.js +0 -54
  121. package/dist/gates/unindexed-reads/schema.test.d.ts +0 -1
  122. package/dist/gates/unindexed-reads/schema.test.js +0 -81
  123. package/dist/gates/unindexed-reads/unindexed-reads.test.d.ts +0 -1
  124. package/dist/gates/unindexed-reads/unindexed-reads.test.js +0 -90
  125. package/dist/hooks/checker.test.d.ts +0 -1
  126. package/dist/hooks/checker.test.js +0 -159
  127. package/dist/hooks/dlp-confidence.test.d.ts +0 -1
  128. package/dist/hooks/dlp-confidence.test.js +0 -51
  129. package/dist/hooks/dlp-feedback.test.d.ts +0 -1
  130. package/dist/hooks/dlp-feedback.test.js +0 -131
  131. package/dist/hooks/input-validator.test.d.ts +0 -1
  132. package/dist/hooks/input-validator.test.js +0 -329
  133. package/dist/hooks/templates.test.d.ts +0 -1
  134. package/dist/hooks/templates.test.js +0 -27
  135. package/dist/inference/brain-placeholder.test.d.ts +0 -1
  136. package/dist/inference/brain-placeholder.test.js +0 -28
  137. package/dist/inference/cloud-provider.test.d.ts +0 -1
  138. package/dist/inference/cloud-provider.test.js +0 -139
  139. package/dist/inference/executable.test.d.ts +0 -1
  140. package/dist/inference/executable.test.js +0 -41
  141. package/dist/inference/http-download.test.d.ts +0 -1
  142. package/dist/inference/http-download.test.js +0 -109
  143. package/dist/inference/llama-engine-checksum.test.d.ts +0 -1
  144. package/dist/inference/llama-engine-checksum.test.js +0 -27
  145. package/dist/inference/llama-engine.test.d.ts +0 -1
  146. package/dist/inference/llama-engine.test.js +0 -51
  147. package/dist/inference/llama-process.test.d.ts +0 -1
  148. package/dist/inference/llama-process.test.js +0 -61
  149. package/dist/inference/local-model.test.d.ts +0 -1
  150. package/dist/inference/local-model.test.js +0 -23
  151. package/dist/inference/model-download.test.d.ts +0 -1
  152. package/dist/inference/model-download.test.js +0 -125
  153. package/dist/inference/model-manager.test.d.ts +0 -1
  154. package/dist/inference/model-manager.test.js +0 -24
  155. package/dist/inference/types.test.d.ts +0 -1
  156. package/dist/inference/types.test.js +0 -19
  157. package/dist/memory/recall.test.d.ts +0 -1
  158. package/dist/memory/recall.test.js +0 -36
  159. package/dist/pattern-index/indexer.test.d.ts +0 -6
  160. package/dist/pattern-index/indexer.test.js +0 -197
  161. package/dist/pattern-index/matcher.test.d.ts +0 -6
  162. package/dist/pattern-index/matcher.test.js +0 -238
  163. package/dist/pattern-index/pattern-reuse.test.d.ts +0 -1
  164. package/dist/pattern-index/pattern-reuse.test.js +0 -76
  165. package/dist/pattern-index/semantic-runtime.test.d.ts +0 -1
  166. package/dist/pattern-index/semantic-runtime.test.js +0 -31
  167. package/dist/pattern-index/staleness.test.d.ts +0 -6
  168. package/dist/pattern-index/staleness.test.js +0 -211
  169. package/dist/review/agent-fixes.test.d.ts +0 -1
  170. package/dist/review/agent-fixes.test.js +0 -32
  171. package/dist/review/backtest-init.test.d.ts +0 -1
  172. package/dist/review/backtest-init.test.js +0 -136
  173. package/dist/review/backtest-judges.test.d.ts +0 -1
  174. package/dist/review/backtest-judges.test.js +0 -32
  175. package/dist/review/backtest-last.test.d.ts +0 -1
  176. package/dist/review/backtest-last.test.js +0 -109
  177. package/dist/review/backtest.test.d.ts +0 -1
  178. package/dist/review/backtest.test.js +0 -183
  179. package/dist/review/baseline.test.d.ts +0 -1
  180. package/dist/review/baseline.test.js +0 -22
  181. package/dist/review/branch-checks.test.d.ts +0 -1
  182. package/dist/review/branch-checks.test.js +0 -48
  183. package/dist/review/check-outcomes.test.d.ts +0 -1
  184. package/dist/review/check-outcomes.test.js +0 -56
  185. package/dist/review/code-patterns.test.d.ts +0 -1
  186. package/dist/review/code-patterns.test.js +0 -142
  187. package/dist/review/dead-code.test.d.ts +0 -1
  188. package/dist/review/dead-code.test.js +0 -154
  189. package/dist/review/deep-runs.test.d.ts +0 -1
  190. package/dist/review/deep-runs.test.js +0 -23
  191. package/dist/review/effectiveness.test.d.ts +0 -1
  192. package/dist/review/effectiveness.test.js +0 -42
  193. package/dist/review/fix-scope.test.d.ts +0 -1
  194. package/dist/review/fix-scope.test.js +0 -104
  195. package/dist/review/generated-files.test.d.ts +0 -1
  196. package/dist/review/generated-files.test.js +0 -25
  197. package/dist/review/migration-order.test.d.ts +0 -1
  198. package/dist/review/migration-order.test.js +0 -62
  199. package/dist/review/quiet.test.d.ts +0 -1
  200. package/dist/review/quiet.test.js +0 -38
  201. package/dist/review/receipt.test.d.ts +0 -1
  202. package/dist/review/receipt.test.js +0 -60
  203. package/dist/review/review-task.test.d.ts +0 -1
  204. package/dist/review/review-task.test.js +0 -89
  205. package/dist/review/review.test.d.ts +0 -1
  206. package/dist/review/review.test.js +0 -203
  207. package/dist/review/reviewer/adapters.test.d.ts +0 -1
  208. package/dist/review/reviewer/adapters.test.js +0 -100
  209. package/dist/review/reviewer/api-judge.test.d.ts +0 -1
  210. package/dist/review/reviewer/api-judge.test.js +0 -108
  211. package/dist/review/reviewer/background.test.d.ts +0 -1
  212. package/dist/review/reviewer/background.test.js +0 -118
  213. package/dist/review/reviewer/context.test.d.ts +0 -1
  214. package/dist/review/reviewer/context.test.js +0 -45
  215. package/dist/review/reviewer/exec.test.d.ts +0 -1
  216. package/dist/review/reviewer/exec.test.js +0 -59
  217. package/dist/review/reviewer/inputs.test.d.ts +0 -1
  218. package/dist/review/reviewer/inputs.test.js +0 -52
  219. package/dist/review/reviewer/panel.test.d.ts +0 -1
  220. package/dist/review/reviewer/panel.test.js +0 -110
  221. package/dist/review/reviewer/record.test.d.ts +0 -1
  222. package/dist/review/reviewer/record.test.js +0 -40
  223. package/dist/review/reviewer/rule-writer.test.d.ts +0 -1
  224. package/dist/review/reviewer/rule-writer.test.js +0 -52
  225. package/dist/review/reviewer/settings.test.d.ts +0 -1
  226. package/dist/review/reviewer/settings.test.js +0 -57
  227. package/dist/review/reviewer/usage.test.d.ts +0 -1
  228. package/dist/review/reviewer/usage.test.js +0 -14
  229. package/dist/review/reviewer.test.d.ts +0 -1
  230. package/dist/review/reviewer.test.js +0 -792
  231. package/dist/review/stories.test.d.ts +0 -1
  232. package/dist/review/stories.test.js +0 -58
  233. package/dist/review/toolchain.test.d.ts +0 -1
  234. package/dist/review/toolchain.test.js +0 -108
  235. package/dist/review/typed/redundancy.test.d.ts +0 -1
  236. package/dist/review/typed/redundancy.test.js +0 -315
  237. package/dist/review/typed/schema-nullability.test.d.ts +0 -1
  238. package/dist/review/typed/schema-nullability.test.js +0 -63
  239. package/dist/review-learning/human-edits.test.d.ts +0 -1
  240. package/dist/review-learning/human-edits.test.js +0 -47
  241. package/dist/review-learning/repo-rules.test.d.ts +0 -1
  242. package/dist/review-learning/repo-rules.test.js +0 -93
  243. package/dist/review-learning/review-learning.test.d.ts +0 -1
  244. package/dist/review-learning/review-learning.test.js +0 -249
  245. package/dist/safety.test.d.ts +0 -1
  246. package/dist/safety.test.js +0 -42
  247. package/dist/semantic/benchmark.test.d.ts +0 -1
  248. package/dist/semantic/benchmark.test.js +0 -22
  249. package/dist/semantic/intent/intent.test.d.ts +0 -1
  250. package/dist/semantic/intent/intent.test.js +0 -46
  251. package/dist/semantic/learn/learn.test.d.ts +0 -1
  252. package/dist/semantic/learn/learn.test.js +0 -67
  253. package/dist/semantic/origins.test.d.ts +0 -1
  254. package/dist/semantic/origins.test.js +0 -77
  255. package/dist/semantic/project-facts.test.d.ts +0 -1
  256. package/dist/semantic/project-facts.test.js +0 -45
  257. package/dist/semantic/sites/call-sites.test.d.ts +0 -1
  258. package/dist/semantic/sites/call-sites.test.js +0 -46
  259. package/dist/services/adaptive-thresholds.test.d.ts +0 -1
  260. package/dist/services/adaptive-thresholds.test.js +0 -53
  261. package/dist/services/agent-history.test.d.ts +0 -1
  262. package/dist/services/agent-history.test.js +0 -69
  263. package/dist/services/context-scope-summary.test.d.ts +0 -1
  264. package/dist/services/context-scope-summary.test.js +0 -17
  265. package/dist/services/context-telemetry-service.test.d.ts +0 -1
  266. package/dist/services/context-telemetry-service.test.js +0 -182
  267. package/dist/services/cursor-usage-sync.test.d.ts +0 -1
  268. package/dist/services/cursor-usage-sync.test.js +0 -173
  269. package/dist/services/engineering-knowledge-graph.test.d.ts +0 -1
  270. package/dist/services/engineering-knowledge-graph.test.js +0 -76
  271. package/dist/services/model-pricing.test.d.ts +0 -1
  272. package/dist/services/model-pricing.test.js +0 -44
  273. package/dist/services/observed-savings.test.d.ts +0 -1
  274. package/dist/services/observed-savings.test.js +0 -37
  275. package/dist/services/score-history.test.d.ts +0 -1
  276. package/dist/services/score-history.test.js +0 -61
  277. package/dist/smoke.test.d.ts +0 -1
  278. package/dist/smoke.test.js +0 -17
  279. package/dist/storage/cache-cleanup.test.d.ts +0 -1
  280. package/dist/storage/cache-cleanup.test.js +0 -54
  281. package/dist/storage/context-telemetry.test.d.ts +0 -1
  282. package/dist/storage/context-telemetry.test.js +0 -80
  283. package/dist/storage/db.test.d.ts +0 -1
  284. package/dist/storage/db.test.js +0 -46
  285. package/dist/storage/fix-lessons.test.d.ts +0 -1
  286. package/dist/storage/fix-lessons.test.js +0 -61
  287. package/dist/storage/lessons.test.d.ts +0 -1
  288. package/dist/storage/lessons.test.js +0 -81
  289. package/dist/storage/local-encryption.test.d.ts +0 -1
  290. package/dist/storage/local-encryption.test.js +0 -34
  291. package/dist/storage/local-memory.test.d.ts +0 -1
  292. package/dist/storage/local-memory.test.js +0 -55
  293. package/dist/storage/share-memory.test.d.ts +0 -1
  294. package/dist/storage/share-memory.test.js +0 -34
  295. package/dist/storage/team-diagnostics.test.d.ts +0 -1
  296. package/dist/storage/team-diagnostics.test.js +0 -51
  297. package/dist/storage/team-scope.test.d.ts +0 -1
  298. package/dist/storage/team-scope.test.js +0 -22
  299. package/dist/storage/team-store.test.d.ts +0 -1
  300. package/dist/storage/team-store.test.js +0 -11
  301. package/dist/storage/team-sync-scope.test.d.ts +0 -1
  302. package/dist/storage/team-sync-scope.test.js +0 -100
  303. package/dist/storage/team-vector-store.test.d.ts +0 -1
  304. package/dist/storage/team-vector-store.test.js +0 -56
  305. package/dist/storage/telemetry-scope.test.d.ts +0 -1
  306. package/dist/storage/telemetry-scope.test.js +0 -38
  307. package/dist/task/thread.test.d.ts +0 -1
  308. package/dist/task/thread.test.js +0 -133
  309. package/dist/telemetry/telemetry.test.d.ts +0 -1
  310. package/dist/telemetry/telemetry.test.js +0 -64
  311. package/dist/types/index.test.d.ts +0 -1
  312. package/dist/types/index.test.js +0 -33
  313. package/dist/utils/command-line.test.d.ts +0 -1
  314. package/dist/utils/command-line.test.js +0 -8
  315. package/dist/utils/diff-removed.test.d.ts +0 -1
  316. package/dist/utils/diff-removed.test.js +0 -29
  317. package/dist/utils/diff.test.d.ts +0 -1
  318. package/dist/utils/diff.test.js +0 -38
  319. package/dist/utils/glob-paths.test.d.ts +0 -1
  320. package/dist/utils/glob-paths.test.js +0 -40
  321. package/dist/utils/profile.test.d.ts +0 -1
  322. package/dist/utils/profile.test.js +0 -68
  323. package/dist/utils/scanner.test.d.ts +0 -1
  324. package/dist/utils/scanner.test.js +0 -48
  325. package/dist/utils/scope.test.d.ts +0 -1
  326. package/dist/utils/scope.test.js +0 -38
@@ -1,325 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach } from 'vitest';
2
- const mockFindFiles = vi.hoisted(() => vi.fn());
3
- const mockReadFile = vi.hoisted(() => vi.fn());
4
- vi.mock('../utils/scanner.js', () => ({
5
- FileScanner: { findFiles: mockFindFiles },
6
- }));
7
- vi.mock('fs-extra', () => ({
8
- default: {
9
- readFile: mockReadFile,
10
- pathExists: vi.fn().mockResolvedValue(false),
11
- pathExistsSync: vi.fn().mockReturnValue(false),
12
- readFileSync: vi.fn().mockReturnValue(''),
13
- readJson: vi.fn().mockResolvedValue(null),
14
- readdirSync: vi.fn().mockReturnValue([]),
15
- },
16
- }));
17
- import { TestQualityGate } from './test-quality.js';
18
- describe('TestQualityGate — JS/TS tests', () => {
19
- let gate;
20
- beforeEach(() => {
21
- gate = new TestQualityGate();
22
- vi.clearAllMocks();
23
- });
24
- it('should flag empty test bodies', async () => {
25
- mockFindFiles.mockResolvedValue(['src/utils.test.ts']);
26
- mockReadFile.mockResolvedValue(`
27
- describe('Utils', () => {
28
- it('should do something', () => {
29
- });
30
- });
31
- `);
32
- const failures = await gate.run({ cwd: '/project' });
33
- expect(failures).toHaveLength(1);
34
- expect(failures[0].details).toContain('empty-test');
35
- });
36
- it('should flag tests with no assertions', async () => {
37
- mockFindFiles.mockResolvedValue(['src/api.test.ts']);
38
- mockReadFile.mockResolvedValue(`
39
- describe('API', () => {
40
- it('should fetch data', () => {
41
- const data = fetchData();
42
- console.log(data);
43
- });
44
- });
45
- `);
46
- const failures = await gate.run({ cwd: '/project' });
47
- expect(failures).toHaveLength(1);
48
- expect(failures[0].details).toContain('no-assertion');
49
- });
50
- it('should not flag type-level tests, where the compiler is the assertion', async () => {
51
- mockFindFiles.mockResolvedValue(['src/types.test.ts']);
52
- mockReadFile.mockResolvedValue(`
53
- it('our document type accepts the published one', () => {
54
- const _published: Document = null as unknown as Published.Document;
55
- });
56
- it('infers the output', () => {
57
- expectTypeOf(output).toEqualTypeOf<string>();
58
- });
59
- `);
60
- const failures = await gate.run({ cwd: '/project' });
61
- expect(failures).toHaveLength(0);
62
- });
63
- it('should flag tautological assertions', async () => {
64
- mockFindFiles.mockResolvedValue(['src/basic.test.ts']);
65
- mockReadFile.mockResolvedValue(`
66
- describe('Basic', () => {
67
- it('should pass', () => {
68
- expect(true).toBe(true);
69
- });
70
- });
71
- `);
72
- const failures = await gate.run({ cwd: '/project' });
73
- expect(failures).toHaveLength(1);
74
- expect(failures[0].details).toContain('tautological');
75
- });
76
- it('should flag mock-heavy tests', async () => {
77
- mockFindFiles.mockResolvedValue(['src/service.test.ts']);
78
- mockReadFile.mockResolvedValue(`
79
- describe('Service', () => {
80
- it('should process', () => {
81
- const mock1 = vi.fn();
82
- const mock2 = vi.fn();
83
- const mock3 = vi.fn();
84
- const mock4 = vi.fn();
85
- const mock5 = vi.fn();
86
- const mock6 = vi.fn();
87
- expect(mock1).toBeDefined();
88
- });
89
- });
90
- `);
91
- const failures = await gate.run({ cwd: '/project' });
92
- expect(failures).toHaveLength(1);
93
- expect(failures[0].details).toContain('mock-heavy');
94
- });
95
- it('should NOT flag well-written tests', async () => {
96
- mockFindFiles.mockResolvedValue(['src/good.test.ts']);
97
- mockReadFile.mockResolvedValue(`
98
- describe('Calculator', () => {
99
- it('should add two numbers', () => {
100
- const result = add(2, 3);
101
- expect(result).toBe(5);
102
- });
103
-
104
- it('should handle negative numbers', () => {
105
- const result = add(-1, -2);
106
- expect(result).toBe(-3);
107
- });
108
- });
109
- `);
110
- const failures = await gate.run({ cwd: '/project' });
111
- expect(failures).toHaveLength(0);
112
- });
113
- it('should NOT flag tests with expect().toEqual()', async () => {
114
- mockFindFiles.mockResolvedValue(['src/valid.test.ts']);
115
- mockReadFile.mockResolvedValue(`
116
- describe('Parser', () => {
117
- it('should parse JSON', () => {
118
- const result = parseConfig('{"key": "value"}');
119
- expect(result).toEqual({ key: 'value' });
120
- });
121
- });
122
- `);
123
- const failures = await gate.run({ cwd: '/project' });
124
- expect(failures).toHaveLength(0);
125
- });
126
- it('should not scan when disabled', async () => {
127
- const disabled = new TestQualityGate({ enabled: false });
128
- const failures = await disabled.run({ cwd: '/project' });
129
- expect(failures).toHaveLength(0);
130
- expect(mockFindFiles).not.toHaveBeenCalled();
131
- });
132
- });
133
- describe('TestQualityGate — Python tests', () => {
134
- let gate;
135
- beforeEach(() => {
136
- gate = new TestQualityGate();
137
- vi.clearAllMocks();
138
- });
139
- it('should flag empty test functions', async () => {
140
- mockFindFiles.mockResolvedValue(['test_utils.py']);
141
- mockReadFile.mockResolvedValue(`
142
- def test_something():
143
- pass
144
- `);
145
- const failures = await gate.run({ cwd: '/project' });
146
- expect(failures).toHaveLength(1);
147
- expect(failures[0].details).toContain('empty-test');
148
- });
149
- it('should flag tests with no assertions', async () => {
150
- mockFindFiles.mockResolvedValue(['test_api.py']);
151
- mockReadFile.mockResolvedValue(`
152
- def test_fetch_data():
153
- data = fetch_data()
154
- print(data)
155
- result = process(data)
156
- `);
157
- const failures = await gate.run({ cwd: '/project' });
158
- expect(failures).toHaveLength(1);
159
- expect(failures[0].details).toContain('no-assertion');
160
- });
161
- it('should flag tautological Python assertions', async () => {
162
- mockFindFiles.mockResolvedValue(['test_basic.py']);
163
- mockReadFile.mockResolvedValue(`
164
- def test_always_passes():
165
- assert True
166
- `);
167
- const failures = await gate.run({ cwd: '/project' });
168
- expect(failures).toHaveLength(1);
169
- expect(failures[0].details).toContain('tautological');
170
- });
171
- it('should NOT flag Python tests with real assertions', async () => {
172
- mockFindFiles.mockResolvedValue(['test_calc.py']);
173
- mockReadFile.mockResolvedValue(`
174
- def test_addition():
175
- result = add(2, 3)
176
- assert result == 5
177
-
178
- def test_subtraction():
179
- result = subtract(5, 3)
180
- assert result == 2
181
- `);
182
- const failures = await gate.run({ cwd: '/project' });
183
- expect(failures).toHaveLength(0);
184
- });
185
- it('should NOT flag tests using pytest.raises', async () => {
186
- mockFindFiles.mockResolvedValue(['test_errors.py']);
187
- mockReadFile.mockResolvedValue(`
188
- def test_invalid_input():
189
- with pytest.raises(ValueError):
190
- parse_int("not a number")
191
- `);
192
- const failures = await gate.run({ cwd: '/project' });
193
- expect(failures).toHaveLength(0);
194
- });
195
- });
196
- describe('TestQualityGate — Go tests', () => {
197
- let gate;
198
- beforeEach(() => {
199
- gate = new TestQualityGate();
200
- vi.clearAllMocks();
201
- });
202
- it('should flag empty Go test functions', async () => {
203
- mockFindFiles.mockResolvedValue(['utils_test.go']);
204
- mockReadFile.mockResolvedValue(`
205
- package utils
206
-
207
- import "testing"
208
-
209
- func TestSomething(t *testing.T) {
210
- }
211
- `);
212
- const failures = await gate.run({ cwd: '/project' });
213
- expect(failures).toHaveLength(1);
214
- expect(failures[0].details).toContain('empty-test');
215
- });
216
- it('should flag Go tests without assertions', async () => {
217
- mockFindFiles.mockResolvedValue(['calc_test.go']);
218
- mockReadFile.mockResolvedValue(`
219
- package calc
220
-
221
- import "testing"
222
-
223
- func TestAdd(t *testing.T) {
224
- result := Add(2, 3)
225
- _ = result
226
- }
227
- `);
228
- const failures = await gate.run({ cwd: '/project' });
229
- expect(failures).toHaveLength(1);
230
- expect(failures[0].details).toContain('no-assertion');
231
- });
232
- it('should NOT flag Go tests with t.Error assertions', async () => {
233
- mockFindFiles.mockResolvedValue(['good_test.go']);
234
- mockReadFile.mockResolvedValue(`
235
- package calc
236
-
237
- import "testing"
238
-
239
- func TestAdd(t *testing.T) {
240
- result := Add(2, 3)
241
- if result != 5 {
242
- t.Errorf("expected 5, got %d", result)
243
- }
244
- }
245
- `);
246
- const failures = await gate.run({ cwd: '/project' });
247
- expect(failures).toHaveLength(0);
248
- });
249
- it('should NOT flag Go tests with testify assertions', async () => {
250
- mockFindFiles.mockResolvedValue(['testify_test.go']);
251
- mockReadFile.mockResolvedValue(`
252
- package main
253
-
254
- import (
255
- "testing"
256
- "github.com/stretchr/testify/assert"
257
- )
258
-
259
- func TestAdd(t *testing.T) {
260
- result := Add(2, 3)
261
- assert.Equal(t, 5, result)
262
- }
263
- `);
264
- const failures = await gate.run({ cwd: '/project' });
265
- expect(failures).toHaveLength(0);
266
- });
267
- });
268
- describe('TestQualityGate — Java tests', () => {
269
- let gate;
270
- beforeEach(() => {
271
- gate = new TestQualityGate();
272
- vi.clearAllMocks();
273
- });
274
- it('should flag Java tests without assertions', async () => {
275
- mockFindFiles.mockResolvedValue(['CalcTest.java']);
276
- mockReadFile.mockResolvedValue(`
277
- import org.junit.jupiter.api.Test;
278
-
279
- class CalcTest {
280
- @Test
281
- void testAdd() {
282
- int result = Calculator.add(2, 3);
283
- System.out.println(result);
284
- }
285
- }
286
- `);
287
- const failures = await gate.run({ cwd: '/project' });
288
- expect(failures).toHaveLength(1);
289
- expect(failures[0].details).toContain('no-assertion');
290
- });
291
- it('should NOT flag Java tests with assertions', async () => {
292
- mockFindFiles.mockResolvedValue(['GoodTest.java']);
293
- mockReadFile.mockResolvedValue(`
294
- import org.junit.jupiter.api.Test;
295
- import static org.junit.jupiter.api.Assertions.*;
296
-
297
- class GoodTest {
298
- @Test
299
- void testAdd() {
300
- int result = Calculator.add(2, 3);
301
- assertEquals(5, result);
302
- }
303
- }
304
- `);
305
- const failures = await gate.run({ cwd: '/project' });
306
- expect(failures).toHaveLength(0);
307
- });
308
- it('should flag tautological Java assertions', async () => {
309
- mockFindFiles.mockResolvedValue(['TautTest.java']);
310
- mockReadFile.mockResolvedValue(`
311
- import org.junit.jupiter.api.Test;
312
- import static org.junit.jupiter.api.Assertions.*;
313
-
314
- class TautTest {
315
- @Test
316
- void testAlwaysPasses() {
317
- assertTrue(true);
318
- }
319
- }
320
- `);
321
- const failures = await gate.run({ cwd: '/project' });
322
- expect(failures.length).toBeGreaterThanOrEqual(1);
323
- expect(failures[0].details).toContain('tautological');
324
- });
325
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,16 +0,0 @@
1
- import fs from 'fs';
2
- import os from 'os';
3
- import path from 'path';
4
- import { afterEach, describe, expect, it } from 'vitest';
5
- import { trustedReviews } from './deep-analysis.js';
6
- let cwd;
7
- afterEach(() => fs.rmSync(cwd, { recursive: true, force: true }));
8
- describe('trustedReviews', () => {
9
- it('lets a normal run skip what agents recorded as reviewed, and an independent run skip nothing', () => {
10
- cwd = fs.mkdtempSync(path.join(os.tmpdir(), 'trusted-reviews-'));
11
- fs.mkdirSync(path.join(cwd, '.rigour'));
12
- fs.writeFileSync(path.join(cwd, '.rigour', 'reviewed.json'), JSON.stringify({ version: 1, entries: [{ file: 'src/a.ts', function: 'f', hash: 'h', reviewer: 'agent', verdict: 'no_issue' }] }));
13
- expect(trustedReviews(cwd, {}).map(r => r.function)).toEqual(['f']);
14
- expect(trustedReviews(cwd, { independent: true })).toEqual([]);
15
- });
16
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,54 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { findReads } from './queries.js';
3
- const reads = (code) => findReads('a.ts', code);
4
- describe('findReads', () => {
5
- it('models a literal supabase-js read: filters, first order column, line', () => {
6
- const [read] = reads(`
7
- const page = await supabase
8
- .from('orders')
9
- .select('id, placed_at')
10
- .eq('status', 'open')
11
- .not('customer_id', 'is', null)
12
- .gt('placed_at', since)
13
- .lte('placed_at', until)
14
- .order('placed_at')
15
- .order('id')
16
- .limit(100);`);
17
- expect(read).toEqual({
18
- table: 'orders', line: 3, uncertain: false, orderBy: 'placed_at',
19
- filters: [
20
- { column: 'status', op: 'eq', value: 'open' },
21
- { column: 'customer_id', op: 'notnull' },
22
- { column: 'placed_at', op: 'range' },
23
- { column: 'placed_at', op: 'range' },
24
- ],
25
- });
26
- });
27
- it('reads .in, .is(null), .match and .filter, and qualifies a non-public schema', () => {
28
- const [read] = reads(`db.schema('billing').from('invoices').select('*').in('id', ids).is('paid_at', null).match({ kind: 'card' }).filter('total', 'gte', 10);`);
29
- expect(read.table).toBe('billing.invoices');
30
- expect(read.filters).toEqual([
31
- { column: 'id', op: 'in' },
32
- { column: 'paid_at', op: 'isnull' },
33
- { column: 'kind', op: 'eq', value: 'card' },
34
- { column: 'total', op: 'range' },
35
- ]);
36
- expect(read.uncertain).toBe(false);
37
- });
38
- it('is uncertain when anything is computed, OR-ed, embedded or unknown', () => {
39
- const uncertain = [
40
- `db.from(table).select('*').eq('a', 1);`,
41
- `db.from('t').select('*').eq(column, 1);`,
42
- `db.from('t').select('*').or('a.eq.1,b.eq.2');`,
43
- `db.from('t').select('*, u!inner(*)').eq('u.id', 1);`,
44
- `db.from('t').select('*').someNewFilter('a', 1);`,
45
- `db.schema(name).from('t').select('*').eq('a', 1);`,
46
- ];
47
- expect(uncertain.map(code => reads(code)[0].uncertain)).toEqual(uncertain.map(() => true));
48
- });
49
- it('ignores writes and calls that are not reads', () => {
50
- expect(reads(`db.from('t').insert({ a: 1 }).select();`)).toEqual([]);
51
- expect(reads(`db.from('t').update({ a: 1 }).eq('id', 1);`)).toEqual([]);
52
- expect(reads(`Array.from(items).filter(Boolean);`)).toEqual([]);
53
- });
54
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,81 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { policyColumns, policyFilters, replayMigrations } from './schema.js';
3
- import { splitStatements } from './sql.js';
4
- describe('splitStatements', () => {
5
- it('keeps comments, quotes and dollar bodies from splitting a statement', () => {
6
- const sql = `-- a; comment\ncreate table a (x text default ';');\n/* b; */ do $$ begin perform 1; end $$;\nselect 'it''s; fine';`;
7
- expect(splitStatements(sql)).toEqual(["create table a (x text default ';')", 'do $$ begin perform 1; end $$', "select 'it''s; fine'"]);
8
- });
9
- });
10
- describe('replayMigrations', () => {
11
- it('collects primary keys, unique columns and table constraints as indexes', () => {
12
- const schema = replayMigrations([`
13
- create table public.orders (
14
- id uuid primary key default gen_random_uuid(),
15
- code text not null unique,
16
- customer_id uuid not null references customers(id),
17
- placed_at timestamptz,
18
- constraint orders_customer_code unique (customer_id, code)
19
- );`]);
20
- expect(schema.get('orders').indexes.map(i => i.leading)).toEqual(['id', 'code', 'customer_id']);
21
- expect(schema.get('orders').uncertain).toBe(false);
22
- });
23
- it('applies indexes, partial predicates, drops and renames in order', () => {
24
- const schema = replayMigrations([
25
- 'create table orders (id uuid primary key, status text, placed_at timestamptz, customer_id uuid);',
26
- `create index concurrently orders_open_idx on public.orders (placed_at desc, id) where status = 'open' and customer_id is not null;`,
27
- 'create index orders_customer_idx on orders using btree (customer_id);',
28
- 'create index orders_lower_idx on orders (lower(status));',
29
- 'drop index if exists public.orders_customer_idx;',
30
- 'alter index orders_open_idx rename to orders_open_v2_idx;',
31
- ]);
32
- const indexes = schema.get('orders').indexes;
33
- expect(indexes.map(i => [i.name, i.leading])).toEqual([[undefined, 'id'], ['orders_open_v2_idx', 'placed_at'], ['orders_lower_idx', null]]);
34
- expect(indexes[1].predicate).toEqual([{ kind: 'eq', column: 'status', value: 'open' }, { kind: 'notnull', column: 'customer_id' }]);
35
- });
36
- it('follows ALTER TABLE: added keys, table renames, dropped tables', () => {
37
- const schema = replayMigrations([
38
- 'create table events (id bigint, kind text);',
39
- 'alter table events add constraint events_pkey primary key (id);',
40
- 'alter table events add column ref text unique;',
41
- 'alter table events rename to audit_events;',
42
- 'create table scratch (x int);',
43
- 'drop table scratch;',
44
- ]);
45
- expect(schema.get('audit_events').indexes.map(i => i.leading)).toEqual(['id', 'ref']);
46
- expect([...schema.keys()]).toEqual(['audit_events']);
47
- });
48
- it('marks a table uncertain when DDL is beyond what it models', () => {
49
- const schema = replayMigrations([
50
- 'create table a (id int, x int); create table b (id int); create table c (like a including indexes); create table d (id int) partition by range (id);',
51
- 'alter table a rename column x to y;',
52
- `create or replace function f() returns void language plpgsql as $$ begin create index on b (id); end $$;`,
53
- ]);
54
- expect(['a', 'b', 'c', 'd'].map(t => schema.get(t).uncertain)).toEqual([true, true, true, true]);
55
- });
56
- it('treats an OR or an unreadable predicate as unknown', () => {
57
- const schema = replayMigrations([
58
- 'create table t (a int, b int);',
59
- `create index t_or on t (a) where a = 1 or b = 2;`,
60
- `create index t_fn on t (a) where coalesce(b, 0) > 0;`,
61
- ]);
62
- expect(schema.get('t').indexes.map(i => i.predicate)).toEqual([[{ kind: 'unknown' }], [{ kind: 'unknown' }]]);
63
- });
64
- it('keeps SELECT and ALL policies as the columns they compare to the user', () => {
65
- const schema = replayMigrations([
66
- 'create table subs (id text primary key, user_id uuid, status text);',
67
- `create policy "own" on subs for select using (auth.uid() = user_id);`,
68
- `create policy "writes" on subs for insert with check (auth.uid() = user_id);`,
69
- `create policy "all" on subs to authenticated using (true);`,
70
- ]);
71
- expect(policyFilters(schema.get('subs'))).toEqual({ columns: ['user_id'], unknown: false });
72
- });
73
- });
74
- describe('policyColumns', () => {
75
- it('reads comparisons to the current user and gives up on anything else', () => {
76
- expect(policyColumns('(select auth.uid()) = owner_id')).toEqual(['owner_id']);
77
- expect(policyColumns('(owner_id = auth.uid()) or (editor_id = auth.uid())')).toEqual(['owner_id', 'editor_id']);
78
- expect(policyColumns('true')).toEqual([]);
79
- expect(policyColumns('exists (select 1 from members m where m.org_id = org_id)')).toBeNull();
80
- });
81
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,90 +0,0 @@
1
- import fs from 'fs';
2
- import os from 'os';
3
- import path from 'path';
4
- import { afterEach, beforeEach, describe, expect, it } from 'vitest';
5
- import { UnindexedReadsGate } from './index.js';
6
- let repo;
7
- const write = (rel, body) => {
8
- fs.mkdirSync(path.dirname(path.join(repo, rel)), { recursive: true });
9
- fs.writeFileSync(path.join(repo, rel), body);
10
- };
11
- const run = (config = { enabled: true }) => new UnindexedReadsGate(config).run({ cwd: repo, patterns: ['src/**/*.ts'] });
12
- const TABLE = `create table orders (
13
- id uuid primary key,
14
- customer_id uuid,
15
- status text not null,
16
- placed_at timestamptz,
17
- campaign_id uuid
18
- );
19
- create index orders_customer_idx on orders (customer_id, status, placed_at desc);
20
- create index orders_campaign_window_idx on orders (placed_at, id) where status = 'open' and campaign_id is not null;
21
- `;
22
- const WINDOW_READ = `
23
- export async function openOrders(db: Db, since: string, until: string) {
24
- return db
25
- .from('orders')
26
- .select('id, placed_at')
27
- .eq('status', 'open')
28
- .not('customer_id', 'is', null)
29
- .gt('placed_at', since)
30
- .lte('placed_at', until)
31
- .order('placed_at')
32
- .order('id');
33
- }
34
- `;
35
- beforeEach(() => { repo = fs.mkdtempSync(path.join(os.tmpdir(), 'unindexed-')); });
36
- afterEach(() => fs.rmSync(repo, { recursive: true, force: true }));
37
- describe('UnindexedReadsGate', () => {
38
- it('flags a window read whose only candidate index is partial on a filter the read does not have', async () => {
39
- write('supabase/migrations/20260101000000_orders.sql', TABLE);
40
- write('src/orders.ts', WINDOW_READ);
41
- const failures = await run();
42
- expect(failures).toHaveLength(1);
43
- expect(failures[0]).toMatchObject({ id: 'unindexed-reads', files: ['src/orders.ts'], line: 4 });
44
- expect(failures[0].details).toContain('`orders`');
45
- expect(failures[0].details).toContain('`placed_at`');
46
- });
47
- it('is silent once a later migration adds an index that serves the read', async () => {
48
- write('supabase/migrations/20260101000000_orders.sql', TABLE);
49
- write('supabase/migrations/20260102000000_orders_open.sql', `create index concurrently orders_open_window_idx on public.orders (placed_at, id) where status = 'open' and customer_id is not null;`);
50
- write('src/orders.ts', WINDOW_READ);
51
- expect(await run()).toEqual([]);
52
- });
53
- it('is silent for a primary-key lookup, a table outside the migrations, and an uncertain table', async () => {
54
- write('db/migrations/001_orders.sql', TABLE + 'create table notes (id int, body text);\nalter table notes rename column body to text;\n');
55
- write('src/reads.ts', `
56
- db.from('orders').select('*').eq('id', id);
57
- db.from('auth_users').select('*').eq('email', email);
58
- db.from('notes').select('*').eq('text', q);
59
- `);
60
- expect(await run()).toEqual([]);
61
- });
62
- it('is silent unless enabled, and for a read that narrows nothing', async () => {
63
- write('supabase/migrations/20260101000000_orders.sql', TABLE);
64
- write('src/orders.ts', WINDOW_READ + `\ndb.from('orders').select('*').limit(10);\n`);
65
- expect(await run({ enabled: false })).toEqual([]);
66
- expect(await new UnindexedReadsGate({ enabled: true }).run({ cwd: repo, patterns: ['src/**/*.ts'] })).toHaveLength(1);
67
- });
68
- it('needs every migration set that defines the table to lack a serving index', async () => {
69
- write('apps/a/supabase/migrations/1_orders.sql', TABLE);
70
- write('apps/b/supabase/migrations/1_orders.sql', TABLE + `create index orders_status_idx on orders (status);`);
71
- write('src/orders.ts', WINDOW_READ);
72
- expect(await run()).toEqual([]);
73
- });
74
- it('counts a row-level policy as a filter: names its column, and is silent once that column is indexed', async () => {
75
- const subs = `create table subs (id text primary key, user_id uuid not null, status text);
76
- create policy "own subs" on subs for select using (auth.uid() = user_id);`;
77
- write('supabase/migrations/1_subs.sql', subs);
78
- write('src/subs.ts', `export const active = (db: Db) => db.from('subs').select('*').in('status', ['active']).maybeSingle();\n`);
79
- const [finding] = await run();
80
- expect(finding.details).toContain('`user_id`');
81
- write('supabase/migrations/2_subs_user.sql', 'create index subs_user_idx on subs (user_id);');
82
- expect(await run()).toEqual([]);
83
- });
84
- it('is silent for a table whose policy it cannot read', async () => {
85
- write('supabase/migrations/1_docs.sql', `create table docs (id int primary key, org_id int, title text);
86
- create policy "members" on docs for select using (exists (select 1 from members m where m.org_id = docs.org_id));`);
87
- write('src/docs.ts', `db.from('docs').select('*').eq('title', t);\n`);
88
- expect(await run()).toEqual([]);
89
- });
90
- });
@@ -1 +0,0 @@
1
- export {};