Skip to content
GitHub

Artifactory catalogue distribution

Look up how to provision repositories, publish through CI, and configure the four reader-authentication providers for a protected enterprise catalogue.

Use this page for the full procedure behind Set enterprise defaults and Host on Artifactory: publishing a catalogue through any CI runner, shipping organization defaults, and configuring how readers sign in. Your organization distributes the AgentBundle wheel through an internal Python package repository and catalogues through a protected Artifactory Generic repository.

The wheel, the catalogue publisher, and the catalogue reader are separate clients, and a login for one does not authenticate the others.

The sequence below first records the non-secret coordinates, then generates organization defaults from them. Do not generate or publish defaults before the Artifactory block is correct.

The wheel, the catalogue publisher, and the catalogue reader are separate clients. A login for one does not authenticate the others.

FlowClientCredential ownerCurrent behavior
Install the agentbundle wheelPip, uv, Poetry, or another Python package clientThe package client and its organization-managed configurationMay reuse that client’s existing .netrc, keyring, or login support. AgentBundle does not read these credentials.
Publish a catalogueJFrog CLI or another upload client in a protected CI jobThe organization’s CI or secrets platformUse a restricted service identity or CI-issued OIDC token. Use a username only when the upload client requires one.
Read a protected catalogueAgentBundle’s HTTPS client via credbroker.resolve_http_accessThe process that launches AgentBundleResolves in priority order: AGENTBUNDLE_HTTP_BEARER_TOKEN, a JFrog CLI 2.105.0+ profile, an exact-machine .netrc record, then anonymous.

The provider order is fixed and the resolution stops as soon as one provider is configured. When a configured provider is broken — for example, a bearer value containing whitespace (invalid_bearer), an unreadable or unsafe .netrc file, or a named JFrog CLI profile that is absent or does not match — the resolution fails rather than falling back to the next provider. A wrong or expired token passes resolution (only the token format is checked at that stage) and fails at fetch time with a 401 or 403 on the direct path, or jfrog_fetch_failed on the JFrog CLI path.

1. Provision the repositories and identities

Section titled “1. Provision the repositories and identities”

Create two Artifactory repositories unless your approved topology provides the same separation another way:

  • A PyPI repository for the agentbundle wheel. Your Python package client owns authentication to this repository.
  • A Generic repository for catalogue archives, SHA256 sidecars, and channel descriptors.

Give the catalogue publisher write access only to the required Generic repository paths. Give a separate read identity access to the published channel and release paths. Prefer a restricted service identity or CI OIDC exchange over an individual developer token.

Set the release paths to immutable. Allow controlled replacement only for channels/, because a channel descriptor is the mutable pointer to the current release.

2. Commit only non-secret catalogue coordinates

Section titled “2. Commit only non-secret catalogue coordinates”

Add the Generic repository coordinates to catalogue.toml:

[distribution.agentbundle.artifactory]
enabled = true
base-url = "https://artifactory.example.test/artifactory"
repository = "agentbundle-catalogues"
bundle = "platform"
channel = "stable"

All five fields are required when enabled = true. base-url must use HTTPS and must not contain user information or a query string. repository, bundle, and channel must match [A-Za-z0-9._-]+.

Do not add a password, token, authenticated URL, or secret lookup instruction to catalogue.toml. The schema closes this table to the five fields above.

3. Generate and ship organization defaults

Section titled “3. Generate and ship organization defaults”

Run:

agentbundle catalogue sync-defaults --root . --write
agentbundle catalogue sync-defaults --root . --check

Commit the generated install-defaults.toml with catalogue.toml, then build and publish the organization wheel. The generated file contains only the same non-secret coordinates.

When the wheel is installed, AgentBundle constructs this source:

catalogue+<base-url>/<repository>/catalogues/<bundle>/channels/<channel>.json

This removes per-machine catalogue URL setup. It does not configure catalogue credentials.

4. Build and verify without publication credentials

Section titled “4. Build and verify without publication credentials”

Install the wheel in the build job using your Python package client’s approved authentication path. Do not reuse catalogue upload credentials for package installation.

The build job needs no Artifactory publication secret:

agentbundle catalogue sync-defaults --root . --check
agentbundle catalogue verify --root . --format json
agentbundle catalogue package \
--root . \
--bundle "$BUNDLE" \
--release "$RELEASE" \
--channel "$CHANNEL" \
--output "$OUTPUT"
agentbundle catalogue verify \
--archive "$OUTPUT/catalogues/$BUNDLE/releases/$RELEASE/catalogue-$RELEASE.tar.gz" \
--sha256-file "$OUTPUT/catalogues/$BUNDLE/releases/$RELEASE/catalogue-$RELEASE.tar.gz.sha256"

Preserve the verification JSON and packaged output as protected CI artifacts for the upload job.

5. Inject publisher credentials only in the upload job

Section titled “5. Inject publisher credentials only in the upload job”

Run publication only from an approved release tag or equivalent protected release event. Serialize the job so two releases cannot update the same channel at once.

Map the portable controls to your CI provider:

ControlGitHub Actions exampleGitLab CI exampleJenkins or another runner
Publisher secretEnvironment or organization Actions secretProtected, masked, and hidden CI/CD variableCredential binding from the controller or external secret store
Non-secret coordinatesActions variablesCI/CD variablesJob parameters or managed configuration
Release gateProtected environment and release tagProtected release tagRestricted release job
Serializationconcurrency groupresource_groupDeployment lock or equivalent

GitHub Actions and GitLab CI are examples, not requirements. The portable contract is the control set in the table.

Configure the upload client inside the protected job. JFrog CLI supports a restricted access token or an organization-configured OIDC exchange for automation. Keep secret values out of commands that print their arguments, workflow logs, artifacts, and receipts.

Upload in this order:

  1. catalogue-<release>.tar.gz
  2. catalogue-<release>.tar.gz.sha256
  3. channels/<channel>.json

Upload the channel descriptor last. It makes the release visible to readers.

The repository’s publish-catalogue.yml is one GitHub-hosted implementation example. It is not the downstream contract.

6. Verify with a read identity and keep a safe receipt

Section titled “6. Verify with a read identity and keep a safe receipt”

After the channel descriptor lands, use a read-only identity to download the archive and sidecar from Artifactory. Verify the downloaded files locally:

agentbundle catalogue verify \
--archive "/path/to/downloaded/catalogue-$RELEASE.tar.gz" \
--sha256-file "/path/to/downloaded/catalogue-$RELEASE.tar.gz.sha256"

Record a credential-free receipt containing the source revision, release and channel names, artifact paths, archive digest, CI run reference, and verification result. Do not record a token, username, authenticated URL, or secret-store location.

7. Configure catalogue read authentication

Section titled “7. Configure catalogue read authentication”

AgentBundle resolves the catalogue reader’s credentials through a four-provider chain, in this order:

  1. Bearer token — set AGENTBUNDLE_HTTP_BEARER_TOKEN in the process environment. AgentBundle attaches it as Authorization: Bearer <token>. Provision, scope, rotate, and revoke this token through the organization credential service.

  2. JFrog CLI profile — configure a JFrog CLI 2.105.0+ profile with jf login or jf config add targeting the same Artifactory instance. AgentBundle selects the profile whose Artifactory URL has the longest matching prefix for the catalogue URL; set JFROG_CLI_SERVER_ID to name a specific profile when multiple profiles exist. AgentBundle delegates the actual fetch to jf api, which uses the stored token from the profile.

  3. Machine-bound .netrc record — add a line of the form machine <host> login <user> password <token> to the user .netrc file (~/.netrc on POSIX; %USERPROFILE%\.netrc on Windows). AgentBundle uses the host or host:port key that matches the catalogue origin. The default key is never used. The file must be readable only by its owner (mode 0600 on POSIX).

  4. Anonymous — no credential is sent. This path succeeds only when the catalogue is publicly accessible.

See Keep the three credential paths separate for the no-fallback rule.

Users can then run:

agentbundle install --pack core

No extra credential injection step is needed when a JFrog CLI profile or .netrc record is already in place.

An explicit catalogue argument wins first. A user-set [settings].source wins next and overrides the organization Artifactory bootstrap.

agentbundle config get source
agentbundle config unset source

Unset the user source only when the organization default should take over.

The wheel installs but the catalogue returns 401 or 403

Section titled “The wheel installs but the catalogue returns 401 or 403”

The package client and AgentBundle use different credential paths. Check which provider AgentBundle selected and whether the credential is valid:

  • Bearer: confirm AGENTBUNDLE_HTTP_BEARER_TOKEN is set and the token has read access to the channel and release paths.
  • JFrog CLI: confirm the profile URL matches the catalogue origin and the stored token has not expired. Run jf config show --format=json to inspect. On the JFrog CLI path, access failures show up as jfrog_fetch_failed rather than an HTTP status code.
  • .netrc: confirm the machine key matches the catalogue host (or host:port for non-standard ports) and the file is 0600.
  • Anonymous: if no provider is configured and the catalogue requires auth, configure one of the providers above.

Do not print credential values while troubleshooting.

A configured credential source fails with an error

Section titled “A configured credential source fails with an error”

When a provider is configured but broken, AgentBundle stops the resolution and reports the provider class and failure code — no credential material appears in the message. Common codes: invalid_bearer (whitespace or a non-ASCII character in the token), netrc_unsafe (wrong file permissions), jfrog_profile_mismatch (named profile not found). Fix the broken configuration; do not remove it and expect fallback to the next provider. See Protected catalogue authentication for the full list of resolution and fetch codes.

TLS verification fails behind the corporate network

Section titled “TLS verification fails behind the corporate network”

For direct HTTPS fetches (bearer, .netrc, anonymous), set AGENTBUNDLE_CA_BUNDLE to the approved PEM CA bundle path. For the JFrog CLI path, AGENTBUNDLE_CA_BUNDLE does not reach the jf api subprocess — TLS failures on that path show up as jfrog_fetch_failed. On Linux, set SSL_CERT_FILE or SSL_CERT_DIR to trust a private CA for jf api. On macOS, add the corporate CA to the system keychain instead — jf api reads only the system keychain there. jf api ignores ~/.jfrog/security/certs/, so a passing jf rt ping does not prove the catalogue fetch will succeed. Keep certificate bundles separate from tokens. AgentBundle keeps HTTPS and certificate verification enabled.

Set the standard HTTPS_PROXY and NO_PROXY variables through the managed environment. Check whether the Artifactory host should use the proxy or bypass it. Do not place proxy credentials in documentation or committed configuration.

Have the organization credential service or support process refresh the managed read token. Do not ask users to paste tokens into issue reports, shell history, or troubleshooting transcripts.

For a host that cannot reach Artifactory, pass a local catalogue explicitly and disable remote default discovery:

AGENTBUNDLE_NO_REMOTE=1 agentbundle install --pack core /path/to/local-catalogue

This skips the organization Artifactory bootstrap and editable-install detection. It does not turn a protected remote catalogue into an offline source.