full diff: https://github.com/moby/buildkit/compare/v0.20.0-rc2...v0.20.0-rc3
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
| ... | ... |
@@ -63,7 +63,7 @@ require ( |
| 63 | 63 |
github.com/miekg/dns v1.1.61 |
| 64 | 64 |
github.com/mistifyio/go-zfs/v3 v3.0.1 |
| 65 | 65 |
github.com/mitchellh/copystructure v1.2.0 |
| 66 |
- github.com/moby/buildkit v0.20.0-rc2 |
|
| 66 |
+ github.com/moby/buildkit v0.20.0-rc3 |
|
| 67 | 67 |
github.com/moby/docker-image-spec v1.3.1 |
| 68 | 68 |
github.com/moby/ipvs v1.1.0 |
| 69 | 69 |
github.com/moby/locker v1.0.1 |
| ... | ... |
@@ -383,8 +383,8 @@ github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:F |
| 383 | 383 |
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= |
| 384 | 384 |
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= |
| 385 | 385 |
github.com/mndrix/tap-go v0.0.0-20171203230836-629fa407e90b/go.mod h1:pzzDgJWZ34fGzaAZGFW22KVZDfyrYW+QABMrWnJBnSs= |
| 386 |
-github.com/moby/buildkit v0.20.0-rc2 h1:QjACghvG0pSAp7dk9aQMYWioDEOljDWyyoUjyg35qfg= |
|
| 387 |
-github.com/moby/buildkit v0.20.0-rc2/go.mod h1:kMXf90l/f3zygRK8bYbyetfyzoJYntb6Bpi2VsLfXgQ= |
|
| 386 |
+github.com/moby/buildkit v0.20.0-rc3 h1:iExrfuZZuFgFudeNJhXfp/5vzJWTNrlqZ/LYJk4dG2Q= |
|
| 387 |
+github.com/moby/buildkit v0.20.0-rc3/go.mod h1:kMXf90l/f3zygRK8bYbyetfyzoJYntb6Bpi2VsLfXgQ= |
|
| 388 | 388 |
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= |
| 389 | 389 |
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= |
| 390 | 390 |
github.com/moby/ipvs v1.1.0 h1:ONN4pGaZQgAx+1Scz5RvWV4Q7Gb+mvfRh3NsPS+1XQQ= |
| ... | ... |
@@ -63,10 +63,6 @@ func getConfig(attrs map[string]string) (*Config, error) {
|
| 63 | 63 |
if !ok {
|
| 64 | 64 |
scope = "buildkit" |
| 65 | 65 |
} |
| 66 |
- url, ok := attrs[attrURL] |
|
| 67 |
- if !ok {
|
|
| 68 |
- return nil, errors.Errorf("url not set for github actions cache")
|
|
| 69 |
- } |
|
| 70 | 66 |
token, ok := attrs[attrToken] |
| 71 | 67 |
if !ok {
|
| 72 | 68 |
return nil, errors.Errorf("token not set for github actions cache")
|
| ... | ... |
@@ -80,12 +76,19 @@ func getConfig(attrs map[string]string) (*Config, error) {
|
| 80 | 80 |
} |
| 81 | 81 |
apiVersionInt = int(i) |
| 82 | 82 |
} |
| 83 |
+ var url string |
|
| 83 | 84 |
if apiVersionInt != 1 {
|
| 84 | 85 |
if v, ok := attrs[attrURLV2]; ok {
|
| 85 | 86 |
url = v |
| 86 | 87 |
apiVersionInt = 2 |
| 87 | 88 |
} |
| 88 | 89 |
} |
| 90 |
+ if v, ok := attrs[attrURL]; ok && url == "" {
|
|
| 91 |
+ url = v |
|
| 92 |
+ } |
|
| 93 |
+ if url == "" {
|
|
| 94 |
+ return nil, errors.Errorf("url not set for github actions cache")
|
|
| 95 |
+ } |
|
| 89 | 96 |
// best effort on old clients |
| 90 | 97 |
if apiVersionInt == 0 {
|
| 91 | 98 |
if strings.Contains(url, "results-receiver.actions.githubusercontent.com") {
|
| ... | ... |
@@ -7,6 +7,7 @@ import ( |
| 7 | 7 |
"io" |
| 8 | 8 |
"maps" |
| 9 | 9 |
"os" |
| 10 |
+ "slices" |
|
| 10 | 11 |
"strings" |
| 11 | 12 |
"time" |
| 12 | 13 |
|
| ... | ... |
@@ -24,7 +25,6 @@ import ( |
| 24 | 24 |
"github.com/moby/buildkit/solver/pb" |
| 25 | 25 |
spb "github.com/moby/buildkit/sourcepolicy/pb" |
| 26 | 26 |
"github.com/moby/buildkit/util/bklog" |
| 27 |
- "github.com/moby/buildkit/util/entitlements" |
|
| 28 | 27 |
ocispecs "github.com/opencontainers/image-spec/specs-go/v1" |
| 29 | 28 |
"github.com/pkg/errors" |
| 30 | 29 |
"github.com/tonistiigi/fsutil" |
| ... | ... |
@@ -45,7 +45,7 @@ type SolveOpt struct {
|
| 45 | 45 |
CacheExports []CacheOptionsEntry |
| 46 | 46 |
CacheImports []CacheOptionsEntry |
| 47 | 47 |
Session []session.Attachable |
| 48 |
- AllowedEntitlements []entitlements.Entitlement |
|
| 48 |
+ AllowedEntitlements []string |
|
| 49 | 49 |
SharedSession *session.Session // TODO: refactor to better session syncing |
| 50 | 50 |
SessionPreInitialized bool // TODO: refactor to better session syncing |
| 51 | 51 |
Internal bool |
| ... | ... |
@@ -277,7 +277,7 @@ func (c *Client) solve(ctx context.Context, def *llb.Definition, runGateway runG |
| 277 | 277 |
FrontendAttrs: frontendAttrs, |
| 278 | 278 |
FrontendInputs: frontendInputs, |
| 279 | 279 |
Cache: &cacheOpt.options, |
| 280 |
- Entitlements: entitlementsToPB(opt.AllowedEntitlements), |
|
| 280 |
+ Entitlements: slices.Clone(opt.AllowedEntitlements), |
|
| 281 | 281 |
Internal: opt.Internal, |
| 282 | 282 |
SourcePolicy: opt.SourcePolicy, |
| 283 | 283 |
}) |
| ... | ... |
@@ -553,11 +553,3 @@ func prepareMounts(opt *SolveOpt) (map[string]fsutil.FS, error) {
|
| 553 | 553 |
} |
| 554 | 554 |
return mounts, nil |
| 555 | 555 |
} |
| 556 |
- |
|
| 557 |
-func entitlementsToPB(entitlements []entitlements.Entitlement) []string {
|
|
| 558 |
- clone := make([]string, len(entitlements)) |
|
| 559 |
- for i, e := range entitlements {
|
|
| 560 |
- clone[i] = string(e) |
|
| 561 |
- } |
|
| 562 |
- return clone |
|
| 563 |
-} |
| ... | ... |
@@ -77,8 +77,9 @@ type OTELConfig struct {
|
| 77 | 77 |
} |
| 78 | 78 |
|
| 79 | 79 |
type CDIConfig struct {
|
| 80 |
- Disabled *bool `toml:"disabled"` |
|
| 81 |
- SpecDirs []string `toml:"specDirs"` |
|
| 80 |
+ Disabled *bool `toml:"disabled"` |
|
| 81 |
+ SpecDirs []string `toml:"specDirs"` |
|
| 82 |
+ AutoAllowed []string `toml:"autoAllowed"` |
|
| 82 | 83 |
} |
| 83 | 84 |
|
| 84 | 85 |
type GCConfig struct {
|
| ... | ... |
@@ -695,7 +695,7 @@ func toPBCDIDevices(manager *cdidevices.Manager) []*apitypes.CDIDevice {
|
| 695 | 695 |
for _, dev := range devs {
|
| 696 | 696 |
out = append(out, &apitypes.CDIDevice{
|
| 697 | 697 |
Name: dev.Name, |
| 698 |
- AutoAllow: true, // TODO |
|
| 698 |
+ AutoAllow: dev.AutoAllow, |
|
| 699 | 699 |
Annotations: dev.Annotations, |
| 700 | 700 |
OnDemand: dev.OnDemand, |
| 701 | 701 |
}) |
| ... | ... |
@@ -138,7 +138,7 @@ func (b *llbBridge) loadResult(ctx context.Context, def *pb.Definition, cacheImp |
| 138 | 138 |
} |
| 139 | 139 |
dpc := &detectPrunedCacheID{}
|
| 140 | 140 |
|
| 141 |
- edge, err := Load(ctx, def, polEngine, dpc.Load, ValidateEntitlements(ent), WithCacheSources(cms), NormalizeRuntimePlatforms(), WithValidateCaps()) |
|
| 141 |
+ edge, err := Load(ctx, def, polEngine, dpc.Load, ValidateEntitlements(ent, w.CDIManager()), WithCacheSources(cms), NormalizeRuntimePlatforms(), WithValidateCaps()) |
|
| 142 | 142 |
if err != nil {
|
| 143 | 143 |
return nil, errors.Wrap(err, "failed to load LLB") |
| 144 | 144 |
} |
| ... | ... |
@@ -2,6 +2,7 @@ package cdidevices |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 | 4 |
"context" |
| 5 |
+ "strconv" |
|
| 5 | 6 |
"strings" |
| 6 | 7 |
|
| 7 | 8 |
"github.com/moby/buildkit/solver/pb" |
| ... | ... |
@@ -13,7 +14,10 @@ import ( |
| 13 | 13 |
"tags.cncf.io/container-device-interface/pkg/parser" |
| 14 | 14 |
) |
| 15 | 15 |
|
| 16 |
-const deviceAnnotationClass = "org.mobyproject.buildkit.device.class" |
|
| 16 |
+const ( |
|
| 17 |
+ deviceAnnotationClass = "org.mobyproject.buildkit.device.class" |
|
| 18 |
+ deviceAnnotationAutoAllow = "org.mobyproject.buildkit.device.autoallow" |
|
| 19 |
+) |
|
| 17 | 20 |
|
| 18 | 21 |
var installers = map[string]Setup{}
|
| 19 | 22 |
|
| ... | ... |
@@ -35,17 +39,38 @@ type Device struct {
|
| 35 | 35 |
} |
| 36 | 36 |
|
| 37 | 37 |
type Manager struct {
|
| 38 |
- cache *cdi.Cache |
|
| 39 |
- locker *locker.Locker |
|
| 38 |
+ cache *cdi.Cache |
|
| 39 |
+ locker *locker.Locker |
|
| 40 |
+ autoAllowed map[string]struct{}
|
|
| 40 | 41 |
} |
| 41 | 42 |
|
| 42 |
-func NewManager(cache *cdi.Cache) *Manager {
|
|
| 43 |
+func NewManager(cache *cdi.Cache, autoAllowed []string) *Manager {
|
|
| 44 |
+ m := make(map[string]struct{})
|
|
| 45 |
+ for _, d := range autoAllowed {
|
|
| 46 |
+ m[d] = struct{}{}
|
|
| 47 |
+ } |
|
| 43 | 48 |
return &Manager{
|
| 44 |
- cache: cache, |
|
| 45 |
- locker: locker.New(), |
|
| 49 |
+ cache: cache, |
|
| 50 |
+ locker: locker.New(), |
|
| 51 |
+ autoAllowed: m, |
|
| 46 | 52 |
} |
| 47 | 53 |
} |
| 48 | 54 |
|
| 55 |
+func (m *Manager) isAutoAllowed(kind, name string, annotations map[string]string) bool {
|
|
| 56 |
+ if _, ok := m.autoAllowed[name]; ok {
|
|
| 57 |
+ return true |
|
| 58 |
+ } |
|
| 59 |
+ if _, ok := m.autoAllowed[kind]; ok {
|
|
| 60 |
+ return true |
|
| 61 |
+ } |
|
| 62 |
+ if v, ok := annotations[deviceAnnotationAutoAllow]; ok {
|
|
| 63 |
+ if b, err := strconv.ParseBool(v); err == nil && b {
|
|
| 64 |
+ return true |
|
| 65 |
+ } |
|
| 66 |
+ } |
|
| 67 |
+ return false |
|
| 68 |
+} |
|
| 69 |
+ |
|
| 49 | 70 |
func (m *Manager) ListDevices() []Device {
|
| 50 | 71 |
devs := m.cache.ListDevices() |
| 51 | 72 |
out := make([]Device, 0, len(devs)) |
| ... | ... |
@@ -53,10 +78,11 @@ func (m *Manager) ListDevices() []Device {
|
| 53 | 53 |
for _, dev := range devs {
|
| 54 | 54 |
kind, _, _ := strings.Cut(dev, "=") |
| 55 | 55 |
dd := m.cache.GetDevice(dev) |
| 56 |
+ annotations := deviceAnnotations(dd) |
|
| 56 | 57 |
out = append(out, Device{
|
| 57 | 58 |
Name: dev, |
| 58 |
- AutoAllow: true, // TODO |
|
| 59 |
- Annotations: deviceAnnotations(dd), |
|
| 59 |
+ AutoAllow: m.isAutoAllowed(kind, dev, annotations), |
|
| 60 |
+ Annotations: annotations, |
|
| 60 | 61 |
}) |
| 61 | 62 |
kinds[kind] = struct{}{}
|
| 62 | 63 |
} |
| ... | ... |
@@ -69,20 +95,31 @@ func (m *Manager) ListDevices() []Device {
|
| 69 | 69 |
continue |
| 70 | 70 |
} |
| 71 | 71 |
out = append(out, Device{
|
| 72 |
- Name: k, |
|
| 73 |
- OnDemand: true, |
|
| 72 |
+ Name: k, |
|
| 73 |
+ OnDemand: true, |
|
| 74 |
+ AutoAllow: true, |
|
| 74 | 75 |
}) |
| 75 | 76 |
} |
| 76 | 77 |
|
| 77 | 78 |
return out |
| 78 | 79 |
} |
| 79 | 80 |
|
| 81 |
+func (m *Manager) GetDevice(name string) Device {
|
|
| 82 |
+ kind, _, _ := strings.Cut(name, "=") |
|
| 83 |
+ annotations := deviceAnnotations(m.cache.GetDevice(name)) |
|
| 84 |
+ return Device{
|
|
| 85 |
+ Name: name, |
|
| 86 |
+ AutoAllow: m.isAutoAllowed(kind, name, annotations), |
|
| 87 |
+ Annotations: annotations, |
|
| 88 |
+ } |
|
| 89 |
+} |
|
| 90 |
+ |
|
| 80 | 91 |
func (m *Manager) Refresh() error {
|
| 81 | 92 |
return m.cache.Refresh() |
| 82 | 93 |
} |
| 83 | 94 |
|
| 84 | 95 |
func (m *Manager) InjectDevices(spec *specs.Spec, devs ...*pb.CDIDevice) error {
|
| 85 |
- pdevs, err := m.parseDevices(devs...) |
|
| 96 |
+ pdevs, err := m.FindDevices(devs...) |
|
| 86 | 97 |
if err != nil {
|
| 87 | 98 |
return err |
| 88 | 99 |
} else if len(pdevs) == 0 {
|
| ... | ... |
@@ -93,13 +130,17 @@ func (m *Manager) InjectDevices(spec *specs.Spec, devs ...*pb.CDIDevice) error {
|
| 93 | 93 |
return err |
| 94 | 94 |
} |
| 95 | 95 |
|
| 96 |
-func (m *Manager) parseDevices(devs ...*pb.CDIDevice) ([]string, error) {
|
|
| 96 |
+func (m *Manager) FindDevices(devs ...*pb.CDIDevice) ([]string, error) {
|
|
| 97 | 97 |
var out []string |
| 98 |
+ if len(devs) == 0 {
|
|
| 99 |
+ return out, nil |
|
| 100 |
+ } |
|
| 101 |
+ list := m.cache.ListDevices() |
|
| 98 | 102 |
for _, dev := range devs {
|
| 99 | 103 |
if dev == nil {
|
| 100 | 104 |
continue |
| 101 | 105 |
} |
| 102 |
- pdev, err := m.parseDevice(dev) |
|
| 106 |
+ pdev, err := m.parseDevice(dev, list) |
|
| 103 | 107 |
if err != nil {
|
| 104 | 108 |
return nil, err |
| 105 | 109 |
} else if len(pdev) == 0 {
|
| ... | ... |
@@ -110,7 +151,7 @@ func (m *Manager) parseDevices(devs ...*pb.CDIDevice) ([]string, error) {
|
| 110 | 110 |
return dedupSlice(out), nil |
| 111 | 111 |
} |
| 112 | 112 |
|
| 113 |
-func (m *Manager) parseDevice(dev *pb.CDIDevice) ([]string, error) {
|
|
| 113 |
+func (m *Manager) parseDevice(dev *pb.CDIDevice, all []string) ([]string, error) {
|
|
| 114 | 114 |
var out []string |
| 115 | 115 |
|
| 116 | 116 |
kind, name, _ := strings.Cut(dev.Name, "=") |
| ... | ... |
@@ -127,7 +168,7 @@ func (m *Manager) parseDevice(dev *pb.CDIDevice) ([]string, error) {
|
| 127 | 127 |
switch name {
|
| 128 | 128 |
case "": |
| 129 | 129 |
// first device of kind if no name is specified |
| 130 |
- for _, d := range m.cache.ListDevices() {
|
|
| 130 |
+ for _, d := range all {
|
|
| 131 | 131 |
if strings.HasPrefix(d, kind+"=") {
|
| 132 | 132 |
out = append(out, d) |
| 133 | 133 |
break |
| ... | ... |
@@ -135,14 +176,14 @@ func (m *Manager) parseDevice(dev *pb.CDIDevice) ([]string, error) {
|
| 135 | 135 |
} |
| 136 | 136 |
case "*": |
| 137 | 137 |
// all devices of kind if the name is a wildcard |
| 138 |
- for _, d := range m.cache.ListDevices() {
|
|
| 138 |
+ for _, d := range all {
|
|
| 139 | 139 |
if strings.HasPrefix(d, kind+"=") {
|
| 140 | 140 |
out = append(out, d) |
| 141 | 141 |
} |
| 142 | 142 |
} |
| 143 | 143 |
default: |
| 144 | 144 |
// the specified device |
| 145 |
- for _, d := range m.cache.ListDevices() {
|
|
| 145 |
+ for _, d := range all {
|
|
| 146 | 146 |
if d == dev.Name {
|
| 147 | 147 |
out = append(out, d) |
| 148 | 148 |
break |
| ... | ... |
@@ -150,7 +191,7 @@ func (m *Manager) parseDevice(dev *pb.CDIDevice) ([]string, error) {
|
| 150 | 150 |
} |
| 151 | 151 |
if len(out) == 0 {
|
| 152 | 152 |
// check class annotation if name unknown |
| 153 |
- for _, d := range m.cache.ListDevices() {
|
|
| 153 |
+ for _, d := range all {
|
|
| 154 | 154 |
if !strings.HasPrefix(d, kind+"=") {
|
| 155 | 155 |
continue |
| 156 | 156 |
} |
| ... | ... |
@@ -214,6 +255,9 @@ func (m *Manager) OnDemandInstaller(name string) (func(context.Context) error, b |
| 214 | 214 |
return errors.Wrapf(err, "failed to refresh CDI cache") |
| 215 | 215 |
} |
| 216 | 216 |
|
| 217 |
+ // TODO: this needs to be set as annotation to survive reboot |
|
| 218 |
+ m.autoAllowed[name] = struct{}{}
|
|
| 219 |
+ |
|
| 217 | 220 |
return nil |
| 218 | 221 |
}, true |
| 219 | 222 |
} |
| ... | ... |
@@ -1110,19 +1110,26 @@ func supportedEntitlements(ents []string) []entitlements.Entitlement {
|
| 1110 | 1110 |
if e == string(entitlements.EntitlementSecurityInsecure) {
|
| 1111 | 1111 |
out = append(out, entitlements.EntitlementSecurityInsecure) |
| 1112 | 1112 |
} |
| 1113 |
+ if e == string(entitlements.EntitlementDevice) {
|
|
| 1114 |
+ out = append(out, entitlements.EntitlementDevice) |
|
| 1115 |
+ } |
|
| 1113 | 1116 |
} |
| 1114 | 1117 |
return out |
| 1115 | 1118 |
} |
| 1116 | 1119 |
|
| 1117 | 1120 |
func loadEntitlements(b solver.Builder) (entitlements.Set, error) {
|
| 1118 |
- var ent entitlements.Set = map[entitlements.Entitlement]struct{}{}
|
|
| 1121 |
+ var ent entitlements.Set = map[entitlements.Entitlement]entitlements.EntitlementsConfig{}
|
|
| 1119 | 1122 |
err := b.EachValue(context.TODO(), keyEntitlements, func(v interface{}) error {
|
| 1120 | 1123 |
set, ok := v.(entitlements.Set) |
| 1121 | 1124 |
if !ok {
|
| 1122 | 1125 |
return errors.Errorf("invalid entitlements %T", v)
|
| 1123 | 1126 |
} |
| 1124 |
- for k := range set {
|
|
| 1125 |
- ent[k] = struct{}{}
|
|
| 1127 |
+ for k, v := range set {
|
|
| 1128 |
+ if prev, ok := ent[k]; ok && prev != nil {
|
|
| 1129 |
+ prev.Merge(v) |
|
| 1130 |
+ } else {
|
|
| 1131 |
+ ent[k] = v |
|
| 1132 |
+ } |
|
| 1126 | 1133 |
} |
| 1127 | 1134 |
return nil |
| 1128 | 1135 |
}) |
| ... | ... |
@@ -7,6 +7,7 @@ import ( |
| 7 | 7 |
|
| 8 | 8 |
"github.com/containerd/platforms" |
| 9 | 9 |
"github.com/moby/buildkit/solver" |
| 10 |
+ "github.com/moby/buildkit/solver/llbsolver/cdidevices" |
|
| 10 | 11 |
"github.com/moby/buildkit/solver/llbsolver/ops/opsutils" |
| 11 | 12 |
"github.com/moby/buildkit/solver/pb" |
| 12 | 13 |
"github.com/moby/buildkit/util/apicaps" |
| ... | ... |
@@ -109,7 +110,7 @@ func NormalizeRuntimePlatforms() LoadOpt {
|
| 109 | 109 |
} |
| 110 | 110 |
} |
| 111 | 111 |
|
| 112 |
-func ValidateEntitlements(ent entitlements.Set) LoadOpt {
|
|
| 112 |
+func ValidateEntitlements(ent entitlements.Set, cdiManager *cdidevices.Manager) LoadOpt {
|
|
| 113 | 113 |
return func(op *pb.Op, _ *pb.OpMetadata, opt *solver.VertexOptions) error {
|
| 114 | 114 |
switch op := op.Op.(type) {
|
| 115 | 115 |
case *pb.Op_Exec: |
| ... | ... |
@@ -120,6 +121,75 @@ func ValidateEntitlements(ent entitlements.Set) LoadOpt {
|
| 120 | 120 |
if err := ent.Check(v); err != nil {
|
| 121 | 121 |
return err |
| 122 | 122 |
} |
| 123 |
+ if device := op.Exec.CdiDevices; len(device) > 0 {
|
|
| 124 |
+ var cfg *entitlements.DevicesConfig |
|
| 125 |
+ if ent, ok := ent[entitlements.EntitlementDevice]; ok {
|
|
| 126 |
+ cfg, ok = ent.(*entitlements.DevicesConfig) |
|
| 127 |
+ if !ok {
|
|
| 128 |
+ return errors.Errorf("invalid device entitlement config %T", ent)
|
|
| 129 |
+ } |
|
| 130 |
+ } |
|
| 131 |
+ if cfg != nil && cfg.All {
|
|
| 132 |
+ return nil |
|
| 133 |
+ } |
|
| 134 |
+ |
|
| 135 |
+ var allowedDevices []*pb.CDIDevice |
|
| 136 |
+ var nonAliasedDevices []*pb.CDIDevice |
|
| 137 |
+ if cfg != nil {
|
|
| 138 |
+ for _, d := range op.Exec.CdiDevices {
|
|
| 139 |
+ if newName, ok := cfg.Devices[d.Name]; ok && newName != "" {
|
|
| 140 |
+ d.Name = newName |
|
| 141 |
+ allowedDevices = append(allowedDevices, d) |
|
| 142 |
+ } else {
|
|
| 143 |
+ nonAliasedDevices = append(nonAliasedDevices, d) |
|
| 144 |
+ } |
|
| 145 |
+ } |
|
| 146 |
+ } else {
|
|
| 147 |
+ nonAliasedDevices = op.Exec.CdiDevices |
|
| 148 |
+ } |
|
| 149 |
+ |
|
| 150 |
+ mountedDevices, err := cdiManager.FindDevices(nonAliasedDevices...) |
|
| 151 |
+ if err != nil {
|
|
| 152 |
+ return err |
|
| 153 |
+ } |
|
| 154 |
+ if len(mountedDevices) == 0 {
|
|
| 155 |
+ op.Exec.CdiDevices = allowedDevices |
|
| 156 |
+ return nil |
|
| 157 |
+ } |
|
| 158 |
+ |
|
| 159 |
+ grantedDevices := make(map[string]struct{})
|
|
| 160 |
+ if cfg != nil {
|
|
| 161 |
+ for d := range cfg.Devices {
|
|
| 162 |
+ resolved, err := cdiManager.FindDevices(&pb.CDIDevice{Name: d})
|
|
| 163 |
+ if err != nil {
|
|
| 164 |
+ return err |
|
| 165 |
+ } |
|
| 166 |
+ for _, r := range resolved {
|
|
| 167 |
+ grantedDevices[r] = struct{}{}
|
|
| 168 |
+ } |
|
| 169 |
+ } |
|
| 170 |
+ } |
|
| 171 |
+ |
|
| 172 |
+ var forbidden []string |
|
| 173 |
+ for _, d := range mountedDevices {
|
|
| 174 |
+ if _, ok := grantedDevices[d]; !ok {
|
|
| 175 |
+ if dev := cdiManager.GetDevice(d); !dev.AutoAllow {
|
|
| 176 |
+ forbidden = append(forbidden, d) |
|
| 177 |
+ continue |
|
| 178 |
+ } |
|
| 179 |
+ } |
|
| 180 |
+ allowedDevices = append(allowedDevices, &pb.CDIDevice{Name: d})
|
|
| 181 |
+ } |
|
| 182 |
+ |
|
| 183 |
+ if len(forbidden) > 0 {
|
|
| 184 |
+ if len(forbidden) == 1 {
|
|
| 185 |
+ return errors.Errorf("device %s is requested by the build but not allowed", forbidden[0])
|
|
| 186 |
+ } |
|
| 187 |
+ return errors.Errorf("devices %s are requested by the build but not allowed", strings.Join(forbidden, ", "))
|
|
| 188 |
+ } |
|
| 189 |
+ |
|
| 190 |
+ op.Exec.CdiDevices = allowedDevices |
|
| 191 |
+ } |
|
| 123 | 192 |
} |
| 124 | 193 |
return nil |
| 125 | 194 |
} |
| ... | ... |
@@ -1,31 +1,119 @@ |
| 1 | 1 |
package entitlements |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
+ "strings" |
|
| 5 |
+ |
|
| 4 | 6 |
"github.com/pkg/errors" |
| 7 |
+ "github.com/tonistiigi/go-csvvalue" |
|
| 5 | 8 |
) |
| 6 | 9 |
|
| 7 | 10 |
type Entitlement string |
| 8 | 11 |
|
| 12 |
+func (e Entitlement) String() string {
|
|
| 13 |
+ return string(e) |
|
| 14 |
+} |
|
| 15 |
+ |
|
| 9 | 16 |
const ( |
| 10 | 17 |
EntitlementSecurityInsecure Entitlement = "security.insecure" |
| 11 | 18 |
EntitlementNetworkHost Entitlement = "network.host" |
| 19 |
+ EntitlementDevice Entitlement = "device" |
|
| 12 | 20 |
) |
| 13 | 21 |
|
| 14 | 22 |
var all = map[Entitlement]struct{}{
|
| 15 | 23 |
EntitlementSecurityInsecure: {},
|
| 16 | 24 |
EntitlementNetworkHost: {},
|
| 25 |
+ EntitlementDevice: {},
|
|
| 26 |
+} |
|
| 27 |
+ |
|
| 28 |
+type EntitlementsConfig interface {
|
|
| 29 |
+ Merge(EntitlementsConfig) error |
|
| 17 | 30 |
} |
| 18 | 31 |
|
| 19 |
-func Parse(s string) (Entitlement, error) {
|
|
| 32 |
+type DevicesConfig struct {
|
|
| 33 |
+ Devices map[string]string |
|
| 34 |
+ All bool |
|
| 35 |
+} |
|
| 36 |
+ |
|
| 37 |
+var _ EntitlementsConfig = &DevicesConfig{}
|
|
| 38 |
+ |
|
| 39 |
+func ParseDevicesConfig(s string) (*DevicesConfig, error) {
|
|
| 40 |
+ if s == "" {
|
|
| 41 |
+ return &DevicesConfig{All: true}, nil
|
|
| 42 |
+ } |
|
| 43 |
+ |
|
| 44 |
+ fields, err := csvvalue.Fields(s, nil) |
|
| 45 |
+ if err != nil {
|
|
| 46 |
+ return nil, err |
|
| 47 |
+ } |
|
| 48 |
+ deviceName := fields[0] |
|
| 49 |
+ var deviceAlias string |
|
| 50 |
+ |
|
| 51 |
+ for _, field := range fields[1:] {
|
|
| 52 |
+ k, v, ok := strings.Cut(field, "=") |
|
| 53 |
+ if !ok {
|
|
| 54 |
+ return nil, errors.Errorf("invalid device config %q", field)
|
|
| 55 |
+ } |
|
| 56 |
+ switch k {
|
|
| 57 |
+ case "alias": |
|
| 58 |
+ deviceAlias = v |
|
| 59 |
+ default: |
|
| 60 |
+ return nil, errors.Errorf("unknown device config key %q", k)
|
|
| 61 |
+ } |
|
| 62 |
+ } |
|
| 63 |
+ |
|
| 64 |
+ cfg := &DevicesConfig{Devices: map[string]string{}}
|
|
| 65 |
+ |
|
| 66 |
+ if deviceAlias != "" {
|
|
| 67 |
+ cfg.Devices[deviceAlias] = deviceName |
|
| 68 |
+ } else {
|
|
| 69 |
+ cfg.Devices[deviceName] = "" |
|
| 70 |
+ } |
|
| 71 |
+ return cfg, nil |
|
| 72 |
+} |
|
| 73 |
+ |
|
| 74 |
+func (c *DevicesConfig) Merge(in EntitlementsConfig) error {
|
|
| 75 |
+ c2, ok := in.(*DevicesConfig) |
|
| 76 |
+ if !ok {
|
|
| 77 |
+ return errors.Errorf("cannot merge %T into %T", in, c)
|
|
| 78 |
+ } |
|
| 79 |
+ |
|
| 80 |
+ if c2.All {
|
|
| 81 |
+ c.All = true |
|
| 82 |
+ return nil |
|
| 83 |
+ } |
|
| 84 |
+ |
|
| 85 |
+ for k, v := range c2.Devices {
|
|
| 86 |
+ if c.Devices == nil {
|
|
| 87 |
+ c.Devices = map[string]string{}
|
|
| 88 |
+ } |
|
| 89 |
+ c.Devices[k] = v |
|
| 90 |
+ } |
|
| 91 |
+ return nil |
|
| 92 |
+} |
|
| 93 |
+ |
|
| 94 |
+func Parse(s string) (Entitlement, EntitlementsConfig, error) {
|
|
| 95 |
+ var cfg EntitlementsConfig |
|
| 96 |
+ key, rest, _ := strings.Cut(s, "=") |
|
| 97 |
+ switch Entitlement(key) {
|
|
| 98 |
+ case EntitlementDevice: |
|
| 99 |
+ s = key |
|
| 100 |
+ var err error |
|
| 101 |
+ cfg, err = ParseDevicesConfig(rest) |
|
| 102 |
+ if err != nil {
|
|
| 103 |
+ return "", nil, err |
|
| 104 |
+ } |
|
| 105 |
+ default: |
|
| 106 |
+ } |
|
| 107 |
+ |
|
| 20 | 108 |
_, ok := all[Entitlement(s)] |
| 21 | 109 |
if !ok {
|
| 22 |
- return "", errors.Errorf("unknown entitlement %s", s)
|
|
| 110 |
+ return "", nil, errors.Errorf("unknown entitlement %s", s)
|
|
| 23 | 111 |
} |
| 24 |
- return Entitlement(s), nil |
|
| 112 |
+ return Entitlement(s), cfg, nil |
|
| 25 | 113 |
} |
| 26 | 114 |
|
| 27 | 115 |
func WhiteList(allowed, supported []Entitlement) (Set, error) {
|
| 28 |
- m := map[Entitlement]struct{}{}
|
|
| 116 |
+ m := map[Entitlement]EntitlementsConfig{}
|
|
| 29 | 117 |
|
| 30 | 118 |
var supm Set |
| 31 | 119 |
if supported != nil {
|
| ... | ... |
@@ -37,7 +125,7 @@ func WhiteList(allowed, supported []Entitlement) (Set, error) {
|
| 37 | 37 |
} |
| 38 | 38 |
|
| 39 | 39 |
for _, e := range allowed {
|
| 40 |
- e, err := Parse(string(e)) |
|
| 40 |
+ e, cfg, err := Parse(string(e)) |
|
| 41 | 41 |
if err != nil {
|
| 42 | 42 |
return nil, err |
| 43 | 43 |
} |
| ... | ... |
@@ -46,13 +134,19 @@ func WhiteList(allowed, supported []Entitlement) (Set, error) {
|
| 46 | 46 |
return nil, errors.Errorf("granting entitlement %s is not allowed by build daemon configuration", e)
|
| 47 | 47 |
} |
| 48 | 48 |
} |
| 49 |
- m[e] = struct{}{}
|
|
| 49 |
+ if prev, ok := m[e]; ok && prev != nil {
|
|
| 50 |
+ if err := prev.Merge(cfg); err != nil {
|
|
| 51 |
+ return nil, err |
|
| 52 |
+ } |
|
| 53 |
+ } else {
|
|
| 54 |
+ m[e] = cfg |
|
| 55 |
+ } |
|
| 50 | 56 |
} |
| 51 | 57 |
|
| 52 | 58 |
return Set(m), nil |
| 53 | 59 |
} |
| 54 | 60 |
|
| 55 |
-type Set map[Entitlement]struct{}
|
|
| 61 |
+type Set map[Entitlement]EntitlementsConfig |
|
| 56 | 62 |
|
| 57 | 63 |
func (s Set) Allowed(e Entitlement) bool {
|
| 58 | 64 |
_, ok := s[e] |
| ... | ... |
@@ -77,4 +171,5 @@ func (s Set) Check(v Values) error {
|
| 77 | 77 |
type Values struct {
|
| 78 | 78 |
NetworkHost bool |
| 79 | 79 |
SecurityInsecure bool |
| 80 |
+ Devices map[string]struct{}
|
|
| 80 | 81 |
} |
| ... | ... |
@@ -755,7 +755,7 @@ github.com/mitchellh/hashstructure/v2 |
| 755 | 755 |
# github.com/mitchellh/reflectwalk v1.0.2 |
| 756 | 756 |
## explicit |
| 757 | 757 |
github.com/mitchellh/reflectwalk |
| 758 |
-# github.com/moby/buildkit v0.20.0-rc2 |
|
| 758 |
+# github.com/moby/buildkit v0.20.0-rc3 |
|
| 759 | 759 |
## explicit; go 1.22.0 |
| 760 | 760 |
github.com/moby/buildkit/api/services/control |
| 761 | 761 |
github.com/moby/buildkit/api/types |