ActingAs does not carry OrgAdmin to the org acted for

Administering one's own org says nothing about the target, so the derived
caller reads and forwards OrgAdmin as false. Owner and Admin, the principal's
own platform authority, are unchanged.

Co-authored-by: Hanzo Dev <[email protected]>
This commit is contained in:
zooqueen
2026-09-24 11:23:38 -07:00
co-authored by Hanzo Dev
parent 8bf54e1f98
commit fc957a2bdb
2 changed files with 23 additions and 0 deletions
+19
View File
@@ -155,3 +155,22 @@ func TestActingAs_IsWhatAnOutboundCallCarries(t *testing.T) {
t.Errorf("a stated ActingAs forwarded org %q acted-by %q, want acme and u-admin", h[HeaderOrg], h[HeaderActedBy])
}
}
// Administering one's own org is not administering the org acted for, so the derived
// caller does not carry OrgAdmin there, on the context or on the next hop.
func TestActingAs_DoesNotCarryOrgAdminToTheTarget(t *testing.T) {
ctx := WithCaller(context.Background(), Caller{User: "u", Org: "acme", Owner: "acme", OrgAdmin: true})
acting, err := ActingAs(ctx, "globex")
if err != nil {
t.Fatal(err)
}
if CallerOf(acting).OrgAdmin {
t.Error("an org admin of acme reads as an org admin of globex")
}
if h := forwarded(acting); h[HeaderUserOrgAdmin] != "" {
t.Errorf("the next hop receives %s = %q for globex", HeaderUserOrgAdmin, h[HeaderUserOrgAdmin])
}
if !CallerOf(ctx).OrgAdmin {
t.Error("ActingAs changed the caller it derived from")
}
}
+4
View File
@@ -294,6 +294,10 @@ func ActingAs(ctx context.Context, org string) (context.Context, error) {
acting := base
acting.Org = org
acting.Project = "" // a project is scoped to the original org, never to the target
// Administering one's own org says nothing about the org acted for, so the derived
// caller does not carry it there. Platform authority (Owner, Admin) is the
// principal's own and stays.
acting.OrgAdmin = false
if base.ActedBy != "" {
// Already an impersonation: the ORIGINAL actor stays the actor, so a
// chain of hops cannot quietly reassign who is responsible.