feat(hooks): manifest lifecycle-hooks schema (#20 phase 1) + fix container test literals

Add controlled post_install/pre_start hook schema to AppDefinition:
LifecycleHooks/HookStep (Exec | CopyFromHost)/HostCopy with allowlist
validation (relative src, no '..', absolute container dest, non-empty
exec). Re-exported from the crate root. Design: docs/manifest-hooks-design.md.

Also add the missing generated_secrets: vec![] field to three
pre-existing ContainerConfig test literals (the field was added to the
struct in 03a4ee1b but the container crate's own tests were never rerun,
so -p archipelago-container failed to compile). cargo test green: 53 pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
archipelago
2026-06-21 11:07:00 -04:00
co-authored by Claude Opus 4.8
parent b0b54a96fa
commit 4c1a4e5976
4 changed files with 289 additions and 2 deletions
+47
View File
@@ -147,6 +147,53 @@ hardening; paid swarm streaming + IndeeHub source (`phase4-streaming-ecash-plan.
Meshroller Rust-native mesh AI (`meshroller-integration-design.md`); dual-ecash
phases 26 (`dual-ecash-design.md`).
## 8b. SESSION STATE + RESUME (2026-06-21, live)
**Landed + committed on main this session (newest first):**
- `f0c6b79d` immich containers named underscore (immich_server/_postgres/_redis) to
match runtime lifecycle code — fixes package.stop/start/restart. **immich fully
migrated + verified on .228** (manifest-driven stack via orchestrator).
- `b0b54a96` immich lifecycle bats suite (tests/lifecycle/bats/immich.bats).
- `d5ef4573`/`9e6c5370`/`011081d1` immich migration (rename→immich, orchestrator-first).
- `f160e0c4` podman-restart.service enabled at startup (reboot-survival).
- `0860dfac` Services-tab UI (backends→Services, parent icons, categories sub-nav, swipe).
- `220666d3`/`7bfbe8fe` registry-manifest infra phases 1+2 (consume + EMBED_MANIFESTS publish).
- `192238cb` docs consolidation 56→28 + CLAUDE.md.
- `03a4ee1b` generated-secrets system + companion/quadlet fixes.
**IN FLIGHT — hook capability (#20), phase 1 (schema):** building controlled
post-install hooks so indeedhub/netbird can migrate. Design: `docs/manifest-hooks-design.md`.
- DONE: `LifecycleHooks`/`HookStep`/`HostCopy` types + `hooks` field on AppDefinition
+ validate() + re-exports + 3 schema tests (manifest.rs).
- **BLOCKING COMPILE FIX NEEDED:** `cargo test -p archipelago-container` fails —
3 pre-existing test `ContainerConfig {…}` literals (manifest.rs ~1658/1711/1752)
are missing the `generated_secrets` field (added in 03a4ee1b but the container
crate's own tests were never run since). Add `generated_secrets: vec![],` to each.
- THEN: implement executor `core/archipelago/src/container/hooks.rs`
(run_post_install: podman exec + copy_from_host with allowlist canonicalisation),
wire into orchestrator install (post-create, install-only), tests, commit.
**NEXT (after #20):** indeedhub migration — author 7 member manifests
(postgres/redis/minio/relay/api/ffmpeg + frontend) on archy-net with container-name
hostnames; frontend carries the `post_install` hook (strip X-Frame-Options, copy
nostr-provider.js, inject script, nginx reload — see `patch_indeedhub_nostr_provider`
in install.rs:68 for exact ops); wire `install_indeedhub_stack` orchestrator-first;
generated_secrets: indeedhub-db-password/indeedhub-jwt/indeedhub-minio-password
(reuse live values); preserve hardcoded AES_MASTER_SECRET literal + minio user
"indeeadmin". Then netbird (assess its setup steps). Then single-container legacy
apps (add to `uses_orchestrator_install_flow` allowlist in install.rs + verify each).
Then the lifecycle gate (#6) — needs harness hardening (#18) + .228 bitcoin synced.
**Test/deploy facts:** .228 = archi resilience node, UI/RPC pw `password123` (https),
SSH pw `archipelago`. Lifecycle harness runs from .116: `cd tests/lifecycle &&
ARCHY_HOST=192.168.1.228 ARCHY_SCHEME=https ARCHY_PASSWORD=password123
ARCHY_ALLOW_DESTRUCTIVE=1 ./run.sh <suite>`. RPC trigger: auth.login (sets session
+ csrf cookies) → send csrf cookie value as `X-CSRF-Token` header. package.install
needs `{"id":"<app>","dockerImage":"<any-valid-image>"}` (dockerImage required even
for stacks). Rust workspace root = `core/`. Linker `undefined hidden symbol`
rebuild with `CARGO_INCREMENTAL=0`. immich on .228: app_id `immich`, containers
immich_server/immich_postgres/immich_redis, data dir owner 100998:100998.
## 9. Documentation map (what survives)
This master plan is the hub. Authoritative standalone docs (linked above), kept: