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-05-13 20:06:06
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/melange (Old)
 and      /work/SRC/openSUSE:Factory/.melange.new.30101 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "melange"

Tue May 13 20:06:06 2025 rev:85 rq:1276954 version:0.23.17

Changes:
--------
--- /work/SRC/openSUSE:Factory/melange/melange.changes  2025-05-12 
16:54:50.607697472 +0200
+++ /work/SRC/openSUSE:Factory/.melange.new.30101/melange.changes       
2025-05-13 20:06:09.568570769 +0200
@@ -1,0 +2,6 @@
+Mon May 12 19:02:12 UTC 2025 - Johannes Kastl 
<opensuse_buildserv...@ojkastl.de>
+
+- Update to version 0.23.17:
+  * experiment: on the fly disk for melange QEMU runner (#1977)
+
+-------------------------------------------------------------------

Old:
----
  melange-0.23.16.obscpio

New:
----
  melange-0.23.17.obscpio

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ melange.spec ++++++
--- /var/tmp/diff_new_pack.CpuqtI/_old  2025-05-13 20:06:11.136636737 +0200
+++ /var/tmp/diff_new_pack.CpuqtI/_new  2025-05-13 20:06:11.140636905 +0200
@@ -17,7 +17,7 @@
 
 
 Name:           melange
-Version:        0.23.16
+Version:        0.23.17
 Release:        0
 Summary:        Build APKs from source code
 License:        Apache-2.0

++++++ _service ++++++
--- /var/tmp/diff_new_pack.CpuqtI/_old  2025-05-13 20:06:11.168638083 +0200
+++ /var/tmp/diff_new_pack.CpuqtI/_new  2025-05-13 20:06:11.172638251 +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.23.16</param>
+    <param name="revision">v0.23.17</param>
     <param name="versionformat">@PARENT_TAG@</param>
     <param name="versionrewrite-pattern">v(.*)</param>
     <param name="changesgenerate">enable</param>

++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.CpuqtI/_old  2025-05-13 20:06:11.192639093 +0200
+++ /var/tmp/diff_new_pack.CpuqtI/_new  2025-05-13 20:06:11.196639261 +0200
@@ -1,6 +1,6 @@
 <servicedata>
 <service name="tar_scm">
                 <param 
name="url">https://github.com/chainguard-dev/melange</param>
-              <param 
name="changesrevision">5b4c1e4b78a5373233946c0d9c81442f85f45dad</param></service></servicedata>
+              <param 
name="changesrevision">76a4bd045fcad1727125b4ee7c12e97cf145c27c</param></service></servicedata>
 (No newline at EOF)
 

++++++ melange-0.23.16.obscpio -> melange-0.23.17.obscpio ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/melange-0.23.16/pkg/build/build.go 
new/melange-0.23.17/pkg/build/build.go
--- old/melange-0.23.16/pkg/build/build.go      2025-05-08 19:18:19.000000000 
+0200
+++ new/melange-0.23.17/pkg/build/build.go      2025-05-12 19:42:00.000000000 
+0200
@@ -16,7 +16,6 @@
 
 import (
        "archive/tar"
-       "compress/gzip"
        "context"
        "encoding/hex"
        "encoding/json"
@@ -309,8 +308,11 @@
        defer os.RemoveAll(tmp)
 
        if b.Runner.Name() == container.QemuName {
+               /*
+                * here we need to inject gnutar+attr in order to syphon back
+                * the workspace from the VM preserving extended attributes.
+                */
                b.ExtraPackages = append(b.ExtraPackages, []string{
-                       "melange-microvm-init",
                        "gnutar",
                        "attr",
                }...)
@@ -1060,6 +1062,47 @@
        return b.Libc
 }
 
+func runAsUID(accts apko_types.ImageAccounts) string {
+       switch accts.RunAs {
+       case "":
+               return "" // Runner defaults
+       case "root", "0":
+               return "0"
+       default:
+       }
+       // If accts.RunAs is numeric, then return it.
+       if _, err := strconv.Atoi(accts.RunAs); err == nil {
+               return accts.RunAs
+       }
+       for _, u := range accts.Users {
+               if accts.RunAs == u.UserName {
+                       return fmt.Sprint(u.UID)
+               }
+       }
+       panic(fmt.Sprintf("unable to find user with username %s", accts.RunAs))
+}
+
+func runAs(accts apko_types.ImageAccounts) string {
+       switch accts.RunAs {
+       case "":
+               return "" // Runner defaults
+       case "root", "0":
+               return "root"
+       default:
+       }
+       // If accts.RunAs is numeric, then look up the username.
+       uid, err := strconv.Atoi(accts.RunAs)
+       if err != nil {
+               return accts.RunAs
+       }
+       for _, u := range accts.Users {
+               if u.UID == uint32(uid) {
+                       return u.UserName
+               }
+       }
+       panic(fmt.Sprintf("unable to find user with UID %d", uid))
+}
+
 func (b *Build) buildWorkspaceConfig(ctx context.Context) *container.Config {
        log := clog.FromContext(ctx)
 
@@ -1099,7 +1142,8 @@
                },
                WorkspaceDir: b.WorkspaceDir,
                Timeout:      b.Configuration.Package.Timeout,
-               RunAs:        b.Configuration.Environment.Accounts.RunAs,
+               RunAsUID:     runAsUID(b.Configuration.Environment.Accounts),
+               RunAs:        runAs(b.Configuration.Environment.Accounts),
        }
 
        if b.Configuration.Package.Resources != nil {
@@ -1137,7 +1181,14 @@
        ctx, span := otel.Tracer("melange").Start(ctx, "retrieveWorkspace")
        defer span.End()
 
-       r, err := b.Runner.WorkspaceTar(ctx, b.containerConfig)
+       extraFiles := []string{}
+       for _, v := range b.Configuration.Package.Copyright {
+               if v.LicensePath != "" {
+                       extraFiles = append(extraFiles, v.LicensePath)
+               }
+       }
+
+       r, err := b.Runner.WorkspaceTar(ctx, b.containerConfig, extraFiles)
        if err != nil {
                return err
        } else if r == nil {
@@ -1145,12 +1196,7 @@
        }
        defer r.Close()
 
-       gr, err := gzip.NewReader(r)
-       if err != nil {
-               return err
-       }
-       defer gr.Close()
-       tr := tar.NewReader(gr)
+       tr := tar.NewReader(r)
 
        for {
                hdr, err := tr.Next()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/melange-0.23.16/pkg/build/test.go 
new/melange-0.23.17/pkg/build/test.go
--- old/melange-0.23.16/pkg/build/test.go       2025-05-08 19:18:19.000000000 
+0200
+++ new/melange-0.23.17/pkg/build/test.go       2025-05-12 19:42:00.000000000 
+0200
@@ -278,13 +278,6 @@
                return fmt.Errorf("compiling %s tests: %w", t.ConfigFile, err)
        }
 
-       if t.Runner.Name() == container.QemuName {
-               t.ExtraTestPackages = append(t.ExtraTestPackages, []string{
-                       "melange-microvm-init",
-                       "gnutar",
-               }...)
-       }
-
        // Filter out any subpackages with false If conditions.
        t.Configuration.Subpackages = 
slices.DeleteFunc(t.Configuration.Subpackages, func(sp config.Subpackage) bool {
                result, err := shouldRun(sp.If)
@@ -501,7 +494,8 @@
                Capabilities: caps,
                WorkspaceDir: t.WorkspaceDir,
                Environment:  map[string]string{},
-               RunAs:        imgcfg.Accounts.RunAs,
+               RunAsUID:     runAsUID(imgcfg.Accounts),
+               RunAs:        runAs(imgcfg.Accounts),
        }
        if t.Configuration.Capabilities.Add != nil {
                cfg.Capabilities.Add = t.Configuration.Capabilities.Add
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/melange-0.23.16/pkg/container/bubblewrap_runner.go 
new/melange-0.23.17/pkg/container/bubblewrap_runner.go
--- old/melange-0.23.16/pkg/container/bubblewrap_runner.go      2025-05-08 
19:18:19.000000000 +0200
+++ new/melange-0.23.17/pkg/container/bubblewrap_runner.go      2025-05-12 
19:42:00.000000000 +0200
@@ -116,10 +116,10 @@
                "--clearenv")
 
        // If we need to run as an user, we run as that user.
-       if cfg.RunAs != "" {
+       if cfg.RunAsUID != "" {
                baseargs = append(baseargs, "--unshare-user")
-               baseargs = append(baseargs, "--uid", cfg.RunAs)
-               baseargs = append(baseargs, "--gid", cfg.RunAs)
+               baseargs = append(baseargs, "--uid", cfg.RunAsUID)
+               baseargs = append(baseargs, "--gid", cfg.RunAsUID)
                // Else if we're not using melange as root, we force the use of 
the
                // Apko build user. This avoids problems on machines where 
default
                // regular user is NOT 1000.
@@ -226,7 +226,7 @@
 
 // WorkspaceTar implements Runner
 // This is a noop for Bubblewrap, which uses bind-mounts to manage the 
workspace
-func (bw *bubblewrap) WorkspaceTar(ctx context.Context, cfg *Config) 
(io.ReadCloser, error) {
+func (bw *bubblewrap) WorkspaceTar(ctx context.Context, cfg *Config, 
extraFiles []string) (io.ReadCloser, error) {
        return nil, nil
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/melange-0.23.16/pkg/container/bubblewrap_runner_test.go 
new/melange-0.23.17/pkg/container/bubblewrap_runner_test.go
--- old/melange-0.23.16/pkg/container/bubblewrap_runner_test.go 2025-05-08 
19:18:19.000000000 +0200
+++ new/melange-0.23.17/pkg/container/bubblewrap_runner_test.go 2025-05-12 
19:42:00.000000000 +0200
@@ -35,7 +35,7 @@
                },
                {
                        name:         "With config RunAs",
-                       config:       &Config{RunAs: "65535"},
+                       config:       &Config{RunAsUID: "65535"},
                        expectedArgs: fmt.Sprintf("--unshare-user --uid %s 
--gid %s", "65535", "65535"),
                },
        }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/melange-0.23.16/pkg/container/config.go 
new/melange-0.23.17/pkg/container/config.go
--- old/melange-0.23.16/pkg/container/config.go 2025-05-08 19:18:19.000000000 
+0200
+++ new/melange-0.23.17/pkg/container/config.go 2025-05-12 19:42:00.000000000 
+0200
@@ -52,6 +52,7 @@
        ImgRef                string
        PodID                 string
        Arch                  apko_types.Architecture
+       RunAsUID              string
        RunAs                 string
        WorkspaceDir          string
        CPU, CPUModel, Memory string
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/melange-0.23.16/pkg/container/docker/docker_runner.go 
new/melange-0.23.17/pkg/container/docker/docker_runner.go
--- old/melange-0.23.16/pkg/container/docker/docker_runner.go   2025-05-08 
19:18:19.000000000 +0200
+++ new/melange-0.23.17/pkg/container/docker/docker_runner.go   2025-05-12 
19:42:00.000000000 +0200
@@ -220,7 +220,7 @@
        }
 
        taskIDResp, err := dk.cli.ContainerExecCreate(ctx, cfg.PodID, 
container.ExecOptions{
-               User:         cfg.RunAs,
+               User:         cfg.RunAsUID,
                Cmd:          args,
                WorkingDir:   runnerWorkdir,
                Env:          environ,
@@ -358,7 +358,7 @@
 
 // WorkspaceTar implements Runner
 // This is a noop for Docker, which uses bind-mounts to manage the workspace
-func (dk *docker) WorkspaceTar(ctx context.Context, cfg *mcontainer.Config) 
(io.ReadCloser, error) {
+func (dk *docker) WorkspaceTar(ctx context.Context, cfg *mcontainer.Config, 
extraFiles []string) (io.ReadCloser, error) {
        return nil, nil
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/melange-0.23.16/pkg/container/qemu_runner.go 
new/melange-0.23.17/pkg/container/qemu_runner.go
--- old/melange-0.23.16/pkg/container/qemu_runner.go    2025-05-08 
19:18:19.000000000 +0200
+++ new/melange-0.23.17/pkg/container/qemu_runner.go    2025-05-12 
19:42:00.000000000 +0200
@@ -18,7 +18,6 @@
        "archive/tar"
        "bufio"
        "bytes"
-       "compress/gzip"
        "context"
        "crypto/ecdsa"
        "crypto/elliptic"
@@ -41,11 +40,13 @@
        "syscall"
        "time"
 
+       apkofs "chainguard.dev/apko/pkg/apk/fs"
        apko_build "chainguard.dev/apko/pkg/build"
        apko_types "chainguard.dev/apko/pkg/build/types"
        apko_cpio "chainguard.dev/apko/pkg/cpio"
        "chainguard.dev/melange/internal/logwriter"
        "github.com/chainguard-dev/clog"
+       "github.com/charmbracelet/log"
        v1 "github.com/google/go-containerregistry/pkg/v1"
        "github.com/google/go-containerregistry/pkg/v1/tarball"
        "github.com/kballard/go-shellquote"
@@ -86,11 +87,10 @@
        defer stdout.Close()
        defer stderr.Close()
 
-       // default to root user but if a different user is specified
-       // we will use the embedded build:1000:1000 user
+       // default to root user, unless a different user is specified
        user := "root"
        if cfg.RunAs != "" {
-               user = "build"
+               user = cfg.RunAs
        }
 
        err := sendSSHCommand(ctx,
@@ -114,13 +114,6 @@
 func (bw *qemu) Debug(ctx context.Context, cfg *Config, envOverride 
map[string]string, args ...string) error {
        clog.InfoContextf(ctx, "debugging command %s", strings.Join(args, " "))
 
-       // default to root user but if a different user is specified
-       // we will use the embedded build:1000:1000 user
-       user := "root"
-       if cfg.RunAs != "" {
-               user = "build"
-       }
-
        // handle terminal size, resizing and sigwinch to keep
        // it updated
        fd := int(os.Stdin.Fd())
@@ -152,6 +145,12 @@
                return err
        }
 
+       // default to root user, unless a different user is specified
+       user := "root"
+       if cfg.RunAs != "" {
+               user = cfg.RunAs
+       }
+
        // Create SSH client configuration
        config := &ssh.ClientConfig{
                User: user,
@@ -159,7 +158,7 @@
                        ssh.PublicKeys(signer),
                },
                Config: ssh.Config{
-                       Ciphers: []string{"aes128-ctr", 
"aes256-...@openssh.com"},
+                       Ciphers: []string{"aes128-...@openssh.com"},
                },
                HostKeyCallback: hostKeyCallback,
        }
@@ -371,15 +370,8 @@
 }
 
 // WorkspaceTar implements Runner
-func (bw *qemu) WorkspaceTar(ctx context.Context, cfg *Config) (io.ReadCloser, 
error) {
-       // default to root user but if a different user is specified
-       // we will use the embedded build:1000:1000 user
-       user := "root"
-       if cfg.RunAs != "" {
-               user = "build"
-       }
-
-       outFile, err := os.Create(filepath.Join(cfg.WorkspaceDir, 
"melange-out.tar.gz"))
+func (bw *qemu) WorkspaceTar(ctx context.Context, cfg *Config, extraFiles 
[]string) (io.ReadCloser, error) {
+       outFile, err := os.Create(filepath.Join(cfg.WorkspaceDir, 
"melange-out.tar"))
        if err != nil {
                return nil, err
        }
@@ -393,6 +385,19 @@
        // We could just cp -a to /mnt as it is our shared workspace directory, 
but
        // this will lose some file metadata like hardlinks, owners and so on.
        // Example of package that won't work when using "cp -a" is glibc.
+       retrieveCommand := "cd /home/build && tar cvpf - --xattrs --acls 
--exclude='*fifo*' melange-out"
+       // we append also all the necessary files that we might need, for 
example Licenses
+       // for license checks
+       for _, v := range extraFiles {
+               retrieveCommand = retrieveCommand + " " + v
+       }
+
+       // default to root user, unless a different user is specified
+       user := "root"
+       if cfg.RunAs != "" {
+               user = cfg.RunAs
+       }
+
        err = sendSSHCommand(ctx,
                user,
                cfg.SSHAddress,
@@ -402,7 +407,7 @@
                nil,
                outFile,
                false,
-               []string{"sh", "-c", "cd /home/build && tar cvpzf - --xattrs 
--acls --exclude='*fifo*' *"},
+               []string{"sh", "-c", retrieveCommand},
        )
        if err != nil {
                return nil, err
@@ -418,42 +423,23 @@
        defer span.End()
 
        // qemu does not have the idea of container images or layers or such, 
just
-       // create an initramfs from the layer
-       guestInitramfs, err := os.CreateTemp("", 
"melange-guest-*.initramfs.cpio")
+       // create a rootfs from the layer
+       guestRootfs, err := os.CreateTemp("", "melange-guest-*.tar")
        if err != nil {
                clog.FromContext(ctx).Errorf("failed to create guest dir: %v", 
err)
                return ref, err
        }
 
-       // in case of some kernel images, we also need the /lib/modules 
directory to load
-       // necessary drivers, like 9p, virtio_net which are foundamental for 
the VM working.
-       if qemuModule, ok := os.LookupEnv("QEMU_KERNEL_MODULES"); ok {
-               clog.FromContext(ctx).Debugf("qemu: QEMU_KERNEL_MODULES env 
set, injecting modules in initramfs")
-               if _, err := os.Stat(qemuModule); err == nil {
-                       clog.FromContext(ctx).Debugf("qemu: local 
QEMU_KERNEL_MODULES dir detected, injecting")
-                       layer, err = injectKernelModules(ctx, layer, qemuModule)
-                       if err != nil {
-                               clog.FromContext(ctx).Errorf("qemu: could not 
inject needed kernel modules into initramfs: %v", err)
-                               return "", err
-                       }
-               }
-       }
-
-       // We see issues with qemu launching the initrd when the size of the
-       // uncompressed CPIO exceeds ~2G and change (very suspiciously around
-       // max signed int32), so take the performance hit of compressing the 
initrd
-       // (a double hit b/c the kernel will decompress).
-       gzw := gzip.NewWriter(guestInitramfs)
-       if err := apko_cpio.FromLayer(layer, gzw); err != nil {
-               clog.FromContext(ctx).Errorf("failed to create cpio initramfs: 
%v", err)
-               return ref, err
-       }
-       if err := gzw.Close(); err != nil {
-               clog.FromContext(ctx).Errorf("failed to close gzip writer: %v", 
err)
-               return ref, err
+       // the uncompressed layer will be unpacked in a rootfs by the
+       // initramfs later
+       layerUncompress, err := layer.Uncompressed()
+       if err != nil {
+               return "", err
        }
+       _, err = io.Copy(guestRootfs, layerUncompress)
+       guestRootfs.Close()
 
-       return guestInitramfs.Name(), nil
+       return guestRootfs.Name(), nil
 }
 
 func (b qemuOCILoader) RemoveImage(ctx context.Context, ref string) error {
@@ -469,13 +455,6 @@
                return err
        }
 
-       // always be sure to create the VM rootfs first!
-       kernelPath, rootfsInitrdPath, err := getKernelPath(ctx, cfg)
-       if err != nil {
-               clog.FromContext(ctx).Errorf("could not prepare rootfs: %v", 
err)
-               return err
-       }
-
        baseargs := []string{}
        bios := false
        useVM := false
@@ -535,9 +514,6 @@
                }
        }
 
-       baseargs = append(baseargs, "-kernel", kernelPath)
-       baseargs = append(baseargs, "-initrd", rootfsInitrdPath)
-
        if cfg.Memory != "" {
                memKb, err := convertHumanToKB(cfg.Memory)
                if err != nil {
@@ -607,7 +583,7 @@
        // panic=-1 ensures that if the init fails, we immediately exit the 
machine
        // Add default SSH keys to the VM
        sshkey := base64.StdEncoding.EncodeToString(pubKey)
-       baseargs = append(baseargs, "-append", kernelConsole+" nomodeset 
panic=-1 sshkey="+sshkey)
+       baseargs = append(baseargs, "-append", kernelConsole+" nomodeset 
random.trust_cpu=on panic=-1 sshkey="+sshkey)
        // we will *not* mount workspace using qemu, this will use 9pfs which 
is network-based, and will
        // kill all performances (lots of small files)
        // instead we will copy back the finished workspace artifacts when done.
@@ -621,6 +597,21 @@
                cfg.Disk = defaultDiskSize
        }
 
+       kernelPath, err := getKernelPath(ctx, cfg)
+       if err != nil {
+               clog.FromContext(ctx).Errorf("could not prepare rootfs: %v", 
err)
+               return err
+       }
+
+       initramFile, err := generateCpio(ctx)
+       if err != nil {
+               clog.FromContext(ctx).Errorf("qemu: could not generate 
initramfs: %v", err)
+               return err
+       }
+
+       baseargs = append(baseargs, "-kernel", kernelPath)
+       baseargs = append(baseargs, "-initrd", initramFile)
+
        // if we want a disk, just add it, the init will mount it to the build 
home automatically
        diskFile, err := generateDiskFile(ctx, cfg.Disk)
        if err != nil {
@@ -628,12 +619,16 @@
                return err
        }
 
+       // save the disk name, we will wipe it off when done
+       cfg.Disk = diskFile
+
        // append raw disk, init will take care of formatting it if present.
        baseargs = append(baseargs, "-object", "iothread,id=io1")
        baseargs = append(baseargs, "-device", 
"virtio-blk-pci,drive=disk0,iothread=io1")
        baseargs = append(baseargs, "-drive", 
"if=none,id=disk0,cache=none,format=raw,aio=threads,werror=report,rerror=report,file="+diskFile)
-       // save the disk name, we will wipe it off when done
-       cfg.Disk = diskFile
+       // append the rootfs tar.gz, init will take care of populating the disk 
with it
+       baseargs = append(baseargs, "-device", 
"virtio-blk-pci,drive=image.tar,serial=input-tar,discard=true")
+       baseargs = append(baseargs, "-blockdev", 
"driver=raw,node-name=image.tar,file.driver=file,file.filename="+cfg.ImgRef)
 
        // qemu-system-x86_64 or qemu-system-aarch64...
        qemuCmd := exec.CommandContext(ctx, fmt.Sprintf("qemu-system-%s", 
cfg.Arch.ToAPK()), baseargs...)
@@ -729,12 +724,12 @@
                return fmt.Errorf("qemu: could not get VM host key")
        }
 
-       // default to root user but if a different user is specified
-       // we will use the embedded build:1000:1000 user
+       // default to root user, unless a different user is specified
        user := "root"
        if cfg.RunAs != "" {
-               user = "build"
+               user = cfg.RunAs
        }
+
        clog.FromContext(ctx).Info("qemu: setting up local workspace")
        return sendSSHCommand(ctx,
                user,
@@ -749,7 +744,7 @@
        )
 }
 
-func getKernelPath(ctx context.Context, cfg *Config) (string, string, error) {
+func getKernelPath(ctx context.Context, cfg *Config) (string, error) {
        clog.FromContext(ctx).Debug("qemu: setting up kernel for vm")
        kernel := "/boot/vmlinuz"
        if kernelVar, ok := os.LookupEnv("QEMU_KERNEL_IMAGE"); ok {
@@ -759,86 +754,10 @@
                        kernel = kernelVar
                }
        } else if _, err := os.Stat(kernel); err != nil {
-               return "", "", fmt.Errorf("qemu: /boot/vmlinuz not found, 
specify a kernel path with env variable QEMU_KERNEL_IMAGE and 
QEMU_KERNEL_MODULES if needed")
-       }
-
-       return kernel, cfg.ImgRef, nil
-}
-
-// in case of external modules (usually for 9p and virtio) we need a matching 
/lib/modules/kernel-$(uname)
-// we need to inject this directly into the initramfs cpio, as we cannot share 
them via 9p later.
-func injectKernelModules(ctx context.Context, rootfs v1.Layer, modulesPath 
string) (v1.Layer, error) {
-       clog.FromContext(ctx).Info("qemu: appending modules to initramfs")
-
-       // get tar layer, we will need to inject new files into it
-       uncompressed, err := rootfs.Uncompressed()
-       if err != nil {
-               return nil, err
-       }
-       defer uncompressed.Close()
-
-       // copy old tar layer into new tar
-       buf := new(bytes.Buffer)
-       tarWriter := tar.NewWriter(buf)
-       tartReader := tar.NewReader(uncompressed)
-
-       for {
-               header, err := tartReader.Next()
-               if err == io.EOF {
-                       break
-               }
-               if err != nil {
-                       return nil, err
-               }
-               if err := tarWriter.WriteHeader(header); err != nil {
-                       return nil, err
-               }
-               if _, err := io.Copy(tarWriter, tartReader); err != nil {
-                       return nil, err
-               }
-       }
-
-       // Walk through the input directory and add files to the tar archive
-       err = filepath.Walk(modulesPath, func(path string, info os.FileInfo, 
err error) error {
-               if err != nil {
-                       return err
-               }
-               if info.IsDir() {
-                       return nil
-               }
-
-               data, err := os.ReadFile(path)
-               if err != nil {
-                       return fmt.Errorf("failed to read file %s: %w", path, 
err)
-               }
-
-               header, err := tar.FileInfoHeader(info, path)
-               if err != nil {
-                       return fmt.Errorf("failed to create tar header for %s: 
%w", path, err)
-               }
-
-               header.Name = "/lib/modules/" + 
filepath.ToSlash(path[len(modulesPath):])
-               if err := tarWriter.WriteHeader(header); err != nil {
-                       return fmt.Errorf("failed to write tar header for %s: 
%w", path, err)
-               }
-
-               if _, err := tarWriter.Write(data); err != nil {
-                       return fmt.Errorf("failed to write file %s to tar: %w", 
path, err)
-               }
-
-               return nil
-       })
-       if err != nil {
-               return nil, err
-       }
-
-       opener := func() (io.ReadCloser, error) {
-               // Return a ReadCloser from the buffer
-               return io.NopCloser(bytes.NewReader(buf.Bytes())), nil
+               return "", fmt.Errorf("qemu: /boot/vmlinuz not found, specify a 
kernel path with env variable QEMU_KERNEL_IMAGE")
        }
 
-       // Create a layer from the Opener
-       return tarball.LayerFromOpener(opener)
+       return kernel, nil
 }
 
 func generateDiskFile(ctx context.Context, diskSize string) (string, error) {
@@ -878,14 +797,14 @@
 // this avoids the ssh client trying to connect on a booting server.
 func checkSSHServer(address string) error {
        // Establish a connection to the address
-       conn, err := net.DialTimeout("tcp", address, time.Second)
+       conn, err := net.DialTimeout("tcp", address, 50*time.Millisecond)
        if err != nil {
                return fmt.Errorf("dial: %w", err)
        }
        defer conn.Close()
 
        // Set a deadline for the connection
-       err = conn.SetDeadline(time.Now().Add(time.Second * 15))
+       err = conn.SetDeadline(time.Now().Add(time.Second))
        if err != nil {
                return err
        }
@@ -914,14 +833,20 @@
                return err
        }
 
+       // default to root user, unless a different user is specified
+       user := "root"
+       if cfg.RunAs != "" {
+               user = cfg.RunAs
+       }
+
        // Create SSH client configuration
        config := &ssh.ClientConfig{
-               User: "build",
+               User: user,
                Auth: []ssh.AuthMethod{
                        ssh.PublicKeys(signer),
                },
                Config: ssh.Config{
-                       Ciphers: []string{"aes128-ctr", 
"aes256-...@openssh.com"},
+                       Ciphers: []string{"aes128-...@openssh.com"},
                },
                HostKeyCallback: func(hostname string, remote net.Addr, key 
ssh.PublicKey) error {
                        hostKey = key
@@ -982,7 +907,7 @@
                        ssh.PublicKeys(signer),
                },
                Config: ssh.Config{
-                       Ciphers: []string{"aes128-ctr", 
"aes256-...@openssh.com"},
+                       Ciphers: []string{"aes128-...@openssh.com"},
                },
                HostKeyCallback: hostKeyCallback,
        }
@@ -1040,7 +965,7 @@
        clog.FromContext(ctx).Debugf("running (%d) %v", len(command), cmd)
        err = session.Run(cmd)
        if err != nil {
-               clog.FromContext(ctx).Errorf("Failed to run command: %v", err)
+               clog.FromContext(ctx).Errorf("Failed to run command %q as %q: 
%v", cmd, user, err)
                return err
        }
 
@@ -1188,3 +1113,176 @@
 
        return l.Addr().(*net.TCPAddr).Port, nil
 }
+
+func generateCpio(ctx context.Context) (string, error) {
+       /*
+        * we only build once, useful for local development, we
+        * cache it.
+        * if present, we nop and return, else we build it.
+        */
+       cacheDir, err := os.UserCacheDir()
+       if err != nil {
+               cacheDir = filepath.Join(
+                       "kernel",
+                       apko_types.Architecture(runtime.GOARCH).ToAPK())
+
+       }
+       cacheDir = filepath.Join(cacheDir, "melange-cpio")
+
+       initramfs := filepath.Join(
+               cacheDir,
+               "melange-guest.initramfs.cpio")
+       initramfsInfo, err := os.Stat(initramfs)
+
+       // if file is presend and less than 24h old, then we just reuse it
+       if err == nil && time.Since(initramfsInfo.ModTime()) < 24*time.Hour {
+               return initramfs, nil
+       }
+
+       clog.FromContext(ctx).Info("qemu: generating initramfs")
+
+       err = os.MkdirAll(cacheDir, os.ModePerm)
+       if err != nil {
+               return "", fmt.Errorf("unable to dest directory: %w", err)
+       }
+
+       spec := apko_types.ImageConfiguration{
+               Contents: apko_types.ImageContents{
+                       BuildRepositories: []string{
+                               "https://apk.cgr.dev/chainguard";,
+                       },
+                       Packages: []string{
+                               "microvm-init",
+                       },
+               },
+       }
+       opts := []apko_build.Option{apko_build.WithImageConfiguration(spec),
+               apko_build.WithArch(apko_types.Architecture(runtime.GOARCH)),
+       }
+
+       tmpDir, err := os.MkdirTemp("", "melange-guest-*.initramfs")
+       if err != nil {
+               return "", fmt.Errorf("unable to create build context: %w", err)
+       }
+       defer os.RemoveAll(tmpDir)
+
+       bc, err := apko_build.New(ctx, apkofs.DirFS(tmpDir, 
apkofs.WithCreateDir()), opts...)
+       if err != nil {
+               return "", fmt.Errorf("unable to create build context: %w", err)
+       }
+
+       bc.Summarize(ctx)
+       if err := bc.BuildImage(ctx); err != nil {
+               return "", fmt.Errorf("unable to generate image: %w", err)
+       }
+       layerTarGZ, layer, err := bc.ImageLayoutToLayer(ctx)
+       if err != nil {
+               return "", err
+       }
+       defer os.Remove(layerTarGZ)
+
+       log.Debugf("using %s for image layer", layerTarGZ)
+
+       // in case of some kernel images, we also need the /lib/modules 
directory to load
+       // necessary drivers, like 9p, virtio_net which are foundamental for 
the VM working.
+       if qemuModule, ok := os.LookupEnv("QEMU_KERNEL_MODULES"); ok {
+               clog.FromContext(ctx).Debugf("qemu: QEMU_KERNEL_MODULES env 
set, injecting modules in initramfs")
+               if _, err := os.Stat(qemuModule); err == nil {
+                       clog.FromContext(ctx).Debugf("qemu: local 
QEMU_KERNEL_MODULES dir detected, injecting")
+                       layer, err = injectKernelModules(ctx, layer, qemuModule)
+                       if err != nil {
+                               clog.FromContext(ctx).Errorf("qemu: could not 
inject needed kernel modules into initramfs: %v", err)
+                               return "", err
+                       }
+               }
+       }
+
+       guestInitramfs, err := os.Create(initramfs)
+       if err != nil {
+               clog.FromContext(ctx).Errorf("failed to create cpio initramfs: 
%v", err)
+               return "", err
+       }
+
+       if err := apko_cpio.FromLayer(layer, guestInitramfs); err != nil {
+               clog.FromContext(ctx).Errorf("failed to convert cpio initramfs: 
%v", err)
+               return "", err
+       }
+
+       return guestInitramfs.Name(), nil
+}
+
+// in case of external modules (usually for 9p and virtio) we need a matching 
/lib/modules/kernel-$(uname)
+// we need to inject this directly into the initramfs cpio, as we cannot share 
them via 9p later.
+func injectKernelModules(ctx context.Context, rootfs v1.Layer, modulesPath 
string) (v1.Layer, error) {
+       clog.FromContext(ctx).Info("qemu: appending modules to initramfs")
+
+       // get tar layer, we will need to inject new files into it
+       uncompressed, err := rootfs.Uncompressed()
+       if err != nil {
+               return nil, err
+       }
+       defer uncompressed.Close()
+
+       // copy old tar layer into new tar
+       buf := new(bytes.Buffer)
+       tarWriter := tar.NewWriter(buf)
+       tartReader := tar.NewReader(uncompressed)
+
+       for {
+               header, err := tartReader.Next()
+               if err == io.EOF {
+                       break
+               }
+               if err != nil {
+                       return nil, err
+               }
+               if err := tarWriter.WriteHeader(header); err != nil {
+                       return nil, err
+               }
+               if _, err := io.Copy(tarWriter, tartReader); err != nil {
+                       return nil, err
+               }
+       }
+
+       // Walk through the input directory and add files to the tar archive
+       err = filepath.Walk(modulesPath, func(path string, info os.FileInfo, 
err error) error {
+               if err != nil {
+                       return err
+               }
+               if info.IsDir() {
+                       return nil
+               }
+
+               data, err := os.ReadFile(path)
+               if err != nil {
+                       return fmt.Errorf("failed to read file %s: %w", path, 
err)
+               }
+
+               header, err := tar.FileInfoHeader(info, path)
+               if err != nil {
+                       return fmt.Errorf("failed to create tar header for %s: 
%w", path, err)
+               }
+
+               header.Name = "/lib/modules/" + 
filepath.ToSlash(path[len(modulesPath):])
+               if err := tarWriter.WriteHeader(header); err != nil {
+                       return fmt.Errorf("failed to write tar header for %s: 
%w", path, err)
+               }
+
+               if _, err := tarWriter.Write(data); err != nil {
+                       return fmt.Errorf("failed to write file %s to tar: %w", 
path, err)
+               }
+
+               return nil
+       })
+       if err != nil {
+               return nil, err
+       }
+
+       opener := func() (io.ReadCloser, error) {
+               // Return a ReadCloser from the buffer
+               return io.NopCloser(bytes.NewReader(buf.Bytes())), nil
+       }
+
+       // Create a layer from the Opener
+       return tarball.LayerFromOpener(opener)
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/melange-0.23.16/pkg/container/runner.go 
new/melange-0.23.17/pkg/container/runner.go
--- old/melange-0.23.16/pkg/container/runner.go 2025-05-08 19:18:19.000000000 
+0200
+++ new/melange-0.23.17/pkg/container/runner.go 2025-05-12 19:42:00.000000000 
+0200
@@ -43,7 +43,7 @@
        // WorkspaceTar returns an io.ReadCloser that can be used to read the 
status of the workspace.
        // The io.ReadCloser itself is a tar stream, which can be written to an 
io.Writer as is,
        // or passed to an fs.FS processor
-       WorkspaceTar(ctx context.Context, cfg *Config) (io.ReadCloser, error)
+       WorkspaceTar(ctx context.Context, cfg *Config, extraFiles []string) 
(io.ReadCloser, error)
 }
 
 type Loader interface {

++++++ melange.obsinfo ++++++
--- /var/tmp/diff_new_pack.CpuqtI/_old  2025-05-13 20:06:11.468650704 +0200
+++ /var/tmp/diff_new_pack.CpuqtI/_new  2025-05-13 20:06:11.472650872 +0200
@@ -1,5 +1,5 @@
 name: melange
-version: 0.23.16
-mtime: 1746724699
-commit: 5b4c1e4b78a5373233946c0d9c81442f85f45dad
+version: 0.23.17
+mtime: 1747071720
+commit: 76a4bd045fcad1727125b4ee7c12e97cf145c27c
 

++++++ vendor.tar.gz ++++++
/work/SRC/openSUSE:Factory/melange/vendor.tar.gz 
/work/SRC/openSUSE:Factory/.melange.new.30101/vendor.tar.gz differ: char 134, 
line 3

Reply via email to