Skip to content

v2.13.0 — AWS provider, S3 object storage, 21 new MCP tools

Choose a tag to compare

@zoltanam zoltanam released this 25 May 20:49
· 89 commits to master since this release

AWS provider, end-to-end

Servonaut now manages AWS EC2 as a first-class provider alongside Hetzner and OVH — full lifecycle in the TUI and full coverage on the MCP server.

TUI

  • AWS sidebar section with ⚙ Manage (per-instance start / stop / reboot / terminate), 📊 CloudWatch, 🔒 IP Ban Manager, and 🔍 CloudTrail — the AWS-specific log + security tools previously lived under their own "Logs & Security" section; they're now grouped where they belong.
  • EC2 launch wizard — full create-instance flow with region / AMI / instance type / keypair / subnet / security-group selection, AMI search with debounce, and Name tag pre-fill.
  • S3 / Object Storage screens for AWS, Hetzner Object Storage, and OVH Object Storage — bucket list, object browser, upload / download / copy / move / delete, presigned-URL generation, breadcrumb navigation. All three providers share the same screen (ObjectStorageScreen(provider=...)).
  • Provider setup wizards now own the S3 form — Hetzner setup adds a Step 4 (Object Storage), OVH setup adds a Step 7. Each setup screen also rebuilds the S3 service on save so the sidebar Object Storage button appears immediately without a restart.
  • Region dropdowns replace free-form text inputs on all three S3 forms. AWS = 21 regions, Hetzner = 3, OVH = 9. Default values selected so the form is never invalid.
  • Docked Save Settings button at the bottom of the Settings screen — no more hunting for Ctrl+S after scrolling through twelve sections.

MCP server (+21 tools)

11 AWS EC2 tools + 10 S3 tools (provider-parameterised across aws / hetzner / ovh):

Tier Tools
readonly aws_list_regions, aws_list_amis, aws_list_instance_types, aws_list_key_pairs, aws_list_subnets, aws_list_security_groups, s3_list_buckets, s3_list_objects
standard aws_start_instance, aws_stop_instance, aws_reboot_instance, s3_download_object
dangerous aws_terminate_instance, aws_run_instances, s3_create_bucket, s3_delete_bucket, s3_upload_object, s3_delete_object, s3_copy_object, s3_move_object, s3_generate_presigned_url

All mutating tools go through the existing audit trail (~/.servonaut/aws_audit.jsonl for AWS lifecycle, ~/.servonaut/mcp_audit.jsonl for the MCP layer). s3_generate_presigned_url is classified dangerous despite being a read — the returned URL is a bearer credential and is masked in the audit row (only the JSON-RPC return value to the agent contains the URL itself).

Sidebar conditional visibility

OVH and Hetzner sections were previously hidden entirely when the compute service wasn't configured — which broke the new "S3-only" use case (configure object-storage credentials without setting up the provider's compute API). Now: section visible when either compute OR S3 is configured, with the compute-only buttons hiding when only S3 is set up. AWS section is always visible per the original design; only its Object Storage button is gated on credential availability.

Fix: config-sync data loss

A separate bug found while testing this PR — Hetzner api_token and OVH application_key / application_secret / consumer_key were being silently wiped on config-sync pull because the preservation loop didn't recurse into nested dataclasses at depth ≥2 and the copy at the top was shallow. Both fixed with deep-copy + materialising depth-aware preservation. Regression tests added.

Under the hood

  • New services/object_storage_service.py — single ObjectStorageService class parameterised by provider; SSRF-guarded endpoint validation (https-only, no @-userinfo, no path/query/fragment, alternate IPv4 encodings rejected via socket.inet_aton), path-traversal validation against (cwd, ~, ~/Downloads).
  • New services/object_storage_factory.py — single build_object_storage_services(config) shared between the TUI app and the headless MCP server so credential-handling logic never drifts between the two surfaces.
  • New services/aws_audit.py — JSONL audit trail with O_NOFOLLOW | O_CREAT | O_APPEND mode 0o600 — symlink-resistant + private by default.
  • New services/object_storage_regions.py — single source of truth for the dropdown options + defaults.
  • config.json is now written atomically with mode 0o600 + O_NOFOLLOW; a leftover symlink at the target is detected and refused rather than silently followed.

Install / upgrade

pipx install servonaut --force
# or for an existing install
pipx upgrade servonaut

Full diff

v2.12.0...v2.13.0