crane
This module provides functionality for copying container images betweenregistries, 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.0Entrypoint
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-imagefunc (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 \
versionfunc (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
| Name | Type | Default Value | Description |
|---|---|---|---|
| source | String ! | - | No description provided |
| target | String ! | - | No description provided |
| sourceRegistry | String | - | No description provided |
| sourceUsername | String | - | No description provided |
| sourcePassword | Secret | - | No description provided |
| targetRegistry | String | - | No description provided |
| targetUsername | String | - | No description provided |
| targetPassword | Secret | - | No description provided |
| insecure | Boolean | false | No description provided |
| platform | String | "linux/amd64" | No description provided |
| dockerConfigSecret | Secret | - | NEW: Docker config.json secret |
Example
dagger -m github.com/stuttgart-things/dagger/crane@f0694938a41392634c2acb9d6efc6842d5f6866d call \
copy --source string --target stringfunc (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
| Name | Type | Default Value | Description |
|---|---|---|---|
| ref | String ! | - | No description provided |
| platform | String | - | Resolve to this platform’s manifest instead of the index. Empty, unlike Copy: a multi-arch release is signed on its index digest. |
| registry | String | - | Registry to log in to; derived from ref when empty |
| username | String | - | No description provided |
| password | Secret | - | No description provided |
| insecure | Boolean | false | No description provided |
Example
dagger -m github.com/stuttgart-things/dagger/crane@f0694938a41392634c2acb9d6efc6842d5f6866d call \
digest --ref stringfunc (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
| Name | Type | Default Value | Description |
|---|---|---|---|
| refA | String ! | - | No description provided |
| refB | String ! | - | No description provided |
| platform | String | - | No description provided |
| registry | String | - | Registry to log in to; derived from each ref when empty |
| username | String | - | No description provided |
| password | Secret | - | No description provided |
| insecure | Boolean | false | No description provided |
Example
dagger -m github.com/stuttgart-things/dagger/crane@f0694938a41392634c2acb9d6efc6842d5f6866d call \
same-digest --ref-a string --ref-b stringfunc (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)
}