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 ¶
- Variables
- func DIDWebResolutionURL(canonicalValue string) (string, error)
- func ProofMethodForKind(kind IdentifierKind) string
- func ValidDiscoveryProfiles() []string
- type AgentActivatedEvent
- type AgentCSR
- type AgentDeprecatedEvent
- type AgentEndpoint
- type AgentEndpoints
- type AgentFunction
- type AgentRegisteredEvent
- type AgentRegistration
- func (r *AgentRegistration) Activate(now time.Time) error
- func (r *AgentRegistration) AdvanceToPendingDNS() error
- func (r *AgentRegistration) AllowsSupersede(newVersion SimplifiedSemVer) bool
- func (r *AgentRegistration) Cancel(now time.Time) error
- func (r *AgentRegistration) ClearEvents() []Event
- func (r *AgentRegistration) Deprecate(supersededByID string, now time.Time) error
- func (r *AgentRegistration) Expire() error
- func (r *AgentRegistration) FQDN() string
- func (r *AgentRegistration) Fail() error
- func (r *AgentRegistration) Revoke(reason RevocationReason, now time.Time) error
- func (r *AgentRegistration) SubmitIdentityCSR(csrID, csrPEM string, now time.Time) (*AgentCSR, error)
- func (r *AgentRegistration) SubmitServerCSR(csrID, csrPEM string, now time.Time) (*AgentCSR, error)
- type AgentRevocation
- type AgentRevokedEvent
- type AnsName
- type ByocServerCertificate
- type CSRStatus
- type CSRType
- type CertRequestedEvent
- type CertificateOrder
- func (o *CertificateOrder) ChallengeOfType(t ChallengeType) (Challenge, bool)
- func (o *CertificateOrder) IsExpired(now time.Time) bool
- func (o *CertificateOrder) IsZero() bool
- func (o *CertificateOrder) MarkCompleted() error
- func (o *CertificateOrder) MarkFailed() error
- func (o *CertificateOrder) MarkIssuing() error
- type CertificateStatus
- type CertificateType
- type Challenge
- type ChallengeType
- type DNSRecordPurpose
- type DNSRecordType
- type DiscoveryProfile
- type Error
- func NewCertificateError(code, message string) *Error
- func NewConflictError(code, message string) *Error
- func NewInternalError(code, message string, cause error) *Error
- func NewInvalidStateError(code, message string) *Error
- func NewNotFoundError(code, message string) *Error
- func NewUnauthorizedError(code, message string) *Error
- func NewUnavailableError(code, message string) *Error
- func NewValidationError(code, message string) *Error
- type Event
- type EventType
- type ExpectedDNSRecord
- type IdentifierKind
- type IdentityChallenge
- type IdentityLink
- type IdentityStatus
- type LinkStatus
- type OrderState
- type Protocol
- type RegistrationDetails
- type RegistrationStatus
- func (s RegistrationStatus) CanTransitionTo(target RegistrationStatus) bool
- func (s RegistrationStatus) IsPending() bool
- func (s RegistrationStatus) IsTerminal() bool
- func (s RegistrationStatus) IsValid() bool
- func (s RegistrationStatus) String() string
- func (s RegistrationStatus) ValidateTransition(target RegistrationStatus) error
- type RenewalType
- type RenewalValidation
- func (v RenewalValidation) ChallengeOfType(t ChallengeType) (Challenge, bool)
- func (v RenewalValidation) IsExpiredWithoutVerification(now time.Time) bool
- func (v RenewalValidation) MarkFailed(now time.Time) (RenewalValidation, error)
- func (v RenewalValidation) MarkVerified(now time.Time) (RenewalValidation, error)
- type RevocationReason
- type ServerCertificateRenewal
- func (r *ServerCertificateRenewal) IsCompleted() bool
- func (r *ServerCertificateRenewal) IsExpired(now time.Time) bool
- func (r *ServerCertificateRenewal) MarkCompleted(now time.Time) error
- func (r *ServerCertificateRenewal) MarkFailed(reason string, now time.Time) error
- func (r *ServerCertificateRenewal) UpdateValidationStatus(v RenewalValidation)
- type SimplifiedSemVer
- func (v SimplifiedSemVer) Compare(other SimplifiedSemVer) int
- func (v SimplifiedSemVer) Equal(other SimplifiedSemVer) bool
- func (v SimplifiedSemVer) GreaterThan(other SimplifiedSemVer) bool
- func (v SimplifiedSemVer) IsZero() bool
- func (v SimplifiedSemVer) Major() int
- func (v SimplifiedSemVer) Minor() int
- func (v SimplifiedSemVer) Patch() int
- func (v SimplifiedSemVer) String() string
- type StoredCertificate
- type Transport
- type ValidationStatus
- type VerifiedIdentity
- func (v *VerifiedIdentity) CheckChallenge(now time.Time) error
- func (v *VerifiedIdentity) CompleteVerification(now time.Time) (string, error)
- func (v *VerifiedIdentity) EffectiveValue() string
- func (v *VerifiedIdentity) IssueChallenge(nonce string, ttl time.Duration, now time.Time) error
- func (v *VerifiedIdentity) Revoke(now time.Time) error
- func (v *VerifiedIdentity) StageRotation(rawValue string, now time.Time) error
- type VersionRange
- type VersionRangeType
Constants ¶
This section is empty.
Variables ¶
var ( ErrNotFound = errors.New("not found") ErrConflict = errors.New("conflict") ErrInvalidState = errors.New("invalid state") ErrValidation = errors.New("validation") ErrCertificate = errors.New("certificate") ErrInternal = errors.New("internal") // 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.
var ValidTransitions = map[RegistrationStatus][]RegistrationStatus{ StatusPendingValidation: {StatusPendingDNS, StatusFailed, StatusRevoked, StatusExpired}, StatusPendingDNS: {StatusActive, StatusFailed, StatusRevoked, StatusExpired}, StatusActive: {StatusDeprecated, StatusRevoked}, StatusDeprecated: {StatusRevoked}, StatusRevoked: {}, StatusFailed: {}, StatusExpired: {}, }
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
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 ¶
NewIdentityCSR creates a new pending identity CSR.
func NewServerCSR ¶
NewServerCSR creates a new pending server CSR.
func (AgentCSR) MarkRejected ¶
MarkRejected transitions the CSR to REJECTED status with a reason.
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 ¶
func (e AgentDeprecatedEvent) Type() EventType
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 ¶
func (e AgentRegisteredEvent) Type() EventType
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 ¶
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 ¶
func (e AgentRevokedEvent) Reason() RevocationReason
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 ¶
ParseAnsName parses an ANS name string like "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.
type CSRType ¶
type CSRType string
CSRType distinguishes identity CSRs from server CSRs. Matches the V2 `CsrStatusResponse.type` enum (§1381) exactly.
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
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
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
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
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 ¶
NewCertificateError creates a certificate domain error.
func NewConflictError ¶
NewConflictError creates a conflict domain error.
func NewInternalError ¶
NewInternalError creates an internal domain error wrapping a cause.
func NewInvalidStateError ¶
NewInvalidStateError creates an invalid-state domain error.
func NewNotFoundError ¶
NewNotFoundError creates a not-found domain error.
func NewUnauthorizedError ¶
NewUnauthorizedError creates an unauthorized domain error.
func NewUnavailableError ¶ added in v0.1.6
NewUnavailableError creates a retryable upstream-unavailable error.
func NewValidationError ¶
NewValidationError creates a validation domain error.
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 ¶ added in v0.1.6
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.
func ParseProtocol ¶
ParseProtocol parses a protocol string (case-insensitive).
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 ¶
func (d RegistrationDetails) WithRenewal(at time.Time) RegistrationDetails
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 ¶
func (c StoredCertificate) Revoke() StoredCertificate
Revoke returns a copy with REVOKED status.
type Transport ¶
type Transport string
Transport represents a communication transport mechanism.
func ParseTransport ¶
ParseTransport parses a transport string (case-insensitive).
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
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 )