56 lines
8.6 KiB
JavaScript
56 lines
8.6 KiB
JavaScript
import { createServer } from 'node:http'
|
|
|
|
const now = '2026-09-14T08:00:00.000Z'
|
|
const policy = { auto_scan: true, min_health_score: 0, max_blockers: 0, require_tests: false, require_ci: false, suppressions: [] }
|
|
const guidance = {
|
|
remediation_class: 'dependency reproducibility', confidence: 'high',
|
|
why: 'A deterministic package-manager lockfile was not found for this workspace.',
|
|
recommended_action: 'Commit the package-manager lockfile used by the build.',
|
|
priority: 800, priority_rationale: 'Blocker signal; retained rule evidence.',
|
|
}
|
|
const finding = { code: 'dependency.no-lockfile', category: 'Dependencies', severity: 'blocker', message: 'No lockfile was retained for the declared dependencies.', path: 'package.json', line: 4, deduction: 8, fingerprint: 'finding-alpha', suppressed: false, guidance }
|
|
const report = {
|
|
id: 'scan-alpha', repository_path: '/scan/Alpha', repository_name: 'Alpha',
|
|
source: { origin: 'gitea', provider: 'gitea', repository_id: 'gitea:1', repository_full_name: 'Jens/Alpha', branch: 'main', requested_revision: 'a'.repeat(40), actual_revision: 'a'.repeat(40), trigger: 'manual' },
|
|
policy, scanned_at: now, duration_ms: 42, metrics: { files: 5, source_files: 2, lines_of_code: 20, test_files: 1, todo: 0, fixme: 0, hack: 0, xxx: 0, dependency_manifests: 1, declared_dependencies: 2, large_files: 0, large_source_files: 0 },
|
|
languages: { TypeScript: 20 }, category_scores: { Architecture: 100, Testing: 100, Maintainability: 100, Documentation: 100, Dependencies: 92, 'Repository hygiene': 100, 'Security basics': 100 },
|
|
health_score: 88, release_readiness: 'BLOCKED', findings: [finding],
|
|
tests: { frameworks: ['Vitest'], coverage_artifacts: [], ci_workflows: ['.gitea/workflows/validate.yml'], ci_validation_workflows: ['.gitea/workflows/validate.yml'], ci_build_workflows: ['.gitea/workflows/validate.yml'], ci_deploy_only_workflows: [], coverage_evidence: ['.gitea/workflows/validate.yml'], test_source_ratio: 50 },
|
|
git: { available: true, commit_count: 3, contributor_count: 1, latest_commit_at: now, tracked_files: 5, renamed_files: [] }, dependencies: { manifests: ['package.json'], lockfiles: [], declared_dependencies: 2, unbounded_dependencies: 0, unpinned_dependencies: 0, duplicate_dependencies: [], included_requirements: [] },
|
|
architecture: { nodes: [{ id: 'src/app.ts', label: 'app.ts', path: 'src/app.ts', language: 'TypeScript', inbound: 0, outbound: 0, visible_inbound: 0, visible_outbound: 0, hotspot_score: 10 }], edges: [], clusters: { src: 1 }, truncated: false, total_nodes: 1, total_edges: 0 }, hotspots: [],
|
|
release_gate: { status: 'BLOCKED', checks: [{ key: 'security', label: 'Security basics', state: 'pass', detail: 'No secret findings' }, { key: 'dependencies', label: 'Dependency hygiene', state: 'block', detail: 'Lockfile missing' }] },
|
|
coverage: { limits: { max_files: 10000, max_text_bytes_per_file: 2000000, max_findings: 2000, max_secret_findings: 20 }, discovered_files: 5, scanned_files: 5, skipped_files_by_budget: 0, skipped_files_by_size: 0, text_bytes_scanned: 256, truncated: false, notes: [] }, compacted: false,
|
|
}
|
|
function repository(id, fullName, readiness = 'READY') {
|
|
const name = fullName.split('/')[1]
|
|
const blocked = readiness === 'BLOCKED'
|
|
return { id, provider: 'gitea', provider_repository_id: id.slice(-1), owner: 'Jens', name, full_name: fullName, description: `${name} fixture repository`, html_url: null, clone_url: null, default_branch: 'main', private: true, archived: false, available: true, latest_revision: 'a'.repeat(40), latest_revision_at: now, last_synced_at: now, sync_error: null, state: 'current', stale: false, active_job_id: null, last_scan_id: id === 'gitea:1' ? report.id : null, last_scan_at: id === 'gitea:1' ? now : null, last_scan_health: id === 'gitea:1' ? 88 : 96, last_scan_readiness: readiness, last_scan_revision: 'a'.repeat(40), last_scan_blockers: blocked ? 1 : 0, last_scan_warnings: 0, last_scan_primary_signal: blocked ? { code: finding.code, category: finding.category, severity: finding.severity, message: finding.message, count: 1, guidance } : null, last_scan_health_delta: 0, last_scan_added_findings: 0, last_scan_resolved_findings: 0, last_scan_priority: blocked ? 800 : 0, last_scan_priority_rationale: blocked ? guidance.priority_rationale : null, policy }
|
|
}
|
|
const repositories = [
|
|
repository('gitea:1', 'Jens/Alpha', 'BLOCKED'),
|
|
repository('gitea:2', 'Jens/Beta'),
|
|
...Array.from({ length: 23 }, (_unused, index) => repository(`gitea:${index + 3}`, `Jens/Gamma-${String(index + 1).padStart(2, '0')}`)),
|
|
]
|
|
let jobPolls = 0
|
|
const job = { id: 'job-alpha', repository_id: 'gitea:1', status: 'queued', trigger: 'manual', requested_revision: 'a'.repeat(40), actual_revision: null, phase: 'queued', progress: 0, message: 'Waiting for an available worker', created_at: now, started_at: null, updated_at: now, finished_at: null, duration_ms: null, scan_id: null, error_code: null, error_detail: null, attempt: 1, deduplicated: false }
|
|
function send(response, status, body, type = 'application/json') { response.writeHead(status, { 'Content-Type': type }); response.end(type === 'application/json' ? JSON.stringify(body) : body) }
|
|
createServer((request, response) => {
|
|
const url = new URL(request.url, 'http://127.0.0.1:8001')
|
|
const path = decodeURIComponent(url.pathname)
|
|
if (path === '/health') return send(response, 200, { status: 'ok' })
|
|
if (path === '/api/v1/meta') return send(response, 200, { name: 'RepoPulse', version: '1.5.0', stage: 'v1.5.0', scan_root_restricted: true, scan_root: '/scan', max_concurrent_scans: 1, requested_max_concurrent_scans: 1, repository_count: repositories.length, repository_states: { current: 2 }, current_repositories: 2, stale_repositories: 0, queue_depth: 0, active_jobs: 0, completed_jobs: 1, failed_jobs: 0, worker_heartbeat: now, gitea: { configured: true, url: 'http://gitea.local', last_sync: { synced_at: now } }, storage: { database_bytes: 1024, journal_bytes: 0, mirror_count: 2, mirror_cache_bytes: 2048, worktree_count: 0, scan_count: 1, compacted_scan_count: 0, oldest_scan_at: now, newest_scan_at: now, history_per_repository: 200, full_reports_per_repository: 30, report_retention_days: 365 }, database_recovery: { status: 'healthy' }, mutation_authentication: 'perimeter_required' })
|
|
if (path === '/api/v1/repositories' && request.method === 'GET') return send(response, 200, repositories)
|
|
if (path === '/api/v1/repositories/sync' && request.method === 'POST') return send(response, 200, { provider: 'gitea', discovered: 2, created: 0, updated: 2, unavailable: 0, errors: [], partial: false, branch_failures: 0, listing_complete: true, synced_at: now })
|
|
if (path === '/api/v1/repositories/gitea:1' && request.method === 'GET') return send(response, 200, { ...repositories[0], latest_scan: report })
|
|
if (path === '/api/v1/repositories/gitea:2' && request.method === 'GET') return send(response, 200, { ...repositories[1], latest_scan: null })
|
|
if (path === '/api/v1/repositories/gitea:1/scans' && request.method === 'GET') return send(response, 200, [{ id: report.id, repository_id: 'gitea:1', scanned_at: now, branch: 'main', requested_revision: report.source.requested_revision, actual_revision: report.source.actual_revision, trigger: 'manual', health_score: 88, release_readiness: 'BLOCKED', findings: 1, duration_ms: 42 }])
|
|
if (path === '/api/v1/repositories/gitea:2/scans' && request.method === 'GET') return send(response, 200, [])
|
|
if (path.endsWith('/trend')) return send(response, 200, [{ scan_id: report.id, scanned_at: now, health_score: 88, findings: 1, blockers: 1, warnings: 0, debt_markers: 0 }])
|
|
if (path === '/api/v1/scans/scan-alpha/comparison') return send(response, 200, { current_scan_id: report.id, previous_scan_id: null, health_score_delta: null, category_score_deltas: {}, metric_deltas: {}, added_findings: [], resolved_findings: [] })
|
|
if (path === '/api/v1/repositories/gitea:1/scans' && request.method === 'POST') { jobPolls = 0; return send(response, 202, job) }
|
|
if (path === '/api/v1/scan-jobs/job-alpha') { jobPolls += 1; if (jobPolls < 2) return send(response, 200, { ...job, status: 'scanning', phase: 'scanning', progress: 40, message: 'Running deterministic repository analysis' }); return send(response, 200, { ...job, status: 'completed', phase: 'completed', progress: 100, message: 'Scan completed', scan_id: report.id, actual_revision: report.source.actual_revision, finished_at: now, duration_ms: 42 }) }
|
|
if (path === '/api/v1/repositories/gitea:1/scans/scan-alpha') return send(response, 200, report)
|
|
if (path === '/api/v1/scans/scan-alpha/export') return send(response, 200, JSON.stringify(report), 'application/json')
|
|
return send(response, 404, { detail: `Unhandled mock endpoint: ${path}` })
|
|
}).listen(8001, '127.0.0.1')
|