@rigour-labs/core 6.8.0 → 6.8.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.
- package/dist/inference/cloud-provider.js +12 -2
- package/package.json +11 -8
- package/dist/brief/briefing.test.d.ts +0 -1
- package/dist/brief/briefing.test.js +0 -107
- package/dist/context/automatic-index-cache.test.d.ts +0 -1
- package/dist/context/automatic-index-cache.test.js +0 -30
- package/dist/context/automatic-index.test.d.ts +0 -1
- package/dist/context/automatic-index.test.js +0 -45
- package/dist/context/cache-engine.test.d.ts +0 -1
- package/dist/context/cache-engine.test.js +0 -99
- package/dist/context/dependency-graph.test.d.ts +0 -1
- package/dist/context/dependency-graph.test.js +0 -13
- package/dist/context/index-status.test.d.ts +0 -1
- package/dist/context/index-status.test.js +0 -26
- package/dist/context.test.d.ts +0 -1
- package/dist/context.test.js +0 -228
- package/dist/deep/agent-review.test.d.ts +0 -1
- package/dist/deep/agent-review.test.js +0 -53
- package/dist/deep/code-context.test.d.ts +0 -1
- package/dist/deep/code-context.test.js +0 -48
- package/dist/deep/code-pass.test.d.ts +0 -1
- package/dist/deep/code-pass.test.js +0 -112
- package/dist/deep/code-review-prompt.test.d.ts +0 -1
- package/dist/deep/code-review-prompt.test.js +0 -20
- package/dist/deep/code-verifier.test.d.ts +0 -1
- package/dist/deep/code-verifier.test.js +0 -54
- package/dist/deep/diff-tests/calls.test.d.ts +0 -1
- package/dist/deep/diff-tests/calls.test.js +0 -33
- package/dist/deep/diff-tests/run.test.d.ts +0 -1
- package/dist/deep/diff-tests/run.test.js +0 -58
- package/dist/deep/fact-extractor.test.d.ts +0 -1
- package/dist/deep/fact-extractor.test.js +0 -581
- package/dist/deep/parse-findings.test.d.ts +0 -1
- package/dist/deep/parse-findings.test.js +0 -25
- package/dist/deep/pr-review.test.d.ts +0 -1
- package/dist/deep/pr-review.test.js +0 -80
- package/dist/deep/prompts.test.d.ts +0 -1
- package/dist/deep/prompts.test.js +0 -235
- package/dist/deep/reference-pack.test.d.ts +0 -1
- package/dist/deep/reference-pack.test.js +0 -46
- package/dist/deep/related-changes.test.d.ts +0 -1
- package/dist/deep/related-changes.test.js +0 -33
- package/dist/deep/review-context-export.test.d.ts +0 -1
- package/dist/deep/review-context-export.test.js +0 -32
- package/dist/deep/review-tools.test.d.ts +0 -1
- package/dist/deep/review-tools.test.js +0 -39
- package/dist/deep/risk.test.d.ts +0 -1
- package/dist/deep/risk.test.js +0 -101
- package/dist/deep/verifier.test.d.ts +0 -1
- package/dist/deep/verifier.test.js +0 -635
- package/dist/discovery.test.d.ts +0 -1
- package/dist/discovery.test.js +0 -93
- package/dist/environment.test.d.ts +0 -1
- package/dist/environment.test.js +0 -94
- package/dist/firewall/firewall.test.d.ts +0 -1
- package/dist/firewall/firewall.test.js +0 -117
- package/dist/firewall/trust-boundaries.test.d.ts +0 -1
- package/dist/firewall/trust-boundaries.test.js +0 -64
- package/dist/firewall/trusted-control.test.d.ts +0 -1
- package/dist/firewall/trusted-control.test.js +0 -188
- package/dist/gates/agent-team.test.d.ts +0 -1
- package/dist/gates/agent-team.test.js +0 -113
- package/dist/gates/ast.test.d.ts +0 -1
- package/dist/gates/ast.test.js +0 -112
- package/dist/gates/checkpoint.test.d.ts +0 -1
- package/dist/gates/checkpoint.test.js +0 -105
- package/dist/gates/content.test.d.ts +0 -1
- package/dist/gates/content.test.js +0 -73
- package/dist/gates/coverage.test.d.ts +0 -1
- package/dist/gates/coverage.test.js +0 -53
- package/dist/gates/dedupe-failures.test.d.ts +0 -1
- package/dist/gates/dedupe-failures.test.js +0 -12
- package/dist/gates/deep-analysis.test.d.ts +0 -1
- package/dist/gates/deep-analysis.test.js +0 -86
- package/dist/gates/deep-intent.test.d.ts +0 -1
- package/dist/gates/deep-intent.test.js +0 -51
- package/dist/gates/deep-timeout.test.d.ts +0 -1
- package/dist/gates/deep-timeout.test.js +0 -10
- package/dist/gates/deprecated-apis.test.d.ts +0 -1
- package/dist/gates/deprecated-apis.test.js +0 -318
- package/dist/gates/deprecated-dependencies.test.d.ts +0 -1
- package/dist/gates/deprecated-dependencies.test.js +0 -55
- package/dist/gates/frontend-secret-exposure.test.d.ts +0 -1
- package/dist/gates/frontend-secret-exposure.test.js +0 -148
- package/dist/gates/hallucinated-imports/framework-modules-nuxt.test.d.ts +0 -1
- package/dist/gates/hallucinated-imports/framework-modules-nuxt.test.js +0 -27
- package/dist/gates/hallucinated-imports/js-resolver-types.test.d.ts +0 -1
- package/dist/gates/hallucinated-imports/js-resolver-types.test.js +0 -14
- package/dist/gates/hallucinated-imports-sveltekit.test.d.ts +0 -1
- package/dist/gates/hallucinated-imports-sveltekit.test.js +0 -132
- package/dist/gates/hallucinated-imports.test.d.ts +0 -1
- package/dist/gates/hallucinated-imports.test.js +0 -1206
- package/dist/gates/js-style-context.test.d.ts +0 -1
- package/dist/gates/js-style-context.test.js +0 -35
- package/dist/gates/logic-drift.test.d.ts +0 -1
- package/dist/gates/logic-drift.test.js +0 -52
- package/dist/gates/phantom-apis.test.d.ts +0 -1
- package/dist/gates/phantom-apis.test.js +0 -396
- package/dist/gates/promise-safety.test.d.ts +0 -1
- package/dist/gates/promise-safety.test.js +0 -34
- package/dist/gates/runner.test.d.ts +0 -1
- package/dist/gates/runner.test.js +0 -77
- package/dist/gates/scoped-gates.test.d.ts +0 -1
- package/dist/gates/scoped-gates.test.js +0 -52
- package/dist/gates/security-patterns-owasp.test.d.ts +0 -1
- package/dist/gates/security-patterns-owasp.test.js +0 -186
- package/dist/gates/security-patterns.test.d.ts +0 -1
- package/dist/gates/security-patterns.test.js +0 -194
- package/dist/gates/semantic-bugs.test.d.ts +0 -1
- package/dist/gates/semantic-bugs.test.js +0 -76
- package/dist/gates/side-effect-analysis.test.d.ts +0 -1
- package/dist/gates/side-effect-analysis.test.js +0 -162
- package/dist/gates/style-drift.test.d.ts +0 -1
- package/dist/gates/style-drift.test.js +0 -26
- package/dist/gates/test-quality.test.d.ts +0 -1
- package/dist/gates/test-quality.test.js +0 -325
- package/dist/gates/trusted-reviews.test.d.ts +0 -1
- package/dist/gates/trusted-reviews.test.js +0 -16
- package/dist/gates/unindexed-reads/queries.test.d.ts +0 -1
- package/dist/gates/unindexed-reads/queries.test.js +0 -54
- package/dist/gates/unindexed-reads/schema.test.d.ts +0 -1
- package/dist/gates/unindexed-reads/schema.test.js +0 -81
- package/dist/gates/unindexed-reads/unindexed-reads.test.d.ts +0 -1
- package/dist/gates/unindexed-reads/unindexed-reads.test.js +0 -90
- package/dist/hooks/checker.test.d.ts +0 -1
- package/dist/hooks/checker.test.js +0 -159
- package/dist/hooks/dlp-confidence.test.d.ts +0 -1
- package/dist/hooks/dlp-confidence.test.js +0 -51
- package/dist/hooks/dlp-feedback.test.d.ts +0 -1
- package/dist/hooks/dlp-feedback.test.js +0 -131
- package/dist/hooks/input-validator.test.d.ts +0 -1
- package/dist/hooks/input-validator.test.js +0 -329
- package/dist/hooks/templates.test.d.ts +0 -1
- package/dist/hooks/templates.test.js +0 -27
- package/dist/inference/brain-placeholder.test.d.ts +0 -1
- package/dist/inference/brain-placeholder.test.js +0 -28
- package/dist/inference/cloud-provider.test.d.ts +0 -1
- package/dist/inference/cloud-provider.test.js +0 -139
- package/dist/inference/executable.test.d.ts +0 -1
- package/dist/inference/executable.test.js +0 -41
- package/dist/inference/http-download.test.d.ts +0 -1
- package/dist/inference/http-download.test.js +0 -109
- package/dist/inference/llama-engine-checksum.test.d.ts +0 -1
- package/dist/inference/llama-engine-checksum.test.js +0 -27
- package/dist/inference/llama-engine.test.d.ts +0 -1
- package/dist/inference/llama-engine.test.js +0 -51
- package/dist/inference/llama-process.test.d.ts +0 -1
- package/dist/inference/llama-process.test.js +0 -61
- package/dist/inference/local-model.test.d.ts +0 -1
- package/dist/inference/local-model.test.js +0 -23
- package/dist/inference/model-download.test.d.ts +0 -1
- package/dist/inference/model-download.test.js +0 -125
- package/dist/inference/model-manager.test.d.ts +0 -1
- package/dist/inference/model-manager.test.js +0 -24
- package/dist/inference/types.test.d.ts +0 -1
- package/dist/inference/types.test.js +0 -19
- package/dist/memory/recall.test.d.ts +0 -1
- package/dist/memory/recall.test.js +0 -36
- package/dist/pattern-index/indexer.test.d.ts +0 -6
- package/dist/pattern-index/indexer.test.js +0 -197
- package/dist/pattern-index/matcher.test.d.ts +0 -6
- package/dist/pattern-index/matcher.test.js +0 -238
- package/dist/pattern-index/pattern-reuse.test.d.ts +0 -1
- package/dist/pattern-index/pattern-reuse.test.js +0 -76
- package/dist/pattern-index/semantic-runtime.test.d.ts +0 -1
- package/dist/pattern-index/semantic-runtime.test.js +0 -31
- package/dist/pattern-index/staleness.test.d.ts +0 -6
- package/dist/pattern-index/staleness.test.js +0 -211
- package/dist/review/agent-fixes.test.d.ts +0 -1
- package/dist/review/agent-fixes.test.js +0 -32
- package/dist/review/backtest-init.test.d.ts +0 -1
- package/dist/review/backtest-init.test.js +0 -136
- package/dist/review/backtest-judges.test.d.ts +0 -1
- package/dist/review/backtest-judges.test.js +0 -32
- package/dist/review/backtest-last.test.d.ts +0 -1
- package/dist/review/backtest-last.test.js +0 -109
- package/dist/review/backtest.test.d.ts +0 -1
- package/dist/review/backtest.test.js +0 -183
- package/dist/review/baseline.test.d.ts +0 -1
- package/dist/review/baseline.test.js +0 -22
- package/dist/review/branch-checks.test.d.ts +0 -1
- package/dist/review/branch-checks.test.js +0 -48
- package/dist/review/check-outcomes.test.d.ts +0 -1
- package/dist/review/check-outcomes.test.js +0 -56
- package/dist/review/code-patterns.test.d.ts +0 -1
- package/dist/review/code-patterns.test.js +0 -142
- package/dist/review/dead-code.test.d.ts +0 -1
- package/dist/review/dead-code.test.js +0 -154
- package/dist/review/deep-runs.test.d.ts +0 -1
- package/dist/review/deep-runs.test.js +0 -23
- package/dist/review/effectiveness.test.d.ts +0 -1
- package/dist/review/effectiveness.test.js +0 -42
- package/dist/review/fix-scope.test.d.ts +0 -1
- package/dist/review/fix-scope.test.js +0 -104
- package/dist/review/generated-files.test.d.ts +0 -1
- package/dist/review/generated-files.test.js +0 -25
- package/dist/review/migration-order.test.d.ts +0 -1
- package/dist/review/migration-order.test.js +0 -62
- package/dist/review/quiet.test.d.ts +0 -1
- package/dist/review/quiet.test.js +0 -38
- package/dist/review/receipt.test.d.ts +0 -1
- package/dist/review/receipt.test.js +0 -60
- package/dist/review/review-task.test.d.ts +0 -1
- package/dist/review/review-task.test.js +0 -89
- package/dist/review/review.test.d.ts +0 -1
- package/dist/review/review.test.js +0 -203
- package/dist/review/reviewer/adapters.test.d.ts +0 -1
- package/dist/review/reviewer/adapters.test.js +0 -100
- package/dist/review/reviewer/api-judge.test.d.ts +0 -1
- package/dist/review/reviewer/api-judge.test.js +0 -108
- package/dist/review/reviewer/background.test.d.ts +0 -1
- package/dist/review/reviewer/background.test.js +0 -118
- package/dist/review/reviewer/context.test.d.ts +0 -1
- package/dist/review/reviewer/context.test.js +0 -45
- package/dist/review/reviewer/exec.test.d.ts +0 -1
- package/dist/review/reviewer/exec.test.js +0 -59
- package/dist/review/reviewer/inputs.test.d.ts +0 -1
- package/dist/review/reviewer/inputs.test.js +0 -52
- package/dist/review/reviewer/panel.test.d.ts +0 -1
- package/dist/review/reviewer/panel.test.js +0 -110
- package/dist/review/reviewer/record.test.d.ts +0 -1
- package/dist/review/reviewer/record.test.js +0 -40
- package/dist/review/reviewer/rule-writer.test.d.ts +0 -1
- package/dist/review/reviewer/rule-writer.test.js +0 -52
- package/dist/review/reviewer/settings.test.d.ts +0 -1
- package/dist/review/reviewer/settings.test.js +0 -57
- package/dist/review/reviewer/usage.test.d.ts +0 -1
- package/dist/review/reviewer/usage.test.js +0 -14
- package/dist/review/reviewer.test.d.ts +0 -1
- package/dist/review/reviewer.test.js +0 -792
- package/dist/review/stories.test.d.ts +0 -1
- package/dist/review/stories.test.js +0 -58
- package/dist/review/toolchain.test.d.ts +0 -1
- package/dist/review/toolchain.test.js +0 -108
- package/dist/review/typed/redundancy.test.d.ts +0 -1
- package/dist/review/typed/redundancy.test.js +0 -315
- package/dist/review/typed/schema-nullability.test.d.ts +0 -1
- package/dist/review/typed/schema-nullability.test.js +0 -63
- package/dist/review-learning/human-edits.test.d.ts +0 -1
- package/dist/review-learning/human-edits.test.js +0 -47
- package/dist/review-learning/repo-rules.test.d.ts +0 -1
- package/dist/review-learning/repo-rules.test.js +0 -93
- package/dist/review-learning/review-learning.test.d.ts +0 -1
- package/dist/review-learning/review-learning.test.js +0 -249
- package/dist/safety.test.d.ts +0 -1
- package/dist/safety.test.js +0 -42
- package/dist/semantic/benchmark.test.d.ts +0 -1
- package/dist/semantic/benchmark.test.js +0 -22
- package/dist/semantic/intent/intent.test.d.ts +0 -1
- package/dist/semantic/intent/intent.test.js +0 -46
- package/dist/semantic/learn/learn.test.d.ts +0 -1
- package/dist/semantic/learn/learn.test.js +0 -67
- package/dist/semantic/origins.test.d.ts +0 -1
- package/dist/semantic/origins.test.js +0 -77
- package/dist/semantic/project-facts.test.d.ts +0 -1
- package/dist/semantic/project-facts.test.js +0 -45
- package/dist/semantic/sites/call-sites.test.d.ts +0 -1
- package/dist/semantic/sites/call-sites.test.js +0 -46
- package/dist/services/adaptive-thresholds.test.d.ts +0 -1
- package/dist/services/adaptive-thresholds.test.js +0 -53
- package/dist/services/agent-history.test.d.ts +0 -1
- package/dist/services/agent-history.test.js +0 -69
- package/dist/services/context-scope-summary.test.d.ts +0 -1
- package/dist/services/context-scope-summary.test.js +0 -17
- package/dist/services/context-telemetry-service.test.d.ts +0 -1
- package/dist/services/context-telemetry-service.test.js +0 -182
- package/dist/services/cursor-usage-sync.test.d.ts +0 -1
- package/dist/services/cursor-usage-sync.test.js +0 -173
- package/dist/services/engineering-knowledge-graph.test.d.ts +0 -1
- package/dist/services/engineering-knowledge-graph.test.js +0 -76
- package/dist/services/model-pricing.test.d.ts +0 -1
- package/dist/services/model-pricing.test.js +0 -44
- package/dist/services/observed-savings.test.d.ts +0 -1
- package/dist/services/observed-savings.test.js +0 -37
- package/dist/services/score-history.test.d.ts +0 -1
- package/dist/services/score-history.test.js +0 -61
- package/dist/smoke.test.d.ts +0 -1
- package/dist/smoke.test.js +0 -17
- package/dist/storage/cache-cleanup.test.d.ts +0 -1
- package/dist/storage/cache-cleanup.test.js +0 -54
- package/dist/storage/context-telemetry.test.d.ts +0 -1
- package/dist/storage/context-telemetry.test.js +0 -80
- package/dist/storage/db.test.d.ts +0 -1
- package/dist/storage/db.test.js +0 -46
- package/dist/storage/fix-lessons.test.d.ts +0 -1
- package/dist/storage/fix-lessons.test.js +0 -61
- package/dist/storage/lessons.test.d.ts +0 -1
- package/dist/storage/lessons.test.js +0 -81
- package/dist/storage/local-encryption.test.d.ts +0 -1
- package/dist/storage/local-encryption.test.js +0 -34
- package/dist/storage/local-memory.test.d.ts +0 -1
- package/dist/storage/local-memory.test.js +0 -55
- package/dist/storage/share-memory.test.d.ts +0 -1
- package/dist/storage/share-memory.test.js +0 -34
- package/dist/storage/team-diagnostics.test.d.ts +0 -1
- package/dist/storage/team-diagnostics.test.js +0 -51
- package/dist/storage/team-scope.test.d.ts +0 -1
- package/dist/storage/team-scope.test.js +0 -22
- package/dist/storage/team-store.test.d.ts +0 -1
- package/dist/storage/team-store.test.js +0 -11
- package/dist/storage/team-sync-scope.test.d.ts +0 -1
- package/dist/storage/team-sync-scope.test.js +0 -100
- package/dist/storage/team-vector-store.test.d.ts +0 -1
- package/dist/storage/team-vector-store.test.js +0 -56
- package/dist/storage/telemetry-scope.test.d.ts +0 -1
- package/dist/storage/telemetry-scope.test.js +0 -38
- package/dist/task/thread.test.d.ts +0 -1
- package/dist/task/thread.test.js +0 -133
- package/dist/telemetry/telemetry.test.d.ts +0 -1
- package/dist/telemetry/telemetry.test.js +0 -64
- package/dist/types/index.test.d.ts +0 -1
- package/dist/types/index.test.js +0 -33
- package/dist/utils/command-line.test.d.ts +0 -1
- package/dist/utils/command-line.test.js +0 -8
- package/dist/utils/diff-removed.test.d.ts +0 -1
- package/dist/utils/diff-removed.test.js +0 -29
- package/dist/utils/diff.test.d.ts +0 -1
- package/dist/utils/diff.test.js +0 -38
- package/dist/utils/glob-paths.test.d.ts +0 -1
- package/dist/utils/glob-paths.test.js +0 -40
- package/dist/utils/profile.test.d.ts +0 -1
- package/dist/utils/profile.test.js +0 -68
- package/dist/utils/scanner.test.d.ts +0 -1
- package/dist/utils/scanner.test.js +0 -48
- package/dist/utils/scope.test.d.ts +0 -1
- package/dist/utils/scope.test.js +0 -38
|
@@ -1,318 +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 { DeprecatedApisGate } from './deprecated-apis.js';
|
|
18
|
-
describe('DeprecatedApisGate — Node.js Security', () => {
|
|
19
|
-
let gate;
|
|
20
|
-
beforeEach(() => {
|
|
21
|
-
gate = new DeprecatedApisGate();
|
|
22
|
-
vi.clearAllMocks();
|
|
23
|
-
});
|
|
24
|
-
it('should flag new Buffer() as security-critical', async () => {
|
|
25
|
-
mockFindFiles.mockResolvedValue(['src/handler.js']);
|
|
26
|
-
mockReadFile.mockResolvedValue(`
|
|
27
|
-
const buf = new Buffer(100);
|
|
28
|
-
const buf2 = new Buffer('hello');
|
|
29
|
-
`);
|
|
30
|
-
const failures = await gate.run({ cwd: '/project' });
|
|
31
|
-
expect(failures.length).toBeGreaterThanOrEqual(1);
|
|
32
|
-
const secFail = failures.find(f => f.title === 'Security-Deprecated APIs');
|
|
33
|
-
expect(secFail).toBeDefined();
|
|
34
|
-
expect(secFail.severity).toBe('critical');
|
|
35
|
-
expect(secFail.details).toContain('Buffer');
|
|
36
|
-
});
|
|
37
|
-
it('should flag crypto.createCipher as security-critical', async () => {
|
|
38
|
-
mockFindFiles.mockResolvedValue(['src/encrypt.ts']);
|
|
39
|
-
mockReadFile.mockResolvedValue(`
|
|
40
|
-
import crypto from 'crypto';
|
|
41
|
-
const cipher = crypto.createCipher('aes-256-cbc', 'password');
|
|
42
|
-
`);
|
|
43
|
-
const failures = await gate.run({ cwd: '/project' });
|
|
44
|
-
expect(failures.length).toBeGreaterThanOrEqual(1);
|
|
45
|
-
expect(failures[0].details).toContain('createCipher');
|
|
46
|
-
});
|
|
47
|
-
it('should flag document.write() as security risk', async () => {
|
|
48
|
-
mockFindFiles.mockResolvedValue(['src/page.tsx']);
|
|
49
|
-
mockReadFile.mockResolvedValue(`
|
|
50
|
-
document.write('<script>alert("xss")</script>');
|
|
51
|
-
`);
|
|
52
|
-
const failures = await gate.run({ cwd: '/project' });
|
|
53
|
-
expect(failures.length).toBeGreaterThanOrEqual(1);
|
|
54
|
-
expect(failures[0].details).toContain('document.write');
|
|
55
|
-
});
|
|
56
|
-
it('should flag eval() as security risk', async () => {
|
|
57
|
-
mockFindFiles.mockResolvedValue(['src/dynamic.js']);
|
|
58
|
-
mockReadFile.mockResolvedValue(`
|
|
59
|
-
const result = eval(userInput);
|
|
60
|
-
`);
|
|
61
|
-
const failures = await gate.run({ cwd: '/project' });
|
|
62
|
-
expect(failures.length).toBeGreaterThanOrEqual(1);
|
|
63
|
-
expect(failures[0].details).toContain('eval');
|
|
64
|
-
});
|
|
65
|
-
});
|
|
66
|
-
describe('DeprecatedApisGate — Node.js Superseded', () => {
|
|
67
|
-
let gate;
|
|
68
|
-
beforeEach(() => {
|
|
69
|
-
gate = new DeprecatedApisGate();
|
|
70
|
-
vi.clearAllMocks();
|
|
71
|
-
});
|
|
72
|
-
it('should flag url.parse() as superseded', async () => {
|
|
73
|
-
mockFindFiles.mockResolvedValue(['src/router.ts']);
|
|
74
|
-
mockReadFile.mockResolvedValue(`
|
|
75
|
-
import url from 'url';
|
|
76
|
-
const parsed = url.parse(req.url);
|
|
77
|
-
`);
|
|
78
|
-
const failures = await gate.run({ cwd: '/project' });
|
|
79
|
-
expect(failures.length).toBeGreaterThanOrEqual(1);
|
|
80
|
-
expect(failures[0].details).toContain('url.parse');
|
|
81
|
-
});
|
|
82
|
-
it('should flag fs.exists() as superseded', async () => {
|
|
83
|
-
mockFindFiles.mockResolvedValue(['src/checker.ts']);
|
|
84
|
-
mockReadFile.mockResolvedValue(`
|
|
85
|
-
const fs = require('fs');
|
|
86
|
-
fs.exists('/tmp/test', (exists) => {});
|
|
87
|
-
`);
|
|
88
|
-
const failures = await gate.run({ cwd: '/project' });
|
|
89
|
-
expect(failures.length).toBeGreaterThanOrEqual(1);
|
|
90
|
-
expect(failures[0].details).toContain('fs.exists');
|
|
91
|
-
});
|
|
92
|
-
it('should flag require("domain") as removed', async () => {
|
|
93
|
-
mockFindFiles.mockResolvedValue(['src/app.js']);
|
|
94
|
-
mockReadFile.mockResolvedValue(`
|
|
95
|
-
const domain = require('domain');
|
|
96
|
-
`);
|
|
97
|
-
const failures = await gate.run({ cwd: '/project' });
|
|
98
|
-
expect(failures.length).toBeGreaterThanOrEqual(1);
|
|
99
|
-
expect(failures[0].details).toContain('domain');
|
|
100
|
-
});
|
|
101
|
-
});
|
|
102
|
-
describe('DeprecatedApisGate — Python', () => {
|
|
103
|
-
let gate;
|
|
104
|
-
beforeEach(() => {
|
|
105
|
-
gate = new DeprecatedApisGate();
|
|
106
|
-
vi.clearAllMocks();
|
|
107
|
-
});
|
|
108
|
-
it('should flag pickle.loads() as security risk', async () => {
|
|
109
|
-
mockFindFiles.mockResolvedValue(['handler.py']);
|
|
110
|
-
mockReadFile.mockResolvedValue(`
|
|
111
|
-
import pickle
|
|
112
|
-
data = pickle.loads(untrusted_input)
|
|
113
|
-
`);
|
|
114
|
-
const failures = await gate.run({ cwd: '/project' });
|
|
115
|
-
expect(failures.length).toBeGreaterThanOrEqual(1);
|
|
116
|
-
expect(failures[0].details).toContain('pickle');
|
|
117
|
-
});
|
|
118
|
-
it('should flag os.system() as security risk', async () => {
|
|
119
|
-
mockFindFiles.mockResolvedValue(['runner.py']);
|
|
120
|
-
mockReadFile.mockResolvedValue(`
|
|
121
|
-
import os
|
|
122
|
-
os.system(user_command)
|
|
123
|
-
`);
|
|
124
|
-
const failures = await gate.run({ cwd: '/project' });
|
|
125
|
-
expect(failures.length).toBeGreaterThanOrEqual(1);
|
|
126
|
-
expect(failures[0].details).toContain('os.system');
|
|
127
|
-
});
|
|
128
|
-
it('should flag subprocess with shell=True', async () => {
|
|
129
|
-
mockFindFiles.mockResolvedValue(['runner.py']);
|
|
130
|
-
mockReadFile.mockResolvedValue(`
|
|
131
|
-
import subprocess
|
|
132
|
-
subprocess.run(cmd, shell=True)
|
|
133
|
-
`);
|
|
134
|
-
const failures = await gate.run({ cwd: '/project' });
|
|
135
|
-
expect(failures.length).toBeGreaterThanOrEqual(1);
|
|
136
|
-
expect(failures[0].details).toContain('shell=True');
|
|
137
|
-
});
|
|
138
|
-
it('should flag import imp as removed', async () => {
|
|
139
|
-
mockFindFiles.mockResolvedValue(['loader.py']);
|
|
140
|
-
mockReadFile.mockResolvedValue(`
|
|
141
|
-
import imp
|
|
142
|
-
module = imp.load_source('name', 'path')
|
|
143
|
-
`);
|
|
144
|
-
const failures = await gate.run({ cwd: '/project' });
|
|
145
|
-
expect(failures.length).toBeGreaterThanOrEqual(1);
|
|
146
|
-
expect(failures[0].details).toContain('imp');
|
|
147
|
-
});
|
|
148
|
-
it('should flag from distutils as removed', async () => {
|
|
149
|
-
mockFindFiles.mockResolvedValue(['setup.py']);
|
|
150
|
-
mockReadFile.mockResolvedValue(`
|
|
151
|
-
from distutils.core import setup
|
|
152
|
-
`);
|
|
153
|
-
const failures = await gate.run({ cwd: '/project' });
|
|
154
|
-
expect(failures.length).toBeGreaterThanOrEqual(1);
|
|
155
|
-
expect(failures[0].details).toContain('distutils');
|
|
156
|
-
});
|
|
157
|
-
it('should flag typing.Dict as superseded', async () => {
|
|
158
|
-
mockFindFiles.mockResolvedValue(['models.py']);
|
|
159
|
-
mockReadFile.mockResolvedValue(`
|
|
160
|
-
from typing import Dict, List, Optional
|
|
161
|
-
`);
|
|
162
|
-
const failures = await gate.run({ cwd: '/project' });
|
|
163
|
-
expect(failures.length).toBeGreaterThanOrEqual(1);
|
|
164
|
-
});
|
|
165
|
-
it('should not flag when disabled', async () => {
|
|
166
|
-
const disabled = new DeprecatedApisGate({ enabled: false });
|
|
167
|
-
const failures = await disabled.run({ cwd: '/project' });
|
|
168
|
-
expect(failures).toHaveLength(0);
|
|
169
|
-
});
|
|
170
|
-
});
|
|
171
|
-
describe('DeprecatedApisGate — Go', () => {
|
|
172
|
-
let gate;
|
|
173
|
-
beforeEach(() => {
|
|
174
|
-
gate = new DeprecatedApisGate();
|
|
175
|
-
vi.clearAllMocks();
|
|
176
|
-
});
|
|
177
|
-
it('should flag ioutil usage as deprecated', async () => {
|
|
178
|
-
mockFindFiles.mockResolvedValue(['main.go']);
|
|
179
|
-
mockReadFile.mockResolvedValue(`
|
|
180
|
-
package main
|
|
181
|
-
import "io/ioutil"
|
|
182
|
-
func main() {
|
|
183
|
-
data, _ := ioutil.ReadFile("test.txt")
|
|
184
|
-
ioutil.WriteFile("out.txt", data, 0644)
|
|
185
|
-
}
|
|
186
|
-
`);
|
|
187
|
-
const failures = await gate.run({ cwd: '/project' });
|
|
188
|
-
expect(failures.length).toBeGreaterThanOrEqual(1);
|
|
189
|
-
expect(failures[0].details).toContain('ioutil');
|
|
190
|
-
});
|
|
191
|
-
it('should flag strings.Title as deprecated', async () => {
|
|
192
|
-
mockFindFiles.mockResolvedValue(['util.go']);
|
|
193
|
-
mockReadFile.mockResolvedValue(`
|
|
194
|
-
package util
|
|
195
|
-
import "strings"
|
|
196
|
-
func Title(s string) string {
|
|
197
|
-
return strings.Title(s)
|
|
198
|
-
}
|
|
199
|
-
`);
|
|
200
|
-
const failures = await gate.run({ cwd: '/project' });
|
|
201
|
-
expect(failures.length).toBeGreaterThanOrEqual(1);
|
|
202
|
-
expect(failures[0].details).toContain('strings.Title');
|
|
203
|
-
});
|
|
204
|
-
});
|
|
205
|
-
describe('DeprecatedApisGate — C#', () => {
|
|
206
|
-
let gate;
|
|
207
|
-
beforeEach(() => {
|
|
208
|
-
gate = new DeprecatedApisGate();
|
|
209
|
-
vi.clearAllMocks();
|
|
210
|
-
});
|
|
211
|
-
it('should flag BinaryFormatter as security-deprecated', async () => {
|
|
212
|
-
mockFindFiles.mockResolvedValue(['Serializer.cs']);
|
|
213
|
-
mockReadFile.mockResolvedValue(`
|
|
214
|
-
using System.Runtime.Serialization.Formatters.Binary;
|
|
215
|
-
var formatter = new BinaryFormatter();
|
|
216
|
-
`);
|
|
217
|
-
const failures = await gate.run({ cwd: '/project' });
|
|
218
|
-
expect(failures.length).toBeGreaterThanOrEqual(1);
|
|
219
|
-
expect(failures[0].details).toContain('BinaryFormatter');
|
|
220
|
-
});
|
|
221
|
-
it('should flag WebClient as deprecated', async () => {
|
|
222
|
-
mockFindFiles.mockResolvedValue(['HttpHelper.cs']);
|
|
223
|
-
mockReadFile.mockResolvedValue(`
|
|
224
|
-
using System.Net;
|
|
225
|
-
var client = new WebClient();
|
|
226
|
-
`);
|
|
227
|
-
const failures = await gate.run({ cwd: '/project' });
|
|
228
|
-
expect(failures.length).toBeGreaterThanOrEqual(1);
|
|
229
|
-
expect(failures[0].details).toContain('WebClient');
|
|
230
|
-
});
|
|
231
|
-
it('should flag Thread.Abort as removed', async () => {
|
|
232
|
-
mockFindFiles.mockResolvedValue(['Worker.cs']);
|
|
233
|
-
mockReadFile.mockResolvedValue(`
|
|
234
|
-
using System.Threading;
|
|
235
|
-
Thread.Abort();
|
|
236
|
-
`);
|
|
237
|
-
const failures = await gate.run({ cwd: '/project' });
|
|
238
|
-
expect(failures.length).toBeGreaterThanOrEqual(1);
|
|
239
|
-
});
|
|
240
|
-
});
|
|
241
|
-
describe('DeprecatedApisGate — Java', () => {
|
|
242
|
-
let gate;
|
|
243
|
-
beforeEach(() => {
|
|
244
|
-
gate = new DeprecatedApisGate();
|
|
245
|
-
vi.clearAllMocks();
|
|
246
|
-
});
|
|
247
|
-
it('should flag Vector and Hashtable as deprecated', async () => {
|
|
248
|
-
mockFindFiles.mockResolvedValue(['Legacy.java']);
|
|
249
|
-
mockReadFile.mockResolvedValue(`
|
|
250
|
-
import java.util.*;
|
|
251
|
-
Vector<String> v = new Vector<String>();
|
|
252
|
-
Hashtable<String, Integer> ht = new Hashtable<String, Integer>();
|
|
253
|
-
`);
|
|
254
|
-
const failures = await gate.run({ cwd: '/project' });
|
|
255
|
-
expect(failures.length).toBeGreaterThanOrEqual(1);
|
|
256
|
-
});
|
|
257
|
-
it('should flag new Integer() as deprecated', async () => {
|
|
258
|
-
mockFindFiles.mockResolvedValue(['Boxing.java']);
|
|
259
|
-
mockReadFile.mockResolvedValue(`
|
|
260
|
-
Integer x = new Integer(42);
|
|
261
|
-
Long y = new Long(100L);
|
|
262
|
-
`);
|
|
263
|
-
const failures = await gate.run({ cwd: '/project' });
|
|
264
|
-
expect(failures.length).toBeGreaterThanOrEqual(1);
|
|
265
|
-
expect(failures[0].details).toMatch(/Integer|Long/);
|
|
266
|
-
});
|
|
267
|
-
it('should flag Thread.stop as security-deprecated', async () => {
|
|
268
|
-
mockFindFiles.mockResolvedValue(['ThreadManager.java']);
|
|
269
|
-
mockReadFile.mockResolvedValue(`
|
|
270
|
-
thread.stop();
|
|
271
|
-
`);
|
|
272
|
-
const failures = await gate.run({ cwd: '/project' });
|
|
273
|
-
expect(failures.length).toBeGreaterThanOrEqual(1);
|
|
274
|
-
});
|
|
275
|
-
it('should flag finalize() as deprecated', async () => {
|
|
276
|
-
mockFindFiles.mockResolvedValue(['Resource.java']);
|
|
277
|
-
mockReadFile.mockResolvedValue(`
|
|
278
|
-
class Resource {
|
|
279
|
-
protected void finalize() throws Throwable {
|
|
280
|
-
super.finalize();
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
`);
|
|
284
|
-
const failures = await gate.run({ cwd: '/project' });
|
|
285
|
-
expect(failures.length).toBeGreaterThanOrEqual(1);
|
|
286
|
-
expect(failures[0].details).toContain('finalize');
|
|
287
|
-
});
|
|
288
|
-
});
|
|
289
|
-
describe('DeprecatedApisGate — word fragments and non-code text', () => {
|
|
290
|
-
let gate;
|
|
291
|
-
beforeEach(() => {
|
|
292
|
-
gate = new DeprecatedApisGate();
|
|
293
|
-
vi.clearAllMocks();
|
|
294
|
-
});
|
|
295
|
-
async function apisFor(file, source) {
|
|
296
|
-
mockFindFiles.mockResolvedValue([file]);
|
|
297
|
-
mockReadFile.mockResolvedValue(source);
|
|
298
|
-
const failures = await gate.run({ cwd: '/project' });
|
|
299
|
-
return failures.map(f => f.details).join('\n');
|
|
300
|
-
}
|
|
301
|
-
it('does not flag ArrayBuffer or SharedArrayBuffer as the Buffer() constructor', async () => {
|
|
302
|
-
const details = await apisFor('src/lib/ingestion-proxy.ts', 'const empty = new ArrayBuffer(0);\nconst shared = new SharedArrayBuffer(8);\n');
|
|
303
|
-
expect(details).not.toContain('Buffer() constructor');
|
|
304
|
-
});
|
|
305
|
-
it('still flags a bare Buffer() constructor call', async () => {
|
|
306
|
-
expect(await apisFor('src/handler.js', "const b = Buffer(10);\n")).toContain('Buffer() constructor');
|
|
307
|
-
});
|
|
308
|
-
it('does not flag "with (" inside a trailing comment or a string', async () => {
|
|
309
|
-
const details = await apisFor('src/lib/aliases.ts', [
|
|
310
|
-
"const pattern = compile(source); // match with (optional) prefix",
|
|
311
|
-
"const label = 'works with (legacy) clients';",
|
|
312
|
-
].join('\n'));
|
|
313
|
-
expect(details).not.toContain('with statement');
|
|
314
|
-
});
|
|
315
|
-
it('still flags a real with statement', async () => {
|
|
316
|
-
expect(await apisFor('src/legacy.js', 'with (obj) {\n x = 1;\n}\n')).toContain('with statement');
|
|
317
|
-
});
|
|
318
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import os from 'os';
|
|
3
|
-
import path from 'path';
|
|
4
|
-
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
5
|
-
import { DeprecatedDependenciesGate, installedVersions, lineOfDependency } from './deprecated-dependencies.js';
|
|
6
|
-
let cwd;
|
|
7
|
-
beforeEach(() => {
|
|
8
|
-
cwd = fs.mkdtempSync(path.join(os.tmpdir(), 'deprecated-deps-'));
|
|
9
|
-
fs.writeFileSync(path.join(cwd, 'package.json'), JSON.stringify({ dependencies: { request: '^2.88.0', 'left-pad': '^1.3.0' }, devDependencies: { '@scope/tool': '1.0.0' } }, null, 2));
|
|
10
|
-
fs.writeFileSync(path.join(cwd, 'package-lock.json'), JSON.stringify({ packages: {
|
|
11
|
-
'node_modules/request': { version: '2.88.2' },
|
|
12
|
-
'node_modules/@scope/tool': { version: '1.0.0' },
|
|
13
|
-
} }));
|
|
14
|
-
});
|
|
15
|
-
afterEach(() => fs.rmSync(cwd, { recursive: true, force: true }));
|
|
16
|
-
/** A registry answering per exact version, like registry.npmjs.org/<name>/<version>. */
|
|
17
|
-
const registry = (deprecated) => vi.fn(async (url) => {
|
|
18
|
-
const [, name, version] = /registry\.test\/(.+)\/([^/]+)$/.exec(url);
|
|
19
|
-
return { ok: true, json: async () => ({ version, deprecated: deprecated[`${decodeURIComponent(name)}@${version}`] }) };
|
|
20
|
-
});
|
|
21
|
-
describe('DeprecatedDependenciesGate', () => {
|
|
22
|
-
it('reports the installed version npm deprecated, on its package.json line', async () => {
|
|
23
|
-
const fetch = registry({ 'request@2.88.2': 'request has been deprecated' });
|
|
24
|
-
const failures = await new DeprecatedDependenciesGate({ enabled: true, registry: 'https://registry.test' }, fetch).run({ cwd });
|
|
25
|
-
expect(failures).toEqual([expect.objectContaining({ id: 'deprecated-dependencies', files: ['package.json'], line: 3 })]);
|
|
26
|
-
expect(failures[0].details).toContain('request@2.88.2 is deprecated on npm: request has been deprecated');
|
|
27
|
-
expect(fetch.mock.calls.map(c => c[0])).toEqual(['https://registry.test/request/2.88.2', 'https://registry.test/@scope%2Ftool/1.0.0']);
|
|
28
|
-
});
|
|
29
|
-
it('asks once a day, and says nothing for a version it cannot determine or a registry that does not answer', async () => {
|
|
30
|
-
const fetch = registry({ 'request@2.88.2': 'deprecated' });
|
|
31
|
-
const gate = new DeprecatedDependenciesGate({ enabled: true, registry: 'https://registry.test' }, fetch);
|
|
32
|
-
await gate.run({ cwd });
|
|
33
|
-
await gate.run({ cwd });
|
|
34
|
-
expect(fetch).toHaveBeenCalledTimes(2); // left-pad has no installed version; the second run is cached
|
|
35
|
-
fs.rmSync(path.join(cwd, '.rigour'), { recursive: true });
|
|
36
|
-
const down = vi.fn(async () => { throw new Error('offline'); });
|
|
37
|
-
expect(await new DeprecatedDependenciesGate({ enabled: true }, down).run({ cwd })).toEqual([]);
|
|
38
|
-
});
|
|
39
|
-
it('is off unless enabled', async () => {
|
|
40
|
-
const fetch = registry({});
|
|
41
|
-
expect(await new DeprecatedDependenciesGate({}, fetch).run({ cwd })).toEqual([]);
|
|
42
|
-
expect(fetch).not.toHaveBeenCalled();
|
|
43
|
-
});
|
|
44
|
-
});
|
|
45
|
-
describe('helpers', () => {
|
|
46
|
-
it('reads installed versions from the lockfile, else node_modules', async () => {
|
|
47
|
-
fs.mkdirSync(path.join(cwd, 'node_modules', 'left-pad'), { recursive: true });
|
|
48
|
-
fs.writeFileSync(path.join(cwd, 'node_modules', 'left-pad', 'package.json'), JSON.stringify({ version: '1.3.0' }));
|
|
49
|
-
expect([...(await installedVersions(cwd, ['request', 'left-pad', 'missing']))]).toEqual([['request', '2.88.2'], ['left-pad', '1.3.0']]);
|
|
50
|
-
});
|
|
51
|
-
it('finds the line declaring a dependency', () => {
|
|
52
|
-
expect(lineOfDependency('{\n "dependencies": {\n "request": "^2"\n }\n}', 'request')).toBe(3);
|
|
53
|
-
expect(lineOfDependency('{}', 'request')).toBeUndefined();
|
|
54
|
-
});
|
|
55
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
-
import { FrontendSecretExposureGate } from './frontend-secret-exposure.js';
|
|
3
|
-
import * as fs from 'fs';
|
|
4
|
-
import * as path from 'path';
|
|
5
|
-
import * as os from 'os';
|
|
6
|
-
describe('FrontendSecretExposureGate', () => {
|
|
7
|
-
let testDir;
|
|
8
|
-
beforeEach(() => {
|
|
9
|
-
testDir = fs.mkdtempSync(path.join(os.tmpdir(), 'frontend-secret-test-'));
|
|
10
|
-
});
|
|
11
|
-
afterEach(() => {
|
|
12
|
-
fs.rmSync(testDir, { recursive: true, force: true });
|
|
13
|
-
});
|
|
14
|
-
it('detects process.env secret usage in client-bundled file', async () => {
|
|
15
|
-
const filePath = path.join(testDir, 'src/components/Checkout.tsx');
|
|
16
|
-
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
17
|
-
fs.writeFileSync(filePath, `
|
|
18
|
-
export function Checkout() {
|
|
19
|
-
const key = process.env.STRIPE_SECRET_KEY;
|
|
20
|
-
return <div>{key}</div>;
|
|
21
|
-
}
|
|
22
|
-
`);
|
|
23
|
-
const gate = new FrontendSecretExposureGate();
|
|
24
|
-
const failures = await gate.run({ cwd: testDir });
|
|
25
|
-
expect(failures.length).toBeGreaterThan(0);
|
|
26
|
-
expect(failures[0].id).toBe('frontend-secret-exposure');
|
|
27
|
-
expect(failures[0].files).toContain('src/components/Checkout.tsx');
|
|
28
|
-
});
|
|
29
|
-
it('detects import.meta.env secret usage in frontend app path', async () => {
|
|
30
|
-
const filePath = path.join(testDir, 'src/app/page.tsx');
|
|
31
|
-
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
32
|
-
fs.writeFileSync(filePath, `
|
|
33
|
-
export default function Page() {
|
|
34
|
-
return <span>{import.meta.env.OPENAI_API_KEY}</span>;
|
|
35
|
-
}
|
|
36
|
-
`);
|
|
37
|
-
const gate = new FrontendSecretExposureGate();
|
|
38
|
-
const failures = await gate.run({ cwd: testDir });
|
|
39
|
-
expect(failures.length).toBeGreaterThan(0);
|
|
40
|
-
});
|
|
41
|
-
it('treats a file outside frontend paths that imports Node built-ins as server code', async () => {
|
|
42
|
-
const cli = path.join(testDir, 'packages/cli/src/commands/post.ts');
|
|
43
|
-
const spawner = path.join(testDir, 'packages/core/src/exec.ts');
|
|
44
|
-
const shared = path.join(testDir, 'packages/shared/src/config.ts');
|
|
45
|
-
const component = path.join(testDir, 'src/components/Admin.tsx');
|
|
46
|
-
for (const file of [cli, spawner, shared, component])
|
|
47
|
-
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
48
|
-
fs.writeFileSync(cli, "import { execFileSync } from 'child_process';\nexport const token = process.env.GITHUB_TOKEN;\n");
|
|
49
|
-
fs.writeFileSync(spawner, "import { execa } from 'execa';\nexport const env = { GH_TOKEN: process.env.GH_TOKEN };\n");
|
|
50
|
-
fs.writeFileSync(shared, 'export const token = process.env.GITHUB_TOKEN;\n');
|
|
51
|
-
fs.writeFileSync(component, "import fs from 'node:fs';\nexport const key = process.env.STRIPE_SECRET_KEY;\n");
|
|
52
|
-
const files = (await new FrontendSecretExposureGate().run({ cwd: testDir })).flatMap(f => f.files ?? []);
|
|
53
|
-
expect(files).not.toContain('packages/cli/src/commands/post.ts'); // Node-only: never bundled
|
|
54
|
-
expect(files).not.toContain('packages/core/src/exec.ts'); // a package that spawns processes is Node-only too
|
|
55
|
-
expect(files).toContain('packages/shared/src/config.ts'); // could be bundled: still flagged
|
|
56
|
-
expect(files).toContain('src/components/Admin.tsx'); // a frontend path stays frontend
|
|
57
|
-
});
|
|
58
|
-
it('does not flag public env prefixes in client files', async () => {
|
|
59
|
-
const filePath = path.join(testDir, 'components/Header.tsx');
|
|
60
|
-
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
61
|
-
fs.writeFileSync(filePath, `
|
|
62
|
-
export const key = process.env.NEXT_PUBLIC_STRIPE_KEY;
|
|
63
|
-
`);
|
|
64
|
-
const gate = new FrontendSecretExposureGate();
|
|
65
|
-
const failures = await gate.run({ cwd: testDir });
|
|
66
|
-
expect(failures).toHaveLength(0);
|
|
67
|
-
});
|
|
68
|
-
it('does not flag server-only API route', async () => {
|
|
69
|
-
const filePath = path.join(testDir, 'pages/api/charge.ts');
|
|
70
|
-
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
71
|
-
fs.writeFileSync(filePath, `
|
|
72
|
-
export default function handler() {
|
|
73
|
-
return process.env.STRIPE_SECRET_KEY;
|
|
74
|
-
}
|
|
75
|
-
`);
|
|
76
|
-
const gate = new FrontendSecretExposureGate();
|
|
77
|
-
const failures = await gate.run({ cwd: testDir });
|
|
78
|
-
expect(failures).toHaveLength(0);
|
|
79
|
-
});
|
|
80
|
-
it('does not flag .server files', async () => {
|
|
81
|
-
const filePath = path.join(testDir, 'src/lib/payments.server.ts');
|
|
82
|
-
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
83
|
-
fs.writeFileSync(filePath, `
|
|
84
|
-
export const stripeSecret = process.env.STRIPE_SECRET_KEY;
|
|
85
|
-
`);
|
|
86
|
-
const gate = new FrontendSecretExposureGate();
|
|
87
|
-
const failures = await gate.run({ cwd: testDir });
|
|
88
|
-
expect(failures).toHaveLength(0);
|
|
89
|
-
});
|
|
90
|
-
it('does not treat server scripts or test configuration as browser bundles', async () => {
|
|
91
|
-
for (const file of ['scripts/migrate.mjs', 'e2e/session.ts', 'tests/helpers/db.ts', 'playwright.config.ts']) {
|
|
92
|
-
const filePath = path.join(testDir, file);
|
|
93
|
-
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
94
|
-
fs.writeFileSync(filePath, 'export const key = process.env.SESSION_SECRET;');
|
|
95
|
-
}
|
|
96
|
-
const gate = new FrontendSecretExposureGate({ server_path_patterns: ['(^|/)pages/api/'] });
|
|
97
|
-
expect(await gate.run({ cwd: testDir })).toHaveLength(0);
|
|
98
|
-
});
|
|
99
|
-
it('ignores shell files even when a broad project scan passes them in', async () => {
|
|
100
|
-
const shellPath = path.join(testDir, 'scripts/rigour-team.sh');
|
|
101
|
-
fs.mkdirSync(path.dirname(shellPath), { recursive: true });
|
|
102
|
-
fs.writeFileSync(shellPath, 'node -e "process.env.APP_DATABASE_URL"');
|
|
103
|
-
const gate = new FrontendSecretExposureGate();
|
|
104
|
-
expect(await gate.run({ cwd: testDir, patterns: ['**/*'] })).toHaveLength(0);
|
|
105
|
-
});
|
|
106
|
-
it('respects explicit allowlist env names', async () => {
|
|
107
|
-
const filePath = path.join(testDir, 'src/views/App.tsx');
|
|
108
|
-
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
109
|
-
fs.writeFileSync(filePath, `
|
|
110
|
-
export const x = process.env.INTERNAL_TOKEN_FOR_DOCS;
|
|
111
|
-
`);
|
|
112
|
-
const gate = new FrontendSecretExposureGate({
|
|
113
|
-
allowlist_env_names: ['INTERNAL_TOKEN_FOR_DOCS'],
|
|
114
|
-
});
|
|
115
|
-
const failures = await gate.run({ cwd: testDir });
|
|
116
|
-
expect(failures).toHaveLength(0);
|
|
117
|
-
});
|
|
118
|
-
it('skips when disabled', async () => {
|
|
119
|
-
const filePath = path.join(testDir, 'src/components/Client.tsx');
|
|
120
|
-
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
121
|
-
fs.writeFileSync(filePath, `
|
|
122
|
-
export const x = process.env.OPENAI_API_KEY;
|
|
123
|
-
`);
|
|
124
|
-
const gate = new FrontendSecretExposureGate({ enabled: false });
|
|
125
|
-
const failures = await gate.run({ cwd: testDir });
|
|
126
|
-
expect(failures).toHaveLength(0);
|
|
127
|
-
});
|
|
128
|
-
it('treats SvelteKit endpoints and root tool configs as server code', async () => {
|
|
129
|
-
const files = {
|
|
130
|
-
'src/routes/api/sync/+server.ts': 'export const GET = () => fetch(url, { headers: { key: process.env.STRIPE_SECRET_KEY } });\n',
|
|
131
|
-
'drizzle.config.ts': 'export default { dbCredentials: { url: process.env.DATABASE_SECRET_URL } };\n',
|
|
132
|
-
'apps/web/drizzle.config.ts': 'export default { dbCredentials: { url: process.env.DATABASE_SECRET_URL } };\n',
|
|
133
|
-
};
|
|
134
|
-
for (const [rel, body] of Object.entries(files)) {
|
|
135
|
-
fs.mkdirSync(path.dirname(path.join(testDir, rel)), { recursive: true });
|
|
136
|
-
fs.writeFileSync(path.join(testDir, rel), body);
|
|
137
|
-
}
|
|
138
|
-
const failures = await new FrontendSecretExposureGate().run({ cwd: testDir });
|
|
139
|
-
expect(failures).toHaveLength(0);
|
|
140
|
-
});
|
|
141
|
-
it('still flags a secret in a config module inside the client source tree', async () => {
|
|
142
|
-
const filePath = path.join(testDir, 'src/components/site.config.ts');
|
|
143
|
-
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
144
|
-
fs.writeFileSync(filePath, 'export const key = process.env.STRIPE_SECRET_KEY;\n');
|
|
145
|
-
const failures = await new FrontendSecretExposureGate().run({ cwd: testDir });
|
|
146
|
-
expect(failures.length).toBeGreaterThan(0);
|
|
147
|
-
});
|
|
148
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,27 +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 { isNuxtProvided, NuxtRoots } from './framework-modules.js';
|
|
6
|
-
let dir;
|
|
7
|
-
beforeEach(() => {
|
|
8
|
-
dir = fs.mkdtempSync(path.join(os.tmpdir(), 'nuxt-'));
|
|
9
|
-
fs.mkdirSync(path.join(dir, 'docs/server/api'), { recursive: true });
|
|
10
|
-
fs.writeFileSync(path.join(dir, 'docs/package.json'), JSON.stringify({ devDependencies: { nuxt: '^4.0.0' } }));
|
|
11
|
-
fs.writeFileSync(path.join(dir, 'package.json'), JSON.stringify({ dependencies: { vue: '^3.0.0' } }));
|
|
12
|
-
});
|
|
13
|
-
afterEach(() => { fs.rmSync(dir, { recursive: true, force: true }); });
|
|
14
|
-
describe('Nuxt-provided modules', () => {
|
|
15
|
-
it('recognises aliases, virtual modules, the generated .nuxt dir and packages Nuxt supplies', () => {
|
|
16
|
-
for (const [spec, pkg] of [['~~/server/api/ai.post', '~~'], ['~/utils/x', '~'], ['@/components/A.vue', '@'], ['#imports', '#imports'], ['../../.nuxt/ui', '..'], ['h3', 'h3'], ['@vue/shared', '@vue/shared']]) {
|
|
17
|
-
expect(isNuxtProvided(spec, pkg)).toBe(true);
|
|
18
|
-
}
|
|
19
|
-
expect(isNuxtProvided('left-pad', 'left-pad')).toBe(false);
|
|
20
|
-
expect(isNuxtProvided('@scope/pkg', '@scope/pkg')).toBe(false);
|
|
21
|
-
});
|
|
22
|
-
it('applies only inside a project that depends on nuxt', async () => {
|
|
23
|
-
const roots = new NuxtRoots(dir);
|
|
24
|
-
expect(await roots.rootFor('docs/server/api/ai.post.ts')).toBe(path.join(dir, 'docs'));
|
|
25
|
-
expect(await roots.rootFor('src/index.ts')).toBeNull();
|
|
26
|
-
});
|
|
27
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import { typeOnlySpecifiers, typesPackageFor } from './js-resolver.js';
|
|
3
|
-
describe('type-only imports', () => {
|
|
4
|
-
it('finds specifiers imported only for types, and everything in a .d.ts file', () => {
|
|
5
|
-
const ts = "import type { Context } from 'aws-lambda';\nimport { handler } from 'aws-lambda';\nexport type { Ev } from 'events-lib';\n";
|
|
6
|
-
expect([...typeOnlySpecifiers(ts, 'src/a.ts')]).toEqual(['aws-lambda', 'events-lib']);
|
|
7
|
-
const dts = "import type { Writable } from 'node:stream';\nimport { Context } from 'aws-lambda';\ntype X = import('express').Request;\n";
|
|
8
|
-
expect([...typeOnlySpecifiers(dts, 'src/global.d.ts')]).toEqual(['node:stream', 'aws-lambda', 'express']);
|
|
9
|
-
});
|
|
10
|
-
it('names the DefinitelyTyped package, scoped ones included', () => {
|
|
11
|
-
expect(typesPackageFor('aws-lambda')).toBe('@types/aws-lambda');
|
|
12
|
-
expect(typesPackageFor('@babel/core')).toBe('@types/babel__core');
|
|
13
|
-
});
|
|
14
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|