Repository navigation
Bundle: three race fixes and the gitpython, virtualenv and filelock security bumps - #482
Conversation
test_stdout_noise_is_diverted_and_wire_is_restored[True] failed on 3.12 because the stdio server's stderr carried "child process pid 3098 exit status already read: will report returncode 255" (#472). relay=True forces the Windows-only relays onto POSIX. When the stdin relay exits on its own as the test closes stdin, and _relay_stdin's cleanup runs before the event loop has processed that exit, process.kill() goes through Popen.send_signal, which polls first (bpo-38630). That waitpid reaps the relay, and asyncio's child watcher then finds it gone, reports 255 and logs the warning. On Windows, where the relays run in production, nothing reaps. The three forced-relay tests that compare the server's stderr exactly now read it through _server_stderr, which drops whole lines matching either watcher's warning (pidfd: "exit status already read", threaded: "Unknown child process pid") and keeps everything else. Two tests pin both directions: both warnings are dropped with the surrounding lines intact, and a line that only contains one is kept. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The race is rare on its own, so the first fix only covered the three exact stderr checks it was seen against. Under four xdist workers on korvid-runners it hit a fourth on 3.12, twice: test_stdio_delivers_large_utf8_output_without_truncation[True] expected an empty stderr log and got "child process pid ... exit status already read: will report returncode 255". The forced-relay entrypoint now logs that exact asyncio warning at startup, so every relay=True test that reads the server's stderr has to filter it on every run instead of passing on a lucky one. With the line emitted, exactly that test failed; it now reads its stderr log through _server_stderr, which accepts text as well as bytes, and test_stdio.py passes in full. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Textual's App._shutdown clears _running, removes every screen and widget, and only then sends the App its Unmount, which is where KorvidApp marks the agent session down. A turn the user interrupted just before quitting can settle in between. _finish_interrupted_turn then still sees _shutting_down as False and hands its TurnInterrupted to the panel port, which looks the panel up on a pruned screen. The resulting NoMatches fails the turn task and escapes app shutdown through wait_for_turn (#476). On #471's CI it surfaced as "No nodes match '#agent-status' on AgentPanel()". AppAgentPanel.apply_event, the one place agent events reach the panel, now drops an event once the app is no longer running. The new test reproduces the ordering deterministically: the interrupted turn's cleanup waits for the panel's Unmount, so it settles after Textual pruned the panel and before the App's Unmount. Without the guard it fails with NoMatches every run. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The operation-journey driver read `.confirm-title` as soon as app.screen was a ConfirmScreen. Textual makes a pushed screen current before it composes the screen's widgets, so on a loaded runner the poll landed in between and the read raised "No nodes match '.confirm-title' on ConfirmScreen()". That failed two journeys on main's 3.11 (#478); the second NoMatches in that log came from the journey tearing down after the first. handle() now first waits, through _await_dialog_composed, until the current dialog has its title or is no longer current; a dialog that closes first falls through to the existing closed-before-a-decision path. The new test delays ConfirmScreen's compose by 0.3 seconds and still expects one matched dialog_observed and no hard failures; without the wait it fails every run with CI's exact pair of errors. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Bumps [gitpython](https://github.com/gitpython-developers/GitPython) from 3.1.62 to 3.2.1. - [Release notes](https://github.com/gitpython-developers/GitPython/releases) - [Changelog](https://github.com/gitpython-developers/GitPython/blob/main/doc/source/changes.rst) - [Commits](gitpython-developers/GitPython@3.1.62...3.2.1) --- updated-dependencies: - dependency-name: gitpython dependency-version: 3.2.1 dependency-type: direct:development ... Signed-off-by: dependabot[bot] <support@github.com> (cherry picked from commit 3861683)
Bumps [virtualenv](https://github.com/pypa/virtualenv) from 21.7.13 to 21.14.9. - [Release notes](https://github.com/pypa/virtualenv/releases) - [Changelog](https://github.com/pypa/virtualenv/blob/main/docs/changelog.rst) - [Commits](pypa/virtualenv@21.7.13...21.14.9) --- updated-dependencies: - dependency-name: virtualenv dependency-version: 21.14.9 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> (cherry picked from commit 5e10f14)
Since 2026-10-23 pip-audit fails every branch on filelock 3.32.0: GHSA-v4x8-3wr5-3wq8 (high), GHSA-9vhv-jxww-xfm5 and GHSA-567q-5qvw-pf92, all fixed in 4.2.1 (#480). The locked virtualenv 21.7.13 required filelock<4; the virtualenv 21.14.9 bump in this branch allows <5, so filelock can now move to 4.2.4. These are the bytes the Relock workflow produced and verified on this branch: run 40155755520, package=filelock, base 293d7a8. Its relock job resolved the lock on a runner with direct PyPI access, confirmed every url, registry and index names PyPI, and ran uv sync --locked, ruff, the format check, mypy, tach and the test suite (13,753 passed). Its propose job then could not open a branch, because the base's uv.lock differs from main's (#481), so the relocked-lock artifact was committed by hand after matching its SHA-256 to the digest the relock job recorded before any resolved code ran (493ce1c4...4f96) and re-checking it with main's scripts/check_lock_hosts.py. uv 0.10.9, which the workflow pins, writes lock revision 3 and keeps the httpcore2 and secretstorage markers, so this also returns those lines to main's form: the branch's net lock change is the four version bumps. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
🟡 Changes recommended
The locked virtualenv 21.14.9 has a high-severity command-injection vulnerability fixed in 21.14.13.
No open issues 🎉
What changed in this PR
Bundles three race fixes with dependency security updates for korvid’s Kubernetes TUI and test infrastructure, consolidating previously separate PRs.
Changes:
- Drop agent-panel events during app shutdown and add a regression test.
- Stabilize forced-relay stderr checks and wait for approval dialogs to compose before evaluation.
- Update filelock, GitPython, virtualenv, and packaging in the lockfile.
| File | Description |
|---|---|
uv.lock |
Updates four dependencies and their locked artifacts. |
tests/ui/test_agent_interrupt.py |
Covers an interrupted turn settling after panel removal. |
tests/mcp/test_stdio.py |
Filters known relay warnings and verifies filtering behavior. |
tests/evals/test_operation_journeys.py |
Adds delayed-dialog composition coverage. |
tests/evals/operation_app.py |
Waits for dialog widgets before reading approval details. |
src/korvid/ui/app_surfaces.py |
Drops agent events once the app stops running. |
Review effort: Balanced
virtualenv 21.14.9, the version Dependabot proposed in #474, introduced GHSA-cx6f-vjhg-g3cc / CVE-2026-115586 (high): the Bash activator leaves the --prompt value unescaped in PS1 when promptvars is off, so prompt expansion later executes it. The advisory was published on 2026-10-23, after #474 passed its checks, and this branch's dependency-review check failed on it. It is fixed in 21.14.13, which still allows filelock<5 and needs packaging>=26.3, both already locked here. These are the bytes the Relock workflow produced and verified on this branch: run 40158406513, package=virtualenv, base cd253a2. Its relock job resolved on a runner with direct PyPI access, confirmed every url, registry and index names PyPI, and ran uv sync --locked, ruff, the format check, mypy, tach and the test suite (13,753 passed). Its propose job hit #481 again, so the relocked-lock artifact was committed by hand after matching its SHA-256 to the digest the relock job recorded (1de17a61...95da) and re-checking it with main's scripts/check_lock_hosts.py. Only the virtualenv block changes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Re the review on cd253a2 ("the locked virtualenv 21.14.9 has a high-severity command-injection vulnerability fixed in 21.14.13"): fixed in f243a0a. The Relock workflow moved virtualenv to 21.14.13 on this branch (run 40158406513: only the virtualenv block changes, PyPI-only, and its full gate passed with 13,753 tests). The commit is its verified artifact, digest-matched and host-checked as described in the PR body. 21.14.13 still allows |
Closes #472
Closes #476
Closes #478
Closes #480
Summary
mainrequires a branch to be up to date before it merges, so every merge sent the other open pull requests back through a rebase and a full CI run. This branch carries everything that was open, so it needs one CI run and one merge.0b1a74f1,96a56bd6d64ad2b9b72b03a348929054293d7a85cd253a2ff243a0abThe four fix commits are unchanged from their reviewed pull requests. The two Dependabot commits are cherry-picked with
-x. The netuv.lockchange againstmainis four version bumps: filelock 4.2.4, gitpython 3.2.1, packaging 26.3 and virtualenv 21.14.13.Why the dependency bumps go together.
securityfails on every branch,mainincluded.pip-auditreports GHSA-v4x8-3wr5-3wq8 (high) and two low advisories against filelock 3.32.0, all fixed in 4.2.1.filelock<4, so filelock can only move once virtualenv is 21.14.x, which is build(deps): bump virtualenv from 21.7.13 to 21.14.9 #474.dependency-reviewrun failed on it.securityanddependency-reviewon its own.The relocked locks.
proposejob then could not branch from a base whoseuv.lockdiffers frommain's (Relock: propose fails when the base branch's uv.lock differs from main's #481).relocked-lockartifact, matched to the SHA-256 its relock job recorded before any resolved code ran (493ce1c4…4f96and1de17a61…95da), and re-checked withmain'sscripts/check_lock_hosts.py.uv.lockchange is just the four version bumps.Merging. Please use Rebase and merge, or a merge commit, rather than squash. That keeps the eight commits, two of them Dependabot's, separate in history, so each can be reverted on its own. A squash would fold four dependency bumps into one test-fix commit.
Superseded. #475, #477 and #479 are closed in favour of this branch. Dependabot should close #473 and #474 itself once those packages are at or past their versions on
main; otherwise they can be closed by hand.Verification
cd253a2f, run 40158165378, hosted runners, four xdist workers):test (3.11)10m47s,test (3.12)16m18s,test (3.13)13m20s,windows-test9m24s andsecurityall passed. Onlydependency-reviewfailed, on virtualenv 21.14.9, whichf243a0abfixes.uv.lockwas exactly the union of build(deps-dev): bump gitpython from 3.1.62 to 3.2.1 #473's and build(deps): bump virtualenv from 21.7.13 to 21.14.9 #474's locks; diffed against either branch's lock, only the other branch's packages differ. Each relock changed only its own package block, apart from the revision and marker normalization described above, and every URL names PyPI.uvx pip-auditonuv export --frozen --all-extras --no-emit-project --no-dev, which is the export thesecurityjob audits, found no known vulnerabilities.uv sync --locked, ruff, the format check, mypy, tach andpytest -qpassed: 13,753 passed, 27 skipped, with filelock 4.2.4, and again with virtualenv 21.14.13.Run locally on macOS with Python 3.13, with gitpython 3.2.1, virtualenv 21.14.9, packaging 26.3 and filelock 4.2.1 installed. This machine's package mirror does not have filelock 4.2.4 or virtualenv 21.14.13 yet, so the local runs used the nearest versions it has; the Relock gates and this PR's CI use the locked ones. Each step ran directly with the project's environment rather than through
make, because this machine cannot sync from PyPI:python scripts/check_lock_hosts.py uv.lockpytest -p no:tach tests/test_lockfile.py(final lock)python scripts/check_source_size.pyruff check src/ tests/andruff format --check src/ tests/SKIP=mypy,source-size pre-commit run --from-ref origin/main --to-ref HEADmypytach checkpytest -n 8 -qThis branch's final CI run (
f243a0ab, run on hosted runners with four xdist workers) passed every required check:pre-commit,security,dependency-review,analyze, and:test (3.11)test (3.12)test (3.13)windows-testChecklist
make checkpasses locally.and a fail-closed audit entry, and sensitive reads are still masked.