Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
124 commits
Select commit Hold shift + click to select a range
4a7d91d
fix(gateway): stop HTTP thread before freeing auth context
cursoragent Aug 24, 2026
48c03f5
fix(sandbox): keep agent workspace off gateway state files
cursoragent Sep 3, 2026
7e5eda6
fix(dispatch): acquire agent mutex around main-loop agent_run
adriannoes Sep 12, 2026
1c42d58
fix(dispatch): serialize /reset and assert mutex release
adriannoes Sep 12, 2026
25a6dbb
Merge pull request #85 from asap-protocol/fix/dispatch-agent-mutex
adriannoes Sep 12, 2026
7d59514
fix(asap): acquire agent mutex around inbound mcp.tool_call
adriannoes Sep 12, 2026
cc08b76
fix(asap): hold agent mutex around inbound state.query
adriannoes Sep 12, 2026
3f706d6
docs: document agent_lock around mcp.tool_call and state.query
adriannoes Sep 12, 2026
7ec25fd
Merge pull request #60 from asap-protocol/cacritical-bug-management-18df
adriannoes Sep 12, 2026
9cc82dc
fix(asap): isolate inbound task.request sessions by sender URN
adriannoes Sep 12, 2026
72e9c62
fix(asap): fail closed on oversized task.request sender URNs
adriannoes Sep 12, 2026
5bc9c57
docs(asap): document trusted_senders for inbound session isolation
adriannoes Sep 12, 2026
c93e5e5
Merge pull request #64 from asap-protocol/cursor/critical-bug-managem…
adriannoes Sep 12, 2026
9aaf8a6
fix(asap): wire provider and tools into POST /asap
adriannoes Sep 12, 2026
6a87687
refactor(core): share bootstrap_fill_agent_tools with POST /asap
adriannoes Sep 12, 2026
3d81b23
test(gateway): assert ASAP JSON payload_type and unknown-tool 400
adriannoes Sep 12, 2026
208f7a4
docs(asap): document protocol-public tool dispatch on POST /asap
adriannoes Sep 12, 2026
47fef71
Merge pull request #53 from asap-protocol/cursor/critical-bug-managem…
adriannoes Sep 12, 2026
e7bb60e
fix(gateway): reject oversized ASAP responses instead of truncating JSON
adriannoes Sep 12, 2026
4534b94
fix(gateway): log ASAP outbound only after the HTTP copy succeeds
adriannoes Sep 12, 2026
e6e6037
docs(asap): document 64 KiB POST /asap response buffer cap
adriannoes Sep 12, 2026
2d56cb2
Merge pull request #61 from asap-protocol/cursor/critical-bug-managem…
adriannoes Sep 13, 2026
3b61f14
fix(asap): avoid double-free on malformed JSON-RPC results
adriannoes Sep 13, 2026
f7028ed
docs(asap): qualify from_object rpc_id ownership on early return
adriannoes Sep 13, 2026
5c653d6
docs(asap): changelog the JSON-RPC result double-free fix
adriannoes Sep 13, 2026
762af7f
Merge pull request #84 from asap-protocol/cursor/high-severity-issues…
adriannoes Sep 13, 2026
744cde3
fix(providers): fail closed when Anthropic parse realloc fails
adriannoes Sep 13, 2026
e489f0b
docs(providers): changelog Anthropic realloc fail-closed parse
adriannoes Sep 13, 2026
c5fadc6
Merge pull request #80 from asap-protocol/cursor/high-severity-issues…
adriannoes Sep 13, 2026
9cf62da
fix(memory): preserve existing DB when sqlite3_open fails
adriannoes Sep 13, 2026
c6717f3
docs(memory): changelog preserve existing DB on open failure
adriannoes Sep 13, 2026
5f8d420
fix(memory): log sqlite errmsg on preserved-DB open failure
adriannoes Sep 13, 2026
50d0bfb
Merge pull request #63 from asap-protocol/cursor/critical-bug-managem…
adriannoes Sep 13, 2026
6e837b2
fix(agent): preserve multi-round ReAct tool results in message history
adriannoes Sep 13, 2026
ccff48c
docs(agent): changelog preserve multi-round ReAct tool results
adriannoes Sep 13, 2026
c7a0b13
test(agent): assert ReAct tool_calls stay live across rounds
adriannoes Sep 13, 2026
c08e3d7
Merge pull request #59 from asap-protocol/cacritical-bug-management-4ed0
adriannoes Sep 13, 2026
0197b9b
fix(agent,memory): refuse session JSON truncation that wipes history
adriannoes Sep 13, 2026
8d8748c
docs(agent,memory): changelog refuse session JSON truncation
adriannoes Sep 13, 2026
1b54efd
fix(agent,memory): log refused session JSON and skip persist on overs…
adriannoes Sep 13, 2026
7c796bd
Merge pull request #70 from asap-protocol/cursor/critical-bug-managem…
adriannoes Sep 13, 2026
93cd374
fix(agent): skip memory injection when system prompt buffer is full
adriannoes Sep 13, 2026
cd236d9
docs(agent): changelog skip memory injection when prompt is full
adriannoes Sep 13, 2026
7deaad7
fix(agent): log skipped memory injection on a full system prompt
adriannoes Sep 13, 2026
805edcb
Merge pull request #75 from asap-protocol/cursor/high-severity-issues…
adriannoes Sep 13, 2026
7db5f3a
Merge branch 'main' into cursor/high-severity-issues-7e6b
adriannoes Sep 13, 2026
2a0f8dc
Merge branch 'development' into cursor/high-severity-issues-7e6b
adriannoes Sep 13, 2026
bf7a797
test(gateway): overlap Bearer GETs with SIGTERM teardown
adriannoes Sep 13, 2026
564766f
docs(gateway): changelog auth_ctx UAF on HTTP teardown
adriannoes Sep 13, 2026
519a6be
Merge pull request #72 from asap-protocol/cursor/high-severity-issues…
adriannoes Sep 13, 2026
ceacd7a
test(gateway): assert listen bind honors gateway.host
adriannoes Sep 13, 2026
04638f1
fix(gateway): bind listen socket to configured host
adriannoes Sep 13, 2026
0231c40
docs(gateway): changelog loopback listen bind via gateway.host
adriannoes Sep 13, 2026
8e7444c
test(gateway): cover IPv6/empty bind-all and v4-mapped ANY
adriannoes Sep 13, 2026
e2eeba9
fix(gateway): treat empty and IPv6 any as bind-all
adriannoes Sep 13, 2026
cbe2416
docs(gateway): changelog IPv6 and empty bind-all hosts
adriannoes Sep 13, 2026
28352b6
Merge pull request #68 from asap-protocol/cursor/critical-bug-managem…
adriannoes Sep 13, 2026
35cbc55
test(ws): assert send_to accepts dispatch-sized payload
adriannoes Sep 13, 2026
341f5ac
fix(webchat): align WebSocket payload limit with agent response buffer
adriannoes Sep 13, 2026
97ac525
docs(webchat): changelog WS payload limit aligned with dispatch
adriannoes Sep 13, 2026
3ab8e5a
test(ws): lock WS_TEXT_MAX minus one and exact payload roundtrip
adriannoes Sep 13, 2026
d69764f
fix(webchat): size WS dest for NUL and write full 32 KiB frames
adriannoes Sep 13, 2026
ca106b3
docs(webchat): changelog WS dest NUL and inclusive frame write
adriannoes Sep 13, 2026
b4b787c
Merge pull request #62 from asap-protocol/cursor/critical-bug-managem…
adriannoes Sep 13, 2026
50b8aec
test(discord): reject route edge cases in helpers
adriannoes Sep 13, 2026
c81a39c
docs(discord): changelog helper route edge-case tests
adriannoes Sep 13, 2026
09043f0
test(discord): lock DM bot-id skip and cleared session on ignore
adriannoes Sep 13, 2026
b1f1288
fix(discord): route MESSAGE_CREATE through helper gating
adriannoes Sep 13, 2026
6ea298f
docs(discord): changelog MESSAGE_CREATE helper routing
adriannoes Sep 13, 2026
c8e4f32
fix(discord): narrow allowlist loop index for cppcheck
adriannoes Sep 13, 2026
3dcc527
Merge pull request #55 from asap-protocol/cursor/test-coverage-automa…
adriannoes Sep 14, 2026
8905d1c
fix(discord): grow gateway RX for trailing NUL to avoid heap OOB
adriannoes Sep 14, 2026
d97452a
fix(gateway): raise WebChat WS rx_buffer_size so inbound JSON is not …
adriannoes Sep 14, 2026
19d4708
Merge pull request #81 from asap-protocol/cursor/high-severity-issues…
adriannoes Sep 14, 2026
080c174
fix(file): write to the intended path and reject dangling symlinks
adriannoes Sep 21, 2026
723cd54
fix(file): persist workspace writes with atomic replace
adriannoes Sep 21, 2026
867008b
fix(camera): fail closed on empty workspace_path and dangling capture…
adriannoes Sep 21, 2026
c466473
fix(cron): keep full SQLite TEXT for schedule and message
adriannoes Sep 21, 2026
dcf193b
fix(cron): defer job commit until agent delivery succeeds
adriannoes Sep 21, 2026
45a8896
fix(cron): advance recurring jobs past the firing minute
adriannoes Sep 21, 2026
088ef19
fix(file): unique write sidecar and honest leaf-symlink reject
adriannoes Sep 21, 2026
2c3f8f4
fix(dispatch): ack cron jobs after slash-command send
adriannoes Sep 21, 2026
a9937e5
fix(cron): wait before re-offer and cap TEXT
adriannoes Sep 21, 2026
86285d6
Merge pull request #95 from asap-protocol/fix/bugbot-batch-cron
adriannoes Sep 21, 2026
c704a59
chore(file): merge development into fix/bugbot-batch-file-camera
adriannoes Sep 21, 2026
a32b1b9
Merge pull request #94 from asap-protocol/fix/bugbot-batch-file-camera
adriannoes Sep 21, 2026
a6da498
fix(asap): free inbound response payload once on envelope OOM
adriannoes Sep 21, 2026
c99e6af
fix(gateway): persist pairing tokens with atomic replace
adriannoes Sep 21, 2026
0fe4653
fix(skills): persist skill files with atomic replace
adriannoes Sep 21, 2026
b5d543c
fix(tools): stop unsandboxed shell hang after output cap
adriannoes Sep 21, 2026
82b62cb
fix(gateway): honor 1 MiB POST /asap body cap
adriannoes Sep 21, 2026
76a763a
fix(tools): kill unsandboxed shell process group before wait
adriannoes Sep 21, 2026
7db8f6b
test(tools): expose POSIX popen and nanosleep in test_shell
adriannoes Sep 21, 2026
3678a09
fix(gateway): apply dashboard JSON config and reload live settings
adriannoes Sep 21, 2026
b8f50eb
test(gateway): cover oversized PUT /api/config 413
adriannoes Sep 21, 2026
d6f79e5
Merge pull request #96 from asap-protocol/fix/bugbot-batch-shell
adriannoes Sep 21, 2026
5cc892b
Merge branch 'development' into fix/bugbot-batch-auth-skills
adriannoes Sep 21, 2026
87d4709
Merge pull request #98 from asap-protocol/fix/bugbot-batch-auth-skills
adriannoes Sep 21, 2026
51c783b
chore(asap): merge development into fix/bugbot-batch-asap
adriannoes Sep 21, 2026
c261e45
refactor(asap): drop owned_payload alias in fill_response_envelope
adriannoes Sep 21, 2026
bfd9685
fix(gateway): treat NULL body as exceeding static cap
adriannoes Sep 21, 2026
7c3d1e2
docs(asap): document inbound 1 MiB POST /asap body cap
adriannoes Sep 21, 2026
5c21411
test(gateway): record POST /asap rate-limit headroom
adriannoes Sep 21, 2026
9001648
Merge pull request #97 from asap-protocol/fix/bugbot-batch-asap
adriannoes Sep 21, 2026
5214365
chore(gateway): merge development into fix/bugbot-batch-config
adriannoes Sep 22, 2026
c0c7d82
fix(config): patch indented TOML and reject mistyped dashboard JSON
adriannoes Sep 22, 2026
eedd31c
fix(gateway): lock config reload and fail PUT when it does not apply
adriannoes Sep 22, 2026
711405d
Merge pull request #99 from asap-protocol/fix/bugbot-batch-config
adriannoes Sep 22, 2026
dc14526
chore(sandbox): merge development into workspace state-file fix
adriannoes Sep 22, 2026
41fdaf8
fix(test): size allowlist state paths for format truncation
adriannoes Sep 22, 2026
e63a7ec
fix(sandbox): block state sidecars and workspace-relative shell names
adriannoes Sep 22, 2026
c8cd91c
Merge pull request #79 from asap-protocol/cursor/high-severity-issues…
adriannoes Sep 22, 2026
5ebb5a9
fix(allowlist): fail closed on workspace escapes and reserved names
adriannoes Sep 22, 2026
554fcf5
fix(sandbox): fail closed when namespace setup cannot be applied
adriannoes Sep 22, 2026
541195a
fix(sandbox): bound host files with Landlock on the workspace
adriannoes Sep 22, 2026
ec9ef6b
docs(security): record Landlock, MS_PRIVATE, and proc remount
adriannoes Sep 22, 2026
337fb31
Merge pull request #89 from asap-protocol/fix/bugbot-batch-sandbox-la…
adriannoes Sep 22, 2026
0e5bc51
fix(cron): deliver other due jobs while one remains unacked
adriannoes Sep 24, 2026
e09b2e9
fix(cron): keep the re-offer wait when the offer table is full
adriannoes Sep 24, 2026
aa6cd98
Merge pull request #100 from asap-protocol/fix/cron-due-sibling-starv…
adriannoes Sep 24, 2026
7ed691b
fix(cron): wait when a due job cannot be recorded
adriannoes Sep 24, 2026
cc43155
fix(sandbox): fail closed when a Landlock rule cannot be added
adriannoes Sep 24, 2026
fab3e7d
fix(gateway): save config through a unique temp and publish once
adriannoes Sep 24, 2026
3b37867
fix(gateway): publish live config before releasing the agent lock
adriannoes Sep 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,59 @@ All notable changes to ShellClaw are documented here. Format follows [Keep a Cha

## [Unreleased]

### Fixed
- Cron re-offer waits the full timeout when a due id could not be stored in the 16-slot table, and an ack frees that slot so the next due job can be delivered and then backed off.
- Landlock device grants stay `/dev/null`, `/dev/zero`, `/dev/urandom`, and `/dev/tty` without `IOCTL_DEV`. A failed `landlock_add_rule` fails the ruleset closed.
- Dashboard config save and JSON patch validation use a unique temp plus `fsync`, and the live gateway config pointer is published once under `agent_lock`.
- Shell `workspace_only` walks the first existing ancestor, collapses `..` lexically (without cancelling across a symlink), and scans quoted/embedded paths, `file:` URLs, `$HOME`/`$PWD` (including glued `$IFS`), and bare relative names such as `cat leak`. `strdup` OOM is fail-closed. Encoded-slash cat-and-mouse is frozen; Landlock is the kernel host-FS bound.
- Shell `sandbox_exec` applies a Landlock ruleset to the configured workspace (fail-closed) as the kernel host-FS bound, so symlink and `chr(47)+` host reads cannot skip the string scanner. Mount/network/PID namespaces fail closed (user namespace first when unprivileged). After `CLONE_NEWPID` the isolator forks so the command is PID 1. Isolation failure uses a control pipe, not `sh` exit 122/123. `/dev/null` stays writable under Landlock.
- Default `workspace_path` is `~/.shellclaw/workspace`, and file/shell tools still refuse `auth_tokens.json`, `shellclaw.pid`, `shellclaw.log`, and `.shellclaw` `config.toml` / `memory.db` (including `memory.db-*` sidecars) when a custom workspace contains them. A bare `cat config.toml` after the sandbox `chdir` is blocked, and a symlink at the workspace path is not accepted.
- Dashboard `PUT /api/config` merges JSON fields into `config.toml` and reloads live settings. Indented keys and `[section] # comment` headers are updated in place; a present field with the wrong JSON type returns 400; a saved file whose live reload fails returns 500. Gateway host and port still need a process restart to rebind.
- Unsandboxed `shell` no longer blocks forever in `waitpid` after the output cap fills; leftover children (including background grandchildren) are SIGKILL'd via the command process group, and truncated capture is NUL-terminated (#69).
- `write_file` maps to the intended path instead of the first existing ancestor, so a nested path cannot truncate a workspace file treated as a directory or overwrite a same-named file in a parent (#67). Leaf workspace symlinks (dangling or an in-workspace alias) are rejected (`lstat` + `O_NOFOLLOW`) instead of creating host files outside the workspace (#90).
- `write_file` persists via unique temp (`mkstemp`)+fsync+rename so a failed write cannot wipe an existing workspace file and a sibling `path.tmp` is not truncated (#78).
- Skill create/update persist via unique temp (`mkstemp`)+fsync+rename so a failed write cannot wipe an existing skill file (#77).
- Camera capture fails closed when `workspace_only` is on with an empty `workspace_path`, and rejects leaf symlink outputs (#91, #90).
- Cron job `schedule` and `message` are delivered as full SQLite TEXT instead of truncating to 127/511 bytes (#73).
- Cron jobs are committed (delete/advance) only after successful agent delivery, so a failed `agent_run` cannot drop a reminder (#57).
- Recurring cron jobs search the next run from the following minute with a 366-day window; ack fail-closes unparseable schedules to now+365d so they cannot re-fire every poll (#65).
- Cron `/reset` and `/status` jobs are acked after a successful channel send, matching the agent-run path, so they cannot stay due and re-fire every poll.
- `cron_poll` honors `timeout_ms` before re-offering the same still-due job (process-local; the DB is not mutated) so a failed delivery cannot busy-spin the daemon.
- Cron `schedule` and `message` TEXT is rejected above 32 KiB at create and at read, instead of unbounded `strdup`.
- Discord Gateway RX grows for the trailing NUL so two 64 KiB libwebsockets fragments cannot write one byte past the heap block (typical READY payloads).
- WebChat inbound WS `rx_buffer_size` is `WS_RX_BUFFER_SIZE` (`WS_TEXT_MAX` plus JSON envelope) so dashboard messages are not split across 256-byte RECEIVE callbacks and dropped.
- WebChat WebSocket sends now accept agent replies up to 32 KiB (`WS_TEXT_MAX`, matching `RESPONSE_BUF_SIZE`) instead of silently dropping payloads above 8 KiB. Dest buffers are `WS_TEXT_BUF_SIZE` so a max-length payload keeps its NUL; a too-large frame is logged instead of skipped with `<`.
- Memory injection is skipped when the system prompt already fills its 64 KiB buffer, instead of writing the full `Relevant memories` prefix past the allocation after clamping recall to 0.
- Session JSON that would exceed the 128 KiB cap is refused instead of truncated, so the next parse cannot wipe history. An oversized stored blob is left in place (distinct `SESSION_LOAD_TOO_LARGE`) rather than replaced by a later small turn.
- Multi-round ReAct copies tool results into the in-flight message list so a later round cannot overwrite earlier outputs.
- `memory_init` no longer deletes an existing SQLite DB when `sqlite3_open` fails (permissions or transient I/O).
- Anthropic `content` parse fails closed when growing the text buffer or `tool_use` array cannot `realloc`, instead of copying against an inflated cap.
- HTTP 200 JSON-RPC results with a malformed ASAP envelope no longer double-free the duplicated request id.
- `POST /asap` honors the 1 MiB dynamic body cap instead of 413'ing envelopes above the 64 KiB static `PUT /api/config` buffer.
- Inbound ASAP `mcp.tool_call` and `state.query` now hold `agent_lock()` around tool execute and SQLite `g_db` reads, matching `task.request`.
- Inbound `POST /asap` now wires the process provider and tool table into `asap_ctx`, so `task.request` and `mcp.tool_call` dispatch instead of failing with `server missing cfg or provider`.
- `POST /asap` rejects serialized JSON-RPC larger than the 64 KiB gateway HTTP buffer (HTTP 500 / JSON-RPC `-32603`) instead of truncating the body.

### Added
- Discord helper tests reject null MESSAGE_CREATE payloads, bot authors, empty author ids, and guild messages without bot identity so allowlist/mention gating cannot silently widen.
- Phase 5 documentation suite (`docs/SECURITY.md`, `docs/ASAP.md`, and related guides).
- `CONTRIBUTING.md` with PR workflow and pre-tag `gpio-mockup` ritual.
- Jetson-aware `[hardware]` defaults in `config.example.toml` and `.env.example`.

### Changed
- Discord `MESSAGE_CREATE` routing calls `discord_helpers_route_message_create` so helper allowlist/mention tests cover live gating; empty content, strdup, and queue stay in `discord.c`.
- `main` is the active line. On-device Jetson sign-off is a known pending item, not a merge gate ([`docs/JETSON_SIGNOFF.md`](docs/JETSON_SIGNOFF.md)).
- Gateway `/health` `version` matches `SHELLCLAW_RELEASE_VERSION`.

### Security
- Inbound ASAP response builder no longer double-frees the payload cJSON when a required envelope field cannot be allocated (unauthenticated `POST /asap` `state.query` / `task.cancel`).
- `auth_pair` persists tokens via unique temp (`mkstemp`)+fsync+rename so a failed write cannot wipe `auth_tokens.json` (#71).
- `auth_pair` fails closed when bearer RNG fails (no uninitialized token, no tokens-file write, pairing code kept) (#92).
- Gateway shutdown joins the HTTP thread before `auth_cleanup`, so in-flight `/api/*`, `/pair`, and WebSocket upgrades cannot call `auth_validate_token` / `auth_pair` on a freed `auth_ctx`.
- Gateway listen bind now uses `gateway.host` (`lws` `info.iface`). `host = "127.0.0.1"` is loopback-only. Bind-all forms (`0.0.0.0`, `*`, `::`, `[::]`, empty) require `allow_bind_all`.
- Camera auto-output keeps the exclusive `mkstemp` inode (no unlink + `${tmpl}.jpg` sibling).
- Reject I2C `bus` outside 0–255 at the tool JSON boundary.
- Document that protocol-public `POST /asap` can invoke local tools; production must set `[asap].trusted_senders` before exposing the gateway.

---

Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ ShellClaw is C99/C11. Follow the project rule files (summarized here — full de
- New tools → `src/tools/<name>.c` + `tests/test_<name>.c` + Makefile target.
- New hardware backend → `src/hardware/` with board-specific code under `src/hardware/boards/`.
- Config and secrets via TOML + environment variables only — see [`.env.example`](.env.example).
- Thread safety: inbound HTTP/WebSocket paths must use `agent_lock()` / `agent_unlock()` around `agent_run()` (see README § Thread Safety).
- Thread safety: inbound HTTP/WebSocket paths must use `agent_lock()` / `agent_unlock()` around `agent_run()`, inbound ASAP `mcp.tool_call` execute, and `state.query` memory-store reads (see README § Thread Safety).

## Testing

Expand Down
Loading
Loading