323 lines
9.3 KiB
Go
323 lines
9.3 KiB
Go
package world
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"git.cin.su/m/Assistant/contracts/identity"
|
|
"git.cin.su/m/Assistant/platform/clock"
|
|
"git.cin.su/m/Assistant/platform/ids"
|
|
)
|
|
|
|
// SemanticReference is the transport envelope used by World contracts. It is
|
|
// a reference only; it does not expose another owner's storage.
|
|
type SemanticReference = ids.SemanticRef
|
|
|
|
// VersionBinding is a typed applicability constraint. Absence of VersionRef
|
|
// means unknown, never an implicit "latest".
|
|
type VersionMatchMode string
|
|
|
|
const (
|
|
VersionExact VersionMatchMode = "EXACT"
|
|
VersionCompatibleFamily VersionMatchMode = "COMPATIBLE_FAMILY"
|
|
VersionAtOrBefore VersionMatchMode = "AT_OR_BEFORE"
|
|
VersionUnknown VersionMatchMode = "UNKNOWN"
|
|
)
|
|
|
|
type VersionBinding struct {
|
|
SubjectRef SemanticReference
|
|
VersionRef SemanticReference
|
|
MatchMode VersionMatchMode
|
|
}
|
|
|
|
type EnvironmentReference struct {
|
|
EnvironmentRef SemanticReference
|
|
VersionRef *SemanticReference
|
|
}
|
|
|
|
func (b VersionBinding) Validate() error {
|
|
if !b.SubjectRef.Valid() || !b.VersionRef.Valid() {
|
|
return fmt.Errorf("version binding references are invalid")
|
|
}
|
|
if b.MatchMode != VersionExact && b.MatchMode != VersionCompatibleFamily && b.MatchMode != VersionAtOrBefore && b.MatchMode != VersionUnknown {
|
|
return fmt.Errorf("version binding match mode is invalid")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (r EnvironmentReference) Validate() error {
|
|
if !r.EnvironmentRef.Valid() {
|
|
return fmt.Errorf("environment reference is invalid")
|
|
}
|
|
if r.VersionRef != nil && !r.VersionRef.Valid() {
|
|
return fmt.Errorf("environment version reference is invalid")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type PrincipalRealm string
|
|
|
|
const (
|
|
RealmPersonal PrincipalRealm = "PERSONAL"
|
|
RealmShared PrincipalRealm = "SHARED"
|
|
RealmPublic PrincipalRealm = "PUBLIC"
|
|
RealmSystem PrincipalRealm = "SYSTEM"
|
|
)
|
|
|
|
type SensitivityClass string
|
|
|
|
const (
|
|
SensitivityPublic SensitivityClass = "PUBLIC"
|
|
SensitivityPrivate SensitivityClass = "PRIVATE"
|
|
SensitivityRestricted SensitivityClass = "RESTRICTED"
|
|
SensitivitySecretReference SensitivityClass = "SECRET_REFERENCE"
|
|
)
|
|
|
|
type ValueTypeKind string
|
|
|
|
const (
|
|
ValueString ValueTypeKind = "STRING"
|
|
ValueInteger ValueTypeKind = "INTEGER"
|
|
ValueDecimal ValueTypeKind = "DECIMAL"
|
|
ValueBoolean ValueTypeKind = "BOOLEAN"
|
|
ValueTime ValueTypeKind = "TIME"
|
|
ValueDuration ValueTypeKind = "DURATION"
|
|
ValueEnum ValueTypeKind = "ENUM"
|
|
ValueReference ValueTypeKind = "REFERENCE"
|
|
ValueBinaryRef ValueTypeKind = "BINARY_REF"
|
|
ValueList ValueTypeKind = "LIST"
|
|
ValueStruct ValueTypeKind = "STRUCT"
|
|
)
|
|
|
|
type ValueField struct {
|
|
Name string
|
|
Type ValueTypeSpec
|
|
}
|
|
|
|
type ValueTypeSpec struct {
|
|
Kind ValueTypeKind
|
|
Element *ValueTypeSpec
|
|
Fields []ValueField
|
|
EnumValues []string
|
|
ReferenceKind string
|
|
}
|
|
|
|
type WorldObjectID ids.StableID
|
|
type KindDefinitionID ids.StableID
|
|
type WorldAliasID ids.StableID
|
|
type PersonReferent struct {
|
|
WorldObjectRef SemanticReference
|
|
DisplayName string
|
|
ConfidenceMillis int64
|
|
}
|
|
|
|
func (p PersonReferent) Valid() bool {
|
|
return p.WorldObjectRef.Valid() && p.DisplayName != "" && p.ConfidenceMillis >= 0 && p.ConfidenceMillis <= 1000
|
|
}
|
|
|
|
type FacetDefinitionID ids.StableID
|
|
type RelationDefinitionID ids.StableID
|
|
type ResolutionDecisionID ids.StableID
|
|
type LineageID ids.StableID
|
|
|
|
type LifecycleState string
|
|
|
|
const (
|
|
LifecycleActive LifecycleState = "ACTIVE"
|
|
LifecycleMerged LifecycleState = "MERGED"
|
|
LifecycleSplit LifecycleState = "SPLIT"
|
|
LifecycleRetired LifecycleState = "RETIRED"
|
|
LifecycleUnknownIdentity LifecycleState = "UNKNOWN_IDENTITY"
|
|
)
|
|
|
|
type WorldObject struct {
|
|
ID WorldObjectID
|
|
PrincipalID identity.PrincipalID
|
|
KindDefinitionRef SemanticReference
|
|
KindRevision ids.Revision
|
|
Lifecycle LifecycleState
|
|
CreatedAt clock.Instant
|
|
}
|
|
|
|
type WorldObjectKindDefinition struct {
|
|
ID KindDefinitionID
|
|
KindKey string
|
|
Revision ids.Revision
|
|
DisplayName string
|
|
ParentKindRef *SemanticReference
|
|
Lifecycle LifecycleState
|
|
DefinitionDigest string
|
|
RecordedAt clock.Instant
|
|
}
|
|
|
|
type WorldAlias struct {
|
|
ID WorldAliasID
|
|
PrincipalID identity.PrincipalID
|
|
ObjectID WorldObjectID
|
|
Alias string
|
|
RecordedAt clock.Instant
|
|
}
|
|
|
|
type FacetDefinition struct {
|
|
ID FacetDefinitionID
|
|
KindKey string
|
|
Revision ids.Revision
|
|
FacetKey string
|
|
ValueType ValueTypeSpec
|
|
DefinitionDigest string
|
|
RecordedAt clock.Instant
|
|
}
|
|
|
|
type RelationDefinition struct {
|
|
ID RelationDefinitionID
|
|
KindKey string
|
|
Revision ids.Revision
|
|
RelationKey string
|
|
TargetKindKey string
|
|
DefinitionDigest string
|
|
RecordedAt clock.Instant
|
|
}
|
|
|
|
type ResolutionDecision string
|
|
|
|
const (
|
|
ResolutionSame ResolutionDecision = "SAME"
|
|
ResolutionDistinct ResolutionDecision = "DISTINCT"
|
|
ResolutionMerge ResolutionDecision = "MERGE"
|
|
ResolutionSplit ResolutionDecision = "SPLIT"
|
|
ResolutionUnresolved ResolutionDecision = "UNRESOLVED"
|
|
)
|
|
|
|
type IdentityResolutionCandidate struct {
|
|
ObjectRef SemanticReference
|
|
Evidence []SemanticReference
|
|
Confidence int64
|
|
}
|
|
|
|
type IdentityResolutionDecisionRecord struct {
|
|
ID ResolutionDecisionID
|
|
PrincipalID identity.PrincipalID
|
|
Candidates []IdentityResolutionCandidate
|
|
Decision ResolutionDecision
|
|
Evidence []SemanticReference
|
|
ConfidenceMillis int64
|
|
DecidedAt clock.Instant
|
|
Revision ids.Revision
|
|
}
|
|
|
|
type WorldLineage struct {
|
|
ID LineageID
|
|
Operation ResolutionDecision
|
|
SourceRefs []SemanticReference
|
|
SuccessorRefs []SemanticReference
|
|
RecordedAt clock.Instant
|
|
}
|
|
|
|
func (w WorldObject) Validate() error {
|
|
if w.ID == "" || !w.KindDefinitionRef.Valid() || !w.KindRevision.Valid() || !validLifecycle(w.Lifecycle) || !w.CreatedAt.Valid() {
|
|
return fmt.Errorf("world object is incomplete")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (k WorldObjectKindDefinition) Validate() error {
|
|
if k.ID == "" || k.KindKey == "" || !k.Revision.Valid() || k.DisplayName == "" || !validLifecycle(k.Lifecycle) || k.DefinitionDigest == "" || !k.RecordedAt.Valid() {
|
|
return fmt.Errorf("world kind definition is incomplete")
|
|
}
|
|
if k.ParentKindRef != nil && !k.ParentKindRef.Valid() {
|
|
return fmt.Errorf("world kind parent reference is invalid")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (a WorldAlias) Validate() error {
|
|
if a.ID == "" || a.ObjectID == "" || a.Alias == "" || !a.RecordedAt.Valid() {
|
|
return fmt.Errorf("world alias is incomplete")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (f FacetDefinition) Validate() error {
|
|
if f.ID == "" || f.KindKey == "" || !f.Revision.Valid() || f.FacetKey == "" || f.DefinitionDigest == "" || !f.RecordedAt.Valid() {
|
|
return fmt.Errorf("facet definition is incomplete")
|
|
}
|
|
return f.ValueType.Validate()
|
|
}
|
|
|
|
func (r RelationDefinition) Validate() error {
|
|
if r.ID == "" || r.KindKey == "" || !r.Revision.Valid() || r.RelationKey == "" || r.TargetKindKey == "" || r.DefinitionDigest == "" || !r.RecordedAt.Valid() {
|
|
return fmt.Errorf("relation definition is incomplete")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (d IdentityResolutionDecisionRecord) Validate() error {
|
|
if d.ID == "" || !validDecision(d.Decision) || len(d.Candidates) == 0 || d.ConfidenceMillis < 0 || !d.DecidedAt.Valid() || !d.Revision.Valid() {
|
|
return fmt.Errorf("identity resolution decision is incomplete")
|
|
}
|
|
for _, candidate := range d.Candidates {
|
|
if !candidate.ObjectRef.Valid() || candidate.Confidence < 0 || candidate.Confidence > 1000 {
|
|
return fmt.Errorf("identity resolution candidate is invalid")
|
|
}
|
|
for _, evidence := range candidate.Evidence {
|
|
if !evidence.Valid() {
|
|
return fmt.Errorf("identity resolution evidence reference is invalid")
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (l WorldLineage) Validate() error {
|
|
if l.ID == "" || (l.Operation != ResolutionMerge && l.Operation != ResolutionSplit) || len(l.SourceRefs) == 0 || len(l.SuccessorRefs) == 0 || !l.RecordedAt.Valid() {
|
|
return fmt.Errorf("world lineage is incomplete")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func validLifecycle(value LifecycleState) bool {
|
|
return value == LifecycleActive || value == LifecycleMerged || value == LifecycleSplit || value == LifecycleRetired || value == LifecycleUnknownIdentity
|
|
}
|
|
|
|
func validDecision(value ResolutionDecision) bool {
|
|
return value == ResolutionSame || value == ResolutionDistinct || value == ResolutionMerge || value == ResolutionSplit || value == ResolutionUnresolved
|
|
}
|
|
|
|
func (s ValueTypeSpec) Validate() error {
|
|
if s.Kind == "" {
|
|
return fmt.Errorf("value type kind is required")
|
|
}
|
|
switch s.Kind {
|
|
case ValueList:
|
|
if s.Element == nil {
|
|
return fmt.Errorf("list element type is required")
|
|
}
|
|
return s.Element.Validate()
|
|
case ValueStruct:
|
|
if len(s.Fields) == 0 {
|
|
return fmt.Errorf("struct fields are required")
|
|
}
|
|
seen := map[string]struct{}{}
|
|
for _, field := range s.Fields {
|
|
if field.Name == "" {
|
|
return fmt.Errorf("struct field name is required")
|
|
}
|
|
if _, ok := seen[field.Name]; ok {
|
|
return fmt.Errorf("duplicate struct field %q", field.Name)
|
|
}
|
|
seen[field.Name] = struct{}{}
|
|
if err := field.Type.Validate(); err != nil {
|
|
return fmt.Errorf("field %s: %w", field.Name, err)
|
|
}
|
|
}
|
|
case ValueEnum:
|
|
if len(s.EnumValues) == 0 {
|
|
return fmt.Errorf("enum values are required")
|
|
}
|
|
case ValueReference:
|
|
if s.ReferenceKind == "" {
|
|
return fmt.Errorf("reference kind is required")
|
|
}
|
|
}
|
|
return nil
|
|
}
|