Files
rustfs/scripts/test_scanner_heal_linux_evidence_plan.sh
T
houseme 824231ff1a test(scanner): report Linux descriptor drift ledger (#7692)
Add a read-only descriptor ledger mode to the Scanner/Heal Linux evidence planner so release operators can separate current-head measured descriptors from old-head measured artifacts and case-level inputs before final bundle assembly.

Co-authored-by: zhi22915 <qiuzgang@gmail.com>
2026-09-12 13:29:29 +08:00

178 lines
5.7 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
RUNNER="$SCRIPT_DIR/run_scanner_heal_linux_evidence_plan.py"
TMP_DIR="$(mktemp -d)"
cleanup() {
rm -rf "$TMP_DIR"
}
trap cleanup EXIT
"${RUSTFS_PYTHON_BIN:-python3}" "$RUNNER" --self-test
"${RUSTFS_PYTHON_BIN:-python3}" "$RUNNER" --phase preflight >"$TMP_DIR/preflight.out"
rg -q "stage=preflight" "$TMP_DIR/preflight.out"
rg -q "scripts/check_test_wiring.py --self-test" "$TMP_DIR/preflight.out"
"${RUSTFS_PYTHON_BIN:-python3}" "$RUNNER" \
--phase functional \
--source-revision aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa \
--format json >"$TMP_DIR/functional.json"
"${RUSTFS_PYTHON_BIN:-python3}" - "$TMP_DIR/functional.json" <<'PY'
import json
import pathlib
import sys
plan = json.loads(pathlib.Path(sys.argv[1]).read_text())
assert plan["schema"] == 1
assert plan["source_revision"] == "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
assert [stage["id"] for stage in plan["stages"]] == ["functional"]
commands = [
" ".join(entry["command"])
for stage in plan["stages"]
for step in stage["steps"]
for entry in step["commands"]
]
assert any("background-target-crash-ec8-4-multi-pool" in command for command in commands)
assert any("run_scanner_heal_status_outcome_probe.py" in command for command in commands)
assert all("--case release" not in command for command in commands)
PY
"${RUSTFS_PYTHON_BIN:-python3}" "$RUNNER" --write-plan --out-dir "$TMP_DIR/plan" >"$TMP_DIR/path.out"
PLAN_PATH="$(tr -d '\n' <"$TMP_DIR/path.out")"
test -s "$PLAN_PATH"
rg -q '"evidence_type": "plan_only"' "$PLAN_PATH"
rg -q '"stop_on_product_failure": true' "$PLAN_PATH"
if "${RUSTFS_PYTHON_BIN:-python3}" "$RUNNER" \
--phase functional \
--source-revision aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa \
--status-root "$TMP_DIR/missing-run" >"$TMP_DIR/status-missing.json"; then
echo "missing evidence status should fail closed" >&2
exit 1
fi
rg -q '"decision": "blocked"' "$TMP_DIR/status-missing.json"
rg -q '"release_approved": false' "$TMP_DIR/status-missing.json"
rg -q '"next_step"' "$TMP_DIR/status-missing.json"
if "${RUSTFS_PYTHON_BIN:-python3}" "$RUNNER" \
--phase functional \
--status-root "$TMP_DIR/missing-run" \
--run-preflight >/dev/null 2>"$TMP_DIR/status-mode.err"; then
echo "status mode should reject preflight execution" >&2
exit 1
fi
rg -q "status-root cannot be combined" "$TMP_DIR/status-mode.err"
"${RUSTFS_PYTHON_BIN:-python3}" - "$RUNNER" "$TMP_DIR/complete-run" <<'PY'
import json
import pathlib
import subprocess
import sys
runner = pathlib.Path(sys.argv[1])
run_root = pathlib.Path(sys.argv[2])
plan = json.loads(subprocess.check_output([
sys.executable,
str(runner),
"--phase",
"functional",
"--source-revision",
"a" * 40,
"--format",
"json",
], text=True))
for stage in plan["stages"]:
for step in stage["steps"]:
for output in step.get("expected_outputs", []):
path = pathlib.Path(output.replace("$RUN_ROOT", str(run_root)))
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text("{}\n")
status = json.loads(subprocess.check_output([
sys.executable,
str(runner),
"--phase",
"functional",
"--source-revision",
"a" * 40,
"--status-root",
str(run_root),
], text=True))
assert status["decision"] == "complete"
assert status["release_approved"] is False
assert status["artifact_totals"]["missing"] == 0
PY
"${RUSTFS_PYTHON_BIN:-python3}" - "$TMP_DIR" <<'PY'
import json
import pathlib
import sys
root = pathlib.Path(sys.argv[1])
same_head = root / "same-head.json"
old_head = root / "old-head.json"
case_level = root / "case-level.json"
same_head.write_text(json.dumps({
"schema": 1,
"evidence": "measured",
"source_revision": "a" * 40,
"gates": {"G01": {}, "G02": {}},
}) + "\n")
old_head.write_text(json.dumps({
"schema": 1,
"evidence": "measured",
"source_revision": "b" * 40,
"gates": {"G03": {}, "G09": {}},
}) + "\n")
case_level.write_text(json.dumps({
"schema": 1,
"evidence": "case",
"source_revision": "a" * 40,
"gates": {"G14": {}},
}) + "\n")
PY
"${RUSTFS_PYTHON_BIN:-python3}" "$RUNNER" \
--source-revision aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa \
--descriptor-ledger "$TMP_DIR/same-head.json" "$TMP_DIR/old-head.json" "$TMP_DIR/case-level.json" \
"$TMP_DIR/missing.json" >"$TMP_DIR/ledger.json"
"${RUSTFS_PYTHON_BIN:-python3}" - "$TMP_DIR/ledger.json" <<'PY'
import json
import pathlib
import sys
ledger = json.loads(pathlib.Path(sys.argv[1]).read_text())
assert ledger["kind"] == "scanner-heal-descriptor-ledger"
assert ledger["release_approved"] is False
assert ledger["same_head_verified_gates"] == ["G01", "G02"]
assert ledger["old_head_measured_gates"] == ["G03", "G09"]
assert "G14" in ledger["missing_measured_gates"]
assert "G03" in ledger["missing_current_head_gates"]
assert ledger["totals"]["invalid_descriptors"] == 1
classifications = {entry["file_name"]: entry["classification"] for entry in ledger["entries"]}
assert classifications["same-head.json"] == "same-head verified"
assert classifications["old-head.json"] == "old-head measured, drift-readable"
assert classifications["case-level.json"] == "case-level only"
assert classifications["missing.json"] == "invalid"
PY
if "${RUSTFS_PYTHON_BIN:-python3}" "$RUNNER" \
--phase performance \
--run-preflight >/dev/null 2>"$TMP_DIR/no-preflight.err"; then
echo "preflight execution without the preflight stage should fail" >&2
exit 1
fi
rg -q "requires the preflight stage" "$TMP_DIR/no-preflight.err"
if "${RUSTFS_PYTHON_BIN:-python3}" "$RUNNER" --source-revision bad >/dev/null 2>"$TMP_DIR/bad.err"; then
echo "invalid source revision should fail" >&2
exit 1
fi
rg -q "source-revision" "$TMP_DIR/bad.err"