diff --git a/.env.example b/.env.example index 88e9712..7c76b6c 100644 --- a/.env.example +++ b/.env.example @@ -15,6 +15,8 @@ POSTGRES_PORT=5432 POSTGRES_USER=agentbase POSTGRES_PASSWORD=agentbase_dev POSTGRES_DB=agentbase +# Set to 'true' for Azure (PostgreSQL Flexible Server requires TLS); false for local Docker +POSTGRES_SSL=false # --- TypeORM Migrations --- # Set to 'true' to automatically run migrations on app startup @@ -30,8 +32,10 @@ MONGO_URI=mongodb://agentbase:agentbase_dev@localhost:27017/agentbase?authSource # --- Redis --- REDIS_HOST=localhost +# Local: 6379 (no TLS). Azure Cache for Redis: 6380 (TLS required) REDIS_PORT=6379 REDIS_PASSWORD=agentbase_dev +REDIS_TLS=false # --- JWT Authentication --- JWT_SECRET=CHANGE_ME_TO_A_RANDOM_SECRET_KEY @@ -53,6 +57,8 @@ ENCRYPTION_KEY= # --- AI Service --- AI_SERVICE_URL=http://localhost:8000 AI_SERVICE_PORT=8000 +# Used by the ai-service for CORS allow_origins (must match the running core URL) +CORE_API_URL=http://localhost:3001 # --- Marketplace --- MARKETPLACE_URL=https://marketplace.agentbase.dev/api/v1 @@ -67,10 +73,11 @@ GOOGLE_CLIENT_ID= GOOGLE_CLIENT_SECRET= GOOGLE_CALLBACK_URL=http://localhost:3001/api/auth/google/callback -# --- Stripe (Phase 4) --- +# --- Stripe --- STRIPE_SECRET_KEY= STRIPE_WEBHOOK_SECRET= -STRIPE_PUBLISHABLE_KEY= +# Must use NEXT_PUBLIC_ prefix so Next.js exposes it to the browser +NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY= # --- Email (optional) --- SMTP_HOST= @@ -83,7 +90,12 @@ EMAIL_FROM=noreply@agentbase.dev # Generate with: node -e "console.log(require('crypto').randomBytes(32).toString('hex'))" PLUGIN_SETTINGS_ENCRYPTION_KEY= -# --- File Uploads (Phase 5) --- +# --- File Uploads --- +# Azure Blob Storage (preferred in Azure deployments — uses managed identity, no keys needed) +AZURE_STORAGE_ACCOUNT= +AZURE_STORAGE_BLOB_ENDPOINT= +AZURE_STORAGE_CONTAINER=uploads +# S3-compatible storage (local/non-Azure deployments; MinIO works for local dev) S3_BUCKET= S3_REGION=us-east-1 S3_ACCESS_KEY= diff --git a/azure-pipelines/agentbase-deploy.yml b/azure-pipelines/agentbase-deploy.yml index 0960f04..a582e7b 100644 --- a/azure-pipelines/agentbase-deploy.yml +++ b/azure-pipelines/agentbase-deploy.yml @@ -7,12 +7,13 @@ # # Prerequisites (one-time, see docs/azure/pipeline.md): # • Variable group 'agentbase-deploy-config' with: -# AZURE_SERVICE_CONNECTION — Azure RM service connection name +# AZURE_SERVICE_CONNECTION_STAGING — Azure RM service connection scoped to RG_STAGING only +# AZURE_SERVICE_CONNECTION_PROD — Azure RM service connection scoped to RG_PROD only # RG_STAGING, RG_PROD — target resource groups # PG_ADMIN_PASSWORD — (secret) PostgreSQL admin password # TEARDOWN_RESOURCE_GROUP — RG the teardown stage deletes (when enabled) # (optional, secret) STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET, -# OPENAI_API_KEY, ANTHROPIC_API_KEY, GEMINI_API_KEY +# OPENAI_API_KEY, ANTHROPIC_API_KEY, GEMINI_API_KEY, HUGGINGFACE_API_KEY # • Environments 'agentbase-staging' and 'agentbase-prod'; add a manual-approval # check on 'agentbase-prod' to gate production. # ============================================================================= @@ -62,7 +63,7 @@ stages: - task: AzureCLI@2 displayName: 'az bicep build + what-if (staging)' inputs: - azureSubscription: $(AZURE_SERVICE_CONNECTION) + azureSubscription: $(AZURE_SERVICE_CONNECTION_STAGING) scriptType: bash scriptLocation: inlineScript inlineScript: | @@ -128,6 +129,7 @@ stages: environment: staging resourceGroup: $(RG_STAGING) parameterFile: infra/main.parameters.staging.json + serviceConnection: $(AZURE_SERVICE_CONNECTION_STAGING) dependsOn: [Validate] # --------------------------------------------------------------------------- @@ -139,6 +141,7 @@ stages: environment: prod resourceGroup: $(RG_PROD) parameterFile: infra/main.parameters.prod.json + serviceConnection: $(AZURE_SERVICE_CONNECTION_PROD) dependsOn: [Deploy_staging] # --------------------------------------------------------------------------- @@ -157,7 +160,7 @@ stages: - task: AzureCLI@2 displayName: 'Delete resource group' inputs: - azureSubscription: $(AZURE_SERVICE_CONNECTION) + azureSubscription: $(AZURE_SERVICE_CONNECTION_PROD) scriptType: bash scriptLocation: inlineScript inlineScript: | diff --git a/azure-pipelines/scripts/seed-keyvault.sh b/azure-pipelines/scripts/seed-keyvault.sh index 2ea9be5..658334b 100644 --- a/azure-pipelines/scripts/seed-keyvault.sh +++ b/azure-pipelines/scripts/seed-keyvault.sh @@ -80,5 +80,6 @@ set_secret stripe-webhook-secret "$(or_placeholder "${STRIPE_WEBHOOK_SECRET:-}") set_secret openai-api-key "$(or_placeholder "${OPENAI_API_KEY:-}")" set_secret anthropic-api-key "$(or_placeholder "${ANTHROPIC_API_KEY:-}")" set_secret gemini-api-key "$(or_placeholder "${GEMINI_API_KEY:-}")" +set_secret huggingface-api-key "$(or_placeholder "${HUGGINGFACE_API_KEY:-}")" echo "Key Vault seeding complete." diff --git a/azure-pipelines/templates/deploy-env.yml b/azure-pipelines/templates/deploy-env.yml index 95ded6a..9a893d5 100644 --- a/azure-pipelines/templates/deploy-env.yml +++ b/azure-pipelines/templates/deploy-env.yml @@ -13,6 +13,8 @@ parameters: type: string - name: parameterFile # infra/main.parameters..json type: string + - name: serviceConnection # Azure RM service connection scoped to this environment + type: string - name: dependsOn type: object default: [] @@ -37,7 +39,7 @@ stages: - task: AzureCLI@2 displayName: '1 · Deploy infrastructure (Bicep)' inputs: - azureSubscription: $(AZURE_SERVICE_CONNECTION) + azureSubscription: ${{ parameters.serviceConnection }} scriptType: bash scriptLocation: inlineScript inlineScript: | @@ -68,7 +70,7 @@ stages: - task: AzureCLI@2 displayName: '2 · Build & push images (az acr build)' inputs: - azureSubscription: $(AZURE_SERVICE_CONNECTION) + azureSubscription: ${{ parameters.serviceConnection }} scriptType: bash scriptLocation: inlineScript inlineScript: | @@ -100,8 +102,9 @@ stages: OPENAI_API_KEY: $(OPENAI_API_KEY) ANTHROPIC_API_KEY: $(ANTHROPIC_API_KEY) GEMINI_API_KEY: $(GEMINI_API_KEY) + HUGGINGFACE_API_KEY: $(HUGGINGFACE_API_KEY) inputs: - azureSubscription: $(AZURE_SERVICE_CONNECTION) + azureSubscription: ${{ parameters.serviceConnection }} scriptType: bash scriptLocation: inlineScript inlineScript: | @@ -113,7 +116,7 @@ stages: - task: AzureCLI@2 displayName: '4 · Update containers & restart' inputs: - azureSubscription: $(AZURE_SERVICE_CONNECTION) + azureSubscription: ${{ parameters.serviceConnection }} scriptType: bash scriptLocation: inlineScript inlineScript: | diff --git a/infra/main.bicep b/infra/main.bicep index 24d0dbb..a1454b9 100644 --- a/infra/main.bicep +++ b/infra/main.bicep @@ -293,6 +293,9 @@ module coreApp 'modules/app-service-container.bicep' = { { name: 'JWT_REFRESH_SECRET', value: kvRef(kvUri, 'jwt-refresh-secret') } { name: 'ENCRYPTION_KEY', value: kvRef(kvUri, 'encryption-key') } { name: 'PLUGIN_SETTINGS_ENCRYPTION_KEY', value: kvRef(kvUri, 'plugin-settings-encryption-key') } + // Auth token lifetimes (match .env.example defaults) + { name: 'JWT_EXPIRATION', value: '24h' } + { name: 'JWT_REFRESH_EXPIRATION', value: '7d' } // Payments { name: 'STRIPE_SECRET_KEY', value: kvRef(kvUri, 'stripe-secret-key') } { name: 'STRIPE_WEBHOOK_SECRET', value: kvRef(kvUri, 'stripe-webhook-secret') } @@ -338,6 +341,10 @@ module aiApp 'modules/app-service-container.bicep' = { { name: 'OPENAI_API_KEY', value: kvRef(kvUri, 'openai-api-key') } { name: 'ANTHROPIC_API_KEY', value: kvRef(kvUri, 'anthropic-api-key') } { name: 'GEMINI_API_KEY', value: kvRef(kvUri, 'gemini-api-key') } + { name: 'HUGGINGFACE_API_KEY', value: kvRef(kvUri, 'huggingface-api-key') } + // CORS allow_origins — must match the actual deployed URLs, not localhost defaults + { name: 'CORE_API_URL', value: 'https://${coreHost}' } + { name: 'FRONTEND_URL', value: 'https://${frontendHost}' } ] } }