diff --git a/action.yml b/action.yml index ad2be8a..dc7161c 100644 --- a/action.yml +++ b/action.yml @@ -10,6 +10,10 @@ inputs: description: "pass|enforce" required: false default: "pass" + profile: + description: "Path to policy profile file (required for enforce)" + required: false + default: "" runs: using: "composite" @@ -18,6 +22,6 @@ runs: shell: bash env: CICULLIS_MODE: ${{ inputs.mode }} + CICULLIS_PROFILE: ${{ inputs.profile }} run: | - chmod +x "$GITHUB_ACTION_PATH/gate.sh" - "$GITHUB_ACTION_PATH/gate.sh" + bash "$GITHUB_ACTION_PATH/gate.sh" diff --git a/gate.sh b/gate.sh index a9d362e..1133193 100755 --- a/gate.sh +++ b/gate.sh @@ -1,24 +1,48 @@ #!/usr/bin/env bash set -euo pipefail -# CICULLIS default: no-op PASS unless explicit policy env is set. -# This keeps Marketplace smoke green while preserving deterministic "fail-closed" option. -# If you want enforcement: set CICULLIS_MODE=enforce and provide your own checks. - mode="${CICULLIS_MODE:-pass}" +profile="${CICULLIS_PROFILE:-}" + +# Exit codes: +# 0 = pass +# 1 = enforcement fail +# 2 = malformed profile / invalid config +die2(){ echo "CICULLIS: $*" >&2; exit 2; } +die1(){ echo "CICULLIS: $*" >&2; exit 1; } + +# Profile validation (always enforced if profile is provided) +if [[ -n "$profile" ]]; then + [[ -f "$profile" ]] || die2 "profile not found: $profile" + [[ -s "$profile" ]] || die2 "profile empty: $profile" + if LC_ALL=C grep -q $'\x00' "$profile" 2>/dev/null; then die2 "profile contains NUL: $profile"; fi + # Must be valid JSON (selftests expect deterministic malformed=2) + python3 - "$profile" <<'PY' || exit 2 +import json,sys +p=sys.argv[1] +try: + with open(p,"rb") as f: + json.load(f) +except Exception: + raise SystemExit(2) +PY +fi case "$mode" in pass) - echo "CICULLIS: pass (default). Set CICULLIS_MODE=enforce to activate enforcement." + echo "CICULLIS: pass" exit 0 ;; enforce) - echo "CICULLIS: enforce requested, but no policy configured in this runner." - echo "Set CICULLIS_POLICY or vendor your policy checks." - exit 1 + [[ -n "$profile" ]] || die2 "enforce requires CICULLIS_PROFILE" + # Placeholder enforcement: profile contains token "DENY" => exit 1 + if grep -qE '(^|[[:space:]])DENY($|[[:space:]])' "$profile" 2>/dev/null; then + die1 "policy denied by profile: $profile" + fi + echo "CICULLIS: enforce pass (profile=$profile)" + exit 0 ;; *) - echo "CICULLIS: invalid CICULLIS_MODE=$mode (use pass|enforce)" - exit 2 + die2 "invalid CICULLIS_MODE=$mode (use pass|enforce)" ;; esac