Commit Graph

21 Commits

Author SHA1 Message Date
Matt 6a94faa0e0 fix: Add CREDENTIALS_PATH and REGISTRATION_TOKEN for persistent auth
Build and Push Docker Image / build (push) Successful in 2m32s Details
- Add REGISTRATION_TOKEN env var (replaces legacy AGENT_TOKEN for new registrations)
- Add CREDENTIALS_PATH=/home/agent/.letsbe-agent/credentials.json to fix
  path mismatch (agent runs as root, ~ expands to /root, but volume is
  mounted at /home/agent/.letsbe-agent)
- Reduce CIRCUIT_BREAKER_COOLDOWN from 300s to 30s for faster recovery
- Update comments to clarify credential persistence behavior

This fixes the issue where agents would fail to reconnect after container
restarts because credentials were being saved to /root/.letsbe-agent/
instead of the persisted volume at /home/agent/.letsbe-agent/

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-09 16:01:04 +01:00
Matt 88ec5416fe chore: Reduce circuit breaker cooldown from 300s to 30s
Build and Push Docker Image / build (push) Successful in 2m37s Details
5 minutes was too long for typical orchestrator restarts that take seconds.
30 seconds is more reasonable for quick recovery.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-09 15:41:54 +01:00
Matt 2d27775a2c fix: Persist credentials across container and orchestrator restarts
Build and Push Docker Image / build (push) Successful in 1m56s Details
Previously, the agent would clear credentials on ANY heartbeat failure,
causing infinite re-registration loops when:
- Agent container was updated while orchestrator was running
- Orchestrator was restarted while agent was running

Changes:
- Add HeartbeatStatus enum and HeartbeatResult dataclass
- Modify heartbeat() to return status info instead of just bool
- Only clear credentials on 401/403 (AUTH_FAILED)
- Keep credentials on transient errors (NETWORK_ERROR, SERVER_ERROR)
- Handle AUTH_FAILED in heartbeat_loop() for mid-session invalidation

Scenarios now handled:
- Agent restart: keeps creds, retries until orchestrator responds
- Orchestrator restart: keeps creds, retries with backoff
- Admin deletes agent: clears creds, breaks out for re-registration

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-09 15:25:44 +01:00
Matt 41691523b5 feat: Add Poste.io and Chatwoot initial setup Playwright scenarios
Build and Push Docker Image / build (push) Successful in 1m54s Details
- Add poste_initial_setup scenario for mail server wizard automation
  - Configures mailserver hostname, creates admin account
  - Auto-generates 24-char password if not provided
  - Returns credentials in result data

- Add chatwoot_initial_setup scenario for super admin creation
  - Fills name, company, email, password fields
  - Unchecks newsletter subscription checkbox
  - Clicks "Finish Setup" to complete wizard
  - Auto-generates password if not provided

Both scenarios include health checks and return generated credentials
for storage in task results.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-09 14:51:17 +01:00
Matt b8e3cc3685 fix: Added circuit breaker
Build and Push Docker Image / build (push) Successful in 2m7s Details
2025-12-09 13:23:21 +01:00
Matt e8674cb763 feat: add Playwright browser automation executor
Build and Push Docker Image / build (push) Successful in 2m22s Details
Stage 1 - Core Framework:
- Add PlaywrightExecutor with scenario-based dispatch
- Implement mandatory domain allowlists for security
- Add route interception to block unauthorized domains
- Create BaseScenario ABC, ScenarioOptions, ScenarioResult
- Add scenario registry with @register_scenario decorator
- Add validation helpers (is_domain_allowed, validate_allowed_domains)
- Add Playwright config settings (artifacts dir, timeouts)

Stage 2 - Scenarios:
- Add 'echo' test scenario for connectivity verification
- Add 'nextcloud_initial_setup' for first-time admin setup wizard
- Install Playwright + Chromium in Dockerfile
- Configure docker-compose with artifacts volume and security opts

Includes 32 unit tests for validation logic and executor behavior.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-08 15:55:16 +01:00
Matt 813e9127f5 Fix auth headers not applied after registration
Build and Push Docker Image / build (push) Successful in 51s Details
Bug: After registration, credentials were set directly on private
attributes (_agent_id, _agent_secret) instead of using property
setters. This bypassed _invalidate_client(), so the HTTP client
kept using old headers without X-Agent-Id/X-Agent-Secret.

Fix: Use property setters (self.agent_id, self.agent_secret) which
trigger _invalidate_client() to recreate the client with new headers.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-08 13:16:21 +01:00
Matt 7b2674debf fix: remove GHA cache (not supported by Gitea Actions)
Build and Push Docker Image / build (push) Successful in 1m3s Details
2025-12-08 12:16:06 +01:00
Matt 9b7ac40ad7 fix: rename secret to REGISTRY_TOKEN
Build and Push Docker Image / build (push) Failing after 30s Details
2025-12-08 12:14:30 +01:00
Matt 9a34834fe4 refactor: use Gitea container registry instead of Docker Hub
Build and Push Docker Image / build (push) Failing after 34s Details
Image will be pushed to: code.letsbe.solutions/letsbe/sysadmin-agent

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-08 12:12:58 +01:00
Matt d17722e362 chore: trigger CI build
Build and Push Docker Image / build (push) Failing after 32s Details
2025-12-08 12:10:15 +01:00
Matt 1df0b7a101 feat: add Gitea Actions workflow for Docker image builds
Automatically builds and pushes to Docker Hub on:
- Push to main/master branch
- Version tags (v*)

Image: letsbesolutions/sysadmin-agent

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-08 12:08:19 +01:00
Matt 51b3050b5c feat: add secure registration with credential persistence
- Add REGISTRATION_TOKEN config for new secure registration flow
- Add agent_secret and credentials_path config options
- Update HTTP client to use X-Agent-Id/X-Agent-Secret headers
- Add credential persistence to ~/.letsbe-agent/credentials.json
- Load persisted credentials on startup to survive restarts
- Verify credentials via heartbeat before skipping registration
- Maintain backward compatibility with legacy Bearer token auth

The agent now:
1. First tries to load persisted credentials
2. Validates them via heartbeat
3. Falls back to registration if invalid/missing
4. Persists new credentials after successful registration

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-07 11:11:59 +01:00
Matt cea54183cc feat: add tenant_id support to agent registration
- Add tenant_id field to Settings (via TENANT_ID env var)
- Include tenant_id in registration payload when configured
- Add TENANT_ID to docker-compose.yml with documentation
- Add ROADMAP.md tracking project progress

Agents can now be associated with a specific tenant at startup.
Required in production, optional in development.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 20:10:43 +01:00
Matt 47b3422829 Add NEXTCLOUD_SET_DOMAIN executor for domain configuration
Implements a Nextcloud-specific executor that accepts a high-level
public_url payload and runs the appropriate occ config:system:set
commands via docker compose exec. The Orchestrator remains unaware
of container names, occ paths, and docker-compose syntax.

Features:
- Task type: NEXTCLOUD_SET_DOMAIN
- Payload: { "public_url": "https://cloud.example.com" }
- Parses URL into scheme and host, defaults to https if not provided
- Strips trailing slashes from URLs
- Runs three occ commands: overwritehost, overwriteprotocol, overwrite.cli.url
- Returns partial results with failed_args for debugging on failure
- Configurable constants for stack dir, service name, occ path, and user

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-04 14:01:41 +01:00
Matt e8eae5a8e0 Add ENV_INSPECT and FILE_INSPECT executors with tests
- Add EnvInspectExecutor to read ENV files and return key-value pairs
- Add FileInspectExecutor to read portions of text files (up to 1MB)
- Add FileExecutor tests including /opt/letsbe/config path verification
- Register new executors in EXECUTOR_REGISTRY

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-04 00:47:08 +01:00
Matt ae78376dfb Download Docker Compose plugin directly from GitHub
docker-compose-plugin isn't in Debian repos, need to download
the binary directly from Docker's GitHub releases.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-03 16:35:51 +01:00
Matt a16a585f86 Add docker-compose-plugin to Dockerfile
docker-cli alone doesn't include 'docker compose' subcommand.
Need docker-compose-plugin for 'docker compose -f' to work.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-03 16:31:47 +01:00
Matt db616aece5 Fix Dockerfile: use docker-cli instead of docker.io
docker.io on Debian Trixie only installs the daemon (dockerd), not the CLI.
The docker CLI is in the separate docker-cli package.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-03 16:02:50 +01:00
Matt 9385ab09e4 Fix docker volume mounts for host directory access
- Replace named volume (agent_data) with bind mounts for /opt/letsbe/{env,stacks,nginx}
- Update ALLOWED_FILE_ROOT default from /opt/agent_data to /opt/letsbe
- Add startup validation that warns (but doesn't block) if host dirs missing

This fixes ENV_UPDATE writes going to container filesystem instead of host,
and DOCKER_RELOAD failing with "File does not exist" errors.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-03 15:20:07 +01:00
Matt b351217509 Initial commit: SysAdmin Agent with executors
- Core agent architecture with task manager and orchestrator client
- Executors: ECHO, SHELL, FILE_WRITE, ENV_UPDATE, DOCKER_RELOAD, COMPOSITE, PLAYWRIGHT
- EnvUpdateExecutor: Secure .env file management with key validation
- DockerExecutor: Docker Compose operations with path security
- CompositeExecutor: Sequential task execution with fail-fast behavior
- Comprehensive unit tests (84 tests)
- Docker deployment configuration

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-03 11:05:54 +01:00