v1

package
v0.1.1 Latest Latest
Warning

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

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

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ExtractIngestionKey

func ExtractIngestionKey(r *http.Request) string

ExtractIngestionKey returns the Bearer token of an ingestion request. The server rate limiter uses the same parsing, so the limit key matches the key the handler authenticates.

func GetTokenRestrictionFromContext

func GetTokenRestrictionFromContext(ctx context.Context) (auth.TokenRestriction, bool)

GetTokenRestrictionFromContext returns the restriction carried by the access token that authenticated the request. The second result is false for a full-access token.

func GetUserFromContext

func GetUserFromContext(ctx context.Context) (*store.UserMessage, bool)

Types

type ACLInterceptor

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

ACLInterceptor enforces the authorization requirement declared on an RPC through the (metaxisdata.v1.permission) method option. The permission is resolved by the IAM engine against the caller's roles and the workspace IAM policy: workspaceAdmin holds the whole catalog, workspaceMember the read baseline, and custom roles exactly what they were granted.

A method without a permission annotation is not gated here (the handler owns its access control), and neither is a method declared allow_without_credential: those must stay reachable before login.

func NewACLInterceptor

func NewACLInterceptor(iamManager *iam.Manager) *ACLInterceptor

NewACLInterceptor returns a new ACL interceptor backed by the IAM manager.

func (*ACLInterceptor) WrapStreamingClient

func (*ACLInterceptor) WrapStreamingHandler

func (*ACLInterceptor) WrapUnary

func (in *ACLInterceptor) WrapUnary(next connect.UnaryFunc) connect.UnaryFunc

type ApplicationSQLHandler

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

ApplicationSQLHandler ingests the SQL an application actually ran, with every literal already replaced by the application or by this server.

It is a plain Echo route, so it never reaches the ConnectRPC interceptor chain: its authentication is the API key below, and its authorization is the scope the key's application reported. See .agents/docs/application-sql-ingestion.md, "The reporting contract".

func NewApplicationSQLHandler

func NewApplicationSQLHandler(s *store.Store, analyzer *lineage.Analyzer, queue applicationSQLLineageQueue) *ApplicationSQLHandler

NewApplicationSQLHandler creates the handler. analyzer is the process-wide one, not a second instance: the gate below has to accept exactly what the runner will later analyze.

func (*ApplicationSQLHandler) RegisterRoutes

func (h *ApplicationSQLHandler) RegisterRoutes(g *echo.Group)

RegisterRoutes mounts the ingestion route. It sits under /api/v1 rather than /v1 because the ConnectRPC gateway owns /v1/*, and the only other machine-ingest endpoint in this server lives alongside it.

type ApplicationService

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

ApplicationService manages the applications that report their SQL and the statements they have reported. See .agents/docs/application-sql-ingestion.md.

func NewApplicationService

func NewApplicationService(s *store.Store) *ApplicationService

NewApplicationService creates the service.

func (*ApplicationService) DeleteApplication

func (*ApplicationService) DeleteApplicationSQL

func (*ApplicationService) RevokeApplicationAPIKey

func (*ApplicationService) UpdateApplication

type AuditInterceptor

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

func NewAuditInterceptor

func NewAuditInterceptor(store *store.Store, trustedProxies []string) *AuditInterceptor

func (*AuditInterceptor) WrapStreamingClient

func (*AuditInterceptor) WrapStreamingHandler

func (*AuditInterceptor) WrapUnary

func (in *AuditInterceptor) WrapUnary(next connect.UnaryFunc) connect.UnaryFunc

type AuditLogService

type AuditLogService struct {
	v1connect.UnimplementedAuditLogServiceHandler
	// contains filtered or unexported fields
}

func NewAuditLogService

func NewAuditLogService(store *store.Store) *AuditLogService

type AuthService

type AuthService struct {
	v1connect.UnimplementedAuthServiceHandler
	// contains filtered or unexported fields
}

AuthService implements the auth service.

func NewAuthService

func NewAuthService(store *store.Store, secret string, profile *config.Profile, stateCfg *state.State) *AuthService

NewAuthService creates a new AuthService.

func (*AuthService) ApproveDeviceLogin

ApproveDeviceLogin records the signed-in caller's decision. The caller becomes the identity the CLI's token is issued for, so their account state is checked again here.

func (*AuthService) CreateDeviceLogin

CreateDeviceLogin starts a device login. It is anonymous by design, so it is throttled per source address rather than per user. That budget is applied on the interceptor chain, not here: a budget inside this handler is wrapped by the audit interceptor, so a refusal it produced would still write a permanent ledger row and an unauthenticated caller could write them without limit.

func (*AuthService) CreateSSOState

CreateSSOState issues a one-time OAuth2 state nonce. The client passes it to the identity provider and then back with the login request. The Connect entry budgets it per source and globally, because the cache holding these nonces is bounded: an unlimited caller would evict the state of everyone mid-sign-in.

func (*AuthService) ExchangeDeviceLogin

ExchangeDeviceLogin polls a request. An approved request is consumed and answered with the token; every other state is reported as-is so the client knows whether to keep waiting, stop, or start over.

func (*AuthService) GetDeviceLogin

GetDeviceLogin returns the request a user code refers to, so the confirmation page can show what is about to be approved.

func (*AuthService) Login

Login is the auth login method including SSO.

func (*AuthService) Logout

Logout is the auth logout method.

func (*AuthService) Refresh

Refresh rotates the web session. The browser calls it when its access token is gone or expired, so it deliberately needs no credential of its own: the refresh cookie is the credential.

It consumes the presented token atomically before issuing anything, which makes rotation single-use; the replacement inherits the session's original issue time and deadline, so refreshing cannot extend a session past its absolute lifetime. A user who has since been deactivated, or whose password changed after the session was established, is refused.

type DatabaseService

type DatabaseService struct {
	v1connect.UnimplementedDatabaseServiceHandler
	// contains filtered or unexported fields
}

DatabaseService implements the database service.

func NewDatabaseService

func NewDatabaseService(store *store.Store, schemaSyncer *schemasync.Syncer) *DatabaseService

NewDatabaseService creates a new DatabaseService.

func (*DatabaseService) CreateManualSQL

func (*DatabaseService) DeleteManualSQL

func (*DatabaseService) GetManualSQL

func (*DatabaseService) UpdateManualSQL

type DebugInterceptor

type DebugInterceptor struct {
}

DebugInterceptor is the v1 debug interceptor for gRPC server.

func NewDebugInterceptor

func NewDebugInterceptor() *DebugInterceptor

NewDebugInterceptor returns a new v1 API debug interceptor.

func (*DebugInterceptor) WrapStreamingClient

func (*DebugInterceptor) WrapStreamingHandler

func (*DebugInterceptor) WrapUnary

func (in *DebugInterceptor) WrapUnary(next connect.UnaryFunc) connect.UnaryFunc

type EnvironmentService

type EnvironmentService struct {
	v1connect.UnimplementedEnvironmentServiceHandler
	// contains filtered or unexported fields
}

EnvironmentService implements the environment service.

func NewEnvironmentService

func NewEnvironmentService(store *store.Store) *EnvironmentService

NewEnvironmentService creates a new EnvironmentService.

func (*EnvironmentService) CreateEnvironment

CreateEnvironment creates an environment.

func (*EnvironmentService) DeleteEnvironment

DeleteEnvironment deletes an environment.

func (*EnvironmentService) ListEnvironments

ListEnvironments lists the workspace environments.

func (*EnvironmentService) UpdateEnvironment

UpdateEnvironment updates an environment.

type ErrorMappingInterceptor

type ErrorMappingInterceptor struct{}

ErrorMappingInterceptor translates the common.Code an error carries into the Connect status the client sees. Store and service code already return common.Errorf(common.NotFound, ...) and friends, but nothing consumed them, so a missing row or a duplicate key surfaced as CodeInternal/HTTP 500.

It is installed closest to the handler so that outer interceptors (the audit interceptor in particular) observe the status the caller received.

func NewErrorMappingInterceptor

func NewErrorMappingInterceptor() *ErrorMappingInterceptor

NewErrorMappingInterceptor returns a new error mapping interceptor.

func (*ErrorMappingInterceptor) WrapStreamingClient

func (*ErrorMappingInterceptor) WrapStreamingHandler

func (*ErrorMappingInterceptor) WrapUnary

type ExplainSQLService

type ExplainSQLService struct {
	v1connect.UnimplementedExplainSQLServiceHandler
	// contains filtered or unexported fields
}

ExplainSQLService implements the explain SQL service.

func NewExplainSQLService

func NewExplainSQLService(st *store.Store, registry *llm.Registry, lineageAnalyzer *lineage.Analyzer) *ExplainSQLService

NewExplainSQLService creates a new ExplainSQLService.

func (*ExplainSQLService) ExplainSQL

ExplainSQL explains SQL using LLM.

type GroupService

type GroupService struct {
	v1connect.UnimplementedGroupServiceHandler
	// contains filtered or unexported fields
}

GroupService manages groups. A group is an IAM principal: the workspace IAM policy may bind roles to `groups/{email}`, granting every member the role. Each RPC is gated by the ACL interceptor with the metaxisdata.groups.* permissions.

func NewGroupService

func NewGroupService(stores *store.Store) *GroupService

NewGroupService creates a new GroupService.

func (*GroupService) CreateGroup

func (*GroupService) DeleteGroup

func (*GroupService) GetGroup

func (*GroupService) ListGroups

func (*GroupService) UpdateGroup

type IamService

type IamService struct {
	v1connect.UnimplementedIamServiceHandler
	// contains filtered or unexported fields
}

IamService exposes the workspace IAM policy. Get reads the whole policy; Set replaces it whole, guarded by the etag returned by Get. Both RPCs are gated by the ACL interceptor with metaxisdata.iam.getPolicy / setPolicy. Set validates every binding before writing and refuses a policy that would leave the workspace without an active admin.

func NewIamService

func NewIamService(stores *store.Store) *IamService

NewIamService creates a new IamService.

func (*IamService) SetWorkspaceIamPolicy

type IdentityProviderService

type IdentityProviderService struct {
	v1connect.UnimplementedIdentityProviderServiceHandler
	// contains filtered or unexported fields
}

IdentityProviderService implements the identity provider management API. It is the write path the `idp` table never had: until it existed a provider could only be configured by hand-written SQL.

func NewIdentityProviderService

func NewIdentityProviderService(stores *store.Store) *IdentityProviderService

NewIdentityProviderService creates a new IdentityProviderService.

func (*IdentityProviderService) CreateIdentityProvider

CreateIdentityProvider creates an identity provider.

func (*IdentityProviderService) DeleteIdentityProvider

DeleteIdentityProvider deletes an identity provider.

func (*IdentityProviderService) DeleteIdentityProviderBinding

DeleteIdentityProviderBinding unbinds one account from one provider subject.

func (*IdentityProviderService) GetIdentityProvider

GetIdentityProvider gets an identity provider by name.

func (*IdentityProviderService) ListIdentityProviderBindings

ListIdentityProviderBindings lists which account is bound to which provider subject.

func (*IdentityProviderService) ListIdentityProviders

ListIdentityProviders lists every configured identity provider. It is public so the login page can render the SSO targets before a session exists; the client secret is never part of the answer.

func (*IdentityProviderService) TestIdentityProvider

TestIdentityProvider completes a real authorization-code exchange against a stored provider and reports the identity it resolved.

It runs the same preconditions a login runs, including the subject-mapping check, so a provider that would refuse every login is reported here rather than after an administrator tells somebody to try again. The credentials themselves have to be sound for the exchange to get this far.

func (*IdentityProviderService) UpdateIdentityProvider

UpdateIdentityProvider updates an identity provider.

type InstanceService

type InstanceService struct {
	v1connect.UnimplementedInstanceServiceHandler
	// contains filtered or unexported fields
}

InstanceService implements the instance service.

func NewInstanceService

func NewInstanceService(store *store.Store, dbFactory *dbfactory.DBFactory, schemaSyncer *schemasync.Syncer, stateCfg *state.State) *InstanceService

NewInstanceService creates a new InstanceService.

func (*InstanceService) BatchSyncInstances

BatchSyncInstances syncs multiple instances.

Each instance is processed independently and its outcome is reported in a BatchSyncInstanceResult, so one bad instance does not hide the syncs that already happened before it. Only a malformed request (no instances) fails the whole call.

func (*InstanceService) BatchUpdateInstances

BatchUpdateInstances update multiple instances. Per-instance failures are reported in the response instead of aborting the whole batch after earlier updates were already committed.

func (*InstanceService) CreateDataSource

CreateDataSource adds a read-only data source to an instance.

func (*InstanceService) CreateInstance

CreateInstance creates an instance.

func (*InstanceService) DeleteDataSource

DeleteDataSource removes a read-only data source from an instance.

func (*InstanceService) DeleteInstance

DeleteInstance deletes an instance.

func (*InstanceService) GetInstance

GetInstance gets an instance.

func (*InstanceService) ListInstances

ListInstances lists all instances.

func (*InstanceService) SyncInstance

SyncInstance syncs the instance.

func (*InstanceService) UndeleteInstance

UndeleteInstance undeletes an instance.

func (*InstanceService) UpdateDataSource

UpdateDataSource updates one data source of an instance. Only the fields named in the update mask are written, so an update built from a read (which never returns credentials) keeps the stored secrets.

func (*InstanceService) UpdateInstance

UpdateInstance updates an instance.

type LLMService

type LLMService struct {
	v1connect.UnimplementedLLMServiceHandler
	// contains filtered or unexported fields
}

LLMService implements the LLM service.

func NewLLMService

func NewLLMService(st *store.Store, registry *llm.Registry) *LLMService

NewLLMService creates a new LLMService.

type LineageService

type LineageService struct {
	v1connect.UnimplementedLineageServiceHandler
	// contains filtered or unexported fields
}

LineageService implements the instance service.

func NewLineageService

func NewLineageService(store *store.Store, lineageAnalyzer *lineage.Analyzer) *LineageService

NewLineageService creates a new LineageService.

func (*LineageService) AnalyzeSQL

AnalyzeSQL parses a statement and resolves it against each requested scope. The analysis is stateless: nothing is written and no runner is triggered.

Every scope is analyzed independently, because the scopes may live on different instances and even different engines. A scope that cannot be analyzed is reported as a warning on that scope alone; the request fails only when every scope failed the same way, which is what a single-scope call with an unusable scope looks like.

func (*LineageService) GetLineageCounts

GetLineageCounts returns how many distinct objects each requested object is connected to. A node's degree cannot be read off its neighbours' relations, so a graph that labels every node it draws would need one GetLineage per node; two aggregates answer the whole set instead.

A GUID with no relations is reported with zero counts rather than refused: the caller is labelling objects it already has, and one that has no lineage yet is a legitimate node. Unknown and blank GUIDs are treated the same way.

func (*LineageService) GetLineageGraph

GetLineageGraph returns the multi-level lineage around one object in a single call. GetLineage answers one hop at a time, which forces every client to walk the graph itself; this walks it on the server, where the per-object column lineage is already fully paginated.

type NotificationService

type NotificationService struct {
	v1connect.UnimplementedNotificationServiceHandler
	// contains filtered or unexported fields
}

NotificationService serves the caller's own in-app messages: the outcome of a sync operation they asked for, and the ingestion failures a workspace administrator needs to see.

No method carries a permission annotation, and none is reachable without credentials. An inbox belongs to one principal, which the workspace-scoped permission catalog cannot express, so every query here is scoped by the authenticated caller's id — the same shape UserService's self-service paths use. Gating these methods on a permission instead would lock a custom role out of its own messages.

func NewNotificationService

func NewNotificationService(store *store.Store, subscriptions NotificationSubscriptions) *NotificationService

NewNotificationService returns a notification service. subscriptions is what carries a written message to a connected caller; a service built without one refuses SubscribeNotifications rather than accepting a stream that would never deliver anything.

func (*NotificationService) BatchMarkNotificationsRead

BatchMarkNotificationsRead marks the named notifications read. A name that belongs to somebody else changes nothing: the update is scoped by recipient.

func (*NotificationService) DeleteNotification

DeleteNotification deletes one of the caller's notifications.

func (*NotificationService) GetUnreadNotificationCount

GetUnreadNotificationCount counts the caller's unread notifications and the subset of them written since the caller last opened the inbox. The stream carries both with every message it delivers, so this is their fallback: it answers from a partial index rather than reading the messages themselves.

func (*NotificationService) ListNotifications

ListNotifications lists the caller's notifications, newest first.

func (*NotificationService) MarkAllNotificationsRead

MarkAllNotificationsRead marks every unread notification of the caller read.

func (*NotificationService) MarkNotificationsSeen

MarkNotificationsSeen records that the caller has opened the inbox, which clears the badge every connected tab of that inbox shows. It is not a mark-read call: the messages stay unread, and each one is read when it is clicked. Calling it twice is harmless — the second call only moves the watermark further forward.

func (*NotificationService) SubscribeNotifications

SubscribeNotifications streams the caller's notifications as they are written.

The stream is the replacement for polling: a client holds one connection and is told about a message when it exists, so a background sync's outcome reaches the user without a page reload. It is scoped like every other method here — the subscription is registered for the authenticated caller's own inbox.

Nothing about it is audited: a connection that lasts half an hour is not an administrative action, and a ledger row per connection would be noise in a table that is kept forever.

type NotificationSubscriptions

type NotificationSubscriptions interface {
	Subscribe(recipientID int) (<-chan notification.Event, func(), error)
}

NotificationSubscriptions is the push side of the notification component: what SubscribeNotifications listens to while a caller's browser is connected. *notification.Service is the production implementation; the interface keeps this handler from depending on how a message is fanned out, and lets a test drive it without a database.

type OAuthService

type OAuthService struct {
	v1connect.UnimplementedOAuthServiceHandler
	// contains filtered or unexported fields
}

OAuthService implements the browser-facing half of the OAuth 2.1 authorization server: the SPA consent page reads one pending request and records the signed-in user's decision. The protocol endpoints themselves are plain HTTP and live outside ConnectRPC.

func NewOAuthService

func NewOAuthService(stores *store.Store, profile *config.Profile, stateCfg *state.State) *OAuthService

NewOAuthService creates a new OAuthService.

func (*OAuthService) ApproveOAuthAuthorizationRequest

ApproveOAuthAuthorizationRequest records the signed-in caller's decision. The caller becomes the identity the authorization code is minted for, so their account state is checked again here with the same rule a device login approval uses.

func (*OAuthService) GetOAuthAuthorizationRequest

GetOAuthAuthorizationRequest returns one pending authorization request so the consent page can show what is about to be approved.

type OpenLineageHandler

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

OpenLineageHandler handles OpenLineage event ingestion via HTTP.

func NewOpenLineageHandler

func NewOpenLineageHandler(s *store.Store, trustedProxies []string, lineageAnalyzer *lineage.Analyzer, notifier OpenLineageNotifier) *OpenLineageHandler

NewOpenLineageHandler creates a new OpenLineageHandler. trustedProxies is the list of peers whose forwarding headers the audit record may believe.

func (*OpenLineageHandler) RegisterRoutes

func (h *OpenLineageHandler) RegisterRoutes(g *echo.Group)

RegisterRoutes registers the OpenLineage HTTP routes on the echo instance.

type OpenLineageNotifier

type OpenLineageNotifier interface {
	SendToWorkspaceAdmins(ctx context.Context, message *storepb.Notification) error
	ReportUnmatchedNamespace(ctx context.Context, namespace, dataset string)
}

OpenLineageNotifier is what an ingestion failure is reported through: the requests this handler refuses, and the datasets the resolver could not match to an instance. *notification.Service is the production implementation; the interface keeps the handler testable without a database.

type OpenLineageService

type OpenLineageService struct {
	v1connect.UnimplementedOpenLineageServiceHandler
	// contains filtered or unexported fields
}

OpenLineageService implements the OpenLineageServiceHandler for managing namespace mappings and API keys.

func NewOpenLineageService

func NewOpenLineageService(s *store.Store) *OpenLineageService

NewOpenLineageService creates a new OpenLineageService.

func (*OpenLineageService) DeleteNamespaceMapping

func (*OpenLineageService) GetOpenLineageDataset

GetOpenLineageDataset resolves the requested GUID back to the spellings the runs reported and reads their references. Resolution is per distinct dataset rather than per run, which is why the GUID is the only lookup key the request needs, and it runs over the same window the list reads: a dataset the list shows is always one this can open.

func (*OpenLineageService) ListOpenLineageFilterOptions

ListOpenLineageFilterOptions answers the filter menus of the index pages. Those pages read one page of rows at a time, so a menu built from what is on screen would only ever offer the values of the current page — one or two namespaces in a workspace that has twenty.

func (*OpenLineageService) RevokeAPIKey

type OperatorType

type OperatorType string
const (
	ComparatorTypeEqual        OperatorType = "="
	ComparatorTypeLessEqual    OperatorType = "<="
	ComparatorTypeGreaterEqual OperatorType = ">="
)

type PermissionChecker

type PermissionChecker interface {
	CheckPermission(ctx context.Context, perm permission.Permission, user *store.UserMessage) (bool, error)
}

PermissionChecker resolves whether a caller holds a permission. *iam.Manager is the production implementation; the interface lets the interceptor be unit-tested with a fake checker.

type PrincipalThrottleInterceptor

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

PrincipalThrottleInterceptor bounds what one signed-in principal may spend on the methods that write a permanent ledger row or reach an upstream LLM. The ledger is kept forever and an audited method is audited whether or not it changes anything, so a caller holding one account could otherwise grow it without limit; the LLM calls carry a cost rather than a row.

It runs after auth, so the principal is known, and before audit, so a request it refuses never runs and leaves no ledger row. That is the whole backpressure semantic: the ledger still records every action that happened, and the caller is told to slow down instead of the record being dropped.

The anonymous methods keep their own budgets (ThrottleInterceptor and the device login limiters): they have no principal, and their key is the resolved client address. This interceptor is a no-op for them.

func NewPrincipalThrottleInterceptor

func NewPrincipalThrottleInterceptor(stateCfg *state.State) *PrincipalThrottleInterceptor

NewPrincipalThrottleInterceptor returns the interceptor reading its budget from stateCfg.

func (*PrincipalThrottleInterceptor) WrapStreamingClient

func (*PrincipalThrottleInterceptor) WrapStreamingHandler

func (*PrincipalThrottleInterceptor) WrapUnary

type RoleService

type RoleService struct {
	v1connect.UnimplementedRoleServiceHandler
	// contains filtered or unexported fields
}

RoleService manages custom roles. Predefined roles are read-only over this API: create/update/delete refuse a resource ID that collides with a predefined role. Each RPC is gated by the ACL interceptor with the metaxisdata.roles.* permissions.

func NewRoleService

func NewRoleService(stores *store.Store) *RoleService

NewRoleService creates a new RoleService.

func (*RoleService) CreateRole

func (*RoleService) DeleteRole

func (*RoleService) GetRole

func (*RoleService) ListRoles

func (*RoleService) UpdateRole

type SettingService

type SettingService struct {
	v1connect.UnimplementedSettingServiceHandler
	// contains filtered or unexported fields
}

SettingService implements the setting service.

func NewSettingService

func NewSettingService(store *store.Store, profile *config.Profile) *SettingService

NewSettingService creates a new SettingService.

func (*SettingService) GetDebugConfig

GetDebugConfig gets the runtime debug config.

func (*SettingService) GetWorkspaceProfileSetting

GetWorkspaceProfileSetting gets the workspace profile setting.

func (*SettingService) UpdateDebugConfig

UpdateDebugConfig updates the runtime debug config.

RuntimeDebug is the single switch the whole process reads: it selects the slog level, gates the debug interceptor's chatty logs and /debug/pprof, and decides whether panic handlers hand stack traces back to the caller. Keep it and the log level in lockstep so a toggle takes effect without a restart.

func (*SettingService) UpdateWorkspaceProfileSetting

UpdateWorkspaceProfileSetting updates the workspace profile setting.

type ThrottleInterceptor

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

ThrottleInterceptor bounds the anonymous request rate at the Connect entry for the methods whose first real work is a bcrypt comparison or hash. Without it an unauthenticated caller reaches Login with an unknown email (which deliberately runs a dummy bcrypt comparison to keep the timing flat) or calls CreateUser (which hashes a password), and roughly 100 requests a second exhausts the CPU for everyone. Login and CreateUser are each counted per source address with a global backstop, so one client cannot spend the deployment's CPU and a proxy that is not listed as trusted cannot let every client share one budget.

CreateSSOState is bounded for a different resource: it is anonymous and writes one nonce into a bounded cache, so an unlimited caller fills that cache and every user who is mid-sign-in loses their state. It is also the gate in front of the identity provider's token endpoint, which a login cannot reach without a state this server issued.

CreateUser exempts a signed-in caller, because an administrator may create users in bulk and bounding an authenticated principal per user is the general rate-limit work (M24). Login does not: it is not a normal signed-in call, and every request still spends bcrypt on whoever the address names.

Logout is here because it is the one other anonymous and audited method: it writes a ledger row per call, and a token this server signed can be replayed against it without limit even though revoking it twice changes nothing. The authenticated methods are bounded per principal by PrincipalThrottleInterceptor instead.

func NewThrottleInterceptor

func NewThrottleInterceptor(stateCfg *state.State, trustedProxies []string) *ThrottleInterceptor

NewThrottleInterceptor returns an interceptor reading its budgets from stateCfg.

func (*ThrottleInterceptor) WrapStreamingClient

func (*ThrottleInterceptor) WrapStreamingHandler

WrapStreamingHandler applies the same budget as the unary path. It used to be a pass-through, which left a hole no test could see: an anonymous, audited method implemented as a stream would pass the guard (its limiter is in limiterFor) and then never be counted at all, writing permanent ledger rows without any bound. There is no such method today — the one streaming RPC, ExplainSQL, requires a credential and is bounded per principal — so this is the shape being kept symmetric rather than a behaviour that changed in production.

func (*ThrottleInterceptor) WrapUnary

type UserService

type UserService struct {
	v1connect.UnimplementedUserServiceHandler
	// contains filtered or unexported fields
}

UserService implements the user service.

func NewUserService

func NewUserService(store *store.Store, iamManager *iam.Manager, profile *config.Profile) *UserService

NewUserService creates a new UserService.

func (*UserService) BatchGetUsers

BatchGetUsers get users in batch.

func (*UserService) CreateUser

CreateUser creates a user.

func (*UserService) DeleteUser

DeleteUser deletes a user.

func (*UserService) GetCurrentUser

func (s *UserService) GetCurrentUser(ctx context.Context, _ *connect.Request[emptypb.Empty]) (*connect.Response[v1pb.User], error)

GetCurrentUser gets the current authenticated user.

func (*UserService) GetUser

GetUser gets a user.

func (*UserService) ListUsers

ListUsers lists all users.

func (*UserService) UndeleteUser

UndeleteUser undeletes a user.

func (*UserService) UpdateUser

UpdateUser updates a user.

Jump to

Keyboard shortcuts

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