diff --git a/claude-code/CHANGELOG.md b/claude-code/CHANGELOG.md index 8459069..801459f 100644 --- a/claude-code/CHANGELOG.md +++ b/claude-code/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## [1.63.0] — 2026-11-10 + +### Fixed +- A program that runs the `test` command by name gets the system one again. The bundled hass-mcp + package installed a development launcher under that name ahead of it on the path; the launcher + is no longer installed, and every image is now checked for a bundled command that hides a system + command. + ## [1.62.6] — 2026-11-10 ### Fixed diff --git a/claude-code/Dockerfile b/claude-code/Dockerfile index 9ee5e9a..77472bd 100644 --- a/claude-code/Dockerfile +++ b/claude-code/Dockerfile @@ -211,6 +211,11 @@ RUN arch="$(dpkg --print-architecture)" \ # the HA Token is set): entity/service queries against the Core API. # Pillow: Python imaging for ad-hoc crops/resizes of dashboard screenshots # (ImageMagick's `magick` covers the CLI side). +# hass-mcp's wheel also declares a `test = pytest:main` console script (a +# development entry point, pytest is not a dependency). Installed into +# /usr/local/bin, it would replace the system `test` for anything that runs +# it by name, so it is removed here; the build fails if a file of that name +# is ever something else. # upstream: pypi homeassistant-cli ARG HASS_CLI_VERSION=1.0.0 # upstream: pypi hass-mcp @@ -220,7 +225,10 @@ ARG PILLOW_VERSION=13.0.0 RUN pip install --no-cache-dir --break-system-packages \ "homeassistant-cli==${HASS_CLI_VERSION}" \ "hass-mcp==${HASS_MCP_VERSION}" \ - "Pillow==${PILLOW_VERSION}" + "Pillow==${PILLOW_VERSION}" \ + && if [ -e /usr/local/bin/test ]; then \ + grep -qx 'from pytest import main' /usr/local/bin/test && rm /usr/local/bin/test; \ + fi # Force HTTPS for GitHub clones (plugin marketplaces) — the container has no SSH key. RUN git config --system url."https://github.com/".insteadOf "git@github.com:" diff --git a/claude-code/app/test/image/behaviour-pins.sh b/claude-code/app/test/image/behaviour-pins.sh index c10f5a3..79ebc34 100644 --- a/claude-code/app/test/image/behaviour-pins.sh +++ b/claude-code/app/test/image/behaviour-pins.sh @@ -30,6 +30,20 @@ IMG=5.0.0 rm -rf "${P}" mkdir -p "${P}" +# --- the image as built: nothing bundled shadows a system command --------------- +# /usr/local/bin comes first on PATH, so a bundled tool's stray entry point +# with the name of a system command (a Python package's `test` launcher, say) +# would replace that command for every program that runs it by name. +shadowed="" +for f in /usr/local/bin/* /usr/local/sbin/*; do + [ -e "${f}" ] || continue + for d in /usr/sbin /usr/bin /sbin /bin; do + if [ -e "${d}/${f##*/}" ]; then shadowed="${shadowed} ${f} (${d}/${f##*/})"; break; fi + done +done +eq "nothing in /usr/local shadows a system command" "${shadowed}" "" +eq "test run by name on PATH is the system's" "$(PATH="${BASE_PATH}" env test 1 -eq 1 2>&1; echo "exit $?")" "exit 0" + # --- 0. the real CLI under a prompt API command line ------------------------------ # A prompt API run reads no settings files (--setting-sources ''), so the secrets # guard's hook reaches it only through the managed settings. With only the