Skip to content

Commit cbeef9e

Browse files
authored
Merge pull request #1774 from objectstack-ai/feat-lock-platform-apps
feat(platform-objects): lock studio & account apps with ADR-0010 full protection
2 parents 8950204 + b779444 commit cbeef9e

4 files changed

Lines changed: 41 additions & 8 deletions

File tree

packages/platform-objects/src/apps/account.app.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,16 @@ export const ACCOUNT_APP: App = {
3838
isDefault: false,
3939
// Surface via the avatar dropdown, not the App Switcher — see App.hidden.
4040
hidden: true,
41+
// ADR-0010 §3.7 — author-facing protection block. Loader translates
42+
// this into the `_lock` envelope at registration time. Every
43+
// authenticated user depends on this app to manage their own
44+
// sessions / API keys / linked accounts, so a tenant overlay that
45+
// breaks it is a security-relevant outage — same class as Setup.
46+
protection: {
47+
lock: 'full',
48+
reason: 'Core self-service security UI shipped by @objectstack/platform-objects — see ADR-0010.',
49+
docsUrl: 'https://docs.objectstack.ai/adr/0010-metadata-protection',
50+
},
4151
branding: {
4252
primaryColor: '#0ea5e9', // sky-500 — distinct from Setup's slate
4353
},

packages/platform-objects/src/apps/setup-nav.contributions.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,9 @@ export const SETUP_NAV_CONTRIBUTIONS: NavigationContribution[] = [
3838
{ id: 'nav_system_overview', type: 'dashboard', label: 'System Overview', dashboardName: 'system_overview', icon: 'activity' },
3939
],
4040
},
41-
{
42-
app: 'setup',
43-
group: 'group_apps',
44-
priority: BASE_PRIORITY,
45-
items: [
46-
],
47-
},
41+
// No group_apps contribution left here — both marketplace entries moved
42+
// out (see header note); the group_apps shell anchor in setup.app.ts is
43+
// filled entirely by capability plugins now.
4844
{
4945
app: 'setup',
5046
group: 'group_people_org',

packages/platform-objects/src/apps/studio.app.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,15 @@ export const STUDIO_APP: App = {
3434
icon: 'hammer',
3535
active: true,
3636
isDefault: false,
37+
// ADR-0010 §3.7 — author-facing protection block. Loader translates
38+
// this into the `_lock` envelope at registration time. Same rationale
39+
// as Setup: tenant overlay edits to the metadata workbench can lock
40+
// implementers out of the very surface used to repair metadata.
41+
protection: {
42+
lock: 'full',
43+
reason: 'Core developer workbench shipped by @objectstack/platform-objects — see ADR-0010.',
44+
docsUrl: 'https://docs.objectstack.ai/adr/0010-metadata-protection',
45+
},
3746
// Studio is the metadata-authoring host, so its ambient copilot is
3847
// pinned to the schema-architect agent. Resolved by the ambient chat
3948
// endpoint via `app.defaultAgent` — no UI-side `?agent=` override

packages/platform-objects/src/platform-objects.test.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import {
2828
SysMetadataHistoryObject,
2929
} from './metadata/index.js';
3030
import { SysSetting } from './system/index.js';
31-
import { SETUP_APP, SETUP_NAV_CONTRIBUTIONS } from './apps/index.js';
31+
import { ACCOUNT_APP, SETUP_APP, SETUP_NAV_CONTRIBUTIONS, STUDIO_APP } from './apps/index.js';
3232
import { AppSchema } from '@objectstack/spec/ui';
3333

3434
const systemObjects = [
@@ -156,6 +156,24 @@ describe('@objectstack/platform-objects', () => {
156156
});
157157
});
158158

159+
describe('platform app protection (ADR-0010 §3.7)', () => {
160+
// All three platform apps are core UI shipped by this package: a
161+
// tenant overlay that breaks Setup/Studio locks admins/implementers
162+
// out of the repair surface, and Account is every user's only
163+
// self-service security surface. The loader translates `protection`
164+
// into the `_lock` envelope; clients (e.g. objectui's
165+
// isNavigationSyncableApp) rely on `_lock` to skip automatic
166+
// navigation writes into these apps.
167+
it.each([
168+
['SETUP_APP', SETUP_APP],
169+
['STUDIO_APP', STUDIO_APP],
170+
['ACCOUNT_APP', ACCOUNT_APP],
171+
])('%s declares a full lock', (_name, app) => {
172+
expect(app.protection?.lock).toBe('full');
173+
expect(() => AppSchema.parse(app)).not.toThrow();
174+
});
175+
});
176+
159177
describe('SETUP_NAV_CONTRIBUTIONS (ADR-0029 D7)', () => {
160178
const shellGroupIds = new Set(
161179
(SETUP_APP.navigation ?? []).map((n) => n.id),

0 commit comments

Comments
 (0)