fix(release): leak guard + export-ignore + env default (review fixes)

The actual file changes for the leak-safety hardening described in a94efb0
(that commit only captured the art/ asset move):
- promote.sh: leak guard refusing to publish a tree carrying a private identifier
  (git.bave.dev / boban/clusev / clusev-staging) or an internal doc; negative test.
- .gitattributes: export-ignore kickoff-prompt.md (leaked the VM IP).
- README: reference the moved art/ SVGs (docs/ is export-ignored).
- .env.example: comment out CLUSEV_REPOSITORY so the public-repo config default
  applies (a present-but-empty value would disable the update check).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
feat/v1-foundation
boban 2026-06-22 22:16:23 +02:00
parent 437221788d
commit 51b8572d98
5 changed files with 36 additions and 6 deletions

View File

@ -85,10 +85,11 @@ ACME_EMAIL=
# .git (the prod image ships none) — leave empty; in dev the page reads .git directly. # .git (the prod image ships none) — leave empty; in dev the page reads .git directly.
CLUSEV_BUILD_SHA= CLUSEV_BUILD_SHA=
CLUSEV_BUILD_BRANCH= CLUSEV_BUILD_BRANCH=
# Update source for the in-app version check. install.sh derives this from the clone origin # Update source for the in-app version check. install.sh sets this from the clone origin
# (git remote get-url origin). Leave empty to disable the check. Never put a private repo URL in a # (git remote get-url origin). Left UNSET (keep this commented), it falls back to the public repo
# tracked file — only here in the per-deployment .env. # default in config/clusev.php — an empty value here would instead disable the check, so leave the
CLUSEV_REPOSITORY= # key absent rather than blank. Never put a private repo URL in a tracked file — only in the .env.
# CLUSEV_REPOSITORY=https://github.com/clusev/clusev
# Display timezone for dashboard times (DB stays UTC). install.sh sets this from the host; UTC default. # Display timezone for dashboard times (DB stays UTC). install.sh sets this from the host; UTC default.
APP_TIMEZONE=UTC APP_TIMEZONE=UTC
# External reverse-proxy TLS: set to the upstream proxy's address/CIDR so Caddy trusts its # External reverse-proxy TLS: set to the upstream proxy's address/CIDR so Caddy trusts its

1
.gitattributes vendored
View File

@ -15,4 +15,5 @@
/CLAUDE.md export-ignore /CLAUDE.md export-ignore
/rules.md export-ignore /rules.md export-ignore
/handoff.md export-ignore /handoff.md export-ignore
/kickoff-prompt.md export-ignore
/docs export-ignore /docs export-ignore

View File

@ -1,6 +1,6 @@
<div align="center"> <div align="center">
<img src="docs/assets/clusev-banner.svg" alt="Clusev — self-hosted control plane for a fleet of Linux servers" width="100%"> <img src="art/clusev-banner.svg" alt="Clusev — self-hosted control plane for a fleet of Linux servers" width="100%">
<br> <br>
@ -61,7 +61,7 @@ colour, dots and pills — never emoji.
## Architecture ## Architecture
<div align="center"> <div align="center">
<img src="docs/assets/clusev-architecture.svg" alt="Operator → Clusev control plane → your fleet" width="100%"> <img src="art/clusev-architecture.svg" alt="Operator → Clusev control plane → your fleet" width="100%">
</div> </div>
Laravel is the **control plane**, not a re-implementation of your servers. The browser talks to it Laravel is the **control plane**, not a re-implementation of your servers. The browser talks to it

View File

@ -28,6 +28,23 @@ git -C "$src" archive --format=tar "$tag" | tar -x -C "$pub"
# Private CI never goes public. # Private CI never goes public.
rm -rf "${pub:?}/.github" rm -rf "${pub:?}/.github"
# Leak guard — never publish a tree that still carries a private identifier or an internal doc. This
# makes promote.sh safe even for a tag cut BEFORE the export-ignore / URL-neutralisation fixes: such
# a tree is refused (the public repo is left untouched) instead of leaking the dev/staging repos.
leak=0
for f in CLAUDE.md rules.md handoff.md kickoff-prompt.md docs; do
[ -e "$pub/$f" ] && { echo "leak-guard: internal path present in the tree: $f" >&2; leak=1; }
done
if grep -rIl -e 'git\.bave\.dev' -e 'boban/clusev' -e 'clusev-staging' "$pub" >/dev/null 2>&1; then
echo "leak-guard: private repo identifier in the tree to be published:" >&2
grep -rIl -e 'git\.bave\.dev' -e 'boban/clusev' -e 'clusev-staging' "$pub" >&2
leak=1
fi
if [ "$leak" -ne 0 ]; then
echo "leak-guard: REFUSING to publish $tag — promote a tag cut after the leak-safety fixes (>= v0.9.58)." >&2
exit 1
fi
git -C "$pub" add -A git -C "$pub" add -A
# --allow-empty: stable promotion re-tags the same source commit as the last beta, so the # --allow-empty: stable promotion re-tags the same source commit as the last beta, so the
# extracted tree is byte-identical and there is nothing to stage — still produce a release commit. # extracted tree is byte-identical and there is nothing to stage — still produce a release commit.

View File

@ -42,4 +42,15 @@ git -C "$work/src" tag v1.0.1 v1.0.0
bash "$here/promote.sh" "$work/src" v1.0.1 "$work/pub" "Release v1.0.1" bash "$here/promote.sh" "$work/src" v1.0.1 "$work/pub" "Release v1.0.1"
git -C "$work/pub" rev-parse v1.0.1 >/dev/null 2>&1 || { echo "FAIL: identical-tree tag missing"; exit 1; } git -C "$work/pub" rev-parse v1.0.1 >/dev/null 2>&1 || { echo "FAIL: identical-tree tag missing"; exit 1; }
git -C "$work/pub" log -1 --pretty=%s | grep -qx 'Release v1.0.1' || { echo "FAIL: identical-tree commit message"; exit 1; } git -C "$work/pub" log -1 --pretty=%s | grep -qx 'Release v1.0.1' || { echo "FAIL: identical-tree commit message"; exit 1; }
# Leak guard: a tree carrying a private identifier in a PUBLISHED file must be REFUSED, with no tag
# created (protects against promoting an old tag cut before the leak-safety fixes).
git init -q "$work/leaky"
printf 'home: https://git.bave.dev/boban/clusev\n' > "$work/leaky/README.md"
git -C "$work/leaky" add -A && git -C "$work/leaky" commit -qm init && git -C "$work/leaky" tag v9.9.9
git init -q "$work/pub2"
if bash "$here/promote.sh" "$work/leaky" v9.9.9 "$work/pub2" "Release v9.9.9" 2>/dev/null; then
echo "FAIL: leak guard did not refuse a private-identifier tree"; exit 1
fi
git -C "$work/pub2" rev-parse v9.9.9 >/dev/null 2>&1 && { echo "FAIL: tag created despite leak"; exit 1; }
echo "PASS" echo "PASS"