Documentation
¶
Index ¶
- Constants
- Variables
- func AgentLastActive(tok *ServiceToken) time.Time
- func BaselineOf(obs []Observation) (map[string]ServiceBaseline, bool)
- func CheckMigrationChoices(spec ApplicationSpec, classes []protocol.StorageClass, ...) error
- func CleanAbsolutePath(p string) bool
- func CommandPermission(action string) (permissions.Action, bool)
- func ExecPodResource(endpointID string, pod protocol.PodTarget) string
- func InstallerUserID(issuer, subject string) string
- func IsAgentScope(scope string) bool
- func Judge(obs []Observation, baseline map[string]ServiceBaseline, final bool) (verdict, detail string)
- func KubernetesProject(name string) string
- func NormalizeNamespaces(in []string) ([]string, error)
- func NormalizeRegistryHost(host string) (string, error)
- func ParseStoredTime(v any) (time.Time, error)
- func ValidDeclaredVolumeName(name string) bool
- func ValidEndpointName(name string) bool
- func ValidVolumeName(name string) bool
- func ValidateApplicationSpec(spec ApplicationSpec) error
- func ValidateInstallerBundle(b applysetup.Common) error
- func ValidateSamples(m protocol.Metrics) error
- func VolumeHostName(project string, v DeclaredVolume) string
- func WorkloadAction(action string) bool
- type AdoptedContainer
- type AdoptionPreview
- type AdoptionRequest
- type AgentIdentity
- type AgentTokenIssue
- type Application
- type ApplicationComparison
- type ApplicationInstance
- type ApplicationMapping
- type ApplicationMigration
- type ApplicationPort
- type ApplicationRevision
- type ApplicationSecretRef
- type ApplicationService
- type ApplicationSpec
- type ApplicationVolume
- type AuditRecord
- type AuditStore
- type BlockedService
- type Command
- type ComparisonContainer
- type ComparisonService
- type DeclaredVolume
- type Deployment
- type DeploymentPlan
- type DeploymentPreflight
- type DevicePairing
- type DeviceStore
- type DigestResolver
- type DirectCommand
- type DirectoryEvent
- type DirectoryTx
- type Endpoint
- type EndpointEvent
- type EnrollmentRequest
- type EnrollmentToken
- type Environment
- type ImageCheck
- type InvalidSpecError
- type Inventory
- type KubernetesExtension
- type KubernetesObject
- type KubernetesVolume
- type LogTarget
- type MFAChallenge
- type MFAState
- type MappingRequest
- type MemberOrganization
- type MigrationAnalysis
- type MigrationChoices
- type MigrationDestination
- type MigrationSource
- type MigrationStart
- type Observation
- type ObservedService
- type Organization
- type OrganizationGroup
- type OrganizationMember
- type OrganizationMembership
- type OrganizationSummary
- type PendingValidation
- type PlanRequest
- type PlannedService
- type PolicyInput
- type PolicyRun
- type PreflightBlockedError
- type PreflightService
- type Pressure
- type Registry
- type RegistryAccess
- type RegistryInput
- type RegistryPolicy
- type RemovalBody
- type RemovalPlanTarget
- type Rollback
- type RollupRow
- type SQLStore
- func (s *SQLStore) ApplyInstaller(ctx context.Context, b applysetup.Common, check bool) (applysetup.Report, error)
- func (s *SQLStore) ApplyInstallerDirectory(ctx context.Context, issuer, subject, event, revision, digest string, ...) error
- func (s *SQLStore) Audit() AuditStore
- func (s *SQLStore) Budget() int64
- func (s *SQLStore) Close() error
- func (s *SQLStore) Devices() DeviceStore
- func (s *SQLStore) Driver() string
- func (s *SQLStore) EvaluatePressure(ctx context.Context) (Pressure, error)
- func (s *SQLStore) InstallerConfiguration(ctx context.Context) (applysetup.Common, bool, error)
- func (s *SQLStore) InstallerUserAllowed(ctx context.Context, u *User) (bool, error)
- func (s *SQLStore) Ping(ctx context.Context) error
- func (s *SQLStore) Pressure() Pressure
- func (s *SQLStore) RevokeInstallerIdentity(ctx context.Context, issuer, subject string) error
- func (s *SQLStore) SampleCeiling() int
- func (s *SQLStore) Sessions() SessionStore
- func (s *SQLStore) SetAllowPrivileged(on bool)
- func (s *SQLStore) SetPressure(p Pressure)
- func (s *SQLStore) Settings() SettingsStore
- func (s *SQLStore) Suite() SuiteStore
- func (s *SQLStore) Tenancy() TenancyStore
- func (s *SQLStore) Usage(ctx context.Context) (int64, error)
- func (s *SQLStore) Users() UserStore
- type SampleRow
- type ScheduledPolicy
- type ServiceBaseline
- type ServicePairing
- type ServiceToken
- type ServiceTokenIssue
- type Session
- type SessionStore
- type Setting
- type SettingsStore
- type Store
- type SuiteOperation
- type SuiteStore
- type TenancyStore
- type TenantAccess
- type TenantRole
- type UpdateCheck
- type UpdatePolicy
- type User
- type UserStore
- type Validation
- type ValidationRollback
- type WorkloadApply
Constants ¶
const ( MaxCapabilities = 64 MaxCapabilityBytes = 4096 )
Capabilities are agent-supplied: bounded in count and bytes like enrollment facts.
const ( ScopePulse = "pulse" ScopeMCPRead = "mcp:read" ScopeMCPOperate = "mcp:operate" )
Scopes of a service_tokens row. A kyPulse token is pulse; an AI agent (MCP) token is one of the two mcp scopes, which the organization administrator picks and may change later.
const ( // AgentTokenPrefix marks an agent token, so a secret scanner and a reader both know it for // one, and so it can never parse as a kyPulse token (64 bare hex characters). AgentTokenPrefix = "kyy_mcp_" // AgentIdleLimit is how long an agent token may go unused before it is revoked. A constant, // not a setting, as in KyCalendar. AgentIdleLimit = 90 * 24 * time.Hour )
const ( MigrationAnalyzed = "analyzed" MigrationDestinationCreated = "destination_created" MigrationValidated = "validated" MigrationCutoverConfirmed = "cutover_confirmed" MigrationAbandoned = "abandoned" MaxMigrationReportBytes = 65536 MaxMigrationNoteRunes = 500 // MaxDestinationSuffix is the last " (n)" a destination name takes when the ones before it // are held. MaxDestinationSuffix = 9 )
Migration statuses. A migration is open until cutover_confirmed or abandoned, and a source has at most one open migration. See docs/application-schema.md, Migration.
const ( MaxApplicationsPerOrganization = 100 MaxApplicationRevisions = 100 MaxApplicationSpecBytes = 64 * 1024 )
const ( ActionRecreate = "container.recreate" ActionRun = "container.run" )
Direct commands recreate or run one container from a configuration the operator saw in full. Each is an endpoint_commands row whose frame is an explicit deployment.apply, settled from the agent's deployment.result.
const ( ActionWorkloadApply = "workload.apply" ActionWorkloadRun = "workload.run" )
ActionWorkloadApply and ActionWorkloadRun are direct commands whose frame is a workload.apply (a run's with create set), settled from the agent's deployment.result with service protocol.WorkloadApplyService.
const ( PolicyModeApply = "apply" PolicyModePlanOnly = "plan_only" PolicyActive = "active" PolicyPaused = "paused" // MinPolicyWindowMinutes is the shortest window. A window never crosses midnight. MinPolicyWindowMinutes = 15 // PolicyFailureLimit consecutive failed windows pause a policy. PolicyFailureLimit = 3 // MaxPolicyRuns bounds one page of runs; the policy read carries the latest policyRunsShown. MaxPolicyRuns = 100 )
Update policies: one per application, saved by an organization administrator and run by the scheduler in internal/api as whoever saved it last. See docs/application-schema.md, Update policies.
const ( RunSkippedMissed = "skipped_missed" RunSkippedBusy = "skipped_busy" RunNoUpdate = "no_update" RunPlanned = "planned" RunApplied = "applied" RunBlocked = "blocked" RunFailed = "failed" RunPaused = "paused" )
A run's outcome. It is empty only while the run is in flight.
const ( PolicyDetailMissed = "the server was not running during this window" PolicyDetailBusy = "another deployment occupied the window" PolicyDetailCreatorLost = "the policy's creator no longer holds application.deploy" PolicyDetailRestarted = "the server restarted during the run" PolicyReasonFailures = "three consecutive windows failed" )
The scheduler's own sentences: the only prose a run's detail or a pause reason holds.
const ( AuditPolicyRun = "application.policy.run" AuditPolicyPaused = "application.policy.paused" )
The scheduler's audit actions. They are not permissions: the scheduler writes them as "system", and each run's own steps are audited under the policy's creator.
const ( SampleRetention = 6 * time.Hour MaxSamplesPerFrame = protocol.MaxSamples // SampleCadence is the documented 60 s reporting interval; a container gains at most one // row per cadence (with a little slack for jitter), so the six-hour window holds about // 360 rows per container whatever an agent sends. SampleCadence = 50 * time.Second EventRetention = 7 * 24 * time.Hour // RollupRetention keeps an hour's summary long after its samples are gone, so a week of // history costs 168 rows per container instead of the 10,080 the raw cadence would. RollupRetention = 7 * 24 * time.Hour // DegradedRollupRetention is the week cut to a day while the disk budget is under // pressure, so summaries give space back as the raw window does rather than being the one // telemetry pruning cannot reclaim. DegradedRollupRetention = 24 * time.Hour // DeploymentHistoryRetention keeps settled deployments; the latest succeeded row of an // instance's current and previous revision, every succeeded apply of an instance while a // rollback of it is undecided, and every row of a removed application (its own retention // prunes them), stay past it. DeploymentHistoryRetention = 90 * 24 * time.Hour // ApplicationRemovedRetention keeps a removed application's revisions and history. ApplicationRemovedRetention = 90 * 24 * time.Hour PruneBatch = 5000 )
Retention limits from docs/retention-policy.md (proposed, soak-gated).
const ( ValidationGrace = 30 * time.Second ValidationWindow = 2 * time.Minute ValidationPoll = 20 * time.Second // PendingValidationsPerOrg is an organization's share of one tick: its oldest rows; the rest // wait for the next tick, so one tenant's backlog never crowds out another's. PendingValidationsPerOrg = 2 // MaxPendingValidations bounds one tick's work after the per-organization cut, oldest first, so // it bounds organizations (MaxPendingValidations / PendingValidationsPerOrg), not one tenant's // backlog, and past that the organizations served rotate as their oldest rows finish. MaxPendingValidations = 256 // AuditValidation is the loop's audit action, written as "system". AuditValidation = "application.validation" )
Health validation: every succeeded apply is watched for a bounded time and given a verdict; an automated one that fails is rolled back when it can be (rollback.go). The loop is api.Server.RunValidations. See docs/application-schema.md, Health validation.
const ( PhaseGrace = "grace" PhaseObserving = "observing" PhaseDone = "done" )
const ( VerdictHealthy = "healthy" VerdictUnhealthy = "unhealthy" VerdictExited = "exited" VerdictRestarting = "restarting" VerdictUnverifiable = "unverifiable" VerdictChanged = "changed" )
const ( RollbackApplied = "applied" RollbackIneligible = "ineligible" RollbackFailed = "failed" // A rollback returns each service to its plan's Replaces image; a service that replaced no // container has none. RollbackNoPriorIdentity = "no_prior_identity" RollbackPriorDefinitionInvalid = "prior_definition_invalid" RollbackServiceSetChanged = "service_set_changed" RollbackPriorImagesMissing = "prior_images_missing" RollbackInFlight = "rollback_in_flight" RollbackAlreadyRolledBack = "already_rolled_back" RollbackCreatorLost = "creator_lost" RollbackNotSent = "not_sent" RollbackInterrupted = "interrupted" // A cluster rollback's service_set_changed names what changed beside it: the namespace, or // the claims or their mounts. RollbackNamespaceChanged = "namespace_changed" RollbackClaimsChanged = "claims_changed" )
A rollback's outcome, and the codes its detail holds besides plan blockers and the scheduler's codes (policyErrorCodes in internal/api).
const ( ValidationDetailUnobserved = "the host could not be observed" ValidationDetailServerDown = "the server was not running during the window" ValidationDetailNoHealth = "the agent cannot report container health" ValidationDetailNoInspect = "the cluster agent cannot report workload status; upgrade the agent image" ValidationDetailInvalid = "an inspection failed validation" ValidationDetailReleased = "the application was released" ValidationReasonRolledBack = "rolled back after a failed update" ValidationReasonNotRolledBack = "update failed and could not be rolled back: " ValidationReasonUnverified = "update could not be validated: " )
The loop's own sentences: the only prose a validation detail or its pause reason holds. A failing verdict's detail is the deciding service's name.
const ( PresencePresent = "present" PresenceGone = "gone" PresenceReplaced = "replaced" PresenceUnknown = "unknown" // no inventory received since the settle: inspect and wait )
Where a settled container stands against the instance's resources and the latest inventory.
const CommandDeadline = 30 * time.Second
CommandDeadline is how long an agent has to answer before the outcome is timed out.
const CommandRetention = 7 * 24 * time.Hour
CommandRetention keeps a settled command long enough to answer "what happened to my restart" the next morning, and no longer. An unsettled one is never pruned: a command whose outcome nobody knows is exactly the record an operator needs.
const DegradedSampleRetention = time.Hour
Prune deletes expired samples and acknowledged events in bounded batches and reports how many rows went, so the caller loops until a pass removes nothing. DegradedSampleRetention is how far back raw samples are kept once the budget is under pressure: refusing new writes alone does not give space back, so the window closes too.
const DeploymentApplyDeadline = 10 * time.Minute
const DeploymentPlanTTL = 10 * time.Minute
const DirectoryEventWindow = 5 * time.Minute
DirectoryEventWindow is how far a directory event's timestamp may be from now.
const GenerationSkew = time.Hour
GenerationSkew is how far ahead of the server clock a generation (a Unix timestamp by construction) may run; anything beyond is a broken or hostile clock and is refused so it cannot pin the endpoint's inventory forever.
const InstallerConfigKey = "installer.config"
const InstallerProvider = "kyidentity"
const LocalDockerEndpointID = "ep_local_docker"
const MaxApplicationValuesBytes = 64 * 1024
const MaxDeployNamespaces = 32
MaxDeployNamespaces bounds the namespaces one cluster manifest grants writes in.
const MaxDeploymentPlanBytes = 64 * 1024
const MaxDeploymentResultStoredBytes = 160 * 1024
const MaxSampleRowsPerEndpoint = 100000
MaxSampleRowsPerEndpoint is the backstop against container-ID cardinality: 100 containers × 360 rows at the capacity targets, with headroom.
const MaxSnapshotBytes = protocol.MaxSnapshotBytes
MaxSnapshotBytes is the shared limit from the protocol package.
Variables ¶
var ( ErrKeyRetired = errors.New("key retired") ErrKeyPendingReview = errors.New("key pending review") )
Sentinel errors let the handshake tell a retired key (the agent should switch to its acknowledged one) from a key still under review (the agent must keep using its old one).
var ( ErrMigrationOpen = errors.New("the application has an open migration") ErrMigrationNotReady = errors.New("the migration report is not ready") ErrMigrationState = errors.New("the migration's status does not allow this") ErrMigrationStale = errors.New("the source definition changed since the analysis") ErrStorageClassUnknown = errors.New("the destination reports no such StorageClass") ErrSizeInvalid = errors.New("invalid claim size") ErrVolumeUnknown = errors.New("the source mounts no such named volume") ErrApplicationNameTaken = errors.New("the destination's name is taken") // ErrDestinationNameTooLong is a destination name over validTenantName's 255 bytes. ErrDestinationNameTooLong = errors.New("the destination's name would be too long") // ErrInventoryStale is a destination cluster whose inventory is not fresh (freshInventory). ErrInventoryStale = errors.New("the destination cluster's inventory is stale") )
var ( ErrCommandInProgress = errors.New("a container recreate or run, or a workload apply or run, is in flight on this endpoint") ErrContainerManaged = errors.New("the container belongs to an adopted application") )
var ( // ErrNamespaceNotGranted is a cluster write in a namespace the endpoint's manifest does not // list: refused before any frame, whatever the agent's grant says. ErrNamespaceNotGranted = errors.New("the cluster's manifest does not grant writes in that namespace") // ErrWorkloadManaged is a configuration read, apply or delete of a workload a KyYard // application deployed; it changes through its application. ErrWorkloadManaged = errors.New("the workload belongs to a KyYard application") )
var ( ErrInvalidTimezone = errors.New("invalid update policy time zone") ErrInvalidWindow = errors.New("invalid update policy window") ErrInvalidWeekdays = errors.New("invalid update policy weekdays") ErrInvalidMode = errors.New("invalid update policy mode") ErrPolicyNotPaused = errors.New("update policy is not paused") // ErrPolicyChanged: a policy run's policy was deleted, paused, switched to plan_only or // saved by someone else before its apply. ErrPolicyChanged = errors.New("update policy changed during its run") )
var ( ErrRevisionCorrupt = errors.New("application revision digest mismatch") ErrRevisionConflict = errors.New("application revision changed") ErrApplicationLimit = errors.New("application storage limit reached") ErrForbidden = errors.New("tenant access denied") ErrInvalid = errors.New("invalid tenant input") ErrNotFound = errors.New("record not found") ErrAlreadyExists = errors.New("record already exists") ErrLastAdmin = errors.New("organization needs one active administrator") ErrStaleEvent = errors.New("directory event already applied or older than the last one") // ErrEndpointOffline says the endpoint is not connected, so there is nowhere to send a // command. It is distinct from a bad request: the caller asked for something reasonable // that cannot happen right now. ErrEndpointOffline = errors.New("endpoint is not connected") ErrInUse = errors.New("record is still referenced") ErrRotationPending = errors.New("a rotated key is already awaiting review") ErrRotationBlocked = errors.New("rotation is blocked until a duplicate connection is cleared") ErrSessionExpired = errors.New("session expired") ErrPairingExpired = errors.New("pairing session expired") ErrDeploymentPlanned = errors.New("a live deployment plan exists") // ErrDeploymentInProgress says a deployment is applying: neither a new plan nor a // release may proceed until it settles. ErrDeploymentInProgress = errors.New("a deployment is being applied") // ErrRemovalTooLarge says an instance holds more containers than one removal frame names. ErrRemovalTooLarge = errors.New("instance has more containers than one removal takes") // ErrRegistryNotConfigured says an image's host has no registry entry and the // organization has not opted in to anonymous pulls. ErrRegistryNotConfigured = errors.New("registry not configured") // ErrPrivateRegistriesDisabled refuses allow_private while the operator has not set // KY_REGISTRY_ALLOW_PRIVATE. ErrPrivateRegistriesDisabled = errors.New("private registries are disabled by the operator") ErrMappingRequired = errors.New("application has no adopted mapping") // ErrRuntimeUnsupported is an action the endpoint's runtime cannot take: a Docker action on // a Kubernetes endpoint, a pod log on a Docker one. ErrRuntimeUnsupported = errors.New("the endpoint's runtime does not support this action") // ErrUnreadableResult is a deployment result that fails validation even read as an older // agent's: nothing is stored, and the row waits for another answer or the sweep. ErrUnreadableResult = errors.New("unreadable deployment result") // ErrNamespaceUnknown is a mapping to a namespace the cluster's manifest does not list. ErrNamespaceUnknown = errors.New("the namespace is not one the cluster's manifest grants") // ErrPairingCodesExhausted says every draw within the retry budget collided with another // organization's still-live code; the caller may simply try again. ErrPairingCodesExhausted = errors.New("could not mint a unique pairing code") )
var ErrAdoptionChanged = errors.New("adoption preview changed or inventory unavailable")
var ErrAgentTokenLimit = errors.New("too many agent tokens")
ErrAgentTokenLimit refuses a token past maxAgentTokens live ones.
var ErrApplicationAdopted = errors.New("application has an adopted instance")
var ErrInstallerOwned = errors.New("installer-owned authority")
var ErrSampleBudget = errors.New("endpoint sample budget exhausted")
var ImageCheckDeadline = 60 * time.Second
ImageCheckDeadline bounds every registry call of one check; the API sizes its write deadline from it. A var so a test can shorten it.
var MigrationAcknowledgeable = []string{"network_references", "port_unpublished", "healthcheck_dropped", "resource_limits_dropped", "read_only_rootfs"}
MigrationAcknowledgeable are the analyzer's codes an operator answers by acknowledging them: in an application of several services, the names the others must use and a service no other can reach; and the settings the destination drops (a healthcheck, resource limits, a read-only root). The analyzer owns the vocabulary; the store only bounds the request.
Functions ¶
func AgentLastActive ¶ added in v0.4.4
func AgentLastActive(tok *ServiceToken) time.Time
AgentLastActive is when tok was last used, or created if never used: the idle clock.
func BaselineOf ¶
func BaselineOf(obs []Observation) (map[string]ServiceBaseline, bool)
BaselineOf is the baseline a first observation gives, false unless every service was either inspected or is known gone or replaced. A cluster service whose Deployment is already missing, recreated or edited gives none: its next poll judges it changed. One listing no pods gets an empty PodRestarts: the first pods to appear are the rollout's own, and their restarts count from 0.
func CheckMigrationChoices ¶
func CheckMigrationChoices(spec ApplicationSpec, classes []protocol.StorageClass, choices MigrationChoices) error
CheckMigrationChoices holds choices to at most MaxKubernetesClaims volumes and distinct MigrationAcknowledgeable codes, each volume to a named volume of spec, a valid size, ReadWriteOnce and one of the destination's classes. The API checks before it spends an inspection; the store checks again against the head revision.
func CleanAbsolutePath ¶
CleanAbsolutePath holds mount paths to absolute, normalized, display-safe (so at most 255 bytes) text with no surrounding whitespace.
func CommandPermission ¶
func CommandPermission(action string) (permissions.Action, bool)
CommandPermission is the permission a command action needs; false for an unknown action.
func ExecPodResource ¶
ExecPodResource is the audit resource of a pod terminal: endpoint/pods/namespace/pod/container.
func InstallerUserID ¶
func IsAgentScope ¶ added in v0.4.4
IsAgentScope reports whether scope is an AI agent token's.
func Judge ¶
func Judge(obs []Observation, baseline map[string]ServiceBaseline, final bool) (verdict, detail string)
Judge applies the verdict rules to one poll against baseline. It returns the terminal verdict and the service that decided it, or "" while the window goes on. final: observe_until has passed, so a service still starting is unhealthy and a complete, passing poll is healthy.
func KubernetesProject ¶
KubernetesProject is the project a Kubernetes instance takes from its application's name: lower-case letters and digits, other runs as one '-', at most 63 characters, "app" when nothing is left. It names the instance's objects and labels.
func NormalizeNamespaces ¶
NormalizeNamespaces sorts a namespace list and refuses one with more than MaxDeployNamespaces entries, a repeat, a name that is not a DNS-1123 label, the agent's own namespace (its Secrets are its identity) or a kube- system namespace.
func NormalizeRegistryHost ¶
NormalizeRegistryHost returns host as image references name it: lowercase host[:port], with Docker Hub's aliases folded into docker.io. Like ParseReference, it takes only localhost or a name with a dot or port as a registry.
func ParseStoredTime ¶
ParseStoredTime reads a timestamp in whichever shape the driver returned it. It is exported because anything inspecting the database from outside has to agree with the store about what it wrote, and a second, narrower copy of these layouts would drift silently.
func ValidDeclaredVolumeName ¶
ValidDeclaredVolumeName is the grammar for a newly declared volume name, at least two characters. Importers use this, not ValidVolumeName, so a one-character name can no longer be declared even though one already stored still validates.
func ValidEndpointName ¶
ValidEndpointName is the rule Enroll and RenameEndpoint apply to an endpoint's name.
func ValidVolumeName ¶
ValidVolumeName is Docker's volume name grammar, as stored: it also validates volumes in revisions saved before ValidDeclaredVolumeName's two-character minimum took effect.
func ValidateApplicationSpec ¶
func ValidateApplicationSpec(spec ApplicationSpec) error
func ValidateInstallerBundle ¶
func ValidateInstallerBundle(b applysetup.Common) error
func ValidateSamples ¶
func VolumeHostName ¶
func VolumeHostName(project string, v DeclaredVolume) string
VolumeHostName is the runtime volume name, as docker compose derives it.
func WorkloadAction ¶
WorkloadAction reports whether action targets a Kubernetes workload or pod.
Types ¶
type AdoptedContainer ¶
type AdoptedContainer struct {
ID string `json:"id"`
Name string `json:"name"`
ImageID string `json:"image_id"`
CreatedAt time.Time `json:"created_at"`
// Mounts as the inventory reported them; nil when the agent reports none (older than
// mounts). Preflight compares binds against them.
Mounts []protocol.Mount `json:"mounts,omitempty"`
MountsTruncated bool `json:"mounts_truncated,omitempty"`
}
type AdoptionPreview ¶
type AdoptionPreview struct {
ApplicationID string `json:"application_id"`
ApplicationName string `json:"application_name"`
Revision int `json:"revision"`
EndpointID string `json:"endpoint_id"`
EndpointName string `json:"endpoint_name"`
Project string `json:"project"`
Containers []AdoptedContainer `json:"containers"`
Digest string `json:"digest"`
}
type AdoptionRequest ¶
type AgentIdentity ¶
AgentIdentity is what the connection handshake needs: the endpoint and the key that may authenticate it. Pending endpoints authenticate with their key under review so they can receive the approval notice; nothing else is granted to them.
type AgentTokenIssue ¶ added in v0.4.4
type AgentTokenIssue struct {
ServiceToken
Token string `json:"token"`
}
AgentTokenIssue is a created agent token: the bearer, once.
type Application ¶
type Application struct {
ID string `json:"id"`
OrganizationID string `json:"organization_id"`
EnvironmentID string `json:"environment_id"`
Name string `json:"name"`
LatestRevision int `json:"latest_revision"`
CreatedBy string `json:"created_by"`
CreatedAt time.Time `json:"created_at"`
// RemovedAt is set once a removal took its containers off the host; revisions and history
// stay until discard or ApplicationRemovedRetention.
RemovedAt *time.Time `json:"removed_at"`
}
type ApplicationComparison ¶
type ApplicationComparison struct {
InstanceID string `json:"instance_id"`
EndpointID string `json:"endpoint_id"`
EndpointName string `json:"endpoint_name"`
Project string `json:"project"`
Revision int `json:"revision"`
AdoptedRevision int `json:"adopted_revision"`
Digest string `json:"digest"`
ReceivedAt *time.Time `json:"received_at"`
Availability string `json:"availability"`
Services []ComparisonService `json:"services"`
Containers []ComparisonContainer `json:"containers"`
}
type ApplicationInstance ¶
type ApplicationInstance struct {
ContainerCount int `json:"container_count"`
EndpointName string `json:"endpoint_name"`
ID string `json:"id"`
ApplicationID string `json:"application_id"`
EndpointID string `json:"endpoint_id"`
Project string `json:"project"`
Revision int `json:"revision"`
MappingVersion int `json:"mapping_version"`
CurrentRevision int `json:"current_revision"`
PreviousRevision int `json:"previous_revision"`
CreatedBy string `json:"created_by"`
CreatedAt time.Time `json:"created_at"`
Containers []AdoptedContainer `json:"containers"`
// Namespace is set exactly for an instance mapped to a Kubernetes endpoint.
Namespace string `json:"namespace,omitempty"`
}
type ApplicationMapping ¶
type ApplicationMapping struct {
InstanceID string `json:"instance_id"`
Version int `json:"version"`
MappedRevision int `json:"mapped_revision"`
Preview *AdoptionPreview `json:"preview"`
Services []string `json:"services"`
Bindings map[string]string `json:"bindings"`
// Runtime is the endpoint's. A Kubernetes mapping names its Namespace and the namespaces
// the cluster's manifest grants; it has no containers and no bindings.
Runtime string `json:"runtime"`
Namespace string `json:"namespace,omitempty"`
DeployNamespaces []string `json:"deploy_namespaces,omitempty"`
}
type ApplicationMigration ¶
type ApplicationMigration struct {
ID string `json:"id"`
ApplicationID string `json:"application_id"`
ApplicationName string `json:"application_name"`
DestinationApplicationID string `json:"destination_application_id,omitempty"`
DestinationApplicationName string `json:"destination_application_name,omitempty"`
DestinationEndpointID string `json:"destination_endpoint_id"`
Namespace string `json:"namespace"`
Status string `json:"status"`
SourceRevision int `json:"source_revision"`
Ready bool `json:"ready"`
Report json.RawMessage `json:"report"`
Choices MigrationChoices `json:"choices"`
CreatedBy string `json:"created_by"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
ValidatedBy string `json:"validated_by,omitempty"`
ValidatedAt *time.Time `json:"validated_at,omitempty"`
ValidatedNote string `json:"validated_note,omitempty"`
ConfirmedBy string `json:"confirmed_by,omitempty"`
ConfirmedAt *time.Time `json:"confirmed_at,omitempty"`
CutoverNote string `json:"cutover_note,omitempty"`
Role string `json:"role"`
}
ApplicationMigration is one migration of a Docker source to a destination application on a cluster. Report is the analyzer's JSON, stored as produced. Role says which end the application it was read for is.
type ApplicationPort ¶
type ApplicationRevision ¶
type ApplicationRevision struct {
ID string `json:"id"`
ApplicationID string `json:"application_id"`
OrganizationID string `json:"organization_id"`
EnvironmentID string `json:"environment_id"`
Number int `json:"number"`
Spec ApplicationSpec `json:"spec"`
Digest string `json:"digest"`
CreatedBy string `json:"created_by"`
CreatedAt time.Time `json:"created_at"`
}
type ApplicationSecretRef ¶
type ApplicationSecretRef struct {
SecretRef string `json:"secret_ref"`
}
type ApplicationService ¶
type ApplicationService struct {
Ports []ApplicationPort `json:"ports,omitempty"`
Restart string `json:"restart,omitempty"`
Name string `json:"name"`
Image string `json:"image"`
Environment map[string]ApplicationSecretRef `json:"environment,omitempty"`
Volumes []ApplicationVolume `json:"volumes,omitempty"`
}
type ApplicationSpec ¶
type ApplicationSpec struct {
Kind string `json:"kind"`
Services []ApplicationService `json:"services"`
Volumes []DeclaredVolume `json:"volumes,omitempty"`
// Kubernetes holds what only a cluster needs: a migration's destination revision carries
// storage and networking choices. The Compose importer never sets it.
Kubernetes *KubernetesExtension `json:"kubernetes,omitempty"`
}
ApplicationSpec is the initial secret-reference-only desired-state contract. It is not a Compose document or a reconstruction of runtime inventory. Import must reject unsupported fields before constructing it (docs/application-schema.md).
type ApplicationVolume ¶
type ApplicationVolume struct {
Kind string `json:"kind"`
Source string `json:"source"`
Target string `json:"target"`
ReadOnly bool `json:"read_only,omitempty"`
}
ApplicationVolume mounts a declared volume (Kind "named", Source its name) or an absolute host path (Kind "bind") at Target.
type AuditRecord ¶
type AuditRecord struct {
Scope string `json:"scope"`
OrganizationID string `json:"organization_id"`
EnvironmentID string `json:"environment_id"`
CorrelationID string `json:"correlation_id"`
Result string `json:"result"`
ID int64 `json:"id"`
UserID string `json:"user_id"`
Action string `json:"action"` // e.g. "auth.login", "scim.user_created"
Resource string `json:"resource"`
Details string `json:"details,omitempty"`
IPAddress string `json:"ip_address"`
CreatedAt time.Time `json:"created_at"`
}
AuditRecord records actor (UserID), target (Resource), scope and outcome.
type AuditStore ¶
type AuditStore interface {
LogAudit(ctx context.Context, r *AuditRecord) error
ListAuditRecords(ctx context.Context, offset, limit int) ([]*AuditRecord, int, error)
}
AuditStore logs security events.
type BlockedService ¶
type BlockedService struct {
Name string `json:"name"`
Blockers []string `json:"blockers"`
Unsupported []string `json:"unsupported,omitempty"`
Details map[string]string `json:"details,omitempty"`
}
BlockedService names a service a refused plan blocked on: its own blockers and the codes a live inspection reported, nothing else about it.
type Command ¶
type Command struct {
ID string `json:"id"`
EndpointID string `json:"endpoint_id"`
OrganizationID string `json:"organization_id"`
EnvironmentID string `json:"environment_id"`
ActorID string `json:"actor_id"`
RequestID string `json:"request_id"`
Action string `json:"action"`
ContainerID string `json:"container_id,omitempty"`
Reference string `json:"reference,omitempty"`
Expects protocol.Expectation `json:"expects"`
Deadline time.Time `json:"deadline"`
Outcome string `json:"outcome"`
Detail string `json:"detail,omitempty"`
CreatedAt time.Time `json:"created_at"`
DispatchedAt *time.Time `json:"dispatched_at,omitempty"`
SettledAt *time.Time `json:"settled_at,omitempty"`
// Result is a direct recreate or run's step table; nil for every other command.
Result *storedDeploymentResult `json:"result,omitempty"`
// ResultContainerID is the container a direct command created; ContainerID stays its target.
ResultContainerID string `json:"result_container_id,omitempty"`
}
Command is one instruction and what became of it. Outcome is empty while the command is in flight; afterwards it is one of protocol's five, and the set is closed, so a command whose answer never arrived reads as unknown rather than as a row with nothing in it.
type ComparisonContainer ¶
type ComparisonService ¶
type DeclaredVolume ¶
type Deployment ¶
type Deployment struct {
ID string `json:"id"`
ApplicationID string `json:"application_id"`
InstanceID string `json:"instance_id"`
EndpointID string `json:"endpoint_id"`
EndpointName string `json:"endpoint_name"`
Kind string `json:"kind"`
State string `json:"state"`
Revision int `json:"revision"`
SpecDigest string `json:"spec_digest"`
MappingVersion int `json:"mapping_version"`
Plan DeploymentPlan `json:"plan"`
CreatedBy string `json:"created_by"`
CreatedAt time.Time `json:"created_at"`
ExpiresAt time.Time `json:"expires_at"`
Expired bool `json:"expired"`
AppliedBy string `json:"applied_by"`
AppliedAt *time.Time `json:"applied_at"`
Deadline *time.Time `json:"deadline"`
SettledAt *time.Time `json:"settled_at"`
Detail string `json:"detail"`
// CorrelationID is the plan's request ID: the frame and every audit row of the deployment carry it.
CorrelationID string `json:"correlation_id"`
Result *protocol.DeploymentResult `json:"result"` // nil until settled
// Validation is the deployment's health validation: nil for a plan, a removal or an apply
// that did not succeed.
Validation *Validation `json:"validation,omitempty"`
// MigrationID names the open migration whose destination this apply deployed, set when the
// row turned applying.
MigrationID string `json:"migration_id,omitempty"`
// RetainedClaims names the claims a settled cluster removal reported kept (retainedClaims).
RetainedClaims []string `json:"retained_claims,omitempty"`
}
type DeploymentPlan ¶
type DeploymentPlan struct {
Project string `json:"project"`
Services []PlannedService `json:"services"`
Containers []RemovalPlanTarget `json:"containers,omitempty"`
// Volumes are the named volumes the agent ensures, host names in first-use order.
Volumes []string `json:"volumes,omitempty"`
// Namespace is set exactly for a Kubernetes plan or removal.
Namespace string `json:"namespace,omitempty"`
// Claims are the PersistentVolumeClaims a Kubernetes apply ensures.
Claims []protocol.KubernetesClaim `json:"claims,omitempty"`
}
DeploymentPlan is what a row decided: the services an apply replaces, or the containers a removal stops and deletes (Services then empty).
type DeploymentPreflight ¶
type DeploymentPreflight struct {
InstanceID string `json:"instance_id"`
EndpointID string `json:"endpoint_id"`
EndpointName string `json:"endpoint_name"`
Revision int `json:"revision"`
MappingVersion int `json:"mapping_version"`
ReceivedAt time.Time `json:"received_at"`
Executable bool `json:"executable"`
Blockers []string `json:"blockers"`
Services []PreflightService `json:"services"`
}
type DevicePairing ¶
type DevicePairing struct {
// Secret and PushToken never serialise: this record is reached by unauthenticated
// pair/verify and pair/poll callers. A handler that must return one needs its own type.
Secret string `json:"-"` // Ephemeral secret for exchange
UserID string `json:"user_id,omitempty"`
DeviceName string `json:"device_name,omitempty"`
Platform string `json:"platform,omitempty"` // "android", "ios", "pwa", "desktop"
PushToken string `json:"-"`
Status string `json:"status"` // "pending", "approved", "consumed", "expired"
CreatedAt time.Time `json:"created_at"`
ExpiresAt time.Time `json:"expires_at"`
}
DevicePairing represents a 90-second ephemeral session to link mobile/PWA wrappers.
type DeviceStore ¶
type DeviceStore interface {
CreatePairing(ctx context.Context, p *DevicePairing) error
GetPairingBySecret(ctx context.Context, secret string) (*DevicePairing, error)
ConsumePairing(ctx context.Context, secret, deviceName, platform, pushToken string) error
CleanExpiredPairings(ctx context.Context) error
}
DeviceStore handles 90s ephemeral QR pairing sessions and paired push clients.
type DigestResolver ¶
type DigestResolver interface {
Head(ctx context.Context, ref registry.Reference, cred *registry.Credential, allowPrivate bool) (string, error)
// CheckHost refuses ref's host where Head would, without a registry request.
CheckHost(ctx context.Context, ref registry.Reference, allowPrivate bool) error
}
DigestResolver is what the check needs from a registry client. The API satisfies it with internal/registry; tests use a fake. Head must return once ctx ends: the check waits for it.
type DirectCommand ¶
type DirectCommand struct {
Action string
// Confirm repeats the container's current name (recreate) or the new one (run).
Confirm string
// State is the replaced container's state the operator saw; recreate only.
State string
MaxFrameBytes int
// AllowPrivileged is KY_CONTAINER_ALLOW_PRIVILEGED: without it a host-level setting is refused.
AllowPrivileged bool
// Frame has one explicit service; identity, issue time and deadline are set here.
Frame protocol.DeploymentRequest
}
DirectCommand is a recreate or run as the API built it.
type DirectoryEvent ¶
DirectoryEvent identifies one signed identity provider event.
type DirectoryTx ¶
type DirectoryTx interface {
GetUserBySSO(provider, subject string) (*User, error)
GetUserByUsername(username string) (*User, error)
CreateUser(u *User) error
// UpdateUserIdentity writes only username, email, display name, role and status, leaving
// credential and MFA columns to their own compare-and-swap writers.
UpdateUserIdentity(u *User) error
DeleteUser(id string) error
DeleteUserSessions(userID string) error
}
DirectoryTx is the identity provider's reads and writes inside one event's transaction. Its writes always apply; an organization they leave without an active administrator gets an organization.last_admin_lost audit row.
type Endpoint ¶
type Endpoint struct {
ID string `json:"id"`
OrganizationID string `json:"organization_id"`
EnvironmentID string `json:"environment_id"`
Name string `json:"name"`
Runtime string `json:"runtime"`
State string `json:"state"`
Facts map[string]string `json:"facts"`
Fingerprint string `json:"fingerprint"` // key under review while pending, approved key afterwards
// PendingFingerprint is a rotated key awaiting operator acknowledgement, if any.
PendingFingerprint string `json:"pending_fingerprint,omitempty"`
Capabilities []string `json:"capabilities"`
Alerts []EndpointEvent `json:"alerts"` // unacknowledged high-severity events
// ClusterHealth is derived on read from the stored inventory; Kubernetes endpoints only.
ClusterHealth string `json:"cluster_health,omitempty"`
CreatedAt time.Time `json:"created_at"`
ApprovedAt *time.Time `json:"approved_at,omitempty"`
ApprovedBy string `json:"approved_by,omitempty"`
RevokedAt *time.Time `json:"revoked_at,omitempty"`
LastSeenAt *time.Time `json:"last_seen_at,omitempty"`
// DeployNamespaces are the namespaces the cluster's last manifest grants writes in, sorted;
// empty for a Docker endpoint.
DeployNamespaces []string `json:"deploy_namespaces"`
}
Endpoint is an enrolled (or enrolling) host. Facts are the bounded enrollment report.
type EndpointEvent ¶
type EndpointEvent struct {
ID int64 `json:"id"`
Severity string `json:"severity"`
Kind string `json:"kind"`
Details string `json:"details"`
CreatedAt time.Time `json:"created_at"`
AcknowledgedAt *time.Time `json:"acknowledged_at,omitempty"`
}
EndpointEvent is a bounded, operator-facing record; high-severity ones surface until acknowledged.
type EnrollmentRequest ¶
type EnrollmentRequest struct {
Token []byte
PublicKey []byte
Proof []byte
Name string
Facts map[string]string
IPAddress string
}
EnrollmentRequest is what an agent presents; everything in it is untrusted.
type EnrollmentToken ¶
type EnrollmentToken struct {
ID string `json:"id"`
EnvironmentID string `json:"environment_id"`
Runtime string `json:"runtime"`
ExpiresAt time.Time `json:"expires_at"`
AgentImage string `json:"agent_image,omitempty"`
Secret []byte `json:"-"`
}
EnrollmentToken is returned once; Secret is the raw token and is never stored.
type Environment ¶
type ImageCheck ¶
type ImageCheck struct {
Service string `json:"service"`
Reference string `json:"reference"`
LocalDigest string `json:"local_digest"`
RemoteDigest string `json:"remote_digest"`
Verdict string `json:"verdict"`
Detail string `json:"detail"`
CheckedAt time.Time `json:"checked_at"`
}
ImageCheck is the cached update verdict for one mapped service.
type InvalidSpecError ¶
type InvalidSpecError struct{ Blockers []string }
InvalidSpecError names what stops a direct command's configuration.
func (*InvalidSpecError) Error ¶
func (e *InvalidSpecError) Error() string
type Inventory ¶
type Inventory struct {
EndpointID string `json:"endpoint_id"`
State string `json:"state"`
Generation uint64 `json:"generation"`
ObservedAt time.Time `json:"observed_at"`
ReceivedAt time.Time `json:"received_at"`
Snapshot json.RawMessage `json:"snapshot"`
}
Inventory is the stored snapshot plus the freshness facts the UI needs to tell stale from current: when the agent observed it, when the server received it, and the endpoint state.
type KubernetesExtension ¶
type KubernetesExtension struct {
Volumes map[string]KubernetesVolume `json:"volumes"`
ServiceIPs map[string]string `json:"service_ips,omitempty"`
}
KubernetesExtension carries storage choices per named volume and optional Service IPs. A chosen volume becomes a PersistentVolumeClaim on a cluster.
type KubernetesObject ¶
KubernetesObject names a service's objects: the Deployment and Service <name>, the ConfigMap <name>-env-<suffix> and the Secret <name>-secret-<suffix>.
type KubernetesVolume ¶
type KubernetesVolume struct {
StorageClass string `json:"storage_class"`
Size string `json:"size"`
AccessMode string `json:"access_mode"`
}
KubernetesVolume is one volume's claim: StorageClass "" is the cluster default, Size a whole number of Mi, Gi or Ti from 1Mi to 16Ti, AccessMode ReadWriteOnce.
func (KubernetesVolume) Valid ¶
func (v KubernetesVolume) Valid() bool
Valid checks one choice's grammar; the destination inventory decides whether its class exists.
type LogTarget ¶
LogTarget is the container a log request resolved to, as the endpoint last reported it.
type MFAState ¶
MFAState is the second-factor slice of a users row that self-service enrolment changes.
type MappingRequest ¶
type MappingRequest struct {
InstanceID string `json:"instance_id"`
Version int `json:"version"`
Digest string `json:"digest"`
Confirm string `json:"confirm"`
Bindings map[string]string `json:"bindings"`
EndpointID string `json:"endpoint_id"`
Namespace string `json:"namespace"`
}
MappingRequest binds services to adopted containers (Docker), or, with EndpointID and Namespace and nothing else, maps the application to a namespace of a Kubernetes endpoint.
type MemberOrganization ¶
type MemberOrganization struct {
ID string `json:"id"`
Name string `json:"name"`
Role TenantRole `json:"role"`
}
MemberOrganization is one of the caller's own organizations with the role held there.
type MigrationAnalysis ¶
MigrationAnalysis is what the analyzer produced for revision Revision of the source.
type MigrationChoices ¶
type MigrationChoices struct {
Volumes map[string]KubernetesVolume `json:"volumes"`
Acknowledged []string `json:"acknowledged"`
}
MigrationChoices are the operator's answers: a claim per named volume, and the findings they acknowledge that have nothing to record (MigrationAcknowledgeable).
type MigrationDestination ¶
type MigrationDestination struct {
EndpointID string
Namespaces []string
StorageClasses []protocol.StorageClass
Name string
Project string
}
MigrationDestination is the cluster side: its namespaces and StorageClasses, and the name and project the destination application takes.
type MigrationSource ¶
type MigrationSource struct {
ApplicationName string
Revision int
Spec ApplicationSpec
Project string
EndpointID string
Containers map[string]protocol.Container
Volumes []protocol.Volume
Destination MigrationDestination
}
MigrationSource is everything the analyzer reads: the source's latest revision, its project and mapped containers by service from the endpoint's fresh inventory, the endpoint's volumes, and the destination.
type MigrationStart ¶
type MigrationStart struct {
DestinationEndpointID string `json:"destination_endpoint_id"`
Namespace string `json:"namespace"`
}
MigrationStart names the cluster and namespace a migration targets.
type Observation ¶
type Observation struct {
Service string
Presence string
Inspection *protocol.ContainerInspection
Generation int64
}
Observation is one service at one poll: its presence and, when one succeeded, its inspection. Generation is a cluster service's settled Deployment generation.
type ObservedService ¶
type ObservedService struct {
protocol.DeploymentIdentity
Presence string
}
ObservedService is a settled identity and where it stands now.
type Organization ¶
type OrganizationGroup ¶
type OrganizationMember ¶
type OrganizationMember struct {
UserID string `json:"user_id"`
Username string `json:"username"`
Role TenantRole `json:"role"`
Status string `json:"status"`
}
OrganizationMember is a membership joined with the account it names.
type OrganizationMembership ¶
type OrganizationMembership struct {
OrganizationID string `json:"organization_id"`
UserID string `json:"user_id"`
Role TenantRole `json:"role"`
Status string `json:"status"`
}
type OrganizationSummary ¶
type PendingValidation ¶
type PendingValidation struct {
Validation
OrganizationID, EnvironmentID, ApplicationID, InstanceID, EndpointID string
Baseline map[string]ServiceBaseline
Services []ObservedService
// Health: the endpoint's agent can report what validation reads, container.inspect.health
// on Docker and kubernetes.inspect on a cluster (Kubernetes).
Health, Kubernetes bool
// Released: the instance is gone.
Released bool
// PolicyID and CreatedBy name the automated run's policy; empty once it is deleted.
PolicyID, CreatedBy string
}
PendingValidation is a validation the loop still has work on, with what it needs to do it.
type PlanRequest ¶
type PlanRequest struct {
InstanceID string `json:"instance_id"`
MappingVersion int `json:"mapping_version"`
Revision int `json:"revision"`
Confirm string `json:"confirm"`
// Update names services to pull from the registry, pinned to its digest at plan time.
Update []string `json:"update"`
// Set by the API, never read from a client: the largest frame the endpoint's agent accepts,
// and one live inspection per mapped container, keyed by container ID.
MaxFrameBytes int `json:"-"`
Inspections map[string]protocol.ContainerInspection `json:"-"`
// PinImages is set only by a validation's rollback: service to image ID, taken instead of
// resolving the service's tag. The ID must be on the host; nothing is pulled. On a cluster it
// maps every service to a digest reference (host/repository@sha256:...), which the plan pulls
// with no registry call.
PinImages map[string]string `json:"-"`
}
type PlannedService ¶
type PlannedService struct {
Name string `json:"name"`
Reference string `json:"reference"`
ImageID string `json:"image_id"`
ImageDigest string `json:"image_digest"`
ContainerID string `json:"container_id"`
Replaces protocol.InspectionTarget `json:"replaces"`
Restart string `json:"restart"`
Ports []ApplicationPort `json:"ports"`
SecretRefs []string `json:"secret_refs"`
// Set for a pulled service: apply sends the pull and no image ID.
PullReference string `json:"pull_reference,omitempty"`
PullDigest string `json:"pull_digest,omitempty"`
// Mounts are the preflight's resolved list; binds on it are already on the replaced container.
Mounts []protocol.Mount `json:"mounts,omitempty"`
// DroppedMounts are the replaced container's mounts the recreate leaves off, for approval.
DroppedMounts []protocol.Mount `json:"dropped_mounts,omitempty"`
// Object is the Deployment (and Service) a Kubernetes plan applies for this service; nil on
// Docker. Replaces, ImageID and Mounts are then empty and the service always pulls.
Object *KubernetesObject `json:"object,omitempty"`
// ClaimMounts mount the plan's claims into a Kubernetes service.
ClaimMounts []protocol.KubernetesMount `json:"claim_mounts,omitempty"`
ClusterIP string `json:"cluster_ip,omitempty"`
}
type PolicyInput ¶
type PolicyInput struct {
Mode string `json:"mode"`
Timezone string `json:"timezone"`
Weekdays []int `json:"weekdays"`
StartMinute int `json:"start_minute"`
EndMinute int `json:"end_minute"`
}
PolicyInput is what an administrator saves: a mode and a weekly window in an IANA zone.
type PolicyRun ¶
type PolicyRun struct {
ID string `json:"id"`
PolicyID string `json:"policy_id"`
// Occurrence is the window's start, UTC: the run's identity with PolicyID.
Occurrence time.Time `json:"occurrence"`
StartedAt time.Time `json:"started_at"`
FinishedAt *time.Time `json:"finished_at"`
Outcome string `json:"outcome"`
DeploymentID string `json:"deployment_id"`
Detail string `json:"detail"`
CorrelationID string `json:"correlation_id"`
// Validation is the run's deployment's health validation, rollback included; nil without one.
Validation *Validation `json:"validation,omitempty"`
}
type PreflightBlockedError ¶
type PreflightBlockedError struct {
Blockers []string
// Services are the planned services that carry blockers of their own.
Services []BlockedService
}
PreflightBlockedError names the findings that stopped a plan. A plan never guesses past them.
func (*PreflightBlockedError) Error ¶
func (e *PreflightBlockedError) Error() string
type PreflightService ¶
type PreflightService struct {
InspectionTarget *protocol.InspectionTarget `json:"inspection_target,omitempty"`
Name string `json:"name"`
Reference string `json:"reference"`
ImageID string `json:"image_id"`
ContainerID string `json:"container_id"`
Blockers []string `json:"blockers"`
// Mounts is the definition's volumes resolved to host names. DroppedMounts are the mapped
// container's mounts a recreate leaves off; DroppedBinds are the binds among them.
// UnsupportedMounts are the container's mounts the agent refuses to replace.
Mounts []protocol.Mount `json:"mounts"`
DroppedBinds []protocol.Mount `json:"dropped_binds"`
DroppedMounts []protocol.Mount `json:"dropped_mounts"`
UnsupportedMounts []protocol.Mount `json:"unsupported_mounts"`
// Unsupported are the codes a plan-time live inspection reported (configuration_unsupported).
Unsupported []string `json:"unsupported,omitempty"`
// Details is a code's parameter, where one has one: k8s_volume is choice_required when every
// volume behind it is a named volume that only lacks a storage choice.
Details map[string]string `json:"details,omitempty"`
}
type Pressure ¶
type Pressure int32
Pressure is how close stored data is to its disk budget (docs/retention-policy.md).
const ( // PressureNormal accepts everything. PressureNormal Pressure = iota // PressureDegraded refuses metrics: they are the cheapest telemetry to lose and the // fastest to grow. Inventory, heartbeats, endpoint state and audit continue. PressureDegraded // PressureStopped refuses inventory as well. Heartbeats, endpoint state and audit // continue, so the fleet stays visible and every refusal is still recorded. PressureStopped )
type Registry ¶
type Registry struct {
ID string `json:"id"`
OrganizationID string `json:"organization_id"`
Host string `json:"host"`
Name string `json:"name"`
Username string `json:"username"`
HasCredential bool `json:"has_credential"`
AllowPrivate bool `json:"allow_private"`
CreatedBy string `json:"created_by"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
Registry is a per-organization registry entry. The credential is write-only: rows report HasCredential and never carry the secret or its ciphertext.
type RegistryAccess ¶
type RegistryAccess struct {
Registry *Registry
Credential *registry.Credential `json:"-"` // nil when anonymous or none stored
Anonymous bool // the host has no entry and the opt-in allowed it
}
RegistryAccess is internal: it holds a decrypted secret and is never serialized.
type RegistryInput ¶
type RegistryPolicy ¶
type RegistryPolicy struct {
AnonymousPullEnabled bool `json:"anonymous_pull_enabled"`
}
type RemovalBody ¶
type RemovalPlanTarget ¶
type Rollback ¶
type Rollback struct {
InstanceID string
MappingVersion int
Project string
Revision int
// Images maps each service to its plan's Replaces image ID on Docker, and on a cluster to the
// prior succeeded apply's pull reference (host/repository@sha256:...).
Images map[string]string
}
Rollback is what an automated rollback re-applies: the revision the failed deployment replaced, each service pinned to the image it ran before.
type RollupRow ¶
type RollupRow struct {
ContainerID string `json:"container_id"`
Hour time.Time `json:"hour"`
Samples int64 `json:"samples"`
CPUAverage float64 `json:"cpu_avg"`
CPUPeak float64 `json:"cpu_max"`
MemoryAvg int64 `json:"memory_avg"`
MemoryPeak int64 `json:"memory_max"`
RxBytes int64 `json:"rx_bytes"`
TxBytes int64 `json:"tx_bytes"`
PidsPeak int64 `json:"pids_max"`
RestartCount int64 `json:"restart_count"`
}
RollupRow is one container's hour, summarised. A sample the runtime would not answer for is counted in neither average nor maximum, and an hour with nothing but such samples reports -1 for that measure rather than zero, so "no data" survives the summary.
type SQLStore ¶
type SQLStore struct {
// contains filtered or unexported fields
}
SQLStore implements Store on top of database/sql.
func (*SQLStore) ApplyInstaller ¶
func (s *SQLStore) ApplyInstaller(ctx context.Context, b applysetup.Common, check bool) (applysetup.Report, error)
func (*SQLStore) ApplyInstallerDirectory ¶
func (s *SQLStore) ApplyInstallerDirectory(ctx context.Context, issuer, subject, event, revision, digest string, assigned, admin bool) error
Directory messages change availability, never account binding or role. Audit, replay fence and grant revocation commit together in the native database.
func (*SQLStore) Audit ¶
func (s *SQLStore) Audit() AuditStore
func (*SQLStore) Devices ¶
func (s *SQLStore) Devices() DeviceStore
func (*SQLStore) EvaluatePressure ¶
EvaluatePressure re-reads usage and settles the level, returning it. Degrading at 95 % leaves room to prune before anything must stop; the threshold divides before multiplying so a very large budget cannot overflow into a negative one.
What raises the level is being over budget *and still growing*. Any prune pass under pressure releases it, whether or not it freed rows.
Release cannot depend on the reading falling. A delete returns pages to the table rather than the file, a plain PostgreSQL vacuum never shrinks an index, and the reading counts data retention cannot touch at all: audit, which is never refused and not yet pruned, and inventory, where a report replaces a row rather than adding one. So once a pass has taken everything retention is owed, holding the level achieves nothing that dropping more metrics could fix — it would only refuse telemetry for the rest of the server's life.
The result at the ceiling is a throttle rather than a stop: telemetry resumes, usage grows, the level returns. That is escapable by construction, and a condition that persists is reported at intervals rather than once, because it needs an operator, not a log line.
func (*SQLStore) InstallerConfiguration ¶
func (*SQLStore) InstallerUserAllowed ¶
func (*SQLStore) RevokeInstallerIdentity ¶
Loss of an app-specific claim disables the account until a newer signed directory assignment explicitly restores it; a login cannot reactivate it.
func (*SQLStore) SampleCeiling ¶
SampleCeiling is the stored-rows-per-endpoint limit this store enforces.
func (*SQLStore) Sessions ¶
func (s *SQLStore) Sessions() SessionStore
func (*SQLStore) SetAllowPrivileged ¶
func (*SQLStore) SetPressure ¶
func (*SQLStore) Settings ¶
func (s *SQLStore) Settings() SettingsStore
func (*SQLStore) Suite ¶ added in v0.4.3
func (s *SQLStore) Suite() SuiteStore
func (*SQLStore) Tenancy ¶
func (s *SQLStore) Tenancy() TenancyStore
type SampleRow ¶
type SampleRow struct {
ContainerID string `json:"container_id"`
ObservedAt time.Time `json:"observed_at"`
CPUPercent float64 `json:"cpu_percent"`
MemoryBytes int64 `json:"memory_bytes"`
MemoryLimit int64 `json:"memory_limit"`
RxBytes int64 `json:"rx_bytes"`
TxBytes int64 `json:"tx_bytes"`
Pids int64 `json:"pids"`
RestartCount int64 `json:"restart_count"`
}
SampleRow is a stored sample with its time; a missing row is "no data", never zero.
type ScheduledPolicy ¶
type ScheduledPolicy struct {
Policy UpdatePolicy
// EndpointID is the adopted instance's endpoint; "" when the application is not adopted.
EndpointID string
// EndpointBusy: a deployment on that endpoint is applying, or planned and unexpired.
EndpointBusy bool
// Open: Occurrence is open now and has no run row.
Open bool
Occurrence time.Time
// Missed: Previous ended after the policy's last change and has no run row.
Missed bool
Previous time.Time
}
ScheduledPolicy is an active policy as the scheduler sees it at one instant.
type ServiceBaseline ¶
type ServiceBaseline struct {
ContainerID string `json:"container_id"`
RestartCount int `json:"restart_count"`
PodRestarts map[string]int `json:"pod_restarts,omitempty"`
}
ServiceBaseline is one service at the first observation after grace. A cluster service keeps PodRestarts instead: each listed pod's UID and its containers' summed restarts.
type ServicePairing ¶
type ServicePairing struct {
ID string `json:"id"`
Code string `json:"code"`
ExpiresAt time.Time `json:"expires_at"`
}
ServicePairing is a six-digit code shown once to an organization administrator.
type ServiceToken ¶
type ServiceToken struct {
ID string `json:"id"`
OrganizationID string `json:"organization_id"`
Name string `json:"name"`
CreatedBy string `json:"created_by"`
CreatedAt time.Time `json:"created_at"`
LastUsedAt *time.Time `json:"last_used_at,omitempty"`
LastIP string `json:"last_ip,omitempty"`
RevokedAt *time.Time `json:"revoked_at,omitempty"`
// Scope is pulse for a kyPulse token, or an agent token's access level (ScopeMCPRead,
// ScopeMCPOperate). A token authenticates only where its scope belongs.
Scope string `json:"scope"`
}
ServiceToken is another Ky product's read-only credential for one organization. The secret is never stored: token_hash is its SHA-256.
type ServiceTokenIssue ¶
type ServiceTokenIssue struct {
Token string `json:"token"`
Organization Organization `json:"organization"`
}
ServiceTokenIssue is the claim response: the token, once, and the organization it reads.
type Session ¶
type Session struct {
TokenHash string `json:"token_hash"`
UserID string `json:"user_id"`
UserAgent string `json:"user_agent"`
IPAddress string `json:"ip_address"`
CreatedAt time.Time `json:"created_at"`
ExpiresAt time.Time `json:"expires_at"`
}
Session represents an active authenticated user session.
type SessionStore ¶
type SessionStore interface {
CreateSession(ctx context.Context, s *Session, expectedPasswordHash string) error
GetSession(ctx context.Context, tokenHash string) (*Session, error)
DeleteSession(ctx context.Context, tokenHash string) error
DeleteUserSessions(ctx context.Context, userID string) error
CleanExpiredSessions(ctx context.Context) error
CreateMFAChallenge(ctx context.Context, challenge *MFAChallenge, expectedPasswordHash string) error
ConsumeMFAChallenge(ctx context.Context, tokenHash string) (userID, passwordHash string, err error)
}
SessionStore defines repository operations for active login sessions.
type Setting ¶
type Setting struct {
Key string `json:"key"`
Value string `json:"value"`
UpdatedAt time.Time `json:"updated_at"`
}
Setting represents a durable server-wide key-value configuration entry.
type SettingsStore ¶
type SettingsStore interface {
GetSetting(ctx context.Context, key string) (string, error)
SetSetting(ctx context.Context, key, val string) error
DeleteSetting(ctx context.Context, key string) error
GetAllSettings(ctx context.Context) (map[string]string, error)
}
SettingsStore handles persistent key-value configuration.
type Store ¶
type Store interface {
InstallerConfiguration(context.Context) (applysetup.Common, bool, error)
ApplyInstaller(context.Context, applysetup.Common, bool) (applysetup.Report, error)
InstallerUserAllowed(context.Context, *User) (bool, error)
ApplyInstallerDirectory(context.Context, string, string, string, string, string, bool, bool) error
RevokeInstallerIdentity(context.Context, string, string) error
Tenancy() TenancyStore
Users() UserStore
Sessions() SessionStore
Devices() DeviceStore
Audit() AuditStore
Settings() SettingsStore
Suite() SuiteStore
Driver() string
// SampleCeiling is the stored metric rows allowed per endpoint.
SampleCeiling() int
Ping(ctx context.Context) error
Close() error
// SetAllowPrivileged is KY_CONTAINER_ALLOW_PRIVILEGED for the application deploy path, set
// at startup: off, a deploy never carries a host-level bind onto another image.
SetAllowPrivileged(bool)
// Usage reports the bytes the database occupies and Budget the ceiling it is measured
// against, zero when the check is disabled. Pressure says what that means for telemetry;
// audit is never refused, whatever the pressure.
Usage(ctx context.Context) (int64, error)
Budget() int64
EvaluatePressure(ctx context.Context) (Pressure, error)
Pressure() Pressure
}
Store defines the unified storage contract implemented across SQLite, PostgreSQL, and MySQL.
type SuiteOperation ¶ added in v0.4.3
type SuiteOperation struct {
ID string `json:"id"`
ActorID string `json:"actor_id"`
Kind string `json:"kind"`
Apps []string `json:"apps"`
Target string `json:"target"`
State string `json:"state"`
StartedAt time.Time `json:"started"`
FinishedAt *time.Time `json:"finished"`
Snapshot json.RawMessage `json:"operation,omitempty"`
ErrorCode string `json:"error_code"`
}
SuiteOperation mirrors one suite runner operation (migration 44). Snapshot is the runner's last answer for it, empty until one is read.
type SuiteStore ¶ added in v0.4.3
type SuiteStore interface {
CreateSuiteOperation(ctx context.Context, op *SuiteOperation) error
ReadSuiteOperation(ctx context.Context, id string) (*SuiteOperation, error)
// UpdateSuiteOperation writes state, finish, snapshot and error code while the row is still
// running, so a slow poll cannot reopen a settled row. A settled row is ErrNotFound.
UpdateSuiteOperation(ctx context.Context, op *SuiteOperation) error
}
SuiteStore is trusted persistence; the API enforces suite.read and suite.manage.
type TenancyStore ¶
type TenancyStore interface {
ReadInspectionTarget(context.Context, TenantAccess, string, string) (protocol.InspectionTarget, error)
// ContainerManaged (endpoint.read) reports whether an adopted application instance owns the container.
ContainerManaged(ctx context.Context, access TenantAccess, endpointID, containerID string) (bool, error)
// RecordConfigurationRead writes the container.configuration.read row under container.configure.
RecordConfigurationRead(ctx context.Context, access TenantAccess, endpointID string, target protocol.InspectionTarget, unsupported int) error
PreviewApplicationAdoption(context.Context, TenantAccess, string, string, string) (*AdoptionPreview, error)
AdoptApplication(context.Context, TenantAccess, string, AdoptionRequest) (*ApplicationInstance, error)
ReleaseApplication(context.Context, TenantAccess, string, string, string) error
ListApplicationInstances(context.Context, TenantAccess, string) ([]ApplicationInstance, error)
ReadApplicationInstance(ctx context.Context, access TenantAccess, applicationID, id string) (*ApplicationInstance, error)
ReplaceApplicationRevision(ctx context.Context, access TenantAccess, id string, expected int, spec ApplicationSpec, values map[string]string, key []byte) (int, error)
SetApplicationServiceIPs(ctx context.Context, access TenantAccess, id string, expected int, ips map[string]string, key []byte) (int, error)
ImportApplication(ctx context.Context, access TenantAccess, name string, spec ApplicationSpec, values map[string]string, key []byte) (*Application, error)
ResolveApplicationSecrets(ctx context.Context, access TenantAccess, applicationID string, number int, key []byte) (map[string]string, error)
DiscardApplication(ctx context.Context, access TenantAccess, applicationID string, expectedRevision int) error
CreateApplication(ctx context.Context, access TenantAccess, name string, spec ApplicationSpec) (*Application, error)
AppendApplicationRevision(ctx context.Context, access TenantAccess, applicationID string, expectedRevision int, spec ApplicationSpec) (int, error)
ListApplications(ctx context.Context, access TenantAccess, offset, limit int) ([]Application, error)
PreflightApplication(ctx context.Context, access TenantAccess, applicationID string) (*DeploymentPreflight, error)
PlanDeployment(ctx context.Context, access TenantAccess, applicationID string, request PlanRequest, resolver DigestResolver, key []byte, privateAllowed bool) (*Deployment, error)
ReadDeployment(ctx context.Context, access TenantAccess, applicationID, id string) (*Deployment, error)
ApplyDeployment(ctx context.Context, access TenantAccess, applicationID, id, confirm string, key []byte, maxFrameBytes int) (*Deployment, *protocol.DeploymentRequest, error)
FailDeployment(ctx context.Context, id, detail string) error
SettleDeployment(ctx context.Context, endpointID string, res protocol.DeploymentResult) error
RefuseDeploymentResult(ctx context.Context, endpointID, id, detail string) error
AbandonDeployments(ctx context.Context, endpointID string) (int64, error)
RemoveApplication(ctx context.Context, access TenantAccess, applicationID string, body RemovalBody) (*Deployment, *protocol.RemovalRequest, error)
ListDeployments(ctx context.Context, access TenantAccess, applicationID string) ([]Deployment, error)
ReadApplicationMapping(ctx context.Context, access TenantAccess, applicationID string) (*ApplicationMapping, error)
ReadImageChecks(ctx context.Context, access TenantAccess, applicationID string) (*UpdateCheck, error)
// CheckImageUpdateAccess authorizes application.deploy on an application in scope, with
// no success row; the API calls it before taking the per-application check slot.
CheckImageUpdateAccess(ctx context.Context, access TenantAccess, applicationID string) error
// CheckApplicationAccess authorizes action on an application in scope the same way, audited
// on the application when denied; the API runs it before its runtime gate.
CheckApplicationAccess(ctx context.Context, access TenantAccess, action permissions.Action, applicationID string) error
// CheckImageUpdates resolves each mapped service's reference through resolver and replaces
// the instance's cached checks, audited as application.deploy on <app>/updates.
CheckImageUpdates(ctx context.Context, access TenantAccess, applicationID string, resolver DigestResolver, key []byte, privateAllowed bool) (*UpdateCheck, error)
// Update policies (docs/application-schema.md, Update policies): writes under
// application.policy, reads under application.read. ReadUpdatePolicy returns a nil policy
// when the application has none.
PutUpdatePolicy(ctx context.Context, access TenantAccess, applicationID string, input PolicyInput) (*UpdatePolicy, bool, error)
ReadUpdatePolicy(ctx context.Context, access TenantAccess, applicationID string) (*UpdatePolicy, []PolicyRun, error)
DeleteUpdatePolicy(ctx context.Context, access TenantAccess, applicationID string) error
ResumeUpdatePolicy(ctx context.Context, access TenantAccess, applicationID string) (*UpdatePolicy, error)
ListPolicyRuns(ctx context.Context, access TenantAccess, applicationID string, limit int) ([]PolicyRun, error)
// The scheduler's side of update policies: trusted, not tenant-scoped. Each run re-authorizes
// its own steps as the policy's creator.
SchedulePolicies(ctx context.Context, now time.Time) ([]ScheduledPolicy, error)
BeginPolicyRun(ctx context.Context, policyID string, occurrence time.Time, correlation string) (string, error)
FinishPolicyRun(ctx context.Context, runID, outcome, deploymentID, detail string) error
// ApplyPolicyDeployment is ApplyDeployment that also requires, in its transaction, the policy
// still active, in apply mode and acting as access.ActorID (ErrPolicyChanged otherwise), and
// records runID (empty for a rollback) as the run that applied the row.
ApplyPolicyDeployment(ctx context.Context, access TenantAccess, policyID, runID, applicationID, id, confirm string, key []byte, maxFrameBytes int) (*Deployment, *protocol.DeploymentRequest, error)
SkipPolicyWindow(ctx context.Context, policyID string, occurrence time.Time, outcome, detail string) error
// AttachPolicyRunDeployment names the deployment an open run is about to send.
AttachPolicyRunDeployment(ctx context.Context, runID, deploymentID string) error
// Health validation (docs/application-schema.md, Health validation): the loop's side, trusted
// and not tenant-scoped.
PendingValidations(ctx context.Context) ([]PendingValidation, error)
BeginObservation(ctx context.Context, deploymentID string, baseline map[string]ServiceBaseline) error
// FinishValidation reports true when a rollback decision is due.
FinishValidation(ctx context.Context, deploymentID, verdict, detail string) (bool, error)
MarkRollbackPlanned(ctx context.Context, deploymentID, rollbackDeploymentID string) error
MarkRollbackOutcome(ctx context.Context, deploymentID, outcome, detail string) error
// DecideNamedRollbacks decides every named, undecided rollback whose deployment has settled.
DecideNamedRollbacks(ctx context.Context) error
// RollbackTarget authorizes application.deploy as the policy's creator and returns the
// replaced revision and images, or an ineligibility reason (docs/application-schema.md, Rollback).
RollbackTarget(ctx context.Context, access TenantAccess, applicationID, deploymentID string) (*Rollback, string, error)
SetApplicationMapping(ctx context.Context, access TenantAccess, applicationID string, request MappingRequest) error
// Migrations (docs/application-schema.md, Migration): writes under application.migrate,
// audited on <app>/migration/<id>; ReadMigration under application.read. The API runs the
// analyzer between ReadMigrationSource and the write that stores its report.
ReadMigrationSource(ctx context.Context, access TenantAccess, applicationID, endpointID string) (*MigrationSource, error)
CreateMigration(ctx context.Context, access TenantAccess, applicationID string, start MigrationStart, analysis MigrationAnalysis) (*ApplicationMigration, error)
ReadMigration(ctx context.Context, access TenantAccess, applicationID string) (*ApplicationMigration, error)
// ReadOpenMigration reads the open migration of a source under application.migrate; nil when none.
ReadOpenMigration(ctx context.Context, access TenantAccess, applicationID string) (*ApplicationMigration, error)
AnalyzeMigration(ctx context.Context, access TenantAccess, applicationID string, choices MigrationChoices, analysis MigrationAnalysis) (*ApplicationMigration, error)
CreateMigrationDestination(ctx context.Context, access TenantAccess, applicationID string, key []byte) (*ApplicationMigration, error)
ConfirmMigration(ctx context.Context, access TenantAccess, applicationID, step, note string) (*ApplicationMigration, error)
AbandonMigration(ctx context.Context, access TenantAccess, applicationID string) (*ApplicationMigration, error)
CompareApplication(ctx context.Context, access TenantAccess, applicationID string) (*ApplicationComparison, error)
ReadApplicationRevision(ctx context.Context, access TenantAccess, applicationID string, number int) (*ApplicationRevision, error)
ReadOrganization(ctx context.Context, access TenantAccess) (*Organization, error)
ReadEnvironment(ctx context.Context, access TenantAccess) (*Environment, error)
ListEnvironments(ctx context.Context, access TenantAccess, offset, limit int) ([]Environment, error)
AddEnvironment(ctx context.Context, access TenantAccess, name string) (*Environment, error)
UpdateEnvironment(ctx context.Context, access TenantAccess, name string) error
RemoveEnvironment(ctx context.Context, access TenantAccess) error
ReadAudit(ctx context.Context, access TenantAccess, offset, limit int) ([]AuditRecord, error)
ReadAuditAfter(ctx context.Context, access TenantAccess, afterID int64, limit int) ([]AuditRecord, error)
ListMembers(ctx context.Context, access TenantAccess, offset, limit int) ([]OrganizationMember, error)
PutMembership(ctx context.Context, access TenantAccess, userID string, role TenantRole, status string) error
RemoveMembership(ctx context.Context, access TenantAccess, userID string) error
CreateServicePairing(ctx context.Context, access TenantAccess) (*ServicePairing, error)
ClaimServiceToken(ctx context.Context, code, serviceName, ip string) (*ServiceTokenIssue, error)
AuthenticateServiceToken(ctx context.Context, token, ip string) (*ServiceToken, error)
// LookupServiceToken is AuthenticateServiceToken without the last-used stamp, for re-checks.
LookupServiceToken(ctx context.Context, token string) (*ServiceToken, error)
ListServiceTokens(ctx context.Context, access TenantAccess) ([]ServiceToken, error)
RevokeServiceToken(ctx context.Context, access TenantAccess, id string) error
// DenyService writes a denied audit row for a refusal the API decides itself (a service
// token asking to follow a log); the store's own checks audit their denials in run.
DenyService(ctx context.Context, access TenantAccess, action permissions.Action, detail string) error
// RecordServiceTokenReads writes the hourly summary row for one token.
RecordServiceTokenReads(ctx context.Context, organizationID, tokenID string, reads int) error
// AI agent (MCP) tokens: service principals with an mcp scope (agent_tokens.go).
CreateAgentToken(ctx context.Context, access TenantAccess, name, scope string) (*AgentTokenIssue, error)
ListAgentTokens(ctx context.Context, access TenantAccess) ([]ServiceToken, error)
SetAgentTokenScope(ctx context.Context, access TenantAccess, id, scope string) error
RevokeAgentToken(ctx context.Context, access TenantAccess, id string) error
LookupAgentToken(ctx context.Context, token string, now time.Time) (*ServiceToken, error)
AuthenticateAgentToken(ctx context.Context, token, ip string, now time.Time) (*ServiceToken, error)
ExpireIdleAgentTokens(ctx context.Context, now time.Time, id string) ([]ServiceToken, error)
RecordAgentAction(ctx context.Context, access TenantAccess, action, resource, details string) error
ListRegistries(ctx context.Context, access TenantAccess) ([]Registry, error)
PutRegistry(ctx context.Context, access TenantAccess, in RegistryInput, key []byte, privateAllowed bool) (*Registry, error)
DeleteRegistry(ctx context.Context, access TenantAccess, id string) error
ReadRegistryPolicy(ctx context.Context, access TenantAccess) (RegistryPolicy, error)
SetAnonymousPull(ctx context.Context, access TenantAccess, enabled bool) error
// ResolveRegistryAccess decrypts the credential for ref's host under action, the permission
// of the operation that uses it (registry.read is refused). It audits only denials and
// failures; callers audit the operation and never return the secret.
ResolveRegistryAccess(ctx context.Context, access TenantAccess, action permissions.Action, ref string, key []byte, privateAllowed bool) (*RegistryAccess, error)
// ListMemberOrganizations returns the caller's own active memberships; it is not tenant-scoped.
ListMemberOrganizations(ctx context.Context, userID string) ([]MemberOrganization, error)
// Platform administration: trusted, not tenant-scoped; callers enforce the platform admin role.
// CreateOrganizationWithAdmin returns ErrNotFound (no user), ErrInvalid (user not active)
// or ErrAlreadyExists (exact name taken).
CreateOrganizationWithAdmin(ctx context.Context, o *Organization, adminUserID string) error
ListOrganizations(ctx context.Context) ([]OrganizationSummary, error)
CheckEnrollmentAccess(ctx context.Context, access TenantAccess) error
// CreateEnrollmentToken records namespaces (Kubernetes only) for the endpoint it enrolls.
CreateEnrollmentToken(ctx context.Context, access TenantAccess, runtime, agentImage string, namespaces ...string) (*EnrollmentToken, error)
// SetEndpointDeployNamespaces replaces a Kubernetes endpoint's namespace list, audited as
// <endpoint>/manifest under endpoint.enroll.
SetEndpointDeployNamespaces(ctx context.Context, access TenantAccess, endpointID string, namespaces []string) (*Endpoint, error)
// Enroll is agent-facing: the token, not a session, selects the tenant.
Enroll(ctx context.Context, request EnrollmentRequest) (*Endpoint, error)
ListEndpoints(ctx context.Context, access TenantAccess, offset, limit int) ([]Endpoint, error)
ReadEndpoint(ctx context.Context, access TenantAccess, endpointID string) (*Endpoint, error)
ApproveEndpoint(ctx context.Context, access TenantAccess, endpointID, fingerprint string) error
RejectEndpoint(ctx context.Context, access TenantAccess, endpointID string) error
RevokeEndpoint(ctx context.Context, access TenantAccess, endpointID string) error
RenameEndpoint(ctx context.Context, access TenantAccess, endpointID, name string) error
// Agent-facing lifecycle: authenticated by endpoint identity, never by a session.
AgentIdentity(ctx context.Context, endpointID, fingerprint string) (*AgentIdentity, error)
RotateEndpointKey(ctx context.Context, endpointID string, newPublicKey, signature []byte, ip string) (string, error)
AcknowledgeEndpointKey(ctx context.Context, access TenantAccess, endpointID, fingerprint string) error
RecordEndpointEvent(ctx context.Context, endpoint *Endpoint, severity, kind, details string) error
AcknowledgeEndpointEvent(ctx context.Context, access TenantAccess, endpointID string, eventID int64) error
SetEndpointCapabilities(ctx context.Context, endpointID string, capabilities []string) error
ReadEndpointRaw(ctx context.Context, endpointID string) (*Endpoint, error)
RecordAgentConnect(ctx context.Context, endpoint *Endpoint, ip, result, details string) error
TouchEndpoint(ctx context.Context, endpointID string) error
AcceptInventory(ctx context.Context, endpointID string, generation uint64, observedAt time.Time, snapshot []byte) (bool, error)
ReadInventory(ctx context.Context, access TenantAccess, endpointID string) (*Inventory, error)
RecordSamples(ctx context.Context, endpointID string, metrics protocol.Metrics) error
LatestSamples(ctx context.Context, access TenantAccess, endpointID string) ([]SampleRow, error)
ReadSamples(ctx context.Context, access TenantAccess, endpointID, containerID string, window time.Duration) ([]SampleRow, error)
// RollUp summarises ended hours before the raw window drops them; ReadRollups serves the
// week of history that summary buys.
// Commands are durable intent: the row exists before the frame is sent, so an operation
// the control plane loses track of can still be marked unknown rather than vanish.
CreateCommand(ctx context.Context, access TenantAccess, endpointID, action, containerID, confirm string, expects protocol.Expectation) (*Command, error)
CheckEndpointAccess(ctx context.Context, access TenantAccess, action permissions.Action, endpointID string) error
OpenExecTarget(ctx context.Context, access TenantAccess, endpointID, streamID, confirm string, spec protocol.ExecSpec) (string, error)
OpenLogTarget(ctx context.Context, access TenantAccess, endpointID, identifier string) (*LogTarget, error)
OpenPodLogTarget(ctx context.Context, access TenantAccess, endpointID string, pod protocol.PodTarget) error
StillAllowed(ctx context.Context, access TenantAccess, action permissions.Action, endpointID string) error
MarkCommandDispatched(ctx context.Context, id string) error
SettleCommand(ctx context.Context, endpointID, id, outcome, detail string) error
// Direct commands (container.recreate, container.run) are explicit deployment frames recorded
// as commands under container.configure and settled from the agent's deployment.result.
CreateDirectCommand(ctx context.Context, access TenantAccess, endpointID string, dc DirectCommand) (*Command, *protocol.DeploymentRequest, error)
ResolveDirectImage(ctx context.Context, access TenantAccess, endpointID, reference string, resolver DigestResolver, key []byte, privateAllowed bool) (*protocol.ImagePull, map[string]protocol.RegistryAuth, error)
SettleDirectCommand(ctx context.Context, endpointID string, res protocol.DeploymentResult) error
CheckDirectCommand(ctx context.Context, access TenantAccess, endpointID string, dc DirectCommand) error
// Workload configuration and apply: a cluster workload's pod template, read and applied
// under container.configure; the apply is a direct command settled from deployment.result.
CheckWorkloadTarget(ctx context.Context, access TenantAccess, action permissions.Action, endpointID string, ref protocol.WorkloadRef) error
RecordWorkloadConfigurationRead(ctx context.Context, access TenantAccess, endpointID string, ref protocol.WorkloadRef, unsupported int) error
CreateWorkloadApply(ctx context.Context, access TenantAccess, endpointID string, w WorkloadApply) (*Command, *protocol.WorkloadApply, error)
CreateWorkloadRun(ctx context.Context, access TenantAccess, endpointID string, w WorkloadApply) (*Command, *protocol.WorkloadApply, error)
CheckWorkloadFrame(ctx context.Context, access TenantAccess, endpointID string, w WorkloadApply, create bool) error
FailDirectCommand(ctx context.Context, endpointID, id, detail string) error
AbandonCommands(ctx context.Context, endpointID string) (int64, error)
// ReconcileAfterStart settles every in-flight command as unknown, fails every open policy run
// and settles validations the previous process left; startup only.
ReconcileAfterStart(ctx context.Context) (int64, error)
ReadCommand(ctx context.Context, access TenantAccess, endpointID, id string) (*Command, error)
ListCommands(ctx context.Context, access TenantAccess, endpointID, containerID, reference string, limit int) ([]Command, error)
RollUp(ctx context.Context, since time.Time) (int64, error)
ReadRollups(ctx context.Context, access TenantAccess, endpointID, containerID string, window time.Duration) ([]RollupRow, error)
Prune(ctx context.Context) (int64, error)
MarkEndpointOffline(ctx context.Context, endpointID string) error
EndpointState(ctx context.Context, endpointID string) (string, error)
Initialize(ctx context.Context) error
InitializeLocalDocker(ctx context.Context, publicKey []byte) (uint64, error)
CreateOrganization(ctx context.Context, organization *Organization) error
GetOrganization(ctx context.Context, organizationID string) (*Organization, error)
SetMembership(ctx context.Context, membership *OrganizationMembership) error
GetMembership(ctx context.Context, organizationID, userID string) (*OrganizationMembership, error)
DeleteMembership(ctx context.Context, organizationID, userID string) error
CreateEnvironment(ctx context.Context, environment *Environment) error
GetEnvironment(ctx context.Context, organizationID, environmentID string) (*Environment, error)
RenameEnvironment(ctx context.Context, organizationID, environmentID, name string) error
DeleteEnvironment(ctx context.Context, organizationID, environmentID string) error
CreateOrganizationGroup(ctx context.Context, group *OrganizationGroup) error
AddOrganizationGroupMember(ctx context.Context, organizationID, groupID, userID string) error
ListOrganizationGroupMembers(ctx context.Context, organizationID, groupID string) ([]string, error)
RemoveOrganizationGroupMember(ctx context.Context, organizationID, groupID, userID string) error
}
TenancyStore provides authorized operations through TenantAccess. The raw methods below Initialize are trusted persistence helpers for bootstrap and management.
type TenantAccess ¶
type TenantAccess struct {
ActorID string
OrganizationID string
EnvironmentID string
CorrelationID string
IPAddress string
// ServiceTokenID is set instead of ActorID for a service token; run resolves its fixed role.
ServiceTokenID string
}
TenantAccess is server-derived request context. Clients cannot choose ActorID or CorrelationID.
func (TenantAccess) Principal ¶
func (a TenantAccess) Principal() string
Principal names the caller for a per-caller key: rate limits, stream slots, agent grants and audit rows. A service token has no ActorID, so keying on it alone would collapse every service token into one shared bucket.
type TenantRole ¶
type TenantRole string
Platform authority remains User.Role; it never implies one of these tenant roles.
const ( RoleOrganizationAdmin TenantRole = "organization_admin" RoleEnvironmentAdmin TenantRole = "environment_admin" RoleOperator TenantRole = "operator" RoleDeveloper TenantRole = "developer" RoleReadOnly TenantRole = "read_only" InitialOrganizationID = "org_initial" )
type UpdateCheck ¶
type UpdateCheck struct {
InstanceID string `json:"instance_id"`
MappingVersion int `json:"mapping_version"`
Services []ImageCheck `json:"services"`
}
UpdateCheck is an instance's cached checks; InstanceID is empty when nothing is adopted.
type UpdatePolicy ¶
type UpdatePolicy struct {
ID string `json:"id"`
ApplicationID string `json:"application_id"`
CreatedBy string `json:"created_by"`
Mode string `json:"mode"`
Timezone string `json:"timezone"`
Weekdays []int `json:"weekdays"`
StartMinute int `json:"start_minute"`
EndMinute int `json:"end_minute"`
Status string `json:"status"`
PausedReason string `json:"paused_reason"`
ConsecutiveFailures int `json:"consecutive_failures"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
// NextOccurrence is computed on read, UTC; nil while paused.
NextOccurrence *time.Time `json:"next_occurrence"`
OrganizationID string `json:"-"`
EnvironmentID string `json:"-"`
}
type User ¶
type User struct {
ID string `json:"id"`
Username string `json:"username"`
Email string `json:"email"`
DisplayName string `json:"display_name"`
PasswordHash string `json:"-"` // Never serialized to JSON
Role string `json:"role"` // "admin", "user", "manager"
Status string `json:"status"` // "active", "suspended", "inactive"
SSOProvider string `json:"sso_provider"` // "local", "kysignon", "oidc", "saml", "scim"
SSOSubject string `json:"sso_subject,omitempty"`
TOTPSecretEnc string `json:"-"` // AES-256-GCM encrypted
TOTPEnabled bool `json:"totp_enabled"`
TOTPLastCounter int64 `json:"-"` // last RFC 6238 counter accepted; refuses replay inside the skew window
RecoveryCodesHash string `json:"-"` // JSON array of sha256 hashes
PushDeviceID string `json:"push_device_id,omitempty"`
MustChangePassword bool `json:"must_change_password"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
LastLoginAt *time.Time `json:"last_login_at,omitempty"`
}
User represents an identity within the system.
type UserStore ¶
type UserStore interface {
CreateUser(ctx context.Context, u *User) error
GetUserByID(ctx context.Context, id string) (*User, error)
GetUserByUsername(ctx context.Context, username string) (*User, error)
GetUserByEmail(ctx context.Context, email string) (*User, error)
GetUserBySSO(ctx context.Context, provider, subject string) (*User, error)
LinkSSO(ctx context.Context, userID, sessionHash, passwordHash, provider, subject, ip string) error
// UpdateUser writes every column from u, credentials included: a trusted full-row write for
// fixtures. The identity provider writes through ApplyDirectoryEvent instead.
UpdateUser(ctx context.Context, u *User) error
ResetAdminPassword(ctx context.Context, userID, newHash string) error
CompletePasswordChange(ctx context.Context, userID, oldHash, newHash, ip string) error
// ChangePassword is CompletePasswordChange for an unflagged account: same revocation and audit.
ChangePassword(ctx context.Context, userID, oldHash, newHash, ip string) error
UpdateRecoveryCodes(ctx context.Context, userID, oldHashes, newHashes string) error
// UpdateMFA compares and swaps the MFA state under the password hash and audits action.
UpdateMFA(ctx context.Context, userID, passwordHash string, from, to MFAState, action, ip string) error
// SpendTOTPCounter records counter as used. It returns ErrAlreadyExists when counter is
// not greater than the stored one, which is how a replayed code inside the skew window fails.
SpendTOTPCounter(ctx context.Context, userID string, counter int64) error
// DeleteUser is a local deletion: it refuses with ErrLastAdmin to leave an organization the
// user administers without an active administrator, the guard membership writes keep.
DeleteUser(ctx context.Context, id string) error
// ApplyDirectoryEvent claims ev and runs apply in one transaction: the replay marker, the
// subject's watermark and apply's writes commit together or not at all, so a failed or
// cancelled event leaves nothing behind and the provider's retry applies. It returns
// ErrStaleEvent for an event ID already applied, or one older than the last applied event
// for the same subject. Events are only acceptable within DirectoryEventWindow of now.
// apply must not use the Store itself: it would wait on this transaction.
ApplyDirectoryEvent(ctx context.Context, ev DirectoryEvent, apply func(DirectoryTx) error) error
ListUsers(ctx context.Context, offset, limit int) ([]*User, int, error)
CountUsers(ctx context.Context) (int, error)
}
UserStore defines repository operations for accounts.
type Validation ¶
type Validation struct {
DeploymentID string `json:"deployment_id"`
PolicyRunID string `json:"policy_run_id"`
Automated bool `json:"automated"`
IsRollback bool `json:"is_rollback"`
Phase string `json:"phase"`
StartedAt time.Time `json:"started_at"`
ObserveUntil time.Time `json:"observe_until"`
Verdict string `json:"verdict"`
Detail string `json:"detail"`
Rollback *ValidationRollback `json:"rollback"`
CorrelationID string `json:"correlation_id"`
FinishedAt *time.Time `json:"finished_at"`
}
Validation is a deployment's health validation as the API shows it: the row without its baseline and tenant columns. Rollback is nil until a rollback is named or decided.
type ValidationRollback ¶
type WorkloadApply ¶
type WorkloadApply struct {
Target protocol.WorkloadRef
Confirm string
Spec protocol.WorkloadConfiguration
}
WorkloadApply is an edited pod template as the API received it: Spec.ResourceVersion is the read's (empty for a run), and Confirm repeats the workload's name.
Source Files
¶
- agent_rotation.go
- agent_session.go
- agent_tokens.go
- application_adoption.go
- application_apply.go
- application_comparison.go
- application_deployment.go
- application_mapping.go
- application_migration.go
- application_networking.go
- application_preflight.go
- application_secrets.go
- application_spec.go
- applications.go
- commands.go
- commands_recreate.go
- commands_workload.go
- endpoints.go
- exec.go
- factory.go
- image_checks.go
- inspection.go
- installer.go
- local_docker.go
- logs.go
- mfa.go
- models.go
- policies.go
- policy_schedule.go
- reconcile.go
- registries.go
- rollback.go
- samples.go
- service_tokens.go
- sqlstore.go
- sso_identity.go
- store.go
- suite.go
- tenancy.go
- tenant_access.go
- tenant_members.go
- validations.go