teleo-infrastructure/docs/gcp-leoclean-nosend-service-package.md

138 lines
5.5 KiB
Markdown

# GCP leoclean no-send service package
## Outcome
This slice packages the revision-bound Hermes/leoclean no-send artifact and one
explicit identity bundle as an immutable OCI image for a separate
`leoclean-gcp-nosend.service` on `teleo-staging-1`.
It is target-architecture staging work, not a production cutover. The image is
the atomic compatibility boundary because Python, the locked Hermes virtual
environment, PostgreSQL client, Cloud SQL CA, runtime artifact, identity files,
and container entrypoint must move and roll back together.
## Exact target and authority boundary
- project: `teleo-501523`
- zone: `europe-west6-a`
- instance: `teleo-staging-1`
- service account:
`sa-teleo-staging-vm@teleo-501523.iam.gserviceaccount.com`
- service: `leoclean-gcp-nosend.service`
- platform: `linux/amd64`
- image repository:
`europe-west6-docker.pkg.dev/teleo-501523/teleo/leoclean-nosend-staging`
The package adds only a deployable, digest-addressed staging service surface.
It does not add IAM, Secret Manager, database-role, proposal-approval,
canonical-apply, transport, production, or VPS authority.
The service has no provider credential in this slice. It can prove the gateway
and database-tool boundary, but paid model calls require a separately reviewed
internal no-send ingress and credential-delivery design during the parity
slice.
## Immutable closure
The dedicated Dockerfile uses only digest-pinned base images:
- Python `3.11.9`;
- uv `0.9.30`;
- PostgreSQL client `16.14` on Bookworm.
There is no `apt-get`, floating `pip install`, editable install, or image tag in
the closure. The final image also binds:
- the exact Teleo Git revision and release-pass artifact receipt;
- Hermes commit and source-tree hash;
- the artifact content and manifest hashes;
- the exact uv lock;
- the identity manifest, lock, `SOUL.md`, and bundle hashes;
- the Cloud SQL server CA hash;
- the Dockerfile, entrypoint, and package-contract hashes.
The runtime image starts with a capability-limited bootstrap that creates a
fresh tmpfs profile, then drops all groups, UID/GID to `65532`, and all Linux
capability bounding sets before executing Hermes. The gateway readiness receipt
is written only after the real zero-adapter runner starts and its sealed tool
registry is rechecked.
The PostgreSQL base image's inherited data-volume path is explicitly shadowed
by a tiny read-only, non-executable, mode-`0000` tmpfs. This prevents Docker
from exposing an unused writable database directory to the runtime.
## Prepare a build context
First compile and release-verify the no-send artifact from the exact clean
revision. Separately provide a reviewed identity directory containing exactly:
- `SOUL.md`
- `identity-lock.json`
- `identity-manifest.json`
Then run:
```bash
python3 ops/gcp_leoclean_nosend_package.py prepare \
--artifact /path/to/artifact \
--receipt /path/to/leoclean-nosend-runtime.json \
--identity /path/to/identity-bundle \
--output /tmp/leoclean-nosend-image-context
```
The command fails closed on a development receipt, revision drift, content or
mode drift, unsafe links, an inconsistent identity lock, a changed CA, a
non-staging target, or an existing output directory. The resulting context is
secret-free.
Use the exact values in `build-args.json` as Docker build arguments. The image
build itself revalidates that those values equal `image-input.json`.
## Finalize one digest-bound release
After an authorized build and Artifact Registry push returns the immutable
image digest:
```bash
python3 ops/gcp_leoclean_nosend_package.py finalize \
--image-input /tmp/leoclean-nosend-image-context/image-input.json \
--image-reference \
europe-west6-docker.pkg.dev/teleo-501523/teleo/leoclean-nosend-staging@sha256:<64-hex-digest> \
--output-release /tmp/leoclean-nosend-release.json \
--output-unit /tmp/leoclean-gcp-nosend.service
```
Tags, alternate repositories, alternate projects/instances/service accounts,
extra descriptor fields, and mismatched labels are rejected.
## Offline evidence and live gate
Offline tests prove descriptor strictness, artifact and identity binding,
digest-only images, pinned runtime versions, a secret-free context, the
capability-drop contract, no published ports, no Docker-socket mount, no
environment file, and no production/VPS/Telegram target.
They do not prove that `teleo-staging-1` currently has a compatible container
engine, enough disk, the expected architecture, the expected service account,
or an unused unit name. Those are the next read-only live preflight. If the
engine is absent, installation is separate infrastructure work; the deploy must
stop instead of falling back to the production sync script or a mutable host
virtual environment.
Publishing the draft branch and stacked PR is only a review handoff. Live
installation, Artifact Registry publication, service restart, IAM/secret
changes, Cloud SQL access, and proposal staging remain separate approvals.
## Rollback and sunset
The rollback boundary is one release descriptor, one image digest, and the
dedicated no-send unit. Rollback restores the prior descriptor/unit and prior
digest; it must never restart or edit the production Leo, Telegram, or VPS
services.
The fresh tmpfs profile intentionally has no session continuity. That is
appropriate for isolated gateway/database and fresh-turn parity proof, but it
is not the production state design. Before traffic cutover, a separate reviewed
slice must bind durable noncanonical session state without making it identity or
knowledge authority. The tmpfs-only state contract sunsets when that cutover
candidate is proven.