Files
attune/work-summary/2026-02-07-env-var-standardization.md

18 KiB

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_IDATTUNE_EXEC_ID
  • Renamed ATTUNE_ACTION_REFATTUNE_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:

    // 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:

    // REMOVE - internal DB ID not useful to actions
    env.insert("ATTUNE_ACTION_ID".to_string(), action_id.to_string());
    
  3. Add API access:

    // 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):

    // 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:

.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_IDATTUNE_EXEC_ID
    • Renamed ATTUNE_ACTION_REFATTUNE_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)

  1. 🔄 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)

  1. 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
  2. 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
  3. 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:

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:

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:

# 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' <files>
sed -i 's/ATTUNE_ACTION_REF/ATTUNE_ACTION/g' <files>
# 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