Files
awoooi/scripts/ci/write-gitea-audit-receipts.sh

189 lines
6.4 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
set +x
# Append two verified JSON receipts to a dedicated Gitea audit branch without
# merging the shallow workflow checkout. Authentication is supplied by the
# caller through GIT_ASKPASS; this script never accepts a token argument.
required_env=(
GITEA_AUDIT_REMOTE_URL
GITEA_AUDIT_BRANCH
GITEA_AUDIT_CONTROLLER_SOURCE
GITEA_AUDIT_VERIFIER_SOURCE
GITEA_AUDIT_CONTROLLER_TARGET
GITEA_AUDIT_VERIFIER_TARGET
GITEA_AUDIT_COMMIT_MESSAGE
)
for name in "${required_env[@]}"; do
if [ -z "${!name:-}" ]; then
echo "BLOCKER audit_writeback_missing_${name}"
exit 2
fi
done
if [ "${GITEA_AUDIT_REMOTE_URL}" = "http://192.168.0.110:3001/wooo/awoooi.git" ]; then
if [ -z "${GIT_ASKPASS:-}" ] || [ ! -x "${GIT_ASKPASS}" ]; then
echo "BLOCKER audit_writeback_askpass_missing_or_not_executable"
exit 2
fi
elif [[ "${GITEA_AUDIT_REMOTE_URL}" == file://* ]] && \
[ "${GITEA_AUDIT_TEST_FILE_REMOTE:-0}" = "1" ]; then
:
else
echo "BLOCKER audit_writeback_remote_not_allowlisted"
exit 2
fi
if ! [[ "${GITEA_AUDIT_BRANCH}" =~ ^mcp-(artifact|replay)-receipts$ ]]; then
echo "BLOCKER audit_writeback_branch_not_allowlisted"
exit 2
fi
if ! [[ "${GITEA_AUDIT_CONTROLLER_TARGET}" =~ ^docs/operations/external-mcp-(artifacts|replays)/[A-Za-z0-9._-]+-controller\.snapshot\.json$ ]]; then
echo "BLOCKER audit_writeback_controller_target_not_allowlisted"
exit 2
fi
if ! [[ "${GITEA_AUDIT_VERIFIER_TARGET}" =~ ^docs/operations/external-mcp-(artifacts|replays)/[A-Za-z0-9._-]+-verifier\.snapshot\.json$ ]]; then
echo "BLOCKER audit_writeback_verifier_target_not_allowlisted"
exit 2
fi
if [ "$(dirname "${GITEA_AUDIT_CONTROLLER_TARGET}")" != "$(dirname "${GITEA_AUDIT_VERIFIER_TARGET}")" ]; then
echo "BLOCKER audit_writeback_target_directory_mismatch"
exit 2
fi
case "${GITEA_AUDIT_BRANCH}" in
mcp-artifact-receipts)
expected_target_directory="docs/operations/external-mcp-artifacts"
expected_controller_schema="awoooi_external_mcp_artifact_receipt_v1"
expected_verifier_schema="awoooi_external_mcp_artifact_verifier_receipt_v1"
;;
mcp-replay-receipts)
expected_target_directory="docs/operations/external-mcp-replays"
expected_controller_schema="awoooi_external_mcp_replay_receipt_v1"
expected_verifier_schema="awoooi_external_mcp_replay_verifier_receipt_v1"
;;
esac
if [ "$(dirname "${GITEA_AUDIT_CONTROLLER_TARGET}")" != "${expected_target_directory}" ]; then
echo "BLOCKER audit_writeback_branch_target_mismatch"
exit 2
fi
if [ "${#GITEA_AUDIT_COMMIT_MESSAGE}" -gt 200 ] || \
[[ "${GITEA_AUDIT_COMMIT_MESSAGE}" == *$'\n'* ]] || \
[[ "${GITEA_AUDIT_COMMIT_MESSAGE}" == *$'\r'* ]]; then
echo "BLOCKER audit_writeback_commit_message_invalid"
exit 2
fi
for source_path in \
"${GITEA_AUDIT_CONTROLLER_SOURCE}" \
"${GITEA_AUDIT_VERIFIER_SOURCE}"; do
if [ ! -f "${source_path}" ] || [ -L "${source_path}" ]; then
echo "BLOCKER audit_writeback_source_invalid"
exit 2
fi
source_size="$(wc -c < "${source_path}" | tr -d ' ')"
if [ "${source_size}" -le 0 ] || [ "${source_size}" -gt 4194304 ]; then
echo "BLOCKER audit_writeback_source_size_invalid"
exit 2
fi
done
python3 - \
"${GITEA_AUDIT_CONTROLLER_SOURCE}" \
"${GITEA_AUDIT_VERIFIER_SOURCE}" \
"${expected_controller_schema}" \
"${expected_verifier_schema}" <<'PY'
import json
import sys
from pathlib import Path
def fail(message: str) -> None:
print(message)
raise SystemExit(2)
try:
receipts = [
json.loads(Path(value).read_text(encoding="utf-8")) for value in sys.argv[1:3]
]
except (OSError, UnicodeError, json.JSONDecodeError):
fail("BLOCKER audit_writeback_receipt_json_invalid")
expected_schemas = sys.argv[3:5]
identity_fields = ("run_id", "trace_id", "work_item_id")
for payload, expected_schema in zip(receipts, expected_schemas):
if not isinstance(payload, dict) or payload.get("schema_version") != expected_schema:
fail("BLOCKER audit_writeback_receipt_schema_invalid")
if any(not str(payload.get(field) or "") for field in identity_fields):
fail("BLOCKER audit_writeback_receipt_identity_missing")
if any(receipts[0][field] != receipts[1][field] for field in identity_fields):
fail("BLOCKER audit_writeback_receipt_identity_mismatch")
PY
remote_name="gitea-audit"
git remote remove "${remote_name}" >/dev/null 2>&1 || true
git remote add "${remote_name}" "${GITEA_AUDIT_REMOTE_URL}"
rm -f \
"${GITEA_AUDIT_CONTROLLER_TARGET}" \
"${GITEA_AUDIT_VERIFIER_TARGET}"
for attempt in 1 2 3; do
if git ls-remote --exit-code --heads "${remote_name}" \
"refs/heads/${GITEA_AUDIT_BRANCH}" >/dev/null 2>&1; then
git fetch --no-tags --depth=1 "${remote_name}" "${GITEA_AUDIT_BRANCH}"
git checkout --force --detach FETCH_HEAD
fi
target_directory="$(dirname "${GITEA_AUDIT_CONTROLLER_TARGET}")"
for ancestor in docs docs/operations "${target_directory}"; do
if [ -L "${ancestor}" ]; then
echo "BLOCKER audit_writeback_target_symlink_rejected"
exit 2
fi
done
mkdir -p "${target_directory}"
for target_path in \
"${GITEA_AUDIT_CONTROLLER_TARGET}" \
"${GITEA_AUDIT_VERIFIER_TARGET}"; do
if [ -L "${target_path}" ]; then
echo "BLOCKER audit_writeback_target_symlink_rejected"
exit 2
fi
done
install -m 0644 \
"${GITEA_AUDIT_CONTROLLER_SOURCE}" \
"${GITEA_AUDIT_CONTROLLER_TARGET}"
install -m 0644 \
"${GITEA_AUDIT_VERIFIER_SOURCE}" \
"${GITEA_AUDIT_VERIFIER_TARGET}"
git add \
"${GITEA_AUDIT_CONTROLLER_TARGET}" \
"${GITEA_AUDIT_VERIFIER_TARGET}"
while IFS= read -r staged_path; do
if [ "${staged_path}" != "${GITEA_AUDIT_CONTROLLER_TARGET}" ] && \
[ "${staged_path}" != "${GITEA_AUDIT_VERIFIER_TARGET}" ]; then
echo "BLOCKER audit_writeback_unexpected_staged_path"
exit 2
fi
done < <(git diff --cached --name-only)
if git diff --cached --quiet; then
echo "receipt_writeback=no_change"
echo "receipt_branch=${GITEA_AUDIT_BRANCH}"
echo "receipt_commit_sha=$(git rev-parse HEAD)"
exit 0
fi
git commit -m "${GITEA_AUDIT_COMMIT_MESSAGE}"
if git push "${remote_name}" "HEAD:refs/heads/${GITEA_AUDIT_BRANCH}"; then
echo "receipt_writeback=verified_audit_branch_normal_push"
echo "receipt_branch=${GITEA_AUDIT_BRANCH}"
echo "receipt_commit_sha=$(git rev-parse HEAD)"
exit 0
fi
echo "receipt_writeback_retry=${attempt}"
sleep 5
done
echo "BLOCKER receipt_writeback_non_fast_forward_after_bounded_retry"
exit 1