diff --git a/app/components/admin/settings/project_reserved_identifiers/table_component.rb b/app/components/admin/settings/project_reserved_identifiers/table_component.rb index 8850b25b493..9dfa5f77a7b 100644 --- a/app/components/admin/settings/project_reserved_identifiers/table_component.rb +++ b/app/components/admin/settings/project_reserved_identifiers/table_component.rb @@ -47,5 +47,7 @@ module Admin::Settings::ProjectReservedIdentifiers def blank_title = t("admin.reserved_identifiers.empty_heading") def blank_description = t("admin.reserved_identifiers.empty_body") def blank_icon = :"check-circle" + + def pagination_params = { params: { action: "index" } } end end diff --git a/app/components/op_primer/border_box_table_component.html.erb b/app/components/op_primer/border_box_table_component.html.erb index bd5866576ce..182aff67bd7 100644 --- a/app/components/op_primer/border_box_table_component.html.erb +++ b/app/components/op_primer/border_box_table_component.html.erb @@ -140,5 +140,5 @@ See COPYRIGHT and LICENSE files for more details. <% end %> <% if paginated? %> - <%= helpers.pagination_links_full rows %> + <%= helpers.pagination_links_full rows, **pagination_params %> <% end %> diff --git a/app/components/op_primer/border_box_table_component.rb b/app/components/op_primer/border_box_table_component.rb index 433eddeab69..98802dbbe81 100644 --- a/app/components/op_primer/border_box_table_component.rb +++ b/app/components/op_primer/border_box_table_component.rb @@ -77,6 +77,8 @@ module OpPrimer self.class.main_column.include?(column) end + def pagination_params = {} + def column_title(name) _, header_options = headers.assoc(name) header_options&.dig(:caption) diff --git a/docker/prod/Dockerfile b/docker/prod/Dockerfile index 1e6d1c509ee..60e0d662e0c 100755 --- a/docker/prod/Dockerfile +++ b/docker/prod/Dockerfile @@ -141,7 +141,7 @@ ENV PGDATA=/var/openproject/pgdata COPY --from=openproject/gosu /go/bin/gosu /usr/local/bin/gosu RUN chmod +x /usr/local/bin/gosu && gosu nobody true -COPY --from=openproject/hocuspocus:17.4.0 --chown=$APP_USER:$APP_USER /app /opt/hocuspocus +COPY --from=openproject/hocuspocus:17.5.0 --chown=$APP_USER:$APP_USER /app /opt/hocuspocus # Keep node/npm in all-in-one for bundled hocuspocus even when BIM support is disabled. COPY --from=build-base /usr/local/bin/node /usr/local/bin/node COPY --from=build-base /usr/local/lib/node_modules /usr/local/lib/node_modules diff --git a/docs/release-notes/17-5-0/README.md b/docs/release-notes/17-5-0/README.md index eb8a8876167..58e864e9df9 100644 --- a/docs/release-notes/17-5-0/README.md +++ b/docs/release-notes/17-5-0/README.md @@ -14,6 +14,10 @@ We released [OpenProject 17.5.0](https://community.openproject.org/versions/2293 ## Important feature changes +Take a look at our release video showing the most important features introduced in OpenProject 17.5.0: + +![Release video of OpenProject 17.5](https://openproject-docs.s3.eu-central-1.amazonaws.com/videos/OpenProject_17_5_release.mp4) + ### Project-based work package identifiers for clearer references and Jira migrations OpenProject 17.5 introduces **optional project-based work package identifiers in Beta**. Administrators can choose between the **default numerical sequence** and **project-based IDs** for the entire OpenProject instance. @@ -21,7 +25,7 @@ OpenProject 17.5 introduces **optional project-based work package identifiers in > [!NOTE] > The setting can be reverted later. Existing numerical IDs remain valid and continue to resolve to the same work packages throughout the application, including existing URLs, bookmarks, and references. -![OpenProject administration to select either 'Instance-wide numerical sequence (default)' or 'Project-based semantic identifiers'](openproject-17-5-identifiers-setting.png) +![Work package table for version 17.5 with highlighted project-based work package IDs](openproject-community-project-based-ids-highlighted.png) Project-based work package identifiers are especially useful for organizations migrating from Jira, as [existing Jira issue identifiers can now be preserved in OpenProject](#jira-migrator-support-for-jira-identifiers-due-dates-and-more). Beyond migrations, project-based IDs provide **shorter sequence numbers and clearer project context**, making it easier to recognize, reference, and share work packages across projects, emails, documents, chats, and integrations. @@ -32,7 +36,7 @@ Switching to project-based work package identifiers is an instance-wide administ > [!NOTE] > Historical references remain functional when project identifiers change. -![OpenProject administration to configure project-based work package identifiers and convert project identifiers](openproject-17-5-project-based-identifier.png) +![OpenProject administration to select either 'Instance-wide numerical sequence (default)' or 'Project-based semantic identifiers'](openproject-17-5-identifiers-setting.png) #### Support across URLs, searches, exports, and integrations @@ -43,6 +47,8 @@ Existing integrations such as GitHub and GitLab already support the new identifi > [!NOTE] > Project-based work package identifiers are still in Beta. While the feature is supported across important areas of OpenProject, **some areas may continue to display numerical identifiers until support for project-based identifiers is fully implemented**. In these cases, numerical identifiers remain fully functional and continue to resolve to the same work packages. +[See our system admin guide for detailed information on how to manage work package identifiers](../../system-admin-guide/manage-work-packages/work-package-identifiers/). + #### Releasing unused numerical identifiers When switching from the default numerical sequence to project-based work package identifiers, previously reserved numerical identifiers can be released again if they are no longer needed. This helps administrators avoid unnecessary gaps and keep numerical identifiers available if they later revert to the default sequence. @@ -116,14 +122,6 @@ Instead of sending an email for every small change, OpenProject now consolidates [Read more about OpenProject's Meetings module](../../user-guide/meetings/). -### Nested groups for organizational structures and inherited permissions - -OpenProject 17.5 introduces nested groups to better represent organizational structures such as departments, teams, or business units. - -Groups can now contain subgroups, allowing administrators to model hierarchies directly in OpenProject. Permissions and memberships can also be inherited from parent groups, making it easier to manage access rights consistently across larger organizations. - -![Mockup showing users and permissions sorted into hierarchical groups](openproject-17-5-nested-groups-mockup.png) - ### Allow multi-selection of roles in workflow OpenProject 17.5 improves workflow administration by allowing administrators to select and configure multiple roles at once in the workflow configuration. This makes it easier and faster to manage workflows across complex role setups and reduces repetitive configuration work for administrators. @@ -153,10 +151,36 @@ to requests and also can't be added or altered through JavaScript. It's unlikely should only be used for browser-contexts, where the new header will still be present. Non-browser API-access should use different authentication methods (e.g. OAuth or API tokens), which are not affected by this change. +### SSRF protection for the SAML integration + +In previous releases, we have introduced improved mechanisms to prevent Server-Side Request Forgery (SSRF) for integrations that communicate with external hosts. In this release, we have extended the SSRF protections to SAML. + +In most installations, this will not require any changes. +However, if you operate your SAML using internal IP addresses, you may need to add your IP or range to the `OPENPROJECT_SSRF_PROTECTION_IP_ALLOWLIST` configuration. Please see [the configuration guide for SSRF](https://www.openproject.org/docs/installation-and-operations/configuration/ssrf-protection/) for more information. + +We'd like to thank GitHub user [@aslantugay](https://github.com/aslantugay) for reporting on the SAML integration still lacking SSRF protection as part of GitHub advisory https://github.com/opf/openproject/security/advisories/GHSA-mq29-cmv3-rcmr. + +## Security fixes + + + +### CVE-2026-52779 - Cross-project authorization bypass allows deleting public Calendar and Team Planner queries from unauthorized projects + +A cross-project IDOR / authorization context confusion in the Calendar and Team Planner modules allows a user with management permissions in one project to delete public Calendar or Team Planner Queries from another project where they do not have the corresponding management permissions. + + + +This vulnerability was reported as part of the [YesWeHack.com OpenProject Bug Bounty program](https://yeswehack.com/programs/openproject), sponsored by the European Commission. + + + +For more information, please see the [GitHub advisory #GHSA-jrx5-px3f-vfq4](https://github.com/opf/openproject/security/advisories/GHSA-jrx5-px3f-vfq4) + + @@ -165,124 +189,129 @@ methods (e.g. OAuth or API tokens), which are not affected by this change. -- Feature: Track working hours and availabilities for each user in the system \[[#34911](https://community.openproject.org/wp/34911)\] +- Feature: Exclude certain work package types from automated backlog (per project) \[[#71305](https://community.openproject.org/wp/71305)\] +- Feature: Container header (Sprint/Bucket/Inbox) restyling \[[#72945](https://community.openproject.org/wp/72945)\] +- Feature: Restyled work package card in "Backlogs and sprints" view \[[#73089](https://community.openproject.org/wp/73089)\] +- Feature: Bring sprint sharing (SAFe) to corporate plan \[[#74147](https://community.openproject.org/wp/74147)\] +- Feature: Create work package links through # notation in documents / BlockNote \[[#73664](https://community.openproject.org/wp/73664)\] +- Feature: Create a WorkPackageCard component \[[#73968](https://community.openproject.org/wp/73968)\] +- Feature: Extend the SubHeader component to support quick filter components \[[#73972](https://community.openproject.org/wp/73972)\] +- Feature: Jira Migrator imports project-based semantic issue identifiers \[[#72427](https://community.openproject.org/wp/72427)\] +- Feature: Jira Migrator supports due date, estimated hours and remaining hours. \[[#74807](https://community.openproject.org/wp/74807)\] - Feature: Meeting series: Add monthly scheduling options \[[#61522](https://community.openproject.org/wp/61522)\] - Feature: Debounce emails for meetings \[[#66645](https://community.openproject.org/wp/66645)\] - Feature: Primerize Types form configuration page \[[#69524](https://community.openproject.org/wp/69524)\] -- Feature: Sprint goals \[[#71059](https://community.openproject.org/wp/71059)\] -- Feature: Exclude certain work package types from automated backlog (per project) \[[#71305](https://community.openproject.org/wp/71305)\] +- Feature: Expand work package mentions (##, ###) macros inside CKEditor \[[#74641](https://community.openproject.org/wp/74641)\] +- Feature: Allow Custom Fields on UserQuery \[[#74758](https://community.openproject.org/wp/74758)\] +- Feature: Primerize users administration to allow all filters \[[#74763](https://community.openproject.org/wp/74763)\] +- Feature: Workflows UX improvement: Allow multi-selection of roles in workflow \[[#72242](https://community.openproject.org/wp/72242)\] - Feature: Administration setting for project-based work package identifiers \[[#71633](https://community.openproject.org/wp/71633)\] - Feature: Background job for converting project-based semantic work package identifiers \[[#71645](https://community.openproject.org/wp/71645)\] -- Feature: Allow nested Groups to show a company org chart \[[#72224](https://community.openproject.org/wp/72224)\] -- Feature: Workflows UX improvement: Allow multi-selection of roles in workflow \[[#72242](https://community.openproject.org/wp/72242)\] -- Feature: Jira Migrator imports project-based semantic work item identifiers \[[#72427](https://community.openproject.org/wp/72427)\] -- Feature: Allow inline Work Package links within text paragraphs \[[#72817](https://community.openproject.org/wp/72817)\] -- Feature: Container header (Sprint/Bucket/Inbox) restyling \[[#72945](https://community.openproject.org/wp/72945)\] -- Feature: Restyled work package card in "Backlogs and sprints" view \[[#73089](https://community.openproject.org/wp/73089)\] +- Feature: Allow inline Work Package links within text paragraphs in the Documents module \[[#72817](https://community.openproject.org/wp/72817)\] - Feature: Adapt creation of projects through the API for semantic identifiers \[[#73175](https://community.openproject.org/wp/73175)\] - Feature: Define database model for project-based work package identifiers \[[#73315](https://community.openproject.org/wp/73315)\] -- Feature: Create work package links through # notation in documents / BlockNote \[[#73664](https://community.openproject.org/wp/73664)\] - Feature: Adapt work package show view for project-based semantic work package identifiers \[[#73716](https://community.openproject.org/wp/73716)\] - Feature: Adapt work package lists for project-based semantic work package identifiers \[[#73717](https://community.openproject.org/wp/73717)\] - Feature: Adapt routes for project-based semantic work package identifiers \[[#73756](https://community.openproject.org/wp/73756)\] - Feature: Search work packages by their identifier \[[#73761](https://community.openproject.org/wp/73761)\] - Feature: Adapt email notifications for project-based work package identifiers \[[#73827](https://community.openproject.org/wp/73827)\] -- Feature: Create a WorkPackageCard component \[[#73968](https://community.openproject.org/wp/73968)\] -- Feature: Extend the SubHeader component to support quick filter components \[[#73972](https://community.openproject.org/wp/73972)\] - Feature: Adapt work package link blocks in BlockNote for project-based semantic work package identifiers \[[#74115](https://community.openproject.org/wp/74115)\] - Feature: Adapt work package links in CKEditor for project-based semantic work package identifiers \[[#74116](https://community.openproject.org/wp/74116)\] -- Feature: Bring sprint sharing (SAFe) to corporate plan \[[#74147](https://community.openproject.org/wp/74147)\] - Feature: Adapt GitHub and GitLab modules for semantic identifiers \[[#74364](https://community.openproject.org/wp/74364)\] - Feature: Adapt work package PDF exports for semantic identifiers \[[#74366](https://community.openproject.org/wp/74366)\] -- Feature: Expand work package mentions (##, ###) macros inside CKEditor \[[#74641](https://community.openproject.org/wp/74641)\] -- Feature: Allow Custom Fields on UserQuery \[[#74758](https://community.openproject.org/wp/74758)\] -- Feature: Primerize users administration to allow all filters \[[#74763](https://community.openproject.org/wp/74763)\] -- Feature: Jira Migrator supports due date, estimated hours and remaining hours. \[[#74807](https://community.openproject.org/wp/74807)\] - Feature: Add better progress indicator to identifier conversion page \[[#74903](https://community.openproject.org/wp/74903)\] - Feature: Put "Beta" label on the setting for enabling semantic identifiers \[[#74975](https://community.openproject.org/wp/74975)\] - Feature: Admin panel for releasing old classic project aliases \[[#74992](https://community.openproject.org/wp/74992)\] -- Bugfix: WP table configuration: overflow due to the very long CF label \[[#46005](https://community.openproject.org/wp/46005)\] -- Bugfix: Tooltip on Team planner not entirely visible \[[#48223](https://community.openproject.org/wp/48223)\] -- Bugfix: Work package configuration dialog's highlighting tab has no space between radio buttons and labels \[[#64359](https://community.openproject.org/wp/64359)\] -- Bugfix: Misalignment of fields in Work estimates and progress when language=DE \[[#65738](https://community.openproject.org/wp/65738)\] -- Bugfix: Wrong calendar week in My time tracking \[[#68272](https://community.openproject.org/wp/68272)\] -- Bugfix: Asterisks on Project attributes displaced \[[#68633](https://community.openproject.org/wp/68633)\] -- Bugfix: Clicking work package tabs triggers page reload and flickering \[[#69210](https://community.openproject.org/wp/69210)\] -- Bugfix: Infinite SAML Seeding Loop Causing Disk Space Exhaustion \[[#69339](https://community.openproject.org/wp/69339)\] -- Bugfix: Mobile - Include project on WP list is missing spacing \[[#69451](https://community.openproject.org/wp/69451)\] -- Bugfix: Roles selectable as "Role given to a non-admin user who creates a project" that lack essential permissions \[[#69496](https://community.openproject.org/wp/69496)\] -- Bugfix: Fix accessibility errors found by ERB Lint \[[#70166](https://community.openproject.org/wp/70166)\] -- Bugfix: BlockNote: Drag and drop of table blocks broken \[[#71900](https://community.openproject.org/wp/71900)\] -- Bugfix: Connection error on successive navigation to and from a document \[[#71901](https://community.openproject.org/wp/71901)\] -- Bugfix: Impossible to search for archived projects, page reverts to active projects list on its own \[[#71971](https://community.openproject.org/wp/71971)\] -- Bugfix: Click position is lost when activating an inline edit field \[[#72837](https://community.openproject.org/wp/72837)\] -- Bugfix: Incorrect confirmation message when deleting a OAuth token \[[#72958](https://community.openproject.org/wp/72958)\] -- Bugfix: Role not created properly when unselecting all permissions \[[#73494](https://community.openproject.org/wp/73494)\] -- Bugfix: POST/PATCH/DELETE requests to APIv3 return unauthorized \[[#73499](https://community.openproject.org/wp/73499)\] -- Bugfix: Copy & Paste Loses Formatting in Documents \[[#73669](https://community.openproject.org/wp/73669)\] -- Bugfix: Not possible to follow link custom field from work package list view \[[#73673](https://community.openproject.org/wp/73673)\] -- Bugfix: Doubled scrollbar on a Board \[[#73714](https://community.openproject.org/wp/73714)\] -- Bugfix: Jira migrator: "An internal error has occurred" \[[#73736](https://community.openproject.org/wp/73736)\] -- Bugfix: Nextcloud integration shows "No connection to Nextcloud" for folders that have "&" in the name \[[#73855](https://community.openproject.org/wp/73855)\] -- Bugfix: Lists of work packages should sort correctly by semantic id \[[#74156](https://community.openproject.org/wp/74156)\] -- Bugfix: Automatically converting project identifiers should not lead to usage of reserved keywords \[[#74161](https://community.openproject.org/wp/74161)\] -- Bugfix: Moving work packages after switching to semantic and back should not lead to errors \[[#74192](https://community.openproject.org/wp/74192)\] -- Bugfix: Cancel occurrence action item is called 'Delete' on My Meetings page and Meeting index page 'Past' tab \[[#74303](https://community.openproject.org/wp/74303)\] -- Bugfix: User cannot restore a cancelled occurrence if series has a deleted WP on the agenda \[[#74304](https://community.openproject.org/wp/74304)\] -- Bugfix: Show default section more clearly when using the section selector for a meeting with no sections \[[#74321](https://community.openproject.org/wp/74321)\] +- Bugfix: Closed work packages are still considered to be part of the bucket. \[[#74773](https://community.openproject.org/wp/74773)\] +- Bugfix: Inconsistent handling of "Definition of Done" \[[#74796](https://community.openproject.org/wp/74796)\] +- Bugfix: Backlogs: Missing space on mobile \[[#75188](https://community.openproject.org/wp/75188)\] +- Bugfix: Sprint field is sometimes not visible on the wp page \[[#75194](https://community.openproject.org/wp/75194)\] +- Bugfix: Backlog settings tab switching doesn't persist in url \[[#75239](https://community.openproject.org/wp/75239)\] +- Bugfix: No "Undisclosed" mention for the parent work package on the wp card for a user without permissions to see the parent \[[#75241](https://community.openproject.org/wp/75241)\] +- Bugfix: Incorrect resize behavior for pasted inline-links \[[#74190](https://community.openproject.org/wp/74190)\] - Bugfix: Inserting "#" inside text removes content after cursor \[[#74325](https://community.openproject.org/wp/74325)\] -- Bugfix: Cards converting to hash links on copy-paste and DnD \[[#74327](https://community.openproject.org/wp/74327)\] +- Bugfix: Сards converting to hash links on copy-paste and DnD \[[#74327](https://community.openproject.org/wp/74327)\] - Bugfix: Type colors are not applied correctly at the beginning \[[#74330](https://community.openproject.org/wp/74330)\] -- Bugfix: Impossible to open work packages list from the sidebar after visiting team planner \[[#74331](https://community.openproject.org/wp/74331)\] - Bugfix: Inconsistent contrast for type colors when switching themes \[[#74332](https://community.openproject.org/wp/74332)\] - Bugfix: Dropdown option order changes depending on selected item \[[#74333](https://community.openproject.org/wp/74333)\] -- Bugfix: Inconsistent inline chip heights in text flow \[[#74341](https://community.openproject.org/wp/74341)\] -- Bugfix: User can only delete a past occurrence \[[#74363](https://community.openproject.org/wp/74363)\] +- Bugfix: Inconsistent inline-link heights in text flow \[[#74341](https://community.openproject.org/wp/74341)\] - Bugfix: Inline work package chip has no visual highlight when selected \[[#74385](https://community.openproject.org/wp/74385)\] - Bugfix: Arrow-down selection for link work package block prevented by tooltip \[[#74393](https://community.openproject.org/wp/74393)\] - Bugfix: Wrong cursor placement after inserting links to Work Packages in BlockNote \[[#74397](https://community.openproject.org/wp/74397)\] -- Bugfix: Copy/paste of a single block(chip) does not work \[[#74538](https://community.openproject.org/wp/74538)\] -- Bugfix: Roles select panel button should be "Apply" \[[#74560](https://community.openproject.org/wp/74560)\] -- Bugfix: Use memory more efficiently \[[#74579](https://community.openproject.org/wp/74579)\] -- Bugfix: After migration job is complete save button is visible and clicking it triggers a 404 \[[#74623](https://community.openproject.org/wp/74623)\] - Bugfix: Improve size menu and remove L+XL blocks \[[#74651](https://community.openproject.org/wp/74651)\] -- Bugfix: Admin page for semantic IDs: grammatical issue \[[#74681](https://community.openproject.org/wp/74681)\] -- Bugfix: Semantic ids: semantic identifier mismatch for new-1 \[[#74692](https://community.openproject.org/wp/74692)\] +- Bugfix: Click position is lost when activating an inline edit field \[[#72837](https://community.openproject.org/wp/72837)\] +- Bugfix: Doubled scrollbar on a Board \[[#73714](https://community.openproject.org/wp/73714)\] +- Bugfix: Quick filters don't react good to medium screen sizes \[[#74832](https://community.openproject.org/wp/74832)\] +- Bugfix: Hide pagination buttons when they are disabled \[[#75258](https://community.openproject.org/wp/75258)\] +- Bugfix: Horizontal ellipsis button misaligned when text expanded on Permissions Report/Workflows pages \[[#75275](https://community.openproject.org/wp/75275)\] +- Bugfix: Jira Migrator: misalignement between the status badge and the import name \[[#72840](https://community.openproject.org/wp/72840)\] +- Bugfix: Imprecise error for unallowed IP when testing Jira connection \[[#75031](https://community.openproject.org/wp/75031)\] +- Bugfix: Imprecise error for SSL errors when testing Jira connection \[[#75032](https://community.openproject.org/wp/75032)\] +- Bugfix: Jira Migrator cannot import a user with non-alphanumeric characters in their name \[[#75238](https://community.openproject.org/wp/75238)\] +- Bugfix: Jira Migrator stops the import for non-existing user in user mention \[[#75248](https://community.openproject.org/wp/75248)\] +- Bugfix: Remove extra space in Jira Migrator backup warning dialog \[[#75353](https://community.openproject.org/wp/75353)\] +- Bugfix: Jira Migrator does not scope issues between import runs. \[[#75355](https://community.openproject.org/wp/75355)\] +- Bugfix: Jira Migrator shows 0 issues info if server does not include the data in serverInfo endpoint \[[#75380](https://community.openproject.org/wp/75380)\] +- Bugfix: Jira Migrator gives unhelpful error message if user email is blank \[[#75381](https://community.openproject.org/wp/75381)\] +- Bugfix: No way to find jira import run history page \[[#75382](https://community.openproject.org/wp/75382)\] +- Bugfix: Enabled rate limiting on Jira instance breaks projects selector. \[[#75391](https://community.openproject.org/wp/75391)\] +- Bugfix: Wrong wording on import page in admin \[[#75422](https://community.openproject.org/wp/75422)\] +- Bugfix: Jira Migrator: Do not disable the new configuration button if the instance is not switched to semantic identifiers \[[#75674](https://community.openproject.org/wp/75674)\] +- Bugfix: Cancel occurence action item is called 'Delete' on My Meetings page and Meeting index page 'Past' tab \[[#74303](https://community.openproject.org/wp/74303)\] +- Bugfix: User cannot restore a cancelled occurrence if series has a deleted WP on the agenda \[[#74304](https://community.openproject.org/wp/74304)\] +- Bugfix: Show default section more clearly when using the section selector for a meeting with no sections \[[#74321](https://community.openproject.org/wp/74321)\] +- Bugfix: Meetings endpoint /api/v3/recurring\_meetings/:id/occurrences/:start\_time/init is not properly authorized \[[#75449](https://community.openproject.org/wp/75449)\] +- Bugfix: ActiveRecord::InvalidForeignKey on RecurringMeetingsController#end\_series \[[#75463](https://community.openproject.org/wp/75463)\] +- Bugfix: Work package configuration dialog's highlighting tab has no space between radio buttons and labels \[[#64359](https://community.openproject.org/wp/64359)\] +- Bugfix: Log time modal dropdown's bottom border is indistignuishable from the modal's bottom border \[[#65523](https://community.openproject.org/wp/65523)\] +- Bugfix: Wrong calendar week in My time tracking \[[#68272](https://community.openproject.org/wp/68272)\] +- Bugfix: Asterisks on Project attributes displaced \[[#68633](https://community.openproject.org/wp/68633)\] +- Bugfix: \[Meetings\] Exception raised while trying to update Stale Object \[[#68703](https://community.openproject.org/wp/68703)\] +- Bugfix: Clicking work package tabs triggers page reload and flickering \[[#69210](https://community.openproject.org/wp/69210)\] +- Bugfix: Mobile - Include project on WP list is missing spacing \[[#69451](https://community.openproject.org/wp/69451)\] +- Bugfix: Roles selectable as "Role given to a non-admin user who creates a project" that lack essential permissions \[[#69496](https://community.openproject.org/wp/69496)\] +- Bugfix: Text overflow in Baseline modal banner \[[#69526](https://community.openproject.org/wp/69526)\] +- Bugfix: Fix accessibility errors found by ERB Lint \[[#70166](https://community.openproject.org/wp/70166)\] +- Bugfix: Role not created properly when unselecting all permissions \[[#73494](https://community.openproject.org/wp/73494)\] +- Bugfix: POST/PATCH/DELETE requests to APIv3 return unauthorized \[[#73499](https://community.openproject.org/wp/73499)\] +- Bugfix: "Upgrade" button label should not be underlined \[[#73570](https://community.openproject.org/wp/73570)\] +- Bugfix: Not possible to filter for blocked users in time and cost report \[[#73660](https://community.openproject.org/wp/73660)\] +- Bugfix: Not possible to follow link custom field from work package list view \[[#73673](https://community.openproject.org/wp/73673)\] - Bugfix: Black font in dark mode on wp description \[[#74697](https://community.openproject.org/wp/74697)\] -- Bugfix: Admin page for semantic IDs: long ids cause overflow \[[#74730](https://community.openproject.org/wp/74730)\] - Bugfix: Add upcoming/past filter to meetings index page filters \[[#74743](https://community.openproject.org/wp/74743)\] +- Bugfix: Redirect to /login is missing the URL query params \[[#74778](https://community.openproject.org/wp/74778)\] +- Bugfix: Missing space between user avatar and name \[[#74853](https://community.openproject.org/wp/74853)\] +- Bugfix: LDAP seeding via OPENPROJECT\_SEED\_LDAP\_\* uses a different (and self-contradictory) key convention than the rest of the env-var settings \[[#75361](https://community.openproject.org/wp/75361)\] +- Bugfix: Incorrect confirmation message when deleting a OAuth token \[[#72958](https://community.openproject.org/wp/72958)\] +- Bugfix: Roles select panel button should be "Apply" \[[#74560](https://community.openproject.org/wp/74560)\] +- Bugfix: Nextcloud integration shows "No connection to Nextcloud" for folders that have "&" in the name \[[#73855](https://community.openproject.org/wp/73855)\] +- Bugfix: Shared work package not showing images of comments \[[#69056](https://community.openproject.org/wp/69056)\] +- Bugfix: Lists of work packages should sort correctly by semantic id \[[#74156](https://community.openproject.org/wp/74156)\] +- Bugfix: Automatically converting project identifiers should not lead to usage of reserved keywords \[[#74161](https://community.openproject.org/wp/74161)\] +- Bugfix: Moving work packages after switching to semantic and back should not lead to errors \[[#74192](https://community.openproject.org/wp/74192)\] +- Bugfix: After migration job is complete save button is visible and clicking it triggers a 404 \[[#74623](https://community.openproject.org/wp/74623)\] +- Bugfix: Admin page for semantic IDs: grammatical issue \[[#74681](https://community.openproject.org/wp/74681)\] +- Bugfix: Admin page for semantic IDs: long ids cause overflow \[[#74730](https://community.openproject.org/wp/74730)\] - Bugfix: Numeric ID still in the URL of the link opened from the email notification \[[#74760](https://community.openproject.org/wp/74760)\] - Bugfix: Numeric ID in the email notification after adding watchers \[[#74762](https://community.openproject.org/wp/74762)\] -- Bugfix: Closed work packages are still considered to be part of the bucket. \[[#74773](https://community.openproject.org/wp/74773)\] -- Bugfix: Redirect to /login is missing the URL query params \[[#74778](https://community.openproject.org/wp/74778)\] -- Bugfix: Inconsistent handling of "Definition of Done" \[[#74796](https://community.openproject.org/wp/74796)\] -- Bugfix: Spanish (ES) localization mixes formal and informal second-person forms \[[#74817](https://community.openproject.org/wp/74817)\] - Bugfix: Numeric ID copied instead of semantic ID in "Copy work package ID" on Backlogs page \[[#74826](https://community.openproject.org/wp/74826)\] -- Bugfix: Search with ID doesn't work in work package table configuration if work package belongs to another project \[[#74830](https://community.openproject.org/wp/74830)\] -- Bugfix: Quick filters don't react good to medium screen sizes \[[#74832](https://community.openproject.org/wp/74832)\] - Bugfix: Numeric ID in URL of the wp link when opened from search results \[[#74834](https://community.openproject.org/wp/74834)\] - Bugfix: Semantic ID is not shown in search results in different places \[[#74844](https://community.openproject.org/wp/74844)\] -- Bugfix: Missing space between user avatar and name \[[#74853](https://community.openproject.org/wp/74853)\] - Bugfix: Numeric ID instead of semantic one in the spent time calendar \[[#74900](https://community.openproject.org/wp/74900)\] - Bugfix: Numeric ID instead of semantic one on the Activity page \[[#74912](https://community.openproject.org/wp/74912)\] - Bugfix: Numeric ID instead of semantic one in Roadmap \[[#74913](https://community.openproject.org/wp/74913)\] - Bugfix: Numeric ID instead of semantic one in bulk edit work packages \[[#74926](https://community.openproject.org/wp/74926)\] - Bugfix: Unable to change a parent on bulk edit of work packages with semantic ID \[[#74927](https://community.openproject.org/wp/74927)\] - Bugfix: Numeric ID instead of semantic one on the error message on bulk edit \[[#74928](https://community.openproject.org/wp/74928)\] -- Bugfix: Show type of field beside the attribute \[[#74931](https://community.openproject.org/wp/74931)\] - Bugfix: Numeric ID instead of semantic one on the table of related work packages \[[#74942](https://community.openproject.org/wp/74942)\] - Bugfix: Numeric ID instead of semantic one on the Time and costs report \[[#74943](https://community.openproject.org/wp/74943)\] - Bugfix: Numeric ID instead of semantic one on the wp delete confirmation dialogue \[[#74944](https://community.openproject.org/wp/74944)\] - Bugfix: All-numeric project identifiers are not properly handled in classic mode \[[#74993](https://community.openproject.org/wp/74993)\] -- Bugfix: Fix markdown generation in Hocuspocus and manual copy to clipboard \[[#75024](https://community.openproject.org/wp/75024)\] -- Bugfix: Imprecise error for unallowed IP when testing Jira connection \[[#75031](https://community.openproject.org/wp/75031)\] -- Bugfix: Imprecise error for SSL errors when testing Jira connection \[[#75032](https://community.openproject.org/wp/75032)\] -- Bugfix: Impossible to go back with single click from the user profile to the users list when a filter is added \[[#75179](https://community.openproject.org/wp/75179)\] - Bugfix: Numeric ID visible in edit mode in links with # \[[#75180](https://community.openproject.org/wp/75180)\] -- Bugfix: Backlogs: Missing space on mobile \[[#75188](https://community.openproject.org/wp/75188)\] -- Bugfix: No tooltip for priority on the wp cards on the backlogs \[[#75240](https://community.openproject.org/wp/75240)\] -- Bugfix: No "Undisclosed" mention for the parent work package on the wp card for a user without permissions to see the parent \[[#75241](https://community.openproject.org/wp/75241)\] -- Feature: Provide project templates within new OpenProject instances \[[#72778](https://community.openproject.org/wp/72778)\] +- Bugfix: Inconsistent naming on admin page \[[#75362](https://community.openproject.org/wp/75362)\] +- Bugfix: Reserved project identifiers: UI fails silently with 404 console error when acting on a deleted project \[[#75483](https://community.openproject.org/wp/75483)\] +- Bugfix: workPackageValue:ID:attribute macros failing with semantic IDs \[[#75574](https://community.openproject.org/wp/75574)\] +- Bugfix: Numeric ID showing in Github tab on work packages without links to PRs \[[#75636](https://community.openproject.org/wp/75636)\] diff --git a/docs/release-notes/17-5-0/openproject-community-project-based-ids-highlighted.png b/docs/release-notes/17-5-0/openproject-community-project-based-ids-highlighted.png new file mode 100644 index 00000000000..a76c7e9b64c Binary files /dev/null and b/docs/release-notes/17-5-0/openproject-community-project-based-ids-highlighted.png differ diff --git a/docs/release-notes/README.md b/docs/release-notes/README.md index d726e5c9f75..3c8d785c1cd 100644 --- a/docs/release-notes/README.md +++ b/docs/release-notes/README.md @@ -13,6 +13,13 @@ Stay up to date and get an overview of the new features included in the releases +## 17.5.0 + +Release date: 2026-06-10 + +[Release Notes](17-5-0/) + + ## 17.3.4 Release date: 2026-06-08 diff --git a/extensions/op-blocknote-hocuspocus/package-lock.json b/extensions/op-blocknote-hocuspocus/package-lock.json index fd6f56fe45e..293f653f450 100644 --- a/extensions/op-blocknote-hocuspocus/package-lock.json +++ b/extensions/op-blocknote-hocuspocus/package-lock.json @@ -12,7 +12,7 @@ "@blocknote/server-util": "^0.51.3", "@hocuspocus/extension-logger": "^3.4.4", "@hocuspocus/server": "^3.4.0", - "op-blocknote-extensions": "https://github.com/opf/op-blocknote-extensions/releases/download/v0.1.1/op-blocknote-extensions-0.1.1.tgz", + "op-blocknote-extensions": "https://github.com/opf/op-blocknote-extensions/releases/download/v0.1.2/op-blocknote-extensions-0.1.2.tgz", "tsx": "^4.21.0" }, "devDependencies": { @@ -4245,9 +4245,9 @@ "license": "MIT" }, "node_modules/op-blocknote-extensions": { - "version": "0.1.1", - "resolved": "https://github.com/opf/op-blocknote-extensions/releases/download/v0.1.1/op-blocknote-extensions-0.1.1.tgz", - "integrity": "sha512-4VO5Qf51Z8WQGD24AYhNmGHGGwnfnB3q8KwL48hWTifZq/9IL5rKpwKB+QkxvVUCaT8iwFYwB6QPzGgLJKRVFA==", + "version": "0.1.2", + "resolved": "https://github.com/opf/op-blocknote-extensions/releases/download/v0.1.2/op-blocknote-extensions-0.1.2.tgz", + "integrity": "sha512-6uGRJ2SlIVq0LwNnb8KZXhX09fvwXzrkrtsoRVZUrZKKsRFCVd15bgOu/3DyOCvwztXj4h+6VP2N6PkzeCBpUA==", "dependencies": { "@primer/octicons-react": "^19.20.0", "i18next": "^25.6.3", diff --git a/extensions/op-blocknote-hocuspocus/package.json b/extensions/op-blocknote-hocuspocus/package.json index ee156887b0a..e93759bf64d 100644 --- a/extensions/op-blocknote-hocuspocus/package.json +++ b/extensions/op-blocknote-hocuspocus/package.json @@ -26,7 +26,7 @@ "@blocknote/server-util": "^0.51.3", "@hocuspocus/extension-logger": "^3.4.4", "@hocuspocus/server": "^3.4.0", - "op-blocknote-extensions": "https://github.com/opf/op-blocknote-extensions/releases/download/v0.1.1/op-blocknote-extensions-0.1.1.tgz", + "op-blocknote-extensions": "https://github.com/opf/op-blocknote-extensions/releases/download/v0.1.2/op-blocknote-extensions-0.1.2.tgz", "tsx": "^4.21.0" }, "devDependencies": { diff --git a/frontend/package-lock.json b/frontend/package-lock.json index a8aa2dbf224..319aabea739 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -106,7 +106,7 @@ "ng2-dragula": "^6.0.0", "ngx-cookie-service": "^21.3.1", "observable-array": "0.0.4", - "op-blocknote-extensions": "https://github.com/opf/op-blocknote-extensions/releases/download/v0.1.1/op-blocknote-extensions-0.1.1.tgz", + "op-blocknote-extensions": "https://github.com/opf/op-blocknote-extensions/releases/download/v0.1.2/op-blocknote-extensions-0.1.2.tgz", "openapi-explorer": "^2.4.799", "pako": "^2.0.3", "qr-creator": "^1.0.0", @@ -17516,9 +17516,9 @@ } }, "node_modules/op-blocknote-extensions": { - "version": "0.1.1", - "resolved": "https://github.com/opf/op-blocknote-extensions/releases/download/v0.1.1/op-blocknote-extensions-0.1.1.tgz", - "integrity": "sha512-4VO5Qf51Z8WQGD24AYhNmGHGGwnfnB3q8KwL48hWTifZq/9IL5rKpwKB+QkxvVUCaT8iwFYwB6QPzGgLJKRVFA==", + "version": "0.1.2", + "resolved": "https://github.com/opf/op-blocknote-extensions/releases/download/v0.1.2/op-blocknote-extensions-0.1.2.tgz", + "integrity": "sha512-6uGRJ2SlIVq0LwNnb8KZXhX09fvwXzrkrtsoRVZUrZKKsRFCVd15bgOu/3DyOCvwztXj4h+6VP2N6PkzeCBpUA==", "dependencies": { "@primer/octicons-react": "^19.20.0", "i18next": "^25.6.3", diff --git a/frontend/package.json b/frontend/package.json index c4b4e2e78c8..8b759c656fb 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -153,7 +153,7 @@ "ng2-dragula": "^6.0.0", "ngx-cookie-service": "^21.3.1", "observable-array": "0.0.4", - "op-blocknote-extensions": "https://github.com/opf/op-blocknote-extensions/releases/download/v0.1.1/op-blocknote-extensions-0.1.1.tgz", + "op-blocknote-extensions": "https://github.com/opf/op-blocknote-extensions/releases/download/v0.1.2/op-blocknote-extensions-0.1.2.tgz", "openapi-explorer": "^2.4.799", "pako": "^2.0.3", "qr-creator": "^1.0.0", diff --git a/frontend/src/app/features/in-app-notifications/center/state/ian-center.service.ts b/frontend/src/app/features/in-app-notifications/center/state/ian-center.service.ts index 31709f6a2fb..3da1115fed6 100644 --- a/frontend/src/app/features/in-app-notifications/center/state/ian-center.service.ts +++ b/frontend/src/app/features/in-app-notifications/center/state/ian-center.service.ts @@ -62,6 +62,9 @@ import { FrameElement } from '@hotwired/turbo'; import { PathHelperService } from 'core-app/core/path-helper/path-helper.service'; import { UrlParamsService } from 'core-app/core/navigation/url-params.service'; import { IanBellService } from 'core-app/features/in-app-notifications/bell/state/ian-bell.service'; +import { WP_ID_URL_PATTERN } from 'core-app/shared/helpers/work-package-id-pattern'; + +const DETAILS_URL_PATTERN = new RegExp(`/details/(${WP_ID_URL_PATTERN})(?:/|$)`); export interface INotificationPageQueryParameters { filter?:string|null; @@ -192,7 +195,7 @@ export class IanCenterService extends UntilDestroyedMixin { public selectedNotification:INotification; - selectedWorkPackage$ = this.urlParams.pathMatching$(/\/details\/(\d+)/); + selectedWorkPackage$ = this.urlParams.pathMatching$(DETAILS_URL_PATTERN); constructor() { super(); diff --git a/lib/open_project/confidential_cache.rb b/lib/open_project/confidential_cache.rb index 966c2ea041b..ec00e50e4af 100644 --- a/lib/open_project/confidential_cache.rb +++ b/lib/open_project/confidential_cache.rb @@ -36,15 +36,20 @@ module OpenProject class << self delegate :delete, :clear, to: Cache - def fetch(*, **) - ciphertext = Cache.fetch(*, **) { token_encryptor.encrypt_and_sign(yield) } - - token_encryptor.decrypt_and_verify(ciphertext) + # Rubocop wants to convert this to ... but we need the first positional args + # for the delete case. + # rubocop:disable Style/ArgumentsForwarding + def fetch(*, **, &) + fetch_and_decrypt(*, **, &) rescue ActiveSupport::MessageEncryptor::InvalidMessage - # Drop values that can't be read, ensuring the cache heals from unreadable values + # Drop the unreadable value and recompute once. The recompute is a guaranteed + # cache miss, so the second attempt returns the freshly computed plaintext + # without decrypting. If it still raises, the error propagates rather than + # looping, since this second attempt is not rescued. delete(*) - retry + fetch_and_decrypt(*, **, &) end + # rubocop:enable Style/ArgumentsForwarding def read(name, **) ciphertext = Cache.read(name, **) @@ -64,10 +69,31 @@ module OpenProject private + # Reads the cached ciphertext and decrypts it, computing and storing an + # encrypted value on a cache miss. On a miss we already hold the plaintext, + # so we return it directly instead of decrypting what we just encrypted. + def fetch_and_decrypt(*, **) + recomputed = false + value = nil + + ciphertext = Cache.fetch(*, **) do + recomputed = true + value = yield + token_encryptor.encrypt_and_sign(value) + end + + return value if recomputed + + token_encryptor.decrypt_and_verify(ciphertext) + end + def token_encryptor @token_encryptor ||= begin key = Rails.application.key_generator.generate_key("op-cache:confidential-values:v1", 32) - ActiveSupport::MessageEncryptor.new(key, cipher: "aes-256-gcm", serializer: YAML) + # MessagePack avoids YAML's alias emission (which broke decryption for hashes + # that reuse the same object for multiple keys, e.g. Saml::Provider#to_h) and, + # unlike :message_pack_allow_marshal, never falls back to Marshal on load. + ActiveSupport::MessageEncryptor.new(key, cipher: "aes-256-gcm", serializer: :message_pack) end end end diff --git a/modules/bim/app/controllers/bim/ifc_models/ifc_models_controller.rb b/modules/bim/app/controllers/bim/ifc_models/ifc_models_controller.rb index e79dd2689c8..87843f7b8b0 100644 --- a/modules/bim/app/controllers/bim/ifc_models/ifc_models_controller.rb +++ b/modules/bim/app/controllers/bim/ifc_models/ifc_models_controller.rb @@ -78,7 +78,7 @@ module Bim end def direct_upload_finished # rubocop:disable Metrics/AbcSize,Metrics/PerceivedComplexity - attachment_id = attachment_id_from_key(request.params[:key]) + attachment_id = session[:pending_ifc_model_attachment_id] unless callback_context_valid?(attachment_id) fail_direct_upload return @@ -264,10 +264,6 @@ module Bim actual_payload == expected_payload end - def attachment_id_from_key(key) - key.to_s.match(%r{\Auploads/[^/]+/file/(\d+)/[^/]+\z})&.captures&.first - end - def fail_direct_upload flash[:error] = t("bim.error_direct_upload_failed") redirect_to action: :new diff --git a/modules/documents/app/components/documents/list_component.html.erb b/modules/documents/app/components/documents/list_component.html.erb index 0db8700e5d2..9e2a170d6b9 100644 --- a/modules/documents/app/components/documents/list_component.html.erb +++ b/modules/documents/app/components/documents/list_component.html.erb @@ -56,7 +56,7 @@ end component.with_row(py: 0) do - helpers.pagination_links_full(documents) + helpers.pagination_links_full(documents, params: { action: "index" }) end end else diff --git a/modules/documents/spec/controllers/documents_controller_spec.rb b/modules/documents/spec/controllers/documents_controller_spec.rb index 9d762982d41..70da35a2432 100644 --- a/modules/documents/spec/controllers/documents_controller_spec.rb +++ b/modules/documents/spec/controllers/documents_controller_spec.rb @@ -214,6 +214,22 @@ RSpec.describe DocumentsController do end end + describe "#search", with_settings: { per_page_options: "1 5 10" } do + let!(:document2) { create(:document, title: "Second Document", project:, type: document_type) } + + it "returns a turbo_stream response" do + get :search, params: { project_id: project.identifier, per_page: 1 }, format: :turbo_stream + + expect(response).to have_http_status(:ok) + end + + it "renders pagination links that target the index action, not the search action" do + get :search, params: { project_id: project.identifier, per_page: 1 }, format: :turbo_stream + + expect(response.body).not_to include("#{search_project_documents_path(project)}?") + end + end + describe "#render_avatars" do let(:user) { create(:user, member_with_permissions: { project => [:view_documents] }) } let!(:non_member) { create(:user) } diff --git a/modules/gitlab_integration/frontend/module/tab-issue/tab-issue.component.ts b/modules/gitlab_integration/frontend/module/tab-issue/tab-issue.component.ts index a26de1027bc..11a261f79b9 100644 --- a/modules/gitlab_integration/frontend/module/tab-issue/tab-issue.component.ts +++ b/modules/gitlab_integration/frontend/module/tab-issue/tab-issue.component.ts @@ -64,6 +64,6 @@ export class TabIssueComponent implements OnInit { } public getEmptyText() { - return this.I18n.t('js.gitlab_integration.tab_issue.empty',{ wp_id: this.workPackage.id }); + return this.I18n.t('js.gitlab_integration.tab_issue.empty', { wp_id: this.workPackage.displayId }); } } diff --git a/publiccode.yml b/publiccode.yml index a79f8fbfc91..9302d4b3be5 100644 --- a/publiccode.yml +++ b/publiccode.yml @@ -7,8 +7,8 @@ name: OpenProject applicationSuite: openDesk url: 'https://github.com/opf/openproject' roadmap: 'https://www.openproject.org/roadmap' -releaseDate: '2026-06-08' -softwareVersion: '17.4.1' +releaseDate: '2026-06-10' +softwareVersion: '17.5.0' developmentStatus: stable softwareType: standalone/web logo: 'publiccode_logo.svg' diff --git a/spec/controllers/admin/settings/project_reserved_identifiers_controller_spec.rb b/spec/controllers/admin/settings/project_reserved_identifiers_controller_spec.rb index d54fe292b63..7c4da30977c 100644 --- a/spec/controllers/admin/settings/project_reserved_identifiers_controller_spec.rb +++ b/spec/controllers/admin/settings/project_reserved_identifiers_controller_spec.rb @@ -73,13 +73,31 @@ RSpec.describe Admin::Settings::ProjectReservedIdentifiersController do end end - describe "GET #search", with_settings: { work_packages_identifier: "classic" } do + describe "GET #search", with_settings: { work_packages_identifier: "classic", per_page_options: "1 5 10" } do + render_views + it "responds with turbo stream" do get :search, format: :turbo_stream expect(response).to have_http_status(:ok) expect(response.media_type).to eq("text/vnd.turbo-stream.html") end + context "with multiple reserved slugs triggering pagination" do + let!(:project1) { create(:project, identifier: "proj-a") } + let!(:project2) { create(:project, identifier: "proj-b") } + + before do + FriendlyId::Slug.create!(sluggable: project1, slug: "old-a") + FriendlyId::Slug.create!(sluggable: project2, slug: "old-b") + end + + it "renders pagination links that target the index action, not the search action (regression #STC-811)" do + get :search, params: { per_page: 1 }, format: :turbo_stream + + expect(response.body).not_to include("#{search_admin_settings_project_reserved_identifiers_path}?") + end + end + context "with a reserved slug" do let!(:project) { create(:project, identifier: "current-id") } diff --git a/spec/lib/open_project/confidential_cache_spec.rb b/spec/lib/open_project/confidential_cache_spec.rb index feb1ee18216..c13c72d8705 100644 --- a/spec/lib/open_project/confidential_cache_spec.rb +++ b/spec/lib/open_project/confidential_cache_spec.rb @@ -96,5 +96,40 @@ RSpec.describe OpenProject::ConfidentialCache do expect(OpenProject::Cache.read(cache_key)).not_to be_nil end + + it "raises instead of looping when the value stays unreadable across a retry" do + # Simulate a value that remains an unreadable cache hit even after delete/retry. + allow(OpenProject::Cache).to receive(:fetch).and_return("some clear text") + + expect { described_class.fetch(cache_key) { "value" } } + .to raise_error(ActiveSupport::MessageEncryptor::InvalidMessage) + end + end + + # Regression: a hash that reuses the same object for two keys was rejected on load + # which the strict read-side load rejected, raising InvalidMessage on every decrypt and + # sending #fetch into an endless delete/retry loop. + describe "with symbol keys and shared object references" do + let(:shared) { "https://idp.example.com/slo" } + let(:value) do + { + my_provider: { + name: :my_provider, + idp_slo_service_url: shared, + idp_slo_target_url: shared + } + } + end + + it "roundtrips via #write and #read" do + described_class.write(cache_key, value) + + expect(described_class.read(cache_key)).to eq(value) + end + + it "decrypts the cached value on a subsequent #fetch without recomputing" do + expect(described_class.fetch(cache_key) { value }).to eq(value) + expect(described_class.fetch(cache_key) { raise "should not recompute" }).to eq(value) + end end end