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 8cc8607 commit 0e3591b
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 16 deletions.
76 changes: 72 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,70 @@ def mangle_path(path):
return path


# When SCE support is enabled, retrieve the SCE checks and embed them in the datastream.
# Collect every SCE check, extract the path to the script content, and include
# every scripts in the datastream.
def collect_sce_checks(datastreamtree, checklists, refdir):
ds_ns = '{' + datastream_namespace + '}'
xccdf_ns = '{' + XCCDF12_NS + '}'
sce_ns = '{' + sce_namespace + '}'
cat_ns = '{' + cat_namespace + '}'
xlink_href = '{' + xlink_namespace + '}' + 'href'

checklists_cref_location = '/'.join([
'./',
ds_ns + 'checklists',
ds_ns + 'component-ref'
])
checklists_component_ref = datastreamtree.find(checklists_cref_location)
# The component ID is the component-ref href without leading '#'
checklist_component_id = checklists_component_ref.get(xlink_href)[1:]

# Locate the <xccdf:check> inside <xccdf:Rule> and detect the SCE checks
checks_location = '/'.join([
'./',
ds_ns + "component[@id='{}']".format(checklist_component_id),
xccdf_ns + 'Rule',
xccdf_ns + "check[@system='{}']".format(SCE_SYSTEM),
xccdf_ns + 'check-content-ref'
])
checks = datastreamtree.findall(checks_location)

# 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 = "scap_{}_ecomp_{}".format(ID_NS, mangle_path(file))
component = ET.SubElement(
datastreamtree, ds_ns + 'extended-component',
attrib={
'id': component_id,
'timestamp': get_timestamp(path)
})
# Append the file content
script_data = ET.SubElement(component, sce_ns + 'script')
with open(path, 'rt', encoding='utf8') as fd:
script_data.text = fd.read()

# Create a component reference to map the checkslist to the extended component
component_ref_id = "scap_{}_cref_{}".format(ID_NS, mangle_path(file))
component_ref = ET.SubElement(
checklists, ds_ns + 'component-ref',
attrib={
'id': component_ref_id,
xlink_href: '#' + component_id
})

# Add the component reference to the catalog of XCCDF checklists
catalog = checklists_component_ref.find(cat_ns + 'catalog')
uri = ET.SubElement(
catalog, cat_ns + 'uri',
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 +194,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 +245,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 +267,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 +277,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 +287,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 0e3591b

Please sign in to comment.