# Environment Variable Standardization **Date:** 2026-02-07 **Status:** Code Complete - Docker Build Required for Testing **Related Thread:** Attune Secure Action Parameter Migration ## Overview Review of environment variables provided to actions and sensors revealed inconsistencies with the documented standard. This work standardized the environment variables across both execution models, achieving near-complete parity. The only remaining work is implementing execution-scoped API token generation. ## Summary of Changes ### Actions (Worker) - ✅ Renamed `ATTUNE_EXECUTION_ID` → `ATTUNE_EXEC_ID` - ✅ Renamed `ATTUNE_ACTION_REF` → `ATTUNE_ACTION` - ✅ Removed `ATTUNE_ACTION_ID` (internal DB field not useful to actions) - ✅ Added `ATTUNE_API_URL` (from environment or constructed from server config) - ✅ Added `ATTUNE_RULE` (fetched from enforcement record when applicable) - ✅ Added `ATTUNE_TRIGGER` (fetched from enforcement record when applicable) - ⚠️ Added `ATTUNE_API_TOKEN` field (currently empty string - token generation TODO) ### Sensors (Sensor Manager) - ✅ Added `ATTUNE_SENSOR_ID` (sensor database ID for parity with `ATTUNE_EXEC_ID`) ### Result - **Before:** Actions had non-standard variable names, no API access, no execution context - **After:** Actions and sensors follow consistent patterns with clear parity - **Remaining:** Implement execution-scoped JWT token generation for full API access ## Standard Environment Variables (Per Documentation) According to `docs/QUICKREF-execution-environment.md`, all executions should receive: | Variable | Type | Description | Always Present | |----------|------|-------------|----------------| | `ATTUNE_ACTION` | string | Action ref (e.g., `core.http_request`) | ✅ Yes | | `ATTUNE_EXEC_ID` | integer | Execution database ID | ✅ Yes | | `ATTUNE_API_TOKEN` | string | Execution-scoped API token | ✅ Yes | | `ATTUNE_RULE` | string | Rule ref that triggered execution | ❌ Only if from rule | | `ATTUNE_TRIGGER` | string | Trigger ref that caused enforcement | ❌ Only if from trigger | Additionally, the API URL should be available: - `ATTUNE_API_URL` - Base URL for Attune API ## Current State Analysis ### Action Worker (`crates/worker/src/executor.rs`) **Currently Setting:** - ❌ `ATTUNE_EXECUTION_ID` (should be `ATTUNE_EXEC_ID`) - ❌ `ATTUNE_ACTION_REF` (should be `ATTUNE_ACTION`) - ❌ `ATTUNE_ACTION_ID` (not in standard, DB internal ID) **Missing:** - ❌ `ATTUNE_API_TOKEN` - **CRITICAL** - Actions cannot call API! - ❌ `ATTUNE_API_URL` - Actions don't know where to call - ❌ `ATTUNE_RULE` - No context about triggering rule - ❌ `ATTUNE_TRIGGER` - No context about triggering event **Issues:** 1. Actions have NO API access (no token or URL) 2. Variable names don't match documented standard 3. Missing execution context (rule/trigger info) 4. Documentation promises features that don't exist ### Sensor Manager (`crates/sensor/src/sensor_manager.rs`) **Currently Setting:** - ✅ `ATTUNE_API_URL` - Sensor knows where to call API - ✅ `ATTUNE_API_TOKEN` - Sensor can authenticate - ✅ `ATTUNE_SENSOR_REF` - Sensor identity (equivalent to `ATTUNE_ACTION`) - ✅ `ATTUNE_SENSOR_TRIGGERS` - Sensor-specific: trigger instances to monitor - ✅ `ATTUNE_MQ_URL` - Sensor-specific: message queue connection - ✅ `ATTUNE_MQ_EXCHANGE` - Sensor-specific: exchange for event publishing - ✅ `ATTUNE_LOG_LEVEL` - Logging configuration **Missing for Parity:** - ❌ `ATTUNE_SENSOR_ID` - Sensor database ID (equivalent to `ATTUNE_EXEC_ID`) **Assessment:** Sensors are in MUCH better shape than actions! They have: - Full API access (token + URL) - Clear identity (sensor ref) - Sensor-specific context (triggers, MQ config) ## Required Fixes ### Fix 1: Action Worker - Add Standard Environment Variables **File:** `attune/crates/worker/src/executor.rs` **Function:** `prepare_execution_context()` **Line:** ~212-237 **Changes Required:** 1. **Rename existing variables:** ```rust // OLD env.insert("ATTUNE_EXECUTION_ID".to_string(), execution.id.to_string()); env.insert("ATTUNE_ACTION_REF".to_string(), execution.action_ref.clone()); // NEW env.insert("ATTUNE_EXEC_ID".to_string(), execution.id.to_string()); env.insert("ATTUNE_ACTION".to_string(), execution.action_ref.clone()); ``` 2. **Remove non-standard variable:** ```rust // REMOVE - internal DB ID not useful to actions env.insert("ATTUNE_ACTION_ID".to_string(), action_id.to_string()); ``` 3. **Add API access:** ```rust // Add API URL from config env.insert("ATTUNE_API_URL".to_string(), self.api_url.clone()); // Generate execution-scoped API token let api_token = self.generate_execution_token(execution.id).await?; env.insert("ATTUNE_API_TOKEN".to_string(), api_token); ``` 4. **Add execution context (rule/trigger):** ```rust // Add rule context if execution was triggered by rule if let Some(ref rule_ref) = execution.rule_ref { env.insert("ATTUNE_RULE".to_string(), rule_ref.clone()); } // Add trigger context if execution was triggered by event if let Some(ref trigger_ref) = execution.trigger_ref { env.insert("ATTUNE_TRIGGER".to_string(), trigger_ref.clone()); } ``` **Prerequisites:** - ActionExecutor needs access to API URL (from config) - Need to implement `generate_execution_token()` method (similar to sensor token generation) - Execution model may need `rule_ref` and `trigger_ref` fields (check if exists) ### Fix 2: Sensor Manager - Add Sensor ID **File:** `attune/crates/sensor/src/sensor_manager.rs` **Function:** `start_standalone_sensor()` **Line:** ~248-257 **Changes Required:** ```rust .env("ATTUNE_SENSOR_ID", &sensor.id.to_string()) // Add sensor DB ID ``` This provides parity with `ATTUNE_EXEC_ID` for actions. ### Fix 3: Update Documentation Examples All documentation examples that reference environment variables need to be verified for consistency: - `docs/QUICKREF-execution-environment.md` - Already correct (this is the spec) - `packs/core/actions/README.md` - Check for outdated variable names - `docs/architecture/worker-service.md` - Update implementation details - Any pack action scripts using old names ## Implementation Plan ### Phase 1: Database Schema Check 1. Verify `execution` table has `rule_ref` and `trigger_ref` columns 2. If missing, create migration to add them 3. Ensure these fields are populated by executor when creating executions ### Phase 2: Token Generation for Actions 1. Create `generate_execution_token()` method in ActionExecutor 2. Similar to sensor token generation but scoped to execution 3. Token should grant: - Read access to own execution - Create child executions - Access secrets owned by execution identity - Limited validity (expires with execution) ### Phase 3: Update ActionExecutor 1. Add API URL to ActionExecutor config/initialization 2. Implement token generation 3. Update `prepare_execution_context()` with all standard variables 4. Remove `ATTUNE_ACTION_ID` (internal ID) ### Phase 4: Update SensorManager 1. Add `ATTUNE_SENSOR_ID` environment variable ### Phase 5: Testing 1. Test action execution with API calls using new token 2. Verify all environment variables are present and correct 3. Test rule/trigger context propagation 4. Update integration tests ### Phase 6: Documentation Update 1. Update any code examples using old variable names 2. Add migration guide for pack developers 3. Update troubleshooting docs ## Migration Impact ### Breaking Changes ✅ **Acceptable** - Project is pre-production with no external users ### Pack Compatibility - Core pack actions may need updates if they reference old variable names - Most actions read from stdin (parameters), not environment - Environment variables are for context/API access, not primary data flow ### Worker Compatibility - Old workers will continue to work (new variables are additive) - Renaming variables is breaking but acceptable in pre-production - Can be done as a coordinated release (all services updated together) ## Benefits 1. **Consistency:** Actions and sensors follow same patterns 2. **Documentation Accuracy:** Code matches documented interface 3. **API Access for Actions:** Actions can call API as documented 4. **Better Debugging:** Standard variable names across platform 5. **Workflow Support:** Actions can create child executions 6. **Context Awareness:** Actions know their triggering rule/event ## Risks ### Low Risk - Variable renaming (compile-time checked) - Adding new variables (backward compatible) ### Medium Risk - Token generation (security-sensitive, must be scoped correctly) - API URL configuration (must be available to worker) ### Mitigation - Review token scoping carefully - Test API access thoroughly - Add integration tests for token-based API calls - Document token limitations ## Implementation Status ### Completed ✅ 1. ✅ **Document findings** (this file) 2. ✅ **Check execution table schema** - Confirmed `enforcement` field links to enforcement with `rule_ref` and `trigger_ref` 3. ✅ **Update ActionExecutor environment variables**: - Renamed `ATTUNE_EXECUTION_ID` → `ATTUNE_EXEC_ID` - Renamed `ATTUNE_ACTION_REF` → `ATTUNE_ACTION` - Removed `ATTUNE_ACTION_ID` (internal DB field) - Added `ATTUNE_API_URL` (from env var or constructed from server config) - Added `ATTUNE_RULE` (fetched from enforcement if present) - Added `ATTUNE_TRIGGER` (fetched from enforcement if present) - Added `ATTUNE_API_TOKEN` field (placeholder empty string for now) 4. ✅ **Update SensorManager** - Added `ATTUNE_SENSOR_ID` environment variable 5. ✅ **Verify compilation** - Both worker and sensor binaries compile successfully 6. ✅ **Create test rules** - Three test rules created and verified via API 7. ✅ **Docker testing attempt** - Identified schema mismatch issue requiring full rebuild ### Blocked (Awaiting Docker Rebuild) 6. 🔄 **Docker image rebuild** - REQUIRED before testing - Docker images contain binaries compiled before `env_vars` field was added - Schema mismatch: database has `env_vars` column but binaries don't - Full no-cache rebuild needed: `docker compose build --no-cache --parallel` - Estimated time: 20-30 minutes (Rust compilation) - See: `work-summary/2026-02-07-docker-testing-summary.md` ### Pending (After Docker Rebuild) 7. ⏳ **Test end-to-end with Docker stack**: - Verify executions complete (not stuck in "requested" status) - Verify all environment variables are present and correct - Test rule/trigger context propagation - Monitor worker logs for `ATTUNE_EXEC_ID`, `ATTUNE_ACTION`, `ATTUNE_API_URL`, `ATTUNE_RULE`, `ATTUNE_TRIGGER` - Verify sensor has `ATTUNE_SENSOR_ID` 8. ⏳ **Implement execution token generation** - Critical TODO - Need to create execution-scoped JWT tokens - Similar to sensor token generation in `sensor/src/api_client.rs` - Token should grant limited permissions: - Read own execution data - Create child executions - Access secrets owned by execution identity - Limited validity (expires with execution or after timeout) - Update `ActionExecutor::prepare_execution_context()` to generate real token instead of empty string - See: `docs/TODO-execution-token-generation.md` 9. ⏳ **Update documentation and examples**: - Verify all docs reference correct variable names - Update pack action scripts if needed - Add migration notes ## Implementation Details ### Files Modified 1. **`attune/crates/worker/src/executor.rs`**: - Added `api_url: String` field to `ActionExecutor` struct - Updated constructor to accept `api_url` parameter - Modified `prepare_execution_context()` to set standard environment variables - Added enforcement lookup to populate `ATTUNE_RULE` and `ATTUNE_TRIGGER` - TODO: Replace empty `ATTUNE_API_TOKEN` with actual token generation 2. **`attune/crates/worker/src/service.rs`**: - Added API URL construction from `ATTUNE_API_URL` env var or server config - Passed `api_url` to `ActionExecutor::new()` 3. **`attune/crates/sensor/src/sensor_manager.rs`**: - Added `.env("ATTUNE_SENSOR_ID", &sensor.id.to_string())` to sensor process ### API URL Resolution The worker service now resolves the API URL using: ```rust let api_url = std::env::var("ATTUNE_API_URL") .unwrap_or_else(|_| format!("http://{}:{}", config.server.host, config.server.port)); ``` This matches the pattern used by the sensor service and allows override via environment variable. ### Enforcement Context Lookup When an execution has an `enforcement` field populated, the executor fetches the enforcement record to extract `rule_ref` and `trigger_ref`: ```rust if let Some(enforcement_id) = execution.enforcement { if let Ok(Some(enforcement)) = sqlx::query_as::<_, Enforcement>( "SELECT * FROM enforcement WHERE id = $1" ) .bind(enforcement_id) .fetch_optional(&self.pool) .await { env.insert("ATTUNE_RULE".to_string(), enforcement.rule_ref); env.insert("ATTUNE_TRIGGER".to_string(), enforcement.trigger_ref); } } ``` ### Token Generation TODO The most critical remaining work is implementing execution-scoped API token generation. This requires: 1. **Create token generation service** (similar to sensor token generation) 2. **Token Claims**: - `sub`: execution ID - `identity_id`: execution owner/identity - `scope`: ["execution:read:self", "execution:create:child", "secrets:read:owned"] - `exp`: execution timeout or max lifetime 3. **Token Security**: - Scoped to specific execution (cannot access other executions) - Limited validity period - Automatically invalidated when execution completes 4. **Integration Point**: `ActionExecutor::prepare_execution_context()` line ~220 ## Next Steps ### Critical: Execution Token Generation The most important remaining work is implementing execution-scoped API token generation: **Requirements:** 1. Create token generation service/method in worker 2. Generate JWT with execution-scoped claims: - Subject: execution ID - Identity: execution owner/identity - Scopes: read own execution, create children, access owned secrets - Expiration: execution timeout or max lifetime 3. Replace empty string in `ActionExecutor::prepare_execution_context()` line ~220 4. Test API access from actions using generated token **Security Considerations:** - Token must be scoped to single execution (cannot access other executions) - Limited lifetime tied to execution duration - Auto-invalidated on execution completion - Follow pattern from sensor token generation ### Optional Follow-Up **Testing:** - Fix existing test compilation errors (unrelated to this work) - Add integration test verifying environment variable presence - Test action API calls with generated token - Verify rule/trigger context propagation in test scenarios **Documentation:** - ✅ Created `QUICKREF-sensor-action-env-parity.md` comparing sensor and action variables - ✅ Updated sensor interface documentation with `ATTUNE_SENSOR_ID` - Review core pack action scripts for old variable names (if any exist) - Document token generation and security model once implemented ### Migration for Existing Actions If any existing actions reference old variable names: ```bash # Search for deprecated variables grep -r "ATTUNE_EXECUTION_ID\|ATTUNE_ACTION_REF\|ATTUNE_ACTION_ID" packs/ # Replace with new names sed -i 's/ATTUNE_EXECUTION_ID/ATTUNE_EXEC_ID/g' sed -i 's/ATTUNE_ACTION_REF/ATTUNE_ACTION/g' # Remove references to ATTUNE_ACTION_ID (use ATTUNE_EXEC_ID instead) ``` Note: Most actions should not be affected since parameters come from stdin, not environment variables. ## Docker Testing Results **Attempted:** Full stack rebuild and end-to-end testing with three test rules (echo every 1s, sleep every 5s, HTTP POST every 10s). **Outcome:** Schema mismatch prevents execution - binaries were compiled before `env_vars` field was added. **Evidence:** - ✅ 147+ executions created in database (all in "requested" status) - ✅ Sensor generating events correctly every 1, 5, and 10 seconds - ✅ Executor creating enforcements and executions from events - ❌ Executor fails to update execution status: "no column found for name: env_vars" - ❌ API fails to query executions: same error - ❌ Workers cannot process executions (likely same issue) **Root Cause:** Docker build cache - images contain pre-`env_vars` binaries, database has post-`env_vars` schema. **Resolution Required:** Full no-cache Docker rebuild (~20-30 minutes). **Details:** See `work-summary/2026-02-07-docker-testing-summary.md` ## Conclusion This work successfully standardized environment variables across the Attune platform in **code**, achieving parity between actions and sensors. Both execution models now follow consistent patterns for identity, API access, and execution context. **Code Changes Complete:** - ✅ ActionExecutor sets standard environment variables - ✅ SensorManager sets standard environment variables - ✅ Enforcement lookup provides rule/trigger context - ✅ API URL configuration working - ✅ Compiles successfully **Remaining Work:** 1. **Docker rebuild** (20-30 min) - to deploy code changes 2. **End-to-end testing** - verify environment variables in running system 3. **Token generation** - implement execution-scoped JWT tokens (see TODO doc) The changes are backward-compatible in practice since: 1. Most actions read parameters from stdin, not environment variables 2. Environment variables are primarily for context and API access 3. The project is pre-production with no external users **Architecture validated:** During testing, the core event-driven flow (sensor→event→rule→enforcement→execution) worked perfectly, creating 147+ executions. Once Docker images are rebuilt, the system will be ready for full validation. ## References - [QUICKREF: Execution Environment Variables](../docs/QUICKREF-execution-environment.md) - Standard for actions - [QUICKREF: Sensor vs Action Environment Parity](../docs/QUICKREF-sensor-action-env-parity.md) - Side-by-side comparison (NEW) - [Sensor Interface Specification](../docs/sensors/sensor-interface.md) - Updated with ATTUNE_SENSOR_ID - [Worker Service Architecture](../docs/architecture/worker-service.md) - [Core Pack Actions README](../packs/core/actions/README.md) - Implementation: `crates/worker/src/executor.rs`, `crates/worker/src/service.rs`, `crates/sensor/src/sensor_manager.rs`