mirror of
https://gitea.com/Lydanne/buildx.git
synced 2025-05-18 00:47:48 +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")
|
|
}
|