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
+7 -3
View File
@@ -1,7 +1,9 @@
import logging
from pathlib import Path
from flask import Blueprint, request, current_app
from flask import Blueprint, current_app, request
from werkzeug.utils import secure_filename
from src.py.builder.gallery_builder import update_gallery, update_hero
# --- Create Flask blueprint for upload routes ---
@@ -10,10 +12,12 @@ upload_bp = Blueprint("upload", __name__)
# --- Allowed file types ---
ALLOWED_EXTENSIONS = {"png", "jpg", "jpeg", "webp"}
def allowed_file(filename: str) -> bool:
"""Check if the uploaded file has an allowed extension."""
return "." in filename and filename.rsplit(".", 1)[1].lower() in ALLOWED_EXTENSIONS
def save_uploaded_file(file, folder: Path):
"""Save an uploaded file to the specified folder."""
folder.mkdir(parents=True, exist_ok=True) # Create folder if not exists
@@ -22,6 +26,7 @@ def save_uploaded_file(file, folder: Path):
logging.info(f"[✓] Uploaded {filename} to {folder}")
return filename
@upload_bp.route("/api/<section>/upload", methods=["POST"])
def upload_photo(section: str):
"""
@@ -35,7 +40,7 @@ def upload_photo(section: str):
# Check if files are provided
if "files" not in request.files:
return {"error": "No files provided"}, 400
files = request.files.getlist("files")
if not files:
return {"error": "No selected files"}, 400
@@ -63,4 +68,3 @@ def upload_photo(section: str):
return {"status": "ok", "uploaded": uploaded}
return {"error": "No valid files uploaded"}, 400