Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion src/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,18 @@ import type { AdminPermission } from './types.js';



// ADMIN_ROLES and ADMIN_PERMISSIONS must mirror the ratified vocabulary in
// @tummycrypt/tinyland-auth v0.4.0 (src/types/auth.ts ADMIN_ROLES,
// src/types/permissions.ts AdminPermission) exactly. See TIN-2435.
// tests/vocabulary-alignment.test.ts asserts this stays in sync.
export const ADMIN_ROLES: AdminRole[] = [
'super_admin',
'admin',
'moderator',
'editor',
'event_manager',
'contributor',
'member',
'viewer',
];

Expand All @@ -32,7 +37,6 @@ export const ADMIN_ROLES: AdminRole[] = [
export const ADMIN_PERMISSIONS: AdminPermission[] = [
'admin.access',
'admin.users.manage',
'admin.users.moderate',
'admin.content.manage',
'admin.content.moderate',
'admin.events.manage',
Expand Down Expand Up @@ -63,6 +67,7 @@ export const adminUserSchema = z.object({
'editor',
'event_manager',
'contributor',
'member',
'viewer',
]),
certificateCn: z.string().nullable().optional(),
Expand Down Expand Up @@ -93,6 +98,7 @@ export const createAdminUserSchema = z.object({
'editor',
'event_manager',
'contributor',
'member',
'viewer',
]),
totpEnabled: z.boolean().optional().default(false),
Expand All @@ -114,6 +120,8 @@ export const updateAdminUserSchema = z.object({
'editor',
'event_manager',
'moderator',
'contributor',
'member',
'viewer',
])
.optional(),
Expand Down
6 changes: 5 additions & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,14 @@



// Must mirror the ratified permission vocabulary in @tummycrypt/tinyland-auth
// v0.4.0 (src/types/permissions.ts AdminPermission). This is a validated
// subset (not the full 21-permission authority set); every entry here must
// also exist there. See TIN-2435; tests/vocabulary-alignment.test.ts asserts
// this stays in sync.
export type AdminPermission =
| 'admin.access'
| 'admin.users.manage'
| 'admin.users.moderate'
| 'admin.content.manage'
| 'admin.content.moderate'
| 'admin.events.manage'
Expand Down
21 changes: 10 additions & 11 deletions tests/admin-validation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,19 +162,18 @@ describe('Types', () => {
expect(log.admin_user_id).toBe('usr_1');
});

it('AdminPermission type allows all 9 permission values', () => {
it('AdminPermission type allows all 8 permission values', () => {
const perms: AdminPermission[] = [
'admin.access',
'admin.users.manage',
'admin.users.moderate',
'admin.content.manage',
'admin.content.moderate',
'admin.events.manage',
'admin.analytics.view',
'admin.settings.manage',
'admin.security.manage',
];
expect(perms).toHaveLength(9);
expect(perms).toHaveLength(8);
});
});

Expand All @@ -183,8 +182,8 @@ describe('Types', () => {


describe('ADMIN_ROLES', () => {
it('has exactly 7 entries', () => {
expect(ADMIN_ROLES).toHaveLength(7);
it('has exactly 8 entries', () => {
expect(ADMIN_ROLES).toHaveLength(8);
});

it('includes super_admin', () => {
Expand Down Expand Up @@ -215,8 +214,8 @@ describe('ADMIN_ROLES', () => {
expect(ADMIN_ROLES).toContain('viewer');
});

it('does not include member', () => {
expect(ADMIN_ROLES).not.toContain('member');
it('includes member', () => {
expect(ADMIN_ROLES).toContain('member');
});

it('is an array', () => {
Expand All @@ -229,8 +228,8 @@ describe('ADMIN_ROLES', () => {


describe('ADMIN_PERMISSIONS', () => {
it('has exactly 9 entries', () => {
expect(ADMIN_PERMISSIONS).toHaveLength(9);
it('has exactly 8 entries', () => {
expect(ADMIN_PERMISSIONS).toHaveLength(8);
});

it('includes admin.access', () => {
Expand All @@ -241,8 +240,8 @@ describe('ADMIN_PERMISSIONS', () => {
expect(ADMIN_PERMISSIONS).toContain('admin.users.manage');
});

it('includes admin.users.moderate', () => {
expect(ADMIN_PERMISSIONS).toContain('admin.users.moderate');
it('does not include the dead admin.users.moderate string (TIN-2435)', () => {
expect(ADMIN_PERMISSIONS).not.toContain('admin.users.moderate');
});

it('includes admin.content.manage', () => {
Expand Down
66 changes: 66 additions & 0 deletions tests/vocabulary-alignment.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { describe, it, expect } from 'vitest';
import { ADMIN_ROLES, ADMIN_PERMISSIONS } from '../src/index.js';

// TIN-2435: ADMIN_ROLES and ADMIN_PERMISSIONS in this package must never
// drift from the ratified vocabulary in @tummycrypt/tinyland-auth v0.4.0.
// This package cannot import runtime values from @tummycrypt/tinyland-auth
// outside the Bazel module graph (it is only linked as a Bazel npm_link
// dependency, not an npm dependency of this package -- see MODULE.bazel /
// BUILD.bazel), so the authority's ADMIN_ROLES is transcribed here by hand
// from tinyland-auth src/types/auth.ts as of v0.4.0. If tinyland-auth's
// role vocabulary changes, this transcription -- and ADMIN_ROLES above --
// must be updated together.
const AUTH_ADMIN_ROLES_V0_4_0 = [
'super_admin',
'admin',
'moderator',
'editor',
'event_manager',
'contributor',
'member',
'viewer',
];

describe('vocabulary alignment with @tummycrypt/tinyland-auth v0.4.0 (TIN-2435)', () => {
it('ADMIN_ROLES matches the authority ADMIN_ROLES exactly (8 roles, includes member)', () => {
expect([...ADMIN_ROLES].sort()).toEqual([...AUTH_ADMIN_ROLES_V0_4_0].sort());
expect(ADMIN_ROLES).toHaveLength(8);
expect(ADMIN_ROLES).toContain('member');
});

it('ADMIN_PERMISSIONS contains no dead strings absent from the authority vocabulary', () => {
// The authority's 21-permission set (src/types/permissions.ts
// AdminPermission in tinyland-auth). This package validates a subset;
// every entry here must also be a member of the authority set.
const AUTHORITY_PERMISSIONS = [
'admin.access',
'admin.users.view',
'admin.users.manage',
'admin.users.delete',
'admin.content.view',
'admin.content.publish',
'admin.content.media_create',
'admin.content.manage',
'admin.content.moderate',
'admin.content.delete',
'admin.events.view',
'admin.events.manage',
'admin.events.delete',
'admin.analytics.view',
'admin.analytics.export',
'admin.settings.view',
'admin.settings.manage',
'admin.security.view',
'admin.security.manage',
'admin.logs.view',
'admin.logs.export',
];

for (const perm of ADMIN_PERMISSIONS) {
expect(AUTHORITY_PERMISSIONS).toContain(perm);
}

// The dead string dropped by TIN-2435 must not reappear.
expect(ADMIN_PERMISSIONS).not.toContain('admin.users.moderate');
});
});
Loading