diff --git a/docs/reports/qa_report.md b/docs/reports/qa_report.md index b2dc9a57..a229d890 100644 --- a/docs/reports/qa_report.md +++ b/docs/reports/qa_report.md @@ -1,7 +1,9 @@ -## QA Report - PR #779 +## QA Report — Import/Save Route Regression Test Suite -- Date: 2026-03-01 -- Scope: Post-remediation merge-readiness gates after Caddy Import E2E fix +- Date: 2026-03-02 +- Branch: `feature/beta-release` (HEAD `2f90d936`) +- Scope: Regression test coverage for import and save function routes +- Full report: [docs/reports/qa_report_import_save_regression.md](qa_report_import_save_regression.md) ## E2E Status diff --git a/docs/reports/qa_report_import_save_regression.md b/docs/reports/qa_report_import_save_regression.md new file mode 100644 index 00000000..f2621285 --- /dev/null +++ b/docs/reports/qa_report_import_save_regression.md @@ -0,0 +1,188 @@ +## QA Report — Import/Save Route Regression Test Suite + +- **Date**: 2026-03-02 +- **Branch**: `feature/beta-release` +- **HEAD**: `2f90d936` — `fix(tests): simplify back/cancel button handling in cross-browser import tests` +- **Scope**: Regression test implementation for import and save function routes + +--- + +## Summary + +| DoD Gate | Result | Notes | +|---|---|---| +| Patch Coverage Preflight | ✅ PASS | 100% — 12/12 changed lines covered | +| Backend Unit Tests + Coverage | ✅ PASS | 87.9% statements (threshold: 87%) | +| Frontend Unit Tests + Coverage | ✅ PASS | 89.63% lines (threshold: 87%) | +| TypeScript Type Check | ✅ PASS | 0 type errors | +| Pre-commit Hooks | ✅ PASS | 17/17 hooks passed | +| GORM Security Scan | ⏭️ SKIP | No model files changed | +| Trivy FS Scan | ✅ PASS | 0 HIGH/CRITICAL in npm packages | +| Docker Image Scan | ✅ PASS | 0 HIGH/CRITICAL (13 LOW/MED total) | +| CodeQL Analysis | ✅ PASS | 1 pre-existing warning (not a regression) | + +**Overall Verdict: PASS** — All gated checks passed. Two pre-existing items documented below. + +--- + +## New Test Files + +Eight test files were added as part of this feature: + +| File | Type | Tests | +|---|---|---| +| `backend/internal/api/routes/routes_import_contract_test.go` | Backend unit | Route contract coverage | +| `backend/internal/api/routes/routes_save_contract_test.go` | Backend unit | Route contract coverage | +| `backend/internal/api/routes/endpoint_inventory_test.go` | Backend unit | Endpoint inventory/matrix | +| `frontend/src/api/__tests__/npmImport.test.ts` | Frontend unit | 6 tests | +| `frontend/src/api/__tests__/jsonImport.test.ts` | Frontend unit | 6 tests | +| `frontend/src/hooks/__tests__/useNPMImport.test.tsx` | Frontend unit | 5 tests | +| `frontend/src/hooks/__tests__/useJSONImport.test.tsx` | Frontend unit | 5 tests | +| `tests/integration/import-save-route-regression.spec.ts` | Integration | Route regression spec | + +All 22 new frontend tests passed. Backend route package runs clean. + +--- + +## Step 1 — Patch Coverage Preflight + +- **Command**: `bash scripts/local-patch-report.sh` +- **Artifacts**: `test-results/local-patch-report.md`, `test-results/local-patch-report.json` +- **Result**: PASS +- **Metrics**: + - Overall patch coverage: 100% (12/12 changed lines) + - Backend changed lines: 8/8 covered (100%) + - Frontend changed lines: 4/4 covered (100%) + +--- + +## Step 2 — Backend Unit Tests + Coverage + +- **Command**: `bash scripts/go-test-coverage.sh` +- **Result**: PASS +- **Metrics**: + - Total statements: 87.9% + - `internal/api/routes` package: 87.8% + - Gate threshold: 87% +- **Package results**: 25/26 packages `ok` +- **Known exception**: `internal/api/handlers` — 1 test fails in full suite only + +### Pre-existing Backend Failure + +| Item | Detail | +|---|---| +| Test | `TestSecurityHandler_UpsertRuleSet_XSSInContent` | +| Package | `internal/api/handlers` | +| File | `security_handler_audit_test.go` | +| Behaviour | Fails in full suite (`FAIL: expected 200, got {"error":"failed to list rule sets"}`); passes in isolation | +| Cause | Parallel test state pollution — shared in-memory SQLite DB contaminated by another test in the same package | +| Introduced by this PR | No — file shows no git changes in this session | +| Regression | No | + +--- + +## Step 3 — Frontend Unit Tests + Coverage + +- **Command**: `bash scripts/frontend-test-coverage.sh` +- **Result**: PASS +- **Metrics**: + - Lines: 89.63% (threshold: 87%) + - Statements: 88.96% + - Functions: 86.06% + - Branches: 81.41% +- **Test counts**: 589 passed, 23 skipped, 0 failed, 24 test suites + +### New Frontend Test Results + +All four new test files passed explicitly: + +``` +✅ npmImport.test.ts 6 tests passed +✅ jsonImport.test.ts 6 tests passed +✅ useNPMImport.test.tsx 5 tests passed +✅ useJSONImport.test.tsx 5 tests passed +``` + +--- + +## Step 4 — TypeScript Type Check + +- **Command**: `npm run type-check` +- **Result**: PASS — 0 errors, clean exit + +--- + +## Step 5 — Pre-commit Hooks + +- **Command**: `pre-commit run --all-files` +- **Result**: PASS — 17/17 hooks passed + +Hooks verified include: `fix-end-of-files`, `trim-trailing-whitespace`, `check-yaml`, `shellcheck`, `actionlint`, `dockerfile-validation`, `go-vet`, `golangci-lint (Fast Linters - BLOCKING)`, `frontend-typecheck`, `frontend-lint`. + +--- + +## Step 6 — GORM Security Scan + +- **Result**: SKIPPED +- **Reason**: No files under `backend/internal/models/**` or GORM service/repository paths were modified in this session. + +--- + +## Step 7 — Security Scans + +### Trivy Filesystem Scan + +- **Command**: `trivy fs . --severity HIGH,CRITICAL --exit-code 1 --skip-dirs .git,node_modules,...` +- **Result**: PASS — 0 HIGH/CRITICAL vulnerabilities +- **Scope**: `package-lock.json` (npm) +- **Report**: `trivy-report.json` + +### Docker Image Scan + +- **Command**: `.github/skills/scripts/skill-runner.sh security-scan-docker-image` +- **Result**: PASS — 0 HIGH/CRITICAL vulnerabilities +- **Total findings**: 13 (all LOW or MEDIUM severity) +- **Verdict**: Gate passed — no action required + +### CodeQL Analysis + +- **SARIF files**: + - `codeql-results-go.sarif` — generated 2026-03-02 + - `codeql-results-javascript.sarif` — generated 2026-03-02 +- **Go results**: 1 finding — `go/cookie-secure-not-set` (warning level) +- **JavaScript results**: 0 findings +- **Result**: PASS (no error-level findings) + +#### Pre-existing CodeQL Finding + +| Item | Detail | +|---|---| +| Rule | `go/cookie-secure-not-set` | +| File | `internal/api/handlers/auth_handler.go:151–159` | +| Severity | Warning (non-blocking) | +| Description | Cookie does not set `Secure` attribute to `true` | +| Context | Intentional design: `secure` flag defaults to `true`; set to `false` **only** for local loopback requests without TLS. This allows the management UI to function over HTTP on `localhost` during development. The code comment explicitly documents this decision: _"Secure: true for HTTPS; false only for local non-HTTPS loopback flows"_ | +| Introduced by this PR | No — `auth_handler.go` was last modified in commits predating HEAD (`e348b5b2`, `00349689`) | +| Regression | No | +| Action | None — accepted as intentional design trade-off for local-dev UX | + +--- + +## Pre-existing Issues Register + +| ID | Location | Nature | Regression? | Action | +|---|---|---|---|---| +| PE-001 | `handlers.TestSecurityHandler_UpsertRuleSet_XSSInContent` | Test isolation failure — parallel SQLite state pollution | No | Track separately; fix with test DB isolation | +| PE-002 | `auth_handler.go:151` — `go/cookie-secure-not-set` | CodeQL warning; intentional local-dev design | No | Accepted; document as acknowledged finding | + +--- + +## Related Commits + +| Hash | Message | +|---|---| +| `63e79664` | `test(routes): add strict route matrix tests for import and save workflows` | +| `077e3c1d` | `chore: add integration tests for import/save route regression coverage` | +| `f60a99d0` | `fix(tests): update route validation functions to ensure canonical success responses in import/save regression tests` | +| `b5fd5d57` | `fix(tests): update import handler test to use temporary directory for Caddyfile path` | +| `2f90d936` | `fix(tests): simplify back/cancel button handling in cross-browser import tests` | diff --git a/tests/core/caddy-import/caddy-import-cross-browser.spec.ts b/tests/core/caddy-import/caddy-import-cross-browser.spec.ts index 703bbbd6..1eb28d5a 100644 --- a/tests/core/caddy-import/caddy-import-cross-browser.spec.ts +++ b/tests/core/caddy-import/caddy-import-cross-browser.spec.ts @@ -160,8 +160,8 @@ async function setupImportMocks( } }); - // Mock cancel endpoint - await page.route('**/api/v1/import/cancel', async (route) => { + // Mock cancel endpoint — pattern ends with * to match DELETE ?session_uuid=... query param + await page.route('**/api/v1/import/cancel*', async (route) => { hasSession = false; await route.fulfill({ status: 204 }); });