Skip to content

Commit

Permalink
Profile resolver selection: XSpec additions and minor XSLT enhancemen…
Browse files Browse the repository at this point in the history
…ts (usnistgov#1101)

* Group scenarios and add edge case scenario
* Group the scenarios that test o:glob-as-regex.
* Add scenario for edge case where input is empty.
* For selection, augment XSpec and update XSLT
* Add XSpec tests for oscal-profile-resolve-select.xsl, mostly at the level of templates and functions.
* Minor enhancements in oscal-profile-resolve-select.xsl:
* Add support for with-parent-controls
* Generate fatal error if resource cannot be fetched
* Provide focused error message if resource has no suitable rlink
* Handle missing matching pattern
* Fix indentation
* Fix scenario that intentionally omits pattern
* Rename o:resource-or-warning as o:resource-or-error
* Attributes, not elements, for "from" and "to"
* Update expected value for 4a3cadf changes in catalog
* The abc-full_catalog.xml file has changed, so the "Loose parameters" test scenario needs adjustment.
* Reduce redundancy in expected metadata
* metadata is copied verbatim, so no need to check details in multiple test scenarios for the match=profile template
* Update verbiage to cross-reference with logged discussion pages
  • Loading branch information
galtm authored and aj-stein-nist committed Jan 10, 2023
1 parent 929005a commit 63def77
Show file tree
Hide file tree
Showing 9 changed files with 1,758 additions and 370 deletions.
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

0 comments on commit 63def77

Please sign in to comment.