Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 32 additions & 15 deletions packages/realm-server/tests/realm-policy-non-grantable-test.ts

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Claude Code 🤖] In "the refusal holds though a compiled policy carries the grant", the positive control passes whether or not the carried policy reaches the gate, so its message ("the carried policy is the one the gate consults") claims more than it checks. The realm's own compiled policy also grants annotate on Ledger (it compiles rules[1] to ['annotate'], as "compiling records a grant of it…" asserts), and it refuses seal and update on its own. So if the helper's compiledPolicy override stopped reaching loadPolicy, every assertion in that test would still pass. The setMotto call through carrying in "no grant admits a write a subtype declares for itself" depends on the same override. Under the realm's own policy it is refused for lack of a grant, not by the policy-card rule.

A refusal under a carried policy that grants nothing would pin this, because the realm's own policy admits the same call:

await assert.rejects(
  carrying([], LEDGER_1)('annotate'),
  /operation-not-permitted/,
  'the gate consults the carried policy, which grants nothing',
);

The assertion is pre-existing, but this PR is what makes it the suite's positive control again. Non-blocking, and worth doing here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Claude Code 🤖] Fixed in e340990228. The test asserts that carrying([], LEDGER_1)('annotate') is refused. The realm's own policy admits that same call, so the assertion fails unless the carried policy reaches the gate. The existing check is relabeled "the carried grant admits annotate". realm-policy-non-grantable-test passes locally, 18 of 18.

Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import type {
} from '@cardstack/runtime-common';
import {
newOperationScope,
resolveGatedOperation,
resolveOperation,
scopeCallerFor,
type CompiledRealmPolicy,
Expand Down Expand Up @@ -374,10 +375,17 @@ module(basename(import.meta.filename), function (hooks) {
});
}

// Resolves invocations on `url` for a reader the realm ACL declined, against
// a compiled policy holding `rules`, as the policy would be had compiling let
// them through. It shows what the gate refuses of a grant that reached a
// compiled policy however it came to be there.
// Resolves invocations on `url` for the reader, whom the realm ACL lets read
// and not write, against a compiled policy holding `rules`, as the policy
// would be had compiling let them through. It shows what the gate refuses of
// a grant that reached a compiled policy however it came to be there.
//
// It resolves through the gated entry and keeps only the definition, so it
// refuses only what the gate refuses: a write the gate admits resolves,
// though the write lock would still judge its stored card. The plain
// resolution refuses every write it would leave to the lock, which is every
// write to a stored card, so through it an admitted write would be refused
// too, and a refusal would say nothing about the gate.
function carrying(
rules: CompiledRealmPolicy['rules'],
url: string,
Expand All @@ -393,16 +401,18 @@ module(basename(import.meta.filename), function (hooks) {
...core,
policy: { ...core.policy!, compiledPolicy: async () => policy },
};
return (name) =>
resolveOperation(
carried,
{ kind: 'instance', url },
name,
newOperationScope(carried, {
caller: scopeCallerFor(READER),
coarseDeclined: 'all',
}),
);
return async (name) =>
(
await resolveGatedOperation(
carried,
{ kind: 'instance', url },
name,
newOperationScope(carried, {
caller: scopeCallerFor(READER),
coarseDeclined: 'writes',
}),
)
).definition;
}

function assertNotPermitted(
Expand Down Expand Up @@ -500,7 +510,14 @@ module(basename(import.meta.filename), function (hooks) {
assert.strictEqual(
(await resolve('annotate')).base,
'transform',
'the carried policy is the one the gate consults',
'the carried grant admits annotate',
);
// The realm's own policy grants annotate too, so only a carried policy
// that grants nothing shows the gate consults the carried one.
await assert.rejects(
carrying([], LEDGER_1)('annotate'),
/operation-not-permitted/,
'the gate consults the carried policy, which grants nothing',
);
for (let name of ['seal', 'update']) {
await assert.rejects(
Expand Down
Loading