Skip to content

UN-2868 [FIX] Make shared workflows read-only for shared users and show the project name instead of its ID - #2273

Open
kirtimanmishrazipstack wants to merge 4 commits into
mainfrom
UN-2868-sharing-improvements
Open

UN-2868 [FIX] Make shared workflows read-only for shared users and show the project name instead of its ID#2273
kirtimanmishrazipstack wants to merge 4 commits into
mainfrom
UN-2868-sharing-improvements

Conversation

@kirtimanmishrazipstack

@kirtimanmishrazipstack kirtimanmishrazipstack commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

What

If a workflow is shared with you, you can now look at how it is set up but you cannot change it. Before, anyone it was shared with could quietly rewrite the owner's settings.

What they could change and no longer can:

  • the destination folder results are written to, and the database table for database workflows
  • which connector the workflow uses
  • the tool settings and the Prompt Studio project it runs

The screen also says so up front. A shared user now sees a "Shared with you — view only" line, greyed out fields and no Save button, instead of a normal-looking form that fails once they press Save.

Separately, shared users were shown the Prompt Studio project's internal ID where the owner saw its name. They now see the name.

Owners, co-owners and organization admins are unaffected.

Closes all four defects in the ticket: 1 (HITL, with the cloud PR), 2 (Change Prompt), 3 (tool settings error), 4 (project ID).

Why

Reported by a customer. Sharing a workflow was meant to let colleagues run and watch it, not reconfigure it — someone could point another team's workflow at a different output folder without meaning to.

When sharing was rebuilt around owners and co-owners, the pieces inside a workflow were never included. Tool instances were fixed then; endpoints were missed.

How

  • New WorkflowOwnerMutationMixin in backend/permissions/permission.py, beside the is_workflow_mutator / IsParentWorkflowOwner it delegates to. Hands update / partial_update / destroy to IsParentWorkflowOwner and guards create explicitly, since DRF never runs object permissions on a collection-level action.
  • Applied to WorkflowEndpointViewSet. Its queryset already spanned shared workflows, so a shared user gets 403 rather than 404.
  • New useWorkflowCanEdit hook reads is_owner (already on the workflow payload) or sessionDetails.isAdmin. Read straight from the workflow store by Agency, ConfigureConnectorModal and ToolSettings — no prop drilling, no changed component signatures.
  • New ReadOnlyNotice widget and a .uneditable class that greys a whole region, used instead of per-input disabled because those regions hold third-party widgets (RJSF, the HITL query builder) with no single disabled prop. The tab bar sits outside it so viewers can still switch tabs.
  • ConfigureConnectorModal's Save now also flushes the HITL plugin's rules through a ref, and is shown in API mode too. It previously lit up for rule changes it could not save, then closed as though it had saved them.
  • The project name fell back to the raw function name because exportedTools holds only the viewer's own projects. It now falls back to the tool instance's name, already set by ToolInstanceSerializer.to_representation, before falling back to the ID.

Can this PR break any existing features. If yes, please list possible items. If no, please explain why.

  • Owners see one change: the connector window's Save now also saves HITL rules, and the separate "Save Rules" button is gone (cloud PR). Nothing is written until Save is pressed.
  • Reading is untouched — shared users can still open and inspect everything.
  • Automations are untouched — service accounts and API keys keep their access.

Database Migrations

  • None.

Env Config

  • None.

Relevant Docs

  • None.

Related Issues or PRs

Dependencies Versions

  • None.

Notes on Testing

Who Change connector config Read it
Owner 200
Org admin, not an owner 200
Shared user (viewer) 403 blocked 200
Org member, not shared 404 blocked

Exercised on both a database and an API destination through DRF's request factory, inside a rolled-back transaction. Frontend build passes.

Screenshots

Checklist

I have read and understood the Contribution Guidelines.

🤖 Generated with Claude Code

https://claude.ai/code/session_016eB6bLmieWVwUnmYH6H5WZ

…and org admins

Workflow sub-resources were never gated when the sharing model landed.
tool_instance_v2 was fixed; endpoint_v2 was missed, so any user a workflow
was shared with could change its destination folder, database table or
connector.

Adds a reusable WorkflowOwnerMutationMixin next to is_workflow_mutator and
applies it to WorkflowEndpointViewSet. Sharing -- direct, group or org-wide
-- now grants read only; owners, co-owners, org admins and service accounts
may still write.

The UI now says so up front instead of failing on save: a shared user sees a
read-only notice and greyed controls in the connector modal, tool settings,
and the Prompt Studio project selector, with no Save button to press.

The connector modal's Save now also flushes the HITL plugin's rules. It
previously lit up for rule changes it could not save, then closed as if it
had saved them.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016eB6bLmieWVwUnmYH6H5WZ
…tead of its ID

The workflow builder resolved the project name from exportedTools, which
holds only the viewer's own exported projects. On a shared workflow the
lookup missed and fell through to the raw function name, so shared users saw
an ID where the owner saw a name.

The tool instance already carries the display name (ToolInstanceSerializer
sets it from the tool's properties), so fall back to that before falling back
to the ID. The ID remains the last resort for a tool the registry can no
longer resolve.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016eB6bLmieWVwUnmYH6H5WZ
@kirtimanmishrazipstack kirtimanmishrazipstack changed the title UN-2868 [FIX] Prevent shared users from changing a workflow's destination connector and tool settings UN-2868 [FIX] Make shared workflows read-only for shared users and show the project name instead of its ID Sep 2, 2026
@kirtimanmishrazipstack
kirtimanmishrazipstack marked this pull request as ready for review September 2, 2026 09:41
@greptile-apps

greptile-apps Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR makes workflow sub-resources read-only for shared viewers while retaining mutation access for owners, co-owners, organization administrators, and service accounts.

  • Adds a reusable backend permission mixin and applies it to workflow endpoint mutations.
  • Adds frontend editability checks, read-only notices, and disabled mutation controls.
  • Displays the Prompt Studio project name from the workflow’s tool instance when the viewer’s exported-project list lacks it.
  • Coordinates connector and HITL rule saving while keeping the modal open after a failed endpoint update.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
backend/permissions/permission.py Adds a fail-closed workflow sub-resource mutation mixin; the previously reported unchecked create path is resolved.
backend/workflow_manager/endpoint_v2/views.py Applies owner-level mutation permissions to endpoint updates while preserving shared-user reads.
frontend/src/components/agency/configure-connector-modal/ConfigureConnectorModal.jsx Adds read-only presentation and coordinates endpoint and HITL saves without continuing after a failed endpoint update.
frontend/src/components/agency/agency/Agency.jsx Disables Prompt Studio project changes for viewers and adds the tool-instance name fallback.
frontend/src/components/agency/tool-settings/ToolSettings.jsx Prevents shared viewers from submitting tool-setting changes and presents the form as read-only.
frontend/src/hooks/useWorkflowCanEdit.js Centralizes frontend workflow editability using workflow ownership and organization-admin state.
frontend/src/components/widgets/read-only-notice/ReadOnlyNotice.jsx Introduces the shared view-only notice used by workflow configuration surfaces.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  U[Workflow user] --> UI[Workflow configuration UI]
  UI --> C{Owner, co-owner, or org admin?}
  C -- No --> RO[Show read-only notice and hide save controls]
  C -- Yes --> M[Submit endpoint mutation]
  M --> API[Workflow endpoint API]
  API --> P{Owner, org admin, or service account?}
  P -- No --> D[Return 403]
  P -- Yes --> S[Persist endpoint configuration]
Loading

Reviews (3): Last reviewed commit: "UN-2868 [FIX] Refuse form submits from v..." | Re-trigger Greptile

Comment thread backend/permissions/permission.py
… save

Addresses review feedback plus two defects found alongside it.

- perform_create skipped authorization entirely when the payload carried no
  workflow, then saved anyway. It now fails closed: every viewset using this
  mixin has a required workflow field, so a payload without one cannot be
  authorised.
- handleValidateAndSubmit swallowed its own error, so a failed endpoint write
  still fell through to the HITL write and "Save and Close" dismissed the
  modal. Both writes now report success and the modal stays open on failure.
- The HITL write only runs when its form is actually dirty; otherwise every
  connector save would have written a rule row too.
- A view-only user can no longer be asked whether to save unsaved changes on
  close. They cannot have made any.
- ReadOnlyNotice used defaultProps, which React 19 ignores on function
  components, so its default message never applied. Uses a default parameter.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016eB6bLmieWVwUnmYH6H5WZ
@kirtimanmishrazipstack

Copy link
Copy Markdown
Contributor Author

@greptile-apps Both findings fixed in 06198cc, plus three more found while tracing the second one.

Partial save / false close — valid, and the sharper of the two. handleValidateAndSubmit caught its own error and returned, so a failed endpoint write fell straight through to the HITL write and handleSaveAndClose dismissed the modal. Both writes now report success and handleSave bails on the first failure:

if (!(await handleValidateAndSubmit(formDataConfig))) {
  return false;
}

Create guard fails open — fixed, replied inline.

Found alongside these:

  • The HITL write now only runs when its form is actually dirty. Chaining it unconditionally meant every connector save also wrote a rule row.
  • A view-only user could be asked whether to save unsaved changes on close, which they cannot have made. hasUnsavedChanges() returns false when the workflow is not editable.
  • ReadOnlyNotice used defaultProps, which React 19 ignores on function components, so the default message never applied. Now a default parameter.

The companion cloud PR (#1751) also fixes the dirty flag that made this reachable: the HITL form was dirty from the moment it opened, because the baseline was either null or the server's raw rule_json compared against a builder-normalised round-trip. Sync destination and TTL are folded into that flag too, since they lost their own Save button.

Re-verified the permission matrix against real shared-workflow data after the change — owner and admin-not-owner write, shared viewer 403, non-shared 404, reads unaffected on both database and API destinations.

@greptile-apps

greptile-apps Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Thanks for the follow-up. The partial-save/false-close path and the create permission guard are addressed, along with the HITL dirty-write, view-only close prompt, and React 19 ReadOnlyNotice default issues. The companion cloud PR covers the remaining dirty-state normalization and destination/TTL tracking, and the permission matrix was re-verified across both destination types. No further concerns from me.

@kirtimanmishrazipstack

Copy link
Copy Markdown
Contributor Author

@greptile-apps review

Both findings from the previous pass are addressed in 06198cc, which landed after that review was generated.

The read-only styling suppresses pointer events but leaves fields focusable,
so a keyboard user could tab into one and press Enter. That fired a request
the backend rejects, producing exactly the confusing error this ticket is
about.

Both RJSF forms now refuse to submit when the workflow is not editable, so
the request is never made.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016eB6bLmieWVwUnmYH6H5WZ
@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Frontend Lint Report (Biome)

All checks passed! No linting or formatting issues found.

@sonarqubecloud

sonarqubecloud Bot commented Sep 2, 2026

Copy link
Copy Markdown

@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Unstract test results

Per-group results

Status Group Tier Passed Failed Errors Skipped Duration (s)
e2e-api-deployment e2e 3 0 0 0 20.3
e2e-coowners e2e 1 0 0 0 1.4
e2e-etl e2e 1 0 0 0 8.8
e2e-login e2e 2 0 0 0 1.2
e2e-prompt-studio e2e 1 0 0 0 4.9
e2e-smoke e2e 2 0 0 0 1.3
e2e-workflow e2e 1 0 0 0 16.3
frontend unit 0 1 0 0 0.0
integration-backend integration 310 0 0 26 37.1
integration-connectors integration 1 0 0 7 10.1
integration-workers integration 157 0 0 1 68.6
ui e2e 0 1 0 0 0.0
unit-backend unit 1158 0 0 1 43.3
unit-connectors unit 63 0 0 0 10.0
unit-core unit 33 0 0 0 1.4
unit-platform-service unit 15 0 0 0 2.6
unit-rig unit 120 0 0 0 4.7
unit-runner unit 5 0 0 0 3.0
unit-sdk1 unit 563 0 0 0 29.9
unit-workers unit 1397 0 0 1 131.3
TOTAL 3833 2 0 36 396.2

Critical paths

⚠️ Critical paths not yet covered

  • workflow-execution-fan-out — Multi-file workflow execution fans out to file-processing workers and rejoins. (declared coverage: no groups declared)
✅ Covered critical paths
  • auth-login — covered by e2e-login
  • adapter-register-llm — covered by integration-backend
  • workflow-author — covered by integration-backend
  • co-owner-manage — covered by integration-backend, e2e-coowners
  • workflow-create-execute — covered by e2e-workflow
  • api-deployment-provision — covered by integration-backend
  • api-deployment-auth — covered by integration-backend
  • api-deployment-run — covered by e2e-api-deployment
  • mcp-server-auth — covered by integration-backend
  • mcp-platform-auth — covered by integration-backend
  • prompt-studio-author — covered by integration-backend
  • prompt-studio-fetch-response — covered by e2e-prompt-studio
  • connector-register-test — covered by integration-backend
  • pipeline-etl-execute — covered by e2e-etl
  • usage-aggregate-read — covered by integration-backend
  • usage-token-tracking — covered by e2e-api-deployment
  • callback-result-delivery — covered by e2e-api-deployment

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.

1 participant