Skip to content

Make the bridge deploy path fail loudly: CI ordering, revision drift, and silent discards #74

Description

@EthanThatOneKid

Follow-up to #66 and PR #67.

PR #67 adds the Gateway bridge (bridge/discord-gateway/), the signed forward route (agent/channels/discord-mentions.ts), the runner (scripts/zo-deploy.ts), and a deploy workflow (.github/workflows/deploy.yml). Two steps stay manual by design: register the computer-discord-bridge service on the Zo host, and set the ZO_API_KEY repository secret. Everything below is about what happens after those exist.

1. The deploy races CI on main

Expected: a revision that failed verify never reaches the host.
Actual: verify.yml and deploy.yml both trigger on push to main and start in parallel. The deploy fast-forwards the live checkout and restarts the service without consulting verify, so a merge that breaks tsc or the test suite deploys anyway and the host then runs it.
Change: gate the deploy on verify — trigger it from workflow_run (completed + success + main), or fold both into one workflow with needs: [verify].

2. Revision drift is silent

scripts/zo-deploy.ts takes --expect-sha from GITHUB_SHA but only prints a note when the live checkout's HEAD differs (scripts/zo-deploy.ts:208). If a second push lands mid-deploy, the workflow is green while the host runs a revision nobody asked for.
Change: fail on mismatch, or at least emit a workflow warning annotation, so the job's status reflects what is actually live.

3. Every denial is invisible

Both halves fail closed, and neither says so.

  • The bridge drops a message locally when resolveDiscordMentionAdmission returns null and logs nothing (bridge/discord-gateway/index.ts, handleMessage).
  • The forward result is discarded: drainQueue passes forward()'s return value nowhere, so 202 {"dispatched": false, "reason": "denied"} — the route's answer when the deployment's allowlists disagree with the bridge's — is indistinguishable from a successful dispatch.

An operator therefore cannot tell "nobody mentioned Computer" from "mentions are being discarded". This is the likeliest real-world failure, because the allowlists and the bridge secret are configured twice, once in the Zo service env and once in the deployment env.
Change: log admission decisions at info level with the reason, and log the route's dispatched/reason for each forward.

4. Nothing checks the deployment the forwards land in

deploy.yml verifies the bridge process only; the eve app deploys through Vercel's Git integration with no post-deploy check.
Change: after the restart, assert GET /eve/v1/health reports ready and an unsigned POST /eve/v1/discord-mentions returns 401. That catches a missing or mismatched DISCORD_BRIDGE_SECRET before the first real mention does instead.

Notes

  • Item 1 is worth doing before the first merge to main that touches the bridge, since that merge is also the first deploy.
  • The local suite already covers the parsers, the admission matrix, the HMAC primitives, and the deploy CLI end-to-end against a fake Zo MCP server (lib/zo-deploy-cli.test.ts); none of these four items are covered today.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions