mirror of
https://github.com/affaan-m/ECC.git
synced 2026-10-15 04:35:29 +02:00
Merge late GateGuard filter and security fixture repairs
This commit is contained in:
@@ -377,10 +377,10 @@ function grepToolFilters(glob, type) {
|
||||
const filters = { positives: [], includes: [], exclusions: [], opaque: false };
|
||||
if (typeof type === 'string' && type) {
|
||||
const globs = rgTypeGlobs(type);
|
||||
if (globs) filters.includes.push(...globs);
|
||||
if (globs) filters.typeIncludes = globs;
|
||||
else filters.opaque = true;
|
||||
}
|
||||
if (typeof glob !== 'string' || !glob) return filters;
|
||||
if (typeof glob !== 'string' || !glob) return resolveTypeFilters(filters);
|
||||
for (const part of splitTopLevelCommas(glob)) {
|
||||
if (part.startsWith('!')) filters.exclusions.push(part.slice(1));
|
||||
else {
|
||||
@@ -388,7 +388,18 @@ function grepToolFilters(glob, type) {
|
||||
filters.includes.push(part);
|
||||
}
|
||||
}
|
||||
return filters;
|
||||
return resolveTypeFilters(filters);
|
||||
}
|
||||
|
||||
function resolveTypeFilters({ typeIncludes = [], typeExclusions = [], ...filters }) {
|
||||
// rg's explicit positive globs override type selection, not union with it.
|
||||
// Keep type alternatives separate until every explicit glob is known.
|
||||
const hasIncludes = filters.includes.length > 0;
|
||||
return {
|
||||
...filters,
|
||||
includes: hasIncludes ? filters.includes : typeIncludes,
|
||||
exclusions: filters.exclusions.concat(hasIncludes ? [] : typeExclusions)
|
||||
};
|
||||
}
|
||||
|
||||
function shellSearchFilters(kind, args) {
|
||||
@@ -401,7 +412,7 @@ function shellSearchFilters(kind, args) {
|
||||
const consumed = applyShellFilterArg(kind, args, i, filters);
|
||||
i += consumed;
|
||||
}
|
||||
return filters;
|
||||
return resolveTypeFilters(filters);
|
||||
}
|
||||
|
||||
function applyShellFilterArg(kind, args, i, filters) {
|
||||
@@ -418,8 +429,10 @@ function applyShellFilterArg(kind, args, i, filters) {
|
||||
const type = (name, indexes, excluded) => {
|
||||
const globs = rgTypeGlobs(name);
|
||||
if (!globs) filters.opaque = true;
|
||||
else if (excluded) globs.forEach(glob => exclude(glob, indexes));
|
||||
else globs.forEach(include);
|
||||
else if (excluded) {
|
||||
filters.typeExclusions = (filters.typeExclusions || []).concat(globs);
|
||||
indexes.forEach(index => filters.dropped.add(index));
|
||||
} else filters.typeIncludes = (filters.typeIncludes || []).concat(globs);
|
||||
};
|
||||
const extension = value => include(value ? `*.${String(value).replace(/^\./, '')}` : '');
|
||||
if (kind.startsWith('git ') && GIT_EXCLUDE_PATHSPEC.test(arg)) {
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
'use strict';
|
||||
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs');
|
||||
const os = require('node:os');
|
||||
const path = require('node:path');
|
||||
const { spawnSync } = require('node:child_process');
|
||||
|
||||
if (process.platform === 'win32') {
|
||||
console.log('Skipping non-Windows Python availability control.');
|
||||
} else {
|
||||
const emptyPath = fs.mkdtempSync(path.join(os.tmpdir(), 'ecc-missing-python-'));
|
||||
try {
|
||||
const result = spawnSync(process.execPath, [path.join(__dirname, 'observe-secret-redaction.test.js')], {
|
||||
env: { ...process.env, PATH: emptyPath }, encoding: 'utf8', timeout: 15000
|
||||
});
|
||||
assert.equal(result.status, 1, result.stderr);
|
||||
assert.match(result.stdout, /FAIL python3 is required/);
|
||||
assert.match(result.stdout, /Passed: 0\nFailed: 1/);
|
||||
assert.doesNotMatch(result.stdout, /Skipping shell fixtures/);
|
||||
console.log('PASS missing Python fails the actual non-Windows redaction gate');
|
||||
} finally {
|
||||
fs.rmSync(emptyPath, { recursive: true, force: true });
|
||||
}
|
||||
}
|
||||
@@ -41,7 +41,13 @@ function capture(phase, input) {
|
||||
}
|
||||
|
||||
console.log('=== Actual registered observation secret redaction ===');
|
||||
if (process.platform !== 'win32' && spawnSync('python3', ['--version']).status === 0) {
|
||||
if (process.platform === 'win32') {
|
||||
console.log('Skipping shell fixtures: native Windows runner requires platform CI.');
|
||||
} else if (spawnSync('python3', ['--version']).status !== 0) {
|
||||
console.log(' FAIL python3 is required for observation redaction tests');
|
||||
failed += 1;
|
||||
} else {
|
||||
// Synthetic canary data proves that captured credential-shaped text is masked.
|
||||
for (const [label, content] of [
|
||||
['double-quoted source', 'const apiKey = "CANARY_TOKEN_abcdefghijk";'],
|
||||
['single-quoted source', "const password = 'CANARY_TOKEN_abcdefghijk';"],
|
||||
@@ -61,8 +67,6 @@ if (process.platform !== 'win32' && spawnSync('python3', ['--version']).status =
|
||||
assert.ok(records.includes('[REDACTED]'));
|
||||
});
|
||||
}
|
||||
} else {
|
||||
console.log('Skipping shell fixtures: native Windows runner requires platform CI.');
|
||||
}
|
||||
console.log(`Passed: ${passed}`);
|
||||
console.log(`Failed: ${failed}`);
|
||||
|
||||
@@ -163,8 +163,9 @@ test('quoted staged paths and untracked paths share identity, and untracked fail
|
||||
assert.ok(snapshot.agents.every(agent => agent.files.includes(file)));
|
||||
for (const code of ['EACCES', 'ETIMEDOUT', 'ENOBUFS']) {
|
||||
childProcess.execFileSync = (command, args, options) => {
|
||||
assert.strictEqual(command, 'git', 'fixture only forwards Git probes');
|
||||
if (args.includes('ls-files')) throw Object.assign(new Error('untracked probe unavailable'), { code });
|
||||
return originalExec(command, args, options);
|
||||
return originalExec('git', args, { ...options, shell: false });
|
||||
};
|
||||
delete require.cache[modulePath];
|
||||
const fresh = require(modulePath);
|
||||
@@ -172,8 +173,9 @@ test('quoted staged paths and untracked paths share identity, and untracked fail
|
||||
assert.ok(tracked, `${code}: tracked changes must survive`);
|
||||
assert.deepStrictEqual(tracked.files.map(entry => entry.path).sort(), ['README', file].sort());
|
||||
childProcess.execFileSync = (command, args, options) => {
|
||||
assert.strictEqual(command, 'git', 'fixture only forwards Git probes');
|
||||
if (args.includes('--name-only')) throw Object.assign(new Error('tracked names unavailable'), { code });
|
||||
return originalExec(command, args, options);
|
||||
return originalExec('git', args, { ...options, shell: false });
|
||||
};
|
||||
delete require.cache[modulePath];
|
||||
const partial = require(modulePath).sessionsToAgents([worktrees[0]]);
|
||||
|
||||
@@ -209,6 +209,8 @@ test('a search confined to the target file name is a lookup, not a search', () =
|
||||
['Grep', { pattern: 'tokenizer', glob: '**/tokenizer.js' }],
|
||||
['Bash', { command: 'find src -name tokenizer.js' }],
|
||||
['Bash', { command: 'rg -g tokenizer.js tokenizer src' }],
|
||||
['Bash', { command: 'rg -t js -g tokenizer.js tokenizer src' }],
|
||||
['Grep', { pattern: 'tokenizer', type: 'js', glob: 'tokenizer.js' }],
|
||||
['Bash', { command: 'rg --files -g tokenizer.js src' }],
|
||||
['Bash', { command: 'rg tokenizer src/**/tokenizer.js' }]
|
||||
];
|
||||
|
||||
@@ -105,6 +105,23 @@ test('rg -T/--type-not excludes the type globs', () => {
|
||||
}
|
||||
});
|
||||
|
||||
test('explicit rg globs take precedence over type alternatives in either flag order', () => {
|
||||
for (const args of [['-t', 'js', '-g', '*.py'], ['-g', '*.py', '--type=js']]) {
|
||||
const item = rgItem([...args, 'tokenizer', 'src']);
|
||||
assert.strictEqual(admitted(item, 'src/tokenizer.js'), false, args.join(' '));
|
||||
assert.strictEqual(admitted(item, 'src/tokenizer.py'), true, args.join(' '));
|
||||
}
|
||||
assert.strictEqual(admitted(rgItem(['-t', 'py', '-g', '*.js']), 'src/tokenizer.js'), true);
|
||||
assert.strictEqual(admitted(rgItem(['-T', 'js', '-g', '*.js']), 'src/tokenizer.js'), true);
|
||||
assert.strictEqual(admitted(rgItem(['-t', 'js', '-g', '!*.js']), 'src/tokenizer.js'), false);
|
||||
});
|
||||
|
||||
test('Grep tool explicit globs do not gain an alternative from its type', () => {
|
||||
const item = { ...grepToolFilters('*.py', 'js'), scopes: [['.']], pathIncludes: true };
|
||||
assert.strictEqual(admitted(item, 'src/tokenizer.js'), false);
|
||||
assert.strictEqual(admitted(item, 'src/tokenizer.py'), true);
|
||||
});
|
||||
|
||||
test('unknown or redefined rg types are unreadable filters', () => {
|
||||
for (const args of [['-t', 'nosuchtype'], ['-T', 'nosuchtype'], ['--type-add', 'web:*.js', '-t', 'web'], ['--type-clear', 'js']]) {
|
||||
assert.strictEqual(admitted(rgItem([...args, 'x']), 'src/tokenizer.js'), false, args.join(' '));
|
||||
|
||||
Reference in New Issue
Block a user