working out the worker/execution interface
This commit is contained in:
458
work-summary/2026-02-07-env-var-standardization.md
Normal file
458
work-summary/2026-02-07-env-var-standardization.md
Normal file
@@ -0,0 +1,458 @@
|
||||
# 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' <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
|
||||
|
||||
- [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`
|
||||
Reference in New Issue
Block a user