Author SHA1 Message Date
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
13 changed files with 601 additions and 4 deletions
+11
View File
@@ -19,6 +19,17 @@ jobs:
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: Install Cross-Compilation Toolchains & Dependencies
run: |
sudo apt-get update
+25
View File
@@ -0,0 +1,25 @@
name: Renovate
on:
schedule:
- cron: "0 4 * * 1"
workflow_dispatch:
jobs:
renovate:
name: Dependency-Updates prüfen & Pull Requests erstellen
runs-on: ubuntu-latest
container: ghcr.io/renovatebot/renovate:44.79.2
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_GIT_AUTHOR: "Renovate Bot <renovate-bot@creative-dragonslayer.de>"
RENOVATE_HOST_RULES: >-
[{"hostType":"cargo","matchHost":"gitea.creative-dragonslayer.de","token":"${{ secrets.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
+11
View File
@@ -19,6 +19,17 @@ jobs:
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: Install Cross-Compilation Toolchains & Dependencies
run: |
sudo apt-get update
+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
+1
View File
@@ -109,3 +109,4 @@ fabric.properties
# Built Visual Studio Code Extensions
*.vsix
.junie/plans
+9
View File
@@ -17,6 +17,15 @@
<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>
</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" />
Generated
+1 -2
View File
@@ -866,7 +866,7 @@ dependencies = [
[[package]]
name = "mirror-package"
version = "1.0.2"
version = "1.0.3"
dependencies = [
"anyhow",
"clap",
@@ -874,7 +874,6 @@ dependencies = [
"logger-ctdra",
"reqwest",
"serde",
"serde_json",
"tokio",
]
+1 -2
View File
@@ -1,6 +1,6 @@
[package]
name = "mirror-package"
version = "1.0.2"
version = "1.0.3"
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]
+59
View File
@@ -0,0 +1,59 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": ["config:recommended"],
"timezone": "Europe/Berlin",
"schedule": ["before 6am on monday"],
"baseBranches": ["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",
"fileMatch": ["^\\.gitea/workflows/.+\\.ya?ml$"],
"matchStrings": [
"TRIVY_VERSION:\\s*\"(?<currentValue>[^\"]+)\""
],
"depNameTemplate": "aquasecurity/trivy",
"datasourceTemplate": "github-releases",
"extractVersionTemplate": "^v(?<version>.*)$"
},
{
"customType": "regex",
"fileMatch": ["^\\.gitea/workflows/.+\\.ya?ml$"],
"matchStrings": [
"OSV_SCANNER_VERSION:\\s*\"(?<currentValue>[^\"]+)\""
],
"depNameTemplate": "google/osv-scanner",
"datasourceTemplate": "github-releases",
"extractVersionTemplate": "^v(?<version>.*)$"
},
{
"customType": "regex",
"fileMatch": ["^\\.gitea/workflows/.+\\.ya?ml$"],
"matchStrings": [
"TRUFFLEHOG_VERSION:\\s*\"(?<currentValue>[^\"]+)\""
],
"depNameTemplate": "trufflesecurity/trufflehog",
"datasourceTemplate": "github-releases",
"extractVersionTemplate": "^v(?<version>.*)$"
}
]
}
+308
View File
@@ -0,0 +1,308 @@
#!/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["GITEA_URL"].rstrip("/")
repo = os.environ["REPO"]
token = os.environ["TOKEN"]
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)
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()