Documentation
¶
Overview ¶
Package config provides application configuration loading from environment variables.
Index ¶
- Constants
- Variables
- func CheckPrefixAgainstAdmin(prefix, adminAddr string) error
- func NormalizeSetupCode(s string) string
- func ResolveDataDir() string
- func ValidatePublicAPIPrefix(p string) error
- type AdminConfig
- type AgentAnalyticsConfig
- type Config
- type DatabaseConfig
- type DemoConfig
- type FeaturesConfig
- type HatamotoConfig
- type PackageConfig
- type PluginConfig
- type PublicSiteConfig
- type SMTPConfig
- type SecurityConfig
- type ServerConfig
Constants ¶
const ( DefaultPageCacheTTL = 5 * time.Minute MinPageCacheTTL = 30 * time.Second MaxPageCacheTTL = 30 * 24 * time.Hour )
Page cache TTL bounds and default. The floor keeps a typo from turning the cache off in effect; the ceiling bounds how long a missed invalidation can show stale markup.
const ( DefaultSMTPFrom = "noreply@localhost" DefaultCanonicalSlug = "site" DefaultSiteName = "My Hatamoto site" )
Defaults that let `hatamoto serve` boot with only DATABASE_URL. Email stays off until SMTP_HOST is a real host (IsConfigured); the site name is a seed for the first-boot row and is edited in the admin afterwards.
const DefaultDataDir = "./data"
DefaultDataDir is HATAMOTO_DATA when unset: the server's writable state directory (the Docker image creates /app/data).
const DefaultRegistryURL = "https://hatamoto.dev/registry.json"
DefaultRegistryURL is the registry plugins and themes are browsed from.
const DemoBanner = "Public demo, resets every hour"
DemoBanner is the fixed notice shown in the admin and on public pages of a public demo (HATAMOTO_DEMO=1).
const FirstPartyKey = "HsfRxf3cApV2VddoUEfOM76UrOWbr2yGT2nD/xeesAo=" // gitleaks:allow (public key)
FirstPartyKey is the public half of the "hatamoto first-party" signing key: the key that signs the first-party plugins in the default registry. It is always trusted, so those plugins install with one click. The private half is never in this repository (`make registry` reads it from HATAMOTO_REGISTRY_KEY_FILE).
Variables ¶
var WasmCacheSubdir = filepath.Join("cache", "wasm")
WasmCacheSubdir is the compile cache's place under the data directory.
Functions ¶
func CheckPrefixAgainstAdmin ¶
CheckPrefixAgainstAdmin refuses a PUBLIC_API_PREFIX that lives under the admin address (the first segments match), where the admin intercept and the public routes would shadow each other. An empty prefix or admin address is fine.
func NormalizeSetupCode ¶
NormalizeSetupCode is the form a setup code is compared in: upper case, with spaces and dashes removed. The length and repetition rules apply to it, so padding that the comparison ignores cannot make a weak code pass.
func ResolveDataDir ¶
func ResolveDataDir() string
ResolveDataDir is HATAMOTO_DATA (or DefaultDataDir) made absolute against the working directory, so a relative value cannot drift once a process hands it to a child.
func ValidatePublicAPIPrefix ¶
ValidatePublicAPIPrefix checks PUBLIC_API_PREFIX: empty, or a lower-case path of at least two segments that does not start in a path the server owns. A CMS page at the same path would be shadowed by the API.
Types ¶
type AdminConfig ¶
type AdminConfig struct {
// SetupCode is HATAMOTO_SETUP_CODE: the code the first-run wizard asks
// for, when you cannot read the logs (empty = generate one per boot).
SetupCode string
// TrustedProxies is HATAMOTO_TRUSTED_PROXIES: comma-separated CIDRs whose
// X-Forwarded-* headers are believed (client IP, scheme, host). Empty means
// loopback only.
TrustedProxies []string
// Dev is HATAMOTO_DEV=1: development-only admin pages (the component
// styleguide at /admin/_styleguide). Never set it in production.
Dev bool
// Path is HATAMOTO_ADMIN_PATH: the admin address pinned by the operator
// ("" = not pinned), lower-cased when it is well formed. It wins over the
// stored address. A malformed value is kept as typed and fails Validate.
Path string
// Resolved is the address the server mounts the admin at. App boot sets it
// after reading the environment and the database; empty means /admin.
Resolved string
// NotFoundPerMin is HATAMOTO_NOTFOUND_PER_MIN: how many not-found
// responses one client IP may cause per minute before it is blocked from
// the admin address (default 60, 0 disables the throttle).
NotFoundPerMin int
// NotFoundBlock is HATAMOTO_NOTFOUND_BLOCK: how long that block lasts
// (default 2m, at least 1s).
NotFoundBlock time.Duration
// contains filtered or unexported fields
}
AdminConfig controls the Go admin UI.
func (AdminConfig) CheckSetupCode ¶
func (a AdminConfig) CheckSetupCode() error
CheckSetupCode reports why HATAMOTO_SETUP_CODE is too weak to use, or nil (also when it is unset). It is not part of Validate: only an install that is still waiting for its first owner needs the rule, and that is known only once the database is open (the server enforces it then; an upgraded install that already has users just logs a warning).
func (AdminConfig) Validate ¶
func (a AdminConfig) Validate() error
Validate rejects an unusable trusted-proxy list, a malformed HATAMOTO_ADMIN_PATH and bad HATAMOTO_NOTFOUND_* values.
type AgentAnalyticsConfig ¶
type AgentAnalyticsConfig struct {
// LogIngestEnabled (AGENT_LOG_INGEST) turns on log ingest. It only takes
// effect together with LogIngestSecret (see LogIngestActive).
LogIngestEnabled bool
// LogIngestSecret (AGENT_LOG_INGEST_SECRET) authenticates POST
// /api/v1/public/agent-logs via X-Agent-Log-Secret. No dev default.
LogIngestSecret string
// CaddyLogPath (AGENT_LOG_CADDY_PATH), when set with the flag on, makes
// the backend tail that Caddy JSON access log (read-only).
CaddyLogPath string
}
AgentAnalyticsConfig holds the opt-in access-log ingest settings. Everything is off by default; nothing here is derived from other secrets.
func (AgentAnalyticsConfig) LogIngestActive ¶
func (c AgentAnalyticsConfig) LogIngestActive() bool
LogIngestActive reports whether the log ingest endpoint should be mounted: the flag is on and a secret is configured.
type Config ¶
type Config struct {
// Server configuration
Server ServerConfig
// Database configuration
Database DatabaseConfig
// Secret is the server secret (HATAMOTO_SECRET, or JWT_SECRET as older
// deployments name it). Flash cookies, theme-preview links and stored
// import credentials are keyed from it.
Secret string
// PublicSite configuration (canonical public origin)
PublicSite PublicSiteConfig
// PageCacheTTL is how long a rendered public page stays in the HTML cache
// (HATAMOTO_PAGE_CACHE_TTL, default 5m, 30s..30d).
PageCacheTTL time.Duration
// PageCacheTTLFromEnv is true when PageCacheTTL came from a valid
// HATAMOTO_PAGE_CACHE_TTL, false when it is the built-in default.
PageCacheTTLFromEnv bool
// Warnings are non-fatal configuration problems found by Load (an invalid
// value fell back to its default); the caller logs them at boot.
Warnings []string
// MCPAllowedOrigins are extra browser origins allowed to call /mcp
// (HATAMOTO_MCP_ALLOWED_ORIGINS, comma-separated). The public origin is
// always allowed; requests without an Origin header are not affected.
MCPAllowedOrigins []string
// AgentAnalytics configures the optional access-log ingest (default off)
AgentAnalytics AgentAnalyticsConfig
// SMTP configuration for email notifications
SMTP SMTPConfig
// Feature flags
Features FeaturesConfig
// Hatamoto-specific brand / identity config (single-tenant)
Hatamoto HatamotoConfig
// Security header toggles (CSP enforce mode, disable switch)
Security SecurityConfig
// Packages controls plugin and theme packages (registry, trusted keys).
Packages PackageConfig
// Plugins controls the WASM plugin runtime.
Plugins PluginConfig
// Admin controls the Go admin UI.
Admin AdminConfig
// Demo is the public demo mode (HATAMOTO_DEMO=1); see demo.go.
Demo DemoConfig
// Environment
Environment string
// AdminCookieSecure controls the Secure attribute on the admin session
// cookie. Defaults to true in production; set false for local HTTP dev.
AdminCookieSecure bool
// EnableCookieAuth lets the /api/v1 session also travel as an HttpOnly
// cookie (with CSRF enforcement). Default FALSE: /api/v1 clients send the
// session token as a bearer. The Go admin always uses its own cookie.
EnableCookieAuth bool
LogLevel string
}
Config holds all application configuration.
type DatabaseConfig ¶
type DatabaseConfig struct {
URL string
MaxConnections int
MinConnections int
MaxConnLifetime time.Duration
MaxConnIdleTime time.Duration
}
DatabaseConfig holds PostgreSQL connection settings.
type DemoConfig ¶
type DemoConfig struct {
// Enabled is HATAMOTO_DEMO=1 (or true).
Enabled bool
// LoginEmail and LoginPassword are HATAMOTO_DEMO_LOGIN_EMAIL and
// HATAMOTO_DEMO_LOGIN_PASSWORD: the public owner login shown on the sign-in
// page. They come from the environment only; nothing is built in.
LoginEmail, LoginPassword string
// MediaQuotaMB caps the total size of the media directory (originals and
// variants): HATAMOTO_DEMO_MEDIA_QUOTA_MB, default 200.
MediaQuotaMB int
// WriteBudgetMB caps the request bodies of all write requests (content,
// uploads, API) between two restarts, so a visitor cannot grow the database
// without bound: HATAMOTO_DEMO_WRITE_BUDGET_MB, default 150.
WriteBudgetMB int
// WritesPerSecond and WriteBurst are the per-address rate of write requests
// (every non-GET): HATAMOTO_DEMO_WRITES_PER_SECOND (default 2), burst 20.
WritesPerSecond float64
WriteBurst int
}
DemoConfig is the public demo mode: HATAMOTO_DEMO=1 turns the instance into a throwaway showcase that anyone can sign in to. It refuses everything that could reach outside the box or lock the next visitor out (uploads, outbound settings, user and key management, updates). Unset, it changes nothing.
func LoadDemoConfig ¶
func LoadDemoConfig() (DemoConfig, error)
LoadDemoConfig reads the demo env vars. In demo mode it also sets EMAIL_DISABLED=true, the existing kill switch, so no mail leaves the box whatever SMTP settings exist.
HATAMOTO_DEMO is on for 1, true, yes or on, and off for 0, false, no, off or empty/unset (any case). Any other value is an error, so a typo cannot start an instance in a mode the operator did not mean.
func (DemoConfig) Refusal ¶
func (d DemoConfig) Refusal(method, path string) (string, bool)
Refusal says whether a public demo refuses the request, and why. It is always false when the demo is off.
func (DemoConfig) ShowLogin ¶
func (d DemoConfig) ShowLogin() bool
ShowLogin reports whether the sign-in page shows the public demo login.
type FeaturesConfig ¶
type FeaturesConfig struct{}
FeaturesConfig holds reversible feature toggles. Empty for now — the rollout flags this struct carried (LINKING_V2_ACTIVE and one other) have been retired post-cutover. Kept as a struct so adding a new flag in the future doesn't require restructuring the config root.
type HatamotoConfig ¶
type HatamotoConfig struct {
// CanonicalSlug is the stable site slug stamped into API responses. Each
// deployment sets its own. Required — validated in Validate().
CanonicalSlug string
// SiteName is the human-readable brand name rendered into outbound
// transactional emails (the shared base.html <title>, header, and
// footer attribution + form-submission footer line). Config-time
// stable on purpose — siteconfig is mutable runtime state and the
// email brand identity should not silently drift if an admin edits
// the company name in the UI. Required —
// validated in Validate().
SiteName string
}
HatamotoConfig holds brand-bearing identifiers that vary per deployment. Kept in its own struct so OSS forks see one place to override their site identity instead of hunting through SMTP / public-site configs.
type PackageConfig ¶
type PackageConfig struct {
// RegistryURL is HATAMOTO_REGISTRY_URL: the signed registry index. "off"
// disables browsing (upload still works).
RegistryURL string
// TrustedKeys is HATAMOTO_TRUSTED_KEYS: base64 ed25519 public keys of the
// signers whose packages and registry indexes are accepted, separated by
// commas or spaces.
TrustedKeys string
// AllowInsecureRegistry is HATAMOTO_REGISTRY_ALLOW_HTTP=true: accept an
// http:// registry (development and tests only; the default is https only).
AllowInsecureRegistry bool
// NoFirstParty is HATAMOTO_TRUST_FIRST_PARTY=false: do not trust the
// built-in first-party key, only HATAMOTO_TRUSTED_KEYS. The first-party
// plugins then install only from a registry you sign yourself.
NoFirstParty bool
}
PackageConfig controls plugin and theme packages.
func LoadPackageConfig ¶
func LoadPackageConfig() PackageConfig
LoadPackageConfig reads the package env vars.
func (PackageConfig) RegistryOff ¶
func (p PackageConfig) RegistryOff() bool
RegistryOff reports that browsing a registry is disabled.
func (PackageConfig) TrustedKeyList ¶
func (p PackageConfig) TrustedKeyList() string
TrustedKeyList is every trusted signer key: the first-party key (unless HATAMOTO_TRUST_FIRST_PARTY=false) and the ones in HATAMOTO_TRUSTED_KEYS.
func (PackageConfig) Validate ¶
func (p PackageConfig) Validate() error
Validate refuses a malformed registry URL and the theme directory variables 1.0 no longer reads (a site must not silently change theme).
type PluginConfig ¶
type PluginConfig struct {
// Dir is HATAMOTO_PLUGIN_DIR, a development override: one <name>/plugin.json
// + plugin.wasm per plugin, loaded after the installed packages and
// replacing a package of the same name. Empty (the default) loads none.
Dir string
// CacheDir is where compiled wasm is cached across restarts:
// HATAMOTO_PLUGIN_CACHE_DIR, else <HATAMOTO_DATA>/cache/wasm. The cache
// is rebuildable and created private (0700). "off" keeps it in memory.
CacheDir string
// AllowPublicDBObjects is HATAMOTO_PLUGIN_DB_ALLOW_PUBLIC_OBJECTS=1: grant
// db.* although objects the application role does not own are open to
// PUBLIC (otherwise db.* is refused until their owner closes them).
AllowPublicDBObjects bool
// FetchPerMinute is HATAMOTO_PLUGIN_FETCH_PER_MINUTE: the most outbound
// http.fetch requests one plugin may make per minute (0: the built-in
// default of 600).
FetchPerMinute int
}
PluginConfig controls the WASM plugin runtime.
func LoadPluginConfig ¶
func LoadPluginConfig() PluginConfig
LoadPluginConfig reads the plugin env vars.
type PublicSiteConfig ¶
type PublicSiteConfig struct {
BaseURL string
// APIPrefix (PUBLIC_API_PREFIX) is an extra mount point for the public API
// (forms and track), served in addition to /api/v1/public. Empty means only
// the default. Pages written by the theme call this prefix.
APIPrefix string
}
PublicSiteConfig holds the canonical public origin for the tenant. When set it is the origin of every absolute public URL the API emits (canonicals, breadcrumbs, JSON-LD, sitemaps, llms.txt) because the request's Host header may be an internal address.
func (PublicSiteConfig) Validate ¶
func (c PublicSiteConfig) Validate() error
Validate checks the public site settings.
type SMTPConfig ¶
type SMTPConfig struct {
Host string
Port int
Username string
Password string
From string
FromName string
// FromNameFromSite is true when SMTP_FROM_NAME is unset: the admin's own
// emails then use the site name as it is in the database at send time.
FromNameFromSite bool
}
SMTPConfig holds SMTP email settings.
type SecurityConfig ¶
SecurityConfig holds security-header toggles. CSPEnforce defaults to false so every deploy ships Content-Security-Policy-Report-Only until an operator explicitly opts into enforcement after verifying the admin editor + public pages under the policy. HeadersDisabled is an escape hatch for local debugging only — never set true in production.
type ServerConfig ¶
type ServerConfig struct {
Host string
Port int
ReadTimeout time.Duration
WriteTimeout time.Duration
IdleTimeout time.Duration
ReportOutputDir string
EnableWorker bool
// Media settings
MediaUploadDir string
MediaBaseURL string
MediaMaxSizeMB int
}
ServerConfig holds HTTP server settings.
func (*ServerConfig) Address ¶
func (c *ServerConfig) Address() string
Address returns the server address in host:port format.