diff options
| author | Christian Breunig <christian@breunig.cc> | 2026-07-16 21:01:50 +0200 |
|---|---|---|
| committer | Christian Breunig <christian@breunig.cc> | 2026-07-16 22:52:17 +0200 |
| commit | 3db21e81c99ae1e8bf8f24450046c18f53d78d74 (patch) | |
| tree | 75be7eff51be43ac1fa6b72ddf9ac9be0bd8b6a4 /scripts | |
| parent | 5e2e9a3375a0ec3845822702fb255ac03e2b661f (diff) | |
| download | vyos-build-3db21e81c99ae1e8bf8f24450046c18f53d78d74.tar.gz vyos-build-3db21e81c99ae1e8bf8f24450046c18f53d78d74.zip | |
sbom: T9098: syft should run un squashfs instead of unpacked chroot
lb (live-build) binary runs binary_rootfs first, then binary_grub-efi.
binary_grub-efi temporarily installs EFI tooling and then runs:
"apt remove --auto-remove --purge --allow-remove-essential"
That cleanup is safe for the already-generated squashfs, but it mutates
build/chroot and can remove vyos-1x, breaking subsequent work that expects
chroot to remain intact for SBOM generation.
But why unpacking the squashfs?
In an ideal world we could call syft on the compressed squashfs file which is
supported. In our world, we do use a BCJ pre-filter chained with LZMA2 for
compressing the squashfs, which will increase the compression ratio without a
decompression penalty.
Difference: ~14.3 MB, ~2.7% smaller
This is unsupported by fyft which means we do need to unpack the squashfs first
before checking the files and generating the SBOM file.
Diffstat (limited to 'scripts')
| -rwxr-xr-x | scripts/image-build/build-vyos-image | 51 |
1 files changed, 32 insertions, 19 deletions
diff --git a/scripts/image-build/build-vyos-image b/scripts/image-build/build-vyos-image index b181a6e4..a1458d99 100755 --- a/scripts/image-build/build-vyos-image +++ b/scripts/image-build/build-vyos-image @@ -31,6 +31,7 @@ import datetime import functools import string import subprocess +import tempfile class ImageBuildError(Exception): pass @@ -156,6 +157,7 @@ def build(): 'qemu-utils', 'gdisk', 'kpartx', + 'squashfs-tools', 'dosfstools' ], 'binaries': [] @@ -727,26 +729,37 @@ Pin-Priority: 600 manifest['artifacts'].append(iso_file) # Now create SBOM - syft_target_dir = 'chroot' - syft_base_path = os.getcwd() + f'/{syft_target_dir}' base_filename = iso_file.rstrip('.iso') - syft_cmd = [['syft', syft_target_dir, - '--source-name', 'VyOS', '--source-version', version, - '-o', f'cyclonedx-json={base_filename}.cdx.json', - '-o', f'spdx-json={base_filename}.spdx.json']] - - # syft bug for CycloneDX https://github.com/anchore/syft/issues/4592#issuecomment-4567247328 - syft_cmd.append(['sed', '-i', '-e', f's@{syft_base_path}@@g', f'{base_filename}.cdx.json']) - syft_cmd.append(['sed', '-i', '-e', f's@{syft_base_path}@//@g', f'{base_filename}.spdx.json']) - - for c in syft_cmd: - with subprocess.Popen(c, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, - text=True, bufsize=1) as p: - for line in p.stdout: - sys.stdout.write(line) - sys.stdout.flush() - p.wait() - print("I: Finished SBOM generation") + syft_target_dir = tempfile.mkdtemp(prefix='unsquashfs_rootfs-', dir=os.getcwd()) + syft_base_path = syft_target_dir + try: + # lb config builds the amd64 squashfs as xz with -Xbcj x86 (a BCJ pre-filter + # chained with LZMA2. Real unsquashfs/mksquashfs fully support multi-filter + # xz streams; syft's own Go-based squashfs/xz decoder apparently only handles + # plain single-filter. Extract squashfs first + print("I: Unpack squashfs for SBOM generation") + syft_cmd = [['unsquashfs', '-quiet', '-no-progress', '-force', '-dest', syft_target_dir, 'binary/live/filesystem.squashfs']] + # run syft on extracted content + syft_cmd.append(['syft', syft_target_dir, + '--source-name', 'VyOS', '--source-version', version, + '-o', f'cyclonedx-json={base_filename}.cdx.json', + '-o', f'spdx-json={base_filename}.spdx.json']) + + # syft bug for CycloneDX https://github.com/anchore/syft/issues/4592#issuecomment-4567247328 + syft_cmd.append(['sed', '-i', '-e', f's@{syft_base_path}@@g', f'{base_filename}.cdx.json']) + syft_cmd.append(['sed', '-i', '-e', f's@{syft_base_path}@//@g', f'{base_filename}.spdx.json']) + + for c in syft_cmd: + with subprocess.Popen(c, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, + text=True, bufsize=1) as p: + for line in p.stdout: + sys.stdout.write(line) + sys.stdout.flush() + p.wait() + print("I: Finished SBOM generation") + finally: + # remove temporary unpacked squashfs, even on failure/interruption + shutil.rmtree(syft_target_dir, ignore_errors=True) # If the flavor has `image_format = "iso"`, then the work is done. |
