Skip to content

Commit d721e50

Browse files
zeevmoneyclaude
andcommitted
test: register the user attribute used by the ABAC condition set
A userset condition set referencing user.<attr> requires that attribute to exist on the built-in user resource; users.sync alone doesn't register it, so the condition-set creation failed with 400 MISSING_RESOURCE_ATTRIBUTE. Register a run-unique attribute on the __user resource before creating the userset, reference it consistently in the condition and the synced users, and remove it in the tolerant afterAll. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 6ade914 commit d721e50

1 file changed

Lines changed: 18 additions & 4 deletions

File tree

src/tests/e2e/condition-sets.e2e.spec.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ const USERSET_KEY = `cs_e2e_userset_${rand}`;
1515
const RESOURCESET_KEY = `cs_e2e_resourceset_${rand}`;
1616
const MATCHING_USER_KEY = `cs_e2e_user_match_${rand}`;
1717
const OTHER_USER_KEY = `cs_e2e_user_other_${rand}`;
18+
// Built-in 'user' resource key in Permit. A userset condition that references
19+
// user.<attr> requires the attribute to exist on this resource first.
20+
const USER_RESOURCE_KEY = '__user';
21+
const USER_ATTR = `cs_e2e_clearance_${rand}`;
1822
const ACTION = 'read';
1923
const PERMISSION = `${RESOURCE_KEY}:${ACTION}`;
2024
const TENANT = 'default';
@@ -33,6 +37,9 @@ afterAll(async () => {
3337
.catch(() => undefined);
3438
await permit.api.conditionSets.delete(USERSET_KEY).catch(() => undefined);
3539
await permit.api.conditionSets.delete(RESOURCESET_KEY).catch(() => undefined);
40+
// Remove the attribute from the built-in user resource after the userset that
41+
// referenced it is gone. The built-in '__user' resource itself is never deleted.
42+
await permit.api.resourceAttributes.delete(USER_RESOURCE_KEY, USER_ATTR).catch(() => undefined);
3643
await permit.api.users.delete(MATCHING_USER_KEY).catch(() => undefined);
3744
await permit.api.users.delete(OTHER_USER_KEY).catch(() => undefined);
3845
await permit.api.resources.delete(RESOURCE_KEY).catch(() => undefined);
@@ -65,13 +72,20 @@ it('ABAC condition-set permission check e2e test', async () => {
6572
expect(resource.key).toBe(RESOURCE_KEY);
6673
expect((resource.actions ?? {})[ACTION]).not.toBe(undefined);
6774

75+
logger.info('registering the user attribute referenced by the userset condition');
76+
const userAttribute = await permit.api.resourceAttributes.create(USER_RESOURCE_KEY, {
77+
key: USER_ATTR,
78+
type: 'string',
79+
});
80+
expect(userAttribute.key).toBe(USER_ATTR);
81+
6882
logger.info('creating the userset condition set (matches a user attribute)');
6983
const userSet = await permit.api.conditionSets.create({
7084
key: USERSET_KEY,
7185
name: USERSET_KEY,
7286
type: 'userset',
7387
conditions: {
74-
allOf: [{ 'user.clearance': { equals: 'top_secret' } }],
88+
allOf: [{ [`user.${USER_ATTR}`]: { equals: 'top_secret' } }],
7589
},
7690
});
7791
expect(userSet.key).toBe(USERSET_KEY);
@@ -103,14 +117,14 @@ it('ABAC condition-set permission check e2e test', async () => {
103117
logger.info('syncing a user that matches the userset, and one that does not');
104118
const { user: matchingUser } = await permit.api.users.sync({
105119
key: MATCHING_USER_KEY,
106-
attributes: { clearance: 'top_secret' },
120+
attributes: { [USER_ATTR]: 'top_secret' },
107121
});
108122
expect(matchingUser.key).toBe(MATCHING_USER_KEY);
109-
expect((matchingUser.attributes as Record<string, unknown>)['clearance']).toBe('top_secret');
123+
expect((matchingUser.attributes as Record<string, unknown>)[USER_ATTR]).toBe('top_secret');
110124

111125
const { user: otherUser } = await permit.api.users.sync({
112126
key: OTHER_USER_KEY,
113-
attributes: { clearance: 'public' },
127+
attributes: { [USER_ATTR]: 'public' },
114128
});
115129
expect(otherUser.key).toBe(OTHER_USER_KEY);
116130

0 commit comments

Comments
 (0)