// tools/create-spec/security-spec-adapter.ts — Security section generator for create_spec
// SPEC-029: adds Seguridad section with OWASP-mapped acceptance criteria
import { detectSecurityProfiles, detectAuthMechanism, detectComplianceFrameworks, } from '../../engine/security-analyzer.js';
// === Security section content generator ===
/**
 * Generates a "## Seguridad" markdown section with OWASP-mapped criteria
 * specific to the feature's security profile. Called by generateHUContent.
 */
export function addSecuritySection(spec, description, knowledge) {
    const profiles = detectSecurityProfiles(spec.title, description, spec.tags);
    const authMechanism = detectAuthMechanism(description, spec.tags);
    const complianceFrameworks = detectComplianceFrameworks(description, knowledge?.projectPath ?? '');
    const lines = ['', '## Seguridad', ''];
    // OWASP profile-based criteria
    const criteria = buildSecurityCriteria(profiles, authMechanism);
    if (criteria.length > 0) {
        lines.push('### Criterios OWASP');
        lines.push('');
        for (const c of criteria) {
            lines.push(`- [ ] ${c}`);
        }
        lines.push('');
    }
    // Auth-specific criteria
    if (authMechanism !== 'none') {
        const authCriteria = buildAuthCriteria(authMechanism);
        if (authCriteria.length > 0) {
            lines.push(`### Mecanismo de autenticación: ${authMechanism.toUpperCase()}`);
            lines.push('');
            for (const c of authCriteria) {
                lines.push(`- [ ] ${c}`);
            }
            lines.push('');
        }
    }
    // STRIDE for sensitive features
    const isHighRisk = profiles.includes('auth') || profiles.includes('pii-data');
    const featureType = detectStrideFeatureType(spec.title, description);
    if (isHighRisk || featureType !== 'generic') {
        lines.push(...buildStrideSection(featureType));
    }
    // Compliance criteria
    if (complianceFrameworks.length > 0) {
        lines.push(...buildComplianceSection(complianceFrameworks));
    }
    // Security headers criterion for public API features
    if (profiles.includes('public-api')) {
        lines.push('### Headers de seguridad');
        lines.push('');
        lines.push('- [ ] Verificar que todos los security headers estén presentes en el nuevo endpoint: ' +
            'Content-Security-Policy, X-Frame-Options, X-Content-Type-Options, Strict-Transport-Security');
        lines.push('');
    }
    // Supply chain criterion for release/infra specs
    if (spec.type === 'infra' || spec.tags.includes('release') || spec.tags.includes('deploy')) {
        lines.push('### Supply Chain Security');
        lines.push('');
        lines.push('- [ ] SBOM (Software Bill of Materials) generado para esta release');
        lines.push('- [ ] Dependencias ancladas a hashes específicos en lockfile');
        lines.push('- [ ] Pipeline de CI verifica la firma de artefactos antes del despliegue');
        lines.push('');
    }
    return lines;
}
// === Internal helpers ===
function buildSecurityCriteria(profiles, authMechanism) {
    const criteria = [];
    const seen = new Set();
    /* v8 ignore start */
    const add = (c) => {
        if (!seen.has(c)) {
            seen.add(c);
            criteria.push(c);
        }
    };
    /* v8 ignore stop */
    if (profiles.includes('public-api')) {
        add('Autenticación requerida en todos los endpoints no públicos [A01-broken-access-control]');
        add('Autorización verificada por rol — usuario solo accede a sus propios recursos [A01]');
        add('Rate limiting aplicado con límites definidos (ej. 100 req/min por IP) [A05]');
        add('Respuestas de error no exponen stack traces ni detalles internos del sistema [A04]');
    }
    if (profiles.includes('db-access')) {
        add('Todas las consultas usan sentencias parametrizadas o queries preparadas [A03-injection]');
        add('Input de usuario validado y sanitizado antes de almacenar en BD [A03]');
        add('Conexión BD usa permisos mínimos necesarios (least privilege) [A01]');
        add('Datos sensibles (PII, contraseñas) encriptados en reposo [A02-cryptographic-failures]');
    }
    if (profiles.includes('file-upload')) {
        add('Archivos subidos validados por tipo, tamaño y contenido (no solo extensión) [A04]');
        add('Archivos almacenados fuera del web root sin permisos de ejecución [A05]');
        add('Nombres de archivo sanitizados — caracteres de path traversal eliminados [A03]');
    }
    if (profiles.includes('html-render')) {
        add('Todo contenido de usuario escapado antes de renderizar en HTML [A03]');
        add('Content-Security-Policy restringe fuentes de scripts permitidas [A05]');
    }
    if (profiles.includes('pii-data')) {
        add('Campos PII (email, teléfono, SSN) encriptados en reposo [A02]');
        add('Datos PII redactados en logs — no aparecen emails completos ni datos sensibles [A09]');
        add('Acceso a PII requiere autorización explícita — no accesible por defecto [A01]');
    }
    if (authMechanism !== 'none' && profiles.includes('auth')) {
        add('Implementar bloqueo de cuenta o delay progresivo tras N intentos fallidos [A07]');
    }
    return criteria;
}
function buildAuthCriteria(mechanism) {
    const map = {
        jwt: [
            'Tokens JWT tienen expiración definida (claim exp) — máximo 1 hora para access tokens',
            'Refresh token rotation implementada — refrescar un token invalida el refresh token anterior',
            'Token blacklisting disponible para revocación inmediata (logout, cambio de contraseña)',
            "Algoritmo explícitamente configurado a RS256 o HS256 — algoritmo 'none' rechazado",
        ],
        oauth2: [
            'Parámetro state validado para prevenir CSRF en flujo authorization code de OAuth2',
            'PKCE implementado para clientes públicos (apps móviles, SPAs)',
            'Access tokens NO almacenados en localStorage — usar sessionStorage o cookies HttpOnly',
            'Redirect URIs en whitelist — sin vulnerabilidad de open redirect',
        ],
        'api-key': [
            'API keys almacenadas como valores hasheados en BD (bcrypt o SHA-256)',
            'Política de rotación de API keys definida — se pueden rotar sin downtime',
            'API keys transmitidas por headers, no por query parameters de URL',
            'API keys comprometidas pueden revocarse inmediatamente',
        ],
        session: [
            'Cookies de sesión tienen flag HttpOnly configurado para prevenir acceso JavaScript',
            'Cookies de sesión tienen flag Secure — solo transmitidas por HTTPS',
            'Cookies de sesión tienen SameSite=Strict o Lax para prevenir CSRF',
            'Session ID regenerado en login para prevenir session fixation',
        ],
    };
    return map[mechanism] ?? [];
}
function detectStrideFeatureType(title, description) {
    const lower = `${title} ${description}`.toLowerCase();
    if (lower.includes('payment') || lower.includes('billing') || lower.includes('checkout')) {
        return 'payment';
    }
    if (lower.includes('admin') || lower.includes('dashboard') || lower.includes('management')) {
        return 'admin';
    }
    if (lower.includes('auth') || lower.includes('login') || lower.includes('register')) {
        return 'auth';
    }
    return 'generic';
}
function buildStrideSection(featureType) {
    const lines = ['### Análisis STRIDE', ''];
    const strideItems = [
        {
            id: 'Spoofing',
            question: featureType === 'auth'
                ? '¿Cómo se verifica que la identidad presentada es legítima y no suplantada?'
                : '¿Cómo se verifica la identidad de quien realiza la operación?',
        },
        {
            id: 'Tampering',
            question: featureType === 'payment'
                ? '¿Cómo se protege la integridad del monto del pago entre cliente y servidor?'
                : '¿Cómo se protege la integridad de los datos en esta operación?',
        },
        {
            id: 'Repudiation',
            question: '¿Qué audit trail existe para esta operación? (usuario, acción, timestamp, recurso)',
        },
        {
            id: 'Information Disclosure',
            question: '¿Qué datos sensibles podrían filtrarse en logs, errores o respuestas de API?',
        },
        {
            id: 'Denial of Service',
            question: '¿Cuáles son los rate limits? ¿Qué previene el abuso de esta operación?',
        },
        {
            id: 'Elevation of Privilege',
            question: featureType === 'admin'
                ? '¿Qué previene que un usuario sin permisos acceda a funcionalidades de admin?'
                : '¿Qué previene la escalada de privilegios en esta funcionalidad?',
        },
    ];
    for (const item of strideItems) {
        lines.push(`**${item.id}**: ${item.question}`);
        lines.push('');
    }
    return lines;
}
function buildComplianceSection(frameworks) {
    const lines = ['### Cumplimiento normativo', ''];
    const criteriaMap = {
        hipaa: [
            'Audit log contiene: ID de usuario, acción, timestamp y recurso afectado para todo acceso a PHI',
            'PHI (Protected Health Information) encriptado en reposo con AES-256',
            'PHI transmitido solo por TLS 1.2+ — TLS 1.0/1.1 deshabilitados',
            'Timeout de sesión automático a los 15-30 minutos de inactividad',
        ],
        'pci-dss': [
            'Número de tarjeta completo (PAN) nunca almacenado tras autorización — solo últimos 4 dígitos',
            'TLS 1.2+ requerido para toda transmisión de datos de tarjeta',
            'Política de rotación de claves criptográficas definida y documentada',
        ],
        fedramp: [
            'Sistema usa módulos criptográficos con validación FIPS 140-2',
            'Datos almacenados solo en regiones cloud autorizadas por FedRAMP',
        ],
        soc2: [
            'Revisiones de acceso realizadas trimestralmente',
            'Eventos de seguridad registrados y retenidos mínimo 12 meses',
        ],
    };
    for (const framework of frameworks) {
        const fCriteria = criteriaMap[framework] ?? [];
        if (fCriteria.length > 0) {
            lines.push(`**${framework.toUpperCase()}**:`);
            lines.push('');
            for (const c of fCriteria) {
                lines.push(`- [ ] ${c}`);
            }
            lines.push('');
        }
    }
    return lines;
}
//# sourceMappingURL=security-spec-adapter.js.map