edge

package
v1.801.360 Latest Latest
Warning

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

Go to latest
Published: Aug 2, 2026 License: Apache-2.0 Imports: 11 Imported by: 0

Documentation

Overview

Package edge is the runtime-mutable store for the cloud edge ("gateway role") policy: the CORS allowlist, the pre-auth per-client-IP flood cap, and the authenticated per-org rate ceiling. It is a LEAF package (stdlib + the Hanzo SQLite driver only, no import of the root cloud package) so BOTH consumers can use it without an import cycle:

  • the edge middleware (package cloud, middleware_edge.go / middleware_ratelimit.go) reads the effective policy live, per request, so an operator's change takes effect without a redeploy;
  • the /v1/gateway HTTP subsystem (clients/gateway) serves GET/PUT over the SAME store, IAM-scoped.

SCOPES. There are two, keyed by org in one encrypted per-tenant SQLite file:

  • PLATFORM policy — the row stored under the admin org (cfg.AdminOrg). It holds the pre-auth edge knobs (CORS origins, per-IP cap + window) that have no tenant at evaluation time (CORS preflight + the anonymous-flood cap run BEFORE identity). Only a SuperAdmin may write it. It is layered over the static boot defaults (env/flags), so an un-provisioned deployment behaves exactly as the static config until an operator PUTs an override.
  • PER-ORG policy — a tenant's own row, holding its self-service edge config: OrgRPM (authenticated rate ceiling), CacheTTLSec + CachePaths (edge-cache TTL, default and per-path), and Methods (accepted-method allowlist). An org admin writes its own; a SuperAdmin may write any. An unset field inherits the platform default, then the static default.

Fail-soft: every resolver (Platform/OrgRPM/CacheTTL/Methods) returns the static/platform default on any store error, so a policy-store outage never takes the edge down. Writes fail loud (an unavailable store returns an error to the PUT handler).

Index

Constants

View Source
const MaxCacheTTLSec = 7 * 24 * 60 * 60

MaxCacheTTLSec bounds a cache TTL (7 days) so a fat-fingered PUT can't pin a stale edge response indefinitely.

Variables

This section is empty.

Functions

This section is empty.

Types

type Policy

type Policy struct {
	// CORSOrigins is the PLATFORM-scope CORS allowlist EdgeCORS admits: an exact
	// origin, a bare host, or a "*.host" wildcard. Writable only by a SuperAdmin —
	// CORS is evaluated before identity, so it has no tenant to scope to.
	CORSOrigins []string `json:"cors_origins,omitempty"`
	// PerIPRPM is the PLATFORM-scope pre-auth flood cap: requests EdgeRateLimit
	// admits per WindowSec from one client IP. SuperAdmin-only, same reason.
	PerIPRPM int `json:"per_ip_rpm,omitempty"`
	// WindowSec is the window PerIPRPM is counted over, in seconds. SuperAdmin-only.
	WindowSec int `json:"window_sec,omitempty"`

	// OrgRPM is the org's OWN authenticated rate ceiling, requests per minute, as
	// ScopeRateLimit enforces it. Unset inherits the platform default, then the
	// static boot default.
	OrgRPM int `json:"org_rpm,omitempty"`
	// CacheTTLSec is the org's default edge-cache TTL for its responses, in seconds;
	// 0 means no caching. Unset inherits the platform default.
	CacheTTLSec int `json:"cache_ttl_sec,omitempty"`
	// CachePaths overrides CacheTTLSec per path PREFIX (key "/v1/models" → seconds).
	// The longest matching prefix wins.
	CachePaths map[string]int `json:"cache_paths,omitempty"`
	// Methods is the allowlist of HTTP methods the edge accepts for this org. Empty
	// means all are accepted.
	Methods []string `json:"methods,omitempty"`

	// UpdatedAt is the unix second this policy row was last written. Server-stamped;
	// a client-supplied value is ignored.
	UpdatedAt int64 `json:"updated_at,omitempty"`
	// UpdatedBy is the validated user id that wrote this policy row. Server-stamped;
	// a client-supplied value is ignored.
	UpdatedBy string `json:"updated_by,omitempty"`
}

Policy is the edge policy for one scope. Zero-valued fields mean "inherit" (from the static default, then the platform policy) — so a PUT that sets only OrgRPM leaves the platform CORS/per-IP untouched. Every field is ENFORCED by a consumer; there is no stored-but-ignored knob. Every field carries its OWN doc comment rather than sharing a section header, because zipdoc lifts a field's comment into the published schema property and a header lifted onto three fields would document the GROUP where the FIELD goes.

func (*Policy) Normalize

func (p *Policy) Normalize()

Normalize canonicalizes free-form input in place (methods → upper-case, trimmed) so a config round-trips in one stable shape. Applied at the write boundary, before Validate.

func (Policy) Validate

func (p Policy) Validate() error

Validate checks structural bounds on the client-settable fields, returning a human-readable error for a 400. It is the ONE validation gate shared by every writer, so the store never persists an incoherent policy.

type Store

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

Store persists Policy per org to one encrypted SQLite file and resolves the effective platform / per-org policy for the edge middleware, cached with a short TTL. A nil db (SQLite unavailable at boot) degrades to STATIC-ONLY: reads return the static default, writes error — the edge never goes down.

func New

func New(dataDir, adminOrg string, static Policy) (*Store, error)

New opens (or creates) {dataDir}/gateway.db and returns a Store layered over the static boot defaults. On any open/migrate error it logs nothing here (the caller owns logging) and returns a static-only Store plus the error, so the caller can wire the edge middleware with a working fallback regardless.

func (*Store) CacheTTL

func (s *Store) CacheTTL(org, path string) int

CacheTTL returns the edge-cache TTL (seconds) for org+path: the org's own longest-matching cache_paths prefix wins, else its default CacheTTLSec, else the platform default, else 0 (no caching). Cached with a short TTL, fail-open (0). The edge cache middleware reads this live, per request, so an operator's PUT takes effect without a redeploy (mirrors OrgRPM / Platform).

func (*Store) Close

func (s *Store) Close() error

Close releases the underlying handle (nil-safe for a static-only Store).

func (*Store) Effective

func (s *Store) Effective(org string) Policy

Effective returns the read-back view for org: the platform edge policy (CORS + per-IP + window) with the org's OWN per-org config (rate ceiling, cache TTL / per-path overrides, method allowlist) overlaid. This is what GET /v1/gateway/config returns — a tenant sees the platform edge policy in force plus its own configuration.

func (*Store) Get

func (s *Store) Get(ctx context.Context, org string) (Policy, bool, error)

Get returns the raw stored policy for org (found=false when none). A static-only store always reports not-found.

func (*Store) Methods

func (s *Store) Methods(org string) []string

Methods returns the allowlist of HTTP methods the edge accepts for org (nil = all allowed): the org's own list wins, else the platform default. Fail-open (nil). The edge method-guard reads this live.

func (*Store) OrgRPM

func (s *Store) OrgRPM(org string) int

OrgRPM returns the authenticated per-org rate ceiling (requests/min) for org: the org's own row wins, else the platform default's OrgRPM, else 0 (no policy limit). Cached with a short TTL, fail-open (0). Called per-request by ScopeRateLimit (post-identity).

func (*Store) Platform

func (s *Store) Platform() Policy

Platform returns the effective PLATFORM policy — the admin-org row merged over the static defaults — cached with a short TTL and fail-open to the static default. Called per-request by EdgeCORS/EdgeRateLimit (pre-identity).

func (*Store) Put

func (s *Store) Put(ctx context.Context, org string, p Policy) (Policy, error)

Put upserts the policy for org (merged over any existing row so a partial write is additive) and invalidates the resolver cache. Errors on a static-only store — a write must never silently vanish.

func (*Store) PutPlatform

func (s *Store) PutPlatform(ctx context.Context, p Policy) (Policy, error)

PutPlatform upserts the PLATFORM policy — the row under the admin org — merged over any existing platform row. This is the ONLY write that may touch the pre-auth edge knobs (CORS, per-IP cap); the /v1/gateway subsystem gates it on SuperAdmin. Targeting the admin org explicitly (not the caller's possibly org-switched X-Org-Id) is what makes a SuperAdmin's platform PUT land on the platform row regardless of which tenant they are currently viewing.

Jump to

Keyboard shortcuts

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