import { nowIso, sanitizeText } from "../../shared/index.js";
const SECRET_RULES = [
    {
        kind: "secret",
        severity: "error",
        policy: "no_api_key_leak",
        message: "Potential OpenAI-style API key was found.",
        pattern: /\bsk-(?:proj-)?[A-Za-z0-9_-]{20,}\b/g,
    },
    {
        kind: "secret",
        severity: "error",
        policy: "no_github_token_leak",
        message: "Potential GitHub token was found.",
        pattern: /\b(?:ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9_]{20,}\b|\bgithub_pat_[A-Za-z0-9_]{20,}\b/g,
    },
    {
        kind: "secret",
        severity: "error",
        policy: "no_aws_key_leak",
        message: "Potential AWS access key was found.",
        pattern: /\b(?:AKIA|ASIA)[A-Z0-9]{16}\b/g,
    },
    {
        kind: "secret",
        severity: "error",
        policy: "no_private_key_leak",
        message: "Potential private key block was found.",
        pattern: /-----BEGIN [A-Z ]*PRIVATE KEY-----/g,
    },
    {
        kind: "secret",
        severity: "error",
        policy: "no_named_secret_leak",
        message: "Potential named secret assignment was found.",
        pattern: /\b(?:api[_-]?key|token|secret|password|authorization|cookie|credential|refresh[_-]?token|access[_-]?token)\b\s*[:=]\s*["']?(?!\[REDACTED\]|<redacted>|\.\.\.)[A-Za-z0-9_./+=:@-]{12,}/gi,
    },
];
const LOCAL_PATH_RULES = [
    {
        kind: "local_path",
        severity: "error",
        policy: "no_home_path_leak",
        message: "Machine-specific home-directory path was found.",
        pattern: /(?:^|[\s"'`(])((?:\/home|\/Users)\/[A-Za-z0-9._-]+\/[^\s"'`)<>]*)/g,
    },
    {
        kind: "local_path",
        severity: "error",
        policy: "no_windows_user_path_leak",
        message: "Machine-specific Windows user path was found.",
        pattern: /(?:^|[\s"'`(])([A-Za-z]:\\Users\\[^"'`\s)<>]+)/g,
    },
];
const PROMPT_INJECTION_RULES = [
    {
        kind: "prompt_injection",
        severity: "warning",
        policy: "mark_prompt_injection_language",
        message: "Prompt-injection-like instruction text was found and should be treated as untrusted evidence.",
        pattern: /\b(ignore (?:all )?(?:previous|prior|above) instructions|disregard (?:all )?(?:previous|prior|above) instructions|reveal (?:the )?system prompt|developer message)\b/gi,
    },
];
export function auditSeedTextPolicy(input) {
    const findings = [
        ...findPolicyMatches(input.content, SECRET_RULES),
        ...findPolicyMatches(input.content, LOCAL_PATH_RULES),
        ...(input.includePromptInjectionWarnings === false ? [] : findPolicyMatches(input.content, PROMPT_INJECTION_RULES)),
        ...(input.includeUrlWarnings ? findUrlPolicyMatches(input.content) : []),
        ...findCanaryMatches(input.content, input.canaryTokens ?? []),
    ];
    const issues = findings.filter((finding) => finding.severity === "error").map((finding) => `${finding.policy}: ${finding.message} at line ${finding.line}.`);
    const warnings = findings.filter((finding) => finding.severity === "warning").map((finding) => `${finding.policy}: ${finding.message} at line ${finding.line}.`);
    return {
        schema_version: 1,
        checked_at: nowIso(),
        scope: sanitizeText(input.scope),
        status: issues.length === 0 ? "passed" : "failed",
        findings,
        issues,
        warnings,
    };
}
function findPolicyMatches(content, rules) {
    const findings = [];
    const lines = content.split(/\r?\n/);
    for (const [index, line] of lines.entries()) {
        for (const rule of rules) {
            rule.pattern.lastIndex = 0;
            for (const match of line.matchAll(rule.pattern)) {
                const raw = match[1] ?? match[0];
                findings.push({
                    kind: rule.kind,
                    severity: rule.severity,
                    policy: rule.policy,
                    message: rule.message,
                    line: index + 1,
                    column: (match.index ?? 0) + 1,
                    sample: redactSample(rule.kind, raw),
                });
            }
        }
    }
    return findings;
}
function findUrlPolicyMatches(content) {
    const findings = [];
    const seen = new Set();
    const lines = content.split(/\r?\n/);
    for (const [index, line] of lines.entries()) {
        for (const match of line.matchAll(/\b(?:https?:\/\/|file:\/\/|javascript:|data:text\/html)[^\s"'<>)]*/gi)) {
            const raw = match[0];
            const result = classifyUrlFinding(raw);
            if (!result)
                continue;
            const key = `${index}:${result.policy}:${result.sample}`;
            if (seen.has(key))
                continue;
            seen.add(key);
            findings.push({
                kind: "unsafe_url",
                severity: "warning",
                policy: result.policy,
                message: result.message,
                line: index + 1,
                column: (match.index ?? 0) + 1,
                sample: result.sample,
            });
        }
    }
    return findings;
}
function classifyUrlFinding(raw) {
    const value = raw.trim();
    const lower = value.toLowerCase();
    if (lower.startsWith("javascript:")) {
        return {
            policy: "mark_active_url_scheme",
            message: "Active javascript URL scheme was found in untrusted content.",
            sample: sanitizeText(value).slice(0, 120),
        };
    }
    if (lower.startsWith("file:")) {
        return {
            policy: "mark_file_url_reference",
            message: "Local file URL reference was found in untrusted content.",
            sample: sanitizeText(value).slice(0, 120),
        };
    }
    if (lower.startsWith("data:text/html")) {
        return {
            policy: "mark_active_data_url",
            message: "Active HTML data URL was found in untrusted content.",
            sample: sanitizeText(value).slice(0, 120),
        };
    }
    let url;
    try {
        url = new URL(value);
    }
    catch {
        return undefined;
    }
    if (hasSensitiveQueryParam(url)) {
        return {
            policy: "mark_sensitive_url_query",
            message: "Sensitive URL query parameter was found in untrusted content.",
            sample: redactSensitiveUrl(url).slice(0, 160),
        };
    }
    if (isLocalOrPrivateHost(url.hostname)) {
        return {
            policy: "mark_local_network_url",
            message: "Local or private network URL was found in untrusted content.",
            sample: sanitizeText(url.toString()).slice(0, 160),
        };
    }
    return undefined;
}
function findCanaryMatches(content, canaryTokens) {
    const findings = [];
    const tokens = [...new Set(canaryTokens.map((token) => token.trim()).filter((token) => token.length >= 8))];
    if (tokens.length === 0)
        return findings;
    const lines = content.split(/\r?\n/);
    for (const [index, line] of lines.entries()) {
        for (const token of tokens) {
            const column = line.indexOf(token);
            if (column < 0)
                continue;
            findings.push({
                kind: "canary",
                severity: "error",
                policy: "no_canary_token_leak",
                message: "Session canary token was found in inspected content.",
                line: index + 1,
                column: column + 1,
                sample: "[CANARY_REDACTED]",
            });
        }
    }
    return findings;
}
function redactSample(kind, value) {
    if (kind === "local_path")
        return "[LOCAL_PATH_REDACTED]";
    if (kind === "secret")
        return `${value.slice(0, Math.min(6, value.length))}...[REDACTED]`;
    if (kind === "canary")
        return "[CANARY_REDACTED]";
    return sanitizeText(value).slice(0, 120);
}
function hasSensitiveQueryParam(url) {
    const sensitive = /^(?:api[_-]?key|token|secret|password|authorization|cookie|credential|refresh[_-]?token|access[_-]?token|auth)$/i;
    return [...url.searchParams.keys()].some((key) => sensitive.test(key));
}
function redactSensitiveUrl(url) {
    const redacted = new URL(url.toString());
    for (const key of [...redacted.searchParams.keys()]) {
        if (/^(?:api[_-]?key|token|secret|password|authorization|cookie|credential|refresh[_-]?token|access[_-]?token|auth)$/i.test(key)) {
            redacted.searchParams.set(key, "[REDACTED]");
        }
    }
    return sanitizeText(redacted.toString().replaceAll("%5BREDACTED%5D", "[REDACTED]"));
}
function isLocalOrPrivateHost(hostname) {
    const host = hostname.toLowerCase().replace(/^\[|\]$/g, "");
    if (host === "localhost" || host === "::1" || host.endsWith(".local"))
        return true;
    if (/^127\./.test(host) || /^10\./.test(host) || /^192\.168\./.test(host) || /^169\.254\./.test(host))
        return true;
    const match = host.match(/^172\.(\d{1,2})\./);
    if (!match)
        return false;
    const second = Number(match[1]);
    return second >= 16 && second <= 31;
}
//# sourceMappingURL=index.js.map