// engine/runtime-security/checkers/input-sanitizer.ts — SPEC-084 AC-05
// Validates lengths, formats, and strips control characters from inputs.
const FIELD_MAX_LENGTHS = {
    specId: 100,
    content: 50_000,
    projectPath: 500,
    fileName: 255,
    name: 255,
    description: 10_000,
};
const DEFAULT_MAX_LENGTH = 10_000;
// Control characters U+0000-U+001F except \n (0x0A) and \t (0x09)
// eslint-disable-next-line no-control-regex -- intentionally detecting control chars for sanitization
const CONTROL_CHARS = /[\u0000-\u0008\u000B\u000C\u000E-\u001F]/g;
const SPEC_ID_PATTERN = /^SPEC-\d{3,4}$/;
function getMaxLength(field) {
    return FIELD_MAX_LENGTHS[field] ?? DEFAULT_MAX_LENGTH;
}
function checkFieldLength(field, value) {
    const maxLen = getMaxLength(field);
    if (value.length > maxLen) {
        return {
            type: 'input-validation',
            severity: 'warning',
            message: `Field "${field}" exceeds max length (${String(value.length)}/${String(maxLen)})`,
            field,
        };
    }
    return null;
}
function checkControlChars(field, value) {
    if (CONTROL_CHARS.test(value)) {
        return {
            type: 'input-validation',
            severity: 'warning',
            message: `Control characters detected in field "${field}"`,
            field,
            pattern: 'control-chars',
        };
    }
    return null;
}
function checkSpecIdFormat(field, value) {
    if (field === 'specId' && !SPEC_ID_PATTERN.test(value)) {
        return {
            type: 'input-validation',
            severity: 'warning',
            message: `Invalid specId format: expected SPEC-NNN, got "${value}"`,
            field,
            pattern: 'specId-format',
        };
    }
    return null;
}
function checkProjectPathFormat(field, value) {
    if (field === 'projectPath') {
        const isAbsolute = value.startsWith('/') || /^[A-Z]:\\/i.test(value);
        if (!isAbsolute) {
            return {
                type: 'input-validation',
                severity: 'warning',
                message: `projectPath must be an absolute path, got: "${value}"`,
                field,
                pattern: 'absolute-path',
            };
        }
    }
    return null;
}
export function sanitizeString(value) {
    return value.replace(CONTROL_CHARS, '');
}
export const inputSanitizerChecker = {
    type: 'input-validation',
    check(_toolName, inputs, _config) {
        const threats = [];
        for (const [key, value] of Object.entries(inputs)) {
            if (typeof value !== 'string') {
                continue;
            }
            const lengthThreat = checkFieldLength(key, value);
            if (lengthThreat) {
                threats.push(lengthThreat);
            }
            const controlThreat = checkControlChars(key, value);
            if (controlThreat) {
                threats.push(controlThreat);
            }
            const specIdThreat = checkSpecIdFormat(key, value);
            if (specIdThreat) {
                threats.push(specIdThreat);
            }
            const pathThreat = checkProjectPathFormat(key, value);
            if (pathThreat) {
                threats.push(pathThreat);
            }
        }
        return threats;
    },
};
//# sourceMappingURL=input-sanitizer.js.map