Skip to content

fix(gateway): apply dashboard JSON config and reload live settings - #99

Merged
adriannoes merged 5 commits into
developmentfrom
fix/bugbot-batch-config
Sep 22, 2026
Merged

adriannoes merged 5 commits into
developmentfrom
fix/bugbot-batch-config

Conversation

@adriannoes

Copy link
Copy Markdown
Collaborator

Summary

  • Rewritten against current development (not a cherry-pick of the main-based drafts). routes.c already includes cron dispatch from fix(cron): full TEXT, deferred ack, no same-minute re-fire聽#95; this only changes handle_config_put.
  • Dashboard PUT /api/config now detects JSON, patches model / max_tokens / temperature / gateway_host / gateway_port into config.toml, and reloads live settings (try_config_reload + http_set_live_config) so GET matches the save without SIGHUP.
  • Shutdown frees the live bootstrap config after stale_free_all so an HTTP-thread reload cannot double-free main's stale pointer.
  • Leftover from test: cover authenticated PUT /api/config validation聽#56: integration test that PUT /api/config with a body >64 KiB returns 413. Invalid TOML + valid TOML PUT were already on development.

Supersedes #58 and #56.

Does not mix sandbox, file, or camera.

Test plan

  • make test_config_patch / ./build/test_config_patch
  • make test_reload / ./build/test_reload
  • GATEWAY=1 make test_gateway_http / ./build/test_gateway_http
  • CI=true make test
  • make static

Made with Cursor

Dashboard PUT /api/config sent JSON while the handler wrote raw TOML
and never swapped live provider/gateway settings. Patch known fields
into config.toml and reload so GET reflects the save immediately.

Refs: #58
Transport already rejects bodies over 64 KiB before routes run; keep
that boundary under test so dashboard saves cannot truncate config.

Refs: #56

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

This is a solid, correctly scoped fix for the dashboard config save path. PUT /api/config was writing the JSON body as if it were TOML and never swapping live settings; this PR patches the five dashboard fields into config.toml, validates the result, then reloads so GET /api/config matches without SIGHUP. The shutdown double-free fix (stale_free_all then config_free(bootstrap_get_cfg())) is real, and the JSON path only touches known keys so a dashboard save cannot clobber sandbox or API-key settings.

I did not find a merge blocker on the happy path (config.example.toml layout + web/js/app.js payload). Locally CI=true make test_config_patch LDLIBS=-lm passed. This image has no libcurl/libwebsockets, so I did not run test_reload or GATEWAY=1 make test_gateway_http. GitHub static, test, release was still pending at review time.

Must Fix

None.

Should Fix

  1. The TOML patcher only matches column-0 keys and section headers whose next character is EOL. Indented keys ( model = ...) and [agent] # comment miss the existing line, insert a duplicate, and tomlc99 then fails with key exists (HTTP 400). I reproduced both. Skip leading whitespace in find_key_line and allow trailing space/comment after ] in find_section so formatter-indented configs save in place.
  2. Present-but-wrong-type JSON fields are ignored and the handler still returns 200. {"model":123} is a successful no-op. If a key is present and not the expected JSON type, return 400 so a client cannot think the save applied.
  3. try_config_reload now runs on the libwebsockets thread. stale_enqueue / bootstrap_set_cfg are unlocked; a SIGHUP on main at the same time can enqueue the same pointer twice and double-free on shutdown. Hold agent_lock() around the swap (or marshal the reload onto the main loop and wait) so GET still reflects the save.
  4. Add a CHANGELOG Unreleased Fixed note. This is a user-visible dashboard bugfix; neighboring gateway fixes are already listed there.

Nice to Have

  • handle_config_put is 82 lines and routes.c is 984 (the 1000-line rule is close). Extract JSON vs TOML PUT + reload into a helper.
  • validate_patched_toml writes *.patch-test, then PUT writes *.tmp and validates again. Drop the first disk round-trip; keep the .tmp + config_load gate.
  • Escape / / in escape_toml_string instead of failing closed on a model that contains a newline.
  • test_api_config_put_json should also assert temperature and gateway_host on GET, plus a unit test for quote escaping (that path already works).
  • Gateway host/port still do not rebind (documented for SIGHUP in main.c). A dashboard save of gateway_port updates GET while the process keeps the old listen port until restart. A UI note would avoid confusion.

Positive Highlights

  • New config_patch module instead of growing config.c (already under a 1000-line waiver). JSON merge is allowlisted to the five dashboard fields; unknown JSON keys cannot rewrite [sandbox] or provider secrets. Raw TOML PUT is unchanged.
  • Reload ownership is thought through: enqueue bootstrap_get_cfg() rather than the caller pointer, extra http_set_live_config because test_reload builds with GATEWAY=0, and shutdown frees the live pointer after stale_free_all. test_try_config_reload_ignores_stale_caller_pointer covers the actual double-free shape.
  • Tests match the bug: unit patch (update, insert, missing section, invalid JSON), HTTP JSON PUT then GET, and the leftover 64 KiB 413 from #56.
Open in Web聽View Automation聽

Sent by Cursor Automation: Adrianno鈥檚 personal code review

Comment thread src/core/config_patch.c
Comment thread src/core/config_patch.c Outdated
Comment thread src/gateway/routes.c
@adriannoes adriannoes self-assigned this Sep 21, 2026
Formatter-indented keys and commented section headers were missed, so a dashboard save inserted a duplicate key and tomlc99 returned 400. A present field with the wrong JSON type now fails instead of a 200 no-op, and string values escape quotes and newlines.
Dashboard save and SIGHUP both swap the live config. Hold agent_lock on both paths so the same pointer cannot be queued twice, and return HTTP 500 when the file is saved but the live reload does not.
@adriannoes

Copy link
Copy Markdown
Collaborator Author

Should Fix from the review is in c0c7d82 and eedd31c (threads resolved).

Nice to have:

  • Newline/quote escaping and the extra GET assertions (temperature, gateway_host) are in those commits.
  • The config form now notes that gateway host/port do not rebind until restart.
  • CHANGELOG Unreleased has the dashboard PUT note.
  • Kept the *.patch-test load inside config_patch_dashboard_json so the unit API fails closed before the HTTP handler writes *.tmp.
  • Did not extract handle_config_put out of routes.c (996 lines). A same-file helper would not move the 1000-line count.

@adriannoes
adriannoes merged commit 711405d into development Sep 22, 2026
2 checks passed
@adriannoes
adriannoes deleted the fix/bugbot-batch-config branch September 22, 2026 16:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant