Dagger
Search

crane

This module provides functionality for copying container images between
registries, and for resolving a tag to the digest it currently points at,
using Google’s `crane` CLI, wrapped in a Dagger pipeline.
It supports authentication, platform targeting, and insecure registry access.

The module is ideal for scenarios where images need to be promoted between
environments (e.g., dev → staging → production) or mirrored across
different registry backends.

Typical usage includes:
- Copying an image from one registry to another (e.g., Harbor to GHCR)
- Providing credentials for source and/or target registries
- Optionally specifying platform (e.g., "linux/amd64")
- Allowing insecure registries in air-gapped or self-hosted setups

This module is designed to be used as part of a CI/CD pipeline via the
Dagger CLI or SDKs.

Installation

dagger install github.com/stuttgart-things/dagger/crane@v0.130.0

Entrypoint

Return Type
Crane
Example
dagger -m github.com/stuttgart-things/dagger/crane@f0694938a41392634c2acb9d6efc6842d5f6866d call \
func (m *MyModule) Example() *dagger.Crane  {
	return dag.
			Crane()
}
@function
def example() -> dagger.Crane:
	return (
		dag.crane()
	)
@func()
example(): Crane {
	return dag
		.crane()
}

Types

Crane 🔗

Crane installs Crane CLI on a Wolfi base image at runtime @module

baseImage() 🔗

Base Wolfi image to use

Return Type
String !
Example
dagger -m github.com/stuttgart-things/dagger/crane@f0694938a41392634c2acb9d6efc6842d5f6866d call \
 base-image
func (m *MyModule) Example(ctx context.Context) string  {
	return dag.
			Crane().
			Baseimage(ctx)
}
@function
async def example() -> str:
	return await (
		dag.crane()
		.baseimage()
	)
@func()
async example(): Promise<string> {
	return dag
		.crane()
		.baseImage()
}

version() 🔗

Crane version to install, as a go-containerregistry release (e.g., “0.22.1”) or “latest”. The binary comes from that release’s image, so the version does not depend on the day the container is built.

Return Type
String !
Example
dagger -m github.com/stuttgart-things/dagger/crane@f0694938a41392634c2acb9d6efc6842d5f6866d call \
 version
func (m *MyModule) Example(ctx context.Context) string  {
	return dag.
			Crane().
			Version(ctx)
}
@function
async def example() -> str:
	return await (
		dag.crane()
		.version()
	)
@func()
async example(): Promise<string> {
	return dag
		.crane()
		.version()
}

copy() 🔗

Copy copies an image between registries with authentication

Return Type
String !
Arguments
NameTypeDefault ValueDescription
sourceString !-No description provided
targetString !-No description provided
sourceRegistryString -No description provided
sourceUsernameString -No description provided
sourcePasswordSecret -No description provided
targetRegistryString -No description provided
targetUsernameString -No description provided
targetPasswordSecret -No description provided
insecureBoolean falseNo description provided
platformString "linux/amd64"No description provided
dockerConfigSecretSecret -

NEW: Docker config.json secret

Example
dagger -m github.com/stuttgart-things/dagger/crane@f0694938a41392634c2acb9d6efc6842d5f6866d call \
 copy --source string --target string
func (m *MyModule) Example(ctx context.Context, source string, target string) string  {
	return dag.
			Crane().
			Copy(ctx, source, target)
}
@function
async def example(source: str, target: str) -> str:
	return await (
		dag.crane()
		.copy(source, target)
	)
@func()
async example(source: string, target: string): Promise<string> {
	return dag
		.crane()
		.copy(source, target)
}

digest() 🔗

Digest resolves a reference to the digest it currently points at and returns it bare (“sha256:…”), so a caller can write ref@ without parsing.

platform defaults to empty, unlike Copy, where it defaults to linux/amd64. That difference is deliberate: a signature on a multi-arch release is made on the index digest, and resolving to one platform’s manifest returns a digest that nothing signed. Set platform only when one platform’s manifest is what you are after. For a reference that is a single manifest rather than an index, crane does not check platform at all and returns that manifest’s digest whatever platform was asked for.

A reference that does not exist is an error carrying the registry’s message (e.g. MANIFEST_UNKNOWN), never an empty string a caller would concatenate into “repo@”.

The answer is never taken from cache: a tag moves, and the digest it pointed at on an earlier run is not necessarily the one it points at now.

Return Type
String !
Arguments
NameTypeDefault ValueDescription
refString !-No description provided
platformString -

Resolve to this platform’s manifest instead of the index. Empty, unlike Copy: a multi-arch release is signed on its index digest.

registryString -

Registry to log in to; derived from ref when empty

usernameString -No description provided
passwordSecret -No description provided
insecureBoolean falseNo description provided
Example
dagger -m github.com/stuttgart-things/dagger/crane@f0694938a41392634c2acb9d6efc6842d5f6866d call \
 digest --ref string
func (m *MyModule) Example(ctx context.Context, ref string) string  {
	return dag.
			Crane().
			Digest(ctx, ref)
}
@function
async def example(ref: str) -> str:
	return await (
		dag.crane()
		.digest(ref)
	)
@func()
async example(ref: string): Promise<string> {
	return dag
		.crane()
		.digest(ref)
}

sameDigest() 🔗

SameDigest checks that two references point at the same digest right now and returns that digest. When they do not, the error names both.

This is the check for a moving tag: latest and a release tag can both report a successful push while naming different images. platform, the credentials and insecure apply to both references, and mean what they mean for Digest.

Return Type
String !
Arguments
NameTypeDefault ValueDescription
refAString !-No description provided
refBString !-No description provided
platformString -No description provided
registryString -

Registry to log in to; derived from each ref when empty

usernameString -No description provided
passwordSecret -No description provided
insecureBoolean falseNo description provided
Example
dagger -m github.com/stuttgart-things/dagger/crane@f0694938a41392634c2acb9d6efc6842d5f6866d call \
 same-digest --ref-a string --ref-b string
func (m *MyModule) Example(ctx context.Context, refA string, refB string) string  {
	return dag.
			Crane().
			Samedigest(ctx, refA, refB)
}
@function
async def example(refa: str, refb: str) -> str:
	return await (
		dag.crane()
		.samedigest(refa, refb)
	)
@func()
async example(refA: string, refB: string): Promise<string> {
	return dag
		.crane()
		.sameDigest(refA, refB)
}