Skip to content

Commit

Permalink
fix: Use correct key for setting main build context
Browse files Browse the repository at this point in the history
The signer implementation was not using standard docker keys for setting
the main build context, this made it so you can't use signers as
standalone frontends executing by `docker build`.

This is a breaking change as anything implementing a signer will need to
be updated to use the correct key.

Signed-off-by: Brian Goff <cpuguy83@gmail.com>
  • Loading branch information
cpuguy83 authored and engelbot committed Nov 12, 2024
1 parent 97bffce commit f68f5a6
Show file tree
Hide file tree
Showing 9 changed files with 221 additions and 93 deletions.
2 changes: 1 addition & 1 deletion frontend/azlinux/handle_rpm.go
Original file line number Diff line number Diff line change
Expand Up @@ -254,5 +254,5 @@ func specToRpmLLB(ctx context.Context, w worker, client gwclient.Client, spec *d
builder := base.With(dalec.SetBuildNetworkMode(spec))
st := rpm.Build(br, builder, specPath, opts...)

return frontend.MaybeSign(ctx, client, st, spec, targetKey, sOpt)
return frontend.MaybeSign(ctx, client, st, spec, targetKey, sOpt, opts...)
}
2 changes: 1 addition & 1 deletion frontend/jammy/handle_deb.go
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ func buildDeb(ctx context.Context, client gwclient.Client, spec *dalec.Spec, sOp
return llb.Scratch(), err
}

signed, err := frontend.MaybeSign(ctx, client, st, spec, targetKey, sOpt)
signed, err := frontend.MaybeSign(ctx, client, st, spec, targetKey, sOpt, opts...)
if err != nil {
return llb.Scratch(), err
}
Expand Down
37 changes: 16 additions & 21 deletions frontend/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package frontend

import (
"context"
"fmt"
"strconv"

"github.com/Azure/dalec"
Expand Down Expand Up @@ -141,9 +140,9 @@ func marshalDockerfile(ctx context.Context, dt []byte, opts ...llb.ConstraintsOp
return st.Marshal(ctx)
}

func getSigningConfigFromContext(ctx context.Context, client gwclient.Client, cfgPath string, configCtxName string, sOpt dalec.SourceOpts) (*dalec.PackageSigner, error) {
func getSigningConfigFromContext(ctx context.Context, client gwclient.Client, cfgPath string, configCtxName string, sOpt dalec.SourceOpts, opts ...llb.ConstraintsOpt) (*dalec.PackageSigner, error) {
sc := dalec.SourceContext{Name: configCtxName}
signConfigState, err := sc.AsState(cfgPath, []string{cfgPath}, nil, sOpt)
signConfigState, err := sc.AsState(cfgPath, []string{cfgPath}, nil, sOpt, opts...)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -180,7 +179,7 @@ func getSigningConfigFromContext(ctx context.Context, client gwclient.Client, cf
return pc.Signer, nil
}

func MaybeSign(ctx context.Context, client gwclient.Client, st llb.State, spec *dalec.Spec, targetKey string, sOpt dalec.SourceOpts) (llb.State, error) {
func MaybeSign(ctx context.Context, client gwclient.Client, st llb.State, spec *dalec.Spec, targetKey string, sOpt dalec.SourceOpts, opts ...llb.ConstraintsOpt) (llb.State, error) {
if signingDisabled(client) {
Warnf(ctx, client, st, "Signing disabled by build-arg %q", keySkipSigningArg)
return st, nil
Expand All @@ -198,7 +197,7 @@ func MaybeSign(ctx context.Context, client gwclient.Client, st llb.State, spec *
Warnf(ctx, client, st, "Root signing spec overridden by target signing spec: target %q", targetKey)
}

return forwardToSigner(ctx, client, cfg, st)
return forwardToSigner(ctx, client, cfg, st, opts...)
}

configCtxName := getSignContextNameWithDefault(client)
Expand All @@ -211,7 +210,7 @@ func MaybeSign(ctx context.Context, client gwclient.Client, st llb.State, spec *
return llb.Scratch(), err
}

return forwardToSigner(ctx, client, cfg, st)
return forwardToSigner(ctx, client, cfg, st, opts...)
}

func getSignContextNameWithDefault(client gwclient.Client) string {
Expand Down Expand Up @@ -245,21 +244,20 @@ func getSignConfigCtxName(client gwclient.Client) string {
return client.BuildOpts().Opts["build-arg:"+buildArgDalecSigningConfigContextName]
}

func forwardToSigner(ctx context.Context, client gwclient.Client, cfg *dalec.PackageSigner, s llb.State) (llb.State, error) {
func forwardToSigner(ctx context.Context, client gwclient.Client, cfg *dalec.PackageSigner, s llb.State, opts ...llb.ConstraintsOpt) (llb.State, error) {
const (
sourceKey = "source"
contextKey = "context"
inputKey = "input"
// See https://github.com/moby/buildkit/blob/d8d946b85c52095d34a52ce210960832f4e06775/frontend/dockerui/context.go#L29
contextKey = "contextkey"
)

opts := client.BuildOpts().Opts
bopts := client.BuildOpts().Opts

req, err := newSolveRequest(toFrontend(cfg.Frontend), withBuildArgs(cfg.Args))
if err != nil {
return llb.Scratch(), err
}

for k, v := range opts {
for k, v := range bopts {
if k == "source" || k == "cmdline" {
continue
}
Expand All @@ -282,18 +280,19 @@ func forwardToSigner(ctx context.Context, client gwclient.Client, cfg *dalec.Pac
}
req.FrontendInputs = m

stateDef, err := s.Marshal(ctx)
opts = append(opts, dalec.ProgressGroup("Sign package"))
stateDef, err := s.Marshal(ctx, opts...)
if err != nil {
return llb.Scratch(), err
}

req.FrontendOpt[contextKey] = compound(inputKey, contextKey)
req.FrontendInputs[contextKey] = stateDef.ToPB()
req.FrontendOpt["dalec.target"] = opts["dalec.target"]
req.FrontendOpt[contextKey] = dockerui.DefaultLocalNameContext
req.FrontendInputs[dockerui.DefaultLocalNameContext] = stateDef.ToPB()
req.FrontendOpt["dalec.target"] = bopts["dalec.target"]

res, err := client.Solve(ctx, req)
if err != nil {
return llb.Scratch(), err
return llb.Scratch(), errors.Wrap(err, "error signing packages")
}

ref, err := res.SingleRef()
Expand All @@ -303,7 +302,3 @@ func forwardToSigner(ctx context.Context, client gwclient.Client, cfg *dalec.Pac

return ref.ToState()
}

func compound(k, v string) string {
return fmt.Sprintf("%s:%s", k, v)
}
10 changes: 6 additions & 4 deletions frontend/windows/handle_zip.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func handleZip(ctx context.Context, client gwclient.Client) (*gwclient.Result, e
return nil, nil, fmt.Errorf("unable to build binaries: %w", err)
}

st := getZipLLB(worker, spec.Name, bin)
st := getZipLLB(worker, spec.Name, bin, pg)

def, err := st.Marshal(ctx)
if err != nil {
Expand Down Expand Up @@ -82,7 +82,7 @@ func specToSourcesLLB(worker llb.State, spec *dalec.Spec, sOpt dalec.SourceOpts,
return out, nil
}

func installBuildDeps(sOpt dalec.SourceOpts, spec *dalec.Spec, targetKey string) llb.StateOption {
func installBuildDeps(sOpt dalec.SourceOpts, spec *dalec.Spec, targetKey string, opts ...llb.ConstraintsOpt) llb.StateOption {

return func(in llb.State) llb.State {
deps := spec.GetBuildDeps(targetKey)
Expand All @@ -102,7 +102,7 @@ func installBuildDeps(sOpt dalec.SourceOpts, spec *dalec.Spec, targetKey string)
Description: "Build dependencies for " + spec.Name,
}

opts := []llb.ConstraintsOpt{dalec.WithConstraint(c)}
opts = append(opts, dalec.WithConstraint(c))

srcPkg, err := deb.SourcePackage(sOpt, in, depsSpec, targetKey, "", opts...)
if err != nil {
Expand Down Expand Up @@ -224,12 +224,13 @@ func buildBinaries(ctx context.Context, spec *dalec.Spec, worker llb.State, clie
return frontend.MaybeSign(ctx, client, st, spec, targetKey, sOpt)
}

func getZipLLB(worker llb.State, name string, artifacts llb.State) llb.State {
func getZipLLB(worker llb.State, name string, artifacts llb.State, opts ...llb.ConstraintsOpt) llb.State {
outName := filepath.Join(outputDir, name+".zip")
zipped := worker.Run(
dalec.ShArgs("zip "+outName+" *"),
llb.Dir("/tmp/artifacts"),
llb.AddMount("/tmp/artifacts", artifacts),
dalec.WithConstraints(opts...),
).AddMount(outputDir, llb.Scratch())
return zipped
}
Expand Down Expand Up @@ -266,6 +267,7 @@ func workerImg(sOpt dalec.SourceOpts, opts ...llb.ConstraintsOpt) (llb.State, er
return llb.Image(workerImgRef, llb.WithMetaResolver(sOpt.Resolver), dalec.WithConstraints(opts...)).Run(
dalec.ShArgs("apt-get update && apt-get install -y build-essential binutils-mingw-w64 g++-mingw-w64-x86-64 gcc git make pkg-config quilt zip aptitude dpkg-dev debhelper-compat="+deb.DebHelperCompat),
dalec.WithMountedAptCache(aptCachePrefix),
dalec.WithConstraints(opts...),
).
// This file prevents installation of things like docs in ubuntu
// containers We don't want to exclude this because tests want to
Expand Down
35 changes: 31 additions & 4 deletions test/azlinux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ func TestMariner2(t *testing.T) {
FormatDepEqual: func(v, _ string) string {
return v
},
ListExpectedSignFiles: azlinuxListSignFiles("cm2"),
},
LicenseDir: "/usr/share/licenses",
SystemdDir: struct {
Expand Down Expand Up @@ -86,9 +87,10 @@ func TestAzlinux3(t *testing.T) {
ctx := startTestSpan(baseCtx, t)
testLinuxDistro(ctx, t, testLinuxConfig{
Target: targetConfig{
Package: "azlinux3/rpm",
Container: "azlinux3/container",
Worker: "azlinux3/worker",
Package: "azlinux3/rpm",
Container: "azlinux3/container",
Worker: "azlinux3/worker",
ListExpectedSignFiles: azlinuxListSignFiles("azl3"),
},
LicenseDir: "/usr/share/licenses",
SystemdDir: struct {
Expand All @@ -112,6 +114,27 @@ func TestAzlinux3(t *testing.T) {
})
}

func azlinuxListSignFiles(ver string) func(*dalec.Spec, ocispecs.Platform) []string {
return func(spec *dalec.Spec, platform ocispecs.Platform) []string {
base := fmt.Sprintf("%s-%s-%s.%s", spec.Name, spec.Version, spec.Revision, ver)

var arch string
switch platform.Architecture {
case "amd64":
arch = "x86_64"
case "arm64":
arch = "aarch64"
default:
arch = platform.Architecture
}

return []string{
filepath.Join("SRPMS", fmt.Sprintf("%s.src.rpm", base)),
filepath.Join("RPMS", arch, fmt.Sprintf("%s.%s.rpm", base, arch)),
}
}
}

func signRepoAzLinux(gpgKey llb.State) llb.StateOption {
// key should be a state that has a public key under /public.key
return func(in llb.State) llb.State {
Expand Down Expand Up @@ -196,6 +219,10 @@ type targetConfig struct {
// what is neccessary for the target distro to set a dependency for an equals
// operator.
FormatDepEqual func(ver, rev string) string

// Given a spec, list all files (including the full path) that are expected
// to be sent to be signed.
ListExpectedSignFiles func(*dalec.Spec, ocispecs.Platform) []string
}

type testLinuxConfig struct {
Expand Down Expand Up @@ -519,7 +546,7 @@ echo "$BAR" > bar.txt
})
})

t.Run("test signing", linuxSigningTests(ctx, testConfig))
t.Run("signing", linuxSigningTests(ctx, testConfig))

t.Run("test systemd unit single", func(t *testing.T) {
t.Parallel()
Expand Down
57 changes: 39 additions & 18 deletions test/fixtures/signer/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,18 @@ import (
_ "embed"
"encoding/json"
"fmt"
"io/fs"
"os"
"strings"

"github.com/Azure/dalec/frontend"
"github.com/Azure/dalec/frontend/pkg/bkfs"
"github.com/moby/buildkit/client/llb"
"github.com/moby/buildkit/frontend/dockerui"
gwclient "github.com/moby/buildkit/frontend/gateway/client"
"github.com/moby/buildkit/frontend/gateway/grpcclient"
"github.com/moby/buildkit/util/appcontext"
"github.com/moby/buildkit/util/bklog"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"google.golang.org/grpc/grpclog"
)
Expand All @@ -28,11 +31,6 @@ func main() {
bopts := c.BuildOpts().Opts
target := bopts["dalec.target"]

inputs, err := c.Inputs(ctx)
if err != nil {
return nil, err
}

type config struct {
OS string
}
Expand All @@ -46,33 +44,56 @@ func main() {
cfg.OS = "linux"
}

curFrontend, ok := c.(frontend.CurrentFrontend)
if !ok {
return nil, fmt.Errorf("cast to currentFrontend failed")
dc, err := dockerui.NewClient(c)
if err != nil {
return nil, err
}

basePtr, err := curFrontend.CurrentFrontend()
if err != nil || basePtr == nil {
if err == nil {
err = fmt.Errorf("base frontend ptr was nil")
}
bctx, err := dc.MainContext(ctx)
if err != nil {
return nil, err
}

inputId := strings.TrimPrefix(bopts["context"], "input:")
_, ok = inputs[inputId]
if !ok {
if bctx == nil {
return nil, fmt.Errorf("no artifact state provided to signer")
}

artifactsFS, err := bkfs.FromState(ctx, bctx, c)
if err != nil {
return nil, err
}

configBytes, err := json.Marshal(&cfg)
if err != nil {
return nil, err
}

var files []string
err = fs.WalkDir(artifactsFS, ".", func(p string, info fs.DirEntry, err error) error {
if err != nil {
return err
}

if info.IsDir() {
return nil
}

files = append(files, p)
return nil
})
if err != nil {
return nil, errors.Wrap(err, "error walking artifacts")
}

mfst, err := json.Marshal(files)
if err != nil {
return nil, errors.Wrap(err, "error marshalling file manifest")
}

output := llb.Scratch().
File(llb.Mkfile("/target", 0o600, []byte(target))).
File(llb.Mkfile("/config.json", 0o600, configBytes))
File(llb.Mkfile("/config.json", 0o600, configBytes)).
File(llb.Mkfile("/manifest.json", 0o600, mfst))

// For any build-arg seen, write a file to /env/<KEY> with the contents
// being the value of the arg.
Expand Down
21 changes: 21 additions & 0 deletions test/jammy_test.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package test

import (
"fmt"
"testing"

"github.com/Azure/dalec"
"github.com/Azure/dalec/frontend/jammy"
"github.com/moby/buildkit/client/llb"
ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
)

func signRepoJammy(gpgKey llb.State) llb.StateOption {
Expand Down Expand Up @@ -51,6 +53,25 @@ func TestJammy(t *testing.T) {
FormatDepEqual: func(ver, rev string) string {
return ver + "-ubuntu22.04u" + rev
},
ListExpectedSignFiles: func(spec *dalec.Spec, platform ocispecs.Platform) []string {
base := fmt.Sprintf("%s_%s-%su%s", spec.Name, spec.Version, "ubuntu22.04", spec.Revision)
sourceBase := fmt.Sprintf("%s_%s.orig", spec.Name, spec.Version)

out := []string{
base + ".debian.tar.xz",
base + ".dsc",
fmt.Sprintf("%s_%s.deb", base, platform.Architecture),
base + "_source.buildinfo",
base + "_source.changes",
sourceBase + ".tar.xz",
}

for src := range spec.Sources {
out = append(out, fmt.Sprintf("%s-%s.tar.gz", sourceBase, src))
}

return out
},
},
LicenseDir: "/usr/share/doc",
SystemdDir: struct {
Expand Down
Loading

0 comments on commit f68f5a6

Please sign in to comment.