-
Notifications
You must be signed in to change notification settings - Fork 39
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
Implement proxy v2 architecture, in Rust #1718
Commits on May 17, 2024
-
Document and diagram request/response flow across qubesdb, qrexec and…
… proxy APIs This is the architecture we've dubbed "proxy v2".
Configuration menu - View commit details
-
Copy full SHA for 4ea10ee - Browse repository at this point
Copy the full SHA 4ea10eeView commit details -
Rewrite proxy in Rust, with v2 behavior
We identified multiple features that the current implementation of the proxy is unable to support (e.g. progress reporting, resuming downloads), necessitating a new protocol dubbed "v2". We are taking the opportunity to rewrite this component in Rust. Normal operation is mostly the same, input is received as a JSON blob (parsed and validated by serde) and output in our custom JSON response format. The `url` crate (from servo) is used to assemble and validate the target URL, and `reqwest` fires off the HTTP request. Downloads are now streamed back to the client over stdout, and metadata passed over stderr. Tests and further integration will happen in follow-up commits. Refs #1678. Co-authored-by: Kunal Mehta <[email protected]>
Configuration menu - View commit details
-
Copy full SHA for 35728c2 - Browse repository at this point
Copy the full SHA 35728c2View commit details -
Rewrite the existing tests to be integration tests against a compiled Rust binary. We use the httpbin library to start up a Python webserver and instruct the proxy to connect to it. This allows to test connection properties that aren't recordable in the VCR format, like timeouts or streamed responses. The tests are reorganized to be split into proxy handling and error handling.
Configuration menu - View commit details
-
Copy full SHA for 664c4e1 - Browse repository at this point
Copy the full SHA 664c4e1View commit details -
The SDK will now unconditionally use proxy v2: in development mode, it'll shell out directly, while production mode will invoke it over qrexec. The dev `./run.sh` script will compile the proxy so it's ready for use before the client starts up. New typed dataclasses represent the two types of responses that can be returned. No user-facting changes are happening at this stage, but this will enable future client features. The union return of send_json_request() means that we need instanceof assertions to make mypy happy. One minor logic bug in API.get_submission() was fixed in the case that no request is made (an undefined exception would've been raised previously).
Configuration menu - View commit details
-
Copy full SHA for 0cd8937 - Browse repository at this point
Copy the full SHA 0cd8937View commit details -
Refactor and update SDK tests to use lightweight VCR interface
We can't use VCR.py's "custom_patches" parameter because our API._send_json_request() is RPC- rather than connection-oriented. But we can just instrument _send_json_request() directly, which is what we do here. We subclass vcr.cassette.Cassette to handle identical requests with different responses, which was suggestd by @vickyliin as a workaround for kevin1024/vcrpy#753. Now that the SDK‒proxy connection is itself instrumented, there's only one path to test, with no special error-handling logic required, so merge TestAPIProxy into TestAPI. I considered merging TestAPI and TestShared as well, now that (without TestAPIProxy) TestAPI is the only subclass of TestShared. But reorganizing the alphabetized helpers in TestShared versus the strictly-sequenced TestAPI methods can wait. The tests are also now more patient with slow deletion operations. I'd want to DRY up this logic if this pattern shows up in more places, but it would require adding another level of indirection. A @Retry decorator isn't appropriate at the level of the test method, and a context manager can't loop over its closure. And re-apply the hack from 880635d by renaming test_logout to start with a "z" so it runs last.
Configuration menu - View commit details
-
Copy full SHA for 348d0f5 - Browse repository at this point
Copy the full SHA 348d0f5View commit details -
Configuration menu - View commit details
-
Copy full SHA for c237931 - Browse repository at this point
Copy the full SHA c237931View commit details -
Add
make regenerate-sdk-cassettes
and use in SDK CIHelp the developer through regenerating SDK cassettes against a development server, as well as in CI.
Configuration menu - View commit details
-
Copy full SHA for ecdd356 - Browse repository at this point
Copy the full SHA ecdd356View commit details -
* Switch to `Arch: any` because the package contains compiled code and this enables debhelper's automatic shlibs dependency system. * Rename the binary to `securedrop-proxy` because that's the Rust name.
Configuration menu - View commit details
-
Copy full SHA for 3711367 - Browse repository at this point
Copy the full SHA 3711367View commit details -
Audits were done by Kunal over the course of a few months.
Configuration menu - View commit details
-
Copy full SHA for 1bb415f - Browse repository at this point
Copy the full SHA 1bb415fView commit details -
Switch functional tests to use custom VCR setup
Same as the SDK, use our custom VCRAPI wrapper instead of pytest-vcr. Because each of the functional tests log in and out, document the server hack needed to run them one after another in the README.
Configuration menu - View commit details
-
Copy full SHA for 5cd8f7d - Browse repository at this point
Copy the full SHA 5cd8f7dView commit details -
Remove Python implementation of proxy
Now replaced by the Rust version.
Configuration menu - View commit details
-
Copy full SHA for 0ca17ab - Browse repository at this point
Copy the full SHA 0ca17abView commit details -
Configuration menu - View commit details
-
Copy full SHA for a6db478 - Browse repository at this point
Copy the full SHA a6db478View commit details -
Read proxy origin from QubesDB
We are setting the proxy's origin in QubesDB (via dom0 salt), and as discussed/agreed upon in <freedomofpress/securedrop-workstation#1013>, we're reading it directly in the proxy. We link directly to libqubesdb, generating the Rust wrapper with bindgen so it stays in sync (at build time at least). As a result, some unsafe is needed, but it is clearly annotated with relevant SAFETY notes. If we're not building with QubesDB (for development purposes), we'll continue to read from the environment and skip the bindgen and linking steps entirely. Fixes <freedomofpress/securedrop-workstation#853>. Co-authored-by: Kunal Mehta <[email protected]>
Configuration menu - View commit details
-
Copy full SHA for 9c1ecd4 - Browse repository at this point
Copy the full SHA 9c1ecd4View commit details -
Install qubesdb dependencies during packaging and CI
libclang is needed by bindgen. The Qubes signing key was fetched from <https://github.com/QubesOS/qubes-builder-debian/blob/64f530a712539829f8f2c1fbb0907d99b562ccdd/keys/qubes-debian-r4.2.asc>.
Configuration menu - View commit details
-
Copy full SHA for c6e7ba6 - Browse repository at this point
Copy the full SHA c6e7ba6View commit details -
Configuration menu - View commit details
-
Copy full SHA for 52bd1fd - Browse repository at this point
Copy the full SHA 52bd1fdView commit details -
Configuration menu - View commit details
-
Copy full SHA for 665bd5f - Browse repository at this point
Copy the full SHA 665bd5fView commit details -
Remove proxy's no-op
make lint
This does nothing because Rust code is linted through the root Makefile's `rust-lint` target, and Python code linted from the root's ruff targets as well.
Configuration menu - View commit details
-
Copy full SHA for c91d76c - Browse repository at this point
Copy the full SHA c91d76cView commit details -
Save downloaded files and replies to ~/Downloads temporarily
Historically production systems used ~/QubesIncoming/sd-proxy as a temporary directory because files were sent over qvm-move. This switches to ~/Downloads as a stop-gap. A better interface would be for the caller to provision a temporary directory, and pass it as the path.
Configuration menu - View commit details
-
Copy full SHA for 4e44b00 - Browse repository at this point
Copy the full SHA 4e44b00View commit details -
Add bounds check in _send_json_request
Avoid IndexError in the case that `response.stdout` is empty.
Configuration menu - View commit details
-
Copy full SHA for 1755185 - Browse repository at this point
Copy the full SHA 1755185View commit details -
Apply suggestions from code review
Co-authored-by: Kunal Mehta <[email protected]>
Configuration menu - View commit details
-
Copy full SHA for 82a71a0 - Browse repository at this point
Copy the full SHA 82a71a0View commit details -
chore(Poetry): remove pinned werkzeug, then "poetry lock --no-update"
The relevant httpbin issue has been resolved and is compatible with newer werkzeug.
Configuration menu - View commit details
-
Copy full SHA for caabec2 - Browse repository at this point
Copy the full SHA caabec2View commit details