1 Commits

Author SHA1 Message Date
Aari
236a068e77
fix(docker): let the Gateway write extensions_config.json in production (#4852)
* fix(docker): let the Gateway write extensions_config.json in production

AGENTS.md states extensions_config.json may be edited at runtime through the
Gateway API, and the Gateway implements that for the MCP enable switch,
PUT/PATCH /api/mcp/config and the skill update route. Two properties of the
production compose stack made every one of those writes fail:

- the file was mounted read-only, and
- Docker mounts it as its own mount point, so the temp-file-plus-rename in
  atomic_write_extensions_config hit EBUSY. Linux refuses rename() over a
  mount point whether or not the mount is writable, so making the mount
  read-write alone is not enough.

Mount it read-write and fall back to an in-place overwrite on EBUSY only.
The fallback is deliberately non-atomic and says so in a warning; it is
reached only where the atomic route cannot work, and any other errno still
propagates. config.yaml stays read-only: no API writes it.

docker-compose-dev.yaml mounts the whole project directory, so the
destination is an ordinary file there and this never surfaced in development.

* test(docker): parse mount options instead of matching a :ro suffix

Docker's short-syntax options segment is comma-separated, so a read-only
mount can legally be spelled ":ro,z" or ":z,ro" — common with SELinux
relabelling. Matching the raw string for a ":ro" suffix reads those as
writable, which silently defeats the guard: the writability assertion would
pass on a read-only mount, and the config.yaml assertion would fail on a
correctly read-only one.

Parse the options segment and test membership instead, and cover the parser
with the spellings that broke the suffix check.

* fix(config): harden mutable extensions config
2026-08-23 15:08:39 +08:00