Add verified project audit links and button actors
Why: Owner-only command audit cannot prove shared business commits, and button dispatch omitted its authenticated actor. Evidence: Local go test ./... passed; isolated PostgreSQL cutoff, link, and SQLite-to-PostgreSQL migration receipts are recorded as SELF in the task card. Impact: Add an optional domain-verified metadata link, exact authorized cross-member read, idempotent storage, actor propagation, and honest PostgreSQL cutoff coverage. Broad audit pagination and other sources remain pending. Refs: Stage 5 W9; approved Stage 6 audit-link design adjustment r1
This commit is contained in:
@@ -36,7 +36,9 @@ import (
|
||||
// ResourceAuthzQuery.Source for per-document publication authorization.
|
||||
// 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"
|
||||
// 2.14.0-experimental: X2 optional committed project-audit link publisher,
|
||||
// verifier, disclosure callback, and exact linked receipt read.
|
||||
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")
|
||||
|
||||
@@ -20,18 +20,89 @@ type ProjectAuditRegistry interface {
|
||||
}
|
||||
|
||||
var (
|
||||
ErrProjectAuditDenied = errors.New("extension: project audit denied")
|
||||
ErrProjectAuditUnsupported = errors.New("extension: project audit unsupported")
|
||||
ErrProjectAuditDenied = errors.New("extension: project audit denied")
|
||||
ErrProjectAuditUnsupported = errors.New("extension: project audit unsupported")
|
||||
ErrProjectAuditLinkConflict = errors.New("extension: project audit link conflict")
|
||||
)
|
||||
|
||||
// ProjectAuditLinkRequest binds one host command receipt to an already
|
||||
// committed domain fact. Owner is never caller supplied; the host handle and
|
||||
// stored audit row establish it. This first slice supports domain-commit only.
|
||||
type ProjectAuditLinkRequest struct {
|
||||
ProjectID core.ID `json:"projectId"`
|
||||
HostAuditOffset int64 `json:"hostAuditOffset"`
|
||||
SourceKind string `json:"sourceKind"`
|
||||
SourceID string `json:"sourceId"`
|
||||
OperationID string `json:"operationId"`
|
||||
ResourceKind string `json:"resourceKind"`
|
||||
ResourceID string `json:"resourceId"`
|
||||
RunID string `json:"runId,omitempty"`
|
||||
DisclosureClass string `json:"disclosureClass"`
|
||||
IdempotencyKey string `json:"idempotencyKey"`
|
||||
}
|
||||
|
||||
// ProjectAuditLinkProof contains the caller request plus identity and source
|
||||
// fields re-read from trusted host storage. The domain verifier must check its
|
||||
// committed source event and operation/resource attribution, not a model claim.
|
||||
type ProjectAuditLinkProof struct {
|
||||
ProjectAuditLinkRequest
|
||||
Owner string
|
||||
}
|
||||
|
||||
type ProjectAuditLinkVerifier func(context.Context, ProjectAuditLinkProof) (bool, error)
|
||||
|
||||
// ProjectAuditLinkedResource is the stored, immutable link presented to the
|
||||
// current domain disclosure policy. A caller ID alone never authorizes it.
|
||||
type ProjectAuditLinkedResource struct {
|
||||
ProjectID core.ID
|
||||
Owner string
|
||||
SourceKind string
|
||||
SourceID string
|
||||
OperationID string
|
||||
ResourceKind string
|
||||
ResourceID string
|
||||
RunID string
|
||||
DisclosureClass string
|
||||
}
|
||||
|
||||
type ProjectAuditDisclosure struct {
|
||||
Metadata bool
|
||||
Body bool
|
||||
}
|
||||
|
||||
type ProjectAuditDisclosureAuthorizer func(context.Context, string, ProjectAuditLinkedResource) (ProjectAuditDisclosure, error)
|
||||
|
||||
// ProjectAuditLinkRegistry is optional. Only the registering compiled domain
|
||||
// plugin may publish or read its links.
|
||||
type ProjectAuditLinkRegistry interface {
|
||||
RegisterProjectAuditLinkVerifier(ProjectAuditLinkVerifier) error
|
||||
RegisterProjectAuditDisclosureAuthorizer(ProjectAuditDisclosureAuthorizer) error
|
||||
}
|
||||
|
||||
type ProjectAuditLinkReceipt struct {
|
||||
LinkID int64 `json:"linkId"`
|
||||
HostAuditOffset int64 `json:"hostAuditOffset"`
|
||||
}
|
||||
|
||||
type ProjectAuditPublisher interface {
|
||||
PublishProjectAuditLink(context.Context, ProjectAuditLinkRequest) (ProjectAuditLinkReceipt, error)
|
||||
}
|
||||
|
||||
// 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.
|
||||
// must be paired with the CutoffOffset returned on the first page. On PostgreSQL
|
||||
// that cutoff bounds offsets but is not a fixed visibility snapshot: a lower ID
|
||||
// from a still-open transaction may commit later. See Coverage.CutoffConsistency.
|
||||
type ProjectAuditQuery struct {
|
||||
ProjectID core.ID `json:"projectId"`
|
||||
BeforeOffset int64 `json:"beforeOffset,omitempty"`
|
||||
CutoffOffset int64 `json:"cutoffOffset,omitempty"`
|
||||
Limit int `json:"limit,omitempty"`
|
||||
// Linked* select one exact committed link. This avoids enumerating hidden
|
||||
// private links or leaking their counts before cursor policy is complete.
|
||||
LinkedSourceKind string `json:"linkedSourceKind,omitempty"`
|
||||
LinkedSourceID string `json:"linkedSourceId,omitempty"`
|
||||
LinkedHostOffset int64 `json:"linkedHostOffset,omitempty"`
|
||||
}
|
||||
|
||||
// HostAuditReceipt is a server-projected receipt, never a raw audit payload.
|
||||
@@ -52,6 +123,7 @@ type HostAuditReceipt struct {
|
||||
// host sources and old unbound rows cannot be inferred from owner-wide audit.
|
||||
type ProjectAuditCoverage struct {
|
||||
CommandAudit string `json:"commandAudit"`
|
||||
CutoffConsistency string `json:"cutoffConsistency"`
|
||||
CrossMember string `json:"crossMember"`
|
||||
LegacyProjectBinding string `json:"legacyProjectBinding"`
|
||||
RunRelations string `json:"runRelations"`
|
||||
|
||||
@@ -9,6 +9,7 @@ AdminZoneSpec
|
||||
Compiled
|
||||
ErrNotLinked
|
||||
ErrProjectAuditDenied
|
||||
ErrProjectAuditLinkConflict
|
||||
ErrProjectAuditUnsupported
|
||||
Handler
|
||||
Host
|
||||
@@ -37,9 +38,21 @@ NewScopedHost
|
||||
Options
|
||||
ProjectAuditAuthorizer
|
||||
ProjectAuditCoverage
|
||||
ProjectAuditDisclosure
|
||||
ProjectAuditDisclosureAuthorizer
|
||||
ProjectAuditHost
|
||||
ProjectAuditHost.QueryProjectAudit
|
||||
ProjectAuditLinkProof
|
||||
ProjectAuditLinkReceipt
|
||||
ProjectAuditLinkRegistry
|
||||
ProjectAuditLinkRegistry.RegisterProjectAuditDisclosureAuthorizer
|
||||
ProjectAuditLinkRegistry.RegisterProjectAuditLinkVerifier
|
||||
ProjectAuditLinkRequest
|
||||
ProjectAuditLinkVerifier
|
||||
ProjectAuditLinkedResource
|
||||
ProjectAuditPage
|
||||
ProjectAuditPublisher
|
||||
ProjectAuditPublisher.PublishProjectAuditLink
|
||||
ProjectAuditQuery
|
||||
ProjectAuditRegistry
|
||||
ProjectAuditRegistry.RegisterProjectAuditAuthorizer
|
||||
|
||||
Reference in New Issue
Block a user