From adade27de4d70f7549a07648432fada62ba4d17b Mon Sep 17 00:00:00 2001 From: Duncan Tourolle Date: Thu, 24 Sep 2026 20:43:40 -0400 Subject: [PATCH] Refuse plain http in the Nextcloud client, below every URL it sends NFR-SEC-3 held only for the address a person types: normalise_endpoint upgrades it to https, and nothing else was checked. The login flow's poll endpoint, an account an older build saved and a redirect all come from somewhere else, and any of them naming http:// would send the app password in Basic auth in the clear. http_client now sets https_only. reqwest checks it before connecting and again on each redirect, so a refused request never opens a socket, which the new test checks with a listener that nothing may reach. A refused scheme is reported as a Configuration error, not Network. The request never left the process, and Network puts the app into offline mode over a connection that is working. Other builder errors (a URL that does not parse) go the same way, for the same reason. Part of #65. --- core/dr-sync-nextcloud/src/lib.rs | 50 ++++++++++++++++++++++++++++++- docs/dev/traceability.md | 12 ++++---- 2 files changed, 55 insertions(+), 7 deletions(-) diff --git a/core/dr-sync-nextcloud/src/lib.rs b/core/dr-sync-nextcloud/src/lib.rs index da56490..667fe49 100644 --- a/core/dr-sync-nextcloud/src/lib.rs +++ b/core/dr-sync-nextcloud/src/lib.rs @@ -723,6 +723,15 @@ pub fn http_client(user_agent: &str) -> Result { // for months. [`EXTRA_ROOTS`] carries those, and is additive — the // webpki-roots set is still installed alongside. .tls_certs_only(extra_roots()) + // TRACES: NFR-SEC-3 + // Refuse `http` here, below every URL this crate builds, rather than + // trusting each place a URL comes from. `normalise_endpoint` upgrades + // what the user types, but the login flow's poll endpoint, the account + // an older build saved and a redirect all arrive from somewhere else, + // and any of them naming `http://` would send the app password in + // Basic auth in the clear. reqwest checks this before connecting and + // again on every redirect, so a refused request never opens a socket. + .https_only(true) // A request that hangs forever is indistinguishable from a worker that // died, and cost a long time to tell apart once. These turn that into // an error the UI can show. @@ -780,8 +789,16 @@ fn map_send_error(e: reqwest::Error) -> RemoteError { let mut detail = e.to_string(); let mut src: Option<&dyn std::error::Error> = std::error::Error::source(&e); let mut tls = false; + // A URL the client refused to send — `http` under `https_only`, on the + // first request or a redirect. Nothing left the process, so this is the + // account's configuration, not the network: reported as `Network` it + // would put the app into offline mode over a connection that is fine. + let mut refused = e.is_builder(); while let Some(s) = src { let text = s.to_string(); + if text.contains("URL scheme is not allowed") { + refused = true; + } // rustls surfaces every verification failure through this wording: // UnknownIssuer, Expired, NotValidForName, BadSignature. if text.contains("invalid peer certificate") @@ -795,7 +812,9 @@ fn map_send_error(e: reqwest::Error) -> RemoteError { src = std::error::Error::source(s); } - if tls { + if refused { + RemoteError::Configuration(detail) + } else if tls { RemoteError::Tls(detail) } else { RemoteError::Network(detail) @@ -1013,6 +1032,35 @@ mod tests { assert!(c.is_ok(), "client must build without a backend"); } + /// TRACES: NFR-SEC-3 + #[tokio::test] + async fn plain_http_is_refused_before_a_connection_opens() { + // A listener that would take the connection if one were made. The + // app password travels in a header, so a request that reached the + // socket has already leaked it; failing on the response is too late. + let listener = std::net::TcpListener::bind("127.0.0.1:0").unwrap(); + listener.set_nonblocking(true).unwrap(); + let url = format!("http://{}/remote.php/dav/", listener.local_addr().unwrap()); + + let err = http_client("test") + .unwrap() + .get(&url) + .basic_auth("duncan", Some("app-password")) + .send() + .await + .expect_err("http must be refused"); + + assert!( + matches!(map_send_error(err), RemoteError::Configuration(_)), + "a refused scheme is configuration, not the network" + ); + assert_eq!( + listener.accept().err().map(|e| e.kind()), + Some(std::io::ErrorKind::WouldBlock), + "nothing may have connected" + ); + } + #[tokio::test] async fn delta_is_unsupported_and_says_why() { // Verified absent in the server; the engine must fall back rather diff --git a/docs/dev/traceability.md b/docs/dev/traceability.md index 967746e..ef0b8f1 100644 --- a/docs/dev/traceability.md +++ b/docs/dev/traceability.md @@ -10,7 +10,7 @@ Denominators are parsed from [`requirements.md`](requirements.md) at run time, n | Metric | Value | |---|---| | Source files scanned | 435 | -| TRACES tags found | 1598 | +| TRACES tags found | 1612 | | Requirements defined | 188 | | Requirements deferred (post-v1) | 24 | | Requirements covered | 155 | @@ -111,10 +111,10 @@ _None._ | FR-MRG-6 | [`core/dr-pipeline/src/sidecar.rs:1033`](../../core/dr-pipeline/src/sidecar.rs#L1033), [`core/dr-pipeline/src/sidecar.rs:113`](../../core/dr-pipeline/src/sidecar.rs#L113), [`core/dr-pipeline/src/sidecar.rs:123`](../../core/dr-pipeline/src/sidecar.rs#L123), [`core/dr-pipeline/src/sidecar.rs:2241`](../../core/dr-pipeline/src/sidecar.rs#L2241), [`core/dr-pipeline/src/sidecar.rs:841`](../../core/dr-pipeline/src/sidecar.rs#L841), [`ui/dr-ui/src/merge.rs:842`](../../ui/dr-ui/src/merge.rs#L842) | | FR-MRG-7 | [`ui/dr-ui/src/merge.rs:1`](../../ui/dr-ui/src/merge.rs#L1), [`ui/dr-ui/src/merge_ui.rs:1`](../../ui/dr-ui/src/merge_ui.rs#L1), [`ui/dr-ui/ui/app.slint:533`](../../ui/dr-ui/ui/app.slint#L533), [`ui/dr-ui/ui/merge.slint:1`](../../ui/dr-ui/ui/merge.slint#L1) | | FR-MRG-8 | [`core/dr-pano/src/xfeat.rs:1`](../../core/dr-pano/src/xfeat.rs#L1), [`core/dr-segment/examples/onnx_probe.rs:1`](../../core/dr-segment/examples/onnx_probe.rs#L1) | -| FR-NC-1 | [`core/dr-sync-nextcloud/src/auth.rs:132`](../../core/dr-sync-nextcloud/src/auth.rs#L132), [`core/dr-sync-nextcloud/src/auth.rs:44`](../../core/dr-sync-nextcloud/src/auth.rs#L44), [`core/dr-sync-nextcloud/src/provider.rs:1`](../../core/dr-sync-nextcloud/src/provider.rs#L1), [`core/dr-sync/src/account.rs:375`](../../core/dr-sync/src/account.rs#L375), [`ui/dr-ui/src/launch.rs:316`](../../ui/dr-ui/src/launch.rs#L316), [`ui/dr-ui/src/launch.rs:61`](../../ui/dr-ui/src/launch.rs#L61), [`ui/dr-ui/src/launch_ui.rs:446`](../../ui/dr-ui/src/launch_ui.rs#L446) | +| FR-NC-1 | [`core/dr-sync-nextcloud/src/auth.rs:206`](../../core/dr-sync-nextcloud/src/auth.rs#L206), [`core/dr-sync-nextcloud/src/auth.rs:49`](../../core/dr-sync-nextcloud/src/auth.rs#L49), [`core/dr-sync-nextcloud/src/provider.rs:1`](../../core/dr-sync-nextcloud/src/provider.rs#L1), [`core/dr-sync/src/account.rs:375`](../../core/dr-sync/src/account.rs#L375), [`ui/dr-ui/src/launch.rs:316`](../../ui/dr-ui/src/launch.rs#L316), [`ui/dr-ui/src/launch.rs:61`](../../ui/dr-ui/src/launch.rs#L61), [`ui/dr-ui/src/launch_ui.rs:450`](../../ui/dr-ui/src/launch_ui.rs#L450) | | FR-NC-10 | [`core/dr-sync/src/account.rs:240`](../../core/dr-sync/src/account.rs#L240), [`ui/dr-ui/src/export.rs:1`](../../ui/dr-ui/src/export.rs#L1), [`ui/dr-ui/src/lib.rs:682`](../../ui/dr-ui/src/lib.rs#L682), [`ui/dr-ui/src/library/paths.rs:69`](../../ui/dr-ui/src/library/paths.rs#L69), [`ui/dr-ui/src/library/sidecar.rs:100`](../../ui/dr-ui/src/library/sidecar.rs#L100), [`ui/dr-ui/src/library/sidecar.rs:427`](../../ui/dr-ui/src/library/sidecar.rs#L427), [`ui/dr-ui/src/library/thumbnails_fetch.rs:449`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L449), [`ui/dr-ui/src/library_ui/controller.rs:657`](../../ui/dr-ui/src/library_ui/controller.rs#L657), [`ui/dr-ui/src/library_ui/offline.rs:623`](../../ui/dr-ui/src/library_ui/offline.rs#L623), [`ui/dr-ui/src/library_ui/sync.rs:100`](../../ui/dr-ui/src/library_ui/sync.rs#L100), [`ui/dr-ui/src/sidecar_cache.rs:1`](../../ui/dr-ui/src/sidecar_cache.rs#L1) | -| FR-NC-12 | [`core/dr-sync-folder/src/lib.rs:1`](../../core/dr-sync-folder/src/lib.rs#L1), [`core/dr-sync-nextcloud/src/lib.rs:1049`](../../core/dr-sync-nextcloud/src/lib.rs#L1049), [`core/dr-sync-nextcloud/src/lib.rs:40`](../../core/dr-sync-nextcloud/src/lib.rs#L40), [`core/dr-sync-nextcloud/src/provider.rs:1`](../../core/dr-sync-nextcloud/src/provider.rs#L1), [`core/dr-sync/src/account.rs:1`](../../core/dr-sync/src/account.rs#L1), [`core/dr-sync/src/account.rs:87`](../../core/dr-sync/src/account.rs#L87), [`core/dr-sync/src/lib.rs:218`](../../core/dr-sync/src/lib.rs#L218), [`core/dr-sync/src/lib.rs:51`](../../core/dr-sync/src/lib.rs#L51), [`core/dr-sync/src/provider.rs:106`](../../core/dr-sync/src/provider.rs#L106), [`core/dr-sync/src/provider.rs:1`](../../core/dr-sync/src/provider.rs#L1), [`core/dr-sync/src/provider.rs:53`](../../core/dr-sync/src/provider.rs#L53), [`core/dr-sync/src/reachability.rs:1`](../../core/dr-sync/src/reachability.rs#L1), [`ui/dr-ui/src/remote.rs:1`](../../ui/dr-ui/src/remote.rs#L1) | -| FR-NC-13 | [`core/dr-sync-folder/src/lib.rs:197`](../../core/dr-sync-folder/src/lib.rs#L197), [`core/dr-sync-folder/src/lib.rs:1`](../../core/dr-sync-folder/src/lib.rs#L1), [`core/dr-sync-folder/src/lib.rs:73`](../../core/dr-sync-folder/src/lib.rs#L73), [`core/dr-sync/src/provider.rs:106`](../../core/dr-sync/src/provider.rs#L106), [`ui/dr-ui/src/launch_ui.rs:345`](../../ui/dr-ui/src/launch_ui.rs#L345), [`ui/dr-ui/src/remote.rs:1`](../../ui/dr-ui/src/remote.rs#L1) | +| FR-NC-12 | [`core/dr-sync-folder/src/lib.rs:1`](../../core/dr-sync-folder/src/lib.rs#L1), [`core/dr-sync-nextcloud/src/lib.rs:1097`](../../core/dr-sync-nextcloud/src/lib.rs#L1097), [`core/dr-sync-nextcloud/src/lib.rs:40`](../../core/dr-sync-nextcloud/src/lib.rs#L40), [`core/dr-sync-nextcloud/src/provider.rs:1`](../../core/dr-sync-nextcloud/src/provider.rs#L1), [`core/dr-sync/src/account.rs:1`](../../core/dr-sync/src/account.rs#L1), [`core/dr-sync/src/account.rs:87`](../../core/dr-sync/src/account.rs#L87), [`core/dr-sync/src/lib.rs:218`](../../core/dr-sync/src/lib.rs#L218), [`core/dr-sync/src/lib.rs:51`](../../core/dr-sync/src/lib.rs#L51), [`core/dr-sync/src/provider.rs:120`](../../core/dr-sync/src/provider.rs#L120), [`core/dr-sync/src/provider.rs:1`](../../core/dr-sync/src/provider.rs#L1), [`core/dr-sync/src/provider.rs:53`](../../core/dr-sync/src/provider.rs#L53), [`core/dr-sync/src/reachability.rs:1`](../../core/dr-sync/src/reachability.rs#L1), [`ui/dr-ui/src/remote.rs:1`](../../ui/dr-ui/src/remote.rs#L1) | +| FR-NC-13 | [`core/dr-sync-folder/src/lib.rs:197`](../../core/dr-sync-folder/src/lib.rs#L197), [`core/dr-sync-folder/src/lib.rs:1`](../../core/dr-sync-folder/src/lib.rs#L1), [`core/dr-sync-folder/src/lib.rs:73`](../../core/dr-sync-folder/src/lib.rs#L73), [`core/dr-sync/src/provider.rs:120`](../../core/dr-sync/src/provider.rs#L120), [`ui/dr-ui/src/launch_ui.rs:349`](../../ui/dr-ui/src/launch_ui.rs#L349), [`ui/dr-ui/src/remote.rs:1`](../../ui/dr-ui/src/remote.rs#L1) | | FR-NC-2 | [`core/dr-sync/src/account.rs:1`](../../core/dr-sync/src/account.rs#L1), [`core/dr-sync/src/account.rs:318`](../../core/dr-sync/src/account.rs#L318), [`core/dr-sync/src/account.rs:375`](../../core/dr-sync/src/account.rs#L375), [`core/dr-sync/src/account.rs:59`](../../core/dr-sync/src/account.rs#L59), [`platform/dr-plat/src/secrets.rs:82`](../../platform/dr-plat/src/secrets.rs#L82) | | FR-NC-3 | [`core/dr-decode/src/locate.rs:1`](../../core/dr-decode/src/locate.rs#L1), [`core/dr-decode/src/preview.rs:148`](../../core/dr-decode/src/preview.rs#L148), [`core/dr-sync/src/capability.rs:85`](../../core/dr-sync/src/capability.rs#L85), [`core/dr-thumbs/src/lib.rs:1`](../../core/dr-thumbs/src/lib.rs#L1), [`core/dr-types/src/place.rs:1`](../../core/dr-types/src/place.rs#L1), [`ui/dr-ui/src/library/mod.rs:1`](../../ui/dr-ui/src/library/mod.rs#L1), [`ui/dr-ui/src/library/sweep.rs:557`](../../ui/dr-ui/src/library/sweep.rs#L557), [`ui/dr-ui/src/library_ui/grid.rs:458`](../../ui/dr-ui/src/library_ui/grid.rs#L458), [`ui/dr-ui/src/library_ui/mod.rs:1`](../../ui/dr-ui/src/library_ui/mod.rs#L1), [`ui/dr-ui/src/library_ui/sync.rs:385`](../../ui/dr-ui/src/library_ui/sync.rs#L385), [`ui/dr-ui/ui/library.slint:737`](../../ui/dr-ui/ui/library.slint#L737), [`ui/dr-ui/ui/settings.slint:362`](../../ui/dr-ui/ui/settings.slint#L362), [`ui/dr-ui/ui/settings.slint:74`](../../ui/dr-ui/ui/settings.slint#L74) | | FR-NC-4 | [`core/dr-sync-folder/src/lib.rs:197`](../../core/dr-sync-folder/src/lib.rs#L197), [`core/dr-sync-nextcloud/src/propfind.rs:103`](../../core/dr-sync-nextcloud/src/propfind.rs#L103), [`core/dr-sync-nextcloud/src/propfind.rs:51`](../../core/dr-sync-nextcloud/src/propfind.rs#L51), [`core/dr-sync/src/capability.rs:6`](../../core/dr-sync/src/capability.rs#L6), [`core/dr-sync/src/lib.rs:218`](../../core/dr-sync/src/lib.rs#L218), [`core/dr-sync/src/scan.rs:129`](../../core/dr-sync/src/scan.rs#L129), [`ui/dr-ui/src/launch.rs:61`](../../ui/dr-ui/src/launch.rs#L61) | @@ -137,7 +137,7 @@ _None._ | FR-PLAT-LIN-1 | [`core/dr-types/src/settings.rs:1`](../../core/dr-types/src/settings.rs#L1), [`platform/dr-plat/src/dirs.rs:1`](../../platform/dr-plat/src/dirs.rs#L1), [`platform/dr-plat/src/storage.rs:344`](../../platform/dr-plat/src/storage.rs#L344), [`ui/dr-ui/src/lib.rs:1386`](../../ui/dr-ui/src/lib.rs#L1386), [`ui/dr-ui/src/preset_store.rs:1`](../../ui/dr-ui/src/preset_store.rs#L1), [`ui/dr-ui/src/settings_store.rs:1`](../../ui/dr-ui/src/settings_store.rs#L1) | | FR-PLAT-LIN-2 | [`platform/dr-plat/src/display.rs:1`](../../platform/dr-plat/src/display.rs#L1), [`platform/dr-plat/src/display/wayland.rs:1`](../../platform/dr-plat/src/display/wayland.rs#L1), [`platform/dr-plat/src/display/x11.rs:1`](../../platform/dr-plat/src/display/x11.rs#L1) | | FR-PLAT-WIN-1 | [`platform/dr-plat/src/dirs.rs:1`](../../platform/dr-plat/src/dirs.rs#L1) | -| FR-PLAT-WIN-2 | [`apps/darkroom-desktop/build.rs:1`](../../apps/darkroom-desktop/build.rs#L1), [`apps/darkroom-desktop/src/main.rs:6`](../../apps/darkroom-desktop/src/main.rs#L6), [`ui/dr-ui/src/launch_ui.rs:848`](../../ui/dr-ui/src/launch_ui.rs#L848) | +| FR-PLAT-WIN-2 | [`apps/darkroom-desktop/build.rs:1`](../../apps/darkroom-desktop/build.rs#L1), [`apps/darkroom-desktop/src/main.rs:6`](../../apps/darkroom-desktop/src/main.rs#L6), [`ui/dr-ui/src/launch_ui.rs:865`](../../ui/dr-ui/src/launch_ui.rs#L865) | | FR-PLAT-WIN-3 | [`apps/darkroom-desktop/src/main.rs:19`](../../apps/darkroom-desktop/src/main.rs#L19) | | FR-RAW-1 | [`core/dr-decode/src/lib.rs:259`](../../core/dr-decode/src/lib.rs#L259), [`core/dr-types/src/lib.rs:132`](../../core/dr-types/src/lib.rs#L132), [`core/dr-types/src/lib.rs:203`](../../core/dr-types/src/lib.rs#L203) | | FR-RAW-3 | [`core/dr-decode/src/lib.rs:155`](../../core/dr-decode/src/lib.rs#L155), [`core/dr-decode/src/lib.rs:546`](../../core/dr-decode/src/lib.rs#L546), [`core/dr-decode/src/locate.rs:1435`](../../core/dr-decode/src/locate.rs#L1435) | @@ -182,7 +182,7 @@ _None._ | NFR-RES-4 | [`core/dr-catalog/src/cache.rs:1`](../../core/dr-catalog/src/cache.rs#L1), [`core/dr-catalog/src/face_shard.rs:1`](../../core/dr-catalog/src/face_shard.rs#L1), [`core/dr-catalog/src/schema.rs:1182`](../../core/dr-catalog/src/schema.rs#L1182), [`core/dr-gpu/src/lib.rs:95`](../../core/dr-gpu/src/lib.rs#L95), [`core/dr-thumbs/src/codec.rs:1`](../../core/dr-thumbs/src/codec.rs#L1), [`core/dr-thumbs/src/lib.rs:1`](../../core/dr-thumbs/src/lib.rs#L1), [`core/dr-thumbs/src/lib.rs:393`](../../core/dr-thumbs/src/lib.rs#L393) | | NFR-SEC-1 | [`core/dr-decode/src/error.rs:1`](../../core/dr-decode/src/error.rs#L1), [`core/dr-decode/src/error.rs:30`](../../core/dr-decode/src/error.rs#L30) | | NFR-SEC-2 | [`core/dr-sync/src/account.rs:318`](../../core/dr-sync/src/account.rs#L318), [`platform/dr-plat/src/crash.rs:1`](../../platform/dr-plat/src/crash.rs#L1), [`platform/dr-plat/src/diagnostics.rs:1`](../../platform/dr-plat/src/diagnostics.rs#L1), [`platform/dr-plat/src/diagnostics/bundle.rs:1`](../../platform/dr-plat/src/diagnostics/bundle.rs#L1), [`platform/dr-plat/src/diagnostics/redact.rs:1`](../../platform/dr-plat/src/diagnostics/redact.rs#L1), [`platform/dr-plat/src/secrets.rs:82`](../../platform/dr-plat/src/secrets.rs#L82) | -| NFR-SEC-3 | [`core/dr-sync-nextcloud/src/lib.rs:1`](../../core/dr-sync-nextcloud/src/lib.rs#L1), [`core/dr-sync-nextcloud/src/provider.rs:1`](../../core/dr-sync-nextcloud/src/provider.rs#L1) | +| NFR-SEC-3 | [`core/dr-sync-nextcloud/src/auth.rs:174`](../../core/dr-sync-nextcloud/src/auth.rs#L174), [`core/dr-sync-nextcloud/src/auth.rs:244`](../../core/dr-sync-nextcloud/src/auth.rs#L244), [`core/dr-sync-nextcloud/src/auth.rs:274`](../../core/dr-sync-nextcloud/src/auth.rs#L274), [`core/dr-sync-nextcloud/src/auth.rs:89`](../../core/dr-sync-nextcloud/src/auth.rs#L89), [`core/dr-sync-nextcloud/src/lib.rs:1035`](../../core/dr-sync-nextcloud/src/lib.rs#L1035), [`core/dr-sync-nextcloud/src/lib.rs:1`](../../core/dr-sync-nextcloud/src/lib.rs#L1), [`core/dr-sync-nextcloud/src/lib.rs:726`](../../core/dr-sync-nextcloud/src/lib.rs#L726), [`core/dr-sync-nextcloud/src/provider.rs:147`](../../core/dr-sync-nextcloud/src/provider.rs#L147), [`core/dr-sync-nextcloud/src/provider.rs:1`](../../core/dr-sync-nextcloud/src/provider.rs#L1), [`core/dr-sync-nextcloud/src/provider.rs:99`](../../core/dr-sync-nextcloud/src/provider.rs#L99), [`core/dr-sync/src/account.rs:513`](../../core/dr-sync/src/account.rs#L513), [`core/dr-sync/src/account.rs:709`](../../core/dr-sync/src/account.rs#L709), [`core/dr-sync/src/account.rs:753`](../../core/dr-sync/src/account.rs#L753), [`core/dr-sync/src/account.rs:774`](../../core/dr-sync/src/account.rs#L774), [`ui/dr-ui/src/launch_ui.rs:1022`](../../ui/dr-ui/src/launch_ui.rs#L1022), [`ui/dr-ui/src/launch_ui.rs:837`](../../ui/dr-ui/src/launch_ui.rs#L837) | | NFR-SEC-4 | [`platform/dr-plat/src/diagnostics/bundle.rs:1`](../../platform/dr-plat/src/diagnostics/bundle.rs#L1) | | NFR-SEC-5 | [`core/dr-catalog/src/faces.rs:1`](../../core/dr-catalog/src/faces.rs#L1), [`core/dr-catalog/src/schema.rs:1011`](../../core/dr-catalog/src/schema.rs#L1011), [`platform/dr-plat/src/diagnostics/bundle.rs:1`](../../platform/dr-plat/src/diagnostics/bundle.rs#L1), [`ui/dr-ui/src/faces.rs:1`](../../ui/dr-ui/src/faces.rs#L1), [`ui/dr-ui/src/identity.rs:1`](../../ui/dr-ui/src/identity.rs#L1), [`ui/dr-ui/src/identity_ui.rs:1`](../../ui/dr-ui/src/identity_ui.rs#L1), [`ui/dr-ui/ui/identity.slint:1`](../../ui/dr-ui/ui/identity.slint#L1) | | R3 | [`core/dr-export/src/lib.rs:1`](../../core/dr-export/src/lib.rs#L1), [`core/dr-pipeline/src/lib.rs:1`](../../core/dr-pipeline/src/lib.rs#L1) |