Skip to content

Getting started

Haven serves three main use cases, and most organizations end up combining them:

  • Publishing crates in a private registry, with guarantees for the people who depend on them: your customers and teams get versions that passed your policy gate, with SBOMs, attestations, and an audit trail behind every release.
  • Consuming crates securely through a mirror of crates.io that applies your rules. Supply chain attacks arrive through the registry, so that is where the protection belongs: quarantine for fresh releases, advisory holds, license allowlists, and publisher trust, enforced before a crate can reach your builds.
  • Hosting static files: versioned release archives, prebuilt binaries, and other artifacts that are not crates, behind the same gate.

The onboarding funnel walks you through the first three steps, then asks which path your first registry takes. All three paths are below. The examples use acme as the registry name and https://haven.example.com as the Haven host; substitute your own.

Sign up, then create your organization. Registries, tokens, members, and the audit log all belong to the organization.

Cargo authenticates to Haven with a token, for publishing and pulling alike. The funnel mints one for you; outside the funnel, use your organization’s Tokens page. The token is shown once, at mint time. Store it somewhere safe. Tokens & access explains the scopes and the least-privilege options for CI.

From the funnel (or the Registries page), create a registry. Two decisions happen here and both are permanent for the registry’s lifetime:

  • Path: a publish registry (a registry for your own crates), a crates.io mirror (your gate on the open source you consume), or a static files registry (versioned files that are not crates).
  • Visibility starts as private. You can flip it to public later; see Registries.

Add the registry to .cargo/config.toml (the funnel and the registry page show this snippet filled in with your real URLs):

[registries.acme]
index = "sparse+https://haven.example.com/r/acme/index/"
[registry]
global-credential-providers = ["cargo:token"]

Store the token for that registry:

Terminal window
cargo login --registry acme

Paste the token when prompted. In CI, set it through the environment instead: CARGO_REGISTRIES_ACME_TOKEN (the registry name uppercased, with - replaced by _). Then publish:

Terminal window
cargo publish --registry acme

The new version appears on the registry’s crate page, and the funnel completes when it lands. If the registry has a policy, the version may start out held rather than available; that is the gate doing its job, not an error. See Policy overview.

To depend on it from another project using the same registry configuration:

[dependencies]
my-crate = { version = "1", registry = "acme" }

First, set the policy: the mirror’s whole point is that its rules decide what your builds can pull. Open the registry’s Policy tab and pick your rules; quarantine, advisory holds, and publisher trust are the usual starting set. With no rules set, everything flows. See the Policy rules reference.

Then point cargo’s built-in crates.io source at the mirror in .cargo/config.toml:

[registries.acme-mirror]
index = "sparse+https://haven.example.com/r/acme-mirror/index/"
[source.crates-io]
replace-with = "acme-mirror"
[registry]
global-credential-providers = ["cargo:token"]

Store the token (cargo login --registry acme-mirror, or the CARGO_REGISTRIES_ACME_MIRROR_TOKEN environment variable in CI), then fetch any project:

Terminal window
cargo fetch

Plain serde = "1" dependencies now resolve through the mirror and its policy, with zero Cargo.toml changes. The funnel completes on the first tarball pulled through. One caveat: dependencies already in cargo’s local cache are not downloaded again, so fetch in a project whose dependencies are not cached yet. More in Mirrors and Consuming crates.

No .cargo/config.toml here; the client is curl. Upload a version’s files, then publish the version:

Terminal window
curl -X PUT -H "Authorization: Bearer $HAVEN_TOKEN" \
--data-binary @some-file.tar.gz \
https://haven.example.com/r/acme/files/some-package/1.0.0/some-file.tar.gz
curl -X POST -H "Authorization: Bearer $HAVEN_TOKEN" \
https://haven.example.com/api/v1/registries/acme/files/some-package/1.0.0/publish

The funnel completes when the version is published. As with crates, CI can skip the stored token: trusted publishing mints one from the job’s own identity. Downloading takes the same token (or a narrower read token):

Terminal window
curl -L -O -H "Authorization: Bearer $HAVEN_TOKEN" \
https://haven.example.com/r/acme/files/some-package/1.0.0/some-file.tar.gz

The full lifecycle — drafts, licenses, yank, policy — is in Publishing files; resolution by version range and grants are in Consuming files.