Created
October 13, 2025 21:19
-
-
Save arubis/93aadce283a76b06897e4b04565850cf to your computer and use it in GitHub Desktop.
Phase 2 Frontend Test Integration - Interactive Demonstrations (RFC-060-AMENDMENT-001)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * TestIntegrationClient Retry Behavior Demonstration | |
| * | |
| * This shows how the backend API client handles errors and retries | |
| * with exponential backoff. | |
| */ | |
| console.log('='.repeat(80)); | |
| console.log('TEST INTEGRATION CLIENT - RETRY BEHAVIOR DEMONSTRATION'); | |
| console.log('='.repeat(80)); | |
| console.log(); | |
| // ============================================================================= | |
| // Helper to simulate timing | |
| // ============================================================================= | |
| class TimingLogger { | |
| private startTime: number; | |
| constructor() { | |
| this.startTime = Date.now(); | |
| } | |
| log(message: string) { | |
| const elapsed = Date.now() - this.startTime; | |
| console.log(`[${elapsed.toString().padStart(5, ' ')}ms] ${message}`); | |
| } | |
| reset() { | |
| this.startTime = Date.now(); | |
| } | |
| } | |
| // ============================================================================= | |
| // DEMO 1: Exponential Backoff Timing | |
| // ============================================================================= | |
| console.log('π DEMO 1: Exponential Backoff Timing'); | |
| console.log('-'.repeat(80)); | |
| console.log(); | |
| const demoExponentialBackoff = () => { | |
| console.log('Formula: delay = baseDelay * 2^attempt'); | |
| console.log('Base delay: 100ms'); | |
| console.log(); | |
| const baseDelay = 100; | |
| const maxRetries = 3; | |
| console.log('Retry schedule:'); | |
| for (let attempt = 0; attempt < maxRetries; attempt++) { | |
| const delay = baseDelay * Math.pow(2, attempt); | |
| console.log(` Attempt ${attempt + 1}: Wait ${delay}ms before retry`); | |
| } | |
| console.log(); | |
| console.log('Timeline for a 3-retry scenario:'); | |
| console.log(' 0ms β Initial request (fails)'); | |
| console.log(' 100ms β Retry 1 (fails)'); | |
| console.log(' 300ms β Retry 2 (100ms + 200ms wait, fails)'); | |
| console.log(' 700ms β Retry 3 (300ms + 400ms wait, succeeds)'); | |
| console.log(' Total: 700ms for 3 retries'); | |
| console.log(); | |
| console.log('Why exponential backoff?'); | |
| console.log(' β’ Gives server time to recover from temporary issues'); | |
| console.log(' β’ Prevents overwhelming server with rapid retries'); | |
| console.log(' β’ Industry standard pattern (AWS, Google Cloud, etc.)'); | |
| }; | |
| demoExponentialBackoff(); | |
| // ============================================================================= | |
| // DEMO 2: Retry Decision Matrix | |
| // ============================================================================= | |
| console.log('\n\nπ DEMO 2: Retry Decision Matrix'); | |
| console.log('-'.repeat(80)); | |
| console.log(); | |
| const demoRetryDecisionMatrix = () => { | |
| const scenarios = [ | |
| { | |
| status: 200, | |
| error: null, | |
| decision: 'β Success', | |
| retries: 0, | |
| reason: 'Request succeeded' | |
| }, | |
| { | |
| status: 400, | |
| error: 'Bad Request', | |
| decision: 'β No Retry', | |
| retries: 0, | |
| reason: 'Client error - request is invalid' | |
| }, | |
| { | |
| status: 401, | |
| error: 'Unauthorized', | |
| decision: 'β No Retry', | |
| retries: 0, | |
| reason: 'Authentication failed - API key is wrong' | |
| }, | |
| { | |
| status: 404, | |
| error: 'Not Found', | |
| decision: 'β No Retry', | |
| retries: 0, | |
| reason: 'Endpoint doesn\'t exist' | |
| }, | |
| { | |
| status: 500, | |
| error: 'Internal Server Error', | |
| decision: 'π Retry', | |
| retries: 3, | |
| reason: 'Server error - might be temporary' | |
| }, | |
| { | |
| status: 502, | |
| error: 'Bad Gateway', | |
| decision: 'π Retry', | |
| retries: 3, | |
| reason: 'Gateway issue - likely temporary' | |
| }, | |
| { | |
| status: 503, | |
| error: 'Service Unavailable', | |
| decision: 'π Retry', | |
| retries: 3, | |
| reason: 'Server overloaded - will recover' | |
| }, | |
| { | |
| status: null, | |
| error: 'ECONNREFUSED', | |
| decision: 'π Retry', | |
| retries: 3, | |
| reason: 'Network error - connection refused' | |
| }, | |
| { | |
| status: null, | |
| error: 'ETIMEDOUT', | |
| decision: 'π Retry', | |
| retries: 3, | |
| reason: 'Network error - request timed out' | |
| } | |
| ]; | |
| console.log('Status Code β Retry Decision:\n'); | |
| for (const scenario of scenarios) { | |
| const statusStr = scenario.status ? `HTTP ${scenario.status}` : scenario.error!; | |
| console.log(` ${statusStr.padEnd(25)} ${scenario.decision.padEnd(15)} ${scenario.reason}`); | |
| } | |
| console.log(); | |
| console.log('Rule Summary:'); | |
| console.log(' β’ 2xx: Success, no retry needed'); | |
| console.log(' β’ 4xx: Client error, NO RETRY (fixing won\'t help)'); | |
| console.log(' β’ 5xx: Server error, RETRY (might be temporary)'); | |
| console.log(' β’ Network errors: RETRY (transient issues)'); | |
| }; | |
| demoRetryDecisionMatrix(); | |
| // ============================================================================= | |
| // DEMO 3: Simulated Network Timeout Scenario | |
| // ============================================================================= | |
| console.log('\n\nπ DEMO 3: Simulated Network Timeout Scenario'); | |
| console.log('-'.repeat(80)); | |
| console.log(); | |
| const demoNetworkTimeout = () => { | |
| const timer = new TimingLogger(); | |
| console.log('Request: POST /api/v1/test-integration/analyze'); | |
| console.log('Headers: { x-api-key: rsolv_xxx, Content-Type: application/json }'); | |
| console.log(); | |
| // Attempt 1 | |
| timer.log('β Attempt 1: Making request...'); | |
| timer.log('β Network timeout error: ETIMEDOUT'); | |
| timer.log('β οΈ Will retry with 100ms backoff'); | |
| console.log(); | |
| // Attempt 2 (after 100ms) | |
| timer.log('β Attempt 2: Making request...'); | |
| timer.log('β Network timeout error: ETIMEDOUT'); | |
| timer.log('β οΈ Will retry with 200ms backoff'); | |
| console.log(); | |
| // Attempt 3 (after 200ms) | |
| timer.log('β Attempt 3: Making request...'); | |
| timer.log('β Success! HTTP 200'); | |
| timer.log('β Request succeeded on attempt 3'); | |
| console.log(); | |
| console.log('Total time: ~300ms (including retry delays)'); | |
| console.log('Result: Resilient to temporary network issues'); | |
| }; | |
| demoNetworkTimeout(); | |
| // ============================================================================= | |
| // DEMO 4: Simulated 503 Service Unavailable Scenario | |
| // ============================================================================= | |
| console.log('\n\nπ DEMO 4: Simulated 503 Service Unavailable Scenario'); | |
| console.log('-'.repeat(80)); | |
| console.log(); | |
| const demo503Retry = () => { | |
| const timer = new TimingLogger(); | |
| console.log('Scenario: Backend server is temporarily overloaded'); | |
| console.log('Request: POST /api/v1/test-integration/generate'); | |
| console.log(); | |
| // Attempt 1 | |
| timer.log('β Attempt 1: Making request...'); | |
| timer.log('β HTTP 503: Service Unavailable'); | |
| timer.log(' Response: { error: "Server overloaded, try again" }'); | |
| timer.log('β οΈ Will retry with 100ms backoff'); | |
| console.log(); | |
| // Attempt 2 (after 100ms) | |
| timer.log('β Attempt 2: Making request...'); | |
| timer.log('β HTTP 503: Service Unavailable'); | |
| timer.log(' Response: { error: "Server overloaded, try again" }'); | |
| timer.log('β οΈ Will retry with 200ms backoff'); | |
| console.log(); | |
| // Attempt 3 (after 200ms) | |
| timer.log('β Attempt 3: Making request...'); | |
| timer.log('β Success! HTTP 200'); | |
| timer.log(' Response: { integratedContent: "...", method: "ast", ... }'); | |
| timer.log('β Request succeeded on attempt 3'); | |
| console.log(); | |
| console.log('Why this works:'); | |
| console.log(' β’ Server had time to shed load'); | |
| console.log(' β’ Exponential backoff gave increasing recovery time'); | |
| console.log(' β’ Client didn\'t give up too early'); | |
| }; | |
| demo503Retry(); | |
| // ============================================================================= | |
| // DEMO 5: Simulated 401 Unauthorized (No Retry) | |
| // ============================================================================= | |
| console.log('\n\nπ DEMO 5: Simulated 401 Unauthorized (No Retry)'); | |
| console.log('-'.repeat(80)); | |
| console.log(); | |
| const demo401NoRetry = () => { | |
| const timer = new TimingLogger(); | |
| console.log('Scenario: Invalid API key provided'); | |
| console.log('Request: POST /api/v1/test-integration/analyze'); | |
| console.log('Headers: { x-api-key: invalid_key, ... }'); | |
| console.log(); | |
| timer.log('β Attempt 1: Making request...'); | |
| timer.log('β HTTP 401: Unauthorized'); | |
| timer.log(' Response: { error: "Invalid API key" }'); | |
| timer.log('β No retry - client error'); | |
| timer.log('β Throwing error: "Unauthorized: Invalid API key"'); | |
| console.log(); | |
| console.log('Why no retry?'); | |
| console.log(' β’ Authentication failed - API key is wrong'); | |
| console.log(' β’ Retrying with same key will always fail'); | |
| console.log(' β’ User needs to fix configuration'); | |
| console.log(' β’ Total requests: 1 (fast failure)'); | |
| }; | |
| demo401NoRetry(); | |
| // ============================================================================= | |
| // DEMO 6: Complete Request/Response Flow | |
| // ============================================================================= | |
| console.log('\n\nπ DEMO 6: Complete Request/Response Flow'); | |
| console.log('-'.repeat(80)); | |
| console.log(); | |
| const demoCompleteFlow = () => { | |
| console.log('Example: Successful analyze() call'); | |
| console.log(); | |
| console.log('1οΈβ£ Client code:'); | |
| console.log(' const client = new TestIntegrationClient(apiKey, baseUrl);'); | |
| console.log(' const result = await client.analyze({'); | |
| console.log(' vulnerableFile: "app/controllers/users_controller.rb",'); | |
| console.log(' vulnerabilityType: "sql_injection",'); | |
| console.log(' candidateTestFiles: ["spec/controllers/users_controller_spec.rb"],'); | |
| console.log(' framework: "rspec"'); | |
| console.log(' });'); | |
| console.log(); | |
| console.log('2οΈβ£ HTTP Request:'); | |
| console.log(' POST https://api.rsolv.dev/api/v1/test-integration/analyze'); | |
| console.log(' Headers:'); | |
| console.log(' x-api-key: rsolv_xxx'); | |
| console.log(' Content-Type: application/json'); | |
| console.log(' Body:'); | |
| console.log(' {'); | |
| console.log(' "vulnerableFile": "app/controllers/users_controller.rb",'); | |
| console.log(' "vulnerabilityType": "sql_injection",'); | |
| console.log(' "candidateTestFiles": ["spec/controllers/users_controller_spec.rb"],'); | |
| console.log(' "framework": "rspec"'); | |
| console.log(' }'); | |
| console.log(); | |
| console.log('3οΈβ£ HTTP Response:'); | |
| console.log(' HTTP 200 OK'); | |
| console.log(' Content-Type: application/json'); | |
| console.log(' Body:'); | |
| console.log(' {'); | |
| console.log(' "recommendations": ['); | |
| console.log(' {'); | |
| console.log(' "path": "spec/controllers/users_controller_spec.rb",'); | |
| console.log(' "score": 1.5,'); | |
| console.log(' "reason": "Direct unit test for vulnerable controller"'); | |
| console.log(' }'); | |
| console.log(' ],'); | |
| console.log(' "fallback": {'); | |
| console.log(' "path": "spec/security/users_controller_security_spec.rb",'); | |
| console.log(' "reason": "Generated security test file"'); | |
| console.log(' }'); | |
| console.log(' }'); | |
| console.log(); | |
| console.log('4οΈβ£ Client receives:'); | |
| console.log(' result.recommendations[0].path β "spec/controllers/users_controller_spec.rb"'); | |
| console.log(' result.recommendations[0].score β 1.5'); | |
| console.log(' result.fallback.path β "spec/security/users_controller_security_spec.rb"'); | |
| }; | |
| demoCompleteFlow(); | |
| // ============================================================================= | |
| // DEMO 7: Environment Configuration | |
| // ============================================================================= | |
| console.log('\n\nπ DEMO 7: Environment Configuration'); | |
| console.log('-'.repeat(80)); | |
| console.log(); | |
| const demoEnvironmentConfig = () => { | |
| console.log('TestIntegrationClient supports multiple environments:'); | |
| console.log(); | |
| const configs = [ | |
| { | |
| scenario: 'Production (default)', | |
| code: 'new TestIntegrationClient(apiKey)', | |
| envVar: 'Not set', | |
| resolvedUrl: 'https://api.rsolv.dev' | |
| }, | |
| { | |
| scenario: 'Staging (via env)', | |
| code: 'new TestIntegrationClient(apiKey)', | |
| envVar: 'RSOLV_API_URL=https://api.rsolv-staging.com', | |
| resolvedUrl: 'https://api.rsolv-staging.com' | |
| }, | |
| { | |
| scenario: 'Local dev (explicit)', | |
| code: 'new TestIntegrationClient(apiKey, "http://localhost:4000")', | |
| envVar: 'Any value', | |
| resolvedUrl: 'http://localhost:4000' | |
| }, | |
| { | |
| scenario: 'CI/Testing (env)', | |
| code: 'new TestIntegrationClient(apiKey)', | |
| envVar: 'RSOLV_API_URL=https://api.rsolv.test', | |
| resolvedUrl: 'https://api.rsolv.test' | |
| } | |
| ]; | |
| for (const config of configs) { | |
| console.log(` ${config.scenario}:`); | |
| console.log(` Code: ${config.code}`); | |
| console.log(` Env Var: ${config.envVar}`); | |
| console.log(` URL: ${config.resolvedUrl}`); | |
| console.log(); | |
| } | |
| console.log('Priority:'); | |
| console.log(' 1. Explicit baseUrl parameter (highest)'); | |
| console.log(' 2. RSOLV_API_URL environment variable'); | |
| console.log(' 3. Default production URL (lowest)'); | |
| }; | |
| demoEnvironmentConfig(); | |
| // ============================================================================= | |
| // SUMMARY | |
| // ============================================================================= | |
| console.log('\n' + '='.repeat(80)); | |
| console.log('TEST INTEGRATION CLIENT DEMONSTRATION COMPLETE'); | |
| console.log('='.repeat(80)); | |
| console.log(); | |
| console.log('Key Features Demonstrated:'); | |
| console.log(); | |
| console.log('β Exponential Backoff:'); | |
| console.log(' β’ 100ms, 200ms, 400ms retry delays'); | |
| console.log(' β’ Prevents overwhelming server'); | |
| console.log(' β’ Industry-standard pattern'); | |
| console.log(); | |
| console.log('β Smart Retry Logic:'); | |
| console.log(' β’ Retries: 5xx errors, network timeouts'); | |
| console.log(' β’ No retry: 4xx client errors'); | |
| console.log(' β’ Max 3 retry attempts'); | |
| console.log(); | |
| console.log('β Authentication:'); | |
| console.log(' β’ x-api-key header (project convention)'); | |
| console.log(' β’ NOT Bearer token (different from GitHub API)'); | |
| console.log(); | |
| console.log('β Environment Support:'); | |
| console.log(' β’ Production, staging, local dev, CI'); | |
| console.log(' β’ RSOLV_API_URL environment variable'); | |
| console.log(' β’ Explicit baseUrl parameter'); | |
| console.log(); | |
| console.log('β Type Safety:'); | |
| console.log(' β’ Full TypeScript interfaces'); | |
| console.log(' β’ AnalyzeRequest/Response'); | |
| console.log(' β’ GenerateRequest/Response'); | |
| console.log(); | |
| console.log('='.repeat(80)); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * Simulation of Retry Flow with Mock LLM Responses | |
| * | |
| * This demonstrates the actual execution path through the retry loop | |
| * by simulating different scenarios with mock data. | |
| */ | |
| import type { Vulnerability, TestFileContext, AttemptHistory, TestFramework } from '../src/modes/types.js'; | |
| console.log('='.repeat(80)); | |
| console.log('RETRY FLOW SIMULATION'); | |
| console.log('Demonstrating actual execution paths through generateTestWithRetry()'); | |
| console.log('='.repeat(80)); | |
| console.log(); | |
| // ============================================================================= | |
| // Setup Mock Data | |
| // ============================================================================= | |
| const mockVulnerability: Vulnerability = { | |
| type: 'sql_injection', | |
| description: 'String interpolation in SQL WHERE clause (CWE-89)', | |
| location: 'app/controllers/users_controller.rb:42', | |
| attackVector: "5') OR admin = 't' --'", | |
| vulnerablePattern: 'User.where("id = \'#{params[:user][:id]}\'")', | |
| source: 'RailsGoat' | |
| }; | |
| const mockTargetFile: TestFileContext = { | |
| path: 'spec/controllers/users_controller_spec.rb', | |
| content: `describe UsersController do | |
| before do | |
| @user = User.create(name: 'testuser', admin: false) | |
| end | |
| it 'updates user' do | |
| patch :update, params: { user: { id: @user.id, name: 'newname' } } | |
| expect(response).to be_successful | |
| end | |
| end`, | |
| framework: 'rspec' | |
| }; | |
| const mockFramework: TestFramework = { | |
| name: 'rspec', | |
| syntaxCheckCommand: 'ruby -c', | |
| testCommand: 'bundle exec rspec' | |
| }; | |
| // ============================================================================= | |
| // SCENARIO 1: Success on First Attempt | |
| // ============================================================================= | |
| console.log('π SCENARIO 1: Success on First Attempt'); | |
| console.log('-'.repeat(80)); | |
| console.log(); | |
| const simulateScenario1 = () => { | |
| console.log('Starting generateTestWithRetry()...'); | |
| console.log(` Vulnerability: ${mockVulnerability.type}`); | |
| console.log(` Target: ${mockTargetFile.path}`); | |
| console.log(` Max attempts: 3`); | |
| console.log(); | |
| const previousAttempts: AttemptHistory[] = []; | |
| let attempt = 1; | |
| console.log(`[Attempt ${attempt}/3]`); | |
| console.log(' Step 1: Generate test with LLM'); | |
| console.log(' β Prompt includes:'); | |
| console.log(' β’ Vulnerability: sql_injection'); | |
| console.log(' β’ Attack vector: 5\') OR admin = \'t\' --\''); | |
| console.log(' β’ Target file content (for context)'); | |
| console.log(' β’ Real-world RailsGoat example'); | |
| console.log(' β’ No previous attempts (first try)'); | |
| console.log(); | |
| const mockTestCode = `it 'rejects SQL injection in user update (CWE-89)' do | |
| # Attack: SQL injection via user ID parameter | |
| patch :update, params: { | |
| user: { | |
| id: "5') OR admin = 't' --'", | |
| name: 'attacker' | |
| } | |
| } | |
| expect(response.status).to eq(400) | |
| expect(User.find(5).admin).to be_falsey | |
| end`; | |
| console.log(' Step 2: Write to temp file'); | |
| console.log(` β File: .rsolv/temp/test_${Date.now()}.rb`); | |
| console.log(' β Content:'); | |
| console.log(' ' + mockTestCode.split('\n').slice(0, 3).join('\n ')); | |
| console.log(' ...'); | |
| console.log(); | |
| console.log(' Step 3: Validate syntax'); | |
| console.log(' β Command: ruby -c test_1234.rb'); | |
| console.log(' β Result: β Syntax OK'); | |
| console.log(); | |
| console.log(' Step 4: Run test'); | |
| console.log(' β Command: bundle exec rspec test_1234.rb'); | |
| console.log(' β Result: β Test FAILED (expected - proves vulnerability!)'); | |
| console.log(' β Output: 1 example, 1 failure'); | |
| console.log(); | |
| console.log(' Step 5: Check regressions'); | |
| console.log(' β Only 1 failure detected (the new test)'); | |
| console.log(' β Result: β No regressions'); | |
| console.log(); | |
| console.log('β SUCCESS on attempt 1!'); | |
| console.log(); | |
| console.log('Return TestSuite:'); | |
| console.log(JSON.stringify({ | |
| framework: 'rspec', | |
| testFile: 'spec/controllers/users_controller_spec.rb', | |
| redTests: [{ | |
| testName: 'rejects SQL injection in user update (CWE-89)', | |
| testCode: mockTestCode.substring(0, 50) + '...', | |
| attackVector: "5') OR admin = 't' --'", | |
| expectedBehavior: 'should_fail_on_vulnerable_code' | |
| }] | |
| }, null, 2)); | |
| }; | |
| simulateScenario1(); | |
| // ============================================================================= | |
| // SCENARIO 2: Syntax Error on First Attempt, Success on Second | |
| // ============================================================================= | |
| console.log('\n\nπ SCENARIO 2: Syntax Error β Retry β Success'); | |
| console.log('-'.repeat(80)); | |
| console.log(); | |
| const simulateScenario2 = () => { | |
| const previousAttempts: AttemptHistory[] = []; | |
| // Attempt 1 | |
| console.log('[Attempt 1/3]'); | |
| console.log(' Step 1: Generate test with LLM'); | |
| console.log(' β Generated test code (with syntax error)'); | |
| console.log(); | |
| const badTestCode = `it 'rejects SQL injection' do | |
| patch :update, params: { user: { id: "5') OR admin = 't' --'" } } | |
| expect(response.status).to eq(400) | |
| # Missing 'end' keyword!`; | |
| console.log(' Step 2: Write to temp file'); | |
| console.log(` β File: .rsolv/temp/test_1234.rb`); | |
| console.log(); | |
| console.log(' Step 3: Validate syntax'); | |
| console.log(' β Command: ruby -c test_1234.rb'); | |
| console.log(' β Result: β SyntaxError'); | |
| console.log(' β Error: "unexpected end-of-input, expecting keyword_end"'); | |
| console.log(); | |
| previousAttempts.push({ | |
| attempt: 1, | |
| error: 'SyntaxError', | |
| errorMessage: 'unexpected end-of-input, expecting keyword_end', | |
| timestamp: new Date().toISOString() | |
| }); | |
| console.log(' β οΈ Syntax error detected'); | |
| console.log(' β Recording attempt in history'); | |
| console.log(' β CONTINUE to attempt 2'); | |
| console.log(); | |
| console.log('-'.repeat(40)); | |
| console.log(); | |
| // Attempt 2 | |
| console.log('[Attempt 2/3]'); | |
| console.log(' Step 1: Generate test with LLM (with error feedback)'); | |
| console.log(' β Prompt NOW includes:'); | |
| console.log(' β’ All previous content'); | |
| console.log(' β’ PREVIOUS ATTEMPTS section:'); | |
| console.log(' - Attempt 1: SyntaxError - unexpected end-of-input, expecting keyword_end'); | |
| console.log(' β’ IMPORTANT: Fix the syntax error. Ensure valid rspec syntax.'); | |
| console.log(); | |
| const fixedTestCode = `it 'rejects SQL injection' do | |
| patch :update, params: { user: { id: "5') OR admin = 't' --'" } } | |
| expect(response.status).to eq(400) | |
| end`; | |
| console.log(' Step 2: Write to temp file'); | |
| console.log(` β File: .rsolv/temp/test_1235.rb`); | |
| console.log(' β LLM fixed the missing end keyword!'); | |
| console.log(); | |
| console.log(' Step 3: Validate syntax'); | |
| console.log(' β Command: ruby -c test_1235.rb'); | |
| console.log(' β Result: β Syntax OK'); | |
| console.log(); | |
| console.log(' Step 4: Run test'); | |
| console.log(' β Command: bundle exec rspec test_1235.rb'); | |
| console.log(' β Result: β Test FAILED (good!)'); | |
| console.log(); | |
| console.log(' Step 5: Check regressions'); | |
| console.log(' β Result: β No regressions'); | |
| console.log(); | |
| console.log('β SUCCESS on attempt 2!'); | |
| console.log(); | |
| console.log('Attempt history for debugging:'); | |
| console.log(JSON.stringify(previousAttempts, null, 2)); | |
| }; | |
| simulateScenario2(); | |
| // ============================================================================= | |
| // SCENARIO 3: Test Passed Unexpectedly β Retry with Stronger Test | |
| // ============================================================================= | |
| console.log('\n\nπ SCENARIO 3: Test Passed Unexpectedly β Retry'); | |
| console.log('-'.repeat(80)); | |
| console.log(); | |
| const simulateScenario3 = () => { | |
| const previousAttempts: AttemptHistory[] = []; | |
| // Attempt 1 | |
| console.log('[Attempt 1/3]'); | |
| console.log(' Steps 1-3: Generate, write, validate syntax β β OK'); | |
| console.log(); | |
| console.log(' Step 4: Run test'); | |
| console.log(' β Command: bundle exec rspec test_1234.rb'); | |
| console.log(' β Result: β Test PASSED'); | |
| console.log(' β Output: 1 example, 0 failures'); | |
| console.log(); | |
| console.log(' β οΈ Problem: Test PASSED when it should FAIL!'); | |
| console.log(' β This means the test did NOT detect the vulnerability'); | |
| console.log(' β Test is too weak or checks wrong thing'); | |
| console.log(); | |
| previousAttempts.push({ | |
| attempt: 1, | |
| error: 'TestPassedUnexpectedly', | |
| errorMessage: 'Test passed when it should fail to demonstrate vulnerability', | |
| timestamp: new Date().toISOString() | |
| }); | |
| console.log(' β Recording attempt in history'); | |
| console.log(' β CONTINUE to attempt 2'); | |
| console.log(); | |
| console.log('-'.repeat(40)); | |
| console.log(); | |
| // Attempt 2 | |
| console.log('[Attempt 2/3]'); | |
| console.log(' Step 1: Generate test with LLM (with error feedback)'); | |
| console.log(' β Prompt NOW includes:'); | |
| console.log(' β’ PREVIOUS ATTEMPTS section:'); | |
| console.log(' - Attempt 1: TestPassedUnexpectedly - Test passed when should fail'); | |
| console.log(' β’ IMPORTANT: Make the test MORE AGGRESSIVE. It must FAIL on vulnerable code.'); | |
| console.log(); | |
| console.log(' LLM adjusts strategy:'); | |
| console.log(' β Original test: Checked if response was successful'); | |
| console.log(' β New test: Actually executes SQL injection AND checks admin flag'); | |
| console.log(); | |
| console.log(' Steps 2-3: Write to file, validate syntax β β OK'); | |
| console.log(); | |
| console.log(' Step 4: Run test'); | |
| console.log(' β Command: bundle exec rspec test_1235.rb'); | |
| console.log(' β Result: β Test FAILED (good!)'); | |
| console.log(' β The more aggressive test detected the vulnerability!'); | |
| console.log(); | |
| console.log('β SUCCESS on attempt 2!'); | |
| console.log(); | |
| console.log('Key insight: Error feedback helps LLM understand what went wrong'); | |
| }; | |
| simulateScenario3(); | |
| // ============================================================================= | |
| // SCENARIO 4: All Retries Exhausted β Tag Issue | |
| // ============================================================================= | |
| console.log('\n\nπ SCENARIO 4: All Retries Exhausted β Tag Issue'); | |
| console.log('-'.repeat(80)); | |
| console.log(); | |
| const simulateScenario4 = () => { | |
| const previousAttempts: AttemptHistory[] = []; | |
| console.log('[Attempt 1/3]'); | |
| console.log(' β SyntaxError: unexpected token'); | |
| previousAttempts.push({ | |
| attempt: 1, | |
| error: 'SyntaxError', | |
| errorMessage: 'unexpected token', | |
| timestamp: new Date().toISOString() | |
| }); | |
| console.log(); | |
| console.log('[Attempt 2/3]'); | |
| console.log(' β SyntaxError: unexpected end-of-input (different error!)'); | |
| previousAttempts.push({ | |
| attempt: 2, | |
| error: 'SyntaxError', | |
| errorMessage: 'unexpected end-of-input', | |
| timestamp: new Date().toISOString() | |
| }); | |
| console.log(); | |
| console.log('[Attempt 3/3]'); | |
| console.log(' β TestPassedUnexpectedly: Test passed when should fail'); | |
| previousAttempts.push({ | |
| attempt: 3, | |
| error: 'TestPassedUnexpectedly', | |
| errorMessage: 'Test passed when it should fail to demonstrate vulnerability', | |
| timestamp: new Date().toISOString() | |
| }); | |
| console.log(); | |
| console.log('β All retries exhausted!'); | |
| console.log(); | |
| console.log('Calling tagIssueNotValidated():'); | |
| console.log(' β Would add "not-validated" label to issue'); | |
| console.log(' β Would add comment with attempt history:'); | |
| console.log(); | |
| console.log(' β οΈ Unable to Generate Valid Test'); | |
| console.log(' '); | |
| console.log(' After 3 attempts, we could not generate a valid RED test for this vulnerability.'); | |
| console.log(' '); | |
| console.log(' **Vulnerability Details:**'); | |
| console.log(' - Type: sql_injection'); | |
| console.log(' - Location: app/controllers/users_controller.rb:42'); | |
| console.log(' '); | |
| console.log(' **Attempt History:**'); | |
| console.log(' 1. Attempt 1: SyntaxError - unexpected token'); | |
| console.log(' 2. Attempt 2: SyntaxError - unexpected end-of-input'); | |
| console.log(' 3. Attempt 3: TestPassedUnexpectedly - Test passed when should fail'); | |
| console.log(' '); | |
| console.log(' **Next Steps:**'); | |
| console.log(' - Manual review recommended'); | |
| console.log(' - May require custom test generation'); | |
| console.log(' - Vulnerability may be too complex for automated testing'); | |
| console.log(); | |
| console.log('Return: null (no valid TestSuite)'); | |
| console.log(); | |
| console.log('Caller (commitTestsToBranch) would:'); | |
| console.log(' β Skip AST integration'); | |
| console.log(' β Skip commit'); | |
| console.log(' β Log failure'); | |
| console.log(' β Continue with next vulnerability'); | |
| }; | |
| simulateScenario4(); | |
| // ============================================================================= | |
| // SCENARIO 5: Regression Detection | |
| // ============================================================================= | |
| console.log('\n\nπ SCENARIO 5: Regression Detection β Retry'); | |
| console.log('-'.repeat(80)); | |
| console.log(); | |
| const simulateScenario5 = () => { | |
| console.log('[Attempt 1/3]'); | |
| console.log(' Steps 1-4: Generate, write, validate, run test β β Test failed (good!)'); | |
| console.log(); | |
| console.log(' Step 5: Check regressions'); | |
| console.log(' β Detected multiple test failures:'); | |
| console.log(' 1. NEW test failed (expected)'); | |
| console.log(' 2. Existing test "updates user" also failed (REGRESSION!)'); | |
| console.log(); | |
| console.log(' β οΈ Problem: New test broke existing tests!'); | |
| console.log(' β Likely modified shared state (database, globals, etc.)'); | |
| console.log(' β Or conflicting setup/teardown'); | |
| console.log(); | |
| const previousAttempts: AttemptHistory[] = [{ | |
| attempt: 1, | |
| error: 'ExistingTestsRegression', | |
| errorMessage: 'Existing tests failed: updates user', | |
| timestamp: new Date().toISOString() | |
| }]; | |
| console.log(' β Recording regression in history'); | |
| console.log(' β CONTINUE to attempt 2'); | |
| console.log(); | |
| console.log('-'.repeat(40)); | |
| console.log(); | |
| console.log('[Attempt 2/3]'); | |
| console.log(' Step 1: Generate test with LLM (with error feedback)'); | |
| console.log(' β Prompt NOW includes:'); | |
| console.log(' β’ PREVIOUS ATTEMPTS:'); | |
| console.log(' - Attempt 1: ExistingTestsRegression - Existing tests failed: updates user'); | |
| console.log(' β’ IMPORTANT: Don\'t break existing tests. Avoid modifying shared state.'); | |
| console.log(); | |
| console.log(' LLM adjusts strategy:'); | |
| console.log(' β Original: Modified @user directly (broke existing test setup)'); | |
| console.log(' β New: Creates separate test user, doesn\'t touch @user'); | |
| console.log(); | |
| console.log(' Steps 2-5: Write, validate, run, check regressions β β All OK'); | |
| console.log(); | |
| console.log('β SUCCESS on attempt 2!'); | |
| }; | |
| simulateScenario5(); | |
| // ============================================================================= | |
| // SUMMARY | |
| // ============================================================================= | |
| console.log('\n\n' + '='.repeat(80)); | |
| console.log('RETRY FLOW SIMULATION COMPLETE'); | |
| console.log('='.repeat(80)); | |
| console.log(); | |
| console.log('Key Takeaways:'); | |
| console.log(); | |
| console.log('1. Error Feedback Loop Works:'); | |
| console.log(' β’ LLM receives specific error messages from previous attempts'); | |
| console.log(' β’ Guidance is error-type specific (syntax vs. test behavior vs. regression)'); | |
| console.log(' β’ Each retry has more context to improve the test'); | |
| console.log(); | |
| console.log('2. Multiple Error Types Handled:'); | |
| console.log(' β’ SyntaxError β Fix syntax'); | |
| console.log(' β’ TestPassedUnexpectedly β Make test more aggressive'); | |
| console.log(' β’ ExistingTestsRegression β Don\'t break existing tests'); | |
| console.log(' β’ TestExecutionError β General execution failures'); | |
| console.log(); | |
| console.log('3. Graceful Degradation:'); | |
| console.log(' β’ After 3 attempts, issue is tagged "not-validated"'); | |
| console.log(' β’ Detailed comment added with attempt history'); | |
| console.log(' β’ Returns null to signal failure'); | |
| console.log(' β’ Caller can skip this vulnerability and continue'); | |
| console.log(); | |
| console.log('4. Success Cases:'); | |
| console.log(' β’ Can succeed on first attempt (ideal case)'); | |
| console.log(' β’ Can recover from errors on retry (common case)'); | |
| console.log(' β’ Test must FAIL on vulnerable code (RED test requirement)'); | |
| console.log(' β’ No regressions allowed (existing tests must pass)'); | |
| console.log(); | |
| console.log('='.repeat(80)); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * Demonstration of Phase 2 Test Integration Implementation | |
| * | |
| * This script demonstrates the key features of the test generation retry loop: | |
| * 1. TestIntegrationClient with retry logic | |
| * 2. ValidationMode.generateTestWithRetry() with LLM feedback | |
| * 3. Syntax validation and test execution | |
| * 4. Error feedback loop | |
| */ | |
| import { TestIntegrationClient } from '../src/modes/test-integration-client.js'; | |
| import { ValidationMode } from '../src/modes/validation-mode.js'; | |
| import type { ActionConfig } from '../src/types/index.js'; | |
| import type { Vulnerability, TestFileContext } from '../src/modes/types.js'; | |
| console.log('='.repeat(80)); | |
| console.log('PHASE 2 TEST INTEGRATION DEMONSTRATION'); | |
| console.log('RFC-060-AMENDMENT-001: Test Generation with Retry Loop'); | |
| console.log('='.repeat(80)); | |
| console.log(); | |
| // ============================================================================= | |
| // DEMO 1: TestIntegrationClient - API Communication with Retry Logic | |
| // ============================================================================= | |
| console.log('π DEMO 1: TestIntegrationClient - Backend API Client'); | |
| console.log('-'.repeat(80)); | |
| const demoTestIntegrationClient = () => { | |
| console.log('\n1οΈβ£ Creating TestIntegrationClient instance...'); | |
| const client = new TestIntegrationClient('demo-api-key', 'https://api.rsolv.test'); | |
| console.log(' β Client created with API key authentication'); | |
| console.log(' β Base URL: https://api.rsolv.test'); | |
| console.log(' β Uses x-api-key header (project convention)'); | |
| console.log('\n2οΈβ£ Client Configuration Features:'); | |
| console.log(' β’ Exponential backoff: 100ms, 200ms, 400ms'); | |
| console.log(' β’ Max retries: 3 attempts'); | |
| console.log(' β’ Retry on: 5xx errors, network timeouts'); | |
| console.log(' β’ No retry on: 4xx client errors'); | |
| console.log(' β’ Environment variable support: RSOLV_API_URL'); | |
| console.log('\n3οΈβ£ API Methods Available:'); | |
| console.log(' β’ analyze(request) - Score test files for integration'); | |
| console.log(' β’ generate(request) - Generate AST-based integration'); | |
| console.log('\n Example analyze() request:'); | |
| const analyzeRequest = { | |
| vulnerableFile: 'app/controllers/users_controller.rb', | |
| vulnerabilityType: 'sql_injection', | |
| candidateTestFiles: ['spec/controllers/users_controller_spec.rb'], | |
| framework: 'rspec' | |
| }; | |
| console.log(' ', JSON.stringify(analyzeRequest, null, 2).split('\n').join('\n ')); | |
| console.log('\n Example generate() request:'); | |
| const generateRequest = { | |
| targetFileContent: 'describe UsersController do\n # existing tests\nend', | |
| testSuite: { | |
| redTests: [{ | |
| testName: 'rejects SQL injection', | |
| testCode: 'expect(response).to have_http_status(400)', | |
| attackVector: "5') OR admin = 't' --'", | |
| expectedBehavior: 'should_fail_on_vulnerable_code' | |
| }] | |
| }, | |
| framework: 'rspec', | |
| language: 'ruby' | |
| }; | |
| console.log(' ', JSON.stringify(generateRequest, null, 2).split('\n').slice(0, 8).join('\n ')); | |
| console.log(' ...'); | |
| return client; | |
| }; | |
| const client = demoTestIntegrationClient(); | |
| // ============================================================================= | |
| // DEMO 2: Framework Detection | |
| // ============================================================================= | |
| console.log('\n\nπ DEMO 2: Framework Detection from File Paths'); | |
| console.log('-'.repeat(80)); | |
| const demoFrameworkDetection = () => { | |
| const mockConfig: ActionConfig = { | |
| apiKey: 'demo-key', | |
| githubToken: 'demo-token', | |
| mode: 'validate', | |
| aiProvider: { | |
| apiKey: 'demo-ai-key', | |
| model: 'claude-sonnet-4-5-20250929', | |
| provider: 'anthropic' | |
| } | |
| } as ActionConfig; | |
| const validationMode = new ValidationMode(mockConfig, '/tmp/demo-repo'); | |
| const testPaths = [ | |
| 'spec/controllers/users_controller_spec.rb', | |
| 'test/models/user_test.py', | |
| 'src/components/Button.test.tsx', | |
| 'src/services/api.spec.ts', | |
| 'tests/Feature/UserTest.php', | |
| 'src/test/java/com/example/UserTest.java', | |
| ]; | |
| console.log('\nDetecting frameworks from test file paths:\n'); | |
| for (const testPath of testPaths) { | |
| // Call private method via type assertion for demo | |
| const framework = (validationMode as any).detectFrameworkFromPath(testPath); | |
| console.log(` ${testPath}`); | |
| console.log(` β Framework: ${framework.name}`); | |
| console.log(` β Syntax check: ${framework.syntaxCheckCommand}`); | |
| console.log(` β Test command: ${framework.testCommand}`); | |
| console.log(); | |
| } | |
| return validationMode; | |
| }; | |
| const validationMode = demoFrameworkDetection(); | |
| // ============================================================================= | |
| // DEMO 3: Realistic Vulnerability Examples | |
| // ============================================================================= | |
| console.log('\nπ DEMO 3: Realistic Vulnerability Examples (from Phase 0)'); | |
| console.log('-'.repeat(80)); | |
| const demoVulnerabilityExamples = () => { | |
| const vulnerabilityTypes = [ | |
| 'sql_injection', | |
| 'nosql_injection', | |
| 'xss', | |
| 'command_injection', | |
| 'path_traversal' | |
| ]; | |
| console.log('\nVulnerability examples used in LLM prompts:\n'); | |
| for (const vulnType of vulnerabilityTypes) { | |
| const example = (validationMode as any).getRealisticVulnerabilityExample(vulnType); | |
| console.log(`π΄ ${vulnType.toUpperCase().replace('_', ' ')}`); | |
| console.log(' ' + example.split('\n').join('\n ')); | |
| console.log(); | |
| } | |
| console.log('These examples come from REALISTIC-VULNERABILITY-EXAMPLES.md:'); | |
| console.log(' β’ Source: NodeGoat, RailsGoat (OWASP projects)'); | |
| console.log(' β’ Real attack vectors from production exploits'); | |
| console.log(' β’ CWE classifications for compliance'); | |
| }; | |
| demoVulnerabilityExamples(); | |
| // ============================================================================= | |
| // DEMO 4: LLM Prompt Building with Retry Feedback | |
| // ============================================================================= | |
| console.log('\n\nπ DEMO 4: LLM Prompt Building with Retry Feedback'); | |
| console.log('-'.repeat(80)); | |
| const demoPromptBuilding = () => { | |
| const vulnerability: Vulnerability = { | |
| type: 'sql_injection', | |
| description: 'String interpolation in SQL WHERE clause (CWE-89)', | |
| location: 'app/controllers/users_controller.rb:42', | |
| attackVector: "5') OR admin = 't' --'", | |
| vulnerablePattern: 'User.where("id = \'#{params[:user][:id]}\'")', | |
| source: 'RailsGoat' | |
| }; | |
| const targetTestFile: TestFileContext = { | |
| path: 'spec/controllers/users_controller_spec.rb', | |
| content: `describe UsersController do | |
| before do | |
| @user = User.create(name: 'testuser', admin: false) | |
| end | |
| it 'updates user' do | |
| patch :update, params: { user: { id: @user.id, name: 'newname' } } | |
| expect(response).to be_successful | |
| end | |
| end`, | |
| framework: 'rspec' | |
| }; | |
| const framework = (validationMode as any).detectFrameworkFromPath(targetTestFile.path); | |
| console.log('\n1οΈβ£ Initial prompt (Attempt 1 - no previous errors):\n'); | |
| const initialPrompt = (validationMode as any).buildLLMPrompt( | |
| vulnerability, | |
| targetTestFile, | |
| [], | |
| framework | |
| ); | |
| console.log(' ' + initialPrompt.split('\n').slice(0, 25).join('\n ')); | |
| console.log(' ...'); | |
| console.log(`\n Total length: ${initialPrompt.length} characters`); | |
| console.log('\n2οΈβ£ Retry prompt after syntax error (Attempt 2):\n'); | |
| const attemptWithSyntaxError = [{ | |
| attempt: 1, | |
| error: 'SyntaxError' as const, | |
| errorMessage: 'unexpected end-of-input, expecting keyword_end', | |
| timestamp: new Date().toISOString() | |
| }]; | |
| const retryPrompt = (validationMode as any).buildLLMPrompt( | |
| vulnerability, | |
| targetTestFile, | |
| attemptWithSyntaxError, | |
| framework | |
| ); | |
| // Show the retry feedback section | |
| const retrySection = retryPrompt.split('PREVIOUS ATTEMPTS')[1]; | |
| if (retrySection) { | |
| console.log(' PREVIOUS ATTEMPTS' + retrySection.split('\n').slice(0, 5).join('\n ')); | |
| } | |
| console.log('\n3οΈβ£ Retry prompt after test passed unexpectedly (Attempt 3):\n'); | |
| const attemptWithTestPassed = [ | |
| ...attemptWithSyntaxError, | |
| { | |
| attempt: 2, | |
| error: 'TestPassedUnexpectedly' as const, | |
| errorMessage: 'Test passed when it should fail to demonstrate vulnerability', | |
| timestamp: new Date().toISOString() | |
| } | |
| ]; | |
| const retryPrompt2 = (validationMode as any).buildLLMPrompt( | |
| vulnerability, | |
| targetTestFile, | |
| attemptWithTestPassed, | |
| framework | |
| ); | |
| const retrySection2 = retryPrompt2.split('PREVIOUS ATTEMPTS')[1]; | |
| if (retrySection2) { | |
| console.log(' PREVIOUS ATTEMPTS' + retrySection2.split('\n').slice(0, 8).join('\n ')); | |
| } | |
| console.log('\n4οΈβ£ Key prompt features:'); | |
| console.log(' β Vulnerability details (type, location, attack vector)'); | |
| console.log(' β Real-world example from NodeGoat/RailsGoat'); | |
| console.log(' β Target file content (so LLM sees existing setup blocks)'); | |
| console.log(' β Framework-specific conventions'); | |
| console.log(' β Previous attempt errors with specific guidance'); | |
| console.log(' β Error-specific instructions (syntax, test passed, regression)'); | |
| }; | |
| demoPromptBuilding(); | |
| // ============================================================================= | |
| // DEMO 5: Retry Loop Logic Flow | |
| // ============================================================================= | |
| console.log('\n\nπ DEMO 5: Retry Loop Logic Flow'); | |
| console.log('-'.repeat(80)); | |
| const demoRetryLogic = () => { | |
| console.log('\nRetry loop implementation (generateTestWithRetry):'); | |
| console.log(); | |
| console.log(' for (attempt = 1; attempt <= 3; attempt++) {'); | |
| console.log(' '); | |
| console.log(' // Step 1: Generate test with LLM'); | |
| console.log(' testSuite = await generateTestWithLLM(vulnerability, targetFile, previousAttempts)'); | |
| console.log(' '); | |
| console.log(' // Step 2: Write to temp file'); | |
| console.log(' fs.writeFileSync(tempFile, testSuite.redTests[0].testCode)'); | |
| console.log(' '); | |
| console.log(' // Step 3: Validate syntax'); | |
| console.log(' try {'); | |
| console.log(' await validateSyntax(tempFile, framework)'); | |
| console.log(' β Syntax OK'); | |
| console.log(' } catch (syntaxError) {'); | |
| console.log(' β Syntax error β Record attempt β CONTINUE to next attempt'); | |
| console.log(' }'); | |
| console.log(' '); | |
| console.log(' // Step 4: Run test (must FAIL on vulnerable code)'); | |
| console.log(' testResult = await runTest(tempFile, framework)'); | |
| console.log(' '); | |
| console.log(' if (testResult.passed) {'); | |
| console.log(' β Test passed unexpectedly β Record attempt β CONTINUE'); | |
| console.log(' }'); | |
| console.log(' '); | |
| console.log(' // Step 5: Check for regressions'); | |
| console.log(' if (testResult.existingTestsFailed) {'); | |
| console.log(' β Existing tests failed β Record attempt β CONTINUE'); | |
| console.log(' }'); | |
| console.log(' '); | |
| console.log(' // Success!'); | |
| console.log(' β Return testSuite'); | |
| console.log(' }'); | |
| console.log(' '); | |
| console.log(' // All retries exhausted'); | |
| console.log(' await tagIssueNotValidated(vulnerability, previousAttempts)'); | |
| console.log(' return null'); | |
| console.log('\n\nError handling by type:\n'); | |
| const errorTypes = [ | |
| { | |
| type: 'SyntaxError', | |
| action: 'Continue to next attempt', | |
| feedback: 'Fix the syntax error. Ensure valid [framework] syntax.' | |
| }, | |
| { | |
| type: 'TestPassedUnexpectedly', | |
| action: 'Continue to next attempt', | |
| feedback: 'Make the test MORE AGGRESSIVE. It must FAIL on vulnerable code.' | |
| }, | |
| { | |
| type: 'ExistingTestsRegression', | |
| action: 'Continue to next attempt', | |
| feedback: 'Don\'t break existing tests. Avoid modifying shared state.' | |
| }, | |
| { | |
| type: 'TestExecutionError', | |
| action: 'Continue to next attempt', | |
| feedback: 'Test execution failed with error details' | |
| } | |
| ]; | |
| for (const error of errorTypes) { | |
| console.log(` π΄ ${error.type}`); | |
| console.log(` Action: ${error.action}`); | |
| console.log(` Feedback to LLM: "${error.feedback}"`); | |
| console.log(); | |
| } | |
| }; | |
| demoRetryLogic(); | |
| // ============================================================================= | |
| // DEMO 6: Language Extension Mapping | |
| // ============================================================================= | |
| console.log('\n\nπ DEMO 6: Language Extension Mapping'); | |
| console.log('-'.repeat(80)); | |
| const demoLanguageExtensions = () => { | |
| const frameworks = [ | |
| 'rspec', 'minitest', 'pytest', 'phpunit', 'pest', | |
| 'jest', 'vitest', 'mocha', 'junit5', 'testng', 'exunit' | |
| ]; | |
| console.log('\nFramework β File Extension Mapping:\n'); | |
| for (const framework of frameworks) { | |
| const ext = (validationMode as any).getLanguageExtension(framework); | |
| console.log(` ${framework.padEnd(12)} β ${ext}`); | |
| } | |
| }; | |
| demoLanguageExtensions(); | |
| // ============================================================================= | |
| // DEMO 7: Type Safety | |
| // ============================================================================= | |
| console.log('\n\nπ DEMO 7: TypeScript Type Safety'); | |
| console.log('-'.repeat(80)); | |
| const demoTypeSafety = () => { | |
| console.log('\nNew types added to src/modes/types.ts:\n'); | |
| const types = [ | |
| { | |
| name: 'Vulnerability', | |
| fields: ['type', 'description', 'location', 'attackVector', 'vulnerablePattern?', 'source?'], | |
| purpose: 'Vulnerability information for test generation' | |
| }, | |
| { | |
| name: 'TestFileContext', | |
| fields: ['path', 'content', 'framework'], | |
| purpose: 'Target test file with content for LLM context' | |
| }, | |
| { | |
| name: 'TestSuite', | |
| fields: ['framework', 'testFile', 'redTests[]'], | |
| purpose: 'Generated test suite structure' | |
| }, | |
| { | |
| name: 'AttemptHistory', | |
| fields: ['attempt', 'error', 'errorMessage', 'timestamp'], | |
| purpose: 'Retry loop history tracking' | |
| }, | |
| { | |
| name: 'TestFramework', | |
| fields: ['name', 'version?', 'testCommand?', 'syntaxCheckCommand?'], | |
| purpose: 'Framework detection metadata' | |
| } | |
| ]; | |
| for (const type of types) { | |
| console.log(` interface ${type.name} {`); | |
| for (const field of type.fields) { | |
| console.log(` ${field}`); | |
| } | |
| console.log(` }`); | |
| console.log(` β ${type.purpose}`); | |
| console.log(); | |
| } | |
| console.log('Benefits:'); | |
| console.log(' β Full TypeScript type checking'); | |
| console.log(' β IntelliSense support in IDEs'); | |
| console.log(' β Compile-time error detection'); | |
| console.log(' β Self-documenting code'); | |
| }; | |
| demoTypeSafety(); | |
| // ============================================================================= | |
| // DEMO 8: Integration with Existing Code | |
| // ============================================================================= | |
| console.log('\n\nπ DEMO 8: Integration with Existing ValidationMode'); | |
| console.log('-'.repeat(80)); | |
| const demoIntegration = () => { | |
| console.log('\nNew ValidationMode capabilities:\n'); | |
| console.log('1οΈβ£ New method: generateTestWithRetry()'); | |
| console.log(' β’ Takes: Vulnerability, TestFileContext, maxAttempts'); | |
| console.log(' β’ Returns: TestSuite | null'); | |
| console.log(' β’ Used by: commitTestsToBranch() (future enhancement)'); | |
| console.log(); | |
| console.log('2οΈβ£ TestIntegrationClient initialization:'); | |
| console.log(' β’ Created in constructor alongside PhaseDataClient'); | |
| console.log(' β’ Uses same rsolvApiKey from config'); | |
| console.log(' β’ Available as private property for future use'); | |
| console.log(); | |
| console.log('3οΈβ£ Helper methods added:'); | |
| console.log(' β’ validateSyntax() - Framework-specific syntax checking'); | |
| console.log(' β’ runTest() - Test execution with pass/fail detection'); | |
| console.log(' β’ scanTestFiles() - Repository test file discovery'); | |
| console.log(' β’ detectFrameworkFromPath() - Auto-detect test framework'); | |
| console.log(' β’ buildLLMPrompt() - Construct prompts with retry feedback'); | |
| console.log(' β’ getRealisticVulnerabilityExample() - Phase 0 examples'); | |
| console.log(); | |
| console.log('4οΈβ£ Ready for commitTestsToBranch() enhancement:'); | |
| console.log(' β’ All pieces in place for full workflow'); | |
| console.log(' β’ Can be called with: vulnerability + target file'); | |
| console.log(' β’ Returns validated TestSuite or null'); | |
| }; | |
| demoIntegration(); | |
| // ============================================================================= | |
| // DEMO 9: Complete Workflow Example | |
| // ============================================================================= | |
| console.log('\n\nπ DEMO 9: Complete Workflow Example'); | |
| console.log('-'.repeat(80)); | |
| const demoCompleteWorkflow = () => { | |
| console.log('\nExample workflow for SQL Injection vulnerability:\n'); | |
| console.log('ββ Issue #123: SQL Injection in users_controller.rb'); | |
| console.log('β'); | |
| console.log('ββ 1. ValidationMode.validateVulnerability(issue)'); | |
| console.log('β ββ Calls generateTestWithRetry()'); | |
| console.log('β'); | |
| console.log('ββ 2. generateTestWithRetry(vulnerability, targetTestFile)'); | |
| console.log('β β'); | |
| console.log('β ββ Attempt 1:'); | |
| console.log('β β ββ LLM generates test with SQL injection attack vector'); | |
| console.log('β β ββ Write to temp file: /tmp/.rsolv/temp/test_1234.rb'); | |
| console.log('β β ββ Validate syntax: ruby -c test_1234.rb'); | |
| console.log('β β β ββ β SyntaxError: "unexpected end"'); | |
| console.log('β β ββ Record error β Continue'); | |
| console.log('β β'); | |
| console.log('β ββ Attempt 2:'); | |
| console.log('β β ββ LLM generates test WITH previous error feedback'); | |
| console.log('β β ββ Write to temp file: /tmp/.rsolv/temp/test_1235.rb'); | |
| console.log('β β ββ Validate syntax: ruby -c test_1235.rb'); | |
| console.log('β β β ββ β Syntax OK'); | |
| console.log('β β ββ Run test: bundle exec rspec test_1235.rb'); | |
| console.log('β β β ββ β Test FAILED (good! proves vulnerability)'); | |
| console.log('β β ββ β SUCCESS - Return TestSuite'); | |
| console.log('β β'); | |
| console.log('β ββ TestSuite {'); | |
| console.log('β framework: "rspec",'); | |
| console.log('β testFile: "spec/controllers/users_controller_spec.rb",'); | |
| console.log('β redTests: [{'); | |
| console.log('β testName: "rejects SQL injection in user update (CWE-89)",'); | |
| console.log('β testCode: "...",'); | |
| console.log('β attackVector: "5\') OR admin = \'t\' --\'",'); | |
| console.log('β expectedBehavior: "should_fail_on_vulnerable_code"'); | |
| console.log('β }]'); | |
| console.log('β }'); | |
| console.log('β'); | |
| console.log('ββ 3. Backend AST Integration (future)'); | |
| console.log('β ββ testIntegrationClient.analyze(testFiles)'); | |
| console.log('β ββ testIntegrationClient.generate(testSuite)'); | |
| console.log('β ββ Write integrated file'); | |
| console.log('β'); | |
| console.log('ββ 4. Commit and push to validation branch'); | |
| console.log(' ββ Branch: rsolv/validate/issue-123'); | |
| console.log(); | |
| }; | |
| demoCompleteWorkflow(); | |
| // ============================================================================= | |
| // SUMMARY | |
| // ============================================================================= | |
| console.log('\n' + '='.repeat(80)); | |
| console.log('DEMONSTRATION COMPLETE'); | |
| console.log('='.repeat(80)); | |
| console.log(); | |
| console.log('β TestIntegrationClient - Backend API client with retry logic'); | |
| console.log('β generateTestWithRetry() - LLM-based test generation with 3-attempt loop'); | |
| console.log('β Realistic vulnerability examples from Phase 0 (NodeGoat, RailsGoat)'); | |
| console.log('β Framework detection and multi-language support'); | |
| console.log('β Syntax validation and test execution'); | |
| console.log('β Intelligent error feedback to LLM'); | |
| console.log('β TypeScript type safety with new interfaces'); | |
| console.log('β Integration with existing ValidationMode'); | |
| console.log(); | |
| console.log('All features are implemented and TypeScript compilation passes.'); | |
| console.log('Ready for integration testing with backend AST service.'); | |
| console.log('='.repeat(80)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment