1313# MSI packaging uses wixl (GNOME msitools), which builds Windows MSIs natively
1414# on Linux - no Windows and no Wine.
1515
16+ # Derive a deterministic GUID from a label (ENT-13792)
17+ deterministic_guid () {
18+ printf ' {%s}\n' " $( uuidgen --sha1 \
19+ --namespace B883FBCC-6F05-4AFA-98FA-CAF09BF464EA \
20+ --name " $1 " | tr ' [:lower:]' ' [:upper:]' ) "
21+ }
22+
23+ # Make the Summary Information reproducible: wixl writes a random package code
24+ # (property 9) and the wall-clock build time (12/13 = Created/Last saved).
25+ # Rewrite them to a version-derived package code and SOURCE_DATE_EPOCH.
26+ # (ENT-13792)
27+ normalize_msi_summary () {
28+ msi=" $1 "
29+ revision=" $2 "
30+ if [ -z " $SOURCE_DATE_EPOCH " ]; then
31+ log_debug " SOURCE_DATE_EPOCH unset; skipping MSI summary normalization"
32+ return 0
33+ fi
34+ pkgcode=$( deterministic_guid " package:$revision " )
35+ datestr=$( TZ=UTC date -u -d " @$SOURCE_DATE_EPOCH " +" %Y/%m/%d %H:%M:%S" )
36+ msiinfo export " $msi " _SummaryInformation | tr -d ' \r' |
37+ awk -v u=" $pkgcode " -v d=" $datestr " -F ' \t' ' BEGIN { OFS = "\t" }
38+ $1 == "9" { $2 = u }
39+ $1 == "12" { $2 = d }
40+ $1 == "13" { $2 = d }
41+ { print }' | sed ' s/$/\r/' > _summary.idt
42+ msibuild " $msi " -i _summary.idt
43+ rm -f _summary.idt
44+ }
45+
1646# Determine build directory name based on Jenkins job or version/arch
1747log_debug " Determining build directory name (JOB_NAME=$JOB_NAME , VERSION=$VERSION , ARCH=$ARCH )"
1848if [ -z " $JOB_NAME " ]; then
@@ -85,6 +115,13 @@ pre() {
85115 if [ " $ARCH " = " x86" ]; then
86116 sed -i ' /lib\(crypto\|ssl\)/s/[_-]x64//g' " $P " /cfengine-nova.wxs
87117 fi
118+
119+ # Reproducible builds (ENT-13792): pin every packaged file's mtime to
120+ # SOURCE_DATE_EPOCH so the CAB stores a fixed timestamp per file instead
121+ # of the time each file was created.
122+ if [ -n " $SOURCE_DATE_EPOCH " ]; then
123+ find " $P " -exec touch -h -d " @$SOURCE_DATE_EPOCH " {} +
124+ fi
88125}
89126
90127# wixl_build() - Build the MSI from the WiX source using wixl (msitools).
@@ -108,7 +145,13 @@ wixl_build() {
108145 log_debug " Running wixl with REVISION=$REVISION , ARCH=$ARCH "
109146 wixl -a " $wixl_arch " \
110147 -D CfSourceDir=. -D CfVersion=" $REVISION " -D CfArch=" $ARCH " \
148+ -D CfProductCode=" $( deterministic_guid " product:$REVISION " ) " \
111149 -o cfengine-nova.msi cfengine-nova.wxs
150+
151+ # wixl still bakes a random package code and the wall-clock build time into
152+ # the Summary Information; rewrite them for a byte-reproducible MSI.
153+ # (ENT-13792)
154+ normalize_msi_summary cfengine-nova.msi " $REVISION "
112155}
113156
114157# package() - Main packaging function that creates the MSI installer
0 commit comments