Skip to content

fix(accounts): the three role vocabularies are one table; a fixture continues only a pending attempt; authority at fab9ea74 - #1302

Merged
antoinetoussaint-byte merged 3 commits into
mainfrom
fix/permission-audit-followups
Nov 4, 2026
Merged

antoinetoussaint-byte merged 3 commits into
mainfrom
fix/permission-audit-followups

Conversation

@antoinetoussaint-byte

@antoinetoussaint-byte antoinetoussaint-byte commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

Permission-layer follow-ups of the module-page audit (the handbook's design/module-page-permission-audit.md), after #1282, #1284, #1285 and #1298. Three commits, each a fix at the owning place.

1. The three role vocabularies are one table the matrix reads from its sources (audit finding 1)

AUTHZ_MATRIX.md's "Three vocabularies" section was prose typed into the generator (rpc_policy_matrix.go). It is now rendered from business.RoleVocabularies() (pkg/business/role_vocabularies.go), one table whose words are read from the code that defines each vocabulary: the organisation roles from the OrgRole enum, the catalogue built-ins from the roles servicePermissionVocabulary grants, the installation roles from the shared authority core's declaration rule (domain.InstallerRole). TestRoleVocabulariesAreReadFromTheirSources holds every word to its source, refuses a platform role in any of the three, and holds the rendered section to RenderRPCPolicyMatrix; TestRPCPolicyMatrixIsCurrent holds the generated file to it. The generated file is byte-for-byte unchanged, so go generate ./pkg/business produces no diff.

2. A fixture takes a fresh approval only once the core no longer holds its installation (#1275 item 7)

fixtures/installations.go reused the stored plan's approval on every pass. After an uninstall the receipt names an operation the core refuses for good (INSTALLATION_APPROVAL_REVISION_CHANGED: the installation's revision moved), so the fixture never installed again. It now continues a stored approval while the core holds the installation pending or active (a same-operation replay is idempotent, and the host's plan guard refuses a fresh operation id against an active record, which the first cut of this change got wrong and the independent review caught); a revoked or absent record takes the fresh review's approval. attemptContinues is pure and tested over pending/active/revoked/another's/absent.

3. Authority pinned at fab9ea74 (codefly-dev/authority#69)

authority-client, authority-core, conformance, delivery and resources move from dea37afac (#65) to the merge commit of authority#69, which closes the code items of authority#60: a redelivery that drops a role drops its grants (solutions too, the review note on #1282); a module page's roles are held to what it serves; a module page's offer review on this host finds the active installation this host named, never a record the core retired under its own id; one active installation per target, and no empty-organisation lookup. No adoption is needed here beyond the pin: this host links the core.

Reused, not built

The matrix generator and its currency test; servicePermissionVocabulary, the OrgRole enum and domain.InstallerRole as the sources; the core's Installations read and the host's SolutionInstallationPlan store for the fixture. No new permission, no new role word, no new store method, no proto change.

Classification

Fixes at the owning place: the vocabulary table lives beside the matrix generator that renders it; the fixture's convergence rule lives in the fixture; the core's rules live in the core and this host takes them by pin.

Tests

  • go test -tags pure ./pkg/business/ ./fixtures/, go vet, gofmt: green.
  • TestAccountsPassesTheHostInterfaceConformanceSuite on the pinned commit, Postgres-backed, with the CI-pinned CLI 0.1.221 on PATH: ok in 201 s, 294 subtests passed, 0 failed. (Under the development CLI on this machine the SDK's dependency start failed on the control socket before the suite ran; that is the toolchain, not the suite, and the run with the pinned CLI is the evidence.) The same suite was also run against the authority branch before its merge through a temporary, uncommitted replace: ok in 170 s.
  • module/tools tests, scripts/check-boundaries.sh, naming-gate.mjs check, commit-identity-gate.mjs, generated-pins-gate.mjs check: clean.

Audit findings, as they stand on main after this (for the handbook's Status)

  1. Three vocabularies, no map: closed here (one tested table, rendered into the gated matrix).
  2. A module may not declare roles: closed by feat(accounts): a module page's roles are accepted and gate its page like a solution's #1282 and authority#59/Model bootstrap Job network-policy edges explicitly #61.
  3. Canonical entitlement path drops modules: closed by feat(accounts): a module page's roles are accepted and gate its page like a solution's #1282 (canonicalSolutionEntitlements lists every RoleGated installation; adapters end-to-end test).
  4. /s/<id> unguarded: closed by feat: shared module and solution pages with declared gateway routing #1120's SolutionLivePage gate, restated and tested in feat(accounts): a module page's roles are accepted and gate its page like a solution's #1282 (unentitled viewer gets not-found).
  5. Setup tab for a role-less module: closed by feat(accounts): a module page's roles are accepted and gate its page like a solution's #1282 (WhenRolesDeclared).
  6. Two admin pages gated on roles:write where the API checks org_admin: the two sets are equal (permissionsByRole owner/admin/*:* vs requireOrgAdmin owner/admin/super_admin), proven by the six-combination "organization administration boundary" test and stated in the matrix table; only the word differs, and naming the API's tier needs an org_admin access level in the published plugin contract, which is a contract move not made here.
  7. Installation administration admin-only by path: still a derivation in pkg/cataloggen/frontend_plugins.go (admin, admin/platform, admin/teams); the navigation items declare access: in frontend.bindings.codefly.yaml and the authz-coverage gate refuses widening. Making routes take their level from a declaration is a generator change argued separately.

Issues

🤖 Generated with Claude Code

antoinetoussaint-byte and others added 3 commits November 3, 2026 23:18
…eads from its sources

The "Three vocabularies" section of AUTHZ_MATRIX.md was prose typed into
the generator. It is now rendered from RoleVocabularies(), one table
whose words come from the code that defines each vocabulary: the
organisation roles from the OrgRole enum, the catalogue built-ins from the
roles the permission vocabulary grants, the installation roles from the
shared authority core's declaration rule. A test holds each word to its
source and the rendered section to the matrix; the generated file is
unchanged.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… longer holds its installation

After an uninstall, the fixture kept presenting the stored plan's approval,
whose receipt the core refuses for good once the installation's revision
moved, so it never installed again (module-saas-starter#1275, item 7). The
stored approval now continues an installation the core holds pending or
active (a same-operation replay is idempotent, and the host's plan guard
refuses a fresh operation id against an active record); a revoked or
absent record takes the fresh review's approval.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
authority-client, authority-core, conformance, delivery and resources move
from dea37afac (authority#65) to fab9ea74a58b, the merge commit of
codefly-dev/authority#69: a dropped role drops its grants, a module page's
roles name what it serves, review finds the installation issuance decides
on, and one installation per target.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@antoinetoussaint-byte
antoinetoussaint-byte force-pushed the fix/permission-audit-followups branch from 30bd7ee to cb8d0b1 Compare November 4, 2026 04:30
@antoinetoussaint-byte
antoinetoussaint-byte added this pull request to the merge queue Nov 4, 2026
Merged via the queue into main with commit ca9e15f Nov 4, 2026
34 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant