From fc6de77e069b2a0ae320bda815de358ba3e73277 Mon Sep 17 00:00:00 2001 From: ZdenekSrotyr <139972147+ZdenekSrotyr@users.noreply.github.com> Date: Tue, 19 May 2026 15:59:39 +0200 Subject: [PATCH] fix(infra): pre-create /data/uploads in customer-instance startup script (#351) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(infra): pre-create /data/uploads in customer-instance startup script v50/0.55.0 introduced marketplace cover-image uploads mounted under ${DATA_DIR}/uploads; app/main.py eagerly mkdirs the directory at boot for the StaticFiles mount. On host-bind deploys where /data root is root-owned, the container's non-root agnes user (UID 999) can't create that directory and crashloops with PermissionError: '/data/uploads'. Add 'uploads' to the existing mkdir + chown block in infra/modules/customer-instance/startup-script.sh.tpl so the dir is pre-created with the correct ownership at provision time — same way state/analytics/extracts have been since infra-v1.7.0. The block runs inside the [ -b $DATA_DEV ] guard, so it only fires when the data disk is attached (idempotent on reboot, no-op when disk missing). Fresh VMs provisioned at infra-v1.9.0+ get the dir at first boot. For existing instances, bump the module pin + terraform apply (rewrites the instance startup-script metadata) and reboot the VM so the refreshed block replays — or run a one-off: sudo mkdir -p /data/uploads && sudo chown 999:999 /data/uploads * release: 0.55.2 — pre-create /data/uploads in customer-instance startup script --- CHANGELOG.md | 20 +++++++++++++++++++ .../customer-instance/startup-script.sh.tpl | 9 ++++++++- pyproject.toml | 2 +- 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d8540d5..4886857 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,26 @@ CalVer image tags (`stable-YYYY.MM.N`, `dev-YYYY.MM.N`) are produced for every C ## [Unreleased] +## [0.55.2] — 2026-05-19 + +### Fixed +- **Customer-instance Terraform module pre-creates `/data/uploads`** + (`infra/modules/customer-instance/startup-script.sh.tpl`). v50/0.55.0 + added a marketplace cover-image upload directory mounted under + `${DATA_DIR}/uploads`; `app/main.py` eagerly mkdirs it at boot for + the `StaticFiles` mount. On host-bind deploys where `/data` root + is root-owned, the container's non-root `agnes` user (UID 999) + can't create the directory and the app crashloops with + `PermissionError: '/data/uploads'`. The startup script now + pre-creates `uploads` alongside `state/analytics/extracts` under + the existing `chown -R 999:999`. Fresh VMs provisioned at + `infra-v1.9.0`+ get the dir at first boot; for existing instances + bump the module pin + `terraform apply` (which rewrites the + instance startup-script metadata) and reboot the VM so the + refreshed mkdir/chown block replays. As a one-off without + rebooting, run `sudo mkdir -p /data/uploads && sudo chown 999:999 + /data/uploads` on the host. + ## [0.55.1] — 2026-05-19 ### Added diff --git a/infra/modules/customer-instance/startup-script.sh.tpl b/infra/modules/customer-instance/startup-script.sh.tpl index e89efd5..b9a82fe 100644 --- a/infra/modules/customer-instance/startup-script.sh.tpl +++ b/infra/modules/customer-instance/startup-script.sh.tpl @@ -39,12 +39,19 @@ if [ -b "$DATA_DEV" ]; then mkdir -p "$DATA_MNT" mountpoint -q "$DATA_MNT" || mount -o discard,defaults "$DATA_DEV" "$DATA_MNT" grep -qF "$DATA_DEV" /etc/fstab || echo "$DATA_DEV $DATA_MNT ext4 discard,defaults,nofail 0 2" >> /etc/fstab - mkdir -p "$DATA_MNT/state" "$DATA_MNT/analytics" "$DATA_MNT/extracts" + mkdir -p "$DATA_MNT/state" "$DATA_MNT/analytics" "$DATA_MNT/extracts" "$DATA_MNT/uploads" # Match Dockerfile USER agnes (uid:gid 999:999). A freshly-attached PD is # root-owned by default; without this chown the non-root container cannot # write to /data/state/system.duckdb and every authed request 500s after # the first upgrade that flips USER from root to agnes (regression hit # agnes-development on 2026-04-29). Idempotent — safe on reboot. + # + # /data/uploads holds admin-uploaded marketplace cover images + # (v50/0.55.0+). app/main.py eagerly mkdirs it at boot for the + # StaticFiles mount; on host-bind setups where /data root is + # root-owned, that mkdir 403s and the container crashloops — so + # pre-create the dir here under the SAME chown -R that already + # covers state/analytics/extracts. Cheap insurance. chown -R 999:999 "$DATA_MNT" fi diff --git a/pyproject.toml b/pyproject.toml index 1bcb86c..c0240a4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "agnes-the-ai-analyst" -version = "0.55.1" +version = "0.55.2" description = "Agnes — AI Data Analyst platform for AI analytical systems" requires-python = ">=3.11,<3.14" license = "MIT"