Skip to content

Commit caeaab9

Browse files
committed
test(automation): pin the run-user remedies at the store, the text slot and the CEL scope
Claude-Session: https://claude.ai/code/session_01VZqqwTj2wsihZEbfT6yyYN Co-authored-by: Claude <noreply@anthropic.com>
1 parent a86164b commit caeaab9

3 files changed

Lines changed: 10 additions & 7 deletions

File tree

‎packages/services/service-automation/src/builtin/crud-fields-value-envelope.test.ts‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -274,10 +274,12 @@ describe.each(NODE_TYPES)('%s `fields.*` — the retired `{…}` template dialec
274274
expect(writes0(withUser.writes).subject).toBe(before.subject);
275275
expect(before.subject).toBe('u1');
276276

277+
// A user-less run writes data only under an explicit `runAs: 'system'` (ADR-0049).
277278
const userless = await makeStack();
278-
userless.automation.registerFlow('price_quote', writeFlow(nodeType, {
279-
subject: { dialect: 'cel', source: 'current_user != null ? current_user.id : null' },
280-
}));
279+
userless.automation.registerFlow('price_quote', {
280+
...writeFlow(nodeType, { subject: { dialect: 'cel', source: 'current_user != null ? current_user.id : null' } }),
281+
runAs: 'system',
282+
});
281283
const res2 = await userless.automation.execute('price_quote', { params: PARAMS } as any);
282284
expect(res2.success, res2.error).toBe(true);
283285
expect(interpolate({ subject: '{$User.Id}' }, new Map(), {} as any).subject).toBeUndefined();

‎packages/services/service-automation/src/builtin/text-slot-template.test.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -355,12 +355,12 @@ describe('#22477 — a text-slot hole may root only at a `$` variable the engine
355355
const withUser = harness();
356356
withUser.engine.registerFlow('by_user', flow('current_user.id') as never);
357357
expect((await withUser.engine.execute('by_user', ctx())).success).toBe(true);
358-
expect(withUser.emitted[0]!.payload).toMatchObject({ message: 'By usr_7' });
358+
expect(withUser.emitted[0]!.payload).toMatchObject({ body: 'By usr_7' });
359359

360360
const userless = harness();
361361
userless.engine.registerFlow('by_user', flow('current_user != null ? current_user.id : null') as never);
362362
const noUser = { event: 'manual', object: 'account', record: ACME } as unknown as AutomationContext;
363363
expect((await userless.engine.execute('by_user', noUser)).success).toBe(true);
364-
expect(userless.emitted[0]!.payload).toMatchObject({ message: 'By ' });
364+
expect(userless.emitted[0]!.payload).toMatchObject({ body: 'By ' });
365365
});
366366
});

‎packages/services/service-automation/src/builtin/value-slot-template-grammar.test.ts‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
*/
3535

3636
import { describe, expect, it } from 'vitest';
37-
import { valueSlotTemplateRefusals } from '@objectstack/spec/automation';
37+
import { VALUE_SLOT_TEMPLATE_REFUSAL, valueSlotTemplateRefusals } from '@objectstack/spec/automation';
3838
import { AutomationEngine } from '../engine.js';
3939
import { interpolateString } from './template.js';
4040

@@ -67,8 +67,9 @@ describe('the run user — `{$User.*}` — is REFUSED, and its remedy reads what
6767
/** A run context the way the trigger doors build one: no `user` object, ever. */
6868
const SHIPPED = { userId: 'usr_1', positions: ['org_member'], tenantId: 'org_1' } as never;
6969
const USERLESS = {} as never;
70+
/** The CEL sources the refusal of `token` prints, in order — read after the rule sentence, whose own `'…'` is not a remedy. */
7071
const sources = (token: string): string[] => {
71-
const message = valueSlotTemplateRefusals(token)[0]?.message ?? '';
72+
const message = (valueSlotTemplateRefusals(token)[0]?.message ?? '').slice(VALUE_SLOT_TEMPLATE_REFUSAL.length);
7273
return [...message.matchAll(/\{ dialect: 'cel', source: '([^']*)' \}/g)].map((m) => m[1]!);
7374
};
7475

0 commit comments

Comments
 (0)