Skip to content

finding: a flow-type action's AutomationContext gets the same stamped record stub when the caller cannot read the row — and the flow face has no recordLoadDenied #14244

Description

@os-support-ai

Observed while implementing #14143 on 66ecc50a. ⛔ Unclaimed. Filed rather than fixed: #14143's dispatch order binds that card to the handler predicate, and this is one surface over.

What #14143 fixed, and where it stops

#14143 adds ctx.recordLoadDenied to the script/body action face: when the dispatcher's caller-scope load of the subject row does not deliver it, the handler is told, instead of only receiving ctx.record = { id: recordId } (the id being stamped on precisely because the load failed).

Both dispatch doors now route their load through one producer, loadActionSubjectRecord (packages/runtime/src/action-execution.ts). But the flow branch consumes the same record object and carries no equivalent signal:

  • packages/runtime/src/action-execution.ts — MCP run_action, the action.type === 'flow' branch passes record into dispatchFlowAction;
  • packages/runtime/src/domains/actions.ts — REST /actions, same;
  • dispatchFlowAction then hands it to automation.execute(action.target, { record, ... }) as the run's AutomationContext.record, and seeds params from the same object via seedFlowActionParams.

So a flow started by a row-scoped action on a row its invoker cannot read receives record = { id: <recordId> } — shaped exactly like a legitimate record-less start, with nothing on the context distinguishing the two.

Why it is a smaller claim than #14143, not the same one

A flow action is deliberately not system-elevated: the flow engine receives the caller's identity and honours runAs (ADR-0049), so a runAs: 'user' flow re-derives the caller's scope on its own reads and the stub simply resolves to nothing. The exposure is narrower and conditional:

⛔ Not claimed

Dedupe

One targeted search_issues (repo-scoped REST search answered 403 for this seat, so the channel switch is declared here). 11 results, positive control holds — #14143 itself and the runAs/automation-elevation family (#14201, #14011, #5494, #7900, #3783, #4366) came back, so the query matched semantically rather than returning a silent zero. Nearest neighbours excluded:

⛔ No duplicate.

Repro sketch

Declare a type: 'flow' action on an object with OWD private, targeting a flow with runAs: 'system'. Invoke it as a caller who cannot read the target row, with that row's id. The run's AutomationContext.record should be observed as { id: <recordId> } rather than absent — identical to a record-less start.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions