Skip to content

feat(ENG-13683): add Maven credential helper - #339

Open
cloudsmith-iduffy wants to merge 1 commit into
masterfrom
maven-shell-plugin
Open

feat(ENG-13683): add Maven credential helper#339
cloudsmith-iduffy wants to merge 1 commit into
masterfrom
maven-shell-plugin

Conversation

@cloudsmith-iduffy

@cloudsmith-iduffy cloudsmith-iduffy commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Description

The last of the stack, rebased onto master now that #336, #337 and #338 have
landed, and squashed to a single commit.

Maven has no credential-helper protocol, so this authenticates it with a shell
plugin instead. credential-helper install maven --org <org> --repo <repo>
writes an mvn shim that wraps every invocation in cloudsmith exec, which
injects an ephemeral mode-0600 settings.xml via mvn -s and deletes it when
the run ends — no token is ever written to durable configuration.

  • credential-helper shell-init prints the shell initialisation (bash, zsh,
    fish) that puts the shims directory first on PATH.
  • cloudsmith exec -- <command> is callable directly, for CI that should not
    touch PATH.
  • Publishing is opt-in: install prints the distributionManagement snippet to
    add to pom.xml.
  • Custom download/upload domains are discovered from the organisation at
    install time. Domains bound to a single repository are left out — they need
    URLs of a different shape, which is its own change — so a repository-scoped
    domain falls back to the default host. Which kind each host is gets recorded
    in package-managers.ini, so wrapped runs need no lookup — the run path
    makes no API call and no cache read.

Credential binding. One <server> id covers download and upload. It
defaults to the literal cloudsmith, matching the distributionManagement
snippet install prints, so a team can share one pom.xml. Maven matches a
server's credentials to a repository by id alone, with no host check, so a
checked-out pom.xml declaring a repository under that id receives the token
on an ordinary mvn compile — the same exposure as the ~/.m2/settings.xml a
Maven user would otherwise keep. Pass --server-id at install time to bind
the credential to an id a third-party pom.xml cannot guess; minting a random
id by default would break a team sharing one pom.xml, so it is opt-in.
Documented in the CHANGELOG's Security section and settings.py's module
docstring.

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update
  • Refactoring
  • Other (please describe)

Additional Notes

Test suite: 682 passed, 40 skipped at this commit.

An earlier, larger draft of this branch was verified end to end in GitHub
Actions with OIDC as the only credential
(run):
a plain mvn -B clean deploy resolved a private dependency through the
organisation's discovered custom domain and published the built jar to
maven.cloudsmith.io/iduffy-demo/default/. That draft carried a cached
settings.xml, a shell fast path and deploy-goal detection; this PR ships
without them to halve the diff, and the shim path itself is unchanged.

Two things a reviewer should know:

  • Wrapped runs do not consult ~/.m2/settings.xml; mirrors, proxies and other
    <server> entries are not seen. Passing your own -s/--settings runs Maven
    unwrapped, with a warning. This is the designed mechanism — Maven has no
    settings-merge — and is called out at install time and in the CHANGELOG.
  • One known limitation ships knowingly. The ephemeral settings.xml is removed
    in a finally, so a SIGKILL/SIGTERM of cloudsmith exec (a cancelled CI step)
    leaves the 0600 token file in /tmp until the agent is recycled; a signal
    handler is the fix and wants its own change.

@cloudsmith-iduffy cloudsmith-iduffy changed the title maven shell plugin feat(ENG-13683): add Maven credential helper via shell plugin Aug 1, 2026
@BartoszBlizniak
BartoszBlizniak changed the base branch from credential-generic to custom-domains August 3, 2026 11:45
cloudsmith-iduffy added a commit that referenced this pull request Aug 4, 2026
This branch shipped an API surface nothing in it calls. Every consumer is in
the Maven helper (#339), which is stacked on top of this branch, so the code
and its tests move there, where the first caller lives and where a reviewer
can see what they are for.

Moved: select_custom_domain and CustomDomain.serves_repository; the
single-host resolvers default_host, default_host_for_type, builtin_host and
builtin_host_for_type with their two private helpers; and domain_scope.
With them go the twelve select_custom_domain tests, the six host-resolver
tests and the persisted-scope test.

Staying: _precedence_key and the CustomDomain.scope / is_bound_to pair it
reads, because get_format_domains sorts by it and the Docker installer and
runtime helper both call that. The DomainScope enum stays with them; only
its string parser moves.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Base automatically changed from custom-domains to master August 9, 2026 01:15
@cloudsmith-iduffy
cloudsmith-iduffy force-pushed the maven-shell-plugin branch 2 times, most recently from d58abdb to da913d2 Compare August 9, 2026 02:35
@cloudsmith-iduffy cloudsmith-iduffy changed the title feat(ENG-13683): add Maven credential helper via shell plugin feat(ENG-13683): add Maven credential helper Aug 16, 2026
@cloudsmith-iduffy
cloudsmith-iduffy marked this pull request as ready for review August 16, 2026 20:09
@cloudsmith-iduffy
cloudsmith-iduffy requested a review from a team as a code owner August 16, 2026 20:09
Copilot AI lite review requested due to automatic review settings August 16, 2026 20:09

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds Maven support to the credential-helper stack by installing an mvn shim that routes through a new cloudsmith exec command, which injects an ephemeral settings.xml (mode 0600) for authenticated dependency resolution and optional publishing, and cleans it up after each run. This extends the existing credential-helper infrastructure (launchers + default/custom domain handling) and adds targeted CLI wiring plus tests.

Changes:

  • Added Maven credential-helper implementation (binding persistence, domain selection, settings.xml generation, and runtime wrapper that injects -s <temp settings.xml> for Maven invocations).
  • Added cloudsmith exec -- <command> and cloudsmith credential-helper shell-init to support shim-based workflows and CI usage without PATH mutation.
  • Refactored/extended helper plumbing for frozen builds and default-domain resolution, plus comprehensive tests and CHANGELOG entries.

Reviewed changes

Copilot reviewed 21 out of 21 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
cloudsmith_cli/templates/maven_settings.xml.tmpl New template for injected Maven settings.xml (server credentials + active profile + repo URLs).
cloudsmith_cli/templates/maven_distribution_management.xml.tmpl New template for opt-in distributionManagement snippet for publishing.
cloudsmith_cli/credential_helpers/maven/settings.py Builds and securely writes ephemeral settings.xml; constructs download/upload URLs.
cloudsmith_cli/credential_helpers/maven/runner.py Implements runtime command wrapper (cloudsmith exec) and Maven detection/settings injection logic.
cloudsmith_cli/credential_helpers/maven/installer.py Implements install/uninstall/status for Maven shim and repository/domain binding.
cloudsmith_cli/credential_helpers/maven/config.py Persists Maven binding in package-managers.ini and defines shims directory.
cloudsmith_cli/credential_helpers/maven/init.py Adds Maven helper package entry point/module doc.
cloudsmith_cli/credential_helpers/launchers.py Adds frozen-build-safe command construction and public launcher filename helper.
cloudsmith_cli/credential_helpers/docker/installer.py Switches Docker launcher target command to shared cloudsmith_command(...) helper.
cloudsmith_cli/credential_helpers/default_domains.py Adds default_host/default_host_for_type helpers that honor trusted [domains] overrides strictly.
cloudsmith_cli/credential_helpers/common.py Adds default-host detection and repository path shaping based on host kind.
cloudsmith_cli/cli/tests/commands/test_default_domains.py Adds coverage for new default-host resolution semantics (including strict override behavior).
cloudsmith_cli/cli/tests/commands/test_credential_helper_maven.py New tests for Maven settings generation, binding persistence, and exec/shim runtime behavior.
cloudsmith_cli/cli/tests/commands/test_credential_helper_maven_installer.py New tests for Maven install/uninstall/list wiring and domain-binding behavior.
cloudsmith_cli/cli/tests/commands/conftest.py Adds fixtures for isolated CLI config dir and a resolved credential for helper tests.
cloudsmith_cli/cli/commands/exec_.py New cloudsmith exec Click command that resolves credentials and runs the wrapper.
cloudsmith_cli/cli/commands/credential_helper/shell.py New credential-helper shell-init command for PATH initialization snippets (bash/zsh/fish).
cloudsmith_cli/cli/commands/credential_helper/manage.py Wires Maven into credential-helper install/uninstall; adds --repo and --server-id.
cloudsmith_cli/cli/commands/credential_helper/init.py Registers shell-init and updates help text/examples to include Maven + generic usage.
cloudsmith_cli/cli/commands/init.py Registers new exec_ command module for CLI import-time command registration.
CHANGELOG.md Documents new Maven helper, exec, and shell-init, plus Maven server-id security note.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +80 to +81
if not (org and credential):
return []
Comment on lines +118 to +122
def _write(parser: configparser.ConfigParser) -> None:
path = config_path()
path.parent.mkdir(parents=True, exist_ok=True)
with click.open_file(str(path), "w") as handle:
parser.write(handle)
Maven has no credential-helper protocol, so `credential-helper install
maven --org <org> --repo <repo>` writes an `mvn` shim that wraps every
invocation in `cloudsmith exec`. Wrapped runs get a mode-0600
settings.xml injected via `mvn -s` and deleted when the run ends, so
dependency resolution authenticates with no pom.xml edits and nothing is
ever written to ~/.m2.

`cloudsmith exec -- <command>` is the same machinery callable directly,
for CI that would rather not touch PATH. `credential-helper shell-init`
prints the PATH line that activates the shims directory.

Publishing stays opt-in: install prints the distributionManagement
snippet to paste into pom.xml, keyed by the same `<server>` id the
generated settings.xml uses (`cloudsmith`, or `--server-id`).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants