mirror of
https://github.com/callstack/agent-device.git
synced 2026-09-14 20:06:34 +08:00
539e848e0c
* fix(ci): stop ten artifact uploads discarding their hidden paths `actions/upload-artifact` has excluded hidden files and directories by default since v4.4 (this repository pins v4.6.2), and most diagnostics here are written under `.tmp`. Ten upload steps across seven files therefore uploaded nothing from those paths: macos.yml's xcresult bundle, both mutation lanes' reports and shards, replays-nightly's fuzz output, xctest-nightly's results, test-app-build-cache's fixture tarball, and 1874-diagnose's per-iteration logs. Most fail silently, since they pair the omission with `if-no-files-found: warn` or `ignore`. test-app-build-cache sets `error`, so that one does not. A structural guard rather than a shared upload wrapper: the wrapper would be a shallow mirror of the action's options over artifacts with different owners, while the policy question — a hidden path needs the flag — is one rule that belongs in one place. Each workflow still declares its own artifact. test/ci/upload-artifact-hidden-paths.test.ts holds it across every workflow and composite action, and is red if any single flag is dropped. * test(ci): scan every YAML shape GitHub accepts, not just top-level *.yml The guard read `.github/workflows/*.yml` and assumed local actions live one directory deep as `action.yml`. GitHub also reads `.yaml` for both, and local actions nest, so a hidden-path upload in any of those shapes passed the gate. It now walks the `.github` tree recursively for either extension, and a second test plants the three shapes the old scan missed and asserts all three are found — executable rather than a one-off manual check. Red against narrowing the extension, against dropping the recursive walk, and against removing any single real flag. Also drops the action-version note under the comment rule in #2087; the version behaviour belongs in the PR, and the assertion message already says what the omission costs.
117 lines
4.7 KiB
YAML
117 lines
4.7 KiB
YAML
name: Replay Nightly
|
|
|
|
# The device replay suites this workflow used to carry moved to replays-manual.yml (#1781 A1)
|
|
# after failing every scheduled run from 2026-07-24 on. What stays here is what a schedule can
|
|
# still keep honest: the device-free parser fuzz lane.
|
|
|
|
on:
|
|
schedule:
|
|
- cron: '0 3 * * *'
|
|
workflow_dispatch:
|
|
inputs:
|
|
fuzz-iterations:
|
|
description: 'Parser fuzz cases per target'
|
|
required: false
|
|
default: '38000'
|
|
fuzz-seed:
|
|
description: 'Parser fuzz PRNG seed (defaults to the run number)'
|
|
required: false
|
|
|
|
permissions:
|
|
contents: read
|
|
actions: read
|
|
|
|
concurrency:
|
|
group: ci-${{ github.workflow }}-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
jobs:
|
|
# Parser fuzz lane (#1414, validation targets #1781 B2): hostile input into parseArgs,
|
|
# selector parsing, .ad replay scripts, batch --steps JSON, and the Maestro compat parser,
|
|
# plus schema-derived CLI/Maestro validation cases that assert a planted outcome (specific
|
|
# error code, or acceptance) so a silent acceptance is a finding too. Every rejection must
|
|
# be a typed AppError with a non-empty hint, and no case hangs. Device-free, so it rides
|
|
# this nightly rather than owning a workflow; the seed varies per run so the lane keeps
|
|
# exploring, and anything it catches is appended to the checked-in corpus that the unit
|
|
# lane replays (scripts/fuzz/corpus/regressions.json).
|
|
#
|
|
# 38,000 cases/target holds the job's wall-clock at the pre-B2 five-target/50k budget now that
|
|
# seven targets share it: measured on a quiet host, 7x38k = 16.5s against 5x50k = 16.6-16.9s.
|
|
# Chosen by measurement rather than rounding — 33k would have been 2s cheaper but cost the
|
|
# five untouched targets a third of their depth for no wall-clock reason. The count is
|
|
# unchanged by #2053; moving case execution out of process cost that run about 3s (17.8s ->
|
|
# 20.9s, best of three on one host), which buys a case that faults its process a named
|
|
# `crash` failure instead of a dead caller.
|
|
nightly-parser-fuzz:
|
|
name: Parser Fuzz Lane
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 20
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
|
|
- name: Setup toolchain
|
|
uses: ./.github/actions/setup-node-pnpm
|
|
|
|
# A lane whose classifier or watchdog regressed would pass forever. This runs the
|
|
# broken-on-purpose targets first and fails unless each violation is caught.
|
|
- name: Self-check the harness
|
|
uses: ./.github/actions/run-gate
|
|
with:
|
|
gate: fuzz-parsers
|
|
args: |
|
|
--self-check
|
|
--artifact-dir
|
|
.tmp/fuzz/self-check
|
|
|
|
# Runs even when the self-check fails, so the lane always produces a fuzz envelope too
|
|
# (a step that never runs writes no envelope, and monitoring cannot tell that apart from
|
|
# a lane that went dark). The job still fails because both steps report their status.
|
|
- name: Fuzz parsers
|
|
if: always()
|
|
env:
|
|
FUZZ_ITERATIONS: ${{ github.event.inputs.fuzz-iterations || '38000' }}
|
|
FUZZ_SEED: ${{ github.event.inputs.fuzz-seed || github.run_number }}
|
|
uses: ./.github/actions/run-gate
|
|
with:
|
|
gate: fuzz-parsers
|
|
args: |
|
|
--iterations
|
|
${{ env.FUZZ_ITERATIONS }}
|
|
--seed
|
|
${{ env.FUZZ_SEED }}
|
|
--artifact-dir
|
|
.tmp/fuzz/run
|
|
|
|
# Uploaded on pass as well as failure: each subdirectory of .tmp/fuzz holds a
|
|
# run-envelope.json on #1430's shared lane contract (scripts/lib/lane-envelope.ts) —
|
|
# commit/ref/run provenance, tool + config hash, seed, result — which is what freshness
|
|
# monitoring reads.
|
|
- name: Upload run envelopes and failing cases
|
|
if: always()
|
|
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
|
with:
|
|
name: parser-fuzz-run-${{ github.run_id }}-${{ github.run_attempt }}
|
|
include-hidden-files: true
|
|
path: .tmp/fuzz
|
|
if-no-files-found: warn
|
|
|
|
# Never fails the job on its own: a missing envelope is reported as such rather than
|
|
# masking the real failure with a `cat` error.
|
|
- name: Summarize
|
|
if: always()
|
|
run: |
|
|
{
|
|
echo '### Parser fuzz lane'
|
|
found=0
|
|
for envelope in .tmp/fuzz/*/run-envelope.json; do
|
|
[ -f "$envelope" ] || continue
|
|
found=1
|
|
echo "#### $envelope"
|
|
echo '```json'
|
|
cat "$envelope"
|
|
echo '```'
|
|
done
|
|
[ "$found" = 1 ] || echo 'No run envelope was produced — the lane failed before it could run.'
|
|
} >> "$GITHUB_STEP_SUMMARY"
|