mirror of
				https://gitea.com/Lydanne/buildx.git
				synced 2025-11-04 01:53:42 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			176 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			176 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package bake
 | 
						|
 | 
						|
import (
 | 
						|
	"bufio"
 | 
						|
	"context"
 | 
						|
	"fmt"
 | 
						|
	"io"
 | 
						|
	"os"
 | 
						|
	"slices"
 | 
						|
	"strings"
 | 
						|
 | 
						|
	"github.com/containerd/console"
 | 
						|
	"github.com/docker/buildx/build"
 | 
						|
	"github.com/moby/buildkit/util/entitlements"
 | 
						|
	"github.com/pkg/errors"
 | 
						|
)
 | 
						|
 | 
						|
type EntitlementKey string
 | 
						|
 | 
						|
const (
 | 
						|
	EntitlementKeyNetworkHost      EntitlementKey = "network.host"
 | 
						|
	EntitlementKeySecurityInsecure EntitlementKey = "security.insecure"
 | 
						|
	EntitlementKeyFSRead           EntitlementKey = "fs.read"
 | 
						|
	EntitlementKeyFSWrite          EntitlementKey = "fs.write"
 | 
						|
	EntitlementKeyFS               EntitlementKey = "fs"
 | 
						|
	EntitlementKeyImagePush        EntitlementKey = "image.push"
 | 
						|
	EntitlementKeyImageLoad        EntitlementKey = "image.load"
 | 
						|
	EntitlementKeyImage            EntitlementKey = "image"
 | 
						|
	EntitlementKeySSH              EntitlementKey = "ssh"
 | 
						|
)
 | 
						|
 | 
						|
type EntitlementConf struct {
 | 
						|
	NetworkHost      bool
 | 
						|
	SecurityInsecure bool
 | 
						|
	FSRead           []string
 | 
						|
	FSWrite          []string
 | 
						|
	ImagePush        []string
 | 
						|
	ImageLoad        []string
 | 
						|
	SSH              bool
 | 
						|
}
 | 
						|
 | 
						|
func ParseEntitlements(in []string) (EntitlementConf, error) {
 | 
						|
	var conf EntitlementConf
 | 
						|
	for _, e := range in {
 | 
						|
		switch e {
 | 
						|
		case string(EntitlementKeyNetworkHost):
 | 
						|
			conf.NetworkHost = true
 | 
						|
		case string(EntitlementKeySecurityInsecure):
 | 
						|
			conf.SecurityInsecure = true
 | 
						|
		case string(EntitlementKeySSH):
 | 
						|
			conf.SSH = true
 | 
						|
		default:
 | 
						|
			k, v, _ := strings.Cut(e, "=")
 | 
						|
			switch k {
 | 
						|
			case string(EntitlementKeyFSRead):
 | 
						|
				conf.FSRead = append(conf.FSRead, v)
 | 
						|
			case string(EntitlementKeyFSWrite):
 | 
						|
				conf.FSWrite = append(conf.FSWrite, v)
 | 
						|
			case string(EntitlementKeyFS):
 | 
						|
				conf.FSRead = append(conf.FSRead, v)
 | 
						|
				conf.FSWrite = append(conf.FSWrite, v)
 | 
						|
			case string(EntitlementKeyImagePush):
 | 
						|
				conf.ImagePush = append(conf.ImagePush, v)
 | 
						|
			case string(EntitlementKeyImageLoad):
 | 
						|
				conf.ImageLoad = append(conf.ImageLoad, v)
 | 
						|
			case string(EntitlementKeyImage):
 | 
						|
				conf.ImagePush = append(conf.ImagePush, v)
 | 
						|
				conf.ImageLoad = append(conf.ImageLoad, v)
 | 
						|
			default:
 | 
						|
				return conf, errors.Errorf("uknown entitlement key %q", k)
 | 
						|
			}
 | 
						|
 | 
						|
			// TODO: dedupe slices and parent paths
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return conf, nil
 | 
						|
}
 | 
						|
 | 
						|
func (c EntitlementConf) Validate(m map[string]build.Options) (EntitlementConf, error) {
 | 
						|
	var expected EntitlementConf
 | 
						|
 | 
						|
	for _, v := range m {
 | 
						|
		if err := c.check(v, &expected); err != nil {
 | 
						|
			return EntitlementConf{}, err
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return expected, nil
 | 
						|
}
 | 
						|
 | 
						|
func (c EntitlementConf) check(bo build.Options, expected *EntitlementConf) error {
 | 
						|
	for _, e := range bo.Allow {
 | 
						|
		switch e {
 | 
						|
		case entitlements.EntitlementNetworkHost:
 | 
						|
			if !c.NetworkHost {
 | 
						|
				expected.NetworkHost = true
 | 
						|
			}
 | 
						|
		case entitlements.EntitlementSecurityInsecure:
 | 
						|
			if !c.SecurityInsecure {
 | 
						|
				expected.SecurityInsecure = true
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (c EntitlementConf) Prompt(ctx context.Context, out io.Writer) error {
 | 
						|
	var term bool
 | 
						|
	if _, err := console.ConsoleFromFile(os.Stdin); err == nil {
 | 
						|
		term = true
 | 
						|
	}
 | 
						|
 | 
						|
	var msgs []string
 | 
						|
	var flags []string
 | 
						|
 | 
						|
	if c.NetworkHost {
 | 
						|
		msgs = append(msgs, " - Running build containers that can access host network")
 | 
						|
		flags = append(flags, "network.host")
 | 
						|
	}
 | 
						|
	if c.SecurityInsecure {
 | 
						|
		msgs = append(msgs, " - Running privileged containers that can make system changes")
 | 
						|
		flags = append(flags, "security.insecure")
 | 
						|
	}
 | 
						|
 | 
						|
	if len(msgs) == 0 {
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
 | 
						|
	fmt.Fprintf(out, "Your build is requesting privileges for following possibly insecure capabilities:\n\n")
 | 
						|
	for _, m := range msgs {
 | 
						|
		fmt.Fprintf(out, "%s\n", m)
 | 
						|
	}
 | 
						|
 | 
						|
	for i, f := range flags {
 | 
						|
		flags[i] = "--allow=" + f
 | 
						|
	}
 | 
						|
 | 
						|
	if term {
 | 
						|
		fmt.Fprintf(out, "\nIn order to not see this message in the future pass %q to grant requested privileges.\n", strings.Join(flags, " "))
 | 
						|
	} else {
 | 
						|
		fmt.Fprintf(out, "\nPass %q to grant requested privileges.\n", strings.Join(flags, " "))
 | 
						|
	}
 | 
						|
 | 
						|
	args := append([]string(nil), os.Args...)
 | 
						|
	if v, ok := os.LookupEnv("DOCKER_CLI_PLUGIN_ORIGINAL_CLI_COMMAND"); ok && v != "" {
 | 
						|
		args[0] = v
 | 
						|
	}
 | 
						|
	idx := slices.Index(args, "bake")
 | 
						|
 | 
						|
	if idx != -1 {
 | 
						|
		fmt.Fprintf(out, "\nYour full command with requested privileges:\n\n")
 | 
						|
		fmt.Fprintf(out, "%s %s %s\n\n", strings.Join(args[:idx+1], " "), strings.Join(flags, " "), strings.Join(args[idx+1:], " "))
 | 
						|
	}
 | 
						|
 | 
						|
	if term {
 | 
						|
		fmt.Fprintf(out, "Do you want to grant requested privileges and continue? [y/N] ")
 | 
						|
		reader := bufio.NewReader(os.Stdin)
 | 
						|
		answerCh := make(chan string, 1)
 | 
						|
		go func() {
 | 
						|
			answer, _, _ := reader.ReadLine()
 | 
						|
			answerCh <- string(answer)
 | 
						|
			close(answerCh)
 | 
						|
		}()
 | 
						|
 | 
						|
		select {
 | 
						|
		case <-ctx.Done():
 | 
						|
		case answer := <-answerCh:
 | 
						|
			if strings.ToLower(string(answer)) == "y" {
 | 
						|
				return nil
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return errors.Errorf("additional privileges requested")
 | 
						|
}
 |