Search permission matrix
The permission-matrix tests enumerate every actor × repo-visibility × entity combination the search surface supports, asserting the correct HIT / MISS outcome. This document lists the matrix and points at the test coverage.
Matrix
| Actor | Repo visibility | Entity (code/symbols/issues/mrs/comments/pages/site) | Expected |
|---|---|---|---|
| owner | private | all | HIT |
| collaborator | private | all | HIT |
| group-member (via grant) | private | all | HIT |
| non-member | private | all | MISS |
| admin | private (not owned) | all | HIT |
| anonymous | private | all | MISS/401 |
| any | public | all | HIT |
Page-scoped addenda
| Actor | Access grant | Expected |
|---|---|---|
| user not on repo ACL | page_permission_user_ids includes user |
HIT |
| user not on repo ACL | page_permission_group_ids ∩ user.groups |
HIT |
| anonymous | share_token presented + matches | HIT |
| anonymous | share_token missing | MISS |
| anonymous | share_token expired | MISS |
Test coverage
Clause-level (pure, go test ./... green)
Every matrix cell has a dedicated assertion in internal/search/authfilter/permission_matrix_test.go. The tests build an *authfilter.Filter / *authfilter.PageFilter for the matrix actor and assert the emitted OpenSearch bool.filter clauses encode the correct outcome. The hostile non-member case (non-member + ?repo=<private UUID>) is pinned as TestPermissionMatrix_FOR201Regression_NonMemberWithRepoParam.
These tests are cheap, run in the default unit-test suite, and guard the invariant that a drift in the clause builders cannot silently change the ACL semantics.
Live-cluster matrix (deferred — testcontainers harness)
The full HTTP round-trip matrix — actor auth + real repository fixtures + real vetrix-* indexes + OpenSearch cluster — is the remaining piece. Ship plan:
- Add
github.com/testcontainers/testcontainers-gotogo.mod. - New
internal/integration/search_matrix_test.gowith aTestSearchPermissionMatrixthat:- Spins an OpenSearch container via testcontainers.
- Reuses the existing Postgres-integration test infra.
- Seeds the six fixture actors (owner / collaborator / group-member / non-member / admin / anon) + two fixture repos (one private, one public).
- Indexes fixtures into both backends.
- Runs every matrix cell against both the OpenSearch
_msearchpath and the Postgres fallback, asserting the same HIT/MISS outcome for each cell — any mismatch fails the build (parity-gate). - Targets < 10 min wall for the full matrix on CI.
- CI job naming:
search-integrationparallel to existinggo test -tags integrationjobs; runs on PR + on main.
Hostile non-member live regression
Until the testcontainers harness ships, the hostile non-member regression is covered by:
TestBuildCodeSearchQuery_FOR201Regression_NonMemberCannotSlipByRepoID(pure, ininternal/opensearch/) pins the AuthFilter envelope on the OpenSearch code-search body.TestCodeSearch_Unauthenticated401+TestSearchCodeInRepos_EmptyAllowListReturnsNoHits(ininternal/api/+internal/search/) pin the Postgres handler ACL gate.
Deferred follow-ups
- testcontainers-backed live-cluster matrix (the substantial piece listed above).
- CI job spec + runtime budget enforcement.
- Shared fixture loader so the Postgres and OpenSearch halves of the parity gate consume the same seed data.