Skip to content

fix: path traversal in init agent + FK cascade for event pruning - #1070

Merged
namastex888 merged 1 commit into
devfrom
fix/pr-review-gaps
Apr 5, 2026
Merged

namastex888 merged 1 commit into
devfrom
fix/pr-review-gaps

Conversation

@namastex888

Copy link
Copy Markdown
Contributor

Summary

Two fixes from bot review findings on PR #1059 (rolling promotion):

[CRITICAL] Path traversal in genie init agent

genie init agent <name> passed CLI input directly to join(baseDir, name) without validation. Names like ../outside or absolute paths would write agent scaffolding to arbitrary filesystem locations.

Fix: Reject names containing /, \, .., or empty strings before they reach the path join.

[HIGH] FK blocks event retention pruning

parent_event_id FK on genie_runtime_events used default NO ACTION delete behavior. When genie db prune-events deletes old parent events, child events referencing them would cause the delete to fail.

Fix: ON DELETE SET NULL — parent can be pruned while children retain their own data with a nulled-out parent reference.

Test plan

  • bun run typecheck — clean
  • bun test — 2163 pass, 0 fail
  • Init tests pass (init-flow.test.ts, init-bootstrap.test.ts)

…t FK

Two fixes from PR #1059 bot review findings:

1. [CRITICAL] src/term-commands/init.ts — genie init agent <name> passed
   CLI input directly to join(baseDir, name) without validation. Names
   like '../outside' or '/etc/passwd' would write to arbitrary paths.
   Added guard rejecting names with path separators or traversal sequences.

2. [HIGH] src/db/migrations/026_events_trace_id.sql — parent_event_id FK
   had no ON DELETE clause (defaults to NO ACTION). This would cause
   genie db prune-events to fail when deleting parent events still
   referenced by children. Changed to ON DELETE SET NULL so pruning
   works and child events retain their own data.
@coderabbitai

coderabbitai Bot commented Apr 5, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 7d61468c-2ced-4791-96b7-4b2aadfbb5a0

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/pr-review-gaps

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a2b626a11f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".


ALTER TABLE genie_runtime_events ADD COLUMN IF NOT EXISTS trace_id UUID;
ALTER TABLE genie_runtime_events ADD COLUMN IF NOT EXISTS parent_event_id BIGINT REFERENCES genie_runtime_events(id);
ALTER TABLE genie_runtime_events ADD COLUMN IF NOT EXISTS parent_event_id BIGINT REFERENCES genie_runtime_events(id) ON DELETE SET NULL;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Add a new migration instead of editing 026 in place

Changing 026_events_trace_id.sql in place will not fix existing databases that already applied migration 026, because runMigrations skips applied migrations by filename (_genie_migrations name check in src/lib/db-migrations.ts). In those environments the FK remains NO ACTION, so genie db prune-events can still fail when deleting parent rows. This needs a follow-up migration (e.g., 027_...) that explicitly alters the existing parent_event_id constraint to ON DELETE SET NULL.

Useful? React with 👍 / 👎.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request updates a database migration to include ON DELETE SET NULL for parent event IDs and adds path traversal protection for agent names in the CLI. Feedback highlights the need for an index on the foreign key to prevent performance degradation during pruning and suggests hardening the agent name validation to prevent potential YAML injection via newlines.


ALTER TABLE genie_runtime_events ADD COLUMN IF NOT EXISTS trace_id UUID;
ALTER TABLE genie_runtime_events ADD COLUMN IF NOT EXISTS parent_event_id BIGINT REFERENCES genie_runtime_events(id);
ALTER TABLE genie_runtime_events ADD COLUMN IF NOT EXISTS parent_event_id BIGINT REFERENCES genie_runtime_events(id) ON DELETE SET NULL;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

Adding a foreign key with ON DELETE SET NULL is correct for the stated goal, but deleting parent records during pruning will trigger a sequential scan of the genie_runtime_events table to find and update child records if an index on parent_event_id is missing. For a table that requires pruning, this will cause significant performance degradation as the table grows.

Additionally, note that ALTER TABLE ... ADD COLUMN IF NOT EXISTS will skip the entire clause if the column already exists. If this migration has already been applied to any environment (e.g., from a previous version of the PR), the ON DELETE SET NULL behavior will not be added. If you need to support existing databases where this column might already exist without the constraint, consider a separate ALTER TABLE ... ADD CONSTRAINT statement.

ALTER TABLE genie_runtime_events ADD COLUMN IF NOT EXISTS parent_event_id BIGINT REFERENCES genie_runtime_events(id) ON DELETE SET NULL;
CREATE INDEX IF NOT EXISTS idx_runtime_events_parent_event_id ON genie_runtime_events(parent_event_id) WHERE parent_event_id IS NOT NULL;

Comment thread src/term-commands/init.ts
/** genie init agent <name> — scaffold agent directory */
async function initAgent(name: string, options: { dir?: string }): Promise<void> {
// Guard against path traversal — name is CLI input and lands in join(baseDir, name)
if (!name || /[\/\\]/.test(name) || name === '.' || name === '..' || name.includes('..')) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

security-medium medium

The path traversal check is effective, but the name is also used directly in the YAML frontmatter of the generated AGENTS.md file. If the name contains newlines, it could result in invalid YAML or broken file content. Consider adding a check for newlines or using a more restrictive identifier pattern.

Also, name === '..' is redundant as it is already covered by name.includes('..').

Suggested change
if (!name || /[\/\\]/.test(name) || name === '.' || name === '..' || name.includes('..')) {
if (!name || /[\\/\\\\\\r\\n]/.test(name) || name === '.' || name.includes('..')) {

@namastex888
namastex888 merged commit 9c4878e into dev Apr 5, 2026
9 of 12 checks passed
@namastex888
namastex888 deleted the fix/pr-review-gaps branch April 10, 2026 16:16
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