-
Notifications
You must be signed in to change notification settings - Fork 5
Mount remote client methods, SDK remote parity, typed-terminal legs #511
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
ScriptedAlchemy
merged 18 commits into
codex/tracedecay-total-redesign-plan
from
cursor/remote-parity-typed-terminals-c299
Aug 19, 2026
Merged
Changes from all commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
f64b06a
fix(mcp): answer reset-refused tools/call with a typed problem
cursoragent 0814d20
fix(daemon-client): read authoritative effects over the response grace
cursoragent 45414c9
feat(sdk): admit the local daemon loopback mount as a remote target
cursoragent aad875b
feat(cli): mount remote capture, query, and transfer-frame journeys
cursoragent d707766
Merge branch 'codex/tracedecay-total-redesign-plan' into cursor/remot…
ScriptedAlchemy f0dacc1
fix(daemon-client): type post-cancel transport failures as indeterminate
cursoragent 175f4ba
Merge branch 'cursor/remote-parity-typed-terminals-c299' of https://g…
cursoragent 3df1e16
docs(next): record green typed-terminal transport legs
cursoragent 3c0f269
fix(sdk): never route the loopback remote target through a proxy
cursoragent bd1e080
fix(sdk): never proxy loopback remote daemon requests
cursoragent d1973f4
fix(cli): compose the caller's own spool evidence for remote query
cursoragent 73ea3c9
style(daemon): tighten remote parity and typed-terminal comments
cursoragent 138256c
merge: adopt the shared loopback no-proxy fix and single test
cursoragent bda96db
Merge remote-tracking branch 'origin/codex/tracedecay-total-redesign-…
ScriptedAlchemy 4bc2e1c
Merge branch 'cursor/remote-parity-typed-terminals-c299' of github.co…
ScriptedAlchemy f4c6303
merge: adopt base fmt/clippy cleanliness
cursoragent fe41d79
style(clippy): simplify the liveness-probe skip in invocation tests
cursoragent 8b3031c
merge: adopt base windows build fixes
cursoragent File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,105 @@ | ||
| //! The plaintext loopback Remote Brain target must never traverse a system | ||
| //! proxy: `HTTP_PROXY`/`ALL_PROXY` would carry the Bearer enrollment | ||
| //! credential off the machine unencrypted, defeating the loopback-only | ||
| //! plaintext admission. This test lives in its own integration binary because | ||
| //! it mutates the process-wide proxy environment. | ||
|
|
||
| use std::io::{Read, Write}; | ||
| use std::net::TcpListener; | ||
| use std::thread; | ||
| use std::time::Duration; | ||
|
|
||
| use tracedecay_application::RequestId; | ||
| use tracedecay_application::remote::protocol::{EnrollmentRequestV1, RemoteProtocolRequestV1}; | ||
| use tracedecay_domain::{ | ||
| BrainId, BrainNodeId, EntityId, ProjectId, RefId, RemoteCapabilityV1, RemoteRepositoryScopeV1, | ||
| RepositoryId, RepositoryStateSnapshotId, UtcMicros, WorktreeId, | ||
| }; | ||
| use tracedecay_sdk::remote_client::{EnrolledRemoteClient, RemoteClientError}; | ||
|
|
||
| #[test] | ||
| fn loopback_http_request_never_routes_through_a_system_proxy() { | ||
| let proxy = TcpListener::bind("127.0.0.1:0").expect("bind proxy listener"); | ||
| let proxy_address = proxy.local_addr().expect("proxy address"); | ||
| let target = TcpListener::bind("127.0.0.1:0").expect("bind target listener"); | ||
| let target_port = target.local_addr().expect("target address").port(); | ||
| let server = thread::spawn(move || { | ||
| let (mut stream, _) = target.accept().expect("direct loopback connection"); | ||
| let mut head = [0u8; 2048]; | ||
| let _ = stream.read(&mut head).expect("read request head"); | ||
| stream | ||
| .write_all( | ||
| b"HTTP/1.1 200 OK\r\n\ | ||
| content-type: application/json\r\n\ | ||
| content-length: 2\r\n\ | ||
| connection: close\r\n\r\n{}", | ||
| ) | ||
| .expect("write canned response"); | ||
| }); | ||
|
|
||
| // SAFETY: this integration binary holds only this test, so no other | ||
| // thread reads or writes the process environment concurrently. | ||
| unsafe { | ||
| std::env::set_var("HTTP_PROXY", format!("http://{proxy_address}")); | ||
| std::env::set_var("ALL_PROXY", format!("http://{proxy_address}")); | ||
| } | ||
| let client = EnrolledRemoteClient::new_local_daemon( | ||
| format!("http://127.0.0.1:{target_port}/remote/"), | ||
| "0123456789abcdef0123456789abcdef", | ||
| Duration::from_secs(5), | ||
| ); | ||
| // SAFETY: as above. | ||
| unsafe { | ||
| std::env::remove_var("HTTP_PROXY"); | ||
| std::env::remove_var("ALL_PROXY"); | ||
| } | ||
| let client = client.expect("loopback client must build under a proxy environment"); | ||
|
|
||
| let outcome = client.enroll(&enrollment_request(), *b"fedcba9876543210fedcba9876543210"); | ||
| // A protocol error proves the request reached the direct loopback target | ||
| // and got the canned garbage back; a proxied request would have died in | ||
| // transport against the never-accepting proxy listener instead. | ||
| match outcome { | ||
| Err(RemoteClientError::Protocol(_)) => {} | ||
| Err(error) => panic!("expected a protocol error from the direct target, got {error:?}"), | ||
| Ok(_) => panic!("the canned non-canonical response must fail as protocol"), | ||
| } | ||
| server.join().expect("target server thread"); | ||
|
|
||
| proxy | ||
| .set_nonblocking(true) | ||
| .expect("nonblocking proxy accept"); | ||
| match proxy.accept() { | ||
| Err(error) if error.kind() == std::io::ErrorKind::WouldBlock => {} | ||
| Ok(_) => panic!("the loopback request must never reach the system proxy"), | ||
| Err(error) => panic!("proxy accept failed: {error}"), | ||
| } | ||
| } | ||
|
|
||
| fn enrollment_request() -> RemoteProtocolRequestV1<EnrollmentRequestV1> { | ||
| let brain_id = BrainId::new("brain.remote-proxy-test").unwrap(); | ||
| let node_id = BrainNodeId::new("node.remote-proxy-test").unwrap(); | ||
| RemoteProtocolRequestV1::new_initial_enrollment( | ||
| RequestId::new("request.remote-proxy-test").unwrap(), | ||
| brain_id.clone(), | ||
| node_id.clone(), | ||
| UtcMicros(1_000_000), | ||
| EnrollmentRequestV1 { | ||
| grant_id: EntityId::new("grant.remote-proxy-test").unwrap(), | ||
| grant_revision: 1, | ||
| enrollment_id: EntityId::new("enrollment.remote-proxy-test").unwrap(), | ||
| brain_id, | ||
| node_id, | ||
| expires_at: UtcMicros(600_000_000), | ||
| capabilities: [RemoteCapabilityV1::Query].into_iter().collect(), | ||
| scope: RemoteRepositoryScopeV1 { | ||
| project_id: ProjectId::new("project.remote-proxy-test").unwrap(), | ||
| repository_id: RepositoryId::new("repository.remote-proxy-test").unwrap(), | ||
| worktree_id: WorktreeId::new("worktree.remote-proxy-test").unwrap(), | ||
| reference: Some(RefId::new("refs/heads/remote-proxy-test").unwrap()), | ||
| snapshot_id: RepositoryStateSnapshotId::new("snapshot.remote-proxy-test").unwrap(), | ||
| }, | ||
| }, | ||
| ) | ||
| .unwrap() | ||
| } |
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
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
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
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
Oops, something went wrong.
Oops, something went wrong.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When
HTTP_PROXY/ALL_PROXYis configured and the loopback host is not excluded byNO_PROXY, reqwest's default system-proxy behavior can route this newly admitted plaintext request through the proxy. Becauseexecute_mountedattaches the enrollment credential as a Bearer header, the credential then leaves the machine unencrypted despite the hostname check; disable proxy use whenever constructing the loopback-HTTP client.Useful? React with 👍 / 👎.