fix(linux-scripts): fix linux scripts when systemd is degraded + imp… (#5871) #123
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: "[Agent] CI" | |
| on: | |
| push: | |
| branches: [main] | |
| tags: | |
| - "[0-9]+.[0-9]+.[0-9]+" | |
| pull_request: | |
| branches: [main] | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| permissions: | |
| contents: read | |
| jobs: | |
| # ────────────────────────────────────────────────────────────────── | |
| # Quality gates (fmt + audit). | |
| # | |
| # Single-platform fast checks. Clippy lives in its own job because | |
| # it needs to run per (os, arch) target to catch cfg-gated code. | |
| # ────────────────────────────────────────────────────────────────── | |
| quality: | |
| name: "🔍 Quality gates (fmt + audit)" | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 20 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v7 | |
| - name: Set up Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| components: rustfmt | |
| - name: Cache | |
| uses: actions/cache@v5 | |
| with: | |
| path: | | |
| ~/.cargo/bin/ | |
| ~/.cargo/registry/index/ | |
| ~/.cargo/registry/cache/ | |
| ~/.cargo/git/db/ | |
| key: cargo-quality-${{ runner.os }}-${{ hashFiles('Cargo.lock') }} | |
| - name: Run cargo fmt | |
| run: cargo fmt -- --check | |
| - name: Install cargo audit | |
| run: | | |
| if [ -x "$HOME/.cargo/bin/cargo-audit" ]; then | |
| echo "cargo-audit already installed." | |
| else | |
| cargo install cargo-audit --locked | |
| fi | |
| - name: Run cargo audit | |
| run: cargo audit | |
| # ────────────────────────────────────────────────────────────────── | |
| # Clippy lint per-OS + PSScriptAnalyzer on Windows. | |
| # Per-OS (not per-arch) is required because the agent has | |
| # cfg(target_os=...) code paths the lint must validate on each | |
| # platform. The cfg gates are arch-independent so one target per | |
| # OS is sufficient. | |
| # ────────────────────────────────────────────────────────────────── | |
| clippy: | |
| name: "🧹 Clippy (${{ matrix.os }})" | |
| runs-on: ${{ matrix.runner }} | |
| timeout-minutes: 20 | |
| env: | |
| IS_MUSL_UBUNTU: ${{ matrix.os == 'ubuntu' }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - os: ubuntu | |
| runner: ubuntu-latest | |
| target: x86_64-unknown-linux-musl | |
| - os: windows | |
| runner: windows-latest | |
| target: x86_64-pc-windows-msvc | |
| - os: macos | |
| runner: macos-latest | |
| target: aarch64-apple-darwin | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v7 | |
| - name: Install musl-tools | |
| if: env.IS_MUSL_UBUNTU == 'true' | |
| run: sudo apt-get update && sudo apt-get install -y musl-tools | |
| - name: Set up Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: ${{ matrix.target }} | |
| components: clippy | |
| - name: Cache | |
| uses: actions/cache@v5 | |
| with: | |
| path: | | |
| ~/.cargo/bin/ | |
| ~/.cargo/registry/index/ | |
| ~/.cargo/registry/cache/ | |
| ~/.cargo/git/db/ | |
| target/ | |
| key: cargo-clippy-${{ runner.os }}-${{ hashFiles('Cargo.lock') }} | |
| - name: Run cargo clippy | |
| run: cargo clippy --target=${{ matrix.target }} -- -D warnings | |
| - name: Lint PowerShell installer scripts (PSScriptAnalyzer) | |
| if: matrix.os == 'windows' | |
| shell: pwsh | |
| run: ./installer/windows/Run-Lint.ps1 | |
| # ────────────────────────────────────────────────────────────────── | |
| # Run the test suite on every (os, arch) target. This is the | |
| # cross-platform correctness gate; `coverage` measures line coverage | |
| # on Linux only. | |
| # ────────────────────────────────────────────────────────────────── | |
| tests: | |
| name: "🧪 Tests (${{ matrix.os }}-${{ matrix.arch }})" | |
| runs-on: ${{ matrix.runner }} | |
| timeout-minutes: 20 | |
| env: | |
| IS_MUSL_UBUNTU: ${{ (matrix.os == 'ubuntu' && contains(matrix.target, 'musl')) }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - os: ubuntu | |
| arch: x86_64 | |
| runner: ubuntu-latest | |
| target: x86_64-unknown-linux-musl | |
| - os: ubuntu | |
| arch: arm64 | |
| runner: ubuntu-24.04-arm | |
| target: aarch64-unknown-linux-musl | |
| - os: windows | |
| arch: x86_64 | |
| runner: windows-latest | |
| target: x86_64-pc-windows-msvc | |
| - os: windows | |
| arch: arm64 | |
| runner: windows-11-arm | |
| target: aarch64-pc-windows-msvc | |
| - os: macos | |
| arch: x86_64 | |
| runner: macos-15-intel | |
| target: x86_64-apple-darwin | |
| - os: macos | |
| arch: arm64 | |
| runner: macos-latest | |
| target: aarch64-apple-darwin | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v7 | |
| - name: Install musl-tools | |
| if: env.IS_MUSL_UBUNTU == 'true' | |
| run: sudo apt-get update && sudo apt-get install -y musl-tools | |
| - name: Set up Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: ${{ matrix.target }} | |
| - name: Cache | |
| uses: actions/cache@v5 | |
| with: | |
| path: | | |
| ~/.cargo/bin/ | |
| ~/.cargo/registry/index/ | |
| ~/.cargo/registry/cache/ | |
| ~/.cargo/git/db/ | |
| target/ | |
| key: cargo-tests-${{ runner.os }}-${{ matrix.arch }}-${{ hashFiles('Cargo.lock') }} | |
| - name: Run cargo test | |
| run: cargo test --target=${{ matrix.target }} --locked | |
| # ────────────────────────────────────────────────────────────────── | |
| # Code coverage (Linux/x86_64 only). cargo-llvm-cov re-runs the | |
| # test suite with LLVM source-based instrumentation to produce | |
| # lcov.info, which is uploaded to Codecov. The `tests` job above | |
| # is the cross-platform correctness gate; this job's role is | |
| # coverage measurement. | |
| # ────────────────────────────────────────────────────────────────── | |
| coverage: | |
| name: "📊 Coverage" | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 30 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v7 | |
| - name: Set up Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| components: llvm-tools-preview | |
| - name: Cache | |
| uses: actions/cache@v5 | |
| with: | |
| path: | | |
| ~/.cargo/bin/ | |
| ~/.cargo/registry/index/ | |
| ~/.cargo/registry/cache/ | |
| ~/.cargo/git/db/ | |
| target/ | |
| key: cargo-coverage-${{ runner.os }}-${{ hashFiles('Cargo.lock') }} | |
| - name: Install cargo-llvm-cov | |
| uses: taiki-e/install-action@v2 | |
| with: | |
| tool: cargo-llvm-cov | |
| - name: Generate coverage (lcov) | |
| run: | | |
| cargo llvm-cov --workspace --all-features --locked \ | |
| --lcov --output-path lcov.info | |
| - name: Upload coverage to Codecov | |
| uses: codecov/codecov-action@v7 | |
| with: | |
| token: ${{ secrets.CODECOV_TOKEN }} | |
| files: lcov.info | |
| flags: agent | |
| disable_search: true | |
| fail_ci_if_error: false | |
| # ────────────────────────────────────────────────────────────────── | |
| # Build + test the agent for every (os, arch) target, then stage | |
| # artifacts for downstream promotion. | |
| # ────────────────────────────────────────────────────────────────── | |
| build: | |
| name: "🔨 Build (${{ matrix.os }}-${{ matrix.arch }})" | |
| runs-on: ${{ matrix.runner }} | |
| timeout-minutes: 60 | |
| env: | |
| IS_MUSL_UBUNTU: ${{ (matrix.os == 'ubuntu' && contains(matrix.target, 'musl')) }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - os: ubuntu | |
| arch: x86_64 | |
| runner: ubuntu-latest | |
| target: x86_64-unknown-linux-musl | |
| jfrog_path: linux/x86_64 | |
| - os: ubuntu | |
| arch: arm64 | |
| runner: ubuntu-24.04-arm | |
| target: aarch64-unknown-linux-musl | |
| jfrog_path: linux/arm64 | |
| - os: windows | |
| arch: x86_64 | |
| runner: windows-latest | |
| target: x86_64-pc-windows-msvc | |
| jfrog_path: windows/x86_64 | |
| - os: windows | |
| arch: arm64 | |
| runner: windows-11-arm | |
| target: aarch64-pc-windows-msvc | |
| jfrog_path: windows/arm64 | |
| - os: macos | |
| arch: x86_64 | |
| runner: macos-15-intel | |
| target: x86_64-apple-darwin | |
| jfrog_path: macos/x86_64 | |
| - os: macos | |
| arch: arm64 | |
| runner: macos-latest | |
| target: aarch64-apple-darwin | |
| jfrog_path: macos/arm64 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v7 | |
| - name: Install musl-tools | |
| if: env.IS_MUSL_UBUNTU == 'true' | |
| run: sudo apt-get update && sudo apt-get install -y musl-tools | |
| - name: Install NSIS (Windows) | |
| if: matrix.os == 'windows' | |
| run: choco install -y nsis | |
| shell: pwsh | |
| - name: Set up Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: ${{ matrix.target }} | |
| - name: Cache | |
| uses: actions/cache@v5 | |
| with: | |
| path: | | |
| ~/.cargo/bin/ | |
| ~/.cargo/registry/index/ | |
| ~/.cargo/registry/cache/ | |
| ~/.cargo/git/db/ | |
| target/ | |
| key: cargo-build-${{ runner.os }}-${{ matrix.arch }}-${{ hashFiles('Cargo.lock') }} | |
| - name: Build (release) | |
| run: | | |
| # Static CRT linkage for Windows is configured in .cargo/config.toml | |
| # (target-feature=+crt-static) so VCRUNTIME140.dll is not required at | |
| # runtime. | |
| # | |
| # IMPORTANT: We must NOT set RUSTFLAGS here because it would *override* | |
| # (not combine with) the target-specific rustflags in .cargo/config.toml, | |
| # effectively dropping +crt-static. This was the root cause of the | |
| # VCRUNTIME140.dll missing error on Windows ARM64. | |
| cargo build --target=${{ matrix.target }} --release --locked | |
| shell: bash | |
| - name: Verify no dynamic CRT dependency (Windows) | |
| if: matrix.os == 'windows' | |
| shell: bash | |
| run: | | |
| BIN="./target/${{ matrix.target }}/release/openaev-agent.exe" | |
| echo "Checking $BIN for VCRUNTIME imports…" | |
| # rustup includes llvm-objdump; use it instead of dumpbin which | |
| # may not be on PATH (especially on windows-11-arm runners). | |
| if rustup run stable llvm-objdump --private-headers "$BIN" \ | |
| | grep -qi "vcruntime"; then | |
| echo "::error::Binary still dynamically links to VCRUNTIME:" | |
| rustup run stable llvm-objdump --private-headers "$BIN" | grep -i "vcruntime" | |
| exit 1 | |
| fi | |
| echo "✅ No VCRUNTIME dependency found — static CRT linkage confirmed." | |
| - name: Build agent installers with NSIS (Windows) | |
| if: matrix.os == 'windows' | |
| shell: pwsh | |
| run: | | |
| # The .nsi files reference ..\..\target\release\openaev-agent.exe (the | |
| # default unflavored release dir). Because we build with --target=..., | |
| # the binary actually lives in target/<triple>/release/. Copy it to the | |
| # legacy path so makensis can find it. | |
| New-Item -ItemType Directory -Force -Path "./target/release" | Out-Null | |
| Copy-Item -Force ` | |
| "./target/${{ matrix.target }}/release/openaev-agent.exe" ` | |
| "./target/release/openaev-agent.exe" | |
| $installers = @( | |
| "agent-installer.nsi", | |
| "agent-installer-service-user.nsi", | |
| "agent-installer-session-user.nsi" | |
| ) | |
| foreach ($nsi in $installers) { | |
| & "C:\Program Files (x86)\NSIS\Bin\makensis.exe" "./installer/windows/$nsi" | |
| if ($LASTEXITCODE -ne 0) { | |
| Write-Host "makensis failed for $nsi with exit code $LASTEXITCODE" | |
| exit 1 | |
| } | |
| } | |
| - name: Install cargo cache | |
| run: | | |
| if command -v cargo-cache &>/dev/null; then | |
| echo "cargo-cache already installed." | |
| else | |
| cargo install cargo-cache --locked | |
| fi | |
| shell: bash | |
| - name: Run cargo cache | |
| run: cargo cache -a -l || true | |
| shell: bash | |
| # ────────────────────────────────────────────────────────────── | |
| # Stage artifacts for downstream promotion. | |
| # | |
| # Each matrix job uploads a flat directory layout matching the | |
| # JFrog destination paths so the downstream workflow only needs | |
| # to append the version suffix and PUT each file. | |
| # | |
| # Layout for the per-target artifact (agent-bin-<os>-<arch>): | |
| # <jfrog_path>/openaev-agent[.exe] binary | |
| # <jfrog_path>/openaev-agent-installer.exe (Windows only) | |
| # <jfrog_path>/openaev-agent-installer-service-user.exe | |
| # <jfrog_path>/openaev-agent-installer-session-user.exe | |
| # ────────────────────────────────────────────────────────────── | |
| - name: Stage binary + Windows installers for upload | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| STAGE="staging/${{ matrix.jfrog_path }}" | |
| mkdir -p "$STAGE" | |
| if [[ "${{ matrix.os }}" == "windows" ]]; then | |
| cp "./target/${{ matrix.target }}/release/openaev-agent.exe" \ | |
| "$STAGE/openaev-agent.exe" | |
| for installer in agent-installer.exe \ | |
| agent-installer-service-user.exe \ | |
| agent-installer-session-user.exe; do | |
| cp "./installer/windows/$installer" "$STAGE/openaev-$installer" | |
| done | |
| else | |
| cp "./target/${{ matrix.target }}/release/openaev-agent" \ | |
| "$STAGE/openaev-agent" | |
| fi | |
| ls -la "$STAGE" | |
| - name: Upload binary artifact | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: agent-bin-${{ matrix.os }}-${{ matrix.arch }} | |
| path: staging/ | |
| if-no-files-found: error | |
| retention-days: 14 | |
| # ────────────────────────────────────────────────────────────────── | |
| # OS-level installer / upgrade scripts (arch-independent). | |
| # Uploaded once per OS so the downstream workflow does not need to | |
| # deduplicate matrix outputs. | |
| # ────────────────────────────────────────────────────────────────── | |
| package-scripts: | |
| name: "📦 Package installer scripts" | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v7 | |
| - name: Stage scripts | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| mkdir -p staging/linux staging/macos staging/windows | |
| # Linux / macOS shell scripts | |
| for os in linux macos; do | |
| for script in \ | |
| agent-installer.sh \ | |
| agent-upgrade.sh \ | |
| agent-installer-session-user.sh \ | |
| agent-upgrade-session-user.sh \ | |
| agent-installer-service-user.sh \ | |
| agent-upgrade-service-user.sh; do | |
| cp "./installer/${os}/${script}" \ | |
| "staging/${os}/openaev-${script%.sh}.sh" | |
| done | |
| done | |
| # Windows PowerShell scripts | |
| for script in \ | |
| agent-installer.ps1 \ | |
| agent-upgrade.ps1 \ | |
| agent-installer-session-user.ps1 \ | |
| agent-upgrade-session-user.ps1 \ | |
| agent-installer-service-user.ps1 \ | |
| agent-upgrade-service-user.ps1; do | |
| cp "./installer/windows/${script}" \ | |
| "staging/windows/openaev-${script%.ps1}.ps1" | |
| done | |
| find staging -type f | |
| - name: Upload scripts artifact | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: agent-scripts | |
| path: staging/ | |
| if-no-files-found: error | |
| retention-days: 14 |