Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions .changeset/staging-host-secrets.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
"everything-dev": minor
---

Add `bos deploy` command, host secrets, and staging environment support

- **New `bos deploy` command**: Publishes config to FastKV and triggers Railway redeploy in one step. Reads service name from `ci.railway.service` in `bos.config.json`. Uses `RAILWAY_TOKEN` (environment-scoped) instead of deployment IDs.

- **New `ci` config section**: `bos.config.json` now accepts `ci.railway.service` for Railway integration. Child projects inherit this via extends.

- **Staging environment support**: `BOS_ENV=staging` or `--env staging` enables staging mode. `staging.domain` overrides `domain`, FastKV publishes under the staging gateway key, and runtime sets `env = "staging"`.

- **Host secrets**: Added `secrets` array to `app.host` for tenant-related environment variables (`TENANT_WHITELIST`, `ALLOW_OVERRIDE`, `ALLOW_UNTRUSTED_SSR`, `CSP_STRICT`). Validated during `bos start` and surfaced in `bos infra`.

- **Workflow simplification**: Replaced `publish.yml` with `deploy.yml`. `release.yml` now only handles npm package releases. `staging.yml` uses `bos deploy --env staging`. All workflows use `railway redeploy` via CLI instead of raw GraphQL API calls.

- **Removed**: `RAILWAY_PRODUCTION_SERVICE_ID` and `RAILWAY_STAGING_SERVICE_ID` variables — replaced by environment-scoped `RAILWAY_TOKEN` secrets.
10 changes: 10 additions & 0 deletions .changeset/tenant-ssr-integrity-gate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
"everything-dev": patch
"host": patch
---

Require ssrIntegrity for tenant SSR — prevent no-cache-per-request MF instance creation

Tenant SSR now requires both `ssrUrl` and `ssrIntegrity` to be present. Previously, a whitelisted tenant with `ssrUrl` but no `ssrIntegrity` would bypass the router module cache (`shouldCacheRouterModule` returns false without `ssrIntegrity`), causing a new Module Federation instance to be created on every SSR request — the same pattern that caused the production SSR failure.

Also fixes pre-existing typecheck errors in host test files (Effect Either narrowing, FederationError type annotation).
4 changes: 4 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@

# app.host
CORS_ORIGIN=http://localhost:3000
TENANT_WHITELIST=
ALLOW_OVERRIDE=
ALLOW_UNTRUSTED_SSR=
CSP_STRICT=

# app.api
API_DATABASE_URL=postgres://everythingdev:everythingdev@localhost:5432/api_db
Expand Down
Original file line number Diff line number Diff line change
@@ -1,31 +1,34 @@
name: Publish Config
name: Deploy

on:
push:
branches:
- main
paths:
- "bos.config.json"
workflow_run:
workflows: [CI]
types: [completed]
workflow_dispatch:
inputs:
deploy:
description: "Build/deploy all workspaces before publish"
required: false
default: false
type: boolean

concurrency: ${{ github.workflow }}-${{ github.ref }}

permissions:
contents: write

jobs:
publish:
if: github.event_name == 'workflow_dispatch' || !contains(github.event.head_commit.message, '[skip ci]')
deploy:
name: Deploy Production
if: >
github.event_name == 'workflow_dispatch' ||
(
github.event_name == 'workflow_run' &&
github.event.workflow_run.conclusion == 'success' &&
github.event.workflow_run.event == 'push' &&
github.event.workflow_run.head_branch == 'main'
)
runs-on: ubuntu-latest
env:
BOS_INSTALL_NEAR_CLI: "true"
NEAR_PRIVATE_KEY: ${{ secrets.NEAR_PRIVATE_KEY }}
ZE_SECRET_TOKEN: ${{ secrets.ZEPHYR_AUTH_TOKEN }}
ZE_USER_EMAIL: ${{ secrets.ZEPHYR_USER_EMAIL }}
RAILWAY_TOKEN: ${{ secrets.RAILWAY_TOKEN }}
steps:
- name: Checkout code
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
Expand All @@ -44,16 +47,14 @@ jobs:
- name: Run postinstall
run: bun run postinstall

- name: Publish app
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ] && [ "${{ inputs.deploy }}" = "true" ]; then
bun packages/everything-dev/src/cli.ts publish --deploy
else
bun packages/everything-dev/src/cli.ts publish
fi
- name: Install Railway CLI
run: npm i -g @railway/cli

- name: Deploy
run: bos deploy

- name: Commit bos.config.json updates
uses: stefanzweifel/git-auto-commit-action@b863ae1933cb653a53c021fe36dbb774e1fb9403 # v5.2.0
with:
commit_message: "chore: update deployment URLs [skip ci]"
file_pattern: "**/bos.config.json"
file_pattern: "**/bos.config.json"
54 changes: 54 additions & 0 deletions .github/templates/workflows/staging.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
name: Staging

on:
push:
branches:
- staging
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

permissions:
contents: write

jobs:
deploy-staging:
name: Deploy Staging
runs-on: ubuntu-latest
env:
BOS_INSTALL_NEAR_CLI: "true"
NEAR_PRIVATE_KEY: ${{ secrets.NEAR_PRIVATE_KEY }}
ZE_SECRET_TOKEN: ${{ secrets.ZEPHYR_AUTH_TOKEN }}
ZE_USER_EMAIL: ${{ secrets.ZEPHYR_USER_EMAIL }}
RAILWAY_TOKEN: ${{ secrets.RAILWAY_STAGING_TOKEN }}
steps:
- name: Checkout code
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1

- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
with:
bun-version: "1.2.20"

- name: Install dependencies
run: bun install --frozen-lockfile --ignore-scripts

- name: Build every-plugin
run: bun run --cwd packages/every-plugin build

- name: Run postinstall
run: bun run postinstall

- name: Install Railway CLI
run: npm i -g @railway/cli

- name: Deploy
run: bos deploy --env staging

- name: Commit bos.config.json updates
uses: stefanzweifel/git-auto-commit-action@b863ae1933cb653a53c021fe36dbb774e1fb9403 # v5.2.0
with:
commit_message: "chore: update staging deployment URLs [skip ci]"
file_pattern: "**/bos.config.json"
Original file line number Diff line number Diff line change
@@ -1,31 +1,34 @@
name: Publish Config
name: Deploy

on:
push:
branches:
- main
paths:
- "bos.config.json"
workflow_run:
workflows: [CI]
types: [completed]
workflow_dispatch:
inputs:
deploy:
description: "Build/deploy all workspaces before publish"
required: false
default: false
type: boolean

concurrency: ${{ github.workflow }}-${{ github.ref }}

permissions:
contents: write

jobs:
publish:
if: github.event_name == 'workflow_dispatch' || !contains(github.event.head_commit.message, '[skip ci]')
deploy:
name: Deploy Production
if: >
github.event_name == 'workflow_dispatch' ||
(
github.event_name == 'workflow_run' &&
github.event.workflow_run.conclusion == 'success' &&
github.event.workflow_run.event == 'push' &&
github.event.workflow_run.head_branch == 'main'
)
runs-on: ubuntu-latest
env:
BOS_INSTALL_NEAR_CLI: "true"
NEAR_PRIVATE_KEY: ${{ secrets.NEAR_PRIVATE_KEY }}
ZE_SECRET_TOKEN: ${{ secrets.ZEPHYR_AUTH_TOKEN }}
ZE_USER_EMAIL: ${{ secrets.ZEPHYR_USER_EMAIL }}
RAILWAY_TOKEN: ${{ secrets.RAILWAY_TOKEN }}
steps:
- name: Checkout code
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
Expand All @@ -38,19 +41,20 @@ jobs:
- name: Install dependencies
run: bun install --frozen-lockfile --ignore-scripts

- name: Build every-plugin
run: bun run --cwd packages/every-plugin build

- name: Run postinstall
run: bun run postinstall

- name: Publish app
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ] && [ "${{ inputs.deploy }}" = "true" ]; then
bun packages/everything-dev/src/cli.ts publish --deploy
else
bun packages/everything-dev/src/cli.ts publish
fi
- name: Install Railway CLI
run: npm i -g @railway/cli

- name: Deploy
run: bun packages/everything-dev/src/cli.ts deploy

- name: Commit bos.config.json updates
uses: stefanzweifel/git-auto-commit-action@b863ae1933cb653a53c021fe36dbb774e1fb9403 # v5.2.0
with:
commit_message: "chore: update deployment URLs [skip ci]"
file_pattern: "**/bos.config.json"
file_pattern: "**/bos.config.json"
3 changes: 2 additions & 1 deletion .github/workflows/docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
github.event_name == 'workflow_run' &&
github.event.workflow_run.conclusion == 'success' &&
github.event.workflow_run.event == 'push' &&
github.event.workflow_run.head_branch == 'main'
(github.event.workflow_run.head_branch == 'main' || github.event.workflow_run.head_branch == 'staging')
)
steps:
- name: Checkout code
Expand Down Expand Up @@ -65,6 +65,7 @@ jobs:
images: ghcr.io/${{ env.REPO }}
tags: |
type=raw,value=latest,enable={{is_default_branch}}
type=raw,value=staging,enable=${{ github.ref == 'refs/heads/staging' }}
type=ref,event=branch
type=sha

Expand Down
16 changes: 0 additions & 16 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ jobs:
github.event.workflow_run.head_branch == 'main'
)
env:
BOS_INSTALL_NEAR_CLI: "true"
TARGET_REF: ${{ inputs.ref != '' && inputs.ref || (github.event_name == 'workflow_run' && github.event.workflow_run.head_sha) || github.sha }}
outputs:
should_publish: ${{ steps.release_mode.outputs.should_publish }}
Expand Down Expand Up @@ -171,18 +170,3 @@ jobs:
--notes "$NOTES" \
--target main
done

- name: Publish runtime config
if: steps.release_mode.outputs.should_publish == 'true'
env:
NEAR_PRIVATE_KEY: ${{ secrets.NEAR_PRIVATE_KEY }}
ZE_SECRET_TOKEN: ${{ secrets.ZEPHYR_AUTH_TOKEN }}
ZE_USER_EMAIL: ${{ secrets.ZEPHYR_USER_EMAIL }}
run: bun packages/everything-dev/src/cli.ts publish --deploy

- name: Commit bos.config.json updates
if: steps.release_mode.outputs.should_publish == 'true'
uses: stefanzweifel/git-auto-commit-action@b863ae1933cb653a53c021fe36dbb774e1fb9403 # v5.2.0
with:
commit_message: "chore: update deployment URLs [skip ci]"
file_pattern: "**/bos.config.json"
55 changes: 55 additions & 0 deletions .github/workflows/staging.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
name: Staging

on:
push:
branches:
- staging
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

permissions:
contents: write
packages: write

jobs:
deploy-staging:
name: Deploy Staging
runs-on: ubuntu-latest
env:
BOS_INSTALL_NEAR_CLI: "true"
NEAR_PRIVATE_KEY: ${{ secrets.NEAR_PRIVATE_KEY }}
ZE_SECRET_TOKEN: ${{ secrets.ZEPHYR_AUTH_TOKEN }}
ZE_USER_EMAIL: ${{ secrets.ZEPHYR_USER_EMAIL }}
RAILWAY_TOKEN: ${{ secrets.RAILWAY_STAGING_TOKEN }}
steps:
- name: Checkout code
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1

- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
with:
bun-version: "1.2.20"

- name: Install dependencies
run: bun install --frozen-lockfile --ignore-scripts

- name: Build every-plugin
run: bun run --cwd packages/every-plugin build

- name: Run postinstall
run: bun run postinstall

- name: Install Railway CLI
run: npm i -g @railway/cli

- name: Deploy
run: bun packages/everything-dev/src/cli.ts deploy --env staging

- name: Commit bos.config.json updates
uses: stefanzweifel/git-auto-commit-action@b863ae1933cb653a53c021fe36dbb774e1fb9403 # v5.2.0
with:
commit_message: "chore: update staging deployment URLs [skip ci]"
file_pattern: "**/bos.config.json"
2 changes: 2 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ RUN mkdir -p .bos/generated .bos/logs && \
ENV NODE_ENV=production
ENV PORT=3000
ENV HOST=0.0.0.0
# BOS_ENV: set to "staging" to enable staging mode (uses staging domain for BOS_GATEWAY)
# Defaults to "production" if unset.
EXPOSE 3000

HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
Expand Down
Loading
Loading