Skip to content

Commit b5e4b51

Browse files
committed
fix: judge the anonymous intake refusal only where a tenancy posture exists
Claude-Session: https://claude.ai/code/session_018zT8d8NpiQ1ExhuNd5TxY6 Co-authored-by: Claude <noreply@anthropic.com>
1 parent 494e770 commit b5e4b51

2 files changed

Lines changed: 9 additions & 19 deletions

File tree

‎packages/metadata-protocol/src/protocol.org-scoped-write-refused.test.ts‎

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -579,11 +579,10 @@ describe('org-scoped anonymous form intake changes the anonymous doors cannot se
579579
config: { sharing: sharing(allowAnonymous) },
580580
});
581581

582-
/** `defaultOrgId` answers what the anonymous doors resolve; `undefined` = no tenancy service. */
583-
function makeTenancyProtocol(defaultOrgId: string | null | undefined) {
582+
/** `defaultOrgId` answers what the anonymous doors resolve. */
583+
function makeTenancyProtocol(defaultOrgId: string | null) {
584584
const { engine, rows } = makeStubEngine();
585-
const services = new Map<string, unknown>();
586-
if (defaultOrgId !== undefined) services.set('tenancy', { defaultOrgId: async () => defaultOrgId });
585+
const services = new Map<string, unknown>([['tenancy', { defaultOrgId: async () => defaultOrgId }]]);
587586
const protocol = new ObjectStackProtocolImplementation(engine, () => services, 'env_prod') as any;
588587
return { protocol, rows };
589588
}
@@ -638,15 +637,6 @@ describe('org-scoped anonymous form intake changes the anonymous doors cannot se
638637
expect(orgRows(rows).filter((r) => r.org === 'org_a' && r.state === 'active')).toEqual([]);
639638
});
640639

641-
it('no tenancy service: the doors read env-wide, so the org-scoped withdrawal is refused', async () => {
642-
const { protocol } = makeTenancyProtocol(undefined);
643-
await publishEnvWide(protocol);
644-
645-
await expect(protocol.saveMetaItem({
646-
type: 'view', name: 'task.intake_form', item: FORM_VIEW(false), organizationId: 'org_a',
647-
})).rejects.toMatchObject({ code: 'NOT_OVERRIDABLE', status: 403 });
648-
});
649-
650640
it('control (walled): an org-scoped edit that leaves the anonymous intake alone still saves', async () => {
651641
const { protocol, rows } = makeTenancyProtocol(null);
652642
await publishEnvWide(protocol);

‎packages/metadata-protocol/src/protocol.ts‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14528,9 +14528,10 @@ export class ObjectStackProtocolImplementation implements
1452814528
* The doors resolve the form in `tenancy.defaultOrgId()`'s organization
1452914529
* (`registerFormEndpoints` in `@objectstack/rest`). Where that is not the
1453014530
* write's organization (every walled posture, degraded or not, answers
14531-
* `null`; so does a composition with no tenancy service), the doors read
14532-
* the env-wide definition, so the write is refused and the author is
14533-
* pointed at the env-wide save, which every door honours.
14531+
* `null`), the doors read the env-wide definition, so the write is refused
14532+
* and the author is pointed at the env-wide save, which every door
14533+
* honours. A composition with no tenancy service has no posture to judge
14534+
* (and no session to carry an organization over HTTP), so it is left as is.
1453414535
*
1453514536
* Judged on the anonymous slug set alone ({@link anonymousFormIntakeSlugs}):
1453614537
* an organization-scoped edit that leaves it as the env-wide definition has
@@ -14549,9 +14550,8 @@ export class ObjectStackProtocolImplementation implements
1454914550
const tenancy = this.getServicesRegistry?.().get('tenancy') as
1455014551
| { defaultOrgId?: () => Promise<string | null> }
1455114552
| undefined;
14552-
const doorOrganization = typeof tenancy?.defaultOrgId === 'function'
14553-
? await tenancy.defaultOrgId()
14554-
: null;
14553+
if (typeof tenancy?.defaultOrgId !== 'function') return null;
14554+
const doorOrganization = await tenancy.defaultOrgId();
1455514555
if (doorOrganization === args.organizationId) return null;
1455614556
const proposed = anonymousFormIntakeSlugs(args.body);
1455714557
const served = anonymousFormIntakeSlugs(

0 commit comments

Comments
 (0)