|
| 1 | +# CLAUDE.md |
| 2 | + |
| 3 | +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. |
| 4 | + |
| 5 | +## Project Overview |
| 6 | + |
| 7 | +This is a GitHub Action for executing remote SSH commands. Built using a composite action pattern, it downloads and runs the [drone-ssh](https://github.com/appleboy/drone-ssh) binary (written in Go) to execute SSH commands on remote hosts. |
| 8 | + |
| 9 | +**Key characteristics:** |
| 10 | + |
| 11 | +- No local compilation required - downloads pre-built binaries from drone-ssh releases |
| 12 | +- Shell-based composite action using `entrypoint.sh` |
| 13 | +- Supports password and SSH key authentication, proxies, multiple hosts, and environment variable passing |
| 14 | +- All input parameters are passed via `INPUT_*` environment variables |
| 15 | + |
| 16 | +## Architecture |
| 17 | + |
| 18 | +### Execution Flow |
| 19 | + |
| 20 | +1. **action.yml** - GitHub Actions composite action definition |
| 21 | + - Defines all input parameters and their descriptions |
| 22 | + - Sets up environment variables with `INPUT_*` prefix |
| 23 | + - Calls `entrypoint.sh` |
| 24 | + |
| 25 | +2. **entrypoint.sh** - Main entry point |
| 26 | + - Detects platform (Linux/Darwin/Windows) and architecture (amd64/arm64) |
| 27 | + - Downloads appropriate `drone-ssh` binary from GitHub releases |
| 28 | + - Executes the binary with all environment variables |
| 29 | + - Handles `capture_stdout` for output capture |
| 30 | + |
| 31 | +3. **drone-ssh binary** - The actual SSH client (separate Go project) |
| 32 | + - Performs SSH connection and command execution |
| 33 | + - Not part of this repository |
| 34 | + |
| 35 | +### Key Files |
| 36 | + |
| 37 | +- `action.yml` - Action metadata and input/output definitions |
| 38 | +- `entrypoint.sh` - Platform detection, binary download, and execution |
| 39 | +- `testdata/` - Test scripts and SSH keys for CI workflows |
| 40 | +- `.github/workflows/main.yml` - Comprehensive test suite using Docker containers |
| 41 | + |
| 42 | +## Testing |
| 43 | + |
| 44 | +### Running Tests |
| 45 | + |
| 46 | +Tests run automatically via GitHub Actions workflows. The test suite uses Docker containers running OpenSSH servers: |
| 47 | + |
| 48 | +```bash |
| 49 | +# Tests run automatically on push via .github/workflows/main.yml |
| 50 | +# Tests create Docker containers with openssh-server and test various scenarios |
| 51 | +``` |
| 52 | + |
| 53 | +### Test Categories (from main.yml) |
| 54 | + |
| 55 | +The test workflow covers: |
| 56 | + |
| 57 | +- **default-user-name-password**: Basic password authentication |
| 58 | +- **check-ssh-key**: RSA key authentication, key priority over password |
| 59 | +- **support-key-passphrase**: Encrypted SSH keys |
| 60 | +- **multiple-server**: Multiple hosts with different ports |
| 61 | +- **support-ed25519-key**: ED25519 key format |
| 62 | +- **testing-with-env**: Environment variable passing, `allenvs`, custom formats |
| 63 | +- **testing06**: IPv6 connectivity |
| 64 | +- **testing07**: Special characters in passwords |
| 65 | +- **testing-capturing-output**: Output capture functionality |
| 66 | +- **testing-script-stop**: Script error handling with `set -e` |
| 67 | +- **testing-script-error**: Error propagation |
| 68 | + |
| 69 | +### Testing Locally |
| 70 | + |
| 71 | +Since this action downloads binaries, local testing should: |
| 72 | + |
| 73 | +1. Create a test SSH server (Docker or VM) |
| 74 | +2. Test `entrypoint.sh` directly with appropriate `INPUT_*` environment variables |
| 75 | + |
| 76 | +Example: |
| 77 | + |
| 78 | +```bash |
| 79 | +export INPUT_HOST="192.168.1.100" |
| 80 | +export INPUT_USERNAME="testuser" |
| 81 | +export INPUT_PASSWORD="testpass" |
| 82 | +export INPUT_PORT="22" |
| 83 | +export INPUT_SCRIPT="whoami" |
| 84 | +export GITHUB_ACTION_PATH="$(pwd)" |
| 85 | +./entrypoint.sh |
| 86 | +``` |
| 87 | + |
| 88 | +## Important Patterns |
| 89 | + |
| 90 | +### Script Execution |
| 91 | + |
| 92 | +Users can provide scripts in two ways: |
| 93 | + |
| 94 | +- `script`: Inline commands (via `INPUT_SCRIPT`) |
| 95 | +- `script_path`: Path to a file in the repository (via `INPUT_SCRIPT_FILE`) |
| 96 | + |
| 97 | +### Error Handling |
| 98 | + |
| 99 | +To stop execution on first error (mimics removed `script_stop` option), users should add `set -e` to their scripts: |
| 100 | + |
| 101 | +```yaml |
| 102 | +script: | |
| 103 | + #!/usr/bin/env bash |
| 104 | + set -e |
| 105 | + command1 |
| 106 | + command2 |
| 107 | +``` |
| 108 | +
|
| 109 | +### Environment Variables |
| 110 | +
|
| 111 | +The action passes GitHub Action inputs as environment variables with `INPUT_*` prefix. The drone-ssh binary reads these to configure SSH behavior. |
| 112 | + |
| 113 | +Special handling: |
| 114 | + |
| 115 | +- `envs`: Comma-separated list of environment variables to pass to remote script |
| 116 | +- `allenvs`: Pass all `GITHUB_*` and `INPUT_*` variables |
| 117 | +- `envs_format`: Custom format for environment variable export (e.g., `export TEST_{NAME}={VALUE}`) |
| 118 | + |
| 119 | +### Multiple Hosts |
| 120 | + |
| 121 | +- Comma-separated hosts: `"host1,host2"` (executes in parallel by default) |
| 122 | +- With custom ports: `"host1:2222,host2:5678"` |
| 123 | +- Synchronous execution: Set `sync: true` |
| 124 | + |
| 125 | +## Common Issues |
| 126 | + |
| 127 | +### Command Not Found |
| 128 | + |
| 129 | +Non-interactive shells may skip `.bashrc`/`.bash_profile`. See README section "Command not found" for details. Solutions: |
| 130 | + |
| 131 | +- Use absolute paths in commands |
| 132 | +- Comment out early return in `/etc/bash.bashrc` |
| 133 | + |
| 134 | +### OpenSSH Compatibility |
| 135 | + |
| 136 | +Ubuntu 20.04+ may require enabling `ssh-rsa` algorithm in sshd_config: |
| 137 | + |
| 138 | +```txt |
| 139 | +CASignatureAlgorithms +ssh-rsa |
| 140 | +``` |
| 141 | + |
| 142 | +Or use ED25519 keys instead (preferred). |
| 143 | + |
| 144 | +## Development Guidelines |
| 145 | + |
| 146 | +### Adding New Parameters |
| 147 | + |
| 148 | +1. Add input definition to `action.yml` with description |
| 149 | +2. Add corresponding `INPUT_*` environment variable mapping in `action.yml` runs.steps |
| 150 | +3. Update README.md parameter tables |
| 151 | +4. The drone-ssh binary handles the actual parameter logic (separate repo) |
| 152 | + |
| 153 | +### Documentation |
| 154 | + |
| 155 | +- Keep parameter tables in README.md synchronized with `action.yml` |
| 156 | +- Maintain Chinese translations (README.zh-cn.md, README.zh-tw.md) |
| 157 | +- Use clear examples for each feature |
| 158 | + |
| 159 | +### Version Management |
| 160 | + |
| 161 | +The action pins to specific drone-ssh versions via: |
| 162 | + |
| 163 | +- Default: `DRONE_SSH_VERSION="1.8.1"` in `entrypoint.sh` |
| 164 | +- Override: Users can specify `version` input parameter |
| 165 | + |
| 166 | +Update the default version when new drone-ssh releases are available. |
| 167 | + |
| 168 | +## Release Process |
| 169 | + |
| 170 | +This action uses semantic versioning with major version tags: |
| 171 | + |
| 172 | +- Tags: `v1.0.0`, `v1.0.1`, etc. |
| 173 | +- Major version tag: `v1` (points to latest v1.x.x) |
| 174 | +- Users reference: `uses: appleboy/ssh-action@v1` |
| 175 | + |
| 176 | +GoReleaser config (`.goreleaser.yaml`) is present but set to `skip: true` since this action doesn't build Go code - it downloads pre-built binaries. |
0 commit comments