Skip to content

Commit

Permalink
build support: when SCE support is enabled, include the SCE scripts i…
Browse files Browse the repository at this point in the history
…n the output datastream
  • Loading branch information
nightmared committed Jan 2, 2023
1 parent ef5baae commit a265c67
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 16 deletions.
54 changes: 50 additions & 4 deletions build-scripts/compose_ds.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
import xml.etree.ElementTree as ET

from ssg.constants import (
cat_namespace, datastream_namespace, oval_namespace, XCCDF12_NS,
xlink_namespace)
cat_namespace, datastream_namespace, oval_namespace, sce_namespace,
SCE_SYSTEM, XCCDF12_NS, xlink_namespace)
import ssg.xml

try:
Expand All @@ -29,6 +29,48 @@ def mangle_path(path):
return path


def collect_sce_checks(datastreamtree, checklists, refdir):
ds_ns = datastream_namespace
checklists_component_ref = datastreamtree.find(
f".//{{{ds_ns}}}checklists/{{{ds_ns}}}component-ref")
# The component ID is the component-ref href without leading '#'
checklist_component_id = checklists_component_ref.get(f'{{{xlink_namespace}}}href')[1:]

# Locate the <xccdf:check> inside <xccdf:Rule> and detect the SCE checks
checks = datastreamtree.findall(f".//{{{ds_ns}}}component[@id='{checklist_component_id}']//{{{XCCDF12_NS}}}Rule/{{{XCCDF12_NS}}}check[@system='{SCE_SYSTEM}']/{{{XCCDF12_NS}}}check-content-ref")
# Extract the file paths of the SCE checks
sce_files = [check.get('href') for check in checks]
for file in sce_files:
path = os.path.join(refdir, file)
component_id = f"scap_{ID_NS}_ecomp_{mangle_path(file)}"
component = ET.SubElement(
datastreamtree, f"{{{ds_ns}}}extended-component",
attrib={
'id': component_id,
'timestamp': get_timestamp(path)
})
# Append the file content
script_data = ET.SubElement(component, f"{{{sce_namespace}}}script")
with open(path, 'rt', encoding='utf8') as fd:
script_data.text = fd.read()

component_ref_id = f"scap_{ID_NS}_cref_{mangle_path(file)}"
component_ref = ET.SubElement(
checklists, f"{{{ds_ns}}}component-ref",
attrib = {
'id': component_ref_id,
f"{{{xlink_namespace}}}href": '#' + component_id
})

# Add to the XCCDF-1.2 checklists list of components
catalog = checklists_component_ref.find(f"{{{cat_namespace}}}catalog")
uri = ET.SubElement(
catalog, "{%s}uri" % cat_namespace,
attrib = {
'name': file,
'uri': '#' + component_ref_id
})

def move_patches_up_to_date_to_source_data_stream_component(datastreamtree):
ds_checklists = datastreamtree.find(
".//{%s}checklists" % datastream_namespace)
Expand Down Expand Up @@ -130,6 +172,7 @@ def parse_args():
parser.add_argument("--ocil", help="OCIL file name")
parser.add_argument("--cpe-dict", help="CPE dictionary file name")
parser.add_argument("--cpe-oval", help="CPE OVAL file name")
parser.add_argument("--enable-sce", action='store_true', help="Enable building sce data")
parser.add_argument(
"--output-12", help="Output SCAP 1.2 source data stream file name")
parser.add_argument(
Expand Down Expand Up @@ -180,7 +223,7 @@ def create_catalog(component_ref, dependencies):

def compose_ds(
xccdf_file_name, oval_file_name, ocil_file_name,
cpe_dict_file_name, cpe_oval_file_name):
cpe_dict_file_name, cpe_oval_file_name, sce_enabled):
ds_collection = ET.Element(
"{%s}data-stream-collection" % datastream_namespace)
name = "from_xccdf_" + os.path.basename(xccdf_file_name)
Expand All @@ -202,6 +245,8 @@ def compose_ds(
add_component(ds_collection, checks, oval_file_name)
add_component(ds_collection, checks, ocil_file_name)
add_component(ds_collection, checks, cpe_oval_file_name)
if sce_enabled:
collect_sce_checks(ds_collection, checklists, os.path.dirname(oval_file_name))
return ET.ElementTree(ds_collection)


Expand All @@ -210,6 +255,7 @@ def upgrade_ds_to_scap_13(ds):
dsc_el.set("schematron-version", "1.3")
ds_el = ds.find("{%s}data-stream" % datastream_namespace)
ds_el.set("scap-version", '1.3')

# Move reference to remote OVAL content to a source data stream component
move_patches_up_to_date_to_source_data_stream_component(ds)
return ds
Expand All @@ -219,7 +265,7 @@ def upgrade_ds_to_scap_13(ds):
args = parse_args()
ssg.xml.register_namespaces()
ds = compose_ds(
args.xccdf, args.oval, args.ocil, args.cpe_dict, args.cpe_oval)
args.xccdf, args.oval, args.ocil, args.cpe_dict, args.cpe_oval, args.enable_sce)
if args.output_12:
ds.write(args.output_12)
ds_13 = upgrade_ds_to_scap_13(ds)
Expand Down
23 changes: 12 additions & 11 deletions cmake/SSGCommon.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -98,15 +98,15 @@ macro(ssg_build_xccdf_oval_ocil PRODUCT)
add_custom_command(
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/profiles"
COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_CURRENT_BINARY_DIR}/profiles"
COMMAND env "PYTHONPATH=$ENV{PYTHONPATH}" "${PYTHON_EXECUTABLE}" "${SSG_BUILD_SCRIPTS}/compile_all.py" --resolved-base "${CMAKE_CURRENT_BINARY_DIR}" --controls-dir "${CMAKE_SOURCE_DIR}/controls" --build-config-yaml "${CMAKE_BINARY_DIR}/build_config.yml" --product-yaml "${CMAKE_CURRENT_SOURCE_DIR}/product.yml" --sce-metadata "${CMAKE_CURRENT_BINARY_DIR}/checks_from_templates/sce/metadata.json"
COMMAND env "PYTHONPATH=$ENV{PYTHONPATH}" "${PYTHON_EXECUTABLE}" "${SSG_BUILD_SCRIPTS}/compile_all.py" --resolved-base "${CMAKE_CURRENT_BINARY_DIR}" --controls-dir "${CMAKE_SOURCE_DIR}/controls" --build-config-yaml "${CMAKE_BINARY_DIR}/build_config.yml" --product-yaml "${CMAKE_CURRENT_SOURCE_DIR}/product.yml" --sce-metadata "${CMAKE_CURRENT_BINARY_DIR}/checks/sce/metadata.json"
DEPENDS generate-internal-${PRODUCT}-sce-metadata.json
COMMENT "[${PRODUCT}-content] compiling everything"
)
else()
add_custom_command(
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/profiles"
COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_CURRENT_BINARY_DIR}/profiles"
COMMAND env "PYTHONPATH=$ENV{PYTHONPATH}" "${PYTHON_EXECUTABLE}" "${SSG_BUILD_SCRIPTS}/compile_all.py" --resolved-base "${CMAKE_CURRENT_BINARY_DIR}" --controls-dir "${CMAKE_SOURCE_DIR}/controls" --build-config-yaml "${CMAKE_BINARY_DIR}/build_config.yml" --product-yaml "${CMAKE_CURRENT_SOURCE_DIR}/product.yml" --sce-metadata "${CMAKE_CURRENT_BINARY_DIR}/checks_from_templates/sce/metadata.json" --stig-references "${STIG_REFERENCE_FILE}"
COMMAND env "PYTHONPATH=$ENV{PYTHONPATH}" "${PYTHON_EXECUTABLE}" "${SSG_BUILD_SCRIPTS}/compile_all.py" --resolved-base "${CMAKE_CURRENT_BINARY_DIR}" --controls-dir "${CMAKE_SOURCE_DIR}/controls" --build-config-yaml "${CMAKE_BINARY_DIR}/build_config.yml" --product-yaml "${CMAKE_CURRENT_SOURCE_DIR}/product.yml" --sce-metadata "${CMAKE_CURRENT_BINARY_DIR}/checks/sce/metadata.json" --stig-references "${STIG_REFERENCE_FILE}"
DEPENDS generate-internal-${PRODUCT}-sce-metadata.json
COMMENT "[${PRODUCT}-content] compiling everything"
)
Expand Down Expand Up @@ -278,7 +278,7 @@ endmacro()
# (without needing a separate XML or XSLT linking step) and also place
# <complex-check /> elements as necessary.
macro(ssg_build_sce PRODUCT)
set(BUILD_CHECKS_DIR "${CMAKE_CURRENT_BINARY_DIR}/checks_from_templates")
set(BUILD_CHECKS_DIR "${CMAKE_CURRENT_BINARY_DIR}/checks")
# Unlike build_oval_unlinked, here we're ignoring the existing checks from
# templates and other places and we're merely appending/templating the
# content from the rules directories. That's why we ignore BUILD_CHECKS_DIR
Expand Down Expand Up @@ -311,7 +311,7 @@ macro(ssg_build_sce PRODUCT)
endif()
add_custom_target(
generate-internal-${PRODUCT}-sce-metadata.json
DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/checks_from_templates/sce/metadata.json"
DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/checks/sce/metadata.json"
)
endmacro()

Expand Down Expand Up @@ -410,11 +410,17 @@ endmacro()
# evaluation using e.g., OpenSCAP) by combining XCCDF, OVAL, SCE, and OCIL
# content. This relies heavily on the OpenSCAP executable here.
macro(ssg_build_sds PRODUCT)
if(SSG_SCE_ENABLED)
set(COMPOSE_EXTRA_ARGS "--enable-sce")
else()
set(COMPOSE_EXTRA_ARGS "")
endif()

if(SSG_BUILD_SCAP_12_DS)
add_custom_command(
OUTPUT "${CMAKE_BINARY_DIR}/ssg-${PRODUCT}-ds-1.2.xml"
OUTPUT "${CMAKE_BINARY_DIR}/ssg-${PRODUCT}-ds.xml"
COMMAND env "PYTHONPATH=$ENV{PYTHONPATH}" "${PYTHON_EXECUTABLE}" "${SSG_BUILD_SCRIPTS}/compose_ds.py" --xccdf "${CMAKE_BINARY_DIR}/ssg-${PRODUCT}-xccdf.xml" --oval "${CMAKE_BINARY_DIR}/ssg-${PRODUCT}-oval.xml" --ocil "${CMAKE_BINARY_DIR}/ssg-${PRODUCT}-ocil.xml" --cpe-dict "${CMAKE_BINARY_DIR}/ssg-${PRODUCT}-cpe-dictionary.xml" --cpe-oval "${CMAKE_BINARY_DIR}/ssg-${PRODUCT}-cpe-oval.xml" --output-12 "${CMAKE_BINARY_DIR}/ssg-${PRODUCT}-ds-1.2.xml" --output-13 "${CMAKE_BINARY_DIR}/ssg-${PRODUCT}-ds.xml"
COMMAND env "PYTHONPATH=$ENV{PYTHONPATH}" "${PYTHON_EXECUTABLE}" "${SSG_BUILD_SCRIPTS}/compose_ds.py" --xccdf "${CMAKE_BINARY_DIR}/ssg-${PRODUCT}-xccdf.xml" --oval "${CMAKE_BINARY_DIR}/ssg-${PRODUCT}-oval.xml" --ocil "${CMAKE_BINARY_DIR}/ssg-${PRODUCT}-ocil.xml" --cpe-dict "${CMAKE_BINARY_DIR}/ssg-${PRODUCT}-cpe-dictionary.xml" --cpe-oval "${CMAKE_BINARY_DIR}/ssg-${PRODUCT}-cpe-oval.xml" --output-12 "${CMAKE_BINARY_DIR}/ssg-${PRODUCT}-ds-1.2.xml" --output-13 "${CMAKE_BINARY_DIR}/ssg-${PRODUCT}-ds.xml" ${COMPOSE_EXTRA_ARGS}
COMMAND "${XMLLINT_EXECUTABLE}" --nsclean --format --output "${CMAKE_BINARY_DIR}/ssg-${PRODUCT}-ds-1.2.xml" "${CMAKE_BINARY_DIR}/ssg-${PRODUCT}-ds-1.2.xml"
COMMAND "${XMLLINT_EXECUTABLE}" --nsclean --format --output "${CMAKE_BINARY_DIR}/ssg-${PRODUCT}-ds.xml" "${CMAKE_BINARY_DIR}/ssg-${PRODUCT}-ds.xml"
DEPENDS generate-ssg-${PRODUCT}-xccdf.xml
Expand All @@ -431,7 +437,7 @@ macro(ssg_build_sds PRODUCT)
else()
add_custom_command(
OUTPUT "${CMAKE_BINARY_DIR}/ssg-${PRODUCT}-ds.xml"
COMMAND env "PYTHONPATH=$ENV{PYTHONPATH}" "${PYTHON_EXECUTABLE}" "${SSG_BUILD_SCRIPTS}/compose_ds.py" --xccdf "${CMAKE_BINARY_DIR}/ssg-${PRODUCT}-xccdf.xml" --oval "${CMAKE_BINARY_DIR}/ssg-${PRODUCT}-oval.xml" --ocil "${CMAKE_BINARY_DIR}/ssg-${PRODUCT}-ocil.xml" --cpe-dict "${CMAKE_BINARY_DIR}/ssg-${PRODUCT}-cpe-dictionary.xml" --cpe-oval "${CMAKE_BINARY_DIR}/ssg-${PRODUCT}-cpe-oval.xml" --output-13 "${CMAKE_BINARY_DIR}/ssg-${PRODUCT}-ds.xml"
COMMAND env "PYTHONPATH=$ENV{PYTHONPATH}" "${PYTHON_EXECUTABLE}" "${SSG_BUILD_SCRIPTS}/compose_ds.py" --xccdf "${CMAKE_BINARY_DIR}/ssg-${PRODUCT}-xccdf.xml" --oval "${CMAKE_BINARY_DIR}/ssg-${PRODUCT}-oval.xml" --ocil "${CMAKE_BINARY_DIR}/ssg-${PRODUCT}-ocil.xml" --cpe-dict "${CMAKE_BINARY_DIR}/ssg-${PRODUCT}-cpe-dictionary.xml" --cpe-oval "${CMAKE_BINARY_DIR}/ssg-${PRODUCT}-cpe-oval.xml" --output-13 "${CMAKE_BINARY_DIR}/ssg-${PRODUCT}-ds.xml" ${COMPOSE_EXTRA_ARGS}
COMMAND "${XMLLINT_EXECUTABLE}" --nsclean --format --output "${CMAKE_BINARY_DIR}/ssg-${PRODUCT}-ds.xml" "${CMAKE_BINARY_DIR}/ssg-${PRODUCT}-ds.xml"
DEPENDS generate-ssg-${PRODUCT}-xccdf.xml
DEPENDS generate-ssg-${PRODUCT}-oval.xml
Expand Down Expand Up @@ -758,11 +764,6 @@ macro(ssg_build_product PRODUCT)
DESTINATION "${SSG_CONTENT_INSTALL_DIR}")
endif()

if (SSG_SCE_ENABLED)
install(DIRECTORY "${CMAKE_BINARY_DIR}/${PRODUCT}/checks/sce/"
DESTINATION "${SSG_CONTENT_INSTALL_DIR}/${PRODUCT}/checks/sce")
endif()

install(FILES "${CMAKE_BINARY_DIR}/ssg-${PRODUCT}-ds.xml"
DESTINATION "${SSG_CONTENT_INSTALL_DIR}")

Expand Down
2 changes: 2 additions & 0 deletions ssg/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
xhtml_namespace = "http://www.w3.org/1999/xhtml"
xsi_namespace = "http://www.w3.org/2001/XMLSchema-instance"
cat_namespace = "urn:oasis:names:tc:entity:xmlns:xml:catalog"
sce_namespace = "http://open-scap.org/page/SCE_xccdf_stream"
ocil_cs = "http://scap.nist.gov/schema/ocil/2"
xccdf_header = xml_version + "<xccdf>"
xccdf_footer = "</xccdf>"
Expand Down Expand Up @@ -140,6 +141,7 @@
"cpe-dict": "http://cpe.mitre.org/dictionary/2.0",
"cat": cat_namespace,
"cpe-lang": "http://cpe.mitre.org/language/2.0",
"sce": sce_namespace,
}

FIX_TYPE_TO_SYSTEM = {
Expand Down
2 changes: 1 addition & 1 deletion ssg/templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"kubernetes": TemplatingLang("kubernetes", ".yml", TemplateType.REMEDIATION, "kubernetes"),
"oval": TemplatingLang("oval", ".xml", TemplateType.CHECK, "oval"),
"puppet": TemplatingLang("puppet", ".pp", TemplateType.REMEDIATION, "puppet"),
"sce-bash": TemplatingLang("sce-bash", ".sh", TemplateType.REMEDIATION, "sce")
"sce-bash": TemplatingLang("sce-bash", ".sh", TemplateType.CHECK, "sce")
}

PREPROCESSING_FILE_NAME = "template.py"
Expand Down

0 comments on commit a265c67

Please sign in to comment.