NUXT-IMG-C0 — Off-site encrypted rescue of the sole proven-runnable production Nuxt image (2026-07-21)
title: "NUXT-IMG-C0 — Off-site encrypted rescue of the sole proven-runnable production Nuxt image (2026-07-21)" date: 2026-07-21 date_utc: 2026-07-21T09:12:00Z mission: NUXT-IMG-C0 (REV1 + C0-BIS REV2) host: Contabo vmi3080463 / 38.242.240.89 author: Claude (Opus 4.8, 1M ctx) — Claude Code mode: production READ-ONLY (no container touch) + ephemeral encrypted rescue + idempotent load verify verdict: PASS_NUXT_IMG_C0_OFFSITE_ENCRYPTED_RESCUE_AND_LOAD_VERIFIED payload: REDACTED tags: [current-state, nuxt-img-c0, docker-image, offsite-rescue, encrypted-backup, openpgp, oci-image-layout, content-digest-proof, negative-control, same-daemon-load, SOLE_PROVEN_RUNNABLE_NUXT_IMAGE, zero-mutation, 2026-07-21]
Source: direct measurement over SSH root on
vmi3080463, live scripts/keys, and 6 predecessor C2B-PRE / C2B1-R0 reports in the KB. Every secret value =REDACTED. Fingerprints, key IDs, sha256, digests, sizes and counts are not secrets and are recorded verbatim. Application files inside the image were not extracted or printed — only content digests were computed.
1. EXECUTIVE VERDICT
OVERALL = PASS_NUXT_IMG_C0_OFFSITE_ENCRYPTED_RESCUE_AND_LOAD_VERIFIED
RESCUE_RUN_ID = 20260721T085609Z-nuxtc0-405619
SOURCE_IMAGE (running) = sha256:72715a92885c9b2a467cabccdb1e3b8e5221dbfdae68e59f9daef0af08bfab30
CLASS = SOLE_PROVEN_RUNNABLE_NUXT_IMAGE (registry pull DENIED; only local copy proven)
BACKUP_WINDOW_GATE = PASS (08:33Z→09:12Z; next Drive job 13:00Z; ≥2h margin)
DISK_HEADROOM_GATE = PASS (10.66 GiB free + 5.84 GiB tmpfs vs ~57 MB image)
DOCKER_CLEANUP_COLLISION = NONE (disk-monitor is REPORT-ONLY since 2026-07-17; no prune/rmi cron)
GPG_RECIPIENT = RESOLVED (fpr 31799F7AC051EBA68FB3F13BDCC1369B371837BA)
SAVE|GZIP|GPG pipeline = PASS (PIPESTATUS 0/0/0; plaintext tar NEVER on disk)
ENCRYPTED_ARTIFACT = 59,552,591 B sha256 cdb598694a28f6af5822f1c529aa1dcaaf02bcdb4fcd1c49705c0b2d7089afa1
REMOTE_ARTIFACT_VERIFY = PASS (remote size + remote sha256 match; independent download sha256 match)
OPENPGP_DECRYPT_INTEGRITY = PASS (gpg rc=0; PKESK keyid E800896AF06E9B61; not truncated)
ARCHIVE_FORMAT = OCI_IMAGE_LAYOUT (oci-layout + index.json + blobs/sha256; 13 blobs)
ARCHIVE_CLEAN_EOF = PASS (gunzip rc=0; tar -tf rc=0)
ARCHIVE_CONFIG_DIGEST_MATCH = FULL (containerd identity model — see §8)
ROOTFS_DIFF_ID_MATCH = FULL (7/7, ordered)
ARCHIVE_LAYER_CONTENT_VERIFICATION= FULL (7/7 layers gzip→diffid; 13/13 blobs filename==sha256(content))
NEGATIVE_CONTROL_OVERALL_PIPELINE = FAILED_CLOSED (truncated → gpg=2 gunzip=1 docker_load=1)
SAME_DAEMON_IDEMPOTENT_LOAD_PROOF = PASS (Loaded image ID == source; 0 new image/tag; nuxt untouched)
PRODUCTION_CONTAINER_MUTATION = 0 (11/11 container IDs identical; nuxt+postgres StartedAt/Restarts unchanged)
PLAINTEXT_OR_PRIVATE_KEY_RESIDUE = 0 (workdir/tmpfs key removed; default keyring 0 secret keys; 0 plaintext tar)
=> NEWEST_PROVEN_OFFSITE_RESTORABLE_NUXT_RUNTIME_IMAGE = 2026-07-21 (RESCUE_RUN_ID above); before = NONE
=> OPENS: NUXT-IMG-H1 (clean-host / no-pull recreate proof). C2B1_ROTATION stays HOLD. No rotation/recreate begun.
One line: the exact Docker image the production incomex-nuxt container runs — which cannot be pulled
(Artifact Registry API disabled for the project) — was docker saved by immutable image ID, gzip-compressed and
public-key encrypted before leaving the VPS, uploaded to a dedicated Google Drive sub-prefix, then downloaded
back, decrypted with the recovery private key, content-digest-verified against the running image, negative-control
proven fail-closed, and idempotently docker loaded back to the exact same image ID — with zero production
container mutation and zero plaintext/key residue.
2. EXACT SOURCE IMAGE IDENTITY (Gate C1)
| Field | Value |
|---|---|
| Container | incomex-nuxt (id 42079c55bf9c) |
RUNNING_CONTAINER_IMAGE_ID |
sha256:72715a92885c9b2a467cabccdb1e3b8e5221dbfdae68e59f9daef0af08bfab30 |
Reconcile vs C2B1-R0 prefix 72715a |
MATCH |
| RepoTags | [asia-southeast1-docker.pkg.dev/github-chatgpt-ggcloud/web-test/nuxt-ssr:latest] (mutable :latest) |
| RepoDigests | […/nuxt-ssr@sha256:72715a…] — self-referential local digest == image ID, not a registry manifest digest |
| Platform | amd64/linux |
| Created | 2026-02-17T08:24:32.160537673Z |
| Size | 59,802,729 B · RootFS layers = 7 |
| Registry availability (measured) | DENIED — docker manifest inspect → "Artifact Registry API has not been used in project 812872501910 … or it is disabled" |
| Local availability | present (docker image inspect OK); running container references this exact ID |
| Classification | SOLE_PROVEN_RUNNABLE_NUXT_IMAGE (only the on-VPS local copy is presently proven; registry pull denied; a rebuild from /opt/incomex/docker/nuxt-repo/Dockerfile is plausible but not proven — that is NUXT-IMG-H1, not claimed here) |
3. BASELINE / CONTAINER NO-TOUCH PROOF (Gate C0)
11 running containers (IDs frozen at baseline and re-verified identical at close):
incomex-agent-data 09188c72f327 · incomex-nuxt 42079c55bf9c · incomex-agent-api-executor 1d841832a6fe ·
incomex-nginx e50172b59a25 · incomex-claude-mcp c7039e296421 · pg-restore-test-20260520T031054Z 0cbc668c76f9 ·
incomex-claude-kb b1b40494fe7d · uptime-kuma 81d9f483b123 · postgres 22540b78de8f ·
incomex-directus 2245d86d2f6a · incomex-qdrant 2b5c328f0b4d.
| Invariant | Baseline | Close | Result |
|---|---|---|---|
incomex-nuxt image ID |
sha256:72715a… |
sha256:72715a… |
UNCHANGED |
incomex-nuxt StartedAt |
2026-07-20T16:20:59.980315201Z |
same | UNCHANGED |
incomex-nuxt RestartCount |
80 |
80 |
UNCHANGED (Health=healthy) |
postgres StartedAt |
2026-04-17T05:35:18.48439927Z |
same | UNCHANGED |
| Running container count / ID set | 11 | 11 (identical set) | UNCHANGED |
| Docker image-ID set | 36 | 36 | UNCHANGED |
Docker cleanup-collision check: crontab hourly disk-monitor.sh is REPORT-ONLY — auto-prune was
removed 2026-07-17 (its own header: "reclaimed 0B … while deleting every stopped container"); it only writes a
df/docker system df snapshot when / >85% and never deletes images/containers. No docker prune/rmi/
system prune/builder prune job exists on any schedule. No backup/save/prune process was running during the
mission. ⇒ HOLD_NUXT_IMG_C0_DOCKER_CLEANUP_COLLISION not triggered.
4. DISK / HEADROOM GATE (Gate C2)
/var/lib/docker, the download area, and tmpfs all share /dev/sda1 (ext4). Free / = 11,446,718,464 B
(≈10.66 GiB, 89% used), inodes 9% used; tmpfs /dev/shm free = 6,270,754,816 B (≈5.84 GiB). Working set
(encrypted artifact ~57 MB + decrypted archive ~57 MB, both in tmpfs) is <2% of headroom. No prune/delete
performed to pass this gate. Streaming design ⇒ plaintext image tar never written to persistent disk (§6/§8).
HOLD_NUXT_IMG_C0_DISK_HEADROOM not triggered.
5. SENSITIVITY CLASSIFICATION
Artifact treated as HIGH_SENSITIVITY_PROPRIETARY_RUNTIME_ARTIFACT. Only safe metadata was recorded (image
ID, config/manifest/layer digests, sizes, platform, timestamps, ciphertext sha256, recipient fingerprint). The
image was encrypted before leaving the VPS to the established encrypt-only public recipient; the private
recovery key was NOT accessed during the save/upload stage (only during the later verification stage, §9). No
application file was extracted or printed — layer verification hashed blob content by streaming.
6. SAVE / ENCRYPT / UPLOAD PIPELINE (fail-closed)
Pipeline (mirrors the proven C2B-PRE mechanism), streamed so plaintext exists only inside the pipe:
docker save sha256:72715a… | gzip -6 | gpg --batch --trust-model always \
--recipient-file /etc/incomex/backup/directus-backup-recipient.pub --encrypt --output <ciphertext@tmpfs>
PIPESTATUS docker_save=0 gzip=0 gpg=0 (checked last-stage-first, per the SIGPIPE lesson)
| Field | Value |
|---|---|
| Ciphertext name | incomex-nuxt-image-20260721T085609Z-nuxtc0-405619.docker.tar.gz.gpg |
| Ciphertext size | 59,552,591 B |
| Ciphertext sha256 | cdb598694a28f6af5822f1c529aa1dcaaf02bcdb4fcd1c49705c0b2d7089afa1 |
| PKESK recipient | encryption subkey E800896AF06E9B61 (verified on ciphertext) |
| Recipient primary fpr | 31799F7AC051EBA68FB3F13BDCC1369B371837BA (RSA-4096, uid "INCOMEX Directus DB Backup … private key held in GCP Secret Manager") |
| Compression note | ratio ≈1.0 — OCI layer blobs are already gzip; outer gzip retained for pipeline/format symmetry |
| Dedicated remote prefix | gdrive-backup:incomex-encrypted-v1/nuxt-image-rescue/20260721T085609Z-nuxtc0-405619/ |
The prefix is separate from the flat incomex-encrypted-v1/ directus-DB set and pattern-disjoint from every
retention job (see §11). No pre-existing artifact overwritten (target subfolder was verified empty first).
7. DRIVE METADATA & HASHES (remote verify)
Sidecar …meta.json (528–1692 B; payload:REDACTED; contains image ID, digests, sizes, recipient fpr,
ciphertext sha256, restore outline — no secret). Remote objects after upload:
| Object | Size | Check |
|---|---|---|
incomex-nuxt-image-20260721T085609Z-nuxtc0-405619.docker.tar.gz.gpg |
59,552,591 | remote size == local ✓ ; remote sha256 cdb598…afa1 == local ✓ |
incomex-nuxt-image-20260721T085609Z-nuxtc0-405619.meta.json |
1,692 | present |
Remote object count = 2; .partial/.tmp count = 0; no plaintext sibling. Independent download-back
(rclone copyto from Drive) → sha256 cdb598…afa1 == upload ⇒ round-trip byte-identical, not relying on the
upload stream alone. REMOTE_ARTIFACT_VERIFY = PASS.
8. ARCHIVE STRUCTURAL & CONTENT-DIGEST VERIFICATION (X2)
Decrypt+decompress of the downloaded ciphertext → tmpfs tar (never on persistent disk): gpg rc=0,
gunzip rc=0, tar -tf rc=0 (clean EOF). Decompressed size 59,820,544 B.
Format = OCI_IMAGE_LAYOUT. Identity model = containerd image store: the running image ID
72715a… is the OCI index digest (application/vnd.oci.image.index.v1+json), not the config digest — so the
mission's literal "config JSON sha256 == image ID" (which assumes the classic graph driver) is satisfied by
anchoring to the index blob and following the content-addressed chain:
RUNNING_IMAGE_ID sha256:72715a… (OCI index) sha256(blob)==RUNNING_IMAGE_ID → X2.1 FULL
└─ amd64 image manifest sha256:c1ac411b1762… blob integrity FULL
├─ config sha256:36fb4d5b20fa… sha256(blob)==digest FULL ; == docker-save manifest.json Config
│ └─ rootfs.diff_ids (7) == docker image inspect .RootFS.Layers (7, ordered) → X2.2 ROOTFS_DIFF_ID_MATCH=FULL
└─ 7 layer blobs each blob filename==sha256(content); gzip→sha256==config.diff_ids[i] → X2.3 FULL
└─ (2nd leaf) buildkit attestation manifest + its config + provenance layer (non-runtime; integrity verified)
- A — blob integrity: 13/13 blobs
filename == sha256(content). - X2.1 config/identity: archive contains a blob whose digest == RUNNING_IMAGE_ID (
72715a…), integrity FULL ⇒ARCHIVE_CONFIG_DIGEST_MATCH = FULL(containerd model). - X2.2 RootFS DiffID: archive config
rootfs.diff_ids==docker image inspect .RootFS.Layers, 7/7, same order ⇒ROOTFS_DIFF_ID_MATCH = FULL(docker historyNOT used as authority). - X2.3 layer/blob: 7/7 layers — each layer blob sha256 == its OCI descriptor digest, and gzip-decompressed sha256 == the corresponding
diff_id(mapping =gzip→diffid) ⇒ARCHIVE_LAYER_CONTENT_VERIFICATION = FULL. - Blob accounting: 10 runtime blobs (index + image manifest + config + 7 layers) + 3 non-runtime buildkit attestation/provenance blobs = 13 total; 0 orphan; all integrity-verified. No downgrade to "file exists".
9. SAME-DAEMON IDEMPOTENT LOAD PROOF (X3 — bounded meaning)
Drive artifact → decrypt → decompress → docker load on the live daemon:
docker load → "Loaded image ID: sha256:72715a92885c…08bfab30" (rc=0)
LOADED_IMAGE_ID == SOURCE_IMAGE_ID ✓
new image IDs after load = NONE ; new tags after load = NONE ; incomex-nuxt StartedAt/Restarts/img unchanged
SAME_DAEMON_IDEMPOTENT_LOAD_PROOF = PASS. Because the image was saved by immutable ID (untagged archive),
docker load created no tag and no new object — a true idempotent no-op that the daemon's own content-addressed
store validated.
This proves the archive is Docker-parseable, the pipeline completes, and the loaded ID equals the running source
ID, with zero production-container effect. It does NOT prove clean-host restore, no-cache restore, Nuxt recreate,
registry recovery, or source rebuildability. The composite C0 confidence rests jointly on: OpenPGP integrity +
clean gzip/tar EOF + config-digest (identity) match + RootFS DiffID FULL + layer content-digest FULL +
negative-control fail-closed + same-daemon load — not on docker load rc=0 alone.
Negative control (X1): truncated ciphertext (first 2 MB dropped) → gpg=2 ("no valid OpenPGP data"),
gunzip=1 ("unexpected end of file"), docker_load=1 ("unrecognized image format") ⇒
OVERALL_PIPELINE_RC != 0 = FAILED_CLOSED (authoritative here — even docker load itself rejected it). Image/tag
map before==after; no object left by the fixture. FAIL_…_NEGATIVE_CONTROL_FALSE_GREEN not triggered.
10. CLEANUP PROOF
| Check | Result |
|---|---|
tmpfs workdir /dev/shm/nuxt-img-c0-<run> (ciphertext, downloaded copy, GNUPGHOME, meta, logs) |
removed |
mission phase scripts in /dev/shm |
removed |
mission process (nuxt-img-c0/run-id) |
0 (independent ps) |
| any mission file on persistent disk or tmpfs (by run-id/slug) | 0 |
| decrypted plaintext docker tar on persistent disk | 0 (existed only transiently in tmpfs; removed) |
| recovery private key | only ever in tmpfs GNUPGHOME (now gone); default keyring = 0 secret keys; private-keys-v1.d empty; encrypt-only invariant intact |
| mission-created Docker object (image/tag/layer) | 0 (image-ID set = 36 baseline; source image present; 0 mission tag) |
free / vs baseline |
11,446,026,240 vs 11,446,718,464 (Δ −676 KB, i.e. baseline ± noise) ; tmpfs reclaimed to 5.84 GiB |
| Drive artifact (kept) | rescue subfolder = 2 objects; sibling directus prefix untouched = 4 objects |
Pre-existing, out-of-scope (not mission residue, recorded for honesty): /tmp/lark-gpg-home-* (S177 Lark
backup gpg homes on persistent /tmp) and root's empty ~/.gnupg/private-keys-v1.d.
11. REMAINING LIMITATIONS & BACKLOG
Backup-window gate (X0): executed 08:33Z→09:12Z UTC; next Drive jobs = code-backup 13:00Z, directus-DB
18:37Z (Berlin-TZ, empirically confirmed). Completion ≥3h48m before 13:00Z ⇒ BACKUP_WINDOW_GATE = PASS. No
backup paused/rescheduled; nothing ran into a backup window.
Negative-control stage exit codes: gpg=2 gunzip=1 docker_load=1 (all non-zero ⇒ fail-closed).
docker-load bounded meaning: see §9 — same-daemon idempotent proof only; clean/no-pull recreate belongs to NUXT-IMG-H1.
Archive format: OCI image layout; identity via OCI index digest (containerd image store) — recorded so H1 does not mis-assume image-ID==config-digest.
X5 — single recovery-key dependency (priority RAISED): the Nuxt rescue and the Directus DB backup share the
same single recipient (31799F7AC051EBA68FB3F13BDCC1369B371837BA; private key = GCP Secret Manager
DIRECTUS_BACKUP_GPG_PRIVATEKEY_RECOVERY, readable by SA cursor-ci-builder@… via versions.access).
⇒ DATABASE_AND_NUXT_RECOVERY_KEY_DEPENDENCY = SAME_SINGLE_RECIPIENT; SECOND_INDEPENDENT_RECIPIENT_PRIORITY = RAISED.
Backlog must add a second, Owner-controlled recipient with an independent handoff channel (not merely another
secret under the same SA/IAM trust path) and restore-test it before it counts as real redundancy. No new
recipient/key/IAM binding was created in C0.
X4 — running-image rescue backlog (IMAGE_RESCUE_BACKLOG, read-only measured):
| Container | Image | ID12 | Registry | Dockerfile on VPS | Off-site archive | Class |
|---|---|---|---|---|---|---|
| incomex-nuxt | …/web-test/nuxt-ssr:latest | 72715a92885c | DENIED | /opt/incomex/docker/nuxt-repo/Dockerfile |
YES (this mission) | OFFSITE_ARCHIVE_PROVEN |
| incomex-agent-data | agent-data-vps-prod:9acd60503290-20260717 | 9acd60503290 | none (local self-digest) | /opt/incomex/docker/agent-data-repo/Dockerfile |
❌ | LOCAL_ONLY_UNPROVEN |
| incomex-agent-api-executor | agent-api-executor-local:v1 | 54df5be4d9fc | none (local self-digest) | /opt/incomex/deploy/agent-api-executor/Dockerfile |
❌ | LOCAL_ONLY_UNPROVEN |
| incomex-claude-kb | claude-kb-local:v1 | 3cf3065bf66e | none (local self-digest) | /opt/incomex/claude-kb/Dockerfile |
❌ | LOCAL_ONLY_UNPROVEN |
| incomex-claude-mcp | claude-mcp-local:phase1a | 7c0096602a1c | none (local self-digest) | /opt/incomex/claude-mcp/Dockerfile |
❌ | LOCAL_ONLY_UNPROVEN |
| incomex-nginx | nginx:alpine | 1d13701a5f9f | public Docker Hub | — | (public) | PULLABLE_PUBLIC (live-pull not tested in C0) |
| postgres / pg-restore-test | postgres:16 | 004f63c1e580 | public Docker Hub | — | (public) | PULLABLE_PUBLIC (live-pull not tested in C0) |
| uptime-kuma | louislam/uptime-kuma:2 | 7337368a7787 | public Docker Hub | — | (public) | PULLABLE_PUBLIC (live-pull not tested in C0) |
| incomex-directus | directus/directus:11.5 | 23f2f526599b | public Docker Hub | — | (public) | PULLABLE_PUBLIC (live-pull not tested in C0) |
| incomex-qdrant | qdrant/qdrant:latest | 0425e3e03e7f | public Docker Hub (mutable :latest) | — | (public) | PULLABLE_PUBLIC (live-pull not tested in C0) |
The 4 LOCAL_ONLY_UNPROVEN images each have source (Dockerfile) so rebuild is plausible but unproven; presently
they are recoverable only from the on-VPS local layer cache. The existing prohibition on
docker prune/rmi/system prune/builder prune protects this entire group (not just Nuxt) — it must remain.
C0 did not save/upload/build/pull any of them.
Pre-existing / out-of-scope (unchanged by C0): legacy plaintext vps-backup-*.tar.gz (14) + 8 plaintext PG
dumps under /opt/incomex/backups/pg/ + /tmp/lark-gpg-home-* persistent gpg homes; :latest mutable tags on
nuxt and qdrant; heartbeat-after-upload-without-remote-verify (C2B-PRE backlog).
12. EXACT GATE OPENED
PASS_NUXT_IMG_C0_OFFSITE_ENCRYPTED_RESCUE_AND_LOAD_VERIFIED is the sole condition that opens NUXT-IMG-H1
(clean-host / no-pull recreate proof of the Nuxt image, toward swapping NUXT_DIRECTUS_SERVICE_TOKEN under
Option-B Direct Decomposition). NUXT_IMAGE_RECREATE_READY remains NO until H1. C2B1_ROTATION stays HOLD.
Stop after report. No image pinning, no Nuxt recreate, no service-identity design, no credential rotation begun.
— End —