Skip to content

fix: keep the install when a clone or an Alpine extract fails - #210

Open
rcourtman wants to merge 2 commits into
community-scripts:mainfrom
rcourtman:fix/git-alpine-clean-install
Open

rcourtman wants to merge 2 commits into
community-scripts:mainfrom
rcourtman:fix/git-alpine-clean-install

Conversation

@rcourtman

Copy link
Copy Markdown

✍️ Description

The follow-up suggested in #201, for the two spots still wiping too early or too widely.

Git clone path. fetch_and_deploy_gh_branch ran rm -rf "$target" before cloning, so a failed clone left nothing. It now clones beside the target and replaces it through _cs_clean_target_dir once the clone has worked. That also brings mount points and CLEAN_INSTALL_KEEP to this path. The target still ends up with the clone's owner and mode, as it did with a direct clone.

lib/alpine.func.

  • The prebuild unzip and tar were unchecked, so a broken archive still emptied the target.
  • A tarball with no top-level directory ran cd "" and copied the current directory into the target.
  • The wipe missed dotfiles, emptied mounts and ignored CLEAN_INSTALL_KEEP.

Extracts are now checked, an empty payload is an error, and the wipe is a copy of _cs_clean_target_dir, so the parity check will flag future edits. It stays in bash because busybox ash already can't parse this file (the array at line 76).

_cs_clean_target_dir itself (second commit, in both copies). It only protected a mount directly listed by find. With a mount at data/uploads, rm -rf data still emptied it. Files now go with rm -f, then directories deepest first with rmdir. A file that can't be removed still stops the script under set -e, as before.

Tested on Proxmox VE 9.2 in real containers, with real tmpfs mounts and under set -eEo pipefail:

Case main This branch
Debian 13, clean clone fails target empty target intact
Debian 13, clean clone from github.com, mount inside target mount emptied, clone fails mount intact, deployed
Debian 13, nested mount, app-owned target not run mount intact, deployed, target root-owned, stamp written
Alpine 3.24, clean prebuild, mount inside target mount emptied mount intact, deployed
Alpine 3.24, clean prebuild, nested mount not run mount intact, deployed

The two new test files pass on Ubuntu and on Alpine with busybox find, tar, sort and xargs. Their failure cases fail on main. All 40 scripts in the test list pass, with no ShellCheck errors and no new warnings. Not tested on Incus (no Incus host here).

Not changed: the update path's git clean -fd also empties an untracked mount inside a checkout, then fails on it. That isn't a clean install, so I left it out.

This and #201 add to the same test list, so whichever merges second will need both sides kept.

Written and tested with Claude Opus 5.5 (reasoning: high).

🔗 Related Issue

Related: #201

✅ Prerequisites (X in brackets)

  • Self-review completed – Code follows project standards.
  • Tested thoroughly – Changes work as expected (Proxmox VE and/or Incus, as applicable).
  • No security risks – No hardcoded secrets, unnecessary privilege escalations, or permission issues.
  • API.txt regenerated – If a function signature or behavior changed, API.txt was updated to match.

🛠️ Type of Change (X in brackets)

  • 🐞 Bug fix – Resolves an issue without breaking functionality.
  • ✨ New feature – Adds new, non-breaking functionality.
  • 💥 Breaking change – Alters existing behavior in a way that may require updates in every downstream script.
  • 🔧 Refactoring / Code Cleanup – Improves readability or maintainability without changing functionality.
  • 📝 Documentation update – Changes to README, docs/, CONTRIBUTING.md, or other docs.

🤖 AI Assistance (X in brackets)

If you used an AI tool (GitHub Copilot, Claude, ChatGPT, etc.) to write or generate any code in this PR, you must confirm compliance below.
Select exactly one option.

  • No AI used – Code was written without AI assistance.
  • AI was used – The output has been reviewed and corrected, and I take responsibility for it matching this repo's conventions.

rcourtman added 2 commits November 4, 2026 23:42
fetch_and_deploy_gh_branch removed the target before cloning, so a failed
clone left nothing. It now clones beside the target and replaces it only
once the clone has worked, through _cs_clean_target_dir, which also brings
mount points and CLEAN_INSTALL_KEEP to this path.

lib/alpine.func ran the prebuild wipe after unchecked unzip and tar calls,
so a broken archive still emptied the target, and the wipe itself missed
dotfiles, took the contents of mounts and ignored CLEAN_INSTALL_KEEP. A
tarball with no top-level directory also ran `cd ""` and copied the current
directory into the target. Extracts are now checked, an empty payload is an
error, and the wipe is the same _cs_clean_target_dir as lib/forge.func.
_cs_clean_target_dir pruned a mount point from its list, but the list still
held the mount's parents, and rm -rf on a parent emptied the mount. A bind
mount at data/uploads lost its contents on a clean install. Files now go
first with rm -f, whose failures still stop the script, then directories
deepest first with rmdir, which leaves a parent that still holds a mount.
@github-actions

github-actions Bot commented Nov 4, 2026

Copy link
Copy Markdown
Contributor

Try this branch

The engine and the scripts resolve independently, so a production script can
be run against the engine from this PR by setting one variable:

COMMUNITY_SCRIPTS_CORE_URL=https://raw.githubusercontent.com/rcourtman/core/fix/git-alpine-clean-install \
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/debian.sh)"

Swap ct/debian.sh for whatever exercises the change.

Run a script from a fork as well
curl -fsSL https://raw.githubusercontent.com/rcourtman/core/fix/git-alpine-clean-install/tools/run.sh |
  bash -s -- https://raw.githubusercontent.com/YOU/DevScripts/your-branch ct/debian.sh \
             https://raw.githubusercontent.com/rcourtman/core/fix/git-alpine-clean-install

Note that run.sh is reached through a pipe, so the script it starts inherits
an exhausted stdin. Whiptail is fine — it opens /dev/tty — but a plain read
would see EOF. The single-variable form above does not have that problem.

Useful flags while testing

dev_mode=net logs every engine fetch with status and duration, which is the
quickest way to confirm the branch is really being used. dev_mode=keep stops a
failed build from deleting the container along with the evidence.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant