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.
This commit is contained in:
+137
@@ -0,0 +1,137 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user