Documentation
¶
Index ¶
- Variables
- func HandleCommandResult(err error)
- func HandlePendingApproval(err error, reRunHint utils.NextAction) bool
- func ParseEnvArg(arg string, env map[string]string) string
- func RunCommandWithRetry(ac *client.AlpaconClient, serverName, command, username, groupname string, ...) error
- func RunExecWithApprovalWait(ac *client.AlpaconClient, serverName, command, username, groupname string, ...) error
- func RunExecWithPresenceStepUp(ac *client.AlpaconClient, serverName, command, username, groupname string, ...) error
- func RunRemoteExec(parsed RemoteExecArgs)
- func ShellJoin(parts []string) string
- type RemoteExecArgs
Constants ¶
This section is empty.
Variables ¶
var ExecCmd = &cobra.Command{ Use: "exec [flags] [USER@]SERVER [--] COMMAND...", Short: "Execute a command on a remote server", Long: `Execute a command on a remote server. This command executes a specified command on a remote server and returns the output. It supports SSH-like syntax for specifying the user and server. Use -- to separate alpacon flags from the remote command, ensuring that flags intended for the remote command (e.g., -U, -d) are not interpreted as alpacon flags. All flags must be placed before the server name. Shell metacharacters (;, |, &, $) pass through unquoted to the remote shell. To send a literal metacharacter, wrap the argument in quotes: alpacon exec server 'echo hello;world' Flags: -u, --username [USER_NAME] Specify the username for command execution. -g, --groupname [GROUP_NAME] Specify the group name for command execution. --env="KEY" Pass an environment variable to the remote command, reading its value from the current shell. This keeps the value off the alpacon command line and out of the audit log—use it for secrets such as passwords or tokens. --env="KEY=VALUE" Set 'KEY' to a literal value. Discouraged: the value is written on the command line and recorded verbatim in the audit log. Never pass credentials this way. --work-session [UUID] Attach this command to a work-session. Overrides the workspace's active session set via 'alpacon work-session use'. --detach Submit the command and return immediately without waiting for completion. Prints the job ID to stdout. Use 'alpacon exec logs JOB_ID' to retrieve the result. --wait When a sudo command needs human approval, block and re-attempt until a reviewer approves it in the Alpacon console (web), or the wait times out. Exit code 3 indicates a WorkSession gate denial; run with --output json to parse a machine-readable diagnostic on stderr. Exit code 4 indicates the sudo command is pending human approval (approve it in the Alpacon console, then re-run, or pass --wait to block); --output json emits {"status":"pending_approval", ...} on stdout. Requires an active WorkSession when using Browser login (Auth0); Token auth (API token or Service token) bypasses this requirement.`, Example: ` # Simple command execution alpacon exec prod-docker docker ps alpacon exec root@prod-docker docker ps # Use -- to pass flags to the remote command alpacon exec root@db-server -- docker exec postgres psql -U myproject -d myproject alpacon exec my-server -- grep -r "pattern" /var/log # Specify user and group with flags alpacon exec -u root prod-docker systemctl status nginx alpacon exec -g docker user@server docker images # Pass a secret via the shell env; the value stays off the alpacon command line # and out of the audit log. psql reads PGPASSWORD from the environment, so it # never lands in the remote process's argv either. export PGPASSWORD=hunter2 alpacon exec --env="PGPASSWORD" db-server -- psql -h localhost -U app -c 'SELECT 1' # Submit a command asynchronously and retrieve the result later alpacon exec --detach web-server -- apt-get update alpacon exec logs <JOB_ID>`, DisableFlagParsing: true, Run: func(cmd *cobra.Command, args []string) { parsed := ParseRemoteExecArgs(args) if parsed.ShowHelp { _ = cmd.Help() return } if parsed.Err != "" { utils.CliErrorWithExit("%s", parsed.Err) return } if parsed.Server == "" { _ = cmd.Help() utils.CliErrorWithExit("server name is required.") return } if parsed.Command == "" { utils.CliErrorWithExit("You must specify a command to execute.") return } RunRemoteExec(parsed) }, }
Functions ¶
func HandleCommandResult ¶ added in v1.4.8
func HandleCommandResult(err error)
HandleCommandResult exits appropriately on error. Output is streamed to stdout during execution; on a remote failure the error carries that output, used here only to surface the sudo-denial hint (not re-printed).
func HandlePendingApproval ¶ added in v1.7.2
func HandlePendingApproval(err error, reRunHint utils.NextAction) bool
HandlePendingApproval emits the structured pending-approval feedback for an exec sudo command that was denied SUDO_APPROVAL_REQUIRED and not waited on, then exits with ExitCodePendingApproval. It reports true when it handled the err; the caller skips its normal result handling on true. The exec denial line carries no approval request id, so the machine signal omits it. reRunHint is the exact command the caller invoked (with any --env caveat in its Description), so a human can copy-paste it once the request is approved.
func ParseEnvArg ¶ added in v1.9.0
ParseEnvArg parses a --env token into env. A bare KEY reads the shell value, warning and skipping if unset; malformed input returns an error message.
func RunCommandWithRetry ¶ added in v1.3.2
func RunCommandWithRetry(ac *client.AlpaconClient, serverName, command, username, groupname string, env map[string]string, workSessionID string, out io.Writer) error
RunCommandWithRetry executes a remote command with MFA/username-required error handling and retry logic, streaming output to out. workSessionID is forwarded as the work_session field; pass "" to omit it.
func RunExecWithApprovalWait ¶ added in v1.7.2
func RunExecWithApprovalWait(ac *client.AlpaconClient, serverName, command, username, groupname string, env map[string]string, workSessionID string, wait bool, out io.Writer) error
RunExecWithApprovalWait runs a command via RunExecWithPresenceStepUp and, when it is denied pending human approval (SUDO_APPROVAL_REQUIRED) and wait is set, blocks and re-attempts the command on a fixed interval until a reviewer approves it out of band (the re-run then succeeds or hits a different, terminal denial), or the bounded timeout elapses. When wait is false, or the denial is anything other than SUDO_APPROVAL_REQUIRED, it returns the first err unchanged so the caller's pending/denial handling runs.
Re-attempting the command is the only poll available here: the plugin's denial line carries the denial code but no approval request id, and this credential channel has no approval-status endpoint to query (ADR 0015 moves approval out of band). Re-running is side-effect-safe: a sudo command pending approval is denied by the server and never executes, so each poll tick is a no-op denial until a reviewer approves, at which point the command runs exactly once. The poll mirrors the MFA step-up structure (api/mfa/mfa.go): a spinner, a fixed-interval ticker, and a precise deadline.
func RunExecWithPresenceStepUp ¶ added in v1.7.2
func RunExecWithPresenceStepUp(ac *client.AlpaconClient, serverName, command, username, groupname string, env map[string]string, workSessionID string, out io.Writer) error
RunExecWithPresenceStepUp runs a command via RunCommandWithRetry and, when it is denied for a missing recent MFA (SUDO_PRESENCE_REQUIRED) on an interactive terminal, offers an MFA step-up and retries once. Non-interactive callers (scripts, CI, AI agents) fall through unchanged so HandleCommandResult prints the static denial hint; non-interactive humans additionally get the verification link they can complete out of band. Reached via RunRemoteExec by exec and websh command mode; interactive websh keeps its own sudo MFA flow.
func RunRemoteExec ¶ added in v1.9.0
func RunRemoteExec(parsed RemoteExecArgs)
RunRemoteExec is the shared post-parse execution path for exec and websh command mode. Requires Server and Command to be non-empty.
func ShellJoin ¶ added in v1.4.8
ShellJoin reassembles tokenized command parts into a single string. Parts containing whitespace or single quotes are re-quoted to preserve argument boundaries; metacharacters pass through for the remote shell. A single-element slice is returned as-is (already a formed command line).
Types ¶
type RemoteExecArgs ¶ added in v1.3.2
type RemoteExecArgs struct {
Username string
Groupname string
WorkSessionID string
OutputFormat string
Server string
Command string
Env map[string]string
Detach bool
Wait bool
ShowHelp bool
Err string
}
RemoteExecArgs holds parsed arguments for remote command execution.
func ParseRemoteExecArgs ¶ added in v1.3.2
func ParseRemoteExecArgs(args []string) RemoteExecArgs
ParseRemoteExecArgs parses raw CLI arguments with manual flag handling. It recognizes -u/--username, -g/--groupname, and -h/--help flags before the server name.
The -- separator has two roles depending on position:
- After the server name: acts as a command separator. Everything after it is the remote command, with no further flag parsing.
- Before the server name (e.g., after flags): acts as an end-of-flags marker. The first arg after -- becomes the server, the rest is the command.
Without --, everything after the server name is the remote command.
Layout: [flags] [USER@]SERVER [--] COMMAND...