Skip to content

feat(no-ticket): add Maven shell-plugin credential helper#314

Draft
cloudsmith-iduffy wants to merge 1 commit into
masterfrom
iduffy/credential-helper-maven
Draft

feat(no-ticket): add Maven shell-plugin credential helper#314
cloudsmith-iduffy wants to merge 1 commit into
masterfrom
iduffy/credential-helper-maven

Conversation

@cloudsmith-iduffy

@cloudsmith-iduffy cloudsmith-iduffy commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Description

Adds a Maven credential helper to the CLI. Maven has no native credential-helper protocol, so this uses a shell-plugin approach: a mvn shim (placed first on PATH via cloudsmith credential-helper shell-init) transparently forwards to cloudsmith exec -- mvn …, which provisions an ephemeral settings.xml from the resolved credential (API key or OIDC), runs the real mvn, and cleans up afterwards.

Highlights:

  • cloudsmith exec — a generic, top-level command that runs any command with Cloudsmith credentials provisioned for it; the package manager is inferred from the command (no format argument), and commands with no integration run unchanged. Plus credential-helper shell-init and install maven (with --repo / --server-id).
  • A single injected <server> authenticates both dependency resolution (download CDN) and distributionManagement (native Maven upload) — Maven matches it by <id>, not host.
  • Custom-domain aware, generically: a reusable common.repo_path_segment helper org-scopes Cloudsmith URLs (a custom domain is bound to one org, so the <org> path segment is dropped; the *.cloudsmith.io defaults keep it). Used by both the download and upload URLs.
  • settings.xml lives in cloudsmith_cli/templates/maven_settings.xml.tmpl (real XML, editor-validated) and is rendered via a shared templates.render() that webserver.py also uses.
  • Shell-plugin state (plugins.json, shims) lives in the CLI config dir (get_default_config_path()), consistent with the custom-domain cache.
  • Built test-first: full suite (552) and pre-commit hooks green.

Proven end-to-end with GitHub OIDC (no API key anywhere) — install, build (download), and a native mvn clean deploy (upload), with ~/.m2 caching:

Type of Change

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

Additional Notes

  • The linked test-repo workflow doubles as a real-world usage example and a living smoke test (OIDC auth, custom-domain discovery, dependency caching). The whole Cloudsmith story is three bare commands: install maven, eval "$(… shell-init)", mvn clean deploy.
  • New subpackages and the template file are picked up by find_packages / existing package_data; no packaging changes needed.

Maven has no native credential-helper protocol, so add a shell-plugin
approach: a `mvn` shim (placed first on PATH via `credential-helper
shell-init`) transparently forwards to the generic top-level `cloudsmith
exec`, which provisions an ephemeral settings.xml from the resolved
credential (API key or OIDC), runs the real `mvn`, and cleans up.

- `cloudsmith exec -- <cmd>`: runs a package-manager command authenticated
  against Cloudsmith. The plugin is inferred from the command's binary name;
  unmatched commands run unchanged. Resolves the real binary while excluding
  the shims dir to avoid recursion, and cleans up temp dirs (even on failure,
  with provisioning errors surfaced as a clean message, never a traceback).
- `credential-helper install maven --org --repo [--registry-id]` and
  `credential-helper shell-init`, wired into the existing installer registry.
- One injected <server> authenticates both dependency resolution (download
  CDN) and distributionManagement (native Maven upload); Maven matches it by
  id. Install prints the distributionManagement snippet for opt-in deploy.
- Custom Cloudsmith domains are org-scoped via a reusable
  common.repo_path_segment (drop <org> for custom domains, keep it for
  *.cloudsmith.io); download custom domains carry backend_kind=None, upload
  custom domains carry BackendKind.MAVEN.
- settings.xml / distributionManagement live in cloudsmith_cli/templates/*.tmpl
  rendered via a shared templates.render() (also adopted by webserver.py).
- Shell-plugin state is stored as [package-manager:<format>] sections in
  package-managers.ini in the CLI config dir, via configparser.
- The `--registry-id` flag and the shared PluginEntry field use a
  package-manager-neutral name (Maven <server> id, NuGet source key, etc.).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@cloudsmith-iduffy cloudsmith-iduffy force-pushed the iduffy/credential-helper-maven branch from 5d8b024 to cbb6c35 Compare June 13, 2026 00:09
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.

1 participant