Harden CI and switch release builds to tagged immutable images
This commit is contained in:
parent
bed2e6cfb6
commit
f24e96efa7
60 changed files with 4710 additions and 64 deletions
6
docs/adr/0001-postgresql-btrfs-cow.md
Normal file
6
docs/adr/0001-postgresql-btrfs-cow.md
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
# ADR-0001: PostgreSQL on btrfs with CoW
|
||||
|
||||
Status: Accepted
|
||||
|
||||
PostgreSQL data remains on the mirrored exclusive btrfs cache with copy-on-write and PostgreSQL page checksums enabled. `chattr +C` is not used because it would remove btrfs data checksums and mirror self-healing for database files. Capacity, WAL growth, and fragmentation will be monitored when operations work is implemented.
|
||||
|
||||
6
docs/adr/0002-opaque-object-identities.md
Normal file
6
docs/adr/0002-opaque-object-identities.md
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
# ADR-0002: Opaque object IDs and same-directory promotion
|
||||
|
||||
Status: Accepted
|
||||
|
||||
Managed objects use opaque physical IDs. PostgreSQL maps SHA-256 content identities to physical objects. Partials and completed blobs share one shard directory so final promotion is a same-directory rename. Blob-manifest export is required because the filesystem alone is not self-describing.
|
||||
|
||||
6
docs/adr/0003-incomplete-transfer-posture.md
Normal file
6
docs/adr/0003-incomplete-transfer-posture.md
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
# ADR-0003: Protect commits, not incomplete transfers
|
||||
|
||||
Status: Accepted
|
||||
|
||||
Committed content and metadata must recover consistently. Incomplete uploads may be failed or discarded after an unclean shutdown. Restart recovery reconciles partial length with the persisted offset and may recompute hashes instead of making incremental hash state crash-durable.
|
||||
|
||||
6
docs/adr/0004-single-application-service.md
Normal file
6
docs/adr/0004-single-application-service.md
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
# ADR-0004: Single application service
|
||||
|
||||
Status: Accepted
|
||||
|
||||
Production runs HTTP handling and PostgreSQL-leased background workers in one Drive container beside PostgreSQL. This favors simple operation on one private Unraid host. Worker failures must be isolated and observable, and durable state must allow later separation without changing domain behavior.
|
||||
|
||||
6
docs/adr/0005-http-conflict-semantics.md
Normal file
6
docs/adr/0005-http-conflict-semantics.md
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
# ADR-0005: HTTP precondition and conflict semantics
|
||||
|
||||
Status: Accepted
|
||||
|
||||
Failed `If-Match` or equivalent representation preconditions return `412 Precondition Failed`. Name collisions, invalid hierarchy operations, and other domain conflicts return `409 Conflict`. Both use RFC 9457 problem documents with stable codes and current state where useful.
|
||||
|
||||
6
docs/adr/0006-v1-product-scope.md
Normal file
6
docs/adr/0006-v1-product-scope.md
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
# ADR-0006: Stable-v1 product scope
|
||||
|
||||
Status: Accepted
|
||||
|
||||
Stable v1 includes file management, resumable transfers, importer, sharing, OnlyOffice, core previews, PWA, backup/recovery foundations, and future-sync-ready file APIs. Desktop sync, Calendar, archive browsing, and 3D previews are deferred without speculative APIs. Other Google-suite categories require separate proposals.
|
||||
|
||||
6
docs/adr/0007-open-first-run-setup.md
Normal file
6
docs/adr/0007-open-first-run-setup.md
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
# ADR-0007: Open first-run setup
|
||||
|
||||
Status: Accepted risk
|
||||
|
||||
An uninitialized server exposes the owner-creation page without a bootstrap secret. Owner creation is an atomic single-winner transaction and setup becomes permanently unavailable afterward. Operations documentation requires completing setup before proxy exposure. The owner accepts the takeover risk if an uninitialized instance is exposed.
|
||||
|
||||
14
docs/adr/README.md
Normal file
14
docs/adr/README.md
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
# Architecture decision records
|
||||
|
||||
ADRs are immutable after acceptance. Supersede an earlier decision with a new ADR rather than rewriting its history.
|
||||
|
||||
| ADR | Decision | Status |
|
||||
| --- | --- | --- |
|
||||
| 0001 | PostgreSQL remains on btrfs with CoW | Accepted |
|
||||
| 0002 | Opaque object IDs and same-directory promotion | Accepted |
|
||||
| 0003 | Protect commits, not incomplete transfers | Accepted |
|
||||
| 0004 | Single application service | Accepted |
|
||||
| 0005 | HTTP precondition and conflict status codes | Accepted |
|
||||
| 0006 | Stable-v1 and deferred product scope | Accepted |
|
||||
| 0007 | Open first-run setup | Accepted risk |
|
||||
|
||||
24
docs/architecture.md
Normal file
24
docs/architecture.md
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
# Architecture guide
|
||||
|
||||
The detailed baseline is `Drive_v2_final_plan.md`. This guide is a short implementation map.
|
||||
|
||||
## Request flow
|
||||
|
||||
```text
|
||||
HTTP transport -> application use case -> domain rules
|
||||
|-> PostgreSQL repository
|
||||
|-> storage/external adapter
|
||||
```
|
||||
|
||||
Transport code handles protocol concerns only. Application services own transactions and coordinate database-plus-storage work. Domain code contains no infrastructure dependencies.
|
||||
|
||||
## Durable work
|
||||
|
||||
No authoritative state lives only in memory. Upload sessions, commit intents, jobs, leases, and cursors are persisted in PostgreSQL. Committed blobs are immutable and become visible only after storage promotion and metadata commit.
|
||||
|
||||
## Frontend
|
||||
|
||||
Each feature owns its routes, API hooks, components, state, and tests. Cross-feature access goes through a small public entrypoint. Server state stays in TanStack Query and local UI state remains close to the component or feature that owns it.
|
||||
|
||||
Preview rendering is capability-driven and lazy-loaded. Adding a format must not require editing the file manager.
|
||||
|
||||
14
docs/dependencies.md
Normal file
14
docs/dependencies.md
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
# Dependency policy
|
||||
|
||||
Dependencies are pinned in `go.mod`, `web/package.json`, the npm lockfile, container tags, and CI workflow references. Add a runtime dependency only when its functionality is actively used, and record architectural additions in an ADR before merging.
|
||||
|
||||
## Phase 0 baseline
|
||||
|
||||
Backend production code currently uses the Go standard library. Chi, pgx, sqlc, and the migration runner are approved by the architecture baseline and will be pinned when their first Phase 1 implementation is added.
|
||||
|
||||
Frontend runtime dependencies are React, React DOM, TanStack Query, and TanStack Router. Development dependencies provide TypeScript, Vite, Vitest, ESLint, React tooling, and type declarations.
|
||||
|
||||
Container baselines are Go 1.26 on Debian Bookworm, Node 24 on Debian Bookworm, PostgreSQL 18.4 on Debian Bookworm, and a Debian Bookworm slim runtime. Production deployment should pin tested image digests as part of its release configuration.
|
||||
|
||||
Dependency updates must pass the full repository check and production image build. Avoid packages that duplicate standard-library functionality or introduce background network behavior, telemetry, install scripts, or unreviewed native binaries.
|
||||
|
||||
37
docs/development.md
Normal file
37
docs/development.md
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
# Development guide
|
||||
|
||||
## Structure
|
||||
|
||||
- `cmd/drive` owns process startup and CLI dispatch.
|
||||
- `internal/domain` contains dependency-free business rules.
|
||||
- `internal/application` coordinates use cases through interfaces.
|
||||
- `internal/adapters` implements PostgreSQL, storage, and external-service ports.
|
||||
- `internal/transport` maps HTTP contracts to application calls.
|
||||
- `internal/workers` executes persistent leased jobs.
|
||||
- `web/src/features` owns frontend product features; `web/src/shared` contains reusable primitives.
|
||||
- `api/openapi.yaml`, migrations, and sqlc queries are reviewed source contracts.
|
||||
|
||||
## Canonical checks
|
||||
|
||||
Native:
|
||||
|
||||
```text
|
||||
go test ./cmd/... ./internal/...
|
||||
npm --prefix web ci
|
||||
npm --prefix web run check
|
||||
```
|
||||
|
||||
Containerized:
|
||||
|
||||
```text
|
||||
docker compose run --rm verify
|
||||
docker compose up --build
|
||||
```
|
||||
|
||||
## Contract workflow
|
||||
|
||||
Do not add an API handler before its OpenAPI operation exists. Do not write SQL directly in transport or application code; add a named sqlc query. Generated files are outputs and are never edited by hand. CI will add strict generation-drift checks when the first generated client and repository are introduced in Phase 1.
|
||||
|
||||
## Architectural changes
|
||||
|
||||
Create an ADR before changing storage semantics, public API conventions, package boundaries, deployment topology, or approved dependencies. An ADR records context, decision, consequences, and superseded decisions.
|
||||
6
docs/operations/README.md
Normal file
6
docs/operations/README.md
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
# Operations documentation
|
||||
|
||||
The production runbook will cover Unraid share layout, permissions, Nginx Proxy Manager, OnlyOffice networking, graceful shutdown timers, backups, restore, importer use, capacity alerts, and troubleshooting.
|
||||
|
||||
Phase 0 provides development Compose only. Do not treat it as a production deployment template until the Phase 7 production checklist is complete.
|
||||
|
||||
36
docs/threat-model.md
Normal file
36
docs/threat-model.md
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
# Threat model
|
||||
|
||||
## Protected assets
|
||||
|
||||
- File contents, metadata, previews, and replacement-recovery blobs.
|
||||
- Password, sessions, TOTP secrets, recovery codes, API tokens, share tokens, and OnlyOffice secrets.
|
||||
- Database-to-object mapping, backup data, and blob manifests.
|
||||
|
||||
## Trust boundaries
|
||||
|
||||
- Browser to Nginx Proxy Manager to Drive HTTP service.
|
||||
- Drive to PostgreSQL on the private container network.
|
||||
- Drive to managed cache/array mounts.
|
||||
- Drive to the existing OnlyOffice Document Server.
|
||||
- Public-link visitors to explicitly shared resources.
|
||||
- Read-only importer mounts to managed Drive storage.
|
||||
|
||||
## Primary threats
|
||||
|
||||
- Unclaimed-instance takeover before first-run setup.
|
||||
- Session theft, CSRF, credential guessing, token leakage, and proxy-address spoofing.
|
||||
- Path traversal, symlink following, MIME confusion, malicious previews, and archive expansion.
|
||||
- SSRF or forged OnlyOffice callbacks.
|
||||
- Stale writes, duplicate requests, interrupted commits, and premature GC.
|
||||
- Secret disclosure through logs, images, configuration, backups, or repository history.
|
||||
|
||||
## Phase 0 controls
|
||||
|
||||
- Production setup must finish before proxy exposure; setup is disabled atomically after owner creation.
|
||||
- Secrets are environment/file inputs and ignored by Git.
|
||||
- Non-root container, explicit mounts, private PostgreSQL network, and health endpoints.
|
||||
- Architectural boundaries prevent HTTP code from reaching database or managed storage directly.
|
||||
- Security headers, CSRF, authentication, rate limits, scoped tokens, and callback validation are implemented with their Phase 1 features.
|
||||
|
||||
Review this document whenever a new external integration, public endpoint, preview processor, or authentication mechanism is introduced.
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue