- Dev Center
- Documentation
- Project
- Contributing
Project
Contributing
How to contribute to diagnos integration: setup with uv and Rust, the checks CI runs, code conventions and the pull request checklist.
English · Português (Brasil)
Thank you for considering a contribution to diagnos, diagnos-cli or diagnos-api. This document is the
practical guide: how to set up the workspace, the loop you run while working, what CI checks and how to reproduce
each check locally, the code conventions carried over from this repository's history, and the pull request
checklist. For the standards of behaviour we hold everyone to, see CODE_OF_CONDUCT.md. To
report a vulnerability, see SECURITY.md instead of opening an issue.
Prerequisites#
| You need | Why |
|---|---|
| uv | one venv for the whole workspace (apps/sdk, apps/cli, apps/api) |
| Python 3.11 – 3.13 | the three CPython versions CI tests against |
| Rust stable | only to build apps/sdk/native (the memory enclave) from source — PyPI wheels ship prebuilt |
You do not need Rust installed to use the packages from PyPI; you need it to build diagnos from a checkout, because
make sync compiles apps/sdk/native for you.
First setup#
git clone https://github.com/diagnos-tech/integration && cd integration
make sync # installs everything and builds the Rust enclave
make check # lint + types + tests + contract check — what CI runs
If make check is green on a fresh clone, your environment matches CI's.
The everyday loop#
make fmt # auto-format and auto-fix Python (ruff) and Rust (cargo fmt)
make test # unit tests: the three Python packages + the Rust enclave
make cov # unit tests with one combined coverage report (htmlcov/)
make contract # Pact consumer tests; regenerates contracts/*.json
Run make help at any time to list every target with a one-line description.
What CI runs, and how to reproduce it locally#
CI is three workflows, each answering one question. make check runs the same four steps in the same order, so a
green make check on your machine means a green PR.
| Workflow | Answers | Local equivalent |
|---|---|---|
CI (.github/workflows/ci.yml) |
Does the code pass static checks and type-check? | make lint (ruff, cargo fmt --check, cargo clippy -D warnings, bilingual-docstring check, docs-pairs/links check) + make types (mypy --strict over the packages, the contract tests and scripts) |
Unit tests (.github/workflows/unit-tests.yml) |
Do the three Python packages and the Rust enclave pass their own tests, on every supported CPython, without the coverage floor slipping? | make cov (or make test for a faster pass without the combined coverage report) |
Contract tests (.github/workflows/contract-tests.yml) |
Does the SDK still speak the HTTP contract the vault verifies? | make contract-check |
make check runs lint, types, test and contract-check in that order — it is exactly what the three workflows
run, just in one command on your machine.
Code conventions#
These rules govern code (.py and .rs files); they used to live in CONVENTIONS.md, which this document replaces.
Bilingual docstrings. Every module, class and public function carries a docstring with an English paragraph prefixed
🇺🇸followed by the Portuguese paragraph prefixed🇧🇷. Inline comments follow the same pair on consecutive lines. Comments explain the why (the threat, the cost, the protocol constraint), never restate the code. Rust doc comments (//!for modules,///for items) follow the identical rule.scripts/check_bilingual.py(part ofmake lint) fails the build when a docstring or doc comment is missing either flag.def sign(request: CanonicalRequest, sign_key: bytes) -> str: """🇺🇸 HMAC-SHA512 over the canonical string, hex-encoded. The vault reconstructs the same string from the raw request; any byte we normalize differently is a 401, so this mirrors `canonical.ts` verbatim. 🇧🇷 HMAC-SHA512 sobre a string canônica, em hex. O cofre reconstrói a mesma string a partir da requisição crua; qualquer byte normalizado diferente é 401, então isto espelha `canonical.ts` ao pé da letra. """Small files, one responsibility. A folder per domain (
crypto/,session/,resources/,transport/). No file above ~250 lines.cliandapiimport onlydiagnos. If they need something the SDK does not expose, the SDK grows — the shells never reimplement cryptography, signing or retry logic.Pending decisions are
TODO(gustavo): .... NoFIXME, noHACK.Secrets never live in a Python
bytearrayorbytes. Session keys, DEKs and private keys live indiagnos._secure.SecretBox— page-locked Rust memory (apps/sdk/native), zeroed on drop. The only exit isreveal(), reserved for the OpenBao auto-unseal export.unsafeRust is confined. It lives only innative/src/locked/(memory and capabilities),native/src/buffer.rsandnative/src/process.rs(rlimit/prctl) — the places that actually touch raw memory. Everyunsafeblock carries aSAFETY:comment stating the invariant that makes it sound.Frozen wire labels never get renamed. The
imgexam-*-v1HKDF/AAD labels (apps/sdk/src/diagnos/crypto/) and the OpenBao static seal key idimgexam-static-v1(apps/api/deploy/) are persisted cryptographic constants. Renaming one would make every stored ciphertext, or an existing OpenBao install, unreadable. SeeMIGRATING.mdfor the full explanation.
Documentation rule#
Every document ships as NAME.md (English) next to NAME.pt-BR.md (Brazilian Portuguese), with a language switcher
right under the H1 linking to its sibling. scripts/check_docs.py (part of make lint) fails the build when a
document has no sibling, no switcher, or a dead relative link. CHANGELOG.md and the files under .github/ are
exempt — see that script's docstring for the exact rule.
Changing the HTTP behaviour of the SDK#
If your change touches what VaultTransport sends to, or reads from, the vault, its contract has to change with it:
- Add or update the interaction in
contracts/tests(seecontracts/README.mdfor how). - Run
make contractto regeneratecontracts/diagnos-sdk-diagnos-vault.json. - Commit the regenerated file in the same pull request.
CI's make contract-check fails a PR whose SDK behaviour changed without a matching contract change — it compares
the committed file against a fresh, full run instead of rewriting it.
Coverage ratchet#
fail_under in the root pyproject.toml ([tool.coverage.report]) is a floor, not a target: raise it when overall
coverage goes up, never lower it to make a pull request pass. make cov prints the current combined number
(branch coverage, all three packages).
Commit style#
Commits follow Conventional Commits: a type, an optional scope, and an
imperative summary — for example fix(sdk): correct clock skew handling, test(contracts): add a lock interaction,
docs: expand the OpenBao auto-unseal tradeoff.
Every commit must carry a DCO sign-off. Use git commit -s (or add
Signed-off-by: Your Name <[email protected]> by hand) on every commit; it certifies you have the right to submit the change under the project license.
Releasing#
Out of scope for this document. In short: there is no separate release process to follow yet — each package's
version lives in its own pyproject.toml (apps/sdk/pyproject.toml, apps/cli/pyproject.toml, apps/api/pyproject.toml), and at
runtime __version__ is read from the installed package's metadata rather than hard-coded.
Pull request checklist#
Before you open a pull request:
-
make checkis green locally (lint, types, tests, contract check). - If the SDK's HTTP behaviour changed,
contracts/diagnos-sdk-diagnos-vault.jsonwas regenerated (make contract) and committed. - Any documentation you added or changed exists in both
NAME.mdandNAME.pt-BR.md, with matching structure and substance. - New or changed public docstrings (Python and Rust) carry both the
🇺🇸and🇧🇷paragraphs. - No secrets, tokens or real credentials are committed — including in test fixtures and deploy examples.
- Commits follow Conventional Commits and are signed off (
git commit -s).
In this section
- Documentation How the diagnos documentation is written, generated and checked: site.json, bilingual pairs, runnable snippets and make docs-check.
- Migrating from imgexam Moving from the imgexam packages to diagnos: renamed packages, CLI, image and environment variables, and what did not change on purpose.
- Security Policy How to report a vulnerability in the diagnos SDK, CLI, API or deploy manifests privately, supported versions and scope.
- Contributor Covenant Code of Conduct The standards of behaviour everyone in the diagnos integration community is held to, and how to report a problem.