Contributing
Mint protects a confidentiality boundary. Prefer a small change that makes the boundary easier to prove.
Before you edit
Section titled “Before you edit”Read VISION.md first. It defines product scope and the non-disclosure invariant.
Read the owning source module and its tests. Use the repository map to find the seam.
Treat source, tests, and deployment declarations as behavior authority. Treat older prose as research input.
Name the observable behavior and the failing check before implementation.
Do not add a fallback that returns a raw credential. Do not turn a compatibility warning into a new contract.
Safe change workflow
Section titled “Safe change workflow”- Create or claim one work item with a concrete acceptance statement.
- Reproduce the current behavior through its real entry point.
- Change the deepest owning module.
- Add or update a focused test for the invariant.
- Update callers, declarations, and public references in the same change.
- Run the focused test and the boundary-specific live check.
- Run every required repository gate.
- Review the diff for values, stale paths, duplicate rules, and obsolete docs.
- Record source links and freshness metadata for changed documentation.
A unit test does not replace a live probe. A live probe does not replace static leak checks.
Use synthetic local values in examples. For an HTTP example, use 127.0.0.1 and example.com.
Add a consumer safely
Section titled “Add a consumer safely”Add a consumer only when an observed local flow needs credentialed work and a non-disclosing oracle exists.
Use a synthetic alias in examples, such as secret://demo/default. Never copy a real alias inventory into public docs.
- Add the alias to the alias declaration.
- Add one least-privilege rule to the policy declaration.
- Require the placeholder on the credentialed request.
- Bind actor, service, method, path, alias, and transport explicitly.
- Add the custody boundary without a value.
- Run the policy parser against the exact declaration.
- Add tests for allow, deny, wrong alias, and malformed input.
- Prove one allowed request and one denied direct path.
- Scan the clean launcher and confirm that raw credentials are absent.
- Revoke or remove the former direct grant before declaring adoption complete.
Keep a rule narrow. Do not copy a broad rule and rely on a later deny.
Change declarations and schemas
Section titled “Change declarations and schemas”Versioned declarations are strict input. Unknown fields, duplicate entries, malformed aliases, secret references, and control characters must fail closed.
Update the owning parser and the declaration schema together. Update the deployed declaration fixture and the exact schema tests together.
Native OAuth exceptions are exact records. Match provider identity, launcher identity, path, schema, allowed fields, owner, mode, and destination.
Do not publish private paths, user names, hostnames, IP addresses, credential identities, or alias inventories. Use placeholders in examples.
Keep declaration files value-free. A digest identifies a record. It must not become a way to publish the value.
When a schema changes, check these surfaces:
- Core parser and error type.
- Core integration test.
- Deployment declaration test.
- CLI validation path.
- MCP inspection path, if it reads the declaration.
- Documentation source map and freshness metadata.
Do not widen a parser to preserve malformed or legacy data. Migrate the data and keep the rejection test.
Update a public surface
Section titled “Update a public surface”A public surface is a deliberate re-export, CLI command, HTTP route, or MCP tool.
Update the owning surface and its consumer test in one change.
For core types, add a deliberate re-export in mint-core lib.rs only when downstream callers need it.
For CLI behavior, update clap help, command tests, and the CLI reference. Keep helper functions and enum internals private in the docs.
For HTTP behavior, update the route owner, proxy integration tests, denial tests, and the HTTP reference. Keep pub(crate) helpers out of API promises.
For MCP behavior, update tool metadata, input schema, JSON-RPC tests, and the MCP reference. Keep the server read-only unless the product contract changes first.
Never claim that an internal helper is stable because its Rust visibility is public inside a crate.
Leak-test requirements
Section titled “Leak-test requirements”The secret path must never expose raw credential bytes to an agent-accessible surface.
Check environment, configuration, process arguments, files, logs, audit records, tool output, response bodies, and captured test output.
Run the hermetic gate:
./scripts/zero-leak-check.shThe script generates a fresh sentinel. It runs the leak and exfil suites with captured output. It fails if the sentinel appears anywhere in that output.
It also runs the remote-probe verifier and shell syntax check. Read the pinned script.
Run the macOS proof for custody and end-to-end behavior:
./scripts/mint-probe.shThe probe uses a local fake vendor and a local keychain entry. It proves placeholder substitution, response and audit scrubbing, deny-before-upstream behavior, and a final zero-leak sweep. Read the pinned probe.
Do not remove a leak assertion because a different test already checks the response. The independent output scan is part of the gate.
Required gates
Section titled “Required gates”Run these commands before review:
cargo fmt --all -- --checkcargo clippy --workspace --all-targets -- -D warningscargo test --workspace./scripts/zero-leak-check.shRun the supply-chain and history checks before merge:
cargo auditgitleaks detect --source . --redact --no-bannergitleaks detect --source . --redact --no-banner --no-gitRun the macOS probe when custody, deployment, broker startup, or response behavior changes:
./scripts/mint-probe.shRun the documentation site gate when docs change:
(cd site && SITE_URL=https://mint.mistystep.io PUBLIC_SOURCE_URL=https://github.com/misty-step/mint npm run verify:public)The CI workflow is the required gate set. The Pages workflow verifies the public site, enables the repository Pages site when repository-admin authority permits it, and then publishes site/dist. Do not weaken a gate, skip a job, replace a real boundary with a mock, or treat a green unit test as full acceptance. Read the pinned CI workflow and Pages workflow.
Documentation provenance and freshness
Section titled “Documentation provenance and freshness”Every public page has title, description, sidebar order, generatedAtSha, and covers frontmatter.
Use the repository commit that supplied the facts. The page's generatedAtSha is the sole committed freshness baseline for its covered source set.
Set covers to the narrowest exact source globs that the page claims. Include tests and scripts when the page describes their contract.
Add a short Source map section. Pin each source link to the immutable implementation commit it describes and include exact line ranges.
Separate shipped behavior from vision. Link to the owning page instead of repeating its facts.
Run site freshness and link checks after source changes:
(cd site && npm run check:freshness)(cd site && npm run check:links)The freshness checker compares covered paths changed from generatedAtSha through HEAD, plus staged, unstaged, and untracked paths. Editing a page never waives a covered source change. Refresh generatedAtSha and review the source map after source changes. The checker and its deterministic fixture are source-linked below.
Do not publish labs, reports, traces, internal receipts, deployment coordinates, secret values, or value-derived data.
Source map
Section titled “Source map”This page uses:
- VISION.md
- declaration parsing tests
- the CI workflow
- the GitHub Pages workflow
- the live secret-scan fixture policy
- the exact historical false-positive fingerprints
- the freshness checker
- the deterministic freshness fixture
- the executable-code typography checker
- the public-origin checker
- the public-origin fixture
- the link checker
Source references pin the implementation commit they describe. The examples above use synthetic values and public loopback addresses only.