Skip to content

fix(modal): support non-main Modal environments#687

Merged
ColeMurray merged 5 commits into
mainfrom
fix/modal-non-main-envs
May 30, 2026
Merged

fix(modal): support non-main Modal environments#687
ColeMurray merged 5 commits into
mainfrom
fix/modal-non-main-envs

Conversation

@ColeMurray

@ColeMurray ColeMurray commented May 30, 2026

Copy link
Copy Markdown
Owner

Summary

  • Takes over fix(modal): Support non-main envs in Modal #629 on a new branch because the original PR head is company-owned.
  • Adds modal_environment through the Modal Terraform module so secrets and deploy commands run in the selected Modal environment.
  • Adds modal_environment_web_suffix / MODAL_ENVIRONMENT_WEB_SUFFIX for Modal endpoint URL hosts, keeping it separate from the CLI environment name.
  • Keeps MODAL_WORKSPACE as the raw workspace, passes MODAL_ENVIRONMENT for dashboard links, and uses the web suffix for Modal API endpoint slugs.
  • Documents the new Modal environment settings and wires them into Terraform GitHub Actions.

Addresses Review Feedback

  • Owner thread on terraform/environments/production/modal.tf: Modal CLI now receives MODAL_ENVIRONMENT for both secret creation and deploys.
  • Owner thread on packages/control-plane/src/sandbox/client.ts: endpoint hosts now use explicit Modal web suffix instead of deriving from environment name.
  • CodeRabbit validation note on modal_environment: rejects empty values, colons, slashes, and backslashes for Modal deployments, including at the module boundary.
  • CodeRabbit deploy script note: validates all required env vars before first use under set -u.

Validation

  • npm run build -w @open-inspect/shared
  • npm test -w @open-inspect/control-plane -- --run src/sandbox/client.test.ts
  • npm run typecheck -w @open-inspect/control-plane
  • npm run lint -w @open-inspect/control-plane
  • terraform fmt -recursive -check terraform
  • terraform -chdir=terraform/environments/production init -backend=false
  • terraform -chdir=terraform/environments/production validate
  • bash -n terraform/modules/modal-app/scripts/deploy.sh
  • bash -n terraform/modules/modal-app/scripts/create-secrets.sh

Summary by CodeRabbit

  • New Features

    • Add selectable Modal deployment environments and pass environment to Modal clients and deploy tooling
    • Configurable environment-to-endpoint web-suffix for Modal URLs and health checks
  • Documentation

    • Updated setup, CI, and Terraform docs to document workspace, environment, and web-suffix and new secrets/vars
  • Tests

    • Added tests for workspace-slug generation and environment-specific client health endpoints

Review Change Stack

kadams54 and others added 2 commits May 30, 2026 10:46
modal_workspace held the full URL slug rather than just the
workspace name. Added modal_environment and a modal_workspace_slug
local so each variable holds its correct semantic value.
@coderabbitai

coderabbitai Bot commented May 30, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Adds first-class Modal environment support: client library and tests accept an environment/web-suffix, control plane passes environment bindings to Modal clients and dashboard URLs, Terraform defines/validates modal_environment and modal_environment_web_suffix and wires them through module triggers and scripts, CI/workflow and docs updated.

Changes

Modal Environment Configuration and Deployment

Layer / File(s) Summary
Type Contracts and Environment Bindings
packages/control-plane/src/types.ts
Env interface adds MODAL_ENVIRONMENT and MODAL_ENVIRONMENT_WEB_SUFFIX optional bindings.
Modal Client Library – Environment Parameter Support
packages/control-plane/src/sandbox/client.ts, packages/control-plane/src/sandbox/providers/modal-provider.ts
New exported buildModalWorkspaceSlug() function; getModalBaseUrl() accepts optional environmentWebSuffix; ModalClient constructor and createModalClient() factory updated to accept and pass through environmentWebSuffix for environment-specific endpoint construction.
Modal Client Tests
packages/control-plane/src/sandbox/client.test.ts
Test coverage for buildModalWorkspaceSlug() workspace passthrough and suffix appending; ModalClient test verifies fetch targets environment-specific health endpoint when initialized with explicit environment string.
Control Plane Runtime Integration
packages/control-plane/src/routes/repo-images.ts, packages/control-plane/src/session/durable-object.ts
Route handlers and session durable object pass MODAL_ENVIRONMENT_WEB_SUFFIX to Modal client initialization and MODAL_ENVIRONMENT when building sandbox dashboard URLs.
Terraform Variable Definition with Validation
terraform/environments/production/variables.tf, terraform/modules/modal-app/variables.tf
Define modal_environment (default "main") and modal_environment_web_suffix (default "") with conditional validation rejecting invalid characters (:, /, \) when Modal sandbox provider is active.
Terraform Module Logic – Workspace Slug and Triggers
terraform/modules/modal-app/main.tf, terraform/modules/modal-app/outputs.tf
Compute local.modal_workspace_slug conditionally based on modal_environment_web_suffix; wire modal_environment into null resource triggers for secret creation and deployment; pass MODAL_ENVIRONMENT via provisioner environment to shell scripts.
Terraform Production Environment Wiring
terraform/environments/production/modal.tf, terraform/environments/production/workers-control-plane.tf
Wire modal_environment and modal_environment_web_suffix inputs through production modal_app module; extend control-plane worker bindings to emit all three Modal environment configuration variables.
Deployment and Secret Scripts – Environment Validation
terraform/modules/modal-app/scripts/create-secrets.sh, terraform/modules/modal-app/scripts/deploy.sh
Add MODAL_ENVIRONMENT as required environment variable with validation that fails fast on missing values; log target environment when starting secret creation and deployment.
GitHub Actions Terraform Workflow
.github/workflows/terraform.yml
Pass TF_VAR_modal_environment from GitHub secrets to Plan and Apply jobs, defaulting to 'main' when secret is unset.
End-User Documentation and Examples
docs/GETTING_STARTED.md, terraform/README.md, terraform/environments/production/terraform.tfvars.example
Update getting-started guide with Modal environment and web suffix setup instructions; document Modal environment in Terraform README with GitHub Secrets and module usage examples; provide terraform.tfvars example with new variables.

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly Related PRs

Suggested reviewers

  • open-inspect

"A rabbit hops with keys and code,
weaving envs where slugs will go.
Secrets set, workflows sing,
modal worlds prepared for spring.
Deploy with hops — the endpoints show!"

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix(modal): support non-main Modal environments' clearly and concisely describes the main change: adding support for Modal environments beyond 'main', which aligns with the PR's core objective of adding modal_environment and modal_environment_web_suffix configuration.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/modal-non-main-envs

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.

@github-actions

Copy link
Copy Markdown

Terraform Validation Results

Step Status
Format
Init
Validate

Note: Terraform plan was skipped because secrets are not configured. This is expected for external contributors. See docs/GETTING_STARTED.md for setup instructions.

Pushed by: @ColeMurray, Action: pull_request

Comment thread terraform/environments/production/modal.tf Outdated
Comment thread packages/control-plane/src/sandbox/client.ts Outdated

@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

🧹 Nitpick comments (2)
terraform/modules/modal-app/variables.tf (1)

23-27: ⚡ Quick win

Add module-level validation for modal_environment.

This module input is externally callable, so it should reject empty values and invalid path delimiters at the module boundary too (not only in the production wrapper).

Proposed diff
 variable "modal_environment" {
   description = "Modal environment name used by the Modal CLI"
   type        = string
   default     = "main"
+
+  validation {
+    condition     = length(var.modal_environment) > 0 && can(regex("^[^:/]+$", var.modal_environment))
+    error_message = "modal_environment must be non-empty and must not contain colons or slashes."
+  }
 }
🤖 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 `@terraform/modules/modal-app/variables.tf` around lines 23 - 27, The variable
"modal_environment" lacks module-level validation allowing empty strings or path
delimiters; add a Terraform validation block on variable "modal_environment"
that enforces a non-empty value (trimmed length > 0) and rejects values
containing path delimiters (e.g., "/" or "\") by using a condition like
can(regex(...)) or (!contains(regexall("[/\\\\]", var.modal_environment), []))
inverted appropriately, and provide a clear error_message indicating the value
must be non-empty and must not contain path delimiters; place this validation
inside the existing variable "modal_environment" block.
packages/control-plane/src/sandbox/client.ts (1)

21-29: 💤 Low value

Consider removing redundant null-coalescing on line 25.

The parameter environment already defaults to DEFAULT_MODAL_ENVIRONMENT (line 23), so the || DEFAULT_MODAL_ENVIRONMENT on line 25 only handles the case where an empty string is explicitly passed. Since callers like buildModalSandboxDashboardUrl already filter empty strings before calling this function, the extra check is redundant.

♻️ Proposed simplification
 export function buildModalWorkspaceSlug(
   workspace: string,
   environment = DEFAULT_MODAL_ENVIRONMENT
 ): string {
-  const modalEnvironment = environment || DEFAULT_MODAL_ENVIRONMENT;
-  return modalEnvironment === DEFAULT_MODAL_ENVIRONMENT
+  return environment === DEFAULT_MODAL_ENVIRONMENT
     ? workspace
-    : `${workspace}-${modalEnvironment}`;
+    : `${workspace}-${environment}`;
 }
🤖 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 `@packages/control-plane/src/sandbox/client.ts` around lines 21 - 29, The
modalEnvironment null-coalescing is redundant: inside buildModalWorkspaceSlug
the parameter environment already defaults to DEFAULT_MODAL_ENVIRONMENT, so
remove the unnecessary "environment || DEFAULT_MODAL_ENVIRONMENT" usage (or the
separate modalEnvironment variable) and use environment directly when comparing
to DEFAULT_MODAL_ENVIRONMENT; ensure callers such as
buildModalSandboxDashboardUrl that filter empty strings remain unchanged.
🤖 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 `@terraform/modules/modal-app/scripts/deploy.sh`:
- Around line 29-33: Echoing environment variables (APP_NAME, DEPLOY_PATH,
DEPLOY_MODULE, MODAL_ENVIRONMENT) before validating them can trigger
unbound-variable errors under set -u; update deploy.sh to validate all required
env vars at the top (check APP_NAME, DEPLOY_PATH, DEPLOY_MODULE and optionally
MODAL_ENVIRONMENT) and exit with a clear error message if any are missing, then
perform the echo lines, ensuring checks occur before any reference to those
variables.

---

Nitpick comments:
In `@packages/control-plane/src/sandbox/client.ts`:
- Around line 21-29: The modalEnvironment null-coalescing is redundant: inside
buildModalWorkspaceSlug the parameter environment already defaults to
DEFAULT_MODAL_ENVIRONMENT, so remove the unnecessary "environment ||
DEFAULT_MODAL_ENVIRONMENT" usage (or the separate modalEnvironment variable) and
use environment directly when comparing to DEFAULT_MODAL_ENVIRONMENT; ensure
callers such as buildModalSandboxDashboardUrl that filter empty strings remain
unchanged.

In `@terraform/modules/modal-app/variables.tf`:
- Around line 23-27: The variable "modal_environment" lacks module-level
validation allowing empty strings or path delimiters; add a Terraform validation
block on variable "modal_environment" that enforces a non-empty value (trimmed
length > 0) and rejects values containing path delimiters (e.g., "/" or "\") by
using a condition like can(regex(...)) or (!contains(regexall("[/\\\\]",
var.modal_environment), [])) inverted appropriately, and provide a clear
error_message indicating the value must be non-empty and must not contain path
delimiters; place this validation inside the existing variable
"modal_environment" block.
🪄 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

Run ID: 208b07f5-a791-4283-a469-7ad879826192

📥 Commits

Reviewing files that changed from the base of the PR and between 7a216a9 and e22e9f9.

📒 Files selected for processing (18)
  • .github/workflows/terraform.yml
  • docs/GETTING_STARTED.md
  • packages/control-plane/src/routes/repo-images.ts
  • packages/control-plane/src/sandbox/client.test.ts
  • packages/control-plane/src/sandbox/client.ts
  • packages/control-plane/src/sandbox/providers/modal-provider.ts
  • packages/control-plane/src/session/durable-object.ts
  • packages/control-plane/src/types.ts
  • terraform/README.md
  • terraform/environments/production/locals.tf
  • terraform/environments/production/modal.tf
  • terraform/environments/production/terraform.tfvars.example
  • terraform/environments/production/variables.tf
  • terraform/environments/production/workers-control-plane.tf
  • terraform/modules/modal-app/main.tf
  • terraform/modules/modal-app/scripts/create-secrets.sh
  • terraform/modules/modal-app/scripts/deploy.sh
  • terraform/modules/modal-app/variables.tf

Comment thread terraform/modules/modal-app/scripts/deploy.sh
open-inspect[bot]
open-inspect Bot previously requested changes May 30, 2026

@open-inspect open-inspect 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.

Summary

PR #687, fix(modal): support non-main Modal environments, by @ColeMurray. Reviewed 18 changed files (+158/-38); the plumbing for MODAL_ENVIRONMENT through Terraform, GitHub Actions, scripts, and the control plane is mostly cohesive, but there is a blocking correctness issue in how Modal endpoint URLs are derived.

Critical Issues

  • [Correctness] packages/control-plane/src/sandbox/client.ts:24 - Modal endpoint URLs use the environment web suffix, not necessarily the environment name. The control plane and Terraform currently derive workspace-environment--... from MODAL_ENVIRONMENT, which can target the wrong host for environments whose web suffix differs from the environment name, for main environments with a non-empty suffix, or for another environment with the empty suffix. I left an inline comment with suggested fixes.

Suggestions

None beyond the blocking URL-source issue.

Nitpicks

None.

Positive Feedback

  • The change consistently threads MODAL_ENVIRONMENT into Modal deploys, secret creation, control-plane bindings, and repo-image client creation.
  • The scripts now fail fast when the Modal environment is missing, which avoids silently deploying/seeding secrets into the wrong environment.
  • The added tests cover default main behavior, non-main endpoint generation, dashboard URLs, and URL component encoding.

Questions

None.

Verdict

Request Changes: please separate the CLI environment name from the Modal endpoint web suffix/source slug, or otherwise use a Modal-provided deployed URL instead of deriving endpoint hosts from MODAL_ENVIRONMENT.

@github-actions

Copy link
Copy Markdown

Terraform Validation Results

Step Status
Format
Init
Validate

Note: Terraform plan was skipped because secrets are not configured. This is expected for external contributors. See docs/GETTING_STARTED.md for setup instructions.

Pushed by: @ColeMurray, Action: pull_request

@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: 2

🤖 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 `@terraform/environments/production/variables.tf`:
- Around line 92-93: The validation regex for modal_environment_web_suffix
currently only forbids colons, slashes, and backslashes but allows internal
whitespace; update the regex in the condition expression to also reject any
whitespace by changing regex("^[^:/\\\\]+$", var.modal_environment_web_suffix)
to regex("^[^[:space:]:/\\\\]+$", var.modal_environment_web_suffix) (keep the
surrounding logic and error_message the same) so values like "prod env" are
rejected.

In `@terraform/modules/modal-app/variables.tf`:
- Around line 40-41: Update the validation for modal_environment_web_suffix to
reject any whitespace characters; replace the current complex
trimspace/length/regex check with a single regex that forbids whitespace,
colons, slashes and backslashes. For example, change the condition to allow
empty string or can(regex("^[^\\s:/\\\\]+$", var.modal_environment_web_suffix))
so modal_environment_web_suffix either is "" or matches the
no-whitespace/no-colon/no-slash/no-backslash pattern.
🪄 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

Run ID: 2236873d-df4a-4254-89fe-4c5a4cdecce0

📥 Commits

Reviewing files that changed from the base of the PR and between e22e9f9 and 635721a.

📒 Files selected for processing (17)
  • .github/workflows/terraform.yml
  • docs/GETTING_STARTED.md
  • packages/control-plane/src/routes/repo-images.ts
  • packages/control-plane/src/sandbox/client.test.ts
  • packages/control-plane/src/sandbox/client.ts
  • packages/control-plane/src/sandbox/providers/modal-provider.ts
  • packages/control-plane/src/session/durable-object.ts
  • packages/control-plane/src/types.ts
  • terraform/README.md
  • terraform/environments/production/modal.tf
  • terraform/environments/production/terraform.tfvars.example
  • terraform/environments/production/variables.tf
  • terraform/environments/production/workers-control-plane.tf
  • terraform/modules/modal-app/main.tf
  • terraform/modules/modal-app/outputs.tf
  • terraform/modules/modal-app/scripts/deploy.sh
  • terraform/modules/modal-app/variables.tf
✅ Files skipped from review due to trivial changes (3)
  • terraform/modules/modal-app/outputs.tf
  • packages/control-plane/src/sandbox/providers/modal-provider.ts
  • docs/GETTING_STARTED.md
🚧 Files skipped from review as they are similar to previous changes (7)
  • packages/control-plane/src/types.ts
  • .github/workflows/terraform.yml
  • terraform/modules/modal-app/scripts/deploy.sh
  • terraform/modules/modal-app/main.tf
  • terraform/environments/production/workers-control-plane.tf
  • packages/control-plane/src/sandbox/client.ts
  • packages/control-plane/src/sandbox/client.test.ts

Comment thread terraform/environments/production/variables.tf Outdated
Comment thread terraform/modules/modal-app/variables.tf Outdated
@github-actions

Copy link
Copy Markdown

Terraform Validation Results

Step Status
Format
Init
Validate

Note: Terraform plan was skipped because secrets are not configured. This is expected for external contributors. See docs/GETTING_STARTED.md for setup instructions.

Pushed by: @ColeMurray, Action: pull_request

@ColeMurray

Copy link
Copy Markdown
Owner Author

Addressed the two follow-ups in 5356dc5.

  • Updated docs/GETTING_STARTED.md and terraform/README.md so manual health checks point users to terraform output verification_commands as the source of truth and show the suffix-aware Modal host shape: https://<workspace>[-<modal_environment_web_suffix>]--open-inspect-api-health.modal.run.
  • Tightened modal_environment_web_suffix validation in both Terraform variable layers to allow only empty, lowercase letters, digits, and dashes (^$|^[a-z0-9-]+$), so normalized-host mismatches fail early.

@github-actions

Copy link
Copy Markdown

Terraform Validation Results

Step Status
Format
Init
Validate

Note: Terraform plan was skipped because secrets are not configured. This is expected for external contributors. See docs/GETTING_STARTED.md for setup instructions.

Pushed by: @ColeMurray, Action: pull_request

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

🧹 Nitpick comments (2)
docs/GETTING_STARTED.md (2)

363-363: ⚡ Quick win

Consider showing empty string as the default example.

The comment correctly notes that empty is the value for default endpoints (https://workspace--...), but the example shows a non-empty placeholder. Since most users start with the default Modal environment, showing modal_environment_web_suffix = "" as the example would be clearer.

📝 Suggested improvement
-modal_environment_web_suffix = "your-modal-web-suffix" # Lowercase letters, digits, dashes; empty for https://workspace--... endpoints
+modal_environment_web_suffix = "" # Lowercase letters, digits, dashes; empty for https://workspace--... endpoints (use non-empty for custom environments)
🤖 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 `@docs/GETTING_STARTED.md` at line 363, Update the example for
modal_environment_web_suffix to show the empty-string default
(modal_environment_web_suffix = "") so users see the typical default for
https://workspace--... endpoints; locate and update the placeholder in the docs
where modal_environment_web_suffix is defined to use "" instead of
"your-modal-web-suffix".

637-641: 💤 Low value

Clarify the hyphen separator in the workspace slug example.

Line 640's comment shows "YOUR-WORKSPACE-YOUR-MODAL-WEB-SUFFIX", but it's ambiguous whether there's a single hyphen separator or if the placeholder names themselves include hyphens. Consider making the separator explicit.

📝 Suggested improvement
-MODAL_WORKSPACE_SLUG="YOUR-WORKSPACE" # or "YOUR-WORKSPACE-YOUR-MODAL-WEB-SUFFIX"
+MODAL_WORKSPACE_SLUG="YOUR-WORKSPACE" # or "YOUR-WORKSPACE-YOUR-SUFFIX" (workspace and suffix joined by single hyphen)
🤖 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 `@docs/GETTING_STARTED.md` around lines 637 - 641, Clarify the hyphen separator
in the MODAL_WORKSPACE_SLUG example by replacing the ambiguous
"YOUR-WORKSPACE-YOUR-MODAL-WEB-SUFFIX" with an explicit form that shows the
separator between the two placeholders (e.g., "YOUR-WORKSPACE -
YOUR-MODAL-WEB-SUFFIX" or "YOUR-WORKSPACE<hyphen>YOUR-MODAL-WEB-SUFFIX") so
readers understand the hyphen is the separator between two distinct
placeholders; update the comment and the example value for MODAL_WORKSPACE_SLUG
to use the chosen explicit notation.
🤖 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.

Nitpick comments:
In `@docs/GETTING_STARTED.md`:
- Line 363: Update the example for modal_environment_web_suffix to show the
empty-string default (modal_environment_web_suffix = "") so users see the
typical default for https://workspace--... endpoints; locate and update the
placeholder in the docs where modal_environment_web_suffix is defined to use ""
instead of "your-modal-web-suffix".
- Around line 637-641: Clarify the hyphen separator in the MODAL_WORKSPACE_SLUG
example by replacing the ambiguous "YOUR-WORKSPACE-YOUR-MODAL-WEB-SUFFIX" with
an explicit form that shows the separator between the two placeholders (e.g.,
"YOUR-WORKSPACE - YOUR-MODAL-WEB-SUFFIX" or
"YOUR-WORKSPACE<hyphen>YOUR-MODAL-WEB-SUFFIX") so readers understand the hyphen
is the separator between two distinct placeholders; update the comment and the
example value for MODAL_WORKSPACE_SLUG to use the chosen explicit notation.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e5241825-de1a-4d12-9d5f-ea83301821e9

📥 Commits

Reviewing files that changed from the base of the PR and between 2bbc122 and 5356dc5.

📒 Files selected for processing (4)
  • docs/GETTING_STARTED.md
  • terraform/README.md
  • terraform/environments/production/variables.tf
  • terraform/modules/modal-app/variables.tf
✅ Files skipped from review due to trivial changes (1)
  • terraform/README.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • terraform/modules/modal-app/variables.tf
  • terraform/environments/production/variables.tf

@ColeMurray ColeMurray merged commit 452416e into main May 30, 2026
18 checks passed
@ColeMurray ColeMurray deleted the fix/modal-non-main-envs branch May 30, 2026 22:55
hreiten added a commit to watchdog-no/background-agents that referenced this pull request May 31, 2026
* Allow Slack sessions to use OpenCode titles (ColeMurray#685)

## Summary
- Stop pre-filling Slack-created session titles from the Slack message
or repo fallback
- Leave Slack session titles unset so OpenCode-generated title events
can populate them
- Add a regression assertion for the Slack session creation payload

## Validation
- npm run build -w @open-inspect/shared
- npm test -w @open-inspect/slack-bot
- npm run typecheck -w @open-inspect/slack-bot
- npm run lint -w @open-inspect/slack-bot

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Refactor**
* Removed title field from session creation requests to the control
plane.

* **Tests**
* Updated tests to verify title field is not included in session
creation requests.

<!-- review_stack_entry_start -->

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/ColeMurray/background-agents/pull/685?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)

<!-- review_stack_entry_end -->

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

* Add provider identity resolution API (ColeMurray#686)

## Summary

- Add a shared canonical user ID validator for 32-character lowercase
hex D1 user IDs.
- Add an internal HMAC-authenticated `PUT
/provider-identities/:provider/:providerUserId` control-plane route that
upserts provider identity metadata through
`UserStore.resolveOrCreateUser` and returns the canonical `userId`.
- Add browser-facing `GET /api/me`, deriving GitHub identity from the
server-side NextAuth session and returning only the canonical user ID.

## Validation

- `npm run build -w @open-inspect/shared`
- `npm test -w @open-inspect/shared -- user-id`
- `npm run typecheck -w @open-inspect/shared`
- `npm run lint -w @open-inspect/shared -- --quiet`
- `npm test -w @open-inspect/control-plane --
routes/provider-identities.test.ts router.provider-identities.test.ts`
- `npm run typecheck -w @open-inspect/control-plane`
- `npm run lint -w @open-inspect/control-plane -- --quiet`
- `npm test -w @open-inspect/web -- app/api/me/route.test.ts`
- `npm run typecheck -w @open-inspect/web`
- `npm run lint -w @open-inspect/web -- --quiet`


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* New API to return the authenticated user's GitHub-derived identity and
canonical user ID.
* New endpoints to upsert GitHub provider identities and return a
canonical user ID.
* Shared validator ensuring canonical 32-character lowercase hex user
IDs.

* **Bug Fixes**
* Improved input validation and explicit error responses for invalid
provider-user IDs and malformed requests.
* Better error handling when identity resolution returns unexpected
values.

* **Tests**
* Added integration and unit tests covering success, validation
failures, and error paths.

<!-- review_stack_entry_start -->

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/ColeMurray/background-agents/pull/686?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)

<!-- review_stack_entry_end -->
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

* Filter sessions by creator (ColeMurray#688)

## Summary
- Add `createdBy` session-list filtering for canonical user IDs in the
control plane and web BFF
- Add a sidebar All/Mine filter that resolves the current canonical user
via `/api/me`
- Revalidate all session-list SWR cache variants and add a D1 index for
creator-filtered recency queries

## Validation
- `npm test -w @open-inspect/control-plane --
src/db/session-index.test.ts`
- `npm run test:integration -w @open-inspect/control-plane --
test/integration/auth.test.ts`
- `npm test -w @open-inspect/web -- src/lib/session-list.test.ts
src/lib/control-plane-query.test.ts
src/components/session-sidebar.test.tsx`
- `npm run typecheck -w @open-inspect/control-plane`
- `npm run lint -w @open-inspect/control-plane -- --quiet`
- `npm run typecheck -w @open-inspect/web`
- `npm run lint -w @open-inspect/web -- --quiet`
- `npm run build -w @open-inspect/shared`
- `npm run build -w @open-inspect/control-plane`
- `npm run build -w @open-inspect/web`
- `npx prettier --check ...changed TS/TSX files`
- `git diff --check`


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Sidebar ownership filter (All vs Mine); session list supports
filtering by creator (createdBy) and scope=mine resolves the current
user.

* **Performance**
  * New DB index to speed creator-filtered session queries.

* **Improvements**
* Unified session-list cache keys and more reliable cache invalidation
for rename, archive/unarchive, and pagination.

* **Bug Fixes**
  * Invalid createdBy or scope now return proper 400 errors.

* **Tests**
* Added coverage for createdBy/scope handling, cache-key behavior, and
related flows.

<!-- review_stack_entry_start -->

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/ColeMurray/background-agents/pull/688?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)

<!-- review_stack_entry_end -->
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

* fix(modal): support non-main Modal environments (ColeMurray#687)

## Summary
- Takes over ColeMurray#629 on a new branch because the original PR head is
company-owned.
- Adds `modal_environment` through the Modal Terraform module so secrets
and deploy commands run in the selected Modal environment.
- Adds `modal_environment_web_suffix` / `MODAL_ENVIRONMENT_WEB_SUFFIX`
for Modal endpoint URL hosts, keeping it separate from the CLI
environment name.
- Keeps `MODAL_WORKSPACE` as the raw workspace, passes
`MODAL_ENVIRONMENT` for dashboard links, and uses the web suffix for
Modal API endpoint slugs.
- Documents the new Modal environment settings and wires them into
Terraform GitHub Actions.

## Addresses Review Feedback
- Owner thread on `terraform/environments/production/modal.tf`: Modal
CLI now receives `MODAL_ENVIRONMENT` for both secret creation and
deploys.
- Owner thread on `packages/control-plane/src/sandbox/client.ts`:
endpoint hosts now use explicit Modal web suffix instead of deriving
from environment name.
- CodeRabbit validation note on `modal_environment`: rejects empty
values, colons, slashes, and backslashes for Modal deployments,
including at the module boundary.
- CodeRabbit deploy script note: validates all required env vars before
first use under `set -u`.

## Validation
- `npm run build -w @open-inspect/shared`
- `npm test -w @open-inspect/control-plane -- --run
src/sandbox/client.test.ts`
- `npm run typecheck -w @open-inspect/control-plane`
- `npm run lint -w @open-inspect/control-plane`
- `terraform fmt -recursive -check terraform`
- `terraform -chdir=terraform/environments/production init
-backend=false`
- `terraform -chdir=terraform/environments/production validate`
- `bash -n terraform/modules/modal-app/scripts/deploy.sh`
- `bash -n terraform/modules/modal-app/scripts/create-secrets.sh`

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Add selectable Modal deployment environments and pass environment to
Modal clients and deploy tooling
* Configurable environment-to-endpoint web-suffix for Modal URLs and
health checks

* **Documentation**
* Updated setup, CI, and Terraform docs to document workspace,
environment, and web-suffix and new secrets/vars

* **Tests**
* Added tests for workspace-slug generation and environment-specific
client health endpoints

<!-- review_stack_entry_start -->

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/ColeMurray/background-agents/pull/687?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)

<!-- review_stack_entry_end -->
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Kyle Adams <kadams54@users.noreply.github.com>

* fix(slack-bot): cap App Home repo-override list under Slack's block limit (ColeMurray#689)

## Problem

The App Home tab renders **one block per repo-specific branch override**
with no upper bound (`slack-bot/src/index.ts`). Slack's `views.publish`
rejects any view over **100 blocks**, so once a user configures ~85+
repo overrides the entire Home tab fails to publish — including the UI
needed to manage those overrides, leaving the user stuck.

## Fix

- Cap rendered overrides at **50** (`MAX_RENDERED_REPO_OVERRIDES`), well
under the 100-block ceiling (~15 base blocks).
- Surface the remainder as a `…and N more` summary instead of dropping
it silently.
- Hidden overrides stay **fully manageable** via the existing "Search
repository" selector → modal, which clears any repo's override on empty
submit — so the cap strands nothing.

## Test

Adds a regression test that drives the real `app_home_opened` →
`views.publish` path with 60 overrides and asserts the published view
stays ≤ 100 blocks, renders exactly 50 rows, and includes the "10 more
overrides" note. Full slack-bot suite (87 tests) + typecheck pass.

Found while syncing this change into a downstream fork. Happy to adjust
the cap value or copy.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Improved handling of large numbers of repository overrides in the
Slack App Home interface. The interface now displays up to 50 overrides
with a summary note indicating additional hidden overrides, ensuring
functionality within Slack's technical constraints.

<!-- review_stack_entry_start -->

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/ColeMurray/background-agents/pull/689?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)

<!-- review_stack_entry_end -->

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

* Refactor Slack App Home module (ColeMurray#690)

## Summary
- move Slack App Home publishing, interaction handling, view
construction, modals, metadata, model lookup, and local Slack view types
into focused `app-home/` modules
- extract user preference persistence/resolution into
`user-preferences.ts`
- keep the `/interactions` route delegating App Home-specific payloads
while leaving generic Slack interaction handling in `index.ts`
- move App Home view unit coverage into `app-home.test.ts`

## Validation
- `npm run typecheck -w @open-inspect/slack-bot`
- `npm run lint -w @open-inspect/slack-bot`
- `npx prettier --check packages/slack-bot/src/app-home
packages/slack-bot/src/app-home.test.ts
packages/slack-bot/src/user-preferences.ts`
- `git diff --check`
- `npm test -w @open-inspect/slack-bot`

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* App Home settings: model selection, reasoning-effort choice, global
and per-repo branch overrides with modals.
* Repo search suggestions and truncated option labels to fit Slack
limits; long override lists show a “more” summary.

* **Refactor**
* Centralized App Home interaction routing and unified preference
resolution.
  * App Home publishing made asynchronous and robust.

* **Tests**
* Expanded coverage for App Home view, suggestions, truncation, and
preference updates.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Cole Murray <colemurray.cs@gmail.com>
Co-authored-by: Kyle Adams <kadams54@users.noreply.github.com>
Co-authored-by: Merlin <40275364+merlin-mk@users.noreply.github.com>
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