Skip to content

fix(devkitd): close duplicate-name holes in agent.start - #418

Open
codeaholicguy wants to merge 2 commits into
mainfrom
fix/agent-start-duplicate-name
Open

codeaholicguy wants to merge 2 commits into
mainfrom
fix/agent-start-duplicate-name

Conversation

@codeaholicguy

Copy link
Copy Markdown
Owner

Summary

Fixes a duplicate-name hole in agent.start: a name registered via the fallback path (AI_DEVKIT_NO_DAEMON or pre-daemon agents) could be claimed again through the daemon.

Root cause — three holes:

  • import_legacy_agents ran once at daemon boot — post-boot legacy registrations were invisible to the name check
  • prune_dead deleted every tombstoned row unconditionally (WHERE gone_at IS NOT NULL), pruning live-pid registrations before the check could see them
  • the name_in_use check required gone_at IS NULL, but imported legacy rows are tombstoned-by-default — a live pid is now sufficient evidence

Fix:

  • Re-import inside start_mutex before the name check
  • prune_dead only deletes tombstones whose pids are actually dead
  • pid_alive alone decides name_in_use (matches TS prune semantics)
  • pid_alive moved to devkit-core (needed by prune_dead; agent.stop will use it too)

Closes #417

Test plan

  • cargo test --workspace — 135 pass, 0 fail
  • cargo clippy --workspace --all-targets -- -D warnings clean
  • cargo fmt --check clean
  • New regression tests: tombstoned_but_live_pid_still_blocks_name, legacy_row_written_after_daemon_boot_blocks_name (reproduces the reported scenario)
  • Manual repro: AI_DEVKIT_NO_DAEMON=1 start → daemon start with same name → expect name_in_use

A name registered via the fallback path (AI_DEVKIT_NO_DAEMON or
pre-daemon agents) could be claimed again through the daemon:

- import_legacy_agents only ran at daemon boot — post-boot legacy
  registrations were invisible to the name check. Now re-imports inside
  the start mutex before lookup_name.
- prune_dead deleted every tombstoned row without checking pid liveness,
  pruning live-pid registrations before the check could see them. It now
  deletes only tombstones whose pids are actually dead.
- the name-in-use check required gone_at IS NULL, but imported legacy
  rows are tombstoned-by-default — a live pid is now sufficient evidence
  regardless of gone_at (matches TS prune semantics).

pid_alive moves to devkit-core (prune_dead needs it; agent.stop will).
Regression tests cover both holes; rusqlite added as devkitd dev-dep
for the legacy-db fixture.
pid 10 is a live kernel thread on Linux, so prune_dead's new liveness
check kept the tombstone and the name reuse hit UNIQUE constraint.
i32::MAX is above every pid_max — dead on any platform.

This branch has not been deployed

No deployments
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.

fix(devkitd): agent.start allows duplicate names for fallback-registered agents

1 participant