Skip to content

feat: add --user override and per-server env to fleet exec/ssh (#763, #816)#944

Merged
chubes4 merged 1 commit intomainfrom
feat/fleet-ssh-user-and-env
Mar 23, 2026
Merged

feat: add --user override and per-server env to fleet exec/ssh (#763, #816)#944
chubes4 merged 1 commit intomainfrom
feat/fleet-ssh-user-and-env

Conversation

@chubes4
Copy link
Member

@chubes4 chubes4 commented Mar 23, 2026

Summary

--user override (#763)

Override the SSH user for a single invocation:

homeboy fleet exec fleet-servers --user root -- homeboy update
homeboy ssh extra-chill --user root -- systemctl restart nginx

No more maintaining duplicate server entries for the same host. The configured user stays correct for deploys, --user overrides for admin ops.

Per-server env config (#816)

Servers can declare environment variables that are injected before every SSH command:

{
  "id": "extra-chill",
  "host": "178.156.238.82",
  "user": "opencode",
  "env": {
    "PATH": "/home/opencode/.local/bin:$PATH"
  }
}

Solves the non-interactive SSH PATH problem — fleet exec now finds user-local binaries.

Implementation

  • Server struct gets env: HashMap<String, String> (serde-defaulted, skip-if-empty)
  • SshClient gets env field + prepend_env() method that wraps commands with export K=V && ...
  • Applied transparently in execute() and execute_interactive() — all SSH consumers get env injection for free

Closes #763, #816

…816)

Two fleet improvements:

1. --user flag on fleet exec and ssh (#763):
   Override the SSH user for a single invocation without maintaining
   duplicate server entries. Threads through collect_exec and applies
   to each SshClient before execution.

   homeboy fleet exec fleet-servers --user root -- homeboy update
   homeboy ssh extra-chill --user root -- systemctl restart nginx

2. Per-server env config (#816):
   Servers can declare environment variables in their config JSON.
   Values are injected via 'export K=V && ...' before every command,
   handling non-interactive SSH's limited PATH. Applies to both
   execute() and execute_interactive().

   {
     "env": { "PATH": "/home/user/.local/bin:$PATH" }
   }

Both features propagate through all SSH consumers (fleet exec, ssh,
deploy, file ops) transparently via SshClient.
@chubes4 chubes4 merged commit 9976f89 into main Mar 23, 2026
1 check passed
@homeboy-ci
Copy link
Contributor

homeboy-ci bot commented Mar 23, 2026

Homeboy Results — homeboy

Audit

Failure Digest

Audit Failure Digest

  • Alignment score: 0.921
  • Severity counts: info: 8, unknown: 3, warning: 15
  • Outliers in current run: 3
  • Parsed outlier entries: 3
  • Drift increased: yes
  • New findings since baseline: 8
    1. intra-method-duplication — Duplicated block in collect_exec — 8 identical lines at line 92 and line 110 (intra-method-duplication::src/core/fleet/exec.rs::IntraMethodDuplicate)
    2. intra-method-duplication — Duplicated block in resolve_internal — 8 identical lines at line 77 and line 98 (intra-method-duplication::src/core/server/connection.rs::IntraMethodDuplicate)
    3. parallel-implementation — Parallel implementation: log_fleet_dashboard has similar call pattern to log_dashboard_table in src/commands/status.rs — shared calls: is_terminal, max, stderr (parallel-implementation::src/commands/fleet.rs::ParallelImplementation)
    4. field_patterns — Repeated field group [stderr, stdout] appears in 4 structs: src/commands/file.rs::FileOutput, src/commands/ssh.rs::SshConnectOutput, src/core/db/operations.rs::DbResult, src/core/fleet/exec.rs::FleetExecProjectResult (field_patterns::src/commands/ssh.rs::RepeatedFieldPattern)
    5. field_patterns — Repeated field group [stderr, stdout] appears in 4 structs: src/commands/file.rs::FileOutput, src/commands/ssh.rs::SshConnectOutput, src/core/db/operations.rs::DbResult, src/core/fleet/exec.rs::FleetExecProjectResult (field_patterns::src/core/fleet/exec.rs::RepeatedFieldPattern)
  • Top actionable findings:
    1. src/commands/fleet.rs — high_item_count — File has 18 top-level items (threshold: 15)
    2. src/commands/server.rs — high_item_count — File has 18 top-level items (threshold: 15)
    3. src/commands/ssh.rs — intra_method_duplicate — Duplicated block in run — 5 identical lines at line 129 and line 147
    4. src/core/fleet/exec.rs — intra_method_duplicate — Duplicated block in collect_exec — 8 identical lines at line 92 and line 110
    5. src/core/server/client.rs — intra_method_duplicate — Duplicated block in get_local_ips — 5 identical lines at line 439 and line 470
All parsed audit findings (26)
1. **src/commands/fleet.rs** — high_item_count — File has 18 top-level items (threshold: 15)
2. **src/commands/server.rs** — high_item_count — File has 18 top-level items (threshold: 15)
3. **src/commands/ssh.rs** — intra_method_duplicate — Duplicated block in `run` — 5 identical lines at line 129 and line 147
4. **src/core/fleet/exec.rs** — intra_method_duplicate — Duplicated block in `collect_exec` — 8 identical lines at line 92 and line 110
5. **src/core/server/client.rs** — intra_method_duplicate — Duplicated block in `get_local_ips` — 5 identical lines at line 439 and line 470
6. **src/core/server/connection.rs** — intra_method_duplicate — Duplicated block in `resolve_internal` — 8 identical lines at line 77 and line 98
7. **src/commands/fleet.rs** — parallel_implementation — Parallel implementation: `log_fleet_dashboard` has similar call pattern to `log_dashboard_table` in src/commands/status.rs — shared calls: `is_terminal`, `max`, `stderr`
8. **src/core/fleet/exec.rs** — missing_test_file — No test file found (expected 'tests/core/fleet/exec_test.rs') and no inline tests
9. **src/core/server/client.rs** — missing_test_method — Method 'execute' has no corresponding test (expected 'test_execute')
10. **src/core/server/client.rs** — missing_test_method — Method 'execute_interactive' has no corresponding test (expected 'test_execute_interactive')
11. **src/core/server/client.rs** — missing_test_method — Method 'execute_local_command' has no corresponding test (expected 'test_execute_local_command')
12. **src/core/server/client.rs** — missing_test_method — Method 'execute_local_command_in_dir' has no corresponding test (expected 'test_execute_local_command_in_dir')
13. **src/core/server/client.rs** — missing_test_method — Method 'execute_local_command_interactive' has no corresponding test (expected 'test_execute_local_command_interactive')
14. **src/core/server/client.rs** — missing_test_method — Method 'execute_local_command_passthrough' has no corresponding test (expected 'test_execute_local_command_passthrough')
15. **src/core/server/client.rs** — missing_test_method — Method 'from_server' has no corresponding test (expected 'test_from_server')
16. **src/core/server/client.rs** — missing_test_method — Method 'upload_file' has no corresponding test (expected 'test_upload_file')
17. **src/core/server/connection.rs** — missing_test_file — No test file found (expected 'tests/core/server/connection_test.rs') and no inline tests
18. **src/core/server/keys.rs** — missing_test_file — No test file found (expected 'tests/core/server/keys_test.rs') and no inline tests
19. **src/commands/ssh.rs** — repeated_field_pattern — Repeated field group [stderr, stdout] appears in 4 structs: src/commands/file.rs::FileOutput, src/commands/ssh.rs::SshConnectOutput, src/core/db/operations.rs::DbResult, src/core/fleet/exec.rs::FleetExecProjectResult
20. **src/core/fleet/exec.rs** — repeated_field_pattern — Repeated field group [stderr, stdout] appears in 4 structs: src/commands/file.rs::FileOutput, src/commands/ssh.rs::SshConnectOutput, src/core/db/operations.rs::DbResult, src/core/fleet/exec.rs::FleetExecProjectResult
21. **src/core/server/client.rs** — repeated_field_pattern — Repeated field group [host, port] appears in 3 structs: src/core/project/mod.rs::DatabaseConfig, src/core/server/client.rs::SshClient, src/core/server/mod.rs::Server
22. **src/core/server/client.rs** — repeated_field_pattern — Repeated field group [stderr, stdout] appears in 7 structs: src/core/engine/cli_tool.rs::CliToolResult, src/core/engine/command.rs::CapturedOutput, src/core/engine/hooks.rs::HookCommandResult, src/core/error/mod.rs::RemoteCommandFailedDetails, src/core/extension/runner.rs::RunnerOutput, src/core/git/operations.rs::GitOutput, src/core/server/client.rs::CommandOutput
23. **src/core/server/mod.rs** — repeated_field_pattern — Repeated field group [host, port] appears in 3 structs: src/core/project/mod.rs::DatabaseConfig, src/core/server/client.rs::SshClient, src/core/server/mod.rs::Server
24. **src/commands/docs.rs** — outlier — (outlier)
25. **tests/commands/deploy_test.rs** — outlier — (outlier)
26. **src/core/engine/undo/rollback.rs** — outlier — (outlier)
- Full audit log: https://github.com/Extra-Chill/homeboy/actions/runs/23420575111

Autofixability classification

  • Overall: auto_fixable
  • Autofix enabled: yes
  • Autofix attempted this run: no
  • Auto-fixable failed commands:
    • audit
  • Failed commands with available automated fixes:
    • audit

Machine-readable artifacts

  • homeboy-lint-summary.json
  • homeboy-test-failures.json
  • homeboy-audit-summary.json
  • homeboy-autofixability.json

⚡ Scope: changed files only

audit (changed files only)

Auto-refactor

ℹ️ Autofix enabled, but no fixable file changes were produced

Failure Digest

Autofixability classification

  • Overall: human_needed
  • Autofix enabled: yes
  • Autofix attempted this run: no
  • Human-needed failed commands:
    • refactor --from all

Machine-readable artifacts

  • homeboy-lint-summary.json
  • homeboy-test-failures.json
  • homeboy-audit-summary.json
  • homeboy-autofixability.json

⚡ Scope: changed files only

refactor --from all

Tooling versions
  • Homeboy CLI: homeboy 0.85.3+90cbd51
  • Extension: rust from https://github.com/Extra-Chill/homeboy-extensions
  • Extension revision: unknown
  • Action: Extra-Chill/homeboy-action@v2

Homeboy Action v1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fleet exec: support per-command SSH user override

1 participant