Skip to content

Add the platform superuser type and Martyrology project roles - #18

Merged
JohnRDOrazio merged 2 commits into
mainfrom
feat/martyrology-platform-superuser
Aug 3, 2026
Merged

Add the platform superuser type and Martyrology project roles#18
JohnRDOrazio merged 2 commits into
mainfrom
feat/martyrology-platform-superuser

Conversation

@JohnRDOrazio

@JohnRDOrazio JohnRDOrazio commented Aug 3, 2026

Copy link
Copy Markdown
Member

Adds the pieces martyrology-api needs to express platform-wide authority and to
tell a curator apart from any other authenticated principal in the umbrella
instance. Pairs with CatholicOS/martyrology-api#23.

OpenFGA: a platform type

type platform
  define superuser: [user]

type governance_body
  define on_platform: [platform]
  define admin:  [user] or superuser from on_platform
  define editor: [user] or admin
  define reader: [user] or editor

A platform superuser becomes admin on every body pointing at the platform, and
through the pre-existing governed_by hop inherits can_admin / can_edit /
can_read_texts on every edition those bodies govern. The edition type is
unchanged.

This is deliberately not a role bypass in the API. Platform authority is a
tuple — listable, auditable, revocable — rather than a claim that silently
defeats the governance model with no per-resource record.

Three structural on_platform tuples are seeded, one per governance body. No
superuser tuple is committed: the bootstrap grant is a per-person operator
action made out-of-band, not version-controlled seed data.

Zitadel: three project roles

admin, martyrology_editor, developer on the MartyrologyAPI project, via
the existing create_roles helper. create_project already enables
projectRoleAssertion, and a live introspection probe confirmed roles are
returned in both the generic and project-scoped claims.

developer is defined but enforced by nothing — martyrology-api has no
API-consumer features to gate yet. It exists so the vocabulary is uniform across
CDCF properties before principals are onboarded, since issuing a role to
already-onboarded principals later is the disruptive path.

Corrections to existing text

Three comment blocks in setup-zitadel.sh argued that Martyrology deliberately
has no roles and that all authorization is OpenFGA. That is no longer true, so
they are rewritten rather than deleted. The handoff doc's claim that the admin
role "is the intended role-granting authority" was never implemented by
anything; granting authority is the OpenFGA admin relation on a governance
body, reached directly or via platform:martyrology.

Verification

jq parses both JSON files; the model retains all original types and the tuples
file its original eight governed_by entries; shellcheck auth/setup-zitadel.sh
reports no findings. Review traced both authorization hops statically rather
than treating valid JSON as sufficient.

Not applied to any environment

The model upload, the bootstrap superuser tuple, the /etc/martyrology/api.env
edit and the live probe are operator steps, performed with a human after the API
side is released. Note that uploading this model mints a new authorization
model ID, and MARTYROLOGY_OPENFGA_MODEL_ID is pinned — the pin, the token and
the project ID must land in one edit followed by a restart. Pinning to the old
model fails closed, so a mistake there is safe but inert.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added platform-level superuser access for governance administration.
    • Added authorization relationships for Martyrology governance bodies.
    • Added an English 2004 edition governance association.
    • Added provisioning for administrator, editor, and developer project roles.
    • Added the permissions grant-management endpoint contract.
  • Documentation

    • Clarified that OpenFGA governs resource-level permissions, while project roles provide a broad curation gate.
    • Expanded governance authorization, bootstrap, and production rollout guidance.

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 896706ed-1e05-41b1-80a8-c48fa96cc9b0

📥 Commits

Reviewing files that changed from the base of the PR and between 49439f3 and dde5dd2.

📒 Files selected for processing (2)
  • auth/handoffs/martyrology.md
  • auth/models/Martyrology.tuples.json
🚧 Files skipped from review as they are similar to previous changes (2)
  • auth/handoffs/martyrology.md
  • auth/models/Martyrology.tuples.json

📝 Walkthrough

Walkthrough

The change adds platform and superuser inheritance to the Martyrology OpenFGA model, associates governance bodies with the platform, provisions three Zitadel project roles, and documents grant-management routes and rollout steps.

Changes

Martyrology authorization

Layer / File(s) Summary
Platform authorization model and tuples
auth/models/Martyrology.json, auth/models/Martyrology.tuples.json
Adds the platform type and superuser relation. Governance bodies can inherit admin access from platform superusers. Martyrology platform tuples and the 2004 English edition tuple are added.
Martyrology role provisioning
auth/setup-zitadel.sh
Defines and creates the admin, martyrology_editor, and developer roles. Provisioning output and help text describe the roles and OpenFGA enforcement.
Authorization handoff and grant contract
auth/handoffs/martyrology.md
Documents role gates, OpenFGA grant authority, platform bootstrap, /admin/permissions routes, and remaining production rollout steps.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

  • CatholicOS/cdcf-infra#16: Introduced the Martyrology OpenFGA model, tuples, provisioning, and handoff that this change extends.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main changes: adding the platform superuser type and Martyrology project roles.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/martyrology-platform-superuser

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@auth/handoffs/martyrology.md`:
- Line 191: Correct the grant-routing statement in the martyrology handoff
documentation: do not claim that subsequent superuser grants use
/admin/permissions. Document the appropriate separate operator/OpenFGA path for
granting user:<sub> on platform:martyrology, or specify a platform-scoped
endpoint if one exists, while preserving the first-superuser flow.
- Around line 184-189: Update the bootstrap curl command to include the
--fail-with-body option, ensuring HTTP errors from the OpenFGA write request
cause curl to exit unsuccessfully while preserving the existing request and
error-body output.

In `@auth/models/Martyrology.tuples.json`:
- Around line 12-14: Update the comment in Martyrology.tuples.json to describe
that the file contains all structural tuples, including both
governance-body-to-edition relationships and platform-to-governance on_platform
relationships. Leave the tuple data unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: c383f8b5-f138-41a6-a66c-6d6c79180867

📥 Commits

Reviewing files that changed from the base of the PR and between c5272b2 and 49439f3.

📒 Files selected for processing (4)
  • auth/handoffs/martyrology.md
  • auth/models/Martyrology.json
  • auth/models/Martyrology.tuples.json
  • auth/setup-zitadel.sh

Comment thread auth/handoffs/martyrology.md
Comment thread auth/handoffs/martyrology.md Outdated
Comment thread auth/models/Martyrology.tuples.json
The handoff claimed that every grant after the bootstrap -- "including
granting a second superuser" -- goes through /admin/permissions. That is
wrong, and it inverts the security property it describes: the grant endpoint
fixes its object type to governance_body in the route itself, precisely so
platform: tuples are structurally unreachable. An endpoint that could write
them would let any governance-body admin mint themselves a superuser.

Superuser grants are therefore always out-of-band, not just the first one.
Documented with the revoke form alongside.

Also: the bootstrap curl gains --fail-with-body, since `curl -sS` exits 0 on
an HTTP error and a silent failure there leaves the operator believing they
hold a superuser tuple they do not; and the tuples file's $comment described
only governed_by, though the file now carries on_platform tuples too.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@JohnRDOrazio
JohnRDOrazio merged commit ff969b3 into main Aug 3, 2026
1 check passed
@JohnRDOrazio
JohnRDOrazio deleted the feat/martyrology-platform-superuser branch August 3, 2026 12:59
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