Skip to content

bench(onthebench): shared measurement lib, generic entrant runner, method overrides - #919

Merged
membphis merged 3 commits into
mainfrom
perf/onthebench-entrants
Aug 10, 2026
Merged

bench(onthebench): shared measurement lib, generic entrant runner, method overrides#919
membphis merged 3 commits into
mainfrom
perf/onthebench-entrants

Conversation

@membphis

@membphis membphis commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

What

Follow-up to #917. Three changes to the same-rig harness, no default-behavior change:

  1. lib.sh — the measurement core (mock lifecycle + TTFT assertion, rig floor, measured windows with CPU%/RSS sampling, validity policy, flamegraph, meta fragments) extracted from run-baseline.sh into one shared file. Both runners below source it, so any two runs are comparable by construction instead of by code review.
  2. run-entrant.sh — a generic runner that measures any gateway-shaped process ("entrant") through the exact same code path: same instruments, core split, windows, floors and validity policy. The entrant contract (documented in the script header) is a sourced entrant.sh providing a start hook that leaves the measured pid in GW_PID, plus optional prepare/teardown hooks, identity metadata, and a request-shape override (REQ_PATH/BODY/AUTH_HEADER) for targets whose only ingress speaks a dialect other than OpenAI chat. Entrant definitions live outside the repository on purpose.
  3. BENCH_* method overrides — grid, reps, window, warmup, max tries, floor reps and flamegraph become env-overridable (defaults unchanged, forwarded by bench.sh), so a two-window spot-check or an added delay tier is an invocation rather than a script edit. Overrides are recorded in meta.json, so a non-default run can never pass silently as the standard grid.

Floors now derive from the grid: one floor per 0-delay tier at its max concurrency (the instrument ceiling barely moves with concurrency there), one floor per concurrency on delayed tiers (the ceiling is ~conc/delay). Under the default grid this reproduces exactly the floors the harness always ran.

Two correctness fixes that fall out of generalizing:

  • Liveness checks use /proc/<pid> existence instead of kill -0, which reports EPERM — reading as death — for a containerized target owned by another user (the RSS sampler would silently record 0).
  • entrant_prepare failures propagate through the tee pipeline (pipefail + explicit message) instead of aborting with no context; the pipeline-subshell semantics are documented in the contract (state hand-off through files, not variables).

Why

The performance program needs same-rig, same-instrument comparisons of multiple gateway targets, and extra load points (e.g. an added delay tier at higher concurrency), without forking the measurement methodology per target. One chokepoint (lib.sh) keeps the family from drifting.

Validation

  • bash -n on all five scripts.
  • Same-rig spot-check of the refactored run-baseline.sh (BENCH_GRID="0:128", byte-identical product binary vs the bench: onthebench-style rig harness for same-rig baselines #917 baseline run) — results recorded in the program tracker, not here.
  • run-entrant.sh exercised against native and containerized targets in the program's measurement session (entrant definitions are deliberately out-of-repo; the results land in the internal tracker).

Summary by CodeRabbit

  • New Features

    • Added benchmarking for gateway-shaped entrant processes, including preparation, validation, resource measurements, and optional flamegraphs.
    • Added configurable benchmark parameters through BENCH_* environment variables.
    • Added concurrency floors across delayed load tiers.
    • Benchmark results now identify the measured entrant and include expanded run metadata.
  • Improvements

    • Standardized measurements, readiness checks, retries, cleanup, and validity tracking across benchmark runs.
    • Configuration overrides are forwarded to remote baseline executions.
    • Improved benchmark documentation covering load grids, validation tiers, configuration, and entrant requirements.

…thod overrides

Extract the measurement core (mock/floor/window/flamegraph primitives,
grid handling, meta fragments) from run-baseline.sh into lib.sh, and add
run-entrant.sh, a runner that measures any gateway-shaped process through
the exact same code path via a small entrant contract (start hook, request
shape override, optional prepare/teardown and identity metadata). Entrant
definitions live outside the repository on purpose.

Method knobs (grid, reps, window, warmup, floor reps, flamegraph) become
BENCH_* environment overrides with unchanged defaults, forwarded by
bench.sh, so a spot-check or an added delay tier is an invocation rather
than a script edit. Floors derive from the grid: one per 0-delay tier at
its max concurrency, one per concurrency on delayed tiers where the
instrument ceiling is ~conc/delay.

Liveness checks use /proc existence instead of kill -0, which reports
EPERM (reading as death) for containerized targets owned by another user.

Default-grid behavior of run-baseline.sh is unchanged; same-rig
spot-checks against the existing baseline validate the refactor.
Copilot AI balanced review requested due to automatic review settings August 10, 2026 08:32
@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The benchmark harness centralizes configuration, validation, measurements, metadata, grid execution, retries, and flamegraph capture. The baseline runner uses these helpers. A new entrant runner benchmarks external gateway-shaped processes with configurable hooks and target metadata.

Changes

Benchmark harness

Layer / File(s) Summary
Shared harness lifecycle and measurement
bench/onthebench/lib.sh
Shared helpers manage configuration, process cleanup, rig validation, readiness checks, resource measurements, request execution, validity tracking, JSONL results, and metadata.
Grid floors, retries, and profiling
bench/onthebench/lib.sh, bench/onthebench/README.md
Zero-delay tiers use the largest configured concurrency for floors. Delayed tiers use one floor per concurrency. Validity retries and optional flamegraph capture are documented and implemented.
Baseline runner integration
bench/onthebench/bench.sh, bench/onthebench/run-baseline.sh
The baseline runner uses shared tier execution and gateway startup. The launcher forwards escaped BENCH_* overrides and commit metadata.
Entrant target benchmarking
bench/onthebench/run-entrant.sh, bench/onthebench/README.md
A new runner supports entrant preparation, target startup, readiness checks, identity metadata, tiered measurements, RSS high-water marks, and symbolized flamegraphs. Output records the entrant name.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant EntrantRunner
  participant EntrantTarget
  participant MockService
  participant LoadGenerator
  participant Results
  EntrantRunner->>EntrantTarget: invoke entrant_start
  EntrantRunner->>EntrantTarget: wait for HTTP readiness
  EntrantRunner->>MockService: start mock for TTFT tier
  EntrantRunner->>LoadGenerator: run floor and concurrency points
  LoadGenerator->>EntrantTarget: send benchmark requests
  EntrantRunner->>Results: append measurements and metadata
Loading

Possibly related PRs

  • api7/aisix#917: Introduces the benchmark harness and baseline runner that this change refactors and extends.

Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error, 1 inconclusive)

Check name Status Explanation Resolution
Security Check ❌ Error Category 1 CRITICAL: entrant AUTH_HEADER is converted to OTB_LOADGEN_HEADERS and serialized in meta.json as loadgen_headers without redaction (lib.sh:29-38, 358-365). Do not store authentication headers or request bodies in metadata; record only redacted header names or a hash, and keep secrets out of the exported load-generator environment when starting entrants.
E2e Test Quality Review ❓ Inconclusive The custom check requires E2E test completeness, but this PR is a benchmarking harness refactor, not a feature implementation. It lacks conventional test files (test*.ts, test*.sh, etc.) and the ch... Clarify whether E2E tests apply: this PR refactors benchmark infrastructure via code reuse (lib.sh) and adds validation (bash -n, runtime spot-checks), not conventional application tests. If the check intends infrastructure/script qualit...
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main changes: shared measurement logic, a generic entrant runner, and configurable method overrides.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch perf/onthebench-entrants

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Extracts shared benchmarking logic and adds support for configurable methods and external gateway entrants.

Changes:

  • Adds shared measurement and metadata utilities.
  • Introduces a generic entrant runner.
  • Supports forwarded BENCH_* overrides and documents usage.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
bench/onthebench/lib.sh Adds shared benchmark measurement logic.
bench/onthebench/run-entrant.sh Adds the generic entrant runner.
bench/onthebench/run-baseline.sh Migrates baseline execution to the shared library.
bench/onthebench/bench.sh Forwards method overrides to the rig.
bench/onthebench/README.md Documents overrides, floors, and entrants.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread bench/onthebench/lib.sh Outdated
Comment on lines +31 to +34
if [ -z "${OTB_LOADGEN_HEADERS:-}" ]; then
OTB_LOADGEN_HEADERS='[["'"${AUTH_HEADER%%:*}"'","'"${AUTH_HEADER#*: }"'"]]'
fi
export OTB_LOADGEN_HEADERS
Comment thread bench/onthebench/run-entrant.sh Outdated
# shellcheck source=lib.sh
source "$(dirname "${BASH_SOURCE[0]}")/lib.sh"

[ -n "$ENTRANT_NAME" ] || { echo "FATAL: entrant.sh must set ENTRANT_NAME"; exit 1; }
Comment thread bench/onthebench/run-entrant.sh Outdated
Comment on lines +86 to +100
local bin_sha
bin_sha=$(sudo -n sha256sum "/proc/$GW_PID/exe" 2>/dev/null | cut -d' ' -f1 || true)
cat > "$OUT/meta.json" <<EOF
{
"entrant": "$ENTRANT_NAME",
"timestamp_utc": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
"rig": $(meta_rig_json),
"cores": $(meta_cores_json),
"instruments": $(meta_instruments_json),
"method": $(meta_method_json),
"target": {
"binary_sha256": "${bin_sha:-unknown}",
"rss_idle_kb": ${RSS_IDLE:-null}, "rss_hwm_kb": $1,
"threads": ${THREADS:-null},
"identity": $(type entrant_meta_json >/dev/null 2>&1 && entrant_meta_json || echo null)

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@bench/onthebench/bench.sh`:
- Around line 49-53: Replace the short-circuit statement in
bench/onthebench/bench.sh lines 49-53 with an if block that appends each set
BENCH_* override to ENVPASS, allowing unset variables without returning failure.
Also update the symbol-check logic in bench/onthebench/run-baseline.sh lines
30-32 to call require_symbols "$BIN" only when FLAMEGRAPH equals 1, so a zero
value continues to bench_init.

In `@bench/onthebench/lib.sh`:
- Around line 169-178: Make both cpu_ticks reads in the measurement flow
fallible, including the read after loadgen, and detect when the target has
exited; in that case set gw_cpu_pct to null and force valid=false. Ensure
cleanup and JSONL record generation still execute under errexit so retry and
HARNESS_RC handling remain effective. Add a regression test that terminates the
target during a measurement window and verifies the invalid record is preserved.
- Around line 15-21: Validate all BENCH_* overrides before measurement: require
positive WINDOW, WARMUP, REPS, MAX_TRIES, and FLOOR_REPS values, a non-empty
BENCH_GRID containing valid ttft_ms:conc entries, and BENCH_FLAMEGRAPH
restricted to 0 or 1; make invalid settings exit nonzero before reporting
success. Update bench/onthebench/README.md lines 71-77 to document the accepted
values and ranges for every override, explicitly describing BENCH_FLAMEGRAPH as
0|1. Add regression tests covering invalid overrides and confirming they fail
before a benchmark run succeeds; if any validation range is ambiguous, state the
assumption or request clarification rather than silently choosing one.
- Around line 203-212: Update the floor loop around loadgen and the floor JSON
emission to use the same validity fields and rules as measured_window, including
rigrefused, budgetexceeded, and spawnfailed, so none can count toward valid_n.
Normalize missing rps, p50_us, and p99_us values to JSON null, including when
loadgen returns an empty line, while preserving valid numeric metrics. Add
regression coverage for an empty loadgen result and each invalidity flag.

In `@bench/onthebench/run-entrant.sh`:
- Line 49: Define and enforce a JSON-safe ENTRANT_NAME contract in
run-entrant.sh: either JSON-escape the value before meta.json generation or
validate it against a documented safe identifier pattern such as [A-Za-z0-9._-]+
and reject invalid names before the existing nonempty check succeeds. Add
regression coverage for names containing JSON-special characters, and state the
chosen validation/escaping assumption explicitly.
- Around line 122-126: Update the symbol discovery command in the flamegraph
conditional around flamegraph_point to invoke nm through sudo -n for
/proc/$GW_PID/exe, while preserving the existing warning path when privileged
access fails or no text symbols are found.
- Around line 59-60: Update the preparation flow around entrant_prepare so it
runs as a standalone command rather than a pipeline element, while still writing
output to "$OUT/prepare.log" and displaying it on stderr. Preserve the existing
fatal message and exit behavior through an ERR/error-reporting path, and add a
regression case where a non-final command inside entrant_prepare fails to ensure
preparation cannot report success.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 29b1b85b-666f-431a-9fc9-7f3e5c5b0c36

📥 Commits

Reviewing files that changed from the base of the PR and between afe9ade and 3fbcf1b.

📒 Files selected for processing (5)
  • bench/onthebench/README.md
  • bench/onthebench/bench.sh
  • bench/onthebench/lib.sh
  • bench/onthebench/run-baseline.sh
  • bench/onthebench/run-entrant.sh

Comment thread bench/onthebench/bench.sh
Comment thread bench/onthebench/lib.sh
Comment thread bench/onthebench/lib.sh Outdated
Comment thread bench/onthebench/lib.sh Outdated
Comment thread bench/onthebench/run-entrant.sh Outdated
Comment thread bench/onthebench/run-entrant.sh Outdated
Comment thread bench/onthebench/run-entrant.sh Outdated
Comment on lines +122 to +126
if nm "/proc/$GW_PID/exe" 2>/dev/null | grep -q ' [tT] '; then
flamegraph_point 128 "$ENTRANT_NAME c=128 0-delay (4 pinned cores)"
else
echo "WARNING: target binary is stripped or unreadable; skipping flamegraph" >&2
fi

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use privileged symbol discovery for /proc/$GW_PID/exe.

/proc/$GW_PID/exe can belong to another user, and the unprivileged nm "/proc/$GW_PID/exe" at line 122 may fail while the earlier process check succeeds. Use sudo -n nm "/proc/$GW_PID/exe" and retain the warning when symbol access or symbols are unavailable.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@bench/onthebench/run-entrant.sh` around lines 122 - 126, Update the symbol
discovery command in the flamegraph conditional around flamegraph_point to
invoke nm through sudo -n for /proc/$GW_PID/exe, while preserving the existing
warning path when privileged access fails or no text symbols are found.

- grid_concs: use if instead of && so the function cannot return nonzero
  when the last grid element belongs to another tier; under set -e +
  pipefail the floor-conc assignment killed the default-grid run silently
  before the first floor window.
- entrant_prepare: run the hook in an explicit errexit subshell and check
  PIPESTATUS[0]; the previous 'pipeline || die' form disabled errexit
  inside the hook, letting a mid-prepare failure pass as success.
- Record and warn about child processes of the measured pid: per-pid
  CPU%/RSS silently understates multi-process targets; the count lands in
  meta.json as target.children.
- THREADS capture no longer appends a second line when ps fails under
  pipefail; flamegraph 'enabled' in meta reflects the grid gate as well as
  the knob; OTB_LOADGEN_HEADERS derives via json.dumps so quotes or
  backslashes in a header value cannot emit invalid JSON; the entrant
  flamegraph gate reuses the >100 text-symbol threshold instead of >=1;
  contract header documents entrant_stop idempotency and which harness
  variables hook bodies may use.
@membphis

Copy link
Copy Markdown
Contributor Author

Independent cold-context audit ran against 3fbcf1b; all findings addressed in 5b32e4c:

  • HIGH-1 (grid_concs returns nonzero when the last grid element is another tier's; default-grid run dies silently at the first floor under set -e + pipefail) — fixed with the if form; a shortened default-grid live run on the rig re-validates the exact failing path (results in the internal tracker).
  • MEDIUM-1 (prepare || die disables errexit inside the hook; mid-prepare failures passed as success) — hook now runs in an explicit ( set -e; ... ) subshell with PIPESTATUS[0] checked.
  • MEDIUM-2 (per-pid CPU%/RSS silently understates multi-process targets) — child-process count is warned about at start and recorded as target.children in meta.json; summing over descendants would change the method mid-program, so surfacing is the chosen floor. All targets measured in the current program are single-process (thread-based); a multi-process entrant would show children > 0 and its CPU/RSS treated as a lower bound.
  • LOW-1..5 — THREADS double-line capture, flamegraph enabled now gated on grid content, headers list derived via json.dumps, entrant flamegraph symbol threshold aligned to >100, contract header documents entrant_stop idempotency and hook-time variable availability.

Re-validation performed on the rig: (a) shortened default-grid baseline run (BENCH_REPS=1 BENCH_FLOOR_REPS=1 BENCH_WINDOW=5 BENCH_WARMUP=1) exercising the HIGH-1 path; (b) an entrant run whose grid ends in a delayed tier. Numbers live in the internal tracker per program policy.

- Validate BENCH_* overrides at startup: grid entries must be
  ttft_ms:conc with positive concurrency, counts must be positive
  integers (warmup may be 0), flamegraph knob must be 0 or 1 - zero-rep
  runs could previously report success while measuring nothing.
- Record a target that dies mid-window as an invalid window: CPU tick
  reads are now fallible, cpu_pct goes null and valid=false, and the
  JSONL line still lands instead of the runner dying at a missing
  /proc/<pid>/stat.
- Bring floor windows up to gateway-window validity: rigrefused,
  budgetexceeded and spawnfailed now invalidate a floor, and an empty
  loadgen line records nulls instead of invalid JSON.
- Always derive OTB_LOADGEN_HEADERS from AUTH_HEADER; an ambient value
  would let measured requests carry credentials the readiness check
  never exercised.
- Constrain ENTRANT_NAME to [A-Za-z0-9._-]+ (spliced verbatim into
  JSON); validate entrant_meta_json output before it reaches meta.json
  and fail loudly on hook failure or unparseable output.
- Replace remaining statement-position '[ cond ] && cmd' with if-form
  (the pattern behind the earlier grid_concs regression), and document
  override value domains in the README.
@membphis

Copy link
Copy Markdown
Contributor Author

Disposition of the 10 inline bot findings, addressed in 9f756fe (all fixes re-validated with a shortened default-grid run on the rig):

Fixed

  • lib.sh BENCH_* validation (coderabbit lib.sh:21) — grid entries, counts and the flamegraph knob are validated at startup; zero-rep runs can no longer report success while measuring nothing. Value domains documented in the README. No bash test infra exists for bench/ in this repo; the regression check is the recorded live-rig validation run, per the harness's existing practice.
  • Target death mid-window (coderabbit lib.sh:182) — CPU tick reads are fallible; cpu_pct records null, the window records valid=false, and the JSONL line lands instead of the runner dying on a missing /proc/<pid>/stat.
  • Floor validity parity (coderabbit lib.sh:216) — floors now reject rigrefused/budgetexceeded/spawnfailed like gateway windows, and an empty loadgen line records nulls, not invalid JSON.
  • Header derivation (copilot lib.sh:38) — OTB_LOADGEN_HEADERS is now always derived from AUTH_HEADER (json.dumps on the first-colon split); an ambient value can no longer diverge from what the readiness check exercised.
  • ENTRANT_NAME JSON safety (copilot + coderabbit run-entrant.sh:55) — constrained to [A-Za-z0-9._-]+ at startup.
  • entrant_meta_json validation (copilot run-entrant.sh:120) — the hook is evaluated before the heredoc; hook failure or unparseable output fails the run loudly instead of shipping a null/invalid identity.
  • Statement-position [ cond ] && cmd (coderabbit bench.sh:53) — converted to if form in both flagged sites as class hygiene: the claim that these sites abort the run is not correct (&&-list context is errexit-exempt, and live runs with all overrides unset / BENCH_FLAMEGRAPH=0 completed exit 0 before this change), but the same pattern in function-return position is exactly how the earlier grid_concs regression happened, so the class is now gone entirely.

No change, with reasons

  • entrant_prepare in a pipeline (coderabbit run-entrant.sh:60) — already fixed in 5b32e4c: the hook runs inside an explicit ( set -e; … ) subshell, which re-arms errexit regardless of pipeline context, and PIPESTATUS[0] is checked. Reproduction of the exact current form: a hook with a failing first step and succeeding last step yields rc=1 and does not continue past the failure. The quoted repro tests the pre-5b32e4c form.
  • sudo -n nm for /proc/<pid>/exe (coderabbit run-entrant.sh:126) — rejected: with kernel.perf_event_paranoid=1, perf record -p cannot attach to another user's process anyway, so escalating the symbol probe would only let the run proceed into a guaranteed perf failure. The unreadable-exe skip is the correct gate; flamegraph-bearing entrants run as the rig user by contract.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@bench/onthebench/run-entrant.sh`:
- Around line 113-117: Update the JSON validation in the entrant_meta_json
handling block to require that the parsed value is a JSON object, rejecting
strings, arrays, numbers, booleans, and null while preserving the existing
failure message and exit behavior. Keep the identity assignment and valid-object
flow unchanged.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: df9af1e2-8b2a-4f72-9c67-6265873bad28

📥 Commits

Reviewing files that changed from the base of the PR and between 3fbcf1b and 9f756fe.

📒 Files selected for processing (5)
  • bench/onthebench/README.md
  • bench/onthebench/bench.sh
  • bench/onthebench/lib.sh
  • bench/onthebench/run-baseline.sh
  • bench/onthebench/run-entrant.sh
🚧 Files skipped from review as they are similar to previous changes (3)
  • bench/onthebench/README.md
  • bench/onthebench/lib.sh
  • bench/onthebench/run-baseline.sh

Comment on lines +113 to +117
if type entrant_meta_json >/dev/null 2>&1; then
identity=$(entrant_meta_json) ||
{ echo "FATAL: entrant_meta_json failed"; exit 1; }
printf '%s' "$identity" | python3 -c 'import json,sys; json.load(sys.stdin)' ||
{ echo "FATAL: entrant_meta_json returned invalid JSON: $identity"; exit 1; }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== file outline/lines =="
wc -l bench/onthebench/run-entrant.sh
sed -n '1,180p' bench/onthebench/run-entrant.sh | nl -ba

echo "== references to entrant_meta_json =="
rg -n "entrant_meta_json|target\.identity|ENTRANT_META_JSON|identity" bench/onthebench or thebench . || true

echo "== json scalar object behavior probe =="
python3 - <<'PY'
import json, subprocess, textwrap

for value in ["1", '"a"', "[1]", "{}", "null"]:
    res = subprocess.run(["python3", "-c",
        "import json,sys; json.load(sys.stdin)"],
        input=value.encode(), text=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    obj_res = subprocess.run(["python3", "-c",
        "import json,sys; value=json.load(sys.stdin); sys.exit(not isinstance(value, dict))"],
        input=value.encode(), text=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    print(value, "load_exit", res.returncode, "load_type", type(json.loads(value)).__name__,
          "is_dict_exit", obj_res.returncode)
PY

Repository: api7/aisix

Length of output: 249


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== lines 1-180 =="
sed -n '1,180p' bench/onthebench/run-entrant.sh | sed 's/^/L /'

echo "== references to entrant_meta_json =="
rg -n "entrant_meta_json|target\.identity|ENTRANT_META_JSON|identity" bench/onthebench || true

echo "== json scalar object behavior probe =="
python3 - <<'PY'
import json, subprocess

for value in ["1", '"a"', "[1]", "{}", "null"]:
    res = subprocess.run(["python3", "-c", "import json,sys; json.load(sys.stdin)"],
        input=value.encode(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    obj_res = subprocess.run(["python3", "-c", "import json,sys; value=json.load(sys.stdin); sys.exit(not isinstance(value, dict))"],
        input=value.encode(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    print(value, "load_exit", res.returncode, "parsed_type", type(json.loads(value)).__name__, "is_dict_exit", obj_res.returncode)
PY

Repository: api7/aisix

Length of output: 10232


Require a JSON object from entrant_meta_json.

The hook is documented as a JSON object, but the current validation accepts any valid JSON value. A string, array, number, or null makes target.identity an invalid stable type. Reject non-object JSON.

Proposed fix
-        printf '%s' "$identity" | python3 -c 'import json,sys; json.load(sys.stdin)' ||
-            { echo "FATAL: entrant_meta_json returned invalid JSON: $identity"; exit 1; }
+        printf '%s' "$identity" |
+            python3 -c 'import json,sys; value=json.load(sys.stdin); sys.exit(not isinstance(value, dict))' ||
+            { echo "FATAL: entrant_meta_json must return a valid JSON object: $identity"; exit 1; }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if type entrant_meta_json >/dev/null 2>&1; then
identity=$(entrant_meta_json) ||
{ echo "FATAL: entrant_meta_json failed"; exit 1; }
printf '%s' "$identity" | python3 -c 'import json,sys; json.load(sys.stdin)' ||
{ echo "FATAL: entrant_meta_json returned invalid JSON: $identity"; exit 1; }
if type entrant_meta_json >/dev/null 2>&1; then
identity=$(entrant_meta_json) ||
{ echo "FATAL: entrant_meta_json failed"; exit 1; }
printf '%s' "$identity" |
python3 -c 'import json,sys; value=json.load(sys.stdin); sys.exit(not isinstance(value, dict))' ||
{ echo "FATAL: entrant_meta_json must return a valid JSON object: $identity"; exit 1; }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@bench/onthebench/run-entrant.sh` around lines 113 - 117, Update the JSON
validation in the entrant_meta_json handling block to require that the parsed
value is a JSON object, rejecting strings, arrays, numbers, booleans, and null
while preserving the existing failure message and exit behavior. Keep the
identity assignment and valid-object flow unchanged.

Source: Coding guidelines

@membphis
membphis merged commit 51e0883 into main Aug 10, 2026
12 checks passed
@membphis
membphis deleted the perf/onthebench-entrants branch August 10, 2026 16:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants