denver
Development Environments as code — reproducible, flexible, simple and fast.
Development Environment Launcher — declares dev environments in a
denver.yml: reproducible and layerable to fit your project's needs.
What problem does this solve?
Every project needs some setup before you can build it — and how much varies enormously. So rather than one big answer, here is the problem built up one step at a time. Each step below is a complete, working denver environment. Stop at whichever one matches your project; there is no requirement to reach the last one.
An environment is described in the denver-world by a denver.yml.
Step 1 — "first, run these commands"
Almost every project starts here: a README section, or a setup.sh, listing
what a newcomer has to do before anything works. The trouble is that a script
in the repo is only a suggestion. Nobody re-runs it after a git pull,
everyone's shell ends up in a slightly different state, and whatever happens
to be installed on your machine silently covers for the steps you forgot to
write down.
The smallest useful denver environment is that script, declared rather than documented:
# my-project/denver.yml
stages:
- setup
setup:
provider: custom
source: setup.sh # sourced, not executed, so what it exports stays in effect
denver my-project # apply setup.sh, then drop into a shell that has it
denver my-project -- make # ...or run a single command in that shell
One stage. No Docker, no Conan, no Python packaging. Everybody gets the same
setup, applied the same way, every time — and the shell you land in is
disposable: what the stage exported is gone again once you exit.
Step 2 — "...and a Python virtualenv with the right packages in it"
Now the manual part is python -m venv, activate, pip install -r, and
remembering to redo it whenever requirements.txt changes. A uv stage
hands that whole job to denver:
stages:
- uv
uv:
provider: uv
python: "3.12.3" # a pinned interpreter, not "whatever python3 happens to be"
requirements:
- requirements.txt
denver my-project now gives you a shell with that venv active: created on
the first run, reused afterwards, and re-installed only when
requirements.txt actually changed. examples/zephyr-uv/ is precisely this
and nothing more.
Step 3 — "...but half our tools aren't Python at all"
Compilers, cmake, ninja, a vendor SDK, a flashing tool. This is what
"install these six things first, versions X.Y" READMEs are made of, and no
Python virtualenv can help. If a package manager can fetch them, denver can
drive it as a further stage — conan ships built in:
stages:
- uv # provides the 'conan' executable itself, via requirements.txt
- conan # ...which then fetches the native tools
uv:
provider: uv
requirements:
- requirements.txt
conan:
provider: conan
conanfiles:
- path: conanfile.py
The order of stages: is the whole point: each stage leaves behind PATH
entries, environment variables and files on disk that the next stage — and
finally your shell — can use. Here that ordering is load-bearing in a way
worth noticing: conan is itself a Python package, so the uv stage has to
run first to put the conan binary on PATH for the stage named after it.
examples/raspberry-pico/ is exactly this two-stage stack.
Step 4 — "...and it only builds on Ubuntu 22.04"
Some things cannot be papered over from inside a venv: glibc, system
libraries, the distribution itself. A docker stage runs the stages after it
inside a container, so the layers above stop depending on which laptop you
are sitting at:
stages:
- docker # everything below this line happens inside the container
- conan
- uv
docker is a wrapper: it installs nothing itself, it relocates the rest
of the pipeline. Which is also why you can drop it whenever you like —
denver my-project --skip docker runs the very same conan/uv stack
straight on your host.
Step 5 — "...and five repositories need that same base"
Copy-pasting a stack into every repository is how it rots. import: lets one
env inherit another's entire stack and restate only what differs:
import:
- ../our-shared-base # its stages, its docker config, its variables
uv: # ...with only this project's packages layered on top
requirements:
- requirements.txt
A new project, or the next SDK version, then becomes a folder with a handful of lines in it instead of another copy of everything.
You only pay for the steps you need
Nothing above is mandatory, and denver has no opinion about which tools you
should use. A stage exists only because your denver.yml lists it:
| If your project… | …you need |
|---|---|
| runs a setup script, or anything else denver has no provider for | custom |
| has Python dependencies | uv — a virtualenv managed by uv |
| has native tools/toolchains to fetch | conan |
| needs a specific OS/system libraries | docker |
| is a west-based Zephyr RTOS workspace | zephyr |
Those five built-in providers are the code that knows how to run a kind of
stage; custom is the escape hatch for everything else, and a one-stage
custom env is as legitimate as the five-stage one walked through below.
Run denver --help for every flag, see
doc/architecture.md
for the full stages:/import:/-c schema, or browse
examples/ —
there is one worked environment per step above, each with a README of its own
explaining what it does and why.
Documentation
| Document | What's in it |
|---|---|
doc/README.md |
Documentation index — start here |
doc/glossary.md |
Every term denver uses, defined once |
doc/how-to.md |
Step-by-step: build your own environment, one stage at a time |
doc/architecture.md |
The denver.yml schema and how the system works |
doc/philosophy.md |
The design principles behind it |
doc/providers/ |
One key reference per provider: uv, conan, docker, zephyr, custom |
doc/development.md |
Contributing: tests, coverage, adding a provider, releasing |
examples/ |
Six working environments, smallest to largest, each with its own README |
Install denver
denver is a small pure-Python package — install it from PyPI or straight from GitHub:
# with pip
pip install denver-tool
pip install git+https://github.com/thorsten-klein/denver.git
# or with uv
uv tool install denver-tool
uv tool install git+https://github.com/thorsten-klein/denver.git
This installs the denver script/entry point.
On a machine with no Python at all, take the standalone executable attached to every release instead — it bundles denver, its providers and a Python interpreter in one file:
# Find Asset from latest release
ASSET=$(curl -sSL https://api.github.com/repos/thorsten-klein/denver/releases/latest | grep -o 'https://[^"]*\.tar\.xz')
# Download the Asset and untar it
curl -sSL "$ASSET" | tar -xJf -
# Run denver
./denver --version
x86_64 Linux with glibc 2.28 or newer (Ubuntu 20.04+, Debian 10+, Fedora 29+,
RHEL/Alma/Rocky 8+, Arch, Mint 20+); musl-based distros such as Alpine are not
covered. Build it yourself with scripts/create-python-exe.sh. Note this only
replaces denver's own installation — the tools its providers drive
(see pre-conditions) still have to be there.
To hack on denver itself (or pin it to a specific commit/tag/branch), clone it and install in editable mode instead:
pip install -e .
If you'd rather vendor denver straight into your own monorepo instead of depending on it as an installed package, add it via git-nested:
git-nested clone https://github.com/thorsten-klein/denver.git
With that approach nothing needs installing — just call src/denver.py
(or the vendored copy's equivalent path) directly, as in the quick start
below.
Pre-conditions
denver itself only needs Python — it never installs the tools its providers
drive. This table is a lookup, not a checklist: only the rows for the
providers your own denver.yml actually lists apply to you. Each of those
expects its tool to already be available wherever that stage runs (on the
host, or inside the container once a docker stage relocated into it):
| Provider | Needs |
|---|---|
docker |
docker with the Compose plugin (v2, docker compose ...), daemon reachable for your user |
uv |
uv |
conan |
conan — usually installed by an earlier uv stage |
zephyr |
west — usually installed by an earlier uv stage |
custom |
whatever your own script calls |
A stage whose tool is missing fails up front with a clear message. Each
provider's page under doc/providers/
has the details, including how to point at a specific binary via exe:.
Anything that must be installed on the host (docker itself, udev rules,
...) typically lives in an env's scripts: setup:, so an env can bring its
own host tools along — run those once with:
denver <env> --run setup
See One-time host setup.
Getting started with a bundled example environment
The chapter above built an environment up from one stage. This one goes the
other way and walks through the biggest bundled example end to end —
examples/zephyr-devshell-4.3.1, a complete
Zephyr RTOS 4.3.1 development setup — to show
what the same mechanism looks like at full size. It is deliberately the
extreme case, not the typical one.
If you would rather start from the small end, read
examples/zephyr-uv/denver.yml (a venv, nothing else) or
examples/simple-env/denver.yml (a couple of shell snippets) instead — both
are a screenful, and the flags in
The handful of options you'll actually use
work identically for them.
Note that every command below works as denver <env> ... or src/denver.py <env> ....
The one command you need
denver examples/zephyr-devshell-4.3.1
That's it. A minute or two later (much less on repeat runs) you are sitting
in a shell where west, cmake, ninja, the Zephyr SDK compilers and all
required Python packages are installed and ready:
$ denver examples/zephyr-devshell-4.3.1
... denver builds/enters each layer ...
dev@container ~/workspace> west build -b nrf52840dk/nrf52840 samples/hello_world
dev@container ~/workspace> exit # back to your normal shell
You did not install a compiler. You did not create a virtualenv. You did not write a bootstrap script. denver did all of it, and it will do exactly the same on your colleague's machine.
The vocabulary, in one place
- An environment is a folder containing a
denver.yml, and you point denver at that folder.denver.ymlis the recipe; denver is the cook that follows it. If you want to know what an environment does, you read itsdenver.yml. - A stage is one step of the setup, listed in
stages:. Order matters: each stage leaves behindPATHentries, environment variables and files that the next stage — and finally your shell or command — can use. Think of getting dressed: underwear before trousers before shoes. - A provider is the code that knows how to run a kind of stage. You
never write provider code; you configure it from
denver.yml.
Every stage names its provider explicitly (provider: uv), so the stage id
itself is just a label. That is what lets a single env run the same provider
twice — this example has two uv stages, uv and uv-zephyr.
<env> also accepts a path straight to a YAML file instead of a folder —
handy when a folder holds several variants side by side (e.g.
denver.debug.yml, denver.release.yml):
denver examples/zephyr-devshell-4.3.1/denver.debug.yml
The 5 stages of this example
stages:
- docker # 1. get into the right operating system
- conan # 2. install native tools (compilers, cmake, ninja, ...)
- uv # 3. install Python packages into a venv
- zephyr # 4. download the Zephyr source repositories
- uv-zephyr # 5. install the Python packages Zephyr itself asks for
Steps 1–3 are the same docker/conan/uv layers built up earlier; steps
4 and 5 are what a Zephyr workspace adds on top. In plain words:
| # | Stage | What it does |
|---|---|---|
| 1 | docker |
Builds a Docker image and drops you inside a container, so everyone gets the same Linux, the same system libraries and the same tools — regardless of whether your laptop runs Ubuntu, Fedora or WSL. |
| 2 | conan |
Uses Conan to fetch native, non-Python tools — the Zephyr SDK cross-compilers, cmake, ninja, ccache, clang, the J-Link tools — and puts them on PATH. These are prebuilt binaries, so nothing is compiled on your machine. |
| 3 | uv |
Creates a Python virtualenv (with uv, a very fast pip replacement) and installs the pinned Python packages listed in this env's requirements.txt — most importantly west, Zephyr's repo-management tool. From here on, python and west mean this venv's versions. |
| 4 | zephyr |
Runs west update, which clones/updates the many git repositories that make up a Zephyr workspace (the kernel, HALs, modules, ...) at exactly the revisions pinned for 4.3.1, applies the patches this env carries via west patches, fetches binary blobs via west blobs, etc... |
| 5 | uv-zephyr |
The Zephyr modules downloaded in step 4 declare Python dependencies of their own (west packages pip). This stage installs those, into the same venv from step 3. It has to run after step 4, because until then we didn't know what they were. |
At the end, denver hands control over to your shell — fish, in this
environment — with everything from steps 1–5 active. When you type exit,
you are back on your host machine and nothing was installed on it.
One-time host setup
A few things cannot be done from inside a container — installing Docker
itself, or the udev rules that let you flash a board over USB without
sudo. Those live in scripts: setup: and are not run on every start.
Run them once, explicitly:
denver examples/zephyr-devshell-4.3.1 --run setup
First run vs. every run after
The first run is slow: the image is built, packages are downloaded, the Zephyr repos are cloned. Later runs are fast, because every stage checks whether its inputs changed (via checksums and fingerprints) and skips its expensive work if they didn't. So starting the environment again is normally just a few seconds.
Two useful flags around this:
# don't build anything, only activate what already exists (fastest)
denver examples/zephyr-devshell-4.3.1 --fast
# ignore all "nothing changed" shortcuts and redo the expensive work
denver examples/zephyr-devshell-4.3.1 --force
The handful of options you'll actually use
# run ONE command inside the environment instead of opening a shell.
# everything after '--' is passed through untouched.
denver examples/zephyr-devshell-4.3.1 -- echo 123
# don't use docker; run the same stack directly on your host
denver examples/zephyr-devshell-4.3.1 --skip docker
# show what the stages would run, without running any of it
denver examples/zephyr-devshell-4.3.1 --dry-run
# stop after a given stage: that stage and every stage before it runs.
# (there is no "run just this one stage" -- a stage practically always
# needs its predecessors: uv needs conan's tools, zephyr needs uv's west)
denver examples/zephyr-devshell-4.3.1 --until uv
# print the final, fully merged configuration and exit -- the best way to
# understand what an environment really does, imports included
denver examples/zephyr-devshell-4.3.1 --show-config
# quieter output (-q keeps stage banners, -qq silences denver completely)
denver examples/zephyr-devshell-4.3.1 -qq -- west --version
Why is zephyr-devshell-4.3.1/denver.yml so short?
If you open it, you'll find under 60 lines — half of them comments, and no
stages: list or docker config at all. That's because of import:,
denver's inheritance mechanism:
import:
- ../zephyr-devshell # inherit that env's entire setup as a base
The chain looks like this:
examples/zephyr-docker/ "how to build & enter the container"
▲ imported by
examples/zephyr-devshell/ the shared base: the 5-stage pipeline,
▲ imported by shared conan recipes, common env variables
examples/zephyr-devshell-4.3.1/ ONLY the 4.3.1-specific bits:
pinned requirements, conanfile, blob list
So a Zephyr 4.4.0 environment would be a new folder whose denver.yml
imports the very same base and changes only the pinned versions — no
copy-pasting of the docker/conan/uv setup. (The shared base sets
runnable: false, so starting it directly is rejected: it is ingredients,
not a meal.)
Where to go next
- Curious what a minimal environment looks like?
examples/zephyr-uv/is nothing but a Python venv, andexamples/simple-env/just runs a shell script. - Writing your first own env? Start from Step 1 above and add a stage only when you hit the problem it solves — most environments never need all five.
- Want to write your own
denver.yml?doc/how-to.mdwalks through building one from an empty folder, stage by stage;doc/architecture.mddocuments every key of the schema; or copy the closestexamples/*/denver.yml. - Want details on one stage type's config keys? Each provider has its own
reference under
doc/providers/— e.g.doc/providers/docker.mdfor everydocker:key — and a terser lookup table in its module docstring next to the code (src/providers/docker.py).
You wanna set up your own environment?
Then start with doc/how-to.md.
It documents how a denver.yml is created from scratch for a common use case.
Helpful: The result of this is stored under:
examples/howto-env/
Environment variables
denver reads two environment variables of its own:
DENVER_STATE_DIR— an explicit root for denver's per-env state (venv, install trees, fingerprints, logs,performance.jsonl), overriding the default location described in Where an environment's state lives below. Useful to put that state on a larger or faster disk.DENVER_CACHE_DIR— the shared cache root denver exports as${DENVER_CACHE_DIR}for an env to point a tool's own download cache at (e.g.CONAN_HOME). Defaults to~/.cache/denver. denver never creates or reads it; it only offers the location, because such caches are content-addressed, safe to share between envs and checkouts, and expensive to duplicate.
Where an environment's state lives
By default, inside the environment's own directory:
my-project/env/
├── denver.yml
└── .denver/ # denver's state, ignores itself via its own .gitignore
└── denver/ # one subdirectory per denver*.yml in this folder
├── .venv.host
├── .conan/
└── performance.jsonl
State belongs with the environment that owns it: deleting a checkout deletes
exactly its own state, two checkouts of one project can never share (or
destroy) each other's, and a docker stage carries it into the container
for free, since the workspace is already bind-mounted there.
The <denver.yml stem> level exists because one folder may hold several
variants (denver.debug.yml, denver.release.yml) — those are different
environments sharing a folder, and must not share a venv.
denver falls back to ~/.denver/<env>-<hash> when it cannot write to the
env directory (a read-only mount, a vendored base env, an env shipped inside
an image), and DENVER_STATE_DIR overrides both.
Upgrading: state used to live in
<checkout-or-~/.denver>/.envs/<env name>, keyed on the directory's bare name. Those old directories are simply no longer read — delete them when convenient; everything in them is a cache denver rebuilds on the next run.
Every other flag (--force, --ci, ...) is set purely by its own CLI flag,
never inherited from a same-named real environment variable — see denver --help.
denver also exports a handful of built-in variables into the environment
it builds (DENVER_ENV_DIR, DENVER_ENV_NAME, ...), usable in ${...}
interpolation inside a denver.yml — see "Variable interpolation" in
doc/architecture.md.
Full flag reference
denver --help lists every flag; the notes below are for the ones whose
behavior isn't obvious from a one-line description.
-
-c/--config KEY.PATH=VALUEoverrides a single value in the mergeddenver.yml(e.g.-c uv.python=3.13); any missing parent section is created as an empty mapping.KEY.PATH+=VALUEappends to an existing list/string/number instead of replacing it (behaves like=if the path doesn't exist yet).VALUEis parsed as YAML, so"true"/"3"/"[a, b]"become their real type, not a string. Repeatable; later-cs win when they target the same path. -
-cf/--config-file FILEoverlays a whole YAML file on top of the env'sdenver.yml, using the same merge rules asimport:. Repeatable, applied in the order given;-coverrides are applied last, on top of every-cffile. -
--until <stage>truncates the pipeline: every stage up to and including<stage>runs, everything after it is dropped — there's no "run only this one stage" flag, since a stage practically always needs the ones before it. The command (if any) still runs afterwards, in whatever partial environment those stages built. -
--skip <stage>removes individual stages from whatever--untilleft; repeatable. Skipping a wrapper stage (--skip docker) is how you run the stack directly on the host instead of relocating into a container. -
--run <name>runs every (filtered) stage's ownscripts: <name>:list, then exits without running the rest of the pipeline — see "One-time host setup" above for an example.<name>is open-ended, not a fixed set of flags: a project can declarescripts: migrate:and rundenver <env> --run migratewithout denver itself changing. -
-q/-qqare two quiet levels.-qsilences info lines,+ cmdechoes, and build-tool subprocess output, but leaves each stage's own banner and "stage finished" summary visible.-qqadditionally silences those too, so only the launched command's own output reaches the terminal. Errors are always reported. -
--fastskips every provider's (re-)build step and only activates what a previous full run already built (each provider's own page underdoc/providers/documents exactly what that means for it). Run once without--fastfirst — a provider dies with a clear message if what it needs isn't there yet. -
--forceforces a provider to redo expensive work it would otherwise skip because nothing looked like it changed (again, see each provider's own page for specifics). Like--cibelow, this is only ever set by the flag itself, never inherited from a same-named real environment variable. -
--ciswaps in narrower/faster args a provider judges appropriate for a CI runner (currently just zephyr'swest update, adding a shallow-clone strategy on top of whateverupdate-args:already configures). -
--dry-runshows what each stage would do instead of doing it: no command is executed for its effect, no file is written, and the final command is printed rather than launched. Useful for answering "what does this env actually run?" without waiting for (or committing to) a real build. Every line is prefixed[dry-run]:marker meaning +a command that would run (skipped) ?a read-only query, really run — its output is what decides the commands below it ~a file or directory write that would happen (skipped) .a script sourced into the environment, really done !a note about what this preview cannot show The two "really" rows are the deliberate limit. A dry run has to answer questions like is the image already cached?, which conan home?, what does
west listsay? to render the commands that follow — so those read-only queries execute, and scripts are still sourced (that is how denver computes the environment a command is rendered against). Two further consequences worth knowing: the preview reflects the state your machine is in now, so an already-built env legitimately shows fewer commands than a clean one (that is what a real run would do too); and a wrapper stage (docker) can't be previewed past its own boundary, since entering the container is itself one of the commands not being run — denver says so and points you at--skip dockerto preview those stages on the host instead. -
--versionprints the running denver's version and exits — derived from the checkout's git tags when denver runs from a checkout (script or editable install), otherwise from the installed package's metadata. A checkout ahead of its last tag reports as a development build of the release it is heading for (1.1.0-17-gabc1234). Adenver.ymlcan require a minimum withdenver-version: ">=1.1.0", and is rejected up front by a denver older than that (seedoc/architecture.md).
Each stage's runtime is also appended to
<DENVER_DIR>/.envs/<env>/performance.jsonl as JSON Lines of Chrome Trace
Event Format events — concatenate them into a {"traceEvents": [...]}
document to load at chrome://tracing or https://ui.perfetto.dev.
Quick start
The same commands as above, as a cheat sheet:
# run the according setup scripts to install (host) requirements for this env
denver examples/zephyr-devshell-4.3.1 --run setup
# run the according login scripts from this env
denver examples/zephyr-devshell-4.3.1 --run login
# start the env (default command, which is fish)
denver examples/zephyr-devshell-4.3.1
# run a specific command in the development environment instead
denver examples/zephyr-devshell-4.3.1 -- echo 1
# same stack, but on the host instead of in docker
denver examples/zephyr-devshell-4.3.1 --skip docker
(If denver is vendored via git-nested, call src/denver.py directly instead.)
Known limitations
Every place denver runs needs import yaml to work. denver is a Python
program with exactly one runtime dependency, PyYAML, so installing it from
PyPI covers the host automatically. What it cannot cover is a wrapped
environment: a docker stage relocates the rest of the stack into the
container and re-invokes denver in there with the image's own bare python3
— an interpreter that knows nothing about the install on your host. That
image must supply PyYAML itself:
RUN apt-get update && apt-get install -y --no-install-recommends \
python3 python3-yaml \
&& rm -rf /var/lib/apt/lists/*
If it doesn't, denver stops with an error naming the interpreter that
failed to import yaml.
Which PyYAML that is, is deliberately not pinned. The host copy and the
image copy are resolved by two different package managers and will drift
apart in general. denver accepts that: it calls exactly two functions from
the library, yaml.safe_load and yaml.safe_dump, whose behaviour has been
stable across PyYAML releases for years. So any reasonably recent PyYAML is
fine, and denver imports whatever it finds instead of demanding a particular
version and forcing every image to track it. The declared dependency is a
floor (pyyaml>=6), not a pin — and it constrains only the host install
anyway, never the image's.
Contributing
Bug reports, feature requests and pull requests are welcome — see
doc/development.md for the workflow (uv run poe all
runs lint, format, mypy and the test suite; denver keeps 100% coverage).
License
Apache License 2.0 — see LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file denver_tool-1.3.0.tar.gz.
File metadata
- Download URL: denver_tool-1.3.0.tar.gz
- Upload date:
- Size: 428.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
19cef91d4c36cb688d6442810060e2554ec69b8021b5edaec63df2519849f85b
|
|
| MD5 |
0595cc0f27a0adc69a2a73ab3e11b54e
|
|
| BLAKE2b-256 |
6d166f6f722e92365924a0809807a73b13fd629eb11a11c64ad2cb02f2a4b536
|
Provenance
The following attestation bundles were made for denver_tool-1.3.0.tar.gz:
Publisher:
publish.yml on thorsten-klein/denver
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
denver_tool-1.3.0.tar.gz -
Subject digest:
19cef91d4c36cb688d6442810060e2554ec69b8021b5edaec63df2519849f85b - Sigstore transparency entry: 2425544640
- Sigstore integration time:
-
Permalink:
thorsten-klein/denver@eb8e105193270a596725354497378042ae4fdd50 -
Branch / Tag:
refs/tags/1.3.0 - Owner: https://github.com/thorsten-klein
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@eb8e105193270a596725354497378042ae4fdd50 -
Trigger Event:
push
-
Statement type:
File details
Details for the file denver_tool-1.3.0-py3-none-any.whl.
File metadata
- Download URL: denver_tool-1.3.0-py3-none-any.whl
- Upload date:
- Size: 125.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4c32954ac3f5974b59c8aea0a149871353e16d7edaf2564b80d88692e342fd66
|
|
| MD5 |
7d995298e2443594004eb47e373e6374
|
|
| BLAKE2b-256 |
9d7426d7697c254331bc0bbe356b784fc19ac3bd4fbd3361c61309d50a3e8556
|
Provenance
The following attestation bundles were made for denver_tool-1.3.0-py3-none-any.whl:
Publisher:
publish.yml on thorsten-klein/denver
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
denver_tool-1.3.0-py3-none-any.whl -
Subject digest:
4c32954ac3f5974b59c8aea0a149871353e16d7edaf2564b80d88692e342fd66 - Sigstore transparency entry: 2425544952
- Sigstore integration time:
-
Permalink:
thorsten-klein/denver@eb8e105193270a596725354497378042ae4fdd50 -
Branch / Tag:
refs/tags/1.3.0 - Owner: https://github.com/thorsten-klein
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@eb8e105193270a596725354497378042ae4fdd50 -
Trigger Event:
push
-
Statement type: