Skip to content

Conversation

@jimsynz
Copy link
Contributor

@jimsynz jimsynz commented Jan 28, 2026

Summary

  • Fix cascade_destroy and cascade_update to pass full context (including actor) to Ash.load!
  • Previously only tenant: tenant was passed, causing policy failures when policies require an actor

Details

The Ash.load! calls in both cascade changes were missing the actor from the context. This was a regression introduced in #1948 when authorize?: false was removed but the actor wasn't added.

The fix uses Ash.Context.to_opts(context) to pass all relevant context options (actor, tenant, tracer, context, authorize?), consistent with how context_opts is already passed to Ash.bulk_destroy!/Ash.bulk_update! in the same code path.

Closes #2536

The `Ash.load!` calls in `cascade_destroy` and `cascade_update` were
only passing `tenant: tenant`, missing the actor and other context
options. This caused policy failures when policies require an actor.

Use `Ash.Context.to_opts(context)` to pass all relevant context options
(actor, tenant, tracer, context, authorize?), consistent with how
`context_opts` is already passed to `Ash.bulk_destroy!`/`Ash.bulk_update!`
in the same code path.

Closes #2536
|> Ash.load!(
[{relationship.name, load_query}],
tenant: tenant
Ash.Context.to_opts(context)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can just do:
scope: context, but we should also do authorize?: false, so scope: context, authorize?: false to retain original behavior.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wasn't authorized?: false removed intentionally in favor of having accessing_from set and having policies?

you didn't explicitly answer the question, but you merged the PR

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, yeah you're right 👍 maybe a comment here saying that this is meant to run authorization.

|> Ash.load!(
[{relationship.name, load_query}],
tenant: tenant
Ash.Context.to_opts(context)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here.

barnabasJ
barnabasJ previously approved these changes Jan 28, 2026
|> Ash.load!(
[{relationship.name, load_query}],
tenant: tenant
scope: context,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Heads up that this function rebinds context above:

context =
Map.merge(relationship.context || %{}, %{
cascade_destroy: true,
accessing_from: %{source: relationship.source, name: relationship.name}
})

So it's missing the tenant here now

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤯 good call!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should not overwrite context in the first place to avoid this confusion.

Rename the rebound `context` variable to `action_context` to preserve
the original context parameter containing tenant, actor, and tracer.
This ensures `scope: context` in `Ash.load!` receives the full context.
@zachdaniel
Copy link
Contributor

@jimsynz my bad, @barnabasJ is right, we shouldn't be doing authorize?: false here. Will merge once that's changed 🙇

Authorization was intentionally removed in #1948 in favour of
`accessing_from` policies. Passing `authorize?: false` here would
bypass that intent.
@jimsynz jimsynz merged commit bfdfa55 into main Feb 8, 2026
45 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

cascade_destroy and cascade_update missing actor in Ash.load! call

4 participants