/**
 * Artifact redaction — strips sensitive data from written artifacts so that
 * secrets (resolved env vars, auth headers, session cookies) never reach
 * local or remote storage.
 *
 * Two-layer approach:
 * 1. **Header stripping** — known-sensitive HTTP header keys are replaced
 *    with "[REDACTED]" regardless of value.
 * 2. **Value-pattern redaction** — string values anywhere in the JSON tree
 *    that match known secret formats are replaced with "[REDACTED]".
 */
// ---------------------------------------------------------------------------
// Sensitive HTTP header keys (case-insensitive)
// ---------------------------------------------------------------------------
/**
 * HTTP headers that should always be redacted in captured artifacts.
 *
 * Stored lower-cased; lookup is done after lower-casing the key. This is
 * intentionally a blocklist rather than an allowlist so that debugging-useful
 * headers (x-request-id, content-type, etc.) are preserved.
 */
const SENSITIVE_HEADER_KEYS = new Set([
    "authorization",
    "proxy-authorization",
    "cookie",
    "set-cookie",
    "x-api-key",
    "x-auth-token",
]);
// ---------------------------------------------------------------------------
// Secret value patterns (same family as comparator + telemetry redactor)
// ---------------------------------------------------------------------------
const SECRET_VALUE_PATTERNS = [
    /^Bearer\s+\S{20,}/, // Authorization header values
    /^Basic\s+[A-Za-z0-9+/=]{20,}/, // Basic auth
    /^sk-[a-zA-Z0-9_-]{20,}/, // OpenAI-style keys
    /^sk[A-Z][a-zA-Z0-9]{20,}/, // Sanity-style tokens
    /^sk-ant-[a-zA-Z0-9_-]{20,}/, // Anthropic keys
    /^xoxb-/, // Slack bot tokens
    /^ghp_/, // GitHub personal tokens
    /^ghs_/, // GitHub server-to-server tokens
    /^AKIA[A-Z0-9]{12,}/, // AWS access keys
];
const REDACTED = "[REDACTED]";
// ---------------------------------------------------------------------------
// Public API
// ---------------------------------------------------------------------------
/**
 * Deep-clone and redact a parsed JSON artifact.
 *
 * Safe to call on any artifact format — non-object inputs are returned
 * as-is (nothing to redact in a plain string or number).
 */
export function redactArtifactData(data) {
    if (data === null || data === undefined)
        return data;
    if (typeof data !== "object") {
        // Scalar — check value patterns
        if (typeof data === "string")
            return redactStringValue(data);
        return data;
    }
    // Deep-clone first so we never mutate the original
    return walkAndRedact(JSON.parse(JSON.stringify(data)));
}
// ---------------------------------------------------------------------------
// Internals
// ---------------------------------------------------------------------------
function redactStringValue(value) {
    for (const pattern of SECRET_VALUE_PATTERNS) {
        if (pattern.test(value))
            return REDACTED;
    }
    return value;
}
/** Returns true if the key is a known-sensitive HTTP header name. */
function isSensitiveHeaderKey(key) {
    return SENSITIVE_HEADER_KEYS.has(key.toLowerCase());
}
function walkAndRedact(node) {
    if (node === null || node === undefined)
        return node;
    if (typeof node === "string") {
        return redactStringValue(node);
    }
    if (Array.isArray(node)) {
        for (let i = 0; i < node.length; i++) {
            node[i] = walkAndRedact(node[i]);
        }
        return node;
    }
    if (typeof node === "object") {
        const obj = node;
        for (const key of Object.keys(obj)) {
            // Layer 1: strip sensitive HTTP headers by key name
            if (isSensitiveHeaderKey(key)) {
                const val = obj[key];
                if (typeof val === "string") {
                    obj[key] = REDACTED;
                }
                else if (Array.isArray(val)) {
                    // Some HTTP parsers serialize set-cookie as string[]
                    obj[key] = val.map((v) => (typeof v === "string" ? REDACTED : v));
                }
                continue;
            }
            // Layer 2: recurse and apply value-pattern redaction
            obj[key] = walkAndRedact(obj[key]);
        }
        return obj;
    }
    return node;
}
