From 96fc1d3879fe4d3d30606ef744fdaa27950aa901 Mon Sep 17 00:00:00 2001 From: Sam & Claude Date: Mon, 15 Jun 2026 16:47:38 +0200 Subject: [PATCH] =?UTF-8?q?feat(build):=20enforce=20clean=20repos=20on=20r?= =?UTF-8?q?elease=20builds=20=E2=80=94=20gate=20now=20covers=20iso/colibri?= =?UTF-8?q?/zot?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.sh | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 78 insertions(+), 8 deletions(-) diff --git a/build.sh b/build.sh index 57b6d5b4..079a96f1 100755 --- a/build.sh +++ b/build.sh @@ -102,14 +102,7 @@ if [ -n "${SSH_PUBLIC_KEY:-}" ]; then fi if [ "${BUILD_CHANNEL}" = "release" ]; then - case "${CLAWDIE_REF}" in - v[0-9]*.[0-9]*.[0-9]*) ;; - *) - echo "ERROR: release builds must pin a Clawdie-AI tag with --clawdie-version X.Y.Z" - echo " Current Clawdie ref: ${CLAWDIE_REF}" - exit 1 - ;; - esac + check_release_gate fi # The ISO carries its own product version (ISO_VERSION in build.cfg). It does not @@ -467,6 +460,69 @@ is_pinned_clawdie_ref() { printf '%s' "$_ref" | grep -Eq '^[0-9a-fA-F]{40}$|^v[0-9]+\.[0-9]+\.[0-9]+$' } +# Release builds require clean, committed sources across the whole stack. +# A release ISO must be a reproducible artifact — no uncommitted local patches. +check_release_gate() { + case "${CLAWDIE_REF}" in + v[0-9]*.[0-9]*.[0-9]*) ;; + *) + echo "ERROR: release builds must pin a Clawdie-AI tag with --clawdie-version X.Y.Z" + echo " Current Clawdie ref: ${CLAWDIE_REF}" + exit 1 + ;; + esac + + _release_errors=0 + + # Clawdie-AI local checkout + resolve_clawdie_ai_repo + if command -v git >/dev/null 2>&1 && git -C "${_resolved_clawdie_ai_repo}" rev-parse --git-dir >/dev/null 2>&1; then + if ! git -C "${_resolved_clawdie_ai_repo}" diff --quiet 2>/dev/null || ! git -C "${_resolved_clawdie_ai_repo}" diff --cached --quiet 2>/dev/null; then + echo "ERROR: release builds require a clean clawdie-ai repo" + echo " Uncommitted changes detected in: ${_resolved_clawdie_ai_repo}" + _release_errors=$((_release_errors + 1)) + fi + fi + + # ISO repo itself + if command -v git >/dev/null 2>&1 && git -C "${SCRIPT_DIR}" rev-parse --git-dir >/dev/null 2>&1; then + if ! git -C "${SCRIPT_DIR}" diff --quiet 2>/dev/null || ! git -C "${SCRIPT_DIR}" diff --cached --quiet 2>/dev/null; then + echo "ERROR: release builds require a clean clawdie-iso repo" + echo " Uncommitted changes detected in: ${SCRIPT_DIR}" + _release_errors=$((_release_errors + 1)) + fi + fi + + # Colibri + if [ "${FEATURE_COLIBRI:-NO}" = "YES" ]; then + resolve_colibri_paths + if command -v git >/dev/null 2>&1 && git -C "${_resolved_colibri_repo}" rev-parse --git-dir >/dev/null 2>&1; then + if ! git -C "${_resolved_colibri_repo}" diff --quiet 2>/dev/null || ! git -C "${_resolved_colibri_repo}" diff --cached --quiet 2>/dev/null; then + echo "ERROR: release builds require a clean colibri repo" + echo " Uncommitted changes detected in: ${_resolved_colibri_repo}" + _release_errors=$((_release_errors + 1)) + fi + fi + + # Zot (agent binary) + if [ "${COLIBRI_STAGE_AGENT:-YES}" = "YES" ]; then + resolve_zot_paths + if command -v git >/dev/null 2>&1 && git -C "${_resolved_zot_repo}" rev-parse --git-dir >/dev/null 2>&1; then + if ! git -C "${_resolved_zot_repo}" diff --quiet 2>/dev/null || ! git -C "${_resolved_zot_repo}" diff --cached --quiet 2>/dev/null; then + echo "ERROR: release builds require a clean zot repo" + echo " Uncommitted changes detected in: ${_resolved_zot_repo}" + _release_errors=$((_release_errors + 1)) + fi + fi + fi + fi + + if [ "${_release_errors}" -gt 0 ]; then + echo "ERROR: release build aborted — ${_release_errors} dirty repo(s). Use BUILD_CHANNEL=dev for iteration builds." + exit 1 + fi +} + write_build_manifest() { _manifest_path="$1" _iso_repo_commit="unknown" @@ -500,6 +556,19 @@ write_build_manifest() { fi fi fi + # Zot provenance (agent binary built from source — record if repo is dirty). + _zot_dirty="null" + if [ "${FEATURE_COLIBRI:-NO}" = "YES" ] && [ "${COLIBRI_STAGE_AGENT:-YES}" = "YES" ]; then + resolve_zot_paths + if command -v git >/dev/null 2>&1 && git -C "${_resolved_zot_repo}" rev-parse --git-dir >/dev/null 2>&1; then + if git -C "${_resolved_zot_repo}" diff --quiet 2>/dev/null && \ + git -C "${_resolved_zot_repo}" diff --cached --quiet 2>/dev/null; then + _zot_dirty="false" + else + _zot_dirty="true" + fi + fi + fi mkdir -p "$(dirname "$_manifest_path")" cat > "$_manifest_path" <