Repository navigation
fix(client): accept a secret that arrived before the read deadline - #27
Merged
Merged
Conversation
read_owned failed as soon as its 250 ms deadline had passed, before it looked at the descriptor again. A receiver that was not scheduled for 250 ms after fixing the deadline therefore failed and closed the descriptor even when the secret and its EOF were already buffered (#24). The deadline now bounds only waiting for bytes that have not arrived. Once it has passed, poll does not wait and a pass that makes no progress fails, so the receiver takes only bytes and an EOF that are already readable. A writer that never writes or never closes still fails. read_owned_by takes the deadline, so the tests stand an already-passed deadline in for the stall on both platforms. The contract describes the new bound in English and Korean; the contracts hashes are recorded. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This was referenced Oct 8, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Requested by Seongjae · project thread
Fixes #24. It is an independent product fix outside CS-RG, made before CS-RG U4 as #24 asks, the same way novelKR/CodeSpace#87 fixed novelKR/CodeSpace#85 before U3. CodeSpace picks it up only through a separate pin change that needs the owner's approval.
Why
Before:
read_ownedfixed a 250 ms deadline and, on every pass, failed as soon as the deadline had passed, before it looked at the descriptor again. A receiver that was not scheduled for 250 ms therefore failed withinvalid, missing or expired private credential FDand closed its one-shot descriptor, even when the whole secret and its EOF had been written in time. CodeSpace's macOS CI saw this in 4 of 143 gateway runs and in about one in ten registration stages (#24).After: the 250 ms deadline bounds only waiting for bytes that have not arrived. Once it has passed, the receiver still takes bytes and an EOF that are already readable, and it fails on the first pass that finds nothing. A writer that never writes or never closes still fails at the deadline, as before.
This matters most for the launch helper.
devguard-launchre-executes itself at utility QoS and only then reads its one-time permit (crates/launch/src/main.rs:172-195), afterBeginLaunchhas committed the launch, so a lost permit read leaves the owner to release the attempt withAbandonLaunch { HelperExited }. CS-RG U4 is the first CodeSpace unit to run the helper. The othertake_inheritedcallers (the CodeSpace UDS worker's consumer secret, and the lease tokens ofdevguard execanddevguardd candidate) gain the same tolerance.Changes
crates/client/src/credential.rsread_owneddelegates to a privateread_owned_by(fd, deadline). Past the deadline,polluses a zero timeout, and anEINTRfrompollor a read that returnsWouldBlockorInterruptedfails instead of looping, so each further pass takes at least one byte or the EOF and the loop stays bounded. Before the deadline the loop is unchanged. Two unit tests stand an already-passed deadline in for the stall: a secret written and closed in time is accepted, and an empty, half-written or EOF-less secret still fails withUnauthorizeddocs/contracts.md,docs/ko/contracts.mdCredentialHandoffparagraph states the new bounddocs/translations.jsoncontractshashes recorded withscripts/check_docs.py recordWhat does not change
docs/contracts.md:19) and the helper's 250 ms authorization deadline (docs/contracts.md:95). A reply that misses them is still a refusal, and the helper still never execs on one.f1f9084and its session retries until a separate change.0.1.0-5daee5d-b3fa569eis not rebuilt. An installed helper gets the fix only from a new release, which is a separate decision.Verification
At
3ae5dc2, based onmainat035936d, in a Linux x86_64 container with Rust 1.95.0:main's deadline loop restored under this head'sread_owned_bysplit,a_secret_written_and_closed_in_time_is_read_after_the_deadlinefails, which reproduces Credential reader rejects an already-buffered secret when its thread stalls for 250 ms #24 deterministically. With the fix it passes. The existinga_full_secret_without_writer_eof_expires_and_closes_the_fdpasses unchanged.python3 scripts/ci_plan.py --base origin/main --head HEAD: profileaffected, componentclient(3 normative paths, 1 component path), Rust on both platforms, suitesdg1-authorityanddg1-authon ubuntu-24.04 and eleven DG-1 suites on macos-14.python3 scripts/validate.py --stages whitespace,source-contract,documentation,protocol-analysis,dependency-boundary,format,clippy,contracts --diff-base origin/main(run20261007T153623Z-8e62f9c8): every stage passed; 200 tests passed, 0 failed, 3 ignored.report.jsonSHA-2567b9a23368d0b7a5b20c84c978d9e7770920dacbc1780cf1b71a6227090e1edd4.SHA256SUMSfile (SHA-2564df7a04477ab0fca696611179c63ee56a736079c03e6c3da8b7075e5c3526c9a).Hosted CI, run 37645735472 attempt 1, on merge source
1318bca(this head into035936d): Plan, Repository checks, contracts (ubuntu-24.04), contracts (macos-14) and Required checks all succeeded. The complete validator passed on both platforms, and so did every planned suite, except thatdg1-launchanddg1-cargoare incomplete only for the casesscripts/ci-policy.jsonallows on hosted macOS runners:claimed-then-refused, which needs an unclamped helper, and the Cargo cases the runner's capacity cannot fit.Required checksmatched each against its allowance. Artifact SHA-256 digests, retained until 2027-01-05:dg0-macos-14-1:ac1a053c250a145e3acdfa83c0d9596f05ca03199dc84da4db43d16315c52612dg0-ubuntu-24.04-1:02f07dd029054eba1774b12857422530672e3ba1ced5c29781595c6dea42a5b2ci-plan-1:ce9aae06150097c03f4b2ccbd24532059b2a4ea803b21652d5ee2617cafedf45ci-repository-1:37eff04ab2a2ea2662990c6919c95e2e94571dbaef19c66ec195cb7bb4fd5668Rollback
Revert the merge (
git revert -m 1 <merge commit>). The reader then fails at the deadline again even when the secret is already buffered. Nothing persisted depends on this change.