mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-24 03:15:46 -06:00
improve(release): reuse exact-SHA validation evidence (#104162)
* perf(release): share changelog verification snapshots
* perf(release): reuse exact-SHA validation evidence
* feat(release): checkpoint candidate workflow state
* feat(release): watch CI transitions compactly
* fix(testbox): rotate stale reusable leases
* refactor(release): move CI verifier into scripts
* fix(release): preserve verifier executable mode
* fix(testbox): force noninteractive remote hydration
* perf(testbox): skip sync for proven clean heads
* fix(testbox): keep changed gates synchronized
* fix(testbox): isolate git state probes
* fix(testbox): isolate wrapper git commands
* fix(testbox): preserve git command contracts
* fix(release): validate reused SHA evidence
* fix(release): resume serialized plugin selections
* fix(testbox): sync source on every lease reuse
* fix(release): verify from trusted workflow checkout
* fix(release): gate evidence reuse on trusted lineage
* fix(release): support legacy verifier checkouts
* fix(testbox): export CI across shell snippets
* fix(release): revalidate reused evidence before publish
* fix(release): reject untrusted reuse before lookup
* fix(release): reuse SHA-pinned root evidence
* fix(ci): allow unreleased notes in QA packages
* fix(release): satisfy script lint contracts
* fix(release): handle Unicode workflow refs safely
(cherry picked from commit c47ceb0f3d)
This commit is contained in:
@@ -1,15 +1,16 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Finds a prior green Full Release Validation run whose evidence still covers
|
||||
# the target SHA: same rerun scope, equal-or-broader release profile/soak, and
|
||||
# a target delta that is release-metadata-only per check-release-metadata-only.
|
||||
# Finds a prior green Full Release Validation run for the exact target SHA.
|
||||
# Cross-SHA evidence reuse is intentionally left to the granular delta manifest,
|
||||
# which can require fresh package/install/provider closure per changed artifact.
|
||||
# Always exits 0 with reuse=true/false; callers fail open to a full validation.
|
||||
|
||||
REPO="${GH_REPO:-}"
|
||||
WORKFLOW_FILE="full-release-validation.yml"
|
||||
TARGET_SHA=""
|
||||
WORKFLOW_SHA=""
|
||||
VERIFIER_WORKFLOW_SHA=""
|
||||
WORKFLOW_REF=""
|
||||
RELEASE_PROFILE=""
|
||||
RUN_RELEASE_SOAK="false"
|
||||
INPUTS_JSON=""
|
||||
@@ -17,22 +18,24 @@ REPO_DIR="."
|
||||
MAX_CANDIDATES=12
|
||||
GITHUB_OUTPUT_FILE="${GITHUB_OUTPUT:-}"
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
CLASSIFIER="${SCRIPT_DIR}/../check-release-metadata-only.mjs"
|
||||
PREFLIGHT="${SCRIPT_DIR}/../release-preflight.mjs"
|
||||
REPO_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
|
||||
VALIDATOR="${OPENCLAW_RELEASE_CI_SUMMARY_VALIDATOR:-${REPO_ROOT}/scripts/release-ci-summary.mjs}"
|
||||
|
||||
usage() {
|
||||
cat >&2 <<'EOF'
|
||||
Usage: find-reusable-release-validation.sh --target-sha <sha> --workflow-sha <sha> \
|
||||
--workflow-ref <main|release-ci/sha12-timestamp> \
|
||||
--release-profile <beta|stable|full> --inputs-json <json> \
|
||||
[--run-release-soak <true|false>] [--repo <owner/repo>] [--repo-dir <path>] \
|
||||
[--workflow <file>] [--max-candidates <n>] [--github-output <file>]
|
||||
|
||||
Scans recent successful Full Release Validation runs for a validation manifest
|
||||
whose targetSha differs from --target-sha only by release metadata paths, whose
|
||||
recorded lane-selection inputs match --inputs-json exactly, whose harness
|
||||
(.github/workflows tree at the run's head SHA) matches --workflow-sha, and
|
||||
whose recorded child runs are still green. Writes reuse=true plus evidence_*
|
||||
outputs when found; reuse=false otherwise.
|
||||
Scans recent successful Full Release Validation runs for an exact-target
|
||||
validation manifest whose recorded lane-selection inputs match --inputs-json
|
||||
and whose normalized strict-v3 evidence is accepted by the current trusted-main
|
||||
verifier identified by --workflow-sha. The historical producer workflow SHA
|
||||
remains independent. Writes reuse=true plus evidence_* outputs when found;
|
||||
reuse=false otherwise.
|
||||
EOF
|
||||
}
|
||||
|
||||
@@ -43,7 +46,11 @@ while [[ $# -gt 0 ]]; do
|
||||
shift 2
|
||||
;;
|
||||
--workflow-sha)
|
||||
WORKFLOW_SHA="${2:-}"
|
||||
VERIFIER_WORKFLOW_SHA="${2:-}"
|
||||
shift 2
|
||||
;;
|
||||
--workflow-ref)
|
||||
WORKFLOW_REF="${2:-}"
|
||||
shift 2
|
||||
;;
|
||||
--release-profile)
|
||||
@@ -107,74 +114,64 @@ no_reuse() {
|
||||
exit 0
|
||||
}
|
||||
|
||||
profile_rank() {
|
||||
case "$1" in
|
||||
beta) echo 1 ;;
|
||||
stable) echo 2 ;;
|
||||
full) echo 3 ;;
|
||||
*) echo 0 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
if [[ ! "$TARGET_SHA" =~ ^[0-9a-f]{40}$ ]]; then
|
||||
echo "Expected --target-sha to be a full lowercase commit SHA; got: ${TARGET_SHA}" >&2
|
||||
exit 2
|
||||
fi
|
||||
if [[ ! "$WORKFLOW_SHA" =~ ^[0-9a-f]{40}$ ]]; then
|
||||
echo "Expected --workflow-sha to be a full lowercase commit SHA; got: ${WORKFLOW_SHA}" >&2
|
||||
if [[ ! "$VERIFIER_WORKFLOW_SHA" =~ ^[0-9a-f]{40}$ ]]; then
|
||||
echo "Expected --workflow-sha to be a full lowercase commit SHA; got: ${VERIFIER_WORKFLOW_SHA}" >&2
|
||||
exit 2
|
||||
fi
|
||||
if [[ "$WORKFLOW_REF" != "main" ]]; then
|
||||
expected_release_ref="release-ci/${VERIFIER_WORKFLOW_SHA:0:12}-"
|
||||
if [[ ! "$WORKFLOW_REF" =~ ^release-ci/[0-9a-f]{12}-[1-9][0-9]*$ ]] ||
|
||||
[[ "$WORKFLOW_REF" != "$expected_release_ref"* ]]; then
|
||||
no_reuse "workflow ref is not a canonical SHA-pinned release ref"
|
||||
fi
|
||||
fi
|
||||
if [[ -z "$REPO" ]]; then
|
||||
echo "Expected --repo <owner/repo> or GH_REPO." >&2
|
||||
exit 2
|
||||
fi
|
||||
current_rank="$(profile_rank "$RELEASE_PROFILE")"
|
||||
if [[ "$current_rank" == "0" ]]; then
|
||||
no_reuse "unknown release profile ${RELEASE_PROFILE}"
|
||||
if [[ "$RUN_RELEASE_SOAK" != "true" && "$RUN_RELEASE_SOAK" != "false" ]]; then
|
||||
echo "Expected --run-release-soak to be true or false; got: ${RUN_RELEASE_SOAK}" >&2
|
||||
exit 2
|
||||
fi
|
||||
case "$RELEASE_PROFILE" in
|
||||
beta|stable|full) ;;
|
||||
*) no_reuse "unknown release profile ${RELEASE_PROFILE}" ;;
|
||||
esac
|
||||
expected_inputs=""
|
||||
if ! expected_inputs="$(jq -Sc . <<< "$INPUTS_JSON" 2>/dev/null)" || [[ -z "$expected_inputs" ]]; then
|
||||
if ! expected_inputs="$(jq -Sc 'if type == "object" then . else error("expected object") end' <<< "$INPUTS_JSON" 2>/dev/null)" || [[ -z "$expected_inputs" ]]; then
|
||||
echo "Expected --inputs-json to be a JSON object of lane-selection inputs." >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
# A metadata-only diff can still leave the target's version stamps mutually
|
||||
# inconsistent (for example package.json bumped without the macOS plist);
|
||||
# validate the target state before trusting any prior evidence.
|
||||
workflow_lineage=""
|
||||
if ! workflow_lineage="$(
|
||||
gh api "repos/${REPO}/compare/${VERIFIER_WORKFLOW_SHA}...main"
|
||||
)"; then
|
||||
no_reuse "could not verify workflow SHA against trusted main"
|
||||
fi
|
||||
if ! jq -e \
|
||||
--arg workflow_sha "$VERIFIER_WORKFLOW_SHA" '
|
||||
(.status == "ahead" or .status == "identical")
|
||||
and .merge_base_commit.sha == $workflow_sha
|
||||
' <<< "$workflow_lineage" >/dev/null; then
|
||||
no_reuse "workflow SHA is not on trusted main lineage"
|
||||
fi
|
||||
|
||||
# Exact-target reuse still requires internally consistent version stamps
|
||||
# (for example package.json must agree with the macOS plist).
|
||||
if ! (cd "$REPO_DIR" && node "$PREFLIGHT" --macos-versions-only >&2); then
|
||||
no_reuse "target version metadata is inconsistent"
|
||||
fi
|
||||
|
||||
# Evidence must come from an equivalent harness: workflows and their helper
|
||||
# scripts run from the workflow ref, so the tree diff between the candidate
|
||||
# run's head SHA and the current workflow SHA must itself be metadata-only.
|
||||
harness_matches() {
|
||||
local candidate_sha="$1"
|
||||
if [[ "$candidate_sha" == "$WORKFLOW_SHA" ]]; then
|
||||
return 0
|
||||
fi
|
||||
if ! git -C "$REPO_DIR" fetch --quiet --depth=1 origin "$candidate_sha" "$WORKFLOW_SHA"; then
|
||||
return 1
|
||||
fi
|
||||
local harness_paths
|
||||
if ! harness_paths="$(git -C "$REPO_DIR" diff --name-only "$candidate_sha" "$WORKFLOW_SHA")"; then
|
||||
return 1
|
||||
fi
|
||||
if [[ -z "$harness_paths" ]]; then
|
||||
return 0
|
||||
fi
|
||||
local -a harness_path_list=()
|
||||
while IFS= read -r harness_path; do
|
||||
[[ -n "$harness_path" ]] && harness_path_list+=("$harness_path")
|
||||
done <<< "$harness_paths"
|
||||
(cd "$REPO_DIR" && node "$CLASSIFIER" --base "$candidate_sha" --head "$WORKFLOW_SHA" -- "${harness_path_list[@]}")
|
||||
}
|
||||
|
||||
runs_json=""
|
||||
if ! runs_json="$(
|
||||
gh api -X GET "repos/${REPO}/actions/workflows/${WORKFLOW_FILE}/runs" \
|
||||
-F status=success -F event=workflow_dispatch -F per_page="$MAX_CANDIDATES" \
|
||||
--jq '[.workflow_runs[] | {id, html_url, head_sha}]'
|
||||
--jq '[.workflow_runs[] | {id}]'
|
||||
)"; then
|
||||
no_reuse "could not list prior successful validation runs"
|
||||
fi
|
||||
@@ -184,157 +181,127 @@ if [[ "$run_count" == "0" ]]; then
|
||||
no_reuse "no prior successful validation runs"
|
||||
fi
|
||||
|
||||
work_dir="$(mktemp -d)"
|
||||
trap 'rm -rf "$work_dir"' EXIT
|
||||
|
||||
for ((index = 0; index < run_count; index += 1)); do
|
||||
run_id="$(jq -r ".[${index}].id" <<< "$runs_json")"
|
||||
run_url="$(jq -r ".[${index}].html_url" <<< "$runs_json")"
|
||||
run_head_sha="$(jq -r ".[${index}].head_sha // \"\"" <<< "$runs_json")"
|
||||
|
||||
if [[ ! "$run_head_sha" =~ ^[0-9a-f]{40}$ ]] || ! harness_matches "$run_head_sha"; then
|
||||
echo "[evidence-reuse] run ${run_id}: harness differs from the current workflow ref beyond release metadata; skipping" >&2
|
||||
continue
|
||||
fi
|
||||
|
||||
artifact_id=""
|
||||
if ! artifact_id="$(
|
||||
gh api "repos/${REPO}/actions/runs/${run_id}/artifacts?per_page=100" \
|
||||
--jq "first(.artifacts[] | select(.name == \"full-release-validation-${run_id}\" and .expired == false) | .id)"
|
||||
validation_record=""
|
||||
if ! validation_record="$(
|
||||
node "$VALIDATOR" \
|
||||
--validate-run "$run_id" \
|
||||
--repo "$REPO" \
|
||||
--trusted-workflow-ref main \
|
||||
--json
|
||||
)"; then
|
||||
echo "[evidence-reuse] run ${run_id}: artifact listing failed; skipping" >&2
|
||||
echo "[evidence-reuse] run ${run_id}: shared evidence validator rejected the run; skipping" >&2
|
||||
continue
|
||||
fi
|
||||
if [[ -z "${artifact_id// }" ]]; then
|
||||
echo "[evidence-reuse] run ${run_id}: no validation manifest artifact; skipping" >&2
|
||||
if ! jq -e \
|
||||
--arg repo "$REPO" \
|
||||
--arg run_id "$run_id" \
|
||||
--arg verifier_sha "$VERIFIER_WORKFLOW_SHA" '
|
||||
. as $record
|
||||
| .schema == "openclaw.release-validation-evidence/v3"
|
||||
and .valid == true
|
||||
and .repository == $repo
|
||||
and .producerOnTrustedMainLineage == true
|
||||
and .trustedWorkflowRef == "main"
|
||||
and .trustedWorkflowFullRef == "refs/heads/main"
|
||||
and .directRoot == true
|
||||
and .evidenceReuse == null
|
||||
and .rerunGroup == "all"
|
||||
and .controls.performanceReportPublication == "artifact-only"
|
||||
and .conclusions.current == "success"
|
||||
and .conclusions.root == "success"
|
||||
and .conclusions.allRequiredSucceeded == true
|
||||
and (.current == .root)
|
||||
and (.root.runId | tostring) == $run_id
|
||||
and (.root.workflowSha | type == "string" and test("^[0-9a-f]{40}$"))
|
||||
and (.root.targetSha | type == "string" and test("^[0-9a-f]{40}$"))
|
||||
and (.root.artifact.digest | type == "string" and test("^sha256:[0-9a-f]{64}$"))
|
||||
and all($record.current, $record.root;
|
||||
. as $parent
|
||||
| .producerOnTrustedMainLineage == true
|
||||
and .workflowRefType == "branch"
|
||||
and .workflowPath == ".github/workflows/full-release-validation.yml"
|
||||
and .workflowFullRef == ("refs/heads/" + .workflowRef)
|
||||
and .workflowQualifiedPath ==
|
||||
(".github/workflows/full-release-validation.yml@" + .workflowFullRef)
|
||||
and (
|
||||
.workflowRunPath == ".github/workflows/full-release-validation.yml"
|
||||
or .workflowRunPath == .workflowQualifiedPath
|
||||
)
|
||||
and (
|
||||
(
|
||||
.workflowRef == "main"
|
||||
and (
|
||||
(.manifestVersion == 3 and .workflowRefProof == "manifest-v3-branch")
|
||||
or (
|
||||
.manifestVersion == 2
|
||||
and .workflowRefProof == "legacy-v2-main-ancestry"
|
||||
)
|
||||
)
|
||||
)
|
||||
or (
|
||||
.manifestVersion == 3
|
||||
and .workflowRefProof == "manifest-v3-sha-pinned-main-ancestry"
|
||||
and (.workflowRef | test("^release-ci/[0-9a-f]{12}-[1-9][0-9]*$"))
|
||||
and (.workflowRef | startswith("release-ci/\($parent.workflowSha[0:12])-"))
|
||||
)
|
||||
)
|
||||
)
|
||||
and (.verifier.schemaVersion == 3)
|
||||
and (.verifier.sourceSha == $verifier_sha)
|
||||
and ([.children[].role] | sort) ==
|
||||
["normalCi", "pluginPrerelease", "productPerformance", "releaseChecks"]
|
||||
and ([.children[].runId] | length == (unique | length))
|
||||
and ([.children[]
|
||||
| select(.role == "productPerformance")
|
||||
| .reportPublication] == ["artifact-only"])
|
||||
and all(.children[];
|
||||
.status == "completed"
|
||||
and .conclusion == "success"
|
||||
and .workflowSha == $record.root.workflowSha
|
||||
and (.sourceParentRunId | tostring) == $run_id
|
||||
)
|
||||
' <<< "$validation_record" >/dev/null 2>&1; then
|
||||
echo "[evidence-reuse] run ${run_id}: normalized evidence is not a strict direct-root full validation; skipping" >&2
|
||||
continue
|
||||
fi
|
||||
|
||||
manifest_zip="${work_dir}/manifest-${run_id}.zip"
|
||||
manifest_path="${work_dir}/manifest-${run_id}.json"
|
||||
if ! gh api "repos/${REPO}/actions/artifacts/${artifact_id}/zip" > "$manifest_zip"; then
|
||||
echo "[evidence-reuse] run ${run_id}: manifest download failed; skipping" >&2
|
||||
continue
|
||||
fi
|
||||
if ! unzip -p "$manifest_zip" full-release-validation-manifest.json > "$manifest_path" 2>/dev/null; then
|
||||
echo "[evidence-reuse] run ${run_id}: manifest missing from artifact; skipping" >&2
|
||||
continue
|
||||
fi
|
||||
|
||||
if ! jq -e '
|
||||
(.version >= 2)
|
||||
and (.rerunGroup == "all")
|
||||
and ((.targetSha // "") | test("^[0-9a-f]{40}$"))
|
||||
' "$manifest_path" >/dev/null 2>&1; then
|
||||
echo "[evidence-reuse] run ${run_id}: manifest is not a full-scope v2 manifest; skipping" >&2
|
||||
continue
|
||||
fi
|
||||
|
||||
prior_profile="$(jq -r '.releaseProfile // ""' "$manifest_path")"
|
||||
prior_rank="$(profile_rank "$prior_profile")"
|
||||
if (( prior_rank < current_rank )); then
|
||||
echo "[evidence-reuse] run ${run_id}: profile ${prior_profile} does not cover ${RELEASE_PROFILE}; skipping" >&2
|
||||
prior_profile="$(jq -r '.releaseProfile // ""' <<< "$validation_record")"
|
||||
if [[ "$prior_profile" != "$RELEASE_PROFILE" ]]; then
|
||||
echo "[evidence-reuse] run ${run_id}: profile ${prior_profile} differs from ${RELEASE_PROFILE}; skipping" >&2
|
||||
continue
|
||||
fi
|
||||
# Lane selection (provider, mode, filters, package specs) changes what the
|
||||
# prior run proved; only exact-match manifests are reusable. Manifests
|
||||
# written before validationInputs existed never match.
|
||||
manifest_inputs="$(jq -Sc '.validationInputs // empty' "$manifest_path")"
|
||||
manifest_inputs="$(jq -Sc '.validationInputs // empty' <<< "$validation_record")"
|
||||
if [[ -z "$manifest_inputs" || "$manifest_inputs" != "$expected_inputs" ]]; then
|
||||
echo "[evidence-reuse] run ${run_id}: validation inputs differ from the current request; skipping" >&2
|
||||
continue
|
||||
fi
|
||||
prior_soak="$(jq -r '.runReleaseSoak // "false"' "$manifest_path")"
|
||||
if [[ "$RUN_RELEASE_SOAK" == "true" && "$prior_soak" != "true" ]]; then
|
||||
echo "[evidence-reuse] run ${run_id}: no soak evidence; skipping" >&2
|
||||
prior_soak="$(jq -r '.runReleaseSoak // false' <<< "$validation_record")"
|
||||
if [[ "$prior_soak" != "$RUN_RELEASE_SOAK" ]]; then
|
||||
echo "[evidence-reuse] run ${run_id}: soak ${prior_soak} differs from ${RUN_RELEASE_SOAK}; skipping" >&2
|
||||
continue
|
||||
fi
|
||||
|
||||
prior_sha="$(jq -r '.targetSha' "$manifest_path")"
|
||||
# Track count/joined separately: empty-array expansion under `set -u` breaks
|
||||
# on the bash 3.2 that macOS ships.
|
||||
changed_paths=()
|
||||
changed_path_count=0
|
||||
changed_paths_joined=""
|
||||
prior_sha="$(jq -r '.root.targetSha' <<< "$validation_record")"
|
||||
if [[ "$prior_sha" != "$TARGET_SHA" ]]; then
|
||||
compare_json=""
|
||||
if ! compare_json="$(
|
||||
gh api "repos/${REPO}/compare/${prior_sha}...${TARGET_SHA}" \
|
||||
--jq '{status, file_count: ((.files // []) | length), files: [(.files // [])[].filename]}'
|
||||
)"; then
|
||||
echo "[evidence-reuse] run ${run_id}: compare ${prior_sha}...${TARGET_SHA} failed; skipping" >&2
|
||||
continue
|
||||
fi
|
||||
compare_status="$(jq -r '.status' <<< "$compare_json")"
|
||||
if [[ "$compare_status" != "ahead" ]]; then
|
||||
echo "[evidence-reuse] run ${run_id}: target is ${compare_status} of prior evidence, not ahead; skipping" >&2
|
||||
continue
|
||||
fi
|
||||
file_count="$(jq -r '.file_count' <<< "$compare_json")"
|
||||
# The compare API truncates at 300 files; a truncated list cannot prove a
|
||||
# metadata-only delta, so fall back to full validation.
|
||||
if (( file_count >= 300 )); then
|
||||
echo "[evidence-reuse] run ${run_id}: delta too large to classify (${file_count} files); skipping" >&2
|
||||
continue
|
||||
fi
|
||||
while IFS= read -r changed_path; do
|
||||
if [[ -n "$changed_path" ]]; then
|
||||
changed_paths+=("$changed_path")
|
||||
changed_path_count=$((changed_path_count + 1))
|
||||
changed_paths_joined="${changed_paths_joined:+${changed_paths_joined} }${changed_path}"
|
||||
fi
|
||||
done < <(jq -r '.files[]' <<< "$compare_json")
|
||||
if (( changed_path_count == 0 )); then
|
||||
echo "[evidence-reuse] run ${run_id}: delta has no file changes" >&2
|
||||
else
|
||||
if ! git -C "$REPO_DIR" fetch --quiet --depth=1 origin "$prior_sha"; then
|
||||
echo "[evidence-reuse] run ${run_id}: could not fetch prior SHA ${prior_sha}; skipping" >&2
|
||||
continue
|
||||
fi
|
||||
if ! (cd "$REPO_DIR" && node "$CLASSIFIER" --base "$prior_sha" --head "$TARGET_SHA" -- "${changed_paths[@]}"); then
|
||||
echo "[evidence-reuse] run ${run_id}: delta is not release-metadata-only; skipping" >&2
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Recorded child runs can be re-run to failure after the parent stays green;
|
||||
# reuse only evidence whose children are still completed/success, matching
|
||||
# the recheck the normal summary performs on its own children.
|
||||
children_healthy=1
|
||||
while IFS= read -r child_run_id; do
|
||||
[[ -n "$child_run_id" ]] || continue
|
||||
if ! child_state="$(gh api "repos/${REPO}/actions/runs/${child_run_id}" --jq '(.status // "") + "/" + (.conclusion // "")')"; then
|
||||
echo "[evidence-reuse] run ${run_id}: could not verify child run ${child_run_id}; skipping" >&2
|
||||
children_healthy=0
|
||||
break
|
||||
fi
|
||||
if [[ "$child_state" != "completed/success" ]]; then
|
||||
echo "[evidence-reuse] run ${run_id}: child run ${child_run_id} is ${child_state}; skipping" >&2
|
||||
children_healthy=0
|
||||
break
|
||||
fi
|
||||
done < <(jq -r '[.childRuns.normalCi // "", .childRuns.pluginPrerelease // "", .childRuns.releaseChecks // "", .childRuns.npmTelegram // "", (.childRuns.productPerformance.runId // "")] | map(select(. != "")) | .[]' "$manifest_path")
|
||||
if [[ "$children_healthy" != "1" ]]; then
|
||||
echo "[evidence-reuse] run ${run_id}: target ${prior_sha} differs from ${TARGET_SHA}; cross-SHA reuse requires granular artifact evidence" >&2
|
||||
continue
|
||||
fi
|
||||
|
||||
# A reused run may itself be a reuse manifest; evidenceReuse.runId points at
|
||||
# the chain root that actually executed the lanes.
|
||||
evidence_root_run_id="$(jq -r '.evidenceReuse.runId // empty' "$manifest_path")"
|
||||
if [[ -z "${evidence_root_run_id// }" ]]; then
|
||||
evidence_root_run_id="$run_id"
|
||||
fi
|
||||
|
||||
echo "[evidence-reuse] reusing run ${run_id} (${run_url}) for ${TARGET_SHA}: prior sha ${prior_sha}, ${changed_path_count} metadata-only changed files" >&2
|
||||
run_url="$(jq -r '.root.url' <<< "$validation_record")"
|
||||
echo "[evidence-reuse] reusing exact-target run ${run_id} (${run_url}) for ${TARGET_SHA}" >&2
|
||||
write_output reuse true
|
||||
write_output evidence_run_id "$run_id"
|
||||
write_output evidence_root_run_id "$evidence_root_run_id"
|
||||
write_output evidence_root_run_id "$run_id"
|
||||
write_output evidence_run_url "$run_url"
|
||||
write_output evidence_sha "$prior_sha"
|
||||
write_output changed_path_count "$changed_path_count"
|
||||
write_output changed_paths "$changed_paths_joined"
|
||||
write_output evidence_manifest "$(jq -c . "$manifest_path")"
|
||||
write_output changed_path_count "0"
|
||||
write_output changed_paths "[]"
|
||||
write_output evidence_manifest "$(jq -c '.manifest' <<< "$validation_record")"
|
||||
exit 0
|
||||
done
|
||||
|
||||
|
||||
Reference in New Issue
Block a user