{"id":52051060,"url":"https://github.com/graylog2/strict-rrf-maven-extension","last_synced_at":"2026-08-02T13:00:44.769Z","repository":{"id":365944280,"uuid":"1129169323","full_name":"Graylog2/strict-rrf-maven-extension","owner":"Graylog2","description":"Strict Remote Repository Filtering extension for Maven","archived":false,"fork":false,"pushed_at":"2026-07-02T00:05:10.000Z","size":168,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-03T19:40:09.983Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Graylog2.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":"CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-01-06T17:49:16.000Z","updated_at":"2026-06-29T08:52:00.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/Graylog2/strict-rrf-maven-extension","commit_stats":null,"previous_names":["graylog2/strict-rrf-maven-extension"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/Graylog2/strict-rrf-maven-extension","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Graylog2%2Fstrict-rrf-maven-extension","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Graylog2%2Fstrict-rrf-maven-extension/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Graylog2%2Fstrict-rrf-maven-extension/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Graylog2%2Fstrict-rrf-maven-extension/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Graylog2","download_url":"https://codeload.github.com/Graylog2/strict-rrf-maven-extension/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Graylog2%2Fstrict-rrf-maven-extension/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":36193575,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-07-20T02:08:10.276Z","status":"online","status_checked_at":"2026-08-02T02:00:06.915Z","response_time":58,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-08-02T13:00:40.947Z","updated_at":"2026-08-02T13:00:44.752Z","avatar_url":"https://github.com/Graylog2.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Strict Remote Repository Filter Maven Extension\n\n[![CI](https://github.com/Graylog2/strict-rrf-maven-extension/actions/workflows/ci.yml/badge.svg)](https://github.com/Graylog2/strict-rrf-maven-extension/actions/workflows/ci.yml)\n\nA Maven extension that implements the Maven Resolver Remote Repository Filter SPI. This extension provides properties-based configuration for filtering artifacts and metadata from remote Maven repositories.\n\n## Features\n\n- **Fail-secure Design**: Blocks all artifacts when no configuration exists\n- **Flexible Pattern Matching**: Support for groupId and coordinate patterns with wildcards\n- **Properties-based Configuration**: Use text files to configure filtering rules per repository\n\n## How It Works\n\nThe filter uses a single `strict.properties` configuration file to define allow and deny rules for multiple repositories:\n\n- **Default Deny**: Everything is denied by default unless explicitly allowed\n- **Allow Rules**: Define which groupIds and artifacts are permitted from a repository\n- **Deny Rules**: Override allow rules to block specific patterns\n- **Glob Patterns**: Support wildcards (`*`) for flexible matching\n- **Fail-secure**: If no configuration exists for a repository, all artifacts are blocked\n- **Enabled by Default**: The filter activates automatically when the extension is registered\n\n## Installation\n\nCreate `.mvn/extensions.xml` in your project root:\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n\u003cextensions\u003e\n    \u003cextension\u003e\n        \u003cgroupId\u003eorg.graylog.maven\u003c/groupId\u003e\n        \u003cartifactId\u003estrict-rrf-maven-extension\u003c/artifactId\u003e\n        \u003cversion\u003e0.3.0\u003c/version\u003e\n    \u003c/extension\u003e\n\u003c/extensions\u003e\n```\n\n## Configuration\n\n### Filter Behavior\n\nThe filter is **enabled by default** when the extension is registered in `.mvn/extensions.xml`.\n\nTo **disable** the filter:\n\n```bash\nmvn clean install -Daether.remoteRepositoryFilter.strict.enabled=false\n```\n\nOr configure in `.mvn/maven.config`:\n\n```\n-Daether.remoteRepositoryFilter.strict.enabled=false\n```\n\n### Configuration Properties\n\n| Property | Type | Default | Description |\n|----------|------|---------|-------------|\n| `aether.remoteRepositoryFilter.strict.enabled` | boolean | **true** | Enable/disable the filter globally |\n| `aether.remoteRepositoryFilter.strict.basedir` | string | `.remoteRepositoryFilters` | Base directory for config files (relative to local repository: `~/.m2/repository/.remoteRepositoryFilters`) |\n\n### Configuration File\n\nA single configuration file named `strict.properties` should be placed in the filter basedir.\n\n**Default location**: `~/.m2/repository/.remoteRepositoryFilters/strict.properties` (global configuration in local repository)\n\n**Project-specific location (recommended)**: Place `strict.properties` in your project's\n`.mvn/remoteRepositoryFilters/` directory. It is discovered automatically — no `.mvn/maven.config`\nor `basedir` property is required.\n\n**Lookup order** (when `basedir` is not set, first match wins):\n\n1. `\u003cprojectRoot\u003e/.mvn/remoteRepositoryFilters/strict.properties` — project-local config\n   (`\u003cprojectRoot\u003e` is the directory containing the topmost `.mvn`). A present file is authoritative\n   even when empty (fail-secure).\n2. `~/.m2/repository/.remoteRepositoryFilters/strict.properties` — global config in the local repository.\n\nSetting `-Daether.remoteRepositoryFilter.strict.basedir=\u003cdir\u003e` explicitly bypasses this lookup and\nuses `\u003cdir\u003e` as the single configuration location.\n\n### File Format\n\nThe properties file defines allow and deny rules per repository:\n\n```properties\n# Shibboleth repository - allow and deny rules\nrepo.shibboleth.allow = org.opensaml*,net.shibboleth*\nrepo.shibboleth.deny = org.opensaml.internal*,net.shibboleth.internal*\n\n# Maven Central - groupId patterns with wildcards\nrepo.central.allow = org.graylog*,org.apache.maven*,org.springframework*\n\n# Company repository - coordinate patterns (groupId:artifactId)\nrepo.company.allow = com.company:*,com.other:lib-*\n\n# Mixed patterns - both groupId and coordinate patterns\nrepo.test.allow = org.junit*,com.google:guava,com.google:gson\n\n# Lines starting with # are comments\n# Empty lines are ignored\n```\n\n**Format Rules**:\n- **Allow rule**: `repo.{repositoryId}.allow = pattern1,pattern2,...`\n  - GroupId exact match: `org.graylog` (matches only exact groupId `org.graylog`)\n  - GroupId wildcard: `org.graylog*` (matches `org.graylog` and all sub-packages like `org.graylog.plugin`)\n  - Coordinate pattern: `com.company:*` (matches all artifacts in groupId `com.company`)\n  - Coordinate pattern: `com.test:lib-*` (matches artifacts starting with \"lib-\" in groupId `com.test`)\n  - Coordinate exact match: `com.google:guava` (matches only the specific artifact)\n- **Deny rule**: `repo.{repositoryId}.deny = pattern1,pattern2,...`\n  - Same pattern formats as allow rules\n- Whitespace around keys, values, and commas is automatically trimmed\n- Comments start with `#`\n- Empty lines are ignored\n\n### Repository IDs and Mirrors\n\nThe `{repositoryId}` in each rule must be the ID of the repository that Maven **actually\ndownloads from** — which is *not* always the ID declared in your POM or in Maven's default\nrepositories.\n\nWhen a mirror is configured in `settings.xml`, Maven replaces the mirrored repository with the\nmirror before any download. The filter therefore sees the **mirror's ID**, not the original one.\nGiven this mirror:\n\n```xml\n\u003cmirror\u003e\n  \u003cid\u003enexus\u003c/id\u003e\n  \u003cmirrorOf\u003e*\u003c/mirrorOf\u003e\n  \u003curl\u003ehttps://nexus.internal/repository/maven-public\u003c/url\u003e\n\u003c/mirror\u003e\n```\n\nrules must be keyed to `nexus`, not `central`:\n\n```properties\n# Correct: the resolver fetches everything through the \"nexus\" mirror\nrepo.nexus.allow = org.graylog*,org.apache.maven*\n\n# Has no effect when the above mirror is active — \"central\" is never contacted directly\nrepo.central.allow = org.graylog*\n```\n\nThis is intentional and fail-secure: a mirror is a distinct download source and must be allowed\nexplicitly, just like any other repository. If no rule matches the effective repository ID, **all\nartifacts from it are blocked**. A rule written for the wrong ID does not loosen the filter — it\nsimply never matches, so the build fails to resolve dependencies rather than fetching them\ninsecurely.\n\n**Finding the effective repository ID**: run a build once with the filter disabled\n(`-Daether.remoteRepositoryFilter.strict.enabled=false`) and check which ID artifacts are stored\nunder in `~/.m2/repository` (see the `_remote.repositories` marker files), or enable debug logging\n(see [Debugging](#debugging)) and look for the `from repository: \u003cid\u003e` messages.\n\n### Filtering Logic\n\nThe filter works in this order:\n\n1. **Default Deny**: If no `.allow` patterns are specified, everything is denied\n2. **Check Allow**: If artifact matches any `.allow` pattern, proceed to step 3; otherwise deny\n3. **Check Deny**: If artifact matches any `.deny` pattern, deny; otherwise allow\n\n**Pattern Matching**:\n\nPatterns support both groupId-only and full coordinate (groupId:artifactId) patterns:\n\n#### GroupId-Only Patterns\n\n- **Exact match** (no wildcard):\n  - `org.graylog` matches only: `org.graylog:*` (exact groupId match)\n  - Does NOT match: `org.graylog.plugin:*`, `org.graylog2:*`\n\n- **Wildcard matching**:\n  - `org.graylog*` matches: `org.graylog:*`, `org.graylog.plugin:*`, `org.graylog.server.*:*`\n  - `com.google.*` matches: `com.google.foo:*`, `com.google.bar.baz:*`\n  - Does NOT match: `com.google:*` (requires dot after google)\n  - `com.google*` matches: `com.google:*`, `com.googlecode:*`, `com.google.foo:*`\n  - `*` matches: everything\n\n#### Coordinate Patterns (groupId:artifactId)\n\n- **Wildcard artifactId**:\n  - `com.opensaml:*` matches: any artifact in groupId `com.opensaml`\n  - Example: `com.opensaml:opensaml-core`, `com.opensaml:opensaml-saml`\n\n- **Pattern artifactId**:\n  - `com.foobar:test-*` matches: artifacts starting with \"test-\" in groupId `com.foobar`\n  - Example: `com.foobar:test-utils`, `com.foobar:test-core`\n  - Does NOT match: `com.foobar:production-lib`\n\n- **Exact artifactId**:\n  - `com.google:guava` matches: only `com.google:guava`\n  - Does NOT match: `com.google:gson` or other artifacts from `com.google`\n\n- **Mixed patterns**:\n  - You can mix groupId-only and coordinate patterns in the same rule:\n  - `repo.test.allow = org.graylog,com.opensaml:*,com.test:lib-*`\n  - This allows: all `org.graylog.*` artifacts, all `com.opensaml` artifacts, and `com.test:lib-*` artifacts\n\n## Usage Examples\n\n### Example 1: Restrict Maven Central (Global Configuration)\n\nCreate `~/.m2/repository/.remoteRepositoryFilters/strict.properties`:\n\n```properties\n# Only allow these groupIds from Maven Central (with wildcards to include sub-packages)\nrepo.central.allow = org.graylog*,org.apache.maven*,org.apache.commons*\n```\n\nRun Maven (filter is enabled by default):\n\n```bash\nmvn clean compile\n```\n\nOnly artifacts from the allowed groupIds and their sub-packages will be fetched from Maven Central. Everything else is denied by default.\n\n**For project-specific configuration**, simply create `.mvn/remoteRepositoryFilters/strict.properties` in your project root with the same content. It is discovered automatically — no `.mvn/maven.config` or `basedir` property is required. (See the \"Configuration File\" section above for the full lookup order.)\n\n### Example 2: Allow with Deny Overrides\n\nAllow broad groupIds but deny specific sub-packages:\n\n```properties\n# Shibboleth repository - allow main packages (with wildcards)\nrepo.shibboleth.allow = org.opensaml*,net.shibboleth*\n\n# But deny internal packages\nrepo.shibboleth.deny = org.opensaml.internal*,net.shibboleth.internal*\n```\n\nThis allows `org.opensaml:opensaml-core` and `org.opensaml.core:*` but denies `org.opensaml.internal:something`.\n\n### Example 3: Multiple Repositories\n\nConfigure multiple repositories in a single file:\n\n```properties\n# Shibboleth repository\nrepo.shibboleth.allow = org.opensaml*,net.shibboleth*\nrepo.shibboleth.deny = *.internal*\n\n# Maven Central\nrepo.central.allow = org.graylog*,org.apache.maven*\n\n# Company internal repository\nrepo.company-nexus.allow = com.company*,com.company.internal*\n```\n\n### Example 4: Glob Pattern Wildcards\n\nUse wildcards for flexible matching:\n\n```properties\n# Allow all Google libraries\nrepo.central.allow = com.google*\n\n# But deny test utilities\nrepo.central.deny = com.google.*.test*\n\n# Allow anything from company, deny snapshots\nrepo.company.allow = com.mycompany*\nrepo.company.deny = *-SNAPSHOT\n```\n\n### Example 5: Coordinate-Based Filtering\n\nRestrict specific artifacts using full coordinates:\n\n```properties\n# Allow only specific Google artifacts (exact match)\nrepo.central.allow = com.google:guava,com.google:gson\n\n# Allow all OpenSAML artifacts\nrepo.shibboleth.allow = com.opensaml:*,net.shibboleth:*\n\n# Allow test utilities only\nrepo.test-repo.allow = com.company:test-*,org.junit:*\n\n# Allow all from groupId but deny specific artifacts\nrepo.central.allow = org.apache.commons:*\nrepo.central.deny = org.apache.commons:commons-io\n\n# Mix groupId and coordinate patterns\nrepo.central.allow = org.graylog*,com.opensaml:*,com.google:guava\n```\n\n### Example 6: Custom Config Directory\n\nUse a custom config directory (different from the default `.mvn/remoteRepositoryFilters`):\n\n```bash\nmvn clean install \\\n  -Daether.remoteRepositoryFilter.strict.basedir=${session.rootDirectory}/.mvn/custom-config\n```\n\nOr add to `.mvn/maven.config`:\n```\n-Daether.remoteRepositoryFilter.strict.basedir=${session.rootDirectory}/.mvn/custom-config\n```\n\nCreate `strict.properties` in `.mvn/custom-config/` in your project:\n\n```\n.mvn/\n  custom-config/\n    strict.properties\n```\n\n### Example 7: Temporarily Disable Filter\n\n```bash\nmvn clean install \\\n  -Daether.remoteRepositoryFilter.strict.enabled=false\n```\n\nThis disables the filter entirely for this build.\n\n## Architecture\n\nThe extension consists of 4 main classes:\n\n1. **StrictRemoteRepositoryFilterSource** - SPI entry point with `@Named(\"strict\")` annotation\n2. **StrictRemoteRepositoryFilter** - Implements the filtering logic\n3. **StrictFilterConfiguration** - Loads and provides configuration\n4. **SimpleFilterResult** - Result object for filter decisions\n\nMaven discovers the extension via Sisu/JSR-330 dependency injection. The `@Named(\"strict\")` annotation makes \"strict\" the filter identifier used in system properties.\n\n## Testing\n\nRun unit tests:\n\n```bash\nmvn test\n```\n\nThe test suite includes:\n- Configuration loading from files\n- Empty/missing configuration handling\n- Artifact filtering with exact and wildcard matching\n- Metadata filtering\n- Relative and absolute path resolution\n- Multiple repository configurations\n\n## Debugging\n\nEnable Maven debug output to see filter activity:\n\n```bash\nmvn clean compile -X\n```\n\nLook for log messages from `StrictRemoteRepositoryFilterSource` and `StrictRemoteRepositoryFilter`.\n\n## Requirements\n\n- **Maven**: 3.9.0 or later\n- **Java**: 17 or later\n\n## Important Notes\n\n1. **The filter is enabled by default** - when you register the extension in `.mvn/extensions.xml`, it activates automatically\n2. **Fail-secure behavior** - blocks all artifacts when no configuration exists\n3. **Not for security** - use `maven-enforcer-plugin` for dependency policies\n4. **Optimization tool** - designed to reduce unnecessary 404 requests and improve privacy\n\n## References\n\n- [Maven Resolver Remote Repository Filtering](https://maven.apache.org/resolver/remote-repository-filtering.html)\n- [Maven Extension Guide](https://maven.apache.org/guides/mini/guide-using-extensions.html)\n- [Maven Resolver SPI](https://maven.apache.org/resolver/maven-resolver-spi/)\n\n---\n\n*This project was developed with [Claude Code](https://claude.com/claude-code).*\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgraylog2%2Fstrict-rrf-maven-extension","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgraylog2%2Fstrict-rrf-maven-extension","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgraylog2%2Fstrict-rrf-maven-extension/lists"}