From b7d5faf568b30c86daf7503f8518e11cbfeeaa81 Mon Sep 17 00:00:00 2001 From: konsti Date: Tue, 31 Mar 2026 12:15:44 +0200 Subject: [PATCH] Reproducible Windows trampoline builds (#18665) Build the Windows trampolines in a fully pinned docker container that allows auditing the compilation in CI. --- .../workflows/test-windows-trampolines.yml | 19 +++ Cargo.lock | 1 + Cargo.toml | 2 + crates/uv-trampoline-builder/Cargo.toml | 7 +- .../src/bin/normalize-pe-timestamps.rs | 110 ++++++++++++++++++ .../uv-trampoline-aarch64-console.exe | Bin 46592 -> 46592 bytes .../trampolines/uv-trampoline-aarch64-gui.exe | Bin 47616 -> 47616 bytes .../uv-trampoline-i686-console.exe | Bin 39424 -> 39424 bytes .../trampolines/uv-trampoline-i686-gui.exe | Bin 39936 -> 39936 bytes .../uv-trampoline-x86_64-console.exe | Bin 46080 -> 46592 bytes .../trampolines/uv-trampoline-x86_64-gui.exe | Bin 47104 -> 47104 bytes crates/uv-trampoline/.cargo/config.toml | 5 + crates/uv-trampoline/Dockerfile | 67 +++++++++++ crates/uv-trampoline/README.md | 8 ++ scripts/build-trampolines.sh | 49 ++++++++ 15 files changed, 267 insertions(+), 1 deletion(-) create mode 100644 crates/uv-trampoline-builder/src/bin/normalize-pe-timestamps.rs create mode 100644 crates/uv-trampoline/Dockerfile create mode 100755 scripts/build-trampolines.sh diff --git a/.github/workflows/test-windows-trampolines.yml b/.github/workflows/test-windows-trampolines.yml index 0bdbc1c53..06a1a4267 100644 --- a/.github/workflows/test-windows-trampolines.yml +++ b/.github/workflows/test-windows-trampolines.yml @@ -25,6 +25,25 @@ jobs: - name: "Check windows crate versions match" run: uv run --no-project scripts/check-trampoline-version-consistency.py + # Verify committed trampolines match a reproducible Docker build + windows-trampoline-reproducible: + timeout-minutes: 30 + runs-on: ubuntu-latest + name: "check reproducible build" + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - name: "Set up Docker Buildx" + uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0 + + - name: "Build trampolines in Docker" + run: scripts/build-trampolines.sh --cache-from type=gha --cache-to type=gha + + - name: "Check committed trampolines match build" + run: git diff --exit-code crates/uv-trampoline-builder/trampolines/ + # Separate jobs for the nightly crate windows-trampoline-check: timeout-minutes: 15 diff --git a/Cargo.lock b/Cargo.lock index ac122a397..c81a71ceb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7387,6 +7387,7 @@ dependencies = [ "assert_cmd", "assert_fs", "fs-err", + "goblin", "rcgen", "tempfile", "thiserror 2.0.18", diff --git a/Cargo.toml b/Cargo.toml index 7a74b7eb3..cfb1c2a84 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -157,6 +157,8 @@ goblin = { version = "0.10.0", default-features = false, features = [ "elf32", "elf64", "endian_fd", + "pe32", + "pe64", ] } h2 = { version = "0.4.7" } hashbrown = { version = "0.16.0" } diff --git a/crates/uv-trampoline-builder/Cargo.toml b/crates/uv-trampoline-builder/Cargo.toml index d8d2acc6e..0cd730a16 100644 --- a/crates/uv-trampoline-builder/Cargo.toml +++ b/crates/uv-trampoline-builder/Cargo.toml @@ -20,10 +20,15 @@ production = [] [lints] workspace = true +[[bin]] +name = "normalize-pe-timestamps" + [dependencies] uv-fs = { workspace = true } -fs-err = { workspace = true } +anyhow = {workspace = true } +fs-err = {workspace = true } +goblin = { workspace = true } tempfile = { workspace = true } thiserror = { workspace = true } zip = { workspace = true } diff --git a/crates/uv-trampoline-builder/src/bin/normalize-pe-timestamps.rs b/crates/uv-trampoline-builder/src/bin/normalize-pe-timestamps.rs new file mode 100644 index 000000000..d5e316aca --- /dev/null +++ b/crates/uv-trampoline-builder/src/bin/normalize-pe-timestamps.rs @@ -0,0 +1,110 @@ +//! Zero out non-deterministic fields in PE executables. +//! +//! Even with the `/Brepro`, the PE timestamp and debug directory GUID change +//! between builds. We have to zero out those fields so the final binaries are +//! byte-for-byte reproducible. +//! +//! Fields zeroed: +//! - COFF header `TimeDateStamp` +//! - Each `IMAGE_DEBUG_DIRECTORY` `TimeDateStamp` +//! - `CodeView` PDB70 `Signature` (GUID) and `Age` + +use std::env; + +use anyhow::{Context, Result, bail, format_err}; +use goblin::pe::PE; +use goblin::pe::debug::{IMAGE_DEBUG_TYPE_CODEVIEW, ImageDebugDirectory}; +use goblin::pe::section_table::SectionTable; +use uv_fs::Simplified; + +/// Collected fixup locations from the PE parse. +struct DebugEntryFixup { + /// File offset of this `IMAGE_DEBUG_DIRECTORY` entry. + entry_file_offset: usize, + /// The `IMAGE_DEBUG_DIRECTORY.data_type` field. + data_type: u32, + /// The `IMAGE_DEBUG_DIRECTORY.pointer_to_raw_data` field (file offset of the payload). + pointer_to_raw_data: u32, +} + +/// Resolve an RVA to a file offset using the PE section table. +fn rva_to_file_offset(sections: &[SectionTable], rva: u32) -> Option { + sections.iter().find_map(|section| { + if rva >= section.virtual_address && rva < section.virtual_address + section.virtual_size { + Some((rva - section.virtual_address + section.pointer_to_raw_data) as usize) + } else { + None + } + }) +} + +fn parse_debug_entries(data: &mut [u8]) -> Result<(usize, Vec)> { + let pe = PE::parse(data)?; + + // COFF header: pe_pointer -> "PE\0\0" (4 bytes) -> CoffHeader fields. + // `CoffHeader.time_date_stamp` is the second u32 field (offset 4). + let coff_timestamp_offset = pe.header.dos_header.pe_pointer as usize + 4 + 4; + + let mut debug_entries = Vec::new(); + if let Some(debug_data_directory) = pe + .header + .optional_header + .and_then(|opt| opt.data_directories.get_debug_table().copied()) + { + if let Some(debug_data) = &pe.debug_data { + let debug_dir_file_offset = + rva_to_file_offset(&pe.sections, debug_data_directory.virtual_address) + .ok_or_else(|| format_err!("cannot resolve debug directory RVA"))?; + let entry_size = size_of::(); + + for (i, entry) in debug_data.entries().enumerate() { + let entry = entry?; + debug_entries.push(DebugEntryFixup { + entry_file_offset: debug_dir_file_offset + i * entry_size, + data_type: entry.data_type, + pointer_to_raw_data: entry.pointer_to_raw_data, + }); + } + } + } + + Ok((coff_timestamp_offset, debug_entries)) +} + +fn clear_debug_entries( + data: &mut [u8], + coff_timestamp_offset: usize, + debug_entries: &[DebugEntryFixup], +) { + // Zero COFF header `TimeDateStamp`. + data[coff_timestamp_offset..coff_timestamp_offset + 4].fill(0); + + // Zero debug directory timestamps and CodeView GUIDs. + for entry in debug_entries { + // Zero `IMAGE_DEBUG_DIRECTORY.time_date_stamp` (offset 4 in the struct). + let timestamp_offset = entry.entry_file_offset + 4; + data[timestamp_offset..timestamp_offset + 4].fill(0); + + if entry.data_type == IMAGE_DEBUG_TYPE_CODEVIEW { + // PDB70 layout: magic[4] ("RSDS") | guid[16] | age[4] | filename... + let payload = entry.pointer_to_raw_data as usize; + data[payload + 4..payload + 20].fill(0); // Signature (GUID) + data[payload + 20..payload + 24].fill(0); // Age + } + } +} + +fn main() -> Result<()> { + let args: Vec = env::args().collect(); + if args.len() < 2 { + bail!("Usage: {} [...]", args[0]); + } + for path in &args[1..] { + let mut data = fs_err::read(path)?; + let (coff_timestamp_offset, debug_entries) = parse_debug_entries(&mut data) + .with_context(|| format!("Failed to normalize: {}", path.user_display()))?; + clear_debug_entries(&mut data, coff_timestamp_offset, &debug_entries); + fs_err::write(path, &data)?; + } + Ok(()) +} diff --git a/crates/uv-trampoline-builder/trampolines/uv-trampoline-aarch64-console.exe b/crates/uv-trampoline-builder/trampolines/uv-trampoline-aarch64-console.exe index e5449cee8e8462fb85530bccb56fc0eb7420f29e..a9cbc2d3bf36d0806e4676188e6cb33155783701 100755 GIT binary patch delta 4165 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 L>Bcy+M!Ee5l3L1E diff --git a/crates/uv-trampoline-builder/trampolines/uv-trampoline-aarch64-gui.exe b/crates/uv-trampoline-builder/trampolines/uv-trampoline-aarch64-gui.exe index 25009cb3c13dc714e793564e7bff5589efba9889..0cdcef8a63c4cbef38c361335cc345c3339e3e25 100755 GIT binary patch delta 4087 zcmeH~k5`ms7RR4E12`%c%8wa-=**NZh_a%BfInzP6cH@}L9swk&>&s&R|#k_DS9+n znU_lfdupXxU6`oQ*AgsDPu8Kf_Q1B8d0ZRNPEeg)R*f8!X1_1acow422*ludBPVms5zC6x^gc&ToVzQ7&H(n?loh z!uV~pMy?(|i)b2uG$Gly<(gJVruHKlI&X^{YMf0J%PUOFsEd!8dZ;}we#utIC`0{$3I9faZo}Yo#Uqy_RxO$c7jnuzvqy-QxJOc++}ot56}IA zf_c+CJ(jU=-c}tA$gYJ|nt+VaqNdF4);qOEM>o>-4&>_O$y~f}GYDVhv#U}h*@yqWO|-+ zv*PI>AI^%?g#}53J66h{XO(E7dt_A{ZrrzOG*OdW{pcv7+x*gF7wKz$IwzG*@VOil zN9F4IR!#sN;W4=;?#|Kkg4_VAk6GfvX zE9Sa#R~{u1u3zFwt5d0kH?Ov8Mp{^2JtNp`8G1(Qy+qB~u_6{FV0UT*9J;;y^XiAF zmlN~WlZ%h$O&t5(BGtZ#}%iM+Kk@TIr z_A)lw3}5E#`}oa#D;?v1=jTx}r?06SPP|fi#-xPd#M_a0&DumtXY1OfG{A?}R#OO@ z3p$ai>jf+5G%qd;9ihah8*AYWg~=M-1eOaY8(%}{O32E-Pyg0ktC*l+*o7%p(v7k3 zPldDLbk@4W#J#_;9IaY9-}jO5ggbN#Ev_CkiL3Z353dM51XS>tqBd}3WV z&Ere!7L9-Sp6xZ&{%+!|oVZ?JG~MF55ofvE7Thwm>4fO-#%#K_d+p+?5H-({h;_== zw)>I7qP_zey&D``jY7A$^_Vqg{fD;~1A}v4j zcsw2Dw=s_5+mDCRAO{sa;7J*t=ZA_;5RK>S#Y^abocP4F5qLf~ZOPCEn#gzolL)1W z4DNidX%MYxC4aj8&A?Z#x@(oRqK^j*r}$qiJ(chMgvDj}Odfa&#rr$f?0AHp|G{qTlHwBmywhAbN>cO>cnRqxPAEysU#rDN z1Ui%|>d^){mi^$aExn@}=P1T{$9!SSSPcC(=sndI09${@0_fcD3u*AD`At9iTUQc zaeVDi1e>c3eBw|DM^#PXpei$GSDE;ustNo;l^;J_W#w^8I8y=|4SiWGnWDelMI>Y)7o5$f&*=8*J$Tu~0+;~s{nj8HjO z1FBXjQ#%n}( zjn8SWa(ttKKR+DpGvk%7qUxtWHCy*-uIX><|L%6n=QIgajwVxq%J2m%!B(&V%p9xy zkP#w!oDd!0Nw6RE@)zO`cs>Y~^)~E-VFN~l2w?$Bz)Y|g%m>3lQQ=@6XanB`D?vk; z$F6)o1`SYHj6$>vo9HlMGDV&!M1pXN67VeKqDex00(O8-(C;@w+ypa0aS9WFzTm`g zAxxkRoC@9n;}t!AhAaRtM&kb!ICm-M)pui8{btxZoS*S!o@(A95#H1BRhZ z{|Stqj)1_E;3uG%0jJ=^nL=CxGh=W+STqa1S}|E1?gb6;$P$V#e54&bkH22ZioOS(kT)hHh&BWS`hqu85Db`uzdKee z>|HPhvfnby19qn28kmwUgt;6BMHo~-(Foc>k%27%Bfw_xMRW^AJ`Z+)@mWG#2JfsC z;ug3)8+CCSwyUs8umhY3UIwRvh8(OEv~R-#!J6%;6Gi`&5F;xvXvV2QP!2&tbFL;AfARDKat9{ykVTSh*L5V9`F$GqN4L4Eek&cYmYo0=n<8=4#C4_f2sKj+hZhX4Qo delta 4110 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 diff --git a/crates/uv-trampoline-builder/trampolines/uv-trampoline-i686-gui.exe b/crates/uv-trampoline-builder/trampolines/uv-trampoline-i686-gui.exe index 0811c065c76c073ee9ec13161bdf0e01637b19ef..b95f3cc4bfb7970e89b122e0458a9927ff3270e7 100755 GIT binary patch delta 2089 zcmc(ek55xq6vyv5KAx3ffMo@b(VrPPrHtGWOIbgFB zo#j+zRupv0m_vhk#uc_G&P|w^N}`!SjMGGBGfl*Z44v8Ac@(DX57=(<$-U>?bI(2J z`|jf%4DVp}@-l+MT4$ug)~B)Vd=nvRYt)R;a$JPqPTK)Ox}}hbu>v$ShhBzO8cRon zpQwhBe}0f71%(EZE3)4SF|sFKA*o>>4D@hb-$(MRdpOyrGdsTOAxnSF@e@*}<#_o^ z@%7zCx$DSju(Cla$>*{ixLSL`AlEt1ilT^d^n$-{QujwRox!C>WK-c9J3`x`H)xgb zW>>0dB5Q=G;J6u)c8+wqQ9{ysO~D4SNMuJ~ZE!DD3b7#zDeV>3g?dst2JeOGsZF>T zcFLO$!#3rsv=|~x<)}(2+(|e8brw zW-8%p!iljElfl=?D`_@7O&$!mIev{%mNa_bH)%9ex@jmSMjk5_R#=2(1&Zu8T>q=A z%E_{lxvezjkSmFzT(yUjzD>)xZE|;9UdfSTsVy84Z?|^9)x~ABA6{Q_jFt$4ODt5b zLJe!jsL?~JsbZOZw(C{{5!oi`&I?ndNJ@J=E(IiHR4_LHS~84`mkok4OKF0zHM518 zP_s~rWrv7tgOs9YN{W=UKTNn|11_r+1!&Du(JzH7S--f`O~MyBR!ZAofhNw=VdY3y zlNH|41wxf(x#xgnJ6!fHw4X`#fXn9ca%nMG^A^#3=*!zee}<*nnDD#O-RGU}D+sdT5R=kn*0f=?UCK@*NW^;+^8LM zGd;8nIHSF#WG1sg#550}IX}iTx)BR`W`#@nr9N4>-kq&fbwxvJfiAoZIO2>8AjFWY z?~K8MoeyWA!Rb4Tp{-ypc7MI#uu>AdRr)~MBC*eMaf(>$)BZ9|m&Dp%c*d_%%HE(< z;DhhVY83QECn>!S-a3t^YCqQCw;#oNgZ9A@-9jeN4mWjcgS}i|*S|gu4;e)4KSE?f z?4Z%dF~knldS#>nL$DbcPN>!hs)QBj4B{?~MgIt#*9Xxm=+~#y6Tq(i#`A;?FWYGw z|1$Sh&!^=uvt*WH7`wpVcgWJCmEKM_yj2oPe-Pd+SwQJ+XkHVJe?;e+G!Og{AFr!) z`{&)Al)BrpVIEC{mJK%i(dU=%ex(o9unZIyIQ<4iu~@gucb8V?eBLgKyGxX^u0FU^ z9*upRGBMbxj7Ny_)vJ;JQGIDvtTKo0Sg^z}N{F(8b*LLWjdB-e4 z^D@YwH3h+nkGEm98n;{7$NK6tkc;<1|#DUM-x&vdCWEABb_qx zw9B;Cs6gnbi^!8U@;`gA{mBtRRvaWmj!cdN=p%MQR4@6CqAwDC>X&@&=u_FPQ9as|1Ij3GYFghU|m$RcDF zqDRUQBU0B)%*2L^uHK~HtTw8hu-Ja?ZxJ5W{Qv*} delta 2092 zcmc(fi%(Nm7{JfD6nT}$fbw*Tcm;;YTZM?`g7}(M3gy*W9h->I8A01lOepO}Q5$iw ze25H0VLHP$V`i>%fJQMsK%E|T-x%Q!cviODO3ZLSgf1y!7+mHGGC%l1_K0qQfuN;c za;GbAL8gF7!Lb3)QSNb}grpA`g0(`CARB}g!2^`=(IK-a-N&yCb)$3$J`7XSD*kNP zArD#&)$C-dfL-h~s^HJF8ROnLjb5}wSt#gPsUTZ}lJ!h|pTSd*RXO4rE#Z&H`%oE&7ImY7uVoZFW?jQdu`3yHD`6*%;Ws9RGNEx!1AV2nzwR%I zL1V5BC;CEk245#Hp)v3@dBnfl5k@abdUDq*>B)RC((RNeX|$MFVG*VkD9G}0{jaoi zV`(LG8)#Iu(}`bs+^3v)HZ=~};M#q02}ky(c5pGRx>;n31)Yrtu?LRw{LG z6Dy$labixD*=BX3*-e^Tq`a?%6AYoo5Fkjx5?SKUOA)|sKT3pBlcK-LbS>1 zo-$0>em?*OPTdm)T?JFI`k{i|tl02Q@qm;?!l3o+8_ggcIn#KIy3fEODf`4}8PJQdsag$cS`o{~h zN3D>nj%BX5f>F&z+(Q#A<|a34RxFKR(~v)_$dUcXq*IO(^Z)S7~NadJNi^hvSRrS)M))AL7H6 zI+uU$-9fRs^{b~*DRiuE!VuHTw@oa@Zdk7s7TA481ff{9)oZI#Vt;->5VmPpNpCUS zDv!jJBo!MOdn<3M;3(tL%%9X6{h`Vj0|}-Om}3lsZetd-7$e}B(G!%l;+zAz+95b$ zN`wfrE67bcoF_w>$p>beJmJ166y}=eIrg71M?#}H9B!EVz~_?*4&ApOtN6H2YQ%bM z%q;JPnB>?PfCqJz-Zi48k0X9aHLSA)OcVdMq78$@BP}h6g^)aDwlZ)rU&fxB5+j#q zM<}wh;wfCTOkA4ynP~4EWqSx=TM4nhrqiMBI_lh!u~Cb<=O_ohrrUx#_cq(4AX7*i zA*o0fqCiTKj}Qy89odH*M$RI`$Zv@IEJ;ZZ2A(2Q1B1bgHTEv2gqY3Bz$Pwf;avAvv`2!Kh zI4m&`5l0-(8HnPg{Hkcv|5Ej#k=N*jR8wiAB?>=oKY diff --git a/crates/uv-trampoline-builder/trampolines/uv-trampoline-x86_64-console.exe b/crates/uv-trampoline-builder/trampolines/uv-trampoline-x86_64-console.exe index 5cdd48d5b13579ee04be332de506d09d3a48feb9..3e3117c2bb698f67fe69a4ea1d93fff3c51259ac 100755 GIT binary patch delta 4724 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 REUYZ4EU$diI9=US{tH51ekT9` delta 4775 zcmchadsJ1`7RJ}wf&=jd>OllSkRzZx0)+&{6hhqSfqOwpZz$jsNmM{UR1^fsws-`b zrj%KjR+ggRHhg4?*U;>VUJ50LkFI%-Xbsdv(sbWB&t8q&X!ze9qcg_G?^|oHz1CcF zuD#EpxI-%LkSdF9-deRgqiXG1{wnm~KDG|Ej18{x?C)mT%a|`?tZoluVH}P4T-eW; z1?pdOg<>AWbD^I5@ZIV~K3Q_ls9{W2P6nTkRXSpoU**zIJ(5#XB2yw$Wo=lY8foJ? zfCs@$XJ_#b-}>Gr)pPhKoPPjUMl8hu zruu!&^I)idjN{r)TJ21}w@JApD{YoqSnj`%H-T@!Gq}$503+VBDj<>XP@4m?B_0D& zK_i1}av3uz*Oc}+#WFGYtY)~f6eCg2lr`qrYlb##pv#U{p2*?%^E@@fXX?8_CEVHZ zwx*fPHhCB@i{loY!KAcX9^HcRBMs8ZPIz&oyOi9i=8x>prI`C_`KUph*TB0WL3|l} z7jlUI4K{}QJ0va^yIX}vN;8aAKM#$N+%7K^y_vFdCiwf($2NIOi&wj{+(nvUGI)i> z@l41LJ2;>f$KjE&3GTer`#7Cm%@6|N;hTD7{)mZC?pU@%OL&;naUJ@M8O*c6Z_IpL zchi^>uhgG3ZEa(2fNVZ!Y{naLFoqwebXj^}^6Az97(Mpi{4}^m1o2s5iparZdLm*F zw^J`h#7aC(^%{Rk;$IzzinHNkAU?(~bXy9}Q*JW)nv{o;ibXSgIFl0Dgz4*}8NS6v zS!3Tae6ZL=#bOF?%JbI@CtzPpqV&x*kS1kGGp|AJq+!yt*I?VEM+0vp<8-(?gKRdG zOr{VqK^K#uR`%xSpheE$hv2zbSBLy7SP12jjE|yn*RtRWWW;XbT>ULJl-n(Qi9!kp zQNyS7;yemsOrZgCg5o_Iw9)pd<;N!wiQ>~j|w`uX9Bj006 z%8wa6FvYUcB|o^3?I@djmrQ|Y;x_R4a4fFSDQOC0M@Qq{EG|BDo-mj;%YKNDFX8^` zx%hV^J^*qPo(+9@DqVeq15C|^bfmiy-^PPv5}xR7J@_ae4J=m@&q0V zhm))M21u9@;=WGC^qsWy>aQ2~SA2f)@W|y!#sbYS5_Zm*VweA%b?!sZIpcMw-jlFV zKJIu7VOSBh%mEDEomqjepwN_cb`Igz(LwNON(w&?Ua2Mc8htNS;nN`~EhMlmnhI)r z5wl1q_6M!`_u~EhyftkLF{dUho||U4^gL`zTPU4BqiSgqm%cu&cALG9^Vv{7$3rqU zLG7FZegeGbMsXX+n49IYasp$eUA%8u6(tZ4a)Eg1mcYHaQ+Rh6KQGY!!FcNqHN$tX zY@VB;nwsX#)|{6PrM+v0&G5mzaroZ+&%C{MJ4RWza|*W2e@ps40>-8X_WO7oMVfm7 zAMLYvO6ZYZneN6z)YsGVxpaRlIA#R$?dpV#McpyJeM^SI!mP>C+Y%hg@`2_h<9az@ zmh~6rOsw<1`L<8mUCI1p6$&C%jRgKhpgD)BV&nrtZ9|>6>v%}z3ppR1KV>3 zNf#c&njBZY1kUB0;@0aEwHr02Yf50z^)1}Xy5o8jIXqZFE$Q=GZm2#Tsa2%RStn!m7VZ*l_R#DVOmwt z&bq2@hMQ%Y*83Gr^F@)riwcCM&9`_Meo0T0(i&m^YfkoQwQK^Wf@RfWb0AdjTo=4R zbQK5|3)VF1Ls^GT2f=FKTU}%6*8B)8~a|xzQcd$3&Osd`YKPCqDH(zpG$)6f?a~W4(Qk21^orX1Wkf71Q!by z3vLmt6Fe<=U1t%qQS}A-2?h#A2__0I5G)kjC|DzSK=7Y}=LIhdwhML%+8v~Iix_jZ z8mx}sWWm{jD+D(S9uWLo@VekHf;J!N8*&o#7u0(hixBO2BCgL;L`SCJ3c>Y)ZwUTA z!9LMG_NV?9(Y`L&^{4AkD>bdp{-Rnxt<=`_*{!efiZhj58jIBja+=rs^#A+wT-b7FQco1U;(SM2T>w-i-0-25~YQYAX)2OTHiH}jV z05RKDUx4^3ih>}XN8LtG3?0l^C3<3_o4%Oj&e$H*Z`e;b0A3)vctmZ)?N_P!t4ljqt=;;fZHZw1HM+#4vq+8EHoO<2=Nx zsKN$3Xk@y1>o*XK@!!P|97Nnd9ADh%i8oNw(f@+%IYJ*#j6kJfKd~G&0~aRNp(u!E zB=gffaV&~TMtq|PzkD+B<~NWXD4K{k{24uJ;xW`(?0<|*57Nh6M|zIJ`eHwEC#nwp z56D>|jD3oJ8S-t^1@y#!p{}A&d6uz_D9U0H89o|oi5G~YP?Tz7Ll{PWSZDSaEDicH zWIg`i^G8oSFrKk!^i9YcDB3acohbC!Py7r;X>TPTjT^>(qVq(2(YD|XXjlx2BASD& zo`N0+Jw(14r|+J44@GCCTRdZfP_!8F1r%kDSb?H45kElD7@}hWV|#H}@;-_JC9)UwiHIwv;ny{eA)Z71f}ZHP6rTe0 z#Ject5uJ;3u}npW7$dU-MLWBMyn~|Xo*+H*bWaQyo|qtfF|r*+_Ywp1^`J)~=b|X> z#5xpZg*axJK89HI3I1`$h=`k3=r<65LbWvLT)0xdfw%=lyMG_~HHrdlM!Fa3&w2&& zvhc)NtMrA5TTql04Y^{q)fZXKW^B+z#GS$uKM|hTCOmyN$D`6P=qzLoY61F6JD#hm>JrUO8sYXxSj-rW(9Vi-4d?@;f k6=gU^J-NrWr=w+W$KI~JtTwH7L2XuTL2a?x+Ay5|7ynXwS^xk5 diff --git a/crates/uv-trampoline/.cargo/config.toml b/crates/uv-trampoline/.cargo/config.toml index 992e4ab63..c5fcd3c82 100644 --- a/crates/uv-trampoline/.cargo/config.toml +++ b/crates/uv-trampoline/.cargo/config.toml @@ -2,3 +2,8 @@ build-std = ["std", "panic_abort"] build-std-features = ["compiler-builtins-mem"] panic-abort-tests = true + +# Make PE binaries reproducible: replace timestamps and debug GUIDs with +# content hashes so identical source produces identical bytes. +[target.'cfg(windows)'] +rustflags = ["-C", "link-arg=/Brepro"] diff --git a/crates/uv-trampoline/Dockerfile b/crates/uv-trampoline/Dockerfile new file mode 100644 index 000000000..09128c626 --- /dev/null +++ b/crates/uv-trampoline/Dockerfile @@ -0,0 +1,67 @@ +# Reproducible cross-compilation environment for Windows trampolines. +# +# All toolchain versions are pinned for binary reproducibility. +# This image provides the build environment; the workspace is bind-mounted +# at runtime by scripts/build-trampolines.sh. + +ARG UBUNTU_SNAPSHOT=20260127T200000Z + +ARG RUST_NIGHTLY=nightly-2025-11-02 + +ARG CARGO_XWIN_VERSION=0.21.4 +ARG XWIN_SDK_VERSION=10.0.22621 +ARG XWIN_CRT_VERSION=14.44.17.14 + +FROM ubuntu:26.04@sha256:4095ef613201918336b5d7d00be15d8b09c72ddb77c80bca249c255887a64d87 AS base + +ARG RUST_NIGHTLY +ARG UBUNTU_SNAPSHOT + +ENV HOME=/app +ENV CARGO_HOME=${HOME}/rust/cargo +ENV RUSTUP_HOME=${HOME}/rust/rustup +ENV XWIN_CACHE_DIR=${HOME}/xwin-cache + +WORKDIR ${HOME} + +# Install build dependencies +RUN apt install -y --update ca-certificates && \ + apt install -y --update --snapshot ${UBUNTU_SNAPSHOT} \ + curl \ + llvm \ + clang \ + lld \ + && ln -s /usr/bin/llvm-mt /usr/bin/mt.exe \ + && rm -rf /var/lib/apt/lists/* + +# Install Rust nightly toolchain with Windows targets +RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | \ + sh -s -- -y --default-toolchain=${RUST_NIGHTLY} --profile=minimal + +ENV PATH="${CARGO_HOME}/bin:${PATH}" + +RUN rustup component add rust-src --toolchain ${RUST_NIGHTLY}-x86_64-unknown-linux-gnu && \ + rustup target add --toolchain ${RUST_NIGHTLY} \ + i686-pc-windows-msvc \ + x86_64-pc-windows-msvc \ + aarch64-pc-windows-msvc + +# Install cargo-xwin and prefetch the Windows SDK/CRT +FROM base AS xwin-cache + +ARG CARGO_XWIN_VERSION +ARG XWIN_SDK_VERSION +ARG XWIN_CRT_VERSION + +RUN cargo install cargo-xwin@${CARGO_XWIN_VERSION} + +RUN cargo xwin cache xwin \ + --xwin-sdk-version ${XWIN_SDK_VERSION} \ + --xwin-crt-version ${XWIN_CRT_VERSION} \ + --xwin-arch x86,x86_64,aarch64 + +FROM base + +COPY --chmod=a+rwX --from=xwin-cache ${HOME}/xwin-cache ${HOME}/xwin-cache +RUN chmod a+w ${HOME}/xwin-cache +COPY --from=xwin-cache ${CARGO_HOME}/bin/cargo-xwin ${CARGO_HOME}/bin/cargo-xwin diff --git a/crates/uv-trampoline/README.md b/crates/uv-trampoline/README.md index 4fec7cc03..a419f504f 100644 --- a/crates/uv-trampoline/README.md +++ b/crates/uv-trampoline/README.md @@ -5,6 +5,14 @@ This is a fork of ## Building +The trampolines checked into the repo use a reproducible dockerfile for auditing. + +```shell +scripts/build-trampolines.sh +``` + +The other build options exist for local development. + ### Cross-compiling from Linux Install [cargo xwin](https://github.com/rust-cross/cargo-xwin). Use your package manager to install diff --git a/scripts/build-trampolines.sh b/scripts/build-trampolines.sh new file mode 100755 index 000000000..504dce009 --- /dev/null +++ b/scripts/build-trampolines.sh @@ -0,0 +1,49 @@ +#!/bin/bash +# Build all Windows trampoline executables reproducibly using Docker. +# +# Extra arguments are forwarded to the docker build command + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +TRAMPOLINE_DIR="$REPO_ROOT/crates/uv-trampoline" +OUTPUT_DIR="$REPO_ROOT/crates/uv-trampoline-builder/trampolines" + +# Read the nightly toolchain from rust-toolchain.toml +TOOLCHAIN="$(grep '^channel' "$TRAMPOLINE_DIR/rust-toolchain.toml" | sed 's/.*"\(.*\)"/\1/')" + +# Build the pinned toolchain image. +docker buildx build -t uv-trampoline-builder --load \ + -f "$TRAMPOLINE_DIR/Dockerfile" "$TRAMPOLINE_DIR" \ + "$@" + +# Build trampolines inside the container with the workspace bind-mounted. +# The working directory must be the trampoline crate so cargo picks up +# .cargo/config.toml (which enables build-std). +docker run --rm \ + -v "$REPO_ROOT:/workspace:ro" \ + -v "$OUTPUT_DIR:/output" \ + -w /workspace/crates/uv-trampoline \ + uv-trampoline-builder \ + bash -c ' + set -euo pipefail + export CARGO_TARGET_DIR=/tmp/target + + cargo +"'"$TOOLCHAIN"'" xwin build --xwin-arch x86 --release --target i686-pc-windows-msvc + cargo +"'"$TOOLCHAIN"'" xwin build --release --target x86_64-pc-windows-msvc + cargo +"'"$TOOLCHAIN"'" xwin build --release --target aarch64-pc-windows-msvc + + for arch in i686 x86_64 aarch64; do + for variant in console gui; do + cp /tmp/target/$arch-pc-windows-msvc/release/uv-trampoline-$variant.exe \ + /output/uv-trampoline-$arch-$variant.exe + done + done + ' + +# Zero out non-deterministic PE fields (timestamps, debug GUIDs) so that +# builds are byte-for-byte reproducible despite LLVM non-determinism. +cargo run --quiet -p uv-trampoline-builder --bin normalize-pe-timestamps -- "$OUTPUT_DIR"/*.exe + +echo "Done. Trampolines written to $OUTPUT_DIR"