Security
- The
/octopusissue-comment workflow now requires a trusted author. The job heldissues: writeandpull-requests: writeand spent the repository's provider API keys for any GitHub user who could comment; it is now gated onauthor_associationbeing OWNER, MEMBER, or COLLABORATOR, matching the guard the siblingpr-reviewjob already had. enable-http-telemetry.shno longer accepts the bearer token on the command line. A token in argv lands in shell history and is readable viapsby every local process. The token is read fromOCTOPUS_TELEMETRY_BEARER_TOKEN, and writing it into the Git-trackedhooks/hooks.jsonnow requires--allow-plaintext-token. Breaking: the second positional argument is rejected with an explanatory error.- The sysadmin safety gate covers macOS home paths. Its
rm -rfpath list was Linux-only (/home), sorm -rf /Users/<you>/...passed unchallenged on the project's primary platform./Users,/Library,/System,/Applicationsand a barerm -rf /are now caught. run_commandin the OpenAI-compatible agent has guardrails.read_file/write_filewere confined to the working directory while the shell tool could reach anything the invoking user could. Privilege escalation, download-and-execute, credential-file reads, raw device writes and absolute-path recursive deletes are refused. SetOPENAI_COMPAT_UNSAFE_COMMANDS=1to opt out inside a disposable container. This is a guardrail, not a sandbox.resolve_provider_envvalidates the variable name before it reachesbash -candexport.detect_project_quality_commandsshell-quotes the project path in the strings later passed toeval.
Fixed
- A council
agyseat that dies demanding a TTY is salvaged under a pseudo-terminal instead of silently failing. agy is a bubbletea TUI app; in--printmode it is headless, but when it must render an interactive screen anyway — a folder-trust prompt on a brand-new worktree, or an auth flow — it opens/dev/ttyand, in a session with no controlling terminal, dies withbubbletea: could not open TTYbefore producing an answer, sinking the seat.agy-exec.shnow detects that specific failure and retries once under a pseudo-terminal viascript, so the auto-dismissed (--dangerously-skip-permissions) TUI has a terminal to draw on. The fallback is gated on the real error — a blanket no-TTY wrap would fire on every autonomous dispatch (which never has a TTY) and leak the pseudo-terminal's caret-notation echo into the answer — and the salvaged output is stripped of that echo (CR / backspace / EOT / leading caret-notation) so it stays byte-clean for the council response parser. Portable across BSD (script … command) and util-linux (script -c)script; opt out withOCTOPUS_AGY_NO_PTY_FALLBACK=1. - Public release guidance now stays synchronized with repository truth.
make syncupdates the root and plugin READMEs plusPRODUCT.mdfrom plugin
metadata, model resolver defaults, runtime capability gates, and the
changelog;make sync-checkand release preparation reject future drift. - An
xaiprovider allowlist silently denied every grok seat. Thecursor|cursor-agent|xai)arm shadowed the dedicatedxai)arm below it, so onlycursor-agentwas authorised. pr_review_state_classify_findingsnever ran.$previous/$currentwere expanded by the shell before jq received the filter, leaving an unparseable program; the function returned empty at exit 3 for every caller. Its test passed only because the fixture variables happened to share those names.json_extract_multireturned nothing on macOS. It used alocal -nnameref, which needs bash 4.3+, while the project supports bash 3.2 — still/bin/bashon macOS. Audit-log and pending-review output rendered with every field blank. Reimplemented withprintf -v.tangle_verifyleaked a temp directory on every run. Cleanup cleared the caller'sEXITtrap instead of restoring it, discardingorchestrate.sh's own$OCTOPUS_TMP_DIRremoval.- Sourced libraries no longer leak shell options.
provider-allowlist.sh,doctor.shanduser-config.shset-eo pipefailat file scope, which persisted in the sourcing shell — includingproviders.sh, which documents itself as source-safe and is full of probes where a nonzero exit is normal. parse_factory_specno longer depends on dynamic scoping.maturity_jsonwas read out of the caller's frame, so any other caller wrote invalid JSON intosession.json. It is now an explicit argument with a valid default.- Careful mode stopped flagging ordinary pushes.
git push .*-fmatched any branch name containing-f(release-final), and patterns were matched against the entire hook payload rather than the extracted command. - The
enable-http-telemetry.shversion guard compares the major component, so a future Claude Code v3.0.0 is no longer rejected as older than v2.1.63. - The codex smoke probe skips rather than reporting a false negative when it cannot enter its temporary git repository.
- Word-count splitting disables globbing, so a value containing
*no longer expands to matching filenames.
Changed
- The OpenClaw registry is generated from the shipped
skills/payload.build-openclaw.shandskill-loader.tsread.claude/skills/— this repository's own project-local skill set — soskill-councilandskill-verifynever reached OpenClaw users while--checkstayed green by regenerating from the same wrong source. The registry grows from 102 to 104 entries. - ShellCheck is an enforcing CI gate. The step ended in
|| trueand had accumulated 406 unread warnings, two of which pinpointed the allowlist and jq defects above. The codebase is at zero withSC2034,SC2155,SC1090andSC1091excluded as stylistic. - One source of truth for the model-resolution cache path (
scripts/lib/model-cache-path.sh).model-resolver.shhonoured$TMPDIRwhileprovider-routing.shandocto-model-config.shhardcoded/tmp, so on macOS the writer and the invalidatingrm -faddressed different files. set_provider_modelandreset_provider_modelderive their matchers and messages from a singleOCTO_MODEL_CONFIG_PROVIDERSlist; the reset message had already drifted, omittingopenai-compatibleandopenai-tools.
Performance
- Event emission is roughly ten times faster.
octo_event_emitcost ~175 ms per event because each record spawnedpython3five or more times for JSON escaping; a pure-bash fast path handles values without control characters. 100 sequential emits drop from 17.5 s to 1.8 s, andtest-octo-events.shfrom about seven minutes to fifteen seconds.
Tests
- Regression coverage for the allowlist shadowing, the shell-option leak, the trap restore and JSON escaping — each verified to fail when its defect is reintroduced.
test-review-run.shexercises the retry classifier's behaviour instead of grepping the source for its name.test-pr-review-state.shfixture variables are renamed so a name collision can no longer mask a broken jq filter.test-openclaw-compat.shscans the shippedskills/tree as well as.claude/skills/.