Enforce View Approval Path, definition scope, condition ownership and chat/email action settings on the server
Description
Depends on (merged to dev first): AP-2450 (Web API v2 decisions and decision details, StepAuthorizations, browsableIssueIds), AP-2146 (Teams, Slack and Teams click checks and their refusal), AP-2380 (ReferenceAccess / readableGrants, Rovo StartRules, definition scope checks), AP-2486 (POST forms of the approvals list and Activity), AP-2496 (the effective "actions without login" value of its fix 2, used by fix 5; or implement both together).
Problem
The UI hides these actions and data, but the server does not check them. A user who sends the request directly gets the data or makes the change.
-
View Approval Path permission. With the app's work item or page permissions on, a user without "View Approval Path" sees no approvals in the work item or page view, but the server returns them to anyone who may see the work item or page:
-
approvals list, including a single approval opened by link, with steps, decisions and comments (
/reference/approvals, GET and, since AP-2486, POST); -
Activity (
/activity/reference, GET and, since AP-2486, POST); -
definitions that can be started there (
/definition/reference); -
latest AI Prompt step run of an approval (
/prompt-step-executions/{approvalId}/{stepId}: error code and message; the result only for the approval's approvers). Decisions in the app view, version checks, the Web API decision details, Web API v2 decisions and Rovo already apply the permission. Affects both apps.
-
-
Reading a definition with
viewOnly(GET /definition/{id}?viewOnly=true) checks no permission. Any user in a project or space session gets that project's or space's and the global definitions (masked) by id, without View Approval Path, "View space settings page" or a definition permission. Affects both apps. -
Definition search (
/definition/search) without a project or space in the session (My overview, My approvals, gadget configuration) trusts thecollection-id/collection-idsof the request without a browse check, and returns every definition of the site when none are sent: id, name and project ids of definitions of any project or space. The Jira workflow configuration list (/workflow/definitions) returns every definition to anyone but a JSM customer. What the filter needs there: global definitions and those of the projects or spaces picked in the project filter, which offers only projects or spaces the user can browse. Affects both apps (workflow list: Jira). -
Conditions of other projects and sites. A definition's start and step conditions are stored by id as sent and loaded by id only, without checking site or project. Condition ids are one sequence shared by all sites. A user who may edit definitions can read, through a start condition, the name, expression, evaluating user and fail message of any condition, of other projects and other customers' sites, and make it decide starts and steps in their project. Rovo starts load definitions the same way. Conditions exist in the Jira app only, but the definition save request is shared by both apps.
-
Decision buttons already sent keep working after the settings are turned off:
-
Slack and Teams buttons refuse a click while "Enable actions without login" is off, but not while "Enable action buttons in notifications" is off;
-
email links check neither setting and work until they expire after 24 hours. Only the step's own approvers can use them, so this is no impersonation. The settings text "The link will be active for 24 hours" is true for email only.
-
Change
-
The four requests of item 1 (both GET and POST forms) are refused ("No access") without View Approval Path on that work item or page, by the rule of the decision request (
canDisplayReferenceView), the same rule Rovo and Web API v2 decisions use throughForgePermissionsService.readableGrants/ReferenceAccess. Portal access for JSM customers and agents and the behaviour with the app's permissions off are unchanged. No extra Atlassian call. -
With
viewOnly,GET /definition/{id}requires View Approval Path in the work item or page view, View space settings page or a definition permission in the space settings view, global admin in the global view.canViewDefinitiondoes not fit as is: View Approval Path counts for every user in the space settings and global views. The project or space scope (404) and masking stay as they are. -
Definition search without a project or space in the session returns global definitions and those of projects or spaces the user can browse, limited to the requested ones when sent (decision 4); global admins: as today. The same applies to
selected-ids./workflow/definitionsfollows decision 5. -
Saving a definition refuses a start or step condition not of the site, or of another project; a global definition may use global conditions only. The error names the id. One query per save checks all ids. Loading definitions and approvals, Rovo starts included, joins conditions within the site only.
-
A Slack or Teams button click and an email link are refused when either setting is off at the moment of the click (the effective "actions without login" value of AP-2496, fix 2). Slack and Teams reuse the existing refusals ("Acting on approvals from chat is turned off. Open the approval in Approval Path to decide.", with a link where the message can carry one); the email link page says "Acting on approvals from email is turned off. Open the approval in Approval Path to decide." The settings text matches decision 2.
Decisions needed
-
Definitions already stored with a foreign condition: list them on production for support before release, then drop the link on load? Recommended: yes.
-
Slack and Teams buttons: 24-hour limit like email, or valid while the step is open? Recommended: while the step is open (the clicker is identified by Slack or Teams), with the text "Email links stay active for 24 hours. Slack and Teams buttons work until the step is decided."
-
The start definitions list (item 1) also lacks the Start approval check; starting is checked on create. Rovo requires both Start approval and View Approval Path to start (
rovo/start/StartRules). Check only View Approval Path on the list, and add the View Approval Path check to the start request, so every start path follows the Rovo rule? Recommended: yes. -
Search outside a project context: one bulk browse permission call per request, cached per user like other access checks, or no call and only definitions of approvals the user may see? Recommended: the cached browse check, it keeps today's filter options.
JiraForgePermissions.browsableIssueIds(AP-2450) checks per work item, not per project, so it needs a project-level counterpart. -
/workflow/definitions: Jira admins only? Recommended: yes, the workflow editor is theirs; confirm team-managed project admins do not use it.
Out of scope
-
Who may decide through Slack, Teams or email links (approver eligibility is unchanged).
-
Already done in AP-2450 / AP-2380: excluded users refused on group steps on every decision path; definitions of another project or space return 404 and are unmasked only for global or same-project admins; search scoped to the session's project or space;
POST /definition/{id}/duplicatechecks the project or space.
Acceptance criteria
-
With permissions on, a user without View Approval Path on a work item or page gets "No access" from the four requests of item 1, GET and POST; with it, the data as today. Portal and permissions-off behaviour unchanged.
-
With
viewOnly, a user without any of the permissions of fix 2 gets "No access"; with one of them, the masked definition as today. -
In My overview, My approvals and gadget configuration, definition search returns global definitions and those of projects or spaces the user can browse, also when other ids or none are sent. Saved filters show names only for definitions the user may see. Global admins: as today.
-
/workflow/definitionsfollows decision 5. -
Saving with a condition of another site, another project, or a project condition on a global definition is refused, naming the id; own project and global conditions save as today.
-
A definition stored earlier with a foreign condition loads and starts without it, also from Rovo.
-
With "Enable action buttons in notifications" or "Enable actions without login" turned off after sending, a Slack button, a Teams button and an email link record no decision and show the refusal.
Manual tester notes
-
Send the requests with the browser developer tools, in the test user's session.
-
Item 1: with work item permissions on and View Approval Path removed from a test user, repeat the approvals list and Activity requests of a work item: refused. Repeat on Confluence; check the JSM portal as customer and agent.
-
Item 2: as a user without the permissions of fix 2, request a definition of the current project with
viewOnly. -
Item 3: as a user who cannot browse project B, open the definition filter in My overview, My approvals and gadget configuration: no project B definition, also when the request sends project B or a project B id in
selected-ids. A global admin sees all. Repeat on Confluence. -
Item 4: send a definition save with a condition id of another project and of another qa site.
-
Item 5: send a Slack and a Teams notification with buttons and an email with action links, turn off "Enable action buttons in notifications", click Approve: no decision. Repeat with "Enable actions without login".