feat(addons): expose the trusted identity of an installed add-on

The Authority binds a grant to the identity of the installed package. It
runs inside admission, which holds the manager lock, so it needs a read
that does not take that lock. Keep the identities beside the completed
operations and update them when an operation applies.

Also export the check for the URL of the official library, which the
blanket approval needs to tell the official library from a source an
administrator named the same.

Assisted-by: Claude:claude-sonnet-5-5 go
This commit is contained in:
Ettore Di Giacinto committed 2026-11-03 22:06:43 +00:00
1 parent 112a753f06
commit f257406d5c
4 files changed
+75 -1

No files matched your search

+4
View File
@@ -73,6 +73,10 @@ func isOfficialAddonURL(url string) bool {
return ok && asset == OfficialReleaseAsset && releaseVersionRE.MatchString(version)
}
// IsOfficialAddonURL reports whether url is the index of the official add-on
// library that LocalAI itself ships: the master index or the index of a release.
func IsOfficialAddonURL(url string) bool { return isOfficialAddonURL(url) }
const (
// OfficialBackendLibraryID is the source ID of the backend library.
OfficialBackendLibraryID = "official-backends"
+32 -1
View File
@@ -121,7 +121,8 @@ func (m *Manager) markCompleted(operationID string) {
m.completed[operationID] = true
}
// rebuildCompleted reads the completed operations from the journal just loaded.
// rebuildCompleted reads the completed operations and the identities of the
// installed add-ons from the journal just loaded.
func (m *Manager) rebuildCompleted() {
m.grantsMu.Lock()
defer m.grantsMu.Unlock()
@@ -131,6 +132,36 @@ func (m *Manager) rebuildCompleted() {
m.completed[id] = true
}
}
m.identities = map[string]string{}
for id, st := range m.journal.Addons {
if st.Installed {
m.identities[id] = st.Identity
}
}
}
// TrustedIdentity returns the trusted identity of the installed package of an
// add-on, or empty when it is not installed. A grant of the owner is bound to
// it. Like OperationCompleted it never takes the manager lock, so an Authority
// may call it from inside a check that the manager makes under that lock.
func (m *Manager) TrustedIdentity(addonID string) string {
m.grantsMu.Lock()
defer m.grantsMu.Unlock()
return m.identities[addonID]
}
// noteIdentity records the identity an applied operation left behind.
func (m *Manager) noteIdentity(addonID string, st Status) {
m.grantsMu.Lock()
defer m.grantsMu.Unlock()
if m.identities == nil {
m.identities = map[string]string{}
}
if st.Installed {
m.identities[addonID] = st.Identity
return
}
delete(m.identities, addonID)
}
// pendingAuthority adds the operations an install or upgrade in flight is
+6
View File
@@ -172,6 +172,9 @@ type Manager struct {
pending map[string][]string
// completed holds the operations that completed; see OperationCompleted.
completed map[string]bool
// identities maps an installed add-on to its trusted identity; see
// TrustedIdentity.
identities map[string]string
}
// SetAuthority sets the Authority that admission and the apps list ask. The
@@ -816,6 +819,9 @@ func (m *Manager) apply(op journalOperation) (OperationStatus, error) {
m.journal.Operations[op.Command.OperationID] = op
e := m.persist(string(lifecycleCompleted))
if e == nil {
// The identity first: an entry whose operation completed must not meet
// an add-on the Authority does not know yet.
m.noteIdentity(op.Command.AddonID, m.journal.Addons[op.Command.AddonID])
m.markCompleted(op.Command.OperationID)
}
if e == nil && uninstall {
@@ -0,0 +1,33 @@
//go:build linux
// SPDX-License-Identifier: MIT
package addons
import (
"github.com/mudler/LocalAI/core/services/addons/catalog"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
var _ = Describe("trusted identity of an installed add-on", func() {
It("follows install and uninstall without the manager lock", func() {
r := newUpdateRig(false)
Expect(r.m.TrustedIdentity("sample")).To(BeEmpty())
r.lib.transform = nil
rel := r.lib.publish("1.2.3-dev", "development", "a", catalog.Requirements{})
r.lib.refresh()
_, e := r.m.Submit(ctx, actor, LifecycleCommand{OperationID: "i1", AddonID: "sample", Action: "install", SourceID: "test", Version: "development"})
Expect(e).NotTo(HaveOccurred(), rel.Digest)
Expect(r.m.TrustedIdentity("sample")).To(Equal("disk-one:sample"))
// The Authority calls it from inside admission, which holds the lock.
r.m.mu.Lock()
got := r.m.TrustedIdentity("sample")
r.m.mu.Unlock()
Expect(got).To(Equal("disk-one:sample"))
_, e = r.m.Submit(ctx, actor, LifecycleCommand{OperationID: "x1", AddonID: "sample", Action: "uninstall"})
Expect(e).NotTo(HaveOccurred())
Expect(r.m.TrustedIdentity("sample")).To(BeEmpty())
})
})