diff --git a/CLAUDE.md b/CLAUDE.md index f0b1399..728d94d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -147,6 +147,5 @@ Update together: - `README.md` - `INSTALL.md` (setup, deployment, and configuration guide) -- `AGENTS.md` - `setup.sh` (if setup/deploy assumptions changed) - Tests under `src/routes/*.test.ts` and `src/test/setup.ts` diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..6b4ffb9 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,86 @@ +# Contributing to kill-the-news + +Thanks for your interest in contributing! This is a small, self-hosted +Cloudflare Worker project. Issues, bug fixes, and well-scoped features are all +welcome. + +## Getting started + +Requirements: Node.js (LTS) and npm. A Cloudflare account is only needed to +deploy, not to run tests locally. + +```bash +git clone https://github.com/juherr/kill-the-news.git +cd kill-the-news +npm install # installs deps and builds client scripts (prepare hook) +npm run dev # start the local dev server (wrangler dev) +``` + +For full setup, deployment, and configuration details, see +[INSTALL.md](INSTALL.md). + +## Development workflow + +```bash +npm test # run all tests once +npm run test:watch # run tests in watch mode +npm run build # dry-run deploy bundle (wrangler deploy --dry-run) +npm run format # format with Prettier +``` + +Run a single test file: + +```bash +npx vitest run src/routes/admin.test.ts +``` + +Client-side scripts live in `src/scripts/client/` and are compiled by esbuild +into `src/scripts/generated/` (gitignored). They rebuild on `npm install`; to +rebuild manually: + +```bash +npm run build:client +``` + +The architecture, source layout, and KV schema are documented in +[CLAUDE.md](CLAUDE.md) — a good orientation before making changes. + +## Before opening a pull request + +- **Add or update tests** for any behavior change. Tests live in + `src/routes/*.test.ts`, with shared mocks in `src/test/setup.ts`. +- **Run the checks**: `npm test`, `npm run build`, and `npm run format`. + Pre-commit hooks (husky + lint-staged) run lint/format on staged files. +- **Keep docs in sync.** When you change behavior, update the relevant files + together: + - `README.md` + - `INSTALL.md` (setup, deployment, configuration) + - `setup.sh` (if setup/deploy assumptions changed) +- **Keep PRs focused.** One logical change per PR is easier to review. + +## Commit messages + +This project follows [Conventional Commits](https://www.conventionalcommits.org/) +with a scope, matching the existing history. Examples: + +``` +feat(admin): collapse create-feed form into accordion +fix(attachments): render inline cid: images in emails and feeds +refactor(home): dedupe byte formatting in storage cards +docs(readme): add Continuous deployment section +``` + +Common types: `feat`, `fix`, `refactor`, `docs`, `test`, `chore`. + +## Reporting bugs and requesting features + +Open an issue at +[github.com/juherr/kill-the-news/issues](https://github.com/juherr/kill-the-news/issues). +For bugs, include reproduction steps, expected vs. actual behavior, and your +environment (ingestion method, relevant config). For security issues, follow +[SECURITY.md](SECURITY.md) instead of opening a public issue. + +## License + +By contributing, you agree that your contributions will be licensed under the +[MIT License](LICENSE). diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..4e668a6 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,61 @@ +# Security Policy + +## Supported versions + +kill-the-news is a self-hosted, single-Worker application. Only the latest +release on the `main` branch receives security fixes. If you run a fork or an +older deployment, update to the latest `main` before reporting an issue. + +## Reporting a vulnerability + +**Please do not open a public GitHub issue for security problems.** + +Report privately through one of: + +- [GitHub Security Advisories](https://github.com/juherr/kill-the-news/security/advisories/new) (preferred) +- Email: me@juherr.dev + +Please include: + +- A description of the issue and its impact +- Steps to reproduce (proof-of-concept if possible) +- Affected route, file, or configuration +- Any suggested remediation + +You can expect an acknowledgement within a few days. Since this is a +volunteer-maintained project, fix timelines depend on severity and +availability, but credible reports are taken seriously. Coordinated disclosure +is appreciated — please give a reasonable window for a fix before going public. + +## Scope + +Because this Worker ingests email and exposes feeds, the security-sensitive +surface includes: + +- **Admin authentication** — password handling, the signed session cookie, and + constant-time secret comparison (`ADMIN_PASSWORD`, `PROXY_AUTH_SECRET`). +- **Inbound ingestion** — the ForwardEmail webhook (`POST /api/inbound`), + IP allowlisting, and the Cloudflare Email Workers handler. +- **Email rendering** — HTML sanitization for stored emails and feed output + (XSS via `entries/`, `rss/`, `atom/`, inline `cid:` images). +- **Public endpoints** — `GET /`, `GET /api/stats`, `GET /rss/:feedId`, + `GET /atom/:feedId`, `GET /files/:attachmentId/:filename`, + `GET /favicon/:feedId`. + +### Out of scope + +- Vulnerabilities in Cloudflare, ForwardEmail, or other third-party + infrastructure (report those to the respective vendor). +- Misconfiguration of a self-hosted deployment (e.g. a weak `ADMIN_PASSWORD`, + an exposed `workers.dev` subdomain, or committing secrets). See the security + notes in [README.md](README.md) and [INSTALL.md](INSTALL.md). +- Denial of service from sending large volumes of email. + +## Hardening reminders for operators + +- Use a strong, unique `ADMIN_PASSWORD` and rotate it periodically. +- Set `ADMIN_PASSWORD` via `wrangler secret put` — never in config files. +- Disable the `workers.dev` subdomain in production (`workers_dev = false`), + since `CF-Connecting-IP` can be spoofed on direct `workers.dev` requests. +- Set per-feed `Allowed senders` for high-value feeds. +- Never commit `wrangler.toml` or `.dev.vars` (both are gitignored).