Skip to content

Commit e2c305f

Browse files
authored
Add the RBAC and Auth API helpers (#50)
* feat(playwright): add the rbac and auth api helpers Signed-off-by: Patrick Knight <pknight@redhat.com> * feat(playwright): add docs for the additional api helpers Signed-off-by: Patrick Knight <pknight@redhat.com> * feat(playwright): add the ability to fetch and delete rbac conditions Signed-off-by: Patrick Knight <pknight@redhat.com> * feat(playwright): handle some review suggestions Signed-off-by: Patrick Knight <pknight@redhat.com> * feat(playwright): throw an error when policy response isn't an array Signed-off-by: Patrick Knight <pknight@redhat.com> * feat(playwright): move plugin-rbac-common from devDependencies to dependencies Signed-off-by: Patrick Knight <pknight@redhat.com> --------- Signed-off-by: Patrick Knight <pknight@redhat.com>
1 parent 9561ad6 commit e2c305f

13 files changed

Lines changed: 935 additions & 12 deletions

File tree

docs/.vitepress/config.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,8 @@ export default defineConfig({
116116
{ text: "UIhelper", link: "/guide/helpers/ui-helper" },
117117
{ text: "LoginHelper", link: "/guide/helpers/login-helper" },
118118
{ text: "APIHelper", link: "/guide/helpers/api-helper" },
119+
{ text: "AuthApiHelper", link: "/guide/helpers/auth-api-helper" },
120+
{ text: "RbacApiHelper", link: "/guide/helpers/rbac-api-helper" },
119121
],
120122
},
121123
{
@@ -219,6 +221,8 @@ export default defineConfig({
219221
{ text: "UIhelper", link: "/api/helpers/ui-helper" },
220222
{ text: "LoginHelper", link: "/api/helpers/login-helper" },
221223
{ text: "APIHelper", link: "/api/helpers/api-helper" },
224+
{ text: "AuthApiHelper", link: "/api/helpers/auth-api-helper" },
225+
{ text: "RbacApiHelper", link: "/api/helpers/rbac-api-helper" },
222226
],
223227
},
224228
{
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# AuthApiHelper API
2+
3+
Retrieves Backstage identity tokens from a running RHDH auth API.
4+
5+
## Import
6+
7+
```typescript
8+
import { AuthApiHelper } from '@red-hat-developer-hub/e2e-test-utils/helpers';
9+
```
10+
11+
## Constructor
12+
13+
```typescript
14+
new AuthApiHelper(page: Page)
15+
```
16+
17+
| Parameter | Type | Description |
18+
| --------- | ------ | --------------------------------------------- |
19+
| `page` | `Page` | Playwright `Page` with an active RHDH session |
20+
21+
## Methods
22+
23+
### `getToken()`
24+
25+
```typescript
26+
async getToken(
27+
provider?: string,
28+
environment?: string
29+
): Promise<string>
30+
```
31+
32+
| Parameter | Type | Default | Description |
33+
| ------------- | -------- | -------------- | ------------------------------------- |
34+
| `provider` | `string` | `"oidc"` | Auth provider name configured in RHDH |
35+
| `environment` | `string` | `"production"` | Auth environment |
36+
37+
**Returns** `Promise<string>` — the Backstage identity token string.
38+
39+
**Throws** `Error` if the HTTP response is not OK, or `TypeError` if the token is absent from the response body.
40+
41+
## Example
42+
43+
```typescript
44+
import { AuthApiHelper } from '@red-hat-developer-hub/e2e-test-utils/helpers';
45+
46+
const authApiHelper = new AuthApiHelper(page);
47+
48+
// Default provider (oidc) and environment (production)
49+
const token = await authApiHelper.getToken();
50+
51+
// Custom provider
52+
const token = await authApiHelper.getToken('github');
53+
```
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
# RbacApiHelper API
2+
3+
Manages RBAC roles, policies, and conditional permission policies via the RHDH Permission API.
4+
5+
## Import
6+
7+
```typescript
8+
import {
9+
RbacApiHelper,
10+
Response,
11+
type Policy,
12+
} from '@red-hat-developer-hub/e2e-test-utils/helpers';
13+
```
14+
15+
## Types
16+
17+
### `Policy`
18+
19+
```typescript
20+
interface Policy {
21+
entityReference: string;
22+
permission: string;
23+
policy: string;
24+
effect: string;
25+
}
26+
```
27+
28+
## `RbacApiHelper`
29+
30+
### Static Methods
31+
32+
#### `build()`
33+
34+
```typescript
35+
static async build(token: string): Promise<RbacApiHelper>
36+
```
37+
38+
| Parameter | Type | Description |
39+
| --------- | -------- | ------------------------ |
40+
| `token` | `string` | Backstage identity token |
41+
42+
**Returns** `Promise<RbacApiHelper>` — a fully initialized instance.
43+
44+
### Instance Methods
45+
46+
#### `getPoliciesByRole()`
47+
48+
```typescript
49+
async getPoliciesByRole(role: string): Promise<APIResponse>
50+
```
51+
52+
| Parameter | Type | Description |
53+
| --------- | -------- | ------------------------------------ |
54+
| `role` | `string` | Role name in the `default` namespace |
55+
56+
#### `getConditions()`
57+
58+
```typescript
59+
async getConditions(): Promise<APIResponse>
60+
```
61+
62+
Fetches all conditional policies across every role.
63+
64+
#### `getConditionsByRole()`
65+
66+
```typescript
67+
async getConditionsByRole(
68+
role: string,
69+
remainingConditions: RoleConditionalPolicyDecision<PermissionAction>[]
70+
): Promise<RoleConditionalPolicyDecision<PermissionAction>[]>
71+
```
72+
73+
| Parameter | Type | Description |
74+
| --------------------- | --------------------------------------------------- | --------------------------------------------------------- |
75+
| `role` | `string` | Full role entity reference, e.g. `"role:default/my-role"` |
76+
| `remainingConditions` | `RoleConditionalPolicyDecision<PermissionAction>[]` | Conditions array fetched from `getConditions()` |
77+
78+
Filters locally — no additional HTTP request is made.
79+
80+
#### `deleteRole()`
81+
82+
```typescript
83+
async deleteRole(role: string): Promise<APIResponse>
84+
```
85+
86+
| Parameter | Type | Description |
87+
| --------- | -------- | ------------------------------------ |
88+
| `role` | `string` | Role name in the `default` namespace |
89+
90+
#### `deletePolicy()`
91+
92+
```typescript
93+
async deletePolicy(role: string, policies: Policy[]): Promise<APIResponse>
94+
```
95+
96+
| Parameter | Type | Description |
97+
| ---------- | ---------- | ------------------------------------ |
98+
| `role` | `string` | Role name in the `default` namespace |
99+
| `policies` | `Policy[]` | Array of policy objects to delete |
100+
101+
#### `deleteCondition()`
102+
103+
```typescript
104+
async deleteCondition(id: string): Promise<APIResponse>
105+
```
106+
107+
| Parameter | Type | Description |
108+
| --------- | -------- | ------------------------------------------------------------ |
109+
| `id` | `string` | The `id` field from a `RoleConditionalPolicyDecision` object |
110+
111+
## `Response`
112+
113+
### Static Methods
114+
115+
#### `removeMetadataFromResponse()`
116+
117+
```typescript
118+
static async removeMetadataFromResponse(
119+
response: APIResponse
120+
): Promise<unknown[]>
121+
```
122+
123+
Parses a Playwright `APIResponse` and strips the `metadata` field from each item in the response array.
124+
125+
**Throws** `Error` if the response cannot be parsed or is not an array.
126+
127+
## Example
128+
129+
```typescript
130+
import {
131+
AuthApiHelper,
132+
RbacApiHelper,
133+
Response,
134+
type Policy,
135+
} from '@red-hat-developer-hub/e2e-test-utils/helpers';
136+
137+
const authApiHelper = new AuthApiHelper(page);
138+
const token = await authApiHelper.getToken();
139+
const rbacApiHelper = await RbacApiHelper.build(token);
140+
141+
// Delete conditional policies for a role
142+
const conditionsResponse = await rbacApiHelper.getConditions();
143+
const allConditions = await conditionsResponse.json();
144+
const roleConditions = await rbacApiHelper.getConditionsByRole(
145+
'role:default/my-role',
146+
allConditions,
147+
);
148+
for (const condition of roleConditions) {
149+
await rbacApiHelper.deleteCondition(condition.id);
150+
}
151+
152+
// Delete standard policies and role
153+
const apiResponse = await rbacApiHelper.getPoliciesByRole('my-role');
154+
const policies = (await Response.removeMetadataFromResponse(
155+
apiResponse,
156+
)) as Policy[];
157+
await rbacApiHelper.deletePolicy('my-role', policies);
158+
await rbacApiHelper.deleteRole('my-role');
159+
```

0 commit comments

Comments
 (0)