From 8a78f99525a9b8054202568ccb2b245909280fa9 Mon Sep 17 00:00:00 2001 From: Ettore Di Giacinto Date: Tue, 3 Nov 2026 21:34:21 +0000 Subject: [PATCH] feat(addons): describe each host operation in plain words The install dialog and the host access page need a title, one sentence and a risk word for each operation an add-on may ask for. Add DescribeOperation next to the supported list, and a test that fails when an operation has no description. Assisted-by: Claude:claude-sonnet-5-5 go --- core/services/addons/hostops/describe.go | 50 +++++++++++++++++++ core/services/addons/hostops/describe_test.go | 22 ++++++++ 2 files changed, 72 insertions(+) create mode 100644 core/services/addons/hostops/describe.go create mode 100644 core/services/addons/hostops/describe_test.go diff --git a/core/services/addons/hostops/describe.go b/core/services/addons/hostops/describe.go new file mode 100644 index 0000000000..c6c48bfe43 --- /dev/null +++ b/core/services/addons/hostops/describe.go @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: MIT +package hostops + +// Risk words of a host operation, for the dialogs that ask an administrator to +// allow it. +const ( + RiskRead = "read" + RiskChangesData = "changes data" + RiskNetwork = "network" + RiskRunsJobs = "runs jobs" +) + +type description struct{ title, text, risk string } + +var descriptions = map[string]description{ + "finetune.start": {"Start fine-tuning", "Start fine-tuning jobs on this server's engines.", RiskRunsJobs}, + "finetune.stop": {"Stop fine-tuning", "Stop fine-tuning jobs.", RiskRunsJobs}, + "finetune.get": {"Read a fine-tuning job", "Read the state of a fine-tuning job.", RiskRead}, + "finetune.list": {"List fine-tuning jobs", "List fine-tuning jobs.", RiskRead}, + "finetune.checkpoints": {"List checkpoints", "Read the checkpoints of fine-tuning jobs.", RiskRead}, + "finetune.progress": {"Read job progress", "Read the progress of fine-tuning jobs.", RiskRead}, + "finetune.dataset": {"Prepare datasets", "Prepare datasets for fine-tuning.", RiskChangesData}, + "finetune.export": {"Export a trained model", "Export a trained model into the model store.", RiskChangesData}, + "quantize.start": {"Start quantization", "Start quantization jobs.", RiskRunsJobs}, + "quantize.stop": {"Stop quantization", "Stop quantization jobs.", RiskRunsJobs}, + "quantize.get": {"Read a quantization job", "Read the state of a quantization job.", RiskRead}, + "quantize.list": {"List quantization jobs", "List quantization jobs.", RiskRead}, + "quantize.progress": {"Read job progress", "Read the progress of quantization jobs.", RiskRead}, + "quantize.import": {"Import a quantized model", "Import a quantized result into the model store.", RiskChangesData}, + "workspace.materialize": {"Copy workspace files", "Copy files of a chat's workspace into the add-on's working area.", RiskChangesData}, + "workspace.commit": {"Write results back", "Write results from the add-on's working area back to a chat's workspace.", RiskChangesData}, + "workspace.import": {"Import workspace files", "Bring files into a chat's workspace.", RiskChangesData}, + "workspace.export": {"Export workspace files", "Take files out of a chat's workspace.", RiskChangesData}, + "workspace.changes": {"See workspace changes", "See which files of a chat's workspace changed.", RiskRead}, + "workspace.admin": {"Check for an administrator", "Ask whether the current person is an administrator, for the add-on's settings.", RiskRead}, + "egress.check": {"Check network access", "Ask the host whether a network connection is allowed.", RiskNetwork}, + "egress.audit": {"Record network decisions", "Record the decision about a network connection in the audit log.", RiskNetwork}, + "connector.inbound": {"Receive messages", "Let a connector hand incoming messages from outside to a chat.", RiskNetwork}, + "connector.file.put": {"Receive files", "Move files from a connector into chats.", RiskChangesData}, + "connector.file.get": {"Send files", "Move files from chats to a connector.", RiskChangesData}, +} + +// DescribeOperation gives the short title, one plain sentence and the risk word of a +// host operation, for the install dialog and the host access page. ok is +// false for a name the host does not register. A test fails when a supported +// operation has no description. +func DescribeOperation(op string) (title, text, risk string, ok bool) { + d, ok := descriptions[op] + return d.title, d.text, d.risk, ok +} diff --git a/core/services/addons/hostops/describe_test.go b/core/services/addons/hostops/describe_test.go new file mode 100644 index 0000000000..414e42c6cb --- /dev/null +++ b/core/services/addons/hostops/describe_test.go @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: MIT +package hostops + +import ( + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +var _ = Describe("DescribeOperation", func() { + It("describes every supported operation, and only those", func() { + for _, op := range SupportedOperations() { + title, text, risk, ok := DescribeOperation(op) + Expect(ok).To(BeTrue(), op) + Expect(title).ToNot(BeEmpty(), op) + Expect(text).To(HaveSuffix("."), op) + Expect(risk).To(BeElementOf(RiskRead, RiskChangesData, RiskNetwork, RiskRunsJobs), op) + } + Expect(descriptions).To(HaveLen(len(SupportedOperations()))) + _, _, _, ok := DescribeOperation("not.registered") + Expect(ok).To(BeFalse()) + }) +})