Skip to content
Merged
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
39 changes: 39 additions & 0 deletions .github/actions/cli/build-test-archive/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: 'Build opentaint test archive'
description: 'Builds the opentaint CLI and packages it into the per-OS archive plus checksums.txt that the installers expect at the download URL'

inputs:
working-directory:
description: 'Directory containing the Go module to build'
required: false
default: 'cli'

runs:
using: 'composite'
steps:
- name: Build archive (linux)
if: runner.os == 'Linux'
shell: bash
working-directory: ${{ inputs.working-directory }}
run: |
go build -o opentaint .
tar -czf opentaint-full_linux_amd64.tar.gz opentaint
sha256sum opentaint-full_linux_amd64.tar.gz > checksums.txt

- name: Build archive (macos)
if: runner.os == 'macOS'
shell: bash
working-directory: ${{ inputs.working-directory }}
run: |
go build -o opentaint .
tar -czf opentaint-full_darwin_arm64.tar.gz opentaint
shasum -a 256 opentaint-full_darwin_arm64.tar.gz > checksums.txt

- name: Build archive (windows)
if: runner.os == 'Windows'
shell: pwsh
working-directory: ${{ inputs.working-directory }}
run: |
go build -o opentaint.exe .
Compress-Archive -Path opentaint.exe -DestinationPath opentaint-full_windows_amd64.zip
$hash = (Get-FileHash -Path opentaint-full_windows_amd64.zip -Algorithm SHA256).Hash.ToLower()
"$hash opentaint-full_windows_amd64.zip" | Out-File -FilePath checksums.txt -Encoding utf8NoBOM
43 changes: 43 additions & 0 deletions .github/actions/cli/serve-archive/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: 'Serve test archive over HTTP (unix only)'
description: |
Starts a Python http.server in a directory and waits until it is reachable.
Linux/macOS only: on Windows the GitHub Actions Job Object kills background
processes at step end, so the server would not survive into the next step.
Windows callers must inline the server start, readiness poll, and consumer
command in a single step.

inputs:
archive-dir:
description: 'Directory whose contents to serve'
required: true
port:
description: 'Port to listen on'
required: false
default: '8080'
timeout-seconds:
description: 'How long to wait for the server to become ready'
required: false
default: '30'

runs:
using: 'composite'
steps:
- name: Reject Windows runner
if: runner.os == 'Windows'
shell: pwsh
run: |
Write-Error 'cli/serve-archive does not support Windows runners. Inline the server start, readiness poll, and the consumer command in a single step.'
exit 1

- name: Start server
if: runner.os != 'Windows'
shell: bash
working-directory: ${{ inputs.archive-dir }}
env:
SERVE_PORT: ${{ inputs.port }}
SERVE_TIMEOUT: ${{ inputs.timeout-seconds }}
run: |
LOG="${RUNNER_TEMP}/http-server.log"
python3 -m http.server "$SERVE_PORT" > "$LOG" 2>&1 &
bash "${GITHUB_WORKSPACE}/scripts/ci/wait-for-http-server.sh" \
"http://127.0.0.1:${SERVE_PORT}/" "$SERVE_TIMEOUT" "$LOG"
30 changes: 30 additions & 0 deletions .github/actions/cli/verify-installed-binary/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: 'Verify installed opentaint binary'
description: 'Runs `<binary> --version`, falling back to the standard per-OS install location when no binary path is provided'

inputs:
binary-path:
description: 'Path to the opentaint binary (typically from an install step output). Falls back to the standard per-OS install location when empty.'
required: false
default: ''

runs:
using: 'composite'
steps:
- name: Verify (unix)
if: runner.os != 'Windows'
shell: bash
env:
BINARY_PATH: ${{ inputs.binary-path }}
run: |
if [ -z "$BINARY_PATH" ]; then BINARY_PATH="$HOME/.opentaint/install/opentaint"; fi
"$BINARY_PATH" --version

- name: Verify (windows)
if: runner.os == 'Windows'
shell: pwsh
env:
BINARY_PATH: ${{ inputs.binary-path }}
run: |
$binaryPath = $env:BINARY_PATH
if ([string]::IsNullOrEmpty($binaryPath)) { $binaryPath = "$env:LOCALAPPDATA\opentaint\install\opentaint.exe" }
& $binaryPath --version
115 changes: 61 additions & 54 deletions .github/workflows/ci-cli.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -323,26 +323,24 @@ jobs:
with:
go-version: ${{ env.GO_VERSION }}
cache-dependency-path: cli/go.sum
- uses: actions/setup-python@v5
with:
python-version: '3.x'
- name: Build test archive
working-directory: cli
run: |
go build -o opentaint .
tar -czf opentaint-full_linux_amd64.tar.gz opentaint
sha256sum opentaint-full_linux_amd64.tar.gz > checksums.txt
- name: Start file server
working-directory: cli
run: python3 -m http.server 8080 &
uses: ./.github/actions/cli/build-test-archive
- name: Serve test archive
uses: ./.github/actions/cli/serve-archive
with:
archive-dir: cli
- name: Run install.sh
id: install-linux
env:
OPENTAINT_DOWNLOAD_BASE_URL: http://localhost:8080
run: |
echo "OPENTAINT_BINARY_PATH=$(bash scripts/install/install.sh | grep ^OPENTAINT_BINARY_PATH= | cut -d= -f2)" >> $GITHUB_OUTPUT
OPENTAINT_DOWNLOAD_BASE_URL: http://127.0.0.1:8080
run: bash scripts/ci/run-installer-sh.sh scripts/install/install.sh
- name: Verify installation
run: |
BINARY_PATH="${{ steps.install-linux.outputs.OPENTAINT_BINARY_PATH }}"
if [ -z "$BINARY_PATH" ]; then BINARY_PATH="$HOME/.opentaint/install/opentaint"; fi
"$BINARY_PATH" --version
uses: ./.github/actions/cli/verify-installed-binary
with:
binary-path: ${{ steps.install-linux.outputs.OPENTAINT_BINARY_PATH }}

test-install-sh-macos:
runs-on: macos-latest
Expand All @@ -352,26 +350,24 @@ jobs:
with:
go-version: ${{ env.GO_VERSION }}
cache-dependency-path: cli/go.sum
- uses: actions/setup-python@v5
with:
python-version: '3.x'
- name: Build test archive
working-directory: cli
run: |
go build -o opentaint .
tar -czf opentaint-full_darwin_arm64.tar.gz opentaint
shasum -a 256 opentaint-full_darwin_arm64.tar.gz > checksums.txt
- name: Start file server
working-directory: cli
run: python3 -m http.server 8080 &
uses: ./.github/actions/cli/build-test-archive
- name: Serve test archive
uses: ./.github/actions/cli/serve-archive
with:
archive-dir: cli
- name: Run install.sh
id: install-macos
env:
OPENTAINT_DOWNLOAD_BASE_URL: http://localhost:8080
run: |
echo "OPENTAINT_BINARY_PATH=$(bash scripts/install/install.sh | grep ^OPENTAINT_BINARY_PATH= | cut -d= -f2)" >> $GITHUB_OUTPUT
OPENTAINT_DOWNLOAD_BASE_URL: http://127.0.0.1:8080
run: bash scripts/ci/run-installer-sh.sh scripts/install/install.sh
- name: Verify installation
run: |
BINARY_PATH="${{ steps.install-macos.outputs.OPENTAINT_BINARY_PATH }}"
if [ -z "$BINARY_PATH" ]; then BINARY_PATH="$HOME/.opentaint/install/opentaint"; fi
"$BINARY_PATH" --version
uses: ./.github/actions/cli/verify-installed-binary
with:
binary-path: ${{ steps.install-macos.outputs.OPENTAINT_BINARY_PATH }}

test-install-ps1:
runs-on: windows-latest
Expand All @@ -381,35 +377,46 @@ jobs:
with:
go-version: ${{ env.GO_VERSION }}
cache-dependency-path: cli/go.sum
- uses: actions/setup-python@v5
with:
python-version: '3.x'
- name: Build test archive
shell: pwsh
working-directory: cli
run: |
go build -o opentaint.exe .
Compress-Archive -Path opentaint.exe -DestinationPath opentaint-full_windows_amd64.zip
$hash = (Get-FileHash -Path opentaint-full_windows_amd64.zip -Algorithm SHA256).Hash.ToLower()
"$hash opentaint-full_windows_amd64.zip" | Out-File -FilePath checksums.txt -Encoding utf8NoBOM
- name: Run install.ps1
uses: ./.github/actions/cli/build-test-archive
# Server start, readiness poll and install must share a single step:
# on windows-latest the runner's Job Object kills background processes
# at step end, so the python server cannot live across steps.
- name: Serve archive and run install.ps1
id: install-windows
shell: pwsh
env:
OPENTAINT_DOWNLOAD_BASE_URL: http://127.0.0.1:8080
SERVE_PORT: '8080'
SERVE_TIMEOUT: '30'
run: |
Start-Process -NoNewWindow python -ArgumentList "-m", "http.server", "8080" -WorkingDirectory cli
Start-Sleep -Seconds 2
$output = pwsh -File scripts/install/install.ps1 2>&1 | Out-String
Write-Host $output
if ($LASTEXITCODE -ne 0) {
throw "install.ps1 exited with code $LASTEXITCODE"
}
if ($output -notmatch 'OPENTAINT_BINARY_PATH=(.+)') {
throw "install.ps1 did not emit OPENTAINT_BINARY_PATH"
$port = [int]$env:SERVE_PORT
$logOut = Join-Path $env:RUNNER_TEMP 'http-server.out.log'
$logErr = Join-Path $env:RUNNER_TEMP 'http-server.err.log'
$server = Start-Process -NoNewWindow -PassThru `
-FilePath python `
-ArgumentList '-m', 'http.server', "$port" `
-WorkingDirectory cli `
-RedirectStandardOutput $logOut `
-RedirectStandardError $logErr
try {
& "$env:GITHUB_WORKSPACE/scripts/ci/wait-for-http-server.ps1" `
-Url "http://127.0.0.1:$port/" `
-TimeoutSec ([int]$env:SERVE_TIMEOUT) `
-Process $server `
-StdoutLog $logOut `
-StderrLog $logErr
& "$env:GITHUB_WORKSPACE/scripts/ci/run-installer-pwsh.ps1" `
-Script scripts/install/install.ps1
} finally {
if ($server -and -not $server.HasExited) {
Stop-Process -Id $server.Id -Force -ErrorAction SilentlyContinue
}
}
$binaryPath = $Matches[1].Trim()
"OPENTAINT_BINARY_PATH=$binaryPath" | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding utf8
- name: Verify installation
shell: pwsh
run: |
$binaryPath = "${{ steps.install-windows.outputs.OPENTAINT_BINARY_PATH }}"
if ([string]::IsNullOrEmpty($binaryPath)) { $binaryPath = "$env:LOCALAPPDATA\opentaint\install\opentaint.exe" }
& $binaryPath --version
uses: ./.github/actions/cli/verify-installed-binary
with:
binary-path: ${{ steps.install-windows.outputs.OPENTAINT_BINARY_PATH }}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,4 @@ config.local.*

# Optional: Allow the .gitignore file itself to be tracked
!.gitignore
!.github
22 changes: 22 additions & 0 deletions scripts/ci/run-installer-pwsh.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Run an opentaint PowerShell install script and propagate its
# OPENTAINT_BINARY_PATH line to $env:GITHUB_OUTPUT so a verify step can
# consume it.
[CmdletBinding()]
param(
[Parameter(Mandatory)] [string]$Script
)

$ErrorActionPreference = 'Stop'

$output = pwsh -File $Script 2>&1 | Out-String
Write-Host $output

if ($LASTEXITCODE -ne 0) {
throw "$Script exited with code $LASTEXITCODE"
}
if ($output -notmatch 'OPENTAINT_BINARY_PATH=(.+)') {
throw "$Script did not emit OPENTAINT_BINARY_PATH"
}

$binaryPath = $Matches[1].Trim()
"OPENTAINT_BINARY_PATH=$binaryPath" | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding utf8
18 changes: 18 additions & 0 deletions scripts/ci/run-installer-sh.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/usr/bin/env bash
# Run an opentaint POSIX install script and propagate its OPENTAINT_BINARY_PATH
# line to $GITHUB_OUTPUT so a verify step can consume it.
# Usage: run-installer-sh.sh PATH_TO_INSTALL_SCRIPT
set -euo pipefail

SCRIPT="${1:?usage: $0 PATH_TO_INSTALL_SCRIPT}"

OUTPUT=$(bash "$SCRIPT")
echo "$OUTPUT"

BINARY_PATH=$(echo "$OUTPUT" | grep '^OPENTAINT_BINARY_PATH=' | cut -d= -f2-)
if [ -z "$BINARY_PATH" ]; then
echo "$SCRIPT did not emit OPENTAINT_BINARY_PATH" >&2
exit 1
fi

echo "OPENTAINT_BINARY_PATH=$BINARY_PATH" >> "$GITHUB_OUTPUT"
28 changes: 28 additions & 0 deletions scripts/ci/wait-for-http-server.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Poll an HTTP URL until it responds; fail and dump the server log on timeout.
# Returns to the caller on success; throws on timeout or early server exit.
[CmdletBinding()]
param(
[Parameter(Mandatory)] [string]$Url,
[int]$TimeoutSec = 30,
[System.Diagnostics.Process]$Process,
[string]$StdoutLog,
[string]$StderrLog
)

$ErrorActionPreference = 'Stop'

for ($i = 1; $i -le $TimeoutSec; $i++) {
if ($Process -and $Process.HasExited) { break }
try {
Invoke-WebRequest -Uri $Url -UseBasicParsing -TimeoutSec 2 -ErrorAction Stop | Out-Null
Write-Host "Server ready after ${i}s"
return
} catch {
Start-Sleep -Seconds 1
}
}

Write-Host "Server did not become ready at $Url within ${TimeoutSec}s."
if ($StdoutLog) { Write-Host '--- stdout ---'; Get-Content $StdoutLog -ErrorAction SilentlyContinue }
if ($StderrLog) { Write-Host '--- stderr ---'; Get-Content $StderrLog -ErrorAction SilentlyContinue }
throw "Local HTTP server did not become ready at $Url"
23 changes: 23 additions & 0 deletions scripts/ci/wait-for-http-server.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/usr/bin/env bash
# Poll an HTTP URL until it responds; fail and dump the server log on timeout.
# Usage: wait-for-http-server.sh URL [TIMEOUT_SECONDS] [LOG_PATH]
set -euo pipefail

URL="${1:?usage: $0 URL [TIMEOUT_SECONDS] [LOG_PATH]}"
TIMEOUT="${2:-30}"
LOG="${3:-}"

for i in $(seq 1 "$TIMEOUT"); do
if curl -fsS "$URL" -o /dev/null 2>/dev/null; then
echo "Server ready after ${i}s"
exit 0
fi
sleep 1
done

echo "Server did not become ready at ${URL} within ${TIMEOUT}s."
if [ -n "$LOG" ] && [ -f "$LOG" ]; then
echo '--- log ---'
cat "$LOG"
fi
exit 1
Loading