Skip to main content

max / quasi-type

Make the mirror hit path testable from a consumer
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session
https://claude.ai/code/session_01MptwXZ8k65v19rFmdGAyki
Author: Max Johnson <me@maxj.phd> · 2026-09-01 15:16 UTC
Signed with PGP, not checked
Commit: 55e74d775c3eb4434abb2ac3f7030b85542ddf4c
Parent: 23ddbea
1 file changed, +257 insertions, -14 deletions
M src/base.rs +257 -14
@@ -553,23 +553,19 @@
553 553 /// for `https://example.invalid/bases/<sha256>`.
554 554 pub const MIRROR_ENV: &str = "QUASI_TYPE_MIRROR";
555 555
556 - /// Where a mirror would hold the file whose pinned digest is `sha256`.
556 + /// Where a mirror holds the file whose pinned digest is `sha256`.
557 557 ///
558 558 /// Content-addressed on purpose, and it is what keeps this from being a new
559 559 /// trust assumption: the digest is the one the pin already carries and the
560 560 /// bytes are verified against it either way, so a mirror can serve the pinned
561 561 /// file or nothing. It cannot serve a different one. That is also why no
562 - /// signature or TLS pinning is wanted here — the integrity guarantee was never
562 + /// signature or TLS pinning is wanted here: the integrity guarantee was never
563 563 /// the transport.
564 - fn mirrored(sha256: &str) -> Option<String> {
565 - mirror_url(&std::env::var(MIRROR_ENV).ok()?, sha256)
566 - }
567 -
568 - /// [`mirrored`] against an explicit base, so the shaping is testable.
569 564 ///
570 - /// Split out because `set_var` is unsafe in a threaded test binary and a test
571 - /// that sets the mirror under the other tests is a flake waiting for a slow
572 - /// machine.
565 + /// Takes the base rather than reading [`MIRROR_ENV`], so the shaping and the
566 + /// order [`cached_from`] tries its two sources in are both testable without
567 + /// `set_var`, which is unsafe in a threaded test binary and would set the
568 + /// mirror under every other test in the run.
573 569 fn mirror_url(base: &str, sha256: &str) -> Option<String> {
574 570 let base = base.trim().trim_end_matches('/');
575 571 (!base.is_empty()).then(|| format!("{base}/{sha256}"))
@@ -599,6 +595,19 @@
599 595 /// the way out, which is unchanged — these fail differently, the same way the
600 596 /// archive's two checks do.
601 597 fn cached(url: &str, path: &Path, offline: bool, expect: &str) -> Result<Vec<u8>, Error> {
598 + let mirror = std::env::var(MIRROR_ENV).ok();
599 + cached_from(mirror.as_deref(), url, path, offline, expect)
600 + }
601 +
602 + /// [`cached`] against an explicit mirror base, which is where the two sources
603 + /// are actually ordered.
604 + fn cached_from(
605 + mirror: Option<&str>,
606 + url: &str,
607 + path: &Path,
608 + offline: bool,
609 + expect: &str,
610 + ) -> Result<Vec<u8>, Error> {
602 611 if !path.exists() {
603 612 if offline {
604 613 return Err(Error::Offline {
@@ -606,10 +615,12 @@
606 615 url: url.to_owned(),
607 616 });
608 617 }
609 - let mirror = mirrored(expect).filter(|mirror| {
610 - fetch_with(mirror, path, Attempt::Mirror).is_ok()
611 - && std::fs::read(path).is_ok_and(|bytes| verify(&bytes, expect).is_ok())
612 - });
618 + let mirror = mirror
619 + .and_then(|base| mirror_url(base, expect))
620 + .filter(|mirror| {
621 + fetch_with(mirror, path, Attempt::Mirror).is_ok()
622 + && std::fs::read(path).is_ok_and(|bytes| verify(&bytes, expect).is_ok())
623 + });
613 624 if mirror.is_none() {
614 625 let _ = std::fs::remove_file(path);
615 626 fetch(url, path)?;
@@ -766,6 +777,115 @@
766 777 mod tests {
767 778 use super::*;
768 779
780 + use std::collections::HashMap;
781 + use std::io::{BufRead, BufReader, Write};
782 + use std::net::{TcpListener, TcpStream};
783 + use std::sync::{Arc, Mutex};
784 +
785 + /// An HTTP server that answers a fixed table of paths and records every
786 + /// path it was asked for.
787 + ///
788 + /// Real sockets and the real `curl` invocation, because what is under test
789 + /// is which host the bytes came from, and a stubbed fetch would be a test
790 + /// of the stub. The table is exact: a path the test did not name gets a
791 + /// 404, so a mirror URL shaped wrongly reaches the same fallback a mirror
792 + /// that lacks the file does.
793 + struct Stub {
794 + base: String,
795 + asked: Arc<Mutex<Vec<String>>>,
796 + }
797 +
798 + impl Stub {
799 + fn new(routes: &[(&str, &[u8])]) -> Self {
800 + let listener = TcpListener::bind("127.0.0.1:0").expect("binding a stub server");
801 + let port = listener.local_addr().expect("stub address").port();
802 + let asked: Arc<Mutex<Vec<String>>> = Arc::new(Mutex::new(Vec::new()));
803 + let table: HashMap<String, Vec<u8>> = routes
804 + .iter()
805 + .map(|(path, body)| ((*path).to_owned(), body.to_vec()))
806 + .collect();
807 + let log = Arc::clone(&asked);
808 + std::thread::spawn(move || {
809 + for stream in listener.incoming() {
810 + let Ok(stream) = stream else { continue };
811 + Self::answer(stream, &table, &log);
812 + }
813 + });
814 + Self {
815 + base: format!("http://127.0.0.1:{port}/bases"),
816 + asked,
817 + }
818 + }
819 +
820 + fn answer(
821 + mut stream: TcpStream,
822 + table: &HashMap<String, Vec<u8>>,
823 + log: &Mutex<Vec<String>>,
824 + ) {
825 + let mut request = String::new();
826 + let mut reader = BufReader::new(stream.try_clone().expect("cloning the socket"));
827 + loop {
828 + let mut line = String::new();
829 + if reader.read_line(&mut line).unwrap_or(0) == 0 || line.trim().is_empty() {
830 + break;
831 + }
832 + if request.is_empty() {
833 + request = line;
834 + }
835 + }
836 + let path = request.split_whitespace().nth(1).unwrap_or("").to_owned();
837 + log.lock().expect("the request log").push(path.clone());
838 + let response = match table.get(&path) {
839 + Some(body) => {
840 + let mut head = format!(
841 + "HTTP/1.1 200 OK\r\nContent-Length: {}\r\nConnection: close\r\n\r\n",
842 + body.len(),
843 + )
844 + .into_bytes();
845 + head.extend_from_slice(body);
846 + head
847 + }
848 + None => b"HTTP/1.1 404 Not Found\r\nContent-Length: 0\r\nConnection: close\r\n\r\n"
849 + .to_vec(),
850 + };
851 + let _ = stream.write_all(&response);
852 + let _ = stream.flush();
853 + }
854 +
855 + /// The URL a pin would carry, for the server standing in for upstream.
856 + fn url(&self, path: &str) -> String {
857 + format!("{}{path}", self.base.trim_end_matches("/bases"))
858 + }
859 +
860 + fn asked(&self) -> Vec<String> {
861 + self.asked.lock().expect("the request log").clone()
862 + }
863 + }
864 +
865 + /// A cache directory that removes itself, so a failing assertion leaves no
866 + /// tree behind.
867 + struct Cache(PathBuf);
868 +
869 + impl Cache {
870 + fn new(label: &str) -> Self {
871 + let dir = std::env::temp_dir()
872 + .join(format!("quasi-type-mirror-{label}-{}", std::process::id()));
873 + let _ = std::fs::remove_dir_all(&dir);
874 + std::fs::create_dir_all(&dir).expect("cache dir");
875 + Self(dir)
876 + }
877 +
878 + fn file(&self) -> PathBuf {
879 + self.0.join("atkinson-mono-2.001-LICENSE.txt")
880 + }
881 + }
882 +
883 + impl Drop for Cache {
884 + fn drop(&mut self) {
885 + let _ = std::fs::remove_dir_all(&self.0);
886 + }
887 + }
888 +
769 889 // The mirror is addressed by the digest the pin already carries, so a
770 890 // mirror can serve the pinned file or nothing at all.
771 891 #[test]
@@ -794,4 +914,127 @@
794 914 assert!(mirror_url("", "abc123").is_none());
795 915 assert!(mirror_url(" ", "abc123").is_none());
796 916 }
917 +
918 + // The mirror is the first source and upstream is not asked at all when it
919 + // answers. Ordering is the whole point of the mirror: upstream rate-limits
920 + // by IP, and a mirror consulted only after a failure would still pay for
921 + // the upstream round trip on every build that works. Reverse the two and
922 + // the upstream server here records a request.
923 + #[test]
924 + fn a_mirrored_file_is_taken_from_the_mirror_and_upstream_is_not_asked() {
925 + let bytes = b"the pinned licence text";
926 + let digest = hex(&Sha256::digest(bytes));
927 + let mirror = Stub::new(&[(&format!("/bases/{digest}"), bytes)]);
928 + let upstream = Stub::new(&[("/mono/OFL.txt", bytes)]);
929 + let cache = Cache::new("hit");
930 +
931 + let got = cached_from(
932 + Some(&format!("{}/", mirror.base)),
933 + &upstream.url("/mono/OFL.txt"),
934 + &cache.file(),
935 + false,
936 + &digest,
937 + )
938 + .expect("the mirrored file");
939 +
940 + assert_eq!(got, bytes, "the bytes are not the ones the mirror served");
941 + assert_eq!(
942 + mirror.asked(),
943 + vec![format!("/bases/{digest}")],
944 + "the mirror was asked for something other than the pinned digest",
945 + );
946 + assert!(
947 + upstream.asked().is_empty(),
948 + "upstream was asked for a file the mirror had: {:?}",
949 + upstream.asked(),
950 + );
951 + assert_eq!(
952 + std::fs::read(cache.file()).expect("the cached file"),
953 + bytes,
954 + "the mirrored bytes did not land in the cache",
955 + );
956 + }
957 +
958 + // A mirror serving the wrong bytes falls through to upstream rather than
959 + // failing the build, or an out-of-date mirror would be worse than no
960 + // mirror. The digest is checked here and again by the caller.
961 + #[test]
962 + fn a_mirror_serving_the_wrong_bytes_falls_through_to_upstream() {
963 + let bytes = b"the pinned licence text";
964 + let digest = hex(&Sha256::digest(bytes));
965 + let mirror = Stub::new(&[(&format!("/bases/{digest}"), b"an older licence")]);
966 + let upstream = Stub::new(&[("/mono/OFL.txt", bytes)]);
967 + let cache = Cache::new("wrong-bytes");
968 +
969 + let got = cached_from(
970 + Some(&mirror.base),
971 + &upstream.url("/mono/OFL.txt"),
972 + &cache.file(),
973 + false,
974 + &digest,
975 + )
976 + .expect("the upstream file");
977 +
978 + assert_eq!(got, bytes, "the wrong bytes were kept");
979 + assert_eq!(
980 + upstream.asked(),
981 + vec!["/mono/OFL.txt".to_owned()],
982 + "the fallback did not reach upstream",
983 + );
984 + assert_eq!(
985 + std::fs::read(cache.file()).expect("the cached file"),
986 + bytes,
987 + "the mirror's bytes were left in the cache for the caller to verify",
988 + );
989 + }
990 +
991 + // A mirror that does not hold the file is a slower build and not a broken
992 + // one, which is what lets the variable default to a host that may be down.
993 + #[test]
994 + fn a_mirror_without_the_file_falls_through_to_upstream() {
995 + let bytes = b"the pinned licence text";
996 + let digest = hex(&Sha256::digest(bytes));
997 + let mirror = Stub::new(&[]);
998 + let upstream = Stub::new(&[("/mono/OFL.txt", bytes)]);
999 + let cache = Cache::new("miss");
1000 +
1001 + let got = cached_from(
1002 + Some(&mirror.base),
1003 + &upstream.url("/mono/OFL.txt"),
1004 + &cache.file(),
1005 + false,
1006 + &digest,
1007 + )
1008 + .expect("the upstream file");
1009 +
1010 + assert_eq!(got, bytes);
1011 + assert_eq!(
1012 + mirror.asked(),
1013 + vec![format!("/bases/{digest}")],
1014 + "the mirror was not asked first",
1015 + );
1016 + assert_eq!(upstream.asked(), vec!["/mono/OFL.txt".to_owned()]);
1017 + }
1018 +
1019 + // No mirror named is no request, which is what `QUASI_TYPE_MIRROR=` in a
1020 + // build is asking for.
1021 + #[test]
1022 + fn no_mirror_named_asks_only_upstream() {
1023 + let bytes = b"the pinned licence text";
1024 + let digest = hex(&Sha256::digest(bytes));
1025 + let upstream = Stub::new(&[("/mono/OFL.txt", bytes)]);
1026 + let cache = Cache::new("no-mirror");
1027 +
1028 + let got = cached_from(
1029 + None,
1030 + &upstream.url("/mono/OFL.txt"),
1031 + &cache.file(),
1032 + false,
1033 + &digest,
1034 + )
1035 + .expect("the upstream file");
1036 +
1037 + assert_eq!(got, bytes);
1038 + assert_eq!(upstream.asked(), vec!["/mono/OFL.txt".to_owned()]);
1039 + }
797 1040 }