v0.9.7: F-6 — journal_write fail-fast on cp/mv failure (silent write-loss fix)
journal_write() at line 116 used bare `cp && mv` with no exit-code capture.
A full disk or read-only mount would cause the atomic write to fail while the
function returned 0, appended a false-success index entry, and left every
calling write tool (nc-set-field, nc-insert-protocol, nc-table) believing the
NetConfig had been modified when it had not. On the next session, rollback
would attempt to revert a write that never happened.
Fix (lib/journal.sh): capture cp and mv exit codes separately; on failure
emit a clear error to stderr, clean up the tmp file, and return exit 4.
The index append and session-manifest append are now skipped on failure.
Caller hardening (all four journal_write call sites):
- lib/nc-set-field.sh: || { ...error...; rm -f "$TMP"; exit 4; }
- lib/nc-table.sh: || { ...error...; return 4; }
- lib/nc-insert-protocol.sh (×2): || { ...error...; rm -f "$tmp"; return 4; }
lib/nc-engine.sh sources journal.sh but has no direct journal_write call
(engine commands don't mutate NetConfig directly) — no change needed.
All 41 lib/*.sh + larry.sh pass bash -n. MANIFEST regenerated (115 entries,
--check=0). VERSION 0.9.6 → 0.9.7. Self-update delivers this fix on next
`larry` launch on any enrolled box.
Ref: tsk-2026-05-28-006 (Vera-flagged hardening item); patch spec
Deliverables/2026-06-14-clover-v3-hardening-patches/F6-journal-write-failure-silent.patch
Co-Authored-By: Clover (claude-sonnet-4-6) <noreply@anthropic.com>
This commit is contained in:
parent
400398ca7d
commit
be8af282ef
12
MANIFEST
12
MANIFEST
@ -23,7 +23,7 @@
|
||||
# scripts/make-manifest.sh and bump VERSION.
|
||||
|
||||
# Top-level scripts
|
||||
larry.sh 81a87ab2232c202990933ccc82c12b125c69ff1b41e65e9c12ee63f88b57128c
|
||||
larry.sh 49cc8dcf8b1f5057aa816b28a07e718293f1d92a573268b65cdb288fc10ae71b
|
||||
larry-tunnel.sh 6b050e4eeab15669f4858eaf3b807f168f211ced07815db9521bc40a093f6aaa
|
||||
larry-auth.sh a220cdf7878569dc3028951ee57fc8d5e706a8ca5c6aa45347b58facb386f831
|
||||
larry-rollback.sh 91b5e9aa6c79266bf306dcfba4ca791c07971bd6924d67a779037531648aa6d0
|
||||
@ -31,7 +31,7 @@ install-larry.sh daf2814a41052783cd8bf4252cec9276878860be8945a7fe678182c51d7eac0
|
||||
uninstall-larry.sh c53ad2d8354c7adeb243b541f027f3f481e4a8661eecfd7af14d7ca53cfcaad9
|
||||
|
||||
# Metadata
|
||||
VERSION fd51233354c9a61adaf49572b45f44f7e9cc76fc2465ea25beca00ef95856ee1
|
||||
VERSION 6c38d2d8c19dec053f658ac7e8963ce25e98f2ab00fe058e62c07010c1988c6c
|
||||
MANUAL.md 5ff54d6d5fae826f8b3da1eb3be6476076bb15f9b1417a4de285e59ea37e1b1f
|
||||
CHANGELOG.md 8573fa4c1911f665f71f792d992ab331e5bb2aa5462ebd29c12994781588843e
|
||||
|
||||
@ -69,7 +69,7 @@ lib/headers-sync.sh 47b1946f807b213a2e77cec71128a84a35f103e12fea13ae88d24610d8ee
|
||||
|
||||
# Logging / capture
|
||||
lib/lessons.sh 225e899ed72ce20906cc454c5f5db87d605859e5e17431731a2ce481623f4e16
|
||||
lib/journal.sh 11c62a2d47b6b67a2f423fd8b86c454126df18d2dc3e150233bbd08293e39fe7
|
||||
lib/journal.sh 1c285df3f5677477c7b675c4f03236823005670b338a1781dd0c73d12fd1424f
|
||||
|
||||
# HL7 utilities
|
||||
lib/hl7-sanitize.sh efd333dc3e267cf2280433e53bbb910023d0bc4b30724181b53873b410d83005
|
||||
@ -98,11 +98,11 @@ lib/table-to-csv.sh ad98e73687bc9e9f6ae0cd79ed5ba26c856076902865230f822dec1a1bea
|
||||
# NetConfig tooling
|
||||
lib/nc-engine.sh e2b12a1c019d40857b96d48d6c185b94aefadab604536ce41077ecc251b0bc58
|
||||
lib/nc-status.sh fa08c5e48704d3d17e2206dafc8522ae7668b7a2f9b97f3521e05fd0ba739443
|
||||
lib/nc-table.sh a6d5c11dd460cfb100ea50c74d57c1a46ef49112632037534a32cd28600abe7f
|
||||
lib/nc-table.sh 4a31b49dd0106f95ed4ed33b5136eff23b178a8e339ae482a9486bfff554d2a6
|
||||
lib/nc-xlate.sh 8621e6f0ef55524dd6ecba91fee055cf9cdc168791e75ba7c15d9bf501fe09bf
|
||||
lib/nc-smat-diff.sh 9c04d9e2f35f22c78d5f3c40a884ed23a3b6aaabc53ee27dfbfb66ab3166a567
|
||||
lib/nc-create-thread.sh e35b0ee27f2c0327928adc21467f2b9d5a29f7436e5b89773f65420281739df7
|
||||
lib/nc-set-field.sh 0977fcab1cd931ecdd78c8aea673db93d898f11f535daf26456a4fb7845542e4
|
||||
lib/nc-set-field.sh 3e718ae88b93433e64a957d782f955b3f5d0a0d40b06072d4a89d56be9cc5b44
|
||||
lib/nc-tclgen.sh 5b8e73d7f6950a2b84f563132562ea82f62f4acac907257e233c7e68d85506c9
|
||||
lib/nc-parse.sh 52fef42d7a4b361534ab0d921deef74586dfeb6c199c941cebb55abcc2c39d4f
|
||||
lib/nc-paths.sh 388d2f4560736587a01218cadc1de612cd59e392819d16db2f56f19174c1111b
|
||||
@ -114,7 +114,7 @@ lib/nc-document.sh 47211e99089c0446d25a1e84545a734894720a1c9ad8f59b920332035e4ea
|
||||
lib/nc-revisions.sh c27856f7decfc4c2e2c990f59eb20136fdff9cf0a52b9d9fbd9370613666a802
|
||||
lib/nc-diff-interface.sh c922d10323f06346efa53ada68b44d32d9568ff0bd848c59af3404135f29d1ad
|
||||
lib/nc-find.sh 2264877c56100378a1b780d640dcaa806aa5501ddd204c6b6a8eb5d3e07bf966
|
||||
lib/nc-insert-protocol.sh ad1fa0bafbf4fdfb12bad20f9c22c3eed519f8846774331e26aa9becd6f8898a
|
||||
lib/nc-insert-protocol.sh acc4345eface7ea77c8ea5e5bb5b2085819d48e8c7b5b2e9eec2d194a52cb046
|
||||
lib/nc-regression.sh 70999a60608439f7bf1a3abb9f5e9854b5ea03025ef29ddbca683896346d1bce
|
||||
|
||||
# v0.9.4: short, directly-invokable command wrappers on PATH (bin/) + dynamic
|
||||
|
||||
2
larry.sh
2
larry.sh
@ -99,7 +99,7 @@ set -o pipefail
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
# Config
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
LARRY_VERSION="0.9.6"
|
||||
LARRY_VERSION="0.9.7"
|
||||
LARRY_HOME="${LARRY_HOME:-$HOME/.larry}"
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
@ -110,10 +110,20 @@ journal_write() {
|
||||
|
||||
diff -u "$backup" "$newcopy" > "$diffp" 2>/dev/null || true
|
||||
|
||||
# Atomically write the new content
|
||||
# Atomically write the new content (F-6 hardening: check each step, return non-zero on failure)
|
||||
local target_dir; target_dir=$(dirname "$target")
|
||||
mkdir -p "$target_dir" 2>/dev/null
|
||||
cp -p "$newfile" "$target.larry-tmp.$$" && mv -f "$target.larry-tmp.$$" "$target"
|
||||
local _tmp="$target.larry-tmp.$$"
|
||||
if ! cp -p "$newfile" "$_tmp"; then
|
||||
echo "journal_write: cp failed — could not stage '$newfile' to '$_tmp' (disk full or read-only?)" >&2
|
||||
rm -f "$_tmp" 2>/dev/null
|
||||
return 4
|
||||
fi
|
||||
if ! mv -f "$_tmp" "$target"; then
|
||||
echo "journal_write: mv failed — could not commit '$_tmp' to '$target'" >&2
|
||||
rm -f "$_tmp" 2>/dev/null
|
||||
return 4
|
||||
fi
|
||||
|
||||
# Append index
|
||||
printf '%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n' \
|
||||
|
||||
@ -131,7 +131,7 @@ cmd_insert() {
|
||||
|
||||
# Hand off to journal for atomic backup+write
|
||||
local entry_id
|
||||
entry_id=$(journal_write "$nc" "$tmp")
|
||||
entry_id=$(journal_write "$nc" "$tmp") || { echo "ERROR: journal_write failed — NetConfig NOT modified" >&2; rm -f "$tmp"; return 4; }
|
||||
rm -f "$tmp"
|
||||
printf 'inserted protocol %s into %s (mode=%s)\n' "$block_name" "$nc" "$mode"
|
||||
printf 'journal entry: %s\n' "$entry_id"
|
||||
@ -243,7 +243,7 @@ cmd_add_route() {
|
||||
fi
|
||||
|
||||
local entry_id
|
||||
entry_id=$(journal_write "$nc" "$tmp")
|
||||
entry_id=$(journal_write "$nc" "$tmp") || { echo "ERROR: journal_write failed — route NOT added" >&2; rm -f "$tmp"; return 4; }
|
||||
rm -f "$tmp"
|
||||
printf 'added route to protocol %s in %s (DATAXLATE block at line %s)\n' "$prot" "$nc" "$dx_start"
|
||||
printf 'journal entry: %s\n' "$entry_id"
|
||||
|
||||
@ -334,7 +334,7 @@ fi
|
||||
|
||||
# Journaled atomic write.
|
||||
if declare -f journal_write >/dev/null 2>&1; then
|
||||
ENTRY_ID=$(journal_write "$NC" "$TMP")
|
||||
ENTRY_ID=$(journal_write "$NC" "$TMP") || { echo "ERROR: journal_write failed — NetConfig NOT modified" >&2; rm -f "$TMP"; exit 4; }
|
||||
rm -f "$TMP"
|
||||
{
|
||||
printf '\nset %s.%s %s = %s (was %s)\n' "$THREAD" "${SITE:-?}" "$FIELD_IN_UC" "$VALUE" "$OLD_DISP"
|
||||
|
||||
@ -120,7 +120,7 @@ modify_via_csv() {
|
||||
|| "$C2T" --has-header "$csv_path" > "$new"
|
||||
|
||||
if declare -f journal_write >/dev/null 2>&1; then
|
||||
journal_write "$target" "$new"
|
||||
journal_write "$target" "$new" || { echo "ERROR: journal_write failed — table NOT modified" >&2; return 4; }
|
||||
else
|
||||
# No journal — direct write with simple backup
|
||||
# v0.7.5: strip non-digits from date — Cygwin date.exe could yield
|
||||
|
||||
Loading…
Reference in New Issue
Block a user