Documentation
¶
Overview ¶
Package connections wires connectionforge into SystemForge (ADR-017): an organization's connections to external services, stored on the platform database with row-level security, their credentials sealed by the keys package (ADR-013), deployment secrets read through omnivault, and authorization and audit through the platform's own.
Index ¶
- Constants
- Variables
- func LogAuditor(logger *slog.Logger) cf.Auditor
- func MigrateSchema(ctx context.Context, db *sql.DB, d sqlstore.Dialect, cfg *rls.Config) error
- func OwnerFor(orgID uuid.UUID) cf.OwnerID
- func RolePermissions(base authz.RolePermissions) authz.RolePermissions
- type AuthErrorWriter
- type Authenticator
- type Connections
- type Options
Constants ¶
const ( ScopeRead = "systemforge:connections:read" ScopeWrite = "systemforge:connections:write" )
OAuth scopes for the connections API, following the platform's "{app}:{resource}:{verb}" convention.
const ( ConnectionsPath = "/api/v1/organizations/{org}/connections" ProvidersPath = "/api/v1/providers" )
API paths.
const PrincipalTypeAgent authz.PrincipalType = "agent"
PrincipalTypeAgent is the authorization principal type for an agent.
const Purpose = keyforge.Purpose(cf.CredentialPurpose)
Purpose is the keys purpose credentials are sealed under. A deployment lists it in keys.Options.Purposes.
const ResourceType authz.ResourceType = "systemforge_connection"
ResourceType is the authorization resource type of a connection. It follows the "{app}_{type}" naming of resource-scoped grants (ADR-008).
const TenantColumn = "owner_id"
TenantColumn is the column of connectionforge's tables that row-level security keys on.
Variables ¶
var ErrNoTenant = errors.New("connections: no organization in context")
ErrNoTenant is returned on PostgreSQL when an operation runs without an organization in the context. It fails closed rather than run unscoped.
var ErrNoVault = errors.New("connections: no vault configured")
ErrNoVault is returned when a deployment secret is read and no vault was configured.
Functions ¶
func LogAuditor ¶
LogAuditor returns an auditor that writes connection events as structured log records, for a deployment without an audit store.
func MigrateSchema ¶
MigrateSchema creates or updates connectionforge's tables and, on PostgreSQL, enables row-level security on the owned ones, keyed on TenantColumn. It needs no keys, so a migration command can run it alone. Run it with a role allowed to change the schema. A nil cfg uses the platform default session variable.
func RolePermissions ¶
func RolePermissions(base authz.RolePermissions) authz.RolePermissions
RolePermissions returns base with the organization roles' permissions on connections added: owners and admins view, use and manage them; members view them. Use it with the role-based provider (rbac.WithPermissions).
Types ¶
type AuthErrorWriter ¶
type AuthErrorWriter func(w http.ResponseWriter, err error, scope string)
AuthErrorWriter writes the response for an Authenticator error.
type Authenticator ¶
Authenticator returns the principal behind an API request whose credentials carry scope. Its errors are written by the paired AuthErrorWriter.
type Connections ¶
type Connections struct {
Store *sqlstore.Store
Crypto cf.Cryptographer
Secrets cf.SecretSource
Authorizer cf.Authorizer
Auditor cf.Auditor
Providers *provider.Registry
// Broker hands out authenticated HTTP clients for a connection.
Broker *broker.Broker
// Service runs create, get, list, rename, test and disconnect.
Service *service.Service
// contains filtered or unexported fields
}
Connections is connectionforge composed with the platform: each field is a connectionforge port backed by SystemForge.
func Open ¶
func Open(o Options) (*Connections, error)
Open composes the ports. It does not change the database: call Connections.Migrate first.
func (*Connections) Handler ¶
func (c *Connections) Handler(auth Authenticator, writeAuthErr AuthErrorWriter, logger *slog.Logger) http.Handler
Handler returns the connections API:
GET /api/v1/providers
GET /api/v1/organizations/{org}/connections
POST /api/v1/organizations/{org}/connections
GET /api/v1/organizations/{org}/connections/{id}
PATCH /api/v1/organizations/{org}/connections/{id}
POST /api/v1/organizations/{org}/connections/{id}/test
DELETE /api/v1/organizations/{org}/connections/{id}
Each request is authenticated by auth with ScopeRead or ScopeWrite, and runs with the organization in the path as the row-level security tenant. No response contains a credential.
func (*Connections) Migrate ¶
func (c *Connections) Migrate(ctx context.Context) error
Migrate creates or updates connectionforge's tables and, on PostgreSQL, enables row-level security on the owned ones. See MigrateSchema.
type Options ¶
type Options struct {
// DB is the platform database. Required.
DB *sql.DB
// Dialect is the database's dialect. Required.
Dialect sqlstore.Dialect
// Keys seals and opens credentials; it must manage [Purpose]. Required.
Keys *keys.Keys
// Authorizer decides who may view, use, manage, share and disconnect a
// connection. Required.
Authorizer authz.Authorizer
// Vault holds deployment secrets such as OAuth client secrets and GitHub
// App keys. Optional: without it, [Connections.Secrets] reads nothing.
Vault vault.Vault
// Audit receives connection events. Optional: without it, and with a
// Logger, events are logged.
Audit sfaudit.Store
// Logger receives connection events when there is no audit store.
Logger *slog.Logger
// RLS configures the session variable that carries the organization. The
// zero value uses the platform default.
RLS *rls.Config
// Providers are the providers applications registered. The zero value is
// an empty registry.
Providers *provider.Registry
// Egress is the outbound policy template. The zero value allows only
// HTTPS to each provider's public hosts; development may allow more.
Egress egress.Policy
}
Options configures Open.