Skip to content

build: install a pre-resolved package list from supplied contents - #2448

Merged
mattmoor merged 1 commit into
chainguard-dev:mainfrom
mattmoor:pre-resolved-packages
Aug 31, 2026
Merged

build: install a pre-resolved package list from supplied contents#2448
mattmoor merged 1 commit into
chainguard-dev:mainfrom
mattmoor:pre-resolved-packages

Conversation

@mattmoor

Copy link
Copy Markdown
Member

InstallPackageContents installs exactly a caller-supplied, pre-settled package list from its contents — no index is consulted, no dependency resolution happens, and nothing is fetched; the package checksum is derived from each carrier's control section (its SHA1, by definition). The installed-database tail is shared with InstallPackages via recordInstalled, so both installers write the database through one code path.

build.WithPreResolvedPackages exposes this to image builds as a third way to satisfy the configured world, beside the existing lockfile path and FixateWorld: the configuration's package list still names the requested world; the option settles how it is satisfied. Downstream callers can then carry package contents in forms of their own choosing without apko learning those forms.

InstallPackageContents installs exactly a caller-supplied, pre-settled
package list from its contents — no index is consulted, no dependency
resolution happens, and nothing is fetched; the package checksum is
derived from each carrier's control section (its SHA1, by definition).
The installed-database tail is shared with InstallPackages via
recordInstalled, so both installers write the database through one code
path.

build.WithPreResolvedPackages exposes this to image builds as a third
way to satisfy the configured world, beside the existing lockfile path
and FixateWorld: the configuration's package list still names the
requested world; the option settles how it is satisfied. Downstream
callers can then carry package contents in forms of their own choosing
without apko learning those forms.
@mattmoor
mattmoor enabled auto-merge (squash) August 31, 2026 16:07
)
if bc.o.Lockfile != "" {
switch {
case len(bc.o.PreResolvedPackages) > 0:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we distinguish an explicitly supplied empty set from an absent option here? WithPreResolvedPackages([]) promises to install precisely that set without consulting indexes, but len == 0 falls through to the lockfile or FixateWorld path. An empty resolved world therefore still fetches and resolves repositories (and can fail offline) instead of performing a zero-package install.

Comment thread pkg/build/options.go
// world (written to /etc/apk/world); this option settles how it is satisfied.
func WithPreResolvedPackages(contents []apk.PackageContents) Option {
return func(bc *Context) error {
bc.o.PreResolvedPackages = contents

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about NewMultiArch callers? It reuses this same option for every architecture, so one contents slice is installed into every target context. InstallPackageContents does not compare PackageInfo.Arch with the context architecture, which lets an x86_64 slice be installed into the aarch64 image without an error. Could we key these contents by architecture, or reject incompatible multi-architecture use?

@mattmoor
mattmoor merged commit 94dfda0 into chainguard-dev:main Aug 31, 2026
26 checks passed
@mattmoor
mattmoor deleted the pre-resolved-packages branch August 31, 2026 16:49
@mattmoor

Copy link
Copy Markdown
Member Author

I have claude looking into the comments to follow up, since this auto-merged.

mattmoor added a commit that referenced this pull request Aug 31, 2026
#2449)

…h contents

Two follow-ups to the pre-resolved install path (#2448):

An explicitly empty set fell through to the lockfile or FixateWorld
branch, so WithPreResolvedPackages([]) — a promise to install precisely
nothing without consulting an index — still resolved repositories and
could fail offline. The option now distinguishes set-but-empty from
unset (nil normalizes to empty; the options field documents nil as
unset), and buildImage branches on presence rather than length. The test
proves it by contradiction: against a repository that cannot satisfy
anything, the control build fails to resolve and the empty-set build
succeeds with zero packages installed.

A multi-arch build reuses one option set for every architecture context,
so contents for the wrong architecture arrived at InstallPackageContents
silently and installed foreign binaries without an error. The installer
now refuses contents whose .PKGINFO architecture disagrees with the
context (noarch and unstated architectures still install everywhere).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants