[READ-ONLY] Mirror of https://github.com/thoda-dev/shhh. Self-hostable zero-knowledge pastebin for secrets that expire on their own
docker end-to-end-encryption nuxt nuxtjs pastebin secrets selft-hosted zero-knowledge
shhh CONTRIBUTING.md
3.8 kB
Markdown

Contributing #

Setup #

Node 24 and pnpm 11 (mise install picks both up), plus a PostgreSQL database.

pnpm install
cp .env.example apps/app/.env   # DATABASE_URL, BETTER_AUTH_SECRET, BETTER_AUTH_URL
pnpm db:migrate
pnpm dev

Run these before opening a pull request. None of them needs a database:

pnpm lint
pnpm typecheck
pnpm test

Schema changes need a migration committed alongside them: pnpm db:generate. CI fails if the migrations and the schema disagree.

Integration tests #

pnpm test:integration builds the app, boots it and drives the routes over HTTP. It needs a database of its own: the schema is dropped on every run, which is why it reads TEST_DATABASE_URL rather than DATABASE_URL.

createdb shhh_test
TEST_DATABASE_URL=postgres://postgres:postgres@127.0.0.1:5432/shhh_test pnpm test:integration

Turnstile is exercised for real, on Cloudflare's always-passes test keys, so the run needs network access. TEST_SKIP_BUILD=true reuses the last .output while you iterate on the tests themselves. ROADMAP.md lists the suites still to write.

By taking part, you agree to the Code of Conduct.

Commit messages #

Conventional Commits: type(scope): subject, where type is one of feat, fix, docs, refactor, perf, test, build, ci or chore.

feat(pastes): allow a per-paste read limit
fix(auth): stop require_2fa being bypassed by disabling 2FA
docs: document the nginx reverse proxy setup

This is not style policing: the release script builds CHANGELOG.md from these messages with changelogen, and anything that does not match the format is dropped from the changelog entirely rather than listed badly.

pnpm install points core.hooksPath at .githooks, so a commit that does not match is refused locally before it exists. git commit --no-verify skips it when you need to. What actually gates a contribution is the pull request title, which CI checks: with squash merging that title becomes the commit on master, and therefore the changelog entry.

Scope #

ROADMAP.md lists what is planned and, at the bottom, what was evaluated and rejected. Reopening something from that second list needs a new argument, not a reminder.

Every pull request has to close an issue, and CI enforces it. Open one first, so the discussion happens before the work rather than on top of a finished branch.

AI assistance #

Part of shhh is written by hand, part with AI assistance, against a written spec. Design decisions — the security model in SECURITY.md in particular — are made and owned by a human, and every line that ships has been read and understood by a maintainer.

The documentation is a different case: this file, the README and the docs site are drafted with AI so that the English reads correctly. The decisions they describe came first — only the wording is assisted.

You are welcome to use AI tools on your contribution. Two things in return:

  • Say so in the pull request. Which tool, and roughly how much of the change it produced. One line is enough. This is not held against you: it tells the reviewer where to look hardest.
  • Be able to defend every line. If you can't explain why a change is correct, it isn't ready. A pull request its author can't discuss gets closed, whoever or whatever wrote it.

Two areas take no generated code without a very good reason: app/utils/crypto.ts and anything under server/api/ that decides authorization. Both are subtle, hard to review, and the cost of getting them wrong is the entire product.

Vulnerability reports follow the same rule — see SECURITY.md.