Phase 8a+8b: Pre-Commit-Hook fuer shared/-Drift + Audit-UI resource_id-Filter
Phase 8a (Hook): - scripts/git-hooks/pre-commit: prueft bei Commits mit src/shared/-Aenderungen den Drift-Stand via sync_shared.py --check und gibt eine Warnung aus (blockiert NICHT - User entscheidet selbst, ob er zurueck will). - scripts/install-hooks.sh: kopiert Hooks aus scripts/git-hooks/ nach .git/hooks/ (idempotent, ueberspringt user-eigene Hooks). Phase 8b (Audit-UI): - dashboard.html: Resource-ID Eingabefeld neben den anderen Audit-Filtern. - audit.js: Filter-Listen erweitern, params um resource_id ergaenzt (Backend hatte den Filter seit Phase 5 schon). - Damit ist die Audit-Spur einer einzelnen Ressource auch im Audit-Log-Tab filterbar (vorher nur per Direkt-URL bzw. per Quellen-Audit-Modal).
Dieser Commit ist enthalten in:
44
scripts/git-hooks/pre-commit
Ausführbare Datei
44
scripts/git-hooks/pre-commit
Ausführbare Datei
@@ -0,0 +1,44 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# AegisSight-Verwaltung Pre-Commit-Hook.
|
||||||
|
#
|
||||||
|
# Ueberprueft bei jeder Aenderung in src/shared/ den Drift-Stand gegen das
|
||||||
|
# Monitor-Repo. Gibt eine Warnung aus, BLOCKIERT den Commit aber NICHT -
|
||||||
|
# der User entscheidet selbst, ob er zurueck will.
|
||||||
|
#
|
||||||
|
# Installation: scripts/install-hooks.sh
|
||||||
|
|
||||||
|
REPO_ROOT="$(git rev-parse --show-toplevel)"
|
||||||
|
cd "$REPO_ROOT" || exit 0
|
||||||
|
|
||||||
|
# Nur prüfen wenn shared/ geändert wird
|
||||||
|
if ! git diff --cached --name-only | grep -q '^src/shared/'; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# venv-Python finden
|
||||||
|
PY=""
|
||||||
|
for cand in "venv/bin/python3" "venv/bin/python" "/home/claude-dev/.venvs/verwaltung/bin/python3"; do
|
||||||
|
if [ -x "$cand" ]; then PY="$cand"; break; fi
|
||||||
|
done
|
||||||
|
if [ -z "$PY" ] || [ ! -f "scripts/sync_shared.py" ]; then
|
||||||
|
# Tool nicht verfuegbar - silent durchlassen
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! out=$("$PY" scripts/sync_shared.py --check 2>&1); then
|
||||||
|
# --check Exit 1 = auto-syncbarer Drift vorhanden
|
||||||
|
echo ""
|
||||||
|
echo "================================================================"
|
||||||
|
echo " WARNUNG: src/shared/ Drift gegen Monitor-Repo erkannt"
|
||||||
|
echo "================================================================"
|
||||||
|
echo "$out" | head -30
|
||||||
|
echo ""
|
||||||
|
echo " Mehr Details: ./venv/bin/python scripts/sync_shared.py --check"
|
||||||
|
echo " Aufloesen: ./venv/bin/python scripts/sync_shared.py --apply"
|
||||||
|
echo " (oder bewusst forken: LOCKED_FILES in scripts/sync_shared.py)"
|
||||||
|
echo ""
|
||||||
|
echo " Commit laeuft trotzdem durch - du entscheidest."
|
||||||
|
echo "================================================================"
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit 0
|
||||||
40
scripts/install-hooks.sh
Ausführbare Datei
40
scripts/install-hooks.sh
Ausführbare Datei
@@ -0,0 +1,40 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Installiert die Git-Hooks aus scripts/git-hooks/ in die lokale Repo-Konfig.
|
||||||
|
#
|
||||||
|
# Nutzung: ./scripts/install-hooks.sh
|
||||||
|
#
|
||||||
|
# Idempotent: Bereits installierte Hooks werden nur ueberschrieben wenn
|
||||||
|
# sie aus scripts/git-hooks/ kommen (Marker-Check), nicht user-eigene.
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
REPO_ROOT="$(git rev-parse --show-toplevel)"
|
||||||
|
SRC_DIR="$REPO_ROOT/scripts/git-hooks"
|
||||||
|
DST_DIR="$REPO_ROOT/.git/hooks"
|
||||||
|
|
||||||
|
if [ ! -d "$SRC_DIR" ]; then
|
||||||
|
echo "FEHLER: $SRC_DIR nicht gefunden" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "$DST_DIR"
|
||||||
|
|
||||||
|
count=0
|
||||||
|
for hook in "$SRC_DIR"/*; do
|
||||||
|
[ -f "$hook" ] || continue
|
||||||
|
name="$(basename "$hook")"
|
||||||
|
target="$DST_DIR/$name"
|
||||||
|
|
||||||
|
# Wenn Ziel existiert und kein AegisSight-Marker drin: ueberspringen
|
||||||
|
if [ -f "$target" ] && ! grep -q "AegisSight-Verwaltung Pre-Commit-Hook\|AegisSight-Verwaltung Hook" "$target" 2>/dev/null; then
|
||||||
|
echo " ! $name uebersprungen (existiert, kein AegisSight-Marker)"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
cp "$hook" "$target"
|
||||||
|
chmod +x "$target"
|
||||||
|
echo " + $name installiert"
|
||||||
|
count=$((count + 1))
|
||||||
|
done
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "$count Hook(s) installiert nach $DST_DIR"
|
||||||
@@ -393,6 +393,7 @@
|
|||||||
<select class="filter-select" id="auditFilterResource">
|
<select class="filter-select" id="auditFilterResource">
|
||||||
<option value="">Alle Ressourcen</option>
|
<option value="">Alle Ressourcen</option>
|
||||||
</select>
|
</select>
|
||||||
|
<input type="number" class="filter-select" id="auditFilterResourceId" placeholder="Ressourcen-ID" min="1" style="width:130px;">
|
||||||
<select class="filter-select" id="auditFilterAdmin">
|
<select class="filter-select" id="auditFilterAdmin">
|
||||||
<option value="">Alle Admins</option>
|
<option value="">Alle Admins</option>
|
||||||
</select>
|
</select>
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Filter-Inputs verdrahten
|
// Filter-Inputs verdrahten
|
||||||
["auditFilterAction", "auditFilterResource", "auditFilterAdmin",
|
["auditFilterAction", "auditFilterResource", "auditFilterResourceId", "auditFilterAdmin",
|
||||||
"auditFilterFrom", "auditFilterTo"].forEach((id) => {
|
"auditFilterFrom", "auditFilterTo"].forEach((id) => {
|
||||||
const el = document.getElementById(id);
|
const el = document.getElementById(id);
|
||||||
if (el) el.addEventListener("change", () => { auditCache.offset = 0; loadAudit(); });
|
if (el) el.addEventListener("change", () => { auditCache.offset = 0; loadAudit(); });
|
||||||
@@ -112,12 +112,14 @@ async function loadAudit() {
|
|||||||
const params = new URLSearchParams();
|
const params = new URLSearchParams();
|
||||||
const action = document.getElementById("auditFilterAction")?.value;
|
const action = document.getElementById("auditFilterAction")?.value;
|
||||||
const resource = document.getElementById("auditFilterResource")?.value;
|
const resource = document.getElementById("auditFilterResource")?.value;
|
||||||
|
const resourceId = document.getElementById("auditFilterResourceId")?.value;
|
||||||
const adminId = document.getElementById("auditFilterAdmin")?.value;
|
const adminId = document.getElementById("auditFilterAdmin")?.value;
|
||||||
const from = document.getElementById("auditFilterFrom")?.value;
|
const from = document.getElementById("auditFilterFrom")?.value;
|
||||||
const to = document.getElementById("auditFilterTo")?.value;
|
const to = document.getElementById("auditFilterTo")?.value;
|
||||||
|
|
||||||
if (action) params.append("action", action);
|
if (action) params.append("action", action);
|
||||||
if (resource) params.append("resource_type", resource);
|
if (resource) params.append("resource_type", resource);
|
||||||
|
if (resourceId) params.append("resource_id", resourceId);
|
||||||
if (adminId) params.append("admin_id", adminId);
|
if (adminId) params.append("admin_id", adminId);
|
||||||
if (from) params.append("from_ts", from);
|
if (from) params.append("from_ts", from);
|
||||||
if (to) params.append("to_ts", to);
|
if (to) params.append("to_ts", to);
|
||||||
|
|||||||
In neuem Issue referenzieren
Einen Benutzer sperren