feat(reconcile): add Permission and Role kinds, bootstrap only creates missing roles#1737
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughSummary by CodeRabbit
WalkthroughThe PR adds declarative reconciliation and export support for ChangesDesired-state reconciliation
Estimated code review effort: 4 (Complex) | ~60 minutes Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 2✅ Passed checks (2 passed)
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. Comment |
Coverage Report for CI Build 29484890319Warning No base build found for commit Coverage: 45.855%Details
Uncovered Changes
Coverage RegressionsRequires a base build to compare against. How to fix this → Coverage Stats
💛 - Coveralls |
|
From the RFC review (#1751), verified on a live sandbox built from this branch: |
|
Checked this against a fresh sandbox built from the current branch, and the exact scenario works: narrowing The review still caught real gaps right next to it, fixed in 2cb94ca:
Kept the differs-only export rather than always exporting predefined roles — the fixes are small, the files stay minimal, and the round-trip rule holds. |
|
Verified the reconciler against the database identity model:
One edge fixed in d555799: slugs flatten |
c0dae6a to
44e365a
Compare
Review notes (self-review after an independent pass)Needs a decision — role metadata is wiped on update
Nothing in non-test code reads role Three ways to fix it:
Leaning towards A. Open to input before I implement. Fixed
Nits (not blocking)
|
|
Update on the metadata-wipe item above: The only residual is a metadata key someone sets directly on a platform role outside this |
71e95c2 to
a226f47
Compare
There was a problem hiding this comment.
Actionable comments posted: 5
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 24d5ff50-595e-4360-a7e8-c16b595f20cd
📒 Files selected for processing (19)
cmd/export.gocmd/reconcile.gocmd/serve.goconfig/sample.config.yamldocs/content/docs/reconcile.mdxdocs/content/docs/reference/cli.mdxinternal/api/v1beta1connect/role.gointernal/api/v1beta1connect/role_test.gointernal/bootstrap/service.gointernal/bootstrap/service_test.gointernal/reconcile/permission.gointernal/reconcile/permission_reconciler.gointernal/reconcile/permission_reconciler_test.gointernal/reconcile/permission_test.gointernal/reconcile/reconcile.gointernal/reconcile/role.gointernal/reconcile/role_reconciler.gointernal/reconcile/role_reconciler_test.gointernal/reconcile/role_test.go
…m roles can be deleted
Rebased onto
mainnow that #1731 (export) and #1761 (schema cleanup) merged.What
Two new desired-state kinds for
frontier reconcileandfrontier export, plus a bootstrap behavior change that makes role management through the API stick.Permission kind
A permission is identity only (namespace + name). It is added or deleted, never updated.
appnamespaces) are server-managed: the diff and export ignore them, and spec entries targeting them are rejected.service/resourcenamespace. Unknown fields in an entry are rejected as well (strict YAML decode), so a typo likedelet: truefails the plan instead of being silently dropped — this applies to both kinds.Role kind
Platform-level roles only. The role name is the identity and never changes. Title, description, permissions, and scopes are the managed fields. For custom roles, a field that is present in an entry is managed and a field that is omitted keeps its server value. Predefined roles converge to their shipped definitions instead: an entry overrides the fields it lists, an omitted field takes the definition's value, and a predefined role with no entry resets to the definition.
delete: true— so the plan fails loudly on unaccounted roles instead of removing anything by omission.slug,service/resource:verb,service.resource.verb); slugs are canonical.managed_by: frontier-reconcilein metadata. An update merges the managed keys (managed_by,description) over the role's existing metadata, so any other metadata keys an operator set are kept, not dropped.Bootstrap change: existing roles are left alone
MigrateRolesused to write a role's definition back whenever its permission set drifted. That meant any change made through the API — including this reconciler's — was reverted on the next boot. Now boot creates a role only when it is missing and never updates an existing one. Operators own existing roles; the reconcile flow is the way to change them.The definition-update job boot loses moves to reconcile: when a new frontier version changes a predefined role's definition, the first reconcile run with the new image plans that change for every role the file does not override, and applying it converges the deployment. The same update that used to happen invisibly at every restart now happens once, reviewed. This also means the reconcile CLI image should match the server's release — it carries the definitions the reset converges to.
Why no role renames
An earlier draft allowed renaming predefined roles. Verifying it showed the server resolves predefined roles by name at runtime in 13+ places (org owner constraint checks, group creation, invitation acceptance, service-user creation, admin listings, notifications). Renaming a predefined role would break all of them, so the name is fixed as the identity and only the display title is renameable.
Tests