Skip to content

fix(reconcile): harden the PlatformUser kind against silent access removal#1775

Merged
rohilsurana merged 4 commits into
mainfrom
fix/reconcile-platform-user-hardening
Jul 20, 2026
Merged

fix(reconcile): harden the PlatformUser kind against silent access removal#1775
rohilsurana merged 4 commits into
mainfrom
fix/reconcile-platform-user-hardening

Conversation

@rohilsurana

@rohilsurana rohilsurana commented Jul 20, 2026

Copy link
Copy Markdown
Member

What

Hardening fixes for the PlatformUser reconcile kind, found by an independent review. Each
commit is one finding, most-severe first. The headline fix (M1) is security-relevant: it
closes a path where a hand-authored file could silently remove a superuser's access. One fix
(m2) also touches the server: it moves the bootstrap-account identity check into a shared
helper so the server's removal guard matches the id in any uuid form, not just the exact
string.

The fixes

M1 (major): validate and canonicalize refs to prevent silent access removal. The diff
matched a file entry to a live principal with a raw string compare, but the server resolves
refs loosely (an uppercase or urn:uuid: id, a name slug, or a display-name email). So an
entry meant to keep alice-id, written as ALICE-ID or a slug, failed to match, and because
adds run before removes the run quietly stripped the access it meant to keep and never
converged. Now a user ref must be a plain email or a uuid and a service user ref must be a
uuid (a slug or Alice <a@x.com> is rejected at plan time), and a uuid ref is canonicalized
so a non-canonical id matches its stored principal.

m1: reject unknown fields in PlatformUser specs. This kind decoded with plain
yaml.Unmarshal, so a mistyped field was silently ignored. It now uses the framework's strict
decodeSpec, matching every other kind.

m2: guard the bootstrap service account by uuid value, on the reconciler and the server.
The check now lives in one place, schema.IsBootstrapServiceUser, which parses both ids and
compares the 128-bit uuid values, so any spelling (uppercase, urn:uuid:, braces, no dashes)
matches. Two call sites use it: the reconciler rejects a serviceuser entry that names the
bootstrap id, and the server's RemovePlatformUser refuses to remove it. The server guard used
an exact string compare before, so a non-canonical spelling could slip past it and reach
UnSudo on the protected account even though the uuid column treats the ids as equal. The
guard is scoped to service-user ids on purpose: the bootstrap id is a service-user id, users
are a separate id space, so a user that happens to share that uuid is a different principal and
must not be rejected.

m5 (docs): warn about the empty-file lock-out. Documents that spec: [] removes every
platform user except the bootstrap account, so app.admin.bootstrap must stay configured as
the recovery path.

Not in this PR (need server-side changes)

  • m3: the report over-counts Applied when the server no-ops an add (for example a uuid
    user ref that does not exist). The admin API does not tell the client whether a call changed
    anything, so this needs a server signal to fix cleanly.
  • m4: a non-existent user ref is a silent no-op while a non-existent service user id fails
    loudly. The user path swallows ErrNotExist server-side; aligning them is a server change.
  • n1 (dropped): an earlier commit failed fast on a malformed --header. It was removed
    because passing the token via the -H flag is interim; the auth mechanism will change, so
    validating that flag is not worth carrying.
  • n2 (dropped): an earlier commit also skipped the bootstrap id in the users list as
    "defense in depth". That was the same conflation: the bootstrap id is a service-user id, so a
    user that happens to share that uuid is a different principal and should still be reconciled,
    not hidden.

Testing

  • New tests: non-canonical uuid matches without a spurious remove; slug and display-name refs
    rejected; service user ref must be a uuid; unknown field fails the plan; the bootstrap
    account rejected in a non-canonical uuid form; a user that shares the bootstrap uuid is not
    rejected; the server refuses to remove the bootstrap account in a non-canonical form; and a
    table test for schema.IsBootstrapServiceUser across uuid forms.
  • go build, go test ./cmd/... ./internal/reconcile/..., go vet, gofmt, and
    golangci-lint all pass.

@vercel

vercel Bot commented Jul 20, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
frontier Ready Ready Preview, Comment Jul 20, 2026 4:05pm

@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 372bc463-3448-4bed-8571-a453b9a60ce5

📥 Commits

Reviewing files that changed from the base of the PR and between b755319 and 1b83493.

📒 Files selected for processing (9)
  • docs/content/docs/reconcile.mdx
  • internal/api/v1beta1connect/platform.go
  • internal/api/v1beta1connect/platform_test.go
  • internal/bootstrap/schema/schema.go
  • internal/bootstrap/schema/schema_test.go
  • internal/reconcile/platformuser.go
  • internal/reconcile/platformuser_reconciler.go
  • internal/reconcile/platformuser_reconciler_test.go
  • internal/reconcile/platformuser_test.go

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Improved platform-user validation for email and UUID references.
    • Normalized UUID formats to prevent unnecessary add/remove changes.
    • Clarified that an empty specification removes platform users while preserving the bootstrap service account.
  • Bug Fixes

    • Protected the bootstrap service account across supported UUID formats.
    • Rejected invalid, display-name email, and non-UUID service-user references.
    • Improved specification parsing to report unknown fields correctly.

Walkthrough

Changes

PlatformUser reconciliation hardening

Layer / File(s) Summary
Generalize bootstrap service-user identity checks
internal/bootstrap/schema/..., internal/api/v1beta1connect/platform*, internal/reconcile/platformuser_reconciler.go
Adds UUID-aware bootstrap service-user detection and applies it to removal and reconciliation protection checks.
Validate and canonicalize PlatformUser refs
internal/reconcile/platformuser.go, internal/reconcile/platformuser_test.go, docs/content/docs/reconcile.mdx
Restricts refs to valid UUIDs or bare emails by principal type, canonicalizes UUIDs before diffing, and documents the rules.
Apply strict decoding in reconciliation
internal/reconcile/platformuser_reconciler.go, internal/reconcile/platformuser_reconciler_test.go
Uses shared spec decoding, rejects unknown fields, and updates exported-principal fixtures to UUID-form identifiers.

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

Possibly related PRs

Suggested reviewers: whoabhisheksah


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.

@coveralls

coveralls commented Jul 20, 2026

Copy link
Copy Markdown

Coverage Report for CI Build 29758034465

Coverage increased (+0.06%) to 46.201%

Details

  • Coverage increased (+0.06%) from the base build.
  • Patch coverage: 39 of 39 lines across 4 files are fully covered (100%).
  • No coverage regressions found.

Uncovered Changes

No uncovered changes found.

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 38436
Covered Lines: 17758
Line Coverage: 46.2%
Coverage Strength: 13.36 hits per line

💛 - Coveralls

@rohilsurana
rohilsurana force-pushed the fix/reconcile-platform-user-hardening branch from b410a3e to 1b83493 Compare July 20, 2026 16:04
@rohilsurana
rohilsurana marked this pull request as ready for review July 20, 2026 17:19
@rohilsurana
rohilsurana merged commit 9c2a0b0 into main Jul 20, 2026
7 of 8 checks passed
@rohilsurana
rohilsurana deleted the fix/reconcile-platform-user-hardening branch July 20, 2026 17:19
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.

2 participants