template-monorepo/test/k6/smoke/permission_admin.js

71 lines
3.4 KiB
JavaScript
Raw Permalink Normal View History

2026-05-26 06:05:33 +00:00
// 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');
}