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
17 changes: 17 additions & 0 deletions .changeset/business-unit-import-export.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
"@objectstack/platform-objects": patch
---

fix(platform-objects): allow import/export on sys_business_unit (#3025)

The Business Units list (Setup → Business Units) surfaces Import/Export buttons,
but `sys_business_unit` declared a restrictive `enable.apiMethods` whitelist of
only the five CRUD verbs. The REST data plane gates import/export on that
whitelist (ADR-0049), so both buttons returned `405 OBJECT_API_METHOD_NOT_ALLOWED`.

This was an unintentional gap, not a deliberate restriction: the object's fields
(`external_ref`, `effective_from/to`) are designed for HRIS batch sync, and the
org tree is expected to support bulk import. Added `'import'` and `'export'` to
the whitelist. Import reuses the `create`/`update` affordances the object already
grants, and the managed-object reconciliation backstop leaves import/export
untouched (it only strips write verbs). Regression test added.
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,10 @@ export const SysBusinessUnit = ObjectSchema.create({
trackHistory: true,
searchable: true,
apiEnabled: true,
apiMethods: ['get', 'list', 'create', 'update', 'delete'],
// Data portability is expected for the org tree: fields like `external_ref`
// and `effective_from/to` are designed for HRIS batch sync (#3025). Import
// reuses the create/update affordances this object already grants.
apiMethods: ['get', 'list', 'create', 'update', 'delete', 'import', 'export'],
trash: true,
mru: false,
},
Expand Down
18 changes: 18 additions & 0 deletions packages/platform-objects/src/platform-objects.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { describe, expect, it } from 'vitest';
import {
SysAccount,
SysApiKey,
SysBusinessUnit,
SysDeviceCode,
SysInvitation,
SysJwks,
Expand Down Expand Up @@ -230,6 +231,23 @@ describe('@objectstack/platform-objects', () => {
});
});

describe('data portability whitelist (#3025)', () => {
it('sys_business_unit allows import/export so the org tree can be batch-synced', () => {
// The Business Units list exposes Import/Export buttons and the object's
// schema (external_ref, effective_from/to) is designed for HRIS batch
// sync. The REST data plane gates these routes on `enable.apiMethods`
// (ADR-0049), so both verbs must be present or the buttons 405 with
// OBJECT_API_METHOD_NOT_ALLOWED. Regression guard for #3025.
expect(SysBusinessUnit.enable?.apiMethods).toContain('import');
expect(SysBusinessUnit.enable?.apiMethods).toContain('export');
// The five CRUD verbs it already granted must remain — import writes
// reuse the create/update affordances.
for (const verb of ['get', 'list', 'create', 'update', 'delete'] as const) {
expect(SysBusinessUnit.enable?.apiMethods).toContain(verb);
}
});
});

describe('SETUP_APP (ADR-0029 D7 shell)', () => {
it('parses cleanly through AppSchema', () => {
expect(() => AppSchema.parse(SETUP_APP)).not.toThrow();
Expand Down