Skip to content

Commit eccb03a

Browse files
test(resource-policies): cover actor grant resolution
1 parent 8b6202e commit eccb03a

1 file changed

Lines changed: 54 additions & 6 deletions

File tree

apps/sim/lib/credential-groups/application/authorization.test.ts

Lines changed: 54 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,26 @@ import type { WorkflowExecutionDelegatedPrincipal } from '@sim/auth/principal'
55
import { beforeEach, describe, expect, it, vi } from 'vitest'
66

77
const mocks = vi.hoisted(() => ({
8+
findPolicyGrant: vi.fn(),
89
loadEnrollmentAccess: vi.fn(),
910
}))
1011

1112
vi.mock('@/lib/credential-groups/credentials', () => ({
1213
loadCredentialGroupEnrollmentAccessForSubject: mocks.loadEnrollmentAccess,
1314
}))
1415

15-
import { requireCredentialGroupEnrollmentAccess } from '@/lib/credential-groups/application/authorization'
16+
vi.mock('@/lib/resource-policies/authorization', () => ({
17+
findResourcePolicyGrant: mocks.findPolicyGrant,
18+
}))
19+
20+
import { requireCredentialGroupCredentialAccess } from '@/lib/credential-groups/application/authorization'
21+
22+
const context = {
23+
workspaceId: 'workspace-1',
24+
workspaceOrganizationId: null,
25+
allowPersonalApiKeys: true,
26+
credentialGroupId: 'group-1',
27+
}
1628

1729
function executorPrincipal(): WorkflowExecutionDelegatedPrincipal {
1830
return {
@@ -44,9 +56,10 @@ function executorPrincipal(): WorkflowExecutionDelegatedPrincipal {
4456
}
4557
}
4658

47-
describe('requireCredentialGroupEnrollmentAccess', () => {
59+
describe('requireCredentialGroupCredentialAccess', () => {
4860
beforeEach(() => {
4961
vi.clearAllMocks()
62+
mocks.findPolicyGrant.mockResolvedValue(null)
5063
mocks.loadEnrollmentAccess.mockResolvedValue({
5164
enrollmentId: 'enrollment-1',
5265
email: 'person@example.com',
@@ -56,7 +69,14 @@ describe('requireCredentialGroupEnrollmentAccess', () => {
5669
it('resolves an external workflow actor to their enrollment', async () => {
5770
const principal = executorPrincipal()
5871

59-
await expect(requireCredentialGroupEnrollmentAccess(principal, 'group-1')).resolves.toEqual({
72+
await expect(
73+
requireCredentialGroupCredentialAccess(
74+
principal,
75+
context,
76+
'credential_groups.credentials.use'
77+
)
78+
).resolves.toEqual({
79+
scope: 'enrollment',
6080
enrollmentId: 'enrollment-1',
6181
email: 'person@example.com',
6282
})
@@ -78,10 +98,14 @@ describe('requireCredentialGroupEnrollmentAccess', () => {
7898
}
7999

80100
await expect(
81-
requireCredentialGroupEnrollmentAccess(principal, 'group-1')
101+
requireCredentialGroupCredentialAccess(
102+
principal,
103+
context,
104+
'credential_groups.credentials.use'
105+
)
82106
).rejects.toMatchObject({
83107
code: 'forbidden',
84-
message: 'Credential Group enrollment access required',
108+
message: 'Credential Group actor access required',
85109
})
86110
expect(mocks.loadEnrollmentAccess).not.toHaveBeenCalled()
87111
})
@@ -96,8 +120,32 @@ describe('requireCredentialGroupEnrollmentAccess', () => {
96120
}
97121

98122
await expect(
99-
requireCredentialGroupEnrollmentAccess(principal, 'group-1')
123+
requireCredentialGroupCredentialAccess(
124+
principal,
125+
context,
126+
'credential_groups.credentials.use'
127+
)
100128
).rejects.toMatchObject({ code: 'forbidden' })
101129
expect(mocks.loadEnrollmentAccess).not.toHaveBeenCalled()
102130
})
131+
132+
it('allows an actorless workflow when an explicit policy grant matches', async () => {
133+
const principal = executorPrincipal()
134+
principal.delegationContext!.principal = {
135+
kind: 'system',
136+
serviceId: 'schedule',
137+
workspaceId: 'workspace-1',
138+
workflowId: 'workflow-1',
139+
}
140+
mocks.findPolicyGrant.mockResolvedValue({ id: 'grant-1' })
141+
142+
await expect(
143+
requireCredentialGroupCredentialAccess(
144+
principal,
145+
context,
146+
'credential_groups.credentials.use'
147+
)
148+
).resolves.toEqual({ scope: 'all', grantId: 'grant-1' })
149+
expect(mocks.loadEnrollmentAccess).not.toHaveBeenCalled()
150+
})
103151
})

0 commit comments

Comments
 (0)