From e8803f8c81b703ad1c11bfb0d9c690678836a3c2 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Mon, 17 Oct 2022 18:47:56 -0400 Subject: [PATCH] Add profile checks with Schematron for usnistgov/oscal-content#128. Profile checker Schematron queryBinding from xslt3->xslt2. We need to do this in the interim or we will need to significantly change or upgrade the CI/CD Schematron checker from current Schematron/schematron skeleton to SchXslt or equivalent. The former is mothballed and there was no addition of XSLT3 support. Potentially investigate further. Team discussion: https://gitter.im/usnistgov-OSCAL/xslt-etc?at=634dc527dcbf067fdc9c47cd Schematron issue: https://github.com/Schematron/schematron/issues/20 SchXslt docs on XSLT 3.0 support: https://github.com/schxslt/schxslt/blob/62f1141613c9d4c02d8de86713bb3f3b29d6cf1c/README.md#additional-xslt-elements --- build/ci-cd/validate-content.sh | 53 +++++++++++++++++++++++++- src/utils/schematron/oscal-profile.sch | 2 +- 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/build/ci-cd/validate-content.sh b/build/ci-cd/validate-content.sh index bcec83b52d..d94e6a6aca 100755 --- a/build/ci-cd/validate-content.sh +++ b/build/ci-cd/validate-content.sh @@ -6,6 +6,7 @@ if [ -z ${OSCAL_SCRIPT_INIT+x} ]; then source "$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)/include/init-oscal.sh" fi source "$OSCALDIR/build/metaschema/scripts/include/init-validate-content.sh" +source "$OSCALDIR/build/metaschema/scripts/include/init-schematron.sh" # Option defaults ARTIFACT_DIR="${OSCALDIR}" @@ -23,10 +24,16 @@ Usage: $0 [options] -o DIR, --oscal-dir DIR OSCAL schema are located in DIR. -h, --help Display help -v Provide verbose output +--scratch-dir DIR Generate temporary artifacts in DIR + If not provided a new directory will be + created under \$TMPDIR if set or in /tmp. +--keep-temp-scratch-dir If a scratch directory is automatically + created, it will not be automatically removed. EOF } -if ! OPTS=$(getopt -o o:vhc:a: --long artifact-dir:,oscal-dir:,help,config-file: -n "$0" -- "$@"); then echo "Failed parsing options." >&2 ; usage ; exit 1 ; fi +OPTS=$(getopt -o o:vhc:a: --long artifact-dir:,oscal-dir:,help,config-file:,scratch-dir:,keep-temp-scratch-dir -n "$0" -- "$@") +if [ $? != 0 ] ; then echo "Failed parsing options." >&2 ; usage ; exit 1 ; fi # Process arguments eval set -- "$OPTS" @@ -45,6 +52,13 @@ while [ $# -gt 0 ]; do ARTIFACT_DIR="$(realpath "$2")" shift # past path ;; + --scratch-dir) + SCRATCH_DIR="$(realpath "$2")" + shift # past path + ;; + --keep-temp-scratch-dir) + KEEP_TEMP_SCRATCH_DIR=true + ;; -v) VERBOSE=true ;; @@ -76,6 +90,28 @@ if [ "$VERBOSE" = "true" ]; then echo -e "${P_INFO}Using config file:${P_END} ${CONFIG_FILE}" fi +if [ -z "${SCRATCH_DIR+x}" ]; then + SCRATCH_DIR="$(mktemp -d)" + if [ "$KEEP_TEMP_SCRATCH_DIR" != "true" ]; then + function CleanupScratchDir() { + rc=$? + if [ "$VERBOSE" = "true" ]; then + echo -e "" + echo -e "${P_INFO}Cleanup${P_END}" + echo -e "${P_INFO}=======${P_END}" + echo -e "${P_INFO}Deleting scratch directory:${P_END} ${SCRATCH_DIR}" + fi + rm -rf "${SCRATCH_DIR}" + exit $rc + } + trap CleanupScratchDir EXIT + fi +fi + +profile_schematron="oscal/src/utils/schematron/oscal-profile.sch" +compiled_profile_schematron="${SCRATCH_DIR}/oscal-profile.xsl" +build_schematron "${profile_schematron}" "${compiled_profile_schematron}" + exitcode=0 shopt -s nullglob shopt -s globstar @@ -113,6 +149,21 @@ while IFS="|" read path format model converttoformats || [ -n "$path" ]; do else echo -e "${P_OK}XML Schema validation passed for '${P_END}${file_relative}${P_OK}' using schema '${P_END}${schema_relative}${P_OK}'.${P_END}" fi + + if [ "${model}" == "profile" ]; then + echo -e "${P_INFO}Validating profile with Schematron for project's requirements and recommendations.${P_INFO}${P_END}" + target_file=$(basename -- "${file_relative}") + svrl_result="/tmp/${target_file}.svrl" + result=$(validate_with_schematron "${SCRATCH_DIR}/oscal-profile.xsl" "${file_relative}" "$svrl_result" 2>&1) + cmd_exitcode=$? + if [ $cmd_exitcode -ne 0 ]; then + echo -e "${P_ERROR}Profile validation execution for '${P_END}${file_relative}${P_ERROR}' with Schematron '${P_END}${profile_schematron}${P_ERROR}' did not complete.${P_END}" + echo -e "${P_ERROR}${result}${P_END}" + exitcode=1 + else + echo -e "${P_OK}Profile validation execution for '${P_END}${file_relative}${P_OK}' with Schematron '${P_END}${profile_schematron}${P_OK}' completed successfully.${P_END}" + fi + fi ;; json) schema="$WORKING_DIR/json/schema/oscal_${model}_schema.json" diff --git a/src/utils/schematron/oscal-profile.sch b/src/utils/schematron/oscal-profile.sch index b0d227b7ab..36364d15a6 100644 --- a/src/utils/schematron/oscal-profile.sch +++ b/src/utils/schematron/oscal-profile.sch @@ -1,5 +1,5 @@ -