Skip to content

v0.2.0 — installs and actually works

Choose a tag to compare

@guyoron1 guyoron1 released this 28 Aug 16:03
· 43 commits to main since this release
155255e

First release since the dashboard was audited end to end. v0.1.0 installed and ran; this one is the first that installs and actually works — four separate wires were connected to the wrong terminal, and every one of them failed silently.

⚠️ Breaking changes

Read these before upgrading.

Change Action
GET /api/github/org-repos?org=&token= is now POST with a JSON body The PAT was landing in access logs and browser history. Update any caller; the bundled UI is already updated.
helm install now fails if runner.enabled: true It could never work — the image ships neither pipeline_runner.py nor the claude CLI, and the runner's cwd doesn't match QF_OUTPUTS_DIR. Remove the value; run pipeline phases from the CLI.
patch_coverage_pct removed from GET /api/metrics/{project} It was declared, never assigned, always null, and read by nothing. The UI's patch % comes from /api/coverage/test/{project}.
?commit= on the coverage read endpoints rejects non-SHA input with 400 Closes an arbitrary-file read (below). Only real commit SHAs were ever valid.

Security

Unauthenticated arbitrary .yaml read. GET /api/coverage/test/{project}/raw?commit=../../../../../config/routing returned the file's contents. With OIDC unset — the default — this was anonymous, and .yaml on a cluster includes mounted config and any secret projected as YAML. The upload path had always required a strict commit SHA; only the read path was missing it. Both ends now share one gate.

Two related holes closed at the same time: the previous sanitizer mapped separators to _ but passed a bare .. through unchanged, and five call sites sanitized a component segment while leaving project_id raw beside it.

GitHub PAT in a URL. A repo-scoped token travelled in the query string of org-repos, where it was written to the uvicorn access log, the ingress log and browser history. Now a POST body, matching the four other call sites that already did that.

Deployment — four silent failures

  • Git sync wrote to a directory nothing reads. It targeted ROOT/outputs while every reader uses OUTPUTS (/data/outputs on the PVC), so the clone succeeded, _last_sync updated, the endpoint returned ok, and nothing pulled was ever displayed. It now also carries config/, which GIT_REPO_URL was documented as delivering but never did.
  • The config volume was mounted empty with nothing to seed it, so a fresh install had no routing.yaml: project resolution silently fell back to a lowercased Jira prefix and /api/projects returned []. A seed-config initContainer now seeds it once with cp -Rn, never clobbering later edits.
  • The chart set a GitHub token variable the main code path never read. GITHUB_TOKEN vs GITHUB_PERSONAL_ACCESS_TOKEN — push-PR, close-PR, org scan and bulk onboard all reported "no token" while other GitHub calls worked, which is why it passed casual testing.
  • No LLM credential existed anywhere in the chart, so every AI feature returned 503 on a stock install. New claude: block covers Vertex and the direct API.

Metrics that were telling the wrong story

  • The coverage delta subtracted the current value from itself. History is newest-first; the reader took index 0 as the previous entry, so every delta on the dashboard read 0.
  • The trend chart plotted the oldest 30 entries backwardshistory[-30:] on a newest-first list.
  • Phase durations could be negative (-1.28h against real data). They were derived from file mtimes, which don't survive a git sync, container rebuild or volume restore. Now uses timestamps recorded by the run, with mtimes as fallback and non-positive values dropped.
  • Project coverage was whichever repo the loop visited last; now line-weighted across repos. Go test functions were never counted, so Go-primary projects under-reported "time saved" by their entire Go contribution.

The dashboard looked broken because it was

#metricsHero was laid out with grid-cols-6a class absent from the vendored Tailwind build. It fell back to one column and stacked nine hero cards as full-width blocks. The same gap silently killed tracking-wide at all 29 of its uses, so every uppercase label rendered un-spaced, plus a dozen other utilities.

Also fixed: the default landing view hid the sidebar while leaving its tab lit active; six loaders caught errors and hid their section, so a transient 500 rendered as "Coverage isn't configured — edit coverage.yaml" and sent people to fix a correct file; the settings gear was a dead button on failure; a failed feature-toggle save left the switch showing a state the server never accepted; and light mode turned skill cards near-black on hover.

Also in this release

Waves 1–4b (#21, #22, #23, #24, #25) — generated tests now actually reach the pull request, real traceability IDs flow through the pipeline, plus triage, trends, navigation, provenance and a run-history view. A non-blocking AI code reviewer (#9, #19, #20). Full QE-pipeline hardening (#26): injection defense, orphaned gates wired, dead validator rules, and an LLM-fabricated STP checksum replaced with a real shasum.

Upgrading

helm upgrade qualityflow-dashboard deploy/helm/qualityflow-dashboard \
  --set image.tag=0.2.0 \
  --set auth.apiKey=<your-key> \
  --set claude.vertexProjectId=<project>   # or --set claude.apiKey=<key>

Drop runner.enabled from your values first — the chart now refuses to render with it set.

Known gaps

Two paths this release changes have not been exercised against real infrastructure, because they can't be from a laptop: a live cluster install, and a real git-sync against a remote. Verify both on a pilot cluster before rolling this out widely.

Two mutation-tested self-checks now run in CI (check_value_metrics.py, check_path_safety.py) guarding the specific defects above — every one of them returned a plausible-looking value while broken, so no syntax or lint gate would have caught any of them.