Skip to content
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

Make eext builds reproducible #101

Merged
merged 1 commit into from
Mar 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 27 additions & 7 deletions cmd/create_srpm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package cmd

import (
"fmt"
"os"
"path/filepath"
"testing"
Expand All @@ -12,11 +13,13 @@ import (
"github.com/stretchr/testify/require"

"code.arista.io/eos/tools/eext/testutil"
"code.arista.io/eos/tools/eext/util"
)

func testCreateSrpm(t *testing.T,
repoName string, expectedPkgName string, quiet bool,
expectedFiles []string,
expectedOutputFile string,
expectedTags map[string]string,
sources []string) {
t.Log("Create temporary working directory")
workingDir, err := os.MkdirTemp("", "createSrpm-wd-test")
Expand Down Expand Up @@ -59,17 +62,26 @@ func testCreateSrpm(t *testing.T,
testutil.RunCmd(t, rootCmd, args, quiet, true)

require.DirExists(t, expectedSrpmDestDir)
for _, filename := range expectedFiles {
path := filepath.Join(expectedSrpmDestDir, filename)
require.FileExists(t, path)
expectedPath := filepath.Join(expectedSrpmDestDir, expectedOutputFile)
require.FileExists(t, expectedPath)

for tag, expVal := range expectedTags {
qfField := fmt.Sprintf("--qf=%%{%s}", tag)
tagVal, rpmErr := util.CheckOutput("rpm", "-q", qfField, "-p", expectedPath)
require.NoError(t, rpmErr)
require.Equal(t, expVal, tagVal)
}
}

func TestCreateSrpmFromSrpm(t *testing.T) {
t.Log("Test createSrpm from SRPM")
testCreateSrpm(t,
"debugedit-1", "debugedit", false,
[]string{"debugedit-5.0-eng.src.rpm"},
"debugedit-5.0-eng.src.rpm",
map[string]string{
"BUILDHOST": testutil.ExpectedBuildHost,
"BUILDTIME": testutil.DebugeditChangeLogTs,
},
nil)
}

Expand All @@ -81,7 +93,11 @@ func TestCreateSrpmFromTarball(t *testing.T) {
}
testCreateSrpm(t,
"mrtparse-1", "mrtparse", true,
[]string{"mrtparse-2.0.1-deadbee_beefdea.src.rpm"},
"mrtparse-2.0.1-deadbee_beefdea.src.rpm",
map[string]string{
"BUILDHOST": testutil.ExpectedBuildHost,
"BUILDTIME": testutil.MrtParseChangeLogTs,
},
sources)
}

Expand All @@ -93,6 +109,10 @@ func TestCreateSrpmFromUnmodifiedSrpm(t *testing.T) {
}
testCreateSrpm(t,
"debugedit-2", "debugedit", true,
[]string{"debugedit-5.0-3.el9.deadbee_beefdea.src.rpm"},
"debugedit-5.0-3.el9.deadbee_beefdea.src.rpm",
map[string]string{
"BUILDHOST": testutil.ExpectedBuildHost,
"BUILDTIME": testutil.DebugeditChangeLogTs,
},
sources)
}
2 changes: 2 additions & 0 deletions cmd/mock_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ func testMock(t *testing.T, setupSrcEnv bool) {
expectedTags := map[string]string{
"release": expectedRelease,
"distribution": expectedDistribution,
"BUILDHOST": testutil.ExpectedBuildHost,
"BUILDTIME": testutil.MrtParseChangeLogTs,
}
runMockAndVerify(t, destDir, repoName, expectedPkgName, false,
expectedRpmFiles, expectedTags)
Expand Down
3 changes: 3 additions & 0 deletions cmd/testData/mrtparse-1/spec/mrtparse.spec
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,6 @@ information base contents, and is standardized in RFC6396. Programs like Quagga
%{python3_sitelib}/mrtparse/params.py*
%{python3_sitelib}/mrtparse/__pycache__/*cpython*

%changelog
* Fri Mar 15 2024 Arun Ajith S <[email protected]>
- Dummy changelog for tests
26 changes: 24 additions & 2 deletions configfiles/mock.cfg.template
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,33 @@ config_opts['use_bootstrap_image'] = False
config_opts['cleanup_on_failure'] = False
config_opts['cleanup_on_success'] = False

# Make sure static libraries are deterministic
config_opts['macros']['__brp_strip_static_archive'] = '/usr/lib/rpm/brp-strip-static-archive "%{__strip} -D"'
# We add in FILE_OFFSET_BITS for 32 bit to be able to handle larger inodes
config_opts['macros']['_preprocessor_defines'] = '-Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -Wp,-D_FILE_OFFSET_BITS=64'

# Reproducible builds - BEGIN

# Make sure static libraries are deterministic
config_opts['macros']['__brp_strip_static_archive'] = '/usr/lib/rpm/brp-strip-static-archive "%{__strip} -D"'

# If true, set the SOURCE_DATE_EPOCH environment variable
# to the timestamp of the topmost changelog entry
config_opts['macros']['source_date_epoch_from_changelog'] = '1'

# If true, make sure that buildtime in built rpms
# is set to the value of SOURCE_DATE_EPOCH.
# Is ignored when SOURCE_DATE_EPOCH is not set.
config_opts['macros']['use_source_date_epoch_as_buildtime'] = '1'

# If true, make sure that timestamps in built rpms
# are not later than the value of SOURCE_DATE_EPOCH.
# Is ignored when SOURCE_DATE_EPOCH is not set.
config_opts['macros']['clamp_mtime_to_source_date_epoch'] = '1'

# Freeze BUILDHOST in rpm metadata
config_opts['macros']['_buildhost'] = 'eext-buildhost'

# Reproducible builds - END

# Autogenerated common configuration
{{- range $key,$val := .DefaultCommonCfg}}
config_opts['{{$key}}'] = "{{$val}}"
Expand Down
14 changes: 14 additions & 0 deletions impl/create_srpm.go
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,13 @@ func (bldr *srpmBuilder) setupRpmbuildTree() error {
return nil
}

var reproducibleBuildMacros = map[string]string{
"source_date_epoch_from_changelog": "1",
"use_source_date_epoch_as_buildtime": "1",
"clamp_mtime_to_source_date_epoch": "1",
"_buildhost": "eext-buildhost",
}

func (bldr *srpmBuilder) build(prep bool) error {
bldr.log("starting")

Expand Down Expand Up @@ -461,6 +468,13 @@ func (bldr *srpmBuilder) build(prep bool) error {
"--define", fmt.Sprintf("eext_release %s", rpmReleaseMacro),
}...)
}

for macro, macroVal := range reproducibleBuildMacros {
rpmbuildArgs = append(rpmbuildArgs, []string{
"--define", fmt.Sprintf("%s %s", macro, macroVal),
}...)
}

rpmbuildArgs = append(rpmbuildArgs, specFile)

if err := util.RunSystemCmd("rpmbuild", rpmbuildArgs...); err != nil {
Expand Down
26 changes: 24 additions & 2 deletions impl/testData/expected-mock.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,33 @@ config_opts['use_bootstrap_image'] = False
config_opts['cleanup_on_failure'] = False
config_opts['cleanup_on_success'] = False

# Make sure static libraries are deterministic
config_opts['macros']['__brp_strip_static_archive'] = '/usr/lib/rpm/brp-strip-static-archive "%{__strip} -D"'
# We add in FILE_OFFSET_BITS for 32 bit to be able to handle larger inodes
config_opts['macros']['_preprocessor_defines'] = '-Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -Wp,-D_FILE_OFFSET_BITS=64'

# Reproducible builds - BEGIN

# Make sure static libraries are deterministic
config_opts['macros']['__brp_strip_static_archive'] = '/usr/lib/rpm/brp-strip-static-archive "%{__strip} -D"'

# If true, set the SOURCE_DATE_EPOCH environment variable
# to the timestamp of the topmost changelog entry
config_opts['macros']['source_date_epoch_from_changelog'] = '1'

# If true, make sure that buildtime in built rpms
# is set to the value of SOURCE_DATE_EPOCH.
# Is ignored when SOURCE_DATE_EPOCH is not set.
config_opts['macros']['use_source_date_epoch_as_buildtime'] = '1'

# If true, make sure that timestamps in built rpms
# are not later than the value of SOURCE_DATE_EPOCH.
# Is ignored when SOURCE_DATE_EPOCH is not set.
config_opts['macros']['clamp_mtime_to_source_date_epoch'] = '1'

# Freeze BUILDHOST in rpm metadata
config_opts['macros']['_buildhost'] = 'eext-buildhost'

# Reproducible builds - END

# Autogenerated common configuration
config_opts['resultdir'] = "{{.TestWorkingDir}}/work/pkg1/mock-x86_64/mock-results"
config_opts['root'] = "pkg1-x86_64"
Expand Down
10 changes: 10 additions & 0 deletions testutil/testutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,16 @@ import (
"github.com/stretchr/testify/require"
)

const ExpectedBuildHost string = "eext-buildhost"

// $ date -d @1710460800
// Fri Mar 15 00:00:00 UTC 2024
const MrtParseChangeLogTs string = "1710460800"

// $ date -d @1628467200
// Mon Aug 9 00:00:00 UTC 2021
const DebugeditChangeLogTs string = "1628467200"

var r, w, rescueStdout *(os.File)

// SetupManifest used to setup a test manifest from testdata for manifest functionality testing
Expand Down
Loading