Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
c67d967
chore: bump version to 0.2.0
VeloraTech Oct 7, 2026
af49fd8
Finish NativeRelay integration in AgentTrace
VeloraTech Oct 28, 2026
050e004
Revert event type naming to match CI test expectations (native_relay.…
VeloraTech Oct 28, 2026
364ed1f
Release 0.3.0: NativeRelay integration complete with platform support…
VeloraTech Oct 28, 2026
3db992e
Fix test expectations to match code output (event types with dots, na…
VeloraTech Oct 28, 2026
9673d12
Update NativeRelay to 0.3.2 in README and CI
VeloraTech Oct 28, 2026
eb0535b
feat: NativeRelay integration improvements - version compatibility, d…
VeloraTech Nov 7, 2026
132ea8b
fix: compilation errors - duplicate missing_error, format string, lib…
VeloraTech Nov 7, 2026
f44016d
fix: update tests to use centralized MIN_NATIVERELAY_VERSION constant…
VeloraTech Nov 7, 2026
5c8077b
feat: add test failure tracker workflow - auto-create/update issues o…
VeloraTech Nov 7, 2026
e0cbf39
chore: remove temporary workflow generator script
VeloraTech Nov 7, 2026
a66ff7a
fix: adjust Linux test for GitHub Actions fanotify directory-only mode
VeloraTech Nov 7, 2026
78f1b6f
fix: use head to trigger file.opened event in Linux integration test
VeloraTech Nov 7, 2026
3830e8f
fix: update test failure tracker to listen for NativeRelay Linux inte…
VeloraTech Nov 7, 2026
7cd527c
feat: realistic NativeRelay CI testing - check root/caps, basic integ…
VeloraTech Nov 8, 2026
8ef279e
fix: add back std::fs import for read_dir usage in nativerelay.rs
VeloraTech Nov 8, 2026
64a1055
fix: Windows CI - add shell: pwsh, fix PowerShell variable syntax, ad…
VeloraTech Nov 8, 2026
adae406
fix: Windows CI - fix background process handling with Start-Process …
VeloraTech Nov 8, 2026
19c5ddd
fix: Windows CI - use procId instead of reserved PID variable
VeloraTech Nov 8, 2026
eea4dbf
fix: CI - fix Linux capability check debugging, add missing vars to b…
VeloraTech Nov 8, 2026
27f3e6e
fix: Windows debug (5s sleep, file check) + Linux capability check (e…
VeloraTech Nov 8, 2026
1c8a268
fix: Windows 10s sleep + debug, Linux 5s sleep + debug, test tracker …
VeloraTech Nov 8, 2026
8a61ae7
fix: flaky test retry logic + nativerelay integration improvements
VeloraTech Nov 9, 2026
da4c15f
fix: recreate nativerelay-integration.yml with correct PowerShell syntax
VeloraTech Nov 10, 2026
68157f5
Support NativeRelay beta version and Windows capability detection
VeloraTech Nov 10, 2026
f2339ad
Gracefully stop NativeRelay on Windows with CTRL_BREAK
VeloraTech Nov 10, 2026
9cbdb11
Use platform-neutral NativeRelay session metadata
VeloraTech Nov 10, 2026
5c83928
Install pinned NativeRelay beta and test supported Windows events
VeloraTech Nov 10, 2026
836c1f4
Align platform support test with Windows collector availability
VeloraTech Nov 10, 2026
09de7d1
Keep Windows file activity inside the monitored workspace
VeloraTech Nov 10, 2026
86631a3
Correct Windows support and NativeRelay installation guidance
VeloraTech Nov 10, 2026
f8668a6
Update missing NativeRelay installation guidance test
VeloraTech Nov 10, 2026
73d84c6
Allow Windows discovery tests with installed NativeRelay
VeloraTech Nov 10, 2026
f09fb70
test: account for installed NativeRelay on Windows
VeloraTech Nov 11, 2026
cef3ab7
ci: avoid PowerShell PID automatic variable collision
VeloraTech Nov 11, 2026
31b04ae
ci: match generated integration activity filename
VeloraTech Nov 11, 2026
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: 93 additions & 18 deletions .github/workflows/nativerelay-integration.yml
Original file line number Diff line number Diff line change
@@ -1,33 +1,108 @@
name: NativeRelay Linux integration
name: NativeRelay Integration

on:
pull_request:
push:
branches: ['**']
branches: [main, "feature/nativerelay-pypi-integration"]
pull_request:
branches: [main]
workflow_dispatch:

permissions:
contents: read

jobs:
nativerelay-linux:
name: NativeRelay 0.2.0 Linux end-to-end
runs-on: ubuntu-latest
timeout-minutes: 20
test-windows:
name: Windows NativeRelay Test
runs-on: windows-2025
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: actions/setup-node@v4
with:
node-version: 24

- uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install NativeRelay 0.2.0
run: python -m pip install nativerelay==0.2.0
- name: Run existing test suite
run: npm test
python-version: "3.12"

- name: Install pinned NativeRelay beta wheel
shell: pwsh
run: |
$wheel = "nativerelay-0.4.0b1-py3-none-any.whl"
$url = "https://github.com/VeloraTech/NativeRelay/releases/download/v0.4.0b1/$wheel"
$destination = Join-Path $env:RUNNER_TEMP $wheel
Invoke-WebRequest -Uri $url -OutFile $destination
$expected = "62e9db9469e1e8eb32f3aaea7c5dd1d4d98065152b95d3f78ad3e4d62b40672c"
$actual = (Get-FileHash -Algorithm SHA256 $destination).Hash.ToLowerInvariant()
if ($actual -ne $expected) { throw "NativeRelay wheel SHA256 mismatch: $actual" }
python -m pip install --disable-pip-version-check --no-deps $destination
$scripts = python -c "import sysconfig; print(sysconfig.get_path('scripts'))"
Add-Content $env:GITHUB_PATH $scripts
$installed = python -c "from importlib.metadata import version; print(version('nativerelay'))"
if ($installed -ne "0.4.0b1") { throw "Unexpected NativeRelay version: $installed" }
if (-not (Test-Path (Join-Path $scripts "nativerelay.exe"))) { throw "nativerelay.exe missing from Python Scripts directory" }

- uses: dtolnay/rust-toolchain@stable
with:
targets: x86_64-pc-windows-msvc

- name: Run Rust tests
run: cargo test --locked

- name: Build AgentTrace
run: cargo build --locked
- name: Verify real Linux NativeRelay observations, recording, and shutdown
run: bash scripts/test-nativerelay-linux.sh

- name: Run NativeRelay live integration test
shell: pwsh
run: |
$agenttrace = Join-Path $env:GITHUB_WORKSPACE "target\debug\agenttrace.exe"
$testDir = Join-Path $env:RUNNER_TEMP ("agenttrace-native-" + [guid]::NewGuid().ToString("N"))
New-Item -ItemType Directory -Path $testDir | Out-Null
$history = Join-Path $testDir "history.jsonl"
$stdout = Join-Path $testDir "agenttrace.stdout"
$stderr = Join-Path $testDir "agenttrace.stderr"
$activity = Join-Path $env:GITHUB_WORKSPACE ".nativerelay-integration-activity-$PID.txt"
$p = Start-Process -FilePath $agenttrace -ArgumentList @("run", "--native-relay", "--json", "--output", $history) -RedirectStandardOutput $stdout -RedirectStandardError $stderr -PassThru
try {
$ready = $false
for ($i = 0; $i -lt 100; $i++) {
if ($p.HasExited) { throw "AgentTrace exited before NativeRelay started. $((Get-Content $stderr -Raw -ErrorAction SilentlyContinue))" }
if (Test-Path $history) {
$records = @(Get-Content $history | ForEach-Object { try { $_ | ConvertFrom-Json } catch {} })
$status = $records | Where-Object { $_.event_type -eq "native_relay.status" -and $_.data.native_record.state -in @("running", "degraded") } | Select-Object -First 1
if ($status) { $ready = $true; break }
}
Start-Sleep -Milliseconds 200
}
if (-not $ready) { throw "NativeRelay did not report running/degraded status. $((Get-Content $stderr -Raw -ErrorAction SilentlyContinue))" }

Set-Content -Path $activity -Value "created"
Start-Sleep -Milliseconds 350
Set-Content -Path $activity -Value "modified"

# Toolhelp fallback polls every 200ms; keep this child alive long enough to observe.
$probe = Start-Process -FilePath "$env:WINDIR\System32\ping.exe" -ArgumentList @("127.0.0.1", "-n", "5") -PassThru
$targetProcessId = $probe.Id
$probe.WaitForExit()

$verified = $false
for ($i = 0; $i -lt 100; $i++) {
if (Test-Path $history) {
$records = @(Get-Content $history | ForEach-Object { try { $_ | ConvertFrom-Json } catch {} })
$observations = @($records | Where-Object { $_.event_type -eq "native_relay.observation" } | ForEach-Object { $_.data.native_record })
$created = $observations | Where-Object { $_.type -eq "file.created" -and $_.resource.path -like "*nativerelay-integration-activity-*" }
$modified = $observations | Where-Object { $_.type -eq "file.modified" -and $_.resource.path -like "*nativerelay-integration-activity-*" }
$started = $observations | Where-Object { $_.type -eq "process.started" -and $_.process.pid -eq $targetProcessId }
$exited = $observations | Where-Object { $_.type -eq "process.exited" -and $_.process.pid -eq $targetProcessId }
if ($created -and $modified -and $started -and $exited) { $verified = $true; break }
}
Start-Sleep -Milliseconds 200
}
if (-not $verified) {
Get-Content $stdout, $stderr, $history -ErrorAction SilentlyContinue | Write-Host
throw "Expected file.created/file.modified and process.started/process.exited observations were not all received."
}
Write-Host "Verified NativeRelay Windows file and process observations (PID $targetProcessId)."
}
finally {
if (-not $p.HasExited) { Stop-Process -Id $p.Id -Force -ErrorAction SilentlyContinue }
Remove-Item $activity -Force -ErrorAction SilentlyContinue
Remove-Item $testDir -Recurse -Force -ErrorAction SilentlyContinue
}
184 changes: 184 additions & 0 deletions .github/workflows/test-failure-tracker.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
name: Track Test Failures

on:
workflow_run:
workflows: ["NativeRelay Integration", "Release"]
types: [completed]

permissions:
contents: read
issues: write

jobs:
track-failures:
name: Track Test Failures
if: ${{ github.event.workflow_run.conclusion == 'failure' }}
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Download test logs
uses: actions/github-script@v7
id: download-logs
with:
script: |
const runId = ${{ github.event.workflow_run.id }};
const logs = await github.rest.actions.downloadWorkflowRunLogs({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: runId,
});
return logs.data;

- name: Extract failed tests
id: extract-tests
run: |
echo "${{ steps.download-logs.outputs.result }}" | base64 -d > logs.zip
unzip -o logs.zip -d logs/
FAILED_TESTS=()
for log_file in $(find logs -name "*.log" -o -name "*.txt" 2>/dev/null); do
while IFS= read -r line; do
if [[ "$line" =~ ^test\ (.+)\ \.\.\.\ FAILED$ ]]; then
FAILED_TESTS+=("${BASH_REMATCH[1]}")
fi
if [[ "$line" =~ ^\ \ \ \ test\ (.+)$ ]] && [[ "$prev_line" =~ ^failures:$ ]]; then
FAILED_TESTS+=("${BASH_REMATCH[1]}")
fi
prev_line="$line"
done < "$log_file"
done
printf '%s\n' "${FAILED_TESTS[@]}" | sort -u > failed_tests.txt
if [[ -s failed_tests.txt ]]; then
echo "failed=true" >> $GITHUB_OUTPUT
echo "tests<<EOF" >> $GITHUB_OUTPUT
cat failed_tests.txt >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
else
echo "failed=false" >> $GITHUB_OUTPUT
fi

- name: Create/Update failure issues
if: ${{ steps.extract-tests.outputs.failed == 'true' }}
uses: actions/github-script@v7
env:
FAILED_TESTS: ${{ steps.extract-tests.outputs.tests }}
RUN_URL: ${{ github.event.workflow_run.html_url }}
RUN_ID: ${{ github.event.workflow_run.id }}
COMMIT_SHA: ${{ github.event.workflow_run.head_sha }}
WORKFLOW_NAME: ${{ github.event.workflow_run.name }}
script: |
const failedTests = process.env.FAILED_TESTS.trim().split('
').filter(t => t);
const runUrl = process.env.RUN_URL;
const runId = process.env.RUN_ID;
const commitSha = process.env.COMMIT_SHA;
const workflowName = process.env.WORKFLOW_NAME;
for (const testName of failedTests) {
const issueTitle = `[Test Failure] ${testName}`;
const existingIssues = await github.rest.issues.listForRepo({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
labels: 'test-failure',
per_page: 100
});
const existingIssue = existingIssues.data.find(issue => issue.title === issueTitle);
const body = `## Test Failure: \`${testName}\`

**Workflow:** ${workflowName}
**Run:** [#${runId}](${runUrl})
**Commit:** \`${commitSha.substring(0, 7)}\`
**Time:** ${new Date().toISOString()}

---

### Failure Details
\`\`\`
Test \`${testName}\` failed in workflow run [#${runId}](${runUrl}).

View full logs: ${runUrl}
\`\`\`

---

*This issue is automatically tracked. It will be closed when the test passes again.*`;
if (existingIssue) {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: existingIssue.number,
body: `### New Failure: ${new Date().toISOString()}

**Workflow:** ${workflowName}
**Run:** [#${runId}](${runUrl})
**Commit:** \`${commitSha.substring(0, 7)}\`

View logs: ${runUrl}

---`
});
console.log(`Updated existing issue #${existingIssue.number} for ${testName}`);
} else {
const newIssue = await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: issueTitle,
body: body,
labels: ['test-failure', 'auto-tracked']
});
console.log(`Created new issue #${newIssue.number} for ${testName}`);
}
}

auto-close-resolved:
name: Auto-Close Resolved Issues
if: ${{ github.event.workflow_run.conclusion == 'success' }}
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Close resolved test failure issues
uses: actions/github-script@v7
env:
RUN_URL: ${{ github.event.workflow_run.html_url }}
RUN_ID: ${{ github.event.workflow_run.id }}
COMMIT_SHA: ${{ github.event.workflow_run.head_sha }}
WORKFLOW_NAME: ${{ github.event.workflow_run.name }}
script: |
const runUrl = process.env.RUN_URL;
const runId = process.env.RUN_ID;
const commitSha = process.env.COMMIT_SHA;
const workflowName = process.env.WORKFLOW_NAME;
const issues = await github.paginate(github.rest.issues.listForRepo, {
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
labels: 'test-failure',
per_page: 100
});
for (const issue of issues) {
const match = issue.title.match(/^\[Test Failure\]\s+(.+)$/);
if (!match) continue;
const testName = match[1];
await github.rest.issues.update({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
state: 'closed',
state_reason: 'completed'
});
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
body: `[SUCCESS] **Test Resolved**

This test (\`${testName}\`) is now passing again.

**Resolved in workflow run:** [#${runId}](${runUrl})
**Commit:** \`${commitSha.substring(0, 7)}\`
**Workflow:** ${workflowName}
**Time:** ${new Date().toISOString()}

---`
});
console.log(`Closed issue #${issue.number} for ${testName}`);
}
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "agenttrace-cli"
version = "0.1.9"
version = "0.3.0"
edition = "2024"
description = "Local process discovery for AI coding agents"
license = "MIT"
Expand Down
Loading
Loading