Skip to content

Conversation

@david-waltermire
Copy link
Contributor

Committer Notes

More refactoring, Javadoc creation, and cleanup of PMD, Java compile, and Spotbugs errors.

All Submissions:

By submitting a pull request, you are agreeing to provide this contribution under the CC0 1.0 Universal public domain dedication.

Changes to Core Features:

  • Have you added an explanation of what your changes do and why you'd like us to include them?
  • Have you written new tests for your core changes, as applicable?
  • Have you included examples of how to use your new feature(s)?
  • Have you updated all website and readme documentation affected by the changes you made?

@david-waltermire david-waltermire marked this pull request as draft October 20, 2024 19:28
@coderabbitai
Copy link

coderabbitai bot commented Oct 20, 2024

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

📝 Walkthrough
📝 Walkthrough

Walkthrough

The changes across various components include updates to GitHub Actions workflows, modifications to Maven project files, enhancements to Java classes and interfaces, and the introduction of new test cases. Key updates involve the addition of input parameters for workflows, improvements in concurrency control using ReadWriteLock, and structural refinements in command implementations for better error handling and logging. Additionally, new XML and JSON files are introduced for testing purposes, and existing test classes are updated to ensure robust validation of functionalities.

Changes

File Path Change Summary
.github/workflows/build.yml Added input parameters for workflow_dispatch and updated environment variables. Updated action versions.
cli-processor/pom.xml Updated parent version from 1.2.0 to 1.3.0-SNAPSHOT and SCM tag from v1.2.0 to HEAD.
cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/CLIProcessor.java Enhanced help message formatting and adjusted internal logic for command processing.
cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/command/ICommand.java Updated filtering mechanism in requiredExtraArgumentsCount method from lambda to method reference.
cli-processor/src/test/java/gov/nist/secauto/metaschema/cli/processor/ExitCodeTest.java Added comments for clarity; no changes to test logic.
core/pom.xml Updated parent version from 1.2.0 to 1.3.0-SNAPSHOT and SCM tag from v1.2.0 to HEAD.
core/src/main/java/gov/nist/secauto/metaschema/core/datatype/AbstractDataTypeProvider.java Replaced ReentrantLock with ReadWriteLock for better concurrency.
core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/MetaschemaDataTypeProvider.java Updated @Deprecated annotation for NCNAME constant.
core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/MarkupXmlEventWriter.java Changed eventFactory visibility from protected to private.
core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/AbstractConstraintBuilder.java Introduced a new abstract class for constraint builders with fluent interface methods.
core/src/test/java/gov/nist/secauto/metaschema/core/model/constraint/ExternalConstraintsModulePostProcessorTest.java New test class added to validate functionality of ExternalConstraintsModulePostProcessor.
core/src/test/resources/content/issue184-metaschema.xml New XML file defining a metaschema structure.
metaschema-cli/pom.xml Updated parent version from 1.2.0 to 1.3.0-SNAPSHOT and SCM tag from v1.2.0 to HEAD.
metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/ConvertContentUsingModuleCommand.java New command for converting resources based on Metaschema module.
metaschema-testing/pom.xml Updated parent version from 1.2.0 to 1.3.0-SNAPSHOT and SCM tag from v1.2.0 to HEAD.
metaschema-testing/src/test/java/gov/nist/secauto/metaschema/databind/DefaultBoundLoaderTest.java New test class added to validate loading of Metaschema modules.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant CLI as Command Line Interface
    participant Executor as Command Executor
    participant ModuleLoader as Module Loader
    participant BindingContext as Binding Context

    User->>CLI: Execute command
    CLI->>Executor: Validate options
    Executor->>ModuleLoader: Load module
    ModuleLoader->>BindingContext: Get binding context
    BindingContext-->>ModuleLoader: Return context
    ModuleLoader-->>Executor: Return loaded module
    Executor-->>CLI: Execute command logic
    CLI-->>User: Return results
Loading

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Inline review comments failed to post. This is likely due to GitHub's limits when posting large numbers of comments.

🛑 Comments failed to post (56)
core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/node/IFeatureOrhpanedDefinitionNodeItem.java (1)

18-18: 💡 Codebase verification

⚠️ Potential issue

Typo confirmed in interface name and its references

The interface name IFeatureOrhpanedDefinitionNodeItem is found in the following files:

  • core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/node/IFeatureOrhpanedDefinitionModelNodeItem.java
  • core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/node/IFeatureOrhpanedDefinitionNodeItem.java
  • core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/node/AbstractDefinitionNodeItem.java

Please update all occurrences to IFeatureOrphanedDefinitionNodeItem.

🔗 Analysis chain

Fix typo in interface name

There's a typo in the interface name: "Orhpaned" should be "Orphaned".

Please apply the following change:

-public interface IFeatureOrhpanedDefinitionNodeItem<D extends IDefinition, I extends INamedInstance>
+public interface IFeatureOrphanedDefinitionNodeItem<D extends IDefinition, I extends INamedInstance>

Don't forget to update any references to this interface in other parts of the codebase.

To find other occurrences of this interface name, run the following command:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for occurrences of the misspelled interface name
rg "IFeatureOrhpanedDefinitionNodeItem"

Length of output: 778

databind/src/test/resources/content/issue187-metaschema.xml (1)

9-21: 💡 Codebase verification

Potential Infinite Recursion and Inconsistent group-as Configurations Detected.

  • All references to assembly "a" use max-occurs="unbounded", which may lead to infinite recursion if not properly controlled.
  • Inconsistent use of group-as names ("as" and "bs" in issue187-metaschema.xml vs. only "bs" in issue184-metaschema.xml) could cause unexpected behavior.
🔗 Analysis chain

Verify the recursive assembly reference and group-as usage.

The define-assembly structure is generally correct, but there are two points that require attention:

  1. Recursive Reference: The assembly "a" references itself within its model. This creates a recursive structure that could lead to infinite nesting if not properly handled in the implementation.

  2. Different group-as for the same assembly: The same assembly "a" is referenced twice with different group-as configurations. While this is syntactically correct, ensure that this is the intended behavior and that the implementing code can handle this structure correctly.

To verify the usage of the "a" assembly across the codebase, run the following script:

This will help ensure that the recursive structure and different group-as configurations are used consistently across the project.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Search for usage of assembly "a" and its group-as configurations

# Search for references to assembly "a"
echo "References to assembly 'a':"
rg -p "ref=\"a\"" --type xml

# Search for group-as configurations
echo "\nGroup-as configurations for 'a':"
rg -p "<group-as.*name=\"(as|bs)\"" --type xml

Length of output: 831


Script:

#!/bin/bash
# Description: Verify all group-as configurations for assembly "a" and check for consistent usage

# Search for all group-as names associated with assembly "a"
echo "All group-as names for assembly 'a':"
rg -p '<assembly ref="a".*?<group-as.*name="([^"]+)"' --type xml | gawk -F'name="' '{print $2}' | cut -d'"' -f1 | sort | uniq

# Check for potential infinite recursion by ensuring max-occurs is set appropriately
echo "\nChecking max-occurs for assembly 'a' references to prevent infinite recursion:"
rg -p '<assembly ref="a".*?max-occurs="([^"]+)"' --type xml

Length of output: 800

databind/src/test/java/gov/nist/secauto/metaschema/databind/io/DefaultBoundLoaderTest.java (1)

26-44: 🛠️ Refactor suggestion

Consider enhancing test robustness and coverage

While the test effectively covers the basic functionality, consider the following enhancements:

  1. Add error handling tests to ensure exceptions are properly thrown and handled for invalid inputs.
  2. Implement resource cleanup to remove temporary directories after the test.
  3. Parameterize the test to cover multiple scenarios with different input files and Metapath expressions.

Here's an example of how you might implement these suggestions:

@ParameterizedTest
@CsvSource({
    "issue187-metaschema.xml, issue187-instance.xml, //a//b, 8",
    // Add more test cases here
})
void testMetapathEvaluationOnLoadedXmlDocument(String metaschemaFile, String instanceFile, 
                                               String metapathExpression, int expectedResultSize) 
        throws IOException, MetaschemaException {
    Path tempDir = null;
    try {
        URL metaschemaUrl = getClass().getResource("/content/" + metaschemaFile);
        URL instanceUrl = getClass().getResource("/content/" + instanceFile);

        IModule module = new ModuleLoader().load(Paths.get(metaschemaUrl.toURI()));

        IBindingContext bindingContext = IBindingContext.instance();
        tempDir = Files.createTempDirectory(Paths.get("target"), "modules-");
        bindingContext.registerModule(module, tempDir);

        IBoundLoader loader = bindingContext.newBoundLoader();
        IDocumentNodeItem docItem = loader.loadAsNodeItem(Paths.get(instanceUrl.toURI()));

        MetapathExpression metapath = MetapathExpression.compile(metapathExpression, docItem.getStaticContext());
        ISequence<?> result = metapath.evaluate(docItem);

        assertEquals(expectedResultSize, result.size(), 
                     String.format("Expected %d elements for expression '%s'", expectedResultSize, metapathExpression));
    } finally {
        // Cleanup temporary directory
        if (tempDir != null) {
            Files.walk(tempDir)
                 .sorted(Comparator.reverseOrder())
                 .map(Path::toFile)
                 .forEach(File::delete);
        }
    }
}

@Test
void testInvalidMetapathExpression() {
    // Test that an invalid Metapath expression throws an appropriate exception
    // ...
}

@Test
void testInvalidXmlDocument() {
    // Test loading an invalid XML document
    // ...
}

This refactored version parameterizes the test, adds cleanup for temporary resources, and suggests additional error handling tests. It allows for easier addition of more test cases and improves overall test robustness.

🧰 Tools
🪛 ast-grep

[warning] 28-28: Detected a cookie where the HttpOnly flag is either missing or disabled. The HttpOnly cookie flag instructs the browser to forbid client-side JavaScript to read the cookie. If JavaScript interaction is required, you can ignore this finding. However, set the HttpOnly flag to true` in all other cases.
Context: (Paths.get("src/test/resources/content/issue187-metaschema.xml"))
Note: [CWE-1004]: Sensitive Cookie Without 'HttpOnly' Flag [OWASP A05:2021]: Security Misconfiguration [REFERENCES]
- https://owasp.org/Top10/A05_2021-Security_Misconfiguration


[warning] 32-32: Detected a cookie where the HttpOnly flag is either missing or disabled. The HttpOnly cookie flag instructs the browser to forbid client-side JavaScript to read the cookie. If JavaScript interaction is required, you can ignore this finding. However, set the HttpOnly flag to true` in all other cases.
Context: (module, Files.createTempDirectory(Paths.get("target"), "modules-"))
Note: [CWE-1004]: Sensitive Cookie Without 'HttpOnly' Flag [OWASP A05:2021]: Security Misconfiguration [REFERENCES]
- https://owasp.org/Top10/A05_2021-Security_Misconfiguration


[warning] 32-32: Detected a cookie where the HttpOnly flag is either missing or disabled. The HttpOnly cookie flag instructs the browser to forbid client-side JavaScript to read the cookie. If JavaScript interaction is required, you can ignore this finding. However, set the HttpOnly flag to true` in all other cases.
Context: (Paths.get("target"), "modules-")
Note: [CWE-1004]: Sensitive Cookie Without 'HttpOnly' Flag [OWASP A05:2021]: Security Misconfiguration [REFERENCES]
- https://owasp.org/Top10/A05_2021-Security_Misconfiguration


[warning] 36-36: Detected a cookie where the HttpOnly flag is either missing or disabled. The HttpOnly cookie flag instructs the browser to forbid client-side JavaScript to read the cookie. If JavaScript interaction is required, you can ignore this finding. However, set the HttpOnly flag to true` in all other cases.
Context: (Paths.get("src/test/resources/content/issue187-instance.xml"))
Note: [CWE-1004]: Sensitive Cookie Without 'HttpOnly' Flag [OWASP A05:2021]: Security Misconfiguration [REFERENCES]
- https://owasp.org/Top10/A05_2021-Security_Misconfiguration


[warning] 28-28: Detected a cookie where the Secure flag is either missing or disabled. The Secure cookie flag instructs the browser to forbid sending the cookie over an insecure HTTP request. Set the Secure flag to true so the cookie will only be sent over HTTPS.
Context: (Paths.get("src/test/resources/content/issue187-metaschema.xml"))
Note: [CWE-614]: Sensitive Cookie in HTTPS Session Without 'Secure' Attribute [OWASP A05:2021]: Security Misconfiguration [REFERENCES]
- https://owasp.org/Top10/A05_2021-Security_Misconfiguration


[warning] 32-32: Detected a cookie where the Secure flag is either missing or disabled. The Secure cookie flag instructs the browser to forbid sending the cookie over an insecure HTTP request. Set the Secure flag to true so the cookie will only be sent over HTTPS.
Context: (module, Files.createTempDirectory(Paths.get("target"), "modules-"))
Note: [CWE-614]: Sensitive Cookie in HTTPS Session Without 'Secure' Attribute [OWASP A05:2021]: Security Misconfiguration [REFERENCES]
- https://owasp.org/Top10/A05_2021-Security_Misconfiguration


[warning] 32-32: Detected a cookie where the Secure flag is either missing or disabled. The Secure cookie flag instructs the browser to forbid sending the cookie over an insecure HTTP request. Set the Secure flag to true so the cookie will only be sent over HTTPS.
Context: (Paths.get("target"), "modules-")
Note: [CWE-614]: Sensitive Cookie in HTTPS Session Without 'Secure' Attribute [OWASP A05:2021]: Security Misconfiguration [REFERENCES]
- https://owasp.org/Top10/A05_2021-Security_Misconfiguration


[warning] 36-36: Detected a cookie where the Secure flag is either missing or disabled. The Secure cookie flag instructs the browser to forbid sending the cookie over an insecure HTTP request. Set the Secure flag to true so the cookie will only be sent over HTTPS.
Context: (Paths.get("src/test/resources/content/issue187-instance.xml"))
Note: [CWE-614]: Sensitive Cookie in HTTPS Session Without 'Secure' Attribute [OWASP A05:2021]: Security Misconfiguration [REFERENCES]
- https://owasp.org/Top10/A05_2021-Security_Misconfiguration

databind/pom.xml (1)

7-7: 💡 Codebase verification

Inconsistent version updates in module POM files.

Please update the parent version in the following POM files to 1.3.0-SNAPSHOT for consistency:

  • metaschema-freemarker-support/pom.xml
  • metaschema-documentation-generator/pom.xml
🔗 Analysis chain

LGTM! Version and SCM tag updates are appropriate.

The changes to the parent version (1.3.0-SNAPSHOT) and SCM tag (HEAD) are consistent with moving the project into a new development cycle. This aligns well with the PR objectives of refactoring and cleanup.

Let's verify if similar changes have been made in other module POM files for consistency:

Also applies to: 27-27

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for consistent version and SCM tag updates across all POM files

# Test 1: Check for consistent parent version updates
echo "Checking parent version updates:"
rg -A 1 '<artifactId>metaschema-framework</artifactId>' **/pom.xml

# Test 2: Check for consistent SCM tag updates
echo "Checking SCM tag updates:"
rg '<tag>' **/pom.xml

Length of output: 2475

databind/src/main/java/gov/nist/secauto/metaschema/databind/model/metaschema/impl/ChoiceModelContainerSupport.java (1)

103-103: 🛠️ Refactor suggestion

Consider enhancing null check implementation

While the added assertion helps catch potential null objects in the choices list, there are a few considerations:

  1. Assertions are typically disabled in production, limiting the effectiveness of this check.
  2. The current placement only catches null objects after the first iteration.

Consider the following improvements:

  1. Replace the assertion with an explicit null check that throws an IllegalArgumentException:
for (Object obj : ObjectUtils.notNull(binding.getChoices())) {
-  assert obj != null;
+  if (obj == null) {
+    throw new IllegalArgumentException("Choice object cannot be null");
+  }
  IBoundInstanceModelGroupedAssembly objInstance
      = (IBoundInstanceModelGroupedAssembly) instance.getItemInstance(obj);
  // ... rest of the code
}
  1. Alternatively, use a null-safe iteration method to skip null elements:
-for (Object obj : ObjectUtils.notNull(binding.getChoices())) {
-  assert obj != null;
+for (Object obj : ObjectUtils.notNull(binding.getChoices()).stream().filter(Objects::nonNull).collect(Collectors.toList())) {
  IBoundInstanceModelGroupedAssembly objInstance
      = (IBoundInstanceModelGroupedAssembly) instance.getItemInstance(obj);
  // ... rest of the code
}

These approaches provide more robust null handling and maintain the integrity of the choice processing.

Committable suggestion was skipped due to low confidence.

databind/src/main/java/gov/nist/secauto/metaschema/databind/model/metaschema/impl/ChoiceGroupModelContainerSupport.java (1)

102-103: 🛠️ Refactor suggestion

Consider using a more robust null-checking approach.

While the added assertion provides an additional safety check during development, it may not be the most effective approach for preventing null pointer exceptions in production code. Consider the following suggestions:

  1. Instead of using an assertion, you could use Objects.requireNonNull(obj) at the start of the loop. This would throw a NullPointerException with a custom message if obj is null, even in production environments.

  2. Alternatively, you could filter out null values before processing the list:

for (Object obj : ObjectUtils.notNull(binding.getChoices()).stream()
    .filter(Objects::nonNull)
    .collect(Collectors.toList())) {
  // ... existing code ...
}

This approach would skip any null values in the list without throwing an exception.

Also, there's a TODO comment above this loop mentioning "make 'instances' a constant". Consider addressing this TODO by extracting the binding.getChoices() call into a constant or method if it's used multiple times in the class.

Would you like me to provide a code snippet implementing one of these suggestions?

core/pom.xml (1)

7-7: 💡 Codebase verification

Inconsistent version updates across modules

The project version was updated to 1.3.0-SNAPSHOT in core/pom.xml, but this update is not reflected in other modules' pom.xml files. Please ensure all modules are updated to maintain version consistency across the project.

  • Verify and update the version in the following modules' pom.xml files:
    • databind/pom.xml
    • metaschema-cli/pom.xml
    • (Add any additional modules as necessary)
🔗 Analysis chain

Version update to 1.3.0-SNAPSHOT

The project version has been updated from 1.2.0 to 1.3.0-SNAPSHOT. This change indicates the start of development for the next release version.

To ensure consistency across the project, let's verify if this version update has been applied to other modules:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for consistent version updates across modules
echo "Checking version consistency across modules:"
grep -r "<version>1.3.0-SNAPSHOT</version>" --include="pom.xml"

Length of output: 2343

databind/src/test/java/gov/nist/secauto/metaschema/databind/testing/model/ModelTest.java (1)

432-434: ⚠️ Potential issue

Fix JSON string construction to use valid syntax.

The current implementation uses single quotes for JSON string construction, which is not valid JSON syntax. JSON requires double quotes for string delimiters.

Please modify the JSON string construction to use double quotes. Here's the corrected version:

-          .append('{')
-          .append("  \"root-assembly-with-fields\": { }")
-          .append('}')
+          .append("{")
+          .append("  \"root-assembly-with-fields\": {}")
+          .append("}")

This change ensures that the JSON string is properly formatted and will be correctly parsed by the JSON deserializer.

Committable suggestion was skipped due to low confidence.

core/src/main/java/gov/nist/secauto/metaschema/core/model/xml/ExternalConstraintsModulePostProcessor.java (1)

21-23: ⚠️ Potential issue

Use @deprecated Javadoc Tag for Consistency

The deprecation notice in the Javadoc should use the @deprecated tag to properly indicate deprecation in generated documentation tools.

Apply this diff to update the Javadoc:

 /**
-   * This implementation has been moved to
-   * {@link gov.nist.secauto.metaschema.core.model.constraint.ExternalConstraintsModulePostProcessor},
-   * which should be used instead.
+   * @deprecated This implementation has been moved to
+   *             {@link gov.nist.secauto.metaschema.core.model.constraint.ExternalConstraintsModulePostProcessor},
+   *             which should be used instead.
    *
    * @param additionalConstraintSets
    *          constraints to configure
    */
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

   /**
    * @deprecated This implementation has been moved to
    *             {@link gov.nist.secauto.metaschema.core.model.constraint.ExternalConstraintsModulePostProcessor},
    *             which should be used instead.
    *
    * @param additionalConstraintSets
    *          constraints to configure
    */
core/src/main/java/gov/nist/secauto/metaschema/core/datatype/AbstractDataTypeProvider.java (1)

34-39: ⚠️ Potential issue

Potential thread-safety issue when returning the internal list

While using readLock allows concurrent reads, returning the internal library list, even as an unmodifiable list, can expose the internal state to concurrent modifications after the lock is released. This may lead to inconsistent views or ConcurrentModificationException if the list is modified by another thread.

Consider returning a shallow copy of the list to ensure thread safety:

try {
   readLock.lock();
-  return CollectionUtil.unmodifiableList(library);
+  return CollectionUtil.unmodifiableList(new ArrayList<>(library));
} finally {
   readLock.unlock();
}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    Lock readLock = libraryLock.readLock();
    try {
      readLock.lock();
      return CollectionUtil.unmodifiableList(new ArrayList<>(library));
    } finally {
      readLock.unlock();
databind/src/main/java/gov/nist/secauto/metaschema/databind/io/json/DefaultJsonSerializer.java (1)

27-27: 🛠️ Refactor suggestion

⚠️ Potential issue

Potential thread-safety issue with Lazy<JsonFactory> factory.

By default, Lazy.lazy() is not thread-safe. If instances of DefaultJsonSerializer are accessed by multiple threads, this could lead to race conditions during the initialization of factory. Consider using Lazy.lazyThreadSafe(this::newFactoryInstance) to ensure thread-safe lazy initialization.

Apply this diff to use thread-safe lazy initialization:

-private Lazy<JsonFactory> factory;
+private Lazy<JsonFactory> factory;

...

-protected final void resetFactory() {
-  this.factory = Lazy.lazy(this::newFactoryInstance);
+protected final void resetFactory() {
+  this.factory = Lazy.lazyThreadSafe(this::newFactoryInstance);
}

Alternatively, if thread safety is not a concern, document that DefaultJsonSerializer is not thread-safe.

Committable suggestion was skipped due to low confidence.

databind/src/main/java/gov/nist/secauto/metaschema/databind/SimpleModuleLoaderStrategy.java (3)

31-31: 🛠️ Refactor suggestion

Remove unnecessary locks

Since you're using ConcurrentHashMap, which handles thread-safe operations internally, and you've refactored the methods to use computeIfAbsent, the explicit locks modulesLock and definitionsLock are no longer necessary.

You can remove the lock declarations:

 private final Map<Class<?>, IBoundModule> modulesByClass = new ConcurrentHashMap<>();
-private final Lock modulesLock = new ReentrantLock();
 private final Map<Class<?>, IBoundDefinitionModelComplex> definitionsByClass = new ConcurrentHashMap<>();
-private final Lock definitionsLock = new ReentrantLock();

Also applies to: 34-34


64-74: 🛠️ Refactor suggestion

Refactor getBoundDefinitionForClass using computeIfAbsent

Similarly, you can refactor getBoundDefinitionForClass to use computeIfAbsent, removing the explicit lock and simplifying the code. Note that if newBoundDefinition(clazz) returns null, the map will not store a mapping for this key, which aligns with your current logic.

Refactored getBoundDefinitionForClass method:

 public IBoundDefinitionModelComplex getBoundDefinitionForClass(@NonNull Class<? extends IBoundObject> clazz) {
-    IBoundDefinitionModelComplex retval;
-    try {
-      definitionsLock.lock();
-      retval = definitionsByClass.get(clazz);
-      if (retval == null) {
-        retval = newBoundDefinition(clazz);
-        if (retval != null) {
-          definitionsByClass.put(clazz, retval);
-        }
-      }
-    } finally {
-      definitionsLock.unlock();
-    }
-    return retval;
+    return definitionsByClass.computeIfAbsent(
+        clazz,
+        c -> newBoundDefinition(c));
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    return definitionsByClass.computeIfAbsent(
        clazz,
        c -> newBoundDefinition(c));

48-56: 🛠️ Refactor suggestion

Simplify concurrent map access using computeIfAbsent

You can eliminate the need for explicit locking by leveraging the computeIfAbsent method provided by ConcurrentHashMap. This method atomically computes and stores the value if it's absent, simplifying your code and enhancing readability.

Here’s how you can refactor the loadModule method:

 public IBoundModule loadModule(@NonNull Class<? extends IBoundModule> clazz) {
-    IBoundModule retval;
-    try {
-      modulesLock.lock();
-      retval = modulesByClass.get(clazz);
-      if (retval == null) {
-        retval = AbstractBoundModule.createInstance(clazz, getBindingContext());
-        modulesByClass.put(clazz, retval);
-      }
-    } finally {
-      modulesLock.unlock();
-    }
-    return ObjectUtils.notNull(retval);
+    return modulesByClass.computeIfAbsent(
+        clazz,
+        c -> ObjectUtils.notNull(AbstractBoundModule.createInstance(c, getBindingContext())));
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    return modulesByClass.computeIfAbsent(
        clazz,
        c -> ObjectUtils.notNull(AbstractBoundModule.createInstance(c, getBindingContext())));
core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnStringLength.java (2)

70-70: ⚠️ Potential issue

Typo in comment: 'if' should be 'is'

On line 70, there is a typo in the comment. The word 'if' should be 'is':

- // the focus should always be non-null, since the function if focus-dependent
+ // the focus should always be non-null, since the function is focus-dependent
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    // the focus should always be non-null, since the function is focus-dependent

85-85: ⚠️ Potential issue

Potential exception on empty sequence due to getFirstItem(true)

In the executeOneArg method, using getFirstItem(true) will throw an exception if the argument sequence is empty. According to the XPath 3.1 specification, if the argument is an empty sequence, the function should return zero without throwing an exception. To handle this case correctly, consider changing getFirstItem(true) to getFirstItem(false):

- IStringItem arg = FunctionUtils.asTypeOrNull(arguments.get(0).getFirstItem(true));
+ IStringItem arg = FunctionUtils.asTypeOrNull(arguments.get(0).getFirstItem(false));
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    IStringItem arg = FunctionUtils.asTypeOrNull(arguments.get(0).getFirstItem(false));
core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/ValueConstraintSet.java (10)

60-65: ⚠️ Potential issue

Incorrect Lock Acquisition Order in 'getAllowedValuesConstraints' Method

Similar to the previous method, readLock.lock() should be called before the try block.

Apply this diff:

@Override
public List<IAllowedValuesConstraint> getAllowedValuesConstraints() {
  Lock readLock = instanceLock.readLock();
+ readLock.lock();
  try {
-   readLock.lock();
    return allowedValuesConstraints;
  } finally {
    readLock.unlock();
  }
}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    Lock readLock = instanceLock.readLock();
    readLock.lock();
    try {
      return allowedValuesConstraints;
    } finally {
      readLock.unlock();

104-110: ⚠️ Potential issue

Incorrect Lock Acquisition Order in 'addConstraint' for AllowedValuesConstraints

writeLock.lock() should be called before the try block to prevent potential issues.

Suggested correction:

@Override
public final void addConstraint(@NonNull IAllowedValuesConstraint constraint) {
  Lock writeLock = instanceLock.writeLock();
+ writeLock.lock();
  try {
-   writeLock.lock();
    constraints.add(constraint);
    allowedValuesConstraints.add(constraint);
  } finally {
    writeLock.unlock();
  }
}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    Lock writeLock = instanceLock.writeLock();
    writeLock.lock();
    try {
      constraints.add(constraint);
      allowedValuesConstraints.add(constraint);
    } finally {
      writeLock.unlock();

82-87: ⚠️ Potential issue

Incorrect Lock Acquisition Order in 'getIndexHasKeyConstraints' Method

Ensure readLock.lock() is called before entering the try block.

Correct it with this diff:

@Override
public List<IIndexHasKeyConstraint> getIndexHasKeyConstraints() {
  Lock readLock = instanceLock.readLock();
+ readLock.lock();
  try {
-   readLock.lock();
    return indexHasKeyConstraints;
  } finally {
    readLock.unlock();
  }
}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    Lock readLock = instanceLock.readLock();
    readLock.lock();
    try {
      return indexHasKeyConstraints;
    } finally {
      readLock.unlock();
    }

140-146: ⚠️ Potential issue

Incorrect Lock Acquisition Order in 'addConstraint' for ExpectConstraints

writeLock.lock() should be called before the try block for consistency and correctness.

Correct it with this diff:

@Override
public final void addConstraint(@NonNull IExpectConstraint constraint) {
  Lock writeLock = instanceLock.writeLock();
+ writeLock.lock();
  try {
-   writeLock.lock();
    constraints.add(constraint);
    expectConstraints.add(constraint);
  } finally {
    writeLock.unlock();
  }
}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    Lock writeLock = instanceLock.writeLock();
    writeLock.lock();
    try {
      constraints.add(constraint);
      expectConstraints.add(constraint);
    } finally {
      writeLock.unlock();

116-122: ⚠️ Potential issue

Incorrect Lock Acquisition Order in 'addConstraint' for MatchesConstraints

Adjust the position of writeLock.lock() to before the try block.

Apply this diff:

@Override
public final void addConstraint(@NonNull IMatchesConstraint constraint) {
  Lock writeLock = instanceLock.writeLock();
+ writeLock.lock();
  try {
-   writeLock.lock();
    constraints.add(constraint);
    matchesConstraints.add(constraint);
  } finally {
    writeLock.unlock();
  }
}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    Lock writeLock = instanceLock.writeLock();
    writeLock.lock();
    try {
      constraints.add(constraint);
      matchesConstraints.add(constraint);
    } finally {
      writeLock.unlock();

49-54: ⚠️ Potential issue

Incorrect Lock Acquisition Order in 'getConstraints' Method

The call to readLock.lock() should be made before entering the try block to ensure the lock is acquired even if an exception is thrown during the locking process. Placing the lock() call inside the try block can lead to unlocking an unacquired lock if lock() throws an exception.

Apply this diff to correct the lock acquisition order:

@Override
public List<IConstraint> getConstraints() {
  Lock readLock = instanceLock.readLock();
+ readLock.lock();
  try {
-   readLock.lock();
    return constraints;
  } finally {
    readLock.unlock();
  }
}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    Lock readLock = instanceLock.readLock();
    readLock.lock();
    try {
      return constraints;
    } finally {
      readLock.unlock();

93-98: ⚠️ Potential issue

Incorrect Lock Acquisition Order in 'getExpectConstraints' Method

Move readLock.lock() before the try block.

Fix it as follows:

@Override
public List<IExpectConstraint> getExpectConstraints() {
  Lock readLock = instanceLock.readLock();
+ readLock.lock();
  try {
-   readLock.lock();
    return expectConstraints;
  } finally {
    readLock.unlock();
  }
}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    Lock readLock = instanceLock.readLock();
    readLock.lock();
    try {
      return expectConstraints;
    } finally {
      readLock.unlock();
    }

128-134: ⚠️ Potential issue

Incorrect Lock Acquisition Order in 'addConstraint' for IndexHasKeyConstraints

Ensure proper locking by moving writeLock.lock() outside the try block.

Here's the fix:

@Override
public final void addConstraint(@NonNull IIndexHasKeyConstraint constraint) {
  Lock writeLock = instanceLock.writeLock();
+ writeLock.lock();
  try {
-   writeLock.lock();
    constraints.add(constraint);
    indexHasKeyConstraints.add(constraint);
  } finally {
    writeLock.unlock();
  }
}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    Lock writeLock = instanceLock.writeLock();
    writeLock.lock();
    try {
      constraints.add(constraint);
      indexHasKeyConstraints.add(constraint);
    } finally {
      writeLock.unlock();

71-76: ⚠️ Potential issue

Incorrect Lock Acquisition Order in 'getMatchesConstraints' Method

The readLock.lock() call should precede the try block.

Here's the suggested fix:

@Override
public List<IMatchesConstraint> getMatchesConstraints() {
  Lock readLock = instanceLock.readLock();
+ readLock.lock();
  try {
-   readLock.lock();
    return matchesConstraints;
  } finally {
    readLock.unlock();
  }
}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    Lock readLock = instanceLock.readLock();
    readLock.lock();
    try {
      return matchesConstraints;
    } finally {
      readLock.unlock();
    }

49-146: 🛠️ Refactor suggestion

Consider Returning Unmodifiable Views of Internal Collections

Returning mutable internal collections like constraints can expose the internal state to external modification, potentially leading to thread safety issues. Consider returning unmodifiable views to protect the integrity of the internal data.

For example, modify the getters to return unmodifiable lists:

import java.util.Collections;
+import java.util.List;

@Override
public List<IConstraint> getConstraints() {
  Lock readLock = instanceLock.readLock();
  readLock.lock();
  try {
    return Collections.unmodifiableList(constraints);
  } finally {
    readLock.unlock();
  }
}

Apply similar changes to other getter methods.

Committable suggestion was skipped due to low confidence.

core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/FunctionLibrary.java (2)

85-90: ⚠️ Potential issue

Potential concurrency issue: Stream may access shared data after lock release

In the stream method, the read lock is acquired, a Stream is created, and then the lock is released:

Lock readLock = instanceLock.readLock();
try {
  readLock.lock();
  return ObjectUtils.notNull(
      libraryByQName.values().stream().flatMap(NamedFunctionSet::getFunctionsAsStream));
} finally {
  readLock.unlock();
}

The returned Stream might access libraryByQName after the lock has been released, leading to potential ConcurrentModificationException if other threads modify the collection concurrently.

Consider collecting the results into an immutable collection within the locked section to ensure thread safety:

Lock readLock = instanceLock.readLock();
readLock.lock();
try {
+  List<IFunction> functions = libraryByQName.values().stream()
+      .flatMap(NamedFunctionSet::getFunctionsAsStream)
+      .collect(Collectors.toUnmodifiableList());
+  return functions.stream();
-  return ObjectUtils.notNull(
-      libraryByQName.values().stream().flatMap(NamedFunctionSet::getFunctionsAsStream));
} finally {
  readLock.unlock();
}

This modification ensures that the Stream operates on a snapshot of the data, preventing concurrent modifications from affecting iteration.


48-58: 🛠️ Refactor suggestion

Adjust the locking pattern to prevent potential exceptions

Currently, the lock is acquired inside the try block:

Lock writeLock = instanceLock.writeLock();
try {
  writeLock.lock();
  // Operations
} finally {
  writeLock.unlock();
}

If an exception occurs before the lock is acquired, the unlock() method could be called without a corresponding lock(), potentially throwing an IllegalMonitorStateException.

Acquire the lock before the try block to ensure that unlock() is only called if the lock was successfully acquired:

Lock writeLock = instanceLock.writeLock();
+ writeLock.lock();
try {
- writeLock.lock();
  // Operations
} finally {
  writeLock.unlock();
}

Apply this pattern consistently in all methods where locks are used (registerFunctionByQName, registerFunctionByName, getFunction, etc.) to enhance reliability.

Also applies to: 68-79, 97-105, 113-121

databind/src/main/java/gov/nist/secauto/metaschema/databind/io/json/DefaultJsonDeserializer.java (3)

30-30: ⚠️ Potential issue

Ensure thread safety with Lazy<JsonFactory>

Using Lazy<JsonFactory> for lazy initialization of the factory variable can introduce thread-safety concerns. Verify that the Lazy implementation from Lazy4j is thread-safe and suitable for use in multi-threaded environments, as DefaultJsonDeserializer may be accessed concurrently.


45-47: ⚠️ Potential issue

Review thread safety of the resetFactory() method

The resetFactory() method reinitializes the factory variable. If configurationChanged can be called by multiple threads, ensure that this method is thread-safe to prevent race conditions or inconsistent states.


50-52: ⚠️ Potential issue

Ensure thread safety when resetting factory on configuration changes

The configurationChanged method invokes resetFactory(). If configurations can change at runtime in a multi-threaded context, confirm that resetting the factory does not introduce concurrency issues.

metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/ConvertContentUsingModuleCommand.java (1)

97-110: ⚠️ Potential issue

Avoid including user input in exception messages to prevent information disclosure

Including user-provided input such as ex.getInput() in exception messages can inadvertently leak sensitive information or provide attackers with hints about the system's internals. Consider sanitizing the input or providing a more generic error message to enhance security.

Apply this diff to prevent potential information disclosure:

-throw new IOException(String.format("Cannot load module as '%s' is not a valid file or URL.", ex.getInput()), ex);
+throw new IOException("Cannot load module: Invalid file or URL.", ex);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    protected IBindingContext getBindingContext() throws IOException, MetaschemaException {
      URI cwd = ObjectUtils.notNull(Paths.get("").toAbsolutePath().toUri());

      IModule module;
      try {
        module = MetaschemaCommands.handleModule(getCommandLine(), cwd, CollectionUtil.emptySet());
      } catch (URISyntaxException ex) {
        throw new IOException("Cannot load module: Invalid file or URL.", ex);
      }
      IBindingContext retval = new DefaultBindingContext();
      retval.registerModule(module, getTempDir());
      return retval;
    }
🧰 Tools
🪛 ast-grep

[warning] 103-104: Detected a cookie where the HttpOnly flag is either missing or disabled. The HttpOnly cookie flag instructs the browser to forbid client-side JavaScript to read the cookie. If JavaScript interaction is required, you can ignore this finding. However, set the HttpOnly flag to true` in all other cases.
Context: (String.format("Cannot load module as '%s' is not a valid file or URL.", ex.getInput()),
ex)
Note: [CWE-1004]: Sensitive Cookie Without 'HttpOnly' Flag [OWASP A05:2021]: Security Misconfiguration [REFERENCES]
- https://owasp.org/Top10/A05_2021-Security_Misconfiguration


[warning] 103-104: Detected a cookie where the Secure flag is either missing or disabled. The Secure cookie flag instructs the browser to forbid sending the cookie over an insecure HTTP request. Set the Secure flag to true so the cookie will only be sent over HTTPS.
Context: (String.format("Cannot load module as '%s' is not a valid file or URL.", ex.getInput()),
ex)
Note: [CWE-614]: Sensitive Cookie in HTTPS Session Without 'Secure' Attribute [OWASP A05:2021]: Security Misconfiguration [REFERENCES]
- https://owasp.org/Top10/A05_2021-Security_Misconfiguration

core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/ExternalConstraintsModulePostProcessor.java (4)

99-99: ⚠️ Potential issue

Replace 'assert' statement with proper null check for 'items'

Assertions may be disabled at runtime, which could lead to unexpected behavior if items is null. Replace assert items != null; with an explicit null check to ensure items is not null.

Apply this diff:

-  assert items != null;
+  if (items == null) {
+    throw new IllegalStateException("Metapath expression evaluation returned a null sequence.");
+  }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

      if (items == null) {
        throw new IllegalStateException("Metapath expression evaluation returned a null sequence.");
      }

83-83: ⚠️ Potential issue

Replace 'assert' statement with proper null check for 'set'

Using assert statements for null checks can be unreliable in production code since assertions can be disabled at runtime. Replace assert set != null; with an explicit null check to ensure set is not null during execution.

Apply this diff:

-  assert set != null;
+  if (set == null) {
+    throw new IllegalArgumentException("Constraint set cannot be null");
+  }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

      if (set == null) {
        throw new IllegalArgumentException("Constraint set cannot be null");
      }

54-61: ⚠️ Potential issue

Filter out null elements from 'additionalConstraintSets'

The constructor does not check for null elements within additionalConstraintSets or the imported constraint sets. To prevent potential NullPointerExceptions, filter out null elements when initializing registeredConstraintSets.

Apply this diff to filter out null elements:

 this.registeredConstraintSets = ObjectUtils.notNull(additionalConstraintSets.stream()
+    .filter(Objects::nonNull)
     .flatMap(set -> Stream.concat(
         Stream.of(set),
+        set.getImportedConstraintSets().stream().filter(Objects::nonNull)))
-        set.getImportedConstraintSets().stream()))
     .distinct()
     .collect(Collectors.toUnmodifiableList()));
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

  public ExternalConstraintsModulePostProcessor(@NonNull Collection<IConstraintSet> additionalConstraintSets) {
    this.registeredConstraintSets = ObjectUtils.notNull(additionalConstraintSets.stream()
        .filter(Objects::nonNull)
        .flatMap(set -> Stream.concat(
            Stream.of(set),
            set.getImportedConstraintSets().stream().filter(Objects::nonNull)))
        .distinct()
        .collect(Collectors.toUnmodifiableList()));
  }

97-103: ⚠️ Potential issue

Handle exceptions when compiling 'targetExpression'

Compiling the targetExpression may throw an exception if the expression is invalid. Wrap MetapathExpression.compile in a try-catch block to handle any potential exceptions and prevent the application from crashing.

Apply this diff:

-  MetapathExpression metapath = MetapathExpression.compile(targetExpression, dynamicContext.getStaticContext());
+  MetapathExpression metapath;
+  try {
+    metapath = MetapathExpression.compile(targetExpression, dynamicContext.getStaticContext());
+  } catch (MetapathException e) {
+    LOGGER.atError().withThrowable(e).log("Failed to compile target expression '{}'.", targetExpression);
+    continue;
+  }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

      MetapathExpression metapath;
      try {
        metapath = MetapathExpression.compile(targetExpression, dynamicContext.getStaticContext());
      } catch (MetapathException e) {
        LOGGER.atError().withThrowable(e).log("Failed to compile target expression '{}'.", targetExpression);
        continue;
      }
      ISequence<?> items = metapath.evaluateAs(moduleItem, ResultType.SEQUENCE, dynamicContext);
      assert items != null;

      // first build a map to ensure the constraint is only applied once to each
      // underlying definition
      Map<IDefinition, IDefinitionNodeItem<?, ?>> definitions = items.stream()
databind/src/main/java/gov/nist/secauto/metaschema/databind/io/xml/DefaultXmlDeserializer.java (2)

74-79: ⚠️ Potential issue

Correct the method comment to reflect XML factory creation

The method newFactoryInstance() at lines 74-79 has a comment that incorrectly states "Get a JSON factory instance." Since this method creates an XMLInputFactory2 instance for XML parsing, please update the comment to accurately describe its purpose.

Apply this diff to correct the comment:

-       * Get a JSON factory instance.
+       * Get an XML input factory instance.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

   * Get an XML input factory instance.
   * <p>
   * This method can be used by sub-classes to create a customized factory
   * instance.
   *
   * @return the factory

84-84: ⚠️ Potential issue

Replace assert with explicit runtime check for type safety

At line 84, using an assert statement to check if retval is an instance of WstxInputFactory is not reliable, as assertions can be disabled at runtime. This might allow an incompatible factory instance to be used without detection. Consider replacing the assert with an explicit type check and throw an exception if the check fails to ensure type safety.

Apply this diff to replace the assert statement:

-        assert retval instanceof WstxInputFactory;
+        if (!(retval instanceof WstxInputFactory)) {
+          throw new IllegalStateException("Expected XMLInputFactory to be an instance of WstxInputFactory.");
+        }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    if (!(retval instanceof WstxInputFactory)) {
      throw new IllegalStateException("Expected XMLInputFactory to be an instance of WstxInputFactory.");
    }
databind/src/test/java/gov/nist/secauto/metaschema/databind/codegen/AbstractMetaschemaTest.java (1)

35-35: 🛠️ Refactor suggestion

Consider Using @TempDir for Temporary Directory

The generationDir is currently set to a fixed path "target/generated-test-sources/metaschema". This could lead to issues when running tests in parallel or leave residual files after tests complete. Consider using JUnit's @TempDir annotation to create a temporary directory for test outputs, ensuring isolation and automatic cleanup.

Apply this diff to adjust the code:

- // @TempDir
- // Path generationDir;
  @NonNull
- Path generationDir = ObjectUtils.notNull(Paths.get("target/generated-test-sources/metaschema"));
+ @TempDir
+ Path generationDir;

Committable suggestion was skipped due to low confidence.

metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/metapath/EvaluateMetapathCommand.java (2)

210-220: 🛠️ Refactor suggestion

Simplify nested try-with-resources statements

The nested try-with-resources statements can be refactored to improve code readability. Multiple resources can be declared in a single try-with-resources statement.

Consider combining the resources into a single statement:

-try (Writer stringWriter = new StringWriter()) {
-  try (PrintWriter writer = new PrintWriter(stringWriter)) {
-    try (IItemWriter itemWriter = new DefaultItemWriter(writer)) {
-      itemWriter.writeSequence(sequence);
-    }
-  }
-
-  // Print the result
-  if (LOGGER.isInfoEnabled()) {
-    LOGGER.info(stringWriter.toString());
-  }
-}
+try (Writer stringWriter = new StringWriter();
+     PrintWriter writer = new PrintWriter(stringWriter);
+     IItemWriter itemWriter = new DefaultItemWriter(writer)) {
+  itemWriter.writeSequence(sequence);
+  // Print the result
+  if (LOGGER.isInfoEnabled()) {
+    LOGGER.info(stringWriter.toString());
+  }
+}

This refactoring simplifies the code while maintaining the same functionality.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

      try (Writer stringWriter = new StringWriter();
           PrintWriter writer = new PrintWriter(stringWriter);
           IItemWriter itemWriter = new DefaultItemWriter(writer)) {
        itemWriter.writeSequence(sequence);
        // Print the result
        if (LOGGER.isInfoEnabled()) {
          LOGGER.info(stringWriter.toString());
        }
      }

188-189: ⚠️ Potential issue

Incorrect option name in error message

The error message references CONTENT_OPTION.getArgName() instead of METASCHEMA_OPTION.getArgName(). Since the error is about requiring the Metaschema module, the option name should reference METASCHEMA_OPTION.

Apply this diff to correct the option name:

return ExitCode.INVALID_ARGUMENTS.exitMessage(
-    String.format("Must use '%s' to specify the Metaschema module.", CONTENT_OPTION.getArgName()));
+    String.format("Must use '%s' to specify the Metaschema module.", METASCHEMA_OPTION.getArgName()));
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

      // content provided, but no module; require module
      return ExitCode.INVALID_ARGUMENTS.exitMessage(
          String.format("Must use '%s' to specify the Metaschema module.", METASCHEMA_OPTION.getArgName()));
🧰 Tools
🪛 ast-grep

[warning] 188-189: Detected a cookie where the HttpOnly flag is either missing or disabled. The HttpOnly cookie flag instructs the browser to forbid client-side JavaScript to read the cookie. If JavaScript interaction is required, you can ignore this finding. However, set the HttpOnly flag to true` in all other cases.
Context: (
String.format("Must use '%s' to specify the Metaschema module.", CONTENT_OPTION.getArgName()))
Note: [CWE-1004]: Sensitive Cookie Without 'HttpOnly' Flag [OWASP A05:2021]: Security Misconfiguration [REFERENCES]
- https://owasp.org/Top10/A05_2021-Security_Misconfiguration


[warning] 188-189: Detected a cookie where the Secure flag is either missing or disabled. The Secure cookie flag instructs the browser to forbid sending the cookie over an insecure HTTP request. Set the Secure flag to true so the cookie will only be sent over HTTPS.
Context: (
String.format("Must use '%s' to specify the Metaschema module.", CONTENT_OPTION.getArgName()))
Note: [CWE-614]: Sensitive Cookie in HTTPS Session Without 'Secure' Attribute [OWASP A05:2021]: Security Misconfiguration [REFERENCES]
- https://owasp.org/Top10/A05_2021-Security_Misconfiguration

metaschema-maven-plugin/src/main/java/gov/nist/secauto/metaschema/maven/plugin/AbstractMetaschemaMojo.java (1)

218-218: ⚠️ Potential issue

Use Charset.defaultCharset().name() instead of displayName() for consistent encoding names

In the getEncoding() method, Charset.defaultCharset().displayName() is used to obtain the system's default encoding. The displayName() method returns a human-readable name, which may vary based on locale and is not guaranteed to be consistent across different environments. For consistent and programmatically reliable encoding names, it's better to use Charset.defaultCharset().name(), which returns the canonical name of the charset.

Apply this diff to ensure consistent encoding names:

-          encoding = Charset.defaultCharset().displayName();
+          encoding = Charset.defaultCharset().name();
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

      encoding = Charset.defaultCharset().name();
databind/src/main/java/gov/nist/secauto/metaschema/databind/codegen/typeinfo/DefaultTypeResolver.java (3)

38-39: 🛠️ Refactor suggestion

Consider using ReadWriteLock for better concurrency

You have introduced ReentrantLock instances (classNameLock and propertyNameLock) to synchronize access to shared resources. If read operations occur more frequently than writes, consider using ReadWriteLock to allow multiple threads to read concurrently while still synchronizing write operations. This can improve concurrency and performance in multithreaded environments.

Also applies to: 49-49, 58-58


196-203: ⚠️ Potential issue

Fix the infinite loop in class name generation logic

The index variable is not incremented within the while loop in the getClassName method, which can lead to an infinite loop when a class name clash occurs. Increment index inside the loop to properly generate unique class names.

Apply this diff to fix the issue:

 int index = 1;
 try {
   classNameLock.lock();
   while (isClassNameClash(packageName, className)) {
-    className = classNameBase + Integer.toString(index);
+    className = classNameBase + Integer.toString(index++);
   }
   addClassName(packageName, className);
 } finally {
   classNameLock.unlock();
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

          int index = 1;
          try {
            classNameLock.lock();
            while (isClassNameClash(packageName, className)) {
              className = classNameBase + Integer.toString(index++);
            }
            addClassName(packageName, className);
          } finally {
            classNameLock.unlock();

214-215: 🛠️ Refactor suggestion

Remove redundant synchronization with Collections.synchronizedSet

In the getClassNamesFor method, you wrap LinkedHashSet with Collections.synchronizedSet. Since you're already using classNameLock to control access to this set, the additional synchronization is unnecessary and may introduce overhead. Replace it with a plain LinkedHashSet.

Apply this diff:

-              pkg -> Collections.synchronizedSet(new LinkedHashSet<>())));
+              pkg -> new LinkedHashSet<>()));
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

          packageOrTypeName,
          pkg -> new LinkedHashSet<>()));
🧰 Tools
🪛 ast-grep

[warning] 214-214: Detected a cookie where the Secure flag is either missing or disabled. The Secure cookie flag instructs the browser to forbid sending the cookie over an insecure HTTP request. Set the Secure flag to true so the cookie will only be sent over HTTPS.
Context: (new LinkedHashSet<>())
Note: [CWE-614]: Sensitive Cookie in HTTPS Session Without 'Secure' Attribute [OWASP A05:2021]: Security Misconfiguration [REFERENCES]
- https://owasp.org/Top10/A05_2021-Security_Misconfiguration


[warning] 214-214: Detected a cookie where the HttpOnly flag is either missing or disabled. The HttpOnly cookie flag instructs the browser to forbid client-side JavaScript to read the cookie. If JavaScript interaction is required, you can ignore this finding. However, set the HttpOnly flag to true` in all other cases.
Context: (new LinkedHashSet<>())
Note: [CWE-1004]: Sensitive Cookie Without 'HttpOnly' Flag [OWASP A05:2021]: Security Misconfiguration [REFERENCES]
- https://owasp.org/Top10/A05_2021-Security_Misconfiguration

databind/src/main/java/gov/nist/secauto/metaschema/databind/io/json/MetaschemaJsonWriter.java (1)

38-38: 🛠️ Refactor suggestion

Consider refactoring to reduce class coupling instead of suppressing PMD warning

Suppressing the PMD.CouplingBetweenObjects warning at the class level indicates that this class has a high level of coupling with other classes, which can make the code harder to maintain and understand. It might be beneficial to refactor the class to reduce coupling, possibly by splitting it into smaller, more focused classes or reducing unnecessary dependencies.

databind-metaschema/src/main/java/gov/nist/secauto/metaschema/modules/sarif/SarifValidationHandler.java (3)

58-58: 🛠️ Refactor suggestion

Consider reducing class coupling instead of suppressing PMD warning.

The suppression of the PMD.CouplingBetweenObjects warning indicates that SarifValidationHandler has high coupling with other classes. High coupling can make the codebase harder to maintain and test. Consider refactoring the class to reduce coupling and improve modularity, rather than suppressing the warning.


428-428: 🛠️ Refactor suggestion

Consider refactoring to avoid object instantiation within loops.

Creating a Result object inside a loop may impact performance due to frequent object creation. If possible, refactor the code to reuse objects or instantiate them outside the loop.


144-145: 💡 Codebase verification

'getSource()' Method Is Used Externally

The getSource() method is referenced in multiple locations outside the SarifValidationHandler class, including:

  • BindingConstraintLoader.java
  • ConstraintSupport.java
  • XmlConstraintLoader.java
  • ConstraintXmlSupport.java
  • ICardinalityConstraint.java
  • IIndexHasKeyConstraint.java
  • IAllowedValuesConstraint.java
  • AbstractConstraintBuilder.java
  • XmlConstraintLoader.java
  • InternalModelSource.java
  • ExternalSource.java
  • AbstractConstraint.java
  • DefaultLet.java

Changing the visibility of getSource() to private may affect these external references. Please review and refactor accordingly to ensure encapsulation without breaking dependencies.

🔗 Analysis chain

Ensure 'getSource()' method is not needed outside the class.

Changing the visibility of getSource() to private enhances encapsulation. Please verify that there are no external references to this method that might be affected by this change.

Run the following script to search for external references to getSource():

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Find usages of 'getSource()' outside 'SarifValidationHandler' class.

# Execute: Search for 'getSource(' in all Java files excluding 'SarifValidationHandler.java'. Expect: No matches.
rg --type java 'getSource\(' --glob '!**/SarifValidationHandler.java' -A 2

Length of output: 8619

core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/AssemblyConstraintSet.java (7)

53-58: ⚠️ Potential issue

Ensure Proper Lock Ordering in Read Operations

In the getHasCardinalityConstraints method, adjust the lock acquisition to occur before the try block for consistent and safe lock handling.

Apply this diff to adjust the lock ordering:

-    try {
-      readLock.lock();
+    readLock.lock();
+    try {
       return cardinalityConstraints;
     } finally {
       readLock.unlock();
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    Lock readLock = instanceLock.readLock();
    readLock.lock();
    try {
      return cardinalityConstraints;
    } finally {
      readLock.unlock();
    }

88-94: ⚠️ Potential issue

Ensure Proper Lock Ordering in Write Operations

In the addConstraint method for ICardinalityConstraint, adjust the placement of writeLock.lock() to occur before the try block.

Apply this diff to adjust the lock ordering:

-    try {
-      writeLock.lock();
+    writeLock.lock();
+    try {
       getConstraints().add(constraint);
       cardinalityConstraints.add(constraint);
     } finally {
       writeLock.unlock();
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    Lock writeLock = instanceLock.writeLock();
    writeLock.lock();
    try {
      getConstraints().add(constraint);
      cardinalityConstraints.add(constraint);
    } finally {
      writeLock.unlock();
    }

31-36: ⚠️ Potential issue

Ensure Proper Lock Ordering in Read Operations

In the getIndexConstraints method, the lock acquisition should occur before the try block to guarantee that the lock is held during the entire operation. Currently, readLock.lock() is inside the try block, which may lead to the lock not being released properly if an exception is thrown before the lock is acquired.

Apply this diff to adjust the lock ordering:

-    try {
-      readLock.lock();
+    readLock.lock();
+    try {
       return indexConstraints;
     } finally {
       readLock.unlock();
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    Lock readLock = instanceLock.readLock();
    readLock.lock();
    try {
      return indexConstraints;
    } finally {
      readLock.unlock();
    }

42-47: ⚠️ Potential issue

Ensure Proper Lock Ordering in Read Operations

Similarly, in the getUniqueConstraints method, the lock should be acquired before entering the try block to ensure correct lock management.

Apply this diff to adjust the lock ordering:

-    try {
-      readLock.lock();
+    readLock.lock();
+    try {
       return uniqueConstraints;
     } finally {
       readLock.unlock();
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    Lock readLock = instanceLock.readLock();
    readLock.lock();
    try {
      return uniqueConstraints;
    } finally {
      readLock.unlock();
    }

64-70: ⚠️ Potential issue

Ensure Proper Lock Ordering in Write Operations

In the addConstraint method for IIndexConstraint, the write lock should be acquired before the try block to prevent any potential issues with lock release.

Apply this diff to adjust the lock ordering:

-    try {
-      writeLock.lock();
+    writeLock.lock();
+    try {
       getConstraints().add(constraint);
       indexConstraints.add(constraint);
     } finally {
       writeLock.unlock();
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    Lock writeLock = instanceLock.writeLock();
    writeLock.lock();
    try {
      getConstraints().add(constraint);
      indexConstraints.add(constraint);
    } finally {
      writeLock.unlock();
    }

76-82: ⚠️ Potential issue

Ensure Proper Lock Ordering in Write Operations

For the addConstraint method handling IUniqueConstraint, ensure the write lock is acquired before entering the try block.

Apply this diff to adjust the lock ordering:

-    try {
-      writeLock.lock();
+    writeLock.lock();
+    try {
       getConstraints().add(constraint);
       uniqueConstraints.add(constraint);
     } finally {
       writeLock.unlock();
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    Lock writeLock = instanceLock.writeLock();
    writeLock.lock();
    try {
      getConstraints().add(constraint);
      uniqueConstraints.add(constraint);
    } finally {
      writeLock.unlock();
    }

10-10: 💡 Codebase verification

⚠️ Potential issue

Import and Declare ReadWriteLock

The instanceLock variable is not declared in AssemblyConstraintSet.java. Please add the following imports and declaration to prevent compilation errors:

+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;

 public class AssemblyConstraintSet
     extends ValueConstraintSet
     implements IModelConstrained {

+  private final ReadWriteLock instanceLock = new ReentrantReadWriteLock();
🔗 Analysis chain

Import Missing ReadWriteLock

The instanceLock variable used for locking is not declared in this class. Ensure that ReadWriteLock is properly declared and initialized to prevent compilation errors.

Run the following script to check for the declaration of instanceLock:

If instanceLock is not declared in this class or a superclass, add the following import and declaration:

+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;

 public class AssemblyConstraintSet
     extends ValueConstraintSet
     implements IModelConstrained {

+  private final ReadWriteLock instanceLock = new ReentrantReadWriteLock();
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that `instanceLock` is declared and initialized.

# Test: Search for `instanceLock` declaration.
# Expect: A declaration of `instanceLock` as a `ReadWriteLock` instance.

rg -A 2 'private.*ReadWriteLock.*instanceLock'

Length of output: 403

@david-waltermire david-waltermire changed the base branch from main to develop October 20, 2024 19:41
David Waltermire added 2 commits October 20, 2024 16:24
… not be removed anytime soon to continue to provide support. Added a bunch of Javadocs.
@david-waltermire david-waltermire force-pushed the feature/add-missing-javadocs-20241020 branch from 7b0c24f to fc4f2ec Compare October 20, 2024 22:50
@david-waltermire david-waltermire marked this pull request as ready for review October 26, 2024 04:59
@david-waltermire david-waltermire merged commit ad49938 into metaschema-framework:develop Oct 26, 2024
@david-waltermire david-waltermire deleted the feature/add-missing-javadocs-20241020 branch October 26, 2024 05:00
david-waltermire pushed a commit to david-waltermire/metaschema-java that referenced this pull request Mar 12, 2025
* More refactoring, Javadoc creation, and cleanup of PMD, Java compile, and Spotbugs errors.
* Removed marking for removal for NcName deprecations, since these will not be removed anytime soon to continue to provide support.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant