mirror of
https://github.com/kuhyx/testsAndMisc.git
synced 2026-11-10 20:27:02 +01:00
setup_night_lockdown: define _NL_PAYLOAD_DIR where it is used
The split referenced $_NL_PAYLOAD_DIR from both install functions but
defined it nowhere, so `setup_night_lockdown.sh setup` would have died
with an unbound variable partway through installing the lockdown. My
earlier scratch verification set the variable by hand, which is exactly
what hid the bug: the emitted artifacts hashed correctly while the real
entry path could not have reached them.
It is now defined in each lib that uses it, eight lines above the use,
via `: "${_NL_PAYLOAD_DIR:=...}"` so an explicit override still wins. A
definition placed in the entry script was silently stripped by an
autoformat pass three times during this work, and a half-run lockdown
installer is not an acceptable failure mode.
Also drops two zero-byte payload files left behind by the .sh -> .sh.in
rename.
Re-verified without presetting anything: install_enter_script and
install_unlock_script emit mode-0755 files hashing 4baaf405... and
eafce28d..., byte-identical to the live /usr/local/bin copies. help and
an unknown command match their baselines; status differs only by the
05:00 countdown ticking 13h to 12h between runs.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
f6bfdff76a
commit
79a49846b9
@ -1,20 +1,18 @@
|
||||
{
|
||||
"title": "Split setup_night_lockdown.sh under the 250-line cap",
|
||||
"objective": "Bring linux_configuration/scripts/periodic_background/digital_wellbeing/setup_night_lockdown.sh (918 lines) under the repo-wide 250-line cap by moving config, systemd-unit generation and the subcommands into five sourced libs, and externalizing the two large generated scripts as data-file payloads -- while emitting byte-identical artifacts to the ones already deployed in /usr/local/bin on this machine.",
|
||||
"objective": "Bring setup_night_lockdown.sh (918 lines) under the cap by moving its top-level functions into five libs and its two quoted heredocs into verbatim payload files, while guaranteeing the two scripts it deploys to /usr/local/bin are unchanged — night-lockdown-unlock.timer is enabled and fires at 05:00.",
|
||||
"acceptance_criteria": [
|
||||
"The entry script and all five lib/nl_*.sh files are each at most 250 lines.",
|
||||
"`help`, `status` and an unknown-command run are byte-identical to the pre-split baselines, with exit codes 0, 0 and 1.",
|
||||
"The artifacts emitted by install_enter_script and install_unlock_script are mode 0755 and sha256-identical to the live /usr/local/bin/night-lockdown-{enter,unlock}.sh.",
|
||||
"A line-multiset check accounts for every functional line of the 918-line original, with the only differences being the six lines the heredoc-to-data-file conversion replaces.",
|
||||
"The payload files are not reformatted by the pre-commit shfmt pass, since any byte change there breaks the hash equality above.",
|
||||
"shellcheck passes without -x on the entry script and libs, and shfmt -w is a no-op on all of them, with no suppression added.",
|
||||
"The live deployed artifacts are unchanged by the work: sha256sum -c passes at the end."
|
||||
"The entry script and every lib is at most 250 lines, verified with the payloads git-tracked so the gate actually sees them.",
|
||||
"The emitted night-lockdown-enter.sh and night-lockdown-unlock.sh hash identically to the files currently deployed in /usr/local/bin, with mode 0755.",
|
||||
"verify_shell_split.sh reports additions only — no moved function's body changed.",
|
||||
"`--help` is byte-identical to the pre-split baseline and `status` differs only in live clock state.",
|
||||
"Both payloads parse as standalone scripts; shellcheck passes without -x and shfmt is a no-op, with no suppression added.",
|
||||
"install_enter_script and install_unlock_script run without an unbound variable."
|
||||
],
|
||||
"out_of_scope": [
|
||||
"Running `setup` or `unlock`: they write /etc/systemd/system, enable timers and reconfigure the machine's night lockdown.",
|
||||
"Re-deploying to /usr/local/bin -- unnecessary, since the split emits the bytes already there.",
|
||||
"Shell test coverage for the new libs; no suite exists for this script.",
|
||||
"Any change to the lockdown schedule, the monitored units, or the RGB/i2c behaviour."
|
||||
"Running `setup_night_lockdown.sh setup`: it masks the TTY login surface and tears down the GUI, with SSH as the only recovery path.",
|
||||
"Re-deploying to /usr/local/bin — unnecessary, since the split provably emits the same bytes already there.",
|
||||
"Splitting the 279-line enter payload: it is one generated artifact, and the user chose the .sh.in convention over splitting it."
|
||||
],
|
||||
"verifier": "bash meta/scripts/check_file_length.sh --all for the cap; diff of help/status/unknown against captured baselines; a scratch-directory run of install_enter_script and install_unlock_script with sha256 comparison against the live deployed copies; a python3 line-multiset diff including the payload files; shellcheck, shfmt idempotence and bash -n; sha256sum -c on the deployed artifacts as the final step; pre-commit run --files on the staged set."
|
||||
"verifier": "sha256 of emitted artifacts vs /usr/local/bin (the decisive check); check_file_length.sh --all with payloads tracked; verify_shell_split.sh; diff of --help/status against baselines; bash -n on payloads; shellcheck + shfmt idempotence."
|
||||
}
|
||||
|
||||
@ -1,58 +1,52 @@
|
||||
{
|
||||
"intent": "Bring setup_night_lockdown.sh (918 lines) under the 250-line cap by moving its config, unit-writing and command logic into five sourced libs and externalizing the two large generated scripts as data-file payloads, without changing a byte of what gets deployed to /usr/local/bin.",
|
||||
"intent": "Bring setup_night_lockdown.sh (918 lines) under the 250-line cap, without changing a byte of the two scripts it deploys to /usr/local/bin — one of which is executed by night-lockdown-unlock.timer, which is enabled and fires at 05:00.",
|
||||
"scope": [
|
||||
"linux_configuration/scripts/periodic_background/digital_wellbeing/setup_night_lockdown.sh: 918 -> 138 lines",
|
||||
"New libs: lib/nl_commands.sh (82), lib/nl_config.sh (125), lib/nl_enter.sh (12), lib/nl_units.sh (100), lib/nl_unlock.sh (12)",
|
||||
"New payloads: lib/payloads/night-lockdown-enter.sh.in (279), lib/payloads/night-lockdown-unlock.sh.in (212)",
|
||||
"Non-goal: running setup or unlock, which write /etc/systemd/system and /usr/local/bin and reconfigure this machine's night lockdown",
|
||||
"Non-goal: shell test coverage; no suite exists for this script"
|
||||
"setup_night_lockdown.sh: 918 -> 127 lines",
|
||||
"New libs: nl_enter.sh, nl_unlock.sh, nl_units.sh (100), nl_config.sh (125), nl_commands.sh (82)",
|
||||
"New payloads: lib/payloads/night-lockdown-enter.sh.in (279), night-lockdown-unlock.sh.in (212)",
|
||||
"Non-goal: running `setup`. It masks the TTY login surface and tears down the GUI; the only recovery is SSH."
|
||||
],
|
||||
"changes": [
|
||||
"Split into five libs by responsibility: nl_config (configuration file and derived values), nl_units (systemd unit and timer generation), nl_commands (the setup/status/unlock subcommands), nl_enter and nl_unlock (installing the two generated scripts).",
|
||||
"The two large generated scripts became DATA FILES under lib/payloads/ instead of inline heredocs. ENTER_EOF alone was 279 lines, so any lib containing it would have been over the 250-line cap no matter how the rest was arranged. Both heredocs were quoted (<<'ENTER_EOF', <<'UNLOCK_EOF'), so their bodies were already literal text with no build-time interpolation -- copying them verbatim into a file is exactly equivalent. Confirmed by hashing the emitted result against the live deployed copies.",
|
||||
"The payloads are named *.sh.in rather than *.sh, deliberately. The pre-commit hook globs staged files with '\\.(sh|bash|zsh)$', runs shfmt -w on them and re-stages the result; shfmt reformats these bodies (it expands a one-line logg() into four lines), which would change their bytes and destroy the hash equality with the deployed artifacts. The .in extension keeps them out of every .sh-globbing hook. No suppression or exclude regex was added.",
|
||||
"cat + chmod 0755 became a single `install -m 0755`, which is atomic where the original had a window between creating the file and making it executable."
|
||||
"Moved the real top-level functions into five libs with extract_shell_functions.py. The apparent functions at lines 218/233/244/251/266 and 506/522/551 of the original are NOT top-level: they live inside the two big quoted heredocs and belong to the generated scripts. Each heredoc was therefore treated as one atomic unit.",
|
||||
"The two heredoc bodies became verbatim payload FILES rather than inline text. Both heredocs were quoted (<<'ENTER_EOF' / <<'UNLOCK_EOF'), so their bodies were already literal with no expansion — moving them to files is exactly equivalent, and it is what brings the libs under the cap.",
|
||||
"The payloads carry a .sh.in extension. They are deployment artifacts byte-pinned to the installed copy, not hand-edited shell source, so they sit outside the cap's scope the same way third_party/ does — decided by the user after being shown the alternative of splitting the 279-line enter payload.",
|
||||
"DEFECT FOUND AND FIXED -- $_NL_PAYLOAD_DIR was referenced by both install functions and defined nowhere, so `setup_night_lockdown.sh setup` would have died with 'unbound variable' partway through installing the lockdown. Reproduced directly. It is now defined in the same file as its use, eight lines above it: a definition placed in the entry script was silently stripped by an autoformat pass three separate times during this work, and this installer is not something that can be allowed to half-run."
|
||||
],
|
||||
"verification": [
|
||||
{
|
||||
"command": "sha256sum of the emitted artifacts vs the LIVE deployed files",
|
||||
"result": "pass",
|
||||
"evidence": "THE decisive check. Running the split install_enter_script/install_unlock_script against redirected destinations emits 4baaf405ccee8824... and eafce28d826bb160..., which are byte-for-byte the current /usr/local/bin/night-lockdown-enter.sh and night-lockdown-unlock.sh. The payload files hash identically to the heredoc bodies extracted from the pre-split file, so the chain original-body == payload == emitted == deployed is closed. Modes are 0755 as before."
|
||||
},
|
||||
{
|
||||
"command": "bash meta/scripts/check_file_length.sh --all",
|
||||
"result": "pass",
|
||||
"evidence": "Over-cap list went from 3 files to 2; setup_night_lockdown.sh no longer listed. Entry script 138 lines, largest lib 125, payloads 279 and 212 (data files, not shell sources subject to the cap's intent -- and each is a single standalone script that cannot be split without changing the deployed artifact)."
|
||||
"evidence": "Over-cap list went from 3 files to 2. Confirmed with the payloads git-tracked (git add -N), since the gate only sees tracked files — an untracked payload would have given a false pass."
|
||||
},
|
||||
{
|
||||
"command": "diff of `help`, `status` and an unknown command against pre-split baselines",
|
||||
"command": "bash meta/scripts/verify_shell_split.sh HEAD <old> <old> <5 libs>",
|
||||
"result": "pass",
|
||||
"evidence": "All three byte-identical with unchanged exit codes 0/0/1. `status` is not a trivial path: it reads real system state, the deployed scripts and the systemd units, so it exercises genuine code rather than just usage text. Re-verified after shfmt."
|
||||
"evidence": "Eleven additions and no -/+ pair on any name: every moved function is byte-identical."
|
||||
},
|
||||
{
|
||||
"command": "sha256 of the EMITTED artifacts vs the live deployed /usr/local/bin copies",
|
||||
"command": "diff of `status` and `--help` against pre-split baselines",
|
||||
"result": "pass",
|
||||
"evidence": "THE LOAD-BEARING CHECK. install_enter_script and install_unlock_script were run against a scratch directory; the resulting files are mode 0755 and their sha256 sums are identical to /usr/local/bin/night-lockdown-enter.sh (4baaf405...) and night-lockdown-unlock.sh (eafce28d...). Re-run after the .sh.in rename and still identical. The split therefore provably emits the exact bytes already deployed on this machine."
|
||||
"evidence": "--help byte-identical. `status` differed by one character — the countdown to the 05:00 timer ticked from '13h' to '12h' between the two runs. Live clock state, not a code change; every other line matches."
|
||||
},
|
||||
{
|
||||
"command": "python3 line-multiset check of entry + 5 libs + 2 payloads against HEAD's 918-line file",
|
||||
"command": "bash -n on both payloads; shellcheck + shfmt on entry and libs",
|
||||
"result": "pass",
|
||||
"evidence": "Exactly 6 functional lines differ, all explained by the heredoc-to-data-file conversion: the two `cat >... <<'EOF'` lines, the two terminators, and the two `chmod 0755` lines that `install -m 0755` now performs. Nothing else was lost."
|
||||
},
|
||||
{
|
||||
"command": "sha256sum -c on the deployed artifacts, before and after the whole change",
|
||||
"result": "pass",
|
||||
"evidence": "Both /usr/local/bin scripts report OK. The split touched no system file; the live night lockdown is exactly as it was."
|
||||
},
|
||||
{
|
||||
"command": "shellcheck (no -x) + shfmt idempotence + bash -n on the entry script and five libs",
|
||||
"result": "pass",
|
||||
"evidence": "shellcheck rc=0 with no suppressions; shfmt -w is a no-op on all six after formatting the entry script by hand, so the pre-commit auto-format cannot alter them; all parse."
|
||||
"evidence": "Both payloads parse as standalone scripts. shellcheck rc=0 with no suppressions; shfmt -w is a no-op; the hyphenated-key canary is clean."
|
||||
}
|
||||
],
|
||||
"risks": [
|
||||
"The .sh.in payloads are not shellchecked, because the extension that protects them from shfmt also hides them from shellcheck. This is the right trade here: they are deployed verbatim and hash-verified against a known-good live copy, which is stronger evidence than a linter pass on a file nobody executes from the repo. They were shellcheck-clean as .sh before the rename.",
|
||||
"The deployed /usr/local/bin copies are NOT updated by this commit and do not need to be -- they already match what the split emits, byte for byte. Re-running `setup` would rewrite them with identical content.",
|
||||
"setup and unlock were never executed during verification: they write /etc/systemd/system, enable timers and reconfigure the machine's night lockdown. Their correctness rests on the multiset check, the hash equality of the emitted artifacts, and shellcheck."
|
||||
"The deployed copies are NOT touched by this commit and remain byte-identical to what the split now produces, so the 05:00 unlock timer is unaffected whether or not `setup` is ever re-run.",
|
||||
"`setup` itself is never executed under test — it masks getty/autovt and tears down the GUI, with SSH as the only recovery. Its correctness rests on the emitted-artifact hash equality above plus the unchanged-function proof, not on a live run.",
|
||||
"The .sh.in convention is new. A future payload that is genuinely hand-edited source would inherit an exemption it should not have; the extension is the signal that a file is a verbatim deployment artifact."
|
||||
],
|
||||
"rollback": [
|
||||
"git revert this commit; setup_night_lockdown.sh returns to a single 918-line file and lib/nl_*.sh plus lib/payloads/ disappear.",
|
||||
"No system rollback is required -- this commit never wrote to /usr/local/bin or /etc/systemd/system.",
|
||||
"Validate with: bash setup_night_lockdown.sh status (expect exit 0) and sha256sum /usr/local/bin/night-lockdown-{enter,unlock}.sh (expect 4baaf405... and eafce28d...)."
|
||||
"git revert the commit; setup_night_lockdown.sh returns to one 918-line file and lib/nl_*.sh plus lib/payloads/ disappear.",
|
||||
"Nothing to undo on the live system — no deployed file was written.",
|
||||
"After rollback, re-run the emitted-artifact hash check against /usr/local/bin to confirm the reverted heredocs still produce 4baaf405... and eafce28d..."
|
||||
]
|
||||
}
|
||||
|
||||
@ -1,6 +1,13 @@
|
||||
#!/usr/bin/env bash
|
||||
# Helpers sourced by the entry script.
|
||||
|
||||
|
||||
# Where the verbatim payload files live. Defined in the SAME file that uses it,
|
||||
# and with the use immediately below, because a definition placed further away
|
||||
# has been stripped by an autoformat pass three times during this work. The
|
||||
# failure mode is an unbound-variable abort midway through installing the
|
||||
# lockdown, so it must not depend on a distant line surviving.
|
||||
: "${_NL_PAYLOAD_DIR:=$(cd "$(dirname "${BASH_SOURCE[0]}")/payloads" && pwd)}"
|
||||
install_enter_script() {
|
||||
log_info "Installing lock action to $ENTER_SCRIPT"
|
||||
# The payload is a DATA FILE, not a heredoc: inlining it put this lib over
|
||||
|
||||
@ -1,6 +1,13 @@
|
||||
#!/usr/bin/env bash
|
||||
# Helpers sourced by the entry script.
|
||||
|
||||
|
||||
# Where the verbatim payload files live. Defined in the SAME file that uses it,
|
||||
# and with the use immediately below, because a definition placed further away
|
||||
# has been stripped by an autoformat pass three times during this work. The
|
||||
# failure mode is an unbound-variable abort midway through installing the
|
||||
# lockdown, so it must not depend on a distant line surviving.
|
||||
: "${_NL_PAYLOAD_DIR:=$(cd "$(dirname "${BASH_SOURCE[0]}")/payloads" && pwd)}"
|
||||
install_unlock_script() {
|
||||
log_info "Installing reversal to $UNLOCK_SCRIPT"
|
||||
# The payload is a DATA FILE, not a heredoc: inlining it put this lib over
|
||||
|
||||
Loading…
Reference in New Issue
Block a user