Commit graph

4 commits

Author SHA1 Message Date
Jason Monk
567e9ee9a7
Fix #426: Test-methodology gap that let #417 ship (#428)
Two gates to prevent reintroduction of the malformed-JSON bug class
that shipped in #417 (Outreach error helpers used a """{...}""" template
with raw exception text, producing unparseable bodies).

(A) Harness-level JSON parse assertion. Introduces shared
`McpToolTestHarness` (in `integrations/src/test/.../testing/`) that
wraps the duplicated mockk(Server) + addTool capture pattern previously
copy-pasted across `OutreachMcpProviderTest`, `UsageMcpProviderTest`,
`NotificationMcpToolExecutionTest`, and `NotificationMcpProviderToolsTest`.
Every `callTool(...)` invocation runs the result body through
`Json.parseToJsonElement`; parse failures throw with the offending tool
name and body content. Per-call `expectJsonBody = false` opt-out for
tools whose contract is plain text (currently only one test uses it,
referencing #427 which tracks the underlying core MCP DSL gap the
harness surfaced).

Regression test `McpToolTestHarnessTest` constructs fake tools that
return non-JSON bodies and asserts the harness throws with the tool
name + body in the message, plus a passing-case to lock down the
expectJsonBody opt-out.

(B) CI grep check. New `scripts/check-no-manual-json.sh` greps
`*/src/main/*.kt` for `"""\{` and fails the build on hits unless the
line carries a `// allow-manual-json: <reason>` marker, or matches the
explicit `AuditDetailScreen.kt` allowlist (Compose preview fixtures).
Wired into `.github/workflows/android-ci.yml` next to the existing
`check-zombie-screens.sh` step. Verified manually that the script
fires on a synthetic `"""{"x":"$bar"}"""` and clears once the marker
is added.

Documents the convention in new `docs/agent-quickstart.md`.

Co-authored-by: Claude Opus 4 (1M context) <noreply@anthropic.com>
2026-04-26 17:31:31 -04:00
Jason Monk
7c5397661f
Fix #215: Render relay env + firebase-sa from GH secrets at deploy time (#219)
Move all relay runtime secrets off manually-maintained /etc/rouse-relay/env
and into GitHub repo secrets. The deploy workflow now renders both the
systemd EnvironmentFile and the Firebase service account JSON from repo
secrets on each run, scps them to /tmp, then moves them into
/etc/rouse-relay/ with the correct ownership and mode.

Rotation is now a gh secret set + workflow_dispatch instead of an SSH
session. Bootstrapping a fork only needs the secrets populated — no more
remembering which env vars the VPS needs.

- relay-deploy.yml: new "Render" step writes env + firebase-sa.json into a
  mode-0700 tempdir using printf + file redirection (never echo, never
  secret values on argv). Deploy step scps and installs alongside the
  binary. Tempdir is shredded on exit.
- scripts/backfill-relay-secrets.sh: maintainer tool that re-syncs GH
  secrets from the live VPS. Explicit "yes" prompt, set -u -o pipefail
  (no -x to avoid leaking values), shred -u on exit, never echoes
  secret values.
- docs/self-hosting.md: new appendix documenting the secret inventory,
  naming convention split (existing CLOUDFLARE_* unprefixed; new
  RELAY_*), rotation procedure, and pointer to the backfill script.

Secrets already populated on the repo (values pulled from the running
VPS and verified byte-for-byte parity with the workflow-rendered output):
  CLOUDFLARE_API_TOKEN, CLOUDFLARE_ZONE_ID (pre-existing, re-synced),
  RELAY_RUST_LOG, RELAY_GTS_EAB_KID, RELAY_GTS_EAB_HMAC,
  RELAY_FIREBASE_SERVICE_ACCOUNT_JSON (base64 of firebase-sa.json).

First post-merge deploy will overwrite /etc/rouse-relay/env and
firebase-sa.json with the workflow-rendered versions. Parity confirmed
before merging; flagging for user's eyes on the first run.

Co-authored-by: Claude Opus 4 (1M context) <noreply@anthropic.com>
2026-04-17 19:39:41 -04:00
Jason Monk
88a6a02e7d Fix #85: Delete unused OnboardingErrorScreen
OnboardingErrorScreen was never wired into AppNavigation and only
referenced by its own screenshot test. OnboardingViewModel's Failed
and RateLimited states are never reached (the ViewModel transitions
straight to Onboarded and handles errors via logs); user-facing error
surfaces live in SettingUpScreen/dashboard. Follows the #75 precedent
of deleting unreachable screens rather than manufacturing a route.

- Delete app/src/main/.../OnboardingErrorScreen.kt
- Delete its 05_onboarding_error_{dark,light}.png goldens
- Drop the corresponding screenshot test cases and import
- Remove the KNOWN_EXEMPT entry from scripts/check-zombie-screens.sh

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 22:07:51 -04:00
Jason Monk
763bc3d3e3 Add zombie-screen detector to CI and reviewer agent
Prevents the class of bug surfaced by the first attempt at #60, where a fix
landed in HealthConnectSettingsScreen.kt — a file that looked live but was
never referenced by AppNavigation. On-device behavior was unchanged despite
a clean merge.

- scripts/check-zombie-screens.sh flags any *Screen.kt whose public @Composable
  functions have no non-self production caller. OnboardingErrorScreen.kt is
  exempted pending #85 resolution.
- android-ci.yml runs the script after lint so new zombies fail CI.
- .claude/agents/reviewer.md gains a render-path check (Step 4b) that blocks
  merge if the edited composable has zero non-self production references.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 16:36:03 -04:00