// tools/challenge-spec/security-challenge-scenarios.ts — Security challenges for challenge_spec
// SPEC-029 criteria 11, 24: authorization challenges and STRIDE-based challenges
import { detectSecurityProfiles } from '../../engine/security-analyzer.js';
/**
 * Generate security challenge scenarios specific to authorization, STRIDE threats,
 * and resource ownership. Used by handleChallengeSpec in the 'security' focus area.
 */
export function generateSecurityChallengeScenarios(spec, _specContent, _knowledge) {
    const profiles = detectSecurityProfiles(spec.title, '', spec.tags);
    const scenarios = [];
    // Authorization challenge (criterion 11): resource ownership
    if (profiles.includes('public-api') || profiles.includes('db-access')) {
        scenarios.push({
            scenario: `[${spec.id}] Broken Object-Level Authorization (BOLA/IDOR): user X accesses a resource belonging to user Y by manipulating the resource ID. Authorization check missing at service layer.`,
            probability: 'high',
            impact: 'critical',
            currentHandling: 'Authorization check may be missing at the data access layer — only route-level guards present.',
            requiredHandling: 'Implement object-level authorization on every data access operation. ' +
                'Never trust client-provided resource IDs without verifying ownership. ' +
                'Use indirect references (UUIDs) instead of sequential IDs.',
            dataConsistency: 'Unauthorized access should return 403, never 404 that leaks resource existence.',
            userExperience: 'Return consistent 403 Forbidden for unauthorized access — do not reveal if the resource exists.',
        });
    }
    // JWT-specific challenges
    const lower = `${spec.title} ${spec.tags.join(' ')}`.toLowerCase();
    const hasJwt = lower.includes('jwt') || lower.includes('token') || lower.includes('auth');
    if (hasJwt) {
        scenarios.push({
            scenario: `[${spec.id}] JWT Algorithm Confusion Attack: attacker changes JWT header algorithm to "none" or switches RS256 to HS256. Server accepts forged token if it trusts the header.`,
            probability: 'medium',
            impact: 'critical',
            currentHandling: 'Algorithm may not be explicitly validated — token header is trusted.',
            requiredHandling: 'Explicitly configure the allowed algorithm(s) in JWT verification. ' +
                'Never use the algorithm from the token header. Reject tokens with "none" algorithm.',
            dataConsistency: 'Invalid tokens must never reach business logic — reject at middleware boundary.',
            userExperience: 'Return 401 Unauthorized for invalid tokens — do not expose algorithm validation details.',
        });
        scenarios.push({
            scenario: `[${spec.id}] Expired Token Access: user presents an expired JWT. Does the API return 401 immediately, or does expired token reach business logic?`,
            probability: 'medium',
            impact: 'high',
            currentHandling: 'Expiry check may not be the first middleware step — race conditions possible.',
            requiredHandling: 'Verify token expiry (exp claim) as the first step in auth middleware. ' +
                'Return 401 with error code "token_expired" so clients can trigger refresh flow.',
            dataConsistency: 'Expired tokens must never modify state — check before any write operations.',
            userExperience: 'Return structured error { "error": "token_expired" } so clients can refresh automatically.',
        });
    }
    // SQL injection challenges for DB features
    if (profiles.includes('db-access')) {
        scenarios.push({
            scenario: `[${spec.id}] SQL/NoSQL Injection in Auth or Query Fields: user submits "admin'--" as username or "x' OR '1'='1" as password. Parameterized queries may be missing.`,
            probability: 'high',
            impact: 'critical',
            currentHandling: 'Query construction may use string concatenation for dynamic values.',
            requiredHandling: 'Use parameterized queries or ORM with auto-escaping for all DB operations. ' +
                'Validate and sanitize all inputs before use in queries. ' +
                'Implement input length limits and character whitelisting where appropriate.',
            dataConsistency: 'Injection must not corrupt database state — use transactions for multi-step ops.',
            userExperience: 'Return generic error message — never expose SQL syntax errors to the end user.',
        });
    }
    // Role-based access challenges
    const hasRoles = lower.includes('role') ||
        lower.includes('admin') ||
        lower.includes('permission') ||
        lower.includes('rbac');
    if (hasRoles) {
        scenarios.push({
            scenario: `[${spec.id}] Privilege Escalation via Role Manipulation: user with role "viewer" calls admin endpoint, or modifies JWT payload claiming role "admin". Role enforcement missing at middleware.`,
            probability: 'medium',
            impact: 'critical',
            currentHandling: 'Role enforcement may be per-handler instead of middleware — inconsistent coverage.',
            requiredHandling: 'Enforce RBAC in middleware, not per-handler. ' +
                'Never derive roles from user-supplied data; always load from a trusted store. ' +
                'Log unauthorized access attempts for monitoring.',
            dataConsistency: 'Admin operations that modify state must verify role before any data mutation.',
            userExperience: 'Return 403 Forbidden with a user-facing message — log the attempt with user ID for audit.',
        });
    }
    // STRIDE elevation of privilege challenge for admin/payment
    const isHighRisk = lower.includes('payment') ||
        lower.includes('admin') ||
        lower.includes('billing') ||
        lower.includes('sensitive');
    if (isHighRisk) {
        scenarios.push({
            scenario: `[${spec.id}] STRIDE Elevation of Privilege: regular user performs a sequence of legitimate API calls that results in unintended elevated access (e.g., create → transfer → access with original permissions).`,
            probability: 'low',
            impact: 'high',
            currentHandling: 'Business logic state transitions may not verify authorization at each step.',
            requiredHandling: 'Model all state transitions and verify authorization at each step. ' +
                'Implement business rule validation server-side. ' +
                'Add rate limiting and anomaly detection for unusual patterns.',
            dataConsistency: 'Multi-step operations must be atomic — partial state on auth failure must roll back.',
            userExperience: 'Log suspicious sequences for security monitoring — alert on unusual access patterns.',
        });
    }
    return scenarios;
}
/**
 * Generate security test case scaffolds for auth/API features.
 * SPEC-029 criterion 12: auto-generate security test scaffolds.
 */
export function generateSecurityTestCases(spec, framework) {
    const profiles = detectSecurityProfiles(spec.title, '', spec.tags);
    const lines = [];
    if (!profiles.includes('public-api') && !profiles.includes('auth')) {
        return lines;
    }
    lines.push(`// Security tests for ${spec.title}`);
    lines.push('');
    if (framework === 'jest' || framework === 'vitest') {
        lines.push(`describe('Security: ${spec.title}', () => {`);
        lines.push(`  it('returns 401 when no authentication token is provided', async () => {`);
        lines.push(`    // Test unauthenticated access — expect 401`);
        lines.push(`  });`);
        lines.push('');
        lines.push(`  it('returns 403 when user has wrong role', async () => {`);
        lines.push(`    // Test insufficient permissions — expect 403`);
        lines.push(`  });`);
        lines.push('');
        lines.push(`  it('returns 401 when token is expired', async () => {`);
        lines.push(`    // Test expired token handling — expect 401 with token_expired`);
        lines.push(`  });`);
        lines.push('');
        if (profiles.includes('db-access')) {
            lines.push(`  it('handles SQL injection attempt gracefully', async () => {`);
            lines.push(`    // Test: payload = "admin'--" should not execute SQL`);
            lines.push(`  });`);
            lines.push('');
        }
        lines.push(`});`);
    }
    return lines;
}
//# sourceMappingURL=security-challenge-scenarios.js.map