4.8 KiB
Work Summary: Pack Installation Fixes (2026-02-13)
Problem
The /packs/install web UI page was completely non-functional when attempting to install packs from git repositories. Multiple cascading issues prevented successful pack installation via the API.
Issues Fixed
1. git binary missing from API container
Error: Failed to execute git clone: No such file or directory (os error 2)
The install_from_git method in PackInstaller runs Command::new("git") to clone repositories, but the runtime Docker image (debian:bookworm-slim) did not include git.
Fix: Added git to the runtime stage's apt-get install in docker/Dockerfile.optimized.
2. Pack tests ran before pack files existed at expected location
Error: Pack directory not found: /opt/attune/packs/python_example
The execute_and_store_pack_tests function always constructed the pack path as packs_base_dir/pack_ref, but during installation the pack files were still in a temp directory. The move to permanent storage happened after test execution.
Fix:
- Added
execute_pack_tests_at(pack_dir, ...)method toTestExecutorthat accepts an explicit directory path - Added
pack_dir_override: Option<&std::path::Path>parameter toexecute_and_store_pack_tests register_pack_internalnow passes the actual pack path through to tests
3. Missing test config treated as installation failure
Error: No testing configuration found in pack.yaml for pack 'python_example'
Packs without a testing section in pack.yaml could not be installed without force=true, because the absence of test config was returned as an error.
Fix: Changed execute_and_store_pack_tests return type from Result<PackTestResult> to Option<Result<PackTestResult>>. Returns None when no testing config exists or testing is disabled, which the caller treats as "no tests to run" (success). All ? operators were replaced with explicit match/return to work with the Option<Result<...>> return type.
4. Packs volume mounted read-only on API container
Error: Read-only file system (os error 30)
The packs_data volume was mounted as :ro on the API container, and files were owned by root (written by init-packs running as root). The API service (running as user attune, uid 1000) could not write.
Fix:
- Changed volume mount from
packs_data:/opt/attune/packs:roto:rwindocker-compose.yaml - Added
chown -R 1000:1000 "$TARGET_PACKS_DIR"todocker/init-packs.sh(runs after initial pack copy and again after all packs loaded)
5. Pack components not loaded into database
Symptom: Pack installed successfully but actions, triggers, and sensors not visible in the UI.
The register_pack_internal function only created the pack table record and synced workflows. It never loaded the pack's individual components (actions, triggers, sensors) from their YAML definition files. This was previously only handled by the Python load_core_pack.py script during init-packs.
Fix: Created PackComponentLoader in crates/common/src/pack_registry/loader.rs — a Rust-native pack component loader that:
- Reads
triggers/*.yamland creates trigger records viaTriggerRepository - Reads
actions/*.yamland creates action records with full field support (parameter_delivery, parameter_format, output_format) via direct SQL - Reads
sensors/*.yamland creates sensor records viaSensorRepository, resolving trigger and runtime references - Loads in dependency order: triggers → actions → sensors
- Skips components that already exist (idempotent)
- Resolves runtime IDs by looking up common ref patterns (e.g.,
shell→core.action.shell)
Integrated into register_pack_internal so both the /packs/install and /packs/register endpoints load components.
6. Pack stored with version suffix in directory name
Symptom: Pack stored at python_example-1.0.0 but workers/sensors look for python_example.
PackStorage::install_pack was called with Some(&pack.version), creating a versioned directory name. The rest of the system expects packs_base_dir/pack_ref without version.
Fix: Changed to install_pack(&installed.path, &pack.r#ref, None) to match the system convention.
Files Changed
| File | Change |
|---|---|
docker/Dockerfile.optimized |
Added git to runtime dependencies |
docker/init-packs.sh |
Added chown -R 1000:1000 for attune user write access |
docker-compose.yaml |
Changed packs volume mount from :ro to :rw on API |
crates/common/src/test_executor.rs |
Added execute_pack_tests_at method |
crates/common/src/pack_registry/loader.rs |
New file — PackComponentLoader |
crates/common/src/pack_registry/mod.rs |
Added loader module and re-exports |
crates/api/src/routes/packs.rs |
Fixed test execution path, no-test-config handling, component loading, storage path |