Repository navigation
CI merge gate: pinned lint/secret/workflow checks and an 81-test regression suite - #2
Merged
Merged
Conversation
tests/run.sh runs each test_* function in a scrubbed env -i process with a scratch HOME/TMPDIR and stub binaries first on PATH. tests/lib provides assertions, stub/call-log helpers and a repo-copy helper; test_harness.sh tests the framework itself. Works on macOS bash 3.2 and bash 5. Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Replaces lint.yml with ci.yml: lint (shellcheck+shfmt), actionlint, gitleaks secret scan over full history, and the test suite on ubuntu (bash 5) and macOS (bash 3.2). The gate job fails unless every job succeeded, so the ruleset only ever needs that one check. actions/checkout is pinned to a commit SHA; every other tool is a checksum-verified release installed by .github/scripts/install-tool.sh. Dependabot keeps the SHA pin current. Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
BSD sed aborts on a symlinked file and GNU sed replaces the link with a regular file, so setup_zsh broke (or silently detached) a ~/.zshrc that points into a dotfiles repo. sed_inplace now resolves the link chain (bounded, so a cycle is an error) and edits the real file. Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Pins nested run_step (crashed before), one summary row per step, soft step never dying, temp-file cleanup, strict confirm ignoring --yes, as_root, safe_link/backup failure leaving the destination intact, append_once idempotence, menu return codes, and sed_inplace editing through symlinks. Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Tasks run under bash (word splitting), failing tasks exit non-zero without a success banner, -y/--yes export, menu survives failures; update.sh brew order, one row per ecosystem, failure isolation, skip path, Linux path. Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
--yes never uninstalls Homebrew, ~/.zprofile/.zshrc are never deleted, symlinked ~/.zshrc survives, brew gets separate args, starship only when missing; ubuntu.sh runs nothing unless confirmed; docker/swap sequencing. Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Spinner animates and cleans up under a real pty, never outlives its shell (survivor check) and nested failures surface the error; alacritty.toml parses and keeps the 'decorations = "Transparent"' literal that shell.sh seds; tmux.conf loads with prefix C-s/mouse/vi keys; every vim plugin fragment the .vimrc sources exists. Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
The first Ubuntu CI run executed a real 'composer self-update' because the runner image ships composer and one test did not stub it, and the 'missing tool' test had to skip itself for the same reason. Tests now get PATH = stubs + a symlink farm of /bin and /usr/bin minus package managers, network/VCS tools and privileged commands, so an unstubbed tool is 'command not found' and absence is deterministic on any image. The OMZ test now stubs git explicitly instead of relying on the host's. Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a CI pipeline whose single required check,
CI gate, passes only when every safety check passes. Stacked on #1 (the tests exercise its scripts); GitHub retargets this PR tomainwhen #1 merges.Pipeline (
.github/workflows/ci.yml, replaceslint.yml)lint: shellcheck 0.11.0 + shfmt 3.14.1 over setup, scripts, CI scripts and tests.actionlint: lints the workflows (and theirrun:blocks with the pinned shellcheck).secrets: gitleaks over the full history,--redactso nothing leaks into the public log.tests: the new suite on Ubuntu (bash 5) and macOS (real/bin/bash3.2.57).gate:if: always(), fails unless all of the above succeeded, so a skipped or cancelled job can't slip through.pull_requestonly (neverpull_request_target), read-only token, no secrets, no path filters.actions/checkoutpinned to a commit SHA; every other tool is a release binary verified against GitHub's published SHA-256 digest by.github/scripts/install-tool.sh. Dependabot keeps the SHA pin current.Tests (
tests/, 81 tests, no dependencies, about 30 s)Each test runs in a scrubbed
env -iprocess with a scratchHOME, stub binaries first onPATH, and pinned ASCII output, so nothing ambient can change a result and no real package manager runs. They pin the behaviors that were real bugs or destructive-action guards in #1: tasks run under bash, nestedrun_step, spinner never outliving its shell,--yescan't answer the Homebrew-uninstall prompt,ubuntu.shruns nothing unless confirmed,.zshrc/.zprofileare never deleted, one summary row per updater, failing tasks exit non-zero, tmux/alacritty configs parse.Found while writing the tests:
sed_inplaceaborted (BSD sed) or silently replaced the link (GNU sed) when~/.zshrcis a symlink into a dotfiles repo, sosetup_zshbroke for that common setup. Fixed incommon.shwith a regression test.How I checked the tests are real
For each guard I reverted it in a scratch copy and confirmed a test fails (zsh interpreter, strict
confirm, ubuntu consent gate,.zprofiledeletion, spinner parent check, summary double-recording, temp-file leaks, tmux/alacritty edits, and more). Only one mutant survived: removing alocalthat affects nothing but a step's elapsed time, which the suite deliberately doesn't assert.After merging
mainis unprotected today. Once #1 and this PR are merged andCI gatehas run onmain, a ruleset requiring a PR and theCI gatecheck (admin bypass allowed, 0 approvals, no force-push or deletion) will be created. It can't be created earlier without blocking #1 on a check that doesn't exist there yet.Known gaps
.ps1scripts andvim/.vimrc(downloads plugins when run) are not executed by CI.exit(notdie) leaves one empty capture file in$TMPDIR; harmless litter, documented by a test.composer, which an unstubbed test then ran for real). Tests now get a PATH of stubs plus a filtered farm of system tools with package managers, git/curl and sudo removed, so an unstubbed tool is "command not found" on any image. Both legs are green.🤖 Generated with Claude Code