Skip to content

feat(cli): add TTY validation for TUI mode #189

feat(cli): add TTY validation for TUI mode

feat(cli): add TTY validation for TUI mode #189

Workflow file for this run

name: CI
on:
push:
branches: [ main ]
paths:
- 'crates/**'
- 'fuzz/**'
- 'Cargo.toml'
- 'Cargo.lock'
- 'deny.toml'
- '.github/workflows/ci.yml'
pull_request:
branches: [ main ]
paths:
- 'crates/**'
- 'fuzz/**'
- 'Cargo.toml'
- 'Cargo.lock'
- 'deny.toml'
- '.github/workflows/ci.yml'
# Cancel outdated workflow runs
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
CARGO_TERM_COLOR: always
RUST_BACKTRACE: 1
CARGO_INCREMENTAL: 0
jobs:
# Job 1: Lockfile validation (fast fail-fast check)
lockfile-validation:
name: Validate Cargo.lock
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install Rust stable
uses: dtolnay/rust-toolchain@stable
- name: Install system dependencies
run: sudo apt-get update && sudo apt-get install -y libpcap-dev pkg-config
- name: Cache dependencies
uses: Swatinem/rust-cache@v2
with:
shared-key: "lockfile-validation"
- name: Validate Cargo.lock is synchronized
run: |
echo "Validating Cargo.lock synchronization..."
if ! cargo build --locked --quiet 2>&1; then
echo "❌ ERROR: Cargo.lock is out of sync with Cargo.toml"
echo ""
echo "This means Cargo.lock needs to be regenerated."
echo "Run the following commands to fix:"
echo " cargo update"
echo " git add Cargo.lock"
echo " git commit --amend"
echo ""
exit 1
fi
echo "✅ Cargo.lock is synchronized"
- name: Check for Cargo.toml changes without Cargo.lock update
run: |
echo "Checking if Cargo.toml was modified without Cargo.lock..."
# Get the list of changed files in this commit
CHANGED_FILES=$(git diff --name-only HEAD~1 HEAD 2>/dev/null || echo "")
# Count Cargo.toml and Cargo.lock changes
CARGO_TOML_CHANGES=$(echo "$CHANGED_FILES" | grep -c "Cargo.toml" || true)
CARGO_LOCK_CHANGES=$(echo "$CHANGED_FILES" | grep -c "Cargo.lock" || true)
echo "Files changed:"
echo "$CHANGED_FILES" | grep -E "(Cargo\.(toml|lock)|crates/)" || echo "(no Cargo files)"
echo ""
echo "Cargo.toml files modified: $CARGO_TOML_CHANGES"
echo "Cargo.lock modified: $CARGO_LOCK_CHANGES"
if [ "$CARGO_TOML_CHANGES" -gt 0 ] && [ "$CARGO_LOCK_CHANGES" -eq 0 ]; then
echo ""
echo "⚠️ WARNING: Cargo.toml modified but Cargo.lock was not updated"
echo "This might indicate the lockfile is out of sync."
echo "The previous step should have caught this if there's an actual issue."
else
echo "✅ Cargo.toml and Cargo.lock changes are consistent"
fi
# Job 2: Format check
format:
name: Format Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust stable
uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt
- name: Check formatting
run: cargo fmt --all -- --check
# Job 3: Clippy linting
clippy:
name: Clippy Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust stable
uses: dtolnay/rust-toolchain@stable
with:
components: clippy
- name: Cache dependencies
uses: Swatinem/rust-cache@v2
with:
shared-key: "clippy"
- name: Run clippy
run: cargo clippy --workspace --all-targets --locked -- -D warnings
# Job 4: Build and Test (Matrix for multiple platforms)
test:
name: Test (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
rust: [stable]
steps:
- uses: actions/checkout@v4
- name: Install Rust ${{ matrix.rust }}
uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ matrix.rust }}
- name: Install system dependencies (Linux)
if: matrix.os == 'ubuntu-latest'
run: sudo apt-get update && sudo apt-get install -y libpcap-dev pkg-config
- name: Install system dependencies (macOS)
if: matrix.os == 'macos-latest'
run: |
# Install libpcap (only if not already present)
brew list libpcap &>/dev/null || brew install libpcap
# pkg-config is provided by pkgconf which is pre-installed on GitHub Actions runners
brew list pkgconf &>/dev/null || brew install pkgconf
- name: Install Npcap SDK and Runtime DLLs (Windows)
if: matrix.os == 'windows-latest'
shell: pwsh
run: |
# Download and extract Npcap SDK (contains Packet.lib for development)
Write-Host "Downloading Npcap SDK..."
curl -L -o npcap-sdk.zip https://npcap.com/dist/npcap-sdk-1.13.zip
Expand-Archive -Path npcap-sdk.zip -DestinationPath npcap-sdk
Write-Host "✓ Npcap SDK extracted"
# Download Npcap installer and extract DLLs without running (avoids hang)
Write-Host "`nDownloading Npcap 1.79 installer..."
curl -L -o npcap-installer.exe https://npcap.com/dist/npcap-1.79.exe
# Extract installer using 7zip (pre-installed on GitHub Actions)
Write-Host "Extracting DLLs from Npcap installer (no execution)..."
7z x npcap-installer.exe -o"npcap-runtime" -y | Out-Null
# Create runtime directory and copy DLLs
New-Item -ItemType Directory -Force -Path "npcap-dlls" | Out-Null
# Find and copy ONLY x64 DLLs (to avoid 32-bit/64-bit architecture mismatch)
Get-ChildItem -Path "npcap-runtime" -Recurse -Filter "*.dll" | Where-Object {
($_.Name -eq "Packet.dll" -or $_.Name -eq "wpcap.dll") -and $_.DirectoryName -like "*x64*"
} | ForEach-Object {
Copy-Item $_.FullName -Destination "npcap-dlls\" -Force
Write-Host "Copied $($_.Name) from $($_.DirectoryName)"
}
# Verify we got the x64 DLLs
if (-not (Test-Path "npcap-dlls\Packet.dll") -or -not (Test-Path "npcap-dlls\wpcap.dll")) {
Write-Error "Failed to extract x64 DLLs from installer"
exit 1
}
# Add SDK lib directory to LIB environment variable for linking
echo "LIB=$PWD\npcap-sdk\Lib\x64;$env:LIB" >> $env:GITHUB_ENV
# Add DLL directory to PATH for runtime
echo "PATH=$PWD\npcap-dlls;$env:PATH" >> $env:GITHUB_ENV
# List what we extracted to verify
Write-Host "`nExtracted DLLs:"
Get-ChildItem "npcap-dlls" | Format-Table Name, Length -AutoSize
- name: Cache dependencies
uses: Swatinem/rust-cache@v2
with:
shared-key: "test-${{ matrix.os }}"
- name: Build
run: cargo build --workspace --locked --verbose
- name: Run tests
run: |
if [ "${{ matrix.os }}" = "windows-latest" ]; then
# Windows: Run only unit tests for crates that don't require Npcap
# Exclude: prtip-network (network layer), prtip-scanner (uses Npcap), prtip-cli integration tests
# Include: prtip-core (core types), prtip-cli unit tests (args parsing, formatting)
cargo test --workspace --locked --lib --exclude prtip-network --exclude prtip-scanner
else
# Linux/macOS: Run unit and integration tests, skip doctests to prevent linker resource exhaustion
# Doctests are redundant (all functionality covered by unit/integration tests)
# Fixes: linker bus error (signal 7) during doctest compilation in CI environment
cargo test --workspace --locked --lib --bins --tests
fi
shell: bash
env:
# Disable history file I/O during tests to prevent race conditions
# when multiple tests run in parallel (same fix as commit 0bf2a70)
PRTIP_DISABLE_HISTORY: "1"
# Note: Release builds removed to prevent "No space left on device" errors in CI.
# Release artifacts are built in the dedicated release.yml workflow.
# CI purpose is testing (debug builds sufficient for test validation).
- name: Install cargo-tarpaulin
if: matrix.os != 'windows-latest'
run: cargo install cargo-tarpaulin
- name: Generate test coverage with tarpaulin
if: matrix.os != 'windows-latest'
run: |
cargo tarpaulin --workspace --locked --lib --bins --tests \
--exclude prtip-network --exclude prtip-scanner \
--out Xml --output-dir ./coverage \
--timeout 300
env:
PRTIP_DISABLE_HISTORY: "1"
- name: Upload test coverage to Codecov
if: ${{ !cancelled() && matrix.os != 'windows-latest' }}
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./coverage/cobertura.xml
fail_ci_if_error: false
verbose: true
# Job 5: Security audit
security_audit:
name: Security Audit
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run cargo-deny
uses: EmbarkStudios/cargo-deny-action@v2
with:
log-level: warn
command: check advisories
arguments: --all-features
# Job 6: MSRV (Minimum Supported Rust Version) check
msrv:
name: MSRV Check (1.85)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust 1.85
uses: dtolnay/rust-toolchain@1.85
- name: Install system dependencies
run: sudo apt-get update && sudo apt-get install -y libpcap-dev pkg-config
- name: Cache dependencies
uses: Swatinem/rust-cache@v2
with:
shared-key: "msrv"
- name: Check build with MSRV
run: cargo build --workspace --locked --verbose