domain

package
v0.1.6 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 26, 2026 License: MIT Imports: 9 Imported by: 0

Documentation

Overview

Package domain contains the pure domain model for the Agent Name Service. It has zero external dependencies — no framework, no database, no HTTP.

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrNotFound     = errors.New("not found")
	ErrConflict     = errors.New("conflict")
	ErrInvalidState = errors.New("invalid state")
	ErrValidation   = errors.New("validation")
	ErrUnauthorized = errors.New("unauthorized")
	ErrCertificate  = errors.New("certificate")
	ErrInternal     = errors.New("internal")
	// ErrUnavailable marks a transient upstream failure: the request
	// was valid but a dependency (the TL, the vlei-verifier) could
	// not confirm it. Maps to 503; the operation is retryable and no
	// state was consumed.
	ErrUnavailable = errors.New("unavailable")
)

Sentinel errors for broad error classification.

ValidTransitions defines the allowed state transitions. Key is the current state; value is the set of valid target states.

Functions

func DIDWebResolutionURL added in v0.1.6

func DIDWebResolutionURL(canonicalValue string) (string, error)

DIDWebResolutionURL maps a canonical did:web identifier to the URL its DID document resolves at, per the did:web method spec:

did:web:example.com           → https://example.com/.well-known/did.json
did:web:example.com:user:al   → https://example.com/user/al/did.json

Pure function — the hardened fetcher in the adapter layer owns the actual I/O and its SSRF posture.

func ProofMethodForKind added in v0.1.6

func ProofMethodForKind(kind IdentifierKind) string

ProofMethodForKind exposes the kind → proofMethod mapping for the service layer's event builder.

func ValidDiscoveryProfiles added in v0.1.6

func ValidDiscoveryProfiles() []string

ValidDiscoveryProfiles returns the canonical valid set as strings — the single source of truth for enum membership. Used by error messages and spec generation tooling so adding a third profile is a one-place change rather than a shotgun edit.

Types

type AgentActivatedEvent

type AgentActivatedEvent struct {
	// contains filtered or unexported fields
}

AgentActivatedEvent is published when an agent transitions to ACTIVE.

func NewAgentActivatedEvent

func NewAgentActivatedEvent(agentID string, ansName AnsName, at time.Time) AgentActivatedEvent

NewAgentActivatedEvent creates a new activation event.

func (AgentActivatedEvent) AgentID

func (e AgentActivatedEvent) AgentID() string

func (AgentActivatedEvent) AnsName

func (e AgentActivatedEvent) AnsName() AnsName

AnsName returns the ANS name from the event.

func (AgentActivatedEvent) OccurredAt

func (e AgentActivatedEvent) OccurredAt() time.Time

func (AgentActivatedEvent) Type

func (e AgentActivatedEvent) Type() EventType

type AgentCSR

type AgentCSR struct {
	CSRID               string    `json:"csrId"`
	Type                CSRType   `json:"type"`
	CSRContent          string    `json:"csrContent"`
	Status              CSRStatus `json:"status"`
	SubmissionTimestamp time.Time `json:"submissionTimestamp"`
	ProcessedTimestamp  time.Time `json:"processedTimestamp,omitzero"`
	RejectionReason     string    `json:"rejectionReason,omitempty"`
}

AgentCSR represents a certificate signing request submitted by an agent — either an identity CSR (the initial and rotation path for the URI-SAN-bearing identity cert the RA's self-CA signs) or a server CSR (the server-certificate path used when the operator wants the RA to sign, as an alternative to BYOC).

Mirrors the reference RA's `AgentCsr` type hierarchy, which splits into identity and server CSR variants. Go lacks a built-in discriminated-union type, so we discriminate on the `Type` field. Everything else matches byte-for-byte with the reference RA's `AgentCertificateSigningRequest` — same status transitions, same fields on the wire, same rejection-reason semantics.

func NewIdentityCSR

func NewIdentityCSR(csrID, csrContent string, submittedAt time.Time) AgentCSR

NewIdentityCSR creates a new pending identity CSR.

func NewServerCSR

func NewServerCSR(csrID, csrContent string, submittedAt time.Time) AgentCSR

NewServerCSR creates a new pending server CSR.

func (AgentCSR) MarkRejected

func (c AgentCSR) MarkRejected(reason string, processedAt time.Time) (AgentCSR, error)

MarkRejected transitions the CSR to REJECTED status with a reason.

func (AgentCSR) MarkSigned

func (c AgentCSR) MarkSigned(processedAt time.Time) (AgentCSR, error)

MarkSigned transitions the CSR to SIGNED status.

type AgentDeprecatedEvent

type AgentDeprecatedEvent struct {
	// contains filtered or unexported fields
}

AgentDeprecatedEvent is published when an agent is deprecated (superseded by new version).

func NewAgentDeprecatedEvent

func NewAgentDeprecatedEvent(agentID string, ansName AnsName, supersededByID string, at time.Time) AgentDeprecatedEvent

NewAgentDeprecatedEvent creates a new deprecation event.

func (AgentDeprecatedEvent) AgentID

func (e AgentDeprecatedEvent) AgentID() string

func (AgentDeprecatedEvent) OccurredAt

func (e AgentDeprecatedEvent) OccurredAt() time.Time

func (AgentDeprecatedEvent) SupersededByID

func (e AgentDeprecatedEvent) SupersededByID() string

SupersededByID returns the ID of the agent that supersedes this one.

func (AgentDeprecatedEvent) Type

type AgentEndpoint

type AgentEndpoint struct {
	Protocol         Protocol        `json:"protocol"`
	AgentURL         string          `json:"agentUrl"`
	MetadataURL      string          `json:"metadataUrl,omitempty"`
	DocumentationURL string          `json:"documentationUrl,omitempty"`
	Functions        []AgentFunction `json:"functions,omitempty"`
	Transports       []Transport     `json:"transports,omitempty"`
	MetadataHash     string          `json:"metadataHash,omitempty"`
}

AgentEndpoint represents a single protocol endpoint for an agent.

func (AgentEndpoint) Validate

func (e AgentEndpoint) Validate() error

Validate checks that the endpoint has valid fields.

func (AgentEndpoint) ValidateHostMatch

func (e AgentEndpoint) ValidateHostMatch(expectedFQDN string) error

ValidateHostMatch checks that the endpoint URL's hostname matches the expected FQDN.

type AgentEndpoints

type AgentEndpoints struct {
	AgentID   string          `json:"agentId"`
	Endpoints []AgentEndpoint `json:"endpoints"`
}

AgentEndpoints is a validated collection of endpoints for an agent.

func (AgentEndpoints) Validate

func (ae AgentEndpoints) Validate(expectedFQDN string) error

Validate checks the endpoint collection is valid.

type AgentFunction

type AgentFunction struct {
	ID   string   `json:"id"`
	Name string   `json:"name"`
	Tags []string `json:"tags,omitempty"`
}

AgentFunction represents a function provided by an agent endpoint.

func (AgentFunction) Validate

func (f AgentFunction) Validate() error

Validate checks that the function has valid fields.

type AgentRegisteredEvent

type AgentRegisteredEvent struct {
	// contains filtered or unexported fields
}

AgentRegisteredEvent is published when a new agent registration is received.

func NewAgentRegisteredEvent

func NewAgentRegisteredEvent(agentID string, ansName AnsName, ownerID string, at time.Time) AgentRegisteredEvent

NewAgentRegisteredEvent creates a new registration event.

func (AgentRegisteredEvent) AgentID

func (e AgentRegisteredEvent) AgentID() string

func (AgentRegisteredEvent) AnsName

func (e AgentRegisteredEvent) AnsName() AnsName

AnsName returns the ANS name from the event.

func (AgentRegisteredEvent) OccurredAt

func (e AgentRegisteredEvent) OccurredAt() time.Time

func (AgentRegisteredEvent) OwnerID

func (e AgentRegisteredEvent) OwnerID() string

OwnerID returns the owner identifier.

func (AgentRegisteredEvent) Type

type AgentRegistration

type AgentRegistration struct {
	// ID is the database primary key (zero for unsaved registrations).
	ID int64 `json:"id,omitempty"`

	// AgentID is the immutable UUID that persists across versions.
	AgentID string `json:"agentId"`

	// OwnerID identifies the authenticated user who owns this registration.
	OwnerID string `json:"ownerId"`

	// AnsName is the versioned agent name (ans://v1.0.0.agent.example.com).
	AnsName AnsName `json:"ansName"`

	// Status is the current lifecycle state.
	Status RegistrationStatus `json:"status"`

	// Details holds display name, description, and timestamps.
	Details RegistrationDetails `json:"details"`

	// Endpoints are the agent's protocol endpoints.
	Endpoints []AgentEndpoint `json:"endpoints"`

	// ServerCert is the BYOC server certificate (if submitted).
	ServerCert *ByocServerCertificate `json:"serverCert,omitempty"`

	// IdentityCSR is the most recent identity CSR on this
	// registration: PENDING between registration and verify-acme
	// (which signs it once domain control is proven), and SIGNED
	// thereafter. A rotation via POST /certificates/identity is signed
	// at submission and replaces this slot with the new SIGNED CSR.
	// Historical CSRs persist in the csrs table — the one embedded
	// here is a "fast path" cache for the status handler.
	IdentityCSR *AgentCSR `json:"identityCsr,omitempty"`

	// ServerCSR is the most recent pending server CSR on this
	// registration, if any. Only set when the operator uses the
	// CA-signed server-cert path (POST /certificates/server). BYOC
	// registrations leave this nil.
	ServerCSR *AgentCSR `json:"serverCsr,omitempty"`

	// SupersedesRegistrationID is the ID of the previous version (for supersession).
	SupersedesRegistrationID int64 `json:"supersedesRegistrationId,omitempty"`

	// CertOrder tracks the certificate order and its domain-control
	// challenges for this registration. CSR-path registrations carry
	// the provider order returned by `ServerCertificateIssuer.
	// CreateOrder`; BYOC registrations carry a self-issued validation
	// order (OrderRef empty) because domain control must be proven
	// even when no certificate is being issued. Zero-value for
	// registrations predating order persistence.
	CertOrder CertificateOrder `json:"certOrder,omitzero"`

	// DiscoveryProfiles is the set of DNS record families the RA emits
	// for this registration. Each value names one family — typically
	// {ANS_DNSAID} (Consolidated Approach), {ANS_TXT} (original `_ans`
	// TXT shape), or the {ANS_DNSAID, ANS_TXT} transition union. Empty
	// at the domain layer is treated as DefaultDiscoveryProfiles() by
	// the service-layer record walker (internal/ra/service/dnsrecords.go).
	DiscoveryProfiles []DiscoveryProfile `json:"discoveryProfiles,omitempty"`

	// PendingEvents holds domain events raised during this aggregate operation.
	// They are cleared after being published.
	PendingEvents []Event `json:"-"`
}

AgentRegistration is the aggregate root for agent registrations. It manages the lifecycle of an agent from registration through activation, deprecation, and revocation.

func NewRegistration

func NewRegistration(
	agentID string,
	ownerID string,
	ansName AnsName,
	displayName string,
	description string,
	endpoints []AgentEndpoint,
	serverCert *ByocServerCertificate,
	identityCSR *AgentCSR,
	now time.Time,
) (*AgentRegistration, error)

NewRegistration creates a new agent registration in PENDING_VALIDATION state.

func (*AgentRegistration) Activate

func (r *AgentRegistration) Activate(now time.Time) error

Activate transitions the registration from a pending state to ACTIVE.

func (*AgentRegistration) AdvanceToPendingDNS

func (r *AgentRegistration) AdvanceToPendingDNS() error

AdvanceToPendingDNS transitions from PENDING_VALIDATION to PENDING_DNS, which is the state the registration enters once domain-control validation (ACME) succeeds AND the certificate order completed — the DNS records the operator must configure (notably TLSA) can only be computed once the server certificate exists.

The agent lifecycle enum stays exactly as the V2 spec's `AgentLifecycleStatus` defines it. Certificate issuance in flight is NOT a lifecycle state: it is tracked on `CertOrder.State` (PENDING → ISSUING → COMPLETED) and surfaced as derived views — `RegistrationPending.status = PENDING_CERTS` and `AgentStatus.phase = CERTIFICATE_ISSUANCE` — while the lifecycle status remains PENDING_VALIDATION. Synchronous issuers (the self-signed CA) pass through the ISSUING window in-process; asynchronous issuers (ACME providers) park the agent there until a re-driven verify-acme finalizes the order.

func (*AgentRegistration) AllowsSupersede

func (r *AgentRegistration) AllowsSupersede(newVersion SimplifiedSemVer) bool

AllowsSupersede returns true if this registration can be superseded by a new version.

func (*AgentRegistration) Cancel

func (r *AgentRegistration) Cancel(now time.Time) error

Cancel transitions a PENDING registration to REVOKED.

Eligibility follows the spec's revoke-route contract: the PENDING_CERTS phase (order ISSUING or terminally FAILED) and PENDING_DNS are cancellable; a registration still awaiting its domain-control challenge (PENDING_VALIDATION with the order PENDING) is not — it auto-expires when the challenge window lapses. Legacy registrations without a persisted order are cancellable: they have no challenge window to expire on, so cancel is their only exit.

func (*AgentRegistration) ClearEvents

func (r *AgentRegistration) ClearEvents() []Event

ClearEvents returns and clears the pending domain events.

func (*AgentRegistration) Deprecate

func (r *AgentRegistration) Deprecate(supersededByID string, now time.Time) error

Deprecate transitions an ACTIVE registration to DEPRECATED.

func (*AgentRegistration) Expire

func (r *AgentRegistration) Expire() error

Expire transitions a PENDING registration to EXPIRED.

func (*AgentRegistration) FQDN

func (r *AgentRegistration) FQDN() string

FQDN returns the lowercase FQDN from the ANS name.

func (*AgentRegistration) Fail

func (r *AgentRegistration) Fail() error

Fail transitions a PENDING registration to FAILED.

func (*AgentRegistration) Revoke

func (r *AgentRegistration) Revoke(reason RevocationReason, now time.Time) error

Revoke transitions the registration to REVOKED. Only ACTIVE or DEPRECATED registrations may be revoked via this method; use Cancel() to revoke a pending registration. This keeps the two semantically distinct user actions on separate methods.

The two rejection paths are reported with distinct error codes:

  • CANNOT_REVOKE_PENDING: caller is holding a pending registration and should be using Cancel() instead (different event metadata).
  • INVALID_STATUS_TRANSITION: caller is holding a terminal-state registration (already REVOKED / FAILED / EXPIRED) — nothing to do.

Splitting them lets API consumers give actionable feedback rather than lumping "wrong state" into a single code.

func (*AgentRegistration) SubmitIdentityCSR

func (r *AgentRegistration) SubmitIdentityCSR(csrID, csrPEM string, now time.Time) (*AgentCSR, error)

SubmitIdentityCSR replaces the registration's pending identity CSR with a new one. Requires status == ACTIVE — per the reference RA's `CertificateOperationsHandler.submitAgentIdentityCsr`: "Agent must be ACTIVE to submit identity CSR". The caller is expected to have validated the CSR PEM before calling this.

Returns the new CSR so the caller can persist it both on the aggregate (via Save) and in the csrs table (for historical lookup).

func (*AgentRegistration) SubmitServerCSR

func (r *AgentRegistration) SubmitServerCSR(csrID, csrPEM string, now time.Time) (*AgentCSR, error)

SubmitServerCSR replaces the registration's pending server CSR with a new one. The reference RA's equivalent is in `CertificateOperationsHandler.submitAgentServerCsr` and it does NOT gate on status — server CSRs can be submitted at any state since operators may want the RA-signed path before the agent is live. The caller is expected to have validated the CSR PEM.

type AgentRevocation

type AgentRevocation struct {
	RegistrationID              int64               `json:"registrationId"`
	AnsName                     AnsName             `json:"ansName"`
	AgentID                     string              `json:"agentId"`
	PreviousStatus              RegistrationStatus  `json:"previousStatus"`
	RevokedAt                   time.Time           `json:"revokedAt"`
	Reason                      RevocationReason    `json:"reason"`
	Comments                    string              `json:"comments,omitempty"`
	RevokedIdentityCertificates []StoredCertificate `json:"revokedIdentityCertificates,omitempty"`
	RevokedServerCertificates   []StoredCertificate `json:"revokedServerCertificates,omitempty"`
}

AgentRevocation records the metadata of an agent revocation event.

type AgentRevokedEvent

type AgentRevokedEvent struct {
	// contains filtered or unexported fields
}

AgentRevokedEvent is published when an agent is revoked.

func NewAgentRevokedEvent

func NewAgentRevokedEvent(agentID string, ansName AnsName, reason RevocationReason, at time.Time) AgentRevokedEvent

NewAgentRevokedEvent creates a new revocation event.

func (AgentRevokedEvent) AgentID

func (e AgentRevokedEvent) AgentID() string

func (AgentRevokedEvent) OccurredAt

func (e AgentRevokedEvent) OccurredAt() time.Time

func (AgentRevokedEvent) Reason

Reason returns the revocation reason.

func (AgentRevokedEvent) Type

func (e AgentRevokedEvent) Type() EventType

type AnsName

type AnsName struct {
	// contains filtered or unexported fields
}

AnsName represents an Agent Name Service name in the format: ans://v{MAJOR.MINOR.PATCH}.{agentHost}

Example: ans://v1.2.0.myagent.example.com

func NewAnsName

func NewAnsName(version SimplifiedSemVer, agentHost string) (AnsName, error)

NewAnsName creates an AnsName from a version and agent host.

func ParseAnsName

func ParseAnsName(s string) (AnsName, error)

ParseAnsName parses an ANS name string like "ans://v1.2.0.myagent.example.com".

func (AnsName) AgentHost

func (n AnsName) AgentHost() string

AgentHost returns the FQDN component (lowercase).

func (AnsName) FQDN

func (n AnsName) FQDN() string

FQDN is an alias for AgentHost.

func (AnsName) IsZero

func (n AnsName) IsZero() bool

IsZero returns true if the AnsName is uninitialized.

func (AnsName) String

func (n AnsName) String() string

String returns the full ANS name: ans://v1.2.0.myagent.example.com.

func (AnsName) Version

func (n AnsName) Version() SimplifiedSemVer

Version returns the semantic version component.

type ByocServerCertificate

type ByocServerCertificate struct {
	LeafCertificatePEM      string    `json:"leafCertificatePem"`
	ChainCertificatesPEM    string    `json:"chainCertificatesPem,omitempty"`
	SubjectCommonName       string    `json:"subjectCommonName"`
	SubjectAlternativeNames []string  `json:"subjectAlternativeNames"`
	IssuerDN                string    `json:"issuerDn"`
	ValidFromTimestamp      time.Time `json:"validFromTimestamp"`
	ValidToTimestamp        time.Time `json:"validToTimestamp"`
	Fingerprint             string    `json:"fingerprint"` // SHA-256
}

ByocServerCertificate represents a Bring-Your-Own-Certificate server certificate.

func (ByocServerCertificate) GetFullChain

func (c ByocServerCertificate) GetFullChain() string

GetFullChain returns the leaf certificate concatenated with the chain.

func (ByocServerCertificate) IsValid

func (c ByocServerCertificate) IsValid(now time.Time) bool

IsValid returns true if the certificate is within its validity period.

func (ByocServerCertificate) MatchesFQDN

func (c ByocServerCertificate) MatchesFQDN(fqdn string) bool

MatchesFQDN returns true if the certificate CN or SANs include the expected FQDN.

type CSRStatus

type CSRStatus string

CSRStatus represents the processing status of a certificate signing request.

const (
	CSRStatusPending  CSRStatus = "PENDING"
	CSRStatusSigned   CSRStatus = "SIGNED"
	CSRStatusRejected CSRStatus = "REJECTED"
)

type CSRType

type CSRType string

CSRType distinguishes identity CSRs from server CSRs. Matches the V2 `CsrStatusResponse.type` enum (§1381) exactly.

const (
	CSRTypeIdentity CSRType = "IDENTITY"
	CSRTypeServer   CSRType = "SERVER"
)

type CertRequestedEvent

type CertRequestedEvent struct {
	// contains filtered or unexported fields
}

CertRequestedEvent is published when a certificate signing request is submitted.

func NewCertRequestedEvent

func NewCertRequestedEvent(agentID, csrID string, certType CertificateType, at time.Time) CertRequestedEvent

NewCertRequestedEvent creates a new CSR event.

func (CertRequestedEvent) AgentID

func (e CertRequestedEvent) AgentID() string

func (CertRequestedEvent) CSRID

func (e CertRequestedEvent) CSRID() string

CSRID returns the CSR identifier.

func (CertRequestedEvent) CertType

func (e CertRequestedEvent) CertType() CertificateType

CertType returns the certificate type.

func (CertRequestedEvent) OccurredAt

func (e CertRequestedEvent) OccurredAt() time.Time

func (CertRequestedEvent) Type

func (e CertRequestedEvent) Type() EventType

type CertificateOrder added in v0.1.6

type CertificateOrder struct {
	OrderRef   string      `json:"orderRef,omitempty"`
	State      OrderState  `json:"state,omitempty"`
	Challenges []Challenge `json:"challenges,omitempty"`
	ExpiresAt  time.Time   `json:"expiresAt,omitzero"`
}

CertificateOrder tracks a certificate issuance order and the domain-control challenges attached to it.

Two shapes exist:

  • Provider order (CSR path): created by the configured `ServerCertificateIssuer` port. OrderRef is the provider-opaque handle (an ACME order URL for ACME providers, an internal id for the self-signed CA) used to finalize the order after the owner satisfies a challenge.
  • Self-issued validation order (BYOC path): no certificate is being issued, but domain control must still be proven before the registration advances. OrderRef is empty and the challenges are RA-issued.

func NewSelfIssuedOrder added in v0.1.6

func NewSelfIssuedOrder(dns01Token, http01Token string, expiresAt time.Time) CertificateOrder

NewSelfIssuedOrder builds the BYOC-path validation order from a pair of RA-generated tokens. The DNS record value and HTTP content default to the raw tokens (no account-key binding).

func (*CertificateOrder) ChallengeOfType added in v0.1.6

func (o *CertificateOrder) ChallengeOfType(t ChallengeType) (Challenge, bool)

ChallengeOfType returns the first challenge of the given type.

func (*CertificateOrder) IsExpired added in v0.1.6

func (o *CertificateOrder) IsExpired(now time.Time) bool

IsExpired reports whether the order's challenge window has elapsed without the order reaching a terminal state.

func (*CertificateOrder) IsZero added in v0.1.6

func (o *CertificateOrder) IsZero() bool

IsZero reports whether the order is unset — true for registrations that predate order persistence.

func (*CertificateOrder) MarkCompleted added in v0.1.6

func (o *CertificateOrder) MarkCompleted() error

MarkCompleted transitions PENDING|ISSUING → COMPLETED: the certificate landed (or, for a BYOC validation order, domain control was proven).

func (*CertificateOrder) MarkFailed added in v0.1.6

func (o *CertificateOrder) MarkFailed() error

MarkFailed transitions PENDING|ISSUING → FAILED: the provider reported a terminal order failure (e.g. an ACME order moved to `invalid`). A failed order cannot be retried — the operator submits a new registration or renewal.

func (*CertificateOrder) MarkIssuing added in v0.1.6

func (o *CertificateOrder) MarkIssuing() error

MarkIssuing transitions PENDING → ISSUING: domain validation passed and the provider accepted the finalize request but has not produced a certificate yet. Idempotent for re-driven verify-acme calls (an ISSUING order stays ISSUING).

type CertificateStatus

type CertificateStatus string

CertificateStatus represents the status of a stored certificate.

const (
	CertStatusPending CertificateStatus = "PENDING"
	CertStatusValid   CertificateStatus = "VALID"
	CertStatusRevoked CertificateStatus = "REVOKED"
)

type CertificateType

type CertificateType string

CertificateType classifies a certificate as server or identity.

const (
	CertTypeServer   CertificateType = "SERVER"
	CertTypeIdentity CertificateType = "IDENTITY"
)

type Challenge added in v0.1.6

type Challenge struct {
	// Type selects the verification mechanism.
	Type ChallengeType `json:"type"`

	// Token is the opaque challenge token issued by the certificate
	// provider (or self-issued by the RA when it is its own CA).
	Token string `json:"token"`

	// KeyAuthorization binds the token to the issuing account's key
	// per RFC 8555 §8.1 (token || "." || base64url(JWK thumbprint)).
	// Empty for self-issued challenges, which have no account binding.
	KeyAuthorization string `json:"keyAuthorization,omitempty"`

	// DNSRecordName overrides the TXT record name for DNS challenges.
	// Empty means the RFC 8555 default `_acme-challenge.<fqdn>`.
	// Non-ACME providers with proprietary DV record names set this.
	DNSRecordName string `json:"dnsRecordName,omitempty"`

	// DNSRecordValue overrides the TXT record value for DNS
	// challenges. ACME providers require
	// base64url(SHA-256(keyAuthorization)); self-issued challenges
	// publish the raw token. Empty means the raw token.
	DNSRecordValue string `json:"dnsRecordValue,omitempty"`

	// HTTPPath overrides the HTTP challenge path. Empty means the
	// RFC 8555 default `/.well-known/acme-challenge/<token>`.
	HTTPPath string `json:"httpPath,omitempty"`
}

Challenge is a single domain-control challenge the domain owner must satisfy by publishing an artifact (a DNS TXT record or an HTTP resource) in the zone or site they control. Challenges are relayed to the owner verbatim — ANS never creates DNS records or serves challenge files on the owner's behalf; the pending-registration and renewal responses carry everything the owner needs to publish them themselves.

Challenges originate from the certificate issuer port when a certificate order is created (`ServerCertificateIssuer.CreateOrder`). For the in-process self-signed CA the tokens are self-issued; for an external ACME CA (e.g. Let's Encrypt) the token and key authorization come from the provider's order and the DNS record value is the provider-computed digest.

func (Challenge) EffectiveDNSRecordName added in v0.1.6

func (c Challenge) EffectiveDNSRecordName(fqdn string) string

EffectiveDNSRecordName returns the TXT record name the owner must publish for a DNS_01 challenge, applying the RFC 8555 default when the provider didn't override it.

func (Challenge) EffectiveDNSRecordValue added in v0.1.6

func (c Challenge) EffectiveDNSRecordValue() string

EffectiveDNSRecordValue returns the TXT record value the owner must publish for a DNS_01 challenge. Defaults to the raw token for self-issued challenges.

func (Challenge) EffectiveHTTPPath added in v0.1.6

func (c Challenge) EffectiveHTTPPath() string

EffectiveHTTPPath returns the URL path (under the agent's FQDN) the owner must serve the challenge content from for an HTTP_01 challenge, applying the RFC 8555 default when the provider didn't override it.

func (Challenge) ExpectedHTTPContent added in v0.1.6

func (c Challenge) ExpectedHTTPContent() string

ExpectedHTTPContent returns the body the owner must serve at the HTTP challenge path: the key authorization when the provider binds the token to an account key (RFC 8555 §8.3), otherwise the raw token.

type ChallengeType added in v0.1.6

type ChallengeType string

ChallengeType enumerates the domain-control challenge mechanisms a certificate provider can demand. Mirrors the V2 spec's `ChallengeInfo.type` enum (spec/api-spec-v2.yaml §ChallengeInfo: DNS_01 | HTTP_01).

const (
	ChallengeTypeDNS01  ChallengeType = "DNS_01"
	ChallengeTypeHTTP01 ChallengeType = "HTTP_01"
)

Challenge types. Values match RFC 8555 challenge identifiers in the wire casing the V2 spec uses.

func (ChallengeType) IsValid added in v0.1.6

func (t ChallengeType) IsValid() bool

IsValid reports whether the challenge type is recognized.

type DNSRecordPurpose

type DNSRecordPurpose string

DNSRecordPurpose describes why a DNS record is needed.

const (
	PurposeDiscovery          DNSRecordPurpose = "DISCOVERY"
	PurposeTrust              DNSRecordPurpose = "TRUST"
	PurposeCertificateBinding DNSRecordPurpose = "CERTIFICATE_BINDING"
	PurposeBadge              DNSRecordPurpose = "BADGE"
)

type DNSRecordType

type DNSRecordType string

DNSRecordType represents a DNS record type.

const (
	DNSRecordTXT   DNSRecordType = "TXT"
	DNSRecordTLSA  DNSRecordType = "TLSA"
	DNSRecordHTTPS DNSRecordType = "HTTPS"
	// DNSRecordSVCB is the "Consolidated Approach" service binding
	// record (RFC 9460) emitted at the agent's bare FQDN. One SVCB
	// record per protocol carries that protocol's connection hints and
	// capability locators in a single DNS lookup. SvcParams from
	// sibling families coexist in the same record per RFC 9460 §8
	// unknown-key ignore semantics.
	DNSRecordSVCB DNSRecordType = "SVCB"
)

type DiscoveryProfile added in v0.1.6

type DiscoveryProfile string

DiscoveryProfile names one DNS record family the RA can emit for an agent registration. A registration carries a *set* of profiles (AgentRegistration.DiscoveryProfiles); operators publishing the union during a Consolidated Approach transition include both ANS_DNSAID and ANS_TXT in the same set.

Wire values are CONSTANT_CASE, matching every other enum on the V2 register schema (Protocol, RevocationReason, AgentLifecycleStatus, NextStep.action, ChallengeInfo.type, DnsRecord.type, etc.). The `ANS_` prefix anchors the namespace so a future second agentic spec adding its own SVCB family doesn't collide.

const (
	// DiscoveryProfileANSDNSAID emits DNS-AID-aligned SVCB records per
	// RFC 9460 — one row per protocol at the bare FQDN, carrying alpn,
	// port, key65402 (bap, the agent protocol), and — when the endpoint
	// supplies them — key65400 (cap, the capability locator from
	// metadataUrl), key65401 (cap-sha256, the capability digest), and
	// key65409 (well-known suffix derived from metadataUrl). These
	// keyNNNNN forms are the RFC 9460 §14.3.1 Private Use presentation of
	// the DNS-AID draft-02 cap/cap-sha256/bap/well-known params, which
	// have no IANA code point; the adapter
	// (internal/adapter/discovery/ans/dnsaid.go) documents why the named
	// forms are unpublishable.
	DiscoveryProfileANSDNSAID DiscoveryProfile = "ANS_DNSAID"

	// DiscoveryProfileANSTXT emits the original `_ans` TXT shape — one row
	// per protocol at `_ans.{fqdn}`. Supported indefinitely for
	// operators with existing zone-edit tooling that targets `_ans.`.
	// Includes an HTTPS RR at the bare FQDN since `_ans` TXT carries
	// no connection hints.
	DiscoveryProfileANSTXT DiscoveryProfile = "ANS_TXT"
)

func DefaultDiscoveryProfiles added in v0.1.6

func DefaultDiscoveryProfiles() []DiscoveryProfile

DefaultDiscoveryProfiles is the set applied when the registration request omits discoveryProfiles entirely. Pinned to {ANS_TXT} — the stable, widely-deployed family — while the DNS-AID profile is brought to conformance; operators opt into ANS_DNSAID explicitly. This also matches the V1 lane, which is always pinned to ANS_TXT. Returned as a fresh slice so callers can mutate without affecting the canonical set.

func (DiscoveryProfile) IsValid added in v0.1.6

func (s DiscoveryProfile) IsValid() bool

IsValid reports whether s is one of the defined profiles. Empty string is treated as invalid; callers normalize empty/missing discoveryProfiles to DefaultDiscoveryProfiles() before validation.

Coherence with the discovery registry is enforced at server start: cmd/ans-ra/main.go asserts that every profile in ValidDiscoveryProfiles() has a registered port.ProfileEmitter adapter and vice versa. Drift fails server start, not the first verify-dns call.

type Error

type Error struct {
	// Code is a machine-readable error code (e.g., "INVALID_ANS_NAME").
	Code string
	// Message is a human-readable description.
	Message string
	// Cause is the underlying sentinel or wrapped error.
	Cause error
}

Error is the base error type for all domain errors. It wraps a sentinel error for type-based classification and carries a machine-readable code and human-readable message.

func NewCertificateError

func NewCertificateError(code, message string) *Error

NewCertificateError creates a certificate domain error.

func NewConflictError

func NewConflictError(code, message string) *Error

NewConflictError creates a conflict domain error.

func NewInternalError

func NewInternalError(code, message string, cause error) *Error

NewInternalError creates an internal domain error wrapping a cause.

func NewInvalidStateError

func NewInvalidStateError(code, message string) *Error

NewInvalidStateError creates an invalid-state domain error.

func NewNotFoundError

func NewNotFoundError(code, message string) *Error

NewNotFoundError creates a not-found domain error.

func NewUnauthorizedError

func NewUnauthorizedError(code, message string) *Error

NewUnauthorizedError creates an unauthorized domain error.

func NewUnavailableError added in v0.1.6

func NewUnavailableError(code, message string) *Error

NewUnavailableError creates a retryable upstream-unavailable error.

func NewValidationError

func NewValidationError(code, message string) *Error

NewValidationError creates a validation domain error.

func (*Error) Error

func (e *Error) Error() string

Error implements the error interface.

func (*Error) Unwrap

func (e *Error) Unwrap() error

Unwrap returns the underlying cause for errors.Is/As support.

type Event

type Event interface {
	// Type returns the event type identifier.
	Type() EventType
	// OccurredAt returns when the event occurred.
	OccurredAt() time.Time
	// AgentID returns the agent this event relates to.
	AgentID() string
}

Event is the interface all domain events implement.

type EventType

type EventType string

EventType classifies a domain event.

const (
	EventAgentRegistered EventType = "AGENT_REGISTERED"
	EventAgentActivated  EventType = "AGENT_ACTIVATED"
	EventAgentDeprecated EventType = "AGENT_DEPRECATED"
	EventAgentRevoked    EventType = "AGENT_REVOKED"
	EventAgentRenewed    EventType = "AGENT_RENEWED"
	EventCertRequested   EventType = "CERT_REQUESTED"
	EventCertIssued      EventType = "CERT_ISSUED"
	EventCertRevoked     EventType = "CERT_REVOKED"
)

type ExpectedDNSRecord

type ExpectedDNSRecord struct {
	Name     string           `json:"name"`
	Type     DNSRecordType    `json:"type"`
	Value    string           `json:"value"`
	Purpose  DNSRecordPurpose `json:"purpose"`
	Required bool             `json:"required"`
	TTL      int              `json:"ttl"`
}

ExpectedDNSRecord represents a DNS record the operator must configure.

func TLSARecordForCert added in v0.1.6

func TLSARecordForCert(fqdn, fingerprint string) ExpectedDNSRecord

TLSARecordForCert builds the single DANE-EE TLSA record binding a server certificate fingerprint to the FQDN at the default TLS port (`_443._tcp.{fqdn}`). It is the server-cert renewal path's analog of the registration record set: the renewal status responses surface the new leaf's record so the operator can update DNS after a rollover.

The registration record set emits one TLSA per distinct TLS endpoint port via the discovery profiles (internal/adapter/discovery/ans.TLSARecord); this helper covers the single-record renewal-status DTO, which carries the freshly-issued leaf's fingerprint rather than reading reg.ServerCert.

`3 0 1 <hex>` = DANE-EE + full-certificate + SHA-256 (RFC 6698). Selector 0 (full cert), not 1 (SPKI): the hex is the certificate fingerprint — a SHA-256 over the full DER cert (internal/crypto/x509.go CertificateFingerprint) — so selector 0 is what matches those bytes.

Required=false: a TLSA record is only trustworthy in a DNSSEC-signed zone, which the domain layer cannot know. The verify layer enforces the stricter rule at query time: a DNSSEC-validated TLSA response MUST match the expected fingerprint.

type IdentifierKind added in v0.1.6

type IdentifierKind string

IdentifierKind classifies a verified identity's identifier scheme. The set is spec-frozen: adding a kind is an ANS-spec amendment plus a per-kind control-proof implementation, never just a new string.

const (
	// KindDIDWeb — did:web. The authoritative keys live in the DID
	// document fetched from the operator's web host; control is
	// possession of the document's assertionMethod keys.
	KindDIDWeb IdentifierKind = "did:web"

	// KindDIDKey — did:key. The key IS the identifier (decoded from
	// the DID string); zero I/O, pure key possession.
	KindDIDKey IdentifierKind = "did:key"

	// KindLEI — an ISO 17442 Legal Entity Identifier, proven through
	// a vLEI credential presentation. Postponed: recognized so the
	// error is precise, but no control verifier ships yet.
	KindLEI IdentifierKind = "lei"
)

Identifier kinds. A kind being *recognized* here is independent of it being *enabled* — the service layer dispatches per kind and returns IDENTIFIER_KIND_UNSUPPORTED for kinds this deployment has no control verifier for (lei is recognized but postponed).

func InferIdentifierKind added in v0.1.6

func InferIdentifierKind(raw string) (IdentifierKind, string, error)

InferIdentifierKind lexically classifies a raw identifier value and returns its canonical form. Kind inference is pure dispatch — it proves nothing; the per-kind control proof is the gate.

type IdentityChallenge added in v0.1.6

type IdentityChallenge struct {
	// Nonce is the base64url-encoded 32-byte random value.
	Nonce string
	// ExpiresAt bounds the challenge's validity.
	ExpiresAt time.Time
	// ConsumedAt is set when a verify-control succeeded against this
	// nonce. A consumed nonce can never verify again.
	ConsumedAt *time.Time
}

IdentityChallenge is the single-use anti-replay nonce issued at register / rotate time. The registrant signs the served IdentityProofInput (which embeds this nonce); the nonce is consumed exactly once, inside the success transaction of verify-control — a failed verification attempt does NOT consume it, so a registrant may retry a bad proof until expiry.

type IdentityLink struct {
	IdentityID string
	AgentID    string
	Status     LinkStatus
	LinkedAt   time.Time
	CreatedAt  time.Time
	UpdatedAt  time.Time
}

IdentityLink associates a verified identity with one agent of the same owner. It is the only thing that touches an agent — a row plus a sealed event on the IDENTITY stream, never a field on the registration aggregate. Links carry no proof: within one owner a link asserts a fact the owner gate already establishes (§4.3).

type IdentityStatus added in v0.1.6

type IdentityStatus string

IdentityStatus is the verified-identity lifecycle state.

const (
	IdentityPendingControl IdentityStatus = "PENDING_CONTROL"
	IdentityVerified       IdentityStatus = "VERIFIED"
	IdentityRevoked        IdentityStatus = "REVOKED"
)

Identity lifecycle states. The machine is deliberately tiny:

PENDING_CONTROL → VERIFIED → REVOKED

with VERIFIED → VERIFIED on rotation (a staged replacement proves control again before anything changes — the previously sealed state stands until the new proof lands).

type LinkStatus added in v0.1.6

type LinkStatus string

LinkStatus is the lifecycle state of one identity↔agent association.

const (
	LinkLinked   LinkStatus = "LINKED"
	LinkUnlinked LinkStatus = "UNLINKED"
)

Link states. UNLINKED rows are history caches — the sealed IDENTITY_UNLINKED event is the authoritative record — and never block re-linking.

type OrderState added in v0.1.6

type OrderState string

OrderState is the lifecycle of a certificate order. It is tracked on the order itself, never on the agent lifecycle — `AgentLifecycle Status` stays exactly as the V2 spec defines it, and views like `RegistrationPending.status` (PENDING_CERTS) and `AgentStatus.phase` (CERTIFICATE_ISSUANCE) are derived from (agent status × order state).

const (
	OrderStatePending   OrderState = "PENDING"
	OrderStateIssuing   OrderState = "ISSUING"
	OrderStateCompleted OrderState = "COMPLETED"
	OrderStateFailed    OrderState = "FAILED"
)

Order states. PENDING means challenges are issued and awaiting domain validation; ISSUING means validation passed and the provider is finalizing asynchronously; COMPLETED and FAILED are terminal.

type Protocol

type Protocol string

Protocol represents the communication protocol an agent endpoint supports.

const (
	ProtocolA2A     Protocol = "A2A"
	ProtocolMCP     Protocol = "MCP"
	ProtocolHTTPAPI Protocol = "HTTP_API"
)

func ParseProtocol

func ParseProtocol(s string) (Protocol, error)

ParseProtocol parses a protocol string (case-insensitive).

func (Protocol) IsValid

func (p Protocol) IsValid() bool

IsValid returns true if the protocol is a recognized value.

func (Protocol) String

func (p Protocol) String() string

String returns the protocol as a string.

type RegistrationDetails

type RegistrationDetails struct {
	RegistrationTimestamp time.Time `json:"registrationTimestamp"`
	LastRenewalTimestamp  time.Time `json:"lastRenewalTimestamp,omitzero"`
	DisplayName           string    `json:"agentDisplayName,omitempty"`
	Description           string    `json:"agentDescription,omitempty"`
}

RegistrationDetails holds metadata about an agent registration.

func (RegistrationDetails) EffectiveTimestamp

func (d RegistrationDetails) EffectiveTimestamp() time.Time

EffectiveTimestamp returns the last renewal timestamp if set, otherwise the registration timestamp.

func (RegistrationDetails) WithRenewal

WithRenewal returns a copy with the renewal timestamp updated.

type RegistrationStatus

type RegistrationStatus string

RegistrationStatus represents the lifecycle state of an agent registration.

const (
	StatusPendingValidation RegistrationStatus = "PENDING_VALIDATION"
	StatusPendingDNS        RegistrationStatus = "PENDING_DNS"
	StatusActive            RegistrationStatus = "ACTIVE"
	StatusDeprecated        RegistrationStatus = "DEPRECATED"
	StatusRevoked           RegistrationStatus = "REVOKED"
	StatusFailed            RegistrationStatus = "FAILED"
	StatusExpired           RegistrationStatus = "EXPIRED"
)

func (RegistrationStatus) CanTransitionTo

func (s RegistrationStatus) CanTransitionTo(target RegistrationStatus) bool

CanTransitionTo returns true if moving from the current status to the target is valid.

func (RegistrationStatus) IsPending

func (s RegistrationStatus) IsPending() bool

IsPending returns true if the status is any pending state. The V2 lifecycle has exactly two pending states: PENDING_VALIDATION (registration created, awaiting ACME domain-control challenge) and PENDING_DNS (challenge passed, awaiting operator DNS publication).

func (RegistrationStatus) IsTerminal

func (s RegistrationStatus) IsTerminal() bool

IsTerminal returns true if the status is a terminal state (no further transitions).

func (RegistrationStatus) IsValid

func (s RegistrationStatus) IsValid() bool

IsValid returns true if the status is a recognized value.

func (RegistrationStatus) String

func (s RegistrationStatus) String() string

String returns the status as a string.

func (RegistrationStatus) ValidateTransition

func (s RegistrationStatus) ValidateTransition(target RegistrationStatus) error

ValidateTransition returns nil if the transition is valid, or an error otherwise.

type RenewalType

type RenewalType string

RenewalType classifies a server certificate renewal. Matches the V2 `ServerCertificateRenewalRequest.renewalType` enum (§1422) and the reference RA's `RenewalType` enum byte-for-byte.

const (
	RenewalTypeBYOC RenewalType = "SERVER_BYOC"
	RenewalTypeCSR  RenewalType = "SERVER_CSR"
)

type RenewalValidation

type RenewalValidation struct {
	OrderRef   string           `json:"orderRef,omitempty"`
	Challenges []Challenge      `json:"challenges,omitempty"`
	Status     ValidationStatus `json:"status"`
	CreatedAt  time.Time        `json:"createdAt"`
	ExpiresAt  time.Time        `json:"expiresAt"`
	UpdatedAt  time.Time        `json:"updatedAt"`
}

RenewalValidation tracks the ACME challenge state for a renewal.

OrderRef and Challenges mirror the registration aggregate's CertOrder: CSR renewals carry the provider order created by `ServerCertificateIssuer.CreateOrder`; BYOC renewals carry self-issued challenges (OrderRef empty) because domain control must still be proven before the operator's certificate goes live.

func (RenewalValidation) ChallengeOfType added in v0.1.6

func (v RenewalValidation) ChallengeOfType(t ChallengeType) (Challenge, bool)

ChallengeOfType returns the first challenge of the given type.

func (RenewalValidation) IsExpiredWithoutVerification

func (v RenewalValidation) IsExpiredWithoutVerification(now time.Time) bool

IsExpiredWithoutVerification returns true if the validation expired before being verified.

func (RenewalValidation) MarkFailed

func (v RenewalValidation) MarkFailed(now time.Time) (RenewalValidation, error)

MarkFailed transitions the validation to FAILED.

func (RenewalValidation) MarkVerified

func (v RenewalValidation) MarkVerified(now time.Time) (RenewalValidation, error)

MarkVerified transitions the validation to VERIFIED.

type RevocationReason

type RevocationReason string

RevocationReason represents why an agent was revoked.

const (
	RevocationKeyCompromise        RevocationReason = "KEY_COMPROMISE"
	RevocationCessationOfOperation RevocationReason = "CESSATION_OF_OPERATION"
	RevocationAffiliationChanged   RevocationReason = "AFFILIATION_CHANGED"
	RevocationSuperseded           RevocationReason = "SUPERSEDED"
	RevocationCertificateHold      RevocationReason = "CERTIFICATE_HOLD"
	RevocationPrivilegeWithdrawn   RevocationReason = "PRIVILEGE_WITHDRAWN"
	RevocationAACompromise         RevocationReason = "AA_COMPROMISE"
)

func (RevocationReason) IsValid

func (r RevocationReason) IsValid() bool

IsValid returns true if the revocation reason is a recognized value.

func (RevocationReason) String

func (r RevocationReason) String() string

String returns the reason as a string.

type ServerCertificateRenewal

type ServerCertificateRenewal struct {
	ID             int64       `json:"id,omitempty"`
	AgentID        string      `json:"agentId"`
	RegistrationID int64       `json:"registrationId"`
	RenewalType    RenewalType `json:"renewalType"`
	// ServerCsrID is set when RenewalType == SERVER_CSR. Points at
	// the CSR row in `agent_csrs` that this renewal was initiated
	// with. Empty for BYOC renewals.
	ServerCsrID   string            `json:"serverCsrId,omitempty"`
	ByocCertPEM   string            `json:"byocCertPem,omitempty"`
	ByocChainPEM  string            `json:"byocChainPem,omitempty"`
	FailureReason string            `json:"failureReason,omitempty"`
	CompletedAt   time.Time         `json:"completedAt,omitzero"`
	CreatedAt     time.Time         `json:"createdAt"`
	Validation    RenewalValidation `json:"validation"`
}

ServerCertificateRenewal is the aggregate root for server certificate renewals.

func NewBYOCRenewal

func NewBYOCRenewal(
	agentID string,
	registrationID int64,
	byocCertPEM string,
	byocChainPEM string,
	order CertificateOrder,
	now time.Time,
) *ServerCertificateRenewal

NewBYOCRenewal creates a new BYOC server certificate renewal. The operator supplies the already-issued certificate; the renewal only validates domain control via the order's challenges then flips the registration's ServerCert to the new leaf.

The order is self-issued (see NewSelfIssuedOrder) — no certificate provider participates in a BYOC renewal. The renewal's validation window is the shorter of the standard renewal expiry and the order's own expiry.

func NewCSRRenewal

func NewCSRRenewal(
	agentID string,
	registrationID int64,
	csrID string,
	order CertificateOrder,
	now time.Time,
) *ServerCertificateRenewal

NewCSRRenewal creates a new server-CSR renewal. The CSR is expected to already be persisted in `agent_csrs` with status=PENDING — this struct only references it by ID. Matches the reference's `AgentServerCertificateRenewal` with `renewalType = SERVER_CSR`.

The order comes from the configured `ServerCertificateIssuer` port (`CreateOrder`), so the challenges relayed to the operator are the provider's own — for an ACME provider that means the provider's token + key authorization, not RA-invented values.

func (*ServerCertificateRenewal) IsCompleted

func (r *ServerCertificateRenewal) IsCompleted() bool

IsCompleted reports whether the renewal reached its terminal completed/failed state — i.e. CompletedAt is set (MarkCompleted or MarkFailed). It is NOT true merely because validation was verified: a CSR renewal whose order is still ISSUING is VERIFIED but not yet completed, and the operator must re-POST verify-acme to finish it.

func (*ServerCertificateRenewal) IsExpired

func (r *ServerCertificateRenewal) IsExpired(now time.Time) bool

IsExpired returns true if the validation has expired.

func (*ServerCertificateRenewal) MarkCompleted

func (r *ServerCertificateRenewal) MarkCompleted(now time.Time) error

MarkCompleted marks the renewal as successfully completed.

func (*ServerCertificateRenewal) MarkFailed

func (r *ServerCertificateRenewal) MarkFailed(reason string, now time.Time) error

MarkFailed marks the renewal as failed with a reason.

func (*ServerCertificateRenewal) UpdateValidationStatus

func (r *ServerCertificateRenewal) UpdateValidationStatus(v RenewalValidation)

UpdateValidationStatus updates the embedded validation.

type SimplifiedSemVer

type SimplifiedSemVer struct {
	// contains filtered or unexported fields
}

SimplifiedSemVer represents a simplified semantic version (major.minor.patch). All components must be non-negative integers.

func NewSemVer

func NewSemVer(major, minor, patch int) (SimplifiedSemVer, error)

NewSemVer creates a SimplifiedSemVer from individual components.

func ParseSemVer

func ParseSemVer(s string) (SimplifiedSemVer, error)

ParseSemVer parses a semver string like "1.2.3".

func (SimplifiedSemVer) Compare

func (v SimplifiedSemVer) Compare(other SimplifiedSemVer) int

Compare returns -1, 0, or 1 comparing v to other.

func (SimplifiedSemVer) Equal

func (v SimplifiedSemVer) Equal(other SimplifiedSemVer) bool

Equal returns true if v == other.

func (SimplifiedSemVer) GreaterThan

func (v SimplifiedSemVer) GreaterThan(other SimplifiedSemVer) bool

GreaterThan returns true if v > other.

func (SimplifiedSemVer) IsZero

func (v SimplifiedSemVer) IsZero() bool

IsZero returns true if the version is uninitialized (0.0.0).

func (SimplifiedSemVer) Major

func (v SimplifiedSemVer) Major() int

Major returns the major version component.

func (SimplifiedSemVer) Minor

func (v SimplifiedSemVer) Minor() int

Minor returns the minor version component.

func (SimplifiedSemVer) Patch

func (v SimplifiedSemVer) Patch() int

Patch returns the patch version component.

func (SimplifiedSemVer) String

func (v SimplifiedSemVer) String() string

String returns the version as "MAJOR.MINOR.PATCH".

type StoredCertificate

type StoredCertificate struct {
	InternalID      int64           `json:"internalId"`
	CSRID           string          `json:"csrId"`
	CertificateType CertificateType `json:"certificateType"`
	CertificatePEM  string          `json:"certificatePem"`
	ChainPEM        string          `json:"chainPem,omitempty"`
	// SerialNumber is the issued certificate's serial (lowercase hex),
	// captured at issuance so CA-side revocation never re-parses the
	// PEM. Empty on rows persisted before serial tracking landed.
	SerialNumber string `json:"serialNumber,omitempty"`
	// CertificateRef is the issuing provider's opaque handle for this
	// certificate (cloud-CA resource name/ARN, ACME certificate URL).
	// Empty for the in-process self-signed CAs, which revoke by
	// serial alone.
	CertificateRef      string            `json:"certificateRef,omitempty"`
	Status              CertificateStatus `json:"status"`
	ExpirationTimestamp time.Time         `json:"expirationTimestamp"`
	IssueTimestamp      time.Time         `json:"issueTimestamp"`
}

StoredCertificate represents a certificate stored in the system.

func StoredCertificateFromByoc

func StoredCertificateFromByoc(byoc *ByocServerCertificate) *StoredCertificate

StoredCertificateFromByoc converts a BYOC server certificate into the StoredCertificate representation, matching the reference RA's `StoredCertificate.fromByoc` factory. Used by the cert-management service to present BYOC and CA-issued server certs through the same shape — the `GET /certificates/server` handler doesn't care which pathway produced the cert.

csrId is empty for BYOC entries because the BYOC flow never involves a CSR on our side; the caller submitted a fully-formed cert. The DTO mapper in the handler layer tolerates the empty string (serializes as an omitted field).

func (StoredCertificate) IsValid

func (c StoredCertificate) IsValid(now time.Time) bool

IsValid returns true if the certificate is valid (VALID status and not expired).

func (StoredCertificate) Revoke

Revoke returns a copy with REVOKED status.

type Transport

type Transport string

Transport represents a communication transport mechanism.

const (
	TransportStreamableHTTP Transport = "STREAMABLE_HTTP"
	TransportSSE            Transport = "SSE"
	TransportJSONRPC        Transport = "JSON_RPC"
	TransportGRPC           Transport = "GRPC"
	TransportREST           Transport = "REST"
	TransportHTTP           Transport = "HTTP"
)

func ParseTransport

func ParseTransport(s string) (Transport, error)

ParseTransport parses a transport string (case-insensitive).

func (Transport) IsValid

func (t Transport) IsValid() bool

IsValid returns true if the transport is a recognized value.

func (Transport) String

func (t Transport) String() string

String returns the transport as a string.

type ValidationStatus

type ValidationStatus string

ValidationStatus represents the status of an ACME validation.

const (
	ValidationPending  ValidationStatus = "PENDING"
	ValidationVerified ValidationStatus = "VERIFIED"
	ValidationFailed   ValidationStatus = "FAILED"
)

type VerifiedIdentity added in v0.1.6

type VerifiedIdentity struct {
	// IdentityID is the RA-assigned UUIDv7 — the TL stream key.
	IdentityID string
	// ProviderID is the owning authentication principal — the same
	// principal that owns the agents this identity may link to.
	ProviderID string
	Kind       IdentifierKind
	// Value is the canonical identifier (e.g.
	// "did:web:identity.acme-corp.com").
	Value  string
	Status IdentityStatus
	// ProofMethod names the control proof that verified this
	// identity ("did-web-sig" | "did-key-sig"). Empty until the
	// first successful verify-control.
	ProofMethod string
	// PendingValue stages a same-kind replacement during rotation
	// (§4.2): set by StageRotation, applied by CompleteVerification.
	// While staged, the previously sealed state stands.
	PendingValue string
	// Challenge is the live anti-replay nonce, if any.
	Challenge  *IdentityChallenge
	VerifiedAt time.Time // zero until first proof
	CreatedAt  time.Time
	UpdatedAt  time.Time
}

VerifiedIdentity is the "who" aggregate — an identity owned by a providerId, proven through a per-kind control proof, sealed onto its own Transparency Log stream, and linked to any number of that owner's agents. It is NOT part of AgentRegistration: the agent (the "what") carries no identity fields, and the two lifecycles never cascade into each other.

No public-key field lives on this aggregate (ANS-0 §6.2 key transience): proven keys are sealed in the identity's TL events, not persisted as live state.

func NewVerifiedIdentity added in v0.1.6

func NewVerifiedIdentity(identityID, providerID, rawValue string, now time.Time) (*VerifiedIdentity, error)

NewVerifiedIdentity constructs a fresh identity in PENDING_CONTROL. The caller supplies the RA-assigned identityID (UUIDv7) and the authenticated owner; the raw value is kind-inferred and canonicalized here so every code path shares one grammar.

func (*VerifiedIdentity) CheckChallenge added in v0.1.6

func (v *VerifiedIdentity) CheckChallenge(now time.Time) error

CheckChallenge reports whether the live challenge can still be proven against: present, unconsumed, unexpired. It does NOT consume — consumption is a storage-level conditional update inside the verify-control success transaction (the TOCTOU guard).

func (*VerifiedIdentity) CompleteVerification added in v0.1.6

func (v *VerifiedIdentity) CompleteVerification(now time.Time) (string, error)

CompleteVerification applies a successful control proof:

  • PENDING_CONTROL → VERIFIED (first proof; seals IDENTITY_VERIFIED)
  • VERIFIED with a staged rotation → swap the value (seals IDENTITY_UPDATED)
  • VERIFIED without a staged rotation → re-proof of the current value (also seals IDENTITY_UPDATED — the proven key set may have changed even when the value did not)

Returns the previous value when the proof completes a rotation that changed the identifier (for the sealed event's previousValue).

func (*VerifiedIdentity) EffectiveValue added in v0.1.6

func (v *VerifiedIdentity) EffectiveValue() string

EffectiveValue is the identifier the current proof round is over: the staged replacement during a rotation, otherwise the proven value.

func (*VerifiedIdentity) IssueChallenge added in v0.1.6

func (v *VerifiedIdentity) IssueChallenge(nonce string, ttl time.Duration, now time.Time) error

IssueChallenge mints a fresh anti-replay nonce, superseding any prior one (idempotent re-add, §4.2: a re-POST while PENDING_CONTROL returns the same identity with a fresh challenge). Valid while the identity is PENDING_CONTROL (initial proof) or VERIFIED (rotation re-proof); a revoked identity can never be challenged again.

func (*VerifiedIdentity) Revoke added in v0.1.6

func (v *VerifiedIdentity) Revoke(now time.Time) error

Revoke transitions a VERIFIED identity to REVOKED — a state change, never a delete: the identity's history is append-only in the TL. Revoking an unproven (PENDING_CONTROL) identity is rejected — it never sealed anything, so there is nothing to revoke; its challenge simply expires.

func (*VerifiedIdentity) StageRotation added in v0.1.6

func (v *VerifiedIdentity) StageRotation(rawValue string, now time.Time) error

StageRotation stages a same-kind replacement value (§4.2 PUT). The row stays VERIFIED with the old value — nothing changes until the replacement proves control. Cross-kind replacement is rejected (remove + add, not a rotation).

type VersionRange

type VersionRange struct {
	// contains filtered or unexported fields
}

VersionRange represents a version matching rule.

func ParseVersionRange

func ParseVersionRange(s string) (VersionRange, error)

ParseVersionRange parses a version range string. Supported formats: "*", "", "1.2.3", "^1.2.3", "~1.2.3".

func (VersionRange) Matches

func (r VersionRange) Matches(v SimplifiedSemVer) bool

Matches returns true if the given version satisfies this range.

func (VersionRange) String

func (r VersionRange) String() string

String returns the string representation of the range.

func (VersionRange) Type

func (r VersionRange) Type() VersionRangeType

Type returns the range type.

func (VersionRange) Version

func (r VersionRange) Version() SimplifiedSemVer

Version returns the base version (zero for Wildcard).

type VersionRangeType

type VersionRangeType int

VersionRangeType classifies how a version range matches.

const (
	// VersionRangeWildcard matches any version.
	VersionRangeWildcard VersionRangeType = iota
	// VersionRangeExact matches a specific version.
	VersionRangeExact
	// VersionRangeCaret is npm-style: ^1.2.3 := >=1.2.3 <2.0.0.
	VersionRangeCaret
	// VersionRangeTilde matches patch updates: ~1.2.3 := >=1.2.3 <1.3.0.
	VersionRangeTilde
)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL