mirror of
https://github.com/Twigpine/zero.git
synced 2026-11-12 16:23:18 -10:00
* Bump toolchain to go1.26.4 to clear reachable stdlib CVEs go.mod pinned toolchain go1.24.13, whose bundled standard library has 9 govulncheck-reachable CVEs (crypto/tls KeyUpdate DoS, net/http2 loop, crypto/x509 x3, net, net/url, os, net/textproto). CI and release build via go-version-file: go.mod, so shipped binaries inherited them. Bumping the toolchain directive to go1.26.4 clears all nine — govulncheck ./... now reports 0 reachable (minimum that clears them is go1.25.11; go1.26.4 matches the team's local Go). The go directive stays at 1.24.2 (minimum language version). Verified: go build/vet/gofmt clean, full go test ./... green. * Add govulncheck CI gate and SHA-pin GitHub Actions - ci.yml: new 'security' job runs govulncheck as a hard gate (fails on a reachable vulnerability; passes now that the toolchain is bumped) plus an advisory deadcode step that surfaces dormant code without blocking. - Pin every GitHub Action to a full commit SHA (checkout, upload-artifact, github-script) with a version comment, across all four workflows — previously only setup-go was pinned, leaving the mutable v4/v7 tags as a supply-chain risk. * Add hooks management command (add/remove/enable/disable) Wires the previously-dormant hooks.ConfigStore (10 unreachable funcs -> 0) into the CLI: zero hooks add <id> --event <event> --command <cmd> [--name --description --matcher --arg --user --json] zero hooks remove|enable|disable <id> [--user --json] Writes the project hook config by default (<cwd>/.zero/hooks.json) or the user config with --user, reusing the store's locking + atomic writes + validation (normalizeDefinition). New hooks are enabled; state is managed via enable/disable. JSON output is secret-scrubbed via redaction. Mirrors the existing 'zero mcp add/remove/enable/disable' shape. Covered by add/remove/toggle round-trip, validation, unknown-event, and JSON-redaction tests. * Fix govulncheck CI job: pin GOTOOLCHAIN to the go.mod toolchain go run govulncheck@latest selected the toolchain from govulncheck's own go.mod (downgrading to go1.25.11), which then could not load our go1.26-requiring packages (fips140only_go1.26.go), failing the security job. Resolve GOTOOLCHAIN from go.mod's toolchain line so govulncheck and deadcode both run under go1.26.4. * Address review: harden CI checkout, pin tool versions, validate hook event CodeRabbit findings on #193: - ci.yml: persist-credentials: false on all checkout steps (smoke/performance/security) — these jobs run repo code and never push, so don't keep the token in git config. - ci.yml: pin [email protected] and [email protected].0 instead of @latest, so the security gate is deterministic and not subject to supply-chain drift. - hooks: add exported IsValidEvent/KnownEvents (single source); parseEvent reuses it, and 'zero hooks add' now rejects an invalid --event with a usage error at parse time instead of falling through to the Upsert app-error crash path.
90 lines
3.3 KiB
YAML
90 lines
3.3 KiB
YAML
name: ZERO Action Smoke
|
|
|
|
on:
|
|
pull_request:
|
|
paths:
|
|
- action.yml
|
|
- .github/workflows/zero-action-smoke.yml
|
|
push:
|
|
branches:
|
|
- main
|
|
paths:
|
|
- action.yml
|
|
- .github/workflows/zero-action-smoke.yml
|
|
|
|
jobs:
|
|
validate:
|
|
name: Validate action.yml
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- name: Parse action.yml and assert documented inputs
|
|
shell: bash
|
|
run: |
|
|
python3 - <<'PY'
|
|
import sys, yaml
|
|
|
|
with open("action.yml", "r", encoding="utf-8") as handle:
|
|
doc = yaml.safe_load(handle)
|
|
|
|
assert isinstance(doc, dict), "action.yml must be a mapping"
|
|
assert doc.get("name"), "action must declare a name"
|
|
assert doc.get("description"), "action must declare a description"
|
|
|
|
runs = doc.get("runs") or {}
|
|
assert runs.get("using") == "composite", "action must be a composite action"
|
|
steps = runs.get("steps") or []
|
|
assert len(steps) >= 2, "composite action must define steps"
|
|
|
|
inputs = doc.get("inputs") or {}
|
|
expected_inputs = [
|
|
"prompt", "prompt-file", "provider", "api-key", "api-key-env",
|
|
"model", "mode", "auto", "self-correct", "add-dir", "worktree",
|
|
"output-format", "post-to", "slack-webhook-url", "github-token",
|
|
"working-directory", "zero-version", "zero-repo",
|
|
]
|
|
missing = [name for name in expected_inputs if name not in inputs]
|
|
assert not missing, f"action.yml is missing inputs: {missing}"
|
|
|
|
# Conservative CI default: autonomy must default to 'low'.
|
|
assert inputs["auto"].get("default") == "low", "auto must default to low"
|
|
# stream-json is the documented default capture format.
|
|
assert inputs["output-format"].get("default") == "stream-json", \
|
|
"output-format must default to stream-json"
|
|
|
|
outputs = doc.get("outputs") or {}
|
|
for name in ("exit-code", "output-file", "summary"):
|
|
assert name in outputs, f"action.yml is missing output: {name}"
|
|
|
|
# The action must never enable unsafe mode implicitly.
|
|
serialized = yaml.safe_dump(doc)
|
|
assert "--skip-permissions-unsafe" not in serialized, \
|
|
"action must never pass --skip-permissions-unsafe"
|
|
|
|
print(f"action.yml OK: {len(inputs)} inputs, {len(outputs)} outputs, {len(steps)} steps")
|
|
PY
|
|
|
|
- name: Shell-syntax-check embedded run blocks
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
python3 - <<'PY'
|
|
import yaml
|
|
with open("action.yml", "r", encoding="utf-8") as handle:
|
|
doc = yaml.safe_load(handle)
|
|
steps = (doc.get("runs") or {}).get("steps") or []
|
|
for index, step in enumerate(steps):
|
|
run = step.get("run")
|
|
if run:
|
|
with open(f"/tmp/zero_step_{index}.sh", "w", encoding="utf-8") as out:
|
|
out.write(run)
|
|
PY
|
|
for script in /tmp/zero_step_*.sh; do
|
|
echo "bash -n ${script}"
|
|
bash -n "${script}"
|
|
done
|