mirror of
https://gitea.com/Lydanne/buildx.git
synced 2025-05-18 00:47:48 +08:00

Allow access to CDI Devices in Buildkit v0.20.0+ for devices that are not automatically allowed to be used by everyone in BuildKit configuration. Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com> Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
176 lines
3.4 KiB
Go
176 lines
3.4 KiB
Go
package entitlements
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"github.com/pkg/errors"
|
|
"github.com/tonistiigi/go-csvvalue"
|
|
)
|
|
|
|
type Entitlement string
|
|
|
|
func (e Entitlement) String() string {
|
|
return string(e)
|
|
}
|
|
|
|
const (
|
|
EntitlementSecurityInsecure Entitlement = "security.insecure"
|
|
EntitlementNetworkHost Entitlement = "network.host"
|
|
EntitlementDevice Entitlement = "device"
|
|
)
|
|
|
|
var all = map[Entitlement]struct{}{
|
|
EntitlementSecurityInsecure: {},
|
|
EntitlementNetworkHost: {},
|
|
EntitlementDevice: {},
|
|
}
|
|
|
|
type EntitlementsConfig interface {
|
|
Merge(EntitlementsConfig) error
|
|
}
|
|
|
|
type DevicesConfig struct {
|
|
Devices map[string]string
|
|
All bool
|
|
}
|
|
|
|
var _ EntitlementsConfig = &DevicesConfig{}
|
|
|
|
func ParseDevicesConfig(s string) (*DevicesConfig, error) {
|
|
if s == "" {
|
|
return &DevicesConfig{All: true}, nil
|
|
}
|
|
|
|
fields, err := csvvalue.Fields(s, nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
deviceName := fields[0]
|
|
var deviceAlias string
|
|
|
|
for _, field := range fields[1:] {
|
|
k, v, ok := strings.Cut(field, "=")
|
|
if !ok {
|
|
return nil, errors.Errorf("invalid device config %q", field)
|
|
}
|
|
switch k {
|
|
case "alias":
|
|
deviceAlias = v
|
|
default:
|
|
return nil, errors.Errorf("unknown device config key %q", k)
|
|
}
|
|
}
|
|
|
|
cfg := &DevicesConfig{Devices: map[string]string{}}
|
|
|
|
if deviceAlias != "" {
|
|
cfg.Devices[deviceAlias] = deviceName
|
|
} else {
|
|
cfg.Devices[deviceName] = ""
|
|
}
|
|
return cfg, nil
|
|
}
|
|
|
|
func (c *DevicesConfig) Merge(in EntitlementsConfig) error {
|
|
c2, ok := in.(*DevicesConfig)
|
|
if !ok {
|
|
return errors.Errorf("cannot merge %T into %T", in, c)
|
|
}
|
|
|
|
if c2.All {
|
|
c.All = true
|
|
return nil
|
|
}
|
|
|
|
for k, v := range c2.Devices {
|
|
if c.Devices == nil {
|
|
c.Devices = map[string]string{}
|
|
}
|
|
c.Devices[k] = v
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func Parse(s string) (Entitlement, EntitlementsConfig, error) {
|
|
var cfg EntitlementsConfig
|
|
key, rest, _ := strings.Cut(s, "=")
|
|
switch Entitlement(key) {
|
|
case EntitlementDevice:
|
|
s = key
|
|
var err error
|
|
cfg, err = ParseDevicesConfig(rest)
|
|
if err != nil {
|
|
return "", nil, err
|
|
}
|
|
default:
|
|
}
|
|
|
|
_, ok := all[Entitlement(s)]
|
|
if !ok {
|
|
return "", nil, errors.Errorf("unknown entitlement %s", s)
|
|
}
|
|
return Entitlement(s), cfg, nil
|
|
}
|
|
|
|
func WhiteList(allowed, supported []Entitlement) (Set, error) {
|
|
m := map[Entitlement]EntitlementsConfig{}
|
|
|
|
var supm Set
|
|
if supported != nil {
|
|
var err error
|
|
supm, err = WhiteList(supported, nil)
|
|
if err != nil { // should not happen
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
for _, e := range allowed {
|
|
e, cfg, err := Parse(string(e))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if supported != nil {
|
|
if !supm.Allowed(e) {
|
|
return nil, errors.Errorf("granting entitlement %s is not allowed by build daemon configuration", e)
|
|
}
|
|
}
|
|
if prev, ok := m[e]; ok && prev != nil {
|
|
if err := prev.Merge(cfg); err != nil {
|
|
return nil, err
|
|
}
|
|
} else {
|
|
m[e] = cfg
|
|
}
|
|
}
|
|
|
|
return Set(m), nil
|
|
}
|
|
|
|
type Set map[Entitlement]EntitlementsConfig
|
|
|
|
func (s Set) Allowed(e Entitlement) bool {
|
|
_, ok := s[e]
|
|
return ok
|
|
}
|
|
|
|
func (s Set) Check(v Values) error {
|
|
if v.NetworkHost {
|
|
if !s.Allowed(EntitlementNetworkHost) {
|
|
return errors.Errorf("%s is not allowed", EntitlementNetworkHost)
|
|
}
|
|
}
|
|
|
|
if v.SecurityInsecure {
|
|
if !s.Allowed(EntitlementSecurityInsecure) {
|
|
return errors.Errorf("%s is not allowed", EntitlementSecurityInsecure)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type Values struct {
|
|
NetworkHost bool
|
|
SecurityInsecure bool
|
|
Devices map[string]struct{}
|
|
}
|