Zof CLI 靜態驗證證據解讀:三種退出碼對應三種審查決策
Reading static verification evidence: three exit codes, three review decisions
Kevin Kissi 以 Zof CLI 0.1.2 的三個 TypeScript 範例説明,退出碼 0、1、2 分別表示在限定範圍內完成檢查、檢查失敗,以及輸入無效或執行不完整。
A passing command is useful evidence only when its meaning is clear. A static checker can complete successfully without running a test, observing production behavior, or proving that a software change is safe. Treating those outcomes as equivalent makes a release decision depend on work that never happened.
Three tiny TypeScript examples make the distinction concrete: a simple addition function, a function containing eval, and a requested file that does not exist. Captured runs of Zof CLI 0.1.2 returned exit codes 0, 1, and 2 respectively. Each outcome calls for a different response from a reviewer.
Disclosure: This article was drafted with AI assistance using captured command output and public documentation. Its examples are synthetic; they do not describe a customer incident or personal production experience.
Affiliation: Kevin Kissi is the founder and CEO of Zof.
Set up a bounded experiment
The original demonstration ran on macOS with Node 24.19.0 and Python 3.12.14, using an existing CLI installation whose compiled distribution files matched the public package. A separate fresh install of 0.1.2 from the official npm registry then reproduced the commands below in a disposable project. All three exits matched; the JSON evidence matched except for generated identifiers and timestamps. These runs establish the examples’ behavior on that environment, not universal compatibility.
Use Node 22 or 24 and Python 3.10 or newer on Linux or macOS. The published instructions document these prerequisites. Installation is a separate step that downloads dependencies; --ignore-scripts disables package lifecycle scripts, while subsequent --no-install invocations decline installing a missing CLI. See the public CLI documentation.
mkdir zof-static-demo
cd zof-static-demo
node --version
python3 --version
npm init -y
npm install --ignore-scripts --no-audit --no-fund --save-exact @zof-ai/cli@0.1.2
npx --no-install zof --help
mkdir -p fixtures/clean fixtures/unsafe
cat > fixtures/clean/math.ts <<'TS'
export function add(a: number, b: number): number {
return a + b
}
TS
cat > fixtures/unsafe/math.ts <<'TS'
export function evaluate(input: string): unknown {
return eval(input)
}
TS
The second file is input to static analysis. Do not run its function. These verification commands inspect source; they do not execute the application or its tests.
Capture stdout, stderr, and the process exit code separately. The conditional preserves expected nonzero results even in a shell configured to stop on errors:
run_case() {
case_name=$1
case_root=$2
case_file=$3
if npx --no-install zof verify --root "$case_root" \
--changed "$case_file" --json \
>"$case_name.stdout.json" 2>"$case_name.stderr.txt"; then
case_exit=0
else
case_exit=$?
fi
printf '%s exit=%s\n' "$case_name" "$case_exit"
}
run_case clean fixtures/clean math.ts
run_case unsafe fixtures/unsafe math.ts
run_case missing-file fixtures/clean missing.ts
The captured exits were:
clean exit=0
unsafe exit=1
missing-file exit=2
Exit 0: a completed check within a stated scope
For the addition function, the evidence reports execution.status: completed and execution.result: pass. Findings, tests, and artifacts are empty arrays. The tool identifies itself as zof-cli version 0.1.2, with evidence type static-analysis.
That supports a narrow conclusion: this invocation completed without reporting a finding. It supplies no test result. An empty tests array cannot establish that arithmetic edge cases, integration behavior, or deployment configuration were checked.
The impact object also reports confidence: high and complete: true. Those fields must be read alongside its limitations. Because the invocation supplies an explicit file list, EXPLICIT_FILES says line changes and changed symbols are unavailable. The source repository and commit are both null in this synthetic example. Neither a reassuring confidence label nor an empty findings list fills those gaps.
Exit 1: evidence that requires a decision
For the eval example, execution completes with result fail. The captured finding identifies the review location precisely:
{
"id": "dynamic-evaluation",
"severity": "high",
"message": "Dynamic code evaluation requires review; do not evaluate untrusted input.",
"path": "math.ts",
"line": 2
}
The impact result changes too: confidence is low, completeness is false, and DYNAMIC_EXECUTION records an analysis limitation. This matters beyond the exit code. The checker has identified a construct it cannot fully analyze, so a reviewer should investigate the input's origin and whether dynamic evaluation is necessary.
The finding does not demonstrate an exploit or establish that every input is hostile. It provides a specific reason to inspect the code. Replacing dynamic evaluation with explicit operations may be appropriate, but that decision depends on the intended behavior. Any resulting tests should be recorded as separate evidence; none ran here.
Exit 2: the requested check did not produce a result
Requesting missing.ts produces exit 2. Stdout is empty, even though the command requested JSON. Stderr contains:
ZOF_INPUT_ERROR: check command, workspace, bounded relative paths and configuration; use zof help. No input details were logged.
A consumer that treats empty output as an empty findings list would turn an input error into false reassurance. Check the exit code before parsing evidence. The documented meanings distinguish successful completion, a configured failure, and invalid or incomplete execution. In this example, the last category requires fixing the requested path and rerunning the check.
Environment failures deserve the same attention. An earlier preserved attempt selected an unsuitable Python runtime and failed closed. Correcting the runtime path enabled the recorded runs. Reproducibility includes prerequisites and unsuccessful execution, not just the final green result.
Turn the evidence into a reviewable decision
For a real change, retain the command, tool version, inspected files, both output streams, and process exit. Check whether repository and commit attribution are present. Read findings and limitations before interpreting confidence or completeness. Then identify the additional evidence the change requires, such as behavior tests or integration checks.
The three cases establish a useful boundary: the clean example completed its static check; the dynamic example produced a concrete review finding; the missing-file example produced no successful verification result. A human release review can use those facts without silently expanding their scope. The decision should explain what was checked, what remains uncertain, and which additional checks support shipping the change.
來源:DEV Community · dev.to