69 Commits
Author SHA1 Message Date
DragonSlayer_14 a734edd76c Merge pull request 'Merge dev in testing: Passt Workflows und Dependencies an' (#32) from dev into testing
Testing Build, Publish & Preview Release / Erkenne relevante Code-Änderungen (push) Successful in 10s
Unit-Tests / Unit-Tests (pull_request) Skipped
Auto-PR (Testing → Main) / Erstelle automatisch PR von testing nach main (push) Successful in 16s
Security Scans / Trivy & OSV-Scanner (push) Successful in 40s
TruffleHog Secret Scan / TruffleHog (pull_request) Successful in 28s
Security Scans / Trivy & OSV-Scanner (pull_request) Successful in 53s
Testing Build, Publish & Preview Release / Build, Publish Packages (Testing) & Create Preview Release (push) Successful in 11m15s
TruffleHog Secret Scan / TruffleHog (push) Successful in 10s
Reviewed-on: #32
2026-09-13 15:09:03 +00:00
Gitea-Bot 64420cc224 Chore: Erhöht Patch-Version auf 1.0.5 für Promotion nach testing
Testing Build, Publish & Preview Release / Build, Publish Packages (Testing) & Create Preview Release (push) Skipped
Security Scans / Trivy & OSV-Scanner (pull_request) Successful in 57s
Security Scans / Trivy & OSV-Scanner (push) Successful in 56s
TruffleHog Secret Scan / TruffleHog (pull_request) Successful in 30s
TruffleHog Secret Scan / TruffleHog (push) Successful in 30s
Code Quality (Auto-Format & Clippy-Fix) / Formatierung & Clippy automatisch beheben (push) Successful in 4m34s
Unit-Tests / Unit-Tests (pull_request) Successful in 3m1s
2026-09-13 14:45:19 +00:00
DragonSlayer_14 bdd26a9189 Merge pull request 'chore(deps): update cargo dependencies' (#30) from renovate/cargo-dependencies into dev
Testing Build, Publish & Preview Release / Build, Publish Packages (Testing) & Create Preview Release (push) Skipped
TruffleHog Secret Scan / TruffleHog (push) Successful in 24s
Security Scans / Trivy & OSV-Scanner (push) Successful in 36s
Auto Patch-Version-Bump (Dev → Testing PR) / Erkenne relevante Änderungen im PR (pull_request) Successful in 12s
TruffleHog Secret Scan / TruffleHog (pull_request) Successful in 30s
Auto Patch-Version-Bump (Dev → Testing PR) / Patch-Version erhöhen & auf Dev pushen (pull_request) Successful in 16s
Security Scans / Trivy & OSV-Scanner (pull_request) Successful in 53s
Unit-Tests / Unit-Tests (pull_request) Successful in 3m9s
Code Quality (Auto-Format & Clippy-Fix) / Formatierung & Clippy automatisch beheben (push) Successful in 4m14s
Reviewed-on: #30
Reviewed-by: dragonslayer14@murena.io <4+dragonslayer_14@noreply.localhost>
2026-09-13 14:44:12 +00:00
DragonSlayer_14 84a64f1bde Merge pull request 'chore(deps): update ghcr.io/renovatebot/renovate docker tag to v44.83.0' (#31) from renovate/gitea-actions into dev
Testing Build, Publish & Preview Release / Build, Publish Packages (Testing) & Create Preview Release (push) Skipped
TruffleHog Secret Scan / TruffleHog (push) Successful in 21s
Security Scans / Trivy & OSV-Scanner (push) Successful in 31s
Code Quality (Auto-Format & Clippy-Fix) / Formatierung & Clippy automatisch beheben (push) Successful in 1m25s
Reviewed-on: #31
Reviewed-by: dragonslayer14@murena.io <4+dragonslayer_14@noreply.localhost>
2026-09-13 14:43:14 +00:00
Renovate-Bot 4d2e92f6bb chore(deps): update ghcr.io/renovatebot/renovate docker tag to v44.83.0
Testing Build, Publish & Preview Release / Build, Publish Packages (Testing) & Create Preview Release (push) Skipped
TruffleHog Secret Scan / TruffleHog (push) Successful in 18s
Unit-Tests / Unit-Tests (pull_request) Skipped
TruffleHog Secret Scan / TruffleHog (pull_request) Successful in 12s
Security Scans / Trivy & OSV-Scanner (pull_request) Successful in 18s
2026-09-13 14:01:59 +00:00
Renovate-Bot eb5519be87 chore(deps): update cargo dependencies
Unit-Tests / Unit-Tests (pull_request) Skipped
Testing Build, Publish & Preview Release / Build, Publish Packages (Testing) & Create Preview Release (push) Skipped
TruffleHog Secret Scan / TruffleHog (pull_request) Successful in 30s
TruffleHog Secret Scan / TruffleHog (push) Successful in 29s
Security Scans / Trivy & OSV-Scanner (pull_request) Successful in 46s
2026-09-13 14:01:55 +00:00
DragonSlayer_14andClaude Sonnet 5 f7f5290404 Feat: Fügt automatischen PR-Workflow für Testing→Main hinzu
Testing Build, Publish & Preview Release / Build, Publish Packages (Testing) & Create Preview Release (push) Skipped
TruffleHog Secret Scan / TruffleHog (push) Successful in 28s
Security Scans / Trivy & OSV-Scanner (push) Successful in 56s
Code Quality (Auto-Format & Clippy-Fix) / Formatierung & Clippy automatisch beheben (push) Successful in 1m32s
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AjPGeW28DpjnMkuvLSRTKv
2026-09-13 14:26:01 +02:00
DragonSlayer_14andClaude Sonnet 5 dffa74f47c Feat: Fügt automatischen Patch-Version-Bump für Dev→Testing-PRs hinzu
Testing Build, Publish & Preview Release / Build, Publish Packages (Testing) & Create Preview Release (push) Skipped
TruffleHog Secret Scan / TruffleHog (push) Successful in 29s
Code Quality (Auto-Format & Clippy-Fix) / Formatierung & Clippy automatisch beheben (push) Successful in 3m28s
Security Scans / Trivy & OSV-Scanner (push) Successful in 52s
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DrWxHCG7URf4FEy8Hja23f
2026-09-13 14:04:51 +02:00
DragonSlayer_14 c455aa894e Merge pull request 'Merge dev in testing: Passt Workflows und README an' (#28) from dev into testing
TruffleHog Secret Scan / TruffleHog (push) Successful in 32s
Security Scans / Trivy & OSV-Scanner (push) Successful in 53s
TruffleHog Secret Scan / TruffleHog (pull_request) Successful in 30s
Testing Build, Publish & Preview Release / Build, Publish Packages (Testing) & Create Preview Release (push) Successful in 15m22s
Security Scans / Trivy & OSV-Scanner (pull_request) Successful in 53s
Unit-Tests / Unit-Tests (pull_request) Skipped
Testing Build, Publish & Preview Release / Erkenne relevante Code-Änderungen (push) Successful in 14s
Reviewed-on: #28
2026-09-13 10:16:11 +00:00
DragonSlayer_14andClaude Sonnet 5 513eae640f Feat: Baut Pakete nur bei tatsächlichen Code-Änderungen
Testing Build, Publish & Preview Release / Build, Publish Packages (Testing) & Create Preview Release (push) Skipped
TruffleHog Secret Scan / TruffleHog (push) Successful in 30s
Security Scans / Trivy & OSV-Scanner (push) Successful in 1m33s
Code Quality (Auto-Format & Clippy-Fix) / Formatierung & Clippy automatisch beheben (push) Successful in 3m38s
TruffleHog Secret Scan / TruffleHog (pull_request) Successful in 17s
Security Scans / Trivy & OSV-Scanner (pull_request) Successful in 26s
Unit-Tests / Unit-Tests (pull_request) Successful in 38s
Fügt einen vorgeschalteten detect-changes-Job ein, der mittels
dorny/paths-filter@v4 prüft, ob sich Programmcode (src/, Cargo.toml,
Cargo.lock, scripts/, .cargo/ bzw. die jeweilige Workflow-Datei selbst)
geändert hat. Der Build-/Publish-/Release-Job wird nur noch ausgeführt,
wenn das der Fall ist; bei reinen Config- oder Workflow-Änderungen
schließt der Workflow erfolgreich ohne Build/Release ab.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TcFzG54jW33nvp1TawCZJV
2026-09-13 11:39:21 +02:00
DragonSlayer_14andClaude Sonnet 5 475f0f9903 Fix: Verschiebt allowCustomCrateRegistries in die globale Renovate-Config
Testing Build, Publish & Preview Release / Build, Publish Packages (Testing) & Create Preview Release (push) Skipped
TruffleHog Secret Scan / TruffleHog (push) Successful in 29s
Security Scans / Trivy & OSV-Scanner (push) Successful in 53s
Code Quality (Auto-Format & Clippy-Fix) / Formatierung & Clippy automatisch beheben (push) Successful in 2m12s
Die Option ist repo-only nicht erlaubt und wurde in der Renovate-Workflow-
Umgebung (RENOVATE_ALLOW_CUSTOM_CRATE_REGISTRIES) gesetzt.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0156cWd2mGWNQU1kBbBPWpD7
2026-09-13 01:18:13 +02:00
Gitea-Bot db42d73adb Style: Automatische Formatierung & Clippy-Fixes
Testing Build, Publish & Preview Release / Build, Publish Packages (Testing) & Create Preview Release (push) Skipped
TruffleHog Secret Scan / TruffleHog (push) Successful in 18s
Security Scans / Trivy & OSV-Scanner (push) Successful in 29s
Code Quality (Auto-Format & Clippy-Fix) / Formatierung & Clippy automatisch beheben (push) Successful in 1m55s
2026-09-12 22:22:15 +00:00
Gitea-Bot 074d5a7ff2 Style: Automatische Formatierung & Clippy-Fixes
Testing Build, Publish & Preview Release / Build, Publish Packages (Testing) & Create Preview Release (push) Skipped
TruffleHog Secret Scan / TruffleHog (push) Successful in 18s
Security Scans / Trivy & OSV-Scanner (push) Successful in 30s
Code Quality (Auto-Format & Clippy-Fix) / Formatierung & Clippy automatisch beheben (push) Successful in 1m5s
2026-09-12 22:21:10 +00:00
DragonSlayer_14 5ac35bb370 Feat: Fügt code-quality-Workflow für automatische Formatierung und fixes hinzu
Testing Build, Publish & Preview Release / Build, Publish Packages (Testing) & Create Preview Release (push) Skipped
TruffleHog Secret Scan / TruffleHog (push) Successful in 17s
Security Scans / Trivy & OSV-Scanner (push) Successful in 28s
Code Quality (Auto-Format & Clippy-Fix) / Formatierung & Clippy automatisch beheben (push) Successful in 1m3s
- Introduced `code-quality.yaml` to automate Rust code formatting and Clippy fixes in the `dev` branch.
- Updated `jsonSchemas.xml` to include schema paths for new Gitea workflows.
2026-09-13 00:20:01 +02:00
DragonSlayer_14 4b5de248cd Merge pull request 'chore(deps): update ghcr.io/renovatebot/renovate docker tag to v44.82.3' (#27) from renovate/gitea-actions into dev
Testing Build, Publish & Preview Release / Build, Publish Packages (Testing) & Create Preview Release (push) Skipped
TruffleHog Secret Scan / TruffleHog (push) Successful in 11s
Security Scans / Trivy & OSV-Scanner (push) Successful in 17s
Reviewed-on: #27
2026-09-12 11:08:07 +00:00
Renovate-Bot 0f01f53391 chore(deps): update ghcr.io/renovatebot/renovate docker tag to v44.82.3
Testing Build, Publish & Preview Release / Build, Publish Packages (Testing) & Create Preview Release (push) Skipped
Unit-Tests / Unit-Tests (pull_request) Skipped
TruffleHog Secret Scan / TruffleHog (push) Successful in 15s
Security Scans / Trivy & OSV-Scanner (pull_request) Successful in 26s
TruffleHog Secret Scan / TruffleHog (pull_request) Successful in 12s
2026-09-12 09:00:36 +00:00
DragonSlayer_14 64a0aaa772 Fix: Aktiviert allowCustomCrateRegistries in renovate.json
Testing Build, Publish & Preview Release / Build, Publish Packages (Testing) & Create Preview Release (push) Skipped
TruffleHog Secret Scan / TruffleHog (push) Successful in 12s
Security Scans / Trivy & OSV-Scanner (push) Successful in 18s
2026-09-11 23:22:32 +02:00
DragonSlayer_14 d247777667 Docs: Entfernt unnötige Security-Scan-Badges aus README.md 2026-09-11 23:20:57 +02:00
DragonSlayer_14 9507bb1cca Merge pull request 'Merge testing in main: Release 1.0.4' (#26) from testing into main
Testing Build, Publish & Preview Release / Build, Publish Packages (Testing) & Create Preview Release (push) Skipped
Security Scans / Trivy & OSV-Scanner (push) Successful in 42s
Main Release & Publish / Build, Publish Packages (Stable) & Create Release (push) Successful in 12m31s
TruffleHog Secret Scan / TruffleHog (push) Successful in 13s
Reviewed-on: #26
2026-09-11 20:52:01 +00:00
DragonSlayer_14 df58f0f08f Merge pull request 'Merge dev in testing: Aktualisiert Workflows' (#25) from dev into testing
Security Scans / Trivy & OSV-Scanner (push) Successful in 28s
TruffleHog Secret Scan / TruffleHog (push) Successful in 14s
Testing Build, Publish & Preview Release / Build, Publish Packages (Testing) & Create Preview Release (push) Successful in 13m2s
Unit-Tests / Unit-Tests (pull_request) Skipped
TruffleHog Secret Scan / TruffleHog (pull_request) Successful in 13s
Security Scans / Trivy & OSV-Scanner (pull_request) Successful in 19s
Reviewed-on: #25
2026-09-11 20:28:08 +00:00
DragonSlayer_14 2a059466b3 Fix: Korrigiert E-Mail-Adresse des Renovate-Bots im Workflow
Testing Build, Publish & Preview Release / Build, Publish Packages (Testing) & Create Preview Release (push) Skipped
TruffleHog Secret Scan / TruffleHog (push) Successful in 12s
Security Scans / Trivy & OSV-Scanner (push) Successful in 20s
TruffleHog Secret Scan / TruffleHog (pull_request) Successful in 17s
Security Scans / Trivy & OSV-Scanner (pull_request) Successful in 29s
Unit-Tests / Unit-Tests (pull_request) Successful in 2m19s
2026-09-11 22:17:06 +02:00
DragonSlayer_14 12828d45e1 Feat: Hebt Version auf 1.0.4
Testing Build, Publish & Preview Release / Build, Publish Packages (Testing) & Create Preview Release (push) Skipped
TruffleHog Secret Scan / TruffleHog (push) Successful in 13s
Security Scans / Trivy & OSV-Scanner (push) Successful in 18s
2026-09-11 22:14:27 +02:00
DragonSlayer_14 32eb649c20 Merge remote-tracking branch 'origin/dev' into dev
Testing Build, Publish & Preview Release / Build, Publish Packages (Testing) & Create Preview Release (push) Skipped
TruffleHog Secret Scan / TruffleHog (push) Successful in 12s
Security Scans / Trivy & OSV-Scanner (push) Successful in 19s
2026-09-11 22:12:49 +02:00
DragonSlayer_14andRenovate-Bot 5f1d677485 Feat: Aktualisiert renovate.json auf die neuste Version.
Co-Authored-By: Renovate-Bot <renovate-bot@creativedragonslayer.de>
2026-09-11 22:12:42 +02:00
DragonSlayer_14 80be163e55 Merge pull request 'chore(deps): update gitea actions' (#23) from renovate/gitea-actions into dev
Testing Build, Publish & Preview Release / Build, Publish Packages (Testing) & Create Preview Release (push) Skipped
TruffleHog Secret Scan / TruffleHog (push) Successful in 12s
Security Scans / Trivy & OSV-Scanner (push) Successful in 18s
Reviewed-on: #23
2026-09-11 20:08:17 +00:00
DragonSlayer_14 5b385b4277 Merge pull request 'chore(deps): update rust crate reqwest to v0.13.5' (#22) from renovate/cargo-dependencies into dev
Testing Build, Publish & Preview Release / Build, Publish Packages (Testing) & Create Preview Release (push) Skipped
TruffleHog Secret Scan / TruffleHog (push) Successful in 11s
Security Scans / Trivy & OSV-Scanner (push) Successful in 17s
Reviewed-on: #22
2026-09-11 20:07:09 +00:00
Renovate Bot dcc7812501 chore(deps): update gitea actions
Testing Build, Publish & Preview Release / Build, Publish Packages (Testing) & Create Preview Release (push) Skipped
TruffleHog Secret Scan / TruffleHog (push) Successful in 23s
Unit-Tests / Unit-Tests (pull_request) Skipped
TruffleHog Secret Scan / TruffleHog (pull_request) Successful in 26s
Security Scans / Trivy & OSV-Scanner (pull_request) Successful in 39s
2026-09-11 16:00:22 +00:00
Renovate Bot 113c5d2120 chore(deps): update rust crate reqwest to v0.13.5
Testing Build, Publish & Preview Release / Build, Publish Packages (Testing) & Create Preview Release (push) Skipped
Unit-Tests / Unit-Tests (pull_request) Skipped
TruffleHog Secret Scan / TruffleHog (push) Successful in 23s
TruffleHog Secret Scan / TruffleHog (pull_request) Successful in 27s
Security Scans / Trivy & OSV-Scanner (pull_request) Successful in 33s
2026-09-11 16:00:16 +00:00
DragonSlayer_14andClaude Sonnet 5 65c115932f Fix: Renovate-CI-Lauf auf stündlich statt wöchentlich erhöht
Testing Build, Publish & Preview Release / Build, Publish Packages (Testing) & Create Preview Release (push) Skipped
TruffleHog Secret Scan / TruffleHog (push) Successful in 12s
Security Scans / Trivy & OSV-Scanner (push) Successful in 18s
Beschleunigt Renovates Reaktion auf Dependency-Dashboard-Checkboxen
(die den in renovate.json gesetzten wöchentlichen Update-Schedule
ohnehin umgehen) von bis zu einer Woche auf bis zu einer Stunde.
Tatsächliche neue Update-PRs entstehen weiterhin nur innerhalb des
renovate.json-Schedules (Montag vor 6 Uhr).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E7r1oHC5ezNRnDuneTRCtN
2026-09-11 17:58:24 +02:00
DragonSlayer_14andClaude Sonnet 5 10a3ae0bf7 Fix: Renovate-Authentifizierung und Custom-Cargo-Registry
Testing Build, Publish & Preview Release / Build, Publish Packages (Testing) & Create Preview Release (push) Skipped
TruffleHog Secret Scan / TruffleHog (push) Successful in 13s
Security Scans / Trivy & OSV-Scanner (push) Successful in 28s
- Renovate-Workflow: Host in RENOVATE_HOST_RULES statt hartkodiert
  über die bereits genutzte server_url-Expression bezogen
- GITHUB_COM_TOKEN (aus neuem Secret GH_RENOVATE_TOKEN) ergänzt, damit
  Renovate GitHub-gehostete Dependencies authentifiziert statt
  rate-limitiert abfragt
- allowCustomCrateRegistries in renovate.json aktiviert, da sonst
  Lookups für die eigenen Cargo-Pakete (config-ctdra, logger-ctdra)
  aus der Gitea-Registry fehlschlagen

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E7r1oHC5ezNRnDuneTRCtN
2026-09-11 17:16:32 +02:00
DragonSlayer_14 9c14d965db Fix: Zusätzliche Prüfung auf leere Umgebungsvariablen in report-security-issue.py 2026-09-10 23:21:29 +02:00
DragonSlayer_14 e85c613e7d Merge branch 'main' into dev 2026-09-10 23:20:20 +02:00
DragonSlayer_14andClaude Sonnet 5 b8a4d2d665 Docs: TruffleHog-Push-Trigger-Scope in AGENTS.md/README.md korrigiert
Aus dem /code-review-Lauf: Beide Dokumente behaupteten, die
Security-Scans liefen nur bei Push auf main/testing/dev. Das stimmt
fuer security-scan.yaml, aber trufflehog-scan.yaml hat keinen
branches-Filter und laeuft tatsaechlich bei Push auf jeden Branch.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kh9v73QApBwJj96w6A8R55
2026-09-10 23:04:24 +02:00
DragonSlayer_14andJunie 7ee0c2d272 Fix: Gezieltes Caching fuer Packaging-Tools und Token-Pruefung in Security-Scans
- Caching in main.yaml und testing.yaml auf die konkreten Packaging-Binaries (~/.cargo/bin/cargo-binstall, cargo-deb, cargo-generate-rpm) eingeschraenkt, statt das gesamte ~/.cargo/bin-Verzeichnis zu sichern (verhindert das Wiederherstellen veralteter Rust-Compiler-Proxys bei Toolchain-Updates).
- AGENTS.md an das praezisierte Caching-Verhalten angepasst.
- scripts/report-security-issue.py sichert den Zugriff auf Umgebungsvariablen (GITEA_URL, REPO, TOKEN) per os.environ.get ab und ueberspringt die Gitea-Issue-Synchronisation bei fehlendem oder leerem Token (verhindert Auth-Crashes bei unprivilegierten PR-Workflow-Laeufen).

Co-authored-by: Junie <junie@jetbrains.com>
2026-09-10 23:02:25 +02:00
DragonSlayer_14andClaude Sonnet 5 8359d6e4bf Docs: AGENTS.md & README.md an aktuelle CI/CD-Pipeline angepasst
Beide Dokumente hinkten dem tatsaechlichen Stand der .gitea/workflows/
und renovate.json hinterher. Ergaenzt:
- Neue Workflow-Dateien (unit-tests, security-scan, trufflehog-scan,
  renovate) und renovate.json in den Projektstruktur-Uebersichten
- AGENTS.md: neuer Abschnitt 5 mit Branch-Flow, actions/cache-Details
  inkl. der target/-Bereinigungs-Falle, der Build-Nummer-Logik ueber
  die Gitea-Packages-API und der Renovate-Gruppierung/baseBranches
- README.md: zwei weitere CI-Badges sowie ein kurzer CI/CD & Contributing-
  Abschnitt fuer Branch-Flow, PR-Tests, Security-Scans und Renovate

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kh9v73QApBwJj96w6A8R55
2026-09-10 22:50:00 +02:00
DragonSlayer_14 3d33972e98 Docs: Projektbeschreibung und Titel im README korrigiert und neu strukturiert
Testing Build, Publish & Preview Release / Build, Publish Packages (Testing) & Create Preview Release (push) Skipped
TruffleHog Secret Scan / TruffleHog (push) Successful in 11s
Security Scans / Trivy & OSV-Scanner (push) Successful in 18s
2026-09-10 22:41:02 +02:00
DragonSlayer_14 5768604ac9 Merge pull request 'Merge testing in main: Release 1.0.3' (#20) from testing into main
Testing Build, Publish & Preview Release / Build, Publish Packages (Testing) & Create Preview Release (push) Skipped
Security Scans / Trivy & OSV-Scanner (push) Successful in 25s
Main Release & Publish / Build, Publish Packages (Stable) & Create Release (push) Successful in 1m54s
TruffleHog Secret Scan / TruffleHog (push) Successful in 9s
Reviewed-on: #20
2026-09-10 20:38:58 +00:00
DragonSlayer_14 07ef691bc1 Merge pull request 'Merge dev in testing: Fix: Alte Paketierungs-Artefakte aus dem Cargo-Cache bereinigen' (#19) from dev into testing
TruffleHog Secret Scan / TruffleHog (push) Successful in 16s
Security Scans / Trivy & OSV-Scanner (push) Successful in 27s
Testing Build, Publish & Preview Release / Build, Publish Packages (Testing) & Create Preview Release (push) Successful in 2m6s
Unit-Tests / Unit-Tests (pull_request) Skipped
TruffleHog Secret Scan / TruffleHog (pull_request) Successful in 11s
Security Scans / Trivy & OSV-Scanner (pull_request) Successful in 18s
Reviewed-on: #19
2026-09-10 20:34:46 +00:00
DragonSlayer_14andClaude Sonnet 5 4d110b7c52 Fix: Alte Paketierungs-Artefakte aus dem Cargo-Cache bereinigen
Testing Build, Publish & Preview Release / Build, Publish Packages (Testing) & Create Preview Release (push) Skipped
TruffleHog Secret Scan / TruffleHog (push) Successful in 11s
Security Scans / Trivy & OSV-Scanner (push) Successful in 17s
TruffleHog Secret Scan / TruffleHog (pull_request) Successful in 16s
Security Scans / Trivy & OSV-Scanner (pull_request) Successful in 25s
Unit-Tests / Unit-Tests (pull_request) Successful in 36s
Der target-Cache (aus dem vorherigen Caching-Fix) haelt zwischen
Laeufen auch target/debian, target/generate-rpm und target/arch am
Leben, obwohl diese nie geleert wurden. Bei einem Cache-Treffer
wurden dadurch alte .deb/.rpm/.pkg.tar.zst-Dateien aus frueheren
Builds wiederhergestellt und beim Registry-Publish erneut mit
hochgeladen - Gitea lehnte die bereits existierende Datei mit 409
ab und riss den kompletten Schritt ab, bevor die eigentlich neue
Datei drankam (beobachtet beim RPM-Upload trotz korrekt berechneter
neuer Build-Nummer).

Die drei Paketierungs-Ausgabeordner werden jetzt direkt nach dem
Cache-Restore geleert, der eigentliche Kompilierungs-Cache
(target/<triple>/release/...) bleibt davon unberuehrt.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kh9v73QApBwJj96w6A8R55
2026-09-10 22:32:57 +02:00
DragonSlayer_14 5f4be34a73 Merge pull request 'Merge dev in testing: Fix: Build-Nummer-Ermittlung uebersah bereits veroeffentlichte RPM/Deb/Arch-Versionen' (#18) from dev into testing
TruffleHog Secret Scan / TruffleHog (push) Successful in 16s
Security Scans / Trivy & OSV-Scanner (push) Successful in 24s
Testing Build, Publish & Preview Release / Build, Publish Packages (Testing) & Create Preview Release (push) Failing after 1m54s
Reviewed-on: #18
2026-09-10 20:24:01 +00:00
DragonSlayer_14andClaude Sonnet 5 2a16a866ed Fix: Build-Nummer-Ermittlung uebersah bereits veroeffentlichte RPM/Deb/Arch-Versionen
Testing Build, Publish & Preview Release / Build, Publish Packages (Testing) & Create Preview Release (push) Skipped
TruffleHog Secret Scan / TruffleHog (push) Successful in 11s
Security Scans / Trivy & OSV-Scanner (push) Successful in 16s
TruffleHog Secret Scan / TruffleHog (pull_request) Successful in 16s
Security Scans / Trivy & OSV-Scanner (pull_request) Successful in 26s
Unit-Tests / Unit-Tests (pull_request) Successful in 38s
Die bisherige Abfrage GET /api/v1/packages/{owner}?limit=50 listete
alle Pakete des Owners ungefiltert (inkl. Docker-Image-Tags aus
main.yaml/testing.yaml), ohne Pagination. Dadurch konnte die
tatsaechlich relevante Paket-Version verdraengt werden, das Skript
hielt eine bereits genutzte Build-Nummer faelschlich fuer frei, und
der anschliessende Registry-Upload schlug mit 409 (Datei existiert
bereits) fehl - beobachtet beim RPM-Upload.

Fragt jetzt stattdessen gezielt pro Paket-Typ (debian/rpm/arch) die
Latest-Version ab (GET .../{type}/{name}/-/latest, ein Request ohne
Pagination). Alle drei Ergebnisse fliessen weiterhin in dasselbe Set
ein, sodass die naechste Build-Nummer weiterhin als globales Maximum
ueber alle Typen hinweg berechnet wird - deb/rpm/arch bleiben also
mit einer gemeinsamen Nummer synchron, auch wenn ein frueherer Lauf
nur bei einem der Typen erfolgreich hochgeladen hat.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kh9v73QApBwJj96w6A8R55
2026-09-10 22:18:58 +02:00
DragonSlayer_14 e96e9dc46a Merge pull request 'Merge dev in testing: Fügt Unit-Test vor Merging in testing hinzu' (#17) from dev into testing
TruffleHog Secret Scan / TruffleHog (push) Successful in 16s
Security Scans / Trivy & OSV-Scanner (push) Successful in 27s
Testing Build, Publish & Preview Release / Build, Publish Packages (Testing) & Create Preview Release (push) Failing after 1m57s
Reviewed-on: #17
2026-09-10 18:56:57 +00:00
DragonSlayer_14andClaude Sonnet 5 b4d2e387da CI: pull_request-Types fuer Unit-Tests explizit gesetzt
Testing Build, Publish & Preview Release / Build, Publish Packages (Testing) & Create Preview Release (push) Skipped
TruffleHog Secret Scan / TruffleHog (push) Successful in 12s
Security Scans / Trivy & OSV-Scanner (push) Successful in 18s
TruffleHog Secret Scan / TruffleHog (pull_request) Successful in 16s
Security Scans / Trivy & OSV-Scanner (pull_request) Successful in 28s
Unit-Tests / Unit-Tests (pull_request) Successful in 38s
types: opened/synchronize/reopened explizit eingetragen, damit der
Workflow sicher auch bei neuen Commits auf einem offenen PR
(synchronize) erneut laeuft, statt sich auf ein nicht dokumentiertes
Gitea-Actions-Default zu verlassen.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kh9v73QApBwJj96w6A8R55
2026-09-10 20:50:48 +02:00
DragonSlayer_14andClaude Sonnet 5 e8820fde59 CI: Unit-Tests bei PRs nach testing hinzugefuegt
Testing Build, Publish & Preview Release / Build, Publish Packages (Testing) & Create Preview Release (push) Skipped
TruffleHog Secret Scan / TruffleHog (push) Successful in 11s
Security Scans / Trivy & OSV-Scanner (push) Successful in 18s
Neuer Workflow, der bei jedem PR mit Ziel-Branch testing
cargo test ausfuehrt. Nutzt denselben Cargo-Cache-Key wie
main.yaml/testing.yaml, damit sich der Cache zwischen den
Workflows teilen laesst.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kh9v73QApBwJj96w6A8R55
2026-09-10 20:41:10 +02:00
DragonSlayer_14andClaude Sonnet 5 906aa81c6c CI: Packaging-Tools & Rustup-Cross-Targets gepinnt und gecacht
Testing Build, Publish & Preview Release / Build, Publish Packages (Testing) & Create Preview Release (push) Skipped
TruffleHog Secret Scan / TruffleHog (push) Successful in 11s
Security Scans / Trivy & OSV-Scanner (push) Successful in 17s
- cargo-binstall/cargo-deb/cargo-generate-rpm auf feste Versionen
  gepinnt (vorher "latest", nicht reproduzierbar) und ~/.cargo/bin
  versionsbasiert gecacht
- rustup target add fuer aarch64/i686 in eigenen Schritt ausgelagert
  und ~/.rustup/.../lib/rustlib/<target> gecacht, Cache-Key basiert
  auf der aufgeloesten rustc-Version (nicht auf dem gleitenden
  "stable"-Label), damit bei einem Rust-Update kein veralteter
  Cache mit neuerem Compiler gemischt wird
- x86_64-unknown-linux-gnu aus rustup target add entfernt (Host-
  Target, war bereits Teil der stable-Toolchain, No-Op)
- drei neue customManagers-Eintraege in renovate.json fuer
  cargo-binstall (github-releases) sowie cargo-deb/cargo-generate-rpm
  (crates.io), damit Renovate die gepinnten Versionen aktuell haelt

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kh9v73QApBwJj96w6A8R55
2026-09-10 20:25:50 +02:00
DragonSlayer_14 9855f91adf Feat: Badges für Main- und Testing-Workflows zum README hinzugefügt
TruffleHog Secret Scan / TruffleHog (push) Successful in 18s
Security Scans / Trivy & OSV-Scanner (push) Successful in 29s
2026-09-10 20:14:35 +02:00
DragonSlayer_14 7821dc40be Merge pull request 'Merge dev in testing: Erweitert Workflow-Skripte um Vulnverability und Dependency-Scanning' (#16) from dev into testing
Security Scans / Trivy & OSV-Scanner (push) Successful in 27s
TruffleHog Secret Scan / TruffleHog (push) Successful in 11s
Testing Build, Publish & Preview Release / Build, Publish Packages (Testing) & Create Preview Release (push) Successful in 10m52s
Reviewed-on: #16
2026-09-10 18:12:47 +00:00
DragonSlayer_14 b540663579 Merge remote-tracking branch 'origin/dev' into dev
TruffleHog Secret Scan / TruffleHog (pull_request) Successful in 22s
TruffleHog Secret Scan / TruffleHog (push) Successful in 23s
Security Scans / Trivy & OSV-Scanner (pull_request) Successful in 32s
Security Scans / Trivy & OSV-Scanner (push) Successful in 32s
2026-09-10 20:11:51 +02:00
DragonSlayer_14 b14e880b4b Merge branch 'main' into dev 2026-09-10 20:11:22 +02:00
DragonSlayer_14 432cad90dc Merge branch 'testing' into dev
TruffleHog Secret Scan / TruffleHog (pull_request) Successful in 21s
TruffleHog Secret Scan / TruffleHog (push) Successful in 23s
Security Scans / Trivy & OSV-Scanner (pull_request) Successful in 32s
Security Scans / Trivy & OSV-Scanner (push) Successful in 34s
2026-09-10 18:10:37 +00:00
DragonSlayer_14 1b9a290260 Feat: Hebt Version auf 1.0.3 an
TruffleHog Secret Scan / TruffleHog (push) Successful in 11s
Security Scans / Trivy & OSV-Scanner (push) Successful in 18s
TruffleHog Secret Scan / TruffleHog (pull_request) Successful in 12s
Security Scans / Trivy & OSV-Scanner (pull_request) Successful in 17s
2026-09-10 20:07:40 +02:00
DragonSlayer_14andClaude Sonnet 5 ea1530680c CI: actions/cache@v6 fuer Cargo- und Scanner-Binaries ergaenzt
TruffleHog Secret Scan / TruffleHog (push) Successful in 14s
Security Scans / Trivy & OSV-Scanner (push) Successful in 27s
- main.yaml/testing.yaml: Cargo-Registry & target/ ueber Cargo.lock-Hash
  gecacht (groesster Zeitfresser bei 3 Cross-Compile-Targets)
- security-scan.yaml: Trivy- und OSV-Scanner-Binary versionsbasiert
  gecacht, zusaetzlich Trivy-Vulnerability-DB tagesbasiert gecacht
  (sonst voller OCI-Download bei jedem Lauf)
- trufflehog-scan.yaml: TruffleHog-Binary versionsbasiert gecacht

Installation aller drei Scanner-Binaries von sudo-basiertem
/usr/local/bin auf $HOME/.local/bin umgestellt, da actions/cache
sonst ohne sudo nicht zuverlaessig in root-Verzeichnisse restoren
kann. TRIVY_VERSION/OSV_SCANNER_VERSION/TRUFFLEHOG_VERSION dafuer auf
Job-Ebene verschoben (Cache-Steps brauchen sie fuer den Cache-Key);
die Renovate-customManagers-Regexe matchen weiterhin, da sie auf dem
rohen Dateitext arbeiten statt auf der YAML-Struktur.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kh9v73QApBwJj96w6A8R55
2026-09-10 20:03:36 +02:00
DragonSlayer_14 072bde05e1 Feat: Zeitplan des TruffleHog-Scans um eine Stunde nach hinten verschoben (Cron "0 5 * * 1" → "0 6 * * 1"). 2026-09-10 19:53:41 +02:00
DragonSlayer_14andClaude Sonnet 5 b3ada88288 Renovate: PRs nur noch gegen dev statt Default-Branch
baseBranches auf dev eingeschraenkt, passend zum bestehenden
dev -> testing -> main Promotion-Flow. Renovate liest Dependency-
Dateien jetzt direkt von dev und oeffnet PRs nur dort; main/testing
werden nicht separat gescannt. Die renovate.json selbst muss laut
Renovate-Doku trotzdem ueber den Gitea-Default-Branch (main)
gefunden werden koennen.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kh9v73QApBwJj96w6A8R55
2026-09-10 19:51:48 +02:00
DragonSlayer_14andClaude Sonnet 5 a91e76b3e1 Renovate: Gruppierung auf Actions/Cargo/Docker umgestellt
- Actions-Gruppe jetzt dateibasiert (matchFileNames statt
  matchManagers), da die Custom-Regex-Manager für Trivy/OSV-Scanner/
  TruffleHog als Manager-Typ "regex" laufen und von
  matchManagers: ["github-actions"] nicht erfasst wurden
- Neue eigene Gruppe für alle Cargo-Dependencies
- separateMajorMinor/separateMinorPatch in allen drei Gruppen
  deaktiviert, sonst reisst Renovate Major-Updates trotz groupName
  standardmaessig in einen eigenen PR

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kh9v73QApBwJj96w6A8R55
2026-09-10 19:42:12 +02:00
DragonSlayer_14andClaude Sonnet 5 f1c261ebdd Fix: Versions-Tracking für Trivy/OSV-Scanner/TruffleHog & Renovate-Update
- Trivy 0.70.0 -> 0.74.0, Renovate-Container 43.279.0 -> 44.79.2
  (OSV-Scanner und TruffleHog waren bereits aktuell)
- OSV-Scanner- und TruffleHog-Versionen in Env-Vars ausgelagert
  (TruffleHog nutzte die Version zuvor zweimal im String, das
  verhinderte einen sauberen Regex-Match)
- Neuer customManagers-Regex-Block in renovate.json, da die drei
  Scanner-Versionen als curl-Strings in run-Blöcken stecken und vom
  github-actions-Manager (nur uses:/container:/services:) nicht
  erfasst werden

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kh9v73QApBwJj96w6A8R55
2026-09-10 19:38:49 +02:00
DragonSlayer_14andClaude Sonnet 5 186251e21a Fix: Trivy manuell via curl installieren statt trivy-action/setup-trivy
setup-trivy's Install-Step macht immer einen git clone von
aquasecurity/trivy gegen github.com, unabhängig vom Cache-Status. Das
scheitert im Gitea act_runner mit "could not read Username for
'https://github.com'", da der Git-Smart-HTTP-Handshake blockiert wird.
Plain curl-Downloads von GitHub-Release-Assets funktionieren dagegen
(siehe OSV-Scanner-Step), daher wird Trivy jetzt genauso installiert.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kh9v73QApBwJj96w6A8R55
2026-09-10 19:28:40 +02:00
DragonSlayer_14andClaude Sonnet 5 eac398a73e Revert: Trivy-Workflow wieder auf trivy-action ohne Workarounds
TruffleHog Secret Scan / TruffleHog (push) Successful in 8s
Security Scans / Trivy & OSV-Scanner (push) Failing after 34s
Manueller Install und token-setup-trivy-Override haben unter dem
Gitea act_runner beide nicht wie erwartet funktioniert. Zurück auf
den ursprünglichen Aufbau mit trivy-action@v0.36.0 pur.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FKMjR9pBxshZYZdhKyT5Ky
2026-09-10 00:20:38 +02:00
DragonSlayer_14andClaude Sonnet 5 50a093afcf Fix: Trivy manuell installieren statt setup-trivy (Gitea act_runner Bug)
TruffleHog Secret Scan / TruffleHog (push) Successful in 10s
Security Scans / Trivy & OSV-Scanner (push) Successful in 22s
Der vorherige Fix (token-setup-trivy: "") schlug fehl: der act_runner
wertet einen leeren String-Input offenbar als "nicht angegeben", statt
ihn als expliziten leeren Wert an actions/checkout durchzureichen -
dessen eigener required-Input "token" fehlt dadurch komplett und der
Schritt bricht ab ("Input required and not supplied: token").

Damit lässt sich der git-basierte Installationsweg von setup-trivy
(Checkout von github.com/aquasecurity/trivy) nicht zuverlässig unter
Gitea nutzen. Trivy wird jetzt wie schon TruffleHog per curl direkt
von den GitHub-Releases installiert, trivy-action überspringt die
eigene Installation via skip-setup-trivy und nutzt nur noch die
Scan-Funktionalität.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FKMjR9pBxshZYZdhKyT5Ky
2026-09-10 00:15:27 +02:00
DragonSlayer_14 9800ddcfc4 Schema: Gitea-Workflow-Dateien für Security- und TruffleHog-Scans in JSON-Schema-Zuordnungen ergänzt 2026-09-10 00:13:01 +02:00
DragonSlayer_14andClaude Sonnet 5 90c9a20871 Fix: Trivy-Scan bricht ab, wenn Gitea-Actions-Cache nicht erreichbar ist
TruffleHog Secret Scan / TruffleHog (push) Successful in 9s
Security Scans / Trivy & OSV-Scanner (push) Failing after 11s
Bei Cache-Restore-Fehlschlag fällt setup-trivy auf einen Git-Checkout
von aquasecurity/trivy zurück, um das Install-Skript zu holen. Dabei
wird github.token als Auth-Token an github.com übergeben - unter Gitea
ist das aber der lokale Gitea-Runner-Token, der von GitHub abgelehnt
wird (401, danach Abbruch wegen deaktivierter Prompts). token-setup-trivy
leer lassen, damit der Fallback-Checkout anonym gegen das öffentliche
GitHub-Repo läuft.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FKMjR9pBxshZYZdhKyT5Ky
2026-09-10 00:12:07 +02:00
DragonSlayer_14andClaude Sonnet 5 134d3048cf Fix: Security-Scan-Report robuster gemacht & TruffleHog läuft bei jedem Push
Security Scans / Trivy & OSV-Scanner (push) Failing after 5m27s
TruffleHog Secret Scan / TruffleHog (push) Successful in 7s
- OSV-Scanner-Funde erhalten jetzt eine echte Severity (aus CVSS-Score
  der Gruppen abgeleitet) statt hartcodiert "-", damit kritische Funde
  nicht unten in der Tabelle verschwinden
- Unerwartete Exit-Codes von osv-scanner/trufflehog gelten jetzt als
  Fehlschlag statt stillschweigend als "keine Funde"
- Timeout für Gitea-API-Requests ergänzt
- Label-Suche paginiert jetzt vollständig statt nur die ersten 50
- Markdown-Tabellenzellen werden escaped (Pipe/Zeilenumbruch)
- Doppeltes Sortieren der Findings entfernt, Dict-Aufbau der Loader
  über gemeinsamen Helper vereinheitlicht
- trufflehog-scan.yaml läuft nun bei jedem Push, nicht nur auf
  main/testing/dev

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FKMjR9pBxshZYZdhKyT5Ky
2026-09-09 23:00:41 +02:00
DragonSlayer_14andClaude Sonnet 5 9445a82b53 Feat: TruffleHog-Secret-Scan als eigene Gitea-Action hinzugefügt
- Neuer Workflow trufflehog-scan.yaml scannt die komplette Git-Historie und
  meldet Funde in ein eigenes Issue (Label security-scan-trufflehog), getrennt
  vom Trivy/OSV-Issue, aber ebenfalls über SECURITY_TOKEN
- report-security-issue.py: Titel/Label per ISSUE_TITLE/ISSUE_LABEL
  konfigurierbar, TruffleHog-JSONL-Parsing (ohne Secret-Wert im Report),
  Workflow schlägt bei verifizierten Funden fehl
- Rotations-Anleitung wird automatisch an Issues mit TruffleHog-Funden angehängt

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FKMjR9pBxshZYZdhKyT5Ky
2026-09-09 22:43:30 +02:00
DragonSlayer_14andClaude Sonnet 5 f56a5c71ab Feat: Gitea-Action für Security-Scans mit Trivy & OSV-Scanner hinzugefügt
- Trivy (fs-Scan: vuln, secret, misconfig) und OSV-Scanner (Cargo.lock)
  laufen als FOSS-Tools ohne Anmeldedaten
- Bei Funden wird automatisch ein Gitea-Issue (Label security-scan)
  erstellt bzw. bei jedem weiteren Lauf per Kommentar aktualisiert,
  solange es offen ist; nach Funden wird nicht automatisch geschlossen

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FKMjR9pBxshZYZdhKyT5Ky
2026-09-09 22:24:14 +02:00
DragonSlayer_14andClaude Sonnet 5 9a59fff032 Feat: Renovate für automatische Dependency-Updates eingerichtet
- renovate.json mit Zeitplan und Gruppierung für Gitea Actions und Docker-Images
- Gitea-Workflow zur wöchentlichen Ausführung von Renovate hinzugefügt
- Workflow-Datei in IDEA JSON-Schema-Zuordnungen registriert

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FKMjR9pBxshZYZdhKyT5Ky
2026-09-09 21:54:28 +02:00
DragonSlayer_14 d9089afdc9 Feat: IDEA-Run-Konfiguration für Cargo hinzugefügt
- Standard-Konfiguration für `cargo run` mit Dev-Profil
- Terminal-Emulation und Projektverzeichnis als Arbeitsordner
2026-09-09 20:43:19 +02:00
DragonSlayer_14 59a81773cc Fix: Abhängigkeit serde_json entfernt (bereits über serde abgedeckt) 2026-09-09 20:43:03 +02:00
DragonSlayer_14 f7957ab9f5 Fix: .junie/plans-Ordner von IDEA-Indexierung ausgeschlossen 2026-09-09 20:42:46 +02:00
DragonSlayer_14 0840f93d0d Merge pull request 'Merge dev in main: Release 1.0.2' (#15) from dev into main
Main Release & Publish / Build, Publish Packages (Stable) & Create Release (push) Successful in 9m43s
Reviewed-on: #15
2026-09-09 18:08:29 +00:00
28 changed files with 1405 additions and 140 deletions
+54
View File
@@ -0,0 +1,54 @@
name: Code Quality (Auto-Format & Clippy-Fix)
on:
push:
branches:
- dev
workflow_dispatch:
jobs:
fix:
name: Formatierung & Clippy automatisch beheben
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v7
with:
ref: ${{ gitea.ref_name || github.ref_name }}
token: ${{ secrets.PACKAGE_TOKEN || secrets.RELEASE_TOKEN || secrets.PUBLISH_TOKEN || secrets.API_TOKEN || secrets.PAT_TOKEN || secrets.CUSTOM_TOKEN || secrets.GITEA_TOKEN || secrets.GITHUB_TOKEN || github.token }}
- name: Install Rust Toolchain
uses: actions-rust-lang/setup-rust-toolchain@v2
with:
toolchain: stable
components: clippy, rustfmt
cache: false
- name: Cache Cargo-Abhängigkeiten & Build-Artefakte
uses: actions/cache@v6
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: cargo-${{ runner.os }}-${{ hashFiles('Cargo.lock') }}
restore-keys: |
cargo-${{ runner.os }}-
- name: Formatierung automatisch beheben
run: cargo fmt
- name: Clippy-Fixes automatisch anwenden
run: cargo clippy --fix --allow-dirty --allow-staged --all-targets
- name: Änderungen committen & pushen
run: |
if [ -n "$(git status --porcelain)" ]; then
git config user.name "Gitea-Bot"
git config user.email "no-reply@creativedragonslayer.de"
git add -A
git commit -m "Style: Automatische Formatierung & Clippy-Fixes"
git push origin HEAD:${{ gitea.ref_name || github.ref_name }}
else
echo "Keine Formatierungs- oder Clippy-Änderungen."
fi
+79 -7
View File
@@ -6,31 +6,103 @@ on:
- main
jobs:
detect-changes:
name: Erkenne relevante Code-Änderungen
runs-on: ubuntu-latest
outputs:
code_changed: ${{ steps.filter.outputs.code }}
steps:
- name: Checkout Repository
uses: actions/checkout@v7
- name: Prüfe auf Änderungen am Programmcode
uses: dorny/paths-filter@v4
id: filter
with:
filters: |
code:
- 'src/**'
- 'Cargo.toml'
- 'Cargo.lock'
- 'scripts/**'
- '.cargo/**'
- 'Dockerfile'
- '.gitea/workflows/main.yaml'
release-and-publish:
name: Build, Publish Packages (Stable) & Create Release
needs: detect-changes
if: needs.detect-changes.outputs.code_changed == 'true'
runs-on: ubuntu-latest
env:
CARGO_BINSTALL_VERSION: "1.23.0"
CARGO_DEB_VERSION: "3.8.0"
CARGO_GENERATE_RPM_VERSION: "0.21.0"
steps:
- name: Checkout Repository
uses: actions/checkout@v7
- name: Install Rust Toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
uses: actions-rust-lang/setup-rust-toolchain@v2
with:
toolchain: stable
cache: false
- name: Install Cross-Compilation Toolchains & Dependencies
- name: Cache Cargo-Abhängigkeiten & Build-Artefakte
uses: actions/cache@v6
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: cargo-${{ runner.os }}-${{ hashFiles('Cargo.lock') }}
restore-keys: |
cargo-${{ runner.os }}-
- name: Alte Paketierungs-Ausgaben aus dem Cache entfernen
run: rm -rf target/debian target/generate-rpm target/arch
- name: Install Cross-Compilation Toolchains (apt)
run: |
sudo apt-get update
sudo apt-get install -y gcc-aarch64-linux-gnu gcc-i686-linux-gnu
rustup target add x86_64-unknown-linux-gnu aarch64-unknown-linux-gnu i686-unknown-linux-gnu
- name: Install Packaging Tools (Prebuilt Binaries)
- name: Ermittle Rust-Version für Rustup-Target-Cache-Key
run: echo "RUST_VERSION=$(rustc --version | awk '{print $2}')" >> "$GITHUB_ENV"
- name: Cache Rustup Cross-Compilation-Targets
id: cache-rustup-targets
uses: actions/cache@v6
with:
path: |
~/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/aarch64-unknown-linux-gnu
~/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/i686-unknown-linux-gnu
key: rustup-targets-${{ runner.os }}-${{ env.RUST_VERSION }}
- name: Add Rust Cross-Compilation Targets
if: steps.cache-rustup-targets.outputs.cache-hit != 'true'
run: rustup target add aarch64-unknown-linux-gnu i686-unknown-linux-gnu
- name: PATH um Cargo-bin-Verzeichnis ergänzen
run: |
mkdir -p ~/.cargo/bin
curl -fsSL https://github.com/cargo-bins/cargo-binstall/releases/latest/download/cargo-binstall-x86_64-unknown-linux-musl.tgz | tar -xz -C ~/.cargo/bin
echo "$HOME/.cargo/bin" >> $GITHUB_PATH
~/.cargo/bin/cargo-binstall -y --no-symlinks cargo-deb cargo-generate-rpm
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
- name: Cache Packaging-Tools (cargo-binstall, cargo-deb, cargo-generate-rpm)
id: cache-packaging-tools
uses: actions/cache@v6
with:
path: |
~/.cargo/bin/cargo-binstall
~/.cargo/bin/cargo-deb
~/.cargo/bin/cargo-generate-rpm
key: packaging-tools-${{ runner.os }}-${{ env.CARGO_BINSTALL_VERSION }}-${{ env.CARGO_DEB_VERSION }}-${{ env.CARGO_GENERATE_RPM_VERSION }}
- name: Install Packaging Tools (Prebuilt Binaries)
if: steps.cache-packaging-tools.outputs.cache-hit != 'true'
run: |
curl -fsSL "https://github.com/cargo-bins/cargo-binstall/releases/download/v${CARGO_BINSTALL_VERSION}/cargo-binstall-x86_64-unknown-linux-musl.tgz" | tar -xz -C ~/.cargo/bin
~/.cargo/bin/cargo-binstall -y --no-symlinks "cargo-deb@${CARGO_DEB_VERSION}" "cargo-generate-rpm@${CARGO_GENERATE_RPM_VERSION}"
- name: Run Tests
run: |
+27
View File
@@ -0,0 +1,27 @@
name: Renovate
on:
schedule:
- cron: "0 * * * *"
workflow_dispatch:
jobs:
renovate:
name: Dependency-Updates prüfen & Pull Requests erstellen
runs-on: ubuntu-latest
container: ghcr.io/renovatebot/renovate:44.83.0
steps:
- name: Renovate ausführen
run: renovate
env:
RENOVATE_PLATFORM: gitea
RENOVATE_ENDPOINT: ${{ gitea.server_url || github.server_url }}/api/v1/
RENOVATE_TOKEN: ${{ secrets.RENOVATE_TOKEN }}
RENOVATE_REPOSITORIES: ${{ gitea.repository || github.repository }}
RENOVATE_AUTODISCOVER: "false"
RENOVATE_ALLOW_CUSTOM_CRATE_REGISTRIES: "true"
RENOVATE_GIT_AUTHOR: "Renovate Bot <renovate-bot@creativedragonslayer.de>"
RENOVATE_HOST_RULES: >-
[{"hostType":"cargo","matchHost":"${{ gitea.server_url || github.server_url }}","token":"${{ secrets.RENOVATE_TOKEN }}"}]
GITHUB_COM_TOKEN: ${{ secrets.GH_RENOVATE_TOKEN }}
LOG_LEVEL: info
+95
View File
@@ -0,0 +1,95 @@
name: Security Scans
on:
push:
branches:
- main
- testing
- dev
pull_request:
schedule:
- cron: "0 5 * * 1"
workflow_dispatch:
jobs:
security-scan:
name: Trivy & OSV-Scanner
runs-on: ubuntu-latest
env:
TRIVY_VERSION: "0.74.0"
OSV_SCANNER_VERSION: "2.5.1"
steps:
- name: Checkout Repository
uses: actions/checkout@v7
- name: Lokales bin-Verzeichnis zum PATH hinzufügen
run: |
mkdir -p "$HOME/.local/bin"
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
- name: Cache Trivy-Binary
id: cache-trivy
uses: actions/cache@v6
with:
path: ~/.local/bin/trivy
key: trivy-bin-${{ runner.os }}-${{ env.TRIVY_VERSION }}
- name: Install Trivy
if: steps.cache-trivy.outputs.cache-hit != 'true'
run: |
curl -fsSL -o trivy.tar.gz \
"https://github.com/aquasecurity/trivy/releases/download/v${TRIVY_VERSION}/trivy_${TRIVY_VERSION}_Linux-64bit.tar.gz"
tar -xzf trivy.tar.gz trivy
chmod +x trivy
mv trivy "$HOME/.local/bin/trivy"
rm -f trivy.tar.gz
- name: Ermittle Cache-Datum für Trivy-DB
run: echo "CACHE_DATE=$(date -u +%Y-%m-%d)" >> "$GITHUB_ENV"
- name: Cache Trivy-Schwachstellen-Datenbank
uses: actions/cache@v6
with:
path: ~/.cache/trivy
key: trivy-db-${{ runner.os }}-${{ env.CACHE_DATE }}
restore-keys: |
trivy-db-${{ runner.os }}-
- name: Run Trivy Scanner
run: |
trivy fs \
--scanners vuln,secret,misconfig \
--severity CRITICAL,HIGH \
--format json \
--output trivy-results.json \
--exit-code 0 \
.
- name: Cache OSV-Scanner-Binary
id: cache-osv-scanner
uses: actions/cache@v6
with:
path: ~/.local/bin/osv-scanner
key: osv-scanner-bin-${{ runner.os }}-${{ env.OSV_SCANNER_VERSION }}
- name: Install OSV-Scanner
if: steps.cache-osv-scanner.outputs.cache-hit != 'true'
run: |
curl -fsSL -o "$HOME/.local/bin/osv-scanner" \
"https://github.com/google/osv-scanner/releases/download/v${OSV_SCANNER_VERSION}/osv-scanner_linux_amd64"
chmod +x "$HOME/.local/bin/osv-scanner"
- name: Run OSV-Scanner
run: |
set +e
osv-scanner scan source --recursive --format json --output-file osv-results.json .
echo "OSV_EXIT=$?" >> "$GITHUB_ENV"
- name: Ergebnisse & Gitea-Issue erstellen/aktualisieren
env:
GITEA_URL: ${{ gitea.server_url || github.server_url }}
REPO: ${{ gitea.repository || github.repository }}
TOKEN: ${{ secrets.SECURITY_TOKEN }}
RUN_URL: ${{ gitea.server_url || github.server_url }}/${{ gitea.repository || github.repository }}/actions/runs/${{ gitea.run_id || github.run_id }}
run: |
python3 scripts/report-security-issue.py trivy-results.json osv-results.json
+111
View File
@@ -0,0 +1,111 @@
name: Auto-PR (Testing → Main)
on:
push:
branches:
- testing
jobs:
create-pr:
name: Erstelle automatisch PR von testing nach main
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Prüfe auf bereits offenen PR nach main
id: check_pr
env:
GITEA_URL: ${{ gitea.server_url || github.server_url }}
REPO: ${{ gitea.repository || github.repository }}
TOKEN: ${{ secrets.PACKAGE_TOKEN || secrets.RELEASE_TOKEN || secrets.PUBLISH_TOKEN || secrets.API_TOKEN || secrets.PAT_TOKEN || secrets.CUSTOM_TOKEN || secrets.GITEA_TOKEN || secrets.GITHUB_TOKEN || github.token }}
run: |
OPEN_PRS=$(curl -s -H "Authorization: token ${TOKEN}" "${GITEA_URL}/api/v1/repos/${REPO}/pulls?state=open&limit=50")
EXISTS=$(echo "$OPEN_PRS" | jq -r '[.[] | select(.base.ref == "main" and .head.ref == "testing")] | length')
echo "Bereits offene testing→main PRs: ${EXISTS}"
echo "exists=${EXISTS}" >> "$GITHUB_OUTPUT"
- name: Ermittle Versionen auf main & testing
id: versions
if: steps.check_pr.outputs.exists == '0'
run: |
git fetch origin main
MAIN_VERSION="$(git show origin/main:Cargo.toml | sed -n 's/^version = "\(.*\)"/\1/p' | head -n1)"
TESTING_VERSION="$(sed -n 's/^version = "\(.*\)"/\1/p' Cargo.toml | head -n1)"
echo "Version auf main: ${MAIN_VERSION} / Version auf testing: ${TESTING_VERSION}"
echo "main_version=${MAIN_VERSION}" >> "$GITHUB_OUTPUT"
echo "testing_version=${TESTING_VERSION}" >> "$GITHUB_OUTPUT"
- name: Ermittle geänderte Kategorien (main...testing)
id: categories
if: steps.check_pr.outputs.exists == '0' && steps.versions.outputs.main_version == steps.versions.outputs.testing_version
run: |
CHANGED_FILES="$(git diff --name-only origin/main...HEAD)"
echo "Geänderte Dateien main...testing:"
echo "$CHANGED_FILES"
WORKFLOWS="false"
CONFIG="false"
DOCS="false"
if echo "$CHANGED_FILES" | grep -q '^\.gitea/workflows/'; then
WORKFLOWS="true"
fi
if echo "$CHANGED_FILES" | grep -qE '^(renovate\.json|qodana\.yaml|Cargo\.toml|Cargo\.lock|\.cargo/)'; then
CONFIG="true"
fi
if echo "$CHANGED_FILES" | grep -qE '(^|/)[^/]+\.md$|^LICENSE$'; then
DOCS="true"
fi
echo "workflows=${WORKFLOWS}" >> "$GITHUB_OUTPUT"
echo "config=${CONFIG}" >> "$GITHUB_OUTPUT"
echo "docs=${DOCS}" >> "$GITHUB_OUTPUT"
- name: Bestimme PR-Titel
id: title
if: steps.check_pr.outputs.exists == '0'
run: |
if [ "${{ steps.versions.outputs.main_version }}" != "${{ steps.versions.outputs.testing_version }}" ]; then
TITLE="Merge testing in main: Release ${{ steps.versions.outputs.testing_version }}"
else
PARTS=()
[ "${{ steps.categories.outputs.workflows }}" = "true" ] && PARTS+=("Workflows")
[ "${{ steps.categories.outputs.config }}" = "true" ] && PARTS+=("Konfigurationen")
[ "${{ steps.categories.outputs.docs }}" = "true" ] && PARTS+=("Dokumentation")
if [ ${#PARTS[@]} -eq 0 ]; then
TITLE="Merge testing in main"
else
JOINED=""
for PART in "${PARTS[@]}"; do
if [ -z "$JOINED" ]; then
JOINED="$PART"
else
JOINED="${JOINED} & ${PART}"
fi
done
TITLE="Merge testing in main: ${JOINED} aktualisiert"
fi
fi
echo "Ermittelter PR-Titel: ${TITLE}"
echo "title=${TITLE}" >> "$GITHUB_OUTPUT"
- name: Erstelle PR (testing -> main)
if: steps.check_pr.outputs.exists == '0'
env:
GITEA_URL: ${{ gitea.server_url || github.server_url }}
REPO: ${{ gitea.repository || github.repository }}
TOKEN: ${{ secrets.PACKAGE_TOKEN || secrets.RELEASE_TOKEN || secrets.PUBLISH_TOKEN || secrets.API_TOKEN || secrets.PAT_TOKEN || secrets.CUSTOM_TOKEN || secrets.GITEA_TOKEN || secrets.GITHUB_TOKEN || github.token }}
TITLE: ${{ steps.title.outputs.title }}
run: |
PAYLOAD=$(jq -n --arg title "$TITLE" --arg head "testing" --arg base "main" \
'{title: $title, head: $head, base: $base}')
curl -f -s -S -X POST \
-H "Authorization: token ${TOKEN}" \
-H "Content-Type: application/json" \
-d "$PAYLOAD" \
"${GITEA_URL}/api/v1/repos/${REPO}/pulls"
echo "PR erstellt: ${TITLE}"
+79 -7
View File
@@ -6,31 +6,103 @@ on:
- testing
jobs:
detect-changes:
name: Erkenne relevante Code-Änderungen
runs-on: ubuntu-latest
outputs:
code_changed: ${{ steps.filter.outputs.code }}
steps:
- name: Checkout Repository
uses: actions/checkout@v7
- name: Prüfe auf Änderungen am Programmcode
uses: dorny/paths-filter@v4
id: filter
with:
filters: |
code:
- 'src/**'
- 'Cargo.toml'
- 'Cargo.lock'
- 'scripts/**'
- '.cargo/**'
- 'Dockerfile'
- '.gitea/workflows/testing.yaml'
build-and-publish:
name: Build, Publish Packages (Testing) & Create Preview Release
needs: detect-changes
if: needs.detect-changes.outputs.code_changed == 'true'
runs-on: ubuntu-latest
env:
CARGO_BINSTALL_VERSION: "1.23.0"
CARGO_DEB_VERSION: "3.8.0"
CARGO_GENERATE_RPM_VERSION: "0.21.0"
steps:
- name: Checkout Repository
uses: actions/checkout@v7
- name: Install Rust Toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
uses: actions-rust-lang/setup-rust-toolchain@v2
with:
toolchain: stable
cache: false
- name: Install Cross-Compilation Toolchains & Dependencies
- name: Cache Cargo-Abhängigkeiten & Build-Artefakte
uses: actions/cache@v6
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: cargo-${{ runner.os }}-${{ hashFiles('Cargo.lock') }}
restore-keys: |
cargo-${{ runner.os }}-
- name: Alte Paketierungs-Ausgaben aus dem Cache entfernen
run: rm -rf target/debian target/generate-rpm target/arch
- name: Install Cross-Compilation Toolchains (apt)
run: |
sudo apt-get update
sudo apt-get install -y gcc-aarch64-linux-gnu gcc-i686-linux-gnu
rustup target add x86_64-unknown-linux-gnu aarch64-unknown-linux-gnu i686-unknown-linux-gnu
- name: Install Packaging Tools (Prebuilt Binaries)
- name: Ermittle Rust-Version für Rustup-Target-Cache-Key
run: echo "RUST_VERSION=$(rustc --version | awk '{print $2}')" >> "$GITHUB_ENV"
- name: Cache Rustup Cross-Compilation-Targets
id: cache-rustup-targets
uses: actions/cache@v6
with:
path: |
~/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/aarch64-unknown-linux-gnu
~/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/i686-unknown-linux-gnu
key: rustup-targets-${{ runner.os }}-${{ env.RUST_VERSION }}
- name: Add Rust Cross-Compilation Targets
if: steps.cache-rustup-targets.outputs.cache-hit != 'true'
run: rustup target add aarch64-unknown-linux-gnu i686-unknown-linux-gnu
- name: PATH um Cargo-bin-Verzeichnis ergänzen
run: |
mkdir -p ~/.cargo/bin
curl -fsSL https://github.com/cargo-bins/cargo-binstall/releases/latest/download/cargo-binstall-x86_64-unknown-linux-musl.tgz | tar -xz -C ~/.cargo/bin
echo "$HOME/.cargo/bin" >> $GITHUB_PATH
~/.cargo/bin/cargo-binstall -y --no-symlinks cargo-deb cargo-generate-rpm
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
- name: Cache Packaging-Tools (cargo-binstall, cargo-deb, cargo-generate-rpm)
id: cache-packaging-tools
uses: actions/cache@v6
with:
path: |
~/.cargo/bin/cargo-binstall
~/.cargo/bin/cargo-deb
~/.cargo/bin/cargo-generate-rpm
key: packaging-tools-${{ runner.os }}-${{ env.CARGO_BINSTALL_VERSION }}-${{ env.CARGO_DEB_VERSION }}-${{ env.CARGO_GENERATE_RPM_VERSION }}
- name: Install Packaging Tools (Prebuilt Binaries)
if: steps.cache-packaging-tools.outputs.cache-hit != 'true'
run: |
curl -fsSL "https://github.com/cargo-bins/cargo-binstall/releases/download/v${CARGO_BINSTALL_VERSION}/cargo-binstall-x86_64-unknown-linux-musl.tgz" | tar -xz -C ~/.cargo/bin
~/.cargo/bin/cargo-binstall -y --no-symlinks "cargo-deb@${CARGO_DEB_VERSION}" "cargo-generate-rpm@${CARGO_GENERATE_RPM_VERSION}"
- name: Run Tests
run: |
+59
View File
@@ -0,0 +1,59 @@
name: TruffleHog Secret Scan
on:
push:
pull_request:
schedule:
- cron: "0 6 * * 1"
workflow_dispatch:
jobs:
trufflehog-scan:
name: TruffleHog
runs-on: ubuntu-latest
env:
TRUFFLEHOG_VERSION: "3.97.4"
steps:
- name: Checkout Repository
uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Lokales bin-Verzeichnis zum PATH hinzufügen
run: |
mkdir -p "$HOME/.local/bin"
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
- name: Cache TruffleHog-Binary
id: cache-trufflehog
uses: actions/cache@v6
with:
path: ~/.local/bin/trufflehog
key: trufflehog-bin-${{ runner.os }}-${{ env.TRUFFLEHOG_VERSION }}
- name: Install TruffleHog
if: steps.cache-trufflehog.outputs.cache-hit != 'true'
run: |
curl -fsSL -o trufflehog.tar.gz \
"https://github.com/trufflesecurity/trufflehog/releases/download/v${TRUFFLEHOG_VERSION}/trufflehog_${TRUFFLEHOG_VERSION}_linux_amd64.tar.gz"
tar -xzf trufflehog.tar.gz trufflehog
chmod +x trufflehog
mv trufflehog "$HOME/.local/bin/trufflehog"
rm trufflehog.tar.gz
- name: Run TruffleHog Scanner
run: |
set +e
trufflehog git file://. --results=verified,unknown --fail --json > trufflehog-results.json
echo "TRUFFLEHOG_EXIT=$?" >> "$GITHUB_ENV"
- name: Ergebnisse & Gitea-Issue erstellen/aktualisieren
env:
GITEA_URL: ${{ gitea.server_url || github.server_url }}
REPO: ${{ gitea.repository || github.repository }}
TOKEN: ${{ secrets.SECURITY_TOKEN }}
RUN_URL: ${{ gitea.server_url || github.server_url }}/${{ gitea.repository || github.repository }}/actions/runs/${{ gitea.run_id || github.run_id }}
ISSUE_TITLE: "Security-Scan: TruffleHog Secrets"
ISSUE_LABEL: "security-scan-trufflehog"
run: |
python3 scripts/report-security-issue.py "" "" trufflehog-results.json
+38
View File
@@ -0,0 +1,38 @@
name: Unit-Tests
on:
pull_request:
types:
- opened
- synchronize
- reopened
branches:
- testing
jobs:
test:
name: Unit-Tests
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v7
- name: Install Rust Toolchain
uses: actions-rust-lang/setup-rust-toolchain@v2
with:
toolchain: stable
cache: false
- name: Cache Cargo-Abhängigkeiten & Build-Artefakte
uses: actions/cache@v6
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: cargo-${{ runner.os }}-${{ hashFiles('Cargo.lock') }}
restore-keys: |
cargo-${{ runner.os }}-
- name: Run Tests
run: cargo test
+85
View File
@@ -0,0 +1,85 @@
name: Auto Patch-Version-Bump (Dev → Testing PR)
on:
pull_request:
types: [opened]
branches:
- testing
jobs:
detect-changes:
name: Erkenne relevante Änderungen im PR
runs-on: ubuntu-latest
if: ${{ (gitea.head_ref || github.head_ref) == 'dev' }}
outputs:
code_changed: ${{ steps.filter.outputs.code }}
steps:
- name: Checkout Dev-Branch (PR-Head)
uses: actions/checkout@v7
with:
ref: ${{ gitea.head_ref || github.head_ref }}
fetch-depth: 0
- name: Prüfe auf Änderungen an Cargo.toml, Cargo.lock, src/ oder Dockerfile
uses: dorny/paths-filter@v4
id: filter
with:
base: ${{ gitea.base_ref || github.base_ref }}
filters: |
code:
- 'Cargo.toml'
- 'Cargo.lock'
- 'src/**'
- 'Dockerfile'
bump-version:
name: Patch-Version erhöhen & auf Dev pushen
needs: detect-changes
if: needs.detect-changes.outputs.code_changed == 'true'
runs-on: ubuntu-latest
steps:
- name: Checkout Dev-Branch (PR-Head)
uses: actions/checkout@v7
with:
ref: ${{ gitea.head_ref || github.head_ref }}
fetch-depth: 0
token: ${{ secrets.PACKAGE_TOKEN || secrets.RELEASE_TOKEN || secrets.PUBLISH_TOKEN || secrets.API_TOKEN || secrets.PAT_TOKEN || secrets.CUSTOM_TOKEN || secrets.GITEA_TOKEN || secrets.GITHUB_TOKEN || github.token }}
- name: Ermittle Cargo-Version auf testing & dev
id: versions
run: |
git fetch origin testing --depth=1
TESTING_VERSION="$(git show origin/testing:Cargo.toml | sed -n 's/^version = "\(.*\)"/\1/p' | head -n1)"
DEV_VERSION="$(sed -n 's/^version = "\(.*\)"/\1/p' Cargo.toml | head -n1)"
echo "Version auf testing: ${TESTING_VERSION} / Version auf dev: ${DEV_VERSION}"
echo "testing_version=${TESTING_VERSION}" >> "$GITHUB_OUTPUT"
echo "dev_version=${DEV_VERSION}" >> "$GITHUB_OUTPUT"
- name: Patch-Version um 1 erhöhen (Cargo.toml & Cargo.lock)
if: steps.versions.outputs.testing_version == steps.versions.outputs.dev_version
run: |
VERSION="${{ steps.versions.outputs.dev_version }}"
MAJOR="$(echo "$VERSION" | cut -d. -f1)"
MINOR="$(echo "$VERSION" | cut -d. -f2)"
PATCH="$(echo "$VERSION" | cut -d. -f3)"
NEW_VERSION="${MAJOR}.${MINOR}.$((PATCH + 1))"
echo "Erhöhe Version: ${VERSION} -> ${NEW_VERSION}"
sed -i "0,/^version = \"${VERSION}\"/s//version = \"${NEW_VERSION}\"/" Cargo.toml
PACKAGE_NAME="$(sed -n 's/^name = "\(.*\)"/\1/p' Cargo.toml | head -n1)"
awk -v new="$NEW_VERSION" -v pkg="$PACKAGE_NAME" '
found_name && /^version = "/ {
print "version = \"" new "\""
found_name = 0
next
}
$0 == "name = \"" pkg "\"" { found_name = 1 }
{ print }
' Cargo.lock > Cargo.lock.tmp && mv Cargo.lock.tmp Cargo.lock
git config user.name "Gitea-Bot"
git config user.email "no-reply@creativedragonslayer.de"
git add Cargo.toml Cargo.lock
git commit -m "Chore: Erhöht Patch-Version auf ${NEW_VERSION} für Promotion nach testing"
git push origin HEAD:${{ gitea.head_ref || github.head_ref }}
+1
View File
@@ -109,3 +109,4 @@ fabric.properties
# Built Visual Studio Code Extensions
*.vsix
.junie/plans
+12
View File
@@ -17,6 +17,18 @@
<Item>
<option name="path" value=".gitea/workflows/testing.yaml" />
</Item>
<Item>
<option name="path" value=".gitea/workflows/renovate.yaml" />
</Item>
<Item>
<option name="path" value=".gitea/workflows/security-scan.yaml" />
</Item>
<Item>
<option name="path" value=".gitea/workflows/trufflehog-scan.yaml" />
</Item>
<Item>
<option name="path" value=".gitea/workflows/code-quality.yaml" />
</Item>
</list>
</option>
</SchemaInfo>
+20
View File
@@ -0,0 +1,20 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Run" type="CargoCommandRunConfiguration" factoryName="Cargo Command" nameIsGenerated="true">
<option name="buildProfileId" value="dev" />
<option name="command" value="run" />
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
<envs />
<option name="emulateTerminal" value="true" />
<option name="channel" value="DEFAULT" />
<option name="requiredFeatures" value="true" />
<option name="allFeatures" value="false" />
<option name="withSudo" value="false" />
<option name="buildTarget" value="REMOTE" />
<option name="backtrace" value="SHORT" />
<option name="isRedirectInput" value="false" />
<option name="redirectInputPath" value="" />
<method v="2">
<option name="CARGO.BUILD_TASK_PROVIDER" enabled="true" />
</method>
</configuration>
</component>
+1
View File
@@ -4,6 +4,7 @@
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/.junie/plans" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
+38 -8
View File
@@ -31,8 +31,12 @@ Dieses Dokument dient als technischer Leitfaden und Kontextdokument für KI-Codi
│ └── config.toml # Linker für Cross-Target-Kompilierung & Registry-Konfiguration
├── .gitea/
│ └── workflows/
│ ├── main.yaml # CI/CD: Stabile Builds, Multi-Arch-Paketierung, Release & Upload
── testing.yaml # CI/CD: Preview-Builds & Testing-Pakete
│ ├── main.yaml # CI/CD: Stabile Builds, Multi-Arch-Paketierung, Release & Upload
── testing.yaml # CI/CD: Preview-Builds & Testing-Pakete
│ ├── unit-tests.yaml # CI: cargo test bei PRs mit Ziel-Branch testing
│ ├── security-scan.yaml # CI: Trivy (vuln/secret/misconfig) & OSV-Scanner
│ ├── trufflehog-scan.yaml # CI: TruffleHog Secret-Scanning
│ └── renovate.yaml # CI: Renovate Dependency-Updates (self-hosted, wöchentlich)
├── scripts/
│ ├── get-build-number.py # Ermittelt automatisch die nächste Revisions-/Build-Nummer
│ └── package-arch.py # Erzeugt native Arch Linux .pkg.tar.zst Pakete
@@ -52,6 +56,7 @@ Dieses Dokument dient als technischer Leitfaden und Kontextdokument für KI-Codi
├── Dockerfile # Minimales & gehärtetes Runtime-Container-Image
├── docker-compose.example.yml # Beispielkonfiguration für Docker Compose
├── Cargo.toml # Projekt-Manifest & Metadaten für deb, rpm und arch
├── renovate.json # Renovate-Konfiguration (baseBranches, Gruppierung, Custom-Manager)
├── LICENSE # Lizenztext
├── README.md # Benutzerdokumentation
└── AGENTS.md # Dieses Agenten-Handbuch
@@ -77,7 +82,7 @@ Bei Änderungen an Binärnamen, Abhängigkeiten oder Beschreibungen müssen die
- `pkgrel`, `arch`, `depends`, `optdepends`.
### 3.3 Skripte in `scripts/`
- **Generizität**: Die Skripte dürfen keine hardcodierten Anwendungsnamen, spezifischen Abhängigkeiten oder projektspezifischen URLs enthalten. Alle Werte müssen dynamisch aus `Cargo.toml` oder Umgebungsvariablen (`BUILD_NUMBER`, `GITEA_URL`, `REPO`, `TOKEN`) ermittelt werden.
- **Generizität**: Die Skripte dürfen keine hardcodierten Anwendungsnamen, spezifischen Abhängigkeiten oder projektspezifischen URLs enthalten. Alle Werte müssen dynamisch aus `Cargo.toml` oder Umgebungsvariablen (`BUILD_NUMBER`, `GITEA_URL`, `REPO`, `REPO_OWNER`, `TOKEN`) ermittelt werden.
- **Python-Kompatibilität**: Verwende Standard-Python 3 ohne externe PyPI-Abhängigkeiten (nur Standardbibliothek).
### 3.4 Container-Sicherheit & Persistenz
@@ -119,8 +124,33 @@ python3 scripts/package-arch.py --arch x86_64 --pkgrel 1
## 5. CI/CD-Pipeline Details
- **Trigger**:
- `push` auf `main`: Baut Binaries für alle 3 Architekturen, baut `.deb`, `.rpm` und `.pkg.tar.zst`, lädt sie in die Gitea Package Registry hoch, erstellt ein Gitea Release `v<VERSION>` und baut/veröffentlicht das Docker-Container-Image mit den Tags `:latest`, `:<VERSION>`, `:v<VERSION>` und `:<VERSION>.<BUILD_NUMBER>`.
- `push` auf `testing`: Baut Binaries & Pakete für den `testing`-Kanal, erstellt ein Pre-Release `v<VERSION>-preview` und baut/veröffentlicht das Docker-Container-Image ausschließlich mit eindeutigen Testing-Tags (`:testing`, `:<VERSION>-preview`, `:<VERSION>-testing`, `:<VERSION>-preview.<BUILD_NUMBER>`, `:testing-<BUILD_NUMBER>`). Der Tag `:latest` ist strikt dem `main`-Workflow vorbehalten.
- **Secrets**:
- `PACKAGE_TOKEN` (bzw. Fallback-Token-Namen wie `RELEASE_TOKEN`, `GITEA_TOKEN`) wird für API-Zugriffe auf Gitea Packages, Container Registry und Releases verwendet.
### 5.1 Branch-Flow & Trigger
Promotion-Flow: `dev` `testing``main`, ausschließlich per Merge (nie direkt gepusht).
- `pull_request` mit Ziel-Branch `testing` (`unit-tests.yaml`): führt `cargo test` aus (`types: opened, synchronize, reopened`).
- `push` auf `main` (`main.yaml`): Baut Binaries für alle 3 Architekturen, baut `.deb`, `.rpm` und `.pkg.tar.zst`, lädt sie in die Gitea Package Registry hoch, erstellt ein Gitea Release `v<VERSION>` und baut/veröffentlicht das Docker-Container-Image mit den Tags `:latest`, `:<VERSION>`, `:v<VERSION>` und `:<VERSION>.<BUILD_NUMBER>`.
- `push` auf `testing` (`testing.yaml`): Baut Binaries & Pakete für den `testing`-Kanal, erstellt ein Pre-Release `v<VERSION>-preview` und baut/veröffentlicht das Docker-Container-Image ausschließlich mit eindeutigen Testing-Tags (`:testing`, `:<VERSION>-preview`, `:<VERSION>-testing`, `:<VERSION>-preview.<BUILD_NUMBER>`, `:testing-<BUILD_NUMBER>`). Der Tag `:latest` ist strikt dem `main`-Workflow vorbehalten.
- `push`/`pull_request`/wöchentlich (`security-scan.yaml`, `trufflehog-scan.yaml`): Trivy (vuln/secret/misconfig) & OSV-Scanner laufen bei Push auf `main`/`testing`/`dev` sowie bei jedem PR; TruffleHog hat **keinen** `branches`-Filter und läuft bei Push auf **jeden** Branch (zusätzlich bei jedem PR). Funde werden per `scripts/report-security-issue.py` als Gitea-Issue gemeldet.
- stündlich, `workflow_dispatch` (`renovate.yaml`): Renovate (containerisiert via `ghcr.io/renovatebot/renovate`) prüft Dependency-Updates, siehe 5.5. Der stündliche CI-Lauf steuert nur, wie schnell Renovate reagiert (z.B. auf Dependency-Dashboard-Checkboxen); tatsächliche neue Update-PRs entstehen weiterhin nur innerhalb des in `renovate.json` gesetzten `schedule` (Montag vor 6 Uhr).
### 5.2 Caching (`actions/cache@v6`)
`main.yaml`/`testing.yaml` cachen mehrere Verzeichnisse, um wiederholte Cross-Compile-Builds zu beschleunigen:
- `~/.cargo/registry`, `~/.cargo/git`, `target` Cache-Key basiert auf `hashFiles('Cargo.lock')`.
- `~/.rustup/.../lib/rustlib/<target>` für die zwei zusätzlichen Cross-Targets Cache-Key basiert auf der **aufgelösten** `rustc --version`, nicht auf dem gleitenden `stable`-Label. Sonst könnte nach einem Rust-Update eine veraltete gecachte Std-Lib mit einem neueren Compiler kombiniert werden.
- `~/.cargo/bin/cargo-binstall`, `~/.cargo/bin/cargo-deb`, `~/.cargo/bin/cargo-generate-rpm` (gezielt die Binaries statt des gesamten Verzeichnisses, um alte Rust-Compiler-Proxys bei Toolchain-Updates nicht wiederherzustellen) alle drei sind auf feste Versionen gepinnt (Job-`env`), nicht auf `latest`.
**Wichtige Falle:** `target/debian`, `target/generate-rpm` und `target/arch` hängen ebenfalls unter `target` und werden dadurch mitgecacht, aber von keinem Tool automatisch geleert. Vor jedem Paketbau werden sie daher explizit per `rm -rf` bereinigt sonst werden alte, bereits hochgeladene Paket-Dateien aus früheren Builds erneut mit hochgeladen, und die Gitea Package Registry lehnt sie mit `409 Conflict` ab (Paket-Dateien sind dort unveränderlich). Bei neuen Paketierungs-Outputs außerhalb dieser drei Ordner muss diese Bereinigung entsprechend erweitert werden.
### 5.3 Build-Nummer (`scripts/get-build-number.py`)
Pro CI-Lauf wird genau **eine** Build-Nummer ermittelt und identisch an `cargo deb`, `cargo generate-rpm` und `package-arch.py --pkgrel` weitergereicht `.deb`, `.rpm` und Arch-Paket tragen also immer dieselbe Nummer. Zur Ermittlung wird pro Paket-Typ (`debian`, `rpm`, `arch`) gezielt `GET /api/v1/packages/{owner}/{type}/{name}/-/latest` abgefragt (ein Request pro Typ, kein Paging, unbeeinflusst von Docker-Tags/anderen Paketen desselben Owners); das Maximum aller drei Typen + 1 ergibt die neue Nummer. Eine pauschale, ungefilterte Abfrage über alle Pakete des Owners (`GET /packages/{owner}`) darf hier nicht mehr verwendet werden, da sie durch Docker-Image-Tags & Co. verdrängt werden kann.
### 5.4 Secrets
- `PACKAGE_TOKEN` (bzw. Fallback-Token-Namen wie `RELEASE_TOKEN`, `GITEA_TOKEN`) wird für API-Zugriffe auf Gitea Packages, Container Registry und Releases verwendet.
- `SECURITY_TOKEN` für die Security-Scan-Workflows (Gitea-Issue-Erstellung).
- `RENOVATE_TOKEN` für den Renovate-Workflow.
- `GH_RENOVATE_TOKEN` (optional, Renovate-Workflow, als `GITHUB_COM_TOKEN` an Renovate durchgereicht) GitHub-PAT (Public-Repo-Read genügt), damit Renovate Release-Infos für GitHub-gehostete Dependencies (u.a. `github-actions`-Manager) authentifiziert statt rate-limitiert abfragt.
### 5.5 Renovate (`renovate.json`)
- `baseBranches: ["dev"]` Renovate liest Dependency-Dateien ausschließlich von `dev` und öffnet PRs nur dort, passend zum `dev → testing → main`-Promotion-Flow. Die Konfigurationsdatei selbst muss trotzdem über den Gitea-Default-Branch auffindbar sein.
- Drei Gruppen (`packageRules`), jeweils mit `separateMajorMinor: false`/`separateMinorPatch: false` (sonst reißt Renovate Major-Updates trotz `groupName` standardmäßig in einen eigenen PR): "Gitea Actions" (dateibasiert über `matchFileNames: [".gitea/workflows/**"]`, deckt auch die Custom-Manager unten ab), "Cargo Dependencies", "Docker-Images".
- `customManagers` (Regex) tracken Versionen, die als reine Strings in `run:`-Blöcken stecken und vom `github-actions`-Manager nicht erkannt werden: `TRIVY_VERSION`, `OSV_SCANNER_VERSION`, `TRUFFLEHOG_VERSION`, `CARGO_BINSTALL_VERSION`, `CARGO_DEB_VERSION`, `CARGO_GENERATE_RPM_VERSION`. Wird in einer Workflow-Datei eine weitere Tool-Version nach demselben Muster (`NAME_VERSION: "x.y.z"`) gepinnt, muss hier ein passender Eintrag ergänzt werden, sonst bleibt sie von Renovate unbemerkt veraltet.
Generated
+19 -14
View File
@@ -93,6 +93,12 @@ version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]]
name = "base64"
version = "0.23.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac07cdecf99051d9a5238b80f35af32cdeba5b336e55d957b318b50137e18da5"
[[package]]
name = "bitflags"
version = "2.13.1"
@@ -213,9 +219,9 @@ dependencies = [
[[package]]
name = "config-ctdra"
version = "1.0.4"
version = "1.0.6"
source = "sparse+https://gitea.creative-dragonslayer.de/api/packages/Rust-Crates/cargo/"
checksum = "f7b3e25b95d4cdb6fc856f2af0106d4558b882c2f10798db46181e51827749a4"
checksum = "83eb23d473fce79e8234ad66baf210289b5c9e4c4a587273b4df7deceb73f416"
dependencies = [
"confy",
"program-ctdra",
@@ -316,7 +322,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
dependencies = [
"libc 0.2.189",
"windows-sys 0.61.2",
"windows-sys 0.52.0",
]
[[package]]
@@ -565,7 +571,7 @@ version = "0.1.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0"
dependencies = [
"base64",
"base64 0.22.1",
"bytes",
"futures-channel",
"futures-util",
@@ -827,9 +833,9 @@ checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6"
[[package]]
name = "logger-ctdra"
version = "1.0.3"
version = "1.0.5"
source = "sparse+https://gitea.creative-dragonslayer.de/api/packages/Rust-Crates/cargo/"
checksum = "af9ea239d80163c80b12cae5f74c0c2824199921dedafba74678e96a11a8b15e"
checksum = "ce612b7d943b77060fa36eab0c85782e650c4cf023e9d560bef791951ed92cad"
dependencies = [
"program-ctdra",
"time",
@@ -866,7 +872,7 @@ dependencies = [
[[package]]
name = "mirror-package"
version = "1.0.2"
version = "1.0.5"
dependencies = [
"anyhow",
"clap",
@@ -874,7 +880,6 @@ dependencies = [
"logger-ctdra",
"reqwest",
"serde",
"serde_json",
"tokio",
]
@@ -1036,7 +1041,7 @@ dependencies = [
"once_cell",
"socket2",
"tracing",
"windows-sys 0.61.2",
"windows-sys 0.52.0",
]
[[package]]
@@ -1091,11 +1096,11 @@ dependencies = [
[[package]]
name = "reqwest"
version = "0.13.4"
version = "0.13.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "219c5811de6525e5416c7d5d53bb656d3afdbc6c5af816e0802bcfa42dbdc1c3"
checksum = "16a1cfa75cc186dd73d5818e510e042e40927bccc9c236b061cea97e1eb08029"
dependencies = [
"base64",
"base64 0.23.1",
"bytes",
"encoding_rs",
"futures-core",
@@ -1215,7 +1220,7 @@ dependencies = [
"security-framework",
"security-framework-sys",
"webpki-root-certs",
"windows-sys 0.61.2",
"windows-sys 0.52.0",
]
[[package]]
@@ -1893,7 +1898,7 @@ version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
dependencies = [
"windows-sys 0.61.2",
"windows-sys 0.52.0",
]
[[package]]
+1 -2
View File
@@ -1,6 +1,6 @@
[package]
name = "mirror-package"
version = "1.0.2"
version = "1.0.5"
edition = "2024"
authors = ['DragonSlayer_14']
readme = "README.md"
@@ -15,7 +15,6 @@ clap = { version = "4.6.6", features = ["derive", "env"] }
reqwest = { version = "0.13.4", features = ["json", "stream"] }
tokio = { version = "1.53.1", features = ["full"] }
serde = { version = "1.0.229", features = ["derive"] }
serde_json = "1.0.151"
anyhow = "1.0.104"
[profile.release]
+19 -2
View File
@@ -1,5 +1,8 @@
# mirror-package
[![Main Release & Publish](https://gitea.creative-dragonslayer.de/Linuxapps/MirrorPackage/actions/workflows/main.yaml/badge.svg?branch=main)](https://gitea.creative-dragonslayer.de/Linuxapps/MirrorPackage/actions?workflow=main.yaml)
[![Testing Build, Publish & Preview Release](https://gitea.creative-dragonslayer.de/Linuxapps/MirrorPackage/actions/workflows/testing.yaml/badge.svg?branch=testing)](https://gitea.creative-dragonslayer.de/Linuxapps/MirrorPackage/actions?workflow=testing.yaml)
Automatisiertes Werkzeug zum Extrahieren, Herunterladen und Spiegeln vorkompilierter Linux-Pakete aus GitHub-Releases in eine selbstgehostete Gitea- / Forgejo-Paket-Registry.
`mirror-package` überwacht konfigurierte GitHub-Repositories (wie z. B. `raspberrypi/rpi-imager` oder `Heroic-Games-Launcher/HeroicGamesLauncher`), identifiziert vorkompilierte Linux-Pakete (`.deb`, `.rpm`, `.pkg.tar.zst`, `.pkg.tar.xz`, `.pkg.tar.gz`, `.pacman`) und veröffentlicht diese anhand von Release-Stabilitätsregeln automatisch in den passenden Distributionen der Gitea-Paket-Registry.
@@ -199,8 +202,12 @@ services:
│ └── config.toml # Linker- & Cargo-Konfiguration
├── .gitea/
│ └── workflows/
│ ├── main.yaml # CI/CD: Release, Pakete & Container (Stable)
── testing.yaml # CI/CD: Preview, Pakete & Container (Testing)
│ ├── main.yaml # CI/CD: Release, Pakete & Container (Stable)
── testing.yaml # CI/CD: Preview, Pakete & Container (Testing)
│ ├── unit-tests.yaml # CI: cargo test bei PRs gegen testing
│ ├── security-scan.yaml # CI: Trivy & OSV-Scanner
│ ├── trufflehog-scan.yaml # CI: TruffleHog Secret-Scanning
│ └── renovate.yaml # CI: automatisierte Abhängigkeits-Updates (Renovate)
├── scripts/
│ ├── get-build-number.py # Dynamische Ermittlung der Build-/Revisionsnummer
│ └── package-arch.py # Erstellung nativer Arch Linux-Pakete
@@ -220,6 +227,7 @@ services:
├── Dockerfile # Gehärtetes, minimales Runtime-Container-Image
├── docker-compose.example.yml # Beispielkonfiguration für Docker Compose
├── Cargo.toml # Projekt-Manifest und Paketierungs-Metadaten
├── renovate.json # Renovate-Konfiguration für automatisierte Abhängigkeits-Updates
├── LICENSE # GPL-3.0-or-later Lizenztext
├── AGENTS.md # Agenten- & Entwickler-Richtlinien
└── README.md # Projektdokumentation
@@ -248,6 +256,15 @@ cargo build --release
---
## CI/CD & Contributing
- **Branch-Flow**: Änderungen durchlaufen `dev``testing``main`, jeweils per Merge (nie direkt gepusht).
- **Pull Requests gegen `testing`** lösen automatisch `cargo test` aus.
- **Sicherheits-Scans**: Trivy & OSV-Scanner laufen bei Push auf `main`/`testing`/`dev` sowie bei jedem Pull Request; TruffleHog läuft bei Push auf **jeden** Branch (kein `branches`-Filter) sowie ebenfalls bei jedem Pull Request. Funde werden als Gitea-Issue gemeldet.
- **Abhängigkeits-Updates** werden automatisiert über [Renovate](https://docs.renovatebot.com/) als PRs gegen `dev` vorgeschlagen.
---
## Lizenz
Dieses Projekt ist unter der [GPL-3.0-or-later](LICENSE)-Lizenz lizenziert.
+101
View File
@@ -0,0 +1,101 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": ["config:recommended"],
"timezone": "Europe/Berlin",
"schedule": ["before 6am on monday"],
"baseBranchPatterns": [
"dev"
],
"packageRules": [
{
"matchFileNames": [".gitea/workflows/**"],
"groupName": "Gitea Actions",
"separateMajorMinor": false,
"separateMinorPatch": false
},
{
"matchManagers": ["cargo"],
"groupName": "Cargo Dependencies",
"separateMajorMinor": false,
"separateMinorPatch": false
},
{
"matchManagers": ["dockerfile", "docker-compose"],
"groupName": "Docker-Images",
"separateMajorMinor": false,
"separateMinorPatch": false
}
],
"customManagers": [
{
"customType": "regex",
"managerFilePatterns": [
"/^\\.gitea/workflows/.+\\.ya?ml$/"
],
"matchStrings": [
"TRIVY_VERSION:\\s*\"(?<currentValue>[^\"]+)\""
],
"depNameTemplate": "aquasecurity/trivy",
"datasourceTemplate": "github-releases",
"extractVersionTemplate": "^v(?<version>.*)$"
},
{
"customType": "regex",
"managerFilePatterns": [
"/^\\.gitea/workflows/.+\\.ya?ml$/"
],
"matchStrings": [
"OSV_SCANNER_VERSION:\\s*\"(?<currentValue>[^\"]+)\""
],
"depNameTemplate": "google/osv-scanner",
"datasourceTemplate": "github-releases",
"extractVersionTemplate": "^v(?<version>.*)$"
},
{
"customType": "regex",
"managerFilePatterns": [
"/^\\.gitea/workflows/.+\\.ya?ml$/"
],
"matchStrings": [
"TRUFFLEHOG_VERSION:\\s*\"(?<currentValue>[^\"]+)\""
],
"depNameTemplate": "trufflesecurity/trufflehog",
"datasourceTemplate": "github-releases",
"extractVersionTemplate": "^v(?<version>.*)$"
},
{
"customType": "regex",
"managerFilePatterns": [
"/^\\.gitea/workflows/.+\\.ya?ml$/"
],
"matchStrings": [
"CARGO_BINSTALL_VERSION:\\s*\"(?<currentValue>[^\"]+)\""
],
"depNameTemplate": "cargo-bins/cargo-binstall",
"datasourceTemplate": "github-releases",
"extractVersionTemplate": "^v(?<version>.*)$"
},
{
"customType": "regex",
"managerFilePatterns": [
"/^\\.gitea/workflows/.+\\.ya?ml$/"
],
"matchStrings": [
"CARGO_DEB_VERSION:\\s*\"(?<currentValue>[^\"]+)\""
],
"depNameTemplate": "cargo-deb",
"datasourceTemplate": "crate"
},
{
"customType": "regex",
"managerFilePatterns": [
"/^\\.gitea/workflows/.+\\.ya?ml$/"
],
"matchStrings": [
"CARGO_GENERATE_RPM_VERSION:\\s*\"(?<currentValue>[^\"]+)\""
],
"depNameTemplate": "cargo-generate-rpm",
"datasourceTemplate": "crate"
}
]
}
+24 -10
View File
@@ -9,9 +9,14 @@ import os
import re
import subprocess
import sys
import urllib.error
import urllib.parse
import urllib.request
# Paket-Typen, unter denen dasselbe Release veroeffentlicht wird und die sich
# daher eine gemeinsame Build-Nummer teilen muessen.
PACKAGE_TYPES = ("debian", "rpm", "arch")
def get_cargo_pkg_info():
try:
@@ -83,20 +88,29 @@ def query_existing_build_numbers(name, version, gitea_url, repo, owner, token=No
except Exception as e:
sys.stderr.write(f"[Hinweis] Konnte Gitea Releases nicht abfragen: {e}\n")
# 2. Gitea Packages API (falls Token vorhanden)
if gitea_url and owner and token:
try:
url = f"{gitea_url.rstrip('/')}/api/v1/packages/{owner}?limit=50"
req = urllib.request.Request(url, headers=headers)
with urllib.request.urlopen(req, timeout=10) as resp:
packages = json.loads(resp.read().decode())
for pkg in packages:
# 2. Gitea Packages API (falls Token vorhanden): pro Paket-Typ gezielt nur die
# neueste Version abfragen (ein Request, keine Pagination noetig). Das haelt
# die Abfrage schnell unabhaengig von der Historie und ist unbeeinflusst von
# Docker-Tags/anderen Paket-Typen, die unter demselben Owner haengen.
if gitea_url and owner and token and name:
for pkg_type in PACKAGE_TYPES:
try:
url = (
f"{gitea_url.rstrip('/')}/api/v1/packages/{owner}/"
f"{pkg_type}/{urllib.parse.quote(name, safe='')}/-/latest"
)
req = urllib.request.Request(url, headers=headers)
with urllib.request.urlopen(req, timeout=10) as resp:
pkg = json.loads(resp.read().decode())
pkg_ver = pkg.get("version", "")
m = pattern.search(pkg_ver)
if m:
build_nums.add(int(m.group(1)))
except Exception as e:
sys.stderr.write(f"[Hinweis] Konnte Gitea Packages nicht abfragen: {e}\n")
except urllib.error.HTTPError as e:
if e.code != 404:
sys.stderr.write(f"[Hinweis] Konnte neueste {pkg_type}-Paketversion nicht abfragen: {e}\n")
except Exception as e:
sys.stderr.write(f"[Hinweis] Konnte neueste {pkg_type}-Paketversion nicht abfragen: {e}\n")
# 3. Lokales Target-Verzeichnis prüfen
target_dirs = ["target/debian", "target/generate-rpm", "target/arch"]
+312
View File
@@ -0,0 +1,312 @@
#!/usr/bin/env python3
"""Erstellt oder kommentiert ein Gitea-Issue mit den Ergebnissen der Security-Scans.
Sucht ein offenes Issue mit dem Label ISSUE_LABEL (Standard: "security-scan").
Existiert eines, wird der aktuelle Scan-Stand als neuer Kommentar angehängt
(die Historie bleibt erhalten). Existiert keines (z.B. weil das letzte
geschlossen wurde), wird ein neues Issue erstellt. Gibt es keine Funde mehr,
wird ein offenes Issue nur kommentiert, nicht geschlossen.
Titel und Label lassen sich per Umgebungsvariable ISSUE_TITLE / ISSUE_LABEL
überschreiben, damit z.B. TruffleHog-Funde in ein eigenes Issue laufen statt
in das gemeinsame Trivy/OSV-Issue.
"""
import json
import os
import sys
import urllib.error
import urllib.request
LABEL_NAME = os.environ.get("ISSUE_LABEL", "security-scan")
LABEL_COLOR = "#b60205"
ISSUE_TITLE = os.environ.get("ISSUE_TITLE", "Security-Scan: Offene Schwachstellen")
SEVERITY_ORDER = {
"VERIFIED": -1,
"CRITICAL": 0,
"HIGH": 1,
"MEDIUM": 2,
"LOW": 3,
"UNKNOWN": 4,
"UNVERIFIED": 6,
}
def api(method, path, token, gitea_url, data=None):
url = f"{gitea_url}/api/v1{path}"
body = json.dumps(data).encode() if data is not None else None
req = urllib.request.Request(url, data=body, method=method)
req.add_header("Authorization", f"token {token}")
req.add_header("Content-Type", "application/json")
try:
with urllib.request.urlopen(req, timeout=10) as resp:
raw = resp.read()
return json.loads(raw) if raw else None
except urllib.error.HTTPError as e:
print(f"Gitea API Fehler ({method} {path}): {e.code} {e.read().decode()}", file=sys.stderr)
raise
def make_finding(source, id, severity, package, installed="-", fixed="-", target="-"):
return {
"source": source,
"id": id,
"severity": severity,
"package": package,
"installed": installed,
"fixed": fixed,
"target": target,
}
def cvss_score_to_severity(score):
try:
score = float(score)
except (TypeError, ValueError):
return "UNKNOWN"
if score >= 9.0:
return "CRITICAL"
if score >= 7.0:
return "HIGH"
if score >= 4.0:
return "MEDIUM"
if score > 0.0:
return "LOW"
return "UNKNOWN"
def load_trivy(path):
findings = []
if not path or not os.path.isfile(path):
return findings
with open(path) as f:
data = json.load(f)
for result in data.get("Results", []) or []:
target = result.get("Target", "?")
for vuln in result.get("Vulnerabilities", []) or []:
findings.append(make_finding(
"Trivy",
vuln.get("VulnerabilityID", "?"),
vuln.get("Severity", "UNKNOWN"),
vuln.get("PkgName", "?"),
installed=vuln.get("InstalledVersion", "?"),
fixed=vuln.get("FixedVersion") or "-",
target=target,
))
for misc in result.get("Misconfigurations", []) or []:
findings.append(make_finding(
"Trivy (Misconfig)",
misc.get("ID", "?"),
misc.get("Severity", "UNKNOWN"),
misc.get("Title", "?"),
target=target,
))
for secret in result.get("Secrets", []) or []:
findings.append(make_finding(
"Trivy (Secret)",
secret.get("RuleID", "?"),
secret.get("Severity", "UNKNOWN"),
secret.get("Title", "?"),
target=target,
))
return findings
def load_osv(path):
findings = []
if not path or not os.path.isfile(path):
return findings
with open(path) as f:
data = json.load(f)
for result in data.get("results", []) or []:
source = (result.get("source") or {}).get("path", "?")
for pkg in result.get("packages", []) or []:
info = pkg.get("package", {})
pkg_name = f"{info.get('name', '?')} ({info.get('ecosystem', '?')})"
severity_by_id = {}
for group in pkg.get("groups", []) or []:
label = cvss_score_to_severity(group.get("max_severity"))
for vuln_id in group.get("ids", []) or []:
severity_by_id[vuln_id] = label
for vuln in pkg.get("vulnerabilities", []) or []:
vuln_id = vuln.get("id", "?")
findings.append(make_finding(
"OSV-Scanner",
vuln_id,
severity_by_id.get(vuln_id, "UNKNOWN"),
pkg_name,
installed=info.get("version", "?"),
target=source,
))
return findings
def load_trufflehog(path):
findings = []
if not path or not os.path.isfile(path):
return findings
with open(path) as f:
for line in f:
line = line.strip()
if not line:
continue
try:
entry = json.loads(line)
except json.JSONDecodeError:
continue
git_meta = ((entry.get("SourceMetadata") or {}).get("Data") or {}).get("Git") or {}
findings.append(make_finding(
"TruffleHog",
entry.get("DetectorName", "?"),
"VERIFIED" if entry.get("Verified") else "UNVERIFIED",
git_meta.get("file", "?"),
target=git_meta.get("commit", "-"),
))
return findings
def sort_findings(findings):
return sorted(findings, key=lambda f: (SEVERITY_ORDER.get(f["severity"], 9), f["id"]))
def print_summary(findings):
if not findings:
print("Keine Funde.")
return
widths = {
key: max(len(key), *(len(str(f[key])) for f in findings))
for key in ("source", "id", "severity", "package", "installed", "fixed", "target")
}
header = ("source", "id", "severity", "package", "installed", "fixed", "target")
row_fmt = " ".join(f"{{:{widths[k]}}}" for k in header)
print(row_fmt.format(*header))
print(row_fmt.format(*("-" * widths[k] for k in header)))
for f in findings:
print(row_fmt.format(*(str(f[k]) for k in header)))
TRUFFLEHOG_GUIDANCE = """### Vorgehen bei gefundenen Secrets
1. **Sofort rotieren/widerrufen**: Das betroffene Secret (Token, Passwort, Schlüssel) beim jeweiligen Dienst ungültig machen und durch ein neues ersetzen. Ein einmal committetes Secret gilt als kompromittiert, auch wenn es später aus der Historie entfernt wird.
2. **Ursache beheben**: Neues Secret nur noch über Umgebungsvariablen/Secrets-Store einbinden, nicht erneut hart codieren.
3. **Historie bereinigen (optional, manuell, erst nach Schritt 1)**: Mit `git filter-repo` oder BFG Repo-Cleaner den Commit-Inhalt entfernen, danach `git push --force` in Absprache mit allen Mitwirkenden bestehende Clones/Forks werden dadurch ungültig.
4. **Issue schließen**, sobald rotiert wurde. TruffleHog findet das alte Secret ggf. weiterhin in der Historie nach der Rotation ist das unkritisch.
> Der Wert des Secrets selbst wird hier bewusst nicht ausgegeben, auch nicht gekürzt nur Detector, Datei und Commit. Fund lässt sich über "Ziel" (Commit-Hash) und "Paket" (Dateipfad) lokalisieren."""
def escape_md_cell(value):
return str(value).replace("|", "\\|").replace("\r", " ").replace("\n", " ")
def build_report(findings, run_url):
lines = [
"Automatisch erstellt vom Security-Scan-Workflow.",
f"Lauf: {run_url}" if run_url else "",
"",
"| Quelle | ID | Schweregrad | Paket | Installiert | Fix | Ziel |",
"|---|---|---|---|---|---|---|",
]
for f in findings:
cells = (f["source"], f["id"], f["severity"], f["package"], f["installed"], f["fixed"], f["target"])
lines.append("| " + " | ".join(escape_md_cell(c) for c in cells) + " |")
if any(f["source"] == "TruffleHog" for f in findings):
lines.append("")
lines.append(TRUFFLEHOG_GUIDANCE)
return "\n".join(lines)
def ensure_label(token, gitea_url, repo):
page = 1
while True:
labels = api("GET", f"/repos/{repo}/labels?limit=50&page={page}", token, gitea_url) or []
for label in labels:
if label.get("name") == LABEL_NAME:
return label["id"]
if len(labels) < 50:
break
page += 1
created = api("POST", f"/repos/{repo}/labels", token, gitea_url, {
"name": LABEL_NAME,
"color": LABEL_COLOR,
"description": "Automatisch verwaltet vom Security-Scan-Workflow",
})
return created["id"]
def find_open_issue(token, gitea_url, repo):
issues = api(
"GET",
f"/repos/{repo}/issues?state=open&type=issues&labels={LABEL_NAME}",
token,
gitea_url,
) or []
for issue in issues:
if issue.get("title") == ISSUE_TITLE:
return issue
return None
def main():
trivy_path = sys.argv[1] if len(sys.argv) > 1 else None
osv_path = sys.argv[2] if len(sys.argv) > 2 else None
trufflehog_path = sys.argv[3] if len(sys.argv) > 3 else None
gitea_url = os.environ.get("GITEA_URL", "").strip().rstrip("/")
repo = os.environ.get("REPO", "").strip()
token = os.environ.get("TOKEN", "").strip()
run_url = os.environ.get("RUN_URL", "")
osv_exit = int(os.environ.get("OSV_EXIT", "0"))
trufflehog_exit = int(os.environ.get("TRUFFLEHOG_EXIT", "0"))
findings = sort_findings(load_trivy(trivy_path) + load_osv(osv_path) + load_trufflehog(trufflehog_path))
print_summary(findings)
if not token or not gitea_url or not repo:
missing = [name for name, val in [("TOKEN", token), ("GITEA_URL", gitea_url), ("REPO", repo)] if not val]
print(f"{', '.join(missing)} nicht gesetzt oder leer überspringe Gitea-Issue-Synchronisation.")
else:
open_issue = find_open_issue(token, gitea_url, repo)
if findings:
report = build_report(findings, run_url)
if open_issue:
print(f"Kommentiere bestehendes Issue #{open_issue['number']} mit {len(findings)} Fund(en).")
api("POST", f"/repos/{repo}/issues/{open_issue['number']}/comments", token, gitea_url, {"body": report})
else:
label_id = ensure_label(token, gitea_url, repo)
print(f"Erstelle neues Issue mit {len(findings)} Fund(en).")
api("POST", f"/repos/{repo}/issues", token, gitea_url, {
"title": ISSUE_TITLE,
"body": report,
"labels": [label_id],
})
elif open_issue:
print(f"Keine aktuellen Funde mehr. Kommentiere Issue #{open_issue['number']}.")
api("POST", f"/repos/{repo}/issues/{open_issue['number']}/comments", token, gitea_url, {
"body": f"Aktueller Scan hat keine offenen Schwachstellen mehr gefunden.\n\n{run_url}".strip(),
})
else:
print("Keine Funde und kein offenes Issue vorhanden.")
osv_ok_exits = {0, 1}
trufflehog_ok_exits = {0, 183}
if osv_exit not in osv_ok_exits:
print(f"WARNUNG: osv-scanner beendete sich mit unerwartetem Exit-Code {osv_exit} - Scan evtl. unvollständig.", file=sys.stderr)
if trufflehog_exit not in trufflehog_ok_exits:
print(f"WARNUNG: trufflehog beendete sich mit unerwartetem Exit-Code {trufflehog_exit} - Scan evtl. unvollständig.", file=sys.stderr)
has_trivy_findings = any(f["source"].startswith("Trivy") for f in findings)
if (
has_trivy_findings
or osv_exit == 1
or trufflehog_exit == 183
or osv_exit not in osv_ok_exits
or trufflehog_exit not in trufflehog_ok_exits
):
sys.exit(1)
if __name__ == "__main__":
main()
+15 -4
View File
@@ -59,7 +59,11 @@ impl AppConfig {
/// Fügt ein Repository zur Konfiguration hinzu oder aktualisiert ein bestehendes.
pub fn add_or_update_repo(&mut self, mut repo: RepoConfig) {
repo.name = Self::normalize_repo_name(&repo.name);
if let Some(existing) = self.repositories.iter_mut().find(|r| Self::normalize_repo_name(&r.name).eq_ignore_ascii_case(&repo.name)) {
if let Some(existing) = self
.repositories
.iter_mut()
.find(|r| Self::normalize_repo_name(&r.name).eq_ignore_ascii_case(&repo.name))
{
existing.name = repo.name;
existing.include_prereleases = repo.include_prereleases;
} else {
@@ -71,20 +75,27 @@ impl AppConfig {
pub fn remove_repo(&mut self, repo_name: &str) -> bool {
let normalized = Self::normalize_repo_name(repo_name);
let before_len = self.repositories.len();
self.repositories.retain(|r| !Self::normalize_repo_name(&r.name).eq_ignore_ascii_case(&normalized));
self.repositories
.retain(|r| !Self::normalize_repo_name(&r.name).eq_ignore_ascii_case(&normalized));
self.repositories.len() < before_len
}
/// Sucht ein Repository anhand des Namens.
pub fn find_repo(&self, repo_name: &str) -> Option<&RepoConfig> {
let normalized = Self::normalize_repo_name(repo_name);
self.repositories.iter().find(|r| Self::normalize_repo_name(&r.name).eq_ignore_ascii_case(&normalized))
self.repositories
.iter()
.find(|r| Self::normalize_repo_name(&r.name).eq_ignore_ascii_case(&normalized))
}
/// Aktualisiert den zuletzt synchronisierten Tag für ein bestimmtes Repository.
pub fn update_last_synced_tag(&mut self, repo_name: &str, tag: String) {
let normalized = Self::normalize_repo_name(repo_name);
if let Some(repo) = self.repositories.iter_mut().find(|r| Self::normalize_repo_name(&r.name).eq_ignore_ascii_case(&normalized)) {
if let Some(repo) = self
.repositories
.iter_mut()
.find(|r| Self::normalize_repo_name(&r.name).eq_ignore_ascii_case(&normalized))
{
repo.last_synced_tag = Some(tag);
}
}
+26 -7
View File
@@ -1,5 +1,5 @@
use crate::github::PackageType;
use anyhow::{bail, Context, Result};
use anyhow::{Context, Result, bail};
use std::path::Path;
use tokio::fs::File;
@@ -12,7 +12,11 @@ pub struct GiteaConfig {
}
impl GiteaConfig {
pub fn new(base_url: impl Into<String>, token: impl Into<String>, owner: impl Into<String>) -> Self {
pub fn new(
base_url: impl Into<String>,
token: impl Into<String>,
owner: impl Into<String>,
) -> Self {
let mut base_url = base_url.into();
while base_url.ends_with('/') {
base_url.pop();
@@ -44,17 +48,29 @@ pub fn get_target_upload_urls(
match pkg_type {
PackageType::Debian => {
if prerelease {
vec![format!("{}/api/packages/{}/debian/pool/testing/main/upload", base, owner)]
vec![format!(
"{}/api/packages/{}/debian/pool/testing/main/upload",
base, owner
)]
} else {
vec![
format!("{}/api/packages/{}/debian/pool/stable/main/upload", base, owner),
format!("{}/api/packages/{}/debian/pool/testing/main/upload", base, owner),
format!(
"{}/api/packages/{}/debian/pool/stable/main/upload",
base, owner
),
format!(
"{}/api/packages/{}/debian/pool/testing/main/upload",
base, owner
),
]
}
}
PackageType::Rpm => {
if prerelease {
vec![format!("{}/api/packages/{}/rpm/testing/upload", base, owner)]
vec![format!(
"{}/api/packages/{}/rpm/testing/upload",
base, owner
)]
} else {
vec![format!("{}/api/packages/{}/rpm/stable/upload", base, owner)]
}
@@ -82,7 +98,10 @@ impl GiteaClient {
let mut headers = reqwest::header::HeaderMap::new();
headers.insert(
reqwest::header::USER_AGENT,
reqwest::header::HeaderValue::from_static(concat!("mirror-package/", env!("CARGO_PKG_VERSION"))),
reqwest::header::HeaderValue::from_static(concat!(
"mirror-package/",
env!("CARGO_PKG_VERSION")
)),
);
let client = reqwest::Client::builder()
+14 -7
View File
@@ -91,7 +91,10 @@ impl GitHubClient {
let mut headers = reqwest::header::HeaderMap::new();
headers.insert(
reqwest::header::USER_AGENT,
reqwest::header::HeaderValue::from_static(concat!("mirror-package/", env!("CARGO_PKG_VERSION"))),
reqwest::header::HeaderValue::from_static(concat!(
"mirror-package/",
env!("CARGO_PKG_VERSION")
)),
);
headers.insert(
reqwest::header::ACCEPT,
@@ -111,7 +114,6 @@ impl GitHubClient {
self.token.as_deref()
}
/// Ruft Releases für ein angegebenes Repository ab (Format "owner/repo").
///
/// Wenn `history` false ist, werden nur die neuesten Releases abgerufen.
@@ -139,7 +141,10 @@ impl GitHubClient {
req = req.bearer_auth(token);
}
let resp = req.send().await.with_context(|| format!("Failed to send request to {}", url))?;
let resp = req
.send()
.await
.with_context(|| format!("Failed to send request to {}", url))?;
let status = resp.status();
if !status.is_success() {
@@ -153,10 +158,12 @@ impl GitHubClient {
);
}
let raw_releases: Vec<GhApiRelease> = resp
.json()
.await
.with_context(|| format!("Failed to parse GitHub releases JSON for {}/{}", owner, name))?;
let raw_releases: Vec<GhApiRelease> = resp.json().await.with_context(|| {
format!(
"Failed to parse GitHub releases JSON for {}/{}",
owner, name
)
})?;
if raw_releases.is_empty() {
break;
+59 -15
View File
@@ -1,11 +1,11 @@
use anyhow::Result;
use clap::Parser;
use logger_ctdra::{log, set_log_level, LogLevel};
use logger_ctdra::{LogLevel, log, set_log_level};
use mirror_package::cli::{Cli, Commands, ConfigAction};
use mirror_package::config::{
get_config_file_path, init_config_path, load_config, modify_config, AppConfig, RepoConfig,
AppConfig, RepoConfig, get_config_file_path, init_config_path, load_config, modify_config,
};
use mirror_package::pipeline::{sync_single_repository, SyncOptions, SyncReport};
use mirror_package::pipeline::{SyncOptions, SyncReport, sync_single_repository};
#[tokio::main]
async fn main() -> Result<()> {
@@ -65,7 +65,9 @@ async fn main() -> Result<()> {
let mut report = SyncReport::default();
for repo in repos_to_sync {
if let Err(e) = sync_single_repository(&repo, &app_config, &options, &mut report).await {
if let Err(e) =
sync_single_repository(&repo, &app_config, &options, &mut report).await
{
log(
"sync",
&format!("Failed to sync repository '{}': {:#}", repo.name, e),
@@ -128,23 +130,38 @@ async fn main() -> Result<()> {
log(
"config",
&format!("Repository '{}' removed from configuration.", normalized_name),
&format!(
"Repository '{}' removed from configuration.",
normalized_name
),
LogLevel::Info,
);
}
Commands::List => {
println!("Configured repositories (Config file: {:?}):", get_config_file_path());
println!(
"Configured repositories (Config file: {:?}):",
get_config_file_path()
);
if app_config.repositories.is_empty() {
println!(" (None configured yet. Use 'mirror-package add <owner/repo>' to add one.)");
println!(
" (None configured yet. Use 'mirror-package add <owner/repo>' to add one.)"
);
} else {
println!("{:<40} {:<15} {:<20}", "REPOSITORY", "PRE-RELEASES", "LAST SYNCED TAG");
println!(
"{:<40} {:<15} {:<20}",
"REPOSITORY", "PRE-RELEASES", "LAST SYNCED TAG"
);
println!("{:-<40} {:-<15} {:-<20}", "", "", "");
for repo in &app_config.repositories {
println!(
"{:<40} {:<15} {:<20}",
repo.name,
if repo.include_prereleases { "yes" } else { "no" },
if repo.include_prereleases {
"yes"
} else {
"no"
},
repo.last_synced_tag.as_deref().unwrap_or("-")
);
}
@@ -154,17 +171,40 @@ async fn main() -> Result<()> {
Commands::Config(config_args) => match config_args.action {
None | Some(ConfigAction::Show) => {
println!("Configuration location: {:?}", get_config_file_path());
println!("Gitea URL: {}", app_config.gitea_url.as_deref().unwrap_or("(not configured)"));
println!("Registry Owner: {}", app_config.registry_owner.as_deref().unwrap_or("(not configured)"));
println!(
"Gitea URL: {}",
app_config
.gitea_url
.as_deref()
.unwrap_or("(not configured)")
);
println!(
"Registry Owner: {}",
app_config
.registry_owner
.as_deref()
.unwrap_or("(not configured)")
);
println!(
"Gitea Token: {}",
if app_config.gitea_token.is_some() { "******** (set)" } else { "(not configured)" }
if app_config.gitea_token.is_some() {
"******** (set)"
} else {
"(not configured)"
}
);
println!(
"GitHub Token: {}",
if app_config.github_token.is_some() { "******** (set)" } else { "(not configured, public access only)" }
if app_config.github_token.is_some() {
"******** (set)"
} else {
"(not configured, public access only)"
}
);
println!(
"Repositories: {} configured",
app_config.repositories.len()
);
println!("Repositories: {} configured", app_config.repositories.len());
}
Some(ConfigAction::Set {
@@ -188,7 +228,11 @@ async fn main() -> Result<()> {
}
})?;
log("config", "Configuration successfully updated.", LogLevel::Info);
log(
"config",
"Configuration successfully updated.",
LogLevel::Info,
);
}
},
}
+39 -26
View File
@@ -1,11 +1,11 @@
use crate::config::{modify_config, AppConfig, RepoConfig};
use crate::gitea::{get_target_upload_urls, GiteaClient, GiteaConfig, UploadStatus};
use crate::config::{AppConfig, RepoConfig, modify_config};
use crate::gitea::{GiteaClient, GiteaConfig, UploadStatus, get_target_upload_urls};
use crate::github::GitHubClient;
use anyhow::{bail, Context, Result};
use logger_ctdra::{log, LogLevel};
use anyhow::{Context, Result, bail};
use logger_ctdra::{LogLevel, log};
use std::path::PathBuf;
use std::time::{SystemTime, UNIX_EPOCH};
use tokio::fs::{remove_file, File};
use tokio::fs::{File, remove_file};
use tokio::io::AsyncWriteExt;
/// Zusammenfassende Statistiken eines Synchronisationsvorgangs.
@@ -52,7 +52,9 @@ pub async fn sync_single_repository(
let gitea_token = app_config.gitea_token.as_deref().unwrap_or_default();
let registry_owner = app_config.registry_owner.as_deref().unwrap_or_default();
if !options.dry_run && (gitea_url.is_empty() || gitea_token.is_empty() || registry_owner.is_empty()) {
if !options.dry_run
&& (gitea_url.is_empty() || gitea_token.is_empty() || registry_owner.is_empty())
{
bail!(
"Missing Gitea configuration. Ensure --gitea-url, --gitea-token, and --registry-owner are provided or configured."
);
@@ -61,12 +63,8 @@ pub async fn sync_single_repository(
let github_client = GitHubClient::new(app_config.github_token.clone())
.context("Failed to initialize GitHub client")?;
let gitea_client = GiteaClient::new(GiteaConfig::new(
gitea_url,
gitea_token,
registry_owner,
))
.context("Failed to initialize Gitea client")?;
let gitea_client = GiteaClient::new(GiteaConfig::new(gitea_url, gitea_token, registry_owner))
.context("Failed to initialize Gitea client")?;
let releases = github_client
.fetch_releases(repo_name, options.history, include_prereleases)
@@ -97,7 +95,11 @@ pub async fn sync_single_repository(
for release in &releases {
report.releases_processed += 1;
let release_type_str = if release.prerelease { "pre-release" } else { "stable release" };
let release_type_str = if release.prerelease {
"pre-release"
} else {
"stable release"
};
log(
"sync",
@@ -156,9 +158,10 @@ pub async fn sync_single_repository(
}
// Asset in temporäre Datei herunterladen
let temp_file_path = download_to_temp_file(&github_client, &asset.download_url, &asset.name)
.await
.with_context(|| format!("Failed to download asset '{}'", asset.name))?;
let temp_file_path =
download_to_temp_file(&github_client, &asset.download_url, &asset.name)
.await
.with_context(|| format!("Failed to download asset '{}'", asset.name))?;
// Asset auf alle Ziel-Distributions-URLs hochladen
for url in &target_urls {
@@ -168,7 +171,10 @@ pub async fn sync_single_repository(
LogLevel::Debug,
);
match gitea_client.upload_file(&temp_file_path, url, options.dry_run).await {
match gitea_client
.upload_file(&temp_file_path, url, options.dry_run)
.await
{
Ok(UploadStatus::Uploaded) => {
log(
"upload",
@@ -220,13 +226,13 @@ pub async fn sync_single_repository(
}
// Zuletzt synchronisierten Tag persistieren, wenn kein Dry-Run
if !options.dry_run {
if let Some(tag) = latest_synced_tag {
let name_copy = repo_name.to_string();
let _ = modify_config(move |cfg| {
cfg.update_last_synced_tag(&name_copy, tag);
});
}
if !options.dry_run
&& let Some(tag) = latest_synced_tag
{
let name_copy = repo_name.to_string();
let _ = modify_config(move |cfg| {
cfg.update_last_synced_tag(&name_copy, tag);
});
}
report.repositories_processed += 1;
@@ -254,7 +260,10 @@ async fn download_to_temp_file(
log(
"download",
&format!("Downloading '{}' to temporary path {:?}...", filename, temp_path),
&format!(
"Downloading '{}' to temporary path {:?}...",
filename, temp_path
),
LogLevel::Debug,
);
@@ -263,7 +272,11 @@ async fn download_to_temp_file(
.await
.with_context(|| format!("Failed to create temp file {:?}", temp_path))?;
while let Some(chunk) = response.chunk().await.context("Error reading download stream")? {
while let Some(chunk) = response
.chunk()
.await
.context("Error reading download stream")?
{
file.write_all(&chunk)
.await
.context("Error writing chunk to temp file")?;
+10 -9
View File
@@ -1,4 +1,3 @@
/// Sanitizes a string by removing surrounding quotes (single or double).
///
/// # Arguments
@@ -12,7 +11,10 @@ pub fn sanitize_string(input: &str) -> String {
let trimmed = input.trim();
if let Some(stripped) = trimmed.strip_prefix('"').and_then(|s| s.strip_suffix('"')) {
stripped.to_string()
} else if let Some(stripped) = trimmed.strip_prefix('\'').and_then(|s| s.strip_suffix('\'')) {
} else if let Some(stripped) = trimmed
.strip_prefix('\'')
.and_then(|s| s.strip_suffix('\''))
{
stripped.to_string()
} else {
trimmed.to_string()
@@ -25,7 +27,7 @@ pub fn sanitize_string(input: &str) -> String {
///
/// * `env_vars` - A reference to a mutable map of environment variables.
pub fn sanitize_env_vars(env_vars: &mut std::collections::HashMap<String, String>) {
for (_key, value) in env_vars.iter_mut() {
for value in env_vars.values_mut() {
*value = sanitize_string(value);
}
}
@@ -35,15 +37,14 @@ pub fn sanitize_env_vars(env_vars: &mut std::collections::HashMap<String, String
/// und umgebende Schrägstriche entfernt werden.
pub fn clean_repo_input(input: &str) -> &str {
let mut trimmed = input.trim();
if (trimmed.starts_with('"') && trimmed.ends_with('"'))
|| (trimmed.starts_with('\'') && trimmed.ends_with('\''))
if ((trimmed.starts_with('"') && trimmed.ends_with('"'))
|| (trimmed.starts_with('\'') && trimmed.ends_with('\'')))
&& trimmed.len() >= 2
{
if trimmed.len() >= 2 {
trimmed = trimmed[1..trimmed.len() - 1].trim();
}
trimmed = trimmed[1..trimmed.len() - 1].trim();
}
let without_query_or_fragment = match trimmed.find(|c| c == '?' || c == '#') {
let without_query_or_fragment = match trimmed.find(['?', '#']) {
Some(idx) => &trimmed[..idx],
None => trimmed,
};
+47 -14
View File
@@ -5,14 +5,23 @@ use std::collections::HashMap;
#[test]
fn test_sanitize_env_vars() {
let mut env_vars = HashMap::new();
env_vars.insert("GITEA_URL".to_string(), "\"https://gitea.example.com\"".to_string());
env_vars.insert(
"GITEA_URL".to_string(),
"\"https://gitea.example.com\"".to_string(),
);
env_vars.insert("GITEA_TOKEN".to_string(), "\"token123\"".to_string());
env_vars.insert("REGISTRY_OWNER".to_string(), "\"owner\"".to_string());
env_vars.insert("GITHUB_TOKEN".to_string(), "\"github_token123\"".to_string());
env_vars.insert(
"GITHUB_TOKEN".to_string(),
"\"github_token123\"".to_string(),
);
sanitize_env_vars(&mut env_vars);
assert_eq!(env_vars.get("GITEA_URL").unwrap(), "https://gitea.example.com");
assert_eq!(
env_vars.get("GITEA_URL").unwrap(),
"https://gitea.example.com"
);
assert_eq!(env_vars.get("GITEA_TOKEN").unwrap(), "token123");
assert_eq!(env_vars.get("REGISTRY_OWNER").unwrap(), "owner");
assert_eq!(env_vars.get("GITHUB_TOKEN").unwrap(), "github_token123");
@@ -31,7 +40,10 @@ fn test_load_config_with_env_vars() {
// Only assert if the environment variables are set
if std::env::var("GITEA_URL").is_ok() {
assert_eq!(config.gitea_url, Some("https://gitea.example.com".to_string()));
assert_eq!(
config.gitea_url,
Some("https://gitea.example.com".to_string())
);
assert_eq!(config.gitea_token, Some("token123".to_string()));
assert_eq!(config.registry_owner, Some("owner".to_string()));
assert_eq!(config.github_token, Some("github_token123".to_string()));
@@ -40,8 +52,14 @@ fn test_load_config_with_env_vars() {
#[test]
fn test_sanitize_string() {
assert_eq!(sanitize_string("\"https://gitea.example.com\""), "https://gitea.example.com");
assert_eq!(sanitize_string("'https://gitea.example.com'"), "https://gitea.example.com");
assert_eq!(
sanitize_string("\"https://gitea.example.com\""),
"https://gitea.example.com"
);
assert_eq!(
sanitize_string("'https://gitea.example.com'"),
"https://gitea.example.com"
);
assert_eq!(sanitize_string("\"token123\""), "token123");
assert_eq!(sanitize_string("'token123'"), "token123");
assert_eq!(sanitize_string("\"owner\""), "owner");
@@ -68,11 +86,23 @@ fn test_sanitize_string() {
#[test]
fn test_clean_repo_input() {
assert_eq!(clean_repo_input("owner/repo"), "owner/repo");
assert_eq!(clean_repo_input("https://github.com/owner/repo"), "owner/repo");
assert_eq!(clean_repo_input("http://github.com/owner/repo"), "owner/repo");
assert_eq!(
clean_repo_input("https://github.com/owner/repo"),
"owner/repo"
);
assert_eq!(
clean_repo_input("http://github.com/owner/repo"),
"owner/repo"
);
assert_eq!(clean_repo_input("github.com/owner/repo"), "owner/repo");
assert_eq!(clean_repo_input("https://github.com/owner/repo.git"), "owner/repo");
assert_eq!(clean_repo_input("https://github.com/owner/repo/"), "owner/repo");
assert_eq!(
clean_repo_input("https://github.com/owner/repo.git"),
"owner/repo"
);
assert_eq!(
clean_repo_input("https://github.com/owner/repo/"),
"owner/repo"
);
assert_eq!(
clean_repo_input("https://github.com/raspberrypi/rpi-imager?tab=readme-ov-file"),
"raspberrypi/rpi-imager"
@@ -123,14 +153,14 @@ fn test_add_or_update_repo() {
config.add_or_update_repo(repo.clone());
assert_eq!(config.repositories.len(), 1);
assert_eq!(config.repositories[0].name, "owner/repo");
assert_eq!(config.repositories[0].include_prereleases, true);
assert!(config.repositories[0].include_prereleases);
// Updating existing repo with a URL with query param
let repo_updated = RepoConfig::new("https://github.com/owner/repo#readme", false);
config.add_or_update_repo(repo_updated);
assert_eq!(config.repositories.len(), 1);
assert_eq!(config.repositories[0].name, "owner/repo");
assert_eq!(config.repositories[0].include_prereleases, false);
assert!(!config.repositories[0].include_prereleases);
}
#[test]
@@ -159,5 +189,8 @@ fn test_update_last_synced_tag() {
let repo = RepoConfig::new("owner/repo", true);
config.add_or_update_repo(repo.clone());
config.update_last_synced_tag("owner/repo", "v1.0.0".to_string());
assert_eq!(config.find_repo("owner/repo").unwrap().last_synced_tag, Some("v1.0.0".to_string()));
}
assert_eq!(
config.find_repo("owner/repo").unwrap().last_synced_tag,
Some("v1.0.0".to_string())
);
}
+20 -8
View File
@@ -41,7 +41,10 @@ fn test_package_classification() {
);
// Nicht unterstützte Paketformate sollten ignoriert werden
assert_eq!(PackageType::from_filename("rpi-imager-1.8.5.AppImage"), None);
assert_eq!(
PackageType::from_filename("rpi-imager-1.8.5.AppImage"),
None
);
assert_eq!(PackageType::from_filename("rpi-imager-1.8.5.dmg"), None);
assert_eq!(PackageType::from_filename("rpi-imager-1.8.5.exe"), None);
assert_eq!(PackageType::from_filename("source-code.tar.gz"), None);
@@ -57,19 +60,25 @@ fn test_parse_repo_owner_name() {
("raspberrypi", "rpi-imager")
);
assert_eq!(
parse_repo_owner_name("https://github.com/Heroic-Games-Launcher/HeroicGamesLauncher").unwrap(),
parse_repo_owner_name("https://github.com/Heroic-Games-Launcher/HeroicGamesLauncher")
.unwrap(),
("Heroic-Games-Launcher", "HeroicGamesLauncher")
);
assert_eq!(
parse_repo_owner_name("https://github.com/Heroic-Games-Launcher/HeroicGamesLauncher.git").unwrap(),
parse_repo_owner_name("https://github.com/Heroic-Games-Launcher/HeroicGamesLauncher.git")
.unwrap(),
("Heroic-Games-Launcher", "HeroicGamesLauncher")
);
assert_eq!(
parse_repo_owner_name("https://github.com/raspberrypi/rpi-imager?tab=readme-ov-file").unwrap(),
parse_repo_owner_name("https://github.com/raspberrypi/rpi-imager?tab=readme-ov-file")
.unwrap(),
("raspberrypi", "rpi-imager")
);
assert_eq!(
parse_repo_owner_name("https://github.com/raspberrypi/rpi-imager/?tab=readme-ov-file#install").unwrap(),
parse_repo_owner_name(
"https://github.com/raspberrypi/rpi-imager/?tab=readme-ov-file#install"
)
.unwrap(),
("raspberrypi", "rpi-imager")
);
assert_eq!(
@@ -86,14 +95,17 @@ async fn test_github_client_empty_token() {
use mirror_package::github::GitHubClient;
// Test that a client with an empty or whitespace token sanitizes it to None
let client = GitHubClient::new(Some("".to_string())).expect("Failed to create client with empty token");
let client =
GitHubClient::new(Some("".to_string())).expect("Failed to create client with empty token");
assert_eq!(client.token(), None);
let client_whitespace = GitHubClient::new(Some(" ".to_string())).expect("Failed to create client with whitespace token");
let client_whitespace = GitHubClient::new(Some(" ".to_string()))
.expect("Failed to create client with whitespace token");
assert_eq!(client_whitespace.token(), None);
// Test with a valid token
let client_with_token = GitHubClient::new(Some("valid_token".to_string())).expect("Failed to create client with valid token");
let client_with_token = GitHubClient::new(Some("valid_token".to_string()))
.expect("Failed to create client with valid token");
assert_eq!(client_with_token.token(), Some("valid_token"));
// Test with no token