DEXUS VAULT
dexus-vault - synchronizer of Dex clients with secrets in Vault or AWS SSM
🚩 Table of Contents
- About the project
- Installation
- Usage
- Configuration
- Vault secret structure
- Pruning
- Metrics
- Running in Kubernetes
- Local testing
- Development
- Releasing
- Upgrading from 0.3
- Thanks
🚀 About the project
Dexus Vault keeps the OAuth2 clients of Dex in sync with secrets stored in HashiCorp Vault or in AWS Systems Manager Parameter Store. The secret backend is the source of truth: every secret under a path describes one Dex client.
How it works
Every SYNC_INTERVAL seconds dexus-vault:
- lists and reads the secrets under
VAULT_MOUNT_POINT/VAULT_CLIENTS_PATH(or the parameters underSSM_PATH), and validates each one as a client; - fetches each client from Dex over gRPC and compares them;
- applies the difference:
- missing clients are created;
- changed clients are updated in place with
UpdateClient; - clients are recreated (deleted and created again) only when Dex cannot update the change in place: a new
secret, a change ofpublic, or clearing a list/name/logo; - with pruning enabled, clients that are no longer in the backend are deleted.
Secrets that are invalid, or that define the same client id twice, are reported and their clients are left untouched.
💾 Installation
uv tool install dexus-vault # Vault backend
uv tool install 'dexus-vault[aws]' # adds the AWS SSM backend (boto3)
pip install dexus-vault works as well.
or with Docker:
docker run --env-file .env ifurs/dexus-vault
The image includes both backends. See the image README.
📙 Usage
dexus-vault # sync continuously
dexus-vault --once # one sync, exit code 1 if anything failed
dexus-vault --dry-run # log what would change, change nothing
dexus-vault --prune # also delete clients that are not in Vault
python3 -m dexus_vault # same as dexus-vault
All options:
--once run one sync and exit, non-zero on errors (SYNC_ONCE)
--dry-run log changes without applying them (SYNC_DRY_RUN)
--prune, --no-prune delete Dex clients missing in the source (SYNC_PRUNE)
--backend {vault,aws-ssm} where clients are read from (SECRETS_BACKEND)
--interval INTERVAL seconds between syncs (SYNC_INTERVAL)
--log-level LOG_LEVEL log level (LOG_LEVEL)
--log-format {text,json} log format (LOG_FORMAT)
--env-file ENV_FILE dotenv file to read (default: .env)
Exit codes: 0 success or clean shutdown (SIGTERM/SIGINT), 1 Dex or Vault unreachable or a failed --once sync, 2 invalid configuration.
🔧 Configuration
Settings are read from environment variables and from a .env file in the working directory (or --env-file). Command line flags win over both.
General and sync
| variable | default | description |
|---|---|---|
| SECRETS_BACKEND | vault | vault or aws-ssm |
| SYNC_INTERVAL | 60 | Seconds between syncs |
| SYNC_ONCE | false | Run one sync and exit |
| SYNC_DRY_RUN | false | Log planned changes without applying them |
| SYNC_PRUNE | false | Delete Dex clients that are not defined in the backend, see Pruning |
| SYNC_PRUNE_PREFIX | - | Only prune clients whose id starts with this prefix |
| SYNC_PRUNE_EXCLUDE | - | Comma-separated client ids that are never pruned |
| LOG_LEVEL | INFO | DEBUG, INFO, WARNING, ERROR or CRITICAL |
| LOG_FORMAT | text | text or json (one JSON object per line) |
Metrics and health
| variable | default | description |
|---|---|---|
| METRICS_ENABLE | true | Serve /metrics, /healthz and /readyz (not in --once mode) |
| METRICS_ADDR | 0.0.0.0 | Listen address |
| METRICS_PORT | 8000 | Listen port |
| INTERNAL_METRICS | false | Also export Python process, platform and GC metrics |
Dex connection
| variable | default | description |
|---|---|---|
| DEX_GRPC_URL | 127.0.0.1:5557 | Dex gRPC address |
| DEX_CA_CRT | - | CA that signed the Dex gRPC server certificate (enables TLS) |
| DEX_CLIENT_CRT | - | Client certificate for mutual TLS |
| DEX_CLIENT_KEY | - | Client certificate key for mutual TLS |
| DEX_TIMEOUT | 10 | Deadline in seconds for each gRPC call |
| DEX_MAX_RETRIES | 20 | Startup retries while Dex is unreachable |
| DEX_RETRY_WAIT | 3 | Seconds between startup retries |
CA_CRT, CLIENT_CRT and CLIENT_KEY are still accepted as aliases.
Without any certificate the connection is not encrypted and a warning is logged. Dex's gRPC API gives full administrative access, so configure grpc.tlsClientCA in Dex and use mutual TLS. Setting only DEX_CA_CRT gives server-authenticated TLS; without it the system CA store is used to verify Dex.
Dex version notes: dexus-vault works with any Dex v2 release, but allowed_connectors, sso_shared_with, backchannel_logout_uri, post_logout_redirect_uris and refresh_token_lifetime need Dex v2.46.0 (they are ignored, with a warning, on older servers), and pruning needs Dex v2.44.0 (ListClients).
Vault connection
| variable | required | default | description |
|---|---|---|---|
| VAULT_ADDR | - | http://127.0.0.1:8200 | Vault address |
| VAULT_MOUNT_POINT | yes | - | KV engine mount point |
| VAULT_CLIENTS_PATH | yes | - | Path inside the engine that holds one secret per client |
| VAULT_ENGINE | - | v2 | KV engine version, v1 or v2 |
| VAULT_NAMESPACE | - | - | Vault Enterprise / HCP namespace |
| VAULT_CERT_CA | - | true | TLS verification: true (system CA store), false, or a path to a CA bundle |
| VAULT_REQUEST_TIMEOUT | - | 10 | Seconds per Vault request |
| VAULT_ALLOW_REDIRECT | - | false | Follow HTTP redirects |
| VAULT_PROXIES | - | - | JSON, e.g. {"https": "http://proxy:3128"} |
| VAULT_MAX_RETRIES | - | 20 | Startup retries while Vault is unreachable or sealed |
| VAULT_RETRY_WAIT | - | 3 | Seconds between startup retries |
| VAULT_AUTH_METHOD | - | auto | auto, token, approle, kubernetes, ldap or cert |
Vault auth
With VAULT_AUTH_METHOD=auto the first configured method in this order is used: AppRole, Kubernetes, LDAP, certificate, token.
| method | variables |
|---|---|
| Token | VAULT_TOKEN |
| AppRole | VAULT_APPROLE_ROLE_ID and either VAULT_APPROLE_SECRET_ID or VAULT_APPROLE_SECRET_PATH (file with the secret id, e.g. written by Vault Agent); VAULT_APPROLE_MOUNT_POINT (default approle) |
| Kubernetes | VAULT_KUBERNETES_ROLE; VAULT_KUBERNETES_JWT_PATH (default /var/run/secrets/kubernetes.io/serviceaccount/token); VAULT_KUBERNETES_MOUNT_POINT (default kubernetes) |
| LDAP | VAULT_LDAP_USERNAME, VAULT_LDAP_PASSWORD; VAULT_LDAP_MOUNT_POINT (default ldap) |
| Certificate | VAULT_CERT, VAULT_CERT_KEY; VAULT_CERT_ROLE (optional role name); VAULT_CERT_MOUNT_POINT (default cert). Requires TLS verification |
Tokens obtained by logging in (all methods except token) are renewed before they expire, replaced by a new login when renewal is not possible, and revoked on shutdown.
Vault policy
# KV v2 mounted at "kv", clients under "dex/"
path "kv/metadata/dex/*" {
capabilities = ["list"]
}
path "kv/data/dex/*" {
capabilities = ["read"]
}
For KV v1 grant list and read on kv/dex/*.
AWS SSM Parameter Store
Set SECRETS_BACKEND=aws-ssm (or --backend aws-ssm) and install the aws extra. Every parameter directly under SSM_PATH is one client; its value is the same JSON object as a Vault secret, and the parameter name below the path is the default client id. Use SecureString parameters, they are decrypted on read.
| variable | required | default | description |
|---|---|---|---|
| SSM_PATH | yes | - | Parameter path, e.g. /dex/clients |
| AWS_REGION | - | from the AWS config | Region of the parameters |
| AWS_PROFILE | - | - | Shared config / SSO profile |
| SSM_ENDPOINT_URL | - | - | Custom endpoint, e.g. a VPC endpoint or a local emulator |
| SSM_TIMEOUT | - | 10 | Connect and read timeout in seconds |
| SSM_MAX_RETRIES | - | 5 | Attempts per request, throttling is retried |
| AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN | - | - | Static credentials, normally not needed |
Credentials come from the standard AWS chain: environment variables, shared config and SSO profiles, web identity (EKS IRSA), EKS Pod Identity, or the ECS/EC2 instance role. The explicit AWS_* key settings exist so credentials can also come from a .env file.
aws ssm put-parameter --type SecureString --name /dex/clients/my-app \
--value '{"secret": "a-long-random-secret", "redirect_uris": ["https://app.example.com/callback"]}'
Minimal IAM policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ssm:GetParametersByPath",
"Resource": "arn:aws:ssm:eu-west-1:123456789012:parameter/dex/clients"
}
]
}
The default aws/ssm KMS key lets every principal in the account decrypt. With a customer managed key, also allow kms:Decrypt on that key. Parameters whose value is not a JSON object are reported, and pruning is skipped until they are fixed. Nested parameters (/dex/clients/team/app) are ignored.
🔒 Vault secret structure
Each secret under VAULT_CLIENTS_PATH (or parameter under SSM_PATH) is one client. All fields of the Dex client API are supported:
{
"id": "my-first-client",
"secret": "a-long-random-secret",
"name": "My First Client",
"logo_url": "https://example.com/logo.png",
"public": false,
"redirect_uris": ["https://app.example.com/callback"],
"trusted_peers": ["my-second-client"],
"allowed_connectors": ["github"],
"sso_shared_with": ["my-second-client"],
"backchannel_logout_uri": "https://app.example.com/backchannel-logout",
"post_logout_redirect_uris": ["https://app.example.com/"],
"refresh_token_lifetime": "standalone"
}
iddefaults to the secret name.secretis required for confidential clients. Public clients ("public": true) may leave it out, Dex then keeps managing it.refresh_token_lifetimeisstandalone(default) orsession.- Lists can be native JSON lists, JSON-encoded strings (
"[\"a\", \"b\"]") or comma-separated strings ("a,b"), so they work with the key/value view of the Vault UI too. The same goes for"public": "true". - camelCase keys (
redirectUris) are accepted. Unknown keys are ignored with a warning, which catches typos such asredirect_uri. - Sub-paths (folders) under
VAULT_CLIENTS_PATHare skipped. Soft-deleted KV v2 secrets count as removed.
✂️ Pruning
With SYNC_PRUNE=true (or --prune) clients that exist in Dex but not in the backend are deleted. Dex clients carry no owner label, so limit the scope:
SYNC_PRUNE_PREFIX=vault-only touches clients whose id starts withvault-;SYNC_PRUNE_EXCLUDE=admin-ui,clinever touches the listed ids.
Safety rules, a sync never prunes when:
- some secret could not be read or some client could not be checked in Dex, since the picture is incomplete;
- the backend returned no clients at all (for example a wrong
VAULT_CLIENTS_PATHorSSM_PATH); - the client belongs to an invalid or duplicated secret.
Static clients from the Dex config file cannot be deleted through the API; the first attempt is logged and they are skipped afterwards. Try --dry-run --prune --once first to see what would be deleted.
📈 Metrics
Served at http://<METRICS_ADDR>:<METRICS_PORT>/metrics:
| metric | type | description |
|---|---|---|
dexus_vault_client_operations_total{operation, status} |
counter | operation: create, update, recreate, delete; status: ok, failed, planned (dry-run) |
dexus_vault_syncs_total{result} |
counter | Sync runs, result: success or failure |
dexus_vault_sync_duration_seconds |
histogram | Duration of a sync run |
dexus_vault_last_sync_timestamp_seconds |
gauge | Time of the last sync run |
dexus_vault_last_success_timestamp_seconds |
gauge | Time of the last sync without errors |
dexus_vault_clients |
gauge | Valid clients defined in the backend |
dexus_vault_invalid_secrets |
gauge | Secrets that are not valid client definitions |
dexus_vault_build_info{version, backend} |
gauge | Build information and the active backend |
Example alert: time() - dexus_vault_last_success_timestamp_seconds > 600.
Health endpoints on the same port:
/healthz: 200 while the process runs (liveness);/readyz: 200 once a sync succeeded and successes keep coming within3 × SYNC_INTERVAL + 60s, 503 otherwise (readiness).
☸️ Running in Kubernetes
containers:
- name: dexus-vault
image: ifurs/dexus-vault:0.4.1
env:
- { name: DEX_GRPC_URL, value: "dex.dex.svc:5557" }
- { name: VAULT_ADDR, value: "https://vault.vault.svc:8200" }
- { name: VAULT_MOUNT_POINT, value: "kv" }
- { name: VAULT_CLIENTS_PATH, value: "dex" }
- { name: VAULT_KUBERNETES_ROLE, value: "dexus-vault" }
- { name: LOG_FORMAT, value: "json" }
ports:
- { name: http, containerPort: 8000 }
livenessProbe:
httpGet: { path: /healthz, port: http }
readinessProbe:
httpGet: { path: /readyz, port: http }
securityContext:
runAsNonRoot: true
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
For a CronJob, add args: ["--once"], the pod then fails when the sync fails.
EKS with the AWS SSM backend
No AWS keys are needed in the pod. Give its service account an IAM role with the SSM policy, using either IRSA or EKS Pod Identity. boto3 picks up both automatically and refreshes the temporary credentials itself, including the rotated IRSA token.
apiVersion: v1
kind: ServiceAccount
metadata:
name: dexus-vault
namespace: dex
annotations:
# IRSA only; with Pod Identity leave this out and create an association instead
eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/dexus-vault
---
# in the Deployment's pod spec
serviceAccountName: dexus-vault
containers:
- name: dexus-vault
image: ifurs/dexus-vault:0.4.1
env:
- { name: SECRETS_BACKEND, value: "aws-ssm" }
- { name: SSM_PATH, value: "/dex/clients" }
- { name: AWS_REGION, value: "eu-west-1" }
- { name: DEX_GRPC_URL, value: "dex.dex.svc:5557" }
# ports, probes and securityContext as above
IRSA: the role's trust policy allows the cluster's OIDC provider for this service account:
{
"Effect": "Allow",
"Principal": { "Federated": "arn:aws:iam::123456789012:oidc-provider/oidc.eks.eu-west-1.amazonaws.com/id/EXAMPLE" },
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"oidc.eks.eu-west-1.amazonaws.com/id/EXAMPLE:sub": "system:serviceaccount:dex:dexus-vault",
"oidc.eks.eu-west-1.amazonaws.com/id/EXAMPLE:aud": "sts.amazonaws.com"
}
}
}
Pod Identity: install the eks-pod-identity-agent add-on. Trust pods.eks.amazonaws.com with sts:AssumeRole and sts:TagSession, then associate the role:
aws eks create-pod-identity-association --cluster-name my-cluster \
--namespace dex --service-account dexus-vault \
--role-arn arn:aws:iam::123456789012:role/dexus-vault
Things that commonly go wrong:
- Static keys win.
AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEYin the pod environment take precedence over IRSA and Pod Identity, so leave them unset. - Private clusters need VPC interface endpoints:
ssm, plusstsfor IRSA oreks-authfor Pod Identity. If you use a custom SSM endpoint, setSSM_ENDPOINT_URL;AWS_ENDPOINT_URL_STSworks for STS. - Don't rely on the node role. IMDSv2 with the default hop limit of 1 usually blocks pods from reaching it, so the sync fails with "Unable to locate credentials".
- Customer managed KMS keys need
kms:Decryptfor the role.
The image works with runAsNonRoot and readOnlyRootFilesystem. Both credential paths were checked that way by hand, against an emulated STS and Pod Identity agent; the integration tests cover IRSA.
💻 Local testing
docker/tests has a Docker Compose stack with Dex, a Vault dev server and an AWS SSM emulator (moto), sample clients and a restricted Vault policy:
docker/tests/start.sh up
dexus-vault --env-file docker/tests/.env # Vault
dexus-vault --env-file docker/tests/.env.ssm # AWS SSM
docker/tests/start.sh down
It is not suitable for production.
🛠 Development
The project is managed with uv. Dependencies are pinned in uv.lock.
uv sync --extra aws # .venv with the locked runtime and dev dependencies
uv run pytest # unit tests
docker/tests/start.sh up && DEXUS_INTEGRATION=1 uv run pytest tests/integration
uv run black . && uv run ruff check .
uv lock --upgrade # update dependencies, then commit uv.lock
The project uses pre-commit; the hooks also keep uv.lock in sync with pyproject.toml.
Security checks, all of which also run in CI:
uv audit --preview-features audit-command --frozen # known vulnerabilities in locked dependencies
uvx zizmor@1.31.1 .github # GitHub Actions security
uvx bandit@1.9.2 -q -r dexus_vault scripts -x dexus_vault/grpc_dexidp
CI also scans the Docker image with Trivy and fails on fixable HIGH or CRITICAL vulnerabilities. See SECURITY.md for reporting vulnerabilities.
For Claude Code, CLAUDE.md holds the project rules, and .claude/ defines project agents and skills:
| agent | model | role |
|---|---|---|
dexus-researcher |
opus | read-only; verifies upstream Dex, Vault/hvac, AWS and dependency behavior against tagged sources, keeps verified facts in project memory |
dexus-developer |
opus | implements changes test-first along the existing seams; a Stop hook blocks it from finishing while lint or unit tests fail |
dexus-tester |
sonnet | runs unit and integration suites against local endpoints only, reproduces bugs as failing tests; may edit test code only |
dexus-reviewer |
opus | independent review of a diff in a fresh context, re-runs the checks, reports only correctness, security and requirement gaps |
dexus-security-auditor |
opus | read-only security audit: runs the scanner suite, checks the threat model, reports only high-confidence exploitable findings; keeps accepted risks in project memory |
| skill | use |
|---|---|
dex-api |
verified Dex RPC semantics and version matrix, preloaded into the agents |
dexus-verify |
the verification gate: which checks to run for which change, and how to report evidence |
/upgrade-dex-api <tag> |
step-by-step upgrade of the vendored Dex API |
/security-audit [full | diff <base>] |
the security audit procedure: scanners, threat model, how findings are judged |
The hooks used by the agents are in scripts/agents/guard.py, tested in tests/test_agent_guard.py.
The Dex gRPC stubs in dexus_vault/grpc_dexidp are generated from api.proto. To update them to another Dex release:
scripts/generate_proto.sh v2.46.0
🚢 Releasing
Releases are automatic and never start from a hand-pushed tag:
- Open a pull request that bumps
__version__indexus_vault/__version__.py(MAJOR.MINOR.PATCH). CI's Release preview check shows "Merging this pull request releases X" and fails if the version is lower than the latest release. - Review and merge it into
main. - The Release workflow (
.github/workflows/publish-to-pypi.yml) sees a version without a tag, then builds withuv build, publishes to PyPI with trusted publishing, creates the tag and a GitHub release with Sigstore-signed files and generated notes, and publishes the signed multi-arch Docker image.
Pushing tags by hand does not release anything, and the Release workflow cannot be started by hand: it only runs for commits on main. If a release job fails, re-run the failed jobs. They reuse the same build, so PyPI and the GitHub release always carry identical files, and the PyPI upload skips files that are already there. Builds set SOURCE_DATE_EPOCH to the commit time, which makes the wheel reproducible (the sdist still records file modification times).
To publish the Docker image of an existing release again, run Publish Docker image manually from main with the tag. It refuses tags that do not point to a commit on main whose __version__ matches, and builds that exact commit; the image label org.opencontainers.image.revision and the cosign signature annotations record it.
The workflows only release from main, but the repository settings decide who can change main and tags. Configure them (Settings → Rules / Environments):
- A branch ruleset on
mainrequiring pull requests, an approving review and passing CI, with no bypass. Without it, a direct push tomainreleases without review. - A tag ruleset on
*.*.*that blocks updates and deletions (creation stays allowed for the release workflow), plus immutable releases, so a published version and its tag cannot be changed. - The
pypianddockerhubenvironments: deployment branches limited tomain, required reviewers, and administrators not allowed to bypass, so every release waits for a maintainer's approval. - On PyPI, the trusted publisher limited to the
pypienvironment.
⬆️ Upgrading from 0.3
- Python 3.11 or newer is required.
VAULT_MOUNT_POINTandVAULT_CLIENTS_PATHare now validated as required, as documented before.- Metrics were renamed and are now counters with a
dexus_vault_prefix, see Metrics. The oldclient_create,client_delete,client_update,client_skipandincorrect_secretsgauges are gone. - Confidential clients with an empty
secretare rejected. Before, Dex replaced the empty secret with a random one, and dexus-vault recreated the client on every sync. - Vault TLS is verified by default for every auth method (
VAULT_CERT_CA=true). SetVAULT_CERT_CA=falseto turn it off, or point it at your CA bundle. - Changes are applied in place with
UpdateClientwhere possible, so clients are no longer deleted and recreated for every change. - The Docker image runs as an unprivileged user (uid 65532).
Roadmap
- Redesign metrics concept to make it more Prometheus friendly
- Switch to pydantic
- Track clients in Dex and prune the ones removed from Vault
- CLI with parameters
- Structured (JSON) logs
- Generate missing client secrets and write them back to Vault
- Read clients from several Vault paths, recursively
- AWS SSM Parameter Store backend
- AWS Secrets Manager and other secret backends
🔥 Thanks
- Hurlenko for references copied from your repos
Metadata
Release files for dexus-vault 0.4.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| dexus_vault-0.4.1.tar.gz | 61.3 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| dexus_vault-0.4.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 106.8 kB
Release files / dexus_vault-0.4.1.tar.gz
| Download URL | dexus_vault-0.4.1.tar.gz |
|---|---|
| Size | 61.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
1e5a137242038fcc1f1c26903d9fefd03e2750257fbf4da582196ef1e79881b2
|
|
BLAKE2b-256 checksum How to use checksums |
14ac05659fdbd1c8dac1713f10c91e296997341aa3c531c550d957eb8d0155e2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.
Transparency logRelease files / dexus_vault-0.4.1-py3-none-any.whl
| Download URL | dexus_vault-0.4.1-py3-none-any.whl |
|---|---|
| Size | 45.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
b5e2de9eb92c5d2fe71146fe62621ae8e6ec29e6732d2da0b39d81cfade08c12
|
|
BLAKE2b-256 checksum How to use checksums |
b4f71984e2cc1d364e5df43c4357884fe5571d1c1ea209028331020703bedd9b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.
Transparency logSecurity for dexus-vault 0.4.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for dexus_vault-0.4.1.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.