Add scoped project command audit read slice
Why: Project audit cannot use owner-wide logs or current conversation project state to establish trusted attribution. Evidence: RED cases were observed locally; go test ./pkg/extension ./internal/store ./internal/app -count=1 passed on this tree (SELF). Impact: Add optional X2 read and audit.read callback, immutable project/name snapshots, safe owner-only projection, and explicit unsupported coverage. Cross-member publication remains pending. Refs: Stage 5 W9; Stage 6 X2 public extension request
This commit is contained in:
@@ -34,7 +34,9 @@ import (
|
||||
// 分区组件自身的命令面 fail-closed)。
|
||||
// 2.12.0-experimental: optional ProjectHost/ProjectLifecycleRegistry and trusted
|
||||
// ResourceAuthzQuery.Source for per-document publication authorization.
|
||||
const SurfaceVersion = "2.12.0-experimental"
|
||||
// 2.13.0-experimental: optional ProjectAuditHost and ProjectAuditRegistry (X2
|
||||
// project-bound command-audit read slice and domain audit.read callback).
|
||||
const SurfaceVersion = "2.13.0-experimental"
|
||||
|
||||
// ErrNotLinked 表示进程没有空白导入 link 包,Main 无法启动服务。
|
||||
var ErrNotLinked = errors.New("extension: runner not linked; blank-import agent-system-backend/pkg/extension/link")
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
package extension
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
core "agent-system-core"
|
||||
)
|
||||
|
||||
// ProjectAuditAuthorizer answers the domain's audit.read decision for the
|
||||
// authenticated actor and a project identified by trusted host storage.
|
||||
// A project ID supplied by a caller is a locator, never an authorization.
|
||||
type ProjectAuditAuthorizer func(actor string, projectID core.ID) (bool, error)
|
||||
|
||||
// ProjectAuditRegistry is optional so older extension registries remain valid.
|
||||
// Only an in-process domain plugin can register this callback.
|
||||
type ProjectAuditRegistry interface {
|
||||
RegisterProjectAuditAuthorizer(ProjectAuditAuthorizer) error
|
||||
}
|
||||
|
||||
var (
|
||||
ErrProjectAuditDenied = errors.New("extension: project audit denied")
|
||||
ErrProjectAuditUnsupported = errors.New("extension: project audit unsupported")
|
||||
)
|
||||
|
||||
// ProjectAuditQuery reads one project-bound command-audit slice. Offset is a
|
||||
// host source offset, not a cross-domain event sequence. A nonzero BeforeOffset
|
||||
// must be paired with the CutoffOffset returned on the first page.
|
||||
type ProjectAuditQuery struct {
|
||||
ProjectID core.ID `json:"projectId"`
|
||||
BeforeOffset int64 `json:"beforeOffset,omitempty"`
|
||||
CutoffOffset int64 `json:"cutoffOffset,omitempty"`
|
||||
Limit int `json:"limit,omitempty"`
|
||||
}
|
||||
|
||||
// HostAuditReceipt is a server-projected receipt, never a raw audit payload.
|
||||
// ActorName is the name recorded with this command; old rows have no snapshot.
|
||||
type HostAuditReceipt struct {
|
||||
SourceOffset int64 `json:"sourceOffset"`
|
||||
Time time.Time `json:"time"`
|
||||
ActorID string `json:"actorId,omitempty"`
|
||||
ActorName string `json:"actorName,omitempty"`
|
||||
ActorNameStatus string `json:"actorNameStatus"`
|
||||
CommandID string `json:"commandId"`
|
||||
State string `json:"state"`
|
||||
OperationID string `json:"operationId,omitempty"`
|
||||
ConversationID string `json:"conversationId"`
|
||||
}
|
||||
|
||||
// ProjectAuditCoverage states the exact scope of this first X2 slice. Missing
|
||||
// host sources and old unbound rows cannot be inferred from owner-wide audit.
|
||||
type ProjectAuditCoverage struct {
|
||||
CommandAudit string `json:"commandAudit"`
|
||||
CrossMember string `json:"crossMember"`
|
||||
LegacyProjectBinding string `json:"legacyProjectBinding"`
|
||||
RunRelations string `json:"runRelations"`
|
||||
ModelReceipts string `json:"modelReceipts"`
|
||||
BackgroundReceipts string `json:"backgroundReceipts"`
|
||||
ResourceBodies string `json:"resourceBodies"`
|
||||
}
|
||||
|
||||
type ProjectAuditPage struct {
|
||||
Receipts []HostAuditReceipt `json:"receipts"`
|
||||
NextOffset int64 `json:"nextOffset,omitempty"`
|
||||
CutoffOffset int64 `json:"cutoffOffset"`
|
||||
Coverage ProjectAuditCoverage `json:"coverage"`
|
||||
}
|
||||
|
||||
// ProjectAuditHost is an optional, actor-bound read capability. A consumer must
|
||||
// treat a failed type assertion as unsupported; an authorized page still reports
|
||||
// partial coverage explicitly.
|
||||
type ProjectAuditHost interface {
|
||||
QueryProjectAudit(context.Context, ProjectAuditQuery) (ProjectAuditPage, error)
|
||||
}
|
||||
@@ -8,6 +8,8 @@ AdminProvider.IsAdmin
|
||||
AdminZoneSpec
|
||||
Compiled
|
||||
ErrNotLinked
|
||||
ErrProjectAuditDenied
|
||||
ErrProjectAuditUnsupported
|
||||
Handler
|
||||
Host
|
||||
Host.ArtifactContent
|
||||
@@ -25,6 +27,7 @@ Host.ParseDocument
|
||||
Host.PluginID
|
||||
Host.TaskCreate
|
||||
Host.TaskUpdate
|
||||
HostAuditReceipt
|
||||
HostClient
|
||||
InProc
|
||||
IntentSpec
|
||||
@@ -32,6 +35,14 @@ Main
|
||||
NewHostClient
|
||||
NewScopedHost
|
||||
Options
|
||||
ProjectAuditAuthorizer
|
||||
ProjectAuditCoverage
|
||||
ProjectAuditHost
|
||||
ProjectAuditHost.QueryProjectAudit
|
||||
ProjectAuditPage
|
||||
ProjectAuditQuery
|
||||
ProjectAuditRegistry
|
||||
ProjectAuditRegistry.RegisterProjectAuditAuthorizer
|
||||
ProjectHost
|
||||
ProjectHost.EnsureProject
|
||||
ProjectHost.OwnedProject
|
||||
|
||||
Reference in New Issue
Block a user