From 1f1b05ce60c8329fcd3daf914104f96c5ffdb13a Mon Sep 17 00:00:00 2001 From: antoinetoussaint-byte <312536060+antoinetoussaint-byte@users.noreply.github.com> Date: Sun, 25 Oct 2026 20:04:05 -0400 Subject: [PATCH] fix(conformance): an already-exposed UnexposedTeam fails as a fixture error Against a long-lived authority a second run finds the fixed UnexposedTeam already exposed by the first; the grant is an idempotent no-op, the revision does not move, and the probe blamed the authority for missing staleness. The probe now reads the installation's teams through the administrator's List first and fails "UnexposedTeam %q is already exposed to %s" as a fixture error. The README and the field say the team must be one the installation does not reach when the run starts. Review follow-up f1 on #8. Co-Authored-By: Claude Opus 5.5 --- libraries/conformance/go/README.md | 12 ++++++++---- libraries/conformance/go/conformance.go | 18 ++++++++++++++++-- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/libraries/conformance/go/README.md b/libraries/conformance/go/README.md index 9402a352..aa2680ee 100644 --- a/libraries/conformance/go/README.md +++ b/libraries/conformance/go/README.md @@ -41,10 +41,14 @@ then resumes acknowledgement. `Lifecycle.Revoke` calls the host's existing uninstall path. These hooks arrange state; the assertions use the public interfaces. No synthetic issuer or parallel permission resolver is allowed. -`UnexposedTeam` is a real team of the organization that `InstalledSolution` is -not yet exposed to, created or found by the host's own fixture. The staleness -probe exposes the installation to it to move the organization's authority, so a -host that validates team ids sees an id it issued, never one the suite invents. +`UnexposedTeam` is a real team of the organization that `InstalledSolution` +does not reach when the run starts; the host's own fixture creates it or finds +one. The staleness probe exposes the installation to it to move the +organization's authority, so a host that validates team ids sees an id it +issued, never one the suite invents. A team the installation already reaches, +as a fixed id does on a second run against a long-lived authority, moves +nothing; the probe checks the installation's teams first and fails it as a +fixture error, never as missed staleness. The authority interface returns an advisory decision, not a hop stamp. The hop transport additionally must preserve it while forwarding: the local hop's diff --git a/libraries/conformance/go/conformance.go b/libraries/conformance/go/conformance.go index 3fe89137..cc3cc1d8 100644 --- a/libraries/conformance/go/conformance.go +++ b/libraries/conformance/go/conformance.go @@ -49,8 +49,8 @@ type Fixture struct { InstalledSolution string // an active installation the viewer is entitled to InstalledCredential string // workload credential of InstalledAudience, required for installation-owned Issue InstalledAudience string // the installed solution principal; distinct from the organisation-role module Audience - // UnexposedTeam is a real team of Organization that InstalledSolution is not - // yet exposed to, named as the host's own fixture creates or finds it. The + // UnexposedTeam is a real team of Organization that InstalledSolution does + // not reach when the run starts, from the host's own fixture. The // staleness probe exposes InstalledSolution to it, which moves the // organisation's authority; its members keep that role for the rest of the // run, so a team with no members is the safe choice. @@ -402,6 +402,20 @@ func Run(t *testing.T, conn grpc.ClientConnInterface, descriptors []byte, f Fixt } admin := c.must(t, ctx, "host.session.v1.SessionService", "SignIn", map[string]any{"fixture_token": f.AdminToken}) c.must(t, ctx, "host.authority.v1.AuthorityService", "Check", map[string]any{"token": token, "audience": f.Audience}) + // A team the installation already reaches moves nothing, as a second run + // against a long-lived authority finds: that is the fixture's failure. + listed := c.must(t, as(ctx, admin), "host.installation.v1.InstallationService", "List", map[string]any{"organization_id": f.Organization}) + for _, inst := range listMsgs(listed, "installations") { + if str(inst, "id") != f.InstalledSolution { + continue + } + teams := field(inst, "team_ids").List() + for i := 0; i < teams.Len(); i++ { + if teams.Get(i).String() == f.UnexposedTeam { + t.Fatalf("required conformance fixture invalid: UnexposedTeam %q is already exposed to %s", f.UnexposedTeam, f.InstalledSolution) + } + } + } c.must(t, as(ctx, admin), "host.installation.v1.InstallationService", "GrantToTeam", map[string]any{"organization_id": f.Organization, "installation_id": f.InstalledSolution, "team_id": f.UnexposedTeam}) _, err := c.call(ctx, "host.authority.v1.AuthorityService", "Check", map[string]any{"token": token, "audience": f.Audience}) if status.Code(err) != codes.PermissionDenied {