Skip to content

Commit 3e1df7f

Browse files
committed
test: main's new fixtures (#25048, #25066 and the ReadableIds, person-title, keyed-text, webhook-report cases) meet a NOT NULL tenant column
- plugin-security: an organization-less permission-set catalogue row is legacy residue, so six suites relax only sys_permission_set to its pre-18 shape. Driver-written seeds name the rig's organization (readable-ids-nested-compose, controlled-by-parent-master-object-write). The lean person-title engine gets the Default Organization. - rest (stored-expression dropped fields), plugin-webhooks (auto-enqueuer report), plugin-approvals (reader-locale labels, keyed text): each lean engine gets the Default Organization. The keyed-text out-of-office delegation names the deals' organization, where its request opens. No assertion changed. Claude-Session: https://claude.ai/code/session_018EszgtA3V2KXBX5tf59Hi4 Co-authored-by: Claude <noreply@anthropic.com>
1 parent d663325 commit 3e1df7f

12 files changed

Lines changed: 63 additions & 6 deletions

‎packages/plugins/plugin-approvals/src/approval-notification-keyed-text.integration.test.ts‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ import { ApprovalService } from './approval-service.js';
5050
import { ApprovalsServicePlugin } from './approvals-plugin.js';
5151
import { ApprovalsTranslations } from './translations/index.js';
5252
import { approvalMessages, enMessages } from './translations/messages.js';
53+
import { installDefaultOrganization } from './default-organization.testkit.js';
5354

5455
const SYSTEM = { isSystem: true, positions: [], permissions: [] } as any;
5556
const asUser = (userId: string) => ({ userId, positions: [], permissions: [] }) as any;
@@ -124,6 +125,9 @@ async function bootEngine(users: Array<Record<string, unknown>>): Promise<Object
124125
engine.registry.registerObject(def as any, 'approvals-test', 'approvals-test');
125126
}
126127
await engine.syncSchemas();
128+
// A real `single` install's Default Organization: the system writes below
129+
// derive it (ADR-0131 D9), as a fresh NOT NULL tenant column requires (D1).
130+
await installDefaultOrganization(engine);
127131
for (const u of users) await engine.insert('sys_user', u, { context: SYSTEM } as any);
128132
return engine;
129133
}
@@ -207,8 +211,10 @@ describe('#24978 — every approval notification carries its text as catalog key
207211
await open('rejected', [{ type: 'user', value: 'u_alice' }]);
208212
await svc.decide(ids.rejected, { decision: 'reject', actorId: 'u_alice', comment: 'Not this quarter.' }, asUser('u_alice'));
209213

214+
// The delegation belongs to the deals' organization, where the request it
215+
// substitutes in is opened.
210216
await engine.insert('sys_approval_delegation', {
211-
id: 'dlg_1', delegator_id: 'u_ooo', delegate_id: 'u_bob', reason: 'leave',
217+
id: 'dlg_1', delegator_id: 'u_ooo', delegate_id: 'u_bob', reason: 'leave', organization_id: ORG,
212218
valid_from: '2026-09-01T00:00:00.000Z', valid_until: '2026-12-31T00:00:00.000Z',
213219
created_at: '2026-09-01T00:00:00.000Z', updated_at: '2026-09-01T00:00:00.000Z',
214220
}, { context: SYSTEM } as any);

‎packages/plugins/plugin-approvals/src/reader-locale-display-labels.integration.test.ts‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ import { TranslationDataSchema } from '@objectstack/spec/system';
5757
import type { EngineQueryOptions } from '@objectstack/spec/data';
5858
import type { ApprovalService } from './approval-service.js';
5959
import { ApprovalsServicePlugin } from './approvals-plugin.js';
60+
import { installDefaultOrganization } from './default-organization.testkit.js';
6061

6162
const SYSTEM = { isSystem: true, positions: [], permissions: [] } as any;
6263
const reader = (userId: string, locale?: string) =>
@@ -187,6 +188,9 @@ describe('[#24863] the approvals door serves a request\'s labels in the reader\'
187188
engine.registry.registerObject(def as any, 'approvals-reader-locale-test', 'approvals-reader-locale-test');
188189
}
189190
await engine.syncSchemas();
191+
// A real `single` install's Default Organization: the system writes below
192+
// derive it (ADR-0131 D9), as a fresh NOT NULL tenant column requires (D1).
193+
await installDefaultOrganization(engine);
190194
for (const [id, name] of [[SUBMITTER, 'Sam Submitter'], [MANAGER, 'Mona Manager'], [DIRECTOR, 'Dina Director']]) {
191195
await engine.insert('sys_user', { id, name, email: `${id}@example.com` }, { context: SYSTEM } as any);
192196
}

‎packages/plugins/plugin-security/src/controlled-by-parent-every-master-edit.test.ts‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ import { SysUserPosition } from './objects/sys-user-position.object.js';
4444
import { SysUserPermissionSet } from './objects/sys-user-permission-set.object.js';
4545
import { SecurityPlugin } from './security-plugin.js';
4646
import { defaultPermissionSets } from './objects/default-permission-sets.js';
47+
import { relaxTenantColumns } from './pre-18-tenant-column.testkit.js';
4748

4849
const SYS = { context: { isSystem: true } } as never;
4950
const ORG = 'org_cbp_eme';
@@ -152,6 +153,10 @@ async function boot() {
152153
],
153154
} as never);
154155
await engine.syncSchemas();
156+
// The organization-less permission-set catalogue row below exists only on a
157+
// store built before 18.x (ADR-0131 D1 makes a fresh tenant column NOT
158+
// NULL): that table is this store's.
159+
await relaxTenantColumns(engine as never, ['sys_permission_set']);
155160

156161
const e = engine as unknown as {
157162
insert: (o: string, row: Record<string, unknown>, opts: never) => Promise<unknown>;

‎packages/plugins/plugin-security/src/controlled-by-parent-master-object-read.test.ts‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ import { SysUserPosition } from './objects/sys-user-position.object.js';
4444
import { SysUserPermissionSet } from './objects/sys-user-permission-set.object.js';
4545
import { SecurityPlugin } from './security-plugin.js';
4646
import { defaultPermissionSets } from './objects/default-permission-sets.js';
47+
import { relaxTenantColumns } from './pre-18-tenant-column.testkit.js';
4748

4849
const SYS = { context: { isSystem: true } } as never;
4950
const ORG = 'org_cbp_mor';
@@ -154,6 +155,10 @@ async function boot() {
154155
],
155156
} as never);
156157
await engine.syncSchemas();
158+
// The organization-less permission-set catalogue row below exists only on a
159+
// store built before 18.x (ADR-0131 D1 makes a fresh tenant column NOT
160+
// NULL): that table is this store's.
161+
await relaxTenantColumns(engine as never, ['sys_permission_set']);
157162

158163
const e = engine as unknown as {
159164
insert: (o: string, row: Record<string, unknown>, opts: never) => Promise<unknown>;

‎packages/plugins/plugin-security/src/controlled-by-parent-master-object-write.test.ts‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -217,10 +217,14 @@ async function boot() {
217217
let n = 0;
218218
return {
219219
engine,
220-
/** A stored detail under `master`, written as SYSTEM (seed replay skips the reference check). */
220+
/**
221+
* A stored detail under `master`, written as SYSTEM (seed replay skips the
222+
* reference check). A driver write is not stamped, so it names the rig's
223+
* organization itself.
224+
*/
221225
seedDetail: async (detail: string, master: string) => {
222226
const id = `${detail}_seed_${n++}`;
223-
await e.getDriver(detail).create(detail, { id, note: 'seeded', master });
227+
await e.getDriver(detail).create(detail, { id, note: 'seeded', master, organization_id: ORG });
224228
return id;
225229
},
226230
stored: async (object: string, id: string) =>

‎packages/plugins/plugin-security/src/controlled-by-parent-write-shape-master-edit.test.ts‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ import { SysUserPosition } from './objects/sys-user-position.object.js';
4444
import { SysUserPermissionSet } from './objects/sys-user-permission-set.object.js';
4545
import { SecurityPlugin } from './security-plugin.js';
4646
import { defaultPermissionSets } from './objects/default-permission-sets.js';
47+
import { relaxTenantColumns } from './pre-18-tenant-column.testkit.js';
4748

4849
const SYS = { context: { isSystem: true } } as never;
4950
const ORG = 'org_cbp_wsme';
@@ -148,6 +149,10 @@ async function boot() {
148149
],
149150
} as never);
150151
await engine.syncSchemas();
152+
// The organization-less permission-set catalogue row below exists only on a
153+
// store built before 18.x (ADR-0131 D1 makes a fresh tenant column NOT
154+
// NULL): that table is this store's.
155+
await relaxTenantColumns(engine as never, ['sys_permission_set']);
151156

152157
const e = engine as unknown as {
153158
insert: (o: string, row: Record<string, unknown>, opts: never) => Promise<unknown>;

‎packages/plugins/plugin-security/src/insert-seam-judges-organization.test.ts‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ import { SysOrganization, SysUser, SysMember } from '@objectstack/platform-objec
4747
import { SysPosition, SysPermissionSet, SysPositionPermissionSet } from './__tests__/legacy-catalog-objects.testkit.js';
4848
import { SysUserPosition } from './objects/sys-user-position.object.js';
4949
import { SysUserPermissionSet } from './objects/sys-user-permission-set.object.js';
50+
import { relaxTenantColumns } from './pre-18-tenant-column.testkit.js';
5051

5152
const OWN_ORG = 'org_a';
5253
const SISTER_ORG = 'org_c';
@@ -339,6 +340,10 @@ describe('[#24822 · ADR-0090 D10] a delegated insert by a crossing operator is
339340
],
340341
} as never);
341342
await engine.syncSchemas();
343+
// The organization-less permission-set catalogue row below exists only on a
344+
// store built before 18.x (ADR-0131 D1 makes a fresh tenant column NOT
345+
// NULL): that table is this store's.
346+
await relaxTenantColumns(engine as never, ['sys_permission_set']);
342347
engines.push(engine);
343348

344349
for (const id of [ORG_A, ORG_C, ORG_D]) {

‎packages/plugins/plugin-security/src/objects/sys-user-permission-set-person-title.test.ts‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ import { SysUser } from '@objectstack/platform-objects';
4444
import { resolveDisplayField, resolveRecordDisplayName } from '@objectstack/spec/data';
4545
import type { ExecutionContext } from '@objectstack/spec/kernel';
4646
import { SysUserPermissionSet } from './sys-user-permission-set.object.js';
47+
import { installDefaultOrganization } from '../default-organization.testkit.js';
4748

4849
const SYS = { context: { isSystem: true } } as any;
4950
const OBJECT = 'sys_user_permission_set';
@@ -83,6 +84,9 @@ describe('sys_user_permission_set is titled by the person, not the raw user id',
8384
engine.registry.registerObject(SysUser as any, 'com.objectstack.test.person-title');
8485
engine.registry.registerObject(SysUserPermissionSet as any, 'com.objectstack.test.person-title');
8586
await engine.syncSchemas();
87+
// A real `single` install's Default Organization: the system writes below
88+
// derive it (ADR-0131 D9), as a fresh NOT NULL tenant column requires (D1).
89+
await installDefaultOrganization(engine);
8690
// Row-level security on `sys_user` for a reader that is not SYSTEM — the
8791
// composition the security plugin makes (its own row scope is "own row or
8892
// an organization member"; here, the ids in `readable`).

‎packages/plugins/plugin-security/src/readable-ids-delegated-compose.test.ts‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ import { SysUserPosition } from './objects/sys-user-position.object.js';
4646
import { SysUserPermissionSet } from './objects/sys-user-permission-set.object.js';
4747
import { SecurityPlugin } from './security-plugin.js';
4848
import { defaultPermissionSets } from './objects/default-permission-sets.js';
49+
import { relaxTenantColumns } from './pre-18-tenant-column.testkit.js';
4950

5051
const SYS = { context: { isSystem: true } } as never;
5152
const ORG = 'org_rid_del';
@@ -151,6 +152,10 @@ async function boot() {
151152
],
152153
} as never);
153154
await engine.syncSchemas();
155+
// The organization-less permission-set catalogue row below exists only on a
156+
// store built before 18.x (ADR-0131 D1 makes a fresh tenant column NOT
157+
// NULL): that table is this store's.
158+
await relaxTenantColumns(engine as never, ['sys_permission_set']);
154159

155160
const e = engine as unknown as {
156161
insert: (o: string, row: Record<string, unknown>, opts: never) => Promise<unknown>;

‎packages/plugins/plugin-security/src/readable-ids-nested-compose.test.ts‎

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ import { SysUserPosition } from './objects/sys-user-position.object.js';
5151
import { SysUserPermissionSet } from './objects/sys-user-permission-set.object.js';
5252
import { SecurityPlugin } from './security-plugin.js';
5353
import { defaultPermissionSets } from './objects/default-permission-sets.js';
54+
import { relaxTenantColumns } from './pre-18-tenant-column.testkit.js';
5455

5556
const SYS = { context: { isSystem: true } } as never;
5657
const ORG = 'org_rid_nest';
@@ -194,6 +195,10 @@ async function boot() {
194195
],
195196
} as never);
196197
await engine.syncSchemas();
198+
// The organization-less permission-set catalogue row below exists only on a
199+
// store built before 18.x (ADR-0131 D1 makes a fresh tenant column NOT
200+
// NULL): that table is this store's.
201+
await relaxTenantColumns(engine as never, ['sys_permission_set']);
197202

198203
const e = engine as unknown as {
199204
insert: (o: string, row: Record<string, unknown>, opts: never) => Promise<unknown>;
@@ -240,12 +245,13 @@ async function boot() {
240245
}, SYS);
241246
// The parents, one per grandparent, plus one with a dangling and one with a
242247
// null master pointer (written through the driver: the required master is
243-
// what the authoring door refuses, and these rows exist to be excluded).
248+
// what the authoring door refuses, and these rows exist to be excluded). A
249+
// driver write is not stamped, so it names the rig's organization itself.
244250
for (const [id, grand] of [
245251
['p_both', 'g_both'], ['p_del_only', 'g_del_only'], ['p_caller_only', 'g_caller_only'],
246252
['p_neither', 'g_neither'], ['p_shared', 'g_shared'], ['p_dangling', 'g_missing'], ['p_null', null],
247253
] as const) {
248-
await e.getDriver(PARENT).create(PARENT, { id, name: id, grand });
254+
await e.getDriver(PARENT).create(PARENT, { id, name: id, grand, organization_id: ORG });
249255
}
250256
// The same children in both tables, so the two paths read the same rows.
251257
for (const child of [CHILD_CBP, CHILD_LEAF]) {
@@ -254,7 +260,7 @@ async function boot() {
254260
['c_neither', 'p_neither'], ['c_shared', 'p_shared'], ['c_via_dangling', 'p_dangling'], ['c_via_null', 'p_null'],
255261
['c_dangling', 'p_missing'], ['c_null', null],
256262
] as const) {
257-
await e.getDriver(child).create(child, { id, note: '', parent });
263+
await e.getDriver(child).create(child, { id, note: '', parent, organization_id: ORG });
258264
}
259265
}
260266

0 commit comments

Comments
 (0)