Skip to content

feat: Add Maven parent POM license resolution (v1.6.0)#29

Merged
oscarvalenzuelab merged 4 commits intomainfrom
feature/maven-parent-pom-resolution
Nov 14, 2025
Merged

feat: Add Maven parent POM license resolution (v1.6.0)#29
oscarvalenzuelab merged 4 commits intomainfrom
feature/maven-parent-pom-resolution

Conversation

@oscarvalenzuelab
Copy link
Contributor

Enhancement

Add Maven-specific license resolution to handle packages where licenses are declared in parent POMs rather than in the package POM itself.

Problem

Maven packages often don't declare licenses directly in their package POM - the license is declared in a parent POM instead. When download_and_scan_package analyzed such packages, it would return no license information even though the license exists in the parent POM.

Example:

<!-- package POM - no license declared -->
<project>
  <parent>
    <groupId>org.example</groupId>
    <artifactId>parent</artifactId>
    <version>1.0</version>
  </parent>
  <!-- ... but license is in parent POM -->
</project>

Solution

Added Maven-specific license resolution using upmex's --registry and --api clearlydefined flags to query ClearlyDefined API, which automatically resolves parent POM licenses.

Workflow Enhancement

After scanning a Maven package (pkg:maven/...), if no license is found:

  1. Detects it's a Maven package (purl.startswith('pkg:maven/'))
  2. Calls upmex extract with --registry --api clearlydefined flags
  3. ClearlyDefined API resolves parent POM licenses automatically
  4. Updates result with license and license_source = 'parent_pom_via_clearlydefined'

Code Example

# Maven package with license in parent POM only
result = await download_and_scan_package(purl="pkg:maven/org.example/library@1.0.0")

# Before (v1.5.8):
#   declared_license: None

# After (v1.5.9):
#   declared_license: "Apache-2.0"
#   metadata.license_source: "parent_pom_via_clearlydefined"

Changes

mcp_semclone/server.py

Added Maven parent POM resolution (lines 2057-2078):

# MAVEN SPECIFIC: If no license found and it's a Maven package, try with --registry and --api
if not result["declared_license"] and purl.startswith("pkg:maven/"):
    logger.info(f"Maven package missing license, trying upmex with --registry --api clearlydefined")
    try:
        upmex_maven_result = _run_tool("upmex", [
            "extract",
            str(download_file),
            "--format", "json",
            "--registry",
            "--api", "clearlydefined"
        ])

        if upmex_maven_result.returncode == 0 and upmex_maven_result.stdout:
            maven_data = json.loads(upmex_maven_result.stdout)
            if maven_data.get("license"):
                result["declared_license"] = maven_data["license"]
                result["metadata"]["license"] = maven_data["license"]
                result["metadata"]["license_source"] = "parent_pom_via_clearlydefined"
                logger.info(f"Maven parent POM license found: {maven_data['license']}")
    except Exception as e:
        logger.warning(f"Maven parent POM resolution failed: {e}")

Updated tool docstring - Added Maven-specific documentation

Version Updates

  • mcp_semclone/__init__.py: 1.5.8 → 1.5.9
  • pyproject.toml: 1.5.8 → 1.5.9
  • examples/strands-agent-ollama/requirements.txt: 1.5.8 → 1.5.9

CHANGELOG.md

Documented Maven parent POM enhancement with examples and impact

tests/test_server.py

Added test_maven_parent_pom_resolution:

  • Verifies Maven package detection
  • Confirms upmex called twice (normal + with --registry --api)
  • Validates parent POM license extraction
  • Checks license_source metadata tracking

Testing

pytest tests/test_server.py::TestDownloadAndScanPackage -v

Results:

tests/test_server.py::TestDownloadAndScanPackage::test_purl2notices_success PASSED [ 16%]
tests/test_server.py::TestDownloadAndScanPackage::test_deep_scan_fallback PASSED [ 33%]
tests/test_server.py::TestDownloadAndScanPackage::test_online_fallback PASSED [ 50%]
tests/test_server.py::TestDownloadAndScanPackage::test_all_methods_fail PASSED [ 66%]
tests/test_server.py::TestDownloadAndScanPackage::test_keep_download PASSED [ 83%]
tests/test_server.py::TestDownloadAndScanPackage::test_maven_parent_pom_resolution PASSED [100%]

============================== 6 passed in 0.22s

Impact

✅ Maven packages now correctly report licenses from parent POMs
✅ Automatic detection - no user configuration needed
✅ Transparent tracking with license_source field
✅ Graceful fallback if parent POM resolution fails
✅ Zero breaking changes - fully backward compatible

User Feedback

User identified the issue:

"for maven packages that don't have license declared, we should use upmex with parent pom feature"

This enhancement directly addresses that feedback by automatically resolving parent POM licenses for Maven packages.

Release

Version: 1.5.9
Type: Enhancement
Breaking Changes: None

…ckage

PROBLEM:
Maven packages often declare licenses in parent POMs rather than in the
package POM itself. The download_and_scan_package tool would return no
license information for such packages even though the license exists.

SOLUTION:
Added Maven-specific license resolution using upmex with --registry and
--api clearlydefined flags to query ClearlyDefined, which resolves parent
POM licenses automatically.

WORKFLOW ENHANCEMENT:
After scanning a Maven package (pkg:maven/...), if no license is found:
1. Detects it's a Maven package (purl.startswith('pkg:maven/'))
2. Calls upmex extract with --registry --api clearlydefined flags
3. ClearlyDefined API resolves parent POM licenses
4. Updates result with license and license_source = 'parent_pom_via_clearlydefined'

CHANGES:
- mcp_semclone/server.py:
  * Added Maven package detection (line 2059)
  * Added parent POM resolution logic (lines 2060-2078)
  * Updated tool docstring with Maven-specific behavior
- mcp_semclone/__init__.py: Bump version 1.5.8 → 1.5.9
- pyproject.toml: Bump version 1.5.8 → 1.5.9
- examples/strands-agent-ollama/requirements.txt: Update dependency
- CHANGELOG.md: Document Maven parent POM enhancement
- tests/test_server.py: Add test_maven_parent_pom_resolution

TESTING:
✅ All 6 download_and_scan_package tests pass
✅ New test verifies parent POM resolution workflow
✅ Confirms upmex called twice (normal + with --registry --api)
✅ Validates license_source metadata tracking

IMPACT:
✅ Maven packages now correctly report licenses from parent POMs
✅ Automatic detection - no user configuration needed
✅ Transparent tracking with license_source field
✅ Graceful fallback if parent POM resolution fails

USER FEEDBACK:
User identified that Maven packages without declared licenses should use
upmex parent POM feature to resolve licenses from parent POMs.
ENHANCEMENT:
Improved Maven parent POM resolution to properly combine licenses found in:
1. Source file headers (detected by osslili)
2. Maven parent POM (resolved via ClearlyDefined)

CHANGES:
- mcp_semclone/server.py:
  * Added detailed comment explaining 3 license sources
  * Parent POM license now added to detected_licenses list
  * Enhanced logging showing combined licenses
  * Improved scan_summary to indicate parent POM source
  * Better summary generation with multiple parts

- tests/test_server.py:
  * Added test_maven_combined_source_and_parent_pom_licenses
  * Verifies both source headers and parent POM licenses are detected
  * Confirms both appear in detected_licenses list
  * Validates summary mentions parent POM

EXAMPLE:
Maven package with MIT in source headers + Apache-2.0 in parent POM:
{
  "declared_license": "Apache-2.0",  # From parent POM
  "detected_licenses": ["MIT", "Apache-2.0"],  # Both sources
  "metadata": {
    "license_source": "parent_pom_via_clearlydefined"
  },
  "scan_summary": "Deep scan completed. found 2 licenses. (includes parent POM license). 1 copyrights."
}

TESTING:
✅ All 7 download_and_scan_package tests pass
✅ New test verifies license combination
✅ Confirms parent POM license added to detected_licenses

USER FEEDBACK:
User noted: "sometimes when license is not detect in the metadata or as
license file, the license could also be in the source header of files, or
in maven, in the parent pom, consider both"
… detection

Updated v1.5.9 changelog to clarify that the tool now checks:
1. Source file headers (osslili)
2. Package POM (upmex)
3. Parent POM (upmex with --registry --api clearlydefined)

Added two example scenarios:
1. License only in parent POM
2. Licenses in BOTH source headers AND parent POM

Expanded Changes and Impact sections to reflect full functionality.
@oscarvalenzuelab
Copy link
Contributor Author

Enhancement Update

Added comprehensive handling of licenses from multiple sources for Maven packages:

Three License Sources Now Checked

  1. Source file headersosslili scans all source files
  2. Package POM metadataupmex extract reads package POM
  3. Parent POMupmex extract --registry --api clearlydefined resolves parent POM licenses

New Behavior

Combines licenses from all sources:

  • Source header licenses (e.g., MIT, BSD) detected by osslili
  • Parent POM licenses (e.g., Apache-2.0) resolved via ClearlyDefined
  • Both added to detected_licenses array
  • Parent POM license set as declared_license
  • Marked with license_source: "parent_pom_via_clearlydefined"

Example Output

Maven package with MIT in source headers + Apache-2.0 in parent POM:

{
  "declared_license": "Apache-2.0",
  "detected_licenses": ["MIT", "Apache-2.0"],
  "metadata": {
    "license_source": "parent_pom_via_clearlydefined"
  },
  "scan_summary": "Deep scan completed. found 2 licenses. (includes parent POM license). 1 copyrights."
}

Testing

Added new test: test_maven_combined_source_and_parent_pom_licenses

All 7 tests pass:

tests/test_server.py::TestDownloadAndScanPackage::test_purl2notices_success PASSED
tests/test_server.py::TestDownloadAndScanPackage::test_deep_scan_fallback PASSED
tests/test_server.py::TestDownloadAndScanPackage::test_online_fallback PASSED
tests/test_server.py::TestDownloadAndScanPackage::test_all_methods_fail PASSED
tests/test_server.py::TestDownloadAndScanPackage::test_keep_download PASSED
tests/test_server.py::TestDownloadAndScanPackage::test_maven_parent_pom_resolution PASSED
tests/test_server.py::TestDownloadAndScanPackage::test_maven_combined_source_and_parent_pom_licenses PASSED ✨

User Feedback Addressed

"sometimes when license is not detect in the metadata or as license file, the license could also be in the source header of files, or in maven, in the parent pom, consider both"

✅ Now considers both source headers AND parent POM
✅ Combines results transparently
✅ Summary indicates multiple sources

Maven parent POM resolution is a significant new feature, so using
a minor version bump (1.6.0) instead of patch (1.5.9) to better
follow semantic versioning conventions.

CHANGES:
- mcp_semclone/__init__.py: 1.5.9 → 1.6.0
- pyproject.toml: 1.5.9 → 1.6.0
- examples/strands-agent-ollama/requirements.txt: 1.5.9 → 1.6.0
- CHANGELOG.md: Updated [1.5.9] → [1.6.0] and section from 'Enhanced' to 'Added'
- CHANGELOG.md: Updated example comment from v1.5.9 → v1.6.0

REASONING:
- v1.5.8: Critical bugfix + redesign
- v1.6.0: New feature (Maven parent POM resolution)
- Minor version bump signals new functionality vs patch-level fixes
@oscarvalenzuelab oscarvalenzuelab changed the title feat: Add Maven parent POM license resolution (v1.5.9) feat: Add Maven parent POM license resolution (v1.6.0) Nov 14, 2025
@oscarvalenzuelab oscarvalenzuelab merged commit 99c6837 into main Nov 14, 2025
2 checks passed
@oscarvalenzuelab oscarvalenzuelab deleted the feature/maven-parent-pom-resolution branch November 14, 2025 04:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant