From 88a52d1098cb6094a408e517e2f3fd88a6f9a716 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Thu, 27 Aug 2026 09:24:53 +0200 Subject: [PATCH 1/4] :paperclip: Update changelog --- CHANGES.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index f76af25171..e2874e9492 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,11 @@ # CHANGELOG +## 2.17.2 + +### :bug: Bugs fixed + +- Fix linear gradients in SVG text exports being emitted as radial gradients [#5972](https://github.com/penpot/penpot/issues/5972) (PR: [#11272](https://github.com/penpot/penpot/pull/11272)) + ## 2.17.1 ### :bug: Bugs fixed From f7bdc9786c12757f7abc70e1d8f68ee533583f49 Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Thu, 27 Aug 2026 09:41:50 +0200 Subject: [PATCH 2/4] :bug: Compare text numeric attrs with float tolerance (#11366) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Editor/WASM round-trips can truncate line-height strings (e.g. 1.3333333333333333 → 1.33333). Exact string compare treated that as a style change and detached typography tokens. --- common/src/app/common/types/text.cljc | 17 +++++++++++++++-- common/test/common_tests/types/text_test.cljc | 11 +++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/common/src/app/common/types/text.cljc b/common/src/app/common/types/text.cljc index 6068cfc829..3b830eb9d3 100644 --- a/common/src/app/common/types/text.cljc +++ b/common/src/app/common/types/text.cljc @@ -9,6 +9,7 @@ [app.common.data :as d] [app.common.data.macros :as dm] [app.common.flags :as flags] + [app.common.math :as mth] [app.common.types.color :as clr] [app.common.types.fills :as types.fills] [clojure.set :as set] @@ -217,7 +218,10 @@ attributes or other things that may be attached). - Consider nil values, empty strings or empty lists all equal. - Normalize numeric values (legacy) into strings. - - No value is equal than the default value." + - No value is equal than the default value. + - Numeric attrs (e.g. line-height) compare with float tolerance so + editor/WASM round-trips like \"1.3333333333333333\" vs \"1.33333\" + do not count as a real style change (avoids detaching tokens)." [key value1 value2] (when (text-node-attr? key) (let [default-value (get default-text-attrs key) @@ -229,7 +233,16 @@ $))) value1' (normalize-value value1) value2' (normalize-value value2)] - (not= value1' value2')))) + (cond + (= value1' value2') + false + + :else + (let [n1 (when (string? value1') (d/parse-double value1')) + n2 (when (string? value2') (d/parse-double value2'))] + (if (and (some? n1) (some? n2)) + (not (mth/close? n1 n2)) + true)))))) (defn- compare-text-content "Given two content text structures, conformed by maps and vectors, diff --git a/common/test/common_tests/types/text_test.cljc b/common/test/common_tests/types/text_test.cljc index b63a6db6e1..98032b8bc4 100644 --- a/common/test/common_tests/types/text_test.cljc +++ b/common/test/common_tests/types/text_test.cljc @@ -78,6 +78,14 @@ (def content-changed-line-height (assoc-in content-base [:children 0 :children 0 :line-height] "1.5")) +;; Token/WASM may store full float precision; editor round-trips often +;; truncate (e.g. CSS / f32). These must compare as equal. +(def content-line-height-full-precision + (assoc-in content-base [:children 0 :children 0 :line-height] "1.3333333333333333")) + +(def content-line-height-truncated + (assoc-in content-base [:children 0 :children 0 :line-height] "1.33333")) + (def content-redundant-span-line-height (assoc-in content-base [:children 0 :children 0 :children 0 :line-height] "1.5")) @@ -208,6 +216,8 @@ ;; Other text-node-attr categories attrs-font-family (cttx/get-diff-attrs content-base content-changed-font-family) attrs-line-height (cttx/get-diff-attrs content-base content-changed-line-height) + attrs-line-height-precision (cttx/get-diff-attrs content-line-height-full-precision + content-line-height-truncated) attrs-span-line-height (cttx/get-diff-attrs content-base content-redundant-span-line-height) attrs-roundtrip-line-height (cttx/get-diff-attrs content-token-like-line-height content-after-editor-roundtrip) @@ -242,6 +252,7 @@ ;; Each text-node-attr category reports correct attr key (t/is (= #{:font-family} attrs-font-family)) (t/is (= #{:line-height} attrs-line-height)) + (t/is (= #{} attrs-line-height-precision)) (t/is (= #{} attrs-span-line-height)) (t/is (= #{} attrs-roundtrip-line-height)) (t/is (= #{} attrs-nil-typography-refs)) From f7fd3e1cd59617d919e21b5b3461d0bc61c05e63 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Thu, 27 Aug 2026 10:00:00 +0200 Subject: [PATCH 3/4] :books: Update the `update-changelog` skill --- .opencode/skills/update-changelog/SKILL.md | 45 ++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/.opencode/skills/update-changelog/SKILL.md b/.opencode/skills/update-changelog/SKILL.md index d5c0ccf2af..d456ce5bf9 100644 --- a/.opencode/skills/update-changelog/SKILL.md +++ b/.opencode/skills/update-changelog/SKILL.md @@ -212,6 +212,37 @@ superseded it: Replace the reference in the changelog entry with the correct merged PR number. +### 5b. Security advisory (GHSA) entries + +Security advisories fixed in a release are documented in the changelog even +though they are **neither milestone issues nor PRs**. The GHSA ID and its +description are supplied by the user or the release notes — they never come +from the milestone fetch in step 2. + +**Format** (matches the existing precedent in `CHANGES.md`, e.g. the +`create-font-variant` arbitrary file read advisory): + +```markdown +- Fix (https://github.com/penpot/penpot/security/advisories/GHSA-XXXX-XXXX-XXXX) +``` + +Rules: +- Place the entry under `### :bug: Bugs fixed`, with **no issue or PR link** — + only the advisory URL. +- The advisory may be **draft/unpublished** at changelog time (the URL 404s + publicly). Do **not** web-fetch or verify the URL, and do **not** drop the + entry because of that. Rely on the GHSA ID provided by the user. +- Derive the description from the supplied advisory title, imperative mood and + user-facing (e.g. `Fix command injection in SVG exporter via legacy fill-color`). +- These entries are **invisible to the automation**: they are not returned by + `gh.py issues`, not matched by `--compare` (step 3), not part of the PR + cross-reference (step 10), and not scanned by the anomaly-report regexes + (step 11, which only match `issues/` and `pull/` links). Add them manually. +- During pre-flight checks (step 6a) apply only the **backport/duplicate** + check: if the same GHSA already appears in an earlier version section, remove + it from the current section. Their absence from milestone cross-references + is expected, not an anomaly. + ### 6. Read the current CHANGES.md Read the top of `CHANGES.md` to understand the existing format and find the @@ -400,6 +431,8 @@ if closed: - ✅ Every merged milestone PR is either in the changelog or excluded by label - ✅ PR and issue counts are internally consistent - ✅ No false-positive PR-to-issue associations +- ✅ Advisory (GHSA) entries are not milestone PRs — their absence from the + cross-reference is intentional (see step 5b) ## Version section template @@ -410,8 +443,12 @@ if closed: - [#](https://github.com/penpot/penpot/issues/) (PR: [#](https://github.com/penpot/penpot/pull/)) - (by @contributor) [#](https://github.com/penpot/penpot/issues/) (PR: [#](https://github.com/penpot/penpot/pull/)) +- (https://github.com/penpot/penpot/security/advisories/GHSA-XXXX-XXXX-XXXX) ``` +Advisory (GHSA) entries have no issue or PR link — just the advisory URL. See +step 5b. + ### 11. Generate anomaly report and save to CHANGES-ISSUES.md After all edits and cross-referencing are complete, generate a structured @@ -732,6 +769,14 @@ self-contained and clickable in any Markdown viewer. Taiga description text or by searching GitHub PRs that reference the Taiga URL. Replace the Taiga reference with the GitHub issue link and add the PR reference if applicable. +- **Security advisory (GHSA) entries.** Advisories fixed in the release are + listed under `### :bug: Bugs fixed` with the advisory URL and **no issue or + PR link**, even though they are not in the milestone. The GHSA ID and + description come from the user — do **not** fetch or verify the URL, and do + not drop a draft (unpublished) advisory. Precedent: + `- Fix arbitrary file read security issue on create-font-variant rpc method + (https://github.com/penpot/penpot/security/advisories/GHSA-xp3f-g8rq-9px2)`. + See step 5b. - **Re-fetch before editing.** Milestones can change — always re-fetch issues before making edits, don't rely on cached data. - **Use `scripts/gh.py`.** Prefer the helper script over raw `gh api` calls for From 1d2c37e52c733f74017d90b0fd1ae2d074a5c33d Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Thu, 27 Aug 2026 10:00:13 +0200 Subject: [PATCH 4/4] :paperclip: Update changelog --- CHANGES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index e2874e9492..c24676eaf3 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,6 +5,8 @@ ### :bug: Bugs fixed - Fix linear gradients in SVG text exports being emitted as radial gradients [#5972](https://github.com/penpot/penpot/issues/5972) (PR: [#11272](https://github.com/penpot/penpot/pull/11272)) +- Fix typography token becoming detached when editing text content [#11362](https://github.com/penpot/penpot/issues/11362) (PR: [#11366](https://github.com/penpot/penpot/pull/11366)) +- Fix command injection in SVG exporter via legacy fill-color (https://github.com/penpot/penpot/security/advisories/GHSA-4f36-m4hj-cv86) ## 2.17.1