export const object = (v) => v !== null && typeof v === 'object' && !Array.isArray(v); const reference = (v) => typeof v === 'string' && /^(?:Bearer )?\$\{(?:env:)?[A-Za-z_][A-Za-z0-9_]*\}$/.test(v); const secretValue = (v) => typeof v === 'string' && /(?:github_pat_|gh[pousr]_|sk_(?:live|test)_)[A-Za-z0-9_]{16,}/.test(v); const secretKey = (k) => /token|password|secret|authorization|api[-_]?key|credential/i.test(k); const scrubUrl = (text) => { try { const u = new URL(text); u.username = ''; u.password = ''; for (const key of [...u.searchParams.keys()]) u.searchParams.set(key, 'REDACTED'); u.hash = ''; return u.href; } catch { return text; } }; export function redactConfig(value) { function walk(v, key = '') { if (secretValue(v)) return 'REDACTED'; if (Array.isArray(v)) { if (['env', 'headers', 'http_headers'].includes(key)) return 'REDACTED'; if (key === 'args') return v.map((x, i) => secretValue(x) ? 'REDACTED' : typeof x !== 'string' ? walk(x) : i > 0 && secretKey(String(v[i - 1])) ? 'REDACTED' : /^[A-Za-z_][A-Za-z0-9_]*=/.test(x) ? x.slice(0, x.indexOf('=') + 1) + 'REDACTED' : /^--[^=]+=/.test(x) && secretKey(x.split('=')[0]) ? x.split('=')[0] + '=REDACTED' : /^https?:\/\//.test(x) ? scrubUrl(x) : x, ); return v.map((x) => walk(x)); } if (object(v)) return Object.fromEntries( Object.entries(v).map(([k, x]) => [ k, ['env', 'headers', 'http_headers'].includes(key) ? reference(x) ? x : 'REDACTED' : secretKey(k) && !['bearer_token_env_var'].includes(k) ? reference(x) ? x : 'REDACTED' : walk(x, k), ]), ); if (typeof v === 'string' && ['url', 'serverUrl'].includes(key)) return scrubUrl(v); return v; } return walk(value); } import { readFileSync } from 'node:fs'; try { const raw=readFileSync(0,'utf8'); if(Buffer.byteLength(raw)>24000) throw new Error(); process.stdout.write(JSON.stringify(redactConfig(JSON.parse(raw)),null,2)+'\n'); } catch { process.stderr.write('Expected valid JSON no larger than 24,000 bytes. No input was printed.\n');process.exitCode=1; }