@rigour-labs/core 2.21.0 → 2.21.2
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/gates/runner.js +4 -4
- package/dist/gates/safety.d.ts +1 -1
- package/dist/gates/safety.js +3 -3
- package/dist/gates/security-patterns.js +1 -1
- package/dist/pattern-index/indexer.js +2 -1
- package/dist/safety.test.js +6 -6
- package/dist/templates/index.js +1 -1
- package/dist/types/index.js +1 -1
- package/package.json +1 -1
- package/src/gates/runner.ts +4 -4
- package/src/gates/safety.ts +3 -3
- package/src/gates/security-patterns.ts +1 -1
- package/src/pattern-index/indexer.ts +2 -1
- package/src/safety.test.ts +6 -6
- package/src/templates/index.ts +1 -1
- package/src/types/index.ts +1 -1
package/dist/gates/runner.js
CHANGED
|
@@ -2,7 +2,7 @@ import { FileGate } from './file.js';
|
|
|
2
2
|
import { ContentGate } from './content.js';
|
|
3
3
|
import { StructureGate } from './structure.js';
|
|
4
4
|
import { ASTGate } from './ast.js';
|
|
5
|
-
import {
|
|
5
|
+
import { FileGuardGate } from './safety.js';
|
|
6
6
|
import { DependencyGate } from './dependency.js';
|
|
7
7
|
import { CoverageGate } from './coverage.js';
|
|
8
8
|
import { ContextGate } from './context.js';
|
|
@@ -38,7 +38,7 @@ export class GateRunner {
|
|
|
38
38
|
}
|
|
39
39
|
this.gates.push(new ASTGate(this.config.gates));
|
|
40
40
|
this.gates.push(new DependencyGate(this.config));
|
|
41
|
-
this.gates.push(new
|
|
41
|
+
this.gates.push(new FileGuardGate(this.config.gates));
|
|
42
42
|
this.gates.push(new CoverageGate(this.config.gates));
|
|
43
43
|
if (this.config.gates.context?.enabled) {
|
|
44
44
|
this.gates.push(new ContextGate(this.config.gates));
|
|
@@ -51,8 +51,8 @@ export class GateRunner {
|
|
|
51
51
|
if (this.config.gates.checkpoint?.enabled) {
|
|
52
52
|
this.gates.push(new CheckpointGate(this.config.gates.checkpoint));
|
|
53
53
|
}
|
|
54
|
-
// Security Patterns Gate (code-level vulnerability detection)
|
|
55
|
-
if (this.config.gates.security?.enabled) {
|
|
54
|
+
// Security Patterns Gate (code-level vulnerability detection) — enabled by default since v2.15
|
|
55
|
+
if (this.config.gates.security?.enabled !== false) {
|
|
56
56
|
this.gates.push(new SecurityPatternsGate(this.config.gates.security));
|
|
57
57
|
}
|
|
58
58
|
// Environment Alignment Gate (Should be prioritized)
|
package/dist/gates/safety.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Gate, GateContext } from './base.js';
|
|
2
2
|
import { Failure, Gates } from '../types/index.js';
|
|
3
|
-
export declare class
|
|
3
|
+
export declare class FileGuardGate extends Gate {
|
|
4
4
|
private config;
|
|
5
5
|
constructor(config: Gates);
|
|
6
6
|
run(context: GateContext): Promise<Failure[]>;
|
package/dist/gates/safety.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { Gate } from './base.js';
|
|
2
2
|
import { execa } from 'execa';
|
|
3
|
-
export class
|
|
3
|
+
export class FileGuardGate extends Gate {
|
|
4
4
|
config;
|
|
5
5
|
constructor(config) {
|
|
6
|
-
super('
|
|
6
|
+
super('file-guard', 'File Guard — Protected Paths');
|
|
7
7
|
this.config = config;
|
|
8
8
|
}
|
|
9
9
|
async run(context) {
|
|
@@ -14,7 +14,7 @@ export class SafetyGate extends Gate {
|
|
|
14
14
|
return [];
|
|
15
15
|
try {
|
|
16
16
|
// Check for modified files in protected paths using git
|
|
17
|
-
//
|
|
17
|
+
// File Guard - if an agent touched protected files, we fail.
|
|
18
18
|
const { stdout } = await execa('git', ['status', '--porcelain'], { cwd: context.cwd });
|
|
19
19
|
const modifiedFiles = stdout.split('\n')
|
|
20
20
|
.filter(line => {
|
|
@@ -138,7 +138,7 @@ export class SecurityPatternsGate extends Gate {
|
|
|
138
138
|
constructor(config = {}) {
|
|
139
139
|
super('security-patterns', 'Security Pattern Detection');
|
|
140
140
|
this.config = {
|
|
141
|
-
enabled: config.enabled ??
|
|
141
|
+
enabled: config.enabled ?? true,
|
|
142
142
|
sql_injection: config.sql_injection ?? true,
|
|
143
143
|
xss: config.xss ?? true,
|
|
144
144
|
path_traversal: config.path_traversal ?? true,
|
|
@@ -89,7 +89,8 @@ export class PatternIndexer {
|
|
|
89
89
|
}
|
|
90
90
|
// Generate embeddings in parallel batches if enabled
|
|
91
91
|
if (this.config.useEmbeddings && patterns.length > 0) {
|
|
92
|
-
|
|
92
|
+
// Use stderr to avoid contaminating JSON output on stdout
|
|
93
|
+
process.stderr.write(`Generating embeddings for ${patterns.length} patterns...\n`);
|
|
93
94
|
for (let i = 0; i < patterns.length; i += BATCH_SIZE) {
|
|
94
95
|
const batch = patterns.slice(i, i + BATCH_SIZE);
|
|
95
96
|
await Promise.all(batch.map(async (pattern) => {
|
package/dist/safety.test.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
-
import {
|
|
2
|
+
import { FileGuardGate } from './gates/safety.js';
|
|
3
3
|
import { execa } from 'execa';
|
|
4
4
|
vi.mock('execa');
|
|
5
|
-
describe('
|
|
5
|
+
describe('FileGuardGate', () => {
|
|
6
6
|
const config = {
|
|
7
7
|
safety: {
|
|
8
8
|
protected_paths: ['docs/'],
|
|
@@ -10,27 +10,27 @@ describe('SafetyGate', () => {
|
|
|
10
10
|
}
|
|
11
11
|
};
|
|
12
12
|
it('should flag modified (M) protected files', async () => {
|
|
13
|
-
const gate = new
|
|
13
|
+
const gate = new FileGuardGate(config);
|
|
14
14
|
vi.mocked(execa).mockResolvedValueOnce({ stdout: ' M docs/SPEC.md\n' });
|
|
15
15
|
const failures = await gate.run({ cwd: '/test', record: {} });
|
|
16
16
|
expect(failures).toHaveLength(1);
|
|
17
17
|
expect(failures[0].title).toContain("Protected file 'docs/SPEC.md' was modified.");
|
|
18
18
|
});
|
|
19
19
|
it('should flag added (A) protected files', async () => {
|
|
20
|
-
const gate = new
|
|
20
|
+
const gate = new FileGuardGate(config);
|
|
21
21
|
vi.mocked(execa).mockResolvedValueOnce({ stdout: 'A docs/NEW.md\n' });
|
|
22
22
|
const failures = await gate.run({ cwd: '/test', record: {} });
|
|
23
23
|
expect(failures).toHaveLength(1);
|
|
24
24
|
expect(failures[0].title).toContain("Protected file 'docs/NEW.md' was modified.");
|
|
25
25
|
});
|
|
26
26
|
it('should NOT flag untracked (??) protected files', async () => {
|
|
27
|
-
const gate = new
|
|
27
|
+
const gate = new FileGuardGate(config);
|
|
28
28
|
vi.mocked(execa).mockResolvedValueOnce({ stdout: '?? docs/UNTRAKED.md\n' });
|
|
29
29
|
const failures = await gate.run({ cwd: '/test', record: {} });
|
|
30
30
|
expect(failures).toHaveLength(0);
|
|
31
31
|
});
|
|
32
32
|
it('should correctly handle multiple mixed statuses', async () => {
|
|
33
|
-
const gate = new
|
|
33
|
+
const gate = new FileGuardGate(config);
|
|
34
34
|
vi.mocked(execa).mockResolvedValueOnce({
|
|
35
35
|
stdout: ' M docs/MODIFIED.md\n?? docs/NEW_UNTRACKED.md\n D docs/DELETED.md\n'
|
|
36
36
|
});
|
package/dist/templates/index.js
CHANGED
package/dist/types/index.js
CHANGED
|
@@ -86,7 +86,7 @@ export const GatesSchema = z.object({
|
|
|
86
86
|
auto_save_on_failure: z.boolean().optional().default(true),
|
|
87
87
|
}).optional().default({}),
|
|
88
88
|
security: z.object({
|
|
89
|
-
enabled: z.boolean().optional().default(
|
|
89
|
+
enabled: z.boolean().optional().default(true),
|
|
90
90
|
sql_injection: z.boolean().optional().default(true),
|
|
91
91
|
xss: z.boolean().optional().default(true),
|
|
92
92
|
path_traversal: z.boolean().optional().default(true),
|
package/package.json
CHANGED
package/src/gates/runner.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { FileGate } from './file.js';
|
|
|
4
4
|
import { ContentGate } from './content.js';
|
|
5
5
|
import { StructureGate } from './structure.js';
|
|
6
6
|
import { ASTGate } from './ast.js';
|
|
7
|
-
import {
|
|
7
|
+
import { FileGuardGate } from './safety.js';
|
|
8
8
|
import { DependencyGate } from './dependency.js';
|
|
9
9
|
import { CoverageGate } from './coverage.js';
|
|
10
10
|
import { ContextGate } from './context.js';
|
|
@@ -44,7 +44,7 @@ export class GateRunner {
|
|
|
44
44
|
}
|
|
45
45
|
this.gates.push(new ASTGate(this.config.gates));
|
|
46
46
|
this.gates.push(new DependencyGate(this.config));
|
|
47
|
-
this.gates.push(new
|
|
47
|
+
this.gates.push(new FileGuardGate(this.config.gates));
|
|
48
48
|
this.gates.push(new CoverageGate(this.config.gates));
|
|
49
49
|
|
|
50
50
|
if (this.config.gates.context?.enabled) {
|
|
@@ -61,8 +61,8 @@ export class GateRunner {
|
|
|
61
61
|
this.gates.push(new CheckpointGate(this.config.gates.checkpoint));
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
// Security Patterns Gate (code-level vulnerability detection)
|
|
65
|
-
if (this.config.gates.security?.enabled) {
|
|
64
|
+
// Security Patterns Gate (code-level vulnerability detection) — enabled by default since v2.15
|
|
65
|
+
if (this.config.gates.security?.enabled !== false) {
|
|
66
66
|
this.gates.push(new SecurityPatternsGate(this.config.gates.security));
|
|
67
67
|
}
|
|
68
68
|
|
package/src/gates/safety.ts
CHANGED
|
@@ -2,9 +2,9 @@ import { Gate, GateContext } from './base.js';
|
|
|
2
2
|
import { Failure, Gates } from '../types/index.js';
|
|
3
3
|
import { execa } from 'execa';
|
|
4
4
|
|
|
5
|
-
export class
|
|
5
|
+
export class FileGuardGate extends Gate {
|
|
6
6
|
constructor(private config: Gates) {
|
|
7
|
-
super('
|
|
7
|
+
super('file-guard', 'File Guard — Protected Paths');
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
async run(context: GateContext): Promise<Failure[]> {
|
|
@@ -16,7 +16,7 @@ export class SafetyGate extends Gate {
|
|
|
16
16
|
|
|
17
17
|
try {
|
|
18
18
|
// Check for modified files in protected paths using git
|
|
19
|
-
//
|
|
19
|
+
// File Guard - if an agent touched protected files, we fail.
|
|
20
20
|
const { stdout } = await execa('git', ['status', '--porcelain'], { cwd: context.cwd });
|
|
21
21
|
const modifiedFiles = stdout.split('\n')
|
|
22
22
|
.filter(line => {
|
|
@@ -171,7 +171,7 @@ export class SecurityPatternsGate extends Gate {
|
|
|
171
171
|
constructor(config: SecurityPatternsConfig = {}) {
|
|
172
172
|
super('security-patterns', 'Security Pattern Detection');
|
|
173
173
|
this.config = {
|
|
174
|
-
enabled: config.enabled ??
|
|
174
|
+
enabled: config.enabled ?? true,
|
|
175
175
|
sql_injection: config.sql_injection ?? true,
|
|
176
176
|
xss: config.xss ?? true,
|
|
177
177
|
path_traversal: config.path_traversal ?? true,
|
|
@@ -109,7 +109,8 @@ export class PatternIndexer {
|
|
|
109
109
|
|
|
110
110
|
// Generate embeddings in parallel batches if enabled
|
|
111
111
|
if (this.config.useEmbeddings && patterns.length > 0) {
|
|
112
|
-
|
|
112
|
+
// Use stderr to avoid contaminating JSON output on stdout
|
|
113
|
+
process.stderr.write(`Generating embeddings for ${patterns.length} patterns...\n`);
|
|
113
114
|
for (let i = 0; i < patterns.length; i += BATCH_SIZE) {
|
|
114
115
|
const batch = patterns.slice(i, i + BATCH_SIZE);
|
|
115
116
|
await Promise.all(batch.map(async (pattern) => {
|
package/src/safety.test.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
-
import {
|
|
2
|
+
import { FileGuardGate } from './gates/safety.js';
|
|
3
3
|
import { Gates } from './types/index.js';
|
|
4
4
|
import { execa } from 'execa';
|
|
5
5
|
|
|
6
6
|
vi.mock('execa');
|
|
7
7
|
|
|
8
|
-
describe('
|
|
8
|
+
describe('FileGuardGate', () => {
|
|
9
9
|
const config: Gates = {
|
|
10
10
|
safety: {
|
|
11
11
|
protected_paths: ['docs/'],
|
|
@@ -14,7 +14,7 @@ describe('SafetyGate', () => {
|
|
|
14
14
|
} as any;
|
|
15
15
|
|
|
16
16
|
it('should flag modified (M) protected files', async () => {
|
|
17
|
-
const gate = new
|
|
17
|
+
const gate = new FileGuardGate(config);
|
|
18
18
|
vi.mocked(execa).mockResolvedValueOnce({ stdout: ' M docs/SPEC.md\n' } as any);
|
|
19
19
|
|
|
20
20
|
const failures = await gate.run({ cwd: '/test', record: {} as any });
|
|
@@ -23,7 +23,7 @@ describe('SafetyGate', () => {
|
|
|
23
23
|
});
|
|
24
24
|
|
|
25
25
|
it('should flag added (A) protected files', async () => {
|
|
26
|
-
const gate = new
|
|
26
|
+
const gate = new FileGuardGate(config);
|
|
27
27
|
vi.mocked(execa).mockResolvedValueOnce({ stdout: 'A docs/NEW.md\n' } as any);
|
|
28
28
|
|
|
29
29
|
const failures = await gate.run({ cwd: '/test', record: {} as any });
|
|
@@ -32,7 +32,7 @@ describe('SafetyGate', () => {
|
|
|
32
32
|
});
|
|
33
33
|
|
|
34
34
|
it('should NOT flag untracked (??) protected files', async () => {
|
|
35
|
-
const gate = new
|
|
35
|
+
const gate = new FileGuardGate(config);
|
|
36
36
|
vi.mocked(execa).mockResolvedValueOnce({ stdout: '?? docs/UNTRAKED.md\n' } as any);
|
|
37
37
|
|
|
38
38
|
const failures = await gate.run({ cwd: '/test', record: {} as any });
|
|
@@ -40,7 +40,7 @@ describe('SafetyGate', () => {
|
|
|
40
40
|
});
|
|
41
41
|
|
|
42
42
|
it('should correctly handle multiple mixed statuses', async () => {
|
|
43
|
-
const gate = new
|
|
43
|
+
const gate = new FileGuardGate(config);
|
|
44
44
|
vi.mocked(execa).mockResolvedValueOnce({
|
|
45
45
|
stdout: ' M docs/MODIFIED.md\n?? docs/NEW_UNTRACKED.md\n D docs/DELETED.md\n'
|
|
46
46
|
} as any);
|
package/src/templates/index.ts
CHANGED
package/src/types/index.ts
CHANGED
|
@@ -87,7 +87,7 @@ export const GatesSchema = z.object({
|
|
|
87
87
|
auto_save_on_failure: z.boolean().optional().default(true),
|
|
88
88
|
}).optional().default({}),
|
|
89
89
|
security: z.object({
|
|
90
|
-
enabled: z.boolean().optional().default(
|
|
90
|
+
enabled: z.boolean().optional().default(true),
|
|
91
91
|
sql_injection: z.boolean().optional().default(true),
|
|
92
92
|
xss: z.boolean().optional().default(true),
|
|
93
93
|
path_traversal: z.boolean().optional().default(true),
|