diff --git a/realm-policy/realm-policy.gts b/realm-policy/realm-policy.gts index 611f77dec..4fb9db49d 100644 --- a/realm-policy/realm-policy.gts +++ b/realm-policy/realm-policy.gts @@ -127,13 +127,16 @@ export class OperationGrant extends FieldDef { @field where = contains(PolicyPredicateField); // Whether the grant also admits a caller who isn't signed in. Off, it // admits only signed-in callers, so a grant written before anonymous - // callers could reach a policy never starts admitting them. Only a grant on - // a base operation under its own name (`read`, `update`, …) may set it, not - // one on a custom operation or a named query. The realm doesn't evaluate a - // `where` that reads `actor()` for such a caller, so a grant whose `where` - // does never admits one: an anonymous grant is scoped by what the target - // holds. How hard anonymous callers may use the realm, and which addresses - // it refuses, are the governed realm's own settings, not the policy's. + // callers could reach a policy never starts admitting them. A grant on a + // base operation other than `explain` or `validate` may set it, and so may + // one on an operation a card declares on such a base. A grant on a named + // query may not: setting it there leaves the whole grant out, for + // signed-in callers too. Such a caller has no actor, so a grant whose + // `where` reads `actor()`, or whose operation does, never admits one, + // though it still applies to signed-in callers: an anonymous grant is + // scoped by what the target holds. How hard anonymous callers may use the + // realm, and which addresses it refuses, are the governed realm's own + // settings, not the policy's. @field anonymous = contains(BooleanField); // For an anonymous grant on a write: the key, exactly as written, in the // governed realm's `realm.json` settings, whose value is the user the write @@ -389,8 +392,9 @@ export class PolicyRule extends FieldDef { } // What each reason an explanation gives means, in the words a policy author -// reads it in. -const REASONS: Record = { +// reads it in. `reads-actor` is named here as well as through the explanation +// type, so the map covers it whichever platform version this realm runs on. +const REASONS: Record = { acl: "The realm's own permissions already allow this, so the policy isn't needed.", granted: 'A grant in this policy allows it.', 'no-grant': "No rule for this card's type grants this operation.", @@ -408,6 +412,8 @@ const REASONS: Record = { 'not-resolved': "This card doesn't have this operation.", 'actor-required': "Someone who isn't signed in is turned away before the policy is checked.", + 'reads-actor': + "This operation depends on who is asking, and someone who isn't signed in can't be identified, so a grant that opens it to them doesn't apply.", 'policy-unloadable': "The realm's policy couldn't be loaded.", }; @@ -1400,6 +1406,9 @@ class ExplainPanel extends GlimmerComponent { data-test-explain-actor /> +

+ Leave this empty to check what someone who isn't signed in can do. +

{{#if this.isCard}}