mirror of
https://github.com/morluto/rea.git
synced 2026-11-15 19:23:24 +00:00
* test(mcp): compile advertised patterns with the regex engines clients run List the built package's tools over stdio in every input, output and catalog profile and compile each distinct advertised regular expression with V8 (plain, u, v), Go regexp (RE2), C++ RE2, Python re, and Rust regex and fancy-regex through the Rust jsonschema crate. A refusal names the engine, its error, and each tool, schema path and profile. The Python engines are pinned, hash-checked wheels; Go is the host toolchain with GOTOOLCHAIN=local. A missing engine is reported as not verified, and REA_REQUIRE_SCHEMA_ENGINES=1 makes it a failure. The pattern owner now also reports patternProperties keys, which clients compile as well. Refs #10830 * test(mcp): run schema engine helpers and listings under the process owner * test(mcp): load advertised schemas in the validators clients build (#10983) * test(mcp): load advertised schemas in the validators clients build Build a validator for every distinct advertised input and output schema with the Rust jsonschema crate's defaults, which check the declared draft's meta-schema and formats and compile every subschema. --complete adds Python jsonschema's check_schema, which jsonschema.validate runs in Python clients; it takes several seconds, so it is opt-in. Refusals are grouped by reason, so one shared pattern that breaks many schemas is reported once with its sites. Ajv strict mode and OpenAI strict mode are documented as not covered, with the reasons. Refs #10830 * ci(mcp): require the client schema engines on every code change (#10984) * ci(mcp): require the client schema engines on every code change Run scripts/verify-advertised-schemas.mjs at the end of the build job, after its artifacts upload, with REA_REQUIRE_SCHEMA_ENGINES=1 so a missing engine fails rather than passes. Go is the runner's toolchain; the Python engines install into a virtual environment cached by the requirements file's digest and interpreter version. Full qualification adds --complete. Refs #10830 * test(ci): require the client schema engine step in code builds * test(mcp): record a reviewable summary of the advertised catalog (#10985) * test(mcp): record a reviewable summary of the advertised catalog Commit scripts/verify/advertised-schemas/summary.json: each advertised pattern with the tool schemas that carry it, and a digest of every tool's schema per input or output profile. The advertised schema check compares it with the packaged listings it already makes and fails on any difference, printing lines such as '119 tool schemas gained pattern /.../', so a change that reaches many tools at once is visible in review. --update-summary regenerates it. Refs #10830 * docs(release): check the packed catalog with client engines before publishing (#10986) * docs(release): check the packed catalog with client engines before publishing Add a pre-publish step to the release guide: install the packed candidate into an empty prefix and run verify-advertised-schemas.mjs against it with --package-root, requiring the RE2 (Go regexp and C++ RE2) and Rust (regex, fancy-regex and jsonschema) engines. CI checks each commit's build; this covers the archive that will be published. Refs #10830 * docs(release): check the exact qualified archive and clean up afterwards * test(mcp): regenerate the advertised catalog summary from current main
1276 lines
59 KiB
YAML
1276 lines
59 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
|
|
remote_cache_write:
|
|
description: Trusted release qualification may publish the remote cache.
|
|
required: false
|
|
type: boolean
|
|
default: false
|
|
secrets:
|
|
TURBO_TOKEN:
|
|
description: Remote cache token. Only trusted release qualification passes it.
|
|
required: false
|
|
|
|
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"
|
|
# Set Actions secret TURBO_TOKEN and variable TURBO_TEAM. OIDC can mint
|
|
# TURBO_TOKEN via vercel/setup-turborepo-remote-cache-action; do not commit a token.
|
|
# A called workflow sees the caller event, so workflow_call is not an event
|
|
# name here. Release qualification sets remote_cache_write and passes the
|
|
# token. Open pull requests get an empty token and the local cache only.
|
|
# Remote reads need a credential, and pull requests do not receive one.
|
|
TURBO_TOKEN: "${{ (inputs.remote_cache_write == true || (github.ref == format('refs/heads/{0}', github.event.repository.default_branch) && (github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'))) && secrets.TURBO_TOKEN || '' }}"
|
|
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
|
|
TURBO_CACHE: "${{ (inputs.remote_cache_write == true || (github.ref == format('refs/heads/{0}', github.event.repository.default_branch) && (github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'))) && 'local:rw,remote:rw' || 'local:rw' }}"
|
|
|
|
jobs:
|
|
changes:
|
|
name: Classify changes
|
|
runs-on: ubuntu-24.04
|
|
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 }}
|
|
reverse_tools: ${{ steps.plan.outputs.reverse_tools }}
|
|
python: ${{ steps.plan.outputs.python }}
|
|
packet_capture: ${{ steps.plan.outputs.packet_capture }}
|
|
signal_recording: ${{ steps.plan.outputs.signal_recording }}
|
|
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 }}
|
|
apk_signature: ${{ steps.plan.outputs.apk_signature }}
|
|
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 }}
|
|
agentenv: ${{ steps.plan.outputs.agentenv }}
|
|
nativeaot: ${{ steps.plan.outputs.nativeaot }}
|
|
ghidra_bridge: ${{ steps.plan.outputs.ghidra_bridge }}
|
|
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
|
|
- name: Validate source architecture before dependency installation
|
|
if: needs.changes.outputs.code == 'true'
|
|
run: node scripts/verify/architecture-guards.mjs
|
|
- name: Cache npm package downloads
|
|
id: npm-cache
|
|
uses: ./.github/actions/npm-cache
|
|
with:
|
|
# Linux x64 writer. Parallel Linux jobs restore this key.
|
|
save: "true"
|
|
- run: npm ci
|
|
- name: Restore static task cache
|
|
if: needs.changes.outputs.code == 'true'
|
|
id: static-cache
|
|
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
|
|
with:
|
|
path: .turbo/cache/
|
|
key: rea-static-v1-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('.nvmrc', '.npmrc', 'package-lock.json') }}-${{ github.sha }}
|
|
# Turbo validates each task's inputs after restoring this snapshot.
|
|
restore-keys: rea-static-v1-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('.nvmrc', '.npmrc', 'package-lock.json') }}-
|
|
- 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=
|
|
# Code tiers run this source-only policy test in their existing shards.
|
|
# Workflow-only changes need the guard, without preparing runtime artifacts.
|
|
- name: Check action pins for workflow-only changes
|
|
if: needs.changes.outputs.workflows == 'true' && needs.changes.outputs.code != 'true'
|
|
run: node scripts/run-exact-tests.mjs run tests/boundary/filesystem/workflowActionPinning.test.ts
|
|
- name: Record static task source and execution identity
|
|
continue-on-error: true
|
|
if: needs.changes.outputs.code == 'true'
|
|
env:
|
|
CI_PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
|
|
CI_STATIC_CONTEXT_SCRIPT: check:ci:fast:tasks
|
|
run: npm run ci:static-context
|
|
- if: needs.changes.outputs.code == 'true'
|
|
run: npm run check:ci:fast
|
|
- if: needs.changes.outputs.code != 'true'
|
|
run: npm run format:check
|
|
- name: Save validated static task cache
|
|
if: >-
|
|
success() && needs.changes.outputs.code == 'true' &&
|
|
steps.npm-cache.outputs.can-save == 'true' &&
|
|
steps.static-cache.outputs.cache-hit != 'true'
|
|
uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
|
|
with:
|
|
path: .turbo/cache/
|
|
key: ${{ steps.static-cache.outputs.cache-primary-key }}
|
|
- 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
|
|
|
|
static-deep:
|
|
name: Deep static checks
|
|
needs: changes
|
|
# Full qualification only. Provider lanes wait on fast static, not this job.
|
|
if: needs.changes.outputs.tier == 'full' && needs.changes.outputs.code == '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
|
|
- name: Cache npm package downloads
|
|
id: npm-cache
|
|
uses: ./.github/actions/npm-cache
|
|
- run: npm ci
|
|
- name: Restore deep static task cache
|
|
id: static-cache
|
|
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
|
|
with:
|
|
path: .turbo/cache/
|
|
key: rea-static-deep-v1-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('.nvmrc', '.npmrc', 'package-lock.json') }}-${{ github.sha }}
|
|
restore-keys: rea-static-deep-v1-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('.nvmrc', '.npmrc', 'package-lock.json') }}-
|
|
- name: Restore Knip analysis cache
|
|
id: knip-cache
|
|
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
|
|
with:
|
|
path: node_modules/.cache/knip
|
|
# Each trusted commit publishes a new entry. Restore still matches the
|
|
# configuration prefix from the previous successful full run.
|
|
key: knip-meta-v1-${{ runner.os }}-${{ hashFiles('knip.json', 'tsconfig.json', 'package.json', 'package-lock.json') }}-${{ github.sha }}
|
|
restore-keys: knip-meta-v1-${{ runner.os }}-${{ hashFiles('knip.json', 'tsconfig.json', 'package.json', 'package-lock.json') }}-
|
|
- name: Record deep static task source and execution identity
|
|
continue-on-error: true
|
|
env:
|
|
CI_PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
|
|
CI_STATIC_CONTEXT_SCRIPT: check:ci:deep:tasks
|
|
run: npm run ci:static-context
|
|
- name: Run deep static checks
|
|
run: npm run check:ci:deep
|
|
- name: Save validated deep static task cache
|
|
if: >-
|
|
success() && steps.npm-cache.outputs.can-save == 'true' &&
|
|
steps.static-cache.outputs.cache-hit != 'true'
|
|
uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
|
|
with:
|
|
path: .turbo/cache/
|
|
key: ${{ steps.static-cache.outputs.cache-primary-key }}
|
|
- name: Save Knip analysis cache
|
|
if: >-
|
|
success() && steps.npm-cache.outputs.can-save == 'true' &&
|
|
steps.knip-cache.outputs.cache-hit != 'true'
|
|
uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
|
|
with:
|
|
path: node_modules/.cache/knip
|
|
key: ${{ steps.knip-cache.outputs.cache-primary-key }}
|
|
- name: Upload complete deep static diagnostics
|
|
if: always()
|
|
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
|
with:
|
|
name: static-deep-check-reports
|
|
path: .cache/static-checks/
|
|
include-hidden-files: true
|
|
if-no-files-found: ignore
|
|
retention-days: 7
|
|
|
|
python:
|
|
name: Python producer tests
|
|
needs: changes
|
|
if: needs.changes.outputs.python == 'true' && needs.changes.outputs.tier == 'fast'
|
|
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: Cache npm package downloads
|
|
id: npm-cache
|
|
uses: ./.github/actions/npm-cache
|
|
- run: npm ci
|
|
# Analysis-efficiency checks import compiled process modules.
|
|
- name: Reuse portable build outputs across runs
|
|
uses: ./.github/actions/portable-build-cache
|
|
- run: npm run test:prepare
|
|
- run: npm run test:python
|
|
|
|
test-source:
|
|
name: Source tests
|
|
needs: changes
|
|
if: needs.changes.outputs.code == 'true' && needs.changes.outputs.tier == 'fast'
|
|
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: Cache npm package downloads
|
|
id: npm-cache
|
|
uses: ./.github/actions/npm-cache
|
|
- run: npm ci
|
|
- name: Run source tests without waiting for build
|
|
run: npm run test:fast -- --reporter=default --reporter=blob
|
|
env:
|
|
VITEST_BLOB_LABEL: source
|
|
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
|
if: ${{ !cancelled() }}
|
|
with:
|
|
name: vitest-report-source
|
|
path: .vitest/blob/*
|
|
include-hidden-files: true
|
|
if-no-files-found: error
|
|
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:
|
|
# Failed PRs release the remaining matrix slots; qualification retains
|
|
# every shard's diagnostics and coverage. Passing PRs run the full suite.
|
|
fail-fast: ${{ github.event_name == 'pull_request' && needs.changes.outputs.tier == 'fast' }}
|
|
matrix:
|
|
# Fast feedback uses one source group and twelve built groups. Shards
|
|
# are balanced by recorded duration, but hosted runner speed varies,
|
|
# so the slowest shard sets the critical path: at eight shards it ran
|
|
# 24% above the mean shard. Smaller shards bound that excess at a few
|
|
# percent more runner time. Classification, build, and report merge
|
|
# sit outside these jobs. Full qualification retains six complete
|
|
# shards with coverage.
|
|
shard: ${{ fromJSON(needs.changes.outputs.tier == 'fast' && '["1/12","2/12","3/12","4/12","5/12","6/12","7/12","8/12","9/12","10/12","11/12","12/12"]' || '["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
|
|
- name: Cache npm package downloads
|
|
id: npm-cache
|
|
uses: ./.github/actions/npm-cache
|
|
- 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 built-dependent tests for fast feedback
|
|
if: needs.changes.outputs.tier == 'fast'
|
|
run: npm run test:built -- --reporter=default --reporter=blob --shard=${{ matrix.shard }}
|
|
env:
|
|
VITEST_BLOB_LABEL: built
|
|
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-built-${{ strategy.job-index }}
|
|
path: .vitest/blob/*
|
|
include-hidden-files: true
|
|
if-no-files-found: error
|
|
overwrite: true
|
|
retention-days: 7
|
|
|
|
reverse-tools-quality:
|
|
name: Reverse tools quality
|
|
needs: [changes, static]
|
|
if: needs.changes.outputs.reverse_tools == 'true'
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 60
|
|
steps:
|
|
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
|
|
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
|
with:
|
|
node-version-file: .nvmrc
|
|
- name: Cache npm package downloads
|
|
id: npm-cache
|
|
uses: ./.github/actions/npm-cache
|
|
- run: npm ci
|
|
- name: Run reverse tools tests with coverage
|
|
run: npm run test:coverage:reverse-tools
|
|
- name: Preflight both reverse tools mutation configurations
|
|
run: |
|
|
node scripts/prepare-reverse-tools-mutation.mjs
|
|
npx --no-install stryker run stryker.config.mjs --dryRunOnly
|
|
npx --no-install stryker run stryker.semantics.config.mjs --dryRunOnly
|
|
- name: Retain available reverse tools diagnostics
|
|
if: ${{ !cancelled() }}
|
|
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
|
with:
|
|
name: reverse-tools-quality-${{ needs.changes.outputs.tier }}-${{ github.run_attempt }}
|
|
path: |
|
|
coverage/reverse-tools/
|
|
reports/mutation/
|
|
if-no-files-found: warn
|
|
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.apk_signature == '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' ||
|
|
needs.changes.outputs.agentenv == 'true' ||
|
|
needs.changes.outputs.packet_capture == 'true' ||
|
|
needs.changes.outputs.signal_recording == '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
|
|
- name: Cache npm package downloads
|
|
id: npm-cache
|
|
uses: ./.github/actions/npm-cache
|
|
- 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
|
|
# Fast and full shards measure different file costs. Download only the
|
|
# matching history so one tier cannot pack the other with its weights.
|
|
- name: Find available trusted 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 }}
|
|
CI_TIMING_TIER: ${{ needs.changes.outputs.tier }}
|
|
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: ${{ steps.history.outputs.artifact-name }}
|
|
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.
|
|
- name: Stage current portable build task cache
|
|
shell: bash
|
|
run: |
|
|
# A new Turbo dry run can evict the entries this build just used.
|
|
node scripts/ci/portable-build-cache.mjs snapshot < .cache/ci-build-plan.json
|
|
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
|
with:
|
|
name: rea-build-cache
|
|
path: .cache/ci-build-cache/
|
|
include-hidden-files: true
|
|
if-no-files-found: error
|
|
retention-days: 7
|
|
|
|
# Compile every advertised pattern and schema from the packaged stdio
|
|
# entry with the engines and validators clients run (#10830). Runs after
|
|
# the uploads so dependent lanes keep their artifacts. Go is the runner's
|
|
# toolchain; the Python engines are pinned wheels in a cached venv.
|
|
- name: Identify the advertised schema engine interpreter
|
|
if: needs.changes.outputs.code == 'true'
|
|
id: schema-python
|
|
run: python3 -c 'import sys; print(f"version={sys.version_info[0]}.{sys.version_info[1]}")' >> "$GITHUB_OUTPUT"
|
|
- name: Restore advertised schema engines
|
|
if: needs.changes.outputs.code == 'true'
|
|
id: schema-engines
|
|
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
|
|
with:
|
|
path: ~/.cache/rea-schema-engines
|
|
key: rea-schema-engines-v1-${{ runner.os }}-${{ runner.arch }}-py${{ steps.schema-python.outputs.version }}-${{ hashFiles('scripts/verify/advertised-schemas/requirements.txt') }}
|
|
- name: Install advertised schema engines
|
|
if: needs.changes.outputs.code == 'true' && steps.schema-engines.outputs.cache-hit != 'true'
|
|
run: |
|
|
python3 -m venv ~/.cache/rea-schema-engines
|
|
~/.cache/rea-schema-engines/bin/pip install --disable-pip-version-check --no-input --require-hashes -r scripts/verify/advertised-schemas/requirements.txt
|
|
- name: Save advertised schema engines
|
|
if: needs.changes.outputs.code == 'true' && steps.schema-engines.outputs.cache-hit != 'true'
|
|
uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
|
|
with:
|
|
path: ~/.cache/rea-schema-engines
|
|
key: ${{ steps.schema-engines.outputs.cache-primary-key }}
|
|
- name: Check advertised schemas with client engines and validators
|
|
if: needs.changes.outputs.code == 'true'
|
|
env:
|
|
REA_REQUIRE_SCHEMA_ENGINES: "1"
|
|
# Full qualification adds the slower Python jsonschema check.
|
|
SCHEMA_CHECK_OPTIONS: ${{ needs.changes.outputs.tier == 'full' && '--complete' || '' }}
|
|
run: |
|
|
REA_SCHEMA_ENGINES_PYTHON="$HOME/.cache/rea-schema-engines/bin/python" \
|
|
node scripts/verify-advertised-schemas.mjs $SCHEMA_CHECK_OPTIONS
|
|
|
|
sqlite-runtime:
|
|
# Admit expensive host/provider work after fast static validation
|
|
# (typecheck, lint, format). Deep static does not gate these lanes.
|
|
# 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-source, 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
|
|
- name: Cache npm package downloads
|
|
if: needs.changes.outputs.code == 'true' && success()
|
|
id: npm-cache
|
|
uses: ./.github/actions/npm-cache
|
|
- if: needs.changes.outputs.code == 'true' && success()
|
|
run: npm ci
|
|
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
|
if: >-
|
|
!cancelled() && needs.changes.outputs.code == 'true' &&
|
|
(needs.test-shard.result == 'success' || needs.test-shard.result == 'failure' ||
|
|
(needs.changes.outputs.tier == 'fast' &&
|
|
(needs.test-source.result == 'success' || needs.test-source.result == 'failure')))
|
|
with:
|
|
path: .vitest/blob
|
|
pattern: vitest-report-*
|
|
merge-multiple: true
|
|
- name: Merge coverage, JUnit, and timing reports
|
|
id: merge
|
|
if: >-
|
|
!cancelled() && needs.changes.outputs.code == 'true' &&
|
|
needs.changes.outputs.tier == 'full' &&
|
|
(needs.test-shard.result == 'success' || needs.test-shard.result == 'failure')
|
|
run: >-
|
|
npm run test:ci:merge --
|
|
--coverage.reportsDirectory=coverage
|
|
--coverage.reporter=text
|
|
--coverage.reporter=json-summary
|
|
--coverage.reporter=lcov
|
|
--reporter=dot
|
|
--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: >-
|
|
!cancelled() && needs.changes.outputs.code == 'true' &&
|
|
needs.changes.outputs.tier == 'fast' &&
|
|
(needs.test-shard.result == 'success' || needs.test-shard.result == 'failure' ||
|
|
needs.test-source.result == 'success' || needs.test-source.result == 'failure')
|
|
run: >-
|
|
npm exec -- vitest --merge-reports
|
|
--reporter=dot
|
|
--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()
|
|
env:
|
|
SHARD_RESULT: ${{ needs.test-shard.result }}
|
|
SOURCE_REQUIRED: ${{ needs.changes.outputs.tier == 'fast' }}
|
|
SOURCE_RESULT: ${{ needs.test-source.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
|
|
# Default-branch runs only. Pull-request artifacts share this name and
|
|
# the lookup reads one page, so publishing them would hide main.
|
|
- name: Publish successful timing history
|
|
if: >-
|
|
success() &&
|
|
needs.changes.outputs.code == 'true' &&
|
|
needs.test-shard.result == 'success' &&
|
|
(
|
|
needs.changes.outputs.tier == 'full' ||
|
|
(needs.changes.outputs.tier == 'fast' && needs.test-source.result == 'success')
|
|
) &&
|
|
github.ref == format('refs/heads/{0}', github.event.repository.default_branch) &&
|
|
(github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch')
|
|
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
|
with:
|
|
name: test-timings-${{ needs.changes.outputs.tier }}
|
|
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 }}
|
|
SOURCE_REQUIRED: ${{ needs.changes.outputs.tier == 'fast' }}
|
|
SOURCE_RESULT: ${{ needs.test-source.result }}
|
|
run: |
|
|
if [ "${CODE_REQUIRED}" = "true" ]; then
|
|
test "${SHARD_RESULT}" = "success" || exit 1
|
|
test "${SOURCE_REQUIRED}" != "true" || test "${SOURCE_RESULT}" = "success"
|
|
fi
|
|
|
|
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
|
|
- name: Cache npm package downloads
|
|
id: npm-cache
|
|
uses: ./.github/actions/npm-cache
|
|
with:
|
|
# ubuntu-latest is the Linux x64 writer above. Other hosts save their own key.
|
|
save: ${{ matrix.os != 'ubuntu-latest' }}
|
|
- 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
|
|
- 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
|
|
# Passing runs take 10-15 minutes on macOS runners of varying speed, so a
|
|
# 15-minute budget cancelled about a third of runs. Keep a hang bounded.
|
|
timeout-minutes: 25
|
|
steps:
|
|
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
|
|
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
|
with:
|
|
node-version-file: .nvmrc
|
|
- name: Cache npm package downloads
|
|
id: npm-cache
|
|
uses: ./.github/actions/npm-cache
|
|
- 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: Verify portable iNES CLI, MCP and source boundaries
|
|
run: >-
|
|
npm run test:focused --
|
|
tests/acceptance/inesContainer.test.ts
|
|
tests/boundary/filesystem/inesArtifact.test.ts
|
|
tests/boundary/filesystem/inesCancellation.test.ts
|
|
- name: Run native Apple and process boundary regressions
|
|
run: >-
|
|
npm run test:focused --
|
|
tests/boundary/providers/hopper/hopperMacLaunchArguments.test.ts
|
|
tests/acceptance/providers/hopperStartupRecovery.test.ts
|
|
tests/boundary/providers/hopper/hopperClient.helperFailure.test.ts
|
|
tests/boundary/providers/hopper/bridgeBootstrapCleanup.test.ts
|
|
tests/boundary/providers/hopper/bridgeTargetLease.integration.test.ts
|
|
tests/boundary/cli/hopperLaunchFailureCli.test.ts
|
|
tests/acceptance/artifactDmgAttachmentRecoveryCli.test.ts
|
|
tests/boundary/providers/native/nativeDmgArtifactReader.test.ts
|
|
tests/process-global/dmgCancellationReason.test.ts
|
|
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/cli/nativeDispatchPropertyAttributes.test.ts
|
|
tests/boundary/mcp/nativeDemangleMcp.test.ts
|
|
tests/boundary/mcp/nativeMachoSummaryMcp.test.ts
|
|
tests/boundary/providers/native/nativeSignatureTargetBinding.test.ts
|
|
tests/boundary/providers/native/nativeUiOffscreenWindow.test.ts
|
|
tests/boundary/process/nativeUiVerifierLane.test.ts
|
|
tests/boundary/cli/nativeSignatureCli.test.ts
|
|
tests/boundary/cli/nativeMachoImportNamesCli.test.ts
|
|
tests/boundary/cli/nativeMachoArm64_32Cli.test.ts
|
|
tests/boundary/cli/nativeMachoEncryptionCli.test.ts
|
|
tests/boundary/mcp/nativeSignatureTargetBindingMcp.test.ts
|
|
src/process/capture/FilesystemSnapshot.test.ts
|
|
tests/process-global/filesystemSnapshotFallbackCancellation.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
|
|
- name: Cache npm package downloads
|
|
id: npm-cache
|
|
uses: ./.github/actions/npm-cache
|
|
- run: npm ci
|
|
- name: Verify static CLI/MCP journeys and synthetic report conformance
|
|
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
|
|
- name: Cache npm package downloads
|
|
id: npm-cache
|
|
uses: ./.github/actions/npm-cache
|
|
with:
|
|
save: "true"
|
|
- run: npm ci
|
|
- name: Typecheck with the official Windows compiler
|
|
env:
|
|
GOMAXPROCS: "2"
|
|
GOMEMLIMIT: "3GiB"
|
|
run: npm run typecheck -- --checkers 2
|
|
- 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
|
|
- run: npm run build:cached
|
|
- 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.
|
|
# Run native proofs before the broad curated suite so an unrelated
|
|
# fixture failure cannot hide the real control and recovery checks.
|
|
- 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: Run curated Windows capability tests
|
|
run: >-
|
|
npx vitest run --coverage.enabled=false
|
|
src/process/capture/FilesystemSnapshot.test.ts
|
|
tests/process-global/filesystemSnapshotFallbackCancellation.test.ts
|
|
tests/boundary/filesystem/typescriptCompiler.test.ts
|
|
tests/boundary/filesystem/releaseProposal.test.ts
|
|
tests/acceptance/byteEntropyWindowsIdentity.test.ts
|
|
tests/boundary/filesystem/binaryTarget.test.ts
|
|
src/contracts/sessionPathInputs.test.ts
|
|
tests/boundary/filesystem/directAnalysisSnapshotReplay.test.ts
|
|
tests/boundary/mcp/rawBinaryMcp.test.ts
|
|
tests/boundary/mcp/advertisedDialect.test.ts
|
|
tests/boundary/mcp/absoluteLocalPathSchema.test.ts
|
|
tests/boundary/mcp/toolSchemaValidity.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/boundary/filesystem/claudeDesktopSkillUninstallWindows.test.ts
|
|
tests/boundary/filesystem/clientConfigurationEnvironment.test.ts
|
|
tests/boundary/filesystem/clientConfigurationLayeredEnvironment.test.ts
|
|
tests/acceptance/setup/registrationRuntimeEnvironmentCli.test.ts
|
|
tests/boundary/android/workspaceGuardianRetry.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/boundary/process/packageNpmInvocation.test.ts
|
|
tests/boundary/process/packedBridgeVerification.test.ts
|
|
tests/boundary/process/windowsOutputCapture.test.ts
|
|
tests/boundary/process/windowsExecutableSelection.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/process-global/runnerCancellation.test.ts
|
|
tests/process-global/windowsOwnedCommand.test.ts
|
|
tests/conformance/providers/ghidra/realGhidraWindowsWorkflow.test.ts
|
|
- 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.23.4
|
|
- 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: Documentation
|
|
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
|
|
- name: Cache npm package downloads
|
|
id: npm-cache
|
|
uses: ./.github/actions/npm-cache
|
|
- run: npm ci
|
|
- run: npm run docs:check
|
|
- name: Verify published routes, source links and local anchors
|
|
run: npm run verify:docs:routes
|
|
- 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
|
|
|
|
# Provider lanes wait for fast static and the portable build, not deep static.
|
|
browser:
|
|
needs: [changes, static, build]
|
|
if: needs.changes.outputs.browser == 'true'
|
|
secrets:
|
|
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
|
uses: ./.github/workflows/real-browser.yml
|
|
with:
|
|
build_cache_artifact: rea-build-cache
|
|
remote_cache_write: ${{ inputs.remote_cache_write == true || (github.ref == format('refs/heads/{0}', github.event.repository.default_branch) && (github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch')) }}
|
|
|
|
binary_layout:
|
|
needs: [changes, static, build]
|
|
if: needs.changes.outputs.binary_layout == 'true'
|
|
secrets:
|
|
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
|
uses: ./.github/workflows/real-binary-layout.yml
|
|
with:
|
|
build_cache_artifact: rea-build-cache
|
|
remote_cache_write: ${{ inputs.remote_cache_write == true || (github.ref == format('refs/heads/{0}', github.event.repository.default_branch) && (github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch')) }}
|
|
|
|
evm:
|
|
needs: [changes, static, build]
|
|
if: needs.changes.outputs.evm == 'true'
|
|
secrets:
|
|
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
|
uses: ./.github/workflows/real-evm-interface.yml
|
|
with:
|
|
build_cache_artifact: rea-build-cache
|
|
remote_cache_write: ${{ inputs.remote_cache_write == true || (github.ref == format('refs/heads/{0}', github.event.repository.default_branch) && (github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch')) }}
|
|
|
|
apk_signature:
|
|
needs: [changes, static, build]
|
|
if: needs.changes.outputs.apk_signature == 'true'
|
|
secrets:
|
|
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
|
uses: ./.github/workflows/real-apk-signature.yml
|
|
with:
|
|
build_cache_artifact: rea-build-cache
|
|
remote_cache_write: ${{ inputs.remote_cache_write == true || (github.ref == format('refs/heads/{0}', github.event.repository.default_branch) && (github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch')) }}
|
|
|
|
javascript_recovery:
|
|
needs: [changes, static, build]
|
|
if: needs.changes.outputs.javascript_recovery == 'true'
|
|
secrets:
|
|
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
|
uses: ./.github/workflows/real-javascript-recovery.yml
|
|
with:
|
|
build_cache_artifact: rea-build-cache
|
|
remote_cache_write: ${{ inputs.remote_cache_write == true || (github.ref == format('refs/heads/{0}', github.event.repository.default_branch) && (github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch')) }}
|
|
|
|
recorded_crash:
|
|
needs: [changes, static, build]
|
|
if: needs.changes.outputs.recorded_crash == 'true'
|
|
secrets:
|
|
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
|
uses: ./.github/workflows/real-recorded-crash.yml
|
|
with:
|
|
build_cache_artifact: rea-build-cache
|
|
remote_cache_write: ${{ inputs.remote_cache_write == true || (github.ref == format('refs/heads/{0}', github.event.repository.default_branch) && (github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch')) }}
|
|
|
|
web_network:
|
|
needs: [changes, static, build]
|
|
if: needs.changes.outputs.web_network == 'true'
|
|
secrets:
|
|
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
|
uses: ./.github/workflows/real-web-network-captures.yml
|
|
with:
|
|
build_cache_artifact: rea-build-cache
|
|
remote_cache_write: ${{ inputs.remote_cache_write == true || (github.ref == format('refs/heads/{0}', github.event.repository.default_branch) && (github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch')) }}
|
|
|
|
web_runtime:
|
|
needs: [changes, static, build]
|
|
if: needs.changes.outputs.web_runtime == 'true'
|
|
secrets:
|
|
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
|
uses: ./.github/workflows/real-web-runtime.yml
|
|
with:
|
|
build_cache_artifact: rea-build-cache
|
|
remote_cache_write: ${{ inputs.remote_cache_write == true || (github.ref == format('refs/heads/{0}', github.event.repository.default_branch) && (github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch')) }}
|
|
|
|
web_source_map:
|
|
needs: [changes, static, build]
|
|
if: needs.changes.outputs.web_source_map == 'true'
|
|
secrets:
|
|
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
|
uses: ./.github/workflows/real-web-source-map.yml
|
|
with:
|
|
build_cache_artifact: rea-build-cache
|
|
remote_cache_write: ${{ inputs.remote_cache_write == true || (github.ref == format('refs/heads/{0}', github.event.repository.default_branch) && (github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch')) }}
|
|
|
|
agentenv:
|
|
needs: [changes, static, build]
|
|
if: needs.changes.outputs.agentenv == 'true'
|
|
secrets:
|
|
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
|
uses: ./.github/workflows/real-agentenv.yml
|
|
with:
|
|
build_cache_artifact: rea-build-cache
|
|
remote_cache_write: ${{ inputs.remote_cache_write == true || (github.ref == format('refs/heads/{0}', github.event.repository.default_branch) && (github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch')) }}
|
|
|
|
packet_capture:
|
|
needs: [changes, static, build]
|
|
if: needs.changes.outputs.packet_capture == 'true'
|
|
secrets:
|
|
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
|
uses: ./.github/workflows/real-packet-capture.yml
|
|
with:
|
|
build_cache_artifact: rea-build-cache
|
|
remote_cache_write: ${{ inputs.remote_cache_write == true || (github.ref == format('refs/heads/{0}', github.event.repository.default_branch) && (github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch')) }}
|
|
|
|
signal_recording:
|
|
needs: [changes, static, build]
|
|
if: needs.changes.outputs.signal_recording == 'true'
|
|
secrets:
|
|
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
|
uses: ./.github/workflows/real-signal-recording.yml
|
|
with:
|
|
build_cache_artifact: rea-build-cache
|
|
remote_cache_write: ${{ inputs.remote_cache_write == true || (github.ref == format('refs/heads/{0}', github.event.repository.default_branch) && (github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch')) }}
|
|
|
|
nativeaot:
|
|
needs: [changes, static]
|
|
if: needs.changes.outputs.nativeaot == 'true'
|
|
uses: ./.github/workflows/nativeaot-fixtures.yml
|
|
|
|
ghidra_bridge:
|
|
needs: [changes, static]
|
|
if: needs.changes.outputs.ghidra_bridge == 'true'
|
|
uses: ./.github/workflows/ghidra-bridge-sources.yml
|
|
|
|
website:
|
|
needs: [changes, static]
|
|
if: needs.changes.outputs.website == 'true'
|
|
uses: ./.github/workflows/website-check.yml
|
|
|
|
required:
|
|
name: CI required
|
|
# Report failed dependencies, but release superseded PR concurrency slots.
|
|
if: ${{ !cancelled() }}
|
|
needs:
|
|
[
|
|
changes,
|
|
static,
|
|
static-deep,
|
|
build,
|
|
reverse-tools-quality,
|
|
python,
|
|
packet_capture,
|
|
signal_recording,
|
|
test-shard,
|
|
test-source,
|
|
sqlite-runtime,
|
|
test,
|
|
conformance-fixtures,
|
|
windows-native-build,
|
|
package-e2e,
|
|
apple-artifacts,
|
|
reconstruction-readiness,
|
|
windows-curated,
|
|
docs,
|
|
browser,
|
|
binary_layout,
|
|
evm,
|
|
apk_signature,
|
|
javascript_recovery,
|
|
recorded_crash,
|
|
web_network,
|
|
web_runtime,
|
|
web_source_map,
|
|
agentenv,
|
|
nativeaot,
|
|
ghidra_bridge,
|
|
website,
|
|
]
|
|
runs-on: ubuntu-24.04
|
|
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
|