commit dec741f11d307a5278cb5b88cd82ca982d1019fc Author: Travis Date: Sat Apr 18 11:30:24 2026 -0400 v1 gauntlet: validation scripts with language detection and artifact generation diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..505a3b1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +# Python-generated files +__pycache__/ +*.py[oc] +build/ +dist/ +wheels/ +*.egg-info + +# Virtual environments +.venv diff --git a/.python-version b/.python-version new file mode 100644 index 0000000..e4fba21 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.12 diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/check-deps.sh b/check-deps.sh new file mode 100755 index 0000000..7e88ea6 --- /dev/null +++ b/check-deps.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash +set -euo pipefail + +RED='\033[0;31m' +GREEN='\033[0;32m' +NC='\033[0m' + +missing=0 + +check() { + if command -v "$1" &>/dev/null; then + printf "${GREEN}✓${NC} %s found: %s\n" "$1" "$(command -v "$1")" + else + printf "${RED}✗${NC} %s not found\n" "$1" + missing=$((missing + 1)) + fi +} + +echo "=== Zero-Check Pipeline: Dependency Check ===" +echo "" +echo "-- Core --" +check git +check docker +check uv + +echo "" +echo "-- Python toolchain --" +check ruff +check semgrep +check gitleaks +check pip-audit +check pytest + +echo "" +echo "-- Go toolchain --" +check go +check golangci-lint +check govulncheck + +echo "" +if [ "$missing" -gt 0 ]; then + echo "Missing $missing tool(s). Install before running the gauntlet." + exit 1 +else + echo "All tools found. Ready to validate." + exit 0 +fi \ No newline at end of file diff --git a/main.py b/main.py new file mode 100644 index 0000000..6ebf0dd --- /dev/null +++ b/main.py @@ -0,0 +1,6 @@ +def main(): + print("Hello from zero-check-pipeline!") + + +if __name__ == "__main__": + main() diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..f1c2b57 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,9 @@ +[project] +name = "zero-check-pipeline" +version = "0.1.0" +description = "Add your description here" +readme = "README.md" +requires-python = ">=3.12" +dependencies = [ + "ruff>=0.15.11", +] diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000..06d9741 --- /dev/null +++ b/uv.lock @@ -0,0 +1,39 @@ +version = 1 +revision = 3 +requires-python = ">=3.12" + +[[package]] +name = "ruff" +version = "0.15.11" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e4/8d/192f3d7103816158dfd5ea50d098ef2aec19194e6cbccd4b3485bdb2eb2d/ruff-0.15.11.tar.gz", hash = "sha256:f092b21708bf0e7437ce9ada249dfe688ff9a0954fc94abab05dcea7dcd29c33", size = 4637264, upload-time = "2026-04-16T18:46:26.58Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/02/1e/6aca3427f751295ab011828e15e9bf452200ac74484f1db4be0197b8170b/ruff-0.15.11-py3-none-linux_armv6l.whl", hash = "sha256:e927cfff503135c558eb581a0c9792264aae9507904eb27809cdcff2f2c847b7", size = 10607943, upload-time = "2026-04-16T18:46:05.967Z" }, + { url = "https://files.pythonhosted.org/packages/e7/26/1341c262e74f36d4e84f3d6f4df0ac68cd53331a66bfc5080daa17c84c0b/ruff-0.15.11-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:7a1b5b2938d8f890b76084d4fa843604d787a912541eae85fd7e233398bbb73e", size = 10988592, upload-time = "2026-04-16T18:46:00.742Z" }, + { url = "https://files.pythonhosted.org/packages/03/71/850b1d6ffa9564fbb6740429bad53df1094082fe515c8c1e74b6d8d05f18/ruff-0.15.11-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d4176f3d194afbdaee6e41b9ccb1a2c287dba8700047df474abfbe773825d1cb", size = 10338501, upload-time = "2026-04-16T18:46:03.723Z" }, + { url = "https://files.pythonhosted.org/packages/f2/11/cc1284d3e298c45a817a6aadb6c3e1d70b45c9b36d8d9cce3387b495a03a/ruff-0.15.11-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b17c886fb88203ced3afe7f14e8d5ae96e9d2f4ccc0ee66aa19f2c2675a27e4", size = 10670693, upload-time = "2026-04-16T18:46:41.941Z" }, + { url = "https://files.pythonhosted.org/packages/ce/9e/f8288b034ab72b371513c13f9a41d9ba3effac54e24bfb467b007daee2ca/ruff-0.15.11-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:49fafa220220afe7758a487b048de4c8f9f767f37dfefad46b9dd06759d003eb", size = 10416177, upload-time = "2026-04-16T18:46:21.717Z" }, + { url = "https://files.pythonhosted.org/packages/85/71/504d79abfd3d92532ba6bbe3d1c19fada03e494332a59e37c7c2dabae427/ruff-0.15.11-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2ab8427e74a00d93b8bda1307b1e60970d40f304af38bccb218e056c220120d", size = 11221886, upload-time = "2026-04-16T18:46:15.086Z" }, + { url = "https://files.pythonhosted.org/packages/43/5a/947e6ab7a5ad603d65b474be15a4cbc6d29832db5d762cd142e4e3a74164/ruff-0.15.11-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:195072c0c8e1fc8f940652073df082e37a5d9cb43b4ab1e4d0566ab8977a13b7", size = 12075183, upload-time = "2026-04-16T18:46:07.944Z" }, + { url = "https://files.pythonhosted.org/packages/9f/a1/0b7bb6268775fdd3a0818aee8efd8f5b4e231d24dd4d528ced2534023182/ruff-0.15.11-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a3a0996d486af3920dec930a2e7daed4847dfc12649b537a9335585ada163e9e", size = 11516575, upload-time = "2026-04-16T18:46:31.687Z" }, + { url = "https://files.pythonhosted.org/packages/30/c3/bb5168fc4d233cc06e95f482770d0f3c87945a0cd9f614b90ea8dc2f2833/ruff-0.15.11-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1bef2cb556d509259f1fe440bb9cd33c756222cf0a7afe90d15edf0866702431", size = 11306537, upload-time = "2026-04-16T18:46:36.988Z" }, + { url = "https://files.pythonhosted.org/packages/e4/92/4cfae6441f3967317946f3b788136eecf093729b94d6561f963ed810c82e/ruff-0.15.11-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:030d921a836d7d4a12cf6e8d984a88b66094ccb0e0f17ddd55067c331191bf19", size = 11296813, upload-time = "2026-04-16T18:46:24.182Z" }, + { url = "https://files.pythonhosted.org/packages/43/26/972784c5dde8313acde8ac71ba8ac65475b85db4a2352a76c9934361f9bc/ruff-0.15.11-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:0e783b599b4577788dbbb66b9addcef87e9a8832f4ce0c19e34bf55543a2f890", size = 10633136, upload-time = "2026-04-16T18:46:39.802Z" }, + { url = "https://files.pythonhosted.org/packages/5b/53/3985a4f185020c2f367f2e08a103032e12564829742a1b417980ce1514a0/ruff-0.15.11-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:ae90592246625ba4a34349d68ec28d4400d75182b71baa196ddb9f82db025ef5", size = 10424701, upload-time = "2026-04-16T18:46:10.381Z" }, + { url = "https://files.pythonhosted.org/packages/d3/57/bf0dfb32241b56c83bb663a826133da4bf17f682ba8c096973065f6e6a68/ruff-0.15.11-py3-none-musllinux_1_2_i686.whl", hash = "sha256:1f111d62e3c983ed20e0ca2e800f8d77433a5b1161947df99a5c2a3fb60514f0", size = 10873887, upload-time = "2026-04-16T18:46:29.157Z" }, + { url = "https://files.pythonhosted.org/packages/02/05/e48076b2a57dc33ee8c7a957296f97c744ca891a8ffb4ffb1aaa3b3f517d/ruff-0.15.11-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:06f483d6646f59eaffba9ae30956370d3a886625f511a3108994000480621d1c", size = 11404316, upload-time = "2026-04-16T18:46:19.462Z" }, + { url = "https://files.pythonhosted.org/packages/88/27/0195d15fe7a897cbcba0904792c4b7c9fdd958456c3a17d2ea6093716a9a/ruff-0.15.11-py3-none-win32.whl", hash = "sha256:476a2aa56b7da0b73a3ee80b6b2f0e19cce544245479adde7baa65466664d5f3", size = 10655535, upload-time = "2026-04-16T18:46:12.47Z" }, + { url = "https://files.pythonhosted.org/packages/3a/5e/c927b325bd4c1d3620211a4b96f47864633199feed60fa936025ab27e090/ruff-0.15.11-py3-none-win_amd64.whl", hash = "sha256:8b6756d88d7e234fb0c98c91511aae3cd519d5e3ed271cae31b20f39cb2a12a3", size = 11779692, upload-time = "2026-04-16T18:46:17.268Z" }, + { url = "https://files.pythonhosted.org/packages/63/b6/aeadee5443e49baa2facd51131159fd6301cc4ccfc1541e4df7b021c37dd/ruff-0.15.11-py3-none-win_arm64.whl", hash = "sha256:063fed18cc1bbe0ee7393957284a6fe8b588c6a406a285af3ee3f46da2391ee4", size = 11032614, upload-time = "2026-04-16T18:46:34.487Z" }, +] + +[[package]] +name = "zero-check-pipeline" +version = "0.1.0" +source = { virtual = "." } +dependencies = [ + { name = "ruff" }, +] + +[package.metadata] +requires-dist = [{ name = "ruff", specifier = ">=0.15.11" }] diff --git a/validate/SUMMARY.md b/validate/SUMMARY.md new file mode 100644 index 0000000..0089724 --- /dev/null +++ b/validate/SUMMARY.md @@ -0,0 +1,15 @@ +# Validation Summary + +**Date:** 2026-04-18T15:20:48Z +**Target:** . +**Result:** passed + +| Check | Status | +|---------|--------| +| Secrets | passed | +| Lint | passed | +| SAST | passed | +| Deps | passed | +| Tests | passed | + +**Totals:** 5 passed, 0 failed, 0 skipped diff --git a/validate/deps.sh b/validate/deps.sh new file mode 100755 index 0000000..9888dcc --- /dev/null +++ b/validate/deps.sh @@ -0,0 +1,67 @@ +#!/usr/bin/env bash +set -euo pipefail + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[0;33m' +NC='\033[0m' + +TARGET="${1:-.}" +errors=0 + +echo "=== Dependency Audit ===" + +has_reqtxt=$(find "$TARGET" -maxdepth 2 -name "requirements*.txt" | head -1) +has_pyproject=$(find "$TARGET" -maxdepth 2 -name "pyproject.toml" | head -1) +has_python="${has_reqtxt}${has_pyproject}" +has_gomod=$(find "$TARGET" -maxdepth 2 -name "go.mod" | head -1) + +if [ -z "$has_python" ] && [ -z "$has_gomod" ]; then + printf "${YELLOW}!${NC} No dependency files found — skipping\n" + exit 0 +fi + +if [ -n "$has_python" ]; then + if ! command -v pip-audit &>/dev/null; then + printf "${RED}✗${NC} pip-audit not installed\n" + exit 2 + fi + + echo "-- Python (pip-audit) --" + if [ -n "$has_reqtxt" ]; then + printf " source: %s (requirements file)\n" "$has_reqtxt" + audit_cmd="pip-audit -r $has_reqtxt" + else + printf " source: %s (environment mode)\n" "$has_pyproject" + audit_cmd="pip-audit" + fi + + if $audit_cmd 2>/dev/null; then + printf "${GREEN}✓${NC} No known vulnerabilities in Python dependencies\n" + else + printf "${RED}✗${NC} Vulnerable Python dependencies found\n" + errors=$((errors + 1)) + fi +fi + +if [ -n "$has_gomod" ]; then + if ! command -v govulncheck &>/dev/null; then + printf "${YELLOW}!${NC} govulncheck not installed — skipping Go audit\n" + else + echo "-- Go (govulncheck) --" + printf " source: %s\n" "$has_gomod" + gomod_dir=$(dirname "$has_gomod") + if (cd "$gomod_dir" && govulncheck ./... 2>/dev/null); then + printf "${GREEN}✓${NC} No known vulnerabilities in Go dependencies\n" + else + printf "${RED}✗${NC} Vulnerable Go dependencies found\n" + errors=$((errors + 1)) + fi + fi +fi + +if [ "$errors" -gt 0 ]; then + exit 1 +else + exit 0 +fi \ No newline at end of file diff --git a/validate/lint.sh b/validate/lint.sh new file mode 100755 index 0000000..7a0550f --- /dev/null +++ b/validate/lint.sh @@ -0,0 +1,55 @@ +#!/usr/bin/env bash +set -euo pipefail + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[0;33m' +NC='\033[0m' + +TARGET="${1:-.}" +errors=0 + +echo "=== Lint Scan ===" + +has_python=$(find "$TARGET" -name "*.py" -not -path "*/.*" | head -1) +has_go=$(find "$TARGET" -name "*.go" -not -path "*/.*" | head -1) + +if [ -z "$has_python" ] && [ -z "$has_go" ]; then + printf "${YELLOW}!${NC} No Python or Go files found — skipping\n" + exit 0 +fi + +if [ -n "$has_python" ]; then + if ! command -v ruff &>/dev/null; then + printf "${RED}✗${NC} ruff not installed\n" + exit 2 + fi + + echo "-- Python (ruff) --" + if ruff check "$TARGET" 2>/dev/null; then + printf "${GREEN}✓${NC} Python lint clean\n" + else + printf "${RED}✗${NC} Python lint errors found\n" + errors=$((errors + 1)) + fi +fi + +if [ -n "$has_go" ]; then + if ! command -v golangci-lint &>/dev/null; then + printf "${YELLOW}!${NC} golangci-lint not installed — skipping Go lint\n" + else + echo "-- Go (golangci-lint) --" + if golangci-lint run "$TARGET/..." 2>/dev/null; then + printf "${GREEN}✓${NC} Go lint clean\n" + else + printf "${RED}✗${NC} Go lint errors found\n" + errors=$((errors + 1)) + fi + fi +fi + +if [ "$errors" -gt 0 ]; then + exit 1 +else + exit 0 +fi \ No newline at end of file diff --git a/validate/results.json b/validate/results.json new file mode 100644 index 0000000..0936ae9 --- /dev/null +++ b/validate/results.json @@ -0,0 +1,15 @@ +{ + "timestamp": "2026-04-18T15:20:48Z", + "target": ".", + "overall": "passed", + "passed": 5, + "failed": 0, + "skipped": 0, + "checks": { + "secrets": "passed", + "lint": "passed", + "sast": "passed", + "deps": "passed", + "tests": "passed" + } +} diff --git a/validate/run-all.sh b/validate/run-all.sh new file mode 100755 index 0000000..cf78f97 --- /dev/null +++ b/validate/run-all.sh @@ -0,0 +1,109 @@ +#!/usr/bin/env bash +set -euo pipefail + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[0;33m' +NC='\033[0m' + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +TARGET="${1:-.}" +TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ") +RESULTS_FILE="$SCRIPT_DIR/results.json" +SUMMARY_FILE="$SCRIPT_DIR/SUMMARY.md" + +checks=("secrets" "lint" "sast" "deps" "tests") +declare -A results +failed=0 +skipped=0 +passed=0 + +echo "╔══════════════════════════════════════╗" +echo "║ Zero-Check Validation Pipeline ║" +echo "╚══════════════════════════════════════╝" +echo "" +echo "Target: $TARGET" +echo "Time: $TIMESTAMP" +echo "" + +for check in "${checks[@]}"; do + script="$SCRIPT_DIR/${check}.sh" + + if [ ! -x "$script" ]; then + printf "${RED}✗${NC} %s — script not found or not executable\n" "$check" + results[$check]="error" + failed=$((failed + 1)) + continue + fi + + if "$script" "$TARGET"; then + results[$check]="passed" + passed=$((passed + 1)) + else + exit_code=$? + if [ "$exit_code" -eq 2 ]; then + results[$check]="skipped" + skipped=$((skipped + 1)) + else + results[$check]="failed" + failed=$((failed + 1)) + fi + fi + echo "" +done + +echo "════════════════════════════════════════" +if [ "$failed" -gt 0 ]; then + printf "${RED}RESULT: %d passed, %d failed, %d skipped${NC}\n" "$passed" "$failed" "$skipped" + overall="failed" +else + printf "${GREEN}RESULT: %d passed, %d failed, %d skipped${NC}\n" "$passed" "$failed" "$skipped" + overall="passed" +fi + +cat > "$RESULTS_FILE" < "$SUMMARY_FILE" </dev/null; then + printf "${RED}✗${NC} semgrep not installed\n" + exit 2 +fi + +has_python=$(find "$TARGET" -name "*.py" -not -path "*/.*" | head -1) +has_go=$(find "$TARGET" -name "*.go" -not -path "*/.*" | head -1) + +if [ -z "$has_python" ] && [ -z "$has_go" ]; then + printf "${YELLOW}!${NC} No Python or Go files found — skipping\n" + exit 0 +fi + +configs="" +if [ -n "$has_python" ]; then + configs="--config=p/python --config=p/owasp-top-ten" +fi +if [ -n "$has_go" ]; then + configs="$configs --config=p/golang --config=p/owasp-top-ten" +fi + +if semgrep scan $configs "$TARGET" --quiet 2>/dev/null; then + printf "${GREEN}✓${NC} No security issues found\n" + exit 0 +else + printf "${RED}✗${NC} Security issues detected — review semgrep output above\n" + exit 1 +fi \ No newline at end of file diff --git a/validate/secrets.sh b/validate/secrets.sh new file mode 100755 index 0000000..76bb87c --- /dev/null +++ b/validate/secrets.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +set -euo pipefail + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[0;33m' +NC='\033[0m' + +TARGET="${1:-.}" + +echo "=== Secrets Scan ===" + +if ! command -v gitleaks &>/dev/null; then + printf "${RED}✗${NC} gitleaks not installed\n" + exit 2 +fi + +if gitleaks detect --source "$TARGET" -v --no-git 2>/dev/null; then + printf "${GREEN}✓${NC} No secrets detected\n" + exit 0 +else + printf "${RED}✗${NC} Secrets found — fix before proceeding\n" + exit 1 +fi \ No newline at end of file diff --git a/validate/tests.sh b/validate/tests.sh new file mode 100755 index 0000000..330f109 --- /dev/null +++ b/validate/tests.sh @@ -0,0 +1,56 @@ +#!/usr/bin/env bash +set -euo pipefail + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[0;33m' +NC='\033[0m' + +TARGET="${1:-.}" +errors=0 + +echo "=== Test Suite ===" + +has_python=$(find "$TARGET" -name "test_*.py" -o -name "*_test.py" | head -1) +has_go=$(find "$TARGET" -name "*_test.go" | head -1) + +if [ -z "$has_python" ] && [ -z "$has_go" ]; then + printf "${YELLOW}!${NC} No test files found — skipping\n" + exit 0 +fi + +if [ -n "$has_python" ]; then + if ! command -v pytest &>/dev/null; then + printf "${RED}✗${NC} pytest not installed\n" + exit 2 + fi + + echo "-- Python (pytest --cov) --" + if pytest "$TARGET" --cov --cov-report=term-missing -q 2>/dev/null; then + printf "${GREEN}✓${NC} Python tests passed\n" + else + printf "${RED}✗${NC} Python tests failed\n" + errors=$((errors + 1)) + fi +fi + +if [ -n "$has_go" ]; then + if ! command -v go &>/dev/null; then + printf "${RED}✗${NC} go not installed\n" + exit 2 + fi + + echo "-- Go (go test -cover) --" + if go test -cover ./... 2>/dev/null; then + printf "${GREEN}✓${NC} Go tests passed\n" + else + printf "${RED}✗${NC} Go tests failed\n" + errors=$((errors + 1)) + fi +fi + +if [ "$errors" -gt 0 ]; then + exit 1 +else + exit 0 +fi \ No newline at end of file