Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
40a9961
feat: add credential provider chain concept
cloudsmith-iduffy Mar 12, 2026
f30e428
fix: review feedback
cloudsmith-iduffy Mar 31, 2026
05fd479
feat: add Docker credential helper for Cloudsmith registries
cloudsmith-iduffy Mar 31, 2026
5a7ce30
Merge origin/master into iduffy/credential-helper-base
Copilot May 27, 2026
8f5e800
Potential fix for pull request finding 'CodeQL / Incomplete URL subst…
BartoszBlizniak May 27, 2026
78e06ff
fix: copilot feedback
BartoszBlizniak May 28, 2026
f74c304
fix: cache file handling
BartoszBlizniak May 28, 2026
3afe390
fix: move to top level import
BartoszBlizniak Jun 3, 2026
5365f4b
fix: import level and add .com to CS domains
BartoszBlizniak Jun 3, 2026
7e82865
refactor: change custom domain calls to use sdk
BartoszBlizniak Jun 8, 2026
7c157b1
feat(credential-helper): add merge_json_file safe JSON writer
BartoszBlizniak Jun 8, 2026
477132b
feat(credential-helper): structured custom-domain discovery + format …
BartoszBlizniak Jun 8, 2026
455c787
refactor(credential-helper): extract docker runtime + boundary error …
BartoszBlizniak Jun 8, 2026
0633088
feat(credential-helper): add install/uninstall/list command + launchers
BartoszBlizniak Jun 8, 2026
2c56a18
feat(credential-helper): auto-discover Docker custom domains on install
BartoszBlizniak Jun 8, 2026
22f3e2b
fix(credential-helper): honor --bin-dir on uninstall
BartoszBlizniak Jun 8, 2026
7c9891c
feat(credential-helper): support -F/--output-format json for install/…
BartoszBlizniak Jun 8, 2026
75326be
feat(credential-helper): scope docker runtime to docker-format custom…
BartoszBlizniak Jun 8, 2026
fd16243
test(credential-helper): consolidate tests to one-per-behavior
BartoszBlizniak Jun 8, 2026
44cb0e5
fix(credential-helper): make launcher tests Python 3.11-safe
BartoszBlizniak Jun 8, 2026
c527835
fix(credential-helper): harden config merge + exact launcher bytes (c…
BartoszBlizniak Jun 8, 2026
c2ba143
chore(credential-helper): add copyright headers to new modules (copil…
BartoszBlizniak Jun 8, 2026
3aacdfa
Merge branch 'master' into iduffy/credential-helper-base
BartoszBlizniak Jun 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cloudsmith_cli/cli/commands/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
auth,
check,
copy,
credential_helper,
delete,
dependencies,
docs,
Expand Down
39 changes: 39 additions & 0 deletions cloudsmith_cli/cli/commands/credential_helper/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Copyright 2026 Cloudsmith Ltd
"""
Comment thread
BartoszBlizniak marked this conversation as resolved.
Comment thread
BartoszBlizniak marked this conversation as resolved.
Credential helper commands for Cloudsmith.

This module provides credential helper commands for package managers
that follow their respective credential helper protocols.
"""

import click

from ..main import main
from .docker import docker as docker_cmd
from .manage import install_cmd, list_cmd, uninstall_cmd


@click.group()
def credential_helper():
"""
Credential helpers for package managers.

These commands provide credentials for package managers like Docker.
Use ``install`` to set up the on-PATH launcher and configure the package
manager automatically, or run the runtime command directly for debugging.

Examples:
# Install Docker credential helper
$ cloudsmith credential-helper install docker

# Test Docker credential helper directly
$ echo "docker.cloudsmith.io" | cloudsmith credential-helper docker
"""


credential_helper.add_command(docker_cmd, name="docker")
credential_helper.add_command(install_cmd, name="install")
credential_helper.add_command(uninstall_cmd, name="uninstall")
credential_helper.add_command(list_cmd, name="list")

main.add_command(credential_helper, name="credential-helper")
66 changes: 66 additions & 0 deletions cloudsmith_cli/cli/commands/credential_helper/docker.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Copyright 2026 Cloudsmith Ltd
"""
Comment thread
BartoszBlizniak marked this conversation as resolved.
Comment thread
BartoszBlizniak marked this conversation as resolved.
Docker credential helper command.

Implements the Docker credential helper protocol for Cloudsmith registries.

See: https://github.com/docker/docker-credential-helpers
"""

import sys

import click

from ....credential_helpers.docker import execute
from ...decorators import common_api_auth_options, resolve_credentials


@click.command()
@click.argument("operation", required=False, default="get")
@common_api_auth_options
@resolve_credentials
def docker(opts, operation):
"""
Docker credential helper for Cloudsmith registries.

Reads a Docker registry server URL from stdin and returns credentials in
JSON format. Implements the full Docker credential helper protocol
(get/store/erase/list).

Provides credentials for all Cloudsmith Docker registries: ``*.cloudsmith.io``,
``*.cloudsmith.com``, and any custom domains configured for the organisation
(requires CLOUDSMITH_ORG and a valid API key/token).

Input (stdin):
Server URL as plain text (e.g. "docker.cloudsmith.io")

Output (stdout):
JSON: {"Username": "token", "Secret": "<cloudsmith-token>"}

Exit codes:
0: Success
1: Error (no credentials available, not a Cloudsmith registry, etc.)

Examples:
# Manual testing
$ echo "docker.cloudsmith.io" | cloudsmith credential-helper docker

# Called by Docker via launcher
$ echo "docker.cloudsmith.io" | docker-credential-cloudsmith get

Environment variables:
CLOUDSMITH_API_KEY: API key for authentication (optional)
CLOUDSMITH_ORG: Organisation slug (required for custom domain support)
"""
exit_code, stdout, stderr = execute(
operation,
sys.stdin,
credential=opts.credential,
api_host=opts.api_host,
)

if stdout is not None:
click.echo(stdout)
if stderr is not None:
click.echo(stderr, err=True)
sys.exit(exit_code)
Loading
Loading