Merge remote-tracking branch 'origin/main' into feature/svc-plugin-host-options
ci / vet-and-test (pull_request) Successful in 1m2s
ci / vet-and-test (pull_request) Successful in 1m2s
Co-authored-by: Cursor <cursoragent@cursor.com> # Conflicts: # pkg/extension/extension.go
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
package extension
|
||||
|
||||
import "context"
|
||||
|
||||
const AccountDirectorySchemaVersion = 1
|
||||
|
||||
const (
|
||||
AccountDirectoryPurposeSystemUsers = "system.users"
|
||||
AccountDirectoryPurposeProjectMembers = "project.member-candidate"
|
||||
AccountDirectoryPurposeDocumentDuties = "document.duty-candidate"
|
||||
AccountDirectoryModeExact = "exact"
|
||||
AccountDirectoryModeFuzzy = "fuzzy"
|
||||
)
|
||||
|
||||
// AccountDirectoryQuery is a request for account candidates. Actor and field
|
||||
// permissions are deliberately absent: the host supplies the authenticated
|
||||
// dispatch actor and obtains current domain authorization from its registrar.
|
||||
type AccountDirectoryQuery struct {
|
||||
SchemaVersion int `json:"schemaVersion"`
|
||||
Purpose string `json:"purpose"`
|
||||
ProjectID string `json:"projectId,omitempty"`
|
||||
DocumentID string `json:"documentId,omitempty"`
|
||||
Mode string `json:"mode"`
|
||||
Query string `json:"query"`
|
||||
SearchFields []string `json:"searchFields,omitempty"`
|
||||
Status string `json:"status,omitempty"` // enabled|disabled|all; domain candidates require enabled
|
||||
Cursor string `json:"cursor,omitempty"`
|
||||
Limit int `json:"limit,omitempty"`
|
||||
}
|
||||
|
||||
// AccountDirectoryEntry contains only identity, effective state and fields
|
||||
// specifically authorized for the current purpose. Contact details never use
|
||||
// this candidate DTO.
|
||||
type AccountDirectoryEntry struct {
|
||||
UserID string `json:"userId"`
|
||||
Owner string `json:"owner"`
|
||||
Name string `json:"name,omitempty"`
|
||||
StaffNo string `json:"staffNo,omitempty"`
|
||||
Valid bool `json:"valid"`
|
||||
}
|
||||
|
||||
type AccountDirectoryPage struct {
|
||||
Entries []AccountDirectoryEntry `json:"entries"`
|
||||
DirectoryVersion string `json:"directoryVersion"`
|
||||
NextCursor string `json:"nextCursor,omitempty"`
|
||||
}
|
||||
|
||||
type AccountDirectoryLookup struct {
|
||||
Entry AccountDirectoryEntry `json:"entry"`
|
||||
DirectoryVersion string `json:"directoryVersion"`
|
||||
}
|
||||
|
||||
// AccountDirectoryProvider is optional on trusted dispatch Host handles.
|
||||
// Missing capability is a denial, not permission to use EXT-19 as a fallback.
|
||||
type AccountDirectoryProvider interface {
|
||||
QueryAccountDirectory(context.Context, AccountDirectoryQuery) (AccountDirectoryPage, error)
|
||||
LookupAccountDirectory(context.Context, AccountDirectoryQuery, string) (AccountDirectoryLookup, error)
|
||||
// LookupAccountDirectoryOwner is an explicit legacy-owner compatibility
|
||||
// lookup; it resolves to the same stable user ID and applies the same scope.
|
||||
LookupAccountDirectoryOwner(context.Context, AccountDirectoryQuery, string) (AccountDirectoryLookup, error)
|
||||
}
|
||||
|
||||
// AccountDirectoryScopeRequest is constructed by the Backend from the trusted
|
||||
// dispatch actor, registered plugin and untrusted locator. A resolver must
|
||||
// validate the locator and current member.manage / duty.assign authority.
|
||||
type AccountDirectoryScopeRequest struct {
|
||||
Actor string
|
||||
PluginID string
|
||||
Purpose string
|
||||
ProjectID string
|
||||
DocumentID string
|
||||
}
|
||||
|
||||
// AccountDirectoryScope is returned by the trusted in-process domain resolver.
|
||||
// AllCandidates is explicit: a nil candidate list never means global access.
|
||||
// CandidateIDs or CandidateOwners are applied before search and pagination;
|
||||
// domain membership stores may use owners while the provider returns stable IDs.
|
||||
type AccountDirectoryScope struct {
|
||||
AllowedFields []string
|
||||
MatchFields []string
|
||||
AllCandidates bool
|
||||
CandidateIDs []string
|
||||
CandidateOwners []string
|
||||
ScopeVersion string
|
||||
}
|
||||
|
||||
type AccountDirectoryScopeResolver func(context.Context, AccountDirectoryScopeRequest) (AccountDirectoryScope, error)
|
||||
|
||||
// AccountDirectoryRegistrar is optional on a compiled in-process Registry.
|
||||
// Only the trusted RDM plugin may register the domain authorization resolver.
|
||||
type AccountDirectoryRegistrar interface {
|
||||
RegisterAccountDirectoryScopeResolver(AccountDirectoryScopeResolver) error
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package extension
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestAccountDirectoryContractIsOptional(t *testing.T) {
|
||||
var host Host
|
||||
_, _ = host.(AccountDirectoryProvider)
|
||||
var registry Registry
|
||||
_, _ = registry.(AccountDirectoryRegistrar)
|
||||
if AccountDirectorySchemaVersion < 1 {
|
||||
t.Fatal("directory schema version must be explicit")
|
||||
}
|
||||
}
|
||||
@@ -36,9 +36,11 @@ import (
|
||||
// 分区组件自身的命令面 fail-closed)。
|
||||
// 2.12.0-experimental: optional ProjectHost/ProjectLifecycleRegistry and trusted
|
||||
// ResourceAuthzQuery.Source for per-document publication authorization.
|
||||
// 2.13.0-experimental:InProc.HostOptions / CLIHook,以及 MergeHostOptions、
|
||||
// 2.13.0-experimental: optional AccountDirectoryProvider and trusted in-process
|
||||
// AccountDirectoryRegistrar for scoped, current account candidate decisions.
|
||||
// 2.14.0-experimental:InProc.HostOptions / CLIHook,以及 MergeHostOptions、
|
||||
// RegisterCLIFlags、RunCLIHooks(组合二进制把插件声明并进基座启动,不覆盖显式参数)。
|
||||
const SurfaceVersion = "2.13.0-experimental"
|
||||
const SurfaceVersion = "2.14.0-experimental"
|
||||
|
||||
// ErrNotLinked 表示进程没有空白导入 link 包,Main 无法启动服务。
|
||||
var ErrNotLinked = errors.New("extension: runner not linked; blank-import agent-system-backend/pkg/extension/link")
|
||||
@@ -101,17 +103,15 @@ type AccountEntry struct {
|
||||
Valid bool `json:"valid"`
|
||||
}
|
||||
|
||||
// AccountLister EXT-19 可选能力接口(实现由宿主注入):游标分页列举系统账号。
|
||||
// 未实现时下游回落现行行为(成员添加不做账号有效性校验);实现后仅用于
|
||||
// 授权管理读面——不授予任何写权。
|
||||
// AccountLister EXT-19 旧接口:仅有受信系统管理员分发上下文时可读取。
|
||||
// 新领域消费者必须使用 AccountDirectoryProvider,不得以本接口作为降级路径。
|
||||
type AccountLister interface {
|
||||
ListAccounts(cursor string, limit int) (entries []AccountEntry, next string, err error)
|
||||
}
|
||||
|
||||
// AccountSearcher EXT-19 扩展可选能力(P3,2026-10-13):按账号或姓名检索账号
|
||||
// 目录,供人员选择器的输入搜索。query 匹配账号子串或姓名子串(大小写不敏感;
|
||||
// 空串=不限,返回首页候选)。仅授权管理读面使用;未实现时下游回落
|
||||
// AccountLister 分页浏览。
|
||||
// 目录。与 AccountLister 相同,它不含领域定位,只允许受信系统管理员上下文;
|
||||
// 新领域消费者不得回落到此接口。
|
||||
type AccountSearcher interface {
|
||||
SearchAccounts(query string, limit int) (entries []AccountEntry, err error)
|
||||
}
|
||||
|
||||
@@ -7,7 +7,9 @@ import (
|
||||
|
||||
// ProjectHost is an optional actor-scoped host projection capability. Metadata
|
||||
// can be shared by an authorizer; registered-lifecycle metadata masks credentials.
|
||||
// OwnedProject remains an owner-only management lookup; mutations remain owner-only.
|
||||
// OwnedProject remains an owner-only management lookup. A request-bound
|
||||
// delegated projection may carry a separate real operator and fixed creator;
|
||||
// its final Store transaction checks both accounts and the persisted owner.
|
||||
type ProjectHost interface {
|
||||
Owner() string
|
||||
OwnedProjects() ([]core.Project, error)
|
||||
@@ -18,6 +20,14 @@ type ProjectHost interface {
|
||||
ProjectNameAvailable(name, exceptID string) (bool, error)
|
||||
}
|
||||
|
||||
// DelegatedProjectProjectionHost is an optional capability of a current,
|
||||
// authenticated RDM request Host. It derives a single-project creator
|
||||
// projection while retaining the original operator for final account fencing.
|
||||
// A globally reconstructed ScopedHost does not implement this capability.
|
||||
type DelegatedProjectProjectionHost interface {
|
||||
ProjectProjectionForCreator(creator, projectID string) (ProjectHost, error)
|
||||
}
|
||||
|
||||
// ProjectLifecycle supplies the domain's public project lifecycle and live work
|
||||
// authorization. Each Host is scoped to the authenticated actor. Errors with a
|
||||
// StatusCode() int method may report 400, 403, 404, 409, or 503 to HTTP clients.
|
||||
|
||||
@@ -1,3 +1,22 @@
|
||||
AccountDirectoryEntry
|
||||
AccountDirectoryLookup
|
||||
AccountDirectoryModeExact
|
||||
AccountDirectoryModeFuzzy
|
||||
AccountDirectoryPage
|
||||
AccountDirectoryProvider
|
||||
AccountDirectoryProvider.LookupAccountDirectory
|
||||
AccountDirectoryProvider.LookupAccountDirectoryOwner
|
||||
AccountDirectoryProvider.QueryAccountDirectory
|
||||
AccountDirectoryPurposeDocumentDuties
|
||||
AccountDirectoryPurposeProjectMembers
|
||||
AccountDirectoryPurposeSystemUsers
|
||||
AccountDirectoryQuery
|
||||
AccountDirectoryRegistrar
|
||||
AccountDirectoryRegistrar.RegisterAccountDirectoryScopeResolver
|
||||
AccountDirectorySchemaVersion
|
||||
AccountDirectoryScope
|
||||
AccountDirectoryScopeRequest
|
||||
AccountDirectoryScopeResolver
|
||||
AccountEntry
|
||||
AccountLister
|
||||
AccountLister.ListAccounts
|
||||
@@ -8,6 +27,8 @@ AdminProvider.IsAdmin
|
||||
AdminZoneSpec
|
||||
CLIHook
|
||||
Compiled
|
||||
DelegatedProjectProjectionHost
|
||||
DelegatedProjectProjectionHost.ProjectProjectionForCreator
|
||||
ErrNotLinked
|
||||
Handler
|
||||
Host
|
||||
|
||||
Reference in New Issue
Block a user