Skip to content
Merged
Show file tree
Hide file tree
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
3 changes: 2 additions & 1 deletion packages/catalog/test-subset.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"repository": "cardstack/boxel-catalog",
"revision": "776baef8ccd1bc4c370711797374a79905c4e965",
"revision": "708a03324f6c0d3b8dceda9a200f4244e07bef5a",
"files": [
{
"path": "realm-policy/realm-policy.gts",
Expand All @@ -21,6 +21,7 @@
"realmServer": [
"catalog-test-subset-test",
"realm-policy-activation-test",
"realm-policy-anonymous-explain-test",
"realm-policy-anonymous-named-operation-test",
"realm-policy-anonymous-read-test",
"realm-policy-anonymous-search-test",
Expand Down
16 changes: 16 additions & 0 deletions packages/host/tests/helpers/index.gts
Original file line number Diff line number Diff line change
Expand Up @@ -2635,6 +2635,13 @@ export function realmConfigCardJSON(
includePrerenderedDefaultRealmIndex?: boolean;
// The URL of the card whose policy governs the realm.
policy?: string;
// The realm's own settings, which a card operation reads with
// `realmConfig("key")`.
config?: Record<string, unknown>;
// How the realm limits and blocks callers its policy admits without a
// session.
anonymousRateLimit?: { requests: number; windowSeconds: number };
anonymousBlocklist?: string[];
} = {},
): string {
let attrs: Record<string, unknown> = {};
Expand All @@ -2654,6 +2661,15 @@ export function realmConfigCardJSON(
if (config.policy !== undefined) {
attrs.policy = config.policy;
}
if (config.config !== undefined) {
attrs.config = config.config;
}
if (config.anonymousRateLimit !== undefined) {
attrs.anonymousRateLimit = config.anonymousRateLimit;
}
if (config.anonymousBlocklist !== undefined) {
attrs.anonymousBlocklist = config.anonymousBlocklist;
}
return JSON.stringify({
data: {
type: 'card',
Expand Down
71 changes: 71 additions & 0 deletions packages/host/tests/integration/realm-policy-test.gts
Original file line number Diff line number Diff line change
Expand Up @@ -752,6 +752,77 @@ module('Integration | realm policy', function (hooks) {
);
}

test('an explanation for someone who is not signed in shows the limit, the blocklist, and who each grant opened to them writes as', async function (assert) {
await setupIntegrationTestRealm({
mockMatrixUtils,
permissions: {
'*': ['read'],
'@testuser:localhost': ['read', 'write', 'realm-owner'],
},
contents: {
'realm.json': realmConfigCardJSON({
policy: `${testRealmURL}policies/classrooms`,
config: { submitter: '@testuser:localhost' },
anonymousRateLimit: { requests: 7, windowSeconds: 30 },
anonymousBlocklist: ['not an address'],
}),
'classroom.gts': classroomModule,
'classrooms/room-204.json': classroom([TEACHER]),
'policies/classrooms.json': policyDocument([
{
targetType: { module: '../classroom', name: 'Classroom' },
grants: [
{ operation: 'update', anonymous: true, actingUser: 'submitter' },
{ operation: 'update', anonymous: true, actingUser: 'missing' },
// Reads the caller, so it is warned about.
{
operation: 'update',
anonymous: true,
actingUser: 'submitter',
where: teachesPredicate,
},
],
},
]),
},
});
await getService('realm').login(testRealmURL);
getService('operations');
let policy = await loadPolicy('policies/classrooms');
await renderCard(loader, policy, 'isolated');

await ask('', `${testRealmURL}classrooms/room-204`, 'update');
assert.dom('[data-test-explanation-actor]').hasText('not signed in');
assert
.dom('[data-test-explanation-reason]')
.hasText(
"This realm's blocklist has an entry that isn't an address or a range, so it turns away everyone who isn't signed in before the policy is checked.",
);
assert
.dom('[data-test-explanation-anonymous-limit]')
.hasText('7 requests per 30 seconds from one address, set by this realm');
assert
.dom('[data-test-explanation-anonymous-blocklist]')
.includesText('"not an address"', 'names the entry to fix');
assert.deepEqual(
[
...document.querySelectorAll('[data-test-explanation-grant-anonymous]'),
].map((el) => el.textContent?.trim()),
[
'Open to people who aren\'t signed in; their writes are made as @testuser:localhost (this realm\'s "submitter" setting).',
'Open to people who aren\'t signed in, but this realm\'s settings have no "missing", so this grant admits none of them.',
'Open to people who aren\'t signed in; their writes are made as @testuser:localhost (this realm\'s "submitter" setting).',
],
);
assert.deepEqual(
[...document.querySelectorAll('[data-test-explanation-grant-issue]')].map(
(el) => el.getAttribute('data-test-explanation-grant-issue'),
),
['anonymous-grant-reads-actor'],
'the grant whose condition reads the caller carries its warning',
);
});

test('the policy explains what it decides for one caller, one card and one operation', async function (assert) {
await renderClassroomPolicy();

Expand Down
Loading
Loading