Merge pull request #5167 from okxlin/maint/renovate-blocked-guards-20260726

Harden Renovate blocked update handling
This commit is contained in:
okxlin
2026-07-26 00:41:57 +08:00
committed by GitHub
4 changed files with 158 additions and 3 deletions
+42 -1
View File
@@ -446,7 +446,12 @@
"apps/geekbench/5/**",
"apps/headscale/0.23.0-alpha3/**",
"apps/headscale/0.26.1/**",
"apps/mysql/5.5.62/**"
"apps/headscale/0.27.1/**",
"apps/headscale/0.28.0/**",
"apps/immich/1.122.3/**",
"apps/mysql/5.5.62/**",
"apps/safeline/7.3.1/**",
"apps/safeline/newnet-7.3.1/**"
],
"enabled": false
},
@@ -472,6 +477,21 @@
],
"groupName": "ClearFlask application images"
},
{
"description": "Group SafeLine release images so all application components update together",
"matchFileNames": [
"apps/safeline/**/docker-compose.yml"
],
"matchPackageNames": [
"chaitin/safeline-chaos",
"chaitin/safeline-detector",
"chaitin/safeline-fvm",
"chaitin/safeline-luigi",
"chaitin/safeline-mgt",
"chaitin/safeline-tengine"
],
"groupName": "SafeLine application images"
},
{
"description": "Disable bundled database-only updates for LinuxServer multi-service apps",
"matchFileNames": [
@@ -529,12 +549,23 @@
],
"matchPackageNames": [
"busybox",
"langgenius/dify-plugin-daemon",
"nginx",
"semitechnologies/weaviate",
"ubuntu/squid"
],
"enabled": false
},
{
"description": "Keep uuWAF on the upstream-supported Percona 5.7 database line",
"matchFileNames": [
"apps/uuwaf/**/docker-compose.yml"
],
"matchPackageNames": [
"percona/percona-server"
],
"enabled": false
},
{
"description": "Disable sidecar-only Renovate updates for DooTask multi-service tracks",
"matchFileNames": [
@@ -545,6 +576,16 @@
],
"enabled": false
},
{
"description": "Keep Langflow on the tested 1.10 security line pending baseline x86_64 support",
"matchFileNames": [
"apps/langflow/**/docker-compose.yml"
],
"matchPackageNames": [
"langflowai/langflow"
],
"enabled": false
},
{
"description": "Disable sidecar-only Renovate updates for Diskover multi-service tracks",
"matchFileNames": [
+10 -2
View File
@@ -12,8 +12,7 @@
"worker",
"worker_beat",
"web",
"sandbox",
"plugin_daemon"
"sandbox"
],
"diskover-linuxserver": [
"diskover"
@@ -21,6 +20,9 @@
"karakeep": [
"karakeep"
],
"immich": [
"immich-server"
],
"librechat": [
"librechat-api",
"librechat-admin",
@@ -32,9 +34,15 @@
"rocketchat": [
"rocketchat"
],
"safeline": [
"safeline-mgt"
],
"teldrive": [
"teldrive"
],
"uuwaf": [
"uuwaf"
],
"weblate": [
"weblate"
],
@@ -1,5 +1,6 @@
#!/usr/bin/env python3
import importlib.util
import json
import unittest
from pathlib import Path
@@ -10,6 +11,10 @@ GUARD = importlib.util.module_from_spec(SPEC)
assert SPEC and SPEC.loader
SPEC.loader.exec_module(GUARD)
REPOSITORY_ROOT = Path(__file__).resolve().parents[2]
PRIMARY_SERVICES_PATH = REPOSITORY_ROOT / ".github" / "renovate-primary-services.json"
RENOVATE_CONFIG_PATH = REPOSITORY_ROOT / ".github" / "renovate-docker.json"
def compose(**images: str) -> dict:
return {"services": {name: {"image": image} for name, image in images.items()}}
@@ -79,5 +84,105 @@ class InferredPrimaryDecisionTests(unittest.TestCase):
self.assertEqual(decision.detail, "single-service compose")
class RepositoryPolicyTests(unittest.TestCase):
@classmethod
def setUpClass(cls) -> None:
cls.primary_services = json.loads(PRIMARY_SERVICES_PATH.read_text(encoding="utf-8"))
cls.renovate_config = json.loads(RENOVATE_CONFIG_PATH.read_text(encoding="utf-8"))
def disabled_rule_exists(self, file_pattern: str, package_name: str | None = None) -> bool:
for rule in self.renovate_config["packageRules"]:
if rule.get("enabled") is not False:
continue
if file_pattern not in rule.get("matchFileNames", []):
continue
if package_name is None or package_name in rule.get("matchPackageNames", []):
return True
return False
def test_dify_plugin_daemon_is_not_a_primary_service(self) -> None:
self.assertNotIn("plugin_daemon", self.primary_services["dify"])
self.assertTrue(
self.disabled_rule_exists(
"apps/dify/**/docker-compose.yml",
"langgenius/dify-plugin-daemon",
)
)
base = compose(api="langgenius/dify-api:1.16.0", plugin_daemon="langgenius/dify-plugin-daemon:0.6.3-local")
head = compose(api="langgenius/dify-api:1.16.0", plugin_daemon="langgenius/dify-plugin-daemon:0.6.5-local")
decision = GUARD.compare_compose(
"dify",
"apps/dify/1.16.0/docker-compose.yml",
base,
head,
self.primary_services["dify"],
)
self.assertEqual(decision.outcome, "close")
def test_safeline_components_are_grouped_behind_management_service(self) -> None:
self.assertEqual(self.primary_services["safeline"], ["safeline-mgt"])
expected_images = {
"chaitin/safeline-chaos",
"chaitin/safeline-detector",
"chaitin/safeline-fvm",
"chaitin/safeline-luigi",
"chaitin/safeline-mgt",
"chaitin/safeline-tengine",
}
grouped_rules = [
rule
for rule in self.renovate_config["packageRules"]
if rule.get("groupName") == "SafeLine application images"
]
self.assertEqual(len(grouped_rules), 1)
self.assertEqual(set(grouped_rules[0]["matchPackageNames"]), expected_images)
self.assertIn("apps/safeline/**/docker-compose.yml", grouped_rules[0]["matchFileNames"])
def test_blocked_historical_tracks_are_immutable(self) -> None:
expected_patterns = {
"apps/headscale/0.27.1/**",
"apps/headscale/0.28.0/**",
"apps/immich/1.122.3/**",
"apps/safeline/7.3.1/**",
"apps/safeline/newnet-7.3.1/**",
}
for pattern in expected_patterns:
with self.subTest(pattern=pattern):
self.assertTrue(self.disabled_rule_exists(pattern))
def test_uuwaf_database_is_not_updated_independently(self) -> None:
self.assertEqual(self.primary_services["uuwaf"], ["uuwaf"])
self.assertTrue(
self.disabled_rule_exists(
"apps/uuwaf/**/docker-compose.yml",
"percona/percona-server",
)
)
base = compose(uuwaf="uusec/nanqiang:v6.8.0", wafdb="percona/percona-server:5.7.44")
head = compose(uuwaf="uusec/nanqiang:v6.8.0", wafdb="percona/percona-server:8.4.2")
decision = GUARD.compare_compose(
"uuwaf",
"apps/uuwaf/6.8.0/docker-compose.yml",
base,
head,
self.primary_services["uuwaf"],
)
self.assertEqual(decision.outcome, "close")
def test_langflow_updates_require_manual_compatibility_review(self) -> None:
self.assertTrue(
self.disabled_rule_exists(
"apps/langflow/**/docker-compose.yml",
"langflowai/langflow",
)
)
if __name__ == "__main__":
unittest.main()
+1
View File
@@ -24,6 +24,7 @@ Immich is a high-performance open source photo and video management platform for
## 部署说明
- 本应用使用 Docker Compose 在 1Panel 中部署。
- `1.122.3` 和 `release` 是为旧安装保留的社区镜像版本,使用 `altran1502/immich-*`,不是 Immich 官方镜像;新安装应优先选择使用 `ghcr.io/immich-app/*` 官方镜像的 `3.x` 固定版本。
- 应用分类:媒体。
- 支持架构:amd64。
- 可选版本以应用商店页面为准。