Add backend policy tests and API client split
All checks were successful
Build and Deploy / build-and-push (push) Successful in 3m8s
All checks were successful
Build and Deploy / build-and-push (push) Successful in 3m8s
This commit is contained in:
64
backend/test/accessPolicy.test.js
Normal file
64
backend/test/accessPolicy.test.js
Normal file
@@ -0,0 +1,64 @@
|
||||
const test = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const {
|
||||
canReadUser,
|
||||
canUpdateUser,
|
||||
canManageUserStatus,
|
||||
canChangeUserEmail,
|
||||
canManageUserRoleOrTeam,
|
||||
canReadAttendance,
|
||||
} = require('../policies/accessPolicy');
|
||||
|
||||
const admin = { id: 'u_admin', tenant_id: 'tenant_a', role: 'admin', team_id: null };
|
||||
const manager = { id: 'u_manager', tenant_id: 'tenant_a', role: 'manager', team_id: 'team_a' };
|
||||
const managerWithoutTeam = { id: 'u_manager_2', tenant_id: 'tenant_a', role: 'manager', team_id: null };
|
||||
const agent = { id: 'u_agent', tenant_id: 'tenant_a', role: 'agent', team_id: 'team_a' };
|
||||
const otherAgent = { id: 'u_other_agent', tenant_id: 'tenant_a', role: 'agent', team_id: 'team_b' };
|
||||
const foreignAgent = { id: 'u_foreign', tenant_id: 'tenant_b', role: 'agent', team_id: 'team_x' };
|
||||
const superAdmin = { id: 'u_super', tenant_id: 'system', role: 'super_admin', team_id: null };
|
||||
|
||||
test('user read policy keeps tenants isolated', () => {
|
||||
assert.equal(canReadUser(admin, agent), true);
|
||||
assert.equal(canReadUser(admin, foreignAgent), false);
|
||||
assert.equal(canReadUser(superAdmin, foreignAgent), true);
|
||||
});
|
||||
|
||||
test('agents can only read and update themselves', () => {
|
||||
assert.equal(canReadUser(agent, agent), true);
|
||||
assert.equal(canReadUser(agent, otherAgent), false);
|
||||
assert.equal(canUpdateUser(agent, agent), true);
|
||||
assert.equal(canUpdateUser(agent, otherAgent), false);
|
||||
});
|
||||
|
||||
test('managers can read their team and update only team agents', () => {
|
||||
assert.equal(canReadUser(manager, agent), true);
|
||||
assert.equal(canReadUser(manager, otherAgent), false);
|
||||
assert.equal(canReadUser(managerWithoutTeam, agent), false);
|
||||
assert.equal(canUpdateUser(manager, agent), true);
|
||||
assert.equal(canUpdateUser(manager, admin), false);
|
||||
assert.equal(canUpdateUser(manager, otherAgent), false);
|
||||
});
|
||||
|
||||
test('only admins can manage role, team, and status fields', () => {
|
||||
assert.equal(canManageUserRoleOrTeam(admin), true);
|
||||
assert.equal(canManageUserRoleOrTeam(manager), false);
|
||||
assert.equal(canManageUserStatus(admin), true);
|
||||
assert.equal(canManageUserStatus(manager), false);
|
||||
assert.equal(canChangeUserEmail(agent, agent), true);
|
||||
assert.equal(canChangeUserEmail(manager, agent), false);
|
||||
});
|
||||
|
||||
test('attendance detail policy matches role boundaries', () => {
|
||||
const ownAttendance = { id: 'att_1', tenant_id: 'tenant_a', user_id: 'u_agent', team_id: 'team_a' };
|
||||
const teamAttendance = { id: 'att_2', tenant_id: 'tenant_a', user_id: 'u_another', team_id: 'team_a' };
|
||||
const otherTeamAttendance = { id: 'att_3', tenant_id: 'tenant_a', user_id: 'u_other_agent', team_id: 'team_b' };
|
||||
const foreignAttendance = { id: 'att_4', tenant_id: 'tenant_b', user_id: 'u_foreign', team_id: 'team_x' };
|
||||
|
||||
assert.equal(canReadAttendance(agent, ownAttendance), true);
|
||||
assert.equal(canReadAttendance(agent, teamAttendance), false);
|
||||
assert.equal(canReadAttendance(manager, teamAttendance), true);
|
||||
assert.equal(canReadAttendance(manager, otherTeamAttendance), false);
|
||||
assert.equal(canReadAttendance(admin, otherTeamAttendance), true);
|
||||
assert.equal(canReadAttendance(admin, foreignAttendance), false);
|
||||
assert.equal(canReadAttendance(superAdmin, foreignAttendance), true);
|
||||
});
|
||||
22
backend/test/security.test.js
Normal file
22
backend/test/security.test.js
Normal file
@@ -0,0 +1,22 @@
|
||||
const test = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const { stripEnvQuotes, hashSecret, maskSecret } = require('../utils/security');
|
||||
|
||||
test('stripEnvQuotes removes leading and trailing double quotes from env values', () => {
|
||||
assert.equal(stripEnvQuotes('"secret"'), 'secret');
|
||||
assert.equal(stripEnvQuotes('secret'), 'secret');
|
||||
assert.equal(stripEnvQuotes('"partly'), 'partly');
|
||||
});
|
||||
|
||||
test('hashSecret returns a stable sha256 digest without exposing the secret', () => {
|
||||
const first = hashSecret('fasto_sk_example');
|
||||
const second = hashSecret('fasto_sk_example');
|
||||
|
||||
assert.equal(first, second);
|
||||
assert.equal(first.length, 64);
|
||||
assert.notEqual(first, 'fasto_sk_example');
|
||||
});
|
||||
|
||||
test('maskSecret stores only an id and secret suffix', () => {
|
||||
assert.equal(maskSecret('rt_123', 'abcdefghijklmnopqrstuvwxyz'), 'masked:rt_123:uvwxyz');
|
||||
});
|
||||
Reference in New Issue
Block a user