Operate

Brokered handoffs

Send managed values through SSH stdin, handle temporary credential files, and rerun consumers with fresh paths.

Keep secret expansion inside the command HASP starts. hasp run supplies an environment value; hasp inject --file supplies a temporary file path. Both redact managed values from captured child output. Neither prevents the child from writing a file or sending a value to an endpoint you selected.

Send a value through SSH stdin

The remote command must accept its input on stdin. Use a fixed, reviewed command and an SSH destination you have verified:

hasp inject --project-root . --grant-project session \
  --env TOKEN=@DEPLOY_TOKEN --file SSH_KEY=@DEPLOY_KEY -- \
  sh -c 'printf "%s" "$TOKEN" | ssh -T -i "$SSH_KEY" deploy@example.com /usr/local/bin/consume-deploy-token'

DEPLOY_KEY must be a file-kind item exposed to this project. Secret policies that require a grant also need --grant-secret once or another permitted scope. The outer single quotes defer $TOKEN and $SSH_KEY expansion until the brokered shell runs. There is no secret reveal or plaintext command substitution in the caller.

OpenSSH's -T option disables pseudo-terminal allocation. Do not use -n, which disconnects stdin, for this handoff. Keep host-key verification enabled. SSH constructs a remote shell command from its trailing arguments; do not interpolate secrets or untrusted text into that command string.

For a file-kind value that the remote tool reads from stdin, put cat "$CREDENTIAL_PATH" on the left of the pipe instead:

hasp inject --project-root . --grant-project session \
  --file CREDENTIAL_PATH=@SERVICE_CREDENTIAL --file SSH_KEY=@DEPLOY_KEY -- \
  sh -c 'cat "$CREDENTIAL_PATH" | ssh -T -i "$SSH_KEY" deploy@example.com /usr/local/bin/consume-service-credential'

A remote tool that requires a file

Install and review the remote consumer separately. It can read stdin into a private temporary file, run the tool, and remove the file when the shell exits:

#!/bin/sh
set -eu
umask 077
credential=$(mktemp)
trap 'rm -f "$credential"' EXIT
trap 'exit 129' HUP
trap 'exit 130' INT
trap 'exit 143' TERM
cat > "$credential"
your-tool --credential-file "$credential"

Replace your-tool with the reviewed consumer. The trap handles ordinary success, failure, and the listed catchable signals. It cannot run after SIGKILL, a machine failure, or an abrupt termination that does not reach the shell. HASP removes its local files; it cannot guarantee remote cleanup. Keep remote creation, use, and cleanup in one invocation, and arrange remote recovery for abandoned files when needed.

Temporary paths expire after each run

HASP creates local injection files outside the repository with mode 0600 in a private run directory. The runner removes that directory when the command ends, including a nonzero exit. A cleanup failure returns an error with the remaining directory and the command's outcome. Inspect both before retrying: the command may already have changed the remote system.

A consumer that saves a credential path in persistent configuration will retain an unusable path after the run. Save the HASP reference in an app profile, then configure and use the consumer within each brokered invocation:

hasp app connect service-task --project-root . --install=never \
  --cmd './scripts/service-task.sh' --file CREDENTIAL_PATH=SERVICE_CREDENTIAL
hasp app run service-task

service-task.sh must read the current $CREDENTIAL_PATH, configure the tool if required, and finish using the file before it exits. Each app run creates a fresh path. A detached service that needs the file after its launcher exits needs a different lifecycle; the launcher cannot make this temporary path durable. Never commit the injected file or copy it into agent output.