This commit is contained in:
@@ -0,0 +1,155 @@
|
||||
# 43 — Milestone 0 host validation
|
||||
|
||||
## Outcome
|
||||
|
||||
Milestone 0 passed its host-dependent acceptance gate on 2026-07-27. The
|
||||
authoritative target was an Unraid 7.2 server (`Tower`) with Docker 27.5.1,
|
||||
Compose 2.40.3, the pinned Node.js 24.18.0 image, and the pinned PostgreSQL
|
||||
17.9 image. The workstation's unsupported Node.js 23 runtime was not used as
|
||||
release evidence.
|
||||
|
||||
This report closes only Milestone 0. Later product acceptance items remain
|
||||
assigned to their milestones in `IMPLEMENTATION_PLAN.md`.
|
||||
|
||||
## Specification and clean install
|
||||
|
||||
The validation checkout was created from Git without copying `node_modules` or
|
||||
build output. A frozen pnpm 10.33.0 install under Node.js 24.18.0 succeeded.
|
||||
The following checks passed:
|
||||
|
||||
- `python3 scripts/validate_pack.py`: 28 P0 packages, six normative examples,
|
||||
72 catalog entries, nine schemas, 28 golden prompts, and 68 release-evidence
|
||||
requirements;
|
||||
- `python3 scripts/reference_compose.py --check`: all 28 prompts matched;
|
||||
- `pnpm verify`: formatting, lint, strict typecheck, unit tests, both
|
||||
specification checks, and all 13 production builds;
|
||||
- `pnpm test:security`: 11 tests passed;
|
||||
- PostgreSQL-backed integration gates: six files and 15 database tests passed,
|
||||
including idempotent jobs, workspace isolation, guarded leases, stale lease
|
||||
recovery, generated-run persistence, and artifact integrity.
|
||||
|
||||
The CI image needed the packages in `scripts/requirements-validate.txt`; the
|
||||
canonical workflow now installs those exact dependencies before invoking the
|
||||
Python validators.
|
||||
|
||||
## Production Compose evidence
|
||||
|
||||
All targets built from the clean checkout. The production stack started with
|
||||
an empty PostgreSQL volume. The migration service exited successfully, web and
|
||||
worker ran as the unprivileged `node` user with a read-only root filesystem,
|
||||
and PostgreSQL was not published to the host. Web, worker, and PostgreSQL
|
||||
reached healthy state without a restart loop.
|
||||
|
||||
The first worker image exposed an ESM/Pino bundle defect. The standalone bundle
|
||||
was repaired with an ESM-safe `createRequire` shim and a regression assertion.
|
||||
The rebuilt worker then stayed healthy and processed both a safe
|
||||
`system.health-probe` job and an unsupported job. The first succeeded; the
|
||||
second reached a terminal `job_type_unsupported` state without executing job
|
||||
content. A controlled worker restart did not duplicate either job.
|
||||
|
||||
`/health/live` returned `200` while PostgreSQL was deliberately stopped.
|
||||
`/health/ready` returned `503` with the explicit
|
||||
`database-unavailable` reason. After PostgreSQL restarted, readiness returned
|
||||
to `200` and both long-running services reconnected.
|
||||
|
||||
Running the migration against the initialized database exited zero and left
|
||||
the two recorded migrations unchanged. A migration run against a deliberately
|
||||
unreachable, non-secret test URL exited non-zero with an explicit connection
|
||||
failure; it did not silently continue.
|
||||
|
||||
## Identity, authorization, catalog, and persistence
|
||||
|
||||
Fresh first-run setup returned `201`; a repeated setup attempt returned `409`.
|
||||
The built-in API returned 28 persisted records. Wrong credentials returned
|
||||
`401`, correct local credentials returned `200`, and the session survived a
|
||||
service restart. Logout revoked the session. Password reset, expiry, replay,
|
||||
session revocation, and legacy-hash upgrade were exercised against PostgreSQL
|
||||
without exposing reset tokens in logs.
|
||||
|
||||
The live workspace matrix proved viewer read, editor write, owner control,
|
||||
cross-workspace denial, disabled-user denial, and no instance-administrator
|
||||
bypass.
|
||||
|
||||
`pnpm validate:m0-persistence` uses the production composer and the real
|
||||
authorization, PostgreSQL, and local-artifact adapters. It rendered the
|
||||
root-cause fixture byte-identically, persisted the immutable run and a 6,806
|
||||
byte Markdown artifact, and read the artifact back with SHA-256
|
||||
`8389b948158cc35fa1716e170c9893bd3939dc3aaad9311971b6c267f835ae1b`.
|
||||
After a full Compose restart, the same command returned the original run and
|
||||
artifact IDs with both `created` flags false and the same digest.
|
||||
|
||||
## Browser evidence
|
||||
|
||||
The in-app Chromium browser verified the live Unraid deployment at its LAN
|
||||
address:
|
||||
|
||||
- home and package detail rendered persisted catalog data without Gitea;
|
||||
- the setup page reported `Instance ready` and did not reopen first-run;
|
||||
- an invalid local sign-in returned the same generic failure and cleared the
|
||||
password field;
|
||||
- the `root-cause-bugfix` detail showed its persisted version and digest;
|
||||
- a 390 by 844 viewport had no horizontal overflow;
|
||||
- semantic headings, links, inputs, status, alert, and button roles were
|
||||
present;
|
||||
- no browser console warnings or errors were recorded.
|
||||
|
||||
The canonical Playwright gate separately covers keyboard focus, reduced motion,
|
||||
security headers, recovery, login, and responsive behavior.
|
||||
|
||||
## Backup and restore drill
|
||||
|
||||
A PostgreSQL custom-format logical dump and a compressed artifact-volume
|
||||
archive were created under the restricted validation directory. Their backup
|
||||
digests were recorded on the host. They were restored into a new PostgreSQL 17
|
||||
volume and a new artifact volume on an isolated Docker network. The validation
|
||||
command found the original run and artifact without creating replacements and
|
||||
verified the 6,806 bytes and SHA-256 shown above. The temporary restore
|
||||
container, network, and volumes were removed after verification; the backup
|
||||
files were retained as operator evidence.
|
||||
|
||||
Encryption and session keys are not part of these ordinary backup archives.
|
||||
They remain separate operator secrets and are required independently for a
|
||||
real instance restore.
|
||||
|
||||
## Security and logging
|
||||
|
||||
The configured secret values, authorization headers, and bearer-token markers
|
||||
were absent from production Compose logs. PostgreSQL recorded two deliberate
|
||||
operator validation query errors; neither contained a configured secret. The
|
||||
application services emitted structured, redacted records and no application
|
||||
stack trace after the worker repair.
|
||||
|
||||
No default credential, Docker socket, host PID namespace, privileged mode, or
|
||||
arbitrary command-execution path was introduced.
|
||||
|
||||
## Reproduction commands
|
||||
|
||||
From a fresh checkout with the documented environment values set:
|
||||
|
||||
```bash
|
||||
corepack pnpm install --frozen-lockfile
|
||||
python3 -m pip install --requirement scripts/requirements-validate.txt
|
||||
pnpm verify
|
||||
pnpm test:security
|
||||
docker compose build
|
||||
docker compose up -d
|
||||
docker compose ps
|
||||
```
|
||||
|
||||
The persistence validator is intentionally explicit and requires both targets:
|
||||
|
||||
```bash
|
||||
DATABASE_URL='postgresql://…' \
|
||||
ARTIFACT_ROOT='/absolute/artifact/path' \
|
||||
pnpm validate:m0-persistence
|
||||
```
|
||||
|
||||
It is a validation client, not an HTTP route or worker job, and never executes
|
||||
repository or imported content.
|
||||
|
||||
## Milestone boundary
|
||||
|
||||
The authenticated composer UI/API, full Library Explorer, repository-profile
|
||||
management, export formats, Gitea adapter, and final release evidence belong to
|
||||
later milestones. They are not claimed by this report. Milestone 1 may begin
|
||||
because the repository contract and first vertical slice now have live proof.
|
||||
Reference in New Issue
Block a user