CI/CD hardening: lint, secret scan, coverage gate, auto CVE-fix PRs, GHCR + GitHub mirror publishing (#34)
CI / build-and-scan (push) Successful in 2m43s

- release changelog: commits rendered as description (link), divider lines dropped
- gitleaks secret scan and hadolint on every push/PR
- ruff lint/format gate (Python repos) with a pytest --cov-fail-under gate
- scheduled CRITICAL Trivy failures attempt an apk upgrade rebuild and open a follow-up PR if it clears the finding, instead of just failing red
- images also published to ghcr.io/djeex/<repo>
- a matching GitHub Release is created on the GitHub mirror, with a notice pointing back to this repo as the source of truth
This commit was merged in pull request #34.
This commit is contained in:
2026-08-26 15:38:54 +02:00
parent edd39febd1
commit f22634e9d9
18 changed files with 354 additions and 111 deletions
+2 -5
View File
@@ -50,9 +50,7 @@ def app_env(tmp_path, monkeypatch, make_image):
theme_dir = root / "config" / "themes" / "modern"
theme_dir.mkdir(parents=True)
(theme_dir / "theme.yaml").write_text(
"colors:\n browser_color: '#ffffff'\n"
"favicon:\n path: favicon.png\n"
"google_fonts: []\n",
"colors:\n browser_color: '#ffffff'\nfavicon:\n path: favicon.png\ngoogle_fonts: []\n",
encoding="utf-8",
)
make_image(theme_dir / "favicon.png", size=(32, 32), fmt="PNG")
@@ -61,8 +59,7 @@ def app_env(tmp_path, monkeypatch, make_image):
"hero:\n images: []\ngallery:\n images: []\n", encoding="utf-8"
)
(root / "config" / "site.yaml").write_text(
"info:\n title: Test\n canonical: https://example.com\n"
"social:\n thumbnail: ''\n",
"info:\n title: Test\n canonical: https://example.com\nsocial:\n thumbnail: ''\n",
encoding="utf-8",
)
+1 -3
View File
@@ -1,5 +1,3 @@
from pathlib import Path
from src.py.builder import utils
@@ -30,7 +28,7 @@ def test_load_theme_config_missing_raises(tmp_path):
themes_dir = tmp_path / "themes"
try:
utils.load_theme_config("missing", themes_dir)
assert False, "expected FileNotFoundError"
raise AssertionError("expected FileNotFoundError")
except FileNotFoundError:
pass
-2
View File
@@ -1,5 +1,3 @@
import yaml
from src.py.builder import gallery_builder as gb
+7 -4
View File
@@ -1,5 +1,3 @@
from pathlib import Path
from PIL import Image
from src.py.builder import image_processor as ip
@@ -101,8 +99,13 @@ def test_generate_favicons_from_logo_creates_all_sizes(tmp_path, make_image):
ip.generate_favicons_from_logo({"favicon": {"path": "favicon.png"}}, theme_dir, output_dir)
expected = [
"favicon-32.png", "favicon-96.png", "favicon-128.png",
"favicon-192.png", "favicon-196.png", "favicon-152.png", "favicon-180.png",
"favicon-32.png",
"favicon-96.png",
"favicon-128.png",
"favicon-192.png",
"favicon-196.png",
"favicon-152.png",
"favicon-180.png",
]
for name in expected:
assert (output_dir / name).exists()
+8 -4
View File
@@ -102,7 +102,13 @@ def test_site_info_get_and_post(client, app_env):
data = resp.get_json()
assert data["info"]["title"] == "Test"
client.post("/api/site-info", json={"info": {"subtitle": "New subtitle"}, "social": {"instagram_url": "https://insta.example"}})
client.post(
"/api/site-info",
json={
"info": {"subtitle": "New subtitle"},
"social": {"instagram_url": "https://insta.example"},
},
)
updated = client.get("/api/site-info").get_json()
assert updated["info"]["title"] == "Test"
@@ -271,9 +277,7 @@ def test_trigger_build_success_invokes_subprocess(client, app_env, monkeypatch):
)
calls = []
monkeypatch.setattr(
webui.subprocess, "run", lambda *a, **k: calls.append((a, k))
)
monkeypatch.setattr(webui.subprocess, "run", lambda *a, **k: calls.append((a, k)))
resp = client.post("/api/build")
assert resp.get_json() == {"status": "ok"}