Files
freebsd/usr.sbin/certctl/tests/certctl_test.sh
T
Warner Losh a259b98fa2 tests: skip gracefully when the tested binary's own package isn't installed
pkgbase splits programs and their tests into separate packages (e.g.
unifdef/yacc/indent/file2c -> toolchain, jail -> jail, etc), while their
tests always land in the generic tests package.  Installing just the
tests package therefore leaves these suites unable to find the binary
they exercise, and they fail confusingly instead of skipping.

Rather than force all packages to be installed for the tests package,
make the tests cope with the missing packages.  Add require.progs (or,
for TAP/PLAIN-style suites with no atf_set hook: TEST_METADATA
required_programs) for the binary under test in: bectl, certctl,
ctfconvert, dhclient, file2c, indent, ipfw, jail, lastcomm, mixer,
newsyslog, nvmecontrol, pfctl, praudit, sa, syslogd, tunefs, unifdef,
yacc, ztest.

I skipped adding data for all the binaries in the base runtime
package for simplicity.

Assisted-by:		Claude Code (Sonnet 5)
Sponsored by:		Netflix
Reviewed by:		ngie
Differential Revision:	https://reviews.freebsd.org/D58262
2026-09-10 23:42:25 -06:00

340 lines
8.2 KiB
Bash

#
# Copyright (c) 2025 Dag-Erling Smørgrav <[email protected]>
#
# SPDX-License-Identifier: BSD-2-Clause
#
. $(atf_get_srcdir)/certctl.subr
# Random sets of eight non-colliding names
set1()
{
cat <<EOF
AVOYKJHSLFHWPVQMKBHENUAHJTEGMCCB 0ca83bbe
UYSYXKDNNJTYOQPBGIKQDHRJYZHTDPKK 0d9a6512
LODHGFXMZYKGOKAYGWTMMYQJYHDATDDM 4e6219f5
NBBTQHJLHKBFFFWJTHHSNKOQYMGLHLPW 5dd76abc
BJFAQZXZHYQLIDDPCAQFPDMNXICUXBXW ad68573d
IOKNTHVEVVIJMNMYAVILMEMQQWLVRESN b577803d
BHGMAJJGNJPIVMHMFCUTJLGFROJICEKN c98a6338
HCRFQMGDQJALMLUQNXMPGLXFLLJRODJW f50c6379
EOF
}
set2()
{
cat <<EOF
GOHKZTSKIPDSYNLMGYXGLROPTATELXIU 30789c88
YOOTYHEGHZIYFXOBLNKENPSJUDGOPJJU 7fadbc13
ETRINNYBGKIENAVGOKVJYFSSHFZIJZRH 8ed664af
DBFGMFFMRNLPQLQPOLXOEUVLCRXLRSWT 8f34355e
WFOPBQPLQFHDHZOUQFEIDGSYDUOTSNDQ ac0471df
HMNETZMGNIWRGXQCVZXVZGWSGFBRRDQC b32f1472
SHFYBXDVAUACBFPPAIGDAQIAGYOYGMQE baca75fa
PCBGDNVPYCDGNRQSGRSLXFHYKXLAVLHW ddeeae01
EOF
}
set3()
{
cat <<EOF
NJWIRLPWAIICVJBKXXHFHLCPAERZATRL 000aa2e5
RJAENDPOCZQEVCPFUWOWDXPCSMYJPVYC 021b95a3
PQUQDSWHBNVLBTNBGONYRLGZZVEFXVLO 071e8c50
VZEXRKJUPZSFBDWBOLUZXOGLNTEAPCZM 3af7bb9b
ZXOWOXQTXNZMAMZIWVFDZDJEWOOAGAOH 48d5c7cc
KQSFQYVJMFTMADIHJIWGSQISWKSHRYQO 509f5ba1
AIECYSLWZOIEPJWWUTWSQXCNCIHHZHYI 8cb0c503
RFHWDJZEPOFLMPGXAHVEJFHCDODAPVEV 9ae4e049
EOF
}
# Random set of three colliding names
collhash=f2888ce3
coll()
{
cat <<EOF
EJFTZEOANQLOYPEHWWXBWEWEFVKHMSNA $collhash
LEMRWZAZLKZLPPSFLNLQZVGKKBEOFYWG $collhash
ZWUPHYWKKTVEFBJOLLPDAIKGRDFVXZID $collhash
EOF
}
sortfile() {
for filename; do
sort "${filename}" >"${filename}"-
mv "${filename}"- "${filename}"
done
}
certctl_setup()
{
export DESTDIR="$PWD"
# Create input directories
mkdir -p ${DESTDIR}${DISTBASE}/usr/share/certs/trusted
mkdir -p ${DESTDIR}${DISTBASE}/usr/share/certs/untrusted
mkdir -p ${DESTDIR}/usr/local/share/certs
# Do not create output directories; certctl will take care of it
#mkdir -p ${DESTDIR}${DISTBASE}/etc/ssl/certs
#mkdir -p ${DESTDIR}${DISTBASE}/etc/ssl/untrusted
# Generate a random key
keyname="testkey"
gen_key ${keyname}
# Generate certificates
:>metalog.expect
:>trusted.expect
:>untrusted.expect
metalog() {
echo ".${DISTBASE}$@ type=file" >>metalog.expect
}
trusted() {
local crtname=$1
local filename=$2
printf "%s\t%s\n" "${filename}" "${crtname}" >>trusted.expect
metalog "/etc/ssl/certs/${filename}"
}
untrusted() {
local crtname=$1
local filename=$2
printf "%s\t%s\n" "${filename}" "${crtname}" >>untrusted.expect
metalog "/etc/ssl/untrusted/${filename}"
}
set1 | while read crtname hash ; do
gen_crt ${crtname} ${keyname}
mv ${crtname}.crt ${DESTDIR}${DISTBASE}/usr/share/certs/trusted
trusted "${crtname}" "${hash}.0"
done
local c=0
coll | while read crtname hash ; do
gen_crt ${crtname} ${keyname}
mv ${crtname}.crt ${DESTDIR}${DISTBASE}/usr/share/certs/trusted
trusted "${crtname}" "${hash}.${c}"
c=$((c+1))
done
set2 | while read crtname hash ; do
gen_crt ${crtname} ${keyname}
openssl x509 -in ${crtname}.crt
rm ${crtname}.crt
trusted "${crtname}" "${hash}.0"
done >usr/local/share/certs/bundle.crt
set3 | while read crtname hash ; do
gen_crt ${crtname} ${keyname}
mv ${crtname}.crt ${DESTDIR}${DISTBASE}/usr/share/certs/untrusted
untrusted "${crtname}" "${hash}.0"
done
metalog "/etc/ssl/cert.pem"
unset -f untrusted
unset -f trusted
unset -f metalog
sortfile *.expect
}
check_trusted() {
local crtname=$1
local subject="$(subject ${crtname})"
local c=${2:-1}
atf_check -e ignore -o match:"found: ${c}\$" \
openssl storeutl -noout -subject "${subject}" \
${DESTDIR}${DISTBASE}/etc/ssl/certs
atf_check -e ignore -o not-match:"found: [1-9]" \
openssl storeutl -noout -subject "${subject}" \
${DESTDIR}${DISTBASE}/etc/ssl/untrusted
}
check_untrusted() {
local crtname=$1
local subject="$(subject ${crtname})"
local c=${2:-1}
atf_check -e ignore -o not-match:"found: [1-9]" \
openssl storeutl -noout -subject "${subject}" \
${DESTDIR}/${DISTBASE}/etc/ssl/certs
atf_check -e ignore -o match:"found: ${c}\$" \
openssl storeutl -noout -subject "${subject}" \
${DESTDIR}/${DISTBASE}/etc/ssl/untrusted
}
check_in_bundle() {
local b=${DISTBASE}${DISTBASE+/}
local crtfile=$1
local line
line=$(tail +5 "${crtfile}" | head -1)
atf_check grep -q "${line}" ${DESTDIR}${DISTBASE}/etc/ssl/cert.pem
}
check_not_in_bundle() {
local b=${DISTBASE}${DISTBASE+/}
local crtfile=$1
local line
line=$(tail +5 "${crtfile}" | head -1)
atf_check -s exit:1 grep -q "${line}" etc/ssl/cert.pem
}
atf_test_case rehash
rehash_head()
{
atf_set "descr" "Test the rehash command"
atf_set "require.progs" certctl
}
rehash_body()
{
certctl_setup
atf_check certctl rehash
# Verify non-colliding trusted certificates
(set1; set2) >trusted
while read crtname hash ; do
check_trusted "${crtname}"
done <trusted
# Verify colliding trusted certificates
coll >coll
while read crtname hash ; do
check_trusted "${crtname}" $(wc -l <coll)
done <coll
# Verify untrusted certificates
set3 >untrusted
while read crtname hash ; do
check_untrusted "${crtname}"
done <untrusted
# Verify bundle
for f in etc/ssl/certs/*.? ; do
check_in_bundle "${f}"
done
for f in etc/ssl/untrusted/*.? ; do
check_not_in_bundle "${f}"
done
}
atf_test_case list
list_head()
{
atf_set "descr" "Test the list and untrusted commands"
atf_set "require.progs" certctl
}
list_body()
{
certctl_setup
atf_check certctl rehash
atf_check -o save:trusted.out certctl list
sortfile trusted.out
# the ordering of the colliding certificates is partly
# determined by fields that change every time we regenerate
# them, so ignore them in the diff
atf_check diff -u \
--ignore-matching-lines $collhash \
trusted.expect trusted.out
atf_check -o save:untrusted.out certctl untrusted
sortfile untrusted.out
atf_check diff -u \
untrusted.expect untrusted.out
}
atf_test_case trust
trust_head()
{
atf_set "descr" "Test the trust command"
atf_set "require.progs" certctl
}
trust_body()
{
certctl_setup
atf_check certctl rehash
crtname=$(set3 | (read crtname hash ; echo ${crtname}))
crtfile=usr/share/certs/untrusted/${crtname}.crt
check_untrusted ${crtname}
check_not_in_bundle ${crtfile}
atf_check -e match:"was previously untrusted" \
certctl trust ${crtfile}
check_trusted ${crtname}
check_in_bundle ${crtfile}
}
atf_test_case untrust
untrust_head()
{
atf_set "descr" "Test the untrust command"
atf_set "require.progs" certctl
}
untrust_body()
{
certctl_setup
atf_check certctl rehash
crtname=$(set1 | (read crtname hash ; echo ${crtname}))
crtfile=usr/share/certs/trusted/${crtname}.crt
check_trusted "${crtname}"
check_in_bundle ${crtfile}
atf_check -e match:"1 new untrusted" \
certctl untrust "${crtfile}"
check_untrusted "${crtname}"
check_not_in_bundle ${crtfile}
}
atf_test_case metalog
metalog_head()
{
atf_set "descr" "Verify the metalog"
atf_set "require.progs" certctl
}
metalog_body()
{
export DISTBASE=/base
certctl_setup
# certctl gets DESTDIR and DISTBASE from environment
rm -f metalog.orig
atf_check certctl -U -M metalog.orig rehash
sed -E 's/(type=file) .*/\1/' metalog.orig | sort >metalog.short
atf_check diff -u metalog.expect metalog.short
# certctl gets DESTDIR and DISTBASE from command line
rm -f metalog.orig
atf_check env -uDESTDIR -uDISTBASE \
certctl -D ${DESTDIR} -d ${DISTBASE} -U -M metalog.orig rehash
sed -E 's/(type=file) .*/\1/' metalog.orig | sort >metalog.short
atf_check diff -u metalog.expect metalog.short
# as above, but intentionally add trailing slashes
rm -f metalog.orig
atf_check env -uDESTDIR -uDISTBASE \
certctl -D ${DESTDIR}// -d ${DISTBASE}/ -U -M metalog.orig rehash
sed -E 's/(type=file) .*/\1/' metalog.orig | sort >metalog.short
atf_check diff -u metalog.expect metalog.short
}
atf_test_case misc
misc_head()
{
atf_set "descr" "Test miscellaneous edge cases"
atf_set "require.progs" certctl
}
misc_body()
{
# certctl rejects DISTBASE that does not begin with a slash
atf_check -s exit:1 -e match:"begin with a slash" \
certctl -d base -n rehash
atf_check -s exit:1 -e match:"begin with a slash" \
env DISTBASE=base certctl -n rehash
}
atf_init_test_cases()
{
atf_add_test_case rehash
atf_add_test_case list
atf_add_test_case trust
atf_add_test_case untrust
atf_add_test_case metalog
atf_add_test_case misc
}