Skip to content

Enforce Flow Model permission at runtime - #62

Merged
ShrihariMahabal merged 1 commit into
developfrom
feat/model-access-limits
Jul 8, 2026
Merged

Enforce Flow Model permission at runtime#62
ShrihariMahabal merged 1 commit into
developfrom
feat/model-access-limits

Conversation

@ShrihariMahabal

Copy link
Copy Markdown
Member

Closes #59

Model selection was never permission-checked at runtime — assemble() only checked enabled, so any user could pass any model name to start_run regardless of User Permission restrictions. Admins can now restrict which Flow Models a user can run via standard Frappe User Permissions, and this is enforced where every session/run resolves its model.

@greptile-apps

greptile-apps Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Confidence Score: 4/5

Safe to merge; the change is narrow and well-tested, though background-job user context deserves a quick sanity check.

The guard is correct and the tests are solid, but assemble() is also called from queue workers — if those run as Administrator, the permission check passes unconditionally and the restriction is silently bypassed. Worth confirming the job-enqueueing code preserves (or re-sets) the originating user before relying on this check in async flows.

flow/flow/doctype/flow_agent/flow_agent.py — confirm assemble() callers in background jobs set the correct Frappe user before the check runs.

Reviews (1): Last reviewed commit: "feat: enforce Flow Model read permission..." | Re-trigger Greptile

Comment on lines +95 to +100
if not frappe.has_permission("Flow Model", "read", model_name):
frappe.throw(
_("You are not permitted to use Flow Model {0}.").format(model_name),
frappe.PermissionError,
title=_("Model Not Permitted"),
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 Permission check bypassed in background jobsfrappe.has_permission reads frappe.session.user, so if any caller of assemble() runs as Administrator in a queue worker (common in Frappe background jobs), the check always passes and the User Permission restriction is silently skipped. Verify that start_run and any enqueue call preserves or re-sets the originating user before this gate can be trusted end-to-end.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Routing a run through the scheduler requires creating/editing a Flow Trigger, which is System Manager-only. A restricted (non-admin) user can't do it. If they could, they'd be an admin and the restriction is moot anyway.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

That's a fair point — if Flow Trigger creation/editing is gated to System Manager, then the only path to a scheduler-triggered background job (where session user might be Administrator) is already admin-only, making the restriction self-reinforcing.

The remaining question is whether start_run called directly (via HTTP/API by a restricted user) ever enqueues a background job that calls assemble() inside the worker. If assemble() is always called synchronously in the web worker before any enqueueing, frappe.session.user is correct and the check is sound. If it's called inside an enqueued job, the session user would be whatever the worker runs as.

Do you want me to look at start_run to confirm?

Tip: You can customize Greptile's behavior for this repo with .greptile/rules.md and .greptile/config.json.

@ShrihariMahabal
ShrihariMahabal merged commit 897f484 into develop Jul 8, 2026
4 checks passed
@ShrihariMahabal
ShrihariMahabal deleted the feat/model-access-limits branch July 13, 2026 13:56
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.

Limits

1 participant