1
0
Fork 0
mirror of https://github.com/vbatts/go-mtree.git synced 2025-10-04 12:31:00 +00:00

cmd: validate: add --strict mode

Due to FreeBSD compatibility, we have so far been forced into some
unfortunate behaviour with regards to which comparison errors we
actually return an error code for. FreeBSD generally does not return
errors if a file or keyword only exists in one of the manifests being
compared.

Some users do not care about FreeBSD compatibility and just want to get
errors if there is any difference between a manifest and directory tree.
Commit 9cdd9152b3 ("cmd: gomtree: re-enable errors when there is a
Modified entry") added a TODO to implement this, but I've only just got
around to implementing it.

This patch adds a new --strict flag to "gomtree validate", which causes
it to error out if any changes were detected and also disables the
FreeBSD compatibility keyword delta filters. This is more akin to what
modern users would expect from a manifest validation tool.

Fixes: 21723a3974 ("*: fix comparison of missing keywords")
Fixes: 9cdd9152b3 ("cmd: gomtree: re-enable errors when there is a Modified entry")
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
This commit is contained in:
Aleksa Sarai 2025-09-16 23:57:31 +10:00
parent 1ce6aa8db5
commit b06e4de597
No known key found for this signature in database
GPG key ID: 2897FAD2B7E9446F
2 changed files with 136 additions and 21 deletions

114
test/cli/0013.sh Normal file
View file

@ -0,0 +1,114 @@
#!/bin/bash
set -ex
name=$(basename $0)
root="$(dirname $(dirname $(dirname $0)))"
gomtree=$(go run ${root}/test/realpath/main.go ${root}/gomtree)
t=$(mktemp -d /tmp/go-mtree.XXXXXX)
setfattr -n user.has.xattrs -v "true" "${t}" || exit 0
echo "[${name}] Running in ${t}"
## Test that --strict mode will error out in cases that stock gomtree will not.
pushd ${root}
mkdir -p ${t}/root
mkdir -p ${t}/root/foo/bar
echo "valid" >${t}/root/foo/bar/file
echo "#!/bin/false" >${t}/root/binary
chmod 755 ${t}/root/binary
date="2025-09-05T13:05:10"
touch -d "$date.12345" ${t}/root/time
touch ${t}/root/xattr
setfattr -n user.mtree.testing -v "apples and=bananas" ${t}/root/xattr
keywords_notime=type,uid,gid,nlink,link,mode,flags,xattr,size,sha256
keywords=$keywords_notime,time
${gomtree} -c -k "$keywords" -p ${t}/root -f ${t}/root.mtree
# Make sure cp -ar still validates.
dir=${t}/copy; cp -ar ${t}/root ${dir}
${gomtree} -k "$keywords" -p ${dir} -f ${t}/root.mtree
${gomtree} --strict -k "$keywords" -p ${dir} -f ${t}/root.mtree
# Missing files should not validate.
dir=${t}/missing; cp -ar ${t}/root ${dir}
rm ${dir}/binary
(! ${gomtree} --strict -p ${dir} -f ${t}/root.mtree)
(! ${gomtree} --strict -k "$keywords" -p ${dir} -f ${t}/root.mtree)
# "size" will tip off gomtree even in stock mode, so re-do with just "type".
${gomtree} -k type -p ${dir} -f ${t}/root.mtree
(! ${gomtree} --strict -k type -p ${dir} -f ${t}/root.mtree)
# Extra files should not validate.
dir=${t}/extra; cp -ar ${t}/root ${dir}
touch ${dir}/newfile
(! ${gomtree} --strict -p ${dir} -f ${t}/root.mtree)
(! ${gomtree} --strict -k "$keywords" -p ${dir} -f ${t}/root.mtree)
# "size" will tip off gomtree even in stock mode, so re-do with just "type".
${gomtree} -k type -p ${dir} -f ${t}/root.mtree
(! ${gomtree} --strict -k type -p ${dir} -f ${t}/root.mtree)
# Extra keywords that are missing from the original manifest should not
# validate.
dir=${t}/root
${gomtree} -k "$keywords,md5" -p ${dir} -f ${t}/root.mtree
(! ${gomtree} --strict -k "$keywords,md5" -p ${dir} -f ${t}/root.mtree)
# Mismatched keywords should not validate when comparing two manifests.
dir=${t}/root
keywords2=type,uid,gid,nlink,mode,flags,xattr,size,sha384,time
${gomtree} -c -k "$keywords2" -p ${dir} -f ${t}/root.mtree2
${gomtree} -k "$keywords" -f ${t}/root.mtree -f ${t}/root.mtree2
(! ${gomtree} --strict -k "$keywords" -f ${t}/root.mtree -f ${t}/root.mtree2)
${gomtree} -k "$keywords" -f ${t}/root.mtree2 -f ${t}/root.mtree
(! ${gomtree} --strict -k "$keywords" -f ${t}/root.mtree2 -f ${t}/root.mtree)
${gomtree} -k "$keywords2" -f ${t}/root.mtree -f ${t}/root.mtree2
(! ${gomtree} --strict -k "$keywords2" -f ${t}/root.mtree -f ${t}/root.mtree2)
${gomtree} -k "$keywords2" -f ${t}/root.mtree2 -f ${t}/root.mtree
(! ${gomtree} --strict -k "$keywords2" -f ${t}/root.mtree2 -f ${t}/root.mtree)
# Changed xattrs should not validate (even without --strict).
dir=${t}/xattr-change; cp -ar ${t}/root ${dir}
setfattr -n user.mtree.testing -v "different value" ${dir}/xattr
(! ${gomtree} -p ${dir} -f ${t}/root.mtree)
(! ${gomtree} -k "$keywords" -p ${dir} -f ${t}/root.mtree)
(! ${gomtree} --strict -p ${dir} -f ${t}/root.mtree)
(! ${gomtree} --strict -k "$keywords" -p ${dir} -f ${t}/root.mtree)
# Adding xattrs to existing xattr-set files should not validate (even without
# --strict).
dir=${t}/xattr-add1; cp -ar ${t}/root ${dir}
setfattr -n user.mtree.new -v "newxattr" ${dir}/xattr
(! ${gomtree} -p ${dir} -f ${t}/root.mtree)
(! ${gomtree} -k "$keywords" -p ${dir} -f ${t}/root.mtree)
(! ${gomtree} --strict -p ${dir} -f ${t}/root.mtree)
(! ${gomtree} --strict -k "$keywords" -p ${dir} -f ${t}/root.mtree)
# Adding xattrs to unrelated files should not validate (even without --strict).
dir=${t}/xattr-add2; cp -ar ${t}/root ${dir}
setfattr -n user.mtree.new -v "newxattr" ${dir}/binary
(! ${gomtree} -p ${dir} -f ${t}/root.mtree)
(! ${gomtree} -k "$keywords" -p ${dir} -f ${t}/root.mtree)
(! ${gomtree} --strict -p ${dir} -f ${t}/root.mtree)
(! ${gomtree} --strict -k "$keywords" -p ${dir} -f ${t}/root.mtree)
# Removing xattrs should not validate (even without --strict).
dir=${t}/xattr-rm; cp -ar ${t}/root ${dir}
setfattr -x user.mtree.testing ${dir}/xattr
(! ${gomtree} -p ${dir} -f ${t}/root.mtree)
(! ${gomtree} -k "$keywords" -p ${dir} -f ${t}/root.mtree)
(! ${gomtree} --strict -p ${dir} -f ${t}/root.mtree)
(! ${gomtree} --strict -k "$keywords" -p ${dir} -f ${t}/root.mtree)
# time -> tar_time validation should still work even with --strict mode.
dir=${t}/tartime; cp -ar ${t}/root ${dir}
touch -d "$date.00000" ${dir}/time
(! ${gomtree} -p ${dir} -f ${t}/root.mtree)
(! ${gomtree} -k "$keywords" -p ${dir} -f ${t}/root.mtree)
(! ${gomtree} --strict -p ${dir} -f ${t}/root.mtree)
(! ${gomtree} --strict -k "$keywords" -p ${dir} -f ${t}/root.mtree)
${gomtree} -k "$keywords_notime,tar_time" -p ${dir} -f ${t}/root.mtree
${gomtree} --strict -k "$keywords_notime,tar_time" -p ${dir} -f ${t}/root.mtree