Skip to Content
GuideHow-tosEnvironment Management

Environment Management

This guide shows you how to manage Probe workflows across multiple environments (development, staging, production) using configuration composition, environment-specific settings, and deployment strategies.

Basic Environment Configuration

The goal is one workflow file that runs against development, staging and production, with only the values changing.

Single Workflow, Multiple Environments

Create a base workflow that works across environments:

base-workflow.yml:

name: Multi-Environment API Test description: API testing workflow that adapts to different environments vars: api_base_url: "{{API_BASE_URL}}" environment: "{{ENVIRONMENT ?? 'Unknown'}}" default_timeout: "{{DEFAULT_TIMEOUT ?? '30s'}}" jobs: - id: api-health-check name: API Health Check defaults: http: headers: User-Agent: "Probe Test Agent" Accept: "application/json" steps: - name: Health Endpoint Test uses: http with: method: GET url: "{{vars.api_base_url}}/health" test: res.code == 200 outputs: api_healthy: res.code == 200 response_time: (rt.sec * 1000) api_version: res.body.version - name: Database Health Check uses: http with: method: GET url: "{{vars.api_base_url}}/health/database" test: res.code == 200 outputs: database_healthy: res.code == 200 db_response_time: (rt.sec * 1000) - id: environment-report name: Environment Report needs: [api-health-check] defaults: http: headers: User-Agent: "Probe Test Agent" Accept: "application/json" steps: - name: Environment Summary uses: hello echo: | 🌍 Environment Test Report ========================= Environment: {{vars.environment}} API Base URL: {{vars.api_base_url}} Health Check Results: API Health: {{outputs['api-health-check'].api_healthy ? "✅ Healthy" : "❌ Down"}} ({{outputs['api-health-check'].response_time}}ms) Database: {{outputs['api-health-check'].database_healthy ? "✅ Healthy" : "❌ Down"}} ({{outputs['api-health-check'].db_response_time}}ms) API Version: {{outputs['api-health-check'].api_version}} Environment-Specific Notes: {{vars.environment == "development" ? "• Development environment - extended timeouts enabled" : ""}} {{vars.environment == "staging" ? "• Staging environment - production-like testing" : ""}} {{vars.environment == "production" ? "• Production environment - strict validation" : ""}}

development.yml:

vars: environment: "{{ENVIRONMENT ?? 'development'}}" api_base_url: "{{API_BASE_URL ?? 'http://localhost:3000'}}" default_timeout: "{{DEFAULT_TIMEOUT ?? '60s'}}" # Development-specific additional checks jobs: - id: dev-specific-checks name: Development Environment Checks needs: [api-health-check] defaults: http: steps: - name: Hot Reload Check uses: http with: method: GET url: "{{vars.api_base_url}}/dev/hot-reload-status" test: res.code == 200 outputs: hot_reload_enabled: res.body.enabled - name: Debug Endpoints Check uses: http with: method: GET url: "{{vars.api_base_url}}/debug/info" test: res.code == 200 outputs: debug_info_available: res.code == 200 - name: Development Summary uses: hello echo: | 🛠️ Development Environment Status: Hot Reload: {{outputs.hot_reload_enabled ? "✅ Enabled" : "❌ Disabled"}} Debug Info: {{outputs.debug_info_available ? "✅ Available" : "❌ Not Available"}}

staging.yml:

vars: environment: "{{ENVIRONMENT ?? 'staging'}}" api_base_url: "{{API_BASE_URL ?? 'https://api.staging.yourcompany.com'}}" default_timeout: "{{DEFAULT_TIMEOUT ?? '30s'}}" # Staging-specific additional checks jobs: - id: staging-specific-checks name: Staging Environment Checks needs: [api-health-check] defaults: http: headers: X-Environment: staging steps: - name: Load Balancer Check uses: http with: method: GET url: "{{vars.api_base_url}}/health/load-balancer" test: res.code == 200 outputs: load_balancer_healthy: res.code == 200 backend_count: res.body.active_backends - name: Cache Layer Check uses: http with: method: GET url: "{{vars.api_base_url}}/health/cache" test: res.code == 200 outputs: cache_healthy: res.code == 200 cache_hit_rate: res.body.hit_rate - name: Integration Tests uses: http with: method: GET url: "{{vars.api_base_url}}/test/integration" test: res.code == 200 && res.body.all_tests_passed == true outputs: integration_tests_passed: res.body.all_tests_passed - name: Staging Summary uses: hello echo: | 🧪 Staging Environment Status: Load Balancer: {{outputs.load_balancer_healthy ? "✅ Healthy" : "❌ Issues"}} ({{outputs.backend_count}} backends) Cache Layer: {{outputs.cache_healthy ? "✅ Healthy" : "❌ Issues"}} ({{(outputs.cache_hit_rate * 100)}}% hit rate) Integration Tests: {{outputs.integration_tests_passed ? "✅ Passed" : "❌ Failed"}}

production.yml:

vars: environment: "{{ENVIRONMENT ?? 'production'}}" api_base_url: "{{API_BASE_URL ?? 'https://api.yourcompany.com'}}" default_timeout: "{{DEFAULT_TIMEOUT ?? '10s'}}" jobs: - id: production-specific-checks name: Production Environment Checks needs: [api-health-check] defaults: http: headers: X-Environment: production steps: - name: SSL Certificate Check uses: http with: method: GET url: "{{vars.api_base_url}}/health/ssl" test: | res.code == 200 && res.body.certificate_valid == true && res.body.days_until_expiry > 30 outputs: ssl_valid: res.body.certificate_valid ssl_days_remaining: res.body.days_until_expiry - name: Performance SLA Check uses: http with: method: GET url: "{{vars.api_base_url}}/health/performance" test: | res.code == 200 && res.body.avg_response_time < 500 && res.body.success_rate > 0.999 outputs: sla_met: res.body.avg_response_time < 500 && res.body.success_rate > 0.999 avg_response_time: res.body.avg_response_time success_rate: res.body.success_rate - name: Security Compliance Check uses: http with: method: GET url: "{{vars.api_base_url}}/health/security" test: | res.code == 200 && res.body.security_score >= 0.95 outputs: security_compliant: res.body.security_score >= 0.95 security_score: res.body.security_score - name: Production Summary uses: hello echo: | 🏭 Production Environment Status: SSL Certificate: {{outputs.ssl_valid ? "✅ Valid" : "❌ Invalid"}} ({{outputs.ssl_days_remaining}} days remaining) Performance SLA: {{outputs.sla_met ? "✅ Met" : "❌ Violated"}} - Avg Response: {{outputs.avg_response_time}}ms - Success Rate: {{(outputs.success_rate * 100)}}% Security Compliance: {{outputs.security_compliant ? "✅ Compliant" : "❌ Non-Compliant"}} ({{(outputs.security_score * 100)}}%)

Usage:

# Development environment probe base-workflow.yml,development.yml # Staging environment probe base-workflow.yml,staging.yml # Production environment probe base-workflow.yml,production.yml

Advanced Environment Management

Environments differ in more than their addresses: which features are enabled, where the credentials come from, and whether the environment is configured correctly at all.

Environment-Specific Feature Flags

Control which features are tested in different environments:

feature-flags.yml:

# Feature flags configuration vars: api_base_url: "{{API_BASE_URL}}" admin_token: "{{ADMIN_TOKEN}}" environment: "{{ENVIRONMENT}}" # Core features (always enabled) feature_user_management: true feature_basic_api: true # Environment-specific features feature_beta_api: "{{vars.environment != 'production'}}" feature_admin_tools: "{{vars.environment == 'development'}}" feature_performance_testing: "{{vars.environment != 'development'}}" feature_security_scanning: "{{vars.environment == 'production'}}" jobs: - id: core-feature-tests name: Core Feature Tests steps: - name: User Management Test uses: http with: method: GET url: "{{vars.api_base_url}}/users" test: res.code == 200 outputs: user_management_working: res.code == 200 - name: Basic API Test uses: http with: method: GET url: "{{vars.api_base_url}}/api/basic" test: res.code == 200 outputs: basic_api_working: res.code == 200 - id: beta-feature-tests name: Beta Feature Tests steps: - name: Beta API Test id: beta-feature-tests uses: http with: method: GET url: "{{vars.api_base_url}}/api/beta" test: res.code == 200 outputs: beta_api_working: res.code == 200 - id: admin-feature-tests name: Admin Feature Tests steps: - name: Admin Tools Test id: admin-feature-tests uses: http with: method: GET url: "{{vars.api_base_url}}/admin/tools" headers: Authorization: "Bearer {{vars.admin_token}}" test: res.code == 200 outputs: admin_tools_working: res.code == 200 - id: performance-tests name: Performance Tests steps: - name: Load Test id: performance-tests uses: http with: url: "{{vars.api_base_url}}/test/load" method: POST body: | { "concurrent_users": {{vars.environment == "staging" ? 10 : 50}}, "duration_seconds": {{vars.environment == "staging" ? 60 : 300}} } test: res.code == 200 outputs: load_test_passed: res.body.success - id: security-tests name: Security Tests steps: - name: Security Scan id: security-tests uses: http with: url: "{{vars.api_base_url}}/security/scan" method: POST test: res.code == 200 && res.body.vulnerabilities_found == 0 outputs: security_scan_clean: res.body.vulnerabilities_found == 0 - id: feature-summary name: Feature Test Summary needs: [core-feature-tests, beta-feature-tests, admin-feature-tests, performance-tests, security-tests] steps: - name: Environment Feature Report uses: hello echo: | 🚀 Feature Test Summary for {{vars.environment}}: ================================================ CORE FEATURES: {{vars.feature_user_management == true ? "User Management: " + (outputs['core-feature-tests'].user_management_working ? "✅ Working" : "❌ Failed") : "User Management: ⏸️ Disabled"}} {{vars.feature_basic_api == true ? "Basic API: " + (outputs['core-feature-tests'].basic_api_working ? "✅ Working" : "❌ Failed") : "Basic API: ⏸️ Disabled"}} BETA FEATURES: {{vars.feature_beta_api == true ? "Beta API: " + (outputs['beta-feature-tests'].beta_api_working ? "✅ Working" : "❌ Failed") : "Beta API: ⏸️ Disabled"}} ADMIN FEATURES: {{vars.feature_admin_tools == true ? "Admin Tools: " + (outputs['admin-feature-tests'].admin_tools_working ? "✅ Working" : "❌ Failed") : "Admin Tools: ⏸️ Disabled"}} PERFORMANCE TESTING: {{vars.feature_performance_testing == true ? "Load Testing: " + (outputs['performance-tests'].load_test_passed ? "✅ Passed" : "❌ Failed") : "Performance Testing: ⏸️ Disabled"}} SECURITY TESTING: {{vars.feature_security_scanning == true ? "Security Scan: " + (outputs['security-tests'].security_scan_clean ? "✅ Clean" : "❌ Vulnerabilities Found") : "Security Testing: ⏸️ Disabled"}} Environment Configuration: Features enabled: {{ (vars.feature_user_management == true ? 1 : 0) + (vars.feature_basic_api == true ? 1 : 0) + (vars.feature_beta_api == true ? 1 : 0) + (vars.feature_admin_tools == true ? 1 : 0) + (vars.feature_performance_testing == true ? 1 : 0) + (vars.feature_security_scanning == true ? 1 : 0) }} / 6

Credential and Secret Management

Manage environment-specific credentials securely:

credentials-development.yml:

vars: # Development credentials (less sensitive) API_TOKEN: dev_token_12345 DB_PASSWORD: dev_password ADMIN_TOKEN: dev_admin_token # Development service URLs API_BASE_URL: http://localhost:3000 DB_URL: localhost:5432 CACHE_URL: localhost:6379 # Development-specific settings LOG_LEVEL: debug RATE_LIMIT_DISABLED: true SECURITY_CHECKS_RELAXED: true

credentials-staging.yml:

vars: # Staging credentials (from environment variables) api_token: "{{STAGING_API_TOKEN}}" db_password: "{{STAGING_DB_PASSWORD}}" admin_token: "{{STAGING_ADMIN_TOKEN}}" # Staging service URLs API_BASE_URL: https://api.staging.yourcompany.com DB_URL: staging-db.yourcompany.com:5432 CACHE_URL: staging-cache.yourcompany.com:6379 # Staging-specific settings LOG_LEVEL: info RATE_LIMIT_DISABLED: false SECURITY_CHECKS_RELAXED: false

credentials-production.yml:

vars: # Production credentials (from secure environment variables) api_token: "{{PROD_API_TOKEN}}" db_password: "{{PROD_DB_PASSWORD}}" admin_token: "{{PROD_ADMIN_TOKEN}}" # Production service URLs API_BASE_URL: https://api.yourcompany.com DB_URL: prod-db.yourcompany.com:5432 CACHE_URL: prod-cache.yourcompany.com:6379 # Production-specific settings LOG_LEVEL: warn RATE_LIMIT_DISABLED: false SECURITY_CHECKS_RELAXED: false # Production-only settings MONITORING_ENABLED: true ALERTS_ENABLED: true AUDIT_LOGGING: true

Environment Validation Workflows

Validate environment configuration before running tests:

environment-validation.yml:

name: Environment Validation description: Validate environment configuration and prerequisites vars: environment: "{{ENVIRONMENT}}" api_base_url: "{{API_BASE_URL}}" api_token: "{{API_TOKEN}}" log_level: "{{LOG_LEVEL}}" default_timeout: "{{DEFAULT_TIMEOUT}}" jobs: - id: environment-validation name: Environment Configuration Validation steps: - name: Required Environment Variables Check uses: hello echo: | 🔍 Environment Variables Validation: Required Variables: ENVIRONMENT: {{vars.environment ? "✅ Set (" + vars.environment + ")" : "❌ Missing"}} API_BASE_URL: {{vars.api_base_url ? "✅ Set (" + vars.api_base_url + ")" : "❌ Missing"}} API_TOKEN: {{vars.api_token ? "✅ Set (***)" : "❌ Missing"}} Optional Variables: LOG_LEVEL: {{vars.log_level ? "✅ Set (" + vars.log_level + ")" : "⚠️ Using default"}} DEFAULT_TIMEOUT: {{vars.default_timeout ? "✅ Set (" + vars.default_timeout + ")" : "⚠️ Using default"}} Validation Status: {{ vars.environment && vars.api_base_url && vars.api_token ? "✅ Valid" : "❌ Invalid" }} - name: Environment-Specific Validation uses: hello echo: | 📋 Environment-Specific Validation: {{vars.environment == "development" ? "Development Environment:" : ""}} {{vars.environment == "development" ? "• Extended timeouts enabled" : ""}} {{vars.environment == "development" ? "• Debug features available" : ""}} {{vars.environment == "development" ? "• Security checks relaxed" : ""}} {{vars.environment == "staging" ? "Staging Environment:" : ""}} {{vars.environment == "staging" ? "• Production-like configuration" : ""}} {{vars.environment == "staging" ? "• Integration testing enabled" : ""}} {{vars.environment == "staging" ? "• Performance testing included" : ""}} {{vars.environment == "production" ? "Production Environment:" : ""}} {{vars.environment == "production" ? "• Strict timeouts enforced" : ""}} {{vars.environment == "production" ? "• Security scanning enabled" : ""}} {{vars.environment == "production" ? "• Full monitoring active" : ""}} - name: Service Connectivity Pre-Check uses: http timeout: 10s with: method: GET url: "{{vars.api_base_url}}/health" test: res.code == 200 outputs: connectivity_ok: res.code == 200 api_version: res.body.version environment_confirmed: res.body.environment - name: Authentication Pre-Check uses: http with: method: GET url: "{{vars.api_base_url}}/auth/validate" headers: Authorization: "Bearer {{vars.api_token}}" test: res.code == 200 outputs: auth_valid: res.code == 200 token_expires_in: res.body.expires_in - name: Validation Summary uses: hello echo: | ✅ Environment Validation Results: Connectivity: {{outputs.connectivity_ok ? "✅ Connected" : "❌ Failed"}} API Version: {{outputs.api_version}} Environment Match: {{outputs.environment_confirmed == vars.environment ? "✅ Confirmed" : "⚠️ Mismatch"}} Authentication: {{outputs.auth_valid ? "✅ Valid" : "❌ Invalid"}} {{outputs.auth_valid ? "Token Expires In: " + outputs.token_expires_in + " seconds" : ""}} Environment Ready: {{ outputs.connectivity_ok && outputs.auth_valid && outputs.environment_confirmed == vars.environment ? "🟢 YES" : "🔴 NO" }}

CI/CD Integration

CI already knows which environment a run targets. Passing that through lets the same workflow select its values and its test suite.

GitHub Actions Integration

Integrate with CI/CD pipelines for automated environment testing:

.github/workflows/probe-tests.yml:

name: Probe Environment Tests on: push: branches: [main, develop] pull_request: branches: [main] jobs: development-tests: name: Development Environment Tests runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Install Probe run: | curl -L https://github.com/linyows/probe/releases/latest/download/probe_linux_x86_64.tar.gz | tar -xz probe chmod +x probe sudo mv probe /usr/local/bin/ - name: Run Development Tests env: DEV_API_TOKEN: ${{ secrets.DEV_API_TOKEN }} run: | probe workflows/base-workflow.yml,environments/development.yml,credentials/development.yml staging-tests: name: Staging Environment Tests runs-on: ubuntu-latest if: github.event_name == 'push' && github.ref == 'refs/heads/main' steps: - uses: actions/checkout@v3 - name: Install Probe run: | curl -L https://github.com/linyows/probe/releases/latest/download/probe_linux_x86_64.tar.gz | tar -xz probe chmod +x probe sudo mv probe /usr/local/bin/ - name: Validate Staging Environment env: STAGING_API_TOKEN: ${{ secrets.STAGING_API_TOKEN }} STAGING_DB_PASSWORD: ${{ secrets.STAGING_DB_PASSWORD }} run: | probe workflows/environment-validation.yml,environments/staging.yml,credentials/staging.yml - name: Run Staging Tests env: STAGING_API_TOKEN: ${{ secrets.STAGING_API_TOKEN }} STAGING_DB_PASSWORD: ${{ secrets.STAGING_DB_PASSWORD }} run: | probe workflows/base-workflow.yml,environments/staging.yml,credentials/staging.yml,features/feature-flags.yml production-smoke-tests: name: Production Smoke Tests runs-on: ubuntu-latest if: github.event_name == 'push' && github.ref == 'refs/heads/main' steps: - uses: actions/checkout@v3 - name: Install Probe run: | curl -L https://github.com/linyows/probe/releases/latest/download/probe_linux_x86_64.tar.gz | tar -xz probe chmod +x probe sudo mv probe /usr/local/bin/ - name: Production Smoke Tests env: PROD_API_TOKEN: ${{ secrets.PROD_API_TOKEN }} PROD_DB_PASSWORD: ${{ secrets.PROD_DB_PASSWORD }} run: | probe workflows/smoke-test.yml,environments/production.yml,credentials/production.yml

Environment-Specific Test Suites

Create different test suites for different environments:

smoke-test.yml (for production):

name: Production Smoke Test description: Minimal smoke test for production environment vars: api_base_url: "{{API_BASE_URL}}" jobs: - id: critical-endpoints name: Critical Endpoints Check steps: - name: Health Check uses: http with: method: GET url: "{{vars.api_base_url}}/health" test: res.code == 200 outputs: api_healthy: res.code == 200 - name: Authentication Check uses: http with: method: GET url: "{{vars.api_base_url}}/auth/health" test: res.code == 200 outputs: auth_healthy: res.code == 200 - name: Database Check uses: http with: method: GET url: "{{vars.api_base_url}}/health/database" test: res.code == 200 outputs: db_healthy: res.code == 200 - id: smoke-test-summary name: Smoke Test Summary needs: [critical-endpoints] steps: - name: Production Health Summary uses: hello echo: | 🏭 Production Smoke Test Results: Critical Systems: API: {{outputs['critical-endpoints'].api_healthy ? "✅ Healthy" : "🚨 DOWN"}} Authentication: {{outputs['critical-endpoints'].auth_healthy ? "✅ Healthy" : "🚨 DOWN"}} Database: {{outputs['critical-endpoints'].db_healthy ? "✅ Healthy" : "🚨 DOWN"}} Overall Status: {{ outputs['critical-endpoints'].api_healthy && outputs['critical-endpoints'].auth_healthy && outputs['critical-endpoints'].db_healthy ? "🟢 ALL SYSTEMS OPERATIONAL" : "🔴 CRITICAL ISSUES DETECTED" }}

comprehensive-test.yml (for staging):

name: Comprehensive Staging Test description: Full test suite for staging environment validation vars: api_base_url: "{{API_BASE_URL}}" jobs: - id: api-tests name: API Test Suite steps: - name: User Management API uses: http with: method: GET url: "{{vars.api_base_url}}/users" test: res.code == 200 - name: Order Management API uses: http with: method: GET url: "{{vars.api_base_url}}/orders" test: res.code == 200 - name: Product Catalog API uses: http with: method: GET url: "{{vars.api_base_url}}/products" test: res.code == 200 - id: integration-tests name: Integration Tests needs: [api-tests] steps: - name: User-Order Integration uses: http with: method: GET url: "{{vars.api_base_url}}/test/user-order-flow" test: res.code == 200 && res.body.test_passed == true - name: Payment Integration uses: http with: method: GET url: "{{vars.api_base_url}}/test/payment-flow" test: res.code == 200 && res.body.test_passed == true - id: performance-tests name: Performance Validation needs: [integration-tests] steps: - name: Load Test uses: http with: url: "{{vars.api_base_url}}/test/load" method: POST body: | { "concurrent_users": 10, "duration_seconds": 60 } test: res.code == 200 && res.body.success_rate > 0.95

Environment Monitoring and Alerting

The same environment configuration that drives the tests can drive the monitoring, so each environment is checked on its own terms.

Environment Health Monitoring

Monitor the health of each environment continuously:

environment-monitor.yml:

name: Environment Health Monitor description: Continuous monitoring of environment health vars: api_base_url: "{{API_BASE_URL}}" environment: "{{ENVIRONMENT}}" smtp_host: "{{SMTP_HOST}}" smtp_username: "{{SMTP_USERNAME}}" smtp_password: "{{SMTP_PASSWORD}}" monitoring_interval: "{{MONITORING_INTERVAL ?? '300'}}" # 5 minutes alert_threshold: "{{ALERT_THRESHOLD ?? '2'}}" # Alert after 2 consecutive failures jobs: - id: environment-health-check name: Environment Health Check steps: - name: System Resources Check id: resources uses: http with: method: GET url: "{{vars.api_base_url}}/health/resources" test: | res.code == 200 && res.body.cpu_usage < 80 && res.body.memory_usage < 80 && res.body.disk_usage < 90 outputs: resources_healthy: | res.code == 200 && res.body.cpu_usage < 80 && res.body.memory_usage < 80 && res.body.disk_usage < 90 cpu_usage: res.body.cpu_usage memory_usage: res.body.memory_usage disk_usage: res.body.disk_usage - name: Service Dependencies Check id: dependencies uses: http with: method: GET url: "{{vars.api_base_url}}/health/dependencies" test: | res.code == 200 && res.body.all_dependencies_healthy == true outputs: dependencies_healthy: res.body.all_dependencies_healthy unhealthy_services: res.body.unhealthy_services - name: Environment-Specific Checks uses: hello id: environment-health-check echo: | Environment-specific validation for {{vars.environment}} outputs: env_specific_checks: | {{vars.environment == "production" ? "SSL, Security, Performance" : vars.environment == "staging" ? "Integration, Load Testing" : "Development Tools, Debug Features"}} - id: alerting name: Environment Alerting needs: [environment-health-check] steps: - name: Environment Alert uses: smtp with: addr: "{{vars.smtp_host}}:587" from: "environment-alerts@yourcompany.com" to: "devops@yourcompany.com" subject: "🚨 Environment Health Alert - {{vars.environment}}" session: 1 message: 1 length: 500 echo: | ENVIRONMENT HEALTH ALERT ======================== Environment: {{vars.environment}} Time: {{unixtime()}} RESOURCE STATUS: {{outputs['environment-health-check'].resources_healthy ? "✅ Resources Healthy" : "❌ Resource Issues"}} {{!outputs['environment-health-check'].resources_healthy ? "CPU Usage: " + outputs['environment-health-check'].cpu_usage + "%" : ""}} {{!outputs['environment-health-check'].resources_healthy ? "Memory Usage: " + outputs['environment-health-check'].memory_usage + "%" : ""}} {{!outputs['environment-health-check'].resources_healthy ? "Disk Usage: " + outputs['environment-health-check'].disk_usage + "%" : ""}} DEPENDENCIES STATUS: {{outputs['environment-health-check'].dependencies_healthy ? "✅ All Dependencies Healthy" : "❌ Dependency Issues"}} {{!outputs['environment-health-check'].dependencies_healthy ? "Unhealthy Services: " + outputs['environment-health-check'].unhealthy_services : ""}} ACTION REQUIRED: Investigate {{vars.environment}} environment immediately - id: health-summary name: Health Summary needs: [environment-health-check] steps: - name: All Systems Healthy uses: hello echo: | ✅ {{vars.environment}} Environment Health Check All systems operational: • Resources: CPU {{outputs['environment-health-check'].cpu_usage}}%, Memory {{outputs['environment-health-check'].memory_usage}}%, Disk {{outputs['environment-health-check'].disk_usage}}% • Dependencies: All healthy • Environment: {{vars.environment}} Next check in {{vars.monitoring_interval}} seconds

Best Practices

The points below cover keeping environments apart, moving changes through them in order, validating the configuration, and handling secrets.

1. Environment Isolation

One file per environment keeps the values apart and makes the differences visible in a diff.

# Good: Clear environment separation environments/ ├── development.yml ├── staging.yml └── production.yml # Good: Environment-specific credentials credentials/ ├── development.yml ├── staging.yml └── production.yml (uses env vars only)

2. Progressive Testing

Each environment carries the checks that make sense there, and the heavier ones run before production.

# Good: Test pipeline progression Development → Unit Tests Staging → Integration Tests + Performance Tests Production → Smoke Tests + Monitoring

3. Configuration Validation

A run against a half-configured environment fails in ways that look like application failures, so the configuration is checked first.

# Good: Validate before running tests vars: environment: "{{ENVIRONMENT}}" api_base_url: "{{API_BASE_URL}}" api_token: "{{API_TOKEN}}"
- name: Pre-Test Validation echo: | Environment: {{vars.environment ? "✅" : "❌"}} API URL: {{vars.api_base_url ? "✅" : "❌"}} Credentials: {{vars.api_token ? "✅" : "❌"}}

4. Secure Secret Management

Secrets are read from the environment, so the environment file can be committed while the values are not.

# Good: Use environment variables for secrets vars: api_token: "{{PROD_API_TOKEN}}" # From secure env var # Avoid: Hardcoded secrets vars: api_token: "hardcoded_secret_123" # Never do this

List the variables in secrets as well, so that their values are replaced by <secret:NAME> in the terminal output, the action logs and the report files, where a CI log or an uploaded artifact would otherwise keep them:

secrets: - PROD_API_TOKEN vars: api_token: "{{PROD_API_TOKEN}}"

What’s Next?

Now that you can manage environments effectively, explore:

Environment management is crucial for reliable testing across the software development lifecycle. Use these patterns to create consistent, secure, and maintainable environment configurations.

Updated at