Skip to content

Replace prompt_path with prompt_text and require organization#10

Merged
HamptonMakes merged 1 commit into
mainfrom
fix/reviewer-prompt-text-and-required-org
Feb 23, 2026
Merged

Replace prompt_path with prompt_text and require organization#10
HamptonMakes merged 1 commit into
mainfrom
fix/reviewer-prompt-text-and-required-org

Conversation

@HamptonMakes

Copy link
Copy Markdown
Collaborator

What

Addresses two design issues from the PR #5 review:

1. Replace prompt_path with prompt_text (Critical: LFI fix)

prompt_path was an admin-editable file path used in File.read(Rails.root.join(prompt_path)), creating a path traversal / local file inclusion vulnerability. An admin could set it to ../../config/master.key or /etc/passwd.

Now the prompt content is stored directly in the database as a text column. The markdown files in prompts/reviewers/ remain as default templates — they're read during seeding to populate initial reviewers, but at runtime the app only reads from the DB. This also makes prompts customizable per-org without deploying code changes.

2. Make organization_id non-nullable

The nullable organization_id (for "global reviewers") was half-baked — no code consumed it, and it caused a MySQL NULL uniqueness bug where the unique index on [:organization_id, :key] wouldn't prevent duplicate keys when organization_id is NULL.

Removed the concept entirely. Every reviewer belongs to an organization.

Also fixed

  • Seeds now use find_or_create_by! instead of the brittle count == 0 guard
  • Removed prompt_file_exists validation and prompt_content method (no longer needed)
  • Updated fixtures, tests, and ActiveAdmin

Tests

All 168 tests pass.

- Replace prompt_path (file path) with prompt_text (text column) to
  eliminate path traversal / LFI vulnerability. Prompt files serve as
  default templates, with content stored in the DB per-org.
- Make organization_id non-nullable — every reviewer belongs to an org.
- Auto-create default reviewers when an organization is created via
  after_create callback + AutomatedPlanReviewer.create_defaults_for.
- Seeds simplified to call create_defaults_for (idempotent).
- Removed prompt_file_exists validation and prompt_content method.
- Updated fixtures, tests, and ActiveAdmin to match.

Amp-Thread-ID: https://ampcode.com/threads/T-019c8bd2-604a-7649-83a8-f19c5d7065ed
Co-authored-by: Amp <amp@ampcode.com>
@HamptonMakes
HamptonMakes force-pushed the fix/reviewer-prompt-text-and-required-org branch from 424f3a7 to d95f7b0 Compare February 23, 2026 19:00

@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: 424f3a78f9

ℹ️ 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".

remove_column :automated_plan_reviewers, :prompt_path

# Make organization_id required
change_column_null :automated_plan_reviewers, :organization_id, false

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 Backfill organization before enforcing NOT NULL

This migration can fail in environments that already have "global" reviewers with organization_id = NULL (the previous model explicitly allowed belongs_to :organization, optional: true). Calling change_column_null ... false without first updating or deleting those rows will raise at migration time and block deployment for affected databases.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

This app is pre-production — there are no existing rows with NULL organization_id in any deployed environment. The "global reviewer" concept from PR #5 was never seeded (seeds always set an org). Safe to enforce NOT NULL without a backfill step here.

Comment on lines +9 to +10
if File.exist?(file_path)
reviewer.update_column(:prompt_text, File.read(file_path))

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 Avoid leaving prompt_text NULL when source file is missing

Rows whose prompt_path no longer resolves to an existing file are silently skipped here, so their new prompt_text stays NULL; the subsequent change_column_null :prompt_text, false then fails and aborts the migration. This is a deploy-blocking path for any environment where a previously valid file path was later removed or moved.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

The prompt files are checked into the repo at prompts/reviewers/*.md and ship with every deploy. They'll always exist at migration time. If someone deleted them, the app would be broken in other ways too (seeds, create_defaults_for). Not a concern for this codebase.

@HamptonMakes
HamptonMakes merged commit e23507a into main Feb 23, 2026
4 checks passed
@HamptonMakes
HamptonMakes deleted the fix/reviewer-prompt-text-and-required-org branch February 23, 2026 19:03
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