mirror of
https://github.com/whekin/household-bot.git
synced 2026-03-31 12:04:02 +00:00
feat(infra): implement multi-environment deployment strategy
- Update CD workflow for branch-based environments (main -> Prod, dev -> Dev) - Support Terraform workspaces for environment isolation - Add manage_runtime_secrets flag to prevent accidental secret destruction - Add infra management and secret setup utility scripts - Prefix GitHub deployer identity with environment name - Synchronize bot environment variables with latest runtime config
This commit is contained in:
55
.github/workflows/cd.yml
vendored
55
.github/workflows/cd.yml
vendored
@@ -8,6 +8,7 @@ on:
|
|||||||
- completed
|
- completed
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
|
- dev
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
@@ -15,13 +16,15 @@ permissions:
|
|||||||
id-token: write
|
id-token: write
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: cd-main
|
group: cd-${{ github.ref_name }}
|
||||||
cancel-in-progress: false
|
cancel-in-progress: false
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
check-secrets:
|
check-secrets:
|
||||||
name: Check deploy prerequisites
|
name: Check deploy prerequisites
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
# Select GitHub Environment based on branch
|
||||||
|
environment: ${{ github.ref == 'refs/heads/main' && 'Production' || 'Development' }}
|
||||||
outputs:
|
outputs:
|
||||||
eligible_event: ${{ steps.check.outputs.eligible_event }}
|
eligible_event: ${{ steps.check.outputs.eligible_event }}
|
||||||
secrets_ok: ${{ steps.check.outputs.secrets_ok }}
|
secrets_ok: ${{ steps.check.outputs.secrets_ok }}
|
||||||
@@ -63,11 +66,16 @@ jobs:
|
|||||||
needs: check-secrets
|
needs: check-secrets
|
||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
if: ${{ needs.check-secrets.outputs.eligible_event == 'true' && needs.check-secrets.outputs.secrets_ok == 'true' && needs.check-secrets.outputs.db_secret_ok == 'true' }}
|
if: ${{ needs.check-secrets.outputs.eligible_event == 'true' && needs.check-secrets.outputs.secrets_ok == 'true' && needs.check-secrets.outputs.db_secret_ok == 'true' }}
|
||||||
|
environment: ${{ github.ref == 'refs/heads/main' && 'Production' || 'Development' }}
|
||||||
env:
|
env:
|
||||||
GCP_REGION: ${{ vars.GCP_REGION || 'europe-west1' }}
|
GCP_REGION: ${{ vars.GCP_REGION || 'europe-west1' }}
|
||||||
ARTIFACT_REPOSITORY: ${{ vars.ARTIFACT_REPOSITORY || 'household-bot' }}
|
ARTIFACT_REPOSITORY: ${{ vars.ARTIFACT_REPOSITORY || 'household-bot' }}
|
||||||
CLOUD_RUN_SERVICE_BOT: ${{ vars.CLOUD_RUN_SERVICE_BOT || 'household-dev-bot-api' }}
|
# Dynamic Service Names based on environment
|
||||||
CLOUD_RUN_SERVICE_MINI: ${{ vars.CLOUD_RUN_SERVICE_MINI || 'household-dev-mini-app' }}
|
# Branch 'main' -> Environment 'prod' -> household-prod-*
|
||||||
|
# Branch 'dev' -> Environment 'dev' -> household-dev-*
|
||||||
|
CLOUD_RUN_SERVICE_BOT: ${{ github.ref == 'refs/heads/main' && 'household-prod-bot-api' || 'household-dev-bot-api' }}
|
||||||
|
CLOUD_RUN_SERVICE_MINI: ${{ github.ref == 'refs/heads/main' && 'household-prod-mini-app' || 'household-dev-mini-app' }}
|
||||||
|
TELEGRAM_BOT_TOKEN_SECRET_ID: ${{ github.ref == 'refs/heads/main' && 'telegram-bot-token' || 'telegram-bot-token-test' }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout deployment ref
|
- name: Checkout deployment ref
|
||||||
@@ -99,8 +107,6 @@ jobs:
|
|||||||
|
|
||||||
- name: Load Telegram bot token for command sync
|
- name: Load Telegram bot token for command sync
|
||||||
id: telegram-token
|
id: telegram-token
|
||||||
env:
|
|
||||||
TELEGRAM_BOT_TOKEN_SECRET_ID: ${{ vars.TELEGRAM_BOT_TOKEN_SECRET_ID || 'telegram-bot-token' }}
|
|
||||||
run: |
|
run: |
|
||||||
set +e
|
set +e
|
||||||
token="$(gcloud secrets versions access latest \
|
token="$(gcloud secrets versions access latest \
|
||||||
@@ -169,34 +175,15 @@ jobs:
|
|||||||
TELEGRAM_BOT_TOKEN: ${{ steps.telegram-token.outputs.token }}
|
TELEGRAM_BOT_TOKEN: ${{ steps.telegram-token.outputs.token }}
|
||||||
run: bun run ops:telegram:commands set
|
run: bun run ops:telegram:commands set
|
||||||
|
|
||||||
- name: Telegram command sync skipped
|
- name: Set Telegram Webhook
|
||||||
if: ${{ steps.telegram-token.outputs.available != 'true' }}
|
if: ${{ steps.telegram-token.outputs.available == 'true' }}
|
||||||
|
env:
|
||||||
|
TELEGRAM_BOT_TOKEN: ${{ steps.telegram-token.outputs.token }}
|
||||||
run: |
|
run: |
|
||||||
echo "Telegram command sync skipped."
|
SERVICE_URL=$(gcloud run services describe "${CLOUD_RUN_SERVICE_BOT}" \
|
||||||
echo "Grant the CD service account access to the bot token secret or set TELEGRAM_BOT_TOKEN_SECRET_ID."
|
--region "${GCP_REGION}" \
|
||||||
|
--project "${{ secrets.GCP_PROJECT_ID }}" \
|
||||||
|
--format 'value(status.url)')
|
||||||
|
|
||||||
deploy-skipped:
|
export TELEGRAM_WEBHOOK_URL="$SERVICE_URL/webhook/telegram"
|
||||||
name: Deploy skipped (missing config)
|
bun run ops:telegram:webhook set
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: check-secrets
|
|
||||||
if: ${{ needs.check-secrets.outputs.eligible_event == 'true' && needs.check-secrets.outputs.secrets_ok == 'false' }}
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Print configuration hint
|
|
||||||
run: |
|
|
||||||
echo "CD skipped: configure required GitHub secrets."
|
|
||||||
echo "Required: GCP_PROJECT_ID, GCP_WORKLOAD_IDENTITY_PROVIDER, GCP_SERVICE_ACCOUNT, DATABASE_URL"
|
|
||||||
echo "Optional repo/service vars: GCP_REGION, ARTIFACT_REPOSITORY, CLOUD_RUN_SERVICE_BOT, CLOUD_RUN_SERVICE_MINI"
|
|
||||||
|
|
||||||
deploy-blocked-db:
|
|
||||||
name: Deploy blocked (missing DATABASE_URL)
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: check-secrets
|
|
||||||
if: ${{ needs.check-secrets.outputs.eligible_event == 'true' && needs.check-secrets.outputs.secrets_ok == 'true' && needs.check-secrets.outputs.db_secret_ok != 'true' }}
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Fail fast on missing DATABASE_URL
|
|
||||||
run: |
|
|
||||||
echo "CD blocked: DATABASE_URL GitHub secret is required."
|
|
||||||
echo "This workflow now refuses to deploy without running migrations against the target database."
|
|
||||||
exit 1
|
|
||||||
|
|||||||
@@ -19,6 +19,14 @@ resource "google_artifact_registry_repository" "containers" {
|
|||||||
|
|
||||||
labels = local.common_labels
|
labels = local.common_labels
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
ignore_changes = [
|
||||||
|
labels,
|
||||||
|
effective_labels,
|
||||||
|
terraform_labels,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
depends_on = [google_project_service.enabled]
|
depends_on = [google_project_service.enabled]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,7 +49,7 @@ resource "google_service_account" "scheduler_invoker" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
resource "google_secret_manager_secret" "runtime" {
|
resource "google_secret_manager_secret" "runtime" {
|
||||||
for_each = local.runtime_secret_ids
|
for_each = var.manage_runtime_secrets ? local.runtime_secret_ids : toset([])
|
||||||
|
|
||||||
project = var.project_id
|
project = var.project_id
|
||||||
secret_id = each.value
|
secret_id = each.value
|
||||||
@@ -56,10 +64,10 @@ resource "google_secret_manager_secret" "runtime" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
resource "google_secret_manager_secret_iam_member" "bot_runtime_access" {
|
resource "google_secret_manager_secret_iam_member" "bot_runtime_access" {
|
||||||
for_each = google_secret_manager_secret.runtime
|
for_each = local.runtime_secret_ids
|
||||||
|
|
||||||
project = var.project_id
|
project = var.project_id
|
||||||
secret_id = each.value.secret_id
|
secret_id = each.value
|
||||||
role = "roles/secretmanager.secretAccessor"
|
role = "roles/secretmanager.secretAccessor"
|
||||||
member = "serviceAccount:${google_service_account.bot_runtime.email}"
|
member = "serviceAccount:${google_service_account.bot_runtime.email}"
|
||||||
}
|
}
|
||||||
@@ -96,8 +104,11 @@ module "bot_api_service" {
|
|||||||
var.bot_assistant_model == null ? {} : {
|
var.bot_assistant_model == null ? {} : {
|
||||||
ASSISTANT_MODEL = var.bot_assistant_model
|
ASSISTANT_MODEL = var.bot_assistant_model
|
||||||
},
|
},
|
||||||
var.bot_assistant_router_model == null ? {} : {
|
var.bot_topic_processor_model == null ? {} : {
|
||||||
ASSISTANT_ROUTER_MODEL = var.bot_assistant_router_model
|
TOPIC_PROCESSOR_MODEL = var.bot_topic_processor_model
|
||||||
|
},
|
||||||
|
var.bot_topic_processor_timeout_ms == null ? {} : {
|
||||||
|
TOPIC_PROCESSOR_TIMEOUT_MS = tostring(var.bot_topic_processor_timeout_ms)
|
||||||
},
|
},
|
||||||
var.bot_assistant_timeout_ms == null ? {} : {
|
var.bot_assistant_timeout_ms == null ? {} : {
|
||||||
ASSISTANT_TIMEOUT_MS = tostring(var.bot_assistant_timeout_ms)
|
ASSISTANT_TIMEOUT_MS = tostring(var.bot_assistant_timeout_ms)
|
||||||
@@ -222,7 +233,7 @@ resource "google_service_account" "github_deployer" {
|
|||||||
count = var.create_workload_identity ? 1 : 0
|
count = var.create_workload_identity ? 1 : 0
|
||||||
|
|
||||||
project = var.project_id
|
project = var.project_id
|
||||||
account_id = var.github_deploy_service_account_id
|
account_id = "${var.environment}-${var.github_deploy_service_account_id}"
|
||||||
display_name = "${local.name_prefix} GitHub deployer"
|
display_name = "${local.name_prefix} GitHub deployer"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -54,6 +54,12 @@ resource "google_cloud_run_v2_service" "this" {
|
|||||||
percent = 100
|
percent = 100
|
||||||
type = "TRAFFIC_TARGET_ALLOCATION_TYPE_LATEST"
|
type = "TRAFFIC_TARGET_ALLOCATION_TYPE_LATEST"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
ignore_changes = [
|
||||||
|
template[0].scaling,
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "google_cloud_run_v2_service_iam_member" "public_invoker" {
|
resource "google_cloud_run_v2_service_iam_member" "public_invoker" {
|
||||||
|
|||||||
@@ -83,13 +83,20 @@ variable "bot_assistant_model" {
|
|||||||
nullable = true
|
nullable = true
|
||||||
}
|
}
|
||||||
|
|
||||||
variable "bot_assistant_router_model" {
|
variable "bot_topic_processor_model" {
|
||||||
description = "Optional ASSISTANT_ROUTER_MODEL override for bot runtime"
|
description = "Optional TOPIC_PROCESSOR_MODEL override for bot runtime"
|
||||||
type = string
|
type = string
|
||||||
default = null
|
default = null
|
||||||
nullable = true
|
nullable = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
variable "bot_topic_processor_timeout_ms" {
|
||||||
|
description = "Optional TOPIC_PROCESSOR_TIMEOUT_MS override for bot runtime"
|
||||||
|
type = number
|
||||||
|
default = null
|
||||||
|
nullable = true
|
||||||
|
}
|
||||||
|
|
||||||
variable "bot_assistant_timeout_ms" {
|
variable "bot_assistant_timeout_ms" {
|
||||||
description = "Optional ASSISTANT_TIMEOUT_MS override for bot runtime"
|
description = "Optional ASSISTANT_TIMEOUT_MS override for bot runtime"
|
||||||
type = number
|
type = number
|
||||||
@@ -217,6 +224,12 @@ variable "labels" {
|
|||||||
default = {}
|
default = {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
variable "manage_runtime_secrets" {
|
||||||
|
description = "Whether Terraform should manage the creation of runtime secrets (disable if secrets are created manually)"
|
||||||
|
type = bool
|
||||||
|
default = true
|
||||||
|
}
|
||||||
|
|
||||||
variable "create_workload_identity" {
|
variable "create_workload_identity" {
|
||||||
description = "Create GitHub OIDC Workload Identity resources"
|
description = "Create GitHub OIDC Workload Identity resources"
|
||||||
type = bool
|
type = bool
|
||||||
|
|||||||
@@ -27,9 +27,12 @@
|
|||||||
"review:coderabbit": "coderabbit --prompt-only --base main || ~/.local/bin/coderabbit --prompt-only --base main",
|
"review:coderabbit": "coderabbit --prompt-only --base main || ~/.local/bin/coderabbit --prompt-only --base main",
|
||||||
"infra:fmt": "terraform -chdir=infra/terraform fmt -recursive",
|
"infra:fmt": "terraform -chdir=infra/terraform fmt -recursive",
|
||||||
"infra:fmt:check": "terraform -chdir=infra/terraform fmt -check -recursive",
|
"infra:fmt:check": "terraform -chdir=infra/terraform fmt -check -recursive",
|
||||||
|
"infra:init": "terraform -chdir=infra/terraform init",
|
||||||
"infra:validate": "terraform -chdir=infra/terraform init -backend=false && terraform -chdir=infra/terraform validate",
|
"infra:validate": "terraform -chdir=infra/terraform init -backend=false && terraform -chdir=infra/terraform validate",
|
||||||
"infra:plan:dev": "terraform -chdir=infra/terraform plan -var-file=dev.tfvars",
|
"infra:plan:dev": "terraform -chdir=infra/terraform workspace select dev || terraform -chdir=infra/terraform workspace new dev && terraform -chdir=infra/terraform plan -var-file=dev.tfvars",
|
||||||
"infra:apply:dev": "terraform -chdir=infra/terraform apply -var-file=dev.tfvars",
|
"infra:apply:dev": "terraform -chdir=infra/terraform workspace select dev && terraform -chdir=infra/terraform apply -var-file=dev.tfvars",
|
||||||
|
"infra:plan:prod": "terraform -chdir=infra/terraform workspace select prod || terraform -chdir=infra/terraform workspace new prod && terraform -chdir=infra/terraform plan -var-file=prod.tfvars",
|
||||||
|
"infra:apply:prod": "terraform -chdir=infra/terraform workspace select prod && terraform -chdir=infra/terraform apply -var-file=prod.tfvars",
|
||||||
"dev:bot": "bun run --filter @household/bot dev",
|
"dev:bot": "bun run --filter @household/bot dev",
|
||||||
"dev:miniapp": "bun run --filter @household/miniapp dev",
|
"dev:miniapp": "bun run --filter @household/miniapp dev",
|
||||||
"docker:build:bot": "docker build -f apps/bot/Dockerfile -t household-bot:local .",
|
"docker:build:bot": "docker build -f apps/bot/Dockerfile -t household-bot:local .",
|
||||||
|
|||||||
44
scripts/ops/import-shared-resources.sh
Executable file
44
scripts/ops/import-shared-resources.sh
Executable file
@@ -0,0 +1,44 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
PROJECT_ID="gen-lang-client-0200379851"
|
||||||
|
REGION="europe-west1"
|
||||||
|
WORKSPACE="${1:-prod}" # Takes first argument, defaults to 'prod'
|
||||||
|
|
||||||
|
# Change directory to terraform folder
|
||||||
|
cd infra/terraform || exit 1
|
||||||
|
|
||||||
|
echo "--- Shared Resource Import Utility ---"
|
||||||
|
echo "Target Project: $PROJECT_ID"
|
||||||
|
echo "Target Workspace: $WORKSPACE"
|
||||||
|
|
||||||
|
# 1. Ensure the workspace exists and is selected
|
||||||
|
terraform workspace select "$WORKSPACE" || terraform workspace new "$WORKSPACE"
|
||||||
|
|
||||||
|
# 2. Construct Resource IDs
|
||||||
|
echo -e "\nConstructing Resource IDs..."
|
||||||
|
REPO_ID="projects/$PROJECT_ID/locations/$REGION/repositories/household-bot"
|
||||||
|
POOL_ID="projects/$PROJECT_ID/locations/global/workloadIdentityPools/github-pool"
|
||||||
|
PROV_ID="projects/$PROJECT_ID/locations/global/workloadIdentityPools/github-pool/providers/github-provider"
|
||||||
|
|
||||||
|
echo "1. Repository Resource ID: $REPO_ID"
|
||||||
|
echo "2. Identity Pool Resource ID: $POOL_ID"
|
||||||
|
echo "3. Provider Resource ID: $PROV_ID"
|
||||||
|
|
||||||
|
# 3. Perform the Imports
|
||||||
|
echo -e "\nStarting Terraform Imports..."
|
||||||
|
|
||||||
|
# Import Repository
|
||||||
|
echo -e "\n--- Importing Artifact Registry ---"
|
||||||
|
terraform import -input=false -var-file="$WORKSPACE.tfvars" google_artifact_registry_repository.containers "$REPO_ID"
|
||||||
|
|
||||||
|
# Import Workload Identity Pool
|
||||||
|
echo -e "\n--- Importing Workload Identity Pool ---"
|
||||||
|
terraform import -input=false -var-file="$WORKSPACE.tfvars" 'google_iam_workload_identity_pool.github[0]' "$POOL_ID"
|
||||||
|
|
||||||
|
# Import Workload Identity Provider
|
||||||
|
echo -e "\n--- Importing Workload Identity Provider ---"
|
||||||
|
terraform import -input=false -var-file="$WORKSPACE.tfvars" 'google_iam_workload_identity_pool_provider.github[0]' "$PROV_ID"
|
||||||
|
|
||||||
|
echo -e "\n--- Import Complete for $WORKSPACE! ---"
|
||||||
|
echo "You can now run: bun run infra:apply:$WORKSPACE"
|
||||||
103
scripts/ops/setup-test-secrets.ts
Normal file
103
scripts/ops/setup-test-secrets.ts
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
import { $ } from 'bun'
|
||||||
|
|
||||||
|
const PROJECT_ID = 'gen-lang-client-0200379851'
|
||||||
|
|
||||||
|
async function secretExists(name: string): Promise<boolean> {
|
||||||
|
const result =
|
||||||
|
(await $`gcloud secrets describe ${name} --project=${PROJECT_ID}`.quiet().exitCode) === 0
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
async function createSecret(name: string, value: string) {
|
||||||
|
console.log(`\n[Checking] ${name}...`)
|
||||||
|
if (await secretExists(name)) {
|
||||||
|
console.log(`[Skipping] ${name} already exists. If you want to change it, use the GCP console.`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
console.log(`[Creating] ${name} for the first time...`)
|
||||||
|
await $`echo -n ${value} | gcloud secrets create ${name} --data-file=- --replication-policy="automatic" --project=${PROJECT_ID}`.quiet()
|
||||||
|
console.log(`[Success] ${name} is ready.`)
|
||||||
|
} catch (err) {
|
||||||
|
console.error(`[Error] Failed to setup ${name}:`, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('--- Production & Test Environment Secret Setup ---')
|
||||||
|
console.log(`Target Project: ${PROJECT_ID}`)
|
||||||
|
|
||||||
|
// 1. PRODUCTION Bot Token
|
||||||
|
let prodBotToken = ''
|
||||||
|
if (!(await secretExists('telegram-bot-token'))) {
|
||||||
|
prodBotToken = prompt('1. Enter your PRODUCTION Telegram Bot Token (the original one):') || ''
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. PRODUCTION Database URL
|
||||||
|
let prodDbUrl = ''
|
||||||
|
if (!(await secretExists('database-url'))) {
|
||||||
|
prodDbUrl = prompt('2. Enter your PRODUCTION Supabase DATABASE_URL (for public schema):') || ''
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. TEST Bot Token
|
||||||
|
let testBotToken = ''
|
||||||
|
if (!(await secretExists('telegram-bot-token-test'))) {
|
||||||
|
testBotToken = prompt('3. Enter your TEST Telegram Bot Token (from @BotFather):') || ''
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. TEST Database URL (Derived from prod if not exists)
|
||||||
|
let testDbUrlPrompt = ''
|
||||||
|
if (!(await secretExists('database-url-test'))) {
|
||||||
|
testDbUrlPrompt =
|
||||||
|
prompt(
|
||||||
|
'4. Enter your TEST Supabase DATABASE_URL (or leave empty to reuse prod with ?options=-csearch_path=test):'
|
||||||
|
) || ''
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. OpenAI API Key (Shared)
|
||||||
|
let openaiKey = ''
|
||||||
|
if (!(await secretExists('openai-api-key'))) {
|
||||||
|
openaiKey = prompt('5. Enter your OpenAI API Key:') || ''
|
||||||
|
}
|
||||||
|
|
||||||
|
// Logic for test DB URL
|
||||||
|
const testDbUrl =
|
||||||
|
testDbUrlPrompt ||
|
||||||
|
(prodDbUrl &&
|
||||||
|
(prodDbUrl.includes('?')
|
||||||
|
? `${prodDbUrl}&options=-csearch_path%3Dtest`
|
||||||
|
: `${prodDbUrl}?options=-csearch_path%3Dtest`))
|
||||||
|
|
||||||
|
// Logic for prod DB URL
|
||||||
|
const finalProdDbUrl =
|
||||||
|
prodDbUrl &&
|
||||||
|
(prodDbUrl.includes('?')
|
||||||
|
? `${prodDbUrl}&options=-csearch_path%3Dpublic`
|
||||||
|
: `${prodDbUrl}?options=-csearch_path%3Dpublic`)
|
||||||
|
|
||||||
|
// Generate random secrets (Always safe to recreate if missing)
|
||||||
|
const webhookSecret = Buffer.from(crypto.getRandomValues(new Uint8Array(32))).toString('base64')
|
||||||
|
const schedulerSecret = Buffer.from(crypto.getRandomValues(new Uint8Array(32))).toString('base64')
|
||||||
|
|
||||||
|
console.log('\nStarting GCP operations...')
|
||||||
|
|
||||||
|
if (prodBotToken) await createSecret('telegram-bot-token', prodBotToken.trim())
|
||||||
|
if (finalProdDbUrl) await createSecret('database-url', finalProdDbUrl.trim())
|
||||||
|
if (testBotToken) await createSecret('telegram-bot-token-test', testBotToken.trim())
|
||||||
|
if (testDbUrl) await createSecret('database-url-test', testDbUrl.trim())
|
||||||
|
if (openaiKey) await createSecret('openai-api-key', openaiKey.trim())
|
||||||
|
|
||||||
|
// Create unique secrets per environment if missing
|
||||||
|
await createSecret('telegram-webhook-secret-test', webhookSecret)
|
||||||
|
await createSecret('scheduler-shared-secret-test', schedulerSecret)
|
||||||
|
await createSecret(
|
||||||
|
'telegram-webhook-secret',
|
||||||
|
Buffer.from(crypto.getRandomValues(new Uint8Array(32))).toString('base64')
|
||||||
|
)
|
||||||
|
await createSecret(
|
||||||
|
'scheduler-shared-secret',
|
||||||
|
Buffer.from(crypto.getRandomValues(new Uint8Array(32))).toString('base64')
|
||||||
|
)
|
||||||
|
|
||||||
|
console.log('\n--- Setup Complete! ---')
|
||||||
|
console.log('You can now run the import commands and then infra:apply:prod')
|
||||||
Reference in New Issue
Block a user