// smoke: permission admin endpoints (Bearer + Casbin RBAC required) // // Goal: verify each route is wired and rejects a non-admin caller. Full happy- // path admin testing lives in journeys/rbac_admin.js (requires seeded admin). // // Covers (12 endpoints, mostly negative since the test user has no admin role): // GET /api/v1/permissions/roles // POST /api/v1/permissions/roles // PATCH /api/v1/permissions/roles/:id // DELETE /api/v1/permissions/roles/:id // GET /api/v1/permissions/roles/:id/permissions // PUT /api/v1/permissions/roles/:id/permissions // GET /api/v1/permissions/users/:uid/roles // POST /api/v1/permissions/users/:uid/roles // DELETE /api/v1/permissions/users/:uid/roles/:role_id // GET /api/v1/permissions/role-mappings // PUT /api/v1/permissions/role-mappings // DELETE /api/v1/permissions/role-mappings // POST /api/v1/permissions/policy/reload // // Each call is expected to return 403 (RBAC) — we just need to confirm the // status is non-2xx and the route exists (no 404). import { get, post, put, patch, del } from '../lib/http.js'; import { check } from 'k6'; import { registerAndConfirm } from '../lib/auth.js'; export const options = { vus: 1, iterations: 1, thresholds: { checks: ['rate==1.0'] }, }; function assertForbidden(res, label) { // Casbin reject → 403 (31507000 forbidden). We tolerate 401/403 here since // the exact code may vary across edge cases (missing role vs RBAC denied). const ok = check(res, { [`${label}: route exists (not 404)`]: (r) => r.status !== 404, [`${label}: non-2xx (RBAC blocks)`]: (r) => r.status >= 400 && r.status < 500, }); if (!ok) { throw new Error(`${label}: unexpected status ${res.status} body=${res.body}`); } } export default function () { const { tokens } = registerAndConfirm(); const bearer = { Authorization: `Bearer ${tokens.access_token}` }; const fakeID = '000000000000000000000000'; assertForbidden(get('/api/v1/permissions/roles', bearer), 'GET /roles'); assertForbidden(post('/api/v1/permissions/roles', { key: 'smoke_role' }, bearer), 'POST /roles'); assertForbidden(patch(`/api/v1/permissions/roles/${fakeID}`, { display_name: 'x' }, bearer), 'PATCH /roles/:id'); assertForbidden(del(`/api/v1/permissions/roles/${fakeID}`, null, bearer), 'DELETE /roles/:id'); assertForbidden(get(`/api/v1/permissions/roles/${fakeID}/permissions`, bearer), 'GET /roles/:id/permissions'); assertForbidden(put(`/api/v1/permissions/roles/${fakeID}/permissions`, { permission_ids: [] }, bearer), 'PUT /roles/:id/permissions'); assertForbidden(get(`/api/v1/permissions/users/${tokens.uid}/roles`, bearer), 'GET /users/:uid/roles'); assertForbidden(post(`/api/v1/permissions/users/${tokens.uid}/roles`, { role_id: fakeID }, bearer), 'POST /users/:uid/roles'); assertForbidden(del(`/api/v1/permissions/users/${tokens.uid}/roles/${fakeID}`, null, bearer), 'DELETE /users/:uid/roles/:role_id'); assertForbidden(get('/api/v1/permissions/role-mappings', bearer), 'GET /role-mappings'); assertForbidden(put('/api/v1/permissions/role-mappings', { external_source: 'zitadel', external_key: 'smoke', internal_role_key: 'platform_admin', }, bearer), 'PUT /role-mappings'); assertForbidden(del('/api/v1/permissions/role-mappings', { external_source: 'zitadel', external_key: 'smoke', }, bearer), 'DELETE /role-mappings'); assertForbidden(post('/api/v1/permissions/policy/reload', {}, bearer), 'POST /policy/reload'); }