Files
steve bb4ed3502d P5: OSS readiness — docs site, contributor onboarding, e2e harness
P5-01 — Documentation site under docs/book/ rendered with mdBook
(downloaded via Makefile, same static-binary pattern as Tailwind).
Structured chapters: getting started, concepts, operations,
security, reference. `make docs` / `make docs-watch`. Generated
output gitignored.

P5-02 — CONTRIBUTING.md rewritten from placeholder to a full
guide. CODE_OF_CONDUCT.md adapted from Contributor Covenant for a
single-maintainer project. .gitea/issue_template/{bug,feature}.md
and PULL_REQUEST_TEMPLATE.md.

P5-04 — Six README screenshots captured live from a fresh server
bootstrap (login, empty dashboard, add-host, alerts, settings,
audit log). README rewritten to centre the screenshot grid and
link out to the docs site.

P5-05 — SECURITY.md with disclosure policy (3-day ack, 30-day
default window), scope in/out, threat-model summary, operator
hardening checklist. Mirrored as a docs-site chapter.

P5-06 — End-to-end test harness. e2e/compose.e2e.yml brings up
server + sibling Linux agent (alpine + restic) + restic/rest-server.
Agent uses announce-and-approve so Playwright can drive the full
operator flow: bootstrap → login → accept pending → backup →
verify terminal status. Second spec scrapes /metrics to assert
the P6-04 endpoint surface. .gitea/workflows/e2e.yml runs on every
PR; local how-to in docs/e2e.md.
2026-05-08 20:08:23 +01:00

138 lines
5.5 KiB
Markdown

# Security policy
restic-manager handles credentials that grant access to backup
repositories — losing them means an attacker can read or destroy a
fleet's backups. We take security reports seriously even at this
project's small scale.
## Supported versions
Pre-1.0, only the latest tagged release on `main` is supported.
Backporting fixes to older tags is not currently offered.
| Version | Supported |
|--------------------|----------------|
| `main` HEAD | Yes |
| Latest released tag| Yes |
| Anything older | No |
## Reporting a vulnerability
**Please don't open a public issue for security problems.**
Instead, use one of these private channels:
1. **Gitea private message** to the repository owner. The
instance is at <https://gitea.dcglab.co.uk> and the owner's
profile (`steve`) has direct-message contact set up.
2. **Email** to the address on the maintainer's Gitea profile.
Use a subject like `[SECURITY] restic-manager: <one-line summary>`
so it doesn't get lost. PGP optional — if you want to encrypt,
ask for a key first.
If you don't get an acknowledgement within **3 working days**,
please escalate through the other channel — solo maintainers do
miss things, and the goal here is to fix the problem, not to
preserve protocol.
### What to include
- A description of the issue and the impact (what does an attacker
gain? confidentiality, integrity, availability?).
- Affected component (server, agent, install script, docs).
- Affected version (`restic-manager-server --version`).
- Reproduction steps if you have them. A working PoC is welcome
but not required — a credible threat model is enough.
- Whether you intend to publish a writeup, and any timing
preferences.
### What we'll do
1. Acknowledge receipt within 3 working days.
2. Confirm or refute the issue, and agree a rough severity (CVSS
or just "this is bad / this isn't"). Asking clarifying
questions is normal at this stage — please don't read it as
foot-dragging.
3. Develop a fix on a private branch, test it, and prepare a
release.
4. Coordinate disclosure timing with you. The default is **30
days from confirmed report to public disclosure**, with a
patched release published before the disclosure date. Faster
if a workable PoC is already circulating; slower only by
mutual agreement.
5. Credit the reporter in the release notes (or omit the credit
if you'd rather stay anonymous — your choice).
## Scope
In scope:
- The server binary (`cmd/server`) and any HTTP, WebSocket, or CLI
surface it exposes.
- The agent binary (`cmd/agent`) and the way it consumes commands
from the server.
- The install scripts (`deploy/install/install.sh`, `install.ps1`)
and the systemd unit shipped with them.
- The docker-compose reference deployment and the docker image we
publish.
- Any cryptographic primitive choice or implementation detail
(AEAD, token hashing, session handling, OIDC handshake).
- Documentation that, if followed, leads operators into an
insecure configuration.
Out of scope (not because they aren't real problems, just not ones
this report channel can act on):
- Vulnerabilities in restic itself — report those upstream at
<https://github.com/restic/restic>.
- Vulnerabilities in third-party dependencies that haven't yet been
patched upstream — report upstream first.
- Issues that require pre-authenticated admin access on the control
plane (admins can already do everything; that's not a privilege
escalation, that's the design).
- DoS via resource exhaustion on a deployment without the
recommended reverse proxy / rate limiting in front (see
`docs/reverse-proxy.md`).
- Social-engineering scenarios that don't have a technical hook
into the project's own surfaces.
## Threat model summary
For context (longer version in [`spec.md`](./spec.md) §11):
- The server is **HTTP-only**; TLS termination, ACME, HSTS, and
edge rate-limiting are the reverse proxy's job.
- Credentials are encrypted at rest with an AEAD key loaded from
`RM_SECRET_KEY_FILE`. The same key encrypts agent secrets that
travel to the agent over the WS channel.
- Agents authenticate with bearer tokens issued at enrolment and
hashed at rest. Compromise of the server DB does **not** leak
bearer tokens in plaintext, but does leak the hashes (which is
enough to log in *as* the agent until the operator revokes —
see [NS-01 / NS-02](./tasks.md) for the revoke + regenerate
flows).
- The control plane intentionally **never touches backup bytes**
the agent runs `restic` directly against the repo. A
compromised control plane can dispatch new jobs but cannot
exfiltrate snapshot contents in-band.
- Append-only credentials are first-class. Forget/prune jobs use a
separate, admin-marked credential that the server only pushes
for the duration of a maintenance dispatch.
## Hardening checklist for operators
- Run behind a TLS-terminating reverse proxy (Caddy/nginx/Traefik).
- Set `RM_TRUSTED_PROXY` to the proxy's CIDR so request IPs aren't
spoofable.
- Back up `RM_SECRET_KEY_FILE` separately from the database.
Without it the encrypted creds are unrecoverable.
- Use append-only credentials for the everyday backup path; only
the optional admin credential should have write/forget/prune
power.
- Disable users (don't delete) when staff change roles — bearer
tokens stay valid until rotated.
- Watch the alert and audit-log views during enrolment of new
hosts.
Thanks for helping keep restic-manager users safe.