[2/2] repro-build-test.py: Test to check images are reproducible

Message ID 20221219144147.31245-3-venkata.pyla@toshiba-tsip.com
State Accepted, archived
Headers show
Series Test for verifiying reproducible images | expand

Commit Message

venkata.pyla@toshiba-tsip.com Dec. 19, 2022, 2:41 p.m. UTC
From: venkata pyla <venkata.pyla@toshiba-tsip.com>

This test verifies whether the images are reproducible by checking with
in-depth comparision tool `diffoscope` and produces a comparision output
in plain text format for checking the differences.

Signed-off-by: venkata pyla <venkata.pyla@toshiba-tsip.com>
---
 testsuite/repro-build-test.py | 68 +++++++++++++++++++++++++++++++++++
 1 file changed, 68 insertions(+)
 create mode 100755 testsuite/repro-build-test.py

Comments

Henning Schild Jan. 7, 2023, 12:01 a.m. UTC | #1
This was merged into "master", if we did have linter checks like
"flake8" on python code this one would certainly fail them.

A simple
black testsuite/repro-build-test.py

already makes it much happier.

And the several "imported but unused" could also be checked.

venkata pyla please have a look at this if you want

run
black testsuite/repro-build-test.py

and see if you like the result

run
flake8 testsuite/repro-build-test.py

and see if you can fix things it reports

possibly do that in "black" and "flake8" loops until both agree

And maybe do the same thing for other .py files if you like.

The whole repro story is about being pedantic so let us use tools that
help us with being very pedantic.

Henning


Am Mon, 19 Dec 2022 20:11:47 +0530
schrieb venkata.pyla@toshiba-tsip.com:

> From: venkata pyla <venkata.pyla@toshiba-tsip.com>
> 
> This test verifies whether the images are reproducible by checking
> with in-depth comparision tool `diffoscope` and produces a
> comparision output in plain text format for checking the differences.
> 
> Signed-off-by: venkata pyla <venkata.pyla@toshiba-tsip.com>
> ---
>  testsuite/repro-build-test.py | 68
> +++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+)
>  create mode 100755 testsuite/repro-build-test.py
> 
> diff --git a/testsuite/repro-build-test.py
> b/testsuite/repro-build-test.py new file mode 100755
> index 0000000..e89becf
> --- /dev/null
> +++ b/testsuite/repro-build-test.py
> @@ -0,0 +1,68 @@
> +#!/usr/bin/env python3
> +
> +import glob
> +import os
> +import re
> +import tempfile
> +import time
> +
> +from cibuilder import CIBuilder, isar_root
> +from avocado.utils import process
> +
> +class ReproBuild(CIBuilder):
> +
> +    """
> +    Test reproducible builds by comparing the artifacts
> +
> +    :avocado: tags=repro-build
> +    """
> +    def test_repro_build(self):
> +        target = self.params.get('build_target',
> default='mc:qemuamd64-bullseye:isar-image-base')
> +        source_date_epoch = self.params.get('source_date_epoch',
> default=self.git_last_commit_timestamp())
> +        self.init()
> +        self.build_repro_image(target, source_date_epoch,
> 'image1.tar.gz')
> +        self.build_repro_image(target, source_date_epoch,
> 'image2.tar.gz')
> +        self.compare_repro_image('image1.tar.gz', 'image2.tar.gz')
> +
> +    def git_last_commit_timestamp(self):
> +        return process.run('git log -1 --pretty=%ct').stdout
> +
> +    def get_image_path(self, target_name):
> +        image_dir = "tmp/deploy/images"
> +        target_params = target_name.split(':')
> +        machine = target_params[1].split('-')[0]
> +        distro = 'debian-' + target_params[1].split('-')[1]
> +        image_type = target_params[2]
> +        return
> f'{image_dir}/{machine}/{image_type}-{distro}-{machine}.tar.gz' +
> +    def build_repro_image(self, target, source_date_epoch=None
> ,image_name='image.tar.gz'): +
> +        if not source_date_epoch:
> +            self.error("Reproducible build should configure with
> source_date_epoch time") +
> +        # clean artifacts before build
> +        self.clean()
> +
> +        # Build
> +        self.log.info("Started Build " + image_name)
> +        self.configure(source_date_epoch=source_date_epoch)
> +        self.bitbake(target)
> +
> +        # copy the artifacts image name with given name
> +        image_path = self.get_image_path(target)
> +        self.log.info("Copy image " + image_path + " as " +
> image_name)
> +        self.move_in_build_dir(image_path, image_name)
> +
> +    def clean(self):
> +        self.delete_from_build_dir('tmp')
> +        self.delete_from_build_dir('sstate-cache')
> +
> +    def compare_repro_image(self, image1, image2):
> +        self.log.info("Compare artifacts image1: " + image1 + ",
> image2: " + image2)
> +        result = process.run('diffoscope '
> +                        '--text ' + self.build_dir +
> '/diffoscope-output.txt'
> +                        ' ' + self.build_dir + '/' + image1 +
> +                        ' ' + self.build_dir + '/' + image2 ,
> +                        ignore_status = True)
> +        if result.exit_status > 0:
> +            self.fail(f'Images {image1} and {image2} are not
> reproducible')

Patch

diff --git a/testsuite/repro-build-test.py b/testsuite/repro-build-test.py
new file mode 100755
index 0000000..e89becf
--- /dev/null
+++ b/testsuite/repro-build-test.py
@@ -0,0 +1,68 @@ 
+#!/usr/bin/env python3
+
+import glob
+import os
+import re
+import tempfile
+import time
+
+from cibuilder import CIBuilder, isar_root
+from avocado.utils import process
+
+class ReproBuild(CIBuilder):
+
+    """
+    Test reproducible builds by comparing the artifacts
+
+    :avocado: tags=repro-build
+    """
+    def test_repro_build(self):
+        target = self.params.get('build_target', default='mc:qemuamd64-bullseye:isar-image-base')
+        source_date_epoch = self.params.get('source_date_epoch', default=self.git_last_commit_timestamp())
+        self.init()
+        self.build_repro_image(target, source_date_epoch, 'image1.tar.gz')
+        self.build_repro_image(target, source_date_epoch, 'image2.tar.gz')
+        self.compare_repro_image('image1.tar.gz', 'image2.tar.gz')
+
+    def git_last_commit_timestamp(self):
+        return process.run('git log -1 --pretty=%ct').stdout
+
+    def get_image_path(self, target_name):
+        image_dir = "tmp/deploy/images"
+        target_params = target_name.split(':')
+        machine = target_params[1].split('-')[0]
+        distro = 'debian-' + target_params[1].split('-')[1]
+        image_type = target_params[2]
+        return f'{image_dir}/{machine}/{image_type}-{distro}-{machine}.tar.gz'
+
+    def build_repro_image(self, target, source_date_epoch=None ,image_name='image.tar.gz'):
+
+        if not source_date_epoch:
+            self.error("Reproducible build should configure with source_date_epoch time")
+
+        # clean artifacts before build
+        self.clean()
+
+        # Build
+        self.log.info("Started Build " + image_name)
+        self.configure(source_date_epoch=source_date_epoch)
+        self.bitbake(target)
+
+        # copy the artifacts image name with given name
+        image_path = self.get_image_path(target)
+        self.log.info("Copy image " + image_path + " as " + image_name)
+        self.move_in_build_dir(image_path, image_name)
+
+    def clean(self):
+        self.delete_from_build_dir('tmp')
+        self.delete_from_build_dir('sstate-cache')
+
+    def compare_repro_image(self, image1, image2):
+        self.log.info("Compare artifacts image1: " + image1 + ", image2: " + image2)
+        result = process.run('diffoscope '
+                        '--text ' + self.build_dir + '/diffoscope-output.txt'
+                        ' ' + self.build_dir + '/' + image1 +
+                        ' ' + self.build_dir + '/' + image2 ,
+                        ignore_status = True)
+        if result.exit_status > 0:
+            self.fail(f'Images {image1} and {image2} are not reproducible')