Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package melange for openSUSE:Factory checked in at 2025-06-23 15:05:11 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/melange (Old) and /work/SRC/openSUSE:Factory/.melange.new.7067 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "melange" Mon Jun 23 15:05:11 2025 rev:99 rq:1287786 version:0.26.13 Changes: -------- --- /work/SRC/openSUSE:Factory/melange/melange.changes 2025-06-16 11:13:04.036752830 +0200 +++ /work/SRC/openSUSE:Factory/.melange.new.7067/melange.changes 2025-06-23 15:06:23.384529521 +0200 @@ -1,0 +2,19 @@ +Mon Jun 23 04:46:13 UTC 2025 - Johannes Kastl <opensuse_buildserv...@ojkastl.de> + +- Update to version 0.26.13: + * SCA: Implement feature flag for versioned shlib depends + * SCA: Improve determineShlibVersion to handle corner cases + * SCA: Implement "no-versioned-shlib-deps" package option + * sca_test: Adjust expected output of Provides/Depends + * sca_test.go: Implement InstalledPackages and PkgResolver methods + * SCA: Implement versioned shared library "depends:" + * SCA: Implement determineShlibVersion + * SCA: Implement InstalledPackages and PkgResolver methods + * build.go: Add PkgResolver field to Build struct + * Implement versioned "provides" for shared libraries + * fix: avoid fetching hardlinks in licenses (#2052) + * Fix integration tests and then enable them. (#2042) + * test(e2e/pipelines): run tests on qemu runner (#1999) + * fix: make checkout expected-commit bump less greedy (#2008) + +------------------------------------------------------------------- Old: ---- melange-0.26.12.obscpio New: ---- melange-0.26.13.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ melange.spec ++++++ --- /var/tmp/diff_new_pack.Lubjyo/_old 2025-06-23 15:06:24.624581255 +0200 +++ /var/tmp/diff_new_pack.Lubjyo/_new 2025-06-23 15:06:24.628581422 +0200 @@ -17,7 +17,7 @@ Name: melange -Version: 0.26.12 +Version: 0.26.13 Release: 0 Summary: Build APKs from source code License: Apache-2.0 ++++++ _service ++++++ --- /var/tmp/diff_new_pack.Lubjyo/_old 2025-06-23 15:06:24.660582757 +0200 +++ /var/tmp/diff_new_pack.Lubjyo/_new 2025-06-23 15:06:24.664582924 +0200 @@ -3,7 +3,7 @@ <param name="url">https://github.com/chainguard-dev/melange</param> <param name="scm">git</param> <param name="exclude">.git</param> - <param name="revision">v0.26.12</param> + <param name="revision">v0.26.13</param> <param name="versionformat">@PARENT_TAG@</param> <param name="versionrewrite-pattern">v(.*)</param> <param name="changesgenerate">enable</param> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.Lubjyo/_old 2025-06-23 15:06:24.684583758 +0200 +++ /var/tmp/diff_new_pack.Lubjyo/_new 2025-06-23 15:06:24.688583925 +0200 @@ -1,6 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/chainguard-dev/melange</param> - <param name="changesrevision">65e385aff51b530faf6c3c001be62e5dc8b91aef</param></service></servicedata> + <param name="changesrevision">4946b0592c319b5915a0570182aa968568962885</param></service></servicedata> (No newline at EOF) ++++++ melange-0.26.12.obscpio -> melange-0.26.13.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/melange-0.26.12/.github/PULL_REQUEST_TEMPLATE.md new/melange-0.26.13/.github/PULL_REQUEST_TEMPLATE.md --- old/melange-0.26.12/.github/PULL_REQUEST_TEMPLATE.md 1970-01-01 01:00:00.000000000 +0100 +++ new/melange-0.26.13/.github/PULL_REQUEST_TEMPLATE.md 2025-06-20 20:50:44.000000000 +0200 @@ -0,0 +1,30 @@ +## Melange Pull Request Template + +<!-- +*** PULL REQUEST CHECKLIST: PLEASE START HERE *** + +The single most important feature of melange is that we can build Wolfi. + +Many changes to melange introduce a risk of breaking the build, and sometimes +these are not flushed out until a package is changed (much) later. This +pertains to basic execution, SCA changes, linter changes, and more. +--> + +### Functional Changes + +- [ ] This change can build all of Wolfi without errors (describe results in notes) + +Notes: + +### SCA Changes + +- [ ] Examining several representative APKs show no regression / the desired effect (details in notes) + +Notes: + +### Linter + +- [ ] The new check is clean across Wolfi +- [ ] The new check is opt-in or a warning + +Notes: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/melange-0.26.12/.github/actions/setup-bubblewrap/action.yaml new/melange-0.26.13/.github/actions/setup-bubblewrap/action.yaml --- old/melange-0.26.12/.github/actions/setup-bubblewrap/action.yaml 1970-01-01 01:00:00.000000000 +0100 +++ new/melange-0.26.13/.github/actions/setup-bubblewrap/action.yaml 2025-06-20 20:50:44.000000000 +0200 @@ -0,0 +1,38 @@ +# Copyright 2025 Chainguard, Inc. +# SPDX-License-Identifier: Apache-2.0 + +name: 'Setup Bubblewrap' +description: 'Make bubblewrap work on ubuntu-latest' +# See https://github.com/chainguard-dev/melange/issues/1508 + +inputs: + path: + description: 'Path to the program that needs to run bubblewrap' + required: true + default: '/usr/bin/melange' + +runs: + using: "composite" + steps: + - name: Disable apparmor userns restrictions + shell: bash + run: | + sudo bash -c "mkdir -p /etc/sysctl.d + echo 'kernel.apparmor_restrict_unprivileged_userns = 0' >> /etc/sysctl.d/60-apparmor-namespace.conf" + + - name: Allow bubblewrap to use unprivileged user namespaces independent of who calls it + shell: bash + run: | + sudo bash -c "cat << EOF > /etc/apparmor.d/local-bwrap + abi <abi/4.0>, + include <tunables/global> + + profile local-bwrap /usr/bin/bwrap flags=(unconfined) { + userns, + + # Site-specific additions and overrides. See local/README for details. + include if exists <local/bwrap> + } + EOF + + systemctl reload apparmor" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/melange-0.26.12/.github/dependabot.yml new/melange-0.26.13/.github/dependabot.yml --- old/melange-0.26.12/.github/dependabot.yml 1970-01-01 01:00:00.000000000 +0100 +++ new/melange-0.26.13/.github/dependabot.yml 2025-06-20 20:50:44.000000000 +0200 @@ -0,0 +1,22 @@ +version: 2 +updates: + - package-ecosystem: gomod + directory: "/" + schedule: + interval: weekly + open-pull-requests-limit: 10 + groups: + gomod: + update-types: + - "patch" + + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: weekly + open-pull-requests-limit: 10 + groups: + actions: + update-types: + - "minor" + - "patch" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/melange-0.26.12/.github/workflows/build.yaml new/melange-0.26.13/.github/workflows/build.yaml --- old/melange-0.26.12/.github/workflows/build.yaml 1970-01-01 01:00:00.000000000 +0100 +++ new/melange-0.26.13/.github/workflows/build.yaml 2025-06-20 20:50:44.000000000 +0200 @@ -0,0 +1,44 @@ +name: ci + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +permissions: {} + +jobs: + build: + name: build + runs-on: ubuntu-latest + + permissions: + contents: read + + steps: + - uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 + with: + egress-policy: audit + + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 + with: + go-version-file: './go.mod' + check-latest: true + + - name: build + run: | + make melange + ./melange version + + - uses: goreleaser/goreleaser-action@9c156ee8a17a598857849441385a2041ef570552 # v6.3.0 + with: + version: latest + install-only: true + + - name: snapshot + run: | + make snapshot + ./dist/melange-build_linux_amd64_v1/melange version diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/melange-0.26.12/.github/workflows/e2e.yaml new/melange-0.26.13/.github/workflows/e2e.yaml --- old/melange-0.26.12/.github/workflows/e2e.yaml 1970-01-01 01:00:00.000000000 +0100 +++ new/melange-0.26.13/.github/workflows/e2e.yaml 2025-06-20 20:50:44.000000000 +0200 @@ -0,0 +1,79 @@ +name: e2e tests + +on: + push: + branches: ["main"] + pull_request: + branches: ["main"] + +env: + SOURCE_DATE_EPOCH: 1669683910 + +permissions: {} + +jobs: + rebuild: + name: rebuild + runs-on: ubuntu-latest + permissions: + contents: read + + strategy: + fail-fast: false + matrix: + cfg: + # build and rebuild examples + - cargo-build.yaml + - gnu-hello.yaml + - go-build.yaml + - minimal.yaml + - npm-install.yaml + - pnpm-install.yaml + + - melange.yaml # special; builds melange itself + + container: + image: alpine:latest + options: | + --cap-add NET_ADMIN --cap-add SYS_ADMIN --security-opt seccomp=unconfined --security-opt apparmor:unconfined + + steps: + - uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 + with: + egress-policy: audit + + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 + with: + go-version-file: "go.mod" + + - name: Fetch dependencies + run: | + apk upgrade -Ua + apk add go build-base git bubblewrap jq + + - name: Build melange + run: | + make melange + ./melange keygen + + - name: Build package + run: | + path=examples/${{matrix.cfg}} + if [ "${{matrix.cfg}}" == "melange.yaml" ]; then + path="melange.yaml" + fi + ./melange build $path --arch=x86_64 --namespace=wolfi + + - name: Rebuild package + run: | + ./melange rebuild ./packages/x86_64/*.apk + + - name: Upload APKs + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + if: always() + with: + path: | + packages/** + rebuilt-packages/** + name: rebuild-${{matrix.cfg}} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/melange-0.26.12/.github/workflows/go-tests.yaml new/melange-0.26.13/.github/workflows/go-tests.yaml --- old/melange-0.26.12/.github/workflows/go-tests.yaml 1970-01-01 01:00:00.000000000 +0100 +++ new/melange-0.26.13/.github/workflows/go-tests.yaml 2025-06-20 20:50:44.000000000 +0200 @@ -0,0 +1,30 @@ +name: Go Tests + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +permissions: {} + +jobs: + test: + runs-on: ubuntu-latest + + permissions: + contents: read + + steps: + - uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 + with: + egress-policy: audit + + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 + with: + go-version-file: './go.mod' + + - name: Integration and Unit Tests + run: make integration diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/melange-0.26.12/.github/workflows/melange-test-pipelines.yaml new/melange-0.26.13/.github/workflows/melange-test-pipelines.yaml --- old/melange-0.26.12/.github/workflows/melange-test-pipelines.yaml 1970-01-01 01:00:00.000000000 +0100 +++ new/melange-0.26.13/.github/workflows/melange-test-pipelines.yaml 2025-06-20 20:50:44.000000000 +0200 @@ -0,0 +1,102 @@ +name: Test melange test command + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +permissions: {} + +jobs: + build-melange: + name: Build melange and add to artifact cache + runs-on: ubuntu-latest + + permissions: + contents: read + + steps: + - uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 + with: + egress-policy: audit + + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 + with: + go-version-file: './go.mod' + check-latest: true + + - name: build + run: | + make melange + + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: melange-${{ github.run_id }} + path: ${{ github.workspace }}/melange + retention-days: 1 + + test-packages: + name: Test packages + needs: + - build-melange + runs-on: ubuntu-latest-8-core + + permissions: + contents: read + + steps: + - uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 + with: + egress-policy: audit + + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + # Grab the melange we uploaded above, and install it. + - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 + with: + name: melange-${{ github.run_id }} + path: ${{ github.workspace }}/.melange-dir + run-id: ${{ github.run_id }} + + - run: | + sudo mv ${{ github.workspace }}/.melange-dir/melange /usr/bin/melange + sudo chmod a+x /usr/bin/melange + melange version + + - run: | + sudo apt-get -y install bubblewrap + - uses: ./.github/actions/setup-bubblewrap + + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 + with: + go-version-file: './go.mod' + check-latest: true + + - name: Download kernel for VMs + run: | + KERNEL_PKG="$(curl -sL https://dl-cdn.alpinelinux.org/alpine/edge/main/x86_64/APKINDEX.tar.gz | tar -Oxz APKINDEX | awk -F':' '$1 == "P" {printf "%s-", $2} $1 == "V" {printf "%s.apk\n", $2}' | grep "linux-virt" | grep -v dev)" + curl -LSo linux-virt.apk "https://dl-cdn.alpinelinux.org/alpine/edge/main/x86_64/$KERNEL_PKG" + mkdir -p /tmp/kernel + tar -xf ./linux-virt.apk -C /tmp/kernel/ + + - name: Install QEMU/KVM + run: | + sudo apt-get update + sudo apt-get -y install qemu-system-x86-64 qemu-kvm + + - name: Enable KVM group perms + run: | + echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules + sudo udevadm control --reload-rules + sudo udevadm trigger --name-match=kvm + + - name: Run e2e-tests + run: | + make \ + QEMU_KERNEL_IMAGE=/tmp/kernel/boot/vmlinuz-virt \ + QEMU_KERNEL_MODULES=/tmp/kernel/lib/modules/ \ + test-e2e diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/melange-0.26.12/.github/workflows/release.yaml new/melange-0.26.13/.github/workflows/release.yaml --- old/melange-0.26.12/.github/workflows/release.yaml 1970-01-01 01:00:00.000000000 +0100 +++ new/melange-0.26.13/.github/workflows/release.yaml 2025-06-20 20:50:44.000000000 +0200 @@ -0,0 +1,82 @@ +name: Release + +on: + schedule: + - cron: '0 0 * * 1' # every Monday at 00:00 UTC + workflow_dispatch: + +permissions: {} + +jobs: + release: + name: Release + runs-on: ubuntu-latest + + # https://docs.github.com/en/actions/reference/authentication-in-a-workflow + permissions: + id-token: write + contents: write + + steps: + - uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 + with: + egress-policy: audit + + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Check if any changes since last release + id: check + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + git fetch --tags + TAG=$(git tag --points-at HEAD) + if [ -z "$TAG" ]; then + echo "No tag points at HEAD, so we need a new tag and then a new release." + echo "need_release=yes" >> $GITHUB_OUTPUT + else + RELEASE=$(gh release view "$TAG" --json tagName --jq '.tagName' || echo "none") + if [ "$RELEASE" == "$TAG" ]; then + echo "A release exists for tag $TAG, which has the latest changes, so no need for a new tag or release." + echo "need_release=no" >> $GITHUB_OUTPUT + else + echo "Tag $TAG exists, but no release is associated. Need a new release." + echo "need_release=yes" >> $GITHUB_OUTPUT + echo "existing_tag=$TAG" >> $GITHUB_OUTPUT + fi + fi + + - name: Bump version and push tag + id: create_tag + uses: mathieudutour/github-tag-action@a22cf08638b34d5badda920f9daf6e72c477b07b # v6.2 + if: steps.check.outputs.need_release == 'yes' && steps.check.outputs.existing_tag == '' + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + if: steps.check.outputs.need_release == 'yes' + with: + ref: ${{ steps.check.outputs.existing_tag || steps.create_tag.outputs.new_tag }} + + - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 + if: steps.check.outputs.need_release == 'yes' + with: + go-version-file: './go.mod' + check-latest: true + + # Cosign is used by goreleaser to sign release artifacts. + - uses: sigstore/cosign-installer@3454372f43399081ed03b604cb2d021dabca52bb # v3.8.2 + if: steps.check.outputs.need_release == 'yes' + + - uses: goreleaser/goreleaser-action@9c156ee8a17a598857849441385a2041ef570552 # v6.3.0 + if: steps.check.outputs.need_release == 'yes' + with: + version: latest + install-only: true + + - name: Release + if: steps.check.outputs.need_release == 'yes' + run: make release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + TAG: ${{ steps.check.outputs.existing_tag || steps.create_tag.outputs.new_tag }} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/melange-0.26.12/.github/workflows/verify.yaml new/melange-0.26.13/.github/workflows/verify.yaml --- old/melange-0.26.12/.github/workflows/verify.yaml 1970-01-01 01:00:00.000000000 +0100 +++ new/melange-0.26.13/.github/workflows/verify.yaml 2025-06-20 20:50:44.000000000 +0200 @@ -0,0 +1,44 @@ +name: verify + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +permissions: {} + +jobs: + golangci: + name: lint + runs-on: ubuntu-latest + + permissions: + contents: read + + steps: + - uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 + with: + egress-policy: audit + + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 + with: + go-version-file: go.mod + check-latest: true + + - name: golangci-lint + uses: golangci/golangci-lint-action@2226d7cb06a077cd73e56eedd38eecad18e5d837 # v6.5.0 + with: + version: v1.64.8 + args: --timeout=5m + + - run: | + make docs-repo + make docs-pipeline + git diff --exit-code + + - run: | + go mod tidy + git diff --exit-code diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/melange-0.26.12/.github/workflows/wolfi-presubmit.yaml new/melange-0.26.13/.github/workflows/wolfi-presubmit.yaml --- old/melange-0.26.12/.github/workflows/wolfi-presubmit.yaml 1970-01-01 01:00:00.000000000 +0100 +++ new/melange-0.26.13/.github/workflows/wolfi-presubmit.yaml 2025-06-20 20:50:44.000000000 +0200 @@ -0,0 +1,215 @@ +name: ci + +on: + push: + branches: ["main"] + pull_request: + branches: ["main"] + +permissions: {} + +jobs: + build-melange: + name: Build melange and add to artifact cache + runs-on: ubuntu-latest + + permissions: + contents: read + + steps: + - uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 + with: + egress-policy: audit + + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 + with: + go-version-file: "./go.mod" + check-latest: true + + - name: build + run: | + make melange + + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: melange-${{ github.run_id }} + path: ${{ github.workspace }}/melange + retention-days: 1 + + build-packages: + name: Build packages + needs: + - build-melange + runs-on: ubuntu-latest-8-core + + permissions: + contents: read + + # This is a list of packages which covers basic and exotic uses of + # the built-in pipelines. Goal is to balance efficiency while also + # exercising Melange with real-world package builds. + # Feel free to add additional packages to this matrix which exercise + # Melange in new ways (e.g. new pipelines, etc.) + strategy: + fail-fast: false + matrix: + runner: + - bubblewrap + - qemu + package: + - hello-wolfi + - glibc + - tini + - lzo + - bubblewrap + - dpkg + #- gdk-pixbuf # Looks like this is broken again, see: https://gitlab.gnome.org/GNOME/gobject-introspection/-/issues/515 + - gitsign + - grafana-image-renderer + - guac + - mdbook + - s3cmd + - py3-pyelftools # Uses license-path + - cadvisor # uses cgroups + - fping # uses get/setcaps + - logstash-8 # uses a diff test user + - perl-yaml-syck + - postfix + - ncurses + - subversion + - sudo + - py3-supported-python + - rust-1.86 + # TODO: https://github.com/wolfi-dev/os/issues/26442 + #- xmlto + + steps: + - uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 + with: + egress-policy: audit + + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + repository: wolfi-dev/os + + - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 + with: + name: melange-${{ github.run_id }} + path: ${{ github.workspace }}/.melange-dir + run-id: ${{ github.run_id }} + + - run: | + sudo mv ${{ github.workspace }}/.melange-dir/melange /usr/bin/melange + sudo chmod a+x /usr/bin/melange + melange version + + # this need to point to main to always get the latest action + - uses: wolfi-dev/actions/install-wolfictl@main # main + + - run: | + wolfictl bump ${{ matrix.package }} + + - if: matrix.runner == 'bubblewrap' + run: | + sudo apt-get -y install bubblewrap + - if: matrix.runner == 'bubblewrap' + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + path: melange-src + - if: matrix.runner == 'bubblewrap' + uses: ./melange-src/.github/actions/setup-bubblewrap + - if: matrix.runner == 'bubblewrap' + run: | + make SHELL="/bin/bash" MELANGE="sudo melange" MELANGE_RUNNER="bubblewrap" package/${{ matrix.package }} + + - name: Download kernel for VMs + if: matrix.runner == 'qemu' + run: | + KERNEL_PKG="$(curl -sL https://dl-cdn.alpinelinux.org/alpine/edge/main/x86_64/APKINDEX.tar.gz | tar -Oxz APKINDEX | awk -F':' '$1 == "P" {printf "%s-", $2} $1 == "V" {printf "%s.apk\n", $2}' | grep "linux-virt" | grep -v dev)" + curl -LSo linux-virt.apk "https://dl-cdn.alpinelinux.org/alpine/edge/main/x86_64/$KERNEL_PKG" + mkdir -p /tmp/kernel + tar -xf ./linux-virt.apk -C /tmp/kernel/ + + - name: Install QEMU/KVM + if: matrix.runner == 'qemu' + run: | + sudo apt-get update + sudo apt-get -y install qemu-system-x86-64 qemu-kvm + + - name: Enable KVM group perms + if: matrix.runner == 'qemu' + run: | + echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules + sudo udevadm control --reload-rules + sudo udevadm trigger --name-match=kvm + + - name: Make package ${{matrix.package}} with QEMU Runner + if: matrix.runner == 'qemu' + run: | + make \ + SHELL="/bin/bash" \ + QEMU_KERNEL_IMAGE=/tmp/kernel/boot/vmlinuz-virt \ + QEMU_KERNEL_MODULES=/tmp/kernel/lib/modules/ \ + MELANGE="/usr/bin/melange" \ + MELANGE_EXTRA_OPTS="--runner qemu" \ + package/${{ matrix.package }} + + - name: Run tests to verify xattrs with bubblewrap runner + if: matrix.runner == 'bubblewrap' && matrix.package == 'fping' + run: | + make SHELL="/bin/bash" MELANGE="sudo melange" MELANGE_RUNNER="bubblewrap" test/${{ matrix.package }} + + - name: Run tests with QEMU runner + if: matrix.runner == 'qemu' + run: | + make \ + SHELL="/bin/bash" \ + QEMU_KERNEL_IMAGE=/tmp/kernel/boot/vmlinuz-virt \ + QEMU_KERNEL_MODULES=/tmp/kernel/lib/modules/ \ + MELANGE="/usr/bin/melange" \ + MELANGE_EXTRA_OPTS="--runner qemu" \ + test/${{ matrix.package }} + + - name: Check package ${{ matrix.package }} xattrs for QEMU-built package + if: matrix.runner == 'qemu' && matrix.package == 'fping' + run: | + for pkg in packages/x86_64/*.apk; do + sudo tar --xattrs --xattrs-include='*.*' -xf "${pkg}" -C packages/x86_64/ + done + getcap packages/x86_64/usr/sbin/fping + + - name: Check package ${{ matrix.package }} for mode bits + if: matrix.package == 'sudo' + run: | + for pkg in packages/x86_64/*.apk; do + sudo tar --xattrs --xattrs-include='*.*' -xf "${pkg}" -C packages/x86_64/ + done + ls -hal packages/x86_64/usr/bin/sudo + + - name: "Retrieve Wolfi advisory data" + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + repository: "wolfi-dev/advisories" + path: "data/wolfi-advisories" + + - name: Test installable and Scan for CVEs + run: | + if [[ "${{ matrix.package }}" == "fping" ]]; then + docker run --rm -v $(pwd):/work --workdir /work cgr.dev/chainguard/wolfi-base /bin/sh -c "sed 's|=.*||' -i /etc/apk/world; apk add --allow-untrusted -X ./packages/ packages/x86_64/${{ matrix.package }}-*.apk; apk add libcap-utils; getcap /usr/sbin/fping" + elif [[ "${{ matrix.package }}" == "sudo" ]]; then + docker run --rm -v $(pwd):/work --workdir /work cgr.dev/chainguard/wolfi-base /bin/sh -c "sed 's|=.*||' -i /etc/apk/world; apk add --allow-untrusted -X ./packages/ packages/x86_64/${{ matrix.package }}-*.apk; ls -hal /usr/bin/sudo" + elif [[ "${{ matrix.package }}" == "postfix" ]]; then + docker run --rm -v $(pwd):/work --workdir /work cgr.dev/chainguard/wolfi-base /bin/sh -c "sed 's|=.*||' -i /etc/apk/world; apk add --allow-untrusted -X ./packages/ packages/x86_64/${{ matrix.package }}-*.apk; ls -hal /var/spool/postfix; ls -hal /var/lib/postfix" + else + docker run --rm -v $(pwd):/work --workdir /work cgr.dev/chainguard/wolfi-base /bin/sh -c "sed 's|=.*||' -i /etc/apk/world; apk add --allow-untrusted -X ./packages/ packages/x86_64/${{ matrix.package }}-*.apk" + fi + # There is a huge fixed cost for every wolfictl scan invocation for grype DB init. + # Do this outside of the loop in one invocation with every package. + wolfictl scan \ + --advisories-repo-dir 'data/wolfi-advisories' \ + --advisory-filter 'resolved' \ + --require-zero \ + packages/x86_64/${{ matrix.package }}-*.apk \ + 2> /dev/null # The error message renders strangely on GitHub Actions, and the important information is already being sent to stdout. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/melange-0.26.12/.gitignore new/melange-0.26.13/.gitignore --- old/melange-0.26.12/.gitignore 1970-01-01 01:00:00.000000000 +0100 +++ new/melange-0.26.13/.gitignore 2025-06-20 20:50:44.000000000 +0200 @@ -0,0 +1,38 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ +.vscode/* + +local-melange.rsa +local-melange.rsa.pub +melange +melange.rsa +melange.rsa.pub +packages/ +rebuilt-packages/ +.idea/ +bin/ +generated/ +melange.images +/.DS_Store +dist/ +tags +ctags + +.DS_Store + + +x86_64/** +aarch64/** diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/melange-0.26.12/docs/BUILD-FILE.md new/melange-0.26.13/docs/BUILD-FILE.md --- old/melange-0.26.12/docs/BUILD-FILE.md 2025-06-14 01:32:20.000000000 +0200 +++ new/melange-0.26.13/docs/BUILD-FILE.md 2025-06-20 20:50:44.000000000 +0200 @@ -208,6 +208,16 @@ no-commands: true ``` +`no-versioned-shlib-deps` - The generated `depends` for shared +libraries shipped by this package should not be versioned. By +default, melange will generate versioned `depends` for shared +libraries. + +``` +options: + no-versioned-shlib-deps: true +``` + ### scriptlets List of executable scripts that run at various stages of the package lifecycle, triggered by configurable events. These are useful to handle tasks that only diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/melange-0.26.12/docs/VAR-TRANSFORMS.md new/melange-0.26.13/docs/VAR-TRANSFORMS.md --- old/melange-0.26.12/docs/VAR-TRANSFORMS.md 2025-06-14 01:32:20.000000000 +0200 +++ new/melange-0.26.13/docs/VAR-TRANSFORMS.md 2025-06-20 20:50:44.000000000 +0200 @@ -46,6 +46,21 @@ uri: https://github.com/openjdk/jdk17u/archive/refs/tags/jdk-${{vars.mangled-package-version}}.tar.gz ``` +`mangled-package-version` can also be used with `git-checkout`: + +```yaml +pipeline: + - uses: git-checkout + with: + repository: https://github.com/openjdk/jdk12u + tag: ${{vars.mangled-package-version}} + expected-commit: 5018cdd1904357c04c9c41e0f8fe8994916cb638 +``` + + +Note: If `melange bump` is run, it will attempt to update the `expected-commit` value. + + Other example: In some case, you need to join two or more regex match subgroups with `_`. Here you must use `${1}` instead of `$1`. More information [here](https://github.com/golang/go/issues/32885#issuecomment-507477621) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/melange-0.26.12/e2e-tests/capabilities-add-drop-build.yaml new/melange-0.26.13/e2e-tests/capabilities-add-drop-build.yaml --- old/melange-0.26.12/e2e-tests/capabilities-add-drop-build.yaml 2025-06-14 01:32:20.000000000 +0200 +++ new/melange-0.26.13/e2e-tests/capabilities-add-drop-build.yaml 2025-06-20 20:50:44.000000000 +0200 @@ -20,12 +20,18 @@ pipeline: - name: Test default effective capability runs: | + # Skip test if on QEMU runner, since the runner does not support process capabilities add/drop Melange feature. + { test -f /sys/class/dmi/id/sys_vendor && grep -E "^QEMU$" /sys/class/dmi/id/sys_vendor && exit 0; } || true capsh --decode=$(grep CapEff /proc/self/status | cut -d ':' -f2 | xargs) | grep -i cap_dac_override - name: Test added non-default effective capability runs: | + # Skip test if on QEMU runner, since the runner does not support process capabilities add/drop Melange feature. + { test -f /sys/class/dmi/id/sys_vendor && grep -E "^QEMU$" /sys/class/dmi/id/sys_vendor && exit 0; } || true capsh --decode=$(grep CapEff /proc/self/status | cut -d ':' -f2 | xargs) | grep -i cap_net_admin - name: Test dropped default effective capability runs: | + # Skip test if on QEMU runner, since the runner does not support process capabilities add/drop Melange feature. + { test -f /sys/class/dmi/id/sys_vendor && grep -E "^QEMU$" /sys/class/dmi/id/sys_vendor && exit 0; } || true capsh --decode=$(grep CapEff /proc/self/status | cut -d ':' -f2 | xargs) | grep -vi cap_sys_chroot diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/melange-0.26.12/e2e-tests/capabilities-add-drop-nopkg-test.yaml new/melange-0.26.13/e2e-tests/capabilities-add-drop-nopkg-test.yaml --- old/melange-0.26.12/e2e-tests/capabilities-add-drop-nopkg-test.yaml 2025-06-14 01:32:20.000000000 +0200 +++ new/melange-0.26.13/e2e-tests/capabilities-add-drop-nopkg-test.yaml 2025-06-20 20:50:44.000000000 +0200 @@ -22,12 +22,18 @@ pipeline: - name: Test default effective capability runs: | + # Skip test if on QEMU runner, since the runner does not support process capabilities add/drop Melange feature. + { test -f /sys/class/dmi/id/sys_vendor && grep -E "^QEMU$" /sys/class/dmi/id/sys_vendor && exit 0; } || true capsh --decode=$(grep CapEff /proc/self/status | cut -d ':' -f2 | xargs) | grep -i cap_dac_override - name: Test added non-default effective capability runs: | + # Skip test if on QEMU runner, since the runner does not support process capabilities add/drop Melange feature. + { test -f /sys/class/dmi/id/sys_vendor && grep -E "^QEMU$" /sys/class/dmi/id/sys_vendor && exit 0; } || true capsh --decode=$(grep CapEff /proc/self/status | cut -d ':' -f2 | xargs) | grep -i cap_net_admin - name: Test dropped default effective capability runs: | + # Skip test if on QEMU runner, since the runner does not support process capabilities add/drop Melange feature. + { test -f /sys/class/dmi/id/sys_vendor && grep -E "^QEMU$" /sys/class/dmi/id/sys_vendor && exit 0; } || true capsh --decode=$(grep CapEff /proc/self/status | cut -d ':' -f2 | xargs) | grep -vi cap_sys_chroot diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/melange-0.26.12/e2e-tests/git-checkout-build.yaml new/melange-0.26.13/e2e-tests/git-checkout-build.yaml --- old/melange-0.26.12/e2e-tests/git-checkout-build.yaml 2025-06-14 01:32:20.000000000 +0200 +++ new/melange-0.26.13/e2e-tests/git-checkout-build.yaml 2025-06-20 20:50:44.000000000 +0200 @@ -271,14 +271,16 @@ else # Ownership of existing files is not changed. expected_runner=42 - expected_melange=6 + expected_melange=1 fi exclude_args="! -regex ^\.\/\.ssh.*$ ! -regex ^./.gitconfig$" found_runner=$(find . -user $runner_user $exclude_args | wc -l) mismatch="" if [[ $found_runner != $expected_runner ]]; then - echo "Expected $expected_runner files owned by $runner_user, found $found_runner" + echo "Expected $expected_runner files owned by the runner user $runner_user, found $found_runner" find . -user $runner_user $exclude_args + echo "files owned by Melange user $melange_user:" + find . -user $melange_user $exclude_args mismatch=true fi if [[ $melange_user != $runner_user ]]; then diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/melange-0.26.12/e2e-tests/greeter-build-test.yaml new/melange-0.26.13/e2e-tests/greeter-build-test.yaml --- old/melange-0.26.12/e2e-tests/greeter-build-test.yaml 2025-06-14 01:32:20.000000000 +0200 +++ new/melange-0.26.13/e2e-tests/greeter-build-test.yaml 2025-06-20 20:50:44.000000000 +0200 @@ -16,7 +16,7 @@ epoch: 0 dependencies: runtime: - - dash-binsh + - busybox environment: contents: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/melange-0.26.12/e2e-tests/run-tests new/melange-0.26.13/e2e-tests/run-tests --- old/melange-0.26.12/e2e-tests/run-tests 2025-06-14 01:32:20.000000000 +0200 +++ new/melange-0.26.13/e2e-tests/run-tests 2025-06-20 20:50:44.000000000 +0200 @@ -67,6 +67,7 @@ vrc "Testing $base from $yaml for $op" \ ${MELANGE} "$op" \ --arch=x86_64 --source-dir=./test-fixtures \ + --runner=qemu \ "$yaml" \ ${args} $opargs \ "--keyring-append=$PWD/$key.pub" \ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/melange-0.26.12/pkg/build/build.go new/melange-0.26.13/pkg/build/build.go --- old/melange-0.26.12/pkg/build/build.go 2025-06-14 01:32:20.000000000 +0200 +++ new/melange-0.26.13/pkg/build/build.go 2025-06-20 20:50:44.000000000 +0200 @@ -148,6 +148,12 @@ // visibility into our packages' (including subpackages') composition. This is // how we get "build-time" SBOMs! SBOMGroup *SBOMGroup + + // The package resolver associated with this build. + // + // This is only applicable when there's a build context. It + // is filled by buildGuest. + PkgResolver *apk.PkgResolver } func New(ctx context.Context, opts ...Option) (*Build, error) { @@ -345,6 +351,13 @@ return "", fmt.Errorf("unable to create build context: %w", err) } + // Get the APK associated with our build, and then get a Resolver + namedIndexes, err := bc.APK().GetRepositoryIndexes(ctx, false) + if err != nil { + return "", fmt.Errorf("unable to obtain repository indexes: %w", err) + } + b.PkgResolver = apk.NewPkgResolver(ctx, namedIndexes) + bc.Summarize(ctx) log.Infof("auth configured for: %s", maps.Keys(b.Auth)) // TODO: add this to summarize @@ -577,6 +590,11 @@ b.summarize(ctx) + ver := b.Configuration.Package.Version + if _, err := apk.ParseVersion(ver); err != nil { + return fmt.Errorf("Unable to parse version '%s' for %s: %v", ver, b.ConfigFile, err) + } + namespace := b.Namespace if namespace == "" { namespace = "unknown" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/melange-0.26.12/pkg/build/build_integration_test.go new/melange-0.26.13/pkg/build/build_integration_test.go --- old/melange-0.26.12/pkg/build/build_integration_test.go 2025-06-14 01:32:20.000000000 +0200 +++ new/melange-0.26.13/pkg/build/build_integration_test.go 2025-06-20 20:50:44.000000000 +0200 @@ -75,9 +75,8 @@ } if err := b.BuildPackage(ctx); err != nil { - errStr := fmt.Sprintf("%s", err) - if tt.buildErrMatch != nil && tt.buildErrMatch.MatchString(errStr) { - t.Logf("%s build failed as expected", tt.name) + if tt.buildErrMatch != nil && tt.buildErrMatch.MatchString(err.Error()) { + t.Logf("%s build correctly identified invalid version %s", tt.name, b.Configuration.Package.Version) return } t.Fatalf("building package: %v", err) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/melange-0.26.12/pkg/build/package.go new/melange-0.26.13/pkg/build/package.go --- old/melange-0.26.12/pkg/build/package.go 2025-06-14 01:32:20.000000000 +0200 +++ new/melange-0.26.13/pkg/build/package.go 2025-06-20 20:50:44.000000000 +0200 @@ -306,6 +306,12 @@ newRuntimeDeps := []string{} for _, dep := range runtimeDeps { + if strings.HasPrefix(dep, "so-ver:") { + // so-ver: dependencies will always have + // explicit versioning. We need to strip it + // out. + dep, _, _ = strings.Cut(dep, ">=") + } _, ok := providedDepsMap[dep] if ok { continue diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/melange-0.26.12/pkg/build/sca_interface.go new/melange-0.26.13/pkg/build/sca_interface.go --- old/melange-0.26.12/pkg/build/sca_interface.go 2025-06-14 01:32:20.000000000 +0200 +++ new/melange-0.26.13/pkg/build/sca_interface.go 2025-06-20 20:50:44.000000000 +0200 @@ -17,7 +17,9 @@ import ( "fmt" "path/filepath" + "strings" + "chainguard.dev/apko/pkg/apk/apk" apkofs "chainguard.dev/apko/pkg/apk/fs" "chainguard.dev/melange/pkg/config" "chainguard.dev/melange/pkg/sca" @@ -84,3 +86,28 @@ func (scabi *SCABuildInterface) BaseDependencies() config.Dependencies { return scabi.PackageBuild.Dependencies } + +// InstalledPackages returns a map [package name] => [package version] +// of the packages installed during build. +func (scabi *SCABuildInterface) InstalledPackages() map[string]string { + pkgVersionMap := make(map[string]string) + + for _, fullpkg := range scabi.PackageBuild.Build.Configuration.Environment.Contents.Packages { + pkg, version, _ := strings.Cut(fullpkg, "=") + pkgVersionMap[pkg] = version + } + + // We also include the packages being built. They have the + // special version string "@CURRENT@" to make it easier for + // the SCA to identify them. + for _, pkg := range scabi.RelativeNames() { + pkgVersionMap[pkg] = "@CURRENT@" + } + + return pkgVersionMap +} + +// PkgResolver returns the package resolver for the package/build being analyzed. +func (scabi *SCABuildInterface) PkgResolver() *apk.PkgResolver { + return scabi.PackageBuild.Build.PkgResolver +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/melange-0.26.12/pkg/build/testdata/build_configs/bogus-version.yaml new/melange-0.26.13/pkg/build/testdata/build_configs/bogus-version.yaml --- old/melange-0.26.12/pkg/build/testdata/build_configs/bogus-version.yaml 2025-06-14 01:32:20.000000000 +0200 +++ new/melange-0.26.13/pkg/build/testdata/build_configs/bogus-version.yaml 2025-06-20 20:50:44.000000000 +0200 @@ -26,7 +26,7 @@ - name: build a package runs: | - bd="${{target.destdir}}/usr/bin/" + bd="${{targets.destdir}}/usr/bin/" fpath="$bd/bogus-version" ver="${{package.version}}" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/melange-0.26.12/pkg/cli/build.go new/melange-0.26.13/pkg/cli/build.go --- old/melange-0.26.12/pkg/cli/build.go 2025-06-14 01:32:20.000000000 +0200 +++ new/melange-0.26.13/pkg/cli/build.go 2025-06-20 20:50:44.000000000 +0200 @@ -25,7 +25,6 @@ "strings" "time" - "chainguard.dev/apko/pkg/apk/apk" apko_types "chainguard.dev/apko/pkg/build/types" "chainguard.dev/melange/pkg/build" "chainguard.dev/melange/pkg/container" @@ -336,11 +335,6 @@ defer bc.Close(ctx) - ver := bc.Configuration.Package.Version - if _, err := apk.ParseVersion(ver); err != nil { - return fmt.Errorf("Unable to parse version '%s' for %s: %v", ver, bc.ConfigFile, err) - } - bcs = append(bcs, bc) } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/melange-0.26.12/pkg/cli/scan.go new/melange-0.26.13/pkg/cli/scan.go --- old/melange-0.26.12/pkg/cli/scan.go 2025-06-14 01:32:20.000000000 +0200 +++ new/melange-0.26.13/pkg/cli/scan.go 2025-06-20 20:50:44.000000000 +0200 @@ -28,6 +28,7 @@ "strings" "time" + "chainguard.dev/apko/pkg/apk/apk" "chainguard.dev/apko/pkg/apk/expandapk" "chainguard.dev/melange/pkg/build" "chainguard.dev/melange/pkg/config" @@ -444,6 +445,29 @@ return s.pb.Dependencies } +func (s *scaImpl) InstalledPackages() map[string]string { + pkgVersionMap := make(map[string]string) + + for _, fullpkg := range s.pb.Build.Configuration.Environment.Contents.Packages { + pkg, version, _ := strings.Cut(fullpkg, "=") + pkgVersionMap[pkg] = version + } + + // We also include the packages being built. + for _, pkg := range s.RelativeNames() { + pkgVersionMap[pkg] = s.Version() + } + + return pkgVersionMap +} + +func (s *scaImpl) PkgResolver() *apk.PkgResolver { + if s.pb.Build == nil || s.pb.Build.PkgResolver == nil { + return nil + } + return s.pb.Build.PkgResolver +} + func isComment(b string) bool { return strings.HasPrefix(b, "#") } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/melange-0.26.12/pkg/config/config.go new/melange-0.26.13/pkg/config/config.go --- old/melange-0.26.12/pkg/config/config.go 2025-06-14 01:32:20.000000000 +0200 +++ new/melange-0.26.13/pkg/config/config.go 2025-06-20 20:50:44.000000000 +0200 @@ -90,6 +90,8 @@ NoDepends bool `json:"no-depends,omitempty" yaml:"no-depends,omitempty"` // Optional: Mark this package as not providing any executables NoCommands bool `json:"no-commands,omitempty" yaml:"no-commands,omitempty"` + // Optional: Don't generate versioned depends for shared libraries + NoVersionedShlibDeps bool `json:"no-versioned-shlib-deps,omitempty" yaml:"no-versioned-shlib-deps,omitempty"` } type Checks struct { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/melange-0.26.12/pkg/config/schema.json new/melange-0.26.13/pkg/config/schema.json --- old/melange-0.26.12/pkg/config/schema.json 2025-06-14 01:32:20.000000000 +0200 +++ new/melange-0.26.13/pkg/config/schema.json 2025-06-20 20:50:44.000000000 +0200 @@ -657,6 +657,10 @@ "no-commands": { "type": "boolean", "description": "Optional: Mark this package as not providing any executables" + }, + "no-versioned-shlib-deps": { + "type": "boolean", + "description": "Optional: Don't generate versioned depends for shared libraries" } }, "additionalProperties": false, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/melange-0.26.12/pkg/container/qemu_runner.go new/melange-0.26.13/pkg/container/qemu_runner.go --- old/melange-0.26.12/pkg/container/qemu_runner.go 2025-06-14 01:32:20.000000000 +0200 +++ new/melange-0.26.13/pkg/container/qemu_runner.go 2025-06-20 20:50:44.000000000 +0200 @@ -925,7 +925,7 @@ nil, bufWriter, false, - []string{"sh", "-c", "cd /mount/home/build && find . -type f -print"}, + []string{"sh", "-c", "cd /mount/home/build && find . -type f -links 1 -print"}, ) if err != nil { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/melange-0.26.12/pkg/renovate/bump/bump.go new/melange-0.26.13/pkg/renovate/bump/bump.go --- old/melange-0.26.12/pkg/renovate/bump/bump.go 2025-06-14 01:32:20.000000000 +0200 +++ new/melange-0.26.13/pkg/renovate/bump/bump.go 2025-06-20 20:50:44.000000000 +0200 @@ -22,7 +22,6 @@ "fmt" "io" "net/http" - "regexp" "strconv" "strings" @@ -225,8 +224,7 @@ if err != nil { log.Infof("git-checkout node does not contain a tag, assume we need to update the expected-commit sha") } else { - versionPattern := regexp.MustCompile(`\${{vars\..+}}`) - if !strings.Contains(tag.Value, "${{package.version}}") && !versionPattern.MatchString(tag.Value) { + if !strings.Contains(tag.Value, "${{package.version}}") && !strings.Contains(tag.Value, "${{vars.mangled-package-version}}") { log.Infof("Skipping git-checkout node as it does not contain a version substitution so assuming it is not the main checkout") return nil } @@ -237,7 +235,7 @@ if expectedGitSha != "" { // Update expected hash nodes. nodeCommit, err := renovate.NodeFromMapping(withNode, "expected-commit") - if err == nil { + if err == nil && !strings.Contains(nodeCommit.Value, "${{") { nodeCommit.Value = expectedGitSha log.Infof(" expected-commit: %s", expectedGitSha) } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/melange-0.26.12/pkg/sca/e2e_test.go new/melange-0.26.13/pkg/sca/e2e_test.go --- old/melange-0.26.12/pkg/sca/e2e_test.go 2025-06-14 01:32:20.000000000 +0200 +++ new/melange-0.26.13/pkg/sca/e2e_test.go 2025-06-20 20:50:44.000000000 +0200 @@ -94,6 +94,25 @@ "cmd:ttx=0.13.2-r0", }, Vendored: []string{ + "so-ver:libXau-154567c4.so.6.0.0=0.13.2-r0", + "so-ver:libbrotlicommon-3ecfe81c.so.1=0.13.2-r0", + "so-ver:libbrotlidec-ba690955.so.1=0.13.2-r0", + "so-ver:libfreetype-f154df84.so.6.20.1=0.13.2-r0", + "so-ver:libgfortran-040039e1.so.5.0.0=0.13.2-r0", + "so-ver:libharfbuzz-2093a78b.so.0.60830.0=0.13.2-r0", + "so-ver:libjpeg-e44fd0cd.so.62.4.0=0.13.2-r0", + "so-ver:liblcms2-e69eef39.so.2.0.16=0.13.2-r0", + "so-ver:liblzma-13fa198c.so.5.4.5=0.13.2-r0", + "so-ver:libopenblas64_p-r0-0cf96a72.3.23.dev.so=0.13.2-r0", + "so-ver:libopenjp2-eca49203.so.2.5.0=0.13.2-r0", + "so-ver:libpng16-78d422d5.so.16.40.0=0.13.2-r0", + "so-ver:libquadmath-96973f99.so.0.0.0=0.13.2-r0", + "so-ver:libsharpyuv-20f78091.so.0.0.1=0.13.2-r0", + "so-ver:libtiff-91af027d.so.6.0.2=0.13.2-r0", + "so-ver:libwebp-850e2bec.so.7.1.8=0.13.2-r0", + "so-ver:libwebpdemux-df9b36c7.so.2.0.14=0.13.2-r0", + "so-ver:libwebpmux-9fe05867.so.3.0.13=0.13.2-r0", + "so-ver:libxcb-f0538cc0.so.1.1.0=0.13.2-r0", "so:libXau-154567c4.so.6.0.0=6.0.0", "so:libbrotlicommon-3ecfe81c.so.1=1", "so:libbrotlidec-ba690955.so.1=1", @@ -181,6 +200,11 @@ "cmd:udevadm=256.2-r1", "cmd:userdbctl=256.2-r1", "cmd:varlinkctl=256.2-r1", + "so-ver:libnss_myhostname.so.2=256.2-r1", + "so-ver:libnss_mymachines.so.2=256.2-r1", + "so-ver:libnss_resolve.so.2=256.2-r1", + "so-ver:libnss_systemd.so.2=256.2-r1", + "so-ver:libudev.so.1=256.2-r1", "so:libnss_myhostname.so.2=2", "so:libnss_mymachines.so.2=2", "so:libnss_resolve.so.2=2", @@ -188,6 +212,8 @@ "so:libudev.so.1=1", }, Vendored: []string{ + "so-ver:libsystemd-core-256.so=256.2-r1", + "so-ver:libsystemd-shared-256.so=256.2-r1", "so:libsystemd-core-256.so=0", "so:libsystemd-shared-256.so=0", }, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/melange-0.26.12/pkg/sca/sca.go new/melange-0.26.13/pkg/sca/sca.go --- old/melange-0.26.12/pkg/sca/sca.go 2025-06-14 01:32:20.000000000 +0200 +++ new/melange-0.26.13/pkg/sca/sca.go 2025-06-20 20:50:44.000000000 +0200 @@ -24,11 +24,13 @@ "fmt" "io" "io/fs" + "os" "path/filepath" "slices" "strings" "unicode" + "chainguard.dev/apko/pkg/apk/apk" apkofs "chainguard.dev/apko/pkg/apk/fs" "github.com/chainguard-dev/clog" "github.com/chainguard-dev/go-pkgconfig" @@ -72,6 +74,14 @@ // BaseDependencies returns the underlying set of declared dependencies before // the SCA engine runs. BaseDependencies() config.Dependencies + + // InstalledPackages returns a map [package name] => [package + // version] for all build dependencies installed during build. + InstalledPackages() map[string]string + + // PkgResolver returns the package resolver associated with + // the current package/build being analyzed. + PkgResolver() *apk.PkgResolver } // DependencyGenerator takes an SCAHandle, config.Dependencies pointer @@ -263,6 +273,181 @@ return "", "", nil } +// determineShlibVersion tries to determine the exact version of the +// package that provides the shared library shlib. It does that by: +// +// - Asking PkgResolver to calculate the list of packages that provide "so:shlib". +// +// - Verifying if any package in that list matches what is currently +// installed in the build environment. The package can offer a +// provided shared library whose version is equal or greater than +// the one the build requires. +// +// - Verifying if the matched package has a versioned shared library +// "provides:". +// +// If all steps succeed, the package version is returned. +// +// If there is a match but the package doesn't currently offer a +// versioned shared library "provides:", then an empty version is +// returned. We can't do versioned "depends:" unless there is a +// matching "provides:". +// +// If no match is found, then we assume that the shared library is +// vendored by the package being built. In this case, we return an +// empty version string. +func determineShlibVersion(ctx context.Context, hdl SCAHandle, shlib string) (string, error) { + log := clog.FromContext(ctx) + + // Feature flag to disable versioned shlib dependencies. + if os.Getenv("MELANGE_VERSIONED_SHLIB_DEPENDS") == "" { + return "", nil + } + + if hdl.Options().NoVersionedShlibDeps { + // This package does not care about versioned shlib + // depends. + return "", nil + } + + // We don't version-depend or provide ld-linux-*.so, otherwise + // we'd be required to rebuild all packages that link against + // glibc whenever the latter is updated. + if strings.HasPrefix(shlib, "ld-linux-x86-64.so") || strings.HasPrefix(shlib, "ld-linux-aarch64.so") { + log.Debugf("Skipping %s", shlib) + return "", nil + } + + pkgResolver := hdl.PkgResolver() + + if pkgResolver == nil { + // When we're invoked from "melange scan", there's no + // package resolver available. Just return an empty + // version. + log.Debugf("Package resolver is nil; returning an empty shlib version") + return "", nil + } + + // Obtain the list of packages that provide the shared + // library. + candidates, err := pkgResolver.ResolvePackage("so:" + shlib, map[*apk.RepositoryPackage]string{}) + if err != nil { + if strings.Contains(err.Error(), "nothing provides") { + // We can reach here if one of the + // (sub)packages we're building provides a new + // version of a shared library. Since this + // new (sub)package isn't present in the + // current APKINDEX, ResolvePackage() won't be + // able to find it. However, we can return + // the current version being built in this + // case. + return hdl.Version(), nil + } + + // This is an unknown error, so we'd better return it. + return "", err + } + + // ResolvePackage will return *all* packages that provide + // shlib, including those that have been obsoleted. For that + // reason, we need sort the list of candidates by build time, + // making sure that we're always considering the newest ones. + slices.SortFunc(candidates, func(p1 *apk.RepositoryPackage, p2 *apk.RepositoryPackage) int { + return p2.BuildTime.Compare(p1.BuildTime) + }) + + // Obtain the list of packages currently installed in the + // build environment. + pkgVersionMap := hdl.InstalledPackages() + + for _, candidate := range candidates { + log.Debugf("Verifying if package %s-%s (which provides shlib %s) is the one used to build the package", candidate.PackageName(), candidate.Version, shlib) + + // The version of the package that's installed in the + // build environment. + installedPackageVersionString, ok := pkgVersionMap[candidate.PackageName()] + if !ok { + // We don't have the candidate package in the + // build environment. That can happen + // e.g. when multiple packages provide the + // same shared library. + // + // Ideally we will see the correct package + // later in the loop. + continue + } + + if installedPackageVersionString == "@CURRENT@" { + // This is the package (or one of its + // subpackages) being built. Return the + // current version as it is equal or greater + // than the one currently in the index. + return hdl.Version(), nil + } else { + // Convert the versions of the candidate and + // installed packages to proper structures so + // that we can compare them. + candidateVersion, err := apk.ParseVersion(candidate.Version) + if err != nil { + return "", err + } + installedPackageVersion, err := apk.ParseVersion(installedPackageVersionString) + if err != nil { + return "", err + } + + if apk.CompareVersions(candidateVersion, installedPackageVersion) < 0 { + // The candidate package provides an + // shlib that is versioned as older + // than the one we have in our build + // environment. + return "", fmt.Errorf("could not find suitable package providing library so-ver:%s>=%s (found so-ver:%s=%s instead)", shlib, installedPackageVersionString, shlib, candidate.Version) + } + + // Check if the package actually provides a + // versioned shlib, otherwise we can't depend on it. + if slices.ContainsFunc(candidate.Provides, func(provides string) bool { + providedArtifact, providedVersion, found := strings.Cut(provides, "=") + if !found { + return false + } + + if providedArtifact != "so-ver:" + shlib { + return false + } + + _, err := apk.ParseVersion(providedVersion) + // If we're able to parse the version, + // then it's a valid one. + return err != nil + }) { + return installedPackageVersionString, nil + } + + // The package (still) doesn't provide a + // versioned shlib. That's ok; just return an + // empty version for now. + return "", nil + } + } + + // If we're here, then one of the following scenarios happened: + // + // - The list of candidates is empty. This happens when we're + // dealing with a vendored shared library that isn't + // provided by any of our packages. Just return an empty + // version string. + // + // - There is a list of candidates, but none of them provides + // the version of shared library we're interested in. This + // has been seen to happen when the package being built uses + // a vendored library that *is* provided by one of our + // packages, but the vendored version is higher than the + // non-vendored one. This is also a case of vendorization, + // so we return an empty version string. + return "", nil +} + func processSymlinkSo(ctx context.Context, hdl SCAHandle, path string, generated *config.Dependencies, extraLibDirs []string) error { log := clog.FromContext(ctx) if !strings.Contains(path, ".so") { @@ -308,6 +493,14 @@ log.Infof(" found soname %s for %s", soname, path) generated.Runtime = append(generated.Runtime, fmt.Sprintf("so:%s", soname)) + + shlibVer, err := determineShlibVersion(ctx, hdl, soname) + if err != nil { + return err + } + if shlibVer != "" { + generated.Runtime = append(generated.Runtime, fmt.Sprintf("so-ver:%s>=%s", soname, shlibVer)) + } } } @@ -404,6 +597,14 @@ if strings.Contains(lib, ".so.") { log.Infof(" found lib %s for %s", lib, path) generated.Runtime = append(generated.Runtime, fmt.Sprintf("so:%s", lib)) + + shlibVer, err := determineShlibVersion(ctx, hdl, lib) + if err != nil { + return err + } + if shlibVer != "" { + generated.Runtime = append(generated.Runtime, fmt.Sprintf("so-ver:%s>=%s", lib, shlibVer)) + } } } @@ -434,8 +635,10 @@ if isInDir(path, expandedLibDirs) { generated.Provides = append(generated.Provides, fmt.Sprintf("so:%s=%s", soname, libver)) + generated.Provides = append(generated.Provides, fmt.Sprintf("so-ver:%s=%s", soname, hdl.Version())) } else { generated.Vendored = append(generated.Vendored, fmt.Sprintf("so:%s=%s", soname, libver)) + generated.Vendored = append(generated.Vendored, fmt.Sprintf("so-ver:%s=%s", soname, hdl.Version())) } } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/melange-0.26.12/pkg/sca/sca_test.go new/melange-0.26.13/pkg/sca/sca_test.go --- old/melange-0.26.12/pkg/sca/sca_test.go 2025-06-14 01:32:20.000000000 +0200 +++ new/melange-0.26.13/pkg/sca/sca_test.go 2025-06-20 20:50:44.000000000 +0200 @@ -83,6 +83,14 @@ return th.cfg.Package.Dependencies } +func (th *testHandle) InstalledPackages() map[string]string { + return map[string]string{} +} + +func (th *testHandle) PkgResolver() *apk.PkgResolver { + return nil +} + // TODO: Loose coupling. func handleFromApk(ctx context.Context, t *testing.T, apkfile, melangefile string) *testHandle { t.Helper() @@ -158,6 +166,8 @@ "so:libpsx.so.2", }, Provides: []string{ + "so-ver:libcap.so.2=2.69-r0", + "so-ver:libpsx.so.2=2.69-r0", "so:libcap.so.2=2", "so:libpsx.so.2=2", }, @@ -195,6 +205,7 @@ "pc:libecpg_compat=4604-r0", "pc:libpgtypes=4604-r0", "pc:libpq=4604-r0", + "so-ver:libecpg_compat.so.3=4604-r0", "so:libecpg_compat.so.3=3", }, } @@ -267,7 +278,10 @@ "so:libaws-checksums.so.1.0.0", "so:libc.so.6", }, - Provides: []string{"so:libaws-c-s3.so.0unstable=0"}, + Provides: []string{ + "so-ver:libaws-c-s3.so.0unstable=0.4.9-r0", + "so:libaws-c-s3.so.0unstable=0", + }, } if diff := cmp.Diff(want, got); diff != "" { ++++++ melange.obsinfo ++++++ --- /var/tmp/diff_new_pack.Lubjyo/_old 2025-06-23 15:06:24.924593771 +0200 +++ /var/tmp/diff_new_pack.Lubjyo/_new 2025-06-23 15:06:24.928593938 +0200 @@ -1,5 +1,5 @@ name: melange -version: 0.26.12 -mtime: 1749857540 -commit: 65e385aff51b530faf6c3c001be62e5dc8b91aef +version: 0.26.13 +mtime: 1750445444 +commit: 4946b0592c319b5915a0570182aa968568962885 ++++++ vendor.tar.gz ++++++ /work/SRC/openSUSE:Factory/melange/vendor.tar.gz /work/SRC/openSUSE:Factory/.melange.new.7067/vendor.tar.gz differ: char 132, line 1