Initial curated RepoPulse source from 2524ccc3c1c27739996dccb2b7992989f88cd26d
This commit is contained in:
commit
0adf8ef5d9
90 files changed
+14315
No files matched your search
@@ -0,0 +1,55 @@
|
||||
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')
|
||||
@@ -0,0 +1,45 @@
|
||||
import { expect, test } from '@playwright/test'
|
||||
|
||||
test('portfolio workflow covers navigation, remediation, a scan lifecycle and export', async ({ page }) => {
|
||||
await page.goto('/')
|
||||
await expect(page.getByRole('heading', { name: /portfolio signal/i })).toBeVisible()
|
||||
await expect(page.getByRole('heading', { name: 'Remediation Center' })).toBeVisible()
|
||||
await expect(page.getByText('A deterministic package-manager lockfile was not found for this workspace.')).toBeVisible()
|
||||
await page.locator('.remediation-center').getByRole('button', { name: /Jens\/Alpha/ }).click()
|
||||
await expect(page.getByRole('heading', { name: 'Jens/Alpha' })).toBeVisible()
|
||||
await page.getByRole('link', { name: 'Dashboard', exact: true }).click()
|
||||
|
||||
await page.getByRole('button', { name: /open repository explorer/i }).click()
|
||||
await expect(page.getByText('25 matching 25 repositories')).toBeVisible()
|
||||
await page.getByRole('button', { name: 'Visual grid' }).click()
|
||||
await page.getByRole('button', { name: 'Pin Jens/Alpha' }).click()
|
||||
await expect(page.getByRole('button', { name: 'Remove Jens/Alpha from pinned repositories' })).toBeVisible()
|
||||
await page.getByRole('button', { name: 'Table' }).click()
|
||||
await expect(page.getByText('Page 1 / 2')).toBeVisible()
|
||||
await page.getByRole('button', { name: 'Next' }).click()
|
||||
await expect(page.getByText('Page 2 / 2')).toBeVisible()
|
||||
await page.getByLabel('Filter by readiness').selectOption('blocked')
|
||||
await expect(page.getByText('1 matching 25 repositories')).toBeVisible()
|
||||
await page.getByRole('link', { name: 'Open Jens/Alpha' }).click()
|
||||
await expect(page.getByRole('heading', { name: 'Jens/Alpha' })).toBeVisible()
|
||||
|
||||
await page.getByRole('link', { name: /findings/i }).click()
|
||||
await expect(page.getByText('No lockfile was retained for the declared dependencies.')).toBeVisible()
|
||||
await page.getByRole('link', { name: /architecture/i }).click()
|
||||
await expect(page.getByText('Local import and dependency topology')).toBeVisible()
|
||||
await page.getByRole('link', { name: /history/i }).click()
|
||||
await expect(page.getByText('Repository health over time')).toBeVisible()
|
||||
|
||||
await page.getByRole('button', { name: 'Scan now' }).click()
|
||||
await expect(page.getByText('Repository analysis completed.')).toBeVisible({ timeout: 10_000 })
|
||||
await page.getByText('Reports').click()
|
||||
const download = page.waitForEvent('download')
|
||||
await page.getByRole('button', { name: 'Export JSON' }).click()
|
||||
await expect(download).resolves.toBeTruthy()
|
||||
|
||||
await page.keyboard.press('Control+k')
|
||||
await page.getByPlaceholder('Search repositories…').fill('Beta')
|
||||
await page.keyboard.press('ArrowDown')
|
||||
await page.keyboard.press('Enter')
|
||||
await expect(page.getByRole('heading', { name: 'Jens/Beta', exact: true })).toBeVisible()
|
||||
})
|
||||
@@ -0,0 +1,11 @@
|
||||
import { spawn } from 'node:child_process'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
const vite = fileURLToPath(new URL('../node_modules/vite/bin/vite.js', import.meta.url))
|
||||
const child = spawn(process.execPath, [vite, '--host', '127.0.0.1', '--port', '4173'], {
|
||||
cwd: new URL('..', import.meta.url),
|
||||
env: { ...process.env, REPOPULSE_API_PROXY: 'http://127.0.0.1:8001' },
|
||||
stdio: 'inherit',
|
||||
})
|
||||
|
||||
child.on('exit', (code) => process.exit(code ?? 0))
|
||||
Reference in new issue
Block a user