mirror of
https://github.com/mudler/LocalAI.git
synced 2026-11-07 13:03:20 -05:00
feat(addons): add the host operation Authority interface
The broker, the supervisor and the manager each copy the grant map at start. An Authority answers what an add-on may call right now, so a later change can apply to the next call without a restart. Add the interface, the Reason type and EffectiveSet, with a static implementation over today's prefix map. Nothing uses it yet and behavior does not change. Assisted-by: Claude:claude-sonnet-5-5 go
This commit is contained in:
2 files changed
+134
No files matched your search
@@ -0,0 +1,101 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
package hostops
|
||||
|
||||
import (
|
||||
"slices"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// Reason says why Authority.Allows refused. It is for the log, the audit line
|
||||
// and the administrator pages. It never reaches an add-on: a refused call
|
||||
// answers the same text whatever the reason.
|
||||
type Reason string
|
||||
|
||||
const (
|
||||
// ReasonNone is the reason of an allowed call.
|
||||
ReasonNone Reason = ""
|
||||
// ReasonNotGranted means no source grants the operation.
|
||||
ReasonNotGranted Reason = "not_granted"
|
||||
// ReasonDeniedByPolicyFile means a deny rule of the policy file or flags
|
||||
// forbids the operation.
|
||||
ReasonDeniedByPolicyFile Reason = "denied_by_policy_file"
|
||||
// ReasonDeniedByAdmin means a deny rule an administrator set in the UI
|
||||
// forbids the operation.
|
||||
ReasonDeniedByAdmin Reason = "denied_by_admin"
|
||||
// ReasonIdentityMismatch means a grant exists but it belongs to another
|
||||
// package than the one installed under this add-on ID.
|
||||
ReasonIdentityMismatch Reason = "identity_mismatch"
|
||||
)
|
||||
|
||||
// Denied reports whether the reason is a deny rule, not a missing grant.
|
||||
func (r Reason) Denied() bool {
|
||||
return r == ReasonDeniedByPolicyFile || r == ReasonDeniedByAdmin
|
||||
}
|
||||
|
||||
// EffectiveSet is what one add-on may call at one revision of the grants. It
|
||||
// is a view for admission and for listings; the check of a call is
|
||||
// Authority.Allows.
|
||||
type EffectiveSet struct {
|
||||
// Revision is the revision of the grants the set was computed at. A static
|
||||
// authority has revision 0.
|
||||
Revision uint64
|
||||
// Prefixes are the operation prefixes the deployment grants (the policy
|
||||
// file floor), sorted.
|
||||
Prefixes []string
|
||||
// Operations are exact operation names granted through the UI store or a
|
||||
// blanket approval, sorted.
|
||||
Operations []string
|
||||
// Denied are the deny rules in force for the add-on, sorted. Each is a
|
||||
// prefix, a literal operation name or "*".
|
||||
Denied []string
|
||||
}
|
||||
|
||||
// Authority answers what an add-on may call right now. Safe for concurrent
|
||||
// use. The broker asks it on every call, so a change applies to the next call
|
||||
// and never to one that already runs.
|
||||
type Authority interface {
|
||||
// Allows reports whether the add-on may call op, and if not, why.
|
||||
Allows(addonID, op string) (ok bool, why Reason)
|
||||
// Snapshot returns the effective operations of an add-on and the revision
|
||||
// they were computed at. It is for admission and for the Apps listing.
|
||||
Snapshot(addonID string) EffectiveSet
|
||||
// Entitled reports whether the add-on holds any operation at all, so the
|
||||
// supervisor decides whether to open an endpoint.
|
||||
Entitled(addonID string) bool
|
||||
}
|
||||
|
||||
// staticAuthority is the Authority of a fixed prefix map: today's behavior.
|
||||
type staticAuthority struct{ prefixes map[string][]string }
|
||||
|
||||
// NewStaticAuthority builds an Authority over a fixed map of add-on ID to
|
||||
// operation prefixes. It copies the map. An empty prefix is ignored and an
|
||||
// add-on that is not listed holds nothing.
|
||||
func NewStaticAuthority(prefixes map[string][]string) Authority {
|
||||
out := make(map[string][]string, len(prefixes))
|
||||
for id, list := range prefixes {
|
||||
clean := make([]string, 0, len(list))
|
||||
for _, p := range list {
|
||||
if p != "" {
|
||||
clean = append(clean, p)
|
||||
}
|
||||
}
|
||||
if len(clean) > 0 {
|
||||
sort.Strings(clean)
|
||||
out[id] = clean
|
||||
}
|
||||
}
|
||||
return staticAuthority{prefixes: out}
|
||||
}
|
||||
|
||||
func (a staticAuthority) Allows(addonID, op string) (bool, Reason) {
|
||||
if hasPrefix(a.prefixes[addonID], op) {
|
||||
return true, ReasonNone
|
||||
}
|
||||
return false, ReasonNotGranted
|
||||
}
|
||||
|
||||
func (a staticAuthority) Snapshot(addonID string) EffectiveSet {
|
||||
return EffectiveSet{Prefixes: slices.Clone(a.prefixes[addonID])}
|
||||
}
|
||||
|
||||
func (a staticAuthority) Entitled(addonID string) bool { return len(a.prefixes[addonID]) > 0 }
|
||||
@@ -0,0 +1,33 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
package hostops
|
||||
|
||||
import (
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("static authority", func() {
|
||||
It("matches the prefix rule of the broker", func() {
|
||||
a := NewStaticAuthority(map[string][]string{"sandbox": {"workspace.", ""}, "x": {}})
|
||||
ok, why := a.Allows("sandbox", "workspace.commit")
|
||||
Expect(ok).To(BeTrue())
|
||||
Expect(why).To(Equal(ReasonNone))
|
||||
ok, why = a.Allows("sandbox", "egress.check")
|
||||
Expect(ok).To(BeFalse())
|
||||
Expect(why).To(Equal(ReasonNotGranted))
|
||||
ok, _ = a.Allows("other", "workspace.commit")
|
||||
Expect(ok).To(BeFalse())
|
||||
Expect(a.Entitled("sandbox")).To(BeTrue())
|
||||
Expect(a.Entitled("x")).To(BeFalse())
|
||||
Expect(a.Entitled("other")).To(BeFalse())
|
||||
Expect(a.Snapshot("sandbox").Prefixes).To(Equal([]string{"workspace."}))
|
||||
})
|
||||
It("does not follow later changes to the map it was built from", func() {
|
||||
in := map[string][]string{"a": {"workspace."}}
|
||||
a := NewStaticAuthority(in)
|
||||
in["a"][0] = "egress."
|
||||
delete(in, "a")
|
||||
ok, _ := a.Allows("a", "workspace.commit")
|
||||
Expect(ok).To(BeTrue())
|
||||
})
|
||||
})
|
||||
Reference in new issue
Block a user