Skip to content

Latest commit

 

History

History
222 lines (165 loc) · 8.13 KB

File metadata and controls

222 lines (165 loc) · 8.13 KB

Contributing to sealed-env

First — thank you. sealed-env is a small open-source project maintained by David Almeida, and any review, PR, or issue from outside eyes is genuinely valuable.

This document covers what you need to contribute productively. Read the sections relevant to what you want to do — you do not need to read the whole thing.


Quick start by contribution type

What you want to do Read
Report a non-security bug Filing a bug
Report a security vulnerability SECURITY.md — DO NOT open a public issue
Suggest a feature Filing a feature request
Submit a code PR Code contribution flow
Propose a change to the wire format Spec changes
Add a new language adapter (Python / Go / Rust) Adapter contributions
Improve docs / fix typos Just open a PR — no ceremony needed

Project layout

sealed-env/
├── node/            Node.js implementation (TypeScript, zero deps)
├── java/            Multi-module Maven (sealed-env-core + spring-boot-starter)
├── docs/            Reading-order numbered guides (01-overview..06-format)
├── site/            Public landing page (GitHub Pages, plain HTML/CSS)
├── test-vectors/v1/ Cross-stack test vectors generated by Node, read by Java
├── assets/          Roman sigillum brand assets (SVGs)
├── SPEC.md          Canonical .env.sealed v1 wire format specification
├── THREAT_MODEL.md  Public threat model — what we defend against
├── SECURITY.md      How to report vulnerabilities privately
└── README.md

Local setup

Node side

cd node
npm install
npm run build
npm test

Requires Node 20 or 22. No global tools. Tests run with the built-in node --test runner.

Java side

cd java
./mvnw verify              # if you have the Maven Wrapper
mvn -B verify              # if you have Maven on PATH

Requires JDK 17 or 21. The Java build also runs cross-stack interoperability tests that consume the JSON vectors in test-vectors/v1/ — make sure those are present (regenerate with node node/scripts/gen-test-vector.mjs).

Cross-stack tests on every commit

The Java CI workflow regenerates the test vectors using Node before running the Java build, so a change in either implementation that breaks interoperability will be caught immediately. Run both sides locally before pushing PRs that touch crypto or format code.


Filing a bug

Use the Bug report issue template. The minimum we need to act:

  1. A minimal reproduction (10 lines of code or fewer ideally).
  2. The mode you're using (basic, team, or enterprise).
  3. Versions: sealed-env (npm) or sealed-env-core (Maven), plus your Node version or JDK version.
  4. OS: Linux distribution, macOS version, or Windows version.
  5. The exact error message you're seeing — full stack trace if Java.

⚠️ If the bug has security implications, do NOT file a public issue. See SECURITY.md for private disclosure.


Filing a feature request

Use the Feature request issue template. The minimum we need:

  1. The use case — what problem are you trying to solve, in your words.
  2. What you tried — current workarounds, why they don't work for you.
  3. Whether this would touch the wire format (a new metadata field, new mode, change to AAD construction, etc.). If yes, see Spec changes.

Code contribution flow

  1. Open an issue first for anything beyond a typo. Saves both of us the pain of you spending an afternoon on a PR I'll have to close.
  2. Fork → branch → PR as usual. One logical change per PR.
  3. Tests are required for code changes. The bar:
    • New crypto code → unit tests + a cross-stack vector if the wire format is touched.
    • New API surface → tests covering happy path + at least one error case.
    • Bug fix → a regression test that fails before your fix and passes after.
  4. CI must be green before review. Run npm test and mvn verify locally first.
  5. Sign your commits if you have GPG configured. Not required, but appreciated.

Commit message convention

Loosely Conventional Commits. Prefixes I use:

  • feat: — a new user-facing capability
  • fix: — a bug fix
  • docs: — documentation only
  • refactor: — code movement with no behavior change
  • test: — tests only
  • ci: — CI / GitHub Actions changes
  • chore: — version bumps, deps, housekeeping

Scope optional: feat(java): ..., fix(node): ..., docs(readme): ....


Changes to the wire format (SPEC)

The SEALED-ENV-V1 wire format is frozen. Files written today will be readable forever. Spec changes require:

  1. An issue describing the change and the threat or capability it enables.
  2. A semver decision: backwards-compatible additions (new optional metadata) are OK on V1. Anything that would break existing readers requires V2.
  3. Both implementations updated in the same PR (Node and Java) plus updated test vectors covering the new behavior.
  4. A spec PR is always also a THREAT_MODEL.md PR — explain what the change does to the threat model.

If you're not sure whether something needs V2, open the issue and we'll work it out.


Crypto changes

This is a security tool. Changes that touch cryptographic code require extra care:

  • No replacing primitives without discussion. AES-GCM, scrypt, Argon2id, HKDF-SHA256, HMAC-SHA256, and TOTP/RFC 6238 are pinned by SPEC. You can add support for additional KDFs (e.g. a future Argon2d) but you cannot remove or weaken existing ones in v1.
  • No custom crypto. If you find yourself writing your own MAC, your own KDF, or your own padding scheme, stop and open an issue first.
  • Constant-time comparisons are mandatory wherever a secret is compared. Use crypto.timingSafeEqual (Node) or MessageDigest.isEqual (Java).
  • Key wiping (wipe(buf) in both implementations) must be called on derived keys after use. JVM/V8 may move memory around, but the hygiene matters.

If you're curious about a specific decision, the threat model document explains the reasoning — read it before proposing alternatives.


Adapter contributions

We'd love to see Python, Go, and Rust readers (and writers) of the .env.sealed v1 format. Suggested approach:

  1. Read the SPEC end to end.
  2. Run the Java tests so you understand what passing the format conformance suite looks like.
  3. Use the test vectors in test-vectors/v1/ as your conformance bar. A new adapter MUST be able to decrypt every vector and produce the expected plaintext.
  4. Open an issue before you start so we can coordinate (and so you don't end up duplicating work that's already in progress).
  5. Adapters live in the same monorepo under their own top-level directory (python/, go/, rust/) for now. We'll split into separate repositories if any grows large enough to need its own release cadence.

What we won't accept

  • Removing the threat model. It's a feature, not noise.
  • Removing the public spec. Same reason.
  • Adding a "convenience" mode that weakens defaults (e.g. a --no-hmac flag for team mode). The whole point of mode tiers is that each tier provides an unbreakable floor.
  • Telemetry or analytics in the library. Period.
  • Dependencies beyond what's already pinned, especially in the Node implementation, without strong justification.

Code of conduct

This project follows the Contributor Covenant 2.1. Be kind, assume good faith, and remember that the person on the other end of the keyboard is trying to do their best.


Questions

If something is unclear in this document or in the code: