#!/usr/bin/env bash
# Copyright 2009 Red Hat Inc., Durham, North Carolina.
# All Rights Reserved.
#
# OpenScap Testing Helpers.
#
# Authors:
# Ondrej Moris <omoris@redhat.com>
# Normalized path.
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin
PREFERRED_PYTHON=@PREFERRED_PYTHON_PATH@
# Some of the tests rely on the "C" locale and would fail with some locales.
LC_ALL=C
export LC_ALL
OSCAP_FULL_VALIDATION=1
export OSCAP_FULL_VALIDATION
if [ -z ${CUSTOM_OSCAP+x} ] ; then
enable_valgrind="@ENABLE_VALGRIND@"
if [ $enable_valgrind != "OFF" ] ; then
actualdir=@CMAKE_BINARY_DIR@
export actualdir
[ -z "@CMAKE_BINARY_DIR@" ] || export OSCAP="@CMAKE_SOURCE_DIR@/tests/valgrind_test.sh"
else
[ -z "@CMAKE_BINARY_DIR@" ] || export OSCAP="bash @CMAKE_BINARY_DIR@/run @CMAKE_BINARY_DIR@/utils/oscap"
fi
[ -z "@CMAKE_BINARY_DIR@" ] || export OSCAP_CHROOTABLE_EXEC="@CMAKE_BINARY_DIR@/utils/oscap-chrootable"
[ -z "@CMAKE_BINARY_DIR@" ] || export OSCAP_CHROOTABLE="bash @CMAKE_BINARY_DIR@/run $OSCAP_CHROOTABLE_EXEC"
else
export OSCAP=${CUSTOM_OSCAP}
fi
export XMLDIFF="@CMAKE_SOURCE_DIR@/tests/xmldiff.pl"
if ! XPATH_ORIG=`command -v xpath 2>&1`; then
echo "I require xpath tool but it's not installed. Aborting." >&2
exit 1
fi
xpath_variant=$(perl -MXML::XPath -e 'print $XML::XPath::VERSION >= 1.34 ? "need_wrapper" : "standard"')
if [ "$xpath_variant" == "need_wrapper" ];
then
export XPATH_ORIG
xpath_wrapper() {
if [ "$#" == "1" ]; then
# read file from stdin
xpath_expr="$1"
"$XPATH_ORIG" -e "$xpath_expr"
elif [ "$#" == "2" ]; then
file="$1"
xpath_expr="$2"
"$XPATH_ORIG" -e "$xpath_expr" "$file"
else
echo "Parameters are not supported by xpath wrapper" >&2
exit 1
fi
}
export -f xpath_wrapper
export XPATH=xpath_wrapper
else
export XPATH="$XPATH_ORIG"
fi
# Overall test result.
result=0
# Set-up testing environment.
function test_init {
:
}
# Execute test and report its results.
function test_run {
printf "+ %-60s\n" "$1";
echo -e "TEST: $1" >&2;
shift
( exec 1>&2 ; eval "$@" )
ret_val=$?
if [ $ret_val -eq 0 ]; then
echo -e "RESULT: PASSED\n" >&2
return 0;
elif [ $ret_val -eq 1 ]; then
result=$(($result + $ret_val))
echo -e "RESULT: FAILED\n" >&2
return 1;
elif [ $ret_val -eq 255 ]; then
echo -e "RESULT: SKIPPED\n" >&2
return 0;
else
result=$(($result + $ret_val))
echo -e "RESULT: WARNING (unknown exist status $ret_val)\n" >&2
return 1;
fi
}
# Clean-up testing environment.
function test_exit {
if [ $# -eq 1 ]
then
( exec 1>&2 ; eval "$@" )
fi
[ $result -eq 0 ] && exit 0
exit 1
}
# Check if requirements are in a path, use it as follows:
# require 'program' || return 255
function require {
eval "which $1 > /dev/null 2>&1"
if [ ! $? -eq 0 ]; then
echo -e "No '$1' found in $PATH!\n"
return 1; # Test is not applicable.
fi
return 0
}
# Check if probe exists, use it as follows:
# probecheck 'probe' || return 255
function probecheck {
if ! $OSCAP --version | grep "\<"$1"\>" >/dev/null ; then
echo -e "Probe $1 does not exist!\n"
return 255 # Test is not applicable.
fi
return 0
}
# Check for package names and return a version number
function package_version {
# loop through multiple potential package names
# return first version number found
for package in $@; do
ver=""
# check rpm for package version first
if [ -f "/usr/bin/rpm" ]; then
ver=$(rpm -q $package --qf="%{version}" 2> /dev/null)
# rpm returns error messages on stdout, check return code
if [ ! "$?" -eq "0" ]; then
ver=""
fi
fi
# fall back to dpkg for debian systems
if [ "${ver}" == "" ] && [ -f "/usr/bin/dpkg-query" ]; then
# for Debian-based systems, return the upstream version
ver="$(dpkg-query -f '${source:Upstream-Version}' -W $package 2> /dev/null)"
fi
# return the first match found
if [ "${ver}" != "" ]; then
echo "${ver}"
return 0
fi
done
# package not found
if [ "${ver}" == "" ]; then
return 255
fi
}
function verify_results {
require "grep" || return 255
local ret_val=0;
local TYPE="$1"
local CONTENT="$2"
local RESULTS="$3"
local COUNT="$4"
local FULLTYPE="definition"
[ $TYPE == "tst" ] && FULLTYPE="test"
ID=1
while [ $ID -le $COUNT ]; do
CON_ITEM=`grep "id=\"oval:[[:digit:]]\+:${TYPE}:${ID}\"" $CONTENT`
RES_ITEM=`grep "${FULLTYPE}_id=\"oval:[[:digit:]]\+:${TYPE}:${ID}\"" $RESULTS`
OVAL_ID=`echo ${CON_ITEM} | grep -o "oval:[[:digit:]]\+:${TYPE}:${ID}"`
if (echo $RES_ITEM | grep "result=\"true\"") >/dev/null; then
RES="TRUE"
elif (echo $RES_ITEM | grep "result=\"false\"" >/dev/null); then
RES="FALSE"
else
RES="ERROR"
fi
if (echo $CON_ITEM | grep "comment=\"true\"" >/dev/null); then
CMT="TRUE"
elif (echo $CON_ITEM | grep "comment=\"false\"" >/dev/null); then
CMT="FALSE"
else
CMT="ERROR"
fi
if [ ! $RES = $CMT ]; then
echo "Result of ${OVAL_ID} should be ${CMT} and is ${RES}"
ret_val=$(($ret_val + 1))
fi
ID=$(($ID+1))
done
return $([ $ret_val -eq 0 ])
}
assert_exists() {
real_cnt="$($XPATH $result 'count('"$2"')' 2>/dev/null)"
if [ "$real_cnt" != "$1" ]; then
echo "Failed: expected count: $1, real count: $real_cnt, xpath: '$2'"
return 1
fi
}
# $1: The chroot directory
set_chroot_offline_test_mode() {
if test -n "$_OSCAP_BEFORE"; then
echo "Already in offline test mode!" >&2
return
fi
if test -x "$OSCAP_CHROOTABLE_EXEC"; then
if ! getcap "$OSCAP_CHROOTABLE_EXEC" | grep -q 'cap_sys_chroot+ep'; then
echo "Skipping test '${FUNCNAME[1]}' as '$OSCAP_CHROOTABLE_EXEC' doesn't have the chroot capability." >&2
return 255
fi
_OSCAP_BEFORE="$OSCAP"
OSCAP="$OSCAP_CHROOTABLE"
elif test $(id -u) -eq 0; then
: # Running offline tests as root is acceptable too
else
echo "Skipping test '${FUNCNAME[1]}' as '$OSCAP_CHROOTABLE_EXEC' oscap which is supposed to have chroot capability doesn't exist." >&2
return 255
fi
set_offline_chroot_dir "$1"
return 0
}
# $1: The chroot directory. If empty, unset the OSCAP_PROBE_ROOT variable
set_offline_chroot_dir() {
if test -n "$1"; then
export OSCAP_PROBE_ROOT="$1"
else
unset OSCAP_PROBE_ROOT
fi
}
unset_chroot_offline_test_mode() {
if test -n "$_OSCAP_BEFORE"; then
OSCAP="$_OSCAP_BEFORE"
_OSCAP_BEFORE=
fi
set_offline_chroot_dir ""
}
export -f assert_exists