feat(ENG-13683): add Maven credential helper via shell plugin - #339
Draft
cloudsmith-iduffy wants to merge 1 commit into
Draft
feat(ENG-13683): add Maven credential helper via shell plugin#339cloudsmith-iduffy wants to merge 1 commit into
cloudsmith-iduffy wants to merge 1 commit into
Conversation
6 tasks
BartoszBlizniak
force-pushed
the
maven-shell-plugin
branch
from
August 3, 2026 11:45
446fb8d to
8479726
Compare
BartoszBlizniak
changed the base branch from
credential-generic
to
custom-domains
August 3, 2026 11:45
BartoszBlizniak
force-pushed
the
maven-shell-plugin
branch
from
August 4, 2026 08:36
8479726 to
ec1bba9
Compare
6 tasks
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>
cloudsmith-iduffy
force-pushed
the
maven-shell-plugin
branch
from
August 9, 2026 01:29
ae3ed6d to
d58abdb
Compare
Maven has no credential-helper protocol, so there is nothing to install a launcher for. This adds a shell plugin instead: an `mvn` shim that wraps every invocation in `cloudsmith exec`, which provisions credentials for that single run and cleans them up afterwards. `cloudsmith credential-helper install maven --org <org> --repo <repo>` writes the shim into the Cloudsmith shims directory and records the binding (org, repo, resolved download/upload hosts, registry id) in `package-managers.ini`. `credential-helper shell-init` emits the bash/zsh/fish snippet that puts the shims directory first on PATH. A wrapped run resolves dependencies through an ephemeral, mode-0600 `settings.xml` injected via `mvn -s` and deleted when the run ends, so no token is ever written to durable configuration. Maven matches a `<server>` to a repository by id alone, with no host check, so the injected download credential is bound to a random id minted per invocation; the stable id named in `distributionManagement` is supplied only when the invocation is actually a deploy. Publishing stays opt-in: `install` prints the snippet to paste into `pom.xml`. A user-supplied `-s/--settings` runs Maven unwrapped, with a warning, rather than silently shadowing their file. Custom domains are discovered as for the Docker helper and ranked the way the server ranks overlapping domains, so the binding records the host Cloudsmith would itself serve. A repository-scoped domain identifies the repository on its own, so its URLs carry neither org nor repo segment; because it serves only the repository it was discovered for, `cloudsmith exec --repo <other>` resets it to the default host for that invocation. Alongside it: - `cloudsmith exec -- <command>` is callable directly, for CI that would rather not touch PATH. The package manager is detected from the command name; `--org`/`--repo` flags override the stored binding, while the same values from the environment or config.ini apply only when nothing is stored, since OIDC users keep CLOUDSMITH_ORG exported permanently. - `default_domains` gains host resolution by backend kind and by domain type, honouring a trusted `[domains]` override, plus `DomainScope` for what a discovered domain is bound to; `common` gains the URL path-segment rule that follows from it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
cloudsmith-iduffy
force-pushed
the
maven-shell-plugin
branch
from
August 9, 2026 02:35
d58abdb to
da913d2
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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
mvnshim that wraps every invocation incloudsmith exec, whichinjects an ephemeral mode-0600
settings.xmlviamvn -sand deletes it whenthe run ends — no token is ever written to durable configuration.
credential-helper shell-initprints the shell initialisation (bash, zsh,fish) that puts the shims directory first on
PATH.cloudsmith exec -- <command>is callable directly, for CI that should nottouch
PATH.installprints thedistributionManagementsnippet toadd to
pom.xml.bound to the repository being installed beats an organisation-wide one, and
one bound to a different repository is never used. Which kind each host is
gets recorded in
package-managers.ini, so wrapped runs need no lookup — therun path makes no API call and no cache read.
Credential binding. Maven matches a
<server>to a repository by id alone,with no host check, and the shim applies to every
mvnrun in every directory.A fixed, guessable server id would therefore let any checked-out
pom.xmldeclaring a repository under that id receive the token on an ordinary
mvn compile. So a wrapped run binds the injected download credential to arandom id generated fresh per invocation, and the stable id your
distributionManagementnames is supplied only when the invocation is actuallya deploy.
Type of Change
Additional Notes
Test suite: 783 passed, 40 skipped at this commit.
Verified end to end in GitHub Actions with OIDC as the only credential
(run):
a plain
mvn -B clean deployresolved a private dependency through theorganisation's discovered custom domain
(
dl-prod.iduffy.cloudsmith.sh/basic/default/maven/— no org segment, as acustom domain identifies it) and published the built jar to
maven.cloudsmith.io/iduffy-demo/default/.Two things a reviewer should know:
~/.m2/settings.xml; mirrors, proxies and other<server>entries are not seen. Passing your own-s/--settingsruns Mavenunwrapped, with a warning. This is the designed mechanism — Maven has no
settings-merge — and is called out at install time and in the CHANGELOG.
settings.xmlis removedin a
finally, so a SIGKILL/SIGTERM ofcloudsmith exec(a cancelled CI step)leaves the 0600 token file in
/tmpuntil the agent is recycled; a signalhandler is the fix and wants its own change. And the residual exposure below.
literal
cloudsmith, so on a deploy a hostile checkout can still claim itduring dependency resolution. Minting it as
cloudsmith-<random>at installtime would close it; that changes a default users paste into
pom.xml, so itis deliberately left to its own change. Documented in
build_settings_xml'sdocstring.