Skip to content

refactor: extract SessionWebSocketManager from SessionDO #136

refactor: extract SessionWebSocketManager from SessionDO

refactor: extract SessionWebSocketManager from SessionDO #136

Workflow file for this run

name: Terraform
on:
push:
branches: [main]
paths:
- "terraform/**"
- "scripts/**"
- "packages/control-plane/**"
- "packages/slack-bot/**"
- "packages/modal-infra/**"
- "packages/shared/**"
- ".github/workflows/terraform.yml"
pull_request:
branches: [main]
paths:
- "terraform/**"
- "scripts/**"
- "packages/control-plane/**"
- "packages/slack-bot/**"
- "packages/modal-infra/**"
- "packages/shared/**"
- ".github/workflows/terraform.yml"
workflow_dispatch: # Allow manual trigger
permissions:
contents: read
pull-requests: write
issues: write
concurrency:
group: terraform-${{ github.ref }}
cancel-in-progress: false # Don't cancel terraform operations
env:
TF_VERSION: "1.9.0"
TF_WORKING_DIR: terraform/environments/production
jobs:
check-secrets:
name: Check Secrets
runs-on: ubuntu-latest
outputs:
has-secrets: ${{ steps.check.outputs.has-secrets }}
steps:
- name: Check if secrets are configured
id: check
run: |
if [ -n "${{ secrets.CLOUDFLARE_API_TOKEN }}" ] && [ -n "${{ secrets.R2_ACCESS_KEY_ID }}" ]; then
echo "has-secrets=true" >> $GITHUB_OUTPUT
else
echo "has-secrets=false" >> $GITHUB_OUTPUT
echo "::notice::Terraform plan/apply skipped - secrets not configured. See docs/GETTING_STARTED.md for setup instructions."
fi
validate:
name: Validate
runs-on: ubuntu-latest
needs: [check-secrets]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: ${{ env.TF_VERSION }}
- name: Terraform Format Check
id: fmt
run: terraform fmt -check -recursive
working-directory: terraform
continue-on-error: true
- name: Terraform Init
id: init
run: |
terraform init -backend=false
working-directory: ${{ env.TF_WORKING_DIR }}
- name: Terraform Validate
id: validate
run: terraform validate -no-color
working-directory: ${{ env.TF_WORKING_DIR }}
- name: Post Validation Results
if: github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
script: |
const hasSecrets = '${{ needs.check-secrets.outputs.has-secrets }}' === 'true';
const planNote = hasSecrets
? ''
: '\n\n> **Note:** Terraform plan was skipped because secrets are not configured. This is expected for external contributors. See [docs/GETTING_STARTED.md](docs/GETTING_STARTED.md) for setup instructions.';
const output = `### Terraform Validation Results
| Step | Status |
|------|--------|
| Format | ${{ steps.fmt.outcome == 'success' && '✅' || '⚠️' }} |
| Init | ${{ steps.init.outcome == 'success' && '✅' || '❌' }} |
| Validate | ${{ steps.validate.outcome == 'success' && '✅' || '❌' }} |
${planNote}
*Pushed by: @${{ github.actor }}, Action: \`${{ github.event_name }}\`*`;
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: output
});
plan:
name: Plan
runs-on: ubuntu-latest
needs: [validate, check-secrets]
if: github.event_name == 'pull_request' && needs.check-secrets.outputs.has-secrets == 'true'
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "22"
cache: "npm"
- name: Install dependencies
run: npm ci
- name: Build worker packages
run: |
npm run build -w @open-inspect/shared
npm run build -w @open-inspect/control-plane
npm run build -w @open-inspect/slack-bot
- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: ${{ env.TF_VERSION }}
- name: Terraform Init
run: |
terraform init \
-backend-config="access_key=${{ secrets.R2_ACCESS_KEY_ID }}" \
-backend-config="secret_key=${{ secrets.R2_SECRET_ACCESS_KEY }}" \
-backend-config='endpoints={s3="https://${{ secrets.CLOUDFLARE_ACCOUNT_ID }}.r2.cloudflarestorage.com"}'
working-directory: ${{ env.TF_WORKING_DIR }}
- name: Terraform Plan
id: plan
run: |
terraform plan -no-color -out=tfplan 2>&1 | tee plan_output.txt
echo "plan<<EOF" >> $GITHUB_OUTPUT
cat plan_output.txt | head -c 60000 >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
working-directory: ${{ env.TF_WORKING_DIR }}
continue-on-error: true
env:
TF_VAR_cloudflare_api_token: ${{ secrets.CLOUDFLARE_API_TOKEN }}
TF_VAR_cloudflare_account_id: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
TF_VAR_cloudflare_worker_subdomain: ${{ secrets.CLOUDFLARE_WORKER_SUBDOMAIN }}
TF_VAR_vercel_api_token: ${{ secrets.VERCEL_API_TOKEN }}
TF_VAR_vercel_team_id: ${{ secrets.VERCEL_TEAM_ID }}
TF_VAR_modal_token_id: ${{ secrets.MODAL_TOKEN_ID }}
TF_VAR_modal_token_secret: ${{ secrets.MODAL_TOKEN_SECRET }}
TF_VAR_modal_workspace: ${{ secrets.MODAL_WORKSPACE }}
TF_VAR_github_client_id: ${{ secrets.GH_OAUTH_CLIENT_ID }}
TF_VAR_github_client_secret: ${{ secrets.GH_OAUTH_CLIENT_SECRET }}
TF_VAR_github_app_id: ${{ secrets.GH_APP_ID }}
TF_VAR_github_app_private_key: ${{ secrets.GH_APP_PRIVATE_KEY }}
TF_VAR_github_app_installation_id: ${{ secrets.GH_APP_INSTALLATION_ID }}
TF_VAR_slack_bot_token: ${{ secrets.SLACK_BOT_TOKEN }}
TF_VAR_slack_signing_secret: ${{ secrets.SLACK_SIGNING_SECRET }}
TF_VAR_anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
TF_VAR_token_encryption_key: ${{ secrets.TOKEN_ENCRYPTION_KEY }}
TF_VAR_repo_secrets_encryption_key: ${{ secrets.REPO_SECRETS_ENCRYPTION_KEY }}
TF_VAR_internal_callback_secret: ${{ secrets.INTERNAL_CALLBACK_SECRET }}
TF_VAR_nextauth_secret: ${{ secrets.NEXTAUTH_SECRET }}
TF_VAR_modal_api_secret: ${{ secrets.MODAL_API_SECRET }}
TF_VAR_allowed_users: ${{ secrets.ALLOWED_USERS }}
TF_VAR_allowed_email_domains: ${{ secrets.ALLOWED_EMAIL_DOMAINS }}
TF_VAR_deployment_name: ${{ secrets.DEPLOYMENT_NAME }}
- name: Post Plan Results
uses: actions/github-script@v7
with:
script: |
const planOutcome = '${{ steps.plan.outcome }}';
const plan = `${{ steps.plan.outputs.plan }}`;
const truncatedPlan = plan.length > 60000
? plan.substring(0, 60000) + '\n... (truncated)'
: plan;
const output = `### Terraform Plan Results
**Status:** ${planOutcome === 'success' ? '✅ Success' : '❌ Failed'}
<details><summary>Show Plan</summary>
\`\`\`terraform
${truncatedPlan}
\`\`\`
</details>
*Pushed by: @${{ github.actor }}*`;
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: output
});
- name: Plan Status
if: steps.plan.outcome == 'failure'
run: exit 1
apply:
name: Apply
runs-on: ubuntu-latest
needs: [validate, check-secrets]
if: (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && github.ref == 'refs/heads/main' && needs.check-secrets.outputs.has-secrets == 'true'
environment: production
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "22"
cache: "npm"
- name: Install dependencies
run: npm ci
- name: Build worker packages
run: |
npm run build -w @open-inspect/shared
npm run build -w @open-inspect/control-plane
npm run build -w @open-inspect/slack-bot
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install Modal CLI and dependencies
run: pip install modal fastapi pydantic httpx PyJWT
- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: ${{ env.TF_VERSION }}
- name: Terraform Init
run: |
terraform init \
-backend-config="access_key=${{ secrets.R2_ACCESS_KEY_ID }}" \
-backend-config="secret_key=${{ secrets.R2_SECRET_ACCESS_KEY }}" \
-backend-config='endpoints={s3="https://${{ secrets.CLOUDFLARE_ACCOUNT_ID }}.r2.cloudflarestorage.com"}'
working-directory: ${{ env.TF_WORKING_DIR }}
- name: Terraform Apply
run: terraform apply -auto-approve
working-directory: ${{ env.TF_WORKING_DIR }}
env:
TF_VAR_cloudflare_api_token: ${{ secrets.CLOUDFLARE_API_TOKEN }}
TF_VAR_cloudflare_account_id: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
TF_VAR_cloudflare_worker_subdomain: ${{ secrets.CLOUDFLARE_WORKER_SUBDOMAIN }}
TF_VAR_vercel_api_token: ${{ secrets.VERCEL_API_TOKEN }}
TF_VAR_vercel_team_id: ${{ secrets.VERCEL_TEAM_ID }}
TF_VAR_modal_token_id: ${{ secrets.MODAL_TOKEN_ID }}
TF_VAR_modal_token_secret: ${{ secrets.MODAL_TOKEN_SECRET }}
TF_VAR_modal_workspace: ${{ secrets.MODAL_WORKSPACE }}
TF_VAR_github_client_id: ${{ secrets.GH_OAUTH_CLIENT_ID }}
TF_VAR_github_client_secret: ${{ secrets.GH_OAUTH_CLIENT_SECRET }}
TF_VAR_github_app_id: ${{ secrets.GH_APP_ID }}
TF_VAR_github_app_private_key: ${{ secrets.GH_APP_PRIVATE_KEY }}
TF_VAR_github_app_installation_id: ${{ secrets.GH_APP_INSTALLATION_ID }}
TF_VAR_slack_bot_token: ${{ secrets.SLACK_BOT_TOKEN }}
TF_VAR_slack_signing_secret: ${{ secrets.SLACK_SIGNING_SECRET }}
TF_VAR_anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
TF_VAR_token_encryption_key: ${{ secrets.TOKEN_ENCRYPTION_KEY }}
TF_VAR_repo_secrets_encryption_key: ${{ secrets.REPO_SECRETS_ENCRYPTION_KEY }}
TF_VAR_internal_callback_secret: ${{ secrets.INTERNAL_CALLBACK_SECRET }}
TF_VAR_nextauth_secret: ${{ secrets.NEXTAUTH_SECRET }}
TF_VAR_modal_api_secret: ${{ secrets.MODAL_API_SECRET }}
TF_VAR_allowed_users: ${{ secrets.ALLOWED_USERS }}
TF_VAR_allowed_email_domains: ${{ secrets.ALLOWED_EMAIL_DOMAINS }}
TF_VAR_deployment_name: ${{ secrets.DEPLOYMENT_NAME }}
MODAL_TOKEN_ID: ${{ secrets.MODAL_TOKEN_ID }}
MODAL_TOKEN_SECRET: ${{ secrets.MODAL_TOKEN_SECRET }}
- name: Post Apply Results
if: always()
run: |
echo "### Terraform Apply Results"
echo "Status: ${{ job.status }}"
echo "Commit: ${{ github.sha }}"
echo "Environment: production"
echo "Applied by: ${{ github.actor }}"