Documentation
¶
Overview ¶
Package sharedstore is the hub's cross-replica key/value store for short-lived login state: browser sessions and published-app authorization codes.
Both are minted by whichever replica served the request and redeemed by whichever replica the load balancer picks next, so process-local maps break as soon as the hub runs more than one pod. Entries live as Secrets in root:railgrid:system:controllers — a hub-internal workspace no tenant, provider, or user identity can reach — which keeps the hub's only hard dependency kcp.
Values are opaque to this package. Keys are hashed into the object name, so neither a session handle nor an authorization code is recoverable from resource names in logs, audit records, or metrics.
Index ¶
- Constants
- Variables
- func RunGC(ctx context.Context, interval time.Duration, stores ...*Store)
- type ActionProofUseStore
- type AppCodeStore
- func (s *AppCodeStore) Peek(ctx context.Context, code string) (appauth.CodeRecord, bool, error)
- func (s *AppCodeStore) Put(ctx context.Context, code string, record appauth.CodeRecord) error
- func (s *AppCodeStore) Store() *Store
- func (s *AppCodeStore) Take(ctx context.Context, code string) (appauth.CodeRecord, bool)
- type SessionBackend
- func (b *SessionBackend) Get(ctx context.Context, key string) (browsersession.Record, error)
- func (b *SessionBackend) Put(ctx context.Context, key string, record browsersession.Record) error
- func (b *SessionBackend) Revoke(ctx context.Context, key string, _ time.Time) error
- func (b *SessionBackend) Store() *Store
- type Store
- func (s *Store) CreateIfAbsent(ctx context.Context, key string, value []byte, expiresAt time.Time) (bool, error)
- func (s *Store) Delete(ctx context.Context, key string) error
- func (s *Store) GC(ctx context.Context) (int, error)
- func (s *Store) Get(ctx context.Context, key string) ([]byte, error)
- func (s *Store) Put(ctx context.Context, key string, value []byte, expiresAt time.Time) error
- func (s *Store) Take(ctx context.Context, key string) ([]byte, error)
Constants ¶
const ActionProofUseKind = "railgrid-action-proof-use"
const AppCodeKind = "railgrid-appcode"
AppCodeKind is the shared-store collection holding published-app authorization codes.
const ( // LabelKind marks every Secret this package owns and names the logical // collection, so the sweeper can list one kind without touching the other. LabelKind = "railgrid.ai/shared-store" )
const PreviewAppCodeKind = "railgrid-preview-appcode-v2"
PreviewAppCodeKind is a versioned, isolated collection for scoped preview handoff and app-authorization codes. Older replicas must not be able to consume scoped codes as ordinary app codes while ignoring their scope and purpose fields.
const PreviewSessionKind = "railgrid-preview-session-v2"
PreviewSessionKind is deliberately separate from SessionKind. Older hub replicas decode session JSON without scoped fields and would otherwise treat a preview handle as an ordinary portal session if it were presented under the portal cookie name.
const SessionKind = "railgrid-session"
SessionKind is the shared-store collection holding browser sessions.
Variables ¶
var ErrNotFound = errors.New("sharedstore: entry not found")
ErrNotFound is returned when a key is absent, expired, or already redeemed.
Functions ¶
Types ¶
type ActionProofUseStore ¶ added in v0.2.21
type ActionProofUseStore struct {
// contains filtered or unexported fields
}
ActionProofUseStore adapts a Store collection to actionproof.UseStore.
func NewActionProofUseStore ¶ added in v0.2.21
func NewActionProofUseStore(store *Store) *ActionProofUseStore
NewActionProofUseStore adapts the supplied collection for durable cross-replica action-proof use tracking.
type AppCodeStore ¶
type AppCodeStore struct {
// contains filtered or unexported fields
}
AppCodeStore adapts Store to appauth.CodeStore, so a code minted on the replica that served the browser's authorize hop can be redeemed on whichever replica the access proxy reaches for the exchange.
Single-use is enforced by Store.Take's resource-version-guarded delete: two concurrent exchanges of one code produce exactly one success, no matter which replicas run them.
func NewAppCodeStore ¶
func NewAppCodeStore(config *rest.Config, namespace string) (*AppCodeStore, error)
NewAppCodeStore builds the shared authorization-code store. config must target the workspace holding the entries.
func NewPreviewAppCodeStore ¶ added in v0.2.16
func NewPreviewAppCodeStore(config *rest.Config, namespace string) (*AppCodeStore, error)
NewPreviewAppCodeStore builds the isolated shared collection for scoped preview codes. Ordinary app authorization codes remain in AppCodeKind for mixed-version compatibility.
func (*AppCodeStore) Peek ¶ added in v0.2.21
func (s *AppCodeStore) Peek(ctx context.Context, code string) (appauth.CodeRecord, bool, error)
Peek reads an app authorization code without consuming it. The separate error result lets identity exchange distinguish a missing/expired code from a shared-store outage and return a retryable response for the latter.
func (*AppCodeStore) Put ¶
func (s *AppCodeStore) Put(ctx context.Context, code string, record appauth.CodeRecord) error
func (*AppCodeStore) Store ¶
func (s *AppCodeStore) Store() *Store
Store exposes the underlying collection so the leader can sweep it.
func (*AppCodeStore) Take ¶
func (s *AppCodeStore) Take(ctx context.Context, code string) (appauth.CodeRecord, bool)
type SessionBackend ¶
type SessionBackend struct {
// contains filtered or unexported fields
}
SessionBackend adapts Store to browsersession.Backend so every hub replica resolves and revokes the same cookies.
Revocation is a delete, not a tombstone: a handle is 32 bytes of crypto/rand, so the collision the in-memory backend's tombstones guard against cannot occur, and a delete propagates to every replica immediately instead of depending on a per-process marker.
func NewPreviewSessionBackend ¶ added in v0.2.16
func NewPreviewSessionBackend(config *rest.Config, namespace string) (*SessionBackend, error)
NewPreviewSessionBackend builds the isolated collection for short-lived, one-app preview sessions. It must not share SessionKind with portal logins: older hub replicas ignore the scoped identity fields when decoding a shared session record.
func NewSessionBackend ¶
func NewSessionBackend(config *rest.Config, namespace string) (*SessionBackend, error)
NewSessionBackend builds the shared browser-session backend. config must target the workspace holding the entries.
func (*SessionBackend) Get ¶
func (b *SessionBackend) Get(ctx context.Context, key string) (browsersession.Record, error)
func (*SessionBackend) Put ¶
func (b *SessionBackend) Put(ctx context.Context, key string, record browsersession.Record) error
func (*SessionBackend) Store ¶
func (b *SessionBackend) Store() *Store
Store exposes the underlying collection so the leader can sweep it.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store is one logical collection of entries (all sharing a `kind`) inside a single kcp workspace namespace. It is safe for concurrent use — it holds no state beyond its client.
func New ¶
New builds a Store. config must already target the workspace holding the entries (its Host carries the /clusters/<path> segment). kind must be a valid label value and DNS-name prefix — it namespaces one collection from another inside the same Kubernetes namespace.
func (*Store) CreateIfAbsent ¶ added in v0.2.21
func (s *Store) CreateIfAbsent(ctx context.Context, key string, value []byte, expiresAt time.Time) (bool, error)
CreateIfAbsent atomically creates value under key. The Kubernetes API's Create operation is the cross-replica compare-and-set: exactly one caller can claim a key, while all others observe AlreadyExists.
func (*Store) GC ¶
GC deletes every expired entry of this kind and returns how many it removed. Readers already refuse expired entries, so this only reclaims space — run it on the elected replica.
func (*Store) Get ¶
Get returns the value stored under key. An expired entry reports ErrNotFound and is deleted opportunistically, so a stale record cannot outlive its expiry even if the sweeper is not running.
func (*Store) Put ¶
Put writes value under key, replacing any existing entry, and stamps the expiry the reader enforces.