fix(api,e2e): finish Sandbox → Box rename — 3 schema gaps + fixture column names#720
Conversation
📝 WalkthroughWalkthroughThis PR finalizes a sandbox→box schema rename by introducing a post-deploy database migration that conditionally renames two table columns and updates a PostgreSQL enum label, while adjusting the e2e test fixture to target the renamed per-box quota limits. ChangesSchema migration sandbox→box rename completion
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Possibly related issues
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
…column names Migration1781016743403 (PR boxlite-ai#706) renamed most sandbox-vocabulary objects to box-vocabulary equivalents but missed three pieces; the API and runner crashed on every box-touching path until those caught up. fixture_setup also still wrote the old organization-quota column names. Schema gaps added in a follow-up post-deploy migration: - `runner.currentStartedSandboxes` -> `currentStartedBoxes` - `organization.sandboxLimitedNetworkEgress` -> `boxLimitedNetworkEgress` - `job_resourcetype_enum` value `SANDBOX` -> `BOX` Symptoms before the fix: - ResourceManager / SnapshotManager queries: `column Runner.currentStartedBoxes does not exist` - Box service create path: `column Organization.boxLimitedNetworkEgress does not exist` - Runner job poll: `invalid input value for enum job_resourcetype_enum: "BOX"` - fixture_setup: `column "max_cpu_per_sandbox" of relation "organization" does not exist` Each migration step is guarded with a state check (`information_schema` / `pg_enum`), so partial-state environments are safe to re-run and the migration is idempotent on hosts where someone has already hand-applied any of the three renames. The down() restores the previous names. Verified locally: applied the migration to a partial-state DB; API + runner come up clean; `scripts/test/e2e/cases/test_unread_stream_back_pressure.py` (3 cases) and existing e2e cases pass against the restored stack. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2e3587a to
9a53ec8
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/api/src/migrations/post-deploy/1781072797240-migration.ts`:
- Around line 108-113: In down(), the ALTER TABLE ... RENAME COLUMN statements
are not safe if the source column is missing; before running the rename via
queryRunner.query, first check for the source column's existence using a SELECT
against information_schema.columns (or pg_catalog) and only execute the ALTER
for organization when "sandboxLimitedNetworkEgress" exists and for runner when
"currentStartedSandboxes" exists; update the two rename sites in the down()
function (the queryRunner.query calls that currently rename
"sandboxLimitedNetworkEgress" -> "boxLimitedNetworkEgress" and
"currentStartedSandboxes" -> "currentStartedBoxes") to perform this conditional
check and skip the ALTER if the column is absent so rollbacks remain idempotent.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 29ecdae3-dcde-4192-8616-e3cb52f84717
📒 Files selected for processing (2)
apps/api/src/migrations/post-deploy/1781072797240-migration.tsscripts/test/e2e/fixture_setup.py
| await queryRunner.query( | ||
| `ALTER TABLE IF EXISTS "organization" RENAME COLUMN "boxLimitedNetworkEgress" TO "sandboxLimitedNetworkEgress"`, | ||
| ) | ||
| await queryRunner.query( | ||
| `ALTER TABLE IF EXISTS "runner" RENAME COLUMN "currentStartedBoxes" TO "currentStartedSandboxes"`, | ||
| ) |
There was a problem hiding this comment.
down() column renames are not safely guarded for partial-state rollbacks.
ALTER TABLE IF EXISTS ... RENAME COLUMN ... only guards table existence. If the table exists but the source column is absent, rollback fails. This breaks the intended idempotent/safe rollback behavior for mixed states.
Suggested fix
- await queryRunner.query(
- `ALTER TABLE IF EXISTS "organization" RENAME COLUMN "boxLimitedNetworkEgress" TO "sandboxLimitedNetworkEgress"`,
- )
- await queryRunner.query(
- `ALTER TABLE IF EXISTS "runner" RENAME COLUMN "currentStartedBoxes" TO "currentStartedSandboxes"`,
- )
+ await queryRunner.query(`
+ DO $$
+ BEGIN
+ IF EXISTS (
+ SELECT 1 FROM information_schema.columns
+ WHERE table_name = 'organization' AND column_name = 'boxLimitedNetworkEgress'
+ ) AND NOT EXISTS (
+ SELECT 1 FROM information_schema.columns
+ WHERE table_name = 'organization' AND column_name = 'sandboxLimitedNetworkEgress'
+ ) THEN
+ ALTER TABLE "organization"
+ RENAME COLUMN "boxLimitedNetworkEgress" TO "sandboxLimitedNetworkEgress";
+ END IF;
+ END $$;
+ `)
+ await queryRunner.query(`
+ DO $$
+ BEGIN
+ IF EXISTS (
+ SELECT 1 FROM information_schema.columns
+ WHERE table_name = 'runner' AND column_name = 'currentStartedBoxes'
+ ) AND NOT EXISTS (
+ SELECT 1 FROM information_schema.columns
+ WHERE table_name = 'runner' AND column_name = 'currentStartedSandboxes'
+ ) THEN
+ ALTER TABLE "runner"
+ RENAME COLUMN "currentStartedBoxes" TO "currentStartedSandboxes";
+ END IF;
+ END $$;
+ `)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| await queryRunner.query( | |
| `ALTER TABLE IF EXISTS "organization" RENAME COLUMN "boxLimitedNetworkEgress" TO "sandboxLimitedNetworkEgress"`, | |
| ) | |
| await queryRunner.query( | |
| `ALTER TABLE IF EXISTS "runner" RENAME COLUMN "currentStartedBoxes" TO "currentStartedSandboxes"`, | |
| ) | |
| await queryRunner.query(` | |
| DO $$ | |
| BEGIN | |
| IF EXISTS ( | |
| SELECT 1 FROM information_schema.columns | |
| WHERE table_name = 'organization' AND column_name = 'boxLimitedNetworkEgress' | |
| ) AND NOT EXISTS ( | |
| SELECT 1 FROM information_schema.columns | |
| WHERE table_name = 'organization' AND column_name = 'sandboxLimitedNetworkEgress' | |
| ) THEN | |
| ALTER TABLE "organization" | |
| RENAME COLUMN "boxLimitedNetworkEgress" TO "sandboxLimitedNetworkEgress"; | |
| END IF; | |
| END $$; | |
| `) | |
| await queryRunner.query(` | |
| DO $$ | |
| BEGIN | |
| IF EXISTS ( | |
| SELECT 1 FROM information_schema.columns | |
| WHERE table_name = 'runner' AND column_name = 'currentStartedBoxes' | |
| ) AND NOT EXISTS ( | |
| SELECT 1 FROM information_schema.columns | |
| WHERE table_name = 'runner' AND column_name = 'currentStartedSandboxes' | |
| ) THEN | |
| ALTER TABLE "runner" | |
| RENAME COLUMN "currentStartedBoxes" TO "currentStartedSandboxes"; | |
| END IF; | |
| END $$; | |
| `) |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/api/src/migrations/post-deploy/1781072797240-migration.ts` around lines
108 - 113, In down(), the ALTER TABLE ... RENAME COLUMN statements are not safe
if the source column is missing; before running the rename via
queryRunner.query, first check for the source column's existence using a SELECT
against information_schema.columns (or pg_catalog) and only execute the ALTER
for organization when "sandboxLimitedNetworkEgress" exists and for runner when
"currentStartedSandboxes" exists; update the two rename sites in the down()
function (the queryRunner.query calls that currently rename
"sandboxLimitedNetworkEgress" -> "boxLimitedNetworkEgress" and
"currentStartedSandboxes" -> "currentStartedBoxes") to perform this conditional
check and skip the ALTER if the column is absent so rollbacks remain idempotent.
Bug
Migration1781016743403 (#706) renamed most sandbox-vocabulary objects to
box-vocabulary equivalents but missed three pieces, leaving the schema
inconsistent with the renamed TypeORM entities and TS enum. Every box-
touching API path crashed until I added the catch-up rename below;
fixture_setup also still wrote the old organization-quota column names.
runner.currentStartedSandboxescurrentStartedBoxes, no schema migrationorganization.sandboxLimitedNetworkEgressboxLimitedNetworkEgress, no schema migrationjob_resourcetype_enumvalueSANDBOXResourceType.BOX = 'BOX', Postgres enum still only knows 'SANDBOX'scripts/test/e2e/fixture_setup.pymax_cpu_per_sandbox/max_memory_per_sandbox/max_disk_per_sandbox(#706's main migration already renamed those columns tomax_*_per_box)Fix
New post-deploy migration
Migration1781072797240performs the threeschema renames the original missed. Each step is guarded with an
information_schema/pg_enumstate check, so partial-stateenvironments are safe to re-run and the migration is idempotent on
hosts where someone has already hand-applied any of the three renames.
fixture_setup.pyis updated to use the new column names.Test plan
Verified locally on a partial-state DB:
fixture_setup 500 on quota patch.
migrationsrow recorded.No down() change to data — the down() just inverts the renames so the
migration is reversible if needed. Each down step is also guarded.
🤖 Generated with Claude Code
Summary by CodeRabbit
Chores
Tests