@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
|
-
|
|
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 (
|
|
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.
|
|
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.
|
|
71
|
-
"@rigour-labs/brain-darwin-arm64": "6.2.
|
|
72
|
-
"@rigour-labs/brain-linux-arm64": "6.2.
|
|
73
|
-
"@rigour-labs/brain-win-x64": "6.2.
|
|
74
|
-
"@rigour-labs/brain-linux-x64": "6.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",
|