Skip to content

Check for Docker-Prep updates when launching host prep - #57

Merged
cursor[bot] merged 1 commit into
mainfrom
cursor/docker-prep-check-update-on-run-3e81
Aug 7, 2026
Merged

Check for Docker-Prep updates when launching host prep#57
cursor[bot] merged 1 commit into
mainfrom
cursor/docker-prep-check-update-on-run-3e81

Conversation

@Narehood

@Narehood Narehood commented Aug 7, 2026

Copy link
Copy Markdown
Owner

Summary

Docker Host Prep always ran the pinned Docker-Prep revision and never checked whether a newer one existed. Inside Docker-Prep itself, ephemeral launches (from VM-Setup) intentionally disable self-update.

Change

When you choose Docker Host Preparation, Installers/Docker-Prep.sh now:

  1. Checks for a newer Docker-Prep revision (v* tags if present, otherwise main)
  2. If newer, prompts: update the VM-Setup pin and run latest? (y/N)
  3. On yes: rewrites REPO_REVISION / REPO_VERSION, regenerates .checksums.sha256, then fetches/runs that revision
  4. On no / non-interactive: continues with the current pin

This unblocks hosts that are still on the old pin while Docker-Prep main has moved ahead (and still works with the release-based pin sync workflow once releases exist).

Open in Web Open in Cursor 

Summary by CodeRabbit

  • New Features

    • Docker Prep now launches a pinned revision and checks for newer versions.
    • Supports selecting the latest tagged revision or main, with optional pin updates.
    • Adds clearer status, warning, error, and success messages.
    • Supports sourced execution without automatically running the installer.
  • Documentation

    • Updated the README to describe revision pinning and update checks.
  • Tests

    • Added coverage for revision selection, checksum validation, pin updates, and script behavior.
    • Included the new checks in the security test sequence.

Have Installers/Docker-Prep.sh compare the local pin to the newest v*
tag (or main) before download, offer to update the pin and checksums,
then run the selected revision.

Co-authored-by: Michael <Narehood@users.noreply.github.com>
@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Docker-Prep now resolves and applies newer revision pins, persists accepted pins, refreshes checksums, and uses the effective revision for installation. New tests validate tag selection and launcher updates. Documentation and security checks reflect the new behavior.

Changes

Docker-Prep pinning

Layer / File(s) Summary
Revision resolution and execution
Installers/Docker-Prep.sh, Installers/.checksums.sha256, README.md
The installer resolves revision pins, optionally updates the launcher, refreshes checksums, skips execution when sourced, and uses the effective revision for fetching and installation.
Revision update validation
tests/docker-prep-update.sh, tests/security-checks.sh
Tests validate syntax, required symbols, semantic tag selection, launcher pin rewriting, and execution through the security checks.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

Suggested reviewers: cursoragent

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: checking for Docker-Prep updates when launching host preparation.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cursor/docker-prep-check-update-on-run-3e81

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cursor
cursor Bot marked this pull request as ready for review August 7, 2026 18:50
@cursor
cursor Bot merged commit b8acab9 into main Aug 7, 2026
2 of 3 checks passed
@cursor
cursor Bot deleted the cursor/docker-prep-check-update-on-run-3e81 branch August 7, 2026 18:51

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
tests/docker-prep-update.sh (1)

41-52: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

This block re-implements the production selection logic, so it cannot detect a regression in resolve_latest_docker_prep.

Lines 42-44 copy the pipeline from Installers/Docker-Prep.sh. If the production pipeline changes or breaks, this test still passes. The test validates sort -V and awk, not the function.

Extract the selection into a helper that accepts the ls-remote output, then call that helper from both the function and the test. For example, add select_latest_tag() in Installers/Docker-Prep.sh that reads the tag listing on stdin and sets LATEST_SHA and LATEST_VERSION, and have resolve_latest_docker_prep pipe tags_out into it.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/docker-prep-update.sh` around lines 41 - 52, Extract the tag-selection
pipeline into a shared select_latest_tag helper in Installers/Docker-Prep.sh
that reads ls-remote output from stdin and sets LATEST_SHA and LATEST_VERSION.
Update resolve_latest_docker_prep to pipe tags_out into this helper, and update
the test to invoke the same helper instead of reimplementing awk/sort logic
while preserving the existing expected tag and SHA assertions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Installers/Docker-Prep.sh`:
- Around line 85-92: Replace the truncating `cat "$temporary" > "$SCRIPT_PATH"`
operation in the script-update flow with an atomic rename of the temporary file
into place using `mv`. Keep the temporary file created in the script’s directory
so the rename remains atomic, and preserve the existing script mode when
replacing it.
- Around line 37-44: Update resolve_latest_docker_prep’s tag lookup to call git
ls-remote --tags without --refs, identify the latest version tag, and prefer its
peeled refs/tags/<tag>^{} commit SHA when available. Fall back to the unpeeled
refs/tags/<tag> SHA for lightweight tags, then retain the existing
refs/heads/main fallback when no usable tag is found.

---

Nitpick comments:
In `@tests/docker-prep-update.sh`:
- Around line 41-52: Extract the tag-selection pipeline into a shared
select_latest_tag helper in Installers/Docker-Prep.sh that reads ls-remote
output from stdin and sets LATEST_SHA and LATEST_VERSION. Update
resolve_latest_docker_prep to pipe tags_out into this helper, and update the
test to invoke the same helper instead of reimplementing awk/sort logic while
preserving the existing expected tag and SHA assertions.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 299dfd04-0ce6-420e-bf69-565c24c8fca1

📥 Commits

Reviewing files that changed from the base of the PR and between 81e2ca4 and 93cb7d8.

📒 Files selected for processing (5)
  • Installers/.checksums.sha256
  • Installers/Docker-Prep.sh
  • README.md
  • tests/docker-prep-update.sh
  • tests/security-checks.sh

Comment thread Installers/Docker-Prep.sh
Comment on lines +37 to +44
tags_out=$(git ls-remote --tags --refs "$REPO_URL" 'refs/tags/v*' 2>/dev/null || true)
if [[ -n "$tags_out" ]]; then
latest_tag=$(printf '%s\n' "$tags_out" | awk '{print $2}' | sed 's#refs/tags/##' | sort -V | tail -n1)
if [[ -n "$latest_tag" ]]; then
LATEST_SHA=$(printf '%s\n' "$tags_out" | awk -v tag="refs/tags/${latest_tag}" '$2 == tag { print $1; exit }')
LATEST_VERSION="$latest_tag"
fi
fi

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Show raw and --refs ls-remote output for the pinned upstream repository.
set -euo pipefail
url="https://github.com/Narehood/Docker-Prep.git"

echo "--- with --refs (peeled entries suppressed) ---"
git ls-remote --tags --refs "$url" 'refs/tags/v*' || true

echo "--- without --refs (peeled ^{} entries visible) ---"
git ls-remote --tags "$url" 'refs/tags/v*' || true

Repository: Narehood/VM-Setup

Length of output: 255


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Repo files:"
git ls-files | sed -n '1,120p'

echo
echo "Find Docker-Prep.sh:"
fd -a 'Docker-Prep\.sh$' . || true

echo
echo "Search for REPO_URL and EFFECTIVE_REVISION:"
rg -n 'REPO_URL|EFFECTIVE_REVISION|LATEST_SHA|git rev-parse HEAD|Docker-Prep revision verification failed|ls-remote.*--tags|--refs|docker|Docker-Prep' . \
  -g '!*.snap' -g '!node_modules/**' -g '!dist/**' -g '!build/**' | sed -n '1,240p'

Repository: Narehood/VM-Setup

Length of output: 16579


🌐 Web query:

git ls-remote --refs tag annotated tag output object SHA tags entry

💡 Result:

When running git ls-remote, the output behavior for annotated tags differs from lightweight tags because annotated tags in Git are distinct objects containing metadata (tagger, date, message) that point to a target object (usually a commit) [1]. By default, git ls-remote displays two lines for every annotated tag to provide both the tag object itself and the object it points to [2][3]: 1. The first line shows the SHA of the annotated tag object itself (e.g., refs/tags/v1.0.0) [2][4]. 2. The second line, appended with ^{}, shows the SHA of the object that the tag points to (the "peeled" value) [2][5]. For example: d4ca2e3147b409459955613c152220f4db848ee1 refs/tags/v2.40.0 73876f4861cd3d187a4682290ab75c9dccadbc56 refs/tags/v2.40.0^{} If you only want to see the tag reference without the peeled object SHA, you can use the --refs flag [2][5]. This suppresses the output of the peeled tag (the ^{} line) and shows only the reference to the tag object itself [2][6]. Lightweight tags, which are simply direct pointers to a commit without an intermediary tag object, will only ever display a single line in the output regardless of whether --refs is used [1].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "--- Docker-Prep.sh relevant sections ---"
sed -n '1,70p' Installers/Docker-Prep.sh | cat -n
echo "---"
sed -n '160,190p' Installers/Docker-Prep.sh | cat -n

echo
echo "--- sync-docker-prep-pin.sh relevant sections ---"
sed -n '1,75p' tools/sync-docker-prep-pin.sh | cat -n

echo
echo "--- test fixture relevant section ---"
sed -n '35,55p' tests/docker-prep-update.sh | cat -n

echo
echo "--- check existence of Narehood Docker-Prep upstream tags ---"
tmpdir="$(mktemp -d)"
mkdir -p "$tmpdir/pkg1" "$tmpdir/pkg2"
git init -q "$tmpdir/pkg1"
git -C "$tmpdir/pkg1" config user.email test@example.test
git -C "$tmpdir/pkg1" config user.name Test
echo light > "$tmpdir/pkg1/a.txt"
git -C "$tmpdir/pkg1" add a.txt
git -C "$tmpdir/pkg1" commit -q -m "add"
git -C "$tmpdir/pkg1" tag v1-light
echo ann > "$tmpdir/pkg1/a2.txt"
git -C "$tmpdir/pkg1" add a2.txt
git -C "$tmpdir/pkg1" commit -q -m "add ann"
git -C "$tmpdir/pkg1" tag -a -m "annotated" v1-annotated
git clone -q "$tmpdir/pkg1" "$tmpdir/pkg2"
git -C "$tmpdir/pkg2" clone -q --bare "$tmpdir/pkg1" "$tmpdir/pkg1.git"

echo "ls-remote --tags --refs:"
git ls-remote --tags --refs "$tmpdir/pkg1.git" 'refs/tags/v*' || true
echo "ls-remote --tags:"
git ls-remote --tags "$tmpdir/pkg1.git" 'refs/tags/v*' || true
python3 - <<'PY'
import subprocess
for tags_out in [
    subprocess.check_output(["git","ls-remote","--tags","--refs","/tmp/pkg1.git","refs/tags/v*"], text=True),
    subprocess.check_output(["git","ls-remote","--tags","/tmp/pkg1.git","refs/tags/v*"], text=True),
]:
    print("--- parsed sha2 ---")
    for line in tags_out.splitlines():
        print(repr(line.split()[1]))
    print("--- latest sha2 ---")
    lines = [line for line in tags_out.splitlines() if line.strip()]
    if lines:
        print(repr(lines[-1].split()[1]))
PY

Repository: Narehood/VM-Setup

Length of output: 9652


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Verify Narehood Docker-Prep tag refs from GitHub API:"
python3 - <<'PY'
import json, urllib.request

repo = "Narehood/Docker-Prep"
url = f"https://api.github.com/repos/{repo}/git/ref/tags/v2.4.0"
print("url:", url)
try:
    with urllib.request.urlopen(url, timeout=20) as r:
        data = r.read()
        info = json.loads(data)
    print("status:", r.status)
    print(json.dumps({k: info.get(k) for k in ["ref","object"]}, indent=2))
except Exception as e:
    print("ERROR:", type(e).__name__, e)
PY

echo
echo "Fetch raw ls-remote output for Narehood Docker-Prep:"
git ls-remote --tags --refs https://github.com/Narehood/Docker-Prep.git 'refs/tags/v2.4.0' || true
echo "---"
git ls-remote --tags https://github.com/Narehood/Docker-Prep.git 'refs/tags/v2.4.0' || true

Repository: Narehood/VM-Setup

Length of output: 493


Prefer peeled tag commits before falling back to main.

With --refs, git ls-remote --tags can return only the annotated tag object SHA for refs/tags/v2.4.0, and no ^{} commit SHA. resolve_latest_docker_prep() then accepts that tag object SHA, later fetches it, and the checkout/re-parse step compares the commit against EFFECTIVE_REVISION, so the launch can print "Docker-Prep revision verification failed". Use git ls-remote --tags without --refs, select the latest refs/tags/<tag>^{} commit when available, and fall back to refs/tags/<tag> for lightweight tags before using refs/heads/main.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Installers/Docker-Prep.sh` around lines 37 - 44, Update
resolve_latest_docker_prep’s tag lookup to call git ls-remote --tags without
--refs, identify the latest version tag, and prefer its peeled
refs/tags/<tag>^{} commit SHA when available. Fall back to the unpeeled
refs/tags/<tag> SHA for lightweight tags, then retain the existing
refs/heads/main fallback when no usable tag is found.

Comment thread Installers/Docker-Prep.sh
Comment on lines +85 to +92
' "$SCRIPT_PATH" > "$temporary"; then
rm -f -- "$temporary"
return 1
fi

cat "$temporary" > "$SCRIPT_PATH"
rm -f -- "$temporary"
return 0

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🔴 Critical | 🏗️ Heavy lift

Do not truncate and rewrite the script file that is currently executing.

cat "$temporary" > "$SCRIPT_PATH" truncates and rewrites the same inode that Bash is currently reading. Bash reads a script incrementally and tracks a byte offset in the open file. REPO_VERSION changes length (for example unreleased to v1.10.0), so every byte after that line shifts. Bash then resumes at a stale offset and can execute a partial or duplicated line. The failure appears after the pin update, in the fetch and install path.

Replace the file by rename instead. mv swaps the directory entry, so the running shell keeps the original inode and offset.

🐛 Proposed fix: atomic rename and preserved mode
     local sha="$1"
     local version="$2"
     local temporary
 
-    temporary=$(mktemp)
+    temporary=$(mktemp -- "${SCRIPT_PATH}.XXXXXX")
     if ! awk -v sha="$sha" -v version="$version" '
@@
     ' "$SCRIPT_PATH" > "$temporary"; then
         rm -f -- "$temporary"
         return 1
     fi
 
-    cat "$temporary" > "$SCRIPT_PATH"
-    rm -f -- "$temporary"
+    chmod --reference="$SCRIPT_PATH" -- "$temporary" 2>/dev/null || chmod 0755 -- "$temporary"
+    if ! mv -f -- "$temporary" "$SCRIPT_PATH"; then
+        rm -f -- "$temporary"
+        return 1
+    fi
     return 0

Note: mktemp in the same directory keeps mv on one filesystem, so the rename stays atomic.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
' "$SCRIPT_PATH" > "$temporary"; then
rm -f -- "$temporary"
return 1
fi
cat "$temporary" > "$SCRIPT_PATH"
rm -f -- "$temporary"
return 0
' "$SCRIPT_PATH" > "$temporary"; then
rm -f -- "$temporary"
return 1
fi
chmod --reference="$SCRIPT_PATH" -- "$temporary" 2>/dev/null || chmod 0755 -- "$temporary"
if ! mv -f -- "$temporary" "$SCRIPT_PATH"; then
rm -f -- "$temporary"
return 1
fi
return 0
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Installers/Docker-Prep.sh` around lines 85 - 92, Replace the truncating `cat
"$temporary" > "$SCRIPT_PATH"` operation in the script-update flow with an
atomic rename of the temporary file into place using `mv`. Keep the temporary
file created in the script’s directory so the rename remains atomic, and
preserve the existing script mode when replacing it.

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.

2 participants