Skip to content

[EN-1038] feat(db): add template disk entitlement schema#3286

Merged
gm-e2b merged 1 commit into
mainfrom
db-migration-disk-size
Jul 20, 2026
Merged

[EN-1038] feat(db): add template disk entitlement schema#3286
gm-e2b merged 1 commit into
mainfrom
db-migration-disk-size

Conversation

@gm-e2b

@gm-e2b gm-e2b commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Separate the default template free-space target from the maximum total root filesystem size that a team may build.

Add nullable default_free_disk_size_mb and max_disk_size_mb columns to tiers, plus extra_max_disk_size_mb to add-ons. Keep extra_disk_mb as the add-on contribution to default free space and add constraints preventing invalid negative or inverted tier values.

Keep the existing team_limits view unchanged for current consumers and introduce team_limits_v2 with the new effective default and maximum fields. Preserve compatibility with legacy add-on writers by treating a null extra maximum as equal to extra_disk_mb.

Leave data population and runtime adoption to later rollout steps so this commit remains an expand-only schema change.

Regenerate the database models and add focused migration coverage for the new columns, the unchanged V1 view, the V2 contract, security invoker behavior, and effective tier-plus-add-on calculations.

Part of: EN-1038

@linear-code

linear-code Bot commented Jul 14, 2026

Copy link
Copy Markdown

EN-1038

@cla-bot cla-bot Bot added the cla-signed label Jul 14, 2026
@codecov

codecov Bot commented Jul 14, 2026

Copy link
Copy Markdown

❌ 4 Tests Failed:

Tests completed Failed Passed Skipped
3426 4 3422 9
View the top 3 failed test(s) by shortest run time
github.com/e2b-dev/infra/tests/integration/internal/tests/proxies::TestMaskRequestHostAPIParameter
Stack Traces | 4.72s run time
=== RUN   TestMaskRequestHostAPIParameter
=== PAUSE TestMaskRequestHostAPIParameter
=== CONT  TestMaskRequestHostAPIParameter
    mask_request_host_test.go:44: Command [python3] output: event:{start:{pid:1122}}
    mask_request_host_test.go:68: Command [cat] output: event:{start:{pid:1123}}
    mask_request_host_test.go:68: Command [cat] output: event:{data:{stderr:"cat: /tmp/nc_output.txt: No such file or directory\n"}}
    mask_request_host_test.go:68: Command [cat] output: event:{end:{exit_code:1 exited:true status:"exit status 1" error:"exit status 1"}}
    mask_request_host_test.go:69: 
        	Error Trace:	.../tests/proxies/mask_request_host_test.go:69
        	Error:      	Received unexpected error:
        	            	command cat in sandbox iixmidm8kj4xgu6xjc7fr failed with exit code 1
        	Test:       	TestMaskRequestHostAPIParameter
--- FAIL: TestMaskRequestHostAPIParameter (4.72s)
github.com/e2b-dev/infra/tests/integration/internal/tests/api/templates::TestDeleteTemplate
Stack Traces | 152s run time
=== RUN   TestDeleteTemplate
=== PAUSE TestDeleteTemplate
=== CONT  TestDeleteTemplate
    build_template_test.go:133: test-to-delete: [info] Building template ehmobvaqh48ncomu9gsw/c3892201-46b1-40a3-ad92-12067882b80a
    build_template_test.go:133: test-to-delete: [info] [base] FROM ubuntu:22.04 [f9f564014e009a9561a82bf8c84f9314242971e833fb019936654ecba452f184]
    build_template_test.go:133: test-to-delete: [info] Base Docker image size: 30 MB
    build_template_test.go:133: test-to-delete: [info] Creating file system and pulling Docker image
    build_template_test.go:133: test-to-delete: [info] Uncompressing layer sha256:d6834b4a794c03efa2c998853e64969fa8851b11b2ade63292268872a37759d0 30 MB
    build_template_test.go:133: test-to-delete: [info] Uncompressing layer sha256:fd19e5fd13aaedd56c2446031086a165b18c55a394267c44dd341d907649a23b 13 MB
    build_template_test.go:133: test-to-delete: [info] Uncompressing layer sha256:8c4b1b28875140ed3abacaf16ad0d696f6bef912f52d2148f261a23e3349465b 168 B
    build_template_test.go:133: test-to-delete: [info] Layers extracted
    build_template_test.go:133: test-to-delete: [info] Root filesystem structure: bin, boot, dev, etc, home, lib, lib32, lib64, libx32, media, mnt, opt, proc, root, run, sbin, srv, sys, tmp, usr, var
    build_template_test.go:133: test-to-delete: [info] Provisioning sandbox template
    build_template_test.go:133: test-to-delete: [info] Provisioning was successful, cleaning up
    build_template_test.go:133: test-to-delete: [info] Sandbox template provisioned
    build_template_test.go:133: test-to-delete: [info] [base] DEFAULT USER user [49e586c2171254c6bc4a09e84eedac32dbcf113a158c24248129af2f49cbed74]
    build_template_test.go:133: test-to-delete: [info] [builder 1/1] RUN echo 'Hello, World!' [c72b4f813c2a16b0fc1a1c5da7b1365a304cbac516b22dc304a71f70aae48ac0]
    build_template_test.go:133: test-to-delete: [info] [builder 1/1] [stdout]: Hello, World!
    build_template_test.go:133: test-to-delete: [info] [finalize] Finalizing template build [92c524e30533398ebb41ce04c2596130f0cdecc9aa328e28fdb16a1b11f61d62]
    build_template_test.go:133: test-to-delete: [error] Build failed: An internal error occurred. Please try again or contact support with the build ID.
    delete_template_test.go:18: Build failed: {<nil> An internal error occurred. Please try again or contact support with the build ID. <nil>}
--- FAIL: TestDeleteTemplate (151.69s)
github.com/e2b-dev/infra/tests/integration/internal/tests/api/templates::TestDeleteTemplateFromAnotherTeamAPIKey
Stack Traces | 173s run time
=== RUN   TestDeleteTemplateFromAnotherTeamAPIKey
=== PAUSE TestDeleteTemplateFromAnotherTeamAPIKey
=== CONT  TestDeleteTemplateFromAnotherTeamAPIKey
    build_template_test.go:133: test-to-delete-another-team-api-key: [info] Building template o4iib2gqzwanlfp5dw03/55c99caf-11f4-479c-b687-94314f57dcbb
    build_template_test.go:133: test-to-delete-another-team-api-key: [info] [base] FROM ubuntu:22.04 [f9f564014e009a9561a82bf8c84f9314242971e833fb019936654ecba452f184]
    build_template_test.go:133: test-to-delete-another-team-api-key: [info] Base Docker image size: 30 MB
    build_template_test.go:133: test-to-delete-another-team-api-key: [info] Creating file system and pulling Docker image
    build_template_test.go:133: test-to-delete-another-team-api-key: [info] Uncompressing layer sha256:d6834b4a794c03efa2c998853e64969fa8851b11b2ade63292268872a37759d0 30 MB
    build_template_test.go:133: test-to-delete-another-team-api-key: [info] Uncompressing layer sha256:fd19e5fd13aaedd56c2446031086a165b18c55a394267c44dd341d907649a23b 13 MB
    build_template_test.go:133: test-to-delete-another-team-api-key: [info] Uncompressing layer sha256:8c4b1b28875140ed3abacaf16ad0d696f6bef912f52d2148f261a23e3349465b 168 B
    build_template_test.go:133: test-to-delete-another-team-api-key: [info] Layers extracted
    build_template_test.go:133: test-to-delete-another-team-api-key: [info] Root filesystem structure: bin, boot, dev, etc, home, lib, lib32, lib64, libx32, media, mnt, opt, proc, root, run, sbin, srv, sys, tmp, usr, var
    build_template_test.go:133: test-to-delete-another-team-api-key: [info] Provisioning sandbox template
    build_template_test.go:133: test-to-delete-another-team-api-key: [info] Provisioning was successful, cleaning up
    build_template_test.go:133: test-to-delete-another-team-api-key: [info] Sandbox template provisioned
    build_template_test.go:133: test-to-delete-another-team-api-key: [info] [base] DEFAULT USER user [49e586c2171254c6bc4a09e84eedac32dbcf113a158c24248129af2f49cbed74]
    build_template_test.go:133: test-to-delete-another-team-api-key: [info] [builder 1/1] RUN echo 'Hello, World!' [c72b4f813c2a16b0fc1a1c5da7b1365a304cbac516b22dc304a71f70aae48ac0]
    build_template_test.go:133: test-to-delete-another-team-api-key: [info] [builder 1/1] [stdout]: Hello, World!
    build_template_test.go:133: test-to-delete-another-team-api-key: [info] [finalize] Finalizing template build [92c524e30533398ebb41ce04c2596130f0cdecc9aa328e28fdb16a1b11f61d62]
    build_template_test.go:133: test-to-delete-another-team-api-key: [error] Build failed: An internal error occurred. Please try again or contact support with the build ID.
    delete_template_test.go:51: Build failed: {<nil> An internal error occurred. Please try again or contact support with the build ID. <nil>}
--- FAIL: TestDeleteTemplateFromAnotherTeamAPIKey (173.43s)
github.com/e2b-dev/infra/tests/integration/internal/tests/api/templates::TestTemplateBuildCOPY
Stack Traces | 186s run time
=== RUN   TestTemplateBuildCOPY
=== PAUSE TestTemplateBuildCOPY
=== CONT  TestTemplateBuildCOPY
    build_template_test.go:133: test-ubuntu-copy: [info] Building template ew8mxoz7z06i45fiyh10/0077e5ab-3e5a-4356-bd61-822f9d5e4b42
    build_template_test.go:133: test-ubuntu-copy: [info] [base] FROM ubuntu:24.04 [a9b3ad91e89daabce8685d67ae12aacb4a128e5aea703dc57457c0ef17079b25]
    build_template_test.go:133: test-ubuntu-copy: [info] Base Docker image size: 30 MB
    build_template_test.go:133: test-ubuntu-copy: [info] Creating file system and pulling Docker image
    build_template_test.go:133: test-ubuntu-copy: [info] Uncompressing layer sha256:ca2678b20700c15185707964d9211b1a6406196114bf675f568b6025d37b3888 30 MB
    build_template_test.go:133: test-ubuntu-copy: [info] Uncompressing layer sha256:fd19e5fd13aaedd56c2446031086a165b18c55a394267c44dd341d907649a23b 13 MB
    build_template_test.go:133: test-ubuntu-copy: [info] Uncompressing layer sha256:8c4b1b28875140ed3abacaf16ad0d696f6bef912f52d2148f261a23e3349465b 168 B
    build_template_test.go:133: test-ubuntu-copy: [info] Layers extracted
    build_template_test.go:133: test-ubuntu-copy: [info] Root filesystem structure: bin, boot, dev, etc, home, lib, lib64, media, mnt, opt, proc, root, run, sbin, srv, sys, tmp, usr, var
    build_template_test.go:133: test-ubuntu-copy: [info] Provisioning sandbox template
    build_template_test.go:133: test-ubuntu-copy: [info] Provisioning was successful, cleaning up
    build_template_test.go:133: test-ubuntu-copy: [info] Sandbox template provisioned
    build_template_test.go:133: test-ubuntu-copy: [info] [base] DEFAULT USER user [f9aaa150221ef19e492ba626b8d9200ab9434ed5f63d02341f9e3be29c4b8760]
    build_template_test.go:133: test-ubuntu-copy: [info] [builder 1/2] COPY . /app/ [2449098e8b0a6a85d9aaa0edf0136f8bc69e9d618dac9611e42bba7c698fd629]
    build_template_test.go:133: test-ubuntu-copy: [info] [builder 2/2] RUN cat /app/hello.txt | grep 'Hello from COPY!' [2f22b685841af46c090bf872491df49e98da0615c4d2c99657645a92a5b4ee67]
    build_template_test.go:133: test-ubuntu-copy: [info] [builder 2/2] [stdout]: Hello from COPY!
    build_template_test.go:133: test-ubuntu-copy: [info] [finalize] Finalizing template build [d8abedde856dad9179d9e99f9778f17106da49a5286a30633b898c2e893b0482]
    build_template_test.go:133: test-ubuntu-copy: [error] Build failed: An internal error occurred. Please try again or contact support with the build ID.
    build_template_test.go:1156: Build failed: {<nil> An internal error occurred. Please try again or contact support with the build ID. <nil>}
--- FAIL: TestTemplateBuildCOPY (186.35s)
github.com/e2b-dev/infra/tests/integration/internal/tests/api/templates::TestTemplateBuildFuseConfiguration
Stack Traces | 189s run time
=== RUN   TestTemplateBuildFuseConfiguration
=== PAUSE TestTemplateBuildFuseConfiguration
=== CONT  TestTemplateBuildFuseConfiguration
    build_template_test.go:133: test-ubuntu-fuse-config: [info] Building template nz7e6r109b2xblxfvhbf/469b4e53-c5a8-47f7-9e15-a43b50b7a7ab
    build_template_test.go:133: test-ubuntu-fuse-config: [info] [base] FROM ubuntu:22.04 [f9f564014e009a9561a82bf8c84f9314242971e833fb019936654ecba452f184]
    build_template_test.go:133: test-ubuntu-fuse-config: [info] Base Docker image size: 30 MB
    build_template_test.go:133: test-ubuntu-fuse-config: [info] Creating file system and pulling Docker image
    build_template_test.go:133: test-ubuntu-fuse-config: [info] Uncompressing layer sha256:d6834b4a794c03efa2c998853e64969fa8851b11b2ade63292268872a37759d0 30 MB
    build_template_test.go:133: test-ubuntu-fuse-config: [info] Uncompressing layer sha256:fd19e5fd13aaedd56c2446031086a165b18c55a394267c44dd341d907649a23b 13 MB
    build_template_test.go:133: test-ubuntu-fuse-config: [info] Uncompressing layer sha256:8c4b1b28875140ed3abacaf16ad0d696f6bef912f52d2148f261a23e3349465b 168 B
    build_template_test.go:133: test-ubuntu-fuse-config: [info] Layers extracted
    build_template_test.go:133: test-ubuntu-fuse-config: [info] Root filesystem structure: bin, boot, dev, etc, home, lib, lib32, lib64, libx32, media, mnt, opt, proc, root, run, sbin, srv, sys, tmp, usr, var
    build_template_test.go:133: test-ubuntu-fuse-config: [info] Provisioning sandbox template
    build_template_test.go:133: test-ubuntu-fuse-config: [info] Provisioning was successful, cleaning up
    build_template_test.go:133: test-ubuntu-fuse-config: [info] Sandbox template provisioned
    build_template_test.go:133: test-ubuntu-fuse-config: [info] [base] DEFAULT USER user [49e586c2171254c6bc4a09e84eedac32dbcf113a158c24248129af2f49cbed74]
    build_template_test.go:133: test-ubuntu-fuse-config: [info] [builder 1/2] RUN grep -q 'z /dev/fuse 0666 root root -' /etc/tmpfiles.d/fuse.conf [064c2aa80e42051b5301f9fd4b4c1bab38adc2b717535b7ca42d5dc9fdc739d1]
    build_template_test.go:133: test-ubuntu-fuse-config: [info] [builder 2/2] RUN echo "Checking /dev/fuse permissions:"; ls -la /dev/fuse; stat -c 'mode=%a owner=%U group=%G' /dev/fuse; test $(stat -c %a /dev/fuse) = '666' [53b9173a7399b3bca212e8c5d1b705f01c09a1180ef92f57f3d3fc1db134b289]
    build_template_test.go:133: test-ubuntu-fuse-config: [info] [builder 2/2] [stdout]: Checking /dev/fuse permissions:
    build_template_test.go:133: test-ubuntu-fuse-config: [info] [builder 2/2] [stdout]: crw-rw-rw- 1 root root 10, 229 Jul 20 13:23 /dev/fuse
    build_template_test.go:133: test-ubuntu-fuse-config: [info] [builder 2/2] [stdout]: mode=666 owner=root group=root
    build_template_test.go:133: test-ubuntu-fuse-config: [info] [finalize] Finalizing template build [44ab07a644985d56c51c27da9742b1dd30905f459dd707130223567c87e03c43]
    build_template_test.go:133: test-ubuntu-fuse-config: [error] Build failed: An internal error occurred. Please try again or contact support with the build ID.
    build_template_test.go:1189: Build failed: {<nil> An internal error occurred. Please try again or contact support with the build ID. <nil>}
--- FAIL: TestTemplateBuildFuseConfiguration (188.66s)

To view more test analytics, go to the Test Analytics Dashboard
📋 Got 3 mins? Take this short survey to help us improve Test Analytics.

@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 introduces database migrations to add disk entitlement columns to the tiers and addons tables, creates a new team_limits_v2 view, and adds corresponding Go models and tests. The review feedback identifies a critical issue where explicit ::bigint casts in the view definition cause sqlc to generate non-nullable int64 fields in Go, which will lead to runtime scan crashes when database values are NULL. To resolve this, the reviewer recommends removing the redundant casts so sqlc can correctly infer nullability, and updating the migration tests to scan into nullable pointer types.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread packages/db/migrations/20260714091415_extend_team_limits.sql
Comment thread packages/db/pkg/tests/disk_entitlements_migration_test.go Outdated

@claude claude 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.

LGTM — straightforward, well-tested expand-only schema migration.

What was reviewed:

  • Migration adds nullable disk-entitlement columns to tiers/addons with CHECK constraints (NULL-safe, no backfill needed).
  • New team_limits_v2 view combines tier + addon values, preserves security_invoker=on and legacy extra_max_disk_size_mb→extra_disk_mb fallback for old add-on writers.
  • Verified the effective default/max math in the migration test matches expectations, and that the existing team_limits (v1) view is left untouched.
  • Checked the generated TeamLimitsV2 Go struct typing NULL-derived columns as int64 instead of pgtype.Int8 — inert since no query in the codebase currently selects from team_limits_v2, so it has no runtime effect and will be corrected on the next real sqlc generation.
Extended reasoning...

Overview

This PR adds two nullable bigint columns (default_free_disk_size_mb, max_disk_size_mb) to tiers, one nullable column (extra_max_disk_size_mb) to addons, and CHECK constraints preventing negative or inverted tier values. It then introduces a new team_limits_v2 view that surfaces the effective (tier + active add-ons) default and maximum disk sizes, while leaving the existing team_limits view untouched for current consumers. Test coverage exercises column nullability, view column sets for v1 vs v2, security_invoker behavior, and the arithmetic for effective values including legacy add-on fallback.

Security risks

None identified. The new view preserves security_invoker=on, matching the existing team_limits v1 view's RLS-respecting behavior, and this is explicitly covered by a test. No auth, crypto, or permission logic is touched.

Level of scrutiny

This is a pure, additive (expand-only) database schema change with no runtime/application code wired up yet — the PR description explicitly defers data population and adoption to later steps. Given the low blast radius (no existing code paths depend on the new columns/view yet) and strong test coverage of the new schema behavior, a lighter level of scrutiny is appropriate compared to changes touching live request paths.

Other factors

The bug-hunting system found no issues. I independently checked the flagged-and-ruled-out concern about the generated TeamLimitsV2 struct mistyping nullable view columns as non-nullable int64, and confirmed it has no functional impact since nothing in the codebase queries team_limits_v2 yet — it's inert generated code that will be corrected whenever sqlc is actually re-run against a query using it. The migration's up/down scripts are symmetric and CHECK constraints are correctly NULL-safe for the expand-only rollout.

@gm-e2b
gm-e2b force-pushed the db-migration-disk-size branch 3 times, most recently from 67bcfe1 to 4621212 Compare July 14, 2026 15:46

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

can we add if not exists to the statements🙏🏻

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Added for new columns. Adding constraint checks does not support IF NOT EXISTS.

Comment thread packages/db/migrations/20260714091415_create_team_limits_v2.sql Outdated
@gm-e2b
gm-e2b force-pushed the db-migration-disk-size branch 3 times, most recently from f688da7 to 1bb4810 Compare July 16, 2026 10:43

@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: 1bb4810cdd

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@gm-e2b
gm-e2b force-pushed the db-migration-disk-size branch from 1bb4810 to 5ad2afa Compare July 20, 2026 10:18
ALTER TABLE "public"."addons"
ADD CONSTRAINT "addons_extra_max_disk_size_mb_check"
CHECK (extra_max_disk_size_mb >= 0);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

default_free_disk_size_mb and max_disk_size_mb should be non null here

Comment thread packages/db/sqlc.yaml Outdated
import: "time"
type: "Time"
pointer: true
# sqlc does not infer nullability for these view expressions.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

this won't be needed afterwards

Add nullable tier entitlements for the default template free-space target
and maximum logical rootfs size, plus an add-on contribution to the maximum.
Validate non-negative defaults and add-on increments, positive maxima, and
that each default does not exceed its maximum.

Backfill existing add-ons so their maximum contribution initially matches
extra_disk_mb. Keep the new field nullable and fall back to extra_disk_mb
for writes from legacy services during rollout. Leave tier population to
the audited follow-up data migration.

Extend team_limits in place, preserving its existing columns and appending
the effective default_free_disk_size_mb and max_disk_size_mb values computed
from active add-ons.

Regenerate sqlc queries and models with nullable int64 entitlement fields,
and cover the schema shape, security-invoker setting, column compatibility,
and tier-plus-add-on calculations in the migration test.

Part of: EN-1038
@gm-e2b
gm-e2b force-pushed the db-migration-disk-size branch from 5ad2afa to 02de0a1 Compare July 20, 2026 13:14

@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: 02de0a15fd

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread packages/db/migrations/20260714091415_extend_team_limits.sql
@gm-e2b
gm-e2b merged commit 3c0bfad into main Jul 20, 2026
41 checks passed
@gm-e2b
gm-e2b deleted the db-migration-disk-size branch July 20, 2026 15:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants