Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 111 additions & 0 deletions .github/workflows/manual_test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
name: Manual Test

on:
workflow_dispatch:
inputs:
password:
type: string
description: 'Password for the test SSH account (webssh_tester). Leave blank to auto-generate a random password.'
required: false
default: ''
duration:
type: string
description: 'How long to keep the test environment running, in minutes (max 60)'
required: false
default: '30'

jobs:
manual-test:
name: Manual Test Environment
runs-on: ubuntu-latest
permissions:
contents: read
timeout-minutes: 65

steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: 'true'
fetch-depth: 0

- name: Set up SSH server and test account
id: setup
shell: bash
env:
TEST_PASS_INPUT: ${{ inputs.password }}
run: |

Copilot AI Apr 3, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

apt-get install is run without an apt-get update, which can intermittently fail on GitHub-hosted runners when package indexes are stale. Adding an update step (or using apt-get update immediately before install) will make the workflow more reliable.

Suggested change
run: |
run: |
sudo apt-get update

Copilot uses AI. Check for mistakes.
sudo apt-get update
sudo apt-get install -y openssh-server
# Enable password authentication
sudo sed -i 's/^#*PasswordAuthentication.*/PasswordAuthentication yes/' /etc/ssh/sshd_config
sudo systemctl start ssh
# Use the provided password or auto-generate one
TEST_USER=webssh_tester
if [ -n "$TEST_PASS_INPUT" ]; then
TEST_PASS="$TEST_PASS_INPUT"
else
TEST_PASS=$(openssl rand -hex 10)
fi
sudo useradd -m -s /bin/bash "$TEST_USER"
echo "$TEST_USER:$TEST_PASS" | sudo chpasswd
echo "test_user=$TEST_USER" >> "$GITHUB_OUTPUT"
echo "test_pass=$TEST_PASS" >> "$GITHUB_OUTPUT"

- name: Configure and build
shell: bash
run: |
cmake -Bbuild -DCMAKE_BUILD_TYPE=Release
cmake --build build --target webssh_cpp -j4

- name: Start webssh_cpp
shell: bash
run: |
./build/src/webssh_cpp -p 8080 &
sleep 2
echo "webssh_cpp started on port 8080"

- name: Print test environment info
shell: bash
run: |
echo "============================================"
echo " WebSSH Manual Test Environment"
echo "============================================"
echo ""
echo " webssh_cpp is running on port 8080 of this runner."
echo " Connect to the tmate session shown below, then"
echo " forward port 8080 to your local machine:"
echo " ssh -L 8080:localhost:8080 <tmate-ssh-address>"
echo " Then open http://localhost:8080/ in your browser."
echo ""
echo " SSH credentials to enter in the web terminal:"
echo " Host : 127.0.0.1"
echo " Port : 22"
echo " Username : ${{ steps.setup.outputs.test_user }}"
echo " Password : ${{ steps.setup.outputs.test_pass }}"
echo ""
echo " Environment will stay up for ${{ inputs.duration }} minutes (max 60)."
echo " Cancel this workflow run to shut it down early."
echo "============================================"

- name: Set up tmate session
uses: mxschmitt/action-tmate@v3
with:
limit-access-to-actor: true
detached: true

- name: Wait for manual testing
shell: bash
run: |
DURATION_INPUT="${{ inputs.duration }}"
# Validate that the input is a positive integer; fall back to 30 if not.
if ! [[ "$DURATION_INPUT" =~ ^[0-9]+$ ]] || [ "$DURATION_INPUT" -le 0 ]; then
DURATION_INPUT=30
fi
# Cap at 60 minutes to avoid excessive runner usage.
if [ "$DURATION_INPUT" -gt 60 ]; then
DURATION_INPUT=60
fi
DURATION_SECONDS=$(( DURATION_INPUT * 60 ))
echo "Keeping environment alive for ${DURATION_INPUT} minute(s)..."
Comment on lines +97 to +110

Copilot AI Apr 3, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The duration input is only validated as a positive integer and has no upper bound, so a dispatch can keep a runner allocated up to the GitHub job timeout (hours), increasing cost/queue pressure. Add a reasonable maximum duration (and/or set timeout-minutes on the job) and clamp the input to that max.

Copilot uses AI. Check for mistakes.
sleep "$DURATION_SECONDS"
84 changes: 84 additions & 0 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
name: Test

on:
workflow_dispatch:

jobs:
test:
name: ${{ matrix.os }} - test
runs-on: ${{ matrix.os }}
permissions:
contents: read
timeout-minutes: 60
strategy:
matrix:
os: [ubuntu-22.04, ubuntu-latest, windows-latest]

steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: 'true'
fetch-depth: 0

- name: Set up SSH server for integration tests (Linux)
if: runner.os == 'Linux'
shell: bash
run: |

Copilot AI Apr 3, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

apt-get install is run without an apt-get update, which can intermittently fail on GitHub-hosted runners when package indexes are stale. Adding an update step (or using apt-get update immediately before install) will make the workflow more reliable.

Suggested change
run: |
run: |
sudo apt-get update

Copilot uses AI. Check for mistakes.
sudo apt-get update
sudo apt-get install -y openssh-server
# Enable password authentication
sudo sed -i 's/^#*PasswordAuthentication.*/PasswordAuthentication yes/' /etc/ssh/sshd_config
sudo systemctl start ssh
# Create a temporary test user with a random password
TEST_USER=webssh_testuser
TEST_PASS=$(openssl rand -hex 8)
sudo useradd -m -s /bin/bash "$TEST_USER"
echo "$TEST_USER:$TEST_PASS" | sudo chpasswd
# Export credentials for subsequent steps
echo "TEST_SSH_HOST=127.0.0.1" >> "$GITHUB_ENV"
echo "TEST_SSH_PORT=22" >> "$GITHUB_ENV"
echo "TEST_SSH_USER=$TEST_USER" >> "$GITHUB_ENV"
echo "TEST_SSH_PASS=$TEST_PASS" >> "$GITHUB_ENV"

- name: Set up SSH server for integration tests (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
# Install and start the built-in OpenSSH server
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
Start-Service sshd
# Create a temporary test user with a cryptographically random password
$TestUser = "webssh_testuser"
$bytes = [byte[]]::new(8)
[System.Security.Cryptography.RandomNumberGenerator]::Fill($bytes)
$TestPass = [System.Convert]::ToHexString($bytes).ToLower()
$SecPass = ConvertTo-SecureString $TestPass -AsPlainText -Force
New-LocalUser $TestUser -Password $SecPass -PasswordNeverExpires
# Export credentials for subsequent steps
"TEST_SSH_HOST=127.0.0.1" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
"TEST_SSH_PORT=22" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
"TEST_SSH_USER=$TestUser" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
"TEST_SSH_PASS=$TestPass" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append

- name: Set reusable strings
id: strings
shell: bash
run: |
unix_workspace_path=$(echo "${{ github.workspace }}" | sed 's/\\/\//g')
echo "build-output-dir=${unix_workspace_path}/build" >> "$GITHUB_OUTPUT"

- name: Configure
shell: bash
run: |
cmake -B${{ steps.strings.outputs.build-output-dir }} -DCMAKE_BUILD_TYPE=Debug

- name: Build tests
shell: bash
run: |
cmake --build ${{ steps.strings.outputs.build-output-dir }} --target webssh_cpp_tests -j4

- name: Run tests
shell: bash
run: |
ctest --test-dir ${{ steps.strings.outputs.build-output-dir }} --output-on-failure