@rigour-labs/core 6.2.2 → 6.2.3

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.
@@ -51,12 +51,20 @@ export class FrontendSecretExposureGate extends Gate {
51
51
  '(^|/)views/',
52
52
  '(^|/)public/',
53
53
  ],
54
- server_path_patterns: config.server_path_patterns ?? [
54
+ // Built-in server locations remain safe when older config files
55
+ // provide their own list; custom patterns extend this baseline.
56
+ server_path_patterns: [
55
57
  '(^|/)pages/api/',
56
58
  '(^|/)src/pages/api/',
57
59
  '(^|/)app/api/',
58
60
  '(^|/)src/app/api/',
61
+ '(^|/)scripts/',
62
+ '(^|/)e2e/',
63
+ '(^|/)tests/',
64
+ '(^|/)server/',
65
+ '(^|/)(?:playwright|vitest|vite|jest|next|webpack|eslint|prettier|tailwind|postcss|babel|tsup|rollup)\\.config\\.[cm]?[jt]s$',
59
66
  '\\.server\\.(?:ts|tsx|js|jsx|mjs|cjs)$',
67
+ ...(config.server_path_patterns ?? []),
60
68
  ],
61
69
  allowlist_env_names: config.allowlist_env_names ?? [],
62
70
  };
@@ -81,7 +89,7 @@ export class FrontendSecretExposureGate extends Gate {
81
89
  ],
82
90
  });
83
91
  // Skip test/fixture files — they routinely use dummy keys
84
- const sourceFiles = files.filter(f => !this.isTestFile(f));
92
+ const sourceFiles = files.filter(f => /\.(?:[cm]?[jt]s|[jt]sx|vue|svelte)$/i.test(f) && !this.isTestFile(f));
85
93
  Logger.info(`Frontend Secret Exposure Gate: scanning ${sourceFiles.length} files`);
86
94
  const exposures = [];
87
95
  for (const file of sourceFiles) {
@@ -70,6 +70,22 @@ describe('FrontendSecretExposureGate', () => {
70
70
  const failures = await gate.run({ cwd: testDir });
71
71
  expect(failures).toHaveLength(0);
72
72
  });
73
+ it('does not treat server scripts or test configuration as browser bundles', async () => {
74
+ for (const file of ['scripts/migrate.mjs', 'e2e/session.ts', 'tests/helpers/db.ts', 'playwright.config.ts']) {
75
+ const filePath = path.join(testDir, file);
76
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
77
+ fs.writeFileSync(filePath, 'export const key = process.env.SESSION_SECRET;');
78
+ }
79
+ const gate = new FrontendSecretExposureGate({ server_path_patterns: ['(^|/)pages/api/'] });
80
+ expect(await gate.run({ cwd: testDir })).toHaveLength(0);
81
+ });
82
+ it('ignores shell files even when a broad project scan passes them in', async () => {
83
+ const shellPath = path.join(testDir, 'scripts/rigour-nmc.sh');
84
+ fs.mkdirSync(path.dirname(shellPath), { recursive: true });
85
+ fs.writeFileSync(shellPath, 'node -e "process.env.RIGOUR_NMC_DATABASE_URL"');
86
+ const gate = new FrontendSecretExposureGate();
87
+ expect(await gate.run({ cwd: testDir, patterns: ['**/*'] })).toHaveLength(0);
88
+ });
73
89
  it('respects explicit allowlist env names', async () => {
74
90
  const filePath = path.join(testDir, 'src/views/App.tsx');
75
91
  fs.mkdirSync(path.dirname(filePath), { recursive: true });
@@ -152,7 +152,7 @@ export class HallucinatedImportsGate extends Gate {
152
152
  `${resolvedPath}/index`,
153
153
  ];
154
154
  }
155
- else if (extension) {
155
+ else if (extension && sourceExtensions.includes(extension)) {
156
156
  candidates = [resolvedPath, `${resolvedPath}/index`];
157
157
  }
158
158
  else {
@@ -165,7 +165,8 @@ export class HallucinatedImportsGate extends Gate {
165
165
  }
166
166
  shouldSkipFile(file) {
167
167
  const normalized = file.replace(/\\/g, '/');
168
- return (normalized.includes('/examples/') ||
168
+ return (/(^|\/)next-env\.d\.ts$/.test(normalized) ||
169
+ normalized.includes('/examples/') ||
169
170
  normalized.includes('/studio-dist/') ||
170
171
  normalized.includes('/__tests__/') ||
171
172
  /\.test\.[^.]+$/i.test(normalized) ||
@@ -470,6 +470,30 @@ import { helper } from './utils.js';
470
470
  const failures = await gate.run(context);
471
471
  expect(failures).toHaveLength(0);
472
472
  });
473
+ it('resolves dotted TypeScript basenames without hiding missing imports', async () => {
474
+ const source = `
475
+ import './adapter.cli';
476
+ import './database.types';
477
+ import './missing.cli';
478
+ `;
479
+ FileScanner.findFiles.mockResolvedValue([
480
+ 'src/main.ts', 'src/adapter.cli.ts', 'src/database.types.ts',
481
+ ]);
482
+ mockReadFile.mockImplementation(async (p) => p.replace(/\\/g, '/').endsWith('/src/main.ts') ? source : 'export const value = 1;');
483
+ mockPathExists.mockImplementation(async (p) => p.replace(/\\/g, '/') === '/tmp/test-node-project/package.json');
484
+ mockReadJson.mockResolvedValue({ dependencies: {}, devDependencies: {} });
485
+ const failures = await gate.run(context);
486
+ expect(failures).toHaveLength(1);
487
+ expect(failures[0].details).toContain('./missing.cli');
488
+ expect(failures[0].details).not.toContain('./adapter.cli');
489
+ expect(failures[0].details).not.toContain('./database.types');
490
+ });
491
+ it('ignores the generated Next.js environment declaration', async () => {
492
+ FileScanner.findFiles.mockResolvedValue(['next-env.d.ts']);
493
+ mockReadFile.mockResolvedValue("import './.next/dev/types/routes.d.ts';");
494
+ const failures = await gate.run(context);
495
+ expect(failures).toHaveLength(0);
496
+ });
473
497
  });
474
498
  describe('HallucinatedImportsGate — ignore generated/test artifacts', () => {
475
499
  let gate;
@@ -34,6 +34,14 @@ describe('getScoreTrend', () => {
34
34
  previousAvg: 94,
35
35
  });
36
36
  });
37
+ it('labels 41 → 41 → 41 → 41 → 52 as improving', () => {
38
+ writeScores([41, 41, 41, 41, 52]);
39
+ expect(getScoreTrend(testDir)).toMatchObject({
40
+ direction: 'improving',
41
+ visibleDelta: 11,
42
+ recentScores: [41, 41, 41, 41, 52],
43
+ });
44
+ });
37
45
  it('labels a falling displayed series as degrading', () => {
38
46
  writeScores([80, 75, 70, 64, 59]);
39
47
  expect(getScoreTrend(testDir)).toMatchObject({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rigour-labs/core",
3
- "version": "6.2.2",
3
+ "version": "6.2.3",
4
4
  "description": "AI-native quality gate engine with local Bayesian learning. AST analysis, drift detection, Fix Packet generation, and agent self-healing across TypeScript, JavaScript, Python, Go, Ruby, and C#.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://rigour.run",
@@ -67,11 +67,11 @@
67
67
  "pg": "^8.16.3",
68
68
  "sqlite3": "^5.1.7",
69
69
  "openai": "^4.104.0",
70
- "@rigour-labs/brain-darwin-x64": "6.2.2",
71
- "@rigour-labs/brain-darwin-arm64": "6.2.2",
72
- "@rigour-labs/brain-linux-arm64": "6.2.2",
73
- "@rigour-labs/brain-win-x64": "6.2.2",
74
- "@rigour-labs/brain-linux-x64": "6.2.2"
70
+ "@rigour-labs/brain-darwin-x64": "6.2.3",
71
+ "@rigour-labs/brain-darwin-arm64": "6.2.3",
72
+ "@rigour-labs/brain-linux-arm64": "6.2.3",
73
+ "@rigour-labs/brain-win-x64": "6.2.3",
74
+ "@rigour-labs/brain-linux-x64": "6.2.3"
75
75
  },
76
76
  "devDependencies": {
77
77
  "@types/fs-extra": "^11.0.4",