frontend styling fixes

This commit is contained in:
master
2026-02-15 12:00:34 +02:00
parent e9aeadc040
commit ab794e167c
860 changed files with 30149 additions and 27297 deletions

View File

@@ -0,0 +1,252 @@
# Scanner Module - Live E2E API Verification
**Date**: 2026-02-14T09:14:00Z
**Tier**: 2a (Live HTTP API)
**Target**: `scanner.stella-ops.local` (Docker: stellaops-scanner-web)
**Infrastructure**: Full 60-service Docker Compose stack
**Test Scan**: `POST /api/v1/scans` with `alpine:3.19` -> scanId `27547150c8ee3542f244a96a8714900134d2a4d9`
## Executive Summary
- **Total endpoints tested**: 55+
- **Healthy endpoints (200/202)**: 22
- **Proper validation (400)**: 14
- **Expected not-found (404 with proper error)**: 8
- **Missing DB tables (500)**: 7
- **Missing auth policies (500)**: 2
- **Not implemented (501)**: 1
- **Service unavailable (503)**: 1
- **Method not allowed (405)**: 3
## Infrastructure Health
| Endpoint | HTTP | Response | Status |
|----------|------|----------|--------|
| `GET /healthz` | 200 | `{"status":"healthy"}` | PASS |
| `GET /readyz` | 200 | `{"status":"ready"}` | PASS |
| `GET /metrics` | 200 | Prometheus metrics (offlinekit_*, attestor_*, rekor_*) | PASS |
## Scan Lifecycle
| Endpoint | HTTP | Response | Status |
|----------|------|----------|--------|
| `POST /api/v1/scans` | 202 | `{"scanId":"27547150...","status":"Pending"}` | PASS |
| `GET /api/v1/scans/{id}` | 200 | Full scan details with image ref, digest, status | PASS |
| `GET /api/v1/scans/{id}/events` | 200 | SSE stream with `event: pending` lifecycle data | PASS |
| `GET /api/v1/scans/{id}/entropy` | 400 | Validates: "Entropy layers are required" | PASS (validation) |
## Layers & Composition
| Endpoint | HTTP | Response | Status |
|----------|------|----------|--------|
| `GET /api/v1/scans/{id}/layers` | 200 | `{"layers":[]}` (scan pending) | PASS |
| `GET /api/v1/scans/{id}/composition-recipe` | 404 | "Composition recipe not available" (scan pending) | PASS (expected) |
## Evidence & Witnesses
| Endpoint | HTTP | Response | Status |
|----------|------|----------|--------|
| `GET /api/v1/scans/{id}/evidence` | 200 | `{"total_count":0,"items":[]}` | PASS |
| `GET /api/v1/witnesses` | 200 | `{"witnesses":[],"totalCount":0}` | PASS |
## Reachability
| Endpoint | HTTP | Response | Status |
|----------|------|----------|--------|
| `GET /api/v1/scans/{id}/reachability/components` | 200 | `{"items":[],"total":0}` | PASS |
| `GET /api/v1/scans/{id}/reachability/findings` | 200 | `{"items":[],"total":0}` | PASS |
| `GET /api/v1/scans/{id}/reachability/explain?cve=X&purl=Y` | 400 | Validates: "Both 'cve' and 'purl' query parameters are required" | PASS (validation) |
| `POST /api/v1/scans/{id}/compute-reachability` | 202 | `{"jobId":"reachability_...","status":"scheduled"}` | PASS |
| `GET /api/v1/scans/{id}/reachability/traces/export` | 501 | "Trace export not supported by current query service" | PASS (expected) |
| `GET /api/v1/scans/{id}/drift` | 500 | Missing `scanner.reachability_drift_results` table | BUG |
## Exports
| Endpoint | HTTP | Response | Status |
|----------|------|----------|--------|
| `GET /api/v1/scans/{id}/exports/sbom` | 404 | "No SBOM data available for export" (scan pending) | PASS (expected) |
| `GET /api/v1/scans/{id}/exports/sarif` | 404 | "No findings available for SARIF export" | PASS (expected) |
| `GET /api/v1/scans/{id}/exports/cdxr` | 404 | "No findings available for CycloneDX export" | PASS (expected) |
| `GET /api/v1/scans/{id}/exports/openvex` | 404 | "No VEX data available for export" | PASS (expected) |
## Smart-Diff
| Endpoint | HTTP | Response | Status |
|----------|------|----------|--------|
| `GET /api/v1/smart-diff/scans/{id}/changes` | 200 | `{"scanId":"...","totalChanges":0,"changes":[]}` | PASS |
| `GET /api/v1/smart-diff/scans/{id}/sarif` | 200 | Full SARIF 2.1.0 doc with 4 rules (SDIFF001-004) | PASS |
| `GET /api/v1/smart-diff/{id}/vex-candidates` | 200 | `{"imageDigest":"...","totalCandidates":0,"candidates":[]}` | PASS |
## Delta Compare
| Endpoint | HTTP | Response | Status |
|----------|------|----------|--------|
| `POST /api/v1/delta/compare` | 400 | Validates input (needs proper scan IDs) | PASS (validation) |
| `GET /api/v1/delta/quick` | 400 | Validates input (needs base/head params) | PASS (validation) |
## Baselines & Counterfactuals
| Endpoint | HTTP | Response | Status |
|----------|------|----------|--------|
| `GET /api/v1/baselines/recommendations/{digest}` | 200 | 3 recommendations: last-green, previous-release, parent-commit | PASS |
| `GET /api/v1/counterfactuals/scan/{id}/summary` | 200 | Rich response: totalBlocked:2, findings with wouldPassIf paths | PASS |
| `POST /api/v1/counterfactuals/compute` | 400 | Validates input | PASS (validation) |
## Approvals
| Endpoint | HTTP | Response | Status |
|----------|------|----------|--------|
| `GET /api/v1/scans/{id}/approvals` | 200 | `{"scan_id":"...","approvals":[],"total_count":0}` | PASS |
| `POST /api/v1/scans/{id}/approvals` | 400 | Validates input | PASS (validation) |
## Triage
| Endpoint | HTTP | Response | Status |
|----------|------|----------|--------|
| `POST /api/v1/triage/query` | 200 | `{"findings":[],"totalCount":0,"summary":{"byLane":{},"byVerdict":{}}}` | PASS |
| `GET /api/v1/triage/summary` | 400 | Validates (needs params) | PASS (validation) |
| `GET /api/v1/triage/inbox` | 400 | Validates (needs params) | PASS (validation) |
| `GET /api/v1/triage/inbox/clusters/stats` | 400 | Validates (needs params) | PASS (validation) |
| `POST /api/v1/triage/proof-bundle` | 400 | Validates input | PASS (validation) |
## Policy
| Endpoint | HTTP | Response | Status |
|----------|------|----------|--------|
| `GET /api/v1/policy/schema` | 200 | Full JSON Schema v1 with rules, severity, actions, exceptions | PASS |
| `POST /api/v1/policy/preview` | 400 | Validates: "imageDigest is required" | PASS (validation) |
| `POST /api/v1/policy/diagnostics` | 400 | Validates input | PASS (validation) |
## SBOM Ingestion
| Endpoint | HTTP | Response | Status |
|----------|------|----------|--------|
| `POST /api/v1/scans/{id}/sbom` | 400 | Validates Content-Type: needs `application/vnd.cyclonedx+json` or `application/spdx+json` | PASS (validation) |
| `POST /api/v1/sbom/upload` | 400 | Validates: "artifactRef is required", "sbom or sbomBase64 is required" | PASS (validation) |
| `GET /api/v1/sbom/hot-lookup/components` | 400 | Validates (needs query params) | PASS (validation) |
| `GET /api/v1/sbom/hot-lookup/pending-triage` | 400 | Validates (needs query params) | PASS (validation) |
## Call Graphs
| Endpoint | HTTP | Response | Status |
|----------|------|----------|--------|
| `POST /api/v1/scans/{id}/callgraphs` | 400 | Validates: "Content-Digest header required for idempotent submission" | PASS (validation) |
## Reports
| Endpoint | HTTP | Response | Status |
|----------|------|----------|--------|
| `POST /api/v1/reports` | 400 | Validates: "imageDigest is required" | PASS (validation) |
## Runtime
| Endpoint | HTTP | Response | Status |
|----------|------|----------|--------|
| `POST /api/v1/runtime/events` | 400 | Validates: "events array must include at least one item" | PASS (validation) |
| `POST /api/v1/runtime/reconcile` | 400 | Validates input | PASS (validation) |
## Offline Kit
| Endpoint | HTTP | Response | Status |
|----------|------|----------|--------|
| `GET /api/offline-kit/status` | 404 | "Offline kit status is not enabled" | PASS (expected, config-dependent) |
| `GET /api/offline-kit/manifest` | 404 | "Offline kit is not enabled" | PASS (expected) |
| `POST /api/offline-kit/validate` | 404 | "Offline kit validation is not enabled" | PASS (expected) |
## EPSS
| Endpoint | HTTP | Response | Status |
|----------|------|----------|--------|
| `GET /api/v1/epss/status` | 500 | Missing `scanner.epss_current` table | BUG |
| `GET /api/v1/epss/current/{cveId}` | 500 | Missing `scanner.epss_current` table | BUG |
| `GET /api/v1/epss/history/{cveId}` | 500 | Missing `scanner.epss_scores` table | BUG |
| `POST /api/v1/epss/current` (bulk) | 503 | "EPSS data is not available. Ensure data has been ingested" | PASS (graceful) |
## Endpoints with Missing DB Tables (500)
| Endpoint | Missing Table | Migration File |
|----------|---------------|----------------|
| `GET /{id}/entrytrace` | `scanner.entry_trace` | `001_create_tables.sql` |
| `GET /{id}/spines` | `scanner.proof_spines` | `002_proof_spine_tables.sql` |
| `GET /{id}/drift` | `scanner.reachability_drift_results` | `010_reachability_drift_tables.sql` |
| `GET /epss/status` | `scanner.epss_current` | `008_epss_integration.sql` |
| `GET /epss/current/{cveId}` | `scanner.epss_current` | `008_epss_integration.sql` |
| `GET /epss/history/{cveId}` | `scanner.epss_scores` | `008_epss_integration.sql` |
| `GET /{id}/ruby-packages` | `scanner.ruby_packages` | in migrations |
| `GET /{id}/bun-packages` | `scanner.bun_packages` | in migrations |
**Root Cause**: 34 migrations recorded in `scanner.schema_migrations` as applied, but corresponding DDL statements did not execute. The migration tracker marks success even when table creation silently fails.
## Endpoints with Missing Auth Policies (500)
| Endpoint | Missing Policy |
|----------|----------------|
| `GET /secrets/config/rules/categories` | `scanner.secrets.settings.read` |
| `GET /api/slices/cache/stats` | `scanner.admin` |
**Root Cause**: Authorization policies referenced in endpoint attributes are not registered in the DI container.
## DI Registration Bug
| Endpoint | Missing Service |
|----------|----------------|
| `POST /api/slices/query` | `ISliceQueryService` not registered |
---
## Bugs Found
### BUG-001: Scanner DB Migration Silent Failures
- **Severity**: High
- **Impact**: 8 endpoints return 500 due to missing tables
- **Tables**: entry_trace, proof_spines, epss_current, epss_scores, reachability_drift_results, ruby_packages, bun_packages
- **Root cause**: Migration runner records success in `schema_migrations` table without verifying DDL execution
- **Fix**: Re-run migrations or manually create tables from migration SQL files
### BUG-002: Missing Authorization Policies
- **Severity**: Medium
- **Impact**: 2 endpoints return 500 when accessed
- **Policies**: `scanner.secrets.settings.read`, `scanner.admin`
- **Root cause**: Policy registration in Program.cs doesn't include all policy names referenced by endpoint attributes
### BUG-003: ISliceQueryService Not Registered
- **Severity**: Medium
- **Impact**: Slice query endpoint returns 500
- **Root cause**: DI container missing registration for `ISliceQueryService`
---
## Verified Feature Mapping
### Features with Live API Endpoints Verified (200 responses)
1. **Health & Readiness**: healthz, readyz, metrics
2. **Scan Lifecycle**: scan creation (202), scan retrieval, events (SSE)
3. **Layers & SBOM**: layer listing, composition-recipe (404 expected)
4. **Evidence**: evidence listing, witnesses listing
5. **Reachability**: components, findings, compute (202 scheduled), explain (validates)
6. **Smart-Diff**: changes, SARIF export (full SARIF 2.1.0), VEX candidates
7. **Baselines**: recommendations (3 types: last-green, previous-release, parent-commit)
8. **Counterfactuals**: scan summary (with wouldPassIf paths)
9. **Approvals**: listing with scan_id, total_count
10. **Triage**: query with summary (byLane, byVerdict, canShipCount, blockingCount)
11. **Policy**: schema (full JSON Schema), preview (validates), diagnostics (validates)
12. **SBOM Upload**: validates format (CycloneDX/SPDX), validates required fields
13. **Call Graphs**: validates Content-Digest header for idempotency
14. **Reports**: validates imageDigest
15. **Runtime**: events ingestion (validates array), reconcile (validates)
16. **Exports**: sbom, sarif, cdxr, openvex (404 expected when no data)
17. **Offline Kit**: status, manifest, validate (404 config-dependent - expected)
18. **EPSS**: bulk lookup (503 graceful when no data)
19. **Delta Compare**: compare, quick (validates input)
### Features with Bugs Blocking Verification
1. **EPSS Integration**: Missing tables (epss_current, epss_scores)
2. **Proof Spines**: Missing table (proof_spines)
3. **Entry Trace**: Missing table (entry_trace)
4. **Reachability Drift**: Missing table (reachability_drift_results)
5. **Ruby Package Analysis**: Missing table (ruby_packages)
6. **Bun Package Analysis**: Missing table (bun_packages)
7. **Secret Detection Config**: Missing auth policy
8. **Slice Query**: Missing DI registration