A snapshot: read at commit 707a04c7ce8 on 2026-10-18T00:06:01Z by majordomus 0.29.0. Nothing on this page is read again. See it live
test/cases/130_archive.sh
An object of kind test
What it is
- URI
majordomus://test/test/cases/130_archive.sh- Kind
test- Identity
test/cases/130_archive.sh- Path
test/cases/130_archive.sh- Provenance
- declared
- Media type
text/plain- As a capability
- test.test/cases/130_archive.sh
Front matter
{}Content
# majordomus-covers: archive
# majordomus-negative: archive
#
# An archive is believed at the far end, where nobody can check it against the original.
# That is what makes its failures expensive: the two this case exists for both look, to
# the recipient, like the repository being broken rather than the copy being wrong.
#
# The first is the file mode. `zip -X` strips the extra fields that carry it, so the
# unpacked tree has no executable in it, every script fails to run, and the person at the
# far end reports a broken repository. That is how this command came to exist. So the
# round trip is measured here rather than assumed: an executable goes in, the archive is
# opened, and it is still executable — and when a reader discards the modes anyway, the
# restore script inside the archive must put them back from the manifest.
#
# The second is a selection that quietly matched nothing. A profile that excludes
# everything, or a .gitattributes rule read the wrong way round, produces a smaller
# archive and no error at all. Every count asserted below is compared against something
# measured from the repository, and each rule is proved by breaking it: the file that
# `derived` drops is shown present before the attribute exists and absent after.
. "$ROOT/test/lib.sh"
"$MJ" init >/dev/null
"$MJ" update >/dev/null
mkdir -p lib docs
echo 'a' > lib/a
echo 'd' > docs/d
printf '#!/bin/sh\necho hi\n' > lib/runme.sh
chmod 755 lib/runme.sh
printf 'projection\n' > docs/PROJECTED.md
git add -A && git commit -qm base
tracked="$(git ls-files | wc -l | tr -d ' ')"
[ "$tracked" -gt 5 ] || { echo " only $tracked tracked file(s); this case is measuring the wrong tree"; exit 1; }
# ---- the profiles are read from the declaration, not from the code ---------------------
expect_exit 0 "$MJ" archive --list
expect_grep 'context'
expect_grep '\(default\)'
expect_grep 'audit'
expect_grep 'governance'
# ---- the selection states its own denominator ------------------------------------------
expect_exit 0 "$MJ" archive --dry-run
expect_grep "of $tracked tracked file"
expect_grep 'nothing written'
n_context="$("$MJ" --json archive --dry-run | sed -n 's/.*"archived":\([0-9]*\).*/\1/p')"
[ -n "$n_context" ] || { echo " --json archive --dry-run reports no archived count"; exit 1; }
[ "$n_context" -gt 0 ] || { echo " the context profile selected 0 of $tracked tracked file(s)"; exit 1; }
n_audit="$("$MJ" --json archive audit --dry-run | sed -n 's/.*"archived":\([0-9]*\).*/\1/p')"
[ "$n_audit" = "$tracked" ] \
|| { echo " the audit profile archives $n_audit of $tracked tracked file(s); it drops nothing"; exit 1; }
# ---- `derived: drop` reads .gitattributes, and does so in both directions ---------------
# before the attribute exists, the file is in the archive
"$MJ" --json archive --dry-run > /dev/null
before="$n_context"
printf 'docs/PROJECTED.md merge=derived\n' > .gitattributes
git add .gitattributes && git commit -qm attrs
[ "$(git check-attr merge -- docs/PROJECTED.md)" = "docs/PROJECTED.md: merge: derived" ] \
|| { echo " the probe did not take: git does not report docs/PROJECTED.md as merge=derived"; exit 1; }
after="$("$MJ" --json archive --dry-run | sed -n 's/.*"archived":\([0-9]*\).*/\1/p')"
# one file gained (.gitattributes), one file lost (the derived one): the net is zero, so
# the count alone proves nothing and the reason is what is asserted
reasons="$("$MJ" --json archive --dry-run | sed -n 's/.*"reasons":{\(.*\)}}/\1/p')"
case "$reasons" in
*'"derived":1'*) ;;
*) echo " .gitattributes marks one file merge=derived and the profile dropped: $reasons"; exit 1 ;;
esac
[ "$after" -le "$before" ] \
|| { echo " the derived file was marked and the archive grew: $before -> $after"; exit 1; }
# ---- the mode survives the container ----------------------------------------------------
# Proves `archive-fidelity`: an archive that lost the file modes fails rather than
# travelling — the round trip is measured, and a reader that discards the modes anyway is
# answered by the restore script putting them back from the manifest.
if command -v zip >/dev/null 2>&1 && command -v unzip >/dev/null 2>&1; then
expect_exit 0 "$MJ" archive audit --out "$T/audit.zip"
expect_grep 'OK archive'
expect_grep 'read back'
expect_file "$T/audit.zip"
U="$T/unpacked"; mkdir -p "$U"
( cd "$U" && unzip -q "$T/audit.zip" ) || { echo " the archive does not unpack"; exit 1; }
D="$(find "$U" -maxdepth 1 -mindepth 1 -type d | head -1)"
[ -n "$D" ] || { echo " the archive unpacked to no directory"; exit 1; }
[ -f "$D/lib/runme.sh" ] || { echo " lib/runme.sh is not in the unpacked archive"; exit 1; }
[ -x "$D/lib/runme.sh" ] \
|| { echo " lib/runme.sh went in executable and came out $(file_mode "$D/lib/runme.sh"); the container discarded the modes"; exit 1; }
# ---- and when a reader discards them anyway, the manifest is what puts them back ------
[ -f "$D/_ARCHIVE/MANIFEST.txt" ] || { echo " the archive carries no _ARCHIVE/MANIFEST.txt"; exit 1; }
grep -q '^100755 .*lib/runme.sh$' "$D/_ARCHIVE/MANIFEST.txt" \
|| { echo " the manifest does not record lib/runme.sh as executable"; exit 1; }
# files only: stripping x from the directories would stop the tree being traversable,
# which is a different failure from the one being reproduced
find "$D/lib" "$D/_ARCHIVE" -type f -exec chmod a-x {} + 2>/dev/null || true
[ -x "$D/lib/runme.sh" ] && { echo " the probe did not take: lib/runme.sh is still executable"; exit 1; }
( cd "$D" && sh _ARCHIVE/restore.sh ) > "$T/restore.out" 2>&1 \
|| { echo " restore.sh failed:"; sed 's/^/ | /' "$T/restore.out"; exit 1; }
[ -x "$D/lib/runme.sh" ] \
|| { echo " restore.sh ran and lib/runme.sh is still not executable"; sed 's/^/ | /' "$T/restore.out"; exit 1; }
grep -q 'modes applied to' "$T/restore.out" \
|| { echo " restore.sh does not say how many modes it applied"; sed 's/^/ | /' "$T/restore.out"; exit 1; }
# ---- a copy the repository's own enumeration can read ---------------------------------
[ -d "$D/.git" ] || { echo " restore.sh created no git index"; sed 's/^/ | /' "$T/restore.out"; exit 1; }
restored="$( cd "$D" && git ls-files | wc -l | tr -d ' ' )"
[ "$restored" -ge "$tracked" ] \
|| { echo " the restored index holds $restored file(s) and the repository tracked $tracked"; exit 1; }
# ---- an existing output is not replaced by accident -----------------------------------
expect_exit 15 "$MJ" archive audit --out "$T/audit.zip"
expect_grep 'exists'
expect_exit 0 "$MJ" archive audit --out "$T/audit.zip" --force
else
echo " skip: zip or unzip is not on PATH; the container round trip was not measured"
fi
# ---- the refusals ------------------------------------------------------------------------
expect_exit 12 "$MJ" archive nosuch
expect_grep 'no profile'
expect_grep 'archive --list'
expect_exit 2 "$MJ" archive --format 7z
expect_grep 'zip or tar.gz'
expect_exit 2 "$MJ" archive --nonesuch
expect_grep 'unknown option'
expect_exit 2 "$MJ" archive context audit
expect_grep 'one profile only'
printf 'ok archive: %s profiles, %s of %s tracked file(s) in the default, modes proved through the container\n' \
3 "$n_context" "$tracked"