liboscal-java icon indicating copy to clipboard operation
liboscal-java copied to clipboard

Metaschema Validation Has Findings For Valid Component

Open lstanden opened this issue 1 year ago • 5 comments

Describe the bug

Valid XML component-definitions are returning findings.

Add the following to src/test/resources/content/component-def.xml

<?xml version="1.0" encoding="UTF-8"?>
<component-definition xmlns="http://csrc.nist.gov/ns/oscal/1.0"
         uuid="6c5149e8-f3a6-437c-8035-025e9b5fc0bc">
    <metadata>
        <title>Test Component Definition</title>
        <last-modified>2023-11-30T01:01:01Z</last-modified>
        <version>1.0</version>
        <oscal-version>1.1.1</oscal-version>
    </metadata>
    <component uuid="849e5b94-5ccb-49c4-97ab-56ac391a8b37" type="service">
        <title>Test Service</title>
        <description></description>
        <protocol uuid="d25e47d8-b5da-475f-854b-6ce292fefaa7" name="http">
            <port-range start="80" end="80" transport="TCP"/>
        </protocol>
    </component>
</component-definition>

Add the following test function to src/test/java/gov/nist/secauto/oscal/java/ExamplesTest.java:

    @Test
    void testComponentDefinition() throws IOException {
        OscalBindingContext bindingContext = OscalBindingContext.instance();
        IBoundLoader loader = bindingContext.newBoundLoader();

        IDocumentNodeItem nodeItem = loader.loadAsNodeItem(ObjectUtils.notNull(Paths.get("src/test/resources/content/component-def.xml")));

        DynamicContext dynamicContext = new StaticContext().newDynamicContext();
        dynamicContext.setDocumentLoader(loader);

        FindingCollectingConstraintValidationHandler handler = new FindingCollectingConstraintValidationHandler();
        DefaultConstraintValidator validator = new DefaultConstraintValidator(dynamicContext, handler);

        validator.validate(nodeItem);
        validator.finalizeValidation();

        assertTrue(handler.isPassing());
        assertTrue(handler.getFindings().isEmpty());
    }

The following log output is shown:

16:38:41.827 [main] WARN  gov.nist.secauto.metaschema.model.common.constraint.LoggingConstraintValidationHandler.logConstraint(LoggingConstraintValidationHandler.java:121) - WARNING: (/component-definition/component[1]/protocol[1]/port-range[1]) A start port exists, but an end point does not. To define a single port, the start and end should be the same value.
16:38:41.831 [main] WARN  gov.nist.secauto.metaschema.model.common.constraint.LoggingConstraintValidationHandler.logConstraint(LoggingConstraintValidationHandler.java:121) - WARNING: (/component-definition/component[1]/protocol[1]/port-range[1]) An end point exists, but a start port does not. To define a single port, the start and end should be the same value.

Who is the bug affecting?

Anyone trying to validate component-definitions. Presumably this applies to other OSCAL types too.

What is affected by this bug?

Findings are returned despite valid input. Doesn't matter if the input is JSON, YAML, or XML.

When does this occur?

See example

How do we replicate the issue?

Please see detailed unit test above.

Expected behavior (i.e. solution)

This particular example should return no findings, as it meets all the metaschema requirements.

Other Comments

lstanden avatar Dec 01 '23 00:12 lstanden

This appears to relate to the port range constraint in OSCAL. The &lt; entity used might be causing the issue. We need to investigate this.

david-waltermire avatar Dec 01 '23 04:12 david-waltermire

It's actually these two tests that fail:

exists(@start) and not(exists(@end))
not(exists(@start)) and exists(@end)

I've tested both of these, and they work as expected:

exists(@start) and exists(@end)
@start &lt;= @end

lstanden avatar Dec 01 '23 07:12 lstanden

Question: if @start or @end is not given or not given correctly (so as to be comparable), is that an error? One might say yes, but it is failing for a different reason; one could also test for that separately.

Indeed since the (non-negative) integer form is already validated separately, one might argue this rule should pass if @start or @end is not formed correctly, since that aspect of conformance is already tested with the data type. So:

not((@start castable as xs:integer) and (@end castable as xs:integer)) or (@end >= @start)

fails only if the numbers are given 'correctly' (as integers), but wrong (as out of order). But if either is missing or not comparable, we get a failure on its value, not this error.

nb > does not typically need to be escaped in XML (although it often is).

wendellpiez avatar Dec 01 '23 15:12 wendellpiez

I will review the underlying metaschema-java code, but I do not believe Metapath (as implemented in the Java version; the spec is very underdefined in this bit 😆) has castable yet but I will have to check. I told Dave I would look into the root cause, so more to follow.

aj-stein-nist avatar Dec 01 '23 15:12 aj-stein-nist

Cool. @start castable as xs:integer might be replaced (XPath 1.0-style) with

number(@start) != number(@start)

which tests true only if number(@start) is NaN, which is the only thing that comes back true as 'not-equal' != with itself. (Of course that is XPath not Metapath or this engine, so I can't speak for what will happen here either.) This is decimal-format not integer checking but to a similar effect.

Not advancing a position on whether to prefer such a thing if castable as is not in the library, only noting there are (more) options.

wendellpiez avatar Dec 01 '23 20:12 wendellpiez