fix: validate profile imports against their own catalogs (oscal-cli#250)#282
Conversation
The oscal-profile-import-has-key-include-exclude-control-id constraint used a document-global named index (profile-import-index-control-id) built from each profile import's resolved catalog. With more than one import the index name collides, so only the first import's index is consulted when checking with-id entries on later imports, causing valid references to be reported as missing. Replace the index/index-has-key pair with an inline expect that uses the per-context $resolved-profile-import let binding to look up the referenced control id directly in the catalog resolved for the same import. Adds a regression test that validates a profile importing two separate catalogs (NIST 800-53 rev5 from the downloaded test content plus a local test catalog); previously failed on the second import, now passes.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (4)
✅ Files skipped from review due to trivial changes (3)
📝 WalkthroughWalkthroughReplaces index/key-field based validation for profile imports with an predicate that asserts the referenced control ID exists in the resolved imported catalog, and adds tests and fixtures validating profiles that import two catalogs (including reversed import order). Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related issues
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (2)
src/test/resources/content/issue-250/test-profile.json (1)
12-12: Prefer a fully local fixture path for deterministic test execution.Using
target/download/...couples the regression test to build-side artifact provisioning. Consider replacing this with a local minimal catalog fixture to keep the test hermetic across environments.♻️ Suggested change
- "href": "../../../../../target/download/content/NIST_SP-800-53_rev5_catalog.json", + "href": "test-catalog-ac-1.json",Then add
src/test/resources/content/issue-250/test-catalog-ac-1.jsoncontaining only theac-1control needed by this test.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/test/resources/content/issue-250/test-profile.json` at line 12, Replace the external build-dependent href in test-profile.json (the "href": "../../../../../target/download/content/NIST_SP-800-53_rev5_catalog.json" entry) with a deterministic local fixture path and add the suggested minimal catalog file; specifically change the href to "src/test/resources/content/issue-250/test-catalog-ac-1.json" in test-profile.json and create src/test/resources/content/issue-250/test-catalog-ac-1.json containing only the AC-1 control required by the test so the test becomes hermetic and does not depend on target/download artifacts.src/test/java/dev/metaschema/oscal/lib/validation/OscalValidationTest.java (1)
115-134: Add a reversed-import-order variant to lock in the original failure mode.Nice regression coverage. Consider adding a companion case with the two imports reversed, since order sensitivity was part of the reported symptom.
✅ Small extension to strengthen regression coverage
`@Test` void testValidateProfileWithMultipleImports() throws MetaschemaException, IOException, URISyntaxException, ConstraintValidationException { @@ assertTrue(validationResult.isPassing()); } + + `@Test` + void testValidateProfileWithMultipleImportsReversedOrder() + throws MetaschemaException, IOException, URISyntaxException, ConstraintValidationException { + IBindingContext bindingContext = OscalBindingContext.newInstance(); + IValidationResult validationResult = bindingContext.validateWithConstraints( + Paths.get("src/test/resources/content/issue-250/test-profile-reversed.json").toUri(), + null); + assertTrue(validationResult.isPassing()); + }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/test/java/dev/metaschema/oscal/lib/validation/OscalValidationTest.java` around lines 115 - 134, Add a companion test to lock in the original failure: create a new test method (e.g., testValidateProfileWithMultipleImportsReversed) in OscalValidationTest that mirrors testValidateProfileWithMultipleImports but validates the profile whose import order is reversed, using the same IBindingContext (OscalBindingContext.newInstance()) and validateWithConstraints call, then assert the validationResult is passing; ensure you add the reversed-import test resource (same catalogs but imports swapped) and reuse the same LoggingValidationHandler/assertTrue checks so the regression is caught if import-order sensitivity reappears.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@src/test/java/dev/metaschema/oscal/lib/validation/OscalValidationTest.java`:
- Around line 115-134: Add a companion test to lock in the original failure:
create a new test method (e.g., testValidateProfileWithMultipleImportsReversed)
in OscalValidationTest that mirrors testValidateProfileWithMultipleImports but
validates the profile whose import order is reversed, using the same
IBindingContext (OscalBindingContext.newInstance()) and validateWithConstraints
call, then assert the validationResult is passing; ensure you add the
reversed-import test resource (same catalogs but imports swapped) and reuse the
same LoggingValidationHandler/assertTrue checks so the regression is caught if
import-order sensitivity reappears.
In `@src/test/resources/content/issue-250/test-profile.json`:
- Line 12: Replace the external build-dependent href in test-profile.json (the
"href":
"../../../../../target/download/content/NIST_SP-800-53_rev5_catalog.json" entry)
with a deterministic local fixture path and add the suggested minimal catalog
file; specifically change the href to
"src/test/resources/content/issue-250/test-catalog-ac-1.json" in
test-profile.json and create
src/test/resources/content/issue-250/test-catalog-ac-1.json containing only the
AC-1 control required by the test so the test becomes hermetic and does not
depend on target/download artifacts.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: eb651609-fd7d-4796-8e40-16b85a8a3046
📒 Files selected for processing (4)
src/main/metaschema-constraints/oscal-external-constraints.xmlsrc/test/java/dev/metaschema/oscal/lib/validation/OscalValidationTest.javasrc/test/resources/content/issue-250/test-catalog.jsonsrc/test/resources/content/issue-250/test-profile.json
Replaces the build-download NIST catalog dependency with a minimal local AC-1 fixture so the test is independent of the download-maven plugin running during test-compile and works regardless of build phase ordering. Adds testValidateProfileWithMultipleImportsReversed to exercise the exact pre-fix asymmetry described in the original bug report (errors followed whichever catalog was imported second), extracting a shared assertMultiImportProfileValidates helper.
c7dede7
into
metaschema-framework:develop
Closes metaschema-framework/oscal-cli#250
Summary
Fixes metaschema-framework/oscal-cli#250: when a profile imports two or more catalogs and uses
with-idsrather thaninclude-all, validation incorrectly reports control identifiers on the second (and later) imports as missing.Root cause
In
src/main/metaschema-constraints/oscal-external-constraints.xml, the/profile/importcontext defined:Metaschema index names are document-global. With two imports, both instances of the constraint try to build an index with the same name — the validator emits a "Duplicate index" finding on the second import, the second index is discarded, and subsequent
with-idlookups resolve against the first import's catalog only. Every id from the second import's catalog is then reported missing.Fix
Replace the index/index-has-key pair with an inline
expectthat uses the per-import$resolved-profile-importletbinding to perform the lookup directly:Each import evaluates its
testagainst the catalog resolved for the same import, with no shared global state.Test plan
OscalValidationTest#testValidateProfileWithMultipleImports— builds a two-import profile (one import uses the build-downloaded NIST 800-53 rev5 catalog attarget/download/content/NIST_SP-800-53_rev5_catalog.json, the other a minimal local catalog with a singletest-01control). Fails on pre-fix, passes on post-fix.OscalValidationTest#testValidateProfileWithMissingControlsstill correctly reports invalid control ids — the newexpectreplaces the missing-control detection end-to-end.mvn test— 47 tests run, 0 failures, 0 errors, 3 skipped.Summary by CodeRabbit
Bug Fixes
Tests