Skip to content

Latest commit

 

History

History
326 lines (249 loc) · 11.4 KB

File metadata and controls

326 lines (249 loc) · 11.4 KB

shimkit 0.2.0

User-facing summary of what 0.2.0 brings, what changes, and what to check before upgrading.

For the full machine-readable changelog, see CHANGELOG.md. For the contribution mechanics that landed alongside this release, see onboarding.md.


TL;DR

Three new tools, end-to-end:

shimkit dns           macOS DNS resolver recovery
shimkit adguard       AdGuard Home port-conflict fixer (Linux)
shimkit docker-clean  Docker resource cleanup (Linux + macOS + WSL)

All three are Python ports of shell scripts. The shell predecessors are removed from the source tree; the Python versions fix several bugs the bash versions had silently.

Plus a uniform CLI surface (--dry-run, --json, --quiet, --verbose, --log-file, --timeout, --yes, --no-input) across every new subcommand, and severe-tier confirmation tokens for destructive operations.


What's new

shimkit dns (macOS)

The "ping works, browser doesn't" recovery tool. Targets the failure mode where Network.framework's resolver state is corrupted but mDNSResponder's cache and the underlying network are fine.

shimkit dns diagnose              read-only: resolver chain, active
                                  service, interference (Tailscale,
                                  Docker Desktop, VPN tunnels)
shimkit dns flush                 the 80% case (dscacheutil + HUP)
shimkit dns fix                   6-step escalation; stops at the
                                  first step that resolves
shimkit dns show / set / reset    inspect / mutate networksetup
shimkit dns test [domain...]      resolve via three paths
shimkit dns profile list          installed Encrypted-DNS profiles
shimkit dns rollback              restore the latest plist backup
shimkit dns diagnostics export    bundle for a support ticket

shimkit adguard (Linux)

AdGuard Home port-conflict fixer. Handles systemd-resolved, NetworkManager, known-safe DNS daemons (dnsmasq, bind, named, unbound), and pi-hole.

shimkit adguard scan              read-only port owners + conflicts
shimkit adguard fix [--dry-run]   apply the remediation
shimkit adguard verify            loopback DNS + /control/status
shimkit adguard ports show/set    inspect/set via API or yaml
shimkit adguard config validate   AdGuardHome --check-config
shimkit adguard service ...       start/stop/restart/status
shimkit adguard logs              journalctl -u AdGuardHome
shimkit adguard rollback          restore yaml + resolv.conf backups

Prefers the HTTP control API when reachable; falls back to a ruamel.yaml round-trip edit with the daemon stopped (so AGH doesn't overwrite the edit on its shutdown).

shimkit docker-clean (Linux + macOS + WSL)

Docker resource cleanup. Uses the docker-py SDK for daemon ops and Docker Desktop CLI for lifecycle on macOS.

shimkit docker-clean status                disk usage breakdown
shimkit docker-clean quick                 stop + prune common
shimkit docker-clean nuke --confirm DELETE remove EVERYTHING
shimkit docker-clean restart               daemon restart
shimkit docker-clean stop-all              stop running containers
shimkit docker-clean prune-{images,volumes,networks,builders}
shimkit docker-clean orphans               dangling + unused only
shimkit docker-clean inspect <kind>        detailed listing
shimkit docker-clean compose-down PATH     per-project teardown
shimkit docker-clean schedule              emit (don't install) a
                                           launchd/systemd/cron unit

Optional dependency extras

The three new tools each ship behind an optional extra so the base install stays lean.

# Pick what you need:
uv tool install 'shimkit[dns]'
uv tool install 'shimkit[adguard]'
uv tool install 'shimkit[docker-clean]'

# Or all of them:
uv tool install 'shimkit[extra-tools]'

# Add an extra to an existing install:
uv tool install --upgrade 'shimkit[adguard]'
# or
pipx inject shimkit ruamel.yaml requests psutil

If you run a tool whose extra isn't installed, shimkit exits 69 with a message naming the install command for your platform.


Bug fixes carried over from the shell ports

These were silently broken in the bash versions:

  • fixdns.sh detect_service used grep -E '\d+'. BSD grep doesn't support \d; the function silently fell through to the fallback on every macOS. The Python port uses real regex.
  • fixdns.sh Wi-Fi power-cycle ran setairportpower "$INTERFACE" unconditionally — silent no-op when the active service was Ethernet. The port branches on networksetup -listallhardwareports.
  • fix-adguardhome-ports.sh ran a full DNS cleanup even when AGH was absent; you could end up with systemd-resolved disabled and no replacement DNS. The port exits 69 unless --dns-cleanup-only is explicitly passed.
  • fix-adguardhome-ports.sh awk-edited AdGuardHome.yaml while the daemon was still running. AGH overwrites the yaml on shutdown per its wiki — the edit could be lost. The port stops AGH first (or uses the HTTP control API entirely).
  • fix-adguardhome-ports.sh only warned that NetworkManager would clobber /etc/resolv.conf. The port writes the canonical dns=none drop-in and nmcli general reloads.
  • docker-nucker.sh build-cache + system-prune read $? immediately after local x=$(...). That reads local's exit code (always 0), not the command's. Both prune operations always reported success regardless of actual outcome.
  • docker-nucker.sh verify_docker used ((attempt++)) under set -e. The first iteration evaluates to 0, returns non-zero, and aborts the loop — so the daemon-health verifier ran at most once. The port uses a real loop with a config-driven timeout.
  • docker-nucker.sh builder pruning ran docker builder prune -af, which only touches the legacy local builder. The port iterates docker buildx ls --format json and prunes each named builder.

Other notable changes

Argv-list package-manager templates

config.package_managers.definitions rows now accept argv lists instead of strings — and defaults.json ships with argv lists for every PM:

// before (still supported for back-compat)
"apt": { "install_cmd": "apt-get install -y ${pkg}", ... }

// after (default in 0.2.0)
"apt": { "install_cmd": ["apt-get", "install", "-y", "${pkg}"], ... }

Argv-list mode runs commands with shell=False, so a malicious package name can't inject shell metacharacters. If you have a custom shimkit.json with string templates, they continue to work unchanged.

Severe-tier confirmation tokens

Destructive subcommands now require a literal token via --confirm <token>. The token comes from config; --yes does not bypass it.

shimkit dns reset             --confirm RESET
shimkit dns fix --nuclear     --confirm REGENERATE
shimkit docker-clean nuke     --confirm DELETE

You can customise the tokens — for example, requiring DESTROY-DEV-ENV instead of DELETE — by setting tools.docker_clean.nuke_confirm_token in shimkit.json. See docs/configuration.md.

Brew installer hardening

Brew.install_self (used by shimkit java when Homebrew is absent) no longer interpolates the config-supplied install URL into a /bin/bash -c "..." shell command. The installer is now downloaded to a tempfile (with HTTPS-scheme validation), chmod'd to 0o700, and executed via /bin/bash <tmpfile> with no shell.

shimkit doctor extensions

doctor now reports:

dns probe      9 resolver(s); top: 1.1.1.1,8.8.8.8,8.8.4.4
adguard        /opt/AdGuardHome/AdGuardHome   (or <absent>)
docker         28.5.2                          (or <not running>)

…on the platforms where each makes sense.

CI hardening

The release workflow now generates SPDX SBOMs (wheel + container image) and actions/attest-build-provenance attestations (pushed to the GHCR registry). The guard job validates that the tag, the pyproject.toml::version, AND the __init__.py::__version__ all match — and that the CHANGELOG has a section for the new tag.

A new adguard-integration CI job runs a real AdGuard Home daemon (version-pinned, on non-default ports) and exercises scan/verify/ports show/fix --dry-run/ports set --dry-run with JSON-asserted output. Closes the "are we sure shimkit works on real Linux" question for the read-only adguard paths.

Dockerfile hardening

  • Base image pinned by manifest digest (python:3.12-slim@sha256:401f6e1a…). Dependabot's docker ecosystem opens PRs when the digest changes.
  • New HEALTHCHECK ["shimkit", "version"] — orchestrators get an authoritative ready signal.

Upgrade notes

From 0.1.0

  • No breaking changes to the existing java / shell / config / doctor / self-update surfaces.
  • Existing shimkit.json user configs continue to work — the new tool sections (tools.dns, tools.adguard, tools.docker_clean) have sensible defaults so partial configs aren't required.
  • If you have custom string-template PM definitions in shimkit.json, they're still supported. To benefit from the shell-injection-free argv form, convert them per the example above.

Recommended pre-upgrade smoke

shimkit --version                # 0.1.0 before upgrade
shimkit doctor                   # baseline output

# Upgrade
shimkit self-update              # auto-detects uv/pipx/brew/pip

shimkit --version                # 0.2.0
shimkit doctor                   # the three new probes now appear
shimkit --help                   # the three new sub-apps now appear

Validation envelope

This release validates on:

  • macOS (Apple Silicon + Intel), Python 3.10–3.13 — CI matrix plus a manual smoke on Apple Silicon.
  • Ubuntu 22.04 / 24.04 LTS — CI matrix plus the adguard-integration job and a manual Phase 7 sign-off on a real Ubuntu host before cutting the tag (see docs/validation-scope.md).

Other systemd-based Linuxes (Debian 12+, Fedora 40+, Arch, …) are expected to work but aren't formally validated in CI. File an issue with lsb_release -a + shimkit doctor output if anything misbehaves.

Not supported: WSL2 (systemd-resolved and NetworkManager don't behave like bare Linux there; the affected tools exit 69 with a clear message). Windows native is also unsupported.


Acknowledgements

This release ports three previously-internal shell scripts (fixdns.sh, fix-adguardhome-ports.sh, docker-nucker.sh) into shimkit's typed-Python kit. The bugs they had — and the docs they didn't have — were the motivation. Each tool's docs/tools/<name>.md page lists the specific defects the port closes.


Verifying the release

The release workflow publishes:

  • shimkit-0.2.0-py3-none-any.whl + shimkit-0.2.0.tar.gz on PyPI (via OIDC trusted-publisher; no token in the workflow).
  • shimkit-sbom.spdx.json as a GitHub Release asset (SPDX SBOM for the wheel).
  • ghcr.io/simtabi/shimkit:0.2.0 (multi-arch: linux/amd64 + linux/arm64), with actions/attest-build-provenance-signed manifests pushed to the registry.
  • The Homebrew formula bump PR in simtabi/homebrew-tap.

To verify the wheel locally:

pip download --no-deps shimkit==0.2.0 -d /tmp
cd /tmp
sha256sum shimkit-0.2.0-py3-none-any.whl

# Compare against the SBOM-listed checksums (or against your prior
# pinned hash if you maintain one).