Files
RedBear-OS/local/scripts/provision-release.sh
vasilito 5851974b20 feat: build system transition to release fork + archive hardening
Release fork infrastructure:
- REDBEAR_RELEASE=0.1.1 with offline enforcement (fetch/distclean/unfetch blocked)
- 195 BLAKE3-verified source archives in standard format
- Atomic provisioning via provision-release.sh (staging + .complete sentry)
- 5-phase improvement plan: restore format auto-detection, source tree
  validation (validate-source-trees.py), archive-map.json, REPO_BINARY fallback

Archive normalization:
- Removed 87 duplicate/unversioned archives from shared pool
- Regenerated all archives in consistent format with source/ + recipe.toml
- BLAKE3SUMS and manifest.json generated from stable tarball set

Patch management:
- verify-patches.sh: pre-sync dry-run report (OK/REVERSED/CONFLICT)
- 121 upstream-absorbed patches moved to absorbed/ directories
- 43 active patches verified clean against rebased sources
- Stress test: base updated to upstream HEAD, relibc reset and patched

Compilation fixes:
- relibc: Vec imports in redox-rt (proc.rs, lib.rs, sys.rs)
- relibc: unsafe from_raw_parts in mod.rs (2024 edition)
- fetch.rs: rev comparison handles short/full hash prefixes
- kibi recipe: corrected rev mismatch

New scripts: restore-sources.sh, provision-release.sh, verify-sources-archived.sh,
check-upstream-releases.sh, validate-source-trees.py, verify-patches.sh,
repair-archive-format.sh, generate-manifest.py

Documentation: AGENTS.md, README.md, local/AGENTS.md updated for release fork model
2026-05-02 01:41:17 +01:00

248 lines
9.3 KiB
Bash
Executable File

#!/usr/bin/env bash
# provision-release.sh — Seal current build tree as a new Red Bear OS release (atomic).
#
# Usage:
# ./local/scripts/provision-release.sh --release=0.2.0 [--ref=<tag>] [--dry-run]
#
# Provisions a self-contained, immutable release archive via staging + atomic mv.
# All 7 completeness gates must pass before .complete sentry is written.
# On failure, staging directory is cleaned up automatically.
#
# Requires explicit --release. Never runs automatically.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
REF=""
RELEASE=""
DRY_RUN=0
usage() {
cat <<EOF
Usage: $(basename "$0") --release=<ver> [--ref=<redox-tag>] [--dry-run]
Seal current source tree as a new Red Bear OS release (atomic provisioning).
Options:
--release=<ver> Red Bear OS release version (e.g., 0.2.0) — REQUIRED
--ref=<tag> Optional Redox OS ref for provenance tracking
--dry-run Preview only — no filesystem changes
-h, --help Show this help
EOF
}
while [ $# -gt 0 ]; do
case "$1" in
--ref=*) REF="${1#*=}" ;;
--release=*) RELEASE="${1#*=}" ;;
--dry-run) DRY_RUN=1 ;;
-h|--help) usage; exit 0 ;;
*) echo "Unknown: $1"; usage >&2; exit 1 ;;
esac
shift
done
if [ -z "$RELEASE" ]; then
echo "ERROR: --release is required" >&2
usage >&2
exit 1
fi
cd "$PROJECT_ROOT"
RED='\033[1;31m'
GREEN='\033[1;32m'
YELLOW='\033[1;33m'
BLUE='\033[1;34m'
NC='\033[0m'
status() { echo -e "${GREEN}==>${NC} $*"; }
warn() { echo -e "${YELLOW}WARN${NC}: $*"; }
err() { echo -e "${RED}ERROR${NC}: $*" >&2; }
info() { echo -e "${BLUE} ${NC} $*"; }
STAGING="sources/.staging/redbear-${RELEASE}"
FINAL="sources/redbear-${RELEASE}"
cleanup_staging() {
if [ -d "$STAGING" ]; then
warn "Cleaning up staging directory..."
rm -rf "$STAGING"
fi
}
trap cleanup_staging EXIT
# ── Step 1: Verify current release is archived ──────────────────────
status "Step 1: Verifying current release..."
CURRENT_RELEASE="${REDBEAR_RELEASE:-0.1.0}"
CURRENT_ARCHIVE="sources/redbear-$CURRENT_RELEASE"
if [ ! -f "$CURRENT_ARCHIVE/.complete" ] && [ ! -f "$CURRENT_ARCHIVE/manifest.txt" ]; then
warn "Current release $CURRENT_RELEASE has no .complete sentry or manifest"
warn "It may not be fully archived. Continue anyway? (y/N)"
if [ "$DRY_RUN" -eq 0 ]; then
read -r confirm
[ "$confirm" = "y" ] || [ "$confirm" = "Y" ] || exit 1
fi
fi
info "Current release: $CURRENT_RELEASE"
# ── Step 2: Ref validation (optional) ───────────────────────────────
if [ -n "$REF" ]; then
status "Step 2: Validating ref=$REF..."
if [ "$DRY_RUN" -eq 1 ]; then
info "[dry-run] Would validate ref $REF"
else
REDOX_URL="https://gitlab.redox-os.org/redox-os/redox.git"
if timeout 10 git ls-remote --tags "$REDOX_URL" "$REF" 2>/dev/null | grep -q "$REF"; then
info "Ref $REF exists in Redox repository"
elif timeout 10 git ls-remote --tags "$REDOX_URL" 2>/dev/null | grep -q .; then
err "Ref $REF not found"
exit 1
else
warn "Cannot reach Redox repository — ref recorded as stated provenance"
fi
fi
fi
# ── Step 3: Staging safety check ────────────────────────────────────
status "Step 3: Checking staging..."
if [ -d "$STAGING" ]; then
err "Staging directory already exists: $STAGING"
err "This may be from a previous failed provisioning run."
err "Remove it first: rm -rf $STAGING"
[ "$DRY_RUN" -eq 1 ] || exit 1
fi
if [ -d "$FINAL" ]; then
err "Release already exists: $FINAL"
err "Releases are immutable. Choose a different --release version."
[ "$DRY_RUN" -eq 1 ] || exit 1
fi
info "Staging path is clear"
# ── Step 4: Archive sources ─────────────────────────────────────────
status "Step 4: Archiving sources..."
if [ "$DRY_RUN" -eq 1 ]; then
info "[dry-run] Would run: archive-sources.sh --release=$RELEASE --all"
else
mkdir -p "$STAGING"/{tarballs,snapshots,configs}
if [ -f "$SCRIPT_DIR/archive-sources.sh" ]; then
bash "$SCRIPT_DIR/archive-sources.sh" --release="$RELEASE" --all
info "Sources archived"
else
err "archive-sources.sh not found"
exit 1
fi
fi
# ── Step 5: Archive configs ─────────────────────────────────────────
status "Step 5: Archiving configs..."
if [ "$DRY_RUN" -eq 1 ]; then
info "[dry-run] Would copy configs"
else
cp config/redbear-*.toml config/base.toml config/minimal.toml "$STAGING/configs/" 2>/dev/null || true
cp .config "$STAGING/configs/" 2>/dev/null || true
info "Configs: $(ls "$STAGING/configs"/*.toml 2>/dev/null | wc -l) files"
fi
# ── Step 6: Archive patches ─────────────────────────────────────────
status "Step 6: Archiving patches..."
if [ "$DRY_RUN" -eq 1 ]; then
info "[dry-run] Would archive patches"
else
if [ -d "local/patches" ]; then
(cd local && tar czf "$PROJECT_ROOT/$STAGING/patches.tar.gz" patches/)
info "Patches archived: patches.tar.gz"
fi
fi
# ── Step 7: Generate manifest ───────────────────────────────────────
status "Step 7: Generating manifest..."
if [ "$DRY_RUN" -eq 1 ]; then
info "[dry-run] Would generate manifest.json"
else
if [ -f "$SCRIPT_DIR/generate-manifest.py" ]; then
python3 "$SCRIPT_DIR/generate-manifest.py" --release="$RELEASE" --staging > "$STAGING/manifest.json" || {
err "Manifest generation failed"
exit 1
}
info "Manifest: $(python3 -c "import json; d=json.load(open('$STAGING/manifest.json')); print(len(d.get('entries',{})))" 2>/dev/null || echo "?") entries"
else
err "generate-manifest.py not found"
exit 1
fi
fi
# ── Step 8: Generate BLAKE3SUMS ─────────────────────────────────────
status "Step 8: Generating checksums..."
if [ "$DRY_RUN" -eq 1 ]; then
info "[dry-run] Would generate BLAKE3SUMS and PAYLOAD.blake3"
else
if [ -d "$STAGING/tarballs" ] && ls "$STAGING/tarballs"/*.tar.gz >/dev/null 2>&1; then
(cd "$STAGING/tarballs" && b3sum *.tar.gz) > "$STAGING/BLAKE3SUMS"
info "BLAKE3SUMS: $(wc -l < "$STAGING/BLAKE3SUMS") entries"
fi
if [ -d "$STAGING/snapshots" ] && ls "$STAGING/snapshots"/*.tar.gz >/dev/null 2>&1; then
(cd "$STAGING/snapshots" && b3sum *.tar.gz) >> "$STAGING/BLAKE3SUMS"
fi
# Generate whole-payload hash
(cd "$STAGING" && find . -type f ! -name PAYLOAD.blake3 ! -name .complete -print0 | sort -z | xargs -0 b3sum) > "$STAGING/PAYLOAD.blake3" 2>/dev/null || true
fi
# ── Step 9: Completeness gates ──────────────────────────────────────
status "Step 9: Running completeness gates..."
if [ "$DRY_RUN" -eq 1 ]; then
info "[dry-run] Would run verify-release-completeness.sh"
else
if [ -f "$SCRIPT_DIR/verify-release-completeness.sh" ]; then
if bash "$SCRIPT_DIR/verify-release-completeness.sh" --release="$RELEASE" --staging; then
info "All completeness gates PASSED"
else
err "Completeness gates FAILED"
exit 1
fi
else
warn "verify-release-completeness.sh not found — skipping gate checks"
fi
fi
# ── Step 10: Seal and deploy ────────────────────────────────────────
status "Step 10: Sealing release..."
if [ "$DRY_RUN" -eq 1 ]; then
info "[dry-run] Would write .complete sentry and move to $FINAL"
else
echo "$(date -u +%Y-%m-%dT%H:%M:%SZ) — Release $RELEASE" > "$STAGING/.complete"
if [ -d "$FINAL" ]; then
err "Release directory already exists: $FINAL"
err "Releases are immutable. Choose a different --release version."
exit 1
fi
mv "$STAGING" "$FINAL"
fi
# ── Report ──────────────────────────────────────────────────────────
echo ""
echo -e "${GREEN}=========================================${NC}"
if [ "$DRY_RUN" -eq 0 ]; then
echo -e "${GREEN} Release $RELEASE provisioned${NC}"
else
echo -e "${GREEN} Dry-run complete — no changes made${NC}"
fi
echo -e "${GREEN}=========================================${NC}"
echo ""
if [ "$DRY_RUN" -eq 0 ]; then
echo "Archive: $FINAL/"
echo " tarballs/: $(ls "$FINAL/tarballs" 2>/dev/null | wc -l) archives"
echo " configs/: $(ls "$FINAL/configs" 2>/dev/null | wc -l) files"
echo " .complete: $(cat "$FINAL/.complete")"
echo ""
echo "To verify: ./local/scripts/verify-sources-archived.sh --release=$RELEASE"
echo ""
echo "To switch: edit .config → REDBEAR_RELEASE?=$RELEASE"
fi
# Prevent trap cleanup on success
trap - EXIT