dsoxlab — DevSecOps XL Labs CLI
Read this in another language: Français
dsoxlab turns declarative exercises into reproducible, runnable and
verifiable environments. A catalog states what it offers through a root
meta.yml and one lab.yaml per lab; the engine provisions what each lab
asks for, opens it, and proves the result with tests that read the state of
the system rather than the commands typed into it.
Nothing about a specific domain lives in the engine: it serves Linux, Ansible, Kubernetes or Terraform labs equally well, and any other catalog that honors the declarative contract. It also scores progress and keeps the history locally, per catalog.
Originally built for the tutorials on blog.stephane-robert.info, and usable without them.
Install and play, in five minutes
Requires Python 3.11+. Nothing to clone, nothing to build.
uv tool install dsoxlab # or: pipx install dsoxlab
dsoxlab demo # installs a one-lab demonstration catalog
cd ~/.local/share/dsoxlab/demo
dsoxlab course premiers-pas # the lesson
dsoxlab run premiers-pas # drops you into the lab's work directory
dsoxlab challenge premiers-pas # the mission
dsoxlab check premiers-pas # the tests, and the score
The demonstration lab is about dsoxlab itself, and needs no VM, no container and no Docker: it runs anywhere dsoxlab runs.
Documentation
Three readers, three doors. Every page names its audience in its first lines.
| I want to… | Read |
|---|---|
| Install dsoxlab, play labs, understand my score | For the learner |
| Write my own catalog of labs | For the catalog author, then the v1 contract field by field |
| Run the machines the labs need | For the trainer |
| Know where dsoxlab writes on my disk | Where dsoxlab writes |
| See every command | Command reference, generated from the CLI |
In the terminal, dsoxlab fullhelp prints the whole platform guide, in English
or in French.
Why dsoxlab
- One engine, many catalogs. A single CLI drives every training
repository. Add a new domain by writing a
meta.yml, not by patching the tool. - Validation proves, it does not trust. Labs are graded on the actual
state of the system (
pytest-testinfra) and, when it matters, on persistence after reboot — the trap that fails RHCSA/LFCS candidates. - Two runtimes. A lab runs either in a shell on your own machine, or in a vm provisioned for you. Which backend serves that VM (KVM/libvirt, Incus, Outscale) is the catalog's decision, not the lab's.
- Progress that sticks, per catalog. Scores, hint costs and history are persisted inside the catalog itself, so two catalogs never mix their histories.
- Bilingual UX. Every user-facing string ships in English and French
(
DSOXLAB_LANG=en|fr).
Contributing
git clone https://github.com/stephrobert/dsoxlab.git
cd dsoxlab
uv tool install --editable .
See CONTRIBUTING.md for the development setup, the quality
gates and the non-negotiable rules (the engine stays domain-agnostic, every
user-facing string goes through _() in both languages).
Security
Security posture is enforced, not aspirational — every workflow is scanned by its own tooling on each push and pull request:
- Hardened GitHub Actions. Every action is pinned to a full commit SHA, the
default token has no permissions (jobs opt into least privilege), and
checkoutnever persists credentials. - zizmor statically analyzes the
workflows on every PR (
ci.yml). - Plumber validates the CI/CD against a trust
policy (
.plumber.yaml) at a 100% compliance threshold, and publishes the score badge (plumber.yml). - OpenSSF Scorecard tracks the
supply-chain posture (
scorecard.yml). - PyPI Trusted Publishing (OIDC). Releases carry no long-lived token and
ship PEP 740 attestations (
release.yml). - Pre-commit secret scanning. TruffleHog and private-key detection run locally before every commit (see CONTRIBUTING.md).
To report a vulnerability, follow SECURITY.md.
The mark and its files are documented in docs/brand.md; the name and the logo are not covered by the Apache 2.0 licence.
License & attribution
Licensed under the Apache License 2.0 — see LICENSE and NOTICE.
You may use, share and adapt this project, including commercially, provided you give appropriate credit to Stephane Robert and link back to https://blog.stephane-robert.info, and indicate whether changes were made. Apache-2.0 keeps those same two obligations — attribution and stating your changes — and adds an express patent grant.
Up to and including 0.1.12, dsoxlab was distributed under Creative Commons
Attribution 4.0 (CC BY 4.0). That grant is irrevocable, so those releases remain
available under CC BY 4.0. From 0.1.13 onwards the project is Apache-2.0:
Creative Commons licences are not designed for software, and this one left the
patent question open while marking the package as Other/NOASSERTION on PyPI.
© 2026 Stephane Robert.
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 dsoxlab-0.1.65.tar.gz.
File metadata
- Download URL: dsoxlab-0.1.65.tar.gz
- Upload date:
- Size: 1.5 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
16b8cf0d6335e4cecdd962151a1ae46b2ea82e11eccc9973e5aaaeb3eb3583d0
|
|
| MD5 |
9919e015e8af25a458ed51a70307d1ee
|
|
| BLAKE2b-256 |
7012fbdf3ea51b2e0f158d9902c73eb560b27fe599abfbe4900d6292b5a3918f
|
Provenance
The following attestation bundles were made for dsoxlab-0.1.65.tar.gz:
Publisher:
release.yml on stephrobert/dsoxlab
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dsoxlab-0.1.65.tar.gz -
Subject digest:
16b8cf0d6335e4cecdd962151a1ae46b2ea82e11eccc9973e5aaaeb3eb3583d0 - Sigstore transparency entry: 2580004226
- Sigstore integration time:
-
Permalink:
stephrobert/dsoxlab@d3bcdf2dfa017ece82c92b73e7cca25670ef13de -
Branch / Tag:
refs/tags/v0.1.65 - Owner: https://github.com/stephrobert
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@d3bcdf2dfa017ece82c92b73e7cca25670ef13de -
Trigger Event:
push
-
Statement type:
File details
Details for the file dsoxlab-0.1.65-py3-none-any.whl.
File metadata
- Download URL: dsoxlab-0.1.65-py3-none-any.whl
- Upload date:
- Size: 296.6 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 |
03e9c3b8d41a43fe1cbda10c5e43631f73dc6cfdbf7ceae72b947eaca5562729
|
|
| MD5 |
27a3e75b7a351bac51e800c442d8614a
|
|
| BLAKE2b-256 |
2f6b29fee82675fa7a17072f5d6a5672452ee7ed33dff8565e6cdb9207ad5702
|
Provenance
The following attestation bundles were made for dsoxlab-0.1.65-py3-none-any.whl:
Publisher:
release.yml on stephrobert/dsoxlab
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dsoxlab-0.1.65-py3-none-any.whl -
Subject digest:
03e9c3b8d41a43fe1cbda10c5e43631f73dc6cfdbf7ceae72b947eaca5562729 - Sigstore transparency entry: 2580004239
- Sigstore integration time:
-
Permalink:
stephrobert/dsoxlab@d3bcdf2dfa017ece82c92b73e7cca25670ef13de -
Branch / Tag:
refs/tags/v0.1.65 - Owner: https://github.com/stephrobert
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@d3bcdf2dfa017ece82c92b73e7cca25670ef13de -
Trigger Event:
push
-
Statement type: