Consolidates three codebases into a single agent orchestration repo: - agentci (from go-scm): Clotho dual-run verification, agent config, SSH security (sanitisation, secure commands, token masking) - jobrunner (from go-scm): Poll-dispatch-report pipeline with 7 handlers (dispatch, completion, auto-merge, publish draft, dismiss reviews, send fix command, tick parent epic) - plugins marketplace (from agentic/plugins): 27 Claude/Codex/Gemini plugins with shared MCP server All 150+ tests passing across 6 packages. Co-Authored-By: Virgil <virgil@lethean.io>
92 lines
3.4 KiB
Bash
Executable file
92 lines
3.4 KiB
Bash
Executable file
#!/bin/bash
|
|
# Sovereign security scanning — local developer workflow
|
|
# Usage: security-scan.sh [path] [--fix]
|
|
# Runs: govulncheck, gitleaks, trivy
|
|
# No cloud dependencies. PCI DSS Req 6.3.2 / 11.3 compliant.
|
|
|
|
set -euo pipefail
|
|
|
|
TARGET="${1:-.}"
|
|
FIX_MODE="${2:-}"
|
|
PASS=0
|
|
FAIL=0
|
|
WARN=0
|
|
|
|
GREEN='\033[0;32m'
|
|
RED='\033[0;31m'
|
|
YELLOW='\033[0;33m'
|
|
DIM='\033[0;90m'
|
|
RESET='\033[0m'
|
|
|
|
header() { echo -e "\n${GREEN}=== $1 ===${RESET}"; }
|
|
pass() { echo -e " ${GREEN}PASS${RESET} $1"; ((PASS++)); }
|
|
fail() { echo -e " ${RED}FAIL${RESET} $1"; ((FAIL++)); }
|
|
warn() { echo -e " ${YELLOW}WARN${RESET} $1"; ((WARN++)); }
|
|
dim() { echo -e " ${DIM}$1${RESET}"; }
|
|
|
|
echo "Security Scan: $(realpath "$TARGET")"
|
|
echo "Date: $(date -u +"%Y-%m-%dT%H:%M:%SZ")"
|
|
|
|
# --- Go vulnerability check ---
|
|
if [ -f "$TARGET/go.mod" ]; then
|
|
header "Go Vulnerability Check (govulncheck)"
|
|
GOVULNCHECK=$(command -v govulncheck 2>/dev/null || echo "$HOME/go/bin/govulncheck")
|
|
if [ -x "$GOVULNCHECK" ]; then
|
|
GOVULN_OUT=$( (cd "$TARGET" && $GOVULNCHECK ./... 2>&1) || true)
|
|
if echo "$GOVULN_OUT" | grep -q "No vulnerabilities found"; then
|
|
pass "No Go vulnerabilities found"
|
|
else
|
|
VULN_COUNT=$(echo "$GOVULN_OUT" | grep -c "^Vulnerability #" || true)
|
|
if [ "$VULN_COUNT" -gt 0 ]; then
|
|
warn "$VULN_COUNT Go vulnerabilities found (run govulncheck ./... for details)"
|
|
else
|
|
pass "govulncheck completed"
|
|
fi
|
|
fi
|
|
else
|
|
dim "govulncheck not installed (go install golang.org/x/vuln/cmd/govulncheck@latest)"
|
|
fi
|
|
fi
|
|
|
|
# --- Secret detection ---
|
|
header "Secret Detection (gitleaks)"
|
|
GITLEAKS=$(command -v gitleaks 2>/dev/null || echo "$HOME/.local/bin/gitleaks")
|
|
if [ -x "$GITLEAKS" ]; then
|
|
if $GITLEAKS detect --source "$TARGET" --no-banner --no-git 2>&1 | grep -q "no leaks found"; then
|
|
pass "No secrets detected in working tree"
|
|
else
|
|
LEAK_COUNT=$($GITLEAKS detect --source "$TARGET" --no-banner --no-git --report-format json --report-path /dev/stdout 2>/dev/null | python3 -c "import sys,json; print(len(json.load(sys.stdin)))" 2>/dev/null || echo "?")
|
|
fail "$LEAK_COUNT potential secrets found (run gitleaks detect --source $TARGET -v)"
|
|
fi
|
|
else
|
|
dim "gitleaks not installed"
|
|
fi
|
|
|
|
# --- Dependency & filesystem scan ---
|
|
header "Dependency Scan (trivy)"
|
|
TRIVY=$(command -v trivy 2>/dev/null || echo "$HOME/.local/bin/trivy")
|
|
if [ -x "$TRIVY" ]; then
|
|
TRIVY_OUT=$($TRIVY fs --scanners vuln --severity HIGH,CRITICAL --quiet "$TARGET" 2>&1 || true)
|
|
if echo "$TRIVY_OUT" | grep -q "Total: 0"; then
|
|
pass "No HIGH/CRITICAL vulnerabilities in dependencies"
|
|
elif [ -z "$TRIVY_OUT" ]; then
|
|
pass "No vulnerable dependencies found"
|
|
else
|
|
TRIVY_VULNS=$(echo "$TRIVY_OUT" | grep -oP 'Total: \K\d+' | awk '{s+=$1}END{print s}' 2>/dev/null || echo "?")
|
|
warn "$TRIVY_VULNS HIGH/CRITICAL dependency vulnerabilities"
|
|
echo "$TRIVY_OUT" | grep -E '│|Total:' | head -20
|
|
fi
|
|
else
|
|
dim "trivy not installed"
|
|
fi
|
|
|
|
# --- Summary ---
|
|
echo ""
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
echo -e " ${GREEN}PASS: $PASS${RESET} ${YELLOW}WARN: $WARN${RESET} ${RED}FAIL: $FAIL${RESET}"
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
|
|
if [ "$FAIL" -gt 0 ]; then
|
|
exit 1
|
|
fi
|
|
exit 0
|