Credentials — credentials.py¶
Stored credentials for authenticating to private registries, so a team can publish to and consume from a self-hosted HTTP or OCI registry without the cores ever being public.
- Source: src/hdlpkg/credentials.py
- Import:
from hdlpkg import Credential, CredentialStore, load_credentials, save_credentials, registry_host, load_docker_config
Model¶
A credential is scoped to a registry host, not a full URL: oci://harbor.corp/ip/a
and oci://harbor.corp/ip/b share one credential for harbor.corp. Local (directory)
registries need no credentials, so their location has no host.
A Credential is a secret plus an optional username:
- bearer token alone (
username is None) — sent directly asAuthorization: Bearer <secret>(the self-hosted / static-token case); - username + secret (password or robot token) — used as HTTP Basic credentials in the OCI token-exchange flow that managed registries require.
| Symbol | Description |
|---|---|
registry_host(location) -> str \| None |
The lowercased host[:port] a credential applies to, or None for a local-path registry. Raises CredentialsError if a network URL has no host. |
Credential(secret, username=None) |
A registry secret with an optional username; .is_basic is true when a username is set. |
CredentialStore(credentials) |
An immutable map host -> Credential. credential_for(host), token_for(host), with_token(host, secret, username=None), without(host), with_fallback(others), to_toml(), from_toml(text). |
default_credentials_path() |
$HDLPKG_CREDENTIALS or ~/.hdlpkg/credentials.toml. |
load_credentials(path=None) / save_credentials(store, path=None) |
Load / atomically write (owner-only 0o600 where the OS allows). |
load_docker_config(path=None) / parse_docker_config(data) |
Read ~/.docker/config.json ($DOCKER_CONFIG honored) into host -> Credential (base64 auth or identitytoken), reused as a fallback. |
The pure CredentialStore / Credential value types and parse_docker_config do all
logic, so they are unit-testable without I/O; load/save/load_docker_config are the
only filesystem access.
On-disk format¶
[registries."harbor.corp.local"]
secret = "tok_..."
[registries."reg.corp.local:5000"]
secret = "robot-password"
username = "robot$ci"
The legacy [tokens] table ("host" = "token") is still read, so an older file keeps
working.
How it is used¶
hdlpkg login <location> [--username U] [--token|--password S] stores a credential
(prompting without echo when the secret is omitted); hdlpkg logout <location> removes
it. registry_from_location reads the store (with docker login
credentials merged in as a fallback) and hands the matching credential to the network
backend: HTTP uses the secret as a direct bearer; OCI uses the full credential, presenting
a username-less one directly and driving the token exchange for a username+secret one.
Missing or wrong credentials fail closed.
Errors¶
CredentialsError — a malformed credentials file, a non-string secret/username, or a
network registry location with no host.
Example¶
from hdlpkg import Credential, load_credentials, save_credentials, registry_host
host = registry_host("oci://harbor.corp/ip/acme") # "harbor.corp"
# a robot account for a managed registry (token-exchange via HTTP Basic):
save_credentials(load_credentials().with_token(host, "robot-pw", username="robot$ci"))
credential = load_credentials().credential_for(host) # Credential("robot-pw", "robot$ci")