Skip to content

Commit e7fc1ef

Browse files
Release OpenProject 16.6.4
2 parents 3aeec0b + c0765ea commit e7fc1ef

File tree

19 files changed

+385
-75
lines changed

19 files changed

+385
-75
lines changed

.github/workflows/continuous-delivery.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,13 @@ jobs:
1717
steps:
1818
- name: Trigger Flavours workflow
1919
env:
20-
TOKEN: ${{ secrets.OPENPROJECT_CI_TOKEN }}
20+
TOKEN: ${{ secrets.OPENPROJECTCI_FLAVOUR_TRIGGER_TOKEN }}
2121
REPOSITORY: opf/openproject-flavours
2222
WORKFLOW_ID: ci.yml
23+
REF_NAME: ${{ github.ref_name }}
2324
run: |
25+
PAYLOAD=$(jq -n --arg ref "$REF_NAME" '{"ref": "dev", "inputs": {"ref": $ref}}')
2426
curl -i --fail-with-body -H"authorization: Bearer $TOKEN" \
2527
-XPOST -H"Accept: application/vnd.github.v3+json" \
2628
https://api.github.com/repos/$REPOSITORY/actions/workflows/$WORKFLOW_ID/dispatches \
27-
-d '{"ref": "dev", "inputs": { "ref" : "${{ github.ref_name }}" }}'
29+
-d "$PAYLOAD"

.github/workflows/create-merge-from-previous-release-branch-pr.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414
steps:
1515
- id: find_previous_release
1616
env:
17-
GITHUB_TOKEN: ${{ secrets.OPENPROJECT_CI_GH_TOKEN }}
17+
GITHUB_TOKEN: ${{ secrets.OPENPROJECTCI_GH_CORE_PAT }}
1818
GITHUB_REPOSITORY: ${{ github.repository }}
1919
run: |
2020
BRANCH=$(curl -H "Authorization: token $GITHUB_TOKEN" \
@@ -29,7 +29,7 @@ jobs:
2929
echo "branch=${BRANCH}" >> $GITHUB_OUTPUT
3030
- id: find_latest_release
3131
env:
32-
GITHUB_TOKEN: ${{ secrets.OPENPROJECT_CI_GH_TOKEN }}
32+
GITHUB_TOKEN: ${{ secrets.OPENPROJECTCI_GH_CORE_PAT }}
3333
GITHUB_REPOSITORY: ${{ github.repository }}
3434
run: |
3535
BRANCH=$(curl -H "Authorization: token $GITHUB_TOKEN" \
@@ -152,4 +152,4 @@ jobs:
152152
fi
153153
fi
154154
env:
155-
GITHUB_TOKEN: ${{ secrets.OPENPROJECT_CI_GH_TOKEN }}
155+
GITHUB_TOKEN: ${{ secrets.OPENPROJECTCI_GH_CORE_PAT }}

.github/workflows/create-merge-release-into-dev-pr.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
steps:
1717
- id: find_latest_release
1818
env:
19-
GITHUB_TOKEN: ${{ secrets.OPENPROJECT_CI_GH_TOKEN }}
19+
GITHUB_TOKEN: ${{ secrets.OPENPROJECTCI_GH_CORE_PAT }}
2020
GITHUB_REPOSITORY: ${{ github.repository }}
2121
run: |
2222
BRANCH=$(curl -H "Authorization: token $GITHUB_TOKEN" \
@@ -107,4 +107,4 @@ jobs:
107107
fi
108108
fi
109109
env:
110-
GITHUB_TOKEN: ${{ secrets.OPENPROJECT_CI_GH_TOKEN }}
110+
GITHUB_TOKEN: ${{ secrets.OPENPROJECTCI_GH_CORE_PAT }}

.github/workflows/docker-release.yml

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,18 @@ jobs:
2323
ref: ${{ github.ref }}
2424
- name: Compute tags and branch
2525
id: compute
26+
env:
27+
EVENT_NAME: ${{ github.event_name }}
28+
INPUT_TAG: ${{ inputs.tag }}
2629
run: |
27-
if [[ ${{ github.event_name }} == 'push' ]]; then
30+
if [[ "$EVENT_NAME" == 'push' ]]; then
2831
# Tag push e.g. refs/tags/v16.3.0 => v16.3.0
2932
TAG_REF="${GITHUB_REF#refs/tags/}"
3033
BRANCH_REF="$GITHUB_REF"
31-
elif [[ ${{ github.event_name }} == 'workflow_dispatch' && -n "${{ inputs.tag }}" ]]; then
34+
elif [[ "$EVENT_NAME" == 'workflow_dispatch' && -n "$INPUT_TAG" ]]; then
3235
# Manual dispatch with tag
33-
TAG_REF="${{ inputs.tag }}"
34-
BRANCH_REF="${{ inputs.tag }}"
36+
TAG_REF="$INPUT_TAG"
37+
BRANCH_REF="$INPUT_TAG"
3538
else
3639
# Fallback to dev
3740
TAG_REF="dev"
@@ -58,11 +61,13 @@ jobs:
5861
steps:
5962
- name: Trigger Helm charts release
6063
env:
61-
TOKEN: ${{ secrets.OPENPROJECT_CI_TOKEN }}
64+
TOKEN: ${{ secrets.OPENPROJECTCI_HELM_CHARTS_TRIGGER_TOKEN }}
6265
REPOSITORY: opf/helm-charts
6366
WORKFLOW_ID: core_release.yml
67+
TAG: ${{ needs.compute-inputs.outputs.tag }}
6468
run: |
69+
PAYLOAD=$(jq -n --arg tag "$TAG" '{"ref": "main", "inputs": {"tag": $tag}}')
6570
curl -i --fail-with-body -H"authorization: Bearer $TOKEN" \
6671
-XPOST -H"Accept: application/vnd.github.v3+json" \
6772
https://api.github.com/repos/$REPOSITORY/actions/workflows/$WORKFLOW_ID/dispatches \
68-
-d '{"ref": "main", "inputs": { "tag" : "${{ needs.compute-inputs.outputs.tag }}" }}'
73+
-d "$PAYLOAD"

.github/workflows/downstream-ci.yml

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,7 @@ on:
77
paths-ignore:
88
- 'docs/**'
99
- 'help/**'
10-
# We run this in the less privileged mode to allow external PRs to use this workflow.
11-
# This means the workflow will be executed on the base branch, making sure only our own workflow logic is used.
12-
pull_request_target:
10+
pull_request:
1311
types: [opened, reopened, synchronize]
1412
branches:
1513
- dev
@@ -33,9 +31,13 @@ jobs:
3331
steps:
3432
- name: Trigger SaaS Tests
3533
env:
36-
TOKEN: ${{ secrets.OPENPROJECT_CI_TOKEN }}
34+
TOKEN: ${{ secrets.OPENPROJECTCI_GH_SAAS_WORKFLOW_PAT }}
3735
REPOSITORY: opf/saas-openproject
3836
WORKFLOW_ID: test-saas.yml
37+
EVENT_NAME: ${{ github.event_name }}
38+
BASE_REF: ${{ github.base_ref }}
39+
HEAD_REF: ${{ github.event.pull_request.head.ref }}
40+
REF_NAME: ${{ github.ref_name }}
3941
# ref:
4042
# * on push this will be `dev` or a specific release branch (e.g. release/16.1) - there is always a matching branch for that downstream
4143
# * on pull_request we use the PR branch's base (e.g. dev or a release branch) to match the above
@@ -47,13 +49,13 @@ jobs:
4749
REF=''
4850
CORE_REF=''
4951
50-
if [ "${{ github.event_name }}" = "pull_request_target" ]; then
52+
if [ "$EVENT_NAME" = "pull_request" ]; then
5153
echo The workflow was triggered by a pull request targetting the dev or a release branch
52-
REF="${{ github.base_ref }}"
53-
CORE_REF="${{ github.event.pull_request.head.ref }}"
54+
REF="$BASE_REF"
55+
CORE_REF="$HEAD_REF"
5456
else
5557
echo The workflow was triggered by a push to the dev or a release branch
56-
REF="${{ github.ref_name }}"
58+
REF="$REF_NAME"
5759
CORE_REF="$REF"
5860
fi
5961
@@ -62,7 +64,7 @@ jobs:
6264
exit 0
6365
fi
6466
65-
PAYLOAD=$(printf '{"ref": "%s", "inputs": {"core_ref": "%s"}}' "$REF" "$CORE_REF")
67+
PAYLOAD=$(jq -n --arg ref "$REF" --arg core_ref "$CORE_REF" '{"ref": $ref, "inputs": {"core_ref": $core_ref}}')
6668
OUTPUT_FILE=/tmp/request-output
6769
6870
echo "Triggering $WORKFLOW_ID workflow on $REPOSITORY branch '$REF', which will check out core branch '$CORE_REF'"

app/models/attachment.rb

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,8 +234,21 @@ def set_digest(file)
234234
self.digest = Digest::MD5.file(file.path).hexdigest
235235
end
236236

237+
##
238+
# Detects the content type of a file based on its actual content.
239+
# This method always relies on file content detection (via the `file` command)
240+
# and never uses filename-based narrowing (MimeType.narrow_type) to ensure
241+
# security-sensitive types like SVG are correctly identified even when the
242+
# filename extension doesn't match the actual content.
243+
#
244+
# @param file_path [String] Path to the file to analyze
245+
# @param fallback [String] Default content type if detection fails
246+
# @return [String] The detected content type
237247
def self.content_type_for(file_path, fallback = OpenProject::ContentTypeDetector::SENSIBLE_DEFAULT)
238-
content_type = OpenProject::MimeType.narrow_type file_path, OpenProject::ContentTypeDetector.new(file_path).detect
248+
# Always use ContentTypeDetector which analyzes file content, not filename
249+
# Do NOT use MimeType.narrow_type here as it could incorrectly narrow
250+
# security-sensitive types (e.g., SVG with .png extension -> image/png)
251+
content_type = OpenProject::ContentTypeDetector.new(file_path).detect
239252
content_type || fallback
240253
end
241254

config/imagemagick/policy.xml

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE policymap [
3+
<!ELEMENT policymap (policy)*>
4+
<!ATTLIST policymap xmlns CDATA #FIXED "">
5+
<!ELEMENT policy EMPTY>
6+
<!ATTLIST policy xmlns CDATA #FIXED "">
7+
<!ATTLIST policy domain NMTOKEN #REQUIRED>
8+
<!ATTLIST policy name NMTOKEN #IMPLIED>
9+
<!ATTLIST policy pattern CDATA #IMPLIED>
10+
<!ATTLIST policy rights NMTOKEN #IMPLIED>
11+
<!ATTLIST policy stealth NMTOKEN #IMPLIED>
12+
<!ATTLIST policy value CDATA #IMPLIED>
13+
]>
14+
<!--
15+
Creating a security policy that fits your specific local environment
16+
before making use of ImageMagick is highly advised. You can find guidance on
17+
setting up this policy at https://imagemagick.org/script/security-policy.php,
18+
and it's important to verify your policy using the validation tool located
19+
at https://imagemagick-secevaluator.doyensec.com/.
20+
21+
22+
Web-safe ImageMagick security policy:
23+
24+
This security protocol designed for web-safe usage focuses on situations
25+
where ImageMagick is applied in publicly accessible contexts, like websites.
26+
It deactivates the capability to read from or write to any image formats
27+
other than web-safe formats like GIF, JPEG, and PNG. Additionally, this
28+
policy prohibits the execution of image filters and indirect reads, thereby
29+
thwarting potential security breaches. By implementing these limitations,
30+
the web-safe policy fortifies the safeguarding of systems accessible to
31+
the public, reducing the risk of exploiting ImageMagick's capabilities
32+
for potential attacks.
33+
-->
34+
<policymap>
35+
<!-- Dynamically yield the CPU relative to the system load average. -->
36+
<policy domain="resource" name="dynamic-throttle" value="false"/>
37+
<!-- Force memory initialization by memory mapping select memory allocations. -->
38+
<policy domain="cache" name="memory-map" value="anonymous"/>
39+
<!-- Ensure all image data is fully flushed and synchronized to disk. -->
40+
<policy domain="cache" name="synchronize" value="true"/>
41+
<!-- Do not permit any delegates to execute. -->
42+
<policy domain="delegate" rights="none" pattern="*"/>
43+
<!-- Do not permit any image filters to load. -->
44+
<policy domain="filter" rights="none" pattern="*"/>
45+
<!-- Don't read/write from/to stdin/stdout. -->
46+
<policy domain="path" rights="none" pattern="-"/>
47+
<!-- don't read sensitive paths. -->
48+
<policy domain="path" rights="none" pattern="/etc/*"/>
49+
<!-- Indirect reads are not permitted. -->
50+
<policy domain="path" rights="none" pattern="@*"/>
51+
<!-- Deny all image modules and specifically exempt reading or writing web-safe image formats. -->
52+
<policy domain="module" rights="none" pattern="*" />
53+
<!-- Allow only web-safe image formats. -->
54+
<policy domain="module" rights="read | write" pattern="{GIF,JPEG,PNG,WEBP}" />
55+
<!-- Disable PDF -->
56+
<policy domain="coder" rights="none" pattern="PDF" />
57+
<!-- CVE-2016–3714 https://imagetragick.com/ -->
58+
<policy domain="coder" rights="none" pattern="EPHEMERAL" />
59+
<policy domain="coder" rights="none" pattern="URL" />
60+
<policy domain="coder" rights="none" pattern="HTTPS" />
61+
<policy domain="coder" rights="none" pattern="MVG" />
62+
<policy domain="coder" rights="none" pattern="MSL" />
63+
<policy domain="coder" rights="none" pattern="TEXT" />
64+
<policy domain="coder" rights="none" pattern="SHOW" />
65+
<policy domain="coder" rights="none" pattern="WIN" />
66+
<policy domain="coder" rights="none" pattern="PLT" />
67+
</policymap>

config/initializers/log_slow_sql_queries.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@
4242
# Skip transaction that may be blocked
4343
next if data[:sql].match?(/BEGIN|COMMIT/)
4444

45-
# Skip tenant creation (load dump)
46-
next if data[:sql][..120].include?("Dumped by pg_dump")
45+
# Skip tenant creation (load dump sql which is around 300kB)
46+
next if data[:sql][..120].include?("Dumped by pg_dump") || data[:sql].size > 200_000
4747

4848
# Skip smaller durations
4949
duration = ((finish - start) * 1000).round(4)

config/initializers/mini_magick.rb

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# frozen_string_literal: true
2+
3+
#-- copyright
4+
# OpenProject is an open source project management software.
5+
# Copyright (C) the OpenProject GmbH
6+
#
7+
# This program is free software; you can redistribute it and/or
8+
# modify it under the terms of the GNU General Public License version 3.
9+
#
10+
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
11+
# Copyright (C) 2006-2013 Jean-Philippe Lang
12+
# Copyright (C) 2010-2013 the ChiliProject Team
13+
#
14+
# This program is free software; you can redistribute it and/or
15+
# modify it under the terms of the GNU General Public License
16+
# as published by the Free Software Foundation; either version 2
17+
# of the License, or (at your option) any later version.
18+
#
19+
# This program is distributed in the hope that it will be useful,
20+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
21+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22+
# GNU General Public License for more details.
23+
#
24+
# You should have received a copy of the GNU General Public License
25+
# along with this program; if not, write to the Free Software
26+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
27+
#
28+
# See COPYRIGHT and LICENSE files for more details.
29+
#++
30+
31+
require "mini_magick"
32+
33+
# Ensure ImageMagick reads the project-local policy.xml (websafe)
34+
# ENV["MAGICK_CONFIGURE_PATH"] ||= Rails.root.join("config/imagemagick").to_s
35+
36+
MiniMagick.configure do |config|
37+
# configure MiniMagick CLI to use ImageMagick (not GraphicsMagick)
38+
config.graphicsmagick = false
39+
# also set the MAGICK_CONFIGURE_PATH for the CLI commands
40+
config.cli_env = {
41+
"MAGICK_CONFIGURE_PATH" => Rails.root.join("config/imagemagick").to_s
42+
}
43+
end
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
---
2+
title: OpenProject 16.6.4
3+
sidebar_navigation:
4+
title: 16.6.4
5+
release_version: 16.6.4
6+
release_date: 2026-01-08
7+
---
8+
9+
# OpenProject 16.6.4
10+
11+
Release date: 2026-01-08
12+
13+
We released OpenProject [OpenProject 16.6.4](https://community.openproject.org/versions/2248).
14+
The release contains several bug fixes and we recommend updating to the newest version.
15+
Below you will find a complete list of all changes and bug fixes.
16+
17+
<!--more-->
18+
19+
## Bug fixes and changes
20+
21+
<!-- Warning: Anything within the below lines will be automatically removed by the release script -->
22+
<!-- BEGIN AUTOMATED SECTION -->
23+
24+
- Bugfix: SVG attachments are interpreted as PNG \[[#70349](https://community.openproject.org/wp/70349)\]
25+
26+
<!-- END AUTOMATED SECTION -->
27+
<!-- Warning: Anything above this line will be automatically removed by the release script -->

0 commit comments

Comments
 (0)