Files
monky-deployd/CHANGELOG.md
T
mdella 037782e1ff fix: accept sites fmt|cbs|pdx|roam (tenancy 0.7.x) and keep the identity read grant alive across tunneller rewrites — 0.1.10
deployd#3 (DD-0620): every kit for a backend registered since 2026-09-08 died at `--site`.
env-dev-08 (2026-09-11..13): two days of "identity is not readable" ticks — ziti-edge-tunnel
re-creates the file with mode 0600, the ACL mask goes to ---, group membership stops helping.
identity-acl.sh + monky-deployd-identity-acl.path re-apply the grant on every directory change.

Doc-Drift: DD-0620 fixed
Closes #3

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ASnneBmT7rfaJLE8NGNw7S
2026-09-13 00:17:35 +00:00

11 KiB
Raw Blame History

Changelog

0.1.10 — sites fmt|pdx|roam, and a read grant that outlives the tunneller (2026-09-13)

  • Install kits for every backend registered since 2026-09-08 died at --site (deployd#3, DD-0620): tenancy 0.7.x issues fmt | pdx | roam, deployd still enforced cbs | pdx. SITES, install.sh and config.example.yaml now accept fmt | cbs | pdx | roam (cbs = the deprecated alias of fmt on rows registered before the rename) and a test pins the set to tenancy's.
  • The agent's read on the ziti identity now survives a tunneller rewrite for real. 0.1.8 made monky-deployd a member of the ziti group; that is not enough: ziti-edge-tunnel re-creates the file with mode 0600, which sets the ACL mask to --- and defeats the group read and the named-user entry alike (env-dev-08, 2026-09-11 → 09-13: two days of "identity is not readable" ticks under a healthy tunnel; the backend went offline). New identity-acl.sh re-applies the entries and the mask; monky-deployd-identity-acl.path re-runs it whenever the identity directory changes; install.sh and the package postinstall arm it.

0.1.9 — an upgrade no longer stops the agent (2026-09-09)

  • dpkg -i over a running agent disabled it. dpkg calls the OLD package's prerm on an upgrade as well as on a removal (rpm passes a remaining-instance count), and preremove.sh ran systemctl disable --now monky-deployd.timer unconditionally. Upgrading env-dev-01 and env-dev-08 from 0.1.6/0.1.7 to 0.1.8 stopped and disabled both agents. It is silent: the box stays up, the containers keep running, and nothing reports that check-ins have ceased — the backend simply stops converging. preremove.sh now returns early for every upgrade shape (upgrade, failed-upgrade, deconfigure, rpm's 1), and postinstall.sh try-restarts the long-lived proxy unit so it picks up the new code. A fleet upgrade would have taken every agent offline at once.

0.1.8 — onboarding: keep the identity readable, refuse a full disk (2026-09-09)

Three faults from one onboarding (env-dev-08, agent-managed, 2026-09-09), each of which sent the diagnosis somewhere other than the fault.

  • The agent's read on the ziti identity now survives a tunneller rewrite. install.sh granted it with a POSIX ACL. ziti-edge-tunnel rewrites the identity file whenever the controller sends a config update, and the rewrite drops the ACL — the agent had applied cleanly and was failing every tick six minutes later. The durable grant is group membership: install.sh and the package's postinstall now add monky-deployd to the identity file's group (ziti) when it exists, and a default ACL on the identity directory carries the grant onto a freshly created file. The explicit ACLs stay.
  • An unusable identity says so. openziti.load() accepts an unreadable or malformed identity, logs "configuration is invalid" at the C layer and hands back a context that fails LATER, at dial, as a bare TypeError — which the transport reported as a missing intercept or a policy gap. The SDK transport now reads and parses the identity itself first, and names the real fault (absent, not readable by this uid, or not JSON) before anything touches the mesh.
  • A full disk is refused before the pull, and the right disk is measured. The pre-flight ran only when the bundle declared disk_need_bytes; a bundle without one sailed past it and died mid-pull with containerd's no space left on device, which reads as a registry fault. A bundle that declares no size now has to clear the headroom floor. The pre-flight also measures containerd's root as well as the docker data-root: docker 29 keeps image layers in the containerd image store, and on env-dev-08 those were on different filesystems — 93 GiB free where the agent looked, 2.8 GiB where the pull wrote.

0.1.7 — registry credential + a pull error you can read (2026-09-08)

  • No hand docker login on a new box (monky-design-docs !225, doc 24 §4a). A manifest entry marked use: registry-auth is the Harbor pull credential, not an env var: it is written to <state_dir>/docker/config.json (0600, in a directory the agent owns) and the docker CLI is pointed at it with an explicit DOCKER_CONFIG. That last part is the trap — the unit runs as monky-deployd, so a docker login by a human or by root is invisible to the agent and looks exactly like no credential at all (env-dev-01, 2026-09-08). Both seeded shapes are accepted: a JSON object, or username:password with the registry from the new registry_host config.
  • compose pull failures carry the registry's own message instead of rc=1. "no basic auth credentials", "manifest unknown" and DNS failures now reach the journal and the report to tenancy.

0.1.6 — 2026-09-07

  • A valid lease token is reused across applies. Every apply requested a new lease, so a failing deploy retried by the 60 s timer burned tenancy's 5-leases-per-hour budget and then failed on LEASE_RATE_LIMITED forever (env-qa-02 pilot). Now: reuse a lease-derived token while lookup-self says it is valid; swap the bootstrap token for a lease once; and if tenancy rate-limits the lease while a working token exists, apply with it and defer the swap instead of failing the deploy.

0.1.5 — 2026-09-07

  • tenancy.port defaults to 443 everywhere — the ansible role default and the TenancyCfg default now match install.sh/config.example.yaml (0.1.5 only changed those two); PROTOCOL.md states the intercept port separately from the in-pod 8081, that the broker does not add #monky-deploy-agent yet, that the jwt mount keeps no jti state, and that release:gitea has not run (doc-drift DD-0523/0525/0527/0528).

  • ${VAR} inside comment lines is not a reference. The renderer's .env.template header literally says "substitutes every ${VAR}", which the refusal check counted as an unresolved variable (ENV_INCOMPLETE: unresolved: VAR) — the first bundle on env-qa-02 was refused for it.

  • config: tenancy.port is the service's intercept port (443), not the in-pod 8081. With 8081 the SDK found no intercept and the dial failed (service not available, then a bare TypeError from the SDK's fallback). install.sh now writes 443; config.example.yaml updated.

  • transport sdk: clear error instead of a TypeError when an address has no intercept or the identity has no dial policy for the service (TransportError names the host:port and what to check).

0.1.4 — 2026-09-07

  • install.sh: ziti-edge-tunnel.service failed to start after enrolment (203/EXEC: the package's ExecStartPre script is not executable by user ziti on ziti-edge-tunnel 1.18.x) and, because the unit was enabled with --now under set -e, the script aborted BEFORE writing config/ACLs/grant/timer — a second kit was needed. The run-host drop-in now clears ExecStartPre=; a tunneler start failure is a WARNING until everything else is in place, then a hard error at the end.

0.1.3 — 2026-09-06

  • install.sh: --version was clobbered by /etc/os-release (it defines VERSION), so the kit tried to download monky-deployd_26.04 LTS (Resolute Raccoon)_amd64.deb (env-qa-02 pilot, first real kit run). Script variables are now DEPLOYD_VERSION; os-release is read in a subshell.
  • install.sh installs Docker Engine when absent (Docker's apt suite for the codename → fallback docker.io), with --docker-data-root <dir> to place the data-root before first start. One script for the end user, per the operator's rule.

v0.1.2 — 2026-09-05

  • The GitLab project is private (its parent groups are private, so it cannot be made public; found when the v0.1.1 one-liner returned 401 anonymously). install.sh gains --token <deploy-token> / MONKY_DEPLOYD_TOKEN: every download from the generic package registry — the script itself included — sends DEPLOY-TOKEN: <token>, a read-only GitLab deploy token (scope read_package_registry only, revocable), seeded in OpenBao at monky/monky-tenancy/deployd-download (key token) and handed to the box by the monky-tenancy install kit. The token never reaches the command line, the log or an xtrace (curl -K config file, 0600, deleted after the download; set +x forced). The one-liner now fetches install.sh from the registry (…/monky-deployd/<ver>/install.sh) instead of -/raw/main, and takes the bootstrap grant via --bootstrap-file — with curl … | bash -s -- stdin IS the script, so it is no longer read for the grant in that mode. --source gitea (no token) stays the off-estate alternative.
  • Ansible role: monky_deployd_download_token (vaulted) → DEPLOY-TOKEN header on both fetches, no_log: true.
  • README / OPERATIONS: why (private project; split-horizon Gitea, cbs/iac#102), token scope, revocation. No agent behaviour change.

v0.1.1 — 2026-09-05

  • install.sh / ansible role / README: the primary download is the public GitLab project's generic package registry on scm.tikali.ai (/api/v4/projects/69/packages/generic/monky-deployd/<ver>/…); the one-liner fetches the script from scm.tikali.ai/…/-/raw/main/packaging/install.sh. Inside the estate gitea.cbs.tikali.net is split-horizon to jump1's RED EIP (no HTTP ingress), so backend boxes could not fetch the artefacts (cbs/iac#102). The Gitea release stays the off-estate alternative (--source gitea / MONKY_DEPLOYD_SOURCE=gitea). No agent behaviour change.

v0.1.0 — 2026-09-05

First release (MONKY-ADR-0028 §D, Reconciliation v2, Gate 1 v2).

  • Stdlib-only Python 3.12 agent: run --once|loop, status, bootstrap, --prune.
  • Protocol: POST /v1/agent/checkin (action apply|none|down), GET /v1/agent/bundle/{env}/{sha} (sha256 verified), POST /v1/agent/leasedeploy grant (login_jwt), POST /v1/agent/report (result applied|failed|down, redacted log_tail). An AppRole-shaped lease is refused (LEASE_SHAPE).
  • OpenBao: POST /v1/auth/jwt-tenancy/login {"role":"see-env","jwt":…}; KV-v2 reads pinned to the manifest's versions, paths pinned to monky/data/<env>/see/; renew-self / re-lease before max TTL.
  • Refusals: ENV_INCOMPLETE (names only), PRIVILEGED_REFUSED, ROLLBACK_REFUSED, DISK_INSUFFICIENT (need × 1.5 + 2 GiB vs docker data-root), BUNDLE_SHA_MISMATCH, BUNDLE_ENV_MISMATCH.
  • Transports sdk (openziti SDK), proxy (ziti tunnel proxy 18443/18200), system.
  • Exit codes 0 / 75 / 78 (AGENT_ENV_MISMATCH, no retry storm) / 1; laptop mode (offline exits 0).
  • Packaging: hardened monky-deployd.service oneshot + 60 s timer, monky-deployd-proxy.service, nfpm .deb with /opt/monky-deployd/venv, packaging/install.sh (Ubuntu 26.04), ansible role skeleton.
  • Known divergence: monky-tenancy main (MR !15) still ships the AppRole lease/kit; the JWT-grant follow-up is the tenancy side of this release (docs/PROTOCOL.md "Divergences").