licensing

package
v1.0.0-rc1 Latest Latest
Warning

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

Go to latest
Published: Oct 16, 2026 License: Apache-2.0 Imports: 27 Imported by: 0

Documentation

Index

Constants

View Source
const (
	KeyListType     = "superplane-license-keys+jwt"
	KeyListAudience = "superplane-license-keys"

	// MaxKeyListBytes bounds every key list input before any decoding.
	MaxKeyListBytes = 64 * 1024
)
View Source
const (
	// KeysURLEnv overrides where SuperPlane downloads the license key list.
	// The value "none" turns downloads off, for example without network
	// access.
	KeysURLEnv     = "SUPERPLANE_LICENSE_KEYS_URL"
	DefaultKeysURL = "https://licensing.superplane.com/.well-known/license-keys.jws"

	KeySyncInterval = 6 * time.Hour
)
View Source
const (
	RevocationListType     = "superplane-license-revocations+jwt"
	RevocationListAudience = "superplane-license-revocations"

	// MaxRevocationListBytes bounds every revocation list before decoding.
	MaxRevocationListBytes = 256 * 1024
)
View Source
const (
	ExpectedIssuer   = "https://licensing.superplane.com"
	ExpectedAudience = "superplane-self-hosted"
	TokenType        = "superplane-license+jwt"
	SigningAlgorithm = "ES256"

	// MaxLicenseBytes bounds every license input before any decoding.
	MaxLicenseBytes = 16 * 1024

	ClockSkew = 5 * time.Minute
)
View Source
const LicensePathEnv = "SUPERPLANE_LICENSE_PATH"

LicensePathEnv configures a license file, for example a mounted Kubernetes secret. When it is set, the file is the only license source.

View Source
const RefreshInterval = 30 * time.Second

RefreshInterval is how often every replica reloads the license, so that install, replace, and remove operations reach all replicas.

View Source
const RevocationSyncInterval = 5 * time.Minute

Variables

View Source
var ErrInvalidKeyList = errors.New("invalid license key list")

ErrInvalidKeyList is returned for every key list that SuperPlane must not trust. It does not say why, so that callers cannot leak details.

View Source
var ErrInvalidRevocationList = errors.New("invalid license revocation list")

ErrInvalidRevocationList is returned for every revocation list that SuperPlane must not trust. It does not say why.

View Source
var ErrKeyListDowngrade = errors.New("license key list is older than the trusted list")

ErrKeyListDowngrade is returned for a key list that is older than the trusted one. Accepting it could restore a key that the issuer removed.

View Source
var ErrKeySyncUnavailable = errors.New("license key updates are not available")

ErrKeySyncUnavailable is returned when the service does not manage keys.

View Source
var ErrManagedByFile = errors.New("the license is managed by the installation configuration")

ErrManagedByFile is returned when an administrator tries to change a license that comes from SUPERPLANE_LICENSE_PATH.

View Source
var ErrNotInstalled = errors.New("no license installed")

ErrNotInstalled tells the service that a source has no license. It is not a verification failure.

View Source
var ErrNotLicensed = errors.New("this action requires a SuperPlane Enterprise license")

ErrNotLicensed reports that the installation license does not grant an Enterprise feature.

View Source
var ErrRevocationListDowngrade = errors.New("license revocation list is older than the trusted list")

ErrRevocationListDowngrade is returned for a list older than the trusted one. Accepting it could drop a revocation the issuer already published.

Functions

func Allows

func Allows(entitlements Entitlements, feature Feature) bool

Allows reports whether entitlements grant a feature. A nil value grants nothing.

func IsRecognizedFeature

func IsRecognizedFeature(key string) bool

IsRecognizedFeature reports whether this SuperPlane version knows the key. Unknown keys in a license never grant access.

func KeysURLFromEnvironment

func KeysURLFromEnvironment() (string, error)

KeysURLFromEnvironment returns the key list URL, or an empty string when downloads are off.

func Require

func Require(entitlements Entitlements, feature Feature) error

Require returns ErrNotLicensed unless the entitlements grant the feature.

func RevocationsURL

func RevocationsURL(keysURL string) string

RevocationsURL returns the revocation list URL for a key-list URL. An empty key-list URL, which disables key downloads, also disables this download.

Types

type DatabaseKeyListCache

type DatabaseKeyListCache struct{}

DatabaseKeyListCache shares the key list between replicas.

func (DatabaseKeyListCache) Load

func (DatabaseKeyListCache) Save

type DatabaseRevocationListCache

type DatabaseRevocationListCache struct{}

DatabaseRevocationListCache shares the revocation list between replicas.

func (DatabaseRevocationListCache) Load

func (DatabaseRevocationListCache) Save

type DatabaseSource

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

DatabaseSource stores the license encrypted at rest with the installation encryptor.

func NewDatabaseSource

func NewDatabaseSource(encryptor crypto.Encryptor) *DatabaseSource

func (*DatabaseSource) Clear

func (d *DatabaseSource) Clear(ctx context.Context) error

func (*DatabaseSource) Kind

func (d *DatabaseSource) Kind() SourceKind

func (*DatabaseSource) Read

func (d *DatabaseSource) Read(ctx context.Context) ([]byte, error)

func (*DatabaseSource) Write

func (d *DatabaseSource) Write(ctx context.Context, raw []byte, installedBy uuid.UUID) error

type Edition

type Edition string
const (
	EditionCommunity  Edition = "community"
	EditionEnterprise Edition = "enterprise"
)

type Entitlements

type Entitlements interface {
	IsEntitled(feature Feature) bool
}

Entitlements answers whether an Enterprise feature is available now.

var Community Entitlements = communityEntitlements{}

Community grants no Enterprise features. Use it when no license service is configured so that Enterprise checks fail closed.

type Feature

type Feature string

Feature is an Enterprise capability key granted by a license. Keys are immutable and compared exactly.

const (
	FeatureCustomRoles Feature = "custom_roles"
	FeatureGroups      Feature = "groups"

	// FeatureAuditLogs is a defined Enterprise entitlement without a product
	// implementation yet.
	FeatureAuditLogs Feature = "audit_logs"
)

func RecognizedFeatures

func RecognizedFeatures() []Feature

RecognizedFeatures returns every Enterprise feature that this SuperPlane version knows.

type FileSource

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

func NewFileSource

func NewFileSource(path string) *FileSource

func (*FileSource) Kind

func (f *FileSource) Kind() SourceKind

func (*FileSource) Read

func (f *FileSource) Read(_ context.Context) ([]byte, error)

type KeyList

type KeyList struct {
	Version  int64
	IssuedAt time.Time
	Keys     *KeySet
	Document string
}

KeyList is a verified, root-signed list of license signing keys.

func VerifyKeyList

func VerifyKeyList(raw []byte, roots *KeySet) (*KeyList, error)

VerifyKeyList verifies a key list signed by one of the root keys. A signing key must never use the key ID of a root key.

type KeyListCache

type KeyListCache interface {
	Load(ctx context.Context) (string, error)
	Save(ctx context.Context, list *KeyList) error
}

KeyListCache stores the newest key list for every replica. Load returns an empty document when nothing is cached.

type KeySet

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

KeySet holds public keys that verify signatures.

func ParseKeySet

func ParseKeySet(data []byte) (*KeySet, error)

ParseKeySet parses a JWKS document and rejects any key that is not an ES256 P-256 signing key with a unique, well-formed key ID.

func ParseOptionalKeySet

func ParseOptionalKeySet(data []byte) (*KeySet, error)

ParseOptionalKeySet is ParseKeySet, but it accepts a key set without keys.

func ProductionRootKeySet

func ProductionRootKeySet() (*KeySet, error)

func (*KeySet) KeyIDs

func (k *KeySet) KeyIDs() []string

func (*KeySet) Len

func (k *KeySet) Len() int

func (*KeySet) Merge

func (k *KeySet) Merge(other *KeySet) (*KeySet, error)

Merge returns a key set with the keys of both sets. Duplicate key IDs are an error because a key ID must never be reused.

func (*KeySet) PublicKey

func (k *KeySet) PublicKey(keyID string) (*ecdsa.PublicKey, bool)

type KeyStore

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

KeyStore holds the license signing keys that SuperPlane trusts now. Only a key list signed by a root key can change them, and the version only grows.

func NewKeyStore

func NewKeyStore(roots *KeySet, bootstrap []byte, extra *KeySet) (*KeyStore, error)

NewKeyStore trusts the bootstrap key list when it is not empty. The extra keys are trusted in addition to every key list; only development builds pass them.

func TrustedKeyStore

func TrustedKeyStore(extra *KeySet) (*KeyStore, error)

TrustedKeyStore returns the keys that verify licenses in this binary. Release builds trust only key lists signed by the embedded root keys.

func (*KeyStore) Current

func (s *KeyStore) Current() *KeyList

Current returns the trusted key list, or nil when there is none.

func (*KeyStore) PublicKey

func (s *KeyStore) PublicKey(keyID string) (*ecdsa.PublicKey, bool)

func (*KeyStore) Roots

func (s *KeyStore) Roots() *KeySet

func (*KeyStore) Update

func (s *KeyStore) Update(list *KeyList) (bool, error)

Update trusts a verified key list when it is newer than the current one. It reports whether the trusted keys changed.

type KeySync

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

KeySync keeps the trusted license signing keys current. It downloads the key list, verifies it with the root keys, and shares it through the cache.

func NewKeySync

func NewKeySync(store *KeyStore, cache KeyListCache, keysURL string) *KeySync

NewKeySync downloads from keysURL. An empty keysURL turns downloads off.

func (*KeySync) Install

func (k *KeySync) Install(ctx context.Context, raw []byte) (*KeyList, error)

Install trusts a key list that an administrator supplies, for example without network access.

func (*KeySync) Reload

func (k *KeySync) Reload(ctx context.Context) (bool, error)

Reload trusts the cached key list when it is newer. Another replica may have saved it. When the cache is older, Reload saves the trusted list, which repairs an earlier failed cache write. It reports whether the trusted keys changed.

func (*KeySync) Start

func (k *KeySync) Start(ctx context.Context, onChange func())

Start syncs once and then every KeySyncInterval until the context ends. It calls onChange after the trusted keys change.

func (*KeySync) Status

func (k *KeySync) Status() KeySyncStatus

func (*KeySync) Sync

func (k *KeySync) Sync(ctx context.Context) (bool, error)

Sync downloads the key list and trusts it when it is newer. It reports whether the trusted keys changed.

func (*KeySync) SyncOnDemand

func (k *KeySync) SyncOnDemand(ctx context.Context) (bool, error)

SyncOnDemand runs Sync at most once per minute. Call it when a license uses an unknown key, which happens after the issuer adds a signing key.

type KeySyncState

type KeySyncState string
const (
	KeySyncDisabled KeySyncState = "disabled"
	KeySyncSyncing  KeySyncState = "syncing"
	KeySyncSynced   KeySyncState = "synced"
	KeySyncFailed   KeySyncState = "failed"
)

type KeySyncStatus

type KeySyncStatus struct {
	State    KeySyncState
	Version  int64
	SyncedAt *time.Time
}

KeySyncStatus describes the trusted key list. Version is zero when no key list is trusted.

type License

type License struct {
	ID         uuid.UUID
	CustomerID uuid.UUID
	KeyID      string
	Issuer     string
	Edition    Edition

	// Features contains only keys that this SuperPlane version recognizes.
	Features  []Feature
	IssuedAt  time.Time
	ValidFrom time.Time
	ExpiresAt time.Time
}

License is the trusted result of a successful signature and claims verification. It never contains the raw artifact.

func (*License) HasFeature

func (l *License) HasFeature(feature Feature) bool

func (*License) ValidityAt

func (l *License) ValidityAt(now time.Time) Validity

type PublicKeys

type PublicKeys interface {
	PublicKey(keyID string) (*ecdsa.PublicKey, bool)
}

PublicKeys finds the public key for a key ID.

type Reason

type Reason string

Reason is a safe failure category. It never contains license content or cryptographic details.

const (
	ReasonMalformed            Reason = "malformed"
	ReasonUnsupportedAlgorithm Reason = "unsupported_algorithm"
	ReasonUnknownKey           Reason = "unknown_key"
	ReasonInvalidSignature     Reason = "invalid_signature"
	ReasonInvalidClaims        Reason = "invalid_claims"
	ReasonExpired              Reason = "expired"
	ReasonNotYetValid          Reason = "not_yet_valid"
	ReasonRevoked              Reason = "revoked"
	ReasonUnreadable           Reason = "unreadable"
)

func ReasonOf

func ReasonOf(err error) Reason

ReasonOf returns the failure category of a verification error.

type RevocationList

type RevocationList struct {
	Version  int64
	IssuedAt time.Time

	Document string
	// contains filtered or unexported fields
}

RevocationList is a verified, root-signed set of revoked license ids.

func VerifyRevocationList

func VerifyRevocationList(raw []byte, roots *KeySet) (*RevocationList, error)

VerifyRevocationList verifies a revocation list signed by one of the root keys. It does not replace an older trusted list; callers compare versions.

func (*RevocationList) Contains

func (l *RevocationList) Contains(id uuid.UUID) bool

Contains reports whether the list names the license id.

type RevocationListCache

type RevocationListCache interface {
	Load(ctx context.Context) (string, error)
	Save(ctx context.Context, list *RevocationList) error
}

RevocationListCache stores the newest revocation list for every replica. Load returns an empty document when nothing is cached.

type RevocationSync

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

RevocationSync downloads the revocation list and keeps the last list that verified. A failed download does not change that list.

func NewRevocationSync

func NewRevocationSync(roots *KeySet, cache RevocationListCache, revocationsURL string) *RevocationSync

NewRevocationSync downloads from revocationsURL. An empty URL turns downloads off.

func (*RevocationSync) Contains

func (k *RevocationSync) Contains(id uuid.UUID) bool

Contains reports whether the last verified list names the license id. No verified list names nothing.

func (*RevocationSync) Reload

func (k *RevocationSync) Reload(ctx context.Context) (bool, error)

Reload trusts the cached list when it is newer. Another replica may have saved it. When the cache is older, Reload saves the trusted list.

func (*RevocationSync) Start

func (k *RevocationSync) Start(ctx context.Context)

Start syncs once and then every RevocationSyncInterval until the context ends.

func (*RevocationSync) Sync

func (k *RevocationSync) Sync(ctx context.Context) (bool, error)

Sync downloads the revocation list and trusts it when it is newer. It reports whether the trusted list changed.

type Service

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

func NewService

func NewService(verifier *Verifier, source Source, options ...ServiceOption) *Service

func (*Service) Install

func (s *Service) Install(ctx context.Context, raw []byte, installedBy uuid.UUID) (Status, error)

Install verifies a license and stores it. It accepts only a license that is valid now, so an installation never replaces a working license with one that grants nothing.

func (*Service) InstallKeyList

func (s *Service) InstallKeyList(ctx context.Context, raw []byte) error

InstallKeyList trusts a key list that an administrator uploads and then reloads the license, which may use a key from the list.

func (*Service) IsEntitled

func (s *Service) IsEntitled(feature Feature) bool

func (*Service) Refresh

func (s *Service) Refresh(ctx context.Context) error

Refresh reloads the trusted keys and the license. A temporary database error keeps the last known state instead of removing Enterprise access.

func (*Service) Remove

func (s *Service) Remove(ctx context.Context, removedBy uuid.UUID) (Status, error)

func (*Service) Start

func (s *Service) Start(ctx context.Context)

Start loads the license once and then refreshes it in the background until the context ends.

func (*Service) Status

func (s *Service) Status() Status

func (*Service) TrustedKeys

func (s *Service) TrustedKeys() (KeySyncStatus, bool)

TrustedKeys reports the trusted key list. It returns false when the service does not sync keys.

type ServiceOption

type ServiceOption func(*Service)

func WithKeySync

func WithKeySync(keySync *KeySync) ServiceOption

WithKeySync keeps the trusted signing keys current while the service runs.

func WithRevocationSync

func WithRevocationSync(revocations *RevocationSync) ServiceOption

WithRevocationSync keeps the revoked-license list current while the service runs.

type Source

type Source interface {
	Kind() SourceKind
	Read(ctx context.Context) ([]byte, error)
}

Source supplies a raw license artifact.

func SourceFromEnvironment

func SourceFromEnvironment(encryptor crypto.Encryptor) Source

SourceFromEnvironment selects the single authoritative license source. A configured license file wins over the database. A configured but invalid file does not fall back to the database.

type SourceKind

type SourceKind string
const (
	SourceNone     SourceKind = "none"
	SourceFile     SourceKind = "file"
	SourceDatabase SourceKind = "database"
)

type State

type State string
const (
	StateNone        State = "none"
	StateActive      State = "active"
	StateExpired     State = "expired"
	StateNotYetValid State = "not_yet_valid"
	StateInvalid     State = "invalid"
	StateRevoked     State = "revoked"
)

type Status

type Status struct {
	Edition  Edition
	Source   SourceKind
	State    State
	Reason   Reason
	License  *License
	Writable bool
}

Status is the safe license state. It never contains the raw license.

func (Status) IsEntitled

func (s Status) IsEntitled(feature Feature) bool

type Validity

type Validity string
const (
	ValidityActive      Validity = "active"
	ValidityNotYetValid Validity = "not_yet_valid"
	ValidityExpired     Validity = "expired"
)

type VerificationError

type VerificationError struct {
	Reason Reason
}

func (*VerificationError) Error

func (e *VerificationError) Error() string

type Verifier

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

Verifier checks license signatures and claims offline against trusted public keys. It does not check the validity window; callers use License.ValidityAt so an expired license can still be reported.

func NewVerifier

func NewVerifier(keys PublicKeys) *Verifier

func (*Verifier) Verify

func (v *Verifier) Verify(raw []byte) (*License, error)

type WritableSource

type WritableSource interface {
	Source
	Write(ctx context.Context, raw []byte, installedBy uuid.UUID) error
	Clear(ctx context.Context) error
}

WritableSource is a Source that installation administrators can change.

Directories

Path Synopsis
Package devlicense grants every Enterprise feature to the development server.
Package devlicense grants every Enterprise feature to the development server.
Package licensingtest signs licenses with ephemeral keys for tests.
Package licensingtest signs licenses with ephemeral keys for tests.

Jump to

Keyboard shortcuts

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