156 lines
6.8 KiB
Markdown
156 lines
6.8 KiB
Markdown
# 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.
|