From fea7a5ca9375c61d25abe55cd1b66563addf9b9a Mon Sep 17 00:00:00 2001 From: Martijn van de Wetering Date: Wed, 11 Nov 2026 21:04:52 +0100 Subject: [PATCH 1/4] chore: Update dependencies with open advisories Composer: symfony/http-foundation, http-kernel, routing, yaml and mime to the patched 7.4.23 / 8.1.11 / 7.4.22 releases (host and path handling, YAML parse time, mime header injection), with the rest of symfony/* and doctrine/deprecations along. composer audit is clean. pnpm: axios 1.21.1 (follow-redirects credential leak), concurrently 9.2.5 (shell-quote command injection), vite 6.4.6 (server.fs.deny bypass). pnpm audit is clean, vite build passes. Backend suite: 541 passed. Co-Authored-By: Claude Mythos 5.1 --- backend/composer.lock | 312 ++++++++++++++++++++--------------------- backend/package.json | 6 +- backend/pnpm-lock.yaml | 58 ++++---- 3 files changed, 188 insertions(+), 188 deletions(-) diff --git a/backend/composer.lock b/backend/composer.lock index 7cff902..0901f95 100644 --- a/backend/composer.lock +++ b/backend/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "3a4192195458939ee9051bcdfacb2239", + "content-hash": "a6302489984a4222fbce9c8d373b9d56", "packages": [ { "name": "brick/math", @@ -545,20 +545,20 @@ }, { "name": "doctrine/deprecations", - "version": "1.1.6", + "version": "1.2.0", "source": { "type": "git", "url": "https://github.com/doctrine/deprecations.git", - "reference": "d4fe3e6fd9bb9e72557a19674f44d8ac7db4c6ca" + "reference": "d2e16653a734c8784c1851ad68b02f997b53ca82" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/deprecations/zipball/d4fe3e6fd9bb9e72557a19674f44d8ac7db4c6ca", - "reference": "d4fe3e6fd9bb9e72557a19674f44d8ac7db4c6ca", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/d2e16653a734c8784c1851ad68b02f997b53ca82", + "reference": "d2e16653a734c8784c1851ad68b02f997b53ca82", "shasum": "" }, "require": { - "php": "^7.1 || ^8.0" + "php": "^7.4 || ^8.0" }, "conflict": { "phpunit/phpunit": "<=7.5 || >=14" @@ -587,9 +587,9 @@ "homepage": "https://www.doctrine-project.org/", "support": { "issues": "https://github.com/doctrine/deprecations/issues", - "source": "https://github.com/doctrine/deprecations/tree/1.1.6" + "source": "https://github.com/doctrine/deprecations/tree/1.2.0" }, - "time": "2026-02-07T07:09:04+00:00" + "time": "2026-11-11T10:04:49+00:00" }, { "name": "doctrine/inflector", @@ -7510,16 +7510,16 @@ }, { "name": "symfony/clock", - "version": "v8.1.0", + "version": "v8.1.9", "source": { "type": "git", "url": "https://github.com/symfony/clock.git", - "reference": "701ef4de9705d6c32292ebee5e8044094a09fbf6" + "reference": "945ea3b64d6da9c1c2c354fe5c07b27455df6442" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/clock/zipball/701ef4de9705d6c32292ebee5e8044094a09fbf6", - "reference": "701ef4de9705d6c32292ebee5e8044094a09fbf6", + "url": "https://api.github.com/repos/symfony/clock/zipball/945ea3b64d6da9c1c2c354fe5c07b27455df6442", + "reference": "945ea3b64d6da9c1c2c354fe5c07b27455df6442", "shasum": "" }, "require": { @@ -7563,7 +7563,7 @@ "time" ], "support": { - "source": "https://github.com/symfony/clock/tree/v8.1.0" + "source": "https://github.com/symfony/clock/tree/v8.1.9" }, "funding": [ { @@ -7583,20 +7583,20 @@ "type": "tidelift" } ], - "time": "2026-05-29T05:06:50+00:00" + "time": "2026-10-12T14:32:04+00:00" }, { "name": "symfony/console", - "version": "v7.4.20", + "version": "v7.4.23", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "d7bca2fe05241dc7732d0c8b6d551b879f5d0a7d" + "reference": "81957c2440c05c962fe8291f318de6e85f8db330" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/d7bca2fe05241dc7732d0c8b6d551b879f5d0a7d", - "reference": "d7bca2fe05241dc7732d0c8b6d551b879f5d0a7d", + "url": "https://api.github.com/repos/symfony/console/zipball/81957c2440c05c962fe8291f318de6e85f8db330", + "reference": "81957c2440c05c962fe8291f318de6e85f8db330", "shasum": "" }, "require": { @@ -7661,7 +7661,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.4.20" + "source": "https://github.com/symfony/console/tree/v7.4.23" }, "funding": [ { @@ -7681,20 +7681,20 @@ "type": "tidelift" } ], - "time": "2026-09-18T15:55:00+00:00" + "time": "2026-11-03T21:47:07+00:00" }, { "name": "symfony/css-selector", - "version": "v8.1.6", + "version": "v8.1.10", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "08e2905152a39cf3fd1745d83f8c483e258887d9" + "reference": "9cfd588b8b07cf83e3426b030dbafd2291c132d9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/08e2905152a39cf3fd1745d83f8c483e258887d9", - "reference": "08e2905152a39cf3fd1745d83f8c483e258887d9", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/9cfd588b8b07cf83e3426b030dbafd2291c132d9", + "reference": "9cfd588b8b07cf83e3426b030dbafd2291c132d9", "shasum": "" }, "require": { @@ -7730,7 +7730,7 @@ "description": "Converts CSS selectors to XPath expressions", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/css-selector/tree/v8.1.6" + "source": "https://github.com/symfony/css-selector/tree/v8.1.10" }, "funding": [ { @@ -7750,20 +7750,20 @@ "type": "tidelift" } ], - "time": "2026-08-23T10:06:25+00:00" + "time": "2026-10-18T14:56:39+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v3.7.1", + "version": "v3.8.1", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "f3202fa1b5097b0af062dc978b32ecf63404e31d" + "reference": "feb1edf4e546af3b85c5caebe8359a20db230ca3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/f3202fa1b5097b0af062dc978b32ecf63404e31d", - "reference": "f3202fa1b5097b0af062dc978b32ecf63404e31d", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/feb1edf4e546af3b85c5caebe8359a20db230ca3", + "reference": "feb1edf4e546af3b85c5caebe8359a20db230ca3", "shasum": "" }, "require": { @@ -7776,7 +7776,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.7-dev" + "dev-main": "3.8-dev" } }, "autoload": { @@ -7801,7 +7801,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.7.1" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.8.1" }, "funding": [ { @@ -7821,20 +7821,20 @@ "type": "tidelift" } ], - "time": "2026-06-05T06:23:12+00:00" + "time": "2026-09-16T14:15:10+00:00" }, { "name": "symfony/error-handler", - "version": "v7.4.20", + "version": "v7.4.22", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "82239fe00f7cdc9f17c4166fff4ebdc22bd26ec0" + "reference": "545852cfe9c4979c82389155b4d8d05f8864e4f1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/82239fe00f7cdc9f17c4166fff4ebdc22bd26ec0", - "reference": "82239fe00f7cdc9f17c4166fff4ebdc22bd26ec0", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/545852cfe9c4979c82389155b4d8d05f8864e4f1", + "reference": "545852cfe9c4979c82389155b4d8d05f8864e4f1", "shasum": "" }, "require": { @@ -7883,7 +7883,7 @@ "description": "Provides tools to manage errors and ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/error-handler/tree/v7.4.20" + "source": "https://github.com/symfony/error-handler/tree/v7.4.22" }, "funding": [ { @@ -7903,7 +7903,7 @@ "type": "tidelift" } ], - "time": "2026-09-22T18:56:40+00:00" + "time": "2026-10-25T14:40:16+00:00" }, { "name": "symfony/event-dispatcher", @@ -7993,16 +7993,16 @@ }, { "name": "symfony/event-dispatcher-contracts", - "version": "v3.7.1", + "version": "v3.8.1", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher-contracts.git", - "reference": "c7de7a00ffb67842132da02ea92988a39ccd9f4e" + "reference": "658e29751424da3ef4758c60f769e59d1b2981eb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/c7de7a00ffb67842132da02ea92988a39ccd9f4e", - "reference": "c7de7a00ffb67842132da02ea92988a39ccd9f4e", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/658e29751424da3ef4758c60f769e59d1b2981eb", + "reference": "658e29751424da3ef4758c60f769e59d1b2981eb", "shasum": "" }, "require": { @@ -8016,7 +8016,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.7-dev" + "dev-main": "3.8-dev" } }, "autoload": { @@ -8049,7 +8049,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.7.1" + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.8.1" }, "funding": [ { @@ -8069,20 +8069,20 @@ "type": "tidelift" } ], - "time": "2026-06-05T06:23:12+00:00" + "time": "2026-09-16T14:15:10+00:00" }, { "name": "symfony/finder", - "version": "v7.4.20", + "version": "v7.4.23", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "2dd31e5208db7a0fda7bfc998ad727b79c2e4d1e" + "reference": "c723f990aefe8c1053b18374faf4231eba84f518" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/2dd31e5208db7a0fda7bfc998ad727b79c2e4d1e", - "reference": "2dd31e5208db7a0fda7bfc998ad727b79c2e4d1e", + "url": "https://api.github.com/repos/symfony/finder/zipball/c723f990aefe8c1053b18374faf4231eba84f518", + "reference": "c723f990aefe8c1053b18374faf4231eba84f518", "shasum": "" }, "require": { @@ -8117,7 +8117,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v7.4.20" + "source": "https://github.com/symfony/finder/tree/v7.4.23" }, "funding": [ { @@ -8137,20 +8137,20 @@ "type": "tidelift" } ], - "time": "2026-09-26T06:31:10+00:00" + "time": "2026-11-02T10:56:49+00:00" }, { "name": "symfony/http-foundation", - "version": "v7.4.20", + "version": "v7.4.23", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "9d0761c0da6bd5b801b401666834901a9a1ffc33" + "reference": "7fb73cffa06e2bcc2cb523fcccb1e8174106b206" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/9d0761c0da6bd5b801b401666834901a9a1ffc33", - "reference": "9d0761c0da6bd5b801b401666834901a9a1ffc33", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/7fb73cffa06e2bcc2cb523fcccb1e8174106b206", + "reference": "7fb73cffa06e2bcc2cb523fcccb1e8174106b206", "shasum": "" }, "require": { @@ -8199,7 +8199,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v7.4.20" + "source": "https://github.com/symfony/http-foundation/tree/v7.4.23" }, "funding": [ { @@ -8219,20 +8219,20 @@ "type": "tidelift" } ], - "time": "2026-09-24T07:12:44+00:00" + "time": "2026-11-04T08:27:22+00:00" }, { "name": "symfony/http-kernel", - "version": "v7.4.20", + "version": "v7.4.23", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "392784b5d7b959b8d872542a2530c50c540a788f" + "reference": "94c57f4c5c45a311d244a0aeadb72b14ee41d25d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/392784b5d7b959b8d872542a2530c50c540a788f", - "reference": "392784b5d7b959b8d872542a2530c50c540a788f", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/94c57f4c5c45a311d244a0aeadb72b14ee41d25d", + "reference": "94c57f4c5c45a311d244a0aeadb72b14ee41d25d", "shasum": "" }, "require": { @@ -8318,7 +8318,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v7.4.20" + "source": "https://github.com/symfony/http-kernel/tree/v7.4.23" }, "funding": [ { @@ -8338,20 +8338,20 @@ "type": "tidelift" } ], - "time": "2026-09-29T14:05:16+00:00" + "time": "2026-11-04T11:26:18+00:00" }, { "name": "symfony/mailer", - "version": "v7.4.19", + "version": "v7.4.22", "source": { "type": "git", "url": "https://github.com/symfony/mailer.git", - "reference": "6f6f2441bef07a42d2617b9b3aadf04a321aa514" + "reference": "1aa1e2ee7515826bb17b0ad0d2f16962fcaa7859" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mailer/zipball/6f6f2441bef07a42d2617b9b3aadf04a321aa514", - "reference": "6f6f2441bef07a42d2617b9b3aadf04a321aa514", + "url": "https://api.github.com/repos/symfony/mailer/zipball/1aa1e2ee7515826bb17b0ad0d2f16962fcaa7859", + "reference": "1aa1e2ee7515826bb17b0ad0d2f16962fcaa7859", "shasum": "" }, "require": { @@ -8402,7 +8402,7 @@ "description": "Helps sending emails", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/mailer/tree/v7.4.19" + "source": "https://github.com/symfony/mailer/tree/v7.4.22" }, "funding": [ { @@ -8422,20 +8422,20 @@ "type": "tidelift" } ], - "time": "2026-09-15T06:01:15+00:00" + "time": "2026-10-23T16:51:52+00:00" }, { "name": "symfony/mime", - "version": "v7.4.19", + "version": "v7.4.22", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "f8ac7d0a800bcabbcd1f7de56594cf05e6cd5693" + "reference": "94a4c017435bc515f5ac80421a2c555fb9ca3676" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/f8ac7d0a800bcabbcd1f7de56594cf05e6cd5693", - "reference": "f8ac7d0a800bcabbcd1f7de56594cf05e6cd5693", + "url": "https://api.github.com/repos/symfony/mime/zipball/94a4c017435bc515f5ac80421a2c555fb9ca3676", + "reference": "94a4c017435bc515f5ac80421a2c555fb9ca3676", "shasum": "" }, "require": { @@ -8491,7 +8491,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v7.4.19" + "source": "https://github.com/symfony/mime/tree/v7.4.22" }, "funding": [ { @@ -8511,20 +8511,20 @@ "type": "tidelift" } ], - "time": "2026-09-04T10:45:44+00:00" + "time": "2026-10-28T17:57:58+00:00" }, { "name": "symfony/options-resolver", - "version": "v8.1.0", + "version": "v8.1.10", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "88f9c561f678a02d54b897014049fa839e33ff82" + "reference": "68cc43038d234c69d510c62f37bd0058b40d548a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/88f9c561f678a02d54b897014049fa839e33ff82", - "reference": "88f9c561f678a02d54b897014049fa839e33ff82", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/68cc43038d234c69d510c62f37bd0058b40d548a", + "reference": "68cc43038d234c69d510c62f37bd0058b40d548a", "shasum": "" }, "require": { @@ -8562,7 +8562,7 @@ "options" ], "support": { - "source": "https://github.com/symfony/options-resolver/tree/v8.1.0" + "source": "https://github.com/symfony/options-resolver/tree/v8.1.10" }, "funding": [ { @@ -8582,7 +8582,7 @@ "type": "tidelift" } ], - "time": "2026-05-29T05:06:50+00:00" + "time": "2026-10-18T14:56:39+00:00" }, { "name": "symfony/polyfill-ctype", @@ -8669,16 +8669,16 @@ }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.43.0", + "version": "v1.43.3", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "5cac8f4db97208823aa353f59a01faad2da52c75" + "reference": "5a8f33c87aeecffce24e721b5064fab05f4becf8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/5cac8f4db97208823aa353f59a01faad2da52c75", - "reference": "5cac8f4db97208823aa353f59a01faad2da52c75", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/5a8f33c87aeecffce24e721b5064fab05f4becf8", + "reference": "5a8f33c87aeecffce24e721b5064fab05f4becf8", "shasum": "" }, "require": { @@ -8727,7 +8727,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.43.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.43.3" }, "funding": [ { @@ -8747,7 +8747,7 @@ "type": "tidelift" } ], - "time": "2026-09-25T15:46:47+00:00" + "time": "2026-10-15T09:18:53+00:00" }, { "name": "symfony/polyfill-intl-idn", @@ -8923,16 +8923,16 @@ }, { "name": "symfony/polyfill-mbstring", - "version": "v1.43.0", + "version": "v1.43.3", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "4d5d331bf731e0aedbc6b2f5e61135b7b7996a72" + "reference": "122889ed24dc000165bcbfd77ec412f15cbdfc6a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/4d5d331bf731e0aedbc6b2f5e61135b7b7996a72", - "reference": "4d5d331bf731e0aedbc6b2f5e61135b7b7996a72", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/122889ed24dc000165bcbfd77ec412f15cbdfc6a", + "reference": "122889ed24dc000165bcbfd77ec412f15cbdfc6a", "shasum": "" }, "require": { @@ -8984,7 +8984,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.43.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.43.3" }, "funding": [ { @@ -9004,7 +9004,7 @@ "type": "tidelift" } ], - "time": "2026-09-24T15:19:04+00:00" + "time": "2026-10-28T09:35:49+00:00" }, { "name": "symfony/polyfill-php80", @@ -9495,16 +9495,16 @@ }, { "name": "symfony/process", - "version": "v7.4.19", + "version": "v7.4.22", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "ed0ae095b86994d370d5791612e55984f15aa30e" + "reference": "a5a6912edbbfc4c98cd080bc4bbe37c8e7eeb20a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/ed0ae095b86994d370d5791612e55984f15aa30e", - "reference": "ed0ae095b86994d370d5791612e55984f15aa30e", + "url": "https://api.github.com/repos/symfony/process/zipball/a5a6912edbbfc4c98cd080bc4bbe37c8e7eeb20a", + "reference": "a5a6912edbbfc4c98cd080bc4bbe37c8e7eeb20a", "shasum": "" }, "require": { @@ -9536,7 +9536,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v7.4.19" + "source": "https://github.com/symfony/process/tree/v7.4.22" }, "funding": [ { @@ -9556,20 +9556,20 @@ "type": "tidelift" } ], - "time": "2026-09-02T12:38:34+00:00" + "time": "2026-10-25T14:40:16+00:00" }, { "name": "symfony/psr-http-message-bridge", - "version": "v8.1.0", + "version": "v8.1.9", "source": { "type": "git", "url": "https://github.com/symfony/psr-http-message-bridge.git", - "reference": "67fd34de15ded1763aa1e330fe345f080a94022c" + "reference": "cfa8f3ac693fec234a91d8745b45ed9a81a0b799" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/psr-http-message-bridge/zipball/67fd34de15ded1763aa1e330fe345f080a94022c", - "reference": "67fd34de15ded1763aa1e330fe345f080a94022c", + "url": "https://api.github.com/repos/symfony/psr-http-message-bridge/zipball/cfa8f3ac693fec234a91d8745b45ed9a81a0b799", + "reference": "cfa8f3ac693fec234a91d8745b45ed9a81a0b799", "shasum": "" }, "require": { @@ -9623,7 +9623,7 @@ "psr-7" ], "support": { - "source": "https://github.com/symfony/psr-http-message-bridge/tree/v8.1.0" + "source": "https://github.com/symfony/psr-http-message-bridge/tree/v8.1.9" }, "funding": [ { @@ -9643,20 +9643,20 @@ "type": "tidelift" } ], - "time": "2026-05-29T05:06:50+00:00" + "time": "2026-10-07T08:21:34+00:00" }, { "name": "symfony/routing", - "version": "v7.4.20", + "version": "v7.4.23", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "2bacb72be5eadeaf9874d5accb75bfb33d21c74b" + "reference": "0000ade604b7bc798cb1e75edf6f17df48185f73" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/2bacb72be5eadeaf9874d5accb75bfb33d21c74b", - "reference": "2bacb72be5eadeaf9874d5accb75bfb33d21c74b", + "url": "https://api.github.com/repos/symfony/routing/zipball/0000ade604b7bc798cb1e75edf6f17df48185f73", + "reference": "0000ade604b7bc798cb1e75edf6f17df48185f73", "shasum": "" }, "require": { @@ -9708,7 +9708,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v7.4.20" + "source": "https://github.com/symfony/routing/tree/v7.4.23" }, "funding": [ { @@ -9728,20 +9728,20 @@ "type": "tidelift" } ], - "time": "2026-09-28T19:09:50+00:00" + "time": "2026-11-04T08:27:22+00:00" }, { "name": "symfony/service-contracts", - "version": "v3.7.3", + "version": "v3.8.1", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "15e6a07ec2a2c75ceb1b21dd98105ee8456d2257" + "reference": "052852a96fd5e5ebdb617dba22031e41a3300fb5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/15e6a07ec2a2c75ceb1b21dd98105ee8456d2257", - "reference": "15e6a07ec2a2c75ceb1b21dd98105ee8456d2257", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/052852a96fd5e5ebdb617dba22031e41a3300fb5", + "reference": "052852a96fd5e5ebdb617dba22031e41a3300fb5", "shasum": "" }, "require": { @@ -9759,7 +9759,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.7-dev" + "dev-main": "3.8-dev" } }, "autoload": { @@ -9795,7 +9795,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.7.3" + "source": "https://github.com/symfony/service-contracts/tree/v3.8.1" }, "funding": [ { @@ -9815,20 +9815,20 @@ "type": "tidelift" } ], - "time": "2026-07-27T15:39:01+00:00" + "time": "2026-10-20T17:38:25+00:00" }, { "name": "symfony/string", - "version": "v8.1.7", + "version": "v8.1.10", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "d950140b5f56f31901e5b7a0c04ffc3a3deb943c" + "reference": "6c6110979c0150393bbb336170e286d51ab4d76c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/d950140b5f56f31901e5b7a0c04ffc3a3deb943c", - "reference": "d950140b5f56f31901e5b7a0c04ffc3a3deb943c", + "url": "https://api.github.com/repos/symfony/string/zipball/6c6110979c0150393bbb336170e286d51ab4d76c", + "reference": "6c6110979c0150393bbb336170e286d51ab4d76c", "shasum": "" }, "require": { @@ -9885,7 +9885,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v8.1.7" + "source": "https://github.com/symfony/string/tree/v8.1.10" }, "funding": [ { @@ -9905,20 +9905,20 @@ "type": "tidelift" } ], - "time": "2026-09-11T14:51:16+00:00" + "time": "2026-10-23T17:06:53+00:00" }, { "name": "symfony/translation", - "version": "v8.1.5", + "version": "v8.1.11", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "d9e1caba0d6b6f9a26710af8a2f88d37f001215a" + "reference": "d065adf56e5508293e80d7c140b0a9e043b63e9c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/d9e1caba0d6b6f9a26710af8a2f88d37f001215a", - "reference": "d9e1caba0d6b6f9a26710af8a2f88d37f001215a", + "url": "https://api.github.com/repos/symfony/translation/zipball/d065adf56e5508293e80d7c140b0a9e043b63e9c", + "reference": "d065adf56e5508293e80d7c140b0a9e043b63e9c", "shasum": "" }, "require": { @@ -9978,7 +9978,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v8.1.5" + "source": "https://github.com/symfony/translation/tree/v8.1.11" }, "funding": [ { @@ -9998,20 +9998,20 @@ "type": "tidelift" } ], - "time": "2026-08-21T17:47:34+00:00" + "time": "2026-11-01T22:27:46+00:00" }, { "name": "symfony/translation-contracts", - "version": "v3.7.1", + "version": "v3.8.1", "source": { "type": "git", "url": "https://github.com/symfony/translation-contracts.git", - "reference": "ccb206b98faccc511ebae8e5fad50f2dc0b30621" + "reference": "0a3ae917402632fcba2aeddae9c98332f3d7dd05" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/ccb206b98faccc511ebae8e5fad50f2dc0b30621", - "reference": "ccb206b98faccc511ebae8e5fad50f2dc0b30621", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/0a3ae917402632fcba2aeddae9c98332f3d7dd05", + "reference": "0a3ae917402632fcba2aeddae9c98332f3d7dd05", "shasum": "" }, "require": { @@ -10024,7 +10024,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.7-dev" + "dev-main": "3.8-dev" } }, "autoload": { @@ -10060,7 +10060,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/translation-contracts/tree/v3.7.1" + "source": "https://github.com/symfony/translation-contracts/tree/v3.8.1" }, "funding": [ { @@ -10080,20 +10080,20 @@ "type": "tidelift" } ], - "time": "2026-06-05T06:23:12+00:00" + "time": "2026-10-03T08:17:19+00:00" }, { "name": "symfony/uid", - "version": "v7.4.20", + "version": "v7.4.21", "source": { "type": "git", "url": "https://github.com/symfony/uid.git", - "reference": "a96bbdb02a04ff3b5592cee6741b03edc78b56aa" + "reference": "3e706a245b5343ea93be9cafe84525bfb54e60fc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/uid/zipball/a96bbdb02a04ff3b5592cee6741b03edc78b56aa", - "reference": "a96bbdb02a04ff3b5592cee6741b03edc78b56aa", + "url": "https://api.github.com/repos/symfony/uid/zipball/3e706a245b5343ea93be9cafe84525bfb54e60fc", + "reference": "3e706a245b5343ea93be9cafe84525bfb54e60fc", "shasum": "" }, "require": { @@ -10138,7 +10138,7 @@ "uuid" ], "support": { - "source": "https://github.com/symfony/uid/tree/v7.4.20" + "source": "https://github.com/symfony/uid/tree/v7.4.21" }, "funding": [ { @@ -10158,20 +10158,20 @@ "type": "tidelift" } ], - "time": "2026-09-23T16:18:28+00:00" + "time": "2026-10-12T14:31:36+00:00" }, { "name": "symfony/var-dumper", - "version": "v7.4.18", + "version": "v7.4.22", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "e088da50b813f32473a76871616cbb8fa54653a8" + "reference": "6e6ff33ea8cf5df27f00a5561ebd5ee9bd7f1618" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/e088da50b813f32473a76871616cbb8fa54653a8", - "reference": "e088da50b813f32473a76871616cbb8fa54653a8", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/6e6ff33ea8cf5df27f00a5561ebd5ee9bd7f1618", + "reference": "6e6ff33ea8cf5df27f00a5561ebd5ee9bd7f1618", "shasum": "" }, "require": { @@ -10225,7 +10225,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v7.4.18" + "source": "https://github.com/symfony/var-dumper/tree/v7.4.22" }, "funding": [ { @@ -10245,7 +10245,7 @@ "type": "tidelift" } ], - "time": "2026-08-30T20:10:52+00:00" + "time": "2026-10-25T21:04:04+00:00" }, { "name": "tbachert/spi", @@ -13309,16 +13309,16 @@ }, { "name": "symfony/yaml", - "version": "v8.1.8", + "version": "v8.1.11", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "030e96eed0303223bfca3af9109e9e64830b6ec3" + "reference": "e8266f55160f674f290a5f567cb55e11e21f921b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/030e96eed0303223bfca3af9109e9e64830b6ec3", - "reference": "030e96eed0303223bfca3af9109e9e64830b6ec3", + "url": "https://api.github.com/repos/symfony/yaml/zipball/e8266f55160f674f290a5f567cb55e11e21f921b", + "reference": "e8266f55160f674f290a5f567cb55e11e21f921b", "shasum": "" }, "require": { @@ -13361,7 +13361,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v8.1.8" + "source": "https://github.com/symfony/yaml/tree/v8.1.11" }, "funding": [ { @@ -13381,7 +13381,7 @@ "type": "tidelift" } ], - "time": "2026-09-26T06:33:49+00:00" + "time": "2026-11-04T08:39:20+00:00" }, { "name": "ta-tikoma/phpunit-architecture-test", diff --git a/backend/package.json b/backend/package.json index 0360a88..59a48db 100644 --- a/backend/package.json +++ b/backend/package.json @@ -8,10 +8,10 @@ }, "devDependencies": { "autoprefixer": "^10.6.1", - "axios": "^1.20.0", - "concurrently": "^9.2.4", + "axios": "^1.21.1", + "concurrently": "^9.2.5", "laravel-echo": "^1.19.0", - "vite": "^6.4.4" + "vite": "^6.4.6" }, "dependencies": { "@fortawesome/fontawesome-free": "^6.7.2", diff --git a/backend/pnpm-lock.yaml b/backend/pnpm-lock.yaml index 1f2fdb0..8a59b4a 100644 --- a/backend/pnpm-lock.yaml +++ b/backend/pnpm-lock.yaml @@ -13,7 +13,7 @@ importers: version: 6.7.2 '@tailwindcss/vite': specifier: ^4.3.3 - version: 4.3.3(vite@6.4.4(jiti@2.7.0)(lightningcss@1.32.0)) + version: 4.3.3(vite@6.4.6(jiti@2.7.0)(lightningcss@1.32.0)) alpinejs: specifier: ^3.17.4 version: 3.17.4 @@ -22,7 +22,7 @@ importers: version: 1.9.12 laravel-vite-plugin: specifier: ^1.3.0 - version: 1.3.0(vite@6.4.4(jiti@2.7.0)(lightningcss@1.32.0)) + version: 1.3.0(vite@6.4.6(jiti@2.7.0)(lightningcss@1.32.0)) tailwindcss: specifier: ^4.3.3 version: 4.3.3 @@ -31,17 +31,17 @@ importers: specifier: ^10.6.1 version: 10.6.1(postcss@8.5.31) axios: - specifier: ^1.20.0 - version: 1.20.0 + specifier: ^1.21.1 + version: 1.21.1 concurrently: - specifier: ^9.2.4 - version: 9.2.4 + specifier: ^9.2.5 + version: 9.2.5 laravel-echo: specifier: ^1.19.0 version: 1.19.0 vite: - specifier: ^6.4.4 - version: 6.4.4(jiti@2.7.0)(lightningcss@1.32.0) + specifier: ^6.4.6 + version: 6.4.6(jiti@2.7.0)(lightningcss@1.32.0) packages: @@ -494,8 +494,8 @@ packages: peerDependencies: postcss: ^8.1.0 - axios@1.20.0: - resolution: {integrity: sha512-r8aOh8j9cGKpgQAqpzrUHnSIc6a59Y3Xf/cv8sy1DrHCkZHzQGEuoq1tARk6qSyDdtQGSDgpb9kFlruzPvrgwg==} + axios@1.21.1: + resolution: {integrity: sha512-6eI5Q/Y4u/Um9dDlsRoq5pY2rxnUTv+L4PpLitnbk/i4jb3MxLZ5CsN5Ih3IysbeRYK4pR+P7qfMsOQl9fwwFQ==} baseline-browser-mapping@2.11.27: resolution: {integrity: sha512-ElY12DaROGuan+lMmZ8Cvo/ZUbXPe7Enc/9VU/b1T3Kp4dwytRcNdR8DoSJN5SNJT/CuvcCA0DHDVmMOCePdRQ==} @@ -533,8 +533,8 @@ packages: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} - concurrently@9.2.4: - resolution: {integrity: sha512-TZ0CEhyzvFjgtAvHTusDMgj7wNdihCh7LLLrzdUOXIhdlnL2JBBGA9eJxR24rtqgmdjh3OA3hrN1rCHj6HM8qA==} + concurrently@9.2.5: + resolution: {integrity: sha512-YMZlvWrTPQEhjKp60XSmMGt60+pffbv6DyRnOMvVO98+J7aF8w8Ui9FhdcOwvSixc/kyR6SoVvmejcn/2lZBqg==} engines: {node: '>=18'} hasBin: true @@ -603,8 +603,8 @@ packages: picomatch: optional: true - follow-redirects@1.16.1: - resolution: {integrity: sha512-FNvFGzoMLWmE6Yj9spb/zjd7yiNCHiAW9/Tg9CXrQ8wuu32HtlJOwWO11OJafl5FfY3DxTdQ0vj42zU1kvv5jg==} + follow-redirects@1.16.3: + resolution: {integrity: sha512-toOSoqN6d51Wjf1aOFJYcoVv1aND9rj/CwjLU0Vz40oDuSpWDayCeKe4JpL5NL0WdFvoOOCI3BRo69HahjbR1A==} engines: {node: '>=4.0'} peerDependencies: debug: '*' @@ -823,8 +823,8 @@ packages: rxjs@7.8.2: resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} - shell-quote@1.9.0: - resolution: {integrity: sha512-Iov+JwFv/2HcTpcwNMKd8+IWNb8tboQJNQTkAY/LLVK7gGH9jy+LGkVqPxfekHl+yMmiqXszdGWXgkfml7hjqA==} + shell-quote@1.12.0: + resolution: {integrity: sha512-PcByqNyT/38F2kDNi006HAMRJaULuBzq/FOsw3qdZvX/GA9W/jamDaRskgHjubHiftXK5sIFxLNkvrXUwcof6Q==} engines: {node: '>= 0.4'} source-map-js@1.2.2: @@ -874,8 +874,8 @@ packages: vite-plugin-full-reload@1.2.0: resolution: {integrity: sha512-kz18NW79x0IHbxRSHm0jttP4zoO9P9gXh+n6UTwlNKnviTTEpOlum6oS9SmecrTtSr+muHEn5TUuC75UovQzcA==} - vite@6.4.4: - resolution: {integrity: sha512-xGjU/SyjeNyb0E4KxXBvYz/1C+3JXuujvf2hXNOtnlcE+58o5ajd9N2/n2VhkiJvpCP2qQasnUpx5PXNeI+p1Q==} + vite@6.4.6: + resolution: {integrity: sha512-RtsraAwEG68idOA6iUOoIpOlcSKROnf815aIq9qHTSrDNpLoBrBa12suyfcEd8qn0xwOVQI1Yhm1GbmTjF600A==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true peerDependencies: @@ -1170,12 +1170,12 @@ snapshots: '@tailwindcss/oxide-win32-arm64-msvc': 4.3.3 '@tailwindcss/oxide-win32-x64-msvc': 4.3.3 - '@tailwindcss/vite@4.3.3(vite@6.4.4(jiti@2.7.0)(lightningcss@1.32.0))': + '@tailwindcss/vite@4.3.3(vite@6.4.6(jiti@2.7.0)(lightningcss@1.32.0))': dependencies: '@tailwindcss/node': 4.3.3 '@tailwindcss/oxide': 4.3.3 tailwindcss: 4.3.3 - vite: 6.4.4(jiti@2.7.0)(lightningcss@1.32.0) + vite: 6.4.6(jiti@2.7.0)(lightningcss@1.32.0) '@types/estree@1.0.9': {} @@ -1212,9 +1212,9 @@ snapshots: postcss: 8.5.31 postcss-value-parser: 4.2.0 - axios@1.20.0: + axios@1.21.1: dependencies: - follow-redirects: 1.16.1 + follow-redirects: 1.16.3 form-data: 4.0.6 https-proxy-agent: 5.0.1 proxy-from-env: 2.1.0 @@ -1260,11 +1260,11 @@ snapshots: dependencies: delayed-stream: 1.0.0 - concurrently@9.2.4: + concurrently@9.2.5: dependencies: chalk: 4.1.2 rxjs: 7.8.2 - shell-quote: 1.9.0 + shell-quote: 1.12.0 supports-color: 8.1.1 tree-kill: 1.2.2 yargs: 17.7.2 @@ -1342,7 +1342,7 @@ snapshots: optionalDependencies: picomatch: 4.0.7 - follow-redirects@1.16.1: {} + follow-redirects@1.16.3: {} form-data@4.0.6: dependencies: @@ -1410,10 +1410,10 @@ snapshots: laravel-echo@1.19.0: {} - laravel-vite-plugin@1.3.0(vite@6.4.4(jiti@2.7.0)(lightningcss@1.32.0)): + laravel-vite-plugin@1.3.0(vite@6.4.6(jiti@2.7.0)(lightningcss@1.32.0)): dependencies: picocolors: 1.1.1 - vite: 6.4.4(jiti@2.7.0)(lightningcss@1.32.0) + vite: 6.4.6(jiti@2.7.0)(lightningcss@1.32.0) vite-plugin-full-reload: 1.2.0 lightningcss-android-arm64@1.32.0: @@ -1537,7 +1537,7 @@ snapshots: dependencies: tslib: 2.8.1 - shell-quote@1.9.0: {} + shell-quote@1.12.0: {} source-map-js@1.2.2: {} @@ -1583,7 +1583,7 @@ snapshots: picocolors: 1.1.1 picomatch: 2.3.2 - vite@6.4.4(jiti@2.7.0)(lightningcss@1.32.0): + vite@6.4.6(jiti@2.7.0)(lightningcss@1.32.0): dependencies: esbuild: 0.25.12 fdir: 6.5.0(picomatch@4.0.7) From a659146a4e8e3c6c4ebabfd4fca0ae3cb7d5f175 Mon Sep 17 00:00:00 2001 From: Martijn van de Wetering Date: Wed, 11 Nov 2026 21:08:39 +0100 Subject: [PATCH 2/4] chore: Drop the compiler toolchain from the production image The serversideup base image ships gcc, g++, make, binutils, libc6-dev and linux-libc-dev. Nothing needs them at runtime, and linux-libc-dev alone put some fifty kernel CVEs into every weekly Trivy image scan. Purge them after the PHP extensions are built. Checked on a local build: the toolchain is gone, opentelemetry, protobuf, redis and pdo_sqlite still load, artisan boots, and Trivy reports no fixable CRITICAL or HIGH findings (the published :latest has 56). Co-Authored-By: Claude Opus 5.5 --- backend/Dockerfile | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/backend/Dockerfile b/backend/Dockerfile index 4c5f8db..69999ca 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -43,6 +43,11 @@ RUN echo "apt refresh: ${APT_REFRESH}" \ && apt-get upgrade -y --no-install-recommends \ && rm -rf /var/lib/apt/lists/* RUN install-php-extensions opentelemetry protobuf +# The base image ships a full compiler toolchain (gcc, g++, make, binutils, libc6-dev, +# linux-libc-dev). Nothing needs it at runtime, and linux-libc-dev alone adds some fifty +# kernel CVEs to every weekly image scan. Drop it once the extensions above are built. +RUN apt-get purge -y --auto-remove gcc g++ make linux-libc-dev libc6-dev binutils cpp pkg-config \ + && rm -rf /var/lib/apt/lists/* # CVE-2026-109618 / CVE-2026-109619 (php2shell) are fixed in PHP 8.4.27. The tag above floats, # so fail the build rather than ship an older PHP from a stale registry mirror or layer cache. From b9211301371482e52873398cf7ca59165eb6b6d2 Mon Sep 17 00:00:00 2001 From: Martijn van de Wetering Date: Wed, 11 Nov 2026 21:13:09 +0100 Subject: [PATCH 3/4] ci: Rebuild the latest release image every week :latest was only built when a v* tag was pushed, so between releases it kept the Debian packages of release day and the weekly Trivy image scan went red on fixes published since. The Monday schedule now also checks out the newest final v* tag and rebuilds it with current packages, pushing :latest, :stable and its version tags. Same code and version string as the release, nothing from dev. A workflow_dispatch input runs just this rebuild on demand. The two builds use separate GHA cache scopes so they do not evict each other. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/docker-build.yml | 94 ++++++++++++++++++++++++++++-- 1 file changed, 90 insertions(+), 4 deletions(-) diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml index 9a804a6..2025671 100644 --- a/.github/workflows/docker-build.yml +++ b/.github/workflows/docker-build.yml @@ -12,10 +12,16 @@ on: - '.github/workflows/docker-build.yml' schedule: # Monday 04:17 UTC, two hours before the weekly image scan in security.yml. Rebuilds - # :dev so the scan sees this week's Debian security fixes instead of whatever was - # current at the last push to backend/. + # :dev and the latest release (:latest, :stable and its version tags) so the scan sees + # this week's Debian security fixes instead of whatever was current at the last push + # or release. - cron: '17 4 * * 1' workflow_dispatch: + inputs: + rebuild_release: + description: 'Rebuild the latest v* release with current Debian packages instead of building the selected ref' + type: boolean + default: false env: REGISTRY: ghcr.io @@ -23,6 +29,7 @@ env: jobs: build-and-push: + if: ${{ !inputs.rebuild_release }} runs-on: ubuntu-24.04 permissions: contents: read @@ -109,5 +116,84 @@ jobs: GIT_TAG=${{ steps.version.outputs.git_tag }} GIT_COMMIT=${{ steps.version.outputs.git_commit }} APT_REFRESH=${{ steps.version.outputs.apt_refresh }} - cache-from: type=gha - cache-to: type=gha,mode=max + # Own cache scope, so the release rebuild below does not evict the layers of dev. + cache-from: type=gha,scope=dev + cache-to: type=gha,mode=max,scope=dev + + # :latest is otherwise only built when a v* tag is pushed, so between releases it keeps + # the Debian packages of release day and the weekly image scan goes red on fixes that + # were published since. Rebuild the newest release from its own tag every week: same + # code, same version string, current packages. Nothing from dev ends up in :latest. + rebuild-release: + if: ${{ github.event_name == 'schedule' || inputs.rebuild_release }} + runs-on: ubuntu-24.04 + permissions: + contents: read + packages: write + + steps: + - name: Checkout repository + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + fetch-depth: 0 + fetch-tags: true + + - name: Find the latest release + id: release + # Final releases only (v1.9.1, not v1.10.0-beta.1), highest version first. + run: | + tag=$(git tag --list 'v*' --sort=-v:refname | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | head -n 1) + if [[ -z "$tag" ]]; then + echo "No release tag found" >&2 + exit 1 + fi + version="${tag#v}" + { + echo "tag=$tag" + echo "version=$version" + echo "minor=${version%.*}" + echo "apt_refresh=$(date -u +%F)" + } >> "$GITHUB_OUTPUT" + echo "Rebuilding $tag" + + - name: Check out the release + env: + RELEASE_TAG: ${{ steps.release.outputs.tag }} + run: git checkout --quiet "refs/tags/$RELEASE_TAG" + + - name: Set up QEMU + uses: docker/setup-qemu-action@96fe6ef7f33517b61c61be40b68a1882f3264fb8 # v4.2.0 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0 + with: + driver: docker-container + + - name: Log in to the Container registry + uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + # The same tags a release push produces, minus the commit sha. + - name: Rebuild and push the release image + uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0 + with: + context: ./backend + platforms: linux/amd64,linux/arm64 + push: true + tags: | + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:stable + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.release.outputs.version }} + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.release.outputs.minor }} + labels: | + org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }} + org.opencontainers.image.version=${{ steps.release.outputs.version }} + build-args: | + GIT_TAG=${{ steps.release.outputs.version }} + GIT_COMMIT= + APT_REFRESH=${{ steps.release.outputs.apt_refresh }} + cache-from: type=gha,scope=release + cache-to: type=gha,mode=max,scope=release From fd8532669f0c9b630f8adf92944d3181ff118333 Mon Sep 17 00:00:00 2001 From: Martijn van de Wetering Date: Wed, 11 Nov 2026 21:18:50 +0100 Subject: [PATCH 4/4] ci: Verify the weekly release rebuild before pushing, move only floating tags The weekly release rebuild pushed straight to :latest and the version tags, and the Trivy scan only looked at it two hours later. Self-hosters who auto-pull :latest would have received a broken or suspicious image first. The job now builds a linux/amd64 candidate and loads it locally, boots it with a production-like env and requires /health to answer 200 and the opentelemetry and protobuf extensions to load, then runs the Trivy gate with today's exceptions file. Only after both pass does it push the multi-platform image, from the cache the candidate build wrote. The rebuild now moves :latest and :stable only. 1.9.1 and 1.9 keep the bytes of their release, so pinning a version means what it says. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/docker-build.yml | 86 +++++++++++++++++++++++++++--- 1 file changed, 78 insertions(+), 8 deletions(-) diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml index 2025671..8d21902 100644 --- a/.github/workflows/docker-build.yml +++ b/.github/workflows/docker-build.yml @@ -12,9 +12,8 @@ on: - '.github/workflows/docker-build.yml' schedule: # Monday 04:17 UTC, two hours before the weekly image scan in security.yml. Rebuilds - # :dev and the latest release (:latest, :stable and its version tags) so the scan sees - # this week's Debian security fixes instead of whatever was current at the last push - # or release. + # :dev and the latest release (:latest and :stable) so the scan sees this week's Debian + # security fixes instead of whatever was current at the last push or release. - cron: '17 4 * * 1' workflow_dispatch: inputs: @@ -123,7 +122,8 @@ jobs: # :latest is otherwise only built when a v* tag is pushed, so between releases it keeps # the Debian packages of release day and the weekly image scan goes red on fixes that # were published since. Rebuild the newest release from its own tag every week: same - # code, same version string, current packages. Nothing from dev ends up in :latest. + # code, same version string, current packages. Nothing from dev ends up in :latest, and + # nothing is pushed before the rebuilt image has passed a smoke test and the Trivy gate. rebuild-release: if: ${{ github.event_name == 'schedule' || inputs.rebuild_release }} runs-on: ubuntu-24.04 @@ -156,6 +156,11 @@ jobs: } >> "$GITHUB_OUTPUT" echo "Rebuilding $tag" + # The exceptions file is policy, not release content: take today's copy from the + # branch this workflow runs on before the checkout below swaps the tree for the tag. + - name: Keep the current Trivy exceptions + run: cp .trivyignore.yaml "$RUNNER_TEMP/trivyignore.yaml" + - name: Check out the release env: RELEASE_TAG: ${{ steps.release.outputs.tag }} @@ -176,8 +181,75 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - # The same tags a release push produces, minus the commit sha. - - name: Rebuild and push the release image + # Nothing is pushed until the rebuilt image has proven itself. Self-hosters pull + # :latest automatically, so a broken or suspicious upstream change has to stop here, + # not two hours later in the weekly scan. Build the runner's platform first and load + # it locally: that is the image the checks below run against. + - name: Build the candidate image + uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0 + with: + context: ./backend + platforms: linux/amd64 + load: true + push: false + tags: spacepad-release:candidate + build-args: | + GIT_TAG=${{ steps.release.outputs.version }} + GIT_COMMIT= + APT_REFRESH=${{ steps.release.outputs.apt_refresh }} + cache-from: type=gha,scope=release + cache-to: type=gha,mode=max,scope=release + + # Boots the image the way a self-hoster runs it and asks Laravel's health route, + # which opens the database and writes to the cache. A container that cannot start, + # misses an extension or fails to boot the framework answers 500 or nothing at all. + - name: Smoke test the candidate + run: | + docker run -d --name candidate -p 8080:8080 \ + -e APP_KEY="base64:$(openssl rand -base64 32)" \ + -e APP_ENV=production \ + -e DB_CONNECTION=sqlite \ + -e DB_DATABASE=/var/www/html/storage/database.sqlite \ + -e CACHE_STORE=array \ + -e SESSION_DRIVER=array \ + -e QUEUE_CONNECTION=sync \ + -e LOG_CHANNEL=stderr \ + spacepad-release:candidate + + code=000 + for _ in $(seq 1 30); do + code=$(curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8080/health || true) + [[ "$code" == "200" ]] && break + sleep 2 + done + + docker exec candidate php -m | grep -qiE '^opentelemetry$' || { echo "opentelemetry extension missing"; code=missing-ext; } + docker exec candidate php -m | grep -qiE '^protobuf$' || { echo "protobuf extension missing"; code=missing-ext; } + + if [[ "$code" != "200" ]]; then + echo "Smoke test failed (health: $code)" + docker logs candidate 2>&1 | tail -n 50 + exit 1 + fi + echo "Smoke test passed" + docker rm -f candidate > /dev/null + + - name: Scan the candidate (block on fixable CRITICAL/HIGH) + uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0 + with: + scan-type: image + image-ref: spacepad-release:candidate + severity: CRITICAL,HIGH + ignore-unfixed: true + exit-code: '1' + format: table + trivyignores: ${{ runner.temp }}/trivyignore.yaml + + # Only the floating tags. 1.9.1 and 1.9 keep the bytes of their release, so whoever + # pins a version gets exactly what was released; whoever wants this week's fixes + # follows :latest or :stable. Every layer for linux/amd64 comes from the cache the + # candidate build just wrote, so this pushes the image that was tested. + - name: Push the release image uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0 with: context: ./backend @@ -186,8 +258,6 @@ jobs: tags: | ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:stable - ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.release.outputs.version }} - ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.release.outputs.minor }} labels: | org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }} org.opencontainers.image.version=${{ steps.release.outputs.version }}