Show provisioning requesters and reserve Maxis for system actions

This commit is contained in:
2026-10-08 16:19:49 -04:00
parent 2b155ded8f
commit d8fb7e1d66
10 changed files with 77 additions and 15 deletions
+24
View File
@@ -54,6 +54,16 @@ function gate<T>() {
}
describe('initial administrator setup', () => {
it('reserves Maxis for system actions regardless of username case', async () => {
for (const username of ['Maxis', 'maxis', 'MAXIS', 'mAxIs']) {
await expect(auth.bootstrapAdmin({ username, password, token: setupToken }, '192.0.2.1'))
.rejects.toMatchObject({ status: 400, message: 'Maxis is reserved for system actions. Choose another username.' });
}
expect(auth.setupRequired()).toBe(true);
expect(auth.listUsers()).toEqual([]);
expect(database.db().prepare('SELECT COUNT(*) AS count FROM auth_sessions').get()).toEqual({ count: 0 });
});
it('requires an owner token and never creates an account from missing or wrong credentials', async () => {
const input = { username: 'Admin', password, token: setupToken };
vi.stubEnv('EC_SETUP_TOKEN', undefined);
@@ -136,6 +146,20 @@ describe('password storage and verification', () => {
});
describe('administrator user management', () => {
it('rejects the reserved system username for every role while allowing distinct usernames', async () => {
const admin = seedUser();
for (const role of ['admin', 'operator', 'viewer'] as const) {
for (const username of ['Maxis', 'maxis', 'MAXIS', 'mAxIs']) {
await expect(auth.createUser(admin.id, { username, role, password }))
.rejects.toMatchObject({ status: 400, message: 'Maxis is reserved for system actions. Choose another username.' });
}
}
expect(auth.listUsers()).toHaveLength(1);
expect(auth.listAuthAudit()).toEqual([]);
await expect(auth.createUser(admin.id, { username: 'maxis-operator', role: 'operator', password }))
.resolves.toMatchObject({ username: 'maxis-operator' });
});
it('creates each supported role with a forced initial password change and rejects case-insensitive duplicate names', async () => {
const admin = seedUser();
for (const role of ['admin', 'operator', 'viewer'] as const) {