Skip to content
Draft
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
147 changes: 111 additions & 36 deletions .github/workflows/platform-vitest-main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
name: CI / Platform Compatibility

on:
workflow_dispatch:
push:
branches:
- main
Expand All @@ -20,7 +19,8 @@ permissions:

concurrency:
group: platform-evidence-${{ github.ref }}
cancel-in-progress: true
queue: max
cancel-in-progress: false

jobs:
ubuntu-2604-contract:
Expand Down Expand Up @@ -82,15 +82,17 @@ jobs:
macos-vitest:
name: macOS compatibility (${{ matrix.shard }}/4)
permissions:
contents: read
packages: read
runs-on: macos-26
timeout-minutes: ${{ matrix.timeout_minutes }}
strategy:
fail-fast: false
matrix:
include:
- shard: 1
# The live E2E has a 70m timeout; every other step shares the remaining job time.
timeout_minutes: 150
timeout_minutes: 30
- shard: 2
timeout_minutes: 30
- shard: 3
Expand Down Expand Up @@ -120,6 +122,7 @@ jobs:
- name: Install macOS test dependencies
run: |
set -euo pipefail
test -x "$(command -v gtar)"
brew install bash coreutils fd gawk ripgrep
printf '%s\n' \
"$(brew --prefix bash)/bin" \
Expand Down Expand Up @@ -148,16 +151,10 @@ jobs:
stat --version | head -n 1
awk --version | head -n 1
- name: Install pinned OpenShell
env:
NEMOCLAW_NON_INTERACTIVE: "1"
run: env -u GH_TOKEN -u GITHUB_TOKEN bash scripts/install-openshell.sh

- name: Install dependencies
run: |
npm ci --ignore-scripts
cd nemoclaw
npm ci --ignore-scripts
env:
NODE_AUTH_TOKEN: ${{ github.token }}
run: bash .github/actions/ci-install-dependencies.sh

- name: Build CLI and plugin
run: |
Expand All @@ -166,11 +163,54 @@ jobs:
npm run build
- name: Run full Vitest suite on macOS
run: npx vitest run --testTimeout 60000 --shard="${{ matrix.shard }}/4"
env:
NEMOCLAW_EXEC_TIMEOUT: "60000"
NEMOCLAW_TEST_TIMEOUT: "60000"
run: |
set -euo pipefail
mkdir -p "$RUNNER_TEMP/nemoclaw-vitest-bin"
ln -s "$(command -v gtar)" "$RUNNER_TEMP/nemoclaw-vitest-bin/tar"
PATH="$RUNNER_TEMP/nemoclaw-vitest-bin:$PATH" \
npx vitest run --testTimeout 60000 --shard="${{ matrix.shard }}/4"
macos-live-e2e:
name: macOS live E2E
if: ${{ github.ref == 'refs/heads/main' }}
permissions:
contents: read
packages: read
runs-on: macos-26
timeout-minutes: 150
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
persist-credentials: false

- name: Setup Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: "22"
cache: npm

- name: Install dependencies
env:
NODE_AUTH_TOKEN: ${{ github.token }}
run: bash .github/actions/ci-install-dependencies.sh

- name: Build CLI and plugin
run: |
npm run build:cli
npm --prefix nemoclaw run build
- name: Install pinned OpenShell
env:
NEMOCLAW_NON_INTERACTIVE: "1"
run: env -u GH_TOKEN -u GITHUB_TOKEN bash scripts/install-openshell.sh

- id: macos_docker
name: Detect Docker availability for macOS E2E
if: ${{ matrix.shard == 1 }}
shell: bash
run: |
set -euo pipefail
Expand All @@ -183,7 +223,7 @@ jobs:
fi
- name: Run macOS live E2E
if: ${{ matrix.shard == 1 && steps.macos_docker.outputs.docker_ok == 'true' && github.ref == 'refs/heads/main' }}
if: ${{ steps.macos_docker.outputs.docker_ok == 'true' }}
env:
GITHUB_TOKEN: ${{ github.token }}
NVIDIA_INFERENCE_API_KEY: ${{ secrets.NVIDIA_INFERENCE_API_KEY }}
Expand All @@ -196,19 +236,13 @@ jobs:
npx vitest run --project e2e-live test/e2e/live/full-e2e.test.ts --silent=false --reporter=default
- name: Explain skipped macOS live E2E
if: ${{ matrix.shard == 1 && (steps.macos_docker.outputs.docker_ok != 'true' || github.ref != 'refs/heads/main') }}
shell: bash
if: ${{ steps.macos_docker.outputs.docker_ok != 'true' }}
run: |
set -euo pipefail
if [[ "$GITHUB_REF" != "refs/heads/main" ]]; then
echo "The macOS live E2E did not run because this workflow does not test main."
else
echo "The macOS live E2E did not run because Docker is unavailable."
fi
echo "The macOS build and Vitest shard still provide platform evidence."
echo "The macOS live E2E did not run because Docker is unavailable."
echo "The macOS Vitest shards still provide platform evidence."
- name: Upload macOS E2E logs on failure
if: ${{ matrix.shard == 1 && failure() }}
if: ${{ failure() }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: macos-platform-evidence-logs
Expand All @@ -220,6 +254,9 @@ jobs:

wsl-vitest:
name: WSL compatibility (${{ matrix.shard }}/4)
permissions:
contents: read
packages: read
runs-on: windows-latest
timeout-minutes: ${{ matrix.timeout_minutes }}
strategy:
Expand All @@ -238,10 +275,6 @@ jobs:
WSL_DISTRO: Ubuntu
WSL_TEST_USER: nemoclaw-ci
TRUSTED_WSL_HELPER: ${{ github.workspace }}\trusted-wsl-ci\tools\wsl\ci-helper.ps1
NEMOCLAW_NON_INTERACTIVE: "1"
NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE: "1"
NEMOCLAW_RECREATE_SANDBOX: "1"
NEMOCLAW_SANDBOX_NAME: "e2e-wsl"
steps:
- name: Force LF line endings for checkout
shell: powershell
Expand Down Expand Up @@ -270,7 +303,7 @@ jobs:
. "$env:TRUSTED_WSL_HELPER"
$null = Set-WslWorkflowPaths `
-Workspace "$env:GITHUB_WORKSPACE\source" `
-WorkdirPrefix '/tmp/nemoclaw-wsl-vitest' `
-WorkdirPrefix '/home/nemoclaw-ci/nemoclaw-wsl-vitest' `
-RunId $env:GITHUB_RUN_ID `
-RunAttempt $env:GITHUB_RUN_ATTEMPT `
-EnvironmentFile $env:GITHUB_ENV
Expand All @@ -287,10 +320,26 @@ jobs:
. "$env:TRUSTED_WSL_HELPER"
$packages = @(
'bash', 'ca-certificates', 'curl', 'git', 'jq', 'lsb-release', 'make',
'python3', 'python3-pip', 'python3-venv', 'ripgrep', 'rsync', 'tar', 'unzip', 'xz-utils'
'docker.io', 'gcc', 'gnu-coreutils', 'iproute2', 'libc6-dev', 'podman',
'procps', 'python3', 'python3-pip', 'python3-venv',
'ripgrep', 'rsync', 'tar', 'unzip', 'xz-utils', 'zip'
)
Install-WslUbuntuDependencies -Distro $env:WSL_DISTRO -Packages $packages -TestUser $env:WSL_TEST_USER
- name: Stop WSL container runtime before non-live tests
shell: powershell
run: |
. "$env:TRUSTED_WSL_HELPER"
$script = @'
set -euo pipefail
service docker stop >/dev/null 2>&1 || true
if docker info >/dev/null 2>&1; then
echo "Docker must remain unavailable during the non-live Vitest suite." >&2
exit 1
fi
'@
Invoke-WslScript -Distro $env:WSL_DISTRO -User root -Script $script
- name: Install Node.js 22 in WSL
shell: powershell
run: |
Expand All @@ -309,18 +358,23 @@ jobs:
- name: Install dependencies and build in WSL
shell: powershell
env:
NODE_AUTH_TOKEN: ${{ github.token }}
run: |
. "$env:TRUSTED_WSL_HELPER"
$testUser = ConvertTo-BashLiteral -Value $env:WSL_TEST_USER
$workdir = ConvertTo-BashLiteral -Value $env:WSL_WORKDIR
$nodeAuthToken = ConvertTo-BashLiteral -Value ([string]$env:NODE_AUTH_TOKEN)
$script = @"
set -euo pipefail
id -un | grep -Fxq $testUser
cd $workdir
npm ci --ignore-scripts
export NPM_CONFIG_CACHE="`$HOME/.npm"
export NODE_AUTH_TOKEN=$nodeAuthToken
bash .github/actions/ci-install-dependencies.sh
unset NODE_AUTH_TOKEN
npm run build:cli
cd nemoclaw
npm ci --ignore-scripts
npm run build
"@
Invoke-WslScript -Distro $env:WSL_DISTRO -User $env:WSL_TEST_USER -Script $script
Expand All @@ -335,6 +389,7 @@ jobs:
set -euo pipefail
id -un | grep -Fxq $testUser
cd $workdir
export NPM_CONFIG_CACHE="`$HOME/.npm"
export NEMOCLAW_EXEC_TIMEOUT=60000
export NEMOCLAW_TEST_TIMEOUT=60000
npx vitest run --testTimeout 60000 --shard='${{ matrix.shard }}/4'
Expand Down Expand Up @@ -372,6 +427,22 @@ jobs:
"@
Invoke-WslScript -Distro $env:WSL_DISTRO -User root -Script $script
- name: Start the WSL container runtime
if: ${{ matrix.shard == 1 && github.ref == 'refs/heads/main' }}
shell: powershell
run: |
. "$env:TRUSTED_WSL_HELPER"
$testUser = ConvertTo-BashLiteral -Value $env:WSL_TEST_USER
$script = @"
set -euo pipefail
usermod -aG docker $testUser
service docker start
docker info
podman --version
ip -Version
"@
Invoke-WslScript -Distro $env:WSL_DISTRO -User root -Script $script
- id: wsl_docker
name: Detect Docker availability in WSL
if: ${{ matrix.shard == 1 }}
Expand All @@ -385,7 +456,7 @@ jobs:
echo DOCKER_OK=0
fi
'@
$result = Invoke-WslScript -Distro $env:WSL_DISTRO -Script $script -CaptureOutput
$result = Invoke-WslScript -Distro $env:WSL_DISTRO -User $env:WSL_TEST_USER -Script $script -CaptureOutput
if ($result -match 'DOCKER_OK=1') {
'docker_ok=true' | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append
Write-Host 'Docker is available in WSL'
Expand All @@ -400,6 +471,10 @@ jobs:
env:
GITHUB_TOKEN: ${{ github.token }}
NVIDIA_INFERENCE_API_KEY: ${{ secrets.NVIDIA_INFERENCE_API_KEY }}
NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE: "1"
NEMOCLAW_NON_INTERACTIVE: "1"
NEMOCLAW_RECREATE_SANDBOX: "1"
NEMOCLAW_SANDBOX_NAME: "e2e-wsl"
run: |
. "$env:TRUSTED_WSL_HELPER"
$workdir = ConvertTo-BashLiteral -Value $env:WSL_WORKDIR
Expand All @@ -418,7 +493,7 @@ jobs:
export NEMOCLAW_RUN_LIVE_E2E=1
npx vitest run --project e2e-live test/e2e/live/full-e2e.test.ts --silent=false --reporter=default
"@
Invoke-WslScript -Distro $env:WSL_DISTRO -Script $script
Invoke-WslScript -Distro $env:WSL_DISTRO -User $env:WSL_TEST_USER -Script $script
- name: Explain skipped WSL live E2E
if: ${{ matrix.shard == 1 && (steps.wsl_docker.outputs.docker_ok != 'true' || github.ref != 'refs/heads/main') }}
Expand Down
15 changes: 15 additions & 0 deletions ci/source-shape-test-budget.json
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,21 @@
"file": "test/runtime/policy/repro-5978-policy-denial-hint.test.ts",
"test": "prints only once when the file is sourced twice in one login shell",
"category": "compatibility"
},
{
"file": "test/automation/e2e/platform-vitest-main-workflow.test.ts",
"test": "preserves distinct main-commit evidence in a serialized queue",
"category": "compatibility"
},
{
"file": "test/automation/e2e/platform-vitest-main-workflow.test.ts",
"test": "grants only the read access needed to install reviewed dependencies",
"category": "security"
},
{
"file": "test/automation/e2e/platform-vitest-main-workflow.test.ts",
"test": "installs container clients before Vitest but starts Docker only afterward",
"category": "compatibility"
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
mkdtempSync,
mkdirSync,
readFileSync,
realpathSync,
readdirSync,
renameSync,
rmSync,
Expand Down Expand Up @@ -53,7 +54,7 @@ import { restoreSnapshotToHost } from "./migration-state.js";
const temporaryRoots: string[] = [];

function makeHome(): string {
const home = mkdtempSync(path.join(tmpdir(), "nemoclaw-restore-transaction-"));
const home = realpathSync(mkdtempSync(path.join(tmpdir(), "nemoclaw-restore-transaction-")));
temporaryRoots.push(home);
return home;
}
Expand Down
3 changes: 2 additions & 1 deletion nemoclaw/src/commands/migration-state-security.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
mkdirSync,
mkdtempSync,
openSync,
realpathSync,
readdirSync,
readFileSync,
rmSync,
Expand Down Expand Up @@ -36,7 +37,7 @@ import { makeSnapshotManifest } from "./migration-state-test-fixtures.js";
const roots: string[] = [];

function makeHome(): string {
const home = mkdtempSync(path.join(tmpdir(), "nemoclaw-migration-state-security-"));
const home = realpathSync(mkdtempSync(path.join(tmpdir(), "nemoclaw-migration-state-security-")));
roots.push(home);
return home;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@ describe("preflightRebuildImage", () => {
}
});

it.runIf(process.platform !== "win32")(
it.runIf(process.platform === "linux")(
"uses the isolated config across the WSL helper and Docker subprocess boundary (#7111)",
async () => {
const root = fs.mkdtempSync(path.join(os.tmpdir(), "nemoclaw-wsl-rebuild-process-"));
Expand Down Expand Up @@ -611,6 +611,7 @@ describe("finalizePreparedRebuildImageMessagingPlan", () => {
removeImage,
env: { DOCKER_CONFIG: dockerConfig, WSL_DISTRO_NAME: "Ubuntu" },
credentialHelperResponds: () => false,
dockerContextIsDefault: () => true,
isWslHost: true,
},
),
Expand Down
Loading
Loading