working on arm64 native
Some checks failed
CI / Rustfmt (push) Successful in 24s
CI / Cargo Audit & Deny (push) Successful in 36s
CI / Security Blocking Checks (push) Successful in 9s
CI / Web Blocking Checks (push) Successful in 48s
CI / Web Advisory Checks (push) Successful in 37s
Publish Images / Resolve Publish Metadata (push) Successful in 2s
CI / Clippy (push) Failing after 1m53s
Publish Images / Publish Docker Dist Bundle (push) Failing after 8s
Publish Images / Publish web (amd64) (push) Successful in 56s
CI / Security Advisory Checks (push) Successful in 38s
Publish Images / Publish web (arm64) (push) Successful in 3m29s
CI / Tests (push) Successful in 9m21s
Publish Images / Build Rust Bundles (amd64) (push) Failing after 12m28s
Publish Images / Build Rust Bundles (arm64) (push) Successful in 12m20s
Publish Images / Publish agent (amd64) (push) Has been skipped
Publish Images / Publish api (amd64) (push) Has been skipped
Publish Images / Publish agent (arm64) (push) Has been skipped
Publish Images / Publish api (arm64) (push) Has been skipped
Publish Images / Publish executor (amd64) (push) Has been skipped
Publish Images / Publish notifier (amd64) (push) Has been skipped
Publish Images / Publish executor (arm64) (push) Has been skipped
Publish Images / Publish notifier (arm64) (push) Has been skipped
Publish Images / Publish manifest attune/agent (push) Has been skipped
Publish Images / Publish manifest attune/api (push) Has been skipped
Publish Images / Publish manifest attune/notifier (push) Has been skipped
Publish Images / Publish manifest attune/executor (push) Has been skipped
Publish Images / Publish manifest attune/web (push) Has been skipped

This commit is contained in:
David Culbreth
2026-03-27 16:37:46 -05:00
parent 3a13bf754a
commit 7ef2b59b23
16 changed files with 553 additions and 159 deletions

View File

@@ -4,18 +4,31 @@
# using musl, suitable for injection into arbitrary runtime containers.
#
# Stages:
# builder - Cross-compile with musl for a fully static binary
# builder - Cross-compile with cargo-zigbuild + musl for a fully static binary
# agent-binary - Minimal scratch image containing just the binary
# agent-init - BusyBox-based image for use as a Kubernetes init container
# or Docker Compose volume-populating service (has `cp`)
#
# Architecture handling:
# Uses cargo-zigbuild for cross-compilation, which bundles all necessary
# cross-compilation toolchains internally. This allows building for any
# target architecture from any host — e.g., building aarch64 musl binaries
# on an x86_64 host, or vice versa. This matches the CI/CD pipeline approach.
#
# The RUST_TARGET build arg controls the output architecture:
# x86_64-unknown-linux-musl -> amd64 static binary (default)
# aarch64-unknown-linux-musl -> arm64 static binary
#
# Usage:
# # Build for the default architecture (x86_64):
# DOCKER_BUILDKIT=1 docker buildx build --target agent-init -f docker/Dockerfile.agent -t attune-agent:latest .
#
# # Build for arm64:
# DOCKER_BUILDKIT=1 docker buildx build --build-arg RUST_TARGET=aarch64-unknown-linux-musl --target agent-init -f docker/Dockerfile.agent -t attune-agent:latest .
#
# # Build the minimal binary-only image:
# DOCKER_BUILDKIT=1 docker buildx build --target agent-binary -f docker/Dockerfile.agent -t attune-agent:binary .
#
# # Build the init container image (for volume population via `cp`):
# DOCKER_BUILDKIT=1 docker buildx build --target agent-init -f docker/Dockerfile.agent -t attune-agent:latest .
#
# # Use in docker-compose.yaml to populate a shared volume:
# # agent-init:
# # image: attune-agent:latest
@@ -37,14 +50,30 @@ FROM rust:${RUST_VERSION}-${DEBIAN_VERSION} AS builder
ARG RUST_TARGET
# Install musl toolchain for static linking
# Install build dependencies.
# - musl-tools: provides the musl libc headers needed for musl target builds
# - python3 + pip: needed to install ziglang (zig is the cross-compilation backend)
# - pkg-config, libssl-dev: needed for native dependency detection during build
# - file, binutils: for verifying the resulting binaries (file, strip)
RUN apt-get update && apt-get install -y \
musl-tools \
pkg-config \
libssl-dev \
ca-certificates \
file \
binutils \
python3 \
python3-pip \
&& rm -rf /var/lib/apt/lists/*
# Install zig (provides cross-compilation toolchains for all architectures)
# and cargo-zigbuild (cargo subcommand that uses zig as the linker/compiler).
# This replaces native musl-gcc and avoids the -m64 flag mismatch that occurs
# when the host arch doesn't match the target arch (e.g., building x86_64 musl
# binaries on an arm64 host).
RUN pip3 install --break-system-packages --no-cache-dir ziglang && \
cargo install --locked cargo-zigbuild
# Add the requested musl target for fully static binaries
RUN rustup target add ${RUST_TARGET}
@@ -96,25 +125,30 @@ RUN --mount=type=cache,target=/usr/local/cargo/registry,sharing=shared \
# ---------------------------------------------------------------------------
# Build layer
# Copy real source code and compile only the agent binary with musl
# Copy real source code and compile only the agent binaries with musl
# ---------------------------------------------------------------------------
COPY migrations/ ./migrations/
COPY crates/ ./crates/
# Build the injected agent binaries, statically linked with musl.
# Uses cargo-zigbuild so that cross-compilation works regardless of host arch.
# Uses a dedicated cache ID (agent-target) so the musl target directory
# doesn't collide with the glibc target cache used by other Dockerfiles.
RUN --mount=type=cache,target=/usr/local/cargo/registry,sharing=shared \
--mount=type=cache,target=/usr/local/cargo/git,sharing=shared \
--mount=type=cache,id=agent-target,target=/build/target,sharing=locked \
cargo build --release --target ${RUST_TARGET} --bin attune-agent --bin attune-sensor-agent && \
cargo zigbuild --release --target ${RUST_TARGET} --bin attune-agent --bin attune-sensor-agent && \
cp /build/target/${RUST_TARGET}/release/attune-agent /build/attune-agent && \
cp /build/target/${RUST_TARGET}/release/attune-sensor-agent /build/attune-sensor-agent
# Strip the binaries to minimize size
RUN strip /build/attune-agent && strip /build/attune-sensor-agent
# Strip the binaries to minimize size.
# When cross-compiling for a different architecture, the host strip may not
# understand the foreign binary format. In that case we skip stripping — the
# binary is still functional, just slightly larger.
RUN (strip /build/attune-agent 2>/dev/null && echo "stripped attune-agent" || echo "strip skipped for attune-agent (cross-arch binary)") && \
(strip /build/attune-sensor-agent 2>/dev/null && echo "stripped attune-sensor-agent" || echo "strip skipped for attune-sensor-agent (cross-arch binary)")
# Verify the binaries are statically linked and functional
# Verify the binaries exist and show their details
RUN ls -lh /build/attune-agent /build/attune-sensor-agent && \
file /build/attune-agent && \
file /build/attune-sensor-agent && \

View File

@@ -1,12 +1,26 @@
# Dockerfile for building pack binaries independently
# Dockerfile for building statically-linked pack binaries independently
#
# This Dockerfile builds native pack binaries (sensors, etc.) with GLIBC compatibility
# The binaries are built separately from service containers and placed in ./packs/
# This Dockerfile builds native pack binaries (sensors, etc.) as fully static
# musl binaries with zero runtime dependencies. Uses cargo-zigbuild for
# cross-compilation, allowing builds for any target architecture from any host
# (e.g., building x86_64 musl binaries on an arm64 Mac, or vice versa).
#
# Architecture handling:
# The RUST_TARGET build arg controls the output architecture:
# x86_64-unknown-linux-musl -> amd64 static binary (default)
# aarch64-unknown-linux-musl -> arm64 static binary
#
# Usage:
# docker build -f docker/Dockerfile.pack-binaries -t attune-pack-builder .
# # Build for the default architecture (x86_64):
# DOCKER_BUILDKIT=1 docker build -f docker/Dockerfile.pack-binaries -t attune-pack-builder .
#
# # Build for arm64:
# DOCKER_BUILDKIT=1 docker build --build-arg RUST_TARGET=aarch64-unknown-linux-musl \
# -f docker/Dockerfile.pack-binaries -t attune-pack-builder .
#
# # Extract binaries:
# docker create --name pack-binaries attune-pack-builder
# docker cp pack-binaries:/build/pack-binaries/. ./packs/
# docker cp pack-binaries:/pack-binaries/. ./packs/
# docker rm pack-binaries
#
# Or use the provided script:
@@ -14,25 +28,56 @@
ARG RUST_VERSION=1.92
ARG DEBIAN_VERSION=bookworm
ARG RUST_TARGET=x86_64-unknown-linux-musl
# ============================================================================
# Stage 1: Builder - Build pack binaries with GLIBC 2.36
# Stage 1: Builder - Cross-compile statically-linked pack binaries with musl
# ============================================================================
FROM rust:${RUST_VERSION}-${DEBIAN_VERSION} AS builder
# Install build dependencies
ARG RUST_TARGET
# Install build dependencies.
# - musl-tools: provides the musl libc headers needed for musl target builds
# - python3 + pip: needed to install ziglang (zig is the cross-compilation backend)
# - pkg-config, libssl-dev: needed for native dependency detection during build
# - file, binutils: for verifying and stripping the resulting binaries
RUN apt-get update && apt-get install -y \
musl-tools \
pkg-config \
libssl-dev \
ca-certificates \
file \
binutils \
python3 \
python3-pip \
&& rm -rf /var/lib/apt/lists/*
# Install zig (provides cross-compilation toolchains for all architectures)
# and cargo-zigbuild (cargo subcommand that uses zig as the linker/compiler).
# This replaces native musl-gcc and avoids the -m64 flag mismatch that occurs
# when the host arch doesn't match the target arch (e.g., building x86_64 musl
# binaries on an arm64 host).
RUN pip3 install --break-system-packages --no-cache-dir ziglang && \
cargo install --locked cargo-zigbuild
# Add the requested musl target for fully static binaries
RUN rustup target add ${RUST_TARGET}
WORKDIR /build
# Increase rustc stack size to prevent SIGSEGV during release builds
ENV RUST_MIN_STACK=67108864
# Copy workspace configuration
# Enable SQLx offline mode — compile-time query checking without a live database
ENV SQLX_OFFLINE=true
# ---------------------------------------------------------------------------
# Dependency caching layer
# Copy only Cargo metadata first so `cargo fetch` is cached when only source
# code changes. This follows the same selective-copy optimization pattern as
# the other active Dockerfiles in this directory.
# ---------------------------------------------------------------------------
COPY Cargo.toml Cargo.lock ./
# Copy all workspace member manifests (required for workspace resolution)
@@ -45,35 +90,63 @@ COPY crates/worker/Cargo.toml ./crates/worker/Cargo.toml
COPY crates/notifier/Cargo.toml ./crates/notifier/Cargo.toml
COPY crates/cli/Cargo.toml ./crates/cli/Cargo.toml
# Create dummy source files for workspace members (not being built)
RUN mkdir -p crates/api/src && echo "fn main() {}" > crates/api/src/main.rs
RUN mkdir -p crates/executor/src && echo "fn main() {}" > crates/executor/src/main.rs
RUN mkdir -p crates/executor/benches && echo "fn main() {}" > crates/executor/benches/context_clone.rs
RUN mkdir -p crates/sensor/src && echo "fn main() {}" > crates/sensor/src/main.rs
RUN mkdir -p crates/worker/src && echo "fn main() {}" > crates/worker/src/main.rs
RUN echo "fn main() {}" > crates/worker/src/agent_main.rs
RUN mkdir -p crates/notifier/src && echo "fn main() {}" > crates/notifier/src/main.rs
RUN mkdir -p crates/cli/src && echo "fn main() {}" > crates/cli/src/main.rs
# Create minimal stub sources so cargo can resolve the workspace and fetch deps.
# These are ONLY used for `cargo fetch` — never compiled.
# NOTE: The worker crate has TWO binary targets (main + agent_main) and the
# sensor crate also has two binary targets (main + agent_main), so we create
# stubs for all of them.
RUN mkdir -p crates/common/src && echo "" > crates/common/src/lib.rs && \
mkdir -p crates/api/src && echo "fn main(){}" > crates/api/src/main.rs && \
mkdir -p crates/executor/src && echo "fn main(){}" > crates/executor/src/main.rs && \
mkdir -p crates/executor/benches && echo "fn main(){}" > crates/executor/benches/context_clone.rs && \
mkdir -p crates/sensor/src && echo "fn main(){}" > crates/sensor/src/main.rs && \
echo "fn main(){}" > crates/sensor/src/agent_main.rs && \
mkdir -p crates/core-timer-sensor/src && echo "fn main(){}" > crates/core-timer-sensor/src/main.rs && \
mkdir -p crates/worker/src && echo "fn main(){}" > crates/worker/src/main.rs && \
echo "fn main(){}" > crates/worker/src/agent_main.rs && \
mkdir -p crates/notifier/src && echo "fn main(){}" > crates/notifier/src/main.rs && \
mkdir -p crates/cli/src && echo "fn main(){}" > crates/cli/src/main.rs
# Copy only the source code needed for pack binaries
# Download all dependencies (cached unless Cargo.toml/Cargo.lock change)
# registry/git use sharing=shared — cargo handles concurrent reads safely
RUN --mount=type=cache,target=/usr/local/cargo/registry,sharing=shared \
--mount=type=cache,target=/usr/local/cargo/git,sharing=shared \
cargo fetch
# ---------------------------------------------------------------------------
# Build layer
# Copy real source code and compile only the pack binaries with musl
# ---------------------------------------------------------------------------
COPY migrations/ ./migrations/
COPY crates/common/ ./crates/common/
COPY crates/core-timer-sensor/ ./crates/core-timer-sensor/
# Build pack binaries with BuildKit cache mounts
# These binaries will have GLIBC 2.36 compatibility (Debian Bookworm)
# Build pack binaries with BuildKit cache mounts, statically linked with musl.
# Uses cargo-zigbuild so that cross-compilation works regardless of host arch.
# - registry/git use sharing=shared (cargo handles concurrent access safely)
# - target uses dedicated cache for pack binaries (separate from service builds)
# - target uses sharing=locked because zigbuild cross-compilation needs
# exclusive access to the target directory
# - dedicated cache ID (target-pack-binaries-static) to avoid collisions with
# other Dockerfiles' target caches
RUN --mount=type=cache,target=/usr/local/cargo/registry,sharing=shared \
--mount=type=cache,target=/usr/local/cargo/git,sharing=shared \
--mount=type=cache,target=/build/target,id=target-pack-binaries \
--mount=type=cache,id=target-pack-binaries-static,target=/build/target,sharing=locked \
mkdir -p /build/pack-binaries && \
cargo build --release --bin attune-core-timer-sensor && \
cp /build/target/release/attune-core-timer-sensor /build/pack-binaries/attune-core-timer-sensor
cargo zigbuild --release --target ${RUST_TARGET} --bin attune-core-timer-sensor && \
cp /build/target/${RUST_TARGET}/release/attune-core-timer-sensor /build/pack-binaries/attune-core-timer-sensor
# Verify binaries were built successfully
RUN ls -lah /build/pack-binaries/ && \
# Strip the binary to minimize size.
# When cross-compiling for a different architecture, the host strip may not
# understand the foreign binary format. In that case we skip stripping — the
# binary is still functional, just slightly larger.
RUN (strip /build/pack-binaries/attune-core-timer-sensor 2>/dev/null && \
echo "stripped attune-core-timer-sensor" || \
echo "strip skipped for attune-core-timer-sensor (cross-arch binary)")
# Verify binaries were built successfully and are statically linked
RUN ls -lh /build/pack-binaries/attune-core-timer-sensor && \
file /build/pack-binaries/attune-core-timer-sensor && \
ldd /build/pack-binaries/attune-core-timer-sensor && \
(ldd /build/pack-binaries/attune-core-timer-sensor 2>&1 || echo "statically linked (no dynamic dependencies)") && \
/build/pack-binaries/attune-core-timer-sensor --version || echo "Built successfully"
# ============================================================================
@@ -87,3 +160,15 @@ COPY --from=builder /build/pack-binaries/ /pack-binaries/
# Default command (not used in FROM scratch)
CMD ["/bin/sh"]
# ============================================================================
# Stage 3: pack-binaries-init - Init container for volume population
# ============================================================================
# Uses busybox so we have `cp`, `sh`, etc. for use as a Docker Compose
# init service that copies pack binaries into the shared packs volume.
FROM busybox:1.36 AS pack-binaries-init
COPY --from=builder /build/pack-binaries/ /pack-binaries/
# No default entrypoint — docker-compose provides the command
ENTRYPOINT ["/bin/sh"]

View File

@@ -1,5 +1,15 @@
# Attune Docker Environment Configuration
# This file overrides base config.yaml settings for Docker deployments
#
# This file is mounted into containers at /opt/attune/config/config.yaml.
# It provides base values for Docker deployments.
#
# Sensitive values (jwt_secret, encryption_key) are overridden by environment
# variables set in docker-compose.yaml using the ATTUNE__ prefix convention:
# ATTUNE__SECURITY__JWT_SECRET=...
# ATTUNE__SECURITY__ENCRYPTION_KEY=...
#
# The `config` crate does NOT support ${VAR} shell interpolation in YAML.
# All overrides must use ATTUNE__<SECTION>__<KEY> environment variables.
environment: docker
@@ -8,36 +18,29 @@ database:
url: postgresql://attune:attune@postgres:5432/attune
max_connections: 20
min_connections: 5
acquire_timeout: 30
connect_timeout: 30
idle_timeout: 600
max_lifetime: 1800
log_statements: false
schema: "attune"
schema: "public"
# Docker message queue (RabbitMQ container)
message_queue:
url: amqp://attune:attune@rabbitmq:5672
connection_timeout: 30
heartbeat: 60
prefetch_count: 10
rabbitmq:
worker_queue_ttl_ms: 300000 # 5 minutes - expire unprocessed executions
dead_letter:
enabled: true
exchange: attune.dlx
ttl_ms: 86400000 # 24 hours - retain DLQ messages for debugging
exchange: attune
enable_dlq: true
message_ttl: 3600 # seconds
# Docker cache (Redis container - optional)
cache:
enabled: true
# Docker cache (Redis container)
redis:
url: redis://redis:6379
connection_timeout: 5
default_ttl: 3600
pool_size: 10
# API server configuration
server:
host: 0.0.0.0
port: 8080
request_timeout: 60
enable_cors: true
cors_origins:
- http://localhost
- http://localhost:3000
@@ -49,8 +52,8 @@ server:
- http://127.0.0.1:3002
- http://127.0.0.1:5173
- http://web
request_timeout: 60
max_request_size: 10485760 # 10MB
- http://web:3000
max_body_size: 10485760 # 10MB
# Logging configuration
log:
@@ -58,30 +61,34 @@ log:
format: json # Structured logs for container environments
console: true
# Security settings (MUST override via environment variables in production)
# Security settings
# jwt_secret and encryption_key are intentional placeholders — they MUST be
# overridden via ATTUNE__SECURITY__JWT_SECRET and ATTUNE__SECURITY__ENCRYPTION_KEY
# environment variables in docker-compose.yaml (or a .env file).
security:
jwt_secret: ${JWT_SECRET}
jwt_secret: override-via-ATTUNE__SECURITY__JWT_SECRET-env-var
jwt_access_expiration: 3600 # 1 hour
jwt_refresh_expiration: 604800 # 7 days
encryption_key: ${ENCRYPTION_KEY}
encryption_key: override-via-ATTUNE__SECURITY__ENCRYPTION_KEY-env-var
enable_auth: true
allow_self_registration: false
login_page:
show_local_login: true
show_oidc_login: true
show_ldap_login: true
oidc:
# example local dev
enabled: false
discovery_url: https://my.sso.provider.com/.well-known/openid-configuration
client_id: 31d194737840d32bd3afe6474826976bae346d77247a158c4dc43887278eb605
client_secret: xL2C9WOC8shZ2QrZs9VFa10JK1Ob95xcMtZU3N86H1Pz0my5
provider_name: my-sso-provider
provider_label: My SSO Provider
provider_icon_url: https://my.sso.provider.com/favicon.ico
redirect_uri: http://localhost:3000/auth/callback
post_logout_redirect_uri: http://localhost:3000/login
scopes:
- groups
# Uncomment and configure for your OIDC provider:
# discovery_url: https://auth.example.com/.well-known/openid-configuration
# client_id: your-client-id
# client_secret: your-client-secret
# provider_name: sso
# provider_label: SSO Login
# provider_icon_url: https://auth.example.com/favicon.ico
# redirect_uri: http://localhost:3000/auth/callback
# post_logout_redirect_uri: http://localhost:3000/login
# scopes:
# - groups
# Packs directory (mounted volume in containers)
packs_base_dir: /opt/attune/packs
@@ -98,61 +105,34 @@ artifacts_dir: /opt/attune/artifacts
# Executor service configuration
executor:
service_name: attune-executor
max_concurrent_executions: 50
heartbeat_interval: 30
task_timeout: 300
cleanup_interval: 120
scheduling_interval: 5
retry_max_attempts: 3
retry_backoff_multiplier: 2.0
retry_backoff_max: 300
scheduled_timeout: 300 # 5 minutes - fail executions stuck in SCHEDULED
timeout_check_interval: 60 # Check every minute for stale executions
enable_timeout_monitor: true
# Worker service configuration
worker:
service_name: attune-worker
worker_type: container
max_concurrent_tasks: 20
heartbeat_interval: 10 # Reduced from 30s for faster stale detection (staleness = 30s)
task_timeout: 300
cleanup_interval: 120
work_dir: /tmp/attune-worker
python:
executable: python3
venv_dir: /tmp/attune-worker/venvs
requirements_timeout: 300
nodejs:
executable: node
npm_executable: npm
modules_dir: /tmp/attune-worker/node_modules
install_timeout: 300
shell:
executable: /bin/bash
allowed_shells:
- /bin/bash
- /bin/sh
max_stdout_bytes: 10485760 # 10MB
max_stderr_bytes: 10485760 # 10MB
shutdown_timeout: 30
stream_logs: true
# Sensor service configuration
sensor:
service_name: attune-sensor
heartbeat_interval: 10 # Reduced from 30s for faster stale detection
max_concurrent_sensors: 50
heartbeat_interval: 10 # Reduced from 30s for faster stale detection
poll_interval: 10
sensor_timeout: 300
polling_interval: 10
cleanup_interval: 120
shutdown_timeout: 30
# Notifier service configuration
notifier:
service_name: attune-notifier
websocket_host: 0.0.0.0
websocket_port: 8081
heartbeat_interval: 30
connection_timeout: 60
host: 0.0.0.0
port: 8081
max_connections: 1000
message_buffer_size: 10000
# Agent binary distribution (serves the agent binary via API for remote downloads)
agent:

View File

@@ -69,6 +69,24 @@ services:
- attune-network
restart: on-failure
# Build and extract statically-linked pack binaries (sensors, etc.)
# These binaries are built with musl for cross-architecture compatibility
# and placed directly into the packs volume for sensor containers to use.
init-pack-binaries:
image: ${ATTUNE_IMAGE_REGISTRY:-git.rdrx.app/attune-system}/attune/pack-builder:${ATTUNE_IMAGE_TAG:-latest}
container_name: attune-init-pack-binaries
volumes:
- packs_data:/opt/attune/packs
entrypoint:
[
"/bin/sh",
"-c",
"mkdir -p /opt/attune/packs/core/sensors && cp /pack-binaries/attune-core-timer-sensor /opt/attune/packs/core/sensors/attune-core-timer-sensor && chmod +x /opt/attune/packs/core/sensors/attune-core-timer-sensor && echo 'Pack binaries copied successfully'",
]
restart: "no"
networks:
- attune-network
init-packs:
image: python:3.11-slim
container_name: attune-init-packs
@@ -93,6 +111,8 @@ services:
DEFAULT_ADMIN_PERMISSION_SET_REF: core.admin
command: ["/bin/sh", "/init-packs.sh"]
depends_on:
init-pack-binaries:
condition: service_completed_successfully
migrations:
condition: service_completed_successfully
postgres:
@@ -166,7 +186,7 @@ services:
ATTUNE__DATABASE__URL: postgresql://attune:attune@postgres:5432/attune
ATTUNE__DATABASE__SCHEMA: public
ATTUNE__MESSAGE_QUEUE__URL: amqp://attune:attune@rabbitmq:5672
ATTUNE__CACHE__URL: redis://redis:6379
ATTUNE__REDIS__URL: redis://redis:6379
ATTUNE__WORKER__WORKER_TYPE: container
ports:
- "8080:8080"
@@ -213,7 +233,7 @@ services:
ATTUNE__DATABASE__URL: postgresql://attune:attune@postgres:5432/attune
ATTUNE__DATABASE__SCHEMA: public
ATTUNE__MESSAGE_QUEUE__URL: amqp://attune:attune@rabbitmq:5672
ATTUNE__CACHE__URL: redis://redis:6379
ATTUNE__REDIS__URL: redis://redis:6379
ATTUNE__WORKER__WORKER_TYPE: container
volumes:
- ${ATTUNE_DOCKER_CONFIG_PATH:-./config.docker.yaml}:/opt/attune/config/config.yaml:ro

View File

@@ -119,14 +119,54 @@ for pack_dir in "$SOURCE_PACKS_DIR"/*; do
target_pack_dir="$TARGET_PACKS_DIR/$pack_name"
if [ -d "$target_pack_dir" ]; then
# Pack exists, update files to ensure we have latest (especially binaries)
# Pack exists, update non-binary files to ensure we have latest.
# Compiled sensor binaries in sensors/ are provided by init-pack-binaries
# (statically-linked musl builds) and must NOT be overwritten by
# the host's copy, which may be dynamically linked or the wrong arch.
echo -e "${YELLOW}${NC} Pack exists at: $target_pack_dir, updating files..."
# Detect ELF binaries already in the target sensors/ dir by
# checking for the 4-byte ELF magic number (\x7fELF) at the
# start of the file. The `file` command is unavailable on
# python:3.11-slim, so we read the magic bytes with `od`.
_skip_bins=""
if [ -d "$target_pack_dir/sensors" ]; then
for _bin in "$target_pack_dir/sensors"/*; do
[ -f "$_bin" ] || continue
_magic=$(od -A n -t x1 -N 4 "$_bin" 2>/dev/null | tr -d ' ')
if [ "$_magic" = "7f454c46" ]; then
_skip_bins="$_skip_bins $(basename "$_bin")"
fi
done
fi
# Copy everything from source, then restore any skipped binaries
# that were overwritten. We do it this way (copy-then-restore)
# rather than exclude-during-copy because busybox cp and POSIX cp
# have no --exclude flag.
if [ -n "$_skip_bins" ]; then
# Back up existing static binaries
_tmpdir=$(mktemp -d)
for _b in $_skip_bins; do
cp "$target_pack_dir/sensors/$_b" "$_tmpdir/$_b"
done
fi
if cp -rf "$pack_dir"/* "$target_pack_dir"/; then
echo -e "${GREEN}${NC} Updated pack files at: $target_pack_dir"
else
echo -e "${RED}${NC} Failed to update pack"
exit 1
fi
# Restore static binaries that were overwritten
if [ -n "$_skip_bins" ]; then
for _b in $_skip_bins; do
cp "$_tmpdir/$_b" "$target_pack_dir/sensors/$_b"
echo -e "${GREEN}${NC} Preserved static binary: sensors/$_b"
done
rm -rf "$_tmpdir"
fi
else
# Copy pack to target directory
echo -e "${YELLOW}${NC} Copying pack files..."