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
155 changes: 155 additions & 0 deletions .github/actions/agent-implant-smoke/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
name: "Agent Smoke Test"
description: >
Downloads the openaev-agent binary from JFrog, launches it with a fake
config pointing at localhost:1, and asserts it fails with a connection
error (proving the binary starts and reaches the network layer).
Comment on lines +2 to +5

inputs:
os:
description: "Target OS: linux, macos, windows"
required: true
jfrog-arch:
description: "JFrog architecture: x86_64, arm64"
required: true
jfrog-base:
description: "JFrog Artifactory base URL"
required: false
default: "https://filigran.jfrog.io/artifactory"
binary-version:
description: "Binary version to download (tag or 'latest')"
required: false
default: "latest"

runs:
using: composite
steps:
# ── Resolve extension ────────────────────────────────────────────
- name: Set binary extension
id: ext
shell: bash
run: |
if [[ "${{ inputs.os }}" == "windows" ]]; then
echo "ext=.exe" >> "$GITHUB_OUTPUT"
else
echo "ext=" >> "$GITHUB_OUTPUT"
fi

# ── Download binaries ────────────────────────────────────────────
- name: Download openaev-agent
shell: bash
run: |
URL="${{ inputs.jfrog-base }}/openaev-agent/${{ inputs.os }}/${{ inputs.jfrog-arch }}/openaev-agent-${{ inputs.binary-version }}${{ steps.ext.outputs.ext }}"
echo "⬇️ Downloading openaev-agent from $URL"
curl -fSL --retry 3 --retry-delay 5 -o "openaev-agent${{ steps.ext.outputs.ext }}" "$URL"
chmod +x "openaev-agent${{ steps.ext.outputs.ext }}" 2>/dev/null || true

# ── Write fake config ────────────────────────────────────────────
- name: Write smoke-test config
shell: bash
run: |
cat > openaev-agent-config.toml <<'EOF'
debug = false

[openaev]
url = "http://localhost:1"
token = "smoke-test-fake-token"
unsecured_certificate = false
with_proxy = false
installation_mode = "session-user"
service_name = "OAEVAgentService"
service_full_name = "OAEVAgentService"
tenant_id = "00000000-0000-0000-0000-000000000000"

[cleanup]
executing_max_time_minutes = 10
directory_max_time_minutes = 10
cleanup_interval_seconds = 180
EOF

# ── Unix smoke test ──────────────────────────────────────────────
- name: "Smoke test (Unix)"
if: inputs.os != 'windows'
shell: bash
run: |
set +e
PATTERN='connection refused|dial tcp|no such host|connect:|i/o timeout|unreachable|connection error|failed to connect|could not connect|error sending|request error'

smoke_test() {
local binary="$1"
local log_file="$2"

echo "🔥 Smoke-testing $binary ..."
./"$binary" --config openaev-agent-config.toml > "$log_file" 2>&1 &
local pid=$!

sleep 15
kill "$pid" 2>/dev/null || true
wait "$pid" 2>/dev/null || true

echo "--- $binary logs ---"
cat "$log_file"
echo "--------------------"

if grep -qiE "$PATTERN" "$log_file"; then
echo "✅ $binary: connection error detected (binary starts correctly)"
else
echo "❌ $binary: no connection error found in logs"
return 1
fi
Comment on lines +93 to +98
}

smoke_test "openaev-agent${{ steps.ext.outputs.ext }}" "agent.log"
echo "✅ Smoke test passed"

# ── Windows smoke test ───────────────────────────────────────────
- name: "Smoke test (Windows)"
if: inputs.os == 'windows'
shell: pwsh
run: |
$ErrorActionPreference = 'Stop'
$pattern = 'connection refused|dial tcp|no such host|connect:|i/o timeout|unreachable|connection error|failed to connect|could not connect|error sending|request error'
$failed = 0

function Invoke-SmokeTest {
param([string]$Binary, [string]$LogPrefix)

Write-Host "🔥 Smoke-testing $Binary ..."
$stdout = "$LogPrefix-stdout.log"
$stderr = "$LogPrefix-stderr.log"

$proc = Start-Process -FilePath ".\$Binary" `
-ArgumentList "--config", "openaev-agent-config.toml" `
-RedirectStandardOutput $stdout `
-RedirectStandardError $stderr `
-PassThru -NoNewWindow

$exited = $proc | Wait-Process -Timeout 15 -ErrorAction SilentlyContinue
if (!$proc.HasExited) {
Stop-Process -Id $proc.Id -Force -ErrorAction SilentlyContinue
Start-Sleep -Seconds 2
}

Write-Host "--- $Binary stdout ---"
if (Test-Path $stdout) { Get-Content $stdout }
Write-Host "--- $Binary stderr ---"
if (Test-Path $stderr) { Get-Content $stderr }
Write-Host "----------------------"

$allLogs = ""
if (Test-Path $stdout) { $allLogs += Get-Content $stdout -Raw }
if (Test-Path $stderr) { $allLogs += Get-Content $stderr -Raw }

if ($allLogs -match $pattern) {
Write-Host "✅ ${Binary}: connection error detected (binary starts correctly)"
return $true
} else {
Write-Host "❌ ${Binary}: no connection error found in logs"
return $false
}
Comment on lines +142 to +148
}

if (-not (Invoke-SmokeTest "openaev-agent.exe" "agent")) {
Write-Host "❌ Smoke test failed"
exit 1
}
Write-Host "✅ Smoke test passed"
49 changes: 49 additions & 0 deletions .github/workflows/agent-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,55 @@ jobs:
if-no-files-found: error
retention-days: 14

# ──────────────────────────────────────────────────────────────────
# Agent & Implant smoke tests (PR-level, latest runners only).
#
# Downloads released binaries from JFrog, starts them with a fake
# config pointing at localhost:1, and asserts they produce a
# connection error (proving startup + network-layer reach).
Comment on lines +403 to +407
# ──────────────────────────────────────────────────────────────────
agent-implant-smoke-tests:
name: "💨 Smoke (${{ matrix.os }}-${{ matrix.arch }})"
runs-on: ${{ matrix.runner }}
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
include:
- os: linux
arch: x86_64
runner: ubuntu-latest
jfrog-arch: x86_64
- os: linux
arch: arm64
runner: ubuntu-24.04-arm
jfrog-arch: arm64
- os: windows
arch: x86_64
runner: windows-latest
jfrog-arch: x86_64
- os: windows
arch: arm64
runner: windows-11-arm
jfrog-arch: arm64
- os: macos
arch: x86_64
runner: macos-15-intel
jfrog-arch: x86_64
- os: macos
arch: arm64
runner: macos-latest
jfrog-arch: arm64
steps:
- name: Checkout code
uses: actions/checkout@v6

- name: Run agent & implant smoke tests
uses: ./.github/actions/agent-implant-smoke
with:
os: ${{ matrix.os }}
jfrog-arch: ${{ matrix.jfrog-arch }}
Comment on lines +445 to +449

# ──────────────────────────────────────────────────────────────────
# OS-level installer / upgrade scripts (arch-independent).
# Uploaded once per OS so the downstream workflow does not need to
Expand Down
92 changes: 92 additions & 0 deletions .github/workflows/nightly-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
name: "[Agent] Nightly CI"

on:
schedule:
- cron: "0 3 * * *" # Every day at 3:00 AM UTC
workflow_dispatch: {} # Manual trigger for on-demand runs

concurrency:
group: agent-nightly-${{ github.ref }}
cancel-in-progress: true

permissions:
contents: read

jobs:
# ──────────────────────────────────────────────────────────────────
# Agent & Implant smoke tests — full OS/arch/version matrix.
#
# Downloads released binaries from JFrog, starts them with a fake
# config pointing at localhost:1, and asserts they produce a
# connection error (proving startup + network-layer reach).
#
# 13 runners covering all supported OS versions and architectures.
# ──────────────────────────────────────────────────────────────────
agent-implant-smoke-tests:
name: "💨 Smoke (${{ matrix.label }})"
runs-on: ${{ matrix.runner }}
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
include:
# ── Linux ────────────────────────────────────────────────
- label: ubuntu-22.04-x64
os: linux
runner: ubuntu-22.04
jfrog-arch: x86_64
- label: ubuntu-22.04-arm64
os: linux
runner: ubuntu-22.04-arm
jfrog-arch: arm64
- label: ubuntu-24.04-x64
os: linux
runner: ubuntu-24.04
jfrog-arch: x86_64
- label: ubuntu-24.04-arm64
os: linux
runner: ubuntu-24.04-arm
jfrog-arch: arm64
# ── Windows ──────────────────────────────────────────────
- label: windows-2022-x64
os: windows
runner: windows-2022
jfrog-arch: x86_64
- label: windows-2025-x64
os: windows
runner: windows-2025
jfrog-arch: x86_64
- label: windows-arm64
os: windows
runner: windows-11-arm
jfrog-arch: arm64
# ── macOS ────────────────────────────────────────────────
- label: macos-14-arm64
os: macos
runner: macos-14
jfrog-arch: arm64
- label: macos-15-arm64
os: macos
runner: macos-15
jfrog-arch: arm64
- label: macos-26-arm64
os: macos
runner: macos-26
jfrog-arch: arm64
- label: macos-15-intel
os: macos
runner: macos-15-intel
jfrog-arch: x86_64
- label: macos-26-intel
os: macos
runner: macos-26-intel
jfrog-arch: x86_64
steps:
- name: Checkout code
uses: actions/checkout@v6

- name: Run agent & implant smoke tests
uses: ./.github/actions/agent-implant-smoke
with:
os: ${{ matrix.os }}
jfrog-arch: ${{ matrix.jfrog-arch }}
Comment on lines +88 to +92
Loading