The module ran searxng on the image's built-in settings, which serve html
only — so the module's own search tool (format=json) was refused by the
software it fronts. And there was no way to configure it per machine: the
only file settings reach was the sidecar's.
settings.yml is now the module's one mergeable file (JSON is YAML): generic
defaults in the manifest (json format on, limiter and image proxy off,
valkey wired), and whatever differs per machine — base_url, method,
autocomplete, suspended times — set as the assignment's settings. The
secret key is filled on the machine through ${secret:secret}, so the
secrets-in-environment exception and the env file go. Directories are
placed. Image pinned to 2026.9.20, what ace runs today (the old pin was
older, 2026.9.1).
The sidecar's config.json is no longer mergeable: settings merge into every
mergeable file of a module, and the sidecar would have received searxng's
keys. It only ever read an optional url, which its env already carries.
Verified on ace: the pinned image serves html and json from a read-only,
root-owned 0600 JSON settings.yml.
The module ran searxng on the image's built-in settings, which serve html
only — so the module's own search tool (format=json) was refused by the
software it fronts. And there was no way to configure it per machine: the
only file settings reach was the sidecar's.
settings.yml is now the module's one mergeable file (JSON is YAML): generic
defaults in the manifest (json format on, limiter and image proxy off,
valkey wired), and whatever differs per machine — base_url, method,
autocomplete, suspended times — set as the assignment's settings. The
secret key is filled on the machine through ${secret:secret}, so the
secrets-in-environment exception and the env file go. Directories are
placed. Image pinned to 2026.9.20, what ace runs today (the old pin was
older, 2026.9.1).
The sidecar's config.json is no longer mergeable: settings merge into every
mergeable file of a module, and the sidecar would have received searxng's
keys. It only ever read an optional url, which its env already carries.
Verified on ace: the pinned image serves html and json from a read-only,
root-owned 0600 JSON settings.yml.
The module ran searxng on the image's built-in settings, which serve html
only — so the module's own search tool (format=json) was refused by the
software it fronts. And there was no way to configure it per machine: the
only file settings reach was the sidecar's.
settings.yml is now the module's one mergeable file (JSON is YAML): generic
defaults in the manifest (json format on, limiter and image proxy off,
valkey wired), and whatever differs per machine — base_url, method,
autocomplete, suspended times — set as the assignment's settings. The
secret key is filled on the machine through ${secret:secret}, so the
secrets-in-environment exception and the env file go. Directories are
placed. Image pinned to 2026.9.20, what ace runs today (the old pin was
older, 2026.9.1).
The sidecar's config.json is no longer mergeable: settings merge into every
mergeable file of a module, and the sidecar would have received searxng's
keys. It only ever read an optional url, which its env already carries.
Verified on ace: the pinned image serves html and json from a read-only,
root-owned 0600 JSON settings.yml.
The route binding still named /var/lib/searxng-module, the directory the
previous commit placed elsewhere — the host would have written it into a
directory nothing declares. Same shape as gitea and nextcloud.
Fixed in 63a255c:binds.route still pointed into /var/lib/searxng-module, the directory this PR stops declaring — the host would have written the route binding into an undeclared directory. Now ${dir:state}/route.json, as gitea and nextcloud do.
Checked against the controller, not assumed:
Settings merge into every mergeable file and every contribution — settle() skips only ports, so endpoints/reach/expose and any route label override also land in settings.yml, and server/search land in the route contribution. Tested: searxng tolerates the extra top-level keys (endpoints, label) — POST + format=json still return results; route-adapter reads only scheme/path from a contribution's values, so the searxng keys there are inert. Still worth an hq issue: a module cannot aim a setting at one file.
${secret:secret} is filled textually, without JSON escaping. Minted secrets are base64url (seal.go), so JSON-safe; only a hand-secret accepted value containing " or \ would break the file.
The image reads a root-owned 0600 settings file (tested) — no owner needed, which matters because owner is a user name and uid 977 has a different name per machine.
MESH_CATALOGUE=… go test ./internal/catalogue/ -run Catalogue passes (without MESH_CATALOGUE the parse test silently skips).
Consequences worth knowing:
valkey starts on a fresh placed directory; the predecessor's cache is not carried (it is a cache).
The own secret moves path; searxng is assigned nowhere today, so nothing holds the old one.
Tor engines (ahmia, torch) log load errors at start — upstream defaults, harmless, also present today.
## Self-review
**Fixed in 63a255c:** `binds.route` still pointed into `/var/lib/searxng-module`, the directory this PR stops declaring — the host would have written the route binding into an undeclared directory. Now `${dir:state}/route.json`, as gitea and nextcloud do.
**Checked against the controller, not assumed:**
- Settings merge into *every* mergeable file and *every* contribution — `settle()` skips only `ports`, so `endpoints`/`reach`/`expose` and any route `label` override also land in `settings.yml`, and `server`/`search` land in the route contribution. Tested: searxng tolerates the extra top-level keys (`endpoints`, `label`) — POST + `format=json` still return results; route-adapter reads only `scheme`/`path` from a contribution's values, so the searxng keys there are inert. Still worth an hq issue: a module cannot aim a setting at one file.
- `${secret:secret}` is filled textually, without JSON escaping. Minted secrets are base64url (`seal.go`), so JSON-safe; only a hand-`secret accept`ed value containing `"` or `\` would break the file.
- The image reads a root-owned `0600` settings file (tested) — no owner needed, which matters because `owner` is a user *name* and uid 977 has a different name per machine.
- `MESH_CATALOGUE=… go test ./internal/catalogue/ -run Catalogue` passes (without `MESH_CATALOGUE` the parse test silently skips).
**Consequences worth knowing:**
- valkey starts on a fresh placed directory; the predecessor's cache is not carried (it is a cache).
- The own secret moves path; searxng is assigned nowhere today, so nothing holds the old one.
- Tor engines (`ahmia`, `torch`) log load errors at start — upstream defaults, harmless, also present today.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
The module ran searxng on the image's built-in settings, which serve html
only — so the module's own search tool (format=json) was refused by the
software it fronts. And there was no way to configure it per machine: the
only file settings reach was the sidecar's.
settings.yml is now the module's one mergeable file (JSON is YAML): generic
defaults in the manifest (json format on, limiter and image proxy off,
valkey wired), and whatever differs per machine — base_url, method,
autocomplete, suspended times — set as the assignment's settings. The
secret key is filled on the machine through ${secret:secret}, so the
secrets-in-environment exception and the env file go. Directories are
placed. Image pinned to 2026.9.20, what ace runs today (the old pin was
older, 2026.9.1).
The sidecar's config.json is no longer mergeable: settings merge into every
mergeable file of a module, and the sidecar would have received searxng's
keys. It only ever read an optional url, which its env already carries.
Verified on ace: the pinned image serves html and json from a read-only,
root-owned 0600 JSON settings.yml.
The module ran searxng on the image's built-in settings, which serve html only — so the module's own search tool (format=json) was refused by the software it fronts. And there was no way to configure it per machine: the only file settings reach was the sidecar's. settings.yml is now the module's one mergeable file (JSON is YAML): generic defaults in the manifest (json format on, limiter and image proxy off, valkey wired), and whatever differs per machine — base_url, method, autocomplete, suspended times — set as the assignment's settings. The secret key is filled on the machine through ${secret:secret}, so the secrets-in-environment exception and the env file go. Directories are placed. Image pinned to 2026.9.20, what ace runs today (the old pin was older, 2026.9.1). The sidecar's config.json is no longer mergeable: settings merge into every mergeable file of a module, and the sidecar would have received searxng's keys. It only ever read an optional url, which its env already carries. Verified on ace: the pinned image serves html and json from a read-only, root-owned 0600 JSON settings.yml.Self-review
Fixed in
63a255c:binds.routestill pointed into/var/lib/searxng-module, the directory this PR stops declaring — the host would have written the route binding into an undeclared directory. Now${dir:state}/route.json, as gitea and nextcloud do.Checked against the controller, not assumed:
settle()skips onlyports, soendpoints/reach/exposeand any routelabeloverride also land insettings.yml, andserver/searchland in the route contribution. Tested: searxng tolerates the extra top-level keys (endpoints,label) — POST +format=jsonstill return results; route-adapter reads onlyscheme/pathfrom a contribution's values, so the searxng keys there are inert. Still worth an hq issue: a module cannot aim a setting at one file.${secret:secret}is filled textually, without JSON escaping. Minted secrets are base64url (seal.go), so JSON-safe; only a hand-secret accepted value containing"or\would break the file.0600settings file (tested) — no owner needed, which matters becauseowneris a user name and uid 977 has a different name per machine.MESH_CATALOGUE=… go test ./internal/catalogue/ -run Cataloguepasses (withoutMESH_CATALOGUEthe parse test silently skips).Consequences worth knowing:
ahmia,torch) log load errors at start — upstream defaults, harmless, also present today.