Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Profile resolver selection: XSpec additions and minor XSLT enhancements #1101

Merged
merged 9 commits into from
Feb 4, 2022
76 changes: 43 additions & 33 deletions src/utils/util/resolver-pipeline/oscal-profile-resolve-select.xsl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
<xsl:stylesheet version="3.0"
xmlns="http://csrc.nist.gov/ns/oscal/1.0"
xmlns:o="http://csrc.nist.gov/ns/oscal/1.0"
xmlns:opr="http://csrc.nist.gov/ns/oscal/profile-resolution"
Expand All @@ -10,7 +10,7 @@
xpath-default-namespace="http://csrc.nist.gov/ns/oscal/1.0">

<!-- Purpose: perform operations supporting the selection stage of OSCAL profile resolution. -->
<!-- XSLT version: 2.0 -->
<!-- XSLT version: 3.0 -->

<xsl:strip-space elements="catalog group control param guideline select part
metadata back-matter annotation party person org rlink address resource role responsible-party citation
Expand Down Expand Up @@ -83,7 +83,6 @@
</metadata>
</xsl:template>-->

<xsl:key name="cross-reference" match="resource" use="'#' || @id"/>
<xsl:key name="cross-reference" match="resource" use="'#' || @uuid"/>

<xsl:template priority="2" mode="o:select" match="import[starts-with(@href,'#')]">
Expand All @@ -94,7 +93,16 @@

<xsl:template match="resource" mode="o:import">
<xsl:variable name="linked-xml" select="child::rlink[ends-with(@href,'.xml') or matches(@media-type,'xml')][1]"/>
<xsl:apply-templates mode="o:select" select="o:resource-or-warning($linked-xml/@href)"/>
<xsl:choose>
<xsl:when test="exists($linked-xml)">
<xsl:apply-templates mode="o:select" select="o:resource-or-error($linked-xml/@href)"/>
</xsl:when>
<xsl:otherwise>
<xsl:message terminate="yes"
expand-text="yes">Document not acquired for resource with uuid {@uuid
}: No rlink with media-type='xml' or href ending with '.xml'</xsl:message>
</xsl:otherwise>
</xsl:choose>
</xsl:template>

<xsl:template priority="1" mode="o:select" match="import">
Expand All @@ -104,7 +112,7 @@
<xsl:apply-templates select="$linked-resource" mode="o:import">
<xsl:with-param name="import-instruction" select="." tunnel="yes"/>
</xsl:apply-templates>
<xsl:apply-templates mode="#current" select="o:resource-or-warning(@href)">
<xsl:apply-templates mode="#current" select="o:resource-or-error(@href)">
<xsl:with-param name="import-instruction" select="." tunnel="yes"/>
</xsl:apply-templates>
</xsl:template>
Expand All @@ -118,10 +126,11 @@
</xsl:copy>
</xsl:template>

<xsl:template name="add-process-id">
<xsl:template name="add-process-id" as="attribute(opr:id)">
<xsl:param name="context" select="." as="element()"/>
<xsl:attribute name="opr:id" namespace="http://csrc.nist.gov/ns/oscal/profile-resolution">
<xsl:value-of
select="concat(opr:catalog-identifier(/o:catalog), '#', (@id, generate-id())[1])"/>
select="concat(opr:catalog-identifier($context/root()/o:catalog), '#', $context/(@id, generate-id())[1])"/>
</xsl:attribute>
</xsl:template>

Expand All @@ -131,7 +140,7 @@
</xsl:function>

<!-- A control is included if it is selected by the provided import instruction -->
<xsl:template match="control" mode="o:select">
<xsl:template match="control" mode="o:select" as="element(o:control)?">
<xsl:param name="import-instruction" tunnel="yes" required="yes"/>
<xsl:if test="o:selects($import-instruction,.)">
<xsl:copy copy-namespaces="no">
Expand Down Expand Up @@ -174,22 +183,30 @@
<xsl:sequence select="exists($importing/include-all)"/>
<xsl:sequence select="some $c in ($importing/include-controls/with-id)
satisfies ($c = $candidate/@id)"/>
<xsl:sequence select="some $c in ($importing/include-controls[o:calls-parents(.)]/with-id)
satisfies ($c = $candidate/descendant::control/@id)"/>
<xsl:sequence select="some $c in ($importing/include-controls[o:calls-children(.)]/with-id)
satisfies ($c = $candidate/ancestor::control/@id)"/>
<xsl:sequence select="some $m in ($importing/include-controls/matching)
<xsl:sequence select="some $m in ($importing/include-controls/matching[@pattern != ''])
satisfies (matches($candidate/@id,$m/@pattern/o:glob-as-regex(string(.)) ))"/>
<xsl:sequence select="some $m in ($importing/include/matching[o:calls-children(.)])
satisfies (matches($candidate/ancestor::control/@id,$m/@pattern/o:glob-as-regex(string(.))))"/>
<xsl:sequence select="some $m in ($importing/include-controls[o:calls-parents(.)]/matching[@pattern != '']), $a in $candidate/descendant::control
satisfies (matches($a/@id,$m/@pattern/o:glob-as-regex(string(.))))"/>
<xsl:sequence select="some $m in ($importing/include-controls[o:calls-children(.)]/matching[@pattern != '']), $a in $candidate/ancestor::control
satisfies (matches($a/@id,$m/@pattern/o:glob-as-regex(string(.))))"/>
</xsl:variable>
<xsl:variable name="exclude-reasons" as="xs:boolean+">
<xsl:sequence select="exists($candidate/parent::control) and $importing/include-all/@with-child-controls='no'"/>
<xsl:sequence select="some $c in ($importing/exclude-controls/with-id) satisfies ($c = $candidate/@id)"/>
<xsl:sequence select="some $c in ($importing/exclude-controls[o:calls-parents(.)]/with-id)
satisfies ($c = $candidate/descendant::control/@id)"/>
<xsl:sequence select="some $c in ($importing/exclude-controls[o:calls-children(.)]/with-id)
satisfies ($c = $candidate/ancestor::control/@id)"/>
<xsl:sequence select="some $m in ($importing/exclude-controls/matching)
<xsl:sequence select="some $m in ($importing/exclude-controls/matching[@pattern != ''])
satisfies (matches($candidate/@id,$m/@pattern/o:glob-as-regex(string(.))))"/>
<xsl:sequence select="some $m in ($importing/exclude-controls[o:calls-children(.)]/matcjomg)
satisfies (matches($candidate/ancestor::control/@id,$m/@pattern/o:glob-as-regex(string(.))))"/>
<xsl:sequence select="some $m in ($importing/exclude-controls[o:calls-parents(.)]/matching[@pattern != '']), $a in $candidate/descendant::control
satisfies (matches($a/@id,$m/@pattern/o:glob-as-regex(string(.))))"/>
<xsl:sequence select="some $m in ($importing/exclude-controls[o:calls-children(.)]/matching[@pattern != '']), $a in $candidate/ancestor::control
satisfies (matches($a/@id,$m/@pattern/o:glob-as-regex(string(.))))"/>
</xsl:variable>
<!-- predicate [.] filters reasons as booleans -->
<xsl:sequence select="exists($include-reasons[.]) and empty($exclude-reasons[.])"/>
Expand All @@ -200,26 +217,19 @@
<xsl:sequence select="$caller/@with-child-controls='yes'"/>
</xsl:function>

<!-- Returns a document when found, a <opr:warning> element when not. -->
<xsl:function name="o:resource-or-warning" as="document-node()">
<xsl:function name="o:calls-parents" as="xs:boolean">
<xsl:param name="caller" as="element()"/>
<xsl:sequence select="not($caller/@with-parent-controls='no')"/>
</xsl:function>

<!-- Returns a document when found, a fatal error when not. -->
<xsl:function name="o:resource-or-error" as="document-node()">
<xsl:param name="href" as="attribute(href)"/>
<xsl:variable name="resolved-href" select="resolve-uri($href,$href/base-uri())"/>
<xsl:choose>
<xsl:when test="doc-available($resolved-href)">
<xsl:sequence select="document($resolved-href)"/>
</xsl:when>
<xsl:otherwise>
<xsl:document>
<opr:WARNING>
<xsl:text>Document not acquired: '</xsl:text>
<xsl:value-of select="$href"/>
<xsl:text>' resolved as '</xsl:text>
<xsl:value-of select="$resolved-href"/>
<xsl:text>' (as OSCAL XML)</xsl:text>
</opr:WARNING>
</xsl:document>
</xsl:otherwise>
</xsl:choose>
<xsl:assert test="doc-available($resolved-href)"
expand-text="yes">Document not acquired: {$href} resolved as {
$resolved-href} (as OSCAL XML)</xsl:assert>
<xsl:sequence select="document($resolved-href)"/>
</xsl:function>

<xsl:include href="oscal-profile-resolve-functions.xsl"/>
Expand All @@ -237,7 +247,7 @@
<xsl:variable name="runtime" as="map(xs:string, item())">
<xsl:map>
<xsl:map-entry key="'xslt-version'" select="3.0"/>
<xsl:map-entry key="'stylesheet-location'" select="'../oscal-profile-RESOLVE.xsl'"/>
<xsl:map-entry key="'stylesheet-location'" select="'oscal-profile-RESOLVE.xsl'"/>
<xsl:map-entry key="'source-node'" select="root($profile)"/>
<xsl:map-entry key="'stylesheet-params'" select="$runtime-params"/>
</xsl:map>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<catalog xmlns="http://csrc.nist.gov/ns/oscal/1.0"/>
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<catalog xmlns="http://csrc.nist.gov/ns/oscal/1.0" uuid="xmlcat"/>
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE x:description [
<!ENTITY filedir "file:/C:/Users/wap1/Documents/usnistgov/OSCAL/src/specifications/profile-resolution/profile-resolution-examples/catalogs" >
]>
<x:description xmlns="http://csrc.nist.gov/ns/oscal/1.0"
xmlns:o="http://csrc.nist.gov/ns/oscal/1.0"
xmlns:opr="http://csrc.nist.gov/ns/oscal/profile-resolution"
xmlns:x="http://www.jenitennison.com/xslt/xspec"
stylesheet="../../oscal-profile-resolve-select.xsl">
<x:scenario label="Tests for o:glob-as-regex function">
<x:scenario label="Simple string">
<x:call function="o:glob-as-regex">
<x:param>ac</x:param>
Expand All @@ -30,5 +28,12 @@
<x:param>ac-1(*)</x:param>
</x:call>
<x:expect label="Anchored and escaped with substitution" select="'^ac-1\(.*\)$'"/>
</x:scenario>
<x:scenario label="Empty string (degenerate case)">
<x:call function="o:glob-as-regex">
<x:param select="''"/>
</x:call>
<x:expect label="Anchored empty string" select="'^$'"/>
</x:scenario>
</x:scenario>
</x:description>
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml-model href="../../../../../specifications/profile-resolution/example-checkup.sch" type="application/xml" schematypens="http://purl.oclc.org/dsdl/schematron"?>
<!-- Modified by conversion XSLT 2021-04-05T11:22:08.131-04:00 - RC2 OSCAL becomes RC3 OSCAL -->
<profile xmlns="http://csrc.nist.gov/ns/oscal/1.0"
uuid="427f8c54-c3af-4ca3-a92c-f6abaa015ba5">
<metadata>
<title>Test Profile with Nonstandard File Name Extension in resource/rlink</title>
<last-modified>2020-05-30T14:39:37.3-04:00</last-modified>
<version>1.0</version>
<oscal-version>1.0.0-rc2</oscal-version>
</metadata>
<import href="#0050231f-4fd0-43d6-8fa0-431367cd83e1">
<include-all/>
</import>
<back-matter>
<resource uuid="0050231f-4fd0-43d6-8fa0-431367cd83e1">
<rlink href="https://some-non-xml-url"/>
<rlink href="catalog-nonstandard-file-name-ext.xmlcat" media-type="xml"/>
</resource>
<resource uuid="0050231f-4fd0-43d6-8fa0-431367cd83e1">
<!-- Duplicate uuid is intentional, for testing template with
mode="o:select" match="import[starts-with(@href,'#')]" -->
<rlink href="catalog-nonstandard-file-name-ext.xmlcat" media-type="xml"/>
</resource>
</back-matter>
</profile>
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml-model href="../../../../../specifications/profile-resolution/example-checkup.sch" type="application/xml" schematypens="http://purl.oclc.org/dsdl/schematron"?>
<!-- Modified by conversion XSLT 2021-04-05T11:22:08.131-04:00 - RC2 OSCAL becomes RC3 OSCAL -->
<profile xmlns="http://csrc.nist.gov/ns/oscal/1.0"
uuid="427f8c54-c3af-4ca3-a92c-f6abaa015ba5">
<metadata>
<title>Test Profile with Nonstandard File Name Extension in resource/rlink</title>
<last-modified>2020-05-30T14:39:37.3-04:00</last-modified>
<version>1.0</version>
<oscal-version>1.0.0-rc2</oscal-version>
</metadata>
<import href="#0050231f-4fd0-43d6-8fa0-431367cd83e1">
<include-all/>
</import>
<back-matter>
<resource uuid="0050231f-4fd0-43d6-8fa0-431367cd83e1">
<rlink href="catalog-nonstandard-file-name-ext.xmlcat" media-type="xml"/>
<rlink href="catalog-no-uuid.xml"/>
</resource>
</back-matter>
</profile>
Loading