Skip to content

Use cloud Box ID as primary identity#800

Merged
DorianZheng merged 4 commits into
mainfrom
codex/single-box-identity
Jun 16, 2026
Merged

Use cloud Box ID as primary identity#800
DorianZheng merged 4 commits into
mainfrom
codex/single-box-identity

Conversation

@law-chain-hot

@law-chain-hot law-chain-hot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Make the 12-character Cloud Box ID the primary box.id and remove the legacy Box.boxId entity/DTO/API-client alias.
  • Update lookup, cache invalidation, REST mapping, admin/dashboard display, and runner create DTO paths to use id directly.
  • Regenerate the Cloud API clients so Box / admin box item models and list sorting no longer expose boxId.

Notes

  • This PR intentionally takes the rebuild/reset-DB path. Fresh databases created from the baseline migration have box.id as varchar(12) and no box.boxId column.
  • Existing deployed DBs that already ran the baseline migration will not be converted in place by this PR. Rebuild/drop the existing DB state before deploying this branch if old UUID box.id rows or box.boxId columns exist.
  • box_last_activity.boxId and ssh_access.boxId remain as relation column names; both foreign-key to box(id) and are not the removed Box.boxId field.
  • Runner HTTP route parameters named {boxId} are path variable names for the public box identity and remain valid.

Validation

  • Remote dev machine: make lint:apps passed with existing warnings only.
  • Remote dev machine: make test:apps passed (36 API suites / 130 tests; app Go test targets passed or matched cache).
  • Remote dev machine: VERSION=0.0.0-dev make build:apps passed.
  • git diff --check passed locally.

@law-chain-hot law-chain-hot requested a review from a team as a code owner June 16, 2026 06:59
@coderabbitai

coderabbitai Bot commented Jun 16, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR collapses the dual Box identity system—a UUID primary key (id) plus a separate public 12-character boxId column—into a single id field holding the public 12-character Box ID. The change spans the database migration, TypeORM entity, service/repository/cache layers, API DTOs, OpenAPI spec, generated Go and TypeScript clients, the runner, and the dashboard UI.

Changes

Single Box identity migration

Layer / File(s) Summary
DB migration and Box entity schema
apps/api/src/migrations/1741087887225-migration.ts, apps/api/src/box/entities/box.entity.ts, apps/api/src/box/entities/box.entity.spec.ts
Migration replaces the UUID id column + boxId column with a single character varying(12) primary key named id and rebuilds indexes. Entity removes UUID default and boxId column; constructor assigns id via generateBoxId(); validateBoxId checks this.id against BOX_ID_REGEX.
Cache key utilities and invalidation service
apps/api/src/box/utils/box-lookup-cache.util.ts, apps/api/src/box/services/box-lookup-cache-invalidation.service.ts, apps/api/src/box/repositories/box.repository.ts
boxLookupCacheKeyById and boxOrgIdCacheKeyById argument shapes change from boxId to id. BoxLookupCacheInvalidationService removes all boxId/previousBoxId paths from InvalidateBoxLookupCacheArgs, invalidate(), and invalidateOrgId(). Repository insert/update invalidation payloads drop boxId/previousBoxId fields.
BoxService lookup and search logic
apps/api/src/box/services/box.service.ts, apps/api/src/box/services/box.service.box-id.spec.ts
findOneByIdOrName, getOrganizationId, getRunnerId, and getRegionId query where.id instead of where.boxId. ILike search filters on id. Cache-key helper imports updated. Error messages updated. Test updated to call findOneByIdOrName with box.id.
API DTOs, BoxDto mapping, and REST mapper
apps/api/src/box/dto/box.dto.ts, apps/api/src/box/dto/box.dto.spec.ts, apps/api/src/box/dto/list-boxes-query.dto.ts, apps/api/src/admin/dto/admin-overview.dto.ts, apps/api/src/boxlite-rest/mappers/box-to-box.mapper.ts, apps/api/src/boxlite-rest/mappers/box-to-box.mapper.spec.ts
BoxDto.id updated to describe the public 12-character Box ID; fromBox() maps id from box.id and drops boxId. BoxSortField enum removes BOX_ID. AdminBoxItemDto drops boxId. REST mapper reads BoxDto.id for box_id.
Admin overview and observability services
apps/api/src/admin/services/overview.service.ts, apps/api/src/admin/services/observability.service.ts, apps/api/src/admin/services/observability.service.spec.ts
listBoxes() drops boxId from mapped output. Observability service resource title, platform-state correlation, and matchesBox all use box.id. Spec tests remove boxId aliases from mocks and update all assertions to box-1.
Generated Go and TS API clients, OpenAPI spec, and docs
apps/api-client-go/api/openapi.yaml, apps/api-client-go/model_box.go, apps/api-client-go/model_admin_box_item.go, apps/api-client-go/api_box.go, apps/libs/api-client/src/models/box.ts, apps/libs/api-client/src/models/admin-box-item.ts, apps/libs/api-client/src/api/box-api.ts, apps/libs/api-client/src/docs/*
OpenAPI spec removes boxId from Box/AdminBoxItem schemas, required list, sort enum, and examples. Go models drop BoxId fields, accessors, constructor parameter, and serialization handling. TS models drop boxId property; ListBoxesPaginatedSortEnum removes BOX_ID. Docs updated throughout.
Go runner DTO and boxlite client
apps/runner/pkg/api/dto/box.go, apps/runner/pkg/boxlite/client.go, apps/runner/pkg/boxlite/daemon_env_test.go
CreateBoxDTO removes BoxId field. Client.Create drops publicBoxId derivation and logs boxDto.Id directly. New reflection-based test asserts CreateBoxDTO has no BoxId field.
Dashboard box-identity helpers, table, and hooks
apps/dashboard/src/lib/box-identity.ts, apps/dashboard/src/lib/box-identity.test.ts, apps/dashboard/src/components/BoxTable/..., apps/dashboard/src/hooks/useBoxWsSync.ts, apps/dashboard/src/components/admin/...
BoxIdentity drops boxId; all identity helpers operate on id. Box table drops "Internal UUID" column, updates sort conversion. useBoxWsSync matches only box.id. Admin helpers remove boxId from AdminBox type and search logic. adminDiagnoseTarget and AdminPeopleBoxesView reference box.id directly. New box-identity unit tests added.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

Suggested reviewers

  • DorianZheng

Poem

🐇 Hop, hop, hooray, the ID is clear!
No more two names — just one to steer.
UUID gone, twelve chars remain,
The box is known by id domain.
One field to rule them all today,
The rabbit cheers and hops away! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 13.04% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Use cloud Box ID as primary identity' accurately summarizes the main change: promoting the 12-character Cloud Box ID as the primary box identity by removing legacy boxId aliases throughout the codebase.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/single-box-identity

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: 37937787db

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

Comment thread apps/api/src/migrations/1741087887225-migration.ts

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/api-client-go/api/openapi.yaml (1)

6704-6711: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Update remaining Box ID examples to the new public ID shape.

Several generated examples still show UUIDs, 6-character IDs, or box_-prefixed IDs for Box identity fields. Use the same 12-character public ID shape everywhere these fields represent box(id).

Representative example updates
-        boxId: "123456"
+        boxId: aB3cD4eF5gH6
...
-        boxId: 123e4567-e89b-12d3-a456-426614174000
+        boxId: aB3cD4eF5gH6
...
-        id: box_abc123
+        id: aB3cD4eF5gH6
...
-          description: Box ID
-          example: box_abc123
+          description: The public 12-character Box ID
+          example: aB3cD4eF5gH6

Also applies to: 6726-6735, 6754-6771, 6804-6816, 8003-8022, 9343-9358

🤖 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-client-go/api/openapi.yaml` around lines 6704 - 6711, The Box ID
examples throughout the OpenAPI specification are inconsistent, using
6-character IDs, UUIDs, or box_-prefixed formats instead of a uniform
12-character public ID shape. Update all boxId example values across the file to
use the consistent 12-character public ID format (matching the shape used
elsewhere in the specification for box identity fields). This includes updates
needed at lines 6704-6711 (anchor location showing the boxId example),
6726-6735, 6754-6771, 6804-6816, 8003-8022, and 9343-9358, where all boxId
example values should be replaced with the same standardized 12-character public
ID format.
🧹 Nitpick comments (1)
apps/api-client-go/api/openapi.yaml (1)

6389-6392: ⚡ Quick win

Make the 12-character Box ID contract machine-readable.

Box.id now documents the public 12-character identity, but the schema still accepts any string. Add minLength/maxLength and, if the alphabet is fixed, a pattern so generated clients and docs preserve the new contract.

Proposed schema tightening
         id:
           description: The public 12-character Box ID
           example: aB3cD4eF5gH6
+          minLength: 12
+          maxLength: 12
           type: string
🤖 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-client-go/api/openapi.yaml` around lines 6389 - 6392, The Box.id
field in the OpenAPI schema currently only documents that it is a 12-character
Box ID but does not enforce this constraint in the schema itself. Add minLength
and maxLength properties both set to 12 to enforce exactly 12-character IDs.
Additionally, if the 12-character Box ID uses a fixed alphabet or character set,
add a pattern property with a regular expression that matches the allowed
character set to make the contract machine-readable for generated clients and
documentation.
🤖 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/libs/api-client/src/docs/BoxApi.md`:
- Line 822: The sort parameter table row at line 822 in BoxApi.md has a
malformed type definition cell that creates extra columns, breaking the Markdown
table structure (MD056 error). Clean up the sort parameter row by removing the
duplicate/conflicting type definitions. The current row appears to have both a
shortened array type and a full Array type definition concatenated together.
Replace this with a single, properly formatted type definition for the sort
parameter that matches the table structure and includes all valid sort field
options (id, name, state, region, updatedAt, createdAt). Ensure the row has the
correct number of columns to align with the table header and other parameter
rows.

---

Outside diff comments:
In `@apps/api-client-go/api/openapi.yaml`:
- Around line 6704-6711: The Box ID examples throughout the OpenAPI
specification are inconsistent, using 6-character IDs, UUIDs, or box_-prefixed
formats instead of a uniform 12-character public ID shape. Update all boxId
example values across the file to use the consistent 12-character public ID
format (matching the shape used elsewhere in the specification for box identity
fields). This includes updates needed at lines 6704-6711 (anchor location
showing the boxId example), 6726-6735, 6754-6771, 6804-6816, 8003-8022, and
9343-9358, where all boxId example values should be replaced with the same
standardized 12-character public ID format.

---

Nitpick comments:
In `@apps/api-client-go/api/openapi.yaml`:
- Around line 6389-6392: The Box.id field in the OpenAPI schema currently only
documents that it is a 12-character Box ID but does not enforce this constraint
in the schema itself. Add minLength and maxLength properties both set to 12 to
enforce exactly 12-character IDs. Additionally, if the 12-character Box ID uses
a fixed alphabet or character set, add a pattern property with a regular
expression that matches the allowed character set to make the contract
machine-readable for generated clients and documentation.
🪄 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: 4c48193e-9d2c-4316-b13c-1eb5468ee56b

📥 Commits

Reviewing files that changed from the base of the PR and between f394033 and 3793778.

📒 Files selected for processing (40)
  • apps/api-client-go/api/openapi.yaml
  • apps/api-client-go/api_box.go
  • apps/api-client-go/model_admin_box_item.go
  • apps/api-client-go/model_box.go
  • apps/api/src/admin/dto/admin-overview.dto.ts
  • apps/api/src/admin/services/observability.service.spec.ts
  • apps/api/src/admin/services/observability.service.ts
  • apps/api/src/admin/services/overview.service.ts
  • apps/api/src/box/dto/box.dto.spec.ts
  • apps/api/src/box/dto/box.dto.ts
  • apps/api/src/box/dto/list-boxes-query.dto.ts
  • apps/api/src/box/entities/box.entity.spec.ts
  • apps/api/src/box/entities/box.entity.ts
  • apps/api/src/box/repositories/box.repository.ts
  • apps/api/src/box/services/box-lookup-cache-invalidation.service.ts
  • apps/api/src/box/services/box.service.box-id.spec.ts
  • apps/api/src/box/services/box.service.ts
  • apps/api/src/box/utils/box-lookup-cache.util.ts
  • apps/api/src/boxlite-rest/mappers/box-to-box.mapper.spec.ts
  • apps/api/src/boxlite-rest/mappers/box-to-box.mapper.ts
  • apps/api/src/migrations/1741087887225-migration.ts
  • apps/dashboard/src/components/BoxTable/BoxTableActions.tsx
  • apps/dashboard/src/components/BoxTable/columns.tsx
  • apps/dashboard/src/components/BoxTable/types.ts
  • apps/dashboard/src/components/BoxTable/useBoxTable.ts
  • apps/dashboard/src/components/admin/AdminPeopleBoxesView.tsx
  • apps/dashboard/src/components/admin/adminDiagnoseTarget.ts
  • apps/dashboard/src/components/admin/adminHelpers.ts
  • apps/dashboard/src/hooks/useBoxWsSync.ts
  • apps/dashboard/src/lib/box-identity.test.ts
  • apps/dashboard/src/lib/box-identity.ts
  • apps/libs/api-client/src/api/box-api.ts
  • apps/libs/api-client/src/docs/AdminBoxItem.md
  • apps/libs/api-client/src/docs/Box.md
  • apps/libs/api-client/src/docs/BoxApi.md
  • apps/libs/api-client/src/models/admin-box-item.ts
  • apps/libs/api-client/src/models/box.ts
  • apps/runner/pkg/api/dto/box.go
  • apps/runner/pkg/boxlite/client.go
  • apps/runner/pkg/boxlite/daemon_env_test.go
💤 Files with no reviewable changes (8)
  • apps/libs/api-client/src/docs/AdminBoxItem.md
  • apps/api/src/admin/services/overview.service.ts
  • apps/libs/api-client/src/models/admin-box-item.ts
  • apps/dashboard/src/components/BoxTable/types.ts
  • apps/api/src/admin/dto/admin-overview.dto.ts
  • apps/api-client-go/model_admin_box_item.go
  • apps/dashboard/src/components/BoxTable/BoxTableActions.tsx
  • apps/runner/pkg/api/dto/box.go

Comment thread apps/libs/api-client/src/docs/BoxApi.md
Comment thread apps/api/src/admin/services/observability.service.spec.ts
@DorianZheng DorianZheng enabled auto-merge June 16, 2026 07:40
@DorianZheng DorianZheng added this pull request to the merge queue Jun 16, 2026
Merged via the queue into main with commit a1740c6 Jun 16, 2026
31 checks passed
@DorianZheng DorianZheng deleted the codex/single-box-identity branch June 16, 2026 07:41
G4614 added a commit that referenced this pull request Jun 16, 2026
…800

Tokyo Api was redeployed with #800 ("Use cloud Box ID as primary
identity") which also switched the supportedImages allowlist from
digest-pinned to tag-pinned:

  Supported:
    ghcr.io/boxlite-ai/boxlite-agent-base:20260605-p0-r3
    ghcr.io/boxlite-ai/boxlite-agent-python:20260605-p0-r3
    ghcr.io/boxlite-ai/boxlite-agent-node:20260605-p0-r3

The workflow was still injecting the previous digest pin
(ghcr.io/.../boxlite-agent-base@sha256:834dcb...), which the new
allowlist no longer accepts. Every create_box leaked HTTP 400
"Unsupported image" and downstream cascade-failed ~38 e2e cases
that all start from POST /boxes. The two CLI smokes that don't
create a box (test_cli_whoami + test_cli_ls) still PASSED, confirming
the auth / list path is healthy and the failure was image-side only.

Switch the env to the tag form so the workflow matches whatever
allowlist is currently deployed. A future hardening (separate change)
would have the test step read Tokyo Api's /api/v1/config /
supportedImages at runtime and pick the first entry — that way an
allowlist swap downstream wouldn't require touching this yml again.
G4614 added a commit that referenced this pull request Jun 16, 2026
…800

Tokyo Api was redeployed with #800 ("Use cloud Box ID as primary
identity") which also switched the supportedImages allowlist from
digest-pinned to tag-pinned:

  Supported:
    ghcr.io/boxlite-ai/boxlite-agent-base:20260605-p0-r3
    ghcr.io/boxlite-ai/boxlite-agent-python:20260605-p0-r3
    ghcr.io/boxlite-ai/boxlite-agent-node:20260605-p0-r3

The workflow was still injecting the previous digest pin
(ghcr.io/.../boxlite-agent-base@sha256:834dcb...), which the new
allowlist no longer accepts. Every create_box leaked HTTP 400
"Unsupported image" and downstream cascade-failed ~38 e2e cases
that all start from POST /boxes. The two CLI smokes that don't
create a box (test_cli_whoami + test_cli_ls) still PASSED, confirming
the auth / list path is healthy and the failure was image-side only.

Switch the env to the tag form so the workflow matches whatever
allowlist is currently deployed. A future hardening (separate change)
would have the test step read Tokyo Api's /api/v1/config /
supportedImages at runtime and pick the first entry — that way an
allowlist swap downstream wouldn't require touching this yml again.
G4614 added a commit that referenced this pull request Jun 16, 2026
…rkflow yml

The previous 'put BOXLITE_E2E_IMAGE in e2e-cloud-test.yml' approach
drifts every time Tokyo Api's curated-images-constant is updated:

  #758 → digest-pinned (834dcb...) → workflow updated to send digest
  #800 → tag-pinned (:20260605-p0-r3) → workflow had to be updated AGAIN
                                         (digest now rejected, 38 cases
                                          cascade-fail at POST /boxes)

The fix: don't trust the workflow's env; query the deployed API at
session start. conftest._discover_supported_image now:

  1. honors BOXLITE_E2E_IMAGE if explicitly set (override path for
     reproducibility audits)
  2. otherwise sends POST /boxes with a sentinel image to the active
     credential profile's API, catches the 400 body's
     'Supported images: a, b, c' list, returns the first entry
     (matches the server's own assertSupportedImage(undefined) default)
  3. falls back to 'alpine:3.23' on any error — tests still 4xx-fail
     loudly so the regression is visible

The discovered value is also pinned to os.environ['BOXLITE_E2E_IMAGE']
so the C / Go / Node entry-driver subprocesses inherit it without
each test re-implementing the probe.

The workflow's BOXLITE_E2E_IMAGE injection is removed (replaced with
a comment explaining the probe). Subsequent allowlist swaps will pick
up automatically.
G4614 added a commit that referenced this pull request Jun 16, 2026
…es probe

Make every case in scripts/test/e2e/cases/ runnable against any
profile pointing at any deployed stack (local boxlite serve, Tokyo
e2e-ci, Singapore dev), removing the hard-codes that only worked
against a local boxlite serve.

(1) Profile name. Every per-file _profile() helper used to hardcode
    "p1"; now reads BOXLITE_E2E_PROFILE env (default "p1" for
    backwards compat). 8 case files updated (test_c_entry,
    test_go_entry, test_node_entry, test_error_code_mapping,
    test_errors, test_quota_enforcement, test_runner_concurrency,
    test_shutdown).

(2) Box id format. UUID_RE only accepted the 36-char UUID form, but
    the local runtime mints 12-char Base62 and a REST server may
    return a ULID. Replace with BOX_ID_RE matching all three
    (UUID / ULID / 12-char Base62). 4 case files updated
    (test_c_entry, test_cli_entry, test_cli_detach_recovery,
    test_go_entry, test_node_entry).

(3) Image allowlist. The previous design relied on the workflow yml
    injecting BOXLITE_E2E_IMAGE at the value the deployed API
    accepted — every supportedImages allowlist update (#758 →
    digest-pinned; #800 → tag-pinned :20260605-p0-r3) required a
    workflow update to keep create_box from cascading 38 4xx FAILs.
    conftest now probes the deployed API at session start (POST
    /boxes with a sentinel out-of-allowlist image; parse the 400
    body's "Supported images: a, b, c" list; pick the first) and
    pins the discovered value back to os.environ so the C / Go /
    Node entry-driver subprocesses inherit it.
    BOXLITE_E2E_IMAGE remains as an override for reproducibility
    audits.

(4) Whoami assertion. test_cli_whoami_against_local_api hard-coded
    "boxlite-admin" + "http://localhost:3000" — only ever passed
    against a local boxlite serve. Now reads the active profile's
    URL from credentials.toml and asserts it appears in whoami
    output + "Not logged in" doesn't.

(5) Path-bypass guard gating. The C / Go / Node / CLI entry smokes
    all ended with a runner_hits_for_box assert that requires
    journalctl access to the host running boxlite-runner. On the
    cloud profiles that runner lives on a remote EC2; the autouse
    Python fixture already bypasses via BOXLITE_E2E_SKIP_PATH_VERIFY
    but the subprocess smokes did not. conftest exposes
    path_verify_skipped() (single truthy reading of the env) and
    the 4 entry tests + detach_recovery gate their hits-check on
    it. Box id / driver output assertions still run.

(6) Image / drain robustness in test_exec_timeout: drain(ex) is
    moved behind a short asyncio.wait_for and reordered after
    ex.wait() — the REST runner's stream pumps don't reliably
    observe stream closure when the workload terminates via SIGKILL,
    so the previous shape blocked indefinitely on cloud.
G4614 added a commit that referenced this pull request Jun 16, 2026
…es probe

Make every case in scripts/test/e2e/cases/ runnable against any
profile pointing at any deployed stack (local boxlite serve, Tokyo
e2e-ci, Singapore dev), removing the hard-codes that only worked
against a local boxlite serve.

(1) Profile name. Every per-file _profile() helper used to hardcode
    "p1"; now reads BOXLITE_E2E_PROFILE env (default "p1" for
    backwards compat). 8 case files updated (test_c_entry,
    test_go_entry, test_node_entry, test_error_code_mapping,
    test_errors, test_quota_enforcement, test_runner_concurrency,
    test_shutdown).

(2) Box id format. UUID_RE only accepted the 36-char UUID form, but
    the local runtime mints 12-char Base62 and a REST server may
    return a ULID. Replace with BOX_ID_RE matching all three
    (UUID / ULID / 12-char Base62). 4 case files updated
    (test_c_entry, test_cli_entry, test_cli_detach_recovery,
    test_go_entry, test_node_entry).

(3) Image allowlist. The previous design relied on the workflow yml
    injecting BOXLITE_E2E_IMAGE at the value the deployed API
    accepted — every supportedImages allowlist update (#758 →
    digest-pinned; #800 → tag-pinned :20260605-p0-r3) required a
    workflow update to keep create_box from cascading 38 4xx FAILs.
    conftest now probes the deployed API at session start (POST
    /boxes with a sentinel out-of-allowlist image; parse the 400
    body's "Supported images: a, b, c" list; pick the first) and
    pins the discovered value back to os.environ so the C / Go /
    Node entry-driver subprocesses inherit it.
    BOXLITE_E2E_IMAGE remains as an override for reproducibility
    audits.

(4) Whoami assertion. test_cli_whoami_against_local_api hard-coded
    "boxlite-admin" + "http://localhost:3000" — only ever passed
    against a local boxlite serve. Now reads the active profile's
    URL from credentials.toml and asserts it appears in whoami
    output + "Not logged in" doesn't.

(5) Path-bypass guard gating. The C / Go / Node / CLI entry smokes
    all ended with a runner_hits_for_box assert that requires
    journalctl access to the host running boxlite-runner. On the
    cloud profiles that runner lives on a remote EC2; the autouse
    Python fixture already bypasses via BOXLITE_E2E_SKIP_PATH_VERIFY
    but the subprocess smokes did not. conftest exposes
    path_verify_skipped() (single truthy reading of the env) and
    the 4 entry tests + detach_recovery gate their hits-check on
    it. Box id / driver output assertions still run.

(6) Image / drain robustness in test_exec_timeout: drain(ex) is
    moved behind a short asyncio.wait_for and reordered after
    ex.wait() — the REST runner's stream pumps don't reliably
    observe stream closure when the workload terminates via SIGKILL,
    so the previous shape blocked indefinitely on cloud.
G4614 added a commit that referenced this pull request Jun 16, 2026
…es probe

Make every case in scripts/test/e2e/cases/ runnable against any
profile pointing at any deployed stack (local boxlite serve, Tokyo
e2e-ci, Singapore dev), removing the hard-codes that only worked
against a local boxlite serve.

(1) Profile name. Every per-file _profile() helper used to hardcode
    "p1"; now reads BOXLITE_E2E_PROFILE env (default "p1" for
    backwards compat). 8 case files updated (test_c_entry,
    test_go_entry, test_node_entry, test_error_code_mapping,
    test_errors, test_quota_enforcement, test_runner_concurrency,
    test_shutdown).

(2) Box id format. UUID_RE only accepted the 36-char UUID form, but
    the local runtime mints 12-char Base62 and a REST server may
    return a ULID. Replace with BOX_ID_RE matching all three
    (UUID / ULID / 12-char Base62). 4 case files updated
    (test_c_entry, test_cli_entry, test_cli_detach_recovery,
    test_go_entry, test_node_entry).

(3) Image allowlist. The previous design relied on the workflow yml
    injecting BOXLITE_E2E_IMAGE at the value the deployed API
    accepted — every supportedImages allowlist update (#758 →
    digest-pinned; #800 → tag-pinned :20260605-p0-r3) required a
    workflow update to keep create_box from cascading 38 4xx FAILs.
    conftest now probes the deployed API at session start (POST
    /boxes with a sentinel out-of-allowlist image; parse the 400
    body's "Supported images: a, b, c" list; pick the first) and
    pins the discovered value back to os.environ so the C / Go /
    Node entry-driver subprocesses inherit it.
    BOXLITE_E2E_IMAGE remains as an override for reproducibility
    audits.

(4) Whoami assertion. test_cli_whoami_against_local_api hard-coded
    "boxlite-admin" + "http://localhost:3000" — only ever passed
    against a local boxlite serve. Now reads the active profile's
    URL from credentials.toml and asserts it appears in whoami
    output + "Not logged in" doesn't.

(5) Path-bypass guard gating. The C / Go / Node / CLI entry smokes
    all ended with a runner_hits_for_box assert that requires
    journalctl access to the host running boxlite-runner. On the
    cloud profiles that runner lives on a remote EC2; the autouse
    Python fixture already bypasses via BOXLITE_E2E_SKIP_PATH_VERIFY
    but the subprocess smokes did not. conftest exposes
    path_verify_skipped() (single truthy reading of the env) and
    the 4 entry tests + detach_recovery gate their hits-check on
    it. Box id / driver output assertions still run.

(6) Image / drain robustness in test_exec_timeout: drain(ex) is
    moved behind a short asyncio.wait_for and reordered after
    ex.wait() — the REST runner's stream pumps don't reliably
    observe stream closure when the workload terminates via SIGKILL,
    so the previous shape blocked indefinitely on cloud.
G4614 added a commit that referenced this pull request Jun 16, 2026
…es probe

Make every case in scripts/test/e2e/cases/ runnable against any
profile pointing at any deployed stack (local boxlite serve, Tokyo
e2e-ci, Singapore dev), removing the hard-codes that only worked
against a local boxlite serve.

(1) Profile name. Every per-file _profile() helper used to hardcode
    "p1"; now reads BOXLITE_E2E_PROFILE env (default "p1" for
    backwards compat). 8 case files updated (test_c_entry,
    test_go_entry, test_node_entry, test_error_code_mapping,
    test_errors, test_quota_enforcement, test_runner_concurrency,
    test_shutdown).

(2) Box id format. UUID_RE only accepted the 36-char UUID form, but
    the local runtime mints 12-char Base62 and a REST server may
    return a ULID. Replace with BOX_ID_RE matching all three
    (UUID / ULID / 12-char Base62). 4 case files updated
    (test_c_entry, test_cli_entry, test_cli_detach_recovery,
    test_go_entry, test_node_entry).

(3) Image allowlist. The previous design relied on the workflow yml
    injecting BOXLITE_E2E_IMAGE at the value the deployed API
    accepted — every supportedImages allowlist update (#758 →
    digest-pinned; #800 → tag-pinned :20260605-p0-r3) required a
    workflow update to keep create_box from cascading 38 4xx FAILs.
    conftest now probes the deployed API at session start (POST
    /boxes with a sentinel out-of-allowlist image; parse the 400
    body's "Supported images: a, b, c" list; pick the first) and
    pins the discovered value back to os.environ so the C / Go /
    Node entry-driver subprocesses inherit it.
    BOXLITE_E2E_IMAGE remains as an override for reproducibility
    audits.

(4) Whoami assertion. test_cli_whoami_against_local_api hard-coded
    "boxlite-admin" + "http://localhost:3000" — only ever passed
    against a local boxlite serve. Now reads the active profile's
    URL from credentials.toml and asserts it appears in whoami
    output + "Not logged in" doesn't.

(5) Path-bypass guard gating. The C / Go / Node / CLI entry smokes
    all ended with a runner_hits_for_box assert that requires
    journalctl access to the host running boxlite-runner. On the
    cloud profiles that runner lives on a remote EC2; the autouse
    Python fixture already bypasses via BOXLITE_E2E_SKIP_PATH_VERIFY
    but the subprocess smokes did not. conftest exposes
    path_verify_skipped() (single truthy reading of the env) and
    the 4 entry tests + detach_recovery gate their hits-check on
    it. Box id / driver output assertions still run.

(6) Image / drain robustness in test_exec_timeout: drain(ex) is
    moved behind a short asyncio.wait_for and reordered after
    ex.wait() — the REST runner's stream pumps don't reliably
    observe stream closure when the workload terminates via SIGKILL,
    so the previous shape blocked indefinitely on cloud.
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.

2 participants