Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/gep/sanitize.js
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,15 @@ function detectEnvValueLeaks(content) {
for (const [key, val] of Object.entries(process.env)) {
if (!val || val.length < 8) continue;
if (ENV_SCAN_SKIP_KEYS.has(key)) continue;
// Filesystem paths and URLs are not secrets, and CI tooling exports dozens
// of env vars whose value is the repo checkout path — the runner
// (GITHUB_WORKSPACE, RUNNER_WORKSPACE) and, when tests run via `npm test`,
// npm itself (INIT_CWD, npm_config_local_prefix, npm_package_json, PWD).
// Reverse-flagging them is a false positive whenever capsule content
// legitimately references the build path: it blocks self-PRs and fails only
// under CI. Genuine sensitive paths in content are still caught by the
// local_path pattern scanner, and credentialed URLs by db_url / basic_auth.
if (/^(\/|[A-Za-z]:\\|[a-z][a-z0-9+.-]*:\/\/)/i.test(val)) continue;
if (content.includes(val)) {
leaks.push({ type: 'env_value_leak', envKey: key, value: val.length > 60 ? val.slice(0, 57) + '...' : val, suggestion: 'process.env.' + key });
}
Expand Down
37 changes: 36 additions & 1 deletion test/sanitize.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -302,4 +302,39 @@ const ghLegacyNoreply = scanForLeaks('opened by classicuser@users.noreply.github
assert.strictEqual(ghLegacyNoreply.found, false,
'scanForLeaks must NOT flag legacy GitHub noreply addresses (any local part)');

console.log('All sanitize tests passed (68 assertions)');
// Regression: CI runners + npm populate several env vars with the repo checkout
// path — GITHUB_WORKSPACE / RUNNER_WORKSPACE from the runner, and INIT_CWD /
// npm_config_local_prefix / npm_package_json / PWD from `npm test`. When capsule
// content legitimately references that build path, detectEnvValueLeaks must NOT
// report it as an env-value leak, or every self-PR from CI would be blocked over
// its own build path. This failed only under CI (where these vars are set to
// /home/runner/work/...) until path/URL-shaped env values were skipped.
const RUNNER_PATH = '/home/runner/work/evolver/evolver';
const SECRET_VAL = 'zzz9988aa77bb66cc55dd';
const _ciEnvKeys = ['GITHUB_WORKSPACE', 'INIT_CWD', 'npm_config_local_prefix', 'EVOLVER_TEST_SECRET'];
const _savedCiEnv = {};
for (const k of _ciEnvKeys) _savedCiEnv[k] = process.env[k];
process.env.GITHUB_WORKSPACE = RUNNER_PATH;
process.env.INIT_CWD = RUNNER_PATH;
process.env.npm_config_local_prefix = RUNNER_PATH;
process.env.EVOLVER_TEST_SECRET = SECRET_VAL;
try {
assert.strictEqual(
fullLeakCheck('build trace from /home/runner/work/evolver/evolver/src/foo.js').found,
false,
'CI runner/npm checkout-path env vars must NOT be flagged as env-value leaks'
);
// Security guarantee intact: a non-path secret env value is still reverse-detected.
assert.strictEqual(
fullLeakCheck('config contains ' + SECRET_VAL + ' inline').found,
true,
'non-path secret env value must still be reverse-detected'
);
} finally {
for (const k of _ciEnvKeys) {
if (_savedCiEnv[k] === undefined) delete process.env[k];
else process.env[k] = _savedCiEnv[k];
}
}

console.log('All sanitize tests passed (70 assertions)');
Loading