Documentation
¶
Overview ¶
Package cloud is the multi-tenant hosted layer ("Keyway Cloud") on top of the open-source engine. It adds accounts, projects, and persisted analysis history around the same discovery/contract/diff/threat logic the CLI and self-hosted server use — so the static, config-driven half of Keyway (auth-contract discovery, drift, threat coverage) can run as a SaaS on repos users connect or upload. The live half (probing, canary, blast radius) stays self-hosted by design; the cloud never handles a customer's signing keys or staging traffic.
Index ¶
- Variables
- func Analyze(ctx context.Context, manifests map[string]string, prev *model.ContractVersion) (model.ContractVersion, []model.ChangeEvent, error)
- type Analysis
- type AnalysisSummary
- type Config
- type GitHub
- func (g *GitHub) AuthURL(redirectURI, state, scope string) string
- func (g *GitHub) Configured() bool
- func (g *GitHub) Exchange(ctx context.Context, code, redirectURI string) (string, error)
- func (g *GitHub) FetchManifests(ctx context.Context, repo, ref, subpath, token string) (map[string]string, string, error)
- func (g *GitHub) FetchUser(ctx context.Context, token string) (User, error)
- type MemoryStore
- func (s *MemoryStore) Close() error
- func (s *MemoryStore) CreateProject(_ context.Context, p Project) error
- func (s *MemoryStore) DeleteProject(_ context.Context, id string) error
- func (s *MemoryStore) GetAnalysis(_ context.Context, id string) (Analysis, error)
- func (s *MemoryStore) GetProject(_ context.Context, id string) (Project, error)
- func (s *MemoryStore) GetUser(_ context.Context, id string) (User, error)
- func (s *MemoryStore) LatestAnalysis(ctx context.Context, projectID string) (Analysis, error)
- func (s *MemoryStore) ListAnalyses(_ context.Context, projectID string, limit int) ([]Analysis, error)
- func (s *MemoryStore) ListProjects(_ context.Context, ownerID string) ([]Project, error)
- func (s *MemoryStore) SaveAnalysis(_ context.Context, a Analysis) error
- func (s *MemoryStore) UpsertUser(_ context.Context, u User) error
- type Project
- type Server
- type Source
- type SourceKind
- type Store
- type User
Constants ¶
This section is empty.
Variables ¶
var ErrNotFound = errors.New("not found")
ErrNotFound is returned when a requested record does not exist (or is not visible to the caller — callers scope by owner before loading).
Functions ¶
func Analyze ¶
func Analyze(ctx context.Context, manifests map[string]string, prev *model.ContractVersion) (model.ContractVersion, []model.ChangeEvent, error)
Analyze runs the engine over a set of manifest files (path → YAML/JSON content) and returns the derived contract version plus the drift versus prev (nil for a first run). It reuses the exact discovery + contract + diff logic the CLI and self-hosted server use — the manifests are written to a throwaway temp dir and removed immediately, so nothing is persisted to disk.
Types ¶
type Analysis ¶
type Analysis struct {
ID string `json:"id"`
ProjectID string `json:"project_id"`
CreatedAt time.Time `json:"created_at"`
TriggerKind string `json:"trigger_kind"` // upload | sync | manual
TriggerRef string `json:"trigger_ref,omitempty"`
Hash string `json:"hash"`
IsBaseline bool `json:"is_baseline"`
Version model.ContractVersion `json:"version"`
Changes []model.ChangeEvent `json:"changes"`
// Denormalized summary for cheap list rendering.
ConsumerCount int `json:"consumer_count"`
IssuerCount int `json:"issuer_count"`
ChangeCount int `json:"change_count"`
}
Analysis is a single run over a project's config: the derived contract plus the drift (change events) versus the project's previous analysis. Stored so a project accrues history over time.
func (Analysis) Summary ¶
func (a Analysis) Summary() AnalysisSummary
Summary projects an Analysis to its compact form.
type AnalysisSummary ¶
type AnalysisSummary struct {
ID string `json:"id"`
CreatedAt time.Time `json:"created_at"`
TriggerKind string `json:"trigger_kind"`
TriggerRef string `json:"trigger_ref,omitempty"`
Hash string `json:"hash"`
IsBaseline bool `json:"is_baseline"`
ConsumerCount int `json:"consumer_count"`
IssuerCount int `json:"issuer_count"`
ChangeCount int `json:"change_count"`
}
AnalysisSummary is the compact form used in list/history views.
type Config ¶
type Config struct {
Addr string // listen address, default :8090
BaseURL string // public base URL, used to build the OAuth redirect
FrontendURL string // where to send the user after login (the web app)
SessionSecret []byte // HMAC key for session cookies
GitHubClientID string // GitHub OAuth app client id
GitHubSecret string // GitHub OAuth app client secret
AllowedOrigins []string // CORS allowlist (the frontend origins)
DevLogin bool // enable a passwordless dev login (local only)
SecureCookies bool // set the Secure flag on cookies (true in production/HTTPS)
}
Config is the cloud server's runtime configuration, sourced from the environment so it deploys anywhere without code changes.
func ConfigFromEnv ¶
func ConfigFromEnv() Config
ConfigFromEnv builds a Config from environment variables:
KEYWAY_CLOUD_ADDR (:8090) KEYWAY_CLOUD_BASE_URL (http://localhost:8090) KEYWAY_CLOUD_FRONTEND_URL (http://localhost:5173) KEYWAY_CLOUD_SESSION_SECRET (random if unset — sessions won't survive restart) KEYWAY_CLOUD_ALLOWED_ORIGINS (comma-separated; defaults to FRONTEND_URL) GITHUB_CLIENT_ID / GITHUB_CLIENT_SECRET KEYWAY_CLOUD_DEV_LOGIN=1 (enable local passwordless login)
type GitHub ¶
type GitHub struct {
ClientID string
ClientSecret string
// contains filtered or unexported fields
}
GitHub wraps the small slice of the GitHub API the cloud needs: OAuth login and reading manifest files from a repository. Uses only the standard library.
func NewGitHub ¶
NewGitHub builds a GitHub client. ClientID/Secret are required only for the OAuth login flow; public-repo manifest reads work without them.
func (*GitHub) AuthURL ¶
AuthURL is the GitHub authorize URL to redirect the user to. `read:user` is the only scope needed for login; add `repo` when private-repo sync is enabled.
func (*GitHub) Configured ¶
Configured reports whether OAuth login is available (client id + secret set).
func (*GitHub) FetchManifests ¶
func (g *GitHub) FetchManifests(ctx context.Context, repo, ref, subpath, token string) (map[string]string, string, error)
FetchManifests reads YAML manifest files from a repository (optionally under a subpath) and returns them keyed by repo path, plus the resolved commit SHA. A token is required for private repos; public repos work with an empty token.
type MemoryStore ¶
type MemoryStore struct {
// contains filtered or unexported fields
}
MemoryStore is an in-process Store for local/dev and tests. Data is lost on restart — hosting should swap in the Postgres store (same interface).
func NewMemoryStore ¶
func NewMemoryStore() *MemoryStore
NewMemoryStore returns an empty in-memory store.
func (*MemoryStore) Close ¶
func (s *MemoryStore) Close() error
func (*MemoryStore) CreateProject ¶
func (s *MemoryStore) CreateProject(_ context.Context, p Project) error
func (*MemoryStore) DeleteProject ¶
func (s *MemoryStore) DeleteProject(_ context.Context, id string) error
func (*MemoryStore) GetAnalysis ¶
func (*MemoryStore) GetProject ¶
func (*MemoryStore) LatestAnalysis ¶
func (*MemoryStore) ListAnalyses ¶
func (*MemoryStore) ListProjects ¶
func (*MemoryStore) SaveAnalysis ¶
func (s *MemoryStore) SaveAnalysis(_ context.Context, a Analysis) error
func (*MemoryStore) UpsertUser ¶
func (s *MemoryStore) UpsertUser(_ context.Context, u User) error
type Project ¶
type Project struct {
ID string `json:"id"`
OwnerID string `json:"owner_id"`
Name string `json:"name"`
Source Source `json:"source"`
CreatedAt time.Time `json:"created_at"`
LatestAnalysisID string `json:"latest_analysis_id,omitempty"`
}
Project is one tracked auth surface (a repo or an uploaded config set) owned by a user. It is the multi-tenant boundary: every project belongs to exactly one OwnerID, and all reads/writes are scoped to the requesting user's projects.
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
Server is the Keyway Cloud HTTP API. It owns accounts, projects, and analysis history; the analysis itself delegates to the shared engine (see analyze.go).
type Source ¶
type Source struct {
Kind SourceKind `json:"kind"`
Repo string `json:"repo,omitempty"` // "owner/name" for github sources
Ref string `json:"ref,omitempty"` // branch or tag (default "main")
Path string `json:"path,omitempty"` // optional subdirectory within the repo
}
Source describes where a project reads its auth configuration from.
type SourceKind ¶
type SourceKind string
SourceKind is where a project's auth config comes from.
const ( SourceUpload SourceKind = "upload" // config files uploaded through the UI/API SourceGitHub SourceKind = "github" // fetched from a connected GitHub repository )
type Store ¶
type Store interface {
// Accounts.
UpsertUser(ctx context.Context, u User) error
GetUser(ctx context.Context, id string) (User, error)
// Projects (tenant boundary: always filter by owner).
CreateProject(ctx context.Context, p Project) error
ListProjects(ctx context.Context, ownerID string) ([]Project, error)
GetProject(ctx context.Context, id string) (Project, error)
DeleteProject(ctx context.Context, id string) error
// Analyses.
SaveAnalysis(ctx context.Context, a Analysis) error
ListAnalyses(ctx context.Context, projectID string, limit int) ([]Analysis, error) // newest first
GetAnalysis(ctx context.Context, id string) (Analysis, error)
LatestAnalysis(ctx context.Context, projectID string) (Analysis, error)
Close() error
}
Store is the persistence seam for the cloud layer. The in-memory implementation backs local/dev; a Postgres implementation (same interface) is the drop-in for hosting — every method is already tenant-scoped by OwnerID/ProjectID so no query leaks across tenants.
type User ¶
type User struct {
ID string `json:"id"` // stable internal id, e.g. "gh:42" (provider:providerID)
Login string `json:"login"`
Name string `json:"name,omitempty"`
AvatarURL string `json:"avatar_url,omitempty"`
Email string `json:"email,omitempty"`
CreatedAt time.Time `json:"created_at"`
}
User is an authenticated account (currently always backed by a GitHub login).