Files
cc-ci-orchestrator/cc-ci-plan/reconcile-upstream.sh
T
autonomic-bot 3047ee7724 config: GITEA_URL is public config, not a credential
The Gitea host was stored in the credentials env file, so a literal
secret scanner treated it as a secret and refused two READMEs in another
repo that link to git.autonomic.zone.

It was never secret: advisory-scan.py, pr-survey.py and recipe-report.py
already default it to git.autonomic.zone, and it is this repo's own
remote host. It is a bare hostname with no scheme, userinfo or path.

Removed from the env file and defaulted here the same way the Python
already does. GITEA_USERNAME and GITEA_PASSWORD keep their :? guard --
those are real credentials and must still fail loudly if unset.
2026-08-26 17:46:58 +00:00

65 lines
3.2 KiB
Bash
Executable File

#!/usr/bin/env bash
# reconcile-upstream — sync recipe mirrors from TRUE upstream. Run this FIRST, always.
# ----------------------------------------------------------------------------------
# Every recipe we maintain is a MIRROR of a coopcloud recipe. Work done against a stale
# mirror is wasted or wrong, in three ways we have actually hit:
#
# 1. A PR whose changes upstream ALREADY MERGED. mailu #6 (2024.06.57 + redis 8.10,
# two internet-facing Roundcube CVEs) sat open and was reported as the fix for
# those CVEs — while upstream had merged and released it as 3.1.3+2024.06.57. The
# work was done; only our mirror was behind.
# 2. A survey that reads the stale mirror and reports "no upgrades available", so a
# recipe silently drops out of the weekly run.
# 3. Reading the WRONG BRANCH. Several coopcloud recipes keep a stale `main` beside
# the real default `master` — gitea's `main` is at 1.24.2-rootless while `master`
# has 1.27.1-rootless plus the merged PRs. Reading `main` there says the recipe is
# three releases behind and missing two CVSS-9.8 RCE fixes, which reads exactly
# like a real finding. open-recipe-pr.sh resolves the default branch itself
# (main OR master) — never hand-pick one.
#
# This is deterministic: it force-syncs each mirror's `main` to upstream's default
# branch and closes any mirror PR whose changes are already upstream. No AI judgement.
#
# reconcile-upstream.sh <recipe>... # specific recipes
# reconcile-upstream.sh --all # every recipe in used-recipes.md
#
# Safe to run repeatedly; a mirror already in sync is a no-op. Recipe work lives in
# BRANCHES, never on mirror `main`, so force-syncing `main` discards nothing.
set -o errexit -o nounset -o pipefail
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ORCH="$(dirname "$HERE")"
SSH="${SSH:-cc-ci}"
TESTENV="${TESTENV:-/srv/cc-ci/.testenv}"
RECONCILE="${RECONCILE:-$ORCH/.claude/skills/recipe-upgrade/open-recipe-pr.sh}"
USED_RECIPES="${USED_RECIPES:-$HERE/used-recipes.md}"
[ -f "$RECONCILE" ] || { echo "ERROR: reconcile helper not found: $RECONCILE" >&2; exit 1; }
set -a; . "$TESTENV"; set +a
: "${GITEA_USERNAME:?}"; : "${GITEA_PASSWORD:?}"; : "${GITEA_URL:=git.autonomic.zone}"
if [ "${1:-}" = "--all" ]; then
mapfile -t RECIPES < <(awk '!/^[[:space:]]*#/ && ($2=="weekly" || $2=="external") {print $1}' "$USED_RECIPES")
else
[ "$#" -gt 0 ] || { echo "usage: reconcile-upstream.sh <recipe>... | --all" >&2; exit 2; }
RECIPES=("$@")
fi
synced=0; closed=0; failed=0
for r in "${RECIPES[@]}"; do
echo "── $r"
if out="$(ssh "$SSH" "GITEA_USERNAME='$GITEA_USERNAME' GITEA_PASSWORD='$GITEA_PASSWORD' GITEA_URL='$GITEA_URL' bash -s $r --reconcile-only" < "$RECONCILE" 2>&1)"; then
printf '%s\n' "$out" | grep -E "Force-syncing|already in sync|closed PR|still open|✓" | sed 's/^/ /' || true
synced=$((synced + 1))
closed=$((closed + $(printf '%s' "$out" | grep -c "closed PR" || true)))
else
printf '%s\n' "$out" | tail -3 | sed 's/^/ /'
echo " ✗ FAILED — do NOT proceed against this mirror until it reconciles"
failed=$((failed + 1))
fi
done
echo
echo "reconcile-upstream: ${synced} mirror(s) synced, ${closed} already-upstream PR(s) closed, ${failed} failed"
[ "$failed" -eq 0 ]