Skip to content

Fix scheduled Kimaki dispatch user mismatch#241

Merged
chubes4 merged 1 commit into
mainfrom
fix/kimaki-cron-user-mismatch
Jun 21, 2026
Merged

Fix scheduled Kimaki dispatch user mismatch#241
chubes4 merged 1 commit into
mainfrom
fix/kimaki-cron-user-mismatch

Conversation

@chubes4

@chubes4 chubes4 commented Jun 21, 2026

Copy link
Copy Markdown
Member

Summary

  • register VPS Kimaki dispatch through a stable sudo wrapper instead of direct private-home binaries
  • install root-owned dispatch target and sudoers rule so www-data can dispatch as the adopted service user
  • add regression coverage for service-user VPS channel registration

Fixes #240.

Tests

  • ==> register Homeboy Codebox guidance
    ok guidance mu-plugin parses with php -l
    ok mu-plugin mode 0644 after fresh write under umask 077
    ok Homeboy Codebox block present
    ==> re-register Homeboy Codebox guidance (idempotent)
    ok file unchanged on re-register
    ==> invalid public API inputs fail before writing broken PHP
    ok invalid section id rejected
    ok invalid priority rejected
    ok invalid sync availability rejected
    ==> skip registration when Data Machine core gate is unavailable
    ok SectionRegistry receives no wp-coding-agents guidance without core AGENTS gate
    ==> apply datamachine_sections action and inspect SectionRegistry call
    ok SectionRegistry receives Homeboy Codebox guidance section
    ==> unregister Homeboy Codebox guidance
    ok mu-plugin mode 0644 after unregister
    ok Homeboy Codebox block removed
    ok post-unregister file parses with php -l

OK: all AGENTS.md guidance assertions passed
==> existing gateway env is reused instead of rotated
�[0;32m[wp-coding-agents]�[0m Reusing existing WP AI Gateway token reference at /var/folders/lr/c_cmmt7s0592m4njz99v5yb40000gn/T/tmp.ZPlhL8Kpkd/site/.opencode/wp-ai-gateway.env
ok existing token preserved
ok base URL refreshed
==> dry-run redacts gateway token material
ok dry-run does not print existing token
ok dry-run does not print fake token
ok dry-run leaves env token untouched
==> unit/plist dry-run diffs redact secrets
ok systemd-style secret redacted
ok plist-style secret redacted
==> Kimaki launchd inherits gateway environment
ok launchd includes gateway base URL
ok launchd includes gateway key
==> recursive gateway topologies are rejected in wp-coding-agents
ok recursive provider rejected
ok recursive provider-qualified model rejected
==> opencode.json merge uses OpenCode custom provider shape
�[0;32m[wp-coding-agents]�[0m Merged WP AI Gateway provider into /var/folders/lr/c_cmmt7s0592m4njz99v5yb40000gn/T/tmp.ZPlhL8Kpkd/site/opencode.json
�[0;32m[wp-coding-agents]�[0m OpenCode env file: /var/folders/lr/c_cmmt7s0592m4njz99v5yb40000gn/T/tmp.ZPlhL8Kpkd/site/.opencode/wp-ai-gateway.env

OK: 11 / 11 assertions passed
==> rendering snapshots
==> diffs
ok cc-connect-launchd
ok cc-connect-systemd
ok kimaki-launchd
ok kimaki-systemd
ok telegram-bot-launchd
ok telegram-bot-systemd
ok telegram-serve-launchd
ok telegram-serve-systemd

OK: all snapshots match
PASS: tests/carried-claude-code-plugin.sh
==> _kimaki_path_is_web_traversable ancestor checks
ok accepts 0755-ancestor path
ok rejects 0700-ancestor (/root) path
ok rejects 0750-ancestor (/home/opencode) path
==> _kimaki_find_native_binary prefers reachable PATH entry
ok skips 0700 wrapper, returns reachable binary
==> _kimaki_register_cli_channel ignores trapped KIMAKI_BIN on local installs
ok trapped KIMAKI_BIN ignored; registered reachable /tmp/wpca-cli-channel.7cAiDT/reachable/bin/kimaki
==> _kimaki_register_cli_channel uses wrapper for service-user VPS installs
ok VPS channel registers sudo dispatch wrapper
==> registered command is web-traversable
ok registered command '/tmp/wpca-cli-channel.7cAiDT/reachable/bin/kimaki' is web-traversable
ok reachable KIMAKI_BIN still honored (no regression)

OK: all cli-channel binary-path assertions passed
==> register kimaki (fresh scaffold, umask 077)
ok fresh scaffold lands as 0644 under umask 077
==> simulate legacy 0600 file and verify self-heal on next register
ok mu-plugin self-healed to 0644 after sibling register
==> unregister opencode-telegram
ok mu-plugin mode 0644 after unregister

OK: all cli-channel perms assertions passed
ok transport mu-plugin written
ok transport mu-plugin matches template
ok transport mu-plugin mode 0644
ok transport mu-plugin mode 0644
OK: CLI transport install assertions passed
OK: existing-site domain detection scopes Studio WP-CLI to the site path and falls back when empty
==> homeboy present: emit generated CLI command map
ok guidance mu-plugin parses with php -l (present)
ok homeboy-cli block present
==> inspect generated section via datamachine_sections action
ok SectionRegistry receives generated Homeboy CLI map
==> re-sync with homeboy present (idempotent)
ok file unchanged on re-sync
==> homeboy absent: complete no-op (section removed, no stub)
ok homeboy-cli block removed when homeboy absent
ok no absent-homeboy stub emitted
ok post-no-op file parses with php -l

OK: all Homeboy CLI command-map assertions passed
OK: Homeboy Codebox canary command construction
OK: Homeboy component attachment prunes stale worktrees and skips metadata-less repos
OK: Homeboy project id resolves local Studio site by base_path
OK: Kimaki native fallback replaces local agent normalization
PASS: tests/kimaki-launchd-start.sh
PASS kimaki managed-plugin rig arg parser self-test
PASS kimaki managed-plugin rig
Artifacts: /var/folders/lr/c_cmmt7s0592m4njz99v5yb40000gn/T/tmp.vqlGVJMVC8/artifacts
OK: Kimaki managed-plugin rig
PASS: tests/opencode-local-plugin-path.sh
==> legacy wrapper is removed and real binary linked back
ok wrapper sentinel removed
ok stale .bak file removed
ok global opencode runs the real binary
ok rerun is idempotent
==> non-wrapper binaries are never touched
ok non-wrapper binary untouched
==> repo no longer ships legacy install machinery
ok lib/patch-claude-auth.py is gone
ok runtimes/opencode.sh has no _install_opencode_wrapper
ok runtimes/opencode.sh has no _patch_claude_auth_plugin
ok runtimes/opencode.sh does not list opencode-claude-auth as a managed plugin
ok lib/repair-opencode-json.py does not append opencode-claude-auth
ok upgrade.sh has no reapply_claude_auth_patch
ok upgrade.sh wires the removal phase

OK: 12 / 12 assertions passed
==> _compose_path_value
ok single dir
ok two distinct dirs
ok drops duplicate (npm-global case: kimaki and node share dir)
ok drops empty entries (no node found)
ok preserves first-occurrence order
ok all empty
==> _resolve_node_bin_dir
ok follows kimaki shim when no node on PATH (nvm case)
ok uses command -v when node is on PATH
ok empty when no node anywhere
ok empty when shim references missing node binary
ok no-hint: uses command -v

OK: 11 / 11 assertions passed
PASS: tests/post-upgrade-restore.sh (6 lines run1, 5 lines run3)
OK: repair-opencode-json removes managed agent shells and repairs local plugin paths
==> register opencode (fresh scaffold, umask 077)
ok mu-plugin created
ok scaffold parses with php -l
ok mu-plugin mode 0644 after fresh write under umask 077
ok opencode block present
==> re-register opencode with same signature (idempotent)
ok file unchanged on re-register
==> simulate legacy 0600 file and verify self-heal on next register
ok two-runtime file parses with php -l
ok mu-plugin mode self-healed to 0644 after sibling register
ok both runtime blocks present
==> re-register opencode with mutated signature
ok opencode block updated
ok kimaki block preserved across opencode mutation
==> unregister kimaki
ok kimaki block removed
ok opencode block preserved across kimaki unregister
ok post-unregister file parses with php -l
ok mu-plugin mode 0644 after unregister
==> apply_filters returns the expected shape
ok filter returns surviving opencode signature

OK: all runtime-signature assertions passed
==> adoption: root default + opencode unit -> opencode
�[0;32m[wp-coding-agents]�[0m Adopting service identity from kimaki.service: User=opencode (script default was root)
ok SERVICE_USER adopted from unit
ok RUN_AS_ROOT flipped to false
ok SERVICE_HOME re-derived
ok KIMAKI_DATA_DIR re-derived
==> adoption: no-op when unit matches script default
ok matching user unchanged
ok matching home unchanged
==> adoption: skipped when SERVICE_USER_FORCED=true
ok forced identity not overridden
==> adoption: skipped in LOCAL_MODE
ok local mode untouched
==> umask preservation
ok UMask carried into env block
ok env lines retained alongside UMask
ok no UMask -> env block unchanged
==> end-to-end: re-render after adoption keeps User=opencode + UMask
�[0;32m[wp-coding-agents]�[0m Adopting service identity from kimaki.service: User=opencode (script default was root)
ok rendered unit keeps User=opencode
ok rendered unit does NOT flip to root
ok rendered unit keeps UMask=0002
ok pkill scoped to adopted user
==> #232: binary resolution follows adopted identity (root invoker + opencode unit)
�[0;32m[wp-coding-agents]�[0m Adopting service identity from kimaki.service: User=opencode (script default was root)
ok resolved bin is under adopted SERVICE_HOME
ok resolved bin is NOT under /root
ok system-prefix binary preferred over per-user home
==> #232: identity guard warns on a /root binary under an opencode unit
ok guard warns on /root ExecStart binary
ok guard warns on /root PATH segment
ok guard silent on consistent opencode identity
ok guard silent on system-prefix binary

OK: all 22 service-identity adoption assertions passed
wp-codebox-subtree tests passed
=== smoke-cli-transport ===
[PASS] valid entry normalizes
[PASS] missing command is rejected
[PASS] non-string arg is rejected
[PASS] legacy option channel is present
[PASS] new option channel is present
[PASS] legacy filter channel is present
[PASS] new filter channel is present
[PASS] new registry wins collisions
[PASS] message token substituted verbatim
[PASS] conversation token substituted
[PASS] claims registered channel
[PASS] declines unknown channel
[PASS] preserves prior handler
[PASS] sync success returns array
[PASS] sync success captures stdout
[PASS] sync true succeeds
[PASS] nonzero exit returns WP_Error
[PASS] timeout returns WP_Error
[PASS] execute unknown returns WP_Error
[PASS] detached returns array
[PASS] detached early exit returns WP_Error
[PASS] empty channel env inherits parent env
[PASS] configured channel env keeps parent env
[PASS] configured channel env adds configured env
[PASS] unwritable inherited HOME is not leaked
[PASS] guarded channel still inherits other parent env
[PASS] pinned writable HOME wins over poisoned inherited HOME

OK

AI assistance

  • AI assistance: Yes
  • Tool(s): openai/gpt-5.5 via OpenCode
  • Used for: Root-cause verification, code changes, regression test updates, and local test execution.

@chubes4 chubes4 merged commit dcf0ef0 into main Jun 21, 2026
12 checks passed
@chubes4 chubes4 deleted the fix/kimaki-cron-user-mismatch branch June 21, 2026 23:26
@chubes4 chubes4 mentioned this pull request Jun 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant