Fix #374: visibility modes split #378

Merged
crueber merged 1 commit from fix/issue-374 into main 2026-09-12 14:55:40 +00:00
Owner

Fixes #374 — replaces the single "private — members only" with two distinct private modes (additive enum; existing private docs keep their value, no data migration).

What changed (per acceptance criteria):

  • authenticated visibility added ("private — logged in only"): any signed-in user reads (API + git + web via Resolve/CheckRead); anonymous gets 401/404 per the #345 convention. Accepted everywhere visibility is parsed (normalizeAccess, POST create path, EnsureRepoAccess, SDK typedef, both UI selects).
  • private refined ("visible only by owner/org"): org MEMBERS read without bindings (new single-probe orgRosterRole — same members.json GET the old owner check paid, no added round trip); user-owned = owner binding + explicit bindings + admin only (fail closed).
  • Host-write fallback ruled DENY (the #347 direction extended to reads): CheckRead early-allows admin only, Resolve grants the admin flag only, #345 listing filter probes writers per repo. Behavioral delta enumerated in docs/features/01 §Decisions: org members GAIN read; host-write outsiders LOSE private read (keep public/authenticated via visibility). Import checkCreate keeps its documented host-credential create-capability explicitly (roles consulted first; flag overcomes a per-repo Forbidden only, 401/503s surface).
  • UI per owner type via the #348 owner-kind probe (orgs.get 404→null): user-owned public/logged-in-only/owner-only; org-owned public/logged-in-only/org-members-only. "members only" wording gone (selects, badge, SDK).
  • Listings treat authenticated like private-for-anon / public-for-authed (rides CheckRead; no filter change beyond the unfiltered admin-only tightening).
  • Docs amended in the same change: features/01 (§4 table + resolution, §4.1, §9, Decisions #374 entry), 07_api §9/§9.1.1. No new deps.

Evidence:

  • NEW internal/identity/visibility374_test.go: full (visibility × owner-type × principal-class) matrix through CheckRead + Resolve role spot-checks + roster/parse/materialize tests.
  • Updated: TestResolve/TestCheckRead (host-write deny), api scriptedGate (admin-only bypass; host-write private → 403), SSH e2e (owner reads via binding + NEW mallory-denied-over-SSH cell).
  • go test -short ./... : 33 packages ok, 0 FAIL. -race: identity, api, server green. Coverage: identity 95.9%, api 95.2%, server 98.4%, repoimport 95.6% (≥95 gate). gofmt/vet clean.
  • Web: node --test 745 pass / 0 fail / 3 smoke-skips (smoke needs a live server; a foreign instance occupies :8080 here — untouched). vite + esbuild builds succeed.
Fixes #374 — replaces the single "private — members only" with two distinct private modes (additive enum; existing private docs keep their value, no data migration). What changed (per acceptance criteria): - `authenticated` visibility added ("private — logged in only"): any signed-in user reads (API + git + web via Resolve/CheckRead); anonymous gets 401/404 per the #345 convention. Accepted everywhere visibility is parsed (normalizeAccess, POST create path, EnsureRepoAccess, SDK typedef, both UI selects). - `private` refined ("visible only by owner/org"): org MEMBERS read without bindings (new single-probe orgRosterRole — same members.json GET the old owner check paid, no added round trip); user-owned = owner binding + explicit bindings + admin only (fail closed). - Host-write fallback ruled DENY (the #347 direction extended to reads): CheckRead early-allows admin only, Resolve grants the admin flag only, #345 listing filter probes writers per repo. Behavioral delta enumerated in docs/features/01 §Decisions: org members GAIN read; host-write outsiders LOSE private read (keep public/authenticated via visibility). Import checkCreate keeps its documented host-credential create-capability explicitly (roles consulted first; flag overcomes a per-repo Forbidden only, 401/503s surface). - UI per owner type via the #348 owner-kind probe (orgs.get 404→null): user-owned public/logged-in-only/owner-only; org-owned public/logged-in-only/org-members-only. "members only" wording gone (selects, badge, SDK). - Listings treat authenticated like private-for-anon / public-for-authed (rides CheckRead; no filter change beyond the unfiltered admin-only tightening). - Docs amended in the same change: features/01 (§4 table + resolution, §4.1, §9, Decisions #374 entry), 07_api §9/§9.1.1. No new deps. Evidence: - NEW internal/identity/visibility374_test.go: full (visibility × owner-type × principal-class) matrix through CheckRead + Resolve role spot-checks + roster/parse/materialize tests. - Updated: TestResolve/TestCheckRead (host-write deny), api scriptedGate (admin-only bypass; host-write private → 403), SSH e2e (owner reads via binding + NEW mallory-denied-over-SSH cell). - go test -short ./... : 33 packages ok, 0 FAIL. -race: identity, api, server green. Coverage: identity 95.9%, api 95.2%, server 98.4%, repoimport 95.6% (≥95 gate). gofmt/vet clean. - Web: node --test 745 pass / 0 fail / 3 smoke-skips (smoke needs a live server; a foreign instance occupies :8080 here — untouched). vite + esbuild builds succeed.
Additive authenticated visibility ("private, logged in only"); private
refined to owner/org-only with org-member read without bindings. Resolve:
single-probe roster role (owner admin/member read), authenticated grant,
host-write grant retired (the #347 direction extended to reads — ruled
DENY, documented with the org-members-gain/host-writers-lose delta; import
checkCreate keeps its host-credential create-capability explicitly). UI:
owner-appropriate options via the #348 owner-kind probe; "members only"
label gone everywhere (selects, badge, SDK typedef). No new deps.
Sign in to join this conversation.
No description provided.