Skip to content

test: route-level coverage for verdict_source owner-scope gate #4378

Description

@bokelley

Gap

PR #4263 added `verdict_source` as an owner-scoped field on `/api/registry/agents/:url/compliance`. Gated on `ownerMembership.is_owner`: populated for the agent's owner, null for everyone else (anonymous, cross-org, non-member).

No route-level test currently asserts this gate. The unit test in `server/tests/unit/membership-tiers.test.ts` covers `resolveOwnerMembership` returning the right shape, but doesn't pin the route-level wiring that gates the field on `is_owner`.

If a future refactor flips the gate (e.g. accidentally exposes `verdict_source` to anonymous callers), nothing catches it.

Fix shape

Add to `server/tests/integration/registry-api.test.ts` (or appropriate compliance-route test file) three assertions:

  1. Anonymous caller hitting `/api/registry/agents/:url/compliance` for a passing agent → response includes `verdict_source: null`
  2. Authenticated cross-org caller → `verdict_source: null`
  3. Authenticated owner → `verdict_source` populated with the actual `triggered_by` value (`'heartbeat'` / `'owner_test'` / `'manual'` / `'webhook'`)

Bonus: assert response `Object.keys()` is identical between owner and non-owner cases (owner-detection-resistance invariant).

Acceptance criteria

  • Three integration tests covering the cases above
  • All pass against current main
  • A purposeful regression (e.g. dropping the `is_owner` gate) makes them fail

Discovered

PR #4263 code review feedback. Deferred as out-of-scope.

Metadata

Metadata

Assignees

No one assigned

    Labels

    claude-triagedIssue has been triaged by the Claude Code triage routine. Remove to re-triage.

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions