mirror of
https://github.com/morluto/rea.git
synced 2026-10-26 17:35:11 +00:00
ci: scope provider and native verification by changed inputs (#1660)
This commit is contained in:
1 parent
28bd0d990a
commit
66c344e289
18 files changed
+967
-354
No files matched your search
@@ -0,0 +1,6 @@
|
|||||||
|
self-hosted-runner:
|
||||||
|
labels:
|
||||||
|
- hopper
|
||||||
|
- ghidra-12-1-2
|
||||||
|
# Hosted label introduced after the pinned actionlint release.
|
||||||
|
- macos-15-intel
|
||||||
+145
-50
@@ -5,6 +5,10 @@ on:
|
|||||||
branches: [main]
|
branches: [main]
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [main, "release/*"]
|
branches: [main, "release/*"]
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: ci-${{ github.event.pull_request.number || github.ref }}
|
group: ci-${{ github.event.pull_request.number || github.ref }}
|
||||||
@@ -36,37 +40,39 @@ jobs:
|
|||||||
name: Classify changes
|
name: Classify changes
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
outputs:
|
outputs:
|
||||||
code: ${{ steps.package.outputs.required }}
|
code: ${{ steps.plan.outputs.code }}
|
||||||
package: ${{ steps.package.outputs.required }}
|
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 }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- name: Select package and Windows lanes
|
- uses: actions/setup-node@v4
|
||||||
id: package
|
with:
|
||||||
shell: bash
|
node-version-file: .nvmrc
|
||||||
|
- name: Select verification lanes
|
||||||
|
id: plan
|
||||||
env:
|
env:
|
||||||
BASE_SHA: ${{ github.event.pull_request.base.sha }}
|
BASE_SHA: ${{ github.event.pull_request.base.sha }}
|
||||||
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
|
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
|
||||||
run: |
|
CI_FULL: ${{ contains(github.event.pull_request.labels.*.name, 'ci:full') }}
|
||||||
if [[ "${GITHUB_EVENT_NAME}" != "pull_request" ]]; then
|
run: node scripts/ci/plan.mjs
|
||||||
echo "required=true" >> "${GITHUB_OUTPUT}"
|
|
||||||
# Compare the PR's changes, excluding unrelated updates on its base.
|
|
||||||
elif git diff --quiet "${BASE_SHA}...${HEAD_SHA}" -- \
|
|
||||||
. \
|
|
||||||
':(exclude)docs/**' \
|
|
||||||
':(top,exclude,glob)README*.md' \
|
|
||||||
':(exclude)AGENTS.md' \
|
|
||||||
':(exclude)CONTRIBUTING.md'; then
|
|
||||||
echo "required=false" >> "${GITHUB_OUTPUT}"
|
|
||||||
else
|
|
||||||
diff_status=$?
|
|
||||||
# A failed comparison must fail classification, not report a scope.
|
|
||||||
if [[ "${diff_status}" -ne 1 ]]; then
|
|
||||||
exit "${diff_status}"
|
|
||||||
fi
|
|
||||||
echo "required=true" >> "${GITHUB_OUTPUT}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
static:
|
static:
|
||||||
name: Static checks
|
name: Static checks
|
||||||
@@ -84,17 +90,17 @@ jobs:
|
|||||||
node-version-file: .nvmrc
|
node-version-file: .nvmrc
|
||||||
cache: npm
|
cache: npm
|
||||||
- run: npm ci
|
- run: npm ci
|
||||||
- if: github.event_name == 'push' || needs.changes.outputs.code == 'true'
|
- if: needs.changes.outputs.code == 'true'
|
||||||
run: npm run check:ci
|
run: npm run check:ci
|
||||||
- if: github.event_name == 'push' || needs.changes.outputs.code == 'true'
|
- if: needs.changes.outputs.code == 'true'
|
||||||
run: npm run verify:test-discovery
|
run: npm run verify:test-discovery
|
||||||
- if: github.event_name == 'pull_request' && needs.changes.outputs.code != 'true'
|
- if: needs.changes.outputs.code != 'true'
|
||||||
run: npm run format:check
|
run: npm run format:check
|
||||||
|
|
||||||
test-shard:
|
test-shard:
|
||||||
name: Test shard (${{ matrix.shard }})
|
name: Test shard (${{ matrix.shard }})
|
||||||
needs: [changes, build]
|
needs: [changes, build]
|
||||||
if: github.event_name == 'push' || needs.changes.outputs.code == 'true'
|
if: needs.changes.outputs.code == 'true'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
@@ -131,7 +137,7 @@ jobs:
|
|||||||
build:
|
build:
|
||||||
name: Build package
|
name: Build package
|
||||||
needs: changes
|
needs: changes
|
||||||
if: github.event_name == 'push' || needs.changes.outputs.code == 'true'
|
if: needs.changes.outputs.code == 'true'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
@@ -224,7 +230,7 @@ jobs:
|
|||||||
conformance-fixtures:
|
conformance-fixtures:
|
||||||
name: Source-built conformance fixtures
|
name: Source-built conformance fixtures
|
||||||
needs: changes
|
needs: changes
|
||||||
if: github.event_name == 'push' || needs.changes.outputs.code == 'true'
|
if: needs.changes.outputs.fixtures == 'true'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
steps:
|
steps:
|
||||||
@@ -235,7 +241,7 @@ jobs:
|
|||||||
windows-native-build:
|
windows-native-build:
|
||||||
name: Build bundled Windows x64 native controls
|
name: Build bundled Windows x64 native controls
|
||||||
needs: changes
|
needs: changes
|
||||||
if: github.event_name == 'push' || needs.changes.outputs.package == 'true'
|
if: needs.changes.outputs.runtime == 'true'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
steps:
|
steps:
|
||||||
@@ -265,24 +271,11 @@ jobs:
|
|||||||
package-e2e:
|
package-e2e:
|
||||||
name: Native package baseline (${{ matrix.platform }} ${{ matrix.architecture }})
|
name: Native package baseline (${{ matrix.platform }} ${{ matrix.architecture }})
|
||||||
needs: [changes, windows-native-build]
|
needs: [changes, windows-native-build]
|
||||||
if: github.event_name == 'push' || needs.changes.outputs.package == 'true'
|
if: needs.changes.outputs.runtime == 'true'
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
max-parallel: 2
|
max-parallel: 2
|
||||||
matrix:
|
matrix: ${{ fromJSON(needs.changes.outputs.matrix) }}
|
||||||
include:
|
|
||||||
- os: ubuntu-latest
|
|
||||||
platform: linux
|
|
||||||
architecture: x64
|
|
||||||
- os: ubuntu-24.04-arm
|
|
||||||
platform: linux
|
|
||||||
architecture: arm64
|
|
||||||
- os: macos-15
|
|
||||||
platform: darwin
|
|
||||||
architecture: arm64
|
|
||||||
- os: macos-15-intel
|
|
||||||
platform: darwin
|
|
||||||
architecture: x64
|
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
timeout-minutes: 20
|
timeout-minutes: 20
|
||||||
env:
|
env:
|
||||||
@@ -317,7 +310,7 @@ jobs:
|
|||||||
apple-artifacts:
|
apple-artifacts:
|
||||||
name: Real Apple artifact CLI/MCP E2E
|
name: Real Apple artifact CLI/MCP E2E
|
||||||
needs: changes
|
needs: changes
|
||||||
if: github.event_name == 'push' || needs.changes.outputs.code == 'true'
|
if: needs.changes.outputs.apple == 'true'
|
||||||
runs-on: macos-15
|
runs-on: macos-15
|
||||||
timeout-minutes: 15
|
timeout-minutes: 15
|
||||||
steps:
|
steps:
|
||||||
@@ -350,7 +343,7 @@ jobs:
|
|||||||
reconstruction-readiness:
|
reconstruction-readiness:
|
||||||
name: Reconstruction readiness
|
name: Reconstruction readiness
|
||||||
needs: changes
|
needs: changes
|
||||||
if: github.event_name == 'push' || needs.changes.outputs.code == 'true'
|
if: needs.changes.outputs.readiness == 'true'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
timeout-minutes: 15
|
timeout-minutes: 15
|
||||||
steps:
|
steps:
|
||||||
@@ -379,7 +372,7 @@ jobs:
|
|||||||
windows-curated:
|
windows-curated:
|
||||||
name: Windows capability and package lane
|
name: Windows capability and package lane
|
||||||
needs: [changes, windows-native-build]
|
needs: [changes, windows-native-build]
|
||||||
if: github.event_name == 'push' || needs.changes.outputs.package == 'true'
|
if: needs.changes.outputs.package == 'true'
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
timeout-minutes: 25
|
timeout-minutes: 25
|
||||||
steps:
|
steps:
|
||||||
@@ -476,7 +469,8 @@ jobs:
|
|||||||
|
|
||||||
docs:
|
docs:
|
||||||
name: Docs Generation
|
name: Docs Generation
|
||||||
if: github.event_name == 'pull_request'
|
needs: changes
|
||||||
|
if: needs.changes.outputs.docs == 'true'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
@@ -496,3 +490,104 @@ jobs:
|
|||||||
docs/verification/managed-conformance-*.json
|
docs/verification/managed-conformance-*.json
|
||||||
skills/reverse-engineer-anything
|
skills/reverse-engineer-anything
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
|
|
||||||
|
workflows:
|
||||||
|
name: Validate workflows
|
||||||
|
needs: changes
|
||||||
|
if: needs.changes.outputs.workflows == 'true'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Validate workflow syntax and expressions
|
||||||
|
run: go run github.com/rhysd/actionlint/cmd/actionlint@v1.7.7 -shellcheck= -pyflakes=
|
||||||
|
|
||||||
|
browser:
|
||||||
|
needs: changes
|
||||||
|
if: needs.changes.outputs.browser == 'true'
|
||||||
|
uses: ./.github/workflows/real-browser.yml
|
||||||
|
|
||||||
|
binary_layout:
|
||||||
|
needs: changes
|
||||||
|
if: needs.changes.outputs.binary_layout == 'true'
|
||||||
|
uses: ./.github/workflows/real-binary-layout.yml
|
||||||
|
|
||||||
|
evm:
|
||||||
|
needs: changes
|
||||||
|
if: needs.changes.outputs.evm == 'true'
|
||||||
|
uses: ./.github/workflows/real-evm-interface.yml
|
||||||
|
|
||||||
|
javascript_recovery:
|
||||||
|
needs: changes
|
||||||
|
if: needs.changes.outputs.javascript_recovery == 'true'
|
||||||
|
uses: ./.github/workflows/real-javascript-recovery.yml
|
||||||
|
|
||||||
|
recorded_crash:
|
||||||
|
needs: changes
|
||||||
|
if: needs.changes.outputs.recorded_crash == 'true'
|
||||||
|
uses: ./.github/workflows/real-recorded-crash.yml
|
||||||
|
|
||||||
|
web_network:
|
||||||
|
needs: changes
|
||||||
|
if: needs.changes.outputs.web_network == 'true'
|
||||||
|
uses: ./.github/workflows/real-web-network-captures.yml
|
||||||
|
|
||||||
|
web_runtime:
|
||||||
|
needs: changes
|
||||||
|
if: needs.changes.outputs.web_runtime == 'true'
|
||||||
|
uses: ./.github/workflows/real-web-runtime.yml
|
||||||
|
|
||||||
|
web_source_map:
|
||||||
|
needs: changes
|
||||||
|
if: needs.changes.outputs.web_source_map == 'true'
|
||||||
|
uses: ./.github/workflows/real-web-source-map.yml
|
||||||
|
|
||||||
|
nativeaot:
|
||||||
|
needs: changes
|
||||||
|
if: needs.changes.outputs.nativeaot == 'true'
|
||||||
|
uses: ./.github/workflows/nativeaot-fixtures.yml
|
||||||
|
|
||||||
|
website:
|
||||||
|
needs: changes
|
||||||
|
if: needs.changes.outputs.website == 'true'
|
||||||
|
uses: ./.github/workflows/website-check.yml
|
||||||
|
|
||||||
|
required:
|
||||||
|
name: CI required
|
||||||
|
if: ${{ always() }}
|
||||||
|
needs:
|
||||||
|
[
|
||||||
|
changes,
|
||||||
|
pr-title,
|
||||||
|
static,
|
||||||
|
build,
|
||||||
|
test-shard,
|
||||||
|
test,
|
||||||
|
conformance-fixtures,
|
||||||
|
windows-native-build,
|
||||||
|
package-e2e,
|
||||||
|
apple-artifacts,
|
||||||
|
reconstruction-readiness,
|
||||||
|
windows-curated,
|
||||||
|
docs,
|
||||||
|
workflows,
|
||||||
|
browser,
|
||||||
|
binary_layout,
|
||||||
|
evm,
|
||||||
|
javascript_recovery,
|
||||||
|
recorded_crash,
|
||||||
|
web_network,
|
||||||
|
web_runtime,
|
||||||
|
web_source_map,
|
||||||
|
nativeaot,
|
||||||
|
website,
|
||||||
|
]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version-file: .nvmrc
|
||||||
|
- name: Require every selected lane to pass
|
||||||
|
env:
|
||||||
|
CI_JOBS: ${{ toJSON(needs) }}
|
||||||
|
run: node scripts/ci/required.mjs
|
||||||
@@ -2,12 +2,7 @@ name: Source-built NativeAOT fixtures
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
pull_request:
|
workflow_call:
|
||||||
paths:
|
|
||||||
- "bridge/ghidra/extensions/nativeaot/**"
|
|
||||||
- "scripts/generate-nativeaot-fixtures.mjs"
|
|
||||||
- "tests/fixtures/nativeaot/**"
|
|
||||||
- ".github/workflows/nativeaot-fixtures.yml"
|
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
|
|||||||
@@ -7,36 +7,7 @@ on:
|
|||||||
description: "Also verify the complete 65,281-section result over MCP (slow)"
|
description: "Also verify the complete 65,281-section result over MCP (slow)"
|
||||||
type: boolean
|
type: boolean
|
||||||
default: false
|
default: false
|
||||||
pull_request:
|
workflow_call:
|
||||||
paths:
|
|
||||||
- ".github/workflows/real-binary-layout.yml"
|
|
||||||
- "bridge/pwntools/**"
|
|
||||||
- "src/native/pwntools/**"
|
|
||||||
- "src/domain/native/binaryLayout*"
|
|
||||||
- "src/application/binaryDiagnostics/**"
|
|
||||||
- "src/contracts/native/binaryDiagnosticsToolContracts.ts"
|
|
||||||
- "src/composition/binaryDiagnostics.ts"
|
|
||||||
- "src/server/registerBinaryDiagnosticsTools.ts"
|
|
||||||
- "src/server/createServer.ts"
|
|
||||||
- "src/cli/binaryDiagnosticsCommands.ts"
|
|
||||||
- "src/cli.ts"
|
|
||||||
- "src/cliCommandNames.ts"
|
|
||||||
- "src/contracts/toolContracts.ts"
|
|
||||||
- "src/contracts/toolEffects.ts"
|
|
||||||
- "src/process/OwnedCommand.ts"
|
|
||||||
- "src/process/ProviderProcess.ts"
|
|
||||||
- "src/process/ProviderDeadline.ts"
|
|
||||||
- "src/process/ProcessOwnership*.ts"
|
|
||||||
- "src/process/PrivateRuntimeRoot.ts"
|
|
||||||
- "src/artifacts/readStableArtifact*.ts"
|
|
||||||
- "src/artifacts/ArtifactReader.ts"
|
|
||||||
- "src/domain/analysisError*.ts"
|
|
||||||
- "scripts/verify-binary-layout.mjs"
|
|
||||||
- "scripts/lib/elf-section-name-fixtures.mjs"
|
|
||||||
- "scripts/lib/large-result-mcp.mjs"
|
|
||||||
- "scripts/fixtures/binary-layout*"
|
|
||||||
- "package.json"
|
|
||||||
- "package-lock.json"
|
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
|
|||||||
@@ -1,40 +1,7 @@
|
|||||||
name: Real browser verification
|
name: Real browser verification
|
||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
workflow_call:
|
||||||
paths:
|
|
||||||
- ".github/workflows/real-browser.yml"
|
|
||||||
- "scripts/verify-real-browser.mjs"
|
|
||||||
- "scripts/verify-browser-network.mjs"
|
|
||||||
- "scripts/verify-browser-scripts.mjs"
|
|
||||||
- "scripts/verify-browser-modules.mjs"
|
|
||||||
- "scripts/verify-browser-dom-destinations.mjs"
|
|
||||||
- "scripts/lib/browser-*.mjs"
|
|
||||||
- "scripts/fixtures/browser-network-site.mjs"
|
|
||||||
- "scripts/fixtures/browser-script-site.mjs"
|
|
||||||
- "scripts/fixtures/browser-module-site.mjs"
|
|
||||||
- "scripts/fixtures/browser-verifier-site.mjs"
|
|
||||||
- "scripts/fixtures/page-cdp-proxy.mjs"
|
|
||||||
- "src/browser/**"
|
|
||||||
- "src/domain/browser*.ts"
|
|
||||||
- "src/domain/webScript*.ts"
|
|
||||||
- "src/domain/webModule*.ts"
|
|
||||||
- "src/application/WebModule*.ts"
|
|
||||||
- "src/composition/webModules.ts"
|
|
||||||
- "src/artifacts/readStableArtifact.ts"
|
|
||||||
- "src/artifacts/ArtifactPaths.ts"
|
|
||||||
- "src/application/WebScriptExportService.ts"
|
|
||||||
- "src/contracts/webScriptToolContracts.ts"
|
|
||||||
- "src/server/registerWebScriptTool.ts"
|
|
||||||
- "src/server/registerWebModuleTool.ts"
|
|
||||||
- "src/server/createServer.ts"
|
|
||||||
- "src/cli/webModuleCommands.ts"
|
|
||||||
- "src/cli.ts"
|
|
||||||
- "src/cliCommandNames.ts"
|
|
||||||
- "src/contracts/toolEffects.ts"
|
|
||||||
- "src/cli/webScriptCommands.ts"
|
|
||||||
- "package.json"
|
|
||||||
- "package-lock.json"
|
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
|
|||||||
@@ -2,33 +2,7 @@ name: Real offline EVM interface
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
pull_request:
|
workflow_call:
|
||||||
paths:
|
|
||||||
- ".github/workflows/real-evm-interface.yml"
|
|
||||||
- "src/evm/**"
|
|
||||||
- "src/domain/evm/**"
|
|
||||||
- "src/application/evm/**"
|
|
||||||
- "src/contracts/evm/**"
|
|
||||||
- "src/composition/evm.ts"
|
|
||||||
- "src/cli/evmCommands.ts"
|
|
||||||
- "src/server/registerEvmTools.ts"
|
|
||||||
- "src/server/createServer.ts"
|
|
||||||
- "src/cli.ts"
|
|
||||||
- "src/cliCommandNames.ts"
|
|
||||||
- "src/contracts/toolContracts.ts"
|
|
||||||
- "src/contracts/toolEffects.ts"
|
|
||||||
- "src/process/OwnedCommand.ts"
|
|
||||||
- "src/process/ProviderProcess.ts"
|
|
||||||
- "src/process/ProcessOwnership*.ts"
|
|
||||||
- "src/process/ProviderDeadline.ts"
|
|
||||||
- "src/process/PrivateRuntimeRoot.ts"
|
|
||||||
- "src/artifacts/readStableArtifact*.ts"
|
|
||||||
- "src/artifacts/ArtifactReader.ts"
|
|
||||||
- "scripts/verify-evm-interface.mjs"
|
|
||||||
- "scripts/fixtures/evm-interface.sol"
|
|
||||||
- "third_party/evmole/**"
|
|
||||||
- "package.json"
|
|
||||||
- "package-lock.json"
|
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
|
|||||||
@@ -1,32 +1,7 @@
|
|||||||
name: Real JavaScript recovery
|
name: Real JavaScript recovery
|
||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
workflow_call:
|
||||||
paths:
|
|
||||||
- ".github/workflows/real-javascript-recovery.yml"
|
|
||||||
- "src/javascript/recovery/**"
|
|
||||||
- "src/domain/javascript/**"
|
|
||||||
- "src/application/javascript/JavaScriptRecovery*.ts"
|
|
||||||
- "src/composition/javascriptRecovery.ts"
|
|
||||||
- "src/contracts/javascript/javascriptRecoveryToolContracts.ts"
|
|
||||||
- "src/cli/javascriptRecoveryCommands.ts"
|
|
||||||
- "src/cli/javascriptApplicationAnalysis.ts"
|
|
||||||
- "src/server/registerJavaScriptRecoveryTool.ts"
|
|
||||||
- "src/server/createServer.ts"
|
|
||||||
- "src/server/sessionAvailabilityPolicy.ts"
|
|
||||||
- "src/application/CapabilityInventory.ts"
|
|
||||||
- "src/cli.ts"
|
|
||||||
- "src/cliCommandNames.ts"
|
|
||||||
- "src/contracts/toolContracts.ts"
|
|
||||||
- "src/contracts/toolEffects.ts"
|
|
||||||
- "scripts/rea.mjs"
|
|
||||||
- "src/process/**"
|
|
||||||
- "src/artifacts/SafeOutputTree.ts"
|
|
||||||
- "scripts/verify/javascript/recovery.mjs"
|
|
||||||
- "scripts/fixtures/javascript-recovery/**"
|
|
||||||
- "third_party/wakaru"
|
|
||||||
- "package.json"
|
|
||||||
- "package-lock.json"
|
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
|
|||||||
@@ -2,34 +2,7 @@ name: Real recorded crash evidence
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
pull_request:
|
workflow_call:
|
||||||
paths:
|
|
||||||
- ".github/workflows/real-recorded-crash.yml"
|
|
||||||
- "bridge/pwntools/**"
|
|
||||||
- "bridge/pwndbg/**"
|
|
||||||
- "src/native/pwntools/**"
|
|
||||||
- "src/native/pwndbg/**"
|
|
||||||
- "src/domain/native/recordedCrash*"
|
|
||||||
- "src/application/binaryDiagnostics/**"
|
|
||||||
- "src/contracts/native/binaryDiagnosticsToolContracts.ts"
|
|
||||||
- "src/contracts/toolEffects.ts"
|
|
||||||
- "src/contracts/toolOutputSchemaGroups.ts"
|
|
||||||
- "src/composition/binaryDiagnostics.ts"
|
|
||||||
- "src/server/registerRecordedCrashTools.ts"
|
|
||||||
- "src/server/createServer.ts"
|
|
||||||
- "src/server/sessionAvailabilityPolicy.ts"
|
|
||||||
- "src/cli/binaryDiagnosticsCommands.ts"
|
|
||||||
- "src/cliCommandNames.ts"
|
|
||||||
- "src/process/**"
|
|
||||||
- "src/artifacts/readStableArtifact*.ts"
|
|
||||||
- "src/domain/analysisError*.ts"
|
|
||||||
- "scripts/verify-recorded-crash.mjs"
|
|
||||||
- "scripts/verify/recorded-crash/**"
|
|
||||||
- "scripts/lib/recorded-core-fixtures.py"
|
|
||||||
- "scripts/fixtures/recorded-crash.c"
|
|
||||||
- "third_party/pwndbg/**"
|
|
||||||
- "package.json"
|
|
||||||
- "package-lock.json"
|
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
|
|||||||
@@ -2,38 +2,7 @@ name: Real historical web network captures
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
pull_request:
|
workflow_call:
|
||||||
paths:
|
|
||||||
- ".github/workflows/real-web-network-captures.yml"
|
|
||||||
- "bridge/mitmproxy/**"
|
|
||||||
- "src/browser/history/**"
|
|
||||||
- "src/domain/webNetworkCapture*.ts"
|
|
||||||
- "src/domain/analysisError*.ts"
|
|
||||||
- "src/contracts/errorSchemas.ts"
|
|
||||||
- "src/domain/explicitSensitive*.ts"
|
|
||||||
- "src/application/WebNetworkCapture*"
|
|
||||||
- "src/composition/webNetworkCaptures.ts"
|
|
||||||
- "src/cli/webNetworkCaptureCommands.ts"
|
|
||||||
- "src/server/registerWebNetworkCaptureTool.ts"
|
|
||||||
- "src/server/createServer.ts"
|
|
||||||
- "src/server/toolRegistrationOptions.ts"
|
|
||||||
- "src/cli.ts"
|
|
||||||
- "src/cliCommandNames.ts"
|
|
||||||
- "src/contracts/toolContracts.ts"
|
|
||||||
- "src/contracts/toolEffects.ts"
|
|
||||||
- "src/process/OwnedCommand.ts"
|
|
||||||
- "src/process/ProviderProcess.ts"
|
|
||||||
- "src/process/ProviderDeadline.ts"
|
|
||||||
- "src/process/ProcessOwnership*.ts"
|
|
||||||
- "src/process/PrivateRuntimeRoot.ts"
|
|
||||||
- "src/process/capture/ProcessCaptureLifecycle.ts"
|
|
||||||
- "src/artifacts/readStableArtifact*.ts"
|
|
||||||
- "src/artifacts/ArtifactReader.ts"
|
|
||||||
- "src/contracts/webNetworkCaptureToolContracts.ts"
|
|
||||||
- "scripts/verify-web-network-captures.mjs"
|
|
||||||
- "scripts/fixtures/generate-mitmproxy-capture.py"
|
|
||||||
- "package.json"
|
|
||||||
- "package-lock.json"
|
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
|
|||||||
@@ -1,34 +1,6 @@
|
|||||||
name: Real website runtime attribution
|
name: Real website runtime attribution
|
||||||
on:
|
on:
|
||||||
pull_request:
|
workflow_call:
|
||||||
paths:
|
|
||||||
- ".github/workflows/real-web-runtime.yml"
|
|
||||||
- "scripts/verify-browser-runtime.mjs"
|
|
||||||
- "scripts/lib/browser-runtime-*.mjs"
|
|
||||||
- "src/process/ProviderProcess.ts"
|
|
||||||
- "src/process/ProcessOwnership*.ts"
|
|
||||||
- "scripts/fixtures/browser-runtime-site.mjs"
|
|
||||||
- "src/browser/execution/**"
|
|
||||||
- "src/browser/CdpConnection.ts"
|
|
||||||
- "src/browser/CdpEndpoint.ts"
|
|
||||||
- "src/browser/CdpTarget*.ts"
|
|
||||||
- "src/browser/CdpCaptureValues.ts"
|
|
||||||
- "src/browser/CdpAuthorized*.ts"
|
|
||||||
- "src/domain/webRuntime.ts"
|
|
||||||
- "src/domain/webExecution.ts"
|
|
||||||
- "src/domain/webEventListeners.ts"
|
|
||||||
- "src/domain/browserObservationError*.ts"
|
|
||||||
- "src/application/WebRuntime*.ts"
|
|
||||||
- "src/composition/webRuntime.ts"
|
|
||||||
- "src/contracts/webRuntimeToolContracts.ts"
|
|
||||||
- "src/contracts/toolEffects.ts"
|
|
||||||
- "src/server/registerWebRuntimeTools.ts"
|
|
||||||
- "src/server/createServer.ts"
|
|
||||||
- "src/cli/webRuntimeCommands.ts"
|
|
||||||
- "src/cli/commandCancellation.ts"
|
|
||||||
- "src/cli.ts"
|
|
||||||
- "package.json"
|
|
||||||
- "package-lock.json"
|
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
|
|||||||
@@ -1,27 +1,6 @@
|
|||||||
name: Real website source-map verification
|
name: Real website source-map verification
|
||||||
on:
|
on:
|
||||||
pull_request:
|
workflow_call:
|
||||||
paths:
|
|
||||||
- ".github/workflows/real-web-source-map.yml"
|
|
||||||
- "scripts/verify-browser-source-maps.mjs"
|
|
||||||
- "scripts/lib/browser-source-map-e2e.mjs"
|
|
||||||
- "scripts/fixtures/browser-source-map-site.mjs"
|
|
||||||
- "src/javascript/sourceMaps/**"
|
|
||||||
- "src/browser/assets/**"
|
|
||||||
- "src/domain/webSource*.ts"
|
|
||||||
- "src/domain/webScript*.ts"
|
|
||||||
- "src/application/WebSourceLocation*.ts"
|
|
||||||
- "src/application/ValidateSelectedWebScript.ts"
|
|
||||||
- "src/composition/webSourceLocations.ts"
|
|
||||||
- "src/server/registerWebSourceLocationTool.ts"
|
|
||||||
- "src/server/createServer.ts"
|
|
||||||
- "src/contracts/webScriptToolContracts.ts"
|
|
||||||
- "src/process/**"
|
|
||||||
- "src/cli/webSourceLocationCommands.ts"
|
|
||||||
- "src/cli.ts"
|
|
||||||
- "src/artifacts/readStableArtifact.ts"
|
|
||||||
- "package.json"
|
|
||||||
- "package-lock.json"
|
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
|
|||||||
@@ -1,12 +1,7 @@
|
|||||||
name: Website checks
|
name: Website checks
|
||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
workflow_call:
|
||||||
branches: [main, "release/*"]
|
|
||||||
paths:
|
|
||||||
- "website/**"
|
|
||||||
- "scripts/*website*.py"
|
|
||||||
- ".github/workflows/**"
|
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
|
|||||||
+31
-6
@@ -771,12 +771,37 @@ Pull requests that change only root `README*.md` files, `docs/`, `AGENTS.md`,
|
|||||||
or `CONTRIBUTING.md` run formatting and generated-document validation without
|
or `CONTRIBUTING.md` run formatting and generated-document validation without
|
||||||
the source-test shards or native package lanes. Classification compares the PR
|
the source-test shards or native package lanes. Classification compares the PR
|
||||||
head with its merge base, so later base-branch changes do not expand that scope.
|
head with its merge base, so later base-branch changes do not expand that scope.
|
||||||
The required static and coverage aggregate jobs remain present and fail if
|
Static and coverage aggregate jobs remain present and fail if classification
|
||||||
classification fails. Mixed changes, unknown paths and CI configuration changes
|
fails. Every code change retains the complete four-shard Linux suite; individual
|
||||||
retain full checks. Main pushes retain the full baseline, including after
|
test files are not selected by imports or filenames.
|
||||||
documentation merges; newer commits cancel superseded CI for the same PR or
|
|
||||||
main branch. Release publication has its own concurrency group and retains its
|
`scripts/ci/plan.mjs` selects lanes using the ownership table in
|
||||||
package verification and public-registry canary.
|
`scripts/ci/scopes.mjs`. Provider implementation changes run their real-provider
|
||||||
|
verifiers and the Linux x64 installed-package/Inspector baseline. Test-only
|
||||||
|
changes run the Linux suite without native package verification. Website changes
|
||||||
|
run website checks. Provider workflow changes validate the workflow and run that provider's verifier.
|
||||||
|
Manual-provider/Android workflow changes run workflow validation only.
|
||||||
|
Shared process/contract/CLI boundaries, dependencies, packaging inputs, unknown
|
||||||
|
paths, and changes to the planner select the full baseline. Package script-only
|
||||||
|
edits select their owning verifier when its entrypoint is identifiable; unknown
|
||||||
|
or shared script changes select everything. Android build-script edits retain
|
||||||
|
the Linux suite and workflow validation; real Android verification stays manual.
|
||||||
|
Renames account for both paths.
|
||||||
|
|
||||||
|
Main pushes and manual dispatch retain the full baseline, including all portable
|
||||||
|
provider lanes and the native matrix below. A `ci:full` PR label selects the full
|
||||||
|
baseline on the next PR run; manual dispatch can request it immediately. Each
|
||||||
|
classification job records its selection and broad-fallback reasons in the run
|
||||||
|
summary. Representative Git-diff cases live in
|
||||||
|
`tests/boundary/filesystem/ciChangeScope.test.ts`.
|
||||||
|
|
||||||
|
`CI required` checks classification and every selected lane, rejecting failed,
|
||||||
|
cancelled, or unexpectedly skipped work. Existing required check names are
|
||||||
|
preserved; changing branch protection to require the new aggregate is a separate
|
||||||
|
repository-settings operation. Newer commits cancel superseded CI for the same
|
||||||
|
PR or main branch. Release publication has its own concurrency group and retains
|
||||||
|
its package verification and public-registry canary. Licensed/self-hosted
|
||||||
|
provider workflows and the Android smoke test retain their explicit triggers.
|
||||||
|
|
||||||
CI exercises the pinned Node.js runtime on native hosted runners:
|
CI exercises the pinned Node.js runtime on native hosted runners:
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,174 @@
|
|||||||
|
import { execFileSync } from "node:child_process";
|
||||||
|
import { appendFileSync } from "node:fs";
|
||||||
|
import { matchesGlob } from "node:path";
|
||||||
|
import { SCOPES } from "./scopes.mjs";
|
||||||
|
|
||||||
|
const flags = [
|
||||||
|
"code",
|
||||||
|
"runtime",
|
||||||
|
"package",
|
||||||
|
"apple",
|
||||||
|
"fixtures",
|
||||||
|
"readiness",
|
||||||
|
"docs",
|
||||||
|
"workflows",
|
||||||
|
...Object.keys(SCOPES),
|
||||||
|
];
|
||||||
|
const selected = Object.fromEntries(flags.map((flag) => [flag, false]));
|
||||||
|
const reasons = [];
|
||||||
|
const full = (reason) => {
|
||||||
|
for (const flag of flags) selected[flag] = true;
|
||||||
|
reasons.push(reason);
|
||||||
|
};
|
||||||
|
const git = (...args) =>
|
||||||
|
execFileSync("git", args, { encoding: "utf8" }).trimEnd();
|
||||||
|
function classifyPackage(base, head) {
|
||||||
|
const before = JSON.parse(git("show", `${base}:package.json`));
|
||||||
|
const after = JSON.parse(git("show", `${head}:package.json`));
|
||||||
|
const { scripts: beforeScripts, ...beforeRest } = before;
|
||||||
|
const { scripts: afterScripts, ...afterRest } = after;
|
||||||
|
if (JSON.stringify(beforeRest) !== JSON.stringify(afterRest)) {
|
||||||
|
full("Package metadata or dependencies changed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
selected.code = true;
|
||||||
|
const changed = [
|
||||||
|
...new Set([
|
||||||
|
...Object.keys(beforeScripts ?? {}),
|
||||||
|
...Object.keys(afterScripts ?? {}),
|
||||||
|
]),
|
||||||
|
].filter((key) => beforeScripts?.[key] !== afterScripts?.[key]);
|
||||||
|
for (const script of changed) {
|
||||||
|
if (
|
||||||
|
/^(test(?::|$)|check(?::|$)|lint(?::|$)|format(?::|$)|knip$|jscpd$)/.test(
|
||||||
|
script,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
continue;
|
||||||
|
if (
|
||||||
|
["compile:termux", "build:termux", "build:termux:run"].includes(script)
|
||||||
|
) {
|
||||||
|
selected.workflows = true;
|
||||||
|
reasons.push(
|
||||||
|
`Android build script changed; real Android verification remains manual: ${script}`,
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Verify scripts own provider setup as well as execution. Reuse their
|
||||||
|
// existing source-file ownership rather than maintaining a second map.
|
||||||
|
const entrypoint = (command) =>
|
||||||
|
/^(?:npm run build:cached && )?node (scripts\/[\w/-]+\.mjs)(?: [\w./=-]+)*$/.exec(
|
||||||
|
command ?? "",
|
||||||
|
)?.[1];
|
||||||
|
const beforeEntry = entrypoint(beforeScripts?.[script]);
|
||||||
|
const afterEntry = entrypoint(afterScripts?.[script]);
|
||||||
|
const entries = [beforeEntry, afterEntry].filter(Boolean);
|
||||||
|
const simple =
|
||||||
|
(!beforeScripts?.[script] || beforeEntry) &&
|
||||||
|
(!afterScripts?.[script] || afterEntry);
|
||||||
|
const scriptOwners =
|
||||||
|
simple &&
|
||||||
|
entries.every((entry) =>
|
||||||
|
Object.values(SCOPES).some((patterns) => patterns.includes(entry)),
|
||||||
|
)
|
||||||
|
? Object.entries(SCOPES)
|
||||||
|
.filter(([, patterns]) =>
|
||||||
|
entries.some((entry) => patterns.includes(entry)),
|
||||||
|
)
|
||||||
|
.map(([owner]) => owner)
|
||||||
|
: [];
|
||||||
|
if (scriptOwners.length)
|
||||||
|
for (const owner of scriptOwners) selected[owner] = true;
|
||||||
|
else full(`Shared or unknown package script: ${script}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const event = process.env.GITHUB_EVENT_NAME;
|
||||||
|
let files = [];
|
||||||
|
if (
|
||||||
|
event === "push" ||
|
||||||
|
event === "schedule" ||
|
||||||
|
event === "workflow_dispatch" ||
|
||||||
|
process.env.CI_FULL === "true"
|
||||||
|
) {
|
||||||
|
full("Full baseline requested by event or ci:full label");
|
||||||
|
} else if (event === "pull_request") {
|
||||||
|
const base = git("merge-base", process.env.BASE_SHA, process.env.HEAD_SHA);
|
||||||
|
const head = process.env.HEAD_SHA;
|
||||||
|
// Disable rename detection so both the removed and added paths participate.
|
||||||
|
files = git("diff", "--name-only", "--no-renames", "-z", base, head)
|
||||||
|
.split("\0")
|
||||||
|
.filter(Boolean);
|
||||||
|
for (const file of files) {
|
||||||
|
if (
|
||||||
|
/^(README(?:_[^/]+)?\.md|AGENTS\.md|CONTRIBUTING\.md)$/.test(file) ||
|
||||||
|
file.startsWith("docs/")
|
||||||
|
) {
|
||||||
|
selected.docs = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (/^(src|tests)\/.*\.(?:test|spec)\.[cm]?[jt]sx?$/.test(file)) {
|
||||||
|
selected.code = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const owners = Object.entries(SCOPES)
|
||||||
|
.filter(([, patterns]) =>
|
||||||
|
patterns.some((pattern) => matchesGlob(file, pattern)),
|
||||||
|
)
|
||||||
|
.map(([owner]) => owner);
|
||||||
|
for (const owner of owners) selected[owner] = true;
|
||||||
|
if (
|
||||||
|
file.startsWith(".github/workflows/") ||
|
||||||
|
file === ".github/actionlint.yaml"
|
||||||
|
) {
|
||||||
|
selected.workflows = true;
|
||||||
|
if (file !== ".github/workflows/ci.yml") continue;
|
||||||
|
}
|
||||||
|
if (owners.length === 1 && owners[0] === "website") continue;
|
||||||
|
if (/^src\/(contracts|domain)\//.test(file)) selected.docs = true;
|
||||||
|
if (file === "package.json") {
|
||||||
|
classifyPackage(base, head);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
selected.code = true;
|
||||||
|
if (file.startsWith("tests/")) continue;
|
||||||
|
if (
|
||||||
|
/^(src\/process\/|src\/filesystem\/|src\/contracts\/tool|src\/server\/createServer|src\/cli\.ts|scripts\/ci\/)/.test(
|
||||||
|
file,
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
full(`Shared boundary: ${file}`);
|
||||||
|
} else if (owners.length) {
|
||||||
|
if (file.startsWith("src/") || file.startsWith("bridge/"))
|
||||||
|
selected.runtime = true;
|
||||||
|
} else {
|
||||||
|
full(`Unclassified input: ${file}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else throw new Error(`Unsupported CI event: ${event}`);
|
||||||
|
selected.runtime ||= selected.package;
|
||||||
|
const linux = { os: "ubuntu-latest", platform: "linux", architecture: "x64" };
|
||||||
|
const matrix = {
|
||||||
|
include: selected.package
|
||||||
|
? [
|
||||||
|
linux,
|
||||||
|
{ os: "ubuntu-24.04-arm", platform: "linux", architecture: "arm64" },
|
||||||
|
{ os: "macos-15", platform: "darwin", architecture: "arm64" },
|
||||||
|
{ os: "macos-15-intel", platform: "darwin", architecture: "x64" },
|
||||||
|
]
|
||||||
|
: [linux],
|
||||||
|
};
|
||||||
|
const plan = { ...selected, matrix, files, reasons };
|
||||||
|
if (process.env.GITHUB_OUTPUT)
|
||||||
|
appendFileSync(
|
||||||
|
process.env.GITHUB_OUTPUT,
|
||||||
|
Object.entries({ ...selected, matrix: JSON.stringify(matrix) })
|
||||||
|
.map(([key, value]) => `${key}=${value}\n`)
|
||||||
|
.join(""),
|
||||||
|
);
|
||||||
|
if (process.env.GITHUB_STEP_SUMMARY)
|
||||||
|
appendFileSync(
|
||||||
|
process.env.GITHUB_STEP_SUMMARY,
|
||||||
|
`### Selected CI lanes\n\n${flags.filter((flag) => selected[flag]).join(", ") || "Formatting only"}\n\n${reasons.join("\n\n")}\n`,
|
||||||
|
);
|
||||||
|
console.log(JSON.stringify(plan));
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
const jobs = JSON.parse(process.env.CI_JOBS);
|
||||||
|
const outputs = jobs.changes.outputs;
|
||||||
|
const required = ["changes", "static", "test"];
|
||||||
|
const lanes = {
|
||||||
|
code: ["build", "test-shard"],
|
||||||
|
runtime: ["windows-native-build", "package-e2e"],
|
||||||
|
package: ["windows-curated"],
|
||||||
|
apple: ["apple-artifacts"],
|
||||||
|
fixtures: ["conformance-fixtures"],
|
||||||
|
readiness: ["reconstruction-readiness"],
|
||||||
|
docs: ["docs"],
|
||||||
|
};
|
||||||
|
for (const [scope, value] of Object.entries(outputs)) {
|
||||||
|
if (value === "true") required.push(...(lanes[scope] ?? [scope]));
|
||||||
|
}
|
||||||
|
const failed = [...new Set(required)].filter(
|
||||||
|
(name) => jobs[name]?.result !== "success",
|
||||||
|
);
|
||||||
|
for (const [name, job] of Object.entries(jobs)) {
|
||||||
|
if (["failure", "cancelled"].includes(job.result) && !failed.includes(name))
|
||||||
|
failed.push(name);
|
||||||
|
}
|
||||||
|
if (failed.length)
|
||||||
|
throw new Error(`CI lanes did not pass: ${failed.join(", ")}`);
|
||||||
|
console.log("Every selected CI lane passed");
|
||||||
@@ -0,0 +1,227 @@
|
|||||||
|
// Ownership of the real-provider and website verification lanes. Shared build
|
||||||
|
// inputs are classified once in plan.mjs rather than repeated in every workflow.
|
||||||
|
export const SCOPES = {
|
||||||
|
browser: [
|
||||||
|
".github/workflows/real-browser.yml",
|
||||||
|
"scripts/verify-real-browser.mjs",
|
||||||
|
"scripts/verify-browser-network.mjs",
|
||||||
|
"scripts/verify-browser-scripts.mjs",
|
||||||
|
"scripts/verify-browser-modules.mjs",
|
||||||
|
"scripts/verify-browser-dom-destinations.mjs",
|
||||||
|
"scripts/lib/browser-*.mjs",
|
||||||
|
"scripts/fixtures/browser-network-site.mjs",
|
||||||
|
"scripts/fixtures/browser-script-site.mjs",
|
||||||
|
"scripts/fixtures/browser-module-site.mjs",
|
||||||
|
"scripts/fixtures/browser-verifier-site.mjs",
|
||||||
|
"scripts/fixtures/page-cdp-proxy.mjs",
|
||||||
|
"src/browser/**",
|
||||||
|
"src/domain/browser*.ts",
|
||||||
|
"src/domain/webScript*.ts",
|
||||||
|
"src/domain/webModule*.ts",
|
||||||
|
"src/application/WebModule*.ts",
|
||||||
|
"src/composition/webModules.ts",
|
||||||
|
"src/artifacts/readStableArtifact.ts",
|
||||||
|
"src/artifacts/ArtifactPaths.ts",
|
||||||
|
"src/application/WebScriptExportService.ts",
|
||||||
|
"src/contracts/webScriptToolContracts.ts",
|
||||||
|
"src/server/registerWebScriptTool.ts",
|
||||||
|
"src/server/registerWebModuleTool.ts",
|
||||||
|
"src/server/createServer.ts",
|
||||||
|
"src/cli/webModuleCommands.ts",
|
||||||
|
"src/cli.ts",
|
||||||
|
"src/cliCommandNames.ts",
|
||||||
|
"src/contracts/toolEffects.ts",
|
||||||
|
"src/cli/webScriptCommands.ts",
|
||||||
|
],
|
||||||
|
binary_layout: [
|
||||||
|
".github/workflows/real-binary-layout.yml",
|
||||||
|
"bridge/pwntools/**",
|
||||||
|
"src/native/pwntools/**",
|
||||||
|
"src/domain/native/binaryLayout*",
|
||||||
|
"src/application/binaryDiagnostics/**",
|
||||||
|
"src/contracts/native/binaryDiagnosticsToolContracts.ts",
|
||||||
|
"src/composition/binaryDiagnostics.ts",
|
||||||
|
"src/server/registerBinaryDiagnosticsTools.ts",
|
||||||
|
"src/server/createServer.ts",
|
||||||
|
"src/cli/binaryDiagnosticsCommands.ts",
|
||||||
|
"src/cli.ts",
|
||||||
|
"src/cliCommandNames.ts",
|
||||||
|
"src/contracts/toolContracts.ts",
|
||||||
|
"src/contracts/toolEffects.ts",
|
||||||
|
"src/process/OwnedCommand.ts",
|
||||||
|
"src/process/ProviderProcess.ts",
|
||||||
|
"src/process/ProviderDeadline.ts",
|
||||||
|
"src/process/ProcessOwnership*.ts",
|
||||||
|
"src/process/PrivateRuntimeRoot.ts",
|
||||||
|
"src/artifacts/readStableArtifact*.ts",
|
||||||
|
"src/artifacts/ArtifactReader.ts",
|
||||||
|
"src/domain/analysisError*.ts",
|
||||||
|
"scripts/verify-binary-layout.mjs",
|
||||||
|
"scripts/lib/elf-section-name-fixtures.mjs",
|
||||||
|
"scripts/lib/large-result-mcp.mjs",
|
||||||
|
"scripts/fixtures/binary-layout*",
|
||||||
|
],
|
||||||
|
evm: [
|
||||||
|
".github/workflows/real-evm-interface.yml",
|
||||||
|
"src/evm/**",
|
||||||
|
"src/domain/evm/**",
|
||||||
|
"src/application/evm/**",
|
||||||
|
"src/contracts/evm/**",
|
||||||
|
"src/composition/evm.ts",
|
||||||
|
"src/cli/evmCommands.ts",
|
||||||
|
"src/server/registerEvmTools.ts",
|
||||||
|
"src/server/createServer.ts",
|
||||||
|
"src/cli.ts",
|
||||||
|
"src/cliCommandNames.ts",
|
||||||
|
"src/contracts/toolContracts.ts",
|
||||||
|
"src/contracts/toolEffects.ts",
|
||||||
|
"src/process/OwnedCommand.ts",
|
||||||
|
"src/process/ProviderProcess.ts",
|
||||||
|
"src/process/ProcessOwnership*.ts",
|
||||||
|
"src/process/ProviderDeadline.ts",
|
||||||
|
"src/process/PrivateRuntimeRoot.ts",
|
||||||
|
"src/artifacts/readStableArtifact*.ts",
|
||||||
|
"src/artifacts/ArtifactReader.ts",
|
||||||
|
"scripts/verify-evm-interface.mjs",
|
||||||
|
"scripts/fixtures/evm-interface.sol",
|
||||||
|
"third_party/evmole/**",
|
||||||
|
],
|
||||||
|
javascript_recovery: [
|
||||||
|
".github/workflows/real-javascript-recovery.yml",
|
||||||
|
"src/javascript/recovery/**",
|
||||||
|
"src/domain/javascript/**",
|
||||||
|
"src/application/javascript/JavaScriptRecovery*.ts",
|
||||||
|
"src/composition/javascriptRecovery.ts",
|
||||||
|
"src/contracts/javascript/javascriptRecoveryToolContracts.ts",
|
||||||
|
"src/cli/javascriptRecoveryCommands.ts",
|
||||||
|
"src/cli/javascriptApplicationAnalysis.ts",
|
||||||
|
"src/server/registerJavaScriptRecoveryTool.ts",
|
||||||
|
"src/server/createServer.ts",
|
||||||
|
"src/server/sessionAvailabilityPolicy.ts",
|
||||||
|
"src/application/CapabilityInventory.ts",
|
||||||
|
"src/cli.ts",
|
||||||
|
"src/cliCommandNames.ts",
|
||||||
|
"src/contracts/toolContracts.ts",
|
||||||
|
"src/contracts/toolEffects.ts",
|
||||||
|
"scripts/rea.mjs",
|
||||||
|
"src/process/**",
|
||||||
|
"src/artifacts/SafeOutputTree.ts",
|
||||||
|
"scripts/verify/javascript/recovery.mjs",
|
||||||
|
"scripts/fixtures/javascript-recovery/**",
|
||||||
|
"third_party/wakaru",
|
||||||
|
],
|
||||||
|
recorded_crash: [
|
||||||
|
".github/workflows/real-recorded-crash.yml",
|
||||||
|
"bridge/pwntools/**",
|
||||||
|
"bridge/pwndbg/**",
|
||||||
|
"src/native/pwntools/**",
|
||||||
|
"src/native/pwndbg/**",
|
||||||
|
"src/domain/native/recordedCrash*",
|
||||||
|
"src/application/binaryDiagnostics/**",
|
||||||
|
"src/contracts/native/binaryDiagnosticsToolContracts.ts",
|
||||||
|
"src/contracts/toolEffects.ts",
|
||||||
|
"src/contracts/toolOutputSchemaGroups.ts",
|
||||||
|
"src/composition/binaryDiagnostics.ts",
|
||||||
|
"src/server/registerRecordedCrashTools.ts",
|
||||||
|
"src/server/createServer.ts",
|
||||||
|
"src/server/sessionAvailabilityPolicy.ts",
|
||||||
|
"src/cli/binaryDiagnosticsCommands.ts",
|
||||||
|
"src/cliCommandNames.ts",
|
||||||
|
"src/process/**",
|
||||||
|
"src/artifacts/readStableArtifact*.ts",
|
||||||
|
"src/domain/analysisError*.ts",
|
||||||
|
"scripts/verify-recorded-crash.mjs",
|
||||||
|
"scripts/verify/recorded-crash/**",
|
||||||
|
"scripts/lib/recorded-core-fixtures.py",
|
||||||
|
"scripts/fixtures/recorded-crash.c",
|
||||||
|
"third_party/pwndbg/**",
|
||||||
|
],
|
||||||
|
web_network: [
|
||||||
|
".github/workflows/real-web-network-captures.yml",
|
||||||
|
"bridge/mitmproxy/**",
|
||||||
|
"src/browser/history/**",
|
||||||
|
"src/domain/webNetworkCapture*.ts",
|
||||||
|
"src/domain/analysisError*.ts",
|
||||||
|
"src/contracts/errorSchemas.ts",
|
||||||
|
"src/domain/explicitSensitive*.ts",
|
||||||
|
"src/application/WebNetworkCapture*",
|
||||||
|
"src/composition/webNetworkCaptures.ts",
|
||||||
|
"src/cli/webNetworkCaptureCommands.ts",
|
||||||
|
"src/server/registerWebNetworkCaptureTool.ts",
|
||||||
|
"src/server/createServer.ts",
|
||||||
|
"src/server/toolRegistrationOptions.ts",
|
||||||
|
"src/cli.ts",
|
||||||
|
"src/cliCommandNames.ts",
|
||||||
|
"src/contracts/toolContracts.ts",
|
||||||
|
"src/contracts/toolEffects.ts",
|
||||||
|
"src/process/OwnedCommand.ts",
|
||||||
|
"src/process/ProviderProcess.ts",
|
||||||
|
"src/process/ProviderDeadline.ts",
|
||||||
|
"src/process/ProcessOwnership*.ts",
|
||||||
|
"src/process/PrivateRuntimeRoot.ts",
|
||||||
|
"src/process/capture/ProcessCaptureLifecycle.ts",
|
||||||
|
"src/artifacts/readStableArtifact*.ts",
|
||||||
|
"src/artifacts/ArtifactReader.ts",
|
||||||
|
"src/contracts/webNetworkCaptureToolContracts.ts",
|
||||||
|
"scripts/verify-web-network-captures.mjs",
|
||||||
|
"scripts/fixtures/generate-mitmproxy-capture.py",
|
||||||
|
],
|
||||||
|
web_runtime: [
|
||||||
|
".github/workflows/real-web-runtime.yml",
|
||||||
|
"scripts/verify-browser-runtime.mjs",
|
||||||
|
"scripts/lib/browser-runtime-*.mjs",
|
||||||
|
"src/process/ProviderProcess.ts",
|
||||||
|
"src/process/ProcessOwnership*.ts",
|
||||||
|
"scripts/fixtures/browser-runtime-site.mjs",
|
||||||
|
"src/browser/execution/**",
|
||||||
|
"src/browser/CdpConnection.ts",
|
||||||
|
"src/browser/CdpEndpoint.ts",
|
||||||
|
"src/browser/CdpTarget*.ts",
|
||||||
|
"src/browser/CdpCaptureValues.ts",
|
||||||
|
"src/browser/CdpAuthorized*.ts",
|
||||||
|
"src/domain/webRuntime.ts",
|
||||||
|
"src/domain/webExecution.ts",
|
||||||
|
"src/domain/webEventListeners.ts",
|
||||||
|
"src/domain/browserObservationError*.ts",
|
||||||
|
"src/application/WebRuntime*.ts",
|
||||||
|
"src/composition/webRuntime.ts",
|
||||||
|
"src/contracts/webRuntimeToolContracts.ts",
|
||||||
|
"src/contracts/toolEffects.ts",
|
||||||
|
"src/server/registerWebRuntimeTools.ts",
|
||||||
|
"src/server/createServer.ts",
|
||||||
|
"src/cli/webRuntimeCommands.ts",
|
||||||
|
"src/cli/commandCancellation.ts",
|
||||||
|
"src/cli.ts",
|
||||||
|
],
|
||||||
|
web_source_map: [
|
||||||
|
".github/workflows/real-web-source-map.yml",
|
||||||
|
"scripts/verify-browser-source-maps.mjs",
|
||||||
|
"scripts/lib/browser-source-map-e2e.mjs",
|
||||||
|
"scripts/fixtures/browser-source-map-site.mjs",
|
||||||
|
"src/javascript/sourceMaps/**",
|
||||||
|
"src/browser/assets/**",
|
||||||
|
"src/domain/webSource*.ts",
|
||||||
|
"src/domain/webScript*.ts",
|
||||||
|
"src/application/WebSourceLocation*.ts",
|
||||||
|
"src/application/ValidateSelectedWebScript.ts",
|
||||||
|
"src/composition/webSourceLocations.ts",
|
||||||
|
"src/server/registerWebSourceLocationTool.ts",
|
||||||
|
"src/server/createServer.ts",
|
||||||
|
"src/contracts/webScriptToolContracts.ts",
|
||||||
|
"src/process/**",
|
||||||
|
"src/cli/webSourceLocationCommands.ts",
|
||||||
|
"src/cli.ts",
|
||||||
|
"src/artifacts/readStableArtifact.ts",
|
||||||
|
],
|
||||||
|
nativeaot: [
|
||||||
|
"bridge/ghidra/extensions/nativeaot/**",
|
||||||
|
"scripts/generate-nativeaot-fixtures.mjs",
|
||||||
|
"tests/fixtures/nativeaot/**",
|
||||||
|
".github/workflows/nativeaot-fixtures.yml",
|
||||||
|
],
|
||||||
|
website: [
|
||||||
|
"website/**",
|
||||||
|
"scripts/*website*.py",
|
||||||
|
".github/workflows/website-check.yml",
|
||||||
|
],
|
||||||
|
};
|
||||||
@@ -11,16 +11,6 @@ import {
|
|||||||
workflowGit as git,
|
workflowGit as git,
|
||||||
} from "../../support/workflowGit.js";
|
} from "../../support/workflowGit.js";
|
||||||
|
|
||||||
const workflowSchema = z.object({
|
|
||||||
jobs: z.object({
|
|
||||||
changes: z.object({
|
|
||||||
steps: z.array(
|
|
||||||
z.object({ id: z.string().optional(), run: z.string().optional() }),
|
|
||||||
),
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
async function commit(directory: string) {
|
async function commit(directory: string) {
|
||||||
await git(directory, ["add", "."]);
|
await git(directory, ["add", "."]);
|
||||||
await git(directory, ["commit", "-m", "fix: fixture change"]);
|
await git(directory, ["commit", "-m", "fix: fixture change"]);
|
||||||
@@ -56,33 +46,26 @@ async function classify(
|
|||||||
base: string,
|
base: string,
|
||||||
head: string,
|
head: string,
|
||||||
event = "pull_request",
|
event = "pull_request",
|
||||||
|
full = false,
|
||||||
) {
|
) {
|
||||||
const workflow = workflowSchema.parse(
|
|
||||||
parse(
|
|
||||||
await readFile(
|
|
||||||
new URL("../../../.github/workflows/ci.yml", import.meta.url),
|
|
||||||
"utf8",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
const command = z
|
|
||||||
.string()
|
|
||||||
.parse(
|
|
||||||
workflow.jobs.changes.steps.find((step) => step.id === "package")?.run,
|
|
||||||
);
|
|
||||||
const output = join(directory, "scope-output");
|
const output = join(directory, "scope-output");
|
||||||
await writeFile(output, "");
|
await writeFile(output, "");
|
||||||
await execFileAsync("bash", ["-e", "-o", "pipefail", "-c", command], {
|
const result = await execFileAsync(
|
||||||
cwd: directory,
|
process.execPath,
|
||||||
env: {
|
[new URL("../../../scripts/ci/plan.mjs", import.meta.url).pathname],
|
||||||
...process.env,
|
{
|
||||||
BASE_SHA: base,
|
cwd: directory,
|
||||||
HEAD_SHA: head,
|
env: {
|
||||||
GITHUB_EVENT_NAME: event,
|
...process.env,
|
||||||
GITHUB_OUTPUT: output,
|
BASE_SHA: base,
|
||||||
|
HEAD_SHA: head,
|
||||||
|
GITHUB_EVENT_NAME: event,
|
||||||
|
CI_FULL: String(full),
|
||||||
|
GITHUB_OUTPUT: output,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
);
|
||||||
return readFile(output, "utf8");
|
return z.record(z.string(), z.unknown()).parse(JSON.parse(result.stdout));
|
||||||
}
|
}
|
||||||
|
|
||||||
it("keeps every translated root README and authored guide on the documentation lane", async () => {
|
it("keeps every translated root README and authored guide on the documentation lane", async () => {
|
||||||
@@ -97,7 +80,11 @@ it("keeps every translated root README and authored guide on the documentation l
|
|||||||
"AGENTS.md",
|
"AGENTS.md",
|
||||||
"CONTRIBUTING.md",
|
"CONTRIBUTING.md",
|
||||||
]);
|
]);
|
||||||
expect(await classify(directory, base, head)).toBe("required=false\n");
|
expect(await classify(directory, base, head)).toMatchObject({
|
||||||
|
code: false,
|
||||||
|
package: false,
|
||||||
|
docs: true,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("does not charge a documentation PR for unrelated implementation updates on main", async () => {
|
it("does not charge a documentation PR for unrelated implementation updates on main", async () => {
|
||||||
@@ -107,15 +94,15 @@ it("does not charge a documentation PR for unrelated implementation updates on m
|
|||||||
await git(directory, ["switch", "main"]);
|
await git(directory, ["switch", "main"]);
|
||||||
const advancedBase = await change(directory, ["src/anotherProvider.ts"]);
|
const advancedBase = await change(directory, ["src/anotherProvider.ts"]);
|
||||||
expect(advancedBase).not.toBe(base);
|
expect(advancedBase).not.toBe(base);
|
||||||
expect(await classify(directory, advancedBase, head)).toBe(
|
expect(await classify(directory, advancedBase, head)).toMatchObject({
|
||||||
"required=false\n",
|
code: false,
|
||||||
);
|
package: false,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it.each([
|
it.each([
|
||||||
"src/README.md",
|
"src/README.md",
|
||||||
"README.md.ts",
|
"README.md.ts",
|
||||||
"package.json",
|
|
||||||
"bridge/ghidra/provider.py",
|
"bridge/ghidra/provider.py",
|
||||||
"tests/fixture.test.ts",
|
"tests/fixture.test.ts",
|
||||||
".github/workflows/ci.yml",
|
".github/workflows/ci.yml",
|
||||||
@@ -125,7 +112,7 @@ it.each([
|
|||||||
async (path) => {
|
async (path) => {
|
||||||
const { directory, base } = await fixture();
|
const { directory, base } = await fixture();
|
||||||
const head = await change(directory, ["README.md", path]);
|
const head = await change(directory, ["README.md", path]);
|
||||||
expect(await classify(directory, base, head)).toBe("required=true\n");
|
expect(await classify(directory, base, head)).toMatchObject({ code: true });
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -137,19 +124,25 @@ it("retains complete checks when implementation is renamed into documentation",
|
|||||||
join(directory, "docs/provider.md"),
|
join(directory, "docs/provider.md"),
|
||||||
);
|
);
|
||||||
const head = await commit(directory);
|
const head = await commit(directory);
|
||||||
expect(await classify(directory, base, head)).toBe("required=true\n");
|
expect(await classify(directory, base, head)).toMatchObject({
|
||||||
|
code: true,
|
||||||
|
package: true,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("retains the complete main-push baseline even for documentation", async () => {
|
it("retains the complete main-push baseline even for documentation", async () => {
|
||||||
const { directory, base } = await fixture();
|
const { directory, base } = await fixture();
|
||||||
const head = await change(directory, ["README_ja.md"]);
|
const head = await change(directory, ["README_ja.md"]);
|
||||||
expect(await classify(directory, base, head, "push")).toBe("required=true\n");
|
expect(await classify(directory, base, head, "push")).toMatchObject({
|
||||||
|
code: true,
|
||||||
|
package: true,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("fails classification rather than treating an invalid Git comparison as a scope", async () => {
|
it("fails classification rather than treating an invalid Git comparison as a scope", async () => {
|
||||||
const { directory, base } = await fixture();
|
const { directory, base } = await fixture();
|
||||||
await expect(classify(directory, "missing-ref", base)).rejects.toMatchObject({
|
await expect(classify(directory, "missing-ref", base)).rejects.toMatchObject({
|
||||||
code: 128,
|
code: 1,
|
||||||
});
|
});
|
||||||
expect(await readFile(join(directory, "scope-output"), "utf8")).toBe("");
|
expect(await readFile(join(directory, "scope-output"), "utf8")).toBe("");
|
||||||
});
|
});
|
||||||
@@ -164,13 +157,6 @@ it("retains native Inspector verification on every documented package host", asy
|
|||||||
.object({
|
.object({
|
||||||
jobs: z.object({
|
jobs: z.object({
|
||||||
"package-e2e": z.object({
|
"package-e2e": z.object({
|
||||||
strategy: z.object({
|
|
||||||
matrix: z.object({
|
|
||||||
include: z.array(
|
|
||||||
z.object({ platform: z.string(), architecture: z.string() }),
|
|
||||||
),
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
steps,
|
steps,
|
||||||
}),
|
}),
|
||||||
"windows-curated": z.object({ steps }),
|
"windows-curated": z.object({ steps }),
|
||||||
@@ -190,10 +176,15 @@ it("retains native Inspector verification on every documented package host", asy
|
|||||||
);
|
);
|
||||||
expect(packageInspector.if).toBeUndefined();
|
expect(packageInspector.if).toBeUndefined();
|
||||||
expect(
|
expect(
|
||||||
packageLane.strategy.matrix.include
|
(await classify((await fixture()).directory, "", "", "push")).matrix,
|
||||||
.map(({ platform, architecture }) => `${platform}/${architecture}`)
|
).toEqual({
|
||||||
.sort(),
|
include: [
|
||||||
).toEqual(["darwin/arm64", "darwin/x64", "linux/arm64", "linux/x64"]);
|
{ os: "ubuntu-latest", platform: "linux", architecture: "x64" },
|
||||||
|
{ os: "ubuntu-24.04-arm", platform: "linux", architecture: "arm64" },
|
||||||
|
{ os: "macos-15", platform: "darwin", architecture: "arm64" },
|
||||||
|
{ os: "macos-15-intel", platform: "darwin", architecture: "x64" },
|
||||||
|
],
|
||||||
|
});
|
||||||
const windowsInspector = stepSchema.parse(
|
const windowsInspector = stepSchema.parse(
|
||||||
workflow.jobs["windows-curated"].steps.find(
|
workflow.jobs["windows-curated"].steps.find(
|
||||||
(step) => step.run === "npm run verify:inspector",
|
(step) => step.run === "npm run verify:inspector",
|
||||||
@@ -201,3 +192,284 @@ it("retains native Inspector verification on every documented package host", asy
|
|||||||
);
|
);
|
||||||
expect(windowsInspector.if).toBeUndefined();
|
expect(windowsInspector.if).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it.each([
|
||||||
|
[
|
||||||
|
"src/evm/client.ts",
|
||||||
|
{ code: true, runtime: true, evm: true, browser: false, package: false },
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"src/browser/execution/evaluate.ts",
|
||||||
|
{
|
||||||
|
code: true,
|
||||||
|
runtime: true,
|
||||||
|
browser: true,
|
||||||
|
web_runtime: true,
|
||||||
|
evm: false,
|
||||||
|
package: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"tests/module/example.test.ts",
|
||||||
|
{ code: true, runtime: false, browser: false, package: false },
|
||||||
|
],
|
||||||
|
["website/src/index.ts", { code: false, website: true, package: false }],
|
||||||
|
[
|
||||||
|
"src/process/ProviderProcess.ts",
|
||||||
|
{ code: true, package: true, evm: true, browser: true },
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"package-lock.json",
|
||||||
|
{ code: true, package: true, evm: true, browser: true },
|
||||||
|
],
|
||||||
|
[
|
||||||
|
".github/workflows/real-evm-interface.yml",
|
||||||
|
{ code: false, evm: true, browser: false, package: false },
|
||||||
|
],
|
||||||
|
["unknown-input", { code: true, package: true, evm: true, browser: true }],
|
||||||
|
])("selects the appropriate lanes for %s", async (path, expected) => {
|
||||||
|
const { directory, base } = await fixture();
|
||||||
|
const head = await change(directory, [path]);
|
||||||
|
expect(await classify(directory, base, head)).toMatchObject(expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("scopes package script edits while retaining broad dependency checks", async () => {
|
||||||
|
const { directory } = await fixture();
|
||||||
|
const before = {
|
||||||
|
name: "fixture",
|
||||||
|
scripts: { "verify:evm": "node scripts/verify-evm-interface.mjs" },
|
||||||
|
};
|
||||||
|
const base = await change(
|
||||||
|
directory,
|
||||||
|
["package.json"],
|
||||||
|
JSON.stringify(before),
|
||||||
|
);
|
||||||
|
const after = {
|
||||||
|
...before,
|
||||||
|
scripts: {
|
||||||
|
"verify:evm": "node scripts/verify-evm-interface.mjs --verbose",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const head = await change(directory, ["package.json"], JSON.stringify(after));
|
||||||
|
expect(await classify(directory, base, head)).toMatchObject({
|
||||||
|
code: true,
|
||||||
|
evm: true,
|
||||||
|
browser: false,
|
||||||
|
package: false,
|
||||||
|
});
|
||||||
|
const dependency = await change(
|
||||||
|
directory,
|
||||||
|
["package.json"],
|
||||||
|
JSON.stringify({ ...after, dependencies: { example: "1.0.0" } }),
|
||||||
|
);
|
||||||
|
expect(await classify(directory, head, dependency)).toMatchObject({
|
||||||
|
code: true,
|
||||||
|
browser: true,
|
||||||
|
package: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it.each([
|
||||||
|
["browser", "real-browser"],
|
||||||
|
["binary_layout", "real-binary-layout"],
|
||||||
|
["evm", "real-evm-interface"],
|
||||||
|
["javascript_recovery", "real-javascript-recovery"],
|
||||||
|
["recorded_crash", "real-recorded-crash"],
|
||||||
|
["web_network", "real-web-network-captures"],
|
||||||
|
["web_runtime", "real-web-runtime"],
|
||||||
|
["web_source_map", "real-web-source-map"],
|
||||||
|
["nativeaot", "nativeaot-fixtures"],
|
||||||
|
["website", "website-check"],
|
||||||
|
])(
|
||||||
|
"routes %s through the selector without a duplicate PR trigger",
|
||||||
|
async (scope, name) => {
|
||||||
|
const workflow = z
|
||||||
|
.object({
|
||||||
|
on: z.object({ workflow_call: z.null() }).passthrough(),
|
||||||
|
})
|
||||||
|
.parse(
|
||||||
|
parse(
|
||||||
|
await readFile(
|
||||||
|
new URL(`../../../.github/workflows/${name}.yml`, import.meta.url),
|
||||||
|
"utf8",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(workflow.on).not.toHaveProperty("pull_request");
|
||||||
|
const ci = z
|
||||||
|
.object({
|
||||||
|
jobs: z.record(
|
||||||
|
z.string(),
|
||||||
|
z.object({
|
||||||
|
uses: z.string().optional(),
|
||||||
|
if: z.string().optional(),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
})
|
||||||
|
.parse(
|
||||||
|
parse(
|
||||||
|
await readFile(
|
||||||
|
new URL("../../../.github/workflows/ci.yml", import.meta.url),
|
||||||
|
"utf8",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(ci.jobs[scope]).toMatchObject({
|
||||||
|
uses: `./.github/workflows/${name}.yml`,
|
||||||
|
if: `needs.changes.outputs.${scope} == 'true'`,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
it("rejects skipped selected work while allowing unselected lanes to skip", async () => {
|
||||||
|
const command = new URL("../../../scripts/ci/required.mjs", import.meta.url)
|
||||||
|
.pathname;
|
||||||
|
const jobs = {
|
||||||
|
changes: { result: "success", outputs: { evm: "true" } },
|
||||||
|
static: { result: "success" },
|
||||||
|
test: { result: "success" },
|
||||||
|
evm: { result: "success" },
|
||||||
|
browser: { result: "skipped" },
|
||||||
|
};
|
||||||
|
const run = (result: string) =>
|
||||||
|
execFileAsync(process.execPath, [command], {
|
||||||
|
env: {
|
||||||
|
...process.env,
|
||||||
|
CI_JOBS: JSON.stringify({ ...jobs, evm: { result } }),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
await expect(run("success")).resolves.toMatchObject({ stderr: "" });
|
||||||
|
for (const result of ["failure", "cancelled", "skipped"]) {
|
||||||
|
await expect(run(result)).rejects.toMatchObject({ code: 1 });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it.each([
|
||||||
|
[
|
||||||
|
".github/workflows/real-termux.yml",
|
||||||
|
{ workflows: true, code: false, package: false, website: false },
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"src/domain/javascript/example.test.ts",
|
||||||
|
{ code: true, runtime: false, javascript_recovery: false, package: false },
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"src/process/capture/example.test.ts",
|
||||||
|
{ code: true, runtime: false, browser: false, package: false },
|
||||||
|
],
|
||||||
|
[".nvmrc", { code: true, package: true, browser: true, evm: true }],
|
||||||
|
[
|
||||||
|
"tsconfig.build.json",
|
||||||
|
{ code: true, package: true, browser: true, evm: true },
|
||||||
|
],
|
||||||
|
["docs/.vitepress/config.ts", { code: false, docs: true, package: false }],
|
||||||
|
[
|
||||||
|
"src/contracts/evm/tools.ts",
|
||||||
|
{ code: true, docs: true, evm: true, package: false },
|
||||||
|
],
|
||||||
|
["scripts/unknown-website-helper.mjs", { code: true, package: true }],
|
||||||
|
])("preserves scope boundaries for %s", async (path, expected) => {
|
||||||
|
const { directory, base } = await fixture();
|
||||||
|
const head = await change(directory, [path]);
|
||||||
|
expect(await classify(directory, base, head)).toMatchObject(expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("unions provider scopes across mixed changes and deletions", async () => {
|
||||||
|
const { directory } = await fixture();
|
||||||
|
const base = await change(directory, ["src/evm/client.ts"]);
|
||||||
|
await git(directory, ["rm", "src/evm/client.ts"]);
|
||||||
|
const head = await change(directory, ["src/browser/execution/evaluate.ts"]);
|
||||||
|
expect(await classify(directory, base, head)).toMatchObject({
|
||||||
|
evm: true,
|
||||||
|
browser: true,
|
||||||
|
runtime: true,
|
||||||
|
package: false,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("fails without emitting a plan when package metadata is malformed", async () => {
|
||||||
|
const { directory } = await fixture();
|
||||||
|
const base = await change(directory, ["package.json"], '{"scripts":{}}');
|
||||||
|
const head = await change(directory, ["package.json"], "{broken");
|
||||||
|
await expect(classify(directory, base, head)).rejects.toMatchObject({
|
||||||
|
code: 1,
|
||||||
|
});
|
||||||
|
expect(await readFile(join(directory, "scope-output"), "utf8")).toBe("");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("retains a broad fallback when a provider script adds shared shell work", async () => {
|
||||||
|
const { directory } = await fixture();
|
||||||
|
const before = {
|
||||||
|
scripts: { "verify:evm": "node scripts/verify-evm-interface.mjs" },
|
||||||
|
};
|
||||||
|
const base = await change(
|
||||||
|
directory,
|
||||||
|
["package.json"],
|
||||||
|
JSON.stringify(before),
|
||||||
|
);
|
||||||
|
const after = {
|
||||||
|
scripts: {
|
||||||
|
"verify:evm": "node scripts/verify-evm-interface.mjs && npm run compile",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const head = await change(directory, ["package.json"], JSON.stringify(after));
|
||||||
|
expect(await classify(directory, base, head)).toMatchObject({
|
||||||
|
evm: true,
|
||||||
|
browser: true,
|
||||||
|
package: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it.each(["workflow_dispatch", "schedule"])(
|
||||||
|
"retains full selection for %s",
|
||||||
|
async (event) => {
|
||||||
|
const { directory, base } = await fixture();
|
||||||
|
expect(await classify(directory, base, base, event)).toMatchObject({
|
||||||
|
code: true,
|
||||||
|
package: true,
|
||||||
|
evm: true,
|
||||||
|
browser: true,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
it("honors ci:full for successive PR revisions", async () => {
|
||||||
|
const { directory, base } = await fixture();
|
||||||
|
const first = await change(directory, ["README.md"]);
|
||||||
|
const second = await change(directory, ["README_ja.md"]);
|
||||||
|
for (const head of [first, second]) {
|
||||||
|
expect(
|
||||||
|
await classify(directory, base, head, "pull_request", true),
|
||||||
|
).toMatchObject({ code: true, package: true, evm: true, browser: true });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it.each(["compile:termux", "build:termux", "build:termux:run"])(
|
||||||
|
"does not expand %s edits into unrelated providers",
|
||||||
|
async (script) => {
|
||||||
|
const { directory } = await fixture();
|
||||||
|
const base = await change(
|
||||||
|
directory,
|
||||||
|
["package.json"],
|
||||||
|
JSON.stringify({ scripts: { [script]: "npm run compile:termux" } }),
|
||||||
|
);
|
||||||
|
const head = await change(
|
||||||
|
directory,
|
||||||
|
["package.json"],
|
||||||
|
JSON.stringify({
|
||||||
|
scripts: {
|
||||||
|
[script]:
|
||||||
|
"node scripts/run-exclusive.mjs artifacts npm run compile:termux",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
expect(await classify(directory, base, head)).toMatchObject({
|
||||||
|
code: true,
|
||||||
|
workflows: true,
|
||||||
|
runtime: false,
|
||||||
|
package: false,
|
||||||
|
browser: false,
|
||||||
|
evm: false,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
@@ -582,12 +582,12 @@ it("runs release PR CI without enabling implementation pushes on release branche
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("checks website changes on release-branch pull requests", async () => {
|
it("routes website verification through the central PR policy", async () => {
|
||||||
const workflow = z
|
const workflow = z
|
||||||
.object({
|
.object({
|
||||||
on: z.object({
|
on: z
|
||||||
pull_request: z.object({ branches: z.array(z.string()) }),
|
.object({ workflow_call: z.null(), workflow_dispatch: z.null() })
|
||||||
}),
|
.passthrough(),
|
||||||
})
|
})
|
||||||
.parse(
|
.parse(
|
||||||
parse(
|
parse(
|
||||||
@@ -600,7 +600,26 @@ it("checks website changes on release-branch pull requests", async () => {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
expect(workflow.on.pull_request.branches).toEqual(["main", "release/*"]);
|
expect(workflow.on).not.toHaveProperty("pull_request");
|
||||||
|
const ci = z
|
||||||
|
.object({
|
||||||
|
jobs: z.object({
|
||||||
|
website: z.object({
|
||||||
|
uses: z.string(),
|
||||||
|
if: z.string(),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
.parse(
|
||||||
|
parse(
|
||||||
|
await readFile(
|
||||||
|
new URL("../../../.github/workflows/ci.yml", import.meta.url),
|
||||||
|
"utf8",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(ci.jobs.website.uses).toBe("./.github/workflows/website-check.yml");
|
||||||
|
expect(ci.jobs.website.if).toBe("needs.changes.outputs.website == 'true'");
|
||||||
});
|
});
|
||||||
|
|
||||||
// Publishing is irreversible. Keep the release authority invariant as a static
|
// Publishing is irreversible. Keep the release authority invariant as a static
|
||||||
|
|||||||
Reference in new issue
Block a user