Skip to content

refactor(api/Principal): rebase #864 onto post-#907 group-only authz model (closes followup) #1010

Description

@cristim

Summary

PR #864 (refactor(api): requireAuth returns resolved Principal, branch fix/194-wave18) is structurally incompatible with the current feat/multicloud-web-frontend base after PR #907 (group-membership-only authorization, removed Session.Role and User.Role) landed. The PR predates that reshape and still encodes role-based identity in the new Principal type. A rebase plus a small design call is needed before the PR can land. Adversarial review of PR #864 surfaced this in the failing CI run on commit f6d3dc51f (internal/api/middleware.go:166:20: session.Role undefined (type *Session has no field or method Role)).

Where it lives

Why this needs a design call rather than a tactical patch

If I had just dropped session.Role from Principal and the bearer-path Principal construction, three further problems would remain:

  1. Silent runtime regression on the user-API-key path. principalFromUserAPIKey does a structural interface assertion against userRaw requiring GetID/GetEmail/GetRole. On base, *auth.User exposes none of those accessors — the assertion ALWAYS fails closed at runtime. Every valid user-API-key request would 401. Tests don't catch it because they pass a synthetic testUserRecord that satisfies the interface. Fixing it requires picking a real shape for the field extraction (add accessor methods on auth.User, or convert via auth.ValidateUserAPIKeyAPI to a typed *APIUser, or push the conversion into the interface).
  2. Principal as "identity + role" is the wrong shape post-Revamp authorization: group-membership-only (remove roles), require >=1 group per user #907. Authorization is now derived from group permissions, not a Role string. The new Principal should either carry GroupIDs []string (and let downstream handlers fan out to HasPermissionAPI), or expose a thin IsAdmin()/Permissions view computed at construction. Both are reasonable but mutually exclusive. Picking one sets the contract every future caller will see (the whole point of PR refactor(api): requireAuth returns resolved Principal (closes #194) #864 is to give downstream handlers a typed identity).
  3. Tests need to be re-written, not just adjusted. The {has-auth, lacks-auth, admin, user} cross-product is currently expressed against Role. In the group-only model the cells need to be {admin-api-key, user-with-admin-group, user-with-other-groups, user-with-zero-groups, no-credential, invalid-credential} — coverage that the current PR doesn't reach.

Proposed shape (for discussion)

type Principal struct {
    Kind     PrincipalKind
    UserID   string   // empty for PrincipalAdminAPIKey
    Email    string   // empty for PrincipalAdminAPIKey
    GroupIDs []string // post-#907 authz scope; "*" sentinel for admin-API-key
    Session  *Session // non-nil only for PrincipalSession
}

with a helper func (p *Principal) HasPermission(ctx, auth, action, resource) that fans out to AuthServiceInterface.HasPermissionAPI for session/user-API-key principals and short-circuits true for admin-API-key. That keeps the "callers don't re-resolve identity" goal of #194 without re-introducing the role string.

Acceptance criteria

  • Rebase fix/194-wave18 onto current feat/multicloud-web-frontend HEAD; resolve internal/api/middleware.go + internal/api/router_authuser_test.go conflicts.
  • Drop Principal.Role; replace with whatever shape is agreed (default: GroupIDs []string + small helper).
  • Replace the local GetID/GetEmail/GetRole interface assertion in principalFromUserAPIKey with the agreed extraction path; add an integration-style test that exercises the real *auth.User value path (catches the regression that the current PR ships).
  • Tests cover the cross-product {admin-api-key, user-with-admin-group, user-with-non-admin-group, user-with-zero-groups, no-credential, invalid-bearer, valid-user-api-key, invalid-user-api-key, nil-auth} — at least one cell per dimension.
  • requireAdmin is NOT re-introduced as a role-based check (Revamp authorization: group-membership-only (remove roles), require >=1 group per user #907 already moved it to HasPermissionAPI).
  • Pre-commit CI green on the merge ref (no vet failure).

Related

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions