mirror of
https://github.com/morluto/rea.git
synced 2026-10-26 17:35:11 +00:00
* fix(ci): run the Windows native lane with its process boundary fixture
`verify-windows-native.mjs` takes the boundary executable as its second
argument and skips every observation that needs it when the argument is
absent. CI passed no argument, so the breakaway denial, caller and child
token comparison, Windows environment semantics and in-place ancestor
reparse attempt have never run there; they only ran for an operator who
built the fixture by hand, which `native/windows/README.md` described as
optional.
The fixture is an ordinary Windows executable independent of the addon,
so the lane that already installs MinGW to cross-build the artifact
cross-builds it too and uploads it beside the existing inspection
fixture. The Windows job downloads it and passes its path, matching how
that inspection fixture already crosses the same job boundary.
No observation, assertion or threshold changes; this only stops four of
them from being silently skipped.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix(ci): pass the process boundary fixture in the real Ghidra Windows lane
`real-ghidra-windows.yml` also runs the native lane without the boundary
executable, so its proof run skipped the same breakaway, caller and child
token, environment semantics and ancestor reparse observations. Its
artifact job already installs MinGW, so it cross-builds and uploads the
fixture the same way, and the self-hosted Windows job downloads it and
passes its path.
This makes the README's claim about both Windows workflows true rather
than narrowing it to one lane.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix(process): report no remaining time after a provider deadline fires
Node timers can fire while performance.now() is still a fraction of a
millisecond short of the monotonic deadline. ProviderStartupDeadline then
reported interruption "timeout" and an aborted signal while remainingMs()
returned ceil(0.x) = 1, so polling loops guarded by remainingMs() > 0
(Hopper and Ghidra startup) could run past an elapsed deadline, and the
real-timer test "aborts a bounded wait when its real monotonic deadline
expires" failed intermittently in CI (expected 1 to be 0).
Once the deadline's own timer has classified a timeout, report zero
remaining time. A deterministic regression test fires the timer with the
monotonic clock 0.4 ms short of the deadline.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit dfdaa0ca74)
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: morluto <morluto@users.noreply.github.com>
Co-authored-by: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com>
828 lines
34 KiB
YAML
828 lines
34 KiB
YAML
name: CI
|
|
|
|
on:
|
|
push:
|
|
branches: [main]
|
|
pull_request:
|
|
branches: [main, "release/*"]
|
|
schedule:
|
|
- cron: "23 0-2,4-23 * * *"
|
|
- cron: "23 3 * * *"
|
|
workflow_dispatch:
|
|
workflow_call:
|
|
inputs:
|
|
source_sha:
|
|
description: Exact qualification source; must match the caller revision.
|
|
required: true
|
|
type: string
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
concurrency:
|
|
# Complete qualification finishes even while main receives more pushes.
|
|
# Main feedback also finishes, coalescing newer pushes to one pending run.
|
|
# Scheduled/manual main runs coalesce to one active and the latest pending;
|
|
# release and label-triggered qualification use exact-revision groups.
|
|
group: ci-${{ (github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' || inputs.source_sha != '' || contains(github.event.pull_request.labels.*.name, 'ci:full')) && 'qualification' || 'feedback' }}-${{ inputs.source_sha || github.event.pull_request.number || github.ref }}
|
|
cancel-in-progress: ${{ github.event_name == 'pull_request' && inputs.source_sha == '' && !contains(github.event.pull_request.labels.*.name, 'ci:full') }}
|
|
|
|
env:
|
|
HUSKY: "0"
|
|
|
|
jobs:
|
|
changes:
|
|
name: Classify changes
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 5
|
|
permissions:
|
|
contents: read
|
|
actions: read
|
|
outputs:
|
|
tier: ${{ steps.plan.outputs.tier }}
|
|
qualification_run_id: ${{ steps.qualification.outputs.run_id }}
|
|
code: ${{ steps.plan.outputs.code }}
|
|
sqlite: ${{ steps.plan.outputs.sqlite }}
|
|
runtime: ${{ steps.plan.outputs.runtime }}
|
|
package: ${{ steps.plan.outputs.package }}
|
|
apple: ${{ steps.plan.outputs.apple }}
|
|
fixtures: ${{ steps.plan.outputs.fixtures }}
|
|
readiness: ${{ steps.plan.outputs.readiness }}
|
|
docs: ${{ steps.plan.outputs.docs }}
|
|
workflows: ${{ steps.plan.outputs.workflows }}
|
|
browser: ${{ steps.plan.outputs.browser }}
|
|
binary_layout: ${{ steps.plan.outputs.binary_layout }}
|
|
evm: ${{ steps.plan.outputs.evm }}
|
|
javascript_recovery: ${{ steps.plan.outputs.javascript_recovery }}
|
|
recorded_crash: ${{ steps.plan.outputs.recorded_crash }}
|
|
web_network: ${{ steps.plan.outputs.web_network }}
|
|
web_runtime: ${{ steps.plan.outputs.web_runtime }}
|
|
web_source_map: ${{ steps.plan.outputs.web_source_map }}
|
|
nativeaot: ${{ steps.plan.outputs.nativeaot }}
|
|
website: ${{ steps.plan.outputs.website }}
|
|
matrix: ${{ steps.plan.outputs.matrix }}
|
|
test_selection: ${{ steps.plan.outputs.test_selection }}
|
|
steps:
|
|
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
|
|
with:
|
|
ref: ${{ inputs.source_sha || github.sha }}
|
|
fetch-depth: 0
|
|
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
|
with:
|
|
node-version-file: .nvmrc
|
|
- name: Bind qualification to the caller revision
|
|
if: inputs.source_sha != ''
|
|
env:
|
|
SOURCE_SHA: ${{ inputs.source_sha }}
|
|
run: |
|
|
test "${SOURCE_SHA}" = "${GITHUB_SHA}"
|
|
test "${SOURCE_SHA}" = "$(git rev-parse HEAD)"
|
|
- name: Find a verified ancestor for push selection
|
|
id: baseline
|
|
if: github.event_name == 'push' && inputs.source_sha == ''
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
HEAD_SHA: ${{ github.sha }}
|
|
CI_REPOSITORY: ${{ github.repository }}
|
|
CI_DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
|
|
run: node scripts/ci/baseline.mjs
|
|
- name: Admit scheduled full qualification
|
|
id: qualification
|
|
if: github.event_name == 'schedule' && inputs.source_sha == ''
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
HEAD_SHA: ${{ github.sha }}
|
|
CI_REPOSITORY: ${{ github.repository }}
|
|
CI_REPOSITORY_ID: ${{ github.repository_id }}
|
|
CI_DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
|
|
CI_FORCE_FULL: ${{ github.event.schedule == '23 3 * * *' }}
|
|
run: node scripts/ci/qualification.mjs
|
|
- name: Select verification lanes
|
|
id: plan
|
|
env:
|
|
BASE_SHA: ${{ steps.baseline.outputs.base || github.event.pull_request.base.sha }}
|
|
BASELINE_REASON: ${{ steps.baseline.outputs.reason }}
|
|
HEAD_SHA: ${{ inputs.source_sha || github.event.pull_request.head.sha || github.sha }}
|
|
CI_FULL: ${{ inputs.source_sha != '' || contains(github.event.pull_request.labels.*.name, 'ci:full') }}
|
|
CI_SKIP_FULL: ${{ steps.qualification.outputs.run_full == 'false' }}
|
|
run: node scripts/ci/plan.mjs
|
|
|
|
static:
|
|
name: Static checks
|
|
needs: changes
|
|
if: ${{ !cancelled() && needs.changes.outputs.tier != 'reused' }}
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 10
|
|
steps:
|
|
- name: Require successful change classification
|
|
env:
|
|
CHANGES_RESULT: ${{ needs.changes.result }}
|
|
run: test "${CHANGES_RESULT}" = "success"
|
|
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
|
|
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
|
with:
|
|
node-version-file: .nvmrc
|
|
cache: npm
|
|
- run: npm ci
|
|
- name: Validate workflow syntax and expressions
|
|
if: needs.changes.outputs.workflows == 'true'
|
|
run: go run github.com/rhysd/actionlint/cmd/actionlint@v1.7.7 -shellcheck= -pyflakes=
|
|
- if: needs.changes.outputs.code == 'true'
|
|
run: npm run check:ci
|
|
- if: needs.changes.outputs.code == 'true'
|
|
run: npm run verify:test-discovery
|
|
- name: Check LLDB producer retention and launch contracts
|
|
if: needs.changes.outputs.code == 'true'
|
|
run: npm run test:python
|
|
- if: needs.changes.outputs.code != 'true'
|
|
run: npm run format:check
|
|
- name: Upload complete static diagnostics
|
|
if: always() && needs.changes.outputs.code == 'true'
|
|
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
|
with:
|
|
name: static-check-reports
|
|
path: .cache/static-checks/
|
|
include-hidden-files: true
|
|
if-no-files-found: ignore
|
|
retention-days: 7
|
|
|
|
test-shard:
|
|
name: Test shard (${{ matrix.shard }})
|
|
needs: [changes, build]
|
|
if: needs.changes.outputs.code == 'true'
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 30
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
shard: [1/6, 2/6, 3/6, 4/6, 5/6, 6/6]
|
|
steps:
|
|
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
|
|
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
|
with:
|
|
node-version-file: .nvmrc
|
|
cache: npm
|
|
- run: npm ci
|
|
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
|
with:
|
|
name: rea-test-runtime
|
|
path: .
|
|
- name: Run complete portable suite with coverage
|
|
if: needs.changes.outputs.tier == 'full'
|
|
run: npm run test:ci:shard:run -- --shard=${{ matrix.shard }}
|
|
env:
|
|
REA_CI_TEST_HISTORY: .cache/ci-test-history/test-results.json
|
|
- name: Run complete portable suite for fast feedback
|
|
if: needs.changes.outputs.tier == 'fast'
|
|
run: npm run test:run -- --reporter=default --reporter=blob --shard=${{ matrix.shard }}
|
|
env:
|
|
REA_CI_TEST_HISTORY: .cache/ci-test-history/test-results.json
|
|
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
|
if: ${{ !cancelled() }}
|
|
with:
|
|
name: vitest-report-${{ strategy.job-index }}
|
|
path: .vitest/blob/*
|
|
include-hidden-files: true
|
|
if-no-files-found: error
|
|
overwrite: true
|
|
retention-days: 7
|
|
|
|
build:
|
|
name: Build package
|
|
needs: changes
|
|
# Reusable provider workflows consume this run's portable build artifact,
|
|
# even when a workflow-only edit selects the lane without portable tests.
|
|
if: >-
|
|
needs.changes.outputs.code == 'true' ||
|
|
needs.changes.outputs.browser == 'true' ||
|
|
needs.changes.outputs.binary_layout == 'true' ||
|
|
needs.changes.outputs.evm == 'true' ||
|
|
needs.changes.outputs.javascript_recovery == 'true' ||
|
|
needs.changes.outputs.recorded_crash == 'true' ||
|
|
needs.changes.outputs.web_network == 'true' ||
|
|
needs.changes.outputs.web_runtime == 'true' ||
|
|
needs.changes.outputs.web_source_map == 'true'
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 10
|
|
permissions:
|
|
contents: read
|
|
actions: read
|
|
steps:
|
|
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
|
|
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
|
with:
|
|
node-version-file: .nvmrc
|
|
cache: npm
|
|
- run: npm ci
|
|
- name: Reuse portable build outputs across runs
|
|
uses: ./.github/actions/portable-build-cache
|
|
with:
|
|
save: ${{ github.event_name != 'pull_request' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch) }}
|
|
- run: npm run test:prepare
|
|
- name: Find available trusted full-suite timing history
|
|
id: history
|
|
continue-on-error: true
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
CI_REPOSITORY: ${{ github.repository }}
|
|
CI_REPOSITORY_ID: ${{ github.repository_id }}
|
|
CI_DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
|
|
run: node scripts/ci/test-history.mjs
|
|
- name: Download previous timing report
|
|
if: steps.history.outputs.run-id != ''
|
|
continue-on-error: true
|
|
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
|
with:
|
|
name: test-timings
|
|
run-id: ${{ steps.history.outputs.run-id }}
|
|
github-token: ${{ github.token }}
|
|
path: .cache/ci-test-history
|
|
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
|
with:
|
|
name: rea-test-runtime
|
|
path: |
|
|
dist/
|
|
skills/
|
|
.cache/mcp-tool-catalog.json
|
|
.cache/ci-test-history/test-results.json
|
|
docs/public/product-catalog.json
|
|
docs/verification/managed-conformance-*.json
|
|
include-hidden-files: true
|
|
if-no-files-found: error
|
|
retention-days: 7
|
|
|
|
# test:prepare caches only portable JS, skill, and catalog outputs.
|
|
# Native package jobs still run their build and prepack checks; Turbo
|
|
# restores matching outputs or rebuilds when their inputs differ.
|
|
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
|
with:
|
|
name: rea-build-cache
|
|
path: .turbo/cache/
|
|
include-hidden-files: true
|
|
if-no-files-found: error
|
|
retention-days: 7
|
|
|
|
sqlite-runtime:
|
|
# Preserve all selected coverage, but admit expensive host/provider work
|
|
# only after static validation. Portable tests still provide early feedback.
|
|
needs: [changes, static, build]
|
|
if: needs.changes.outputs.sqlite == 'true'
|
|
uses: ./.github/workflows/sqlite-runtime.yml
|
|
|
|
test:
|
|
name: Portable tests
|
|
needs: [changes, test-shard]
|
|
if: ${{ !cancelled() && needs.changes.outputs.tier != 'reused' }}
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 10
|
|
steps:
|
|
- name: Require successful change classification
|
|
env:
|
|
CHANGES_RESULT: ${{ needs.changes.result }}
|
|
run: test "${CHANGES_RESULT}" = "success"
|
|
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
|
|
if: needs.changes.outputs.code == 'true' && success()
|
|
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
|
if: needs.changes.outputs.code == 'true' && success()
|
|
with:
|
|
node-version-file: .nvmrc
|
|
cache: npm
|
|
- if: needs.changes.outputs.code == 'true' && success()
|
|
run: npm ci
|
|
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
|
if: needs.changes.outputs.code == 'true' && success()
|
|
with:
|
|
path: .vitest/blob
|
|
pattern: vitest-report-*
|
|
merge-multiple: true
|
|
- name: Merge coverage, JUnit, and timing reports
|
|
id: merge
|
|
if: needs.changes.outputs.code == 'true' && needs.changes.outputs.tier == 'full' && success()
|
|
run: >-
|
|
npm run test:ci:merge --
|
|
--coverage.reportsDirectory=coverage
|
|
--coverage.reporter=text
|
|
--coverage.reporter=json-summary
|
|
--coverage.reporter=lcov
|
|
--reporter=default
|
|
--reporter=junit
|
|
--reporter=json
|
|
--reporter=./scripts/ci/test-timing-reporter.mjs
|
|
--outputFile.junit=test-results.xml
|
|
--outputFile.json=test-results.json
|
|
- name: Merge fast-suite JUnit and timing reports
|
|
id: merge-fast
|
|
if: needs.changes.outputs.code == 'true' && needs.changes.outputs.tier == 'fast' && success()
|
|
run: >-
|
|
npm exec -- vitest --merge-reports
|
|
--reporter=default
|
|
--reporter=junit
|
|
--reporter=json
|
|
--reporter=./scripts/ci/test-timing-reporter.mjs
|
|
--outputFile.junit=test-results.xml
|
|
--outputFile.json=test-results.json
|
|
- name: Summarize slowest test files
|
|
if: needs.changes.outputs.code == 'true' && !cancelled() && hashFiles('test-timings.json') != ''
|
|
env:
|
|
SHARD_RESULT: ${{ needs.test-shard.result }}
|
|
MERGE_RESULT: ${{ needs.changes.outputs.tier == 'full' && steps.merge.outcome || steps.merge-fast.outcome }}
|
|
CI_VERIFY_TEST_INVENTORY: "true"
|
|
CI_TEST_SELECTION: ${{ needs.changes.outputs.test_selection }}
|
|
CI_PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
|
|
run: node scripts/ci/test-report.mjs
|
|
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
|
if: needs.changes.outputs.code == 'true' && !cancelled() && hashFiles('test-results.json') != ''
|
|
with:
|
|
name: test-results
|
|
path: |
|
|
test-results.xml
|
|
test-results.json
|
|
test-timings.json
|
|
coverage/
|
|
.cache/ci-test-selection/report.json
|
|
include-hidden-files: true
|
|
if-no-files-found: error
|
|
retention-days: 30
|
|
- name: Publish successful timing history
|
|
if: needs.changes.outputs.code == 'true' && needs.changes.outputs.tier == 'full' && success() && needs.test-shard.result == 'success'
|
|
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
|
with:
|
|
name: test-timings
|
|
path: .cache/ci-test-history/test-results.json
|
|
include-hidden-files: true
|
|
if-no-files-found: error
|
|
retention-days: 30
|
|
- name: Require successful test shards
|
|
if: ${{ !cancelled() }}
|
|
env:
|
|
CODE_REQUIRED: ${{ needs.changes.outputs.code }}
|
|
SHARD_RESULT: ${{ needs.test-shard.result }}
|
|
run: test "${CODE_REQUIRED}" != "true" || test "${SHARD_RESULT}" = "success"
|
|
|
|
conformance-fixtures:
|
|
name: Source-built conformance fixtures
|
|
needs: [changes, static]
|
|
if: needs.changes.outputs.fixtures == 'true'
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 10
|
|
steps:
|
|
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
|
|
- name: Verify fixtures from a clean checkout
|
|
run: npm run verify:fixtures
|
|
|
|
windows-native-build:
|
|
name: Build bundled Windows x64 native controls
|
|
needs: [changes, static]
|
|
if: needs.changes.outputs.runtime == 'true'
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 10
|
|
steps:
|
|
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
|
|
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
|
with:
|
|
node-version-file: .nvmrc
|
|
- name: Prepare cross compiler
|
|
run: |
|
|
# Slow Azure archive transfers can exhaust the job before compilation.
|
|
# Keep the same signed packages and avoid slow HTTP mirror fallback.
|
|
for source in /etc/apt/apt-mirrors.txt /etc/apt/sources.list /etc/apt/sources.list.d/ubuntu.sources; do
|
|
if [ -f "$source" ]; then
|
|
sudo sed -i 's|azure.archive.ubuntu.com|archive.ubuntu.com|g; s|http://archive.ubuntu.com|https://archive.ubuntu.com|g' "$source"
|
|
fi
|
|
done
|
|
sudo apt-get update
|
|
sudo apt-get install --no-install-recommends -y g++-mingw-w64-x86-64
|
|
- run: npm run build:windows-native
|
|
- run: npm run verify:windows-native:artifact
|
|
- run: node scripts/build-windows-native.mjs --inspection-fixture
|
|
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
|
with:
|
|
name: windows-native-inspection-fixture
|
|
path: .cache/windows-native-inspection-fixture/
|
|
if-no-files-found: error
|
|
# The process boundary observations are independent of the addon: they
|
|
# report the caller's and child's own token, environment and breakaway
|
|
# results from a separate executable. Cross-build it in the lane that
|
|
# already has MinGW so the Windows job can observe them too.
|
|
- name: Build Windows process boundary fixture
|
|
run: |
|
|
mkdir -p .cache/windows-process-boundary
|
|
x86_64-w64-mingw32-g++ -municode -std=c++17 -O2 -static -Wall -Wextra \
|
|
-o .cache/windows-process-boundary/process-boundary.exe \
|
|
tests/fixtures/windows/processBoundary.cc -ladvapi32
|
|
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
|
with:
|
|
name: windows-process-boundary-fixture
|
|
path: .cache/windows-process-boundary/
|
|
if-no-files-found: error
|
|
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
|
with:
|
|
name: windows-native-controls
|
|
path: native/windows/build/
|
|
if-no-files-found: error
|
|
|
|
package-e2e:
|
|
name: Native package baseline (${{ matrix.platform }} ${{ matrix.architecture }})
|
|
needs: [changes, static, build, windows-native-build]
|
|
if: needs.changes.outputs.runtime == 'true'
|
|
strategy:
|
|
fail-fast: false
|
|
# The four platform jobs use independent hosted runners; keep each
|
|
# runner's existing heap and threadpool limits while avoiding a queued
|
|
# second platform wave.
|
|
max-parallel: 4
|
|
matrix: ${{ fromJSON(needs.changes.outputs.matrix) }}
|
|
runs-on: ${{ matrix.os }}
|
|
timeout-minutes: 20
|
|
env:
|
|
NODE_OPTIONS: "--max-old-space-size=1024"
|
|
UV_THREADPOOL_SIZE: "2"
|
|
steps:
|
|
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
|
|
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
|
with:
|
|
node-version-file: .nvmrc
|
|
cache: npm
|
|
- name: Verify native runtime identity
|
|
env:
|
|
EXPECTED_CI_PLATFORM: ${{ matrix.platform }}
|
|
EXPECTED_CI_ARCHITECTURE: ${{ matrix.architecture }}
|
|
run: >-
|
|
node -e "const assert = require('node:assert/strict');
|
|
assert.equal(process.platform, process.env.EXPECTED_CI_PLATFORM);
|
|
assert.equal(process.arch, process.env.EXPECTED_CI_ARCHITECTURE);
|
|
console.log(JSON.stringify({ platform: process.platform, architecture: process.arch, node: process.version }));"
|
|
- run: npm ci
|
|
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
|
with:
|
|
name: rea-build-cache
|
|
path: .turbo/cache/
|
|
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
|
with:
|
|
name: windows-native-controls
|
|
path: native/windows/build/
|
|
- run: npm run verify:windows-native:artifact
|
|
- name: Verify NativeAOT diagnostic applicability on this host
|
|
run: npm run test:focused -- tests/evaluation/package/nativeAotDiagnostics.test.ts
|
|
- name: Resolve npm cache before verifier HOME isolation
|
|
id: npm-cache
|
|
run: |
|
|
cache_path="$(npm config get cache)"
|
|
echo "path=${cache_path}" >> "${GITHUB_OUTPUT}"
|
|
- run: npm run verify:package
|
|
env:
|
|
npm_config_cache: ${{ steps.npm-cache.outputs.path }}
|
|
REA_VERIFIED_PACKAGE_DIRECTORY: ${{ needs.changes.outputs.tier == 'full' && matrix.platform == 'linux' && matrix.architecture == 'x64' && '.cache/verified-package' || '' }}
|
|
- name: Verify real Node Inspector discovery and observation
|
|
timeout-minutes: 10
|
|
run: npm run verify:inspector
|
|
- name: Retain the exact qualified release package
|
|
if: needs.changes.outputs.tier == 'full' && matrix.platform == 'linux' && matrix.architecture == 'x64'
|
|
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
|
with:
|
|
name: verified-release-package
|
|
path: .cache/verified-package/
|
|
include-hidden-files: true
|
|
if-no-files-found: error
|
|
overwrite: true
|
|
retention-days: 7
|
|
|
|
apple-artifacts:
|
|
name: Real Apple artifact CLI/MCP E2E
|
|
needs: [changes, static, build]
|
|
if: needs.changes.outputs.apple == 'true'
|
|
runs-on: macos-15
|
|
timeout-minutes: 15
|
|
steps:
|
|
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
|
|
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
|
with:
|
|
node-version-file: .nvmrc
|
|
cache: npm
|
|
- run: npm ci
|
|
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
|
with:
|
|
name: rea-build-cache
|
|
path: .turbo/cache/
|
|
- name: Verify Apple artifact formats and metadata
|
|
env:
|
|
REA_ARTIFACT_NODE_COMPILE_CACHE: ${{ runner.temp }}/rea-artifact-node-cache
|
|
run: |
|
|
npm run verify:keyed-archive
|
|
npm run verify:asset-catalog
|
|
npm run verify:macos-bundle
|
|
npm run verify:legacy-simulator
|
|
npm run verify:apple-dispatch
|
|
npm run verify:interface-builder
|
|
- name: Run native Apple and process boundary regressions
|
|
run: >-
|
|
npm run test:focused --
|
|
tests/boundary/filesystem/installScript.test.ts
|
|
tests/boundary/filesystem/nibNativeHierarchy.test.ts
|
|
tests/boundary/filesystem/interfaceBuilderBundle.test.ts
|
|
tests/boundary/cli/nativePlistCli.test.ts
|
|
tests/boundary/cli/nativePlistPrototypeKeyCli.test.ts
|
|
tests/boundary/cli/nativePlistSelectionFailureCli.test.ts
|
|
tests/boundary/cli/nativeDemangleCli.test.ts
|
|
tests/boundary/mcp/nativeDemangleMcp.test.ts
|
|
tests/boundary/providers/native/nativeSignatureTargetBinding.test.ts
|
|
tests/boundary/cli/nativeSignatureCli.test.ts
|
|
tests/boundary/mcp/nativeSignatureTargetBindingMcp.test.ts
|
|
src/process/capture/FilesystemSnapshot.test.ts
|
|
tests/boundary/process/darwinProcessRunTokenReader.test.ts
|
|
tests/boundary/process/directAnalysisSignals.test.ts
|
|
tests/boundary/process/processCaptureLifecycle.test.ts
|
|
tests/boundary/process/processCli.test.ts
|
|
tests/boundary/mcp/sessionMcp.test.ts
|
|
|
|
reconstruction-readiness:
|
|
name: Reconstruction readiness
|
|
needs: [changes, static]
|
|
if: needs.changes.outputs.readiness == 'true'
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 15
|
|
steps:
|
|
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
|
|
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
|
with:
|
|
node-version-file: .nvmrc
|
|
cache: npm
|
|
- run: npm ci
|
|
- name: Run the public CLI/MCP reconstruction journey
|
|
env:
|
|
REA_READINESS_REPORT_PATH: readiness-report.json
|
|
run: |
|
|
set -o pipefail
|
|
npm run verify:readiness | tee readiness-summary.json
|
|
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
|
if: ${{ !cancelled() }}
|
|
with:
|
|
name: reconstruction-readiness
|
|
path: |
|
|
readiness-summary.json
|
|
readiness-report.json
|
|
if-no-files-found: error
|
|
retention-days: 30
|
|
|
|
windows-curated:
|
|
name: Windows capability and package lane
|
|
needs: [changes, static, build, windows-native-build]
|
|
if: needs.changes.outputs.package == 'true'
|
|
runs-on: windows-latest
|
|
timeout-minutes: 25
|
|
steps:
|
|
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
|
|
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
|
with:
|
|
node-version-file: .nvmrc
|
|
cache: npm
|
|
- run: npm ci
|
|
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
|
with:
|
|
name: rea-build-cache
|
|
path: .turbo/cache/
|
|
- run: npm run build:cached
|
|
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
|
with:
|
|
name: windows-native-controls
|
|
path: native/windows/build/
|
|
- run: npm run verify:windows-native:artifact
|
|
- name: Record named Windows host capabilities
|
|
run: node scripts/windows-capabilities.mjs | Out-File -Encoding utf8NoBOM windows-capabilities.json
|
|
- name: Validate Windows host capability report
|
|
run: >-
|
|
node -e "const report = JSON.parse(require('node:fs').readFileSync('windows-capabilities.json', 'utf8'));
|
|
if (report.platform !== 'win32' || report.architecture !== 'x64')
|
|
throw new Error('expected a Windows x64 capability report');"
|
|
# Keep this list aligned with tests/process-global/curatedWindowsLane.test.ts,
|
|
# which fails when any path below is renamed or removed. Vitest silently
|
|
# ignores unmatched paths, so a stale entry would otherwise report green
|
|
# while skipping coverage.
|
|
#
|
|
# The matching native artifact establishes real Job Object and private
|
|
# runtime boundaries for these fixtures. Ghidra and Java are not needed;
|
|
# real engine claims remain in the separate controlled-provider workflow.
|
|
- name: Run curated Windows capability tests
|
|
run: >-
|
|
npx vitest run --coverage.enabled=false
|
|
tests/boundary/filesystem/binaryTarget.test.ts
|
|
tests/boundary/filesystem/safeOutputTree.test.ts
|
|
tests/boundary/providers/native/artifactProvider.archiveSafety.test.ts
|
|
tests/boundary/providers/native/artifactProvider.extractionCompleteness.test.ts
|
|
tests/boundary/filesystem/setupUnavailableProvider.test.ts
|
|
tests/boundary/filesystem/windowsNpxRegistration.test.ts
|
|
tests/acceptance/setup/homeDirectoryFallback.test.ts
|
|
tests/boundary/filesystem/javascriptApplicationWorkflows.test.ts
|
|
tests/boundary/filesystem/webScriptManifestPaths.test.ts
|
|
tests/boundary/process/ProcessEvidence.host.test.ts
|
|
tests/acceptance/webModuleCli.test.ts
|
|
tests/acceptance/webSourceLocationCli.test.ts
|
|
tests/boundary/cli/referenceSourceImportStatus.test.ts
|
|
tests/boundary/filesystem/asarInventoryFreshness.test.ts
|
|
tests/boundary/filesystem/javascript-applications/javascriptArtifactReconstruction.test.ts
|
|
tests/conformance/providers/ghidra/windowsCapabilities.test.ts
|
|
src/ghidra/GhidraInstallation.test.ts
|
|
tests/boundary/filesystem/ghidraJavaProbe.test.ts
|
|
tests/boundary/providers/ghidra/ghidraTransport.test.ts
|
|
tests/boundary/providers/ghidra/ghidraTargetSnapshot.test.ts
|
|
tests/boundary/providers/ghidra/ghidraLauncher.test.ts
|
|
tests/boundary/providers/hopper/hopperClient.cleanupRetry.test.ts
|
|
src/windows/WindowsNativeLoader.test.ts
|
|
src/windows/WindowsOwnedProcess.test.ts
|
|
src/ghidra/GhidraLauncherEnvironment.test.ts
|
|
src/process/ProcessOwnership.test.ts
|
|
src/process/ProcessOwnership.part2.test.ts
|
|
src/process/ProcessOwnership.part3.test.ts
|
|
src/process/ProcessOwnership.validation.test.ts
|
|
src/application/Update.test.ts
|
|
tests/process-global/updateMaintenance.test.ts
|
|
tests/conformance/providers/ghidra/realGhidraWindowsWorkflow.test.ts
|
|
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
|
with:
|
|
name: windows-process-boundary-fixture
|
|
path: .cache/windows-process-boundary/
|
|
# Passing the fixture adds the breakaway, caller/child token, environment
|
|
# semantics and ancestor reparse observations, which the lane skips
|
|
# entirely when it is absent.
|
|
- run: >-
|
|
npm run verify:windows-native -- .
|
|
"${{ github.workspace }}\.cache\windows-process-boundary\process-boundary.exe"
|
|
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
|
with:
|
|
name: windows-native-inspection-fixture
|
|
path: .cache/windows-native-inspection-fixture/
|
|
- name: Verify native inspection failure ownership and recovery
|
|
run: node scripts/verify-windows-native-inspection.mjs
|
|
- name: Verify real Node Inspector discovery and observation
|
|
timeout-minutes: 10
|
|
env:
|
|
NODE_OPTIONS: "--max-old-space-size=1024"
|
|
UV_THREADPOOL_SIZE: "2"
|
|
run: npm run verify:inspector
|
|
- run: npm run verify:package:windows
|
|
- name: Verify native directory identity on Node 24
|
|
run: >-
|
|
npx vitest run --coverage.enabled=false
|
|
tests/boundary/filesystem/directoryArtifactReaderOpen.test.ts
|
|
tests/boundary/filesystem/javascriptPackagePrecedence.test.ts
|
|
tests/boundary/filesystem/javascriptArtifactContentIdentity.test.ts
|
|
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
|
with:
|
|
node-version: 22.19.0
|
|
- name: Verify native path boundaries on Node 22
|
|
run: >-
|
|
npx vitest run --coverage.enabled=false
|
|
tests/boundary/filesystem/directoryArtifactReaderOpen.test.ts
|
|
tests/boundary/filesystem/javascriptPackagePrecedence.test.ts
|
|
tests/boundary/filesystem/javascriptArtifactContentIdentity.test.ts
|
|
tests/boundary/process/sourceMapUncHosts.test.ts
|
|
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
|
if: always()
|
|
with:
|
|
name: windows-capabilities
|
|
path: windows-capabilities.json
|
|
retention-days: 30
|
|
|
|
docs:
|
|
name: Docs Generation
|
|
needs: changes
|
|
if: needs.changes.outputs.docs == 'true'
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 10
|
|
steps:
|
|
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
|
|
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
|
with:
|
|
node-version-file: .nvmrc
|
|
cache: npm
|
|
- run: npm ci
|
|
- run: npm run docs:check
|
|
- name: Generation leaves authored files unchanged
|
|
run: git diff --exit-code
|
|
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
|
with:
|
|
name: generated-docs
|
|
path: |
|
|
docs/public/product-catalog.json
|
|
docs/verification/managed-conformance-*.json
|
|
skills/reverse-engineer-anything
|
|
if-no-files-found: error
|
|
|
|
browser:
|
|
needs: [changes, static, build]
|
|
if: needs.changes.outputs.browser == 'true'
|
|
uses: ./.github/workflows/real-browser.yml
|
|
with:
|
|
build_cache_artifact: rea-build-cache
|
|
|
|
binary_layout:
|
|
needs: [changes, static, build]
|
|
if: needs.changes.outputs.binary_layout == 'true'
|
|
uses: ./.github/workflows/real-binary-layout.yml
|
|
with:
|
|
build_cache_artifact: rea-build-cache
|
|
|
|
evm:
|
|
needs: [changes, static, build]
|
|
if: needs.changes.outputs.evm == 'true'
|
|
uses: ./.github/workflows/real-evm-interface.yml
|
|
with:
|
|
build_cache_artifact: rea-build-cache
|
|
|
|
javascript_recovery:
|
|
needs: [changes, static, build]
|
|
if: needs.changes.outputs.javascript_recovery == 'true'
|
|
uses: ./.github/workflows/real-javascript-recovery.yml
|
|
with:
|
|
build_cache_artifact: rea-build-cache
|
|
|
|
recorded_crash:
|
|
needs: [changes, static, build]
|
|
if: needs.changes.outputs.recorded_crash == 'true'
|
|
uses: ./.github/workflows/real-recorded-crash.yml
|
|
with:
|
|
build_cache_artifact: rea-build-cache
|
|
|
|
web_network:
|
|
needs: [changes, static, build]
|
|
if: needs.changes.outputs.web_network == 'true'
|
|
uses: ./.github/workflows/real-web-network-captures.yml
|
|
with:
|
|
build_cache_artifact: rea-build-cache
|
|
|
|
web_runtime:
|
|
needs: [changes, static, build]
|
|
if: needs.changes.outputs.web_runtime == 'true'
|
|
uses: ./.github/workflows/real-web-runtime.yml
|
|
with:
|
|
build_cache_artifact: rea-build-cache
|
|
|
|
web_source_map:
|
|
needs: [changes, static, build]
|
|
if: needs.changes.outputs.web_source_map == 'true'
|
|
uses: ./.github/workflows/real-web-source-map.yml
|
|
with:
|
|
build_cache_artifact: rea-build-cache
|
|
|
|
nativeaot:
|
|
needs: [changes, static]
|
|
if: needs.changes.outputs.nativeaot == 'true'
|
|
uses: ./.github/workflows/nativeaot-fixtures.yml
|
|
|
|
website:
|
|
needs: [changes, static]
|
|
if: needs.changes.outputs.website == 'true'
|
|
uses: ./.github/workflows/website-check.yml
|
|
|
|
required:
|
|
name: CI required
|
|
if: ${{ always() }}
|
|
needs:
|
|
[
|
|
changes,
|
|
static,
|
|
build,
|
|
test-shard,
|
|
sqlite-runtime,
|
|
test,
|
|
conformance-fixtures,
|
|
windows-native-build,
|
|
package-e2e,
|
|
apple-artifacts,
|
|
reconstruction-readiness,
|
|
windows-curated,
|
|
docs,
|
|
browser,
|
|
binary_layout,
|
|
evm,
|
|
javascript_recovery,
|
|
recorded_crash,
|
|
web_network,
|
|
web_runtime,
|
|
web_source_map,
|
|
nativeaot,
|
|
website,
|
|
]
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 5
|
|
steps:
|
|
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
|
|
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
|
with:
|
|
node-version-file: .nvmrc
|
|
- name: Require every selected lane to pass
|
|
id: gate
|
|
env:
|
|
CI_JOBS: ${{ toJSON(needs) }}
|
|
CI_QUALIFICATION_DIRECTORY: .cache/ci-qualification
|
|
run: node scripts/ci/required.mjs
|
|
- name: Upload full qualification receipt artifact
|
|
if: needs.changes.outputs.tier == 'full' && success()
|
|
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
|
with:
|
|
name: ${{ steps.gate.outputs.receipt_name }}
|
|
path: ${{ steps.gate.outputs.receipt_path }}
|
|
if-no-files-found: error
|
|
overwrite: true
|
|
retention-days: 7
|