Skip to content

Commit edae1dd

Browse files
committed
wip(security): test fixtures hold the Default Organization the single boot creates
Claude-Session: https://claude.ai/code/session_01A3vH4wwSVnJvvx5BcfUpPf Co-authored-by: Claude <noreply@anthropic.com>
1 parent 052aaf7 commit edae1dd

8 files changed

Lines changed: 89 additions & 17 deletions

‎packages/plugins/plugin-security/src/bootstrap-platform-admin-authenticable-target.test.ts‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
import { describe, it, expect, afterEach } from 'vitest';
4949
import { ObjectQL } from '@objectstack/objectql';
5050
import { SqlDriver } from '@objectstack/driver-sql';
51-
import { SysUser, SysAccount } from '@objectstack/platform-objects/identity';
51+
import { SysUser, SysAccount, SysOrganization } from '@objectstack/platform-objects/identity';
5252
import { bootstrapPlatformAdmin, shouldReplayBootstrapFor } from './bootstrap-platform-admin.js';
5353
import { seedLegacyPlatformBucket } from './__tests__/legacy-catalog-rows.testkit.js';
5454
import { SysPermissionSet } from './__tests__/legacy-catalog-objects.testkit.js';
@@ -92,7 +92,7 @@ async function boot(): Promise<ObjectQL> {
9292
version: '1.0.0',
9393
type: 'plugin',
9494
scope: 'system',
95-
objects: [SysPermissionSet, SysUserPermissionSet, SysUser, SysAccount],
95+
objects: [SysPermissionSet, SysUserPermissionSet, SysUser, SysAccount, SysOrganization],
9696
} as any);
9797
engine.registerApp({
9898
id: 'com.example.seeded-app',
@@ -110,6 +110,9 @@ async function boot(): Promise<ObjectQL> {
110110
],
111111
} as any);
112112
await engine.syncSchemas();
113+
// [ADR-0131 D3/D5] The Default Organization a `single` boot creates before any
114+
// `kernel:ready` hook runs; it owns the promotion's grant.
115+
await engine.insert('sys_organization', { id: 'org_default', name: 'Default Organization', slug: 'default' }, { context: { isSystem: true } });
113116
engines.push(engine);
114117
return engine;
115118
}

‎packages/plugins/plugin-security/src/bootstrap-platform-admin-existing-holder-scan.test.ts‎

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ import { assertEngineUpdateDispatch } from '@objectstack/metadata-core';
7373
import { ObjectQL } from '@objectstack/objectql';
7474
import { SqlDriver } from '@objectstack/driver-sql';
7575
import { resetPlatformAdminEmailMemo } from '@objectstack/core';
76-
import { SysUser, SysAccount } from '@objectstack/platform-objects/identity';
76+
import { SysUser, SysAccount, SysOrganization } from '@objectstack/platform-objects/identity';
7777
import {
7878
bootstrapPlatformAdmin,
7979
PLATFORM_ADMIN_GRANT_PAGE_SIZE,
@@ -128,9 +128,12 @@ async function boot(): Promise<ObjectQL> {
128128
version: '1.0.0',
129129
type: 'plugin',
130130
scope: 'system',
131-
objects: [SysPermissionSet, SysUserPermissionSet, SysUser, SysAccount],
131+
objects: [SysPermissionSet, SysUserPermissionSet, SysUser, SysAccount, SysOrganization],
132132
} as any);
133133
await engine.syncSchemas();
134+
// [ADR-0131 D3/D5] The Default Organization a `single` boot creates before any
135+
// `kernel:ready` hook runs; it owns the promotion's grant.
136+
await engine.insert('sys_organization', { id: 'org_default', name: 'Default Organization', slug: 'default' }, { context: { isSystem: true } });
134137
engines.push(engine);
135138
return engine;
136139
}
@@ -469,9 +472,10 @@ describe('#16861 — an existing platform admin is found, not sampled for', () =
469472
if (k.startsWith('$')) throw new Error(`fake driver: unsupported operator ${k}`);
470473
}
471474
if (object === 'sys_user_permission_set') {
472-
// Every synthetic row is organization-scoped, so the narrow leg
473-
// (`organization_id: null`) legitimately answers with nothing.
474-
if ('organization_id' in where && where.organization_id === null) return [];
475+
// Every synthetic row is another organization's, so the narrow leg
476+
// (`organization_id: null`, and the Default Organization's)
477+
// legitimately answers with nothing.
478+
if ('organization_id' in where && (where.organization_id === null || where.organization_id === 'org_default')) return [];
475479
const offset = q?.offset ?? 0;
476480
const limit = q?.limit ?? 100;
477481
const out: any[] = [];
@@ -493,6 +497,8 @@ describe('#16861 — an existing platform admin is found, not sampled for', () =
493497
: [];
494498
}
495499
if (object === 'sys_account') return [{ id: 'acc_p', user_id: 'usr_promotable' }];
500+
// [ADR-0131 D5] The Default Organization, which owns the promotion's grant.
501+
if (object === 'sys_organization') return [{ id: 'org_default', slug: 'default' }];
496502
return [];
497503
},
498504
async insert(object: string, data: any) {
@@ -523,7 +529,7 @@ describe('#16861 — an existing platform admin is found, not sampled for', () =
523529
expect(said).toContain('stopped at its ceiling');
524530
expect(said).toContain(String(PLATFORM_ADMIN_GRANT_SCAN_CEILING));
525531
expect(said).toContain('were NOT examined');
526-
expect(said).toContain('SECOND unscoped grant');
532+
expect(said).toContain('SECOND platform-admin grant');
527533
});
528534

529535
it('CONTROL: a population inside the ceiling produces no truncation warning', async () => {

‎packages/plugins/plugin-security/src/bootstrap-platform-admin-fresh-boot.golden.test.ts‎

Lines changed: 48 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import { describe, it, expect, afterEach, beforeEach } from 'vitest';
2525
import { ObjectQL } from '@objectstack/objectql';
2626
import { SqlDriver } from '@objectstack/driver-sql';
2727
import { resetPlatformAdminEmailMemo } from '@objectstack/core';
28-
import { SysUser, SysAccount } from '@objectstack/platform-objects/identity';
28+
import { SysUser, SysAccount, SysOrganization } from '@objectstack/platform-objects/identity';
2929
import { bootstrapPlatformAdmin } from './bootstrap-platform-admin.js';
3030
import { securityObjects } from './manifest.js';
3131
import { defaultPermissionSets } from './objects/default-permission-sets.js';
@@ -53,7 +53,12 @@ afterEach(async () => {
5353
resetPlatformAdminEmailMemo();
5454
});
5555

56-
/** A fresh `:memory:` database holding the security plugin's own objects and the identity tables. */
56+
/**
57+
* A fresh `:memory:` database holding the security plugin's own objects and the
58+
* identity tables — and the Default Organization a `single` boot creates before
59+
* any `kernel:ready` hook runs (ADR-0131 D3, plugin-auth's boot invariant),
60+
* which owns the promotion's grant (D5).
61+
*/
5762
async function freshEngine(): Promise<ObjectQL> {
5863
const engine = new ObjectQL();
5964
engine.registerDriver(
@@ -67,9 +72,10 @@ async function freshEngine(): Promise<ObjectQL> {
6772
version: '1.0.0',
6873
type: 'plugin',
6974
scope: 'system',
70-
objects: [SysUser, SysAccount, ...securityObjects],
75+
objects: [SysUser, SysAccount, SysOrganization, ...securityObjects],
7176
} as any);
7277
await engine.syncSchemas();
78+
await engine.insert('sys_organization', { id: 'org_default', name: 'Default Organization', slug: 'default' }, SYS);
7379
engines.push(engine);
7480
return engine;
7581
}
@@ -80,7 +86,7 @@ async function human(engine: ObjectQL, id: string, email: string, createdAt: str
8086
}
8187

8288
describe('[ADR-0131 D3/D4] a fresh single-posture database promotes its first human', () => {
83-
it('promotes the oldest account that can sign in, granting admin_full_access by name', async () => {
89+
it('promotes the oldest account that can sign in, granting admin_full_access by name, owned by the Default Organization', async () => {
8490
const engine = await freshEngine();
8591
await human(engine, 'usr_first', 'first@fresh.example', '2026-01-01T00:00:00.000Z');
8692
await human(engine, 'usr_second', 'second@fresh.example', '2026-02-01T00:00:00.000Z');
@@ -89,8 +95,9 @@ describe('[ADR-0131 D3/D4] a fresh single-posture database promotes its first hu
8995

9096
expect(report).toMatchObject({ adminPromoted: true, adminUserId: 'usr_first' });
9197
const grants = (await engine.find('sys_user_permission_set', { where: {}, ...SYS })) as any[];
98+
// [ADR-0131 D5] The row is the Default Organization's — ⛔ never a NULL organization.
9299
expect(grants.map((g) => [g.user_id, g.permission_set, g.organization_id ?? null])).toEqual([
93-
['usr_first', 'admin_full_access', null],
100+
['usr_first', 'admin_full_access', 'org_default'],
94101
]);
95102
});
96103

@@ -103,5 +110,41 @@ describe('[ADR-0131 D3/D4] a fresh single-posture database promotes its first hu
103110
const again = await bootstrapPlatformAdmin(engine, defaultPermissionSets);
104111

105112
expect(again).toMatchObject({ adminPromoted: false, reason: 'already_have_admin', adminUserId: 'usr_first' });
113+
const grants = (await engine.find('sys_user_permission_set', { where: {}, ...SYS })) as any[];
114+
expect(grants).toHaveLength(1);
115+
});
116+
117+
it('an upgraded database whose administrator\'s grant the ceremony gave the Default Organization promotes nobody else', async () => {
118+
// ADR-0131 D10 attributes a `single` database's organization-less grants to
119+
// the Default Organization. A holder scan reading only the NULL row found
120+
// nobody on such a database and minted a second grant on every boot.
121+
const engine = await freshEngine();
122+
await human(engine, 'usr_admin', 'admin@fresh.example', '2026-01-01T00:00:00.000Z');
123+
await human(engine, 'usr_older', 'older@fresh.example', '2025-01-01T00:00:00.000Z');
124+
await engine.insert('sys_user_permission_set', {
125+
id: 'ups_attributed', user_id: 'usr_admin', permission_set: 'admin_full_access', organization_id: 'org_default',
126+
}, SYS);
127+
128+
const report = await bootstrapPlatformAdmin(engine, defaultPermissionSets);
129+
130+
expect(report).toMatchObject({ adminPromoted: false, reason: 'already_have_admin', adminUserId: 'usr_admin' });
131+
const grants = (await engine.find('sys_user_permission_set', { where: {}, ...SYS })) as any[];
132+
expect(grants.map((g) => g.id)).toEqual(['ups_attributed']);
133+
});
134+
135+
it('⛔ a database that names no Default Organization is not promoted, says so at error, and writes no grant', async () => {
136+
const engine = await freshEngine();
137+
await engine.insert('sys_organization', { id: 'org_second', name: 'Second', slug: 'second' }, SYS);
138+
await engine.update('sys_organization', { slug: 'first' }, { where: { id: 'org_default' }, ...SYS } as any);
139+
await human(engine, 'usr_first', 'first@fresh.example', '2026-01-01T00:00:00.000Z');
140+
const errors: string[] = [];
141+
142+
const report = await bootstrapPlatformAdmin(engine, defaultPermissionSets, {
143+
logger: { info: () => {}, warn: () => {}, error: (m: string) => errors.push(m) },
144+
});
145+
146+
expect(report).toMatchObject({ adminPromoted: false, reason: 'default_organization_unresolved' });
147+
expect(errors).toHaveLength(1);
148+
expect(await engine.find('sys_user_permission_set', { where: {}, ...SYS })).toEqual([]);
106149
});
107150
});

‎packages/plugins/plugin-security/src/bootstrap-platform-admin-promotion-selection.test.ts‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ import { assertEngineUpdateDispatch } from '@objectstack/metadata-core';
6464
import { ObjectQL } from '@objectstack/objectql';
6565
import { SqlDriver } from '@objectstack/driver-sql';
6666
import { resetPlatformAdminEmailMemo } from '@objectstack/core';
67-
import { SysUser, SysAccount } from '@objectstack/platform-objects/identity';
67+
import { SysUser, SysAccount, SysOrganization } from '@objectstack/platform-objects/identity';
6868
import {
6969
bootstrapPlatformAdmin,
7070
PLATFORM_ADMIN_CANDIDATE_PAGE_SIZE,
@@ -125,9 +125,12 @@ async function boot(): Promise<ObjectQL> {
125125
version: '1.0.0',
126126
type: 'plugin',
127127
scope: 'system',
128-
objects: [SysPermissionSet, SysUserPermissionSet, SysUser, SysAccount],
128+
objects: [SysPermissionSet, SysUserPermissionSet, SysUser, SysAccount, SysOrganization],
129129
} as any);
130130
await engine.syncSchemas();
131+
// [ADR-0131 D3/D5] The Default Organization a `single` boot creates before any
132+
// `kernel:ready` hook runs; it owns the promotion's grant.
133+
await engine.insert('sys_organization', { id: 'org_default', name: 'Default Organization', slug: 'default' }, { context: { isSystem: true } });
131134
engines.push(engine);
132135
return engine;
133136
}
@@ -463,6 +466,8 @@ describe('#16682 — the promotion target is chosen, not sampled', () => {
463466
['sys_user', users.map((r) => ({ ...r }))],
464467
['sys_user_permission_set', []],
465468
['sys_account', accounts.map((r) => ({ ...r }))],
469+
// [ADR-0131 D5] The Default Organization, which owns the promotion's grant.
470+
['sys_organization', [{ id: 'org_default', slug: 'default' }]],
466471
]);
467472
return {
468473
grants: () => tables.get('sys_user_permission_set')!,

‎packages/plugins/plugin-security/src/bootstrap-platform-admin-walled-owner.test.ts‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ function makeQl(seed: { users?: any[]; grants?: any[]; sets?: any[]; accounts?:
6565
['sys_user', (seed.users ?? []).map((r) => ({ ...r }))],
6666
['sys_user_permission_set', (seed.grants ?? []).map((r) => ({ ...r }))],
6767
['sys_account', (seed.accounts ?? []).map((r) => ({ ...r }))],
68+
// [ADR-0131 D3/D5] The Default Organization a `single` boot creates, which
69+
// owns the promotion's grant.
70+
['sys_organization', [{ id: 'org_default', slug: 'default' }]],
6871
]);
6972
const rowsOf = (object: string) => tables.get(object) ?? [];
7073
return {

‎packages/plugins/plugin-security/src/builtin-positions.boot.test.ts‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,11 @@ async function boot(scenario: Scenario): Promise<Booted> {
322322
};
323323
if (scenario.organizationAtBoot) {
324324
await engine.insert('sys_organization', { id: ORG, name: 'Eq Org', slug: 'eq' }, { context: SYS } as any);
325+
} else if (scenario.posture === 'single') {
326+
// [ADR-0131 D3/D5] A `single` boot always holds its Default Organization —
327+
// plugin-auth's boot invariant creates it before `kernel:ready` — and it owns
328+
// the first platform administrator's grant. No membership comes with it.
329+
await engine.insert('sys_organization', { id: 'org_default', name: 'Default Organization', slug: 'default' }, { context: SYS } as any);
325330
}
326331
await user('usr_admin', 'admin@eq.example', '2025-01-01T00:00:00.000Z');
327332
await user('usr_orgadmin', 'orgadmin@eq.example', '2025-02-01T00:00:00.000Z');

‎packages/plugins/plugin-security/src/claim-seed-ownership-seed-settle-rerun.test.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,8 @@ async function bootPlugin(existing?: Record<string, any[]>) {
199199
sys_account: [{ id: 'acc_1', user_id: ADMIN, provider_id: 'credential' }],
200200
sys_user_permission_set: [],
201201
sys_permission_set: [],
202+
// [ADR-0131 D5] The Default Organization, which owns the promotion's grant.
203+
sys_organization: [{ id: 'org_default', slug: 'default' }],
202204
// WINNER: rows the seeder already wrote before the promotion instant.
203205
crm_account: [seedRow('acc_seed_1'), seedRow('acc_seed_2')],
204206
// LOSER: the object whose rows the background seed has not reached yet.

‎packages/plugins/plugin-security/src/grant-permission-set-name.writers.test.ts‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import { describe, it, expect, afterEach } from 'vitest';
2121
import { ObjectQL } from '@objectstack/objectql';
2222
import { SqlDriver } from '@objectstack/driver-sql';
2323
import { resetPlatformAdminEmailMemo } from '@objectstack/core';
24-
import { SysUser, SysAccount, SysMember } from '@objectstack/platform-objects/identity';
24+
import { SysUser, SysAccount, SysMember, SysOrganization } from '@objectstack/platform-objects/identity';
2525
import { bootstrapPlatformAdmin, findExistingPlatformAdmin } from './bootstrap-platform-admin.js';
2626
import { reconcileOrgAdminGrant } from './auto-org-admin-grant.js';
2727
import { SysPermissionSet } from './__tests__/legacy-catalog-objects.testkit.js';
@@ -53,9 +53,12 @@ async function boot(): Promise<ObjectQL> {
5353
version: '1.0.0',
5454
type: 'plugin',
5555
scope: 'system',
56-
objects: [SysPermissionSet, SysUserPermissionSet, SysUser, SysAccount, SysMember],
56+
objects: [SysPermissionSet, SysUserPermissionSet, SysUser, SysAccount, SysMember, SysOrganization],
5757
} as any);
5858
await engine.syncSchemas();
59+
// [ADR-0131 D3/D5] The Default Organization a `single` boot creates before any
60+
// `kernel:ready` hook runs; it owns the promotion's grant.
61+
await engine.insert('sys_organization', { id: 'org_default', name: 'Default Organization', slug: 'default' }, { context: { isSystem: true } });
5962
engines.push(engine);
6063
return engine;
6164
}
@@ -92,6 +95,8 @@ describe('[ADR-0131 D4] the grant writers in plugin-security write the set by na
9295
const grants = await grantsOf(engine, 'usr_first');
9396
expect(grants).toHaveLength(1);
9497
expectNamedOnly(grants[0], 'admin_full_access');
98+
// [ADR-0131 D5] …owned by the Default Organization, never NULL.
99+
expect(grants[0]?.organization_id).toBe('org_default');
95100

96101
// [C3 stage 6b-2] The bootstrap wrote no catalog row, and the holder is
97102
// read by name with none.

0 commit comments

Comments
 (0)