Skip to content

fix(agent-challenge): stop public log redaction from wedging the event loop - #66

Open
echobt wants to merge 1 commit into
mainfrom
fix/public-task-event-redaction-redos
Open

fix(agent-challenge): stop public log redaction from wedging the event loop#66
echobt wants to merge 1 commit into
mainfrom
fix/public-task-event-redaction-redos

Conversation

@echobt

@echobt echobt commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Summary

  • A catastrophic-backtracking regex in the public task-event redaction path pinned the validator event loop at 100% CPU, starving the evaluation worker and freezing the job queue in production.
  • Redaction is rewritten as a single linear pass. Redaction decisions are unchanged.

Root cause

_PUBLIC_SECRET_SEGMENT_RE nested (?:[A-Za-z0-9_.]+[-_.])* over a character class that also contained the separators _ and .. Any dotted or underscored run that never reached secret/token could therefore be split in exponentially many ways before the match failed.

Measured on the live pattern:

input time
37 chars 23 ms
61 chars 91 s

Terminal-Bench task events carry pip output (Successfully installed agent-challenge-1.0.1 aiohappyeyeballs-2.7.1 ...), which is exactly that shape, and get_submission_task_events replays it on an unauthenticated endpoint. One log line was enough to wedge the loop.

Observed in production: py-spy showed the main thread parked in _public_task_event_text (routes.py:5108) with wchan=0, validator at 101% CPU, a job stuck running for hours with no containers and no log events.

Because the endpoint is public and unauthenticated, this was also a remote denial-of-service vector.

Changes

  • Replace the nested-quantifier regex with _PUBLIC_SECRET_WORD_RE (one linear pass over delimited words) plus two bounded marker checks.
  • Redaction semantics preserved: whole-segment token redacted, count-dataset-tokens left alone, secret/raw-ref/broker-ref/pod- markers redacted, surrounding text untouched.

Test plan

  • New regression test: pathological input must sanitize in under 1s. Before the fix this file hung past a 10-minute timeout; it now runs in 0.11s.
  • New test: realistic pip output stays fast and is not redacted.
  • Existing redaction contracts green (test_public_task_event_redaction.py, test_frontend_api_contract.py, test_submission_status.py — 21 passed).
  • Full package suite: 2309 passed / 24 failed, and an A/B against clean main reproduces the same 24 failures, so they are pre-existing and unrelated.
  • ruff check and ruff format --check clean.
  • Verified on the production validator: pathological 241-char input went from unbounded to 0.30 ms; four own-runner-task-* containers started within seconds and CPU settled at 6.6%.

CI

  • Waiting for required checks to go green on this head SHA.

Notes

  • The fix is already hot-patched onto the live validator to unblock the queue; this PR makes it durable.
  • Out of scope: construction fail-fast currently sits in the orchestrator, which never trips under the real one-task-per-runner topology. That belongs in the validator task loop and is tracked separately.

Summary by CodeRabbit

  • Bug Fixes

    • Improved redaction of secrets and tokens in public task-event text.
    • Prevented slowdowns when processing long or complex text.
    • Reduced the risk of incorrectly redacting legitimate package and version information.
  • Tests

    • Added coverage for fast processing of large and realistic command output.

…t loop

_PUBLIC_SECRET_SEGMENT_RE nested (?:[A-Za-z0-9_.]+[-_.])* over a character
class that also contained the separators _ and ., so any dotted or
underscored run that never reached secret/token could be split in
exponentially many ways. Measured on the live pattern: 37 characters took
23ms and 61 characters took 91s.

Terminal-Bench task events carry pip output, which has exactly that shape,
and get_submission_task_events replays them on an unauthenticated endpoint.
One log line therefore pinned the validator event loop at 100% CPU, starved
the evaluation worker, and left a job stuck running with no containers and
no logs for hours.

Redaction is now a single linear pass over delimited words plus two bounded
marker checks, which keeps the previous redaction decisions unchanged:
whole-segment token matches, tokens left alone, secret markers redacted.
@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 69e34c4f-690d-41ab-bf95-f2f92315f6ed

📥 Commits

Reviewing files that changed from the base of the PR and between 7b076d3 and 32ca672.

📒 Files selected for processing (2)
  • packages/challenges/agent-challenge/src/agent_challenge/api/routes.py
  • packages/challenges/agent-challenge/tests/test_public_task_event_redaction.py

📝 Walkthrough

Walkthrough

The task-event text redaction path replaces a monolithic secret-matching regex with bounded candidate and marker checks. New tests cover dotted-input performance and preservation of non-secret identifiers in realistic pip output.

Changes

Public secret redaction

Layer / File(s) Summary
Bounded redaction implementation
packages/challenges/agent-challenge/src/agent_challenge/api/routes.py
Adds candidate-word and marker regexes, introduces _redact_public_secret_segments(...), and routes _public_task_event_text(...) through it.
Performance and preservation validation
packages/challenges/agent-challenge/tests/test_public_task_event_redaction.py
Adds timing tests for dotted/underscored input and repeated pip output, while checking that agent-challenge-1.0.1 remains unredacted.

Estimated code review effort: 3 (Moderate) | ~20 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main fix: replacing public log redaction logic to prevent event-loop wedging.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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 fix/public-task-event-redaction-redos

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.

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.

1 participant