Documentation
¶
Index ¶
- Constants
- Variables
- type AmbiguousTokenCacheError
- type AuthResult
- type CachedIssuer
- type CachedToken
- type Client
- func (c *Client) Close() error
- func (c *Client) CreateSync(ctx context.Context, remoteURL string, cids []string, opts *CreateSyncOptions) (string, error)
- func (c *Client) Delete(ctx context.Context, recordRef *corev1.RecordRef) error
- func (c *Client) DeleteBatch(ctx context.Context, recordRefs []*corev1.RecordRef) error
- func (c *Client) DeleteReferrer(ctx context.Context, req *storev1.DeleteReferrerRequest) (*storev1.DeleteReferrerResponse, error)
- func (c *Client) DeleteStream(ctx context.Context, refsCh <-chan *corev1.RecordRef) (streaming.StreamResult[emptypb.Empty], error)
- func (c *Client) DeleteSync(ctx context.Context, syncID string) error
- func (c *Client) GetSync(ctx context.Context, syncID string) (*storev1.GetSyncResponse, error)
- func (c *Client) GetVerificationInfo(ctx context.Context, cid string) (*namingv1.GetVerificationInfoResponse, error)
- func (c *Client) GetVerificationInfoByName(ctx context.Context, name string, version string) (*namingv1.GetVerificationInfoResponse, error)
- func (c *Client) GetWorkload(ctx context.Context, workloadID string) (*runtimev1.Workload, error)
- func (c *Client) List(ctx context.Context, req *routingv1.ListRequest) (<-chan *routingv1.ListResponse, error)
- func (c *Client) ListSyncs(ctx context.Context, req *storev1.ListSyncsRequest) (<-chan *storev1.ListSyncsItem, error)
- func (c *Client) ListWorkloads(ctx context.Context, labels map[string]string) ([]*runtimev1.Workload, error)
- func (c *Client) ListWorkloadsStream(ctx context.Context, labels map[string]string) (streaming.StreamResult[runtimev1.Workload], error)
- func (c *Client) ListenStream(ctx context.Context, req *eventsv1.ListenRequest) (streaming.StreamResult[eventsv1.ListenResponse], error)
- func (c *Client) Lookup(ctx context.Context, recordRef *corev1.RecordRef) (*corev1.RecordMeta, error)
- func (c *Client) LookupBatch(ctx context.Context, recordRefs []*corev1.RecordRef) ([]*corev1.RecordMeta, error)
- func (c *Client) LookupStream(ctx context.Context, refsCh <-chan *corev1.RecordRef) (streaming.StreamResult[corev1.RecordMeta], error)
- func (c *Client) Publish(ctx context.Context, req *routingv1.PublishRequest) error
- func (c *Client) Pull(ctx context.Context, recordRef *corev1.RecordRef) (*corev1.Record, error)
- func (c *Client) PullBatch(ctx context.Context, recordRefs []*corev1.RecordRef) ([]*corev1.Record, error)
- func (c *Client) PullPublicKeys(ctx context.Context, recordRef *corev1.RecordRef) ([]string, error)
- func (c *Client) PullReferrer(ctx context.Context, req *storev1.PullReferrerRequest) ([]*storev1.PullReferrerResponse, error)
- func (c *Client) PullSignatures(ctx context.Context, recordRef *corev1.RecordRef) ([]*signv1.Signature, error)
- func (c *Client) PullStream(ctx context.Context, refsCh <-chan *corev1.RecordRef) (streaming.StreamResult[corev1.Record], error)
- func (c *Client) Push(ctx context.Context, record *corev1.Record) (*corev1.RecordRef, error)
- func (c *Client) PushBatch(ctx context.Context, records []*corev1.Record) ([]*corev1.RecordRef, error)
- func (c *Client) PushReferrer(ctx context.Context, req *storev1.PushReferrerRequest) (*storev1.PushReferrerResponse, error)
- func (c *Client) PushStream(ctx context.Context, recordsCh <-chan *corev1.Record) (streaming.StreamResult[corev1.RecordRef], error)
- func (c *Client) Resolve(ctx context.Context, name string, version string) (*namingv1.ResolveResponse, error)
- func (c *Client) SearchCIDs(ctx context.Context, req *searchv1.SearchCIDsRequest) (streaming.StreamResult[searchv1.SearchCIDsResponse], error)
- func (c *Client) SearchRecords(ctx context.Context, req *searchv1.SearchRecordsRequest) (streaming.StreamResult[searchv1.SearchRecordsResponse], error)
- func (c *Client) SearchRouting(ctx context.Context, req *routingv1.SearchRequest) (<-chan *routingv1.SearchResponse, error)
- func (c *Client) Sign(ctx context.Context, req *signv1.SignRequest) (*signv1.SignResponse, error)
- func (c *Client) Unpublish(ctx context.Context, req *routingv1.UnpublishRequest) error
- func (c *Client) Verify(ctx context.Context, req *signv1.VerifyRequest) (*signv1.VerifyResponse, error)
- type Config
- type CreateSyncOptions
- type DeviceFlowConfig
- type OIDCProvider
- type Option
- type PKCEConfig
- type RefreshTokenConfig
- type TokenCache
- func (c *TokenCache) Clear() error
- func (c *TokenCache) GetCachePath() string
- func (c *TokenCache) GetValidToken() (*CachedToken, error)
- func (c *TokenCache) IsValid(token *CachedToken) bool
- func (c *TokenCache) Load() (*CachedToken, error)
- func (c *TokenCache) Save(token *CachedToken) error
- func (c *TokenCache) SaveAtomic(token *CachedToken) error
- type TokenCacheEntry
Constants ¶
const ( DefaultEnvPrefix = "DIRECTORY_CLIENT" DefaultServerAddress = "0.0.0.0:8888" DefaultTlsSkipVerify = false DefaultCallbackPort = 8484 DefaultOAuthTimeout = 5 * time.Minute )
const ( // DefaultTokenCacheDir is the default directory for storing cached tokens (relative to home directory). // When XDG_CONFIG_HOME is set, tokens are stored at $XDG_CONFIG_HOME/dirctl instead. //nolint:gosec // G101: This is a directory path, not a credential DefaultTokenCacheDir = ".config/dirctl" // TokenCacheFile is the filename for the cached token. //nolint:gosec // G101: This is a filename, not a credential TokenCacheFile = "auth-token.json" // TokenCacheSubdir is where issuer-scoped token cache files are stored. TokenCacheSubdir = "tokens" // DefaultTokenValidityDuration is how long a token is considered valid if no expiry is set. DefaultTokenValidityDuration = 8 * time.Hour // TokenExpiryBuffer is how much time before actual expiry we consider a token expired. TokenExpiryBuffer = 5 * time.Minute )
const DefaultOIDCScopes = "openid email profile offline_access"
DefaultOIDCScopes are the OIDC scopes requested for interactive login.
Variables ¶
var ( // ErrTokenCacheNotFound indicates that a specific token cache file does not exist. ErrTokenCacheNotFound = errors.New("token cache not found") // ErrNoCachedIssuer indicates that no issuer-scoped token cache could be selected. ErrNoCachedIssuer = errors.New("no cached OIDC issuer found") )
var DefaultConfig = Config{ ServerAddress: DefaultServerAddress, }
var OIDC = &OIDCProvider{}
OIDC provides OIDC authentication flows.
Functions ¶
This section is empty.
Types ¶
type AmbiguousTokenCacheError ¶ added in v1.3.0
type AmbiguousTokenCacheError struct {
Issuers []string
}
AmbiguousTokenCacheError indicates multiple issuer-scoped caches exist and the caller must select one.
func (*AmbiguousTokenCacheError) Error ¶ added in v1.3.0
func (e *AmbiguousTokenCacheError) Error() string
type AuthResult ¶ added in v1.2.0
type AuthResult struct {
AccessToken string
RefreshToken string
TokenType string
ExpiresAt time.Time
IDToken string
Subject string
Email string
Name string
}
AuthResult is the unified result from any OIDC authentication flow (PKCE or device).
type CachedIssuer ¶ added in v1.3.0
CachedIssuer describes one issuer-scoped cache file.
func ListCachedIssuers ¶ added in v1.3.0
func ListCachedIssuers() ([]CachedIssuer, error)
ListCachedIssuers returns all issuer-scoped token caches on disk.
type CachedToken ¶ added in v1.0.0
type CachedToken struct {
// AccessToken is the authentication token.
AccessToken string `json:"access_token"` // #nosec G117: intentional field - for cached token
// TokenType is the token type (usually "bearer").
TokenType string `json:"token_type,omitempty"`
// Provider is the authentication provider (oidc, github, google, azure, etc.)
Provider string `json:"provider,omitempty"`
// Issuer is the OIDC issuer URL (for Provider=oidc). Enables multi-issuer support.
Issuer string `json:"issuer,omitempty"`
// RefreshToken is the refresh token, if the IdP returned one (for token refresh).
RefreshToken string `json:"refresh_token,omitempty"` // #nosec G101: intentional field - for cached token
// ExpiresAt is when the token expires.
ExpiresAt time.Time `json:"expires_at,omitzero"`
// User is the authenticated username (e.g. preferred_username or name for OIDC).
User string `json:"user,omitempty"`
// UserID is the provider-specific user ID (e.g. sub for OIDC).
UserID string `json:"user_id,omitempty"`
// Email is the user's email address.
Email string `json:"email,omitempty"`
// CreatedAt is when the token was cached.
CreatedAt time.Time `json:"created_at"`
}
CachedToken represents a cached authentication token from any provider.
type Client ¶
type Client struct {
storev1.StoreServiceClient
routingv1.RoutingServiceClient
searchv1.SearchServiceClient
storev1.SyncServiceClient
signv1.SignServiceClient
eventsv1.EventServiceClient
namingv1.NamingServiceClient
runtimev1.DiscoveryServiceClient
// contains filtered or unexported fields
}
func (*Client) CreateSync ¶
func (*Client) DeleteBatch ¶
DeleteBatch removes multiple records from the store in a single stream for efficiency.
func (*Client) DeleteReferrer ¶ added in v1.2.0
func (c *Client) DeleteReferrer( ctx context.Context, req *storev1.DeleteReferrerRequest, ) (*storev1.DeleteReferrerResponse, error)
func (*Client) DeleteStream ¶
func (c *Client) DeleteStream(ctx context.Context, refsCh <-chan *corev1.RecordRef) (streaming.StreamResult[emptypb.Empty], error)
DeleteStream provides efficient streaming delete operations using channels. Record references are sent as they become available and delete confirmations are returned as they're processed. This method maintains a single gRPC stream for all operations, dramatically improving efficiency.
func (*Client) GetVerificationInfo ¶ added in v1.0.0
func (c *Client) GetVerificationInfo(ctx context.Context, cid string) (*namingv1.GetVerificationInfoResponse, error)
GetVerificationInfo retrieves the verification info for a record by CID.
func (*Client) GetVerificationInfoByName ¶ added in v1.0.0
func (c *Client) GetVerificationInfoByName(ctx context.Context, name string, version string) (*namingv1.GetVerificationInfoResponse, error)
GetVerificationInfoByName retrieves the verification info for a record by name. If version is empty, the latest version is used.
func (*Client) GetWorkload ¶ added in v1.2.0
func (*Client) List ¶
func (c *Client) List(ctx context.Context, req *routingv1.ListRequest) (<-chan *routingv1.ListResponse, error)
func (*Client) ListSyncs ¶
func (c *Client) ListSyncs(ctx context.Context, req *storev1.ListSyncsRequest) (<-chan *storev1.ListSyncsItem, error)
func (*Client) ListWorkloads ¶ added in v1.2.0
func (*Client) ListWorkloadsStream ¶ added in v1.2.0
func (*Client) ListenStream ¶
func (c *Client) ListenStream(ctx context.Context, req *eventsv1.ListenRequest) (streaming.StreamResult[eventsv1.ListenResponse], error)
ListenStream streams events from the server with the specified filters.
Returns a StreamResult that provides structured channels for receiving events, errors, and completion signals.
Example - Listen to all events:
result, err := client.ListenStream(ctx, &eventsv1.ListenRequest{})
if err != nil {
return err
}
for {
select {
case resp := <-result.ResCh():
event := resp.GetEvent()
fmt.Printf("Event: %s - %s\n", event.Type, event.ResourceId)
case err := <-result.ErrCh():
return fmt.Errorf("stream error: %w", err)
case <-result.DoneCh():
return nil
case <-ctx.Done():
return ctx.Err()
}
}
Example - Filter by event type:
result, err := client.ListenStream(ctx, &eventsv1.ListenRequest{
EventTypes: []eventsv1.EventType{
eventsv1.EventType_EVENT_TYPE_RECORD_PUSHED,
eventsv1.EventType_EVENT_TYPE_RECORD_PUBLISHED,
},
})
Example - Filter by labels:
result, err := client.ListenStream(ctx, &eventsv1.ListenRequest{
LabelFilters: []string{"/skills/AI"},
})
func (*Client) Lookup ¶
func (c *Client) Lookup(ctx context.Context, recordRef *corev1.RecordRef) (*corev1.RecordMeta, error)
Lookup retrieves metadata for a record using its reference.
func (*Client) LookupBatch ¶
func (c *Client) LookupBatch(ctx context.Context, recordRefs []*corev1.RecordRef) ([]*corev1.RecordMeta, error)
LookupBatch retrieves metadata for multiple records in a single stream for efficiency.
func (*Client) LookupStream ¶
func (c *Client) LookupStream(ctx context.Context, refsCh <-chan *corev1.RecordRef) (streaming.StreamResult[corev1.RecordMeta], error)
LookupStream provides efficient streaming lookup operations using channels. Record references are sent as they become available and metadata is returned as it's processed. This method maintains a single gRPC stream for all operations, dramatically improving efficiency.
Uses sequential streaming pattern (Send → Recv → Send → Recv) which ensures strict ordering of request-response pairs.
func (*Client) Pull ¶
Pull retrieves a single record from the store using its reference. This is a convenience wrapper around PullBatch for single-record operations.
func (*Client) PullBatch ¶
func (c *Client) PullBatch(ctx context.Context, recordRefs []*corev1.RecordRef) ([]*corev1.Record, error)
PullBatch retrieves multiple records in a single stream for efficiency. This is a convenience method that accepts a slice and returns a slice, built on top of the streaming implementation for consistency.
func (*Client) PullPublicKeys ¶ added in v1.1.0
PullPublicKeys fetches all public key referrers for a record.
func (*Client) PullReferrer ¶
func (c *Client) PullReferrer(ctx context.Context, req *storev1.PullReferrerRequest) ([]*storev1.PullReferrerResponse, error)
PullReferrer retrieves all referrers using the PullReferrer RPC.
func (*Client) PullSignatures ¶ added in v1.1.0
func (c *Client) PullSignatures(ctx context.Context, recordRef *corev1.RecordRef) ([]*signv1.Signature, error)
PullSignatures fetches all signature referrers for a record.
func (*Client) PullStream ¶
func (c *Client) PullStream(ctx context.Context, refsCh <-chan *corev1.RecordRef) (streaming.StreamResult[corev1.Record], error)
PullStream retrieves multiple records efficiently using a single bidirectional stream. This method is ideal for batch operations and takes full advantage of gRPC streaming. The input channel allows you to send record refs as they become available.
func (*Client) Push ¶
Push sends a complete record to the store and returns a record reference. This is a convenience wrapper around PushBatch for single-record operations. The record must be ≤4MB as per the v1 store service specification.
func (*Client) PushBatch ¶
func (c *Client) PushBatch(ctx context.Context, records []*corev1.Record) ([]*corev1.RecordRef, error)
PushBatch sends multiple records in a single stream for efficiency. This is a convenience method that accepts a slice and returns a slice, built on top of the streaming implementation for consistency.
func (*Client) PushReferrer ¶
func (c *Client) PushReferrer(ctx context.Context, req *storev1.PushReferrerRequest) (*storev1.PushReferrerResponse, error)
PushReferrer stores a signature using the PushReferrer RPC.
func (*Client) PushStream ¶
func (c *Client) PushStream(ctx context.Context, recordsCh <-chan *corev1.Record) (streaming.StreamResult[corev1.RecordRef], error)
PushStream uploads multiple records efficiently using a single bidirectional stream. This method is ideal for batch operations and takes full advantage of gRPC streaming. The input channel allows you to send records as they become available.
func (*Client) Resolve ¶ added in v1.0.0
func (c *Client) Resolve(ctx context.Context, name string, version string) (*namingv1.ResolveResponse, error)
Resolve resolves a record reference (name with optional version) to CIDs. Returns all matching records sorted by created_at descending (newest first). If version is empty, returns all versions; otherwise returns matches for the specific version.
func (*Client) SearchCIDs ¶ added in v0.5.6
func (c *Client) SearchCIDs(ctx context.Context, req *searchv1.SearchCIDsRequest) (streaming.StreamResult[searchv1.SearchCIDsResponse], error)
SearchCIDs searches for record CIDs matching the given request.
func (*Client) SearchRecords ¶ added in v0.5.6
func (c *Client) SearchRecords(ctx context.Context, req *searchv1.SearchRecordsRequest) (streaming.StreamResult[searchv1.SearchRecordsResponse], error)
SearchRecords searches for full records matching the given request.
func (*Client) SearchRouting ¶
func (c *Client) SearchRouting(ctx context.Context, req *routingv1.SearchRequest) (<-chan *routingv1.SearchResponse, error)
func (*Client) Sign ¶
func (c *Client) Sign(ctx context.Context, req *signv1.SignRequest) (*signv1.SignResponse, error)
Sign routes to the appropriate signing method based on provider type. This is the main entry point for signing operations.
func (*Client) Verify ¶
func (c *Client) Verify(ctx context.Context, req *signv1.VerifyRequest) (*signv1.VerifyResponse, error)
Verify verifies signatures for a record. When from_server is true, the result is the server's cached verification; when false, verification is performed locally.
type Config ¶
type Config struct {
ServerAddress string `json:"server_address,omitempty" mapstructure:"server_address"`
TlsSkipVerify bool `json:"tls_skip_verify,omitempty" mapstructure:"tls_skip_verify"`
TlsCertFile string `json:"tls_cert_file,omitempty" mapstructure:"tls_cert_file"`
TlsKeyFile string `json:"tls_key_file,omitempty" mapstructure:"tls_key_file"`
TlsCAFile string `json:"tls_ca_file,omitempty" mapstructure:"tls_ca_file"`
SpiffeSocketPath string `json:"spiffe_socket_path,omitempty" mapstructure:"spiffe_socket_path"`
SpiffeToken string `json:"spiffe_token,omitempty" mapstructure:"spiffe_token"`
AuthMode string `json:"auth_mode,omitempty" mapstructure:"auth_mode"`
JWTAudience string `json:"jwt_audience,omitempty" mapstructure:"jwt_audience"`
// OIDC configuration (for interactive login)
OIDCIssuer string `json:"oidc_issuer,omitempty" mapstructure:"oidc_issuer"`
OIDCClientID string `json:"oidc_client_id,omitempty" mapstructure:"oidc_client_id"`
// Pre-issued Bearer token for CI/scripts (skips interactive login)
AuthToken string `json:"auth_token,omitempty" mapstructure:"auth_token"`
}
func LoadConfig ¶
type CreateSyncOptions ¶ added in v1.3.0
CreateSyncOptions holds optional parameters for creating a sync.
type DeviceFlowConfig ¶ added in v1.0.0
type DeviceFlowConfig struct {
Issuer string
ClientID string
Scopes []string
PollInterval time.Duration
Timeout time.Duration
Output io.Writer
}
DeviceFlowConfig holds configuration for the OAuth 2.0 Device Authorization Grant (RFC 8628).
type OIDCProvider ¶ added in v1.2.0
type OIDCProvider struct{}
OIDCProvider groups OIDC-related methods.
func (*OIDCProvider) RefreshAccessToken ¶ added in v1.3.0
func (*OIDCProvider) RefreshAccessToken(ctx context.Context, cfg *RefreshTokenConfig) (*AuthResult, error)
RefreshAccessToken exchanges a cached refresh token for fresh access credentials.
func (*OIDCProvider) RunDeviceFlow ¶ added in v1.2.0
func (*OIDCProvider) RunDeviceFlow(ctx context.Context, cfg *DeviceFlowConfig) (*AuthResult, error)
RunDeviceFlow performs the OAuth 2.0 Device Authorization Grant (RFC 8628).
func (*OIDCProvider) RunPKCEFlow ¶ added in v1.2.0
func (*OIDCProvider) RunPKCEFlow(ctx context.Context, cfg *PKCEConfig) (*AuthResult, error)
RunPKCEFlow performs the OIDC Authorization Code flow with PKCE.
type Option ¶
type Option func(*options) error
func WithConfig ¶
func WithEnvConfig ¶
func WithEnvConfig() Option
type PKCEConfig ¶ added in v1.2.0
type PKCEConfig struct {
Issuer string
ClientID string
RedirectURI string
Scopes []string
CallbackPort int
SkipBrowserOpen bool
Timeout time.Duration
Output io.Writer
}
PKCEConfig holds configuration for the OIDC PKCE flow.
type RefreshTokenConfig ¶ added in v1.3.0
type RefreshTokenConfig struct {
Issuer string
ClientID string
RefreshToken string
Timeout time.Duration
}
RefreshTokenConfig holds configuration for the OAuth 2.0 refresh token grant.
type TokenCache ¶ added in v1.0.0
type TokenCache struct {
// CacheDir is the directory where tokens are stored.
CacheDir string
// CacheFile is the cache filename inside CacheDir.
CacheFile string
// Issuer is the issuer this cache is scoped to, if any.
Issuer string
}
TokenCache manages cached authentication tokens from any provider.
func NewTokenCache ¶ added in v1.0.0
func NewTokenCache() *TokenCache
NewTokenCache creates a new token cache with the default directory. Respects XDG_CONFIG_HOME environment variable for config directory location.
func NewTokenCacheForIssuer ¶ added in v1.3.0
func NewTokenCacheForIssuer(issuer string) (*TokenCache, error)
NewTokenCacheForIssuer creates a token cache scoped to a specific issuer.
func NewTokenCacheWithDir ¶ added in v1.0.0
func NewTokenCacheWithDir(dir string) *TokenCache
NewTokenCacheWithDir creates a new token cache with a custom directory.
func NewTokenCacheWithDirAndIssuer ¶ added in v1.3.0
func NewTokenCacheWithDirAndIssuer(dir, issuer string) (*TokenCache, error)
NewTokenCacheWithDirAndIssuer creates a token cache for a specific issuer using a custom root directory.
func ResolveTokenCacheForIssuer ¶ added in v1.3.0
func ResolveTokenCacheForIssuer(issuer string) (*TokenCache, error)
ResolveTokenCacheForIssuer resolves the appropriate token cache. If issuer is provided, the corresponding issuer-scoped cache is returned. If issuer is empty, the only available issuer cache is returned when exactly one exists. Returns ErrNoCachedIssuer when no issuer is provided and no caches exist.
func (*TokenCache) Clear ¶ added in v1.0.0
func (c *TokenCache) Clear() error
Clear removes the cached token.
func (*TokenCache) GetCachePath ¶ added in v1.0.0
func (c *TokenCache) GetCachePath() string
GetCachePath returns the full path to the token cache file.
func (*TokenCache) GetValidToken ¶ added in v1.0.0
func (c *TokenCache) GetValidToken() (*CachedToken, error)
GetValidToken returns a valid cached token or nil if none exists.
func (*TokenCache) IsValid ¶ added in v1.0.0
func (c *TokenCache) IsValid(token *CachedToken) bool
IsValid checks if a cached token is still valid. A token is considered valid if it exists and hasn't expired.
func (*TokenCache) Load ¶ added in v1.0.0
func (c *TokenCache) Load() (*CachedToken, error)
Load loads the cached token from disk. Returns nil if no valid token is found.
func (*TokenCache) Save ¶ added in v1.0.0
func (c *TokenCache) Save(token *CachedToken) error
Save saves a token to the cache.
func (*TokenCache) SaveAtomic ¶ added in v1.3.0
func (c *TokenCache) SaveAtomic(token *CachedToken) error
SaveAtomic saves a token using atomic replacement to prevent partial cache writes.
type TokenCacheEntry ¶ added in v1.0.0
type TokenCacheEntry = CachedToken
TokenCacheEntry is an alias for CachedToken (for compatibility).