Documentation
¶
Overview ¶
Package edge generates the per-project artefacts the long-running containers read: a caddy site file and a pgweb bookmark.
Both are plain files in DRAGONRUN_HOME, mounted read-only into the containers. Registering a project therefore never restarts the stack -- caddy gets a reload, pgweb picks bookmarks up on next page load.
Index ¶
- Constants
- Variables
- func Bookmarks() ([]string, error)
- func CertHosts() ([]string, error)
- func DeleteCA(fp string) error
- func EnsureCertLifetimes() (bool, error)
- func Fingerprint(path string) (string, error)
- func KeychainCAs() ([]string, error)
- func Reload() error
- func RemoveBookmark(name string) error
- func RemoveSite(name string) error
- func RootCA() (string, error)
- func SiteFiles() ([]string, error)
- func TrustCA(path string) error
- func UntrustCA(rootCrt string) (bool, error)
- func WriteAllSites(c *registry.Config) error
- func WriteBookmark(c *registry.Config, p registry.Project) error
- func WriteServiceSites(c *registry.Config) error
- func WriteSite(p registry.Project) error
Constants ¶
const ( CertLifetime = "2160h" // 90 days IntermediateLifetime = "8760h" // 365 days )
Lifetimes for the certificates caddy's local CA issues. `tls internal` defaults to a 12-hour leaf off a 7-day intermediate, which assumes a server that is always up to renew them. A dev edge is stopped overnight and hit again in the morning, and by then the certificate has expired.
A leaf is truncated to its issuer's notAfter, so the intermediate has to comfortably outlive it. Caddy renews the intermediate with a third of its life left -- four months here -- which is still longer than a whole leaf lifetime, so a leaf is never issued short. 90 days also stays under the 398-day ceiling browsers apply to server certificates.
CertLifetime is written into each generated site file. IntermediateLifetime is a global option and lives in the stack's Caddyfile; the constant is here so the two are stated together, and a test keeps them equal.
Variables ¶
var ServiceHosts = map[string]string{
"mail": "mailpit:8025",
"pgweb": "pgweb:8081",
}
ServiceHosts are the built-in UIs dragonrun serves under its own domain, so you never have to remember a port. They proxy to the CONTAINERS by service name -- caddy shares a network with them -- rather than back out through the host's published ports.
These are browser URLs, which is why a hostname is fine here while the database and SMTP DSNs deliberately stay on localhost: a browser URL failing off-network is a mild annoyance, an app failing to boot is not.
Functions ¶
func Bookmarks ¶ added in v0.2.0
Bookmarks lists the pgweb bookmarks present on disk, by project name.
func CertHosts ¶ added in v0.2.0
CertHosts lists the hostnames caddy holds a certificate for.
A certificate outlives the site file that caused it: unregister a project and caddy keeps its certificate until the volume is recreated, which is how a host nobody serves any more goes on looking real.
func EnsureCertLifetimes ¶ added in v0.2.0
EnsureCertLifetimes brings a running stack's certificates up to the lifetimes above, and reports whether it had to change anything.
Raising them in config is not enough on a stack that has already run. Caddy keeps the intermediate it minted under the old settings until it is nearly expired, and truncates every leaf to that date; it also keeps each cached leaf until that leaf's own renewal window. An install upgraded in place would go on serving twelve-hour certificates -- silently, which is the whole bug.
Deleting the intermediate makes caddy mint a replacement from the SAME root, so nothing has to be re-trusted and no keychain entry goes stale. The cached leaves go with it so every site is re-issued now rather than at its next renewal.
func Fingerprint ¶
Fingerprint returns the SHA-1 of a PEM certificate, formatted the way `security find-certificate -Z` prints it.
func KeychainCAs ¶
KeychainCAs lists every trusted caddy root, by fingerprint. Used to find roots left behind when the caddy volume was recreated.
func Reload ¶
func Reload() error
Reload asks caddy to re-read its config in place. A restart would drop in-flight requests and, more annoyingly, re-issue certificates.
func RemoveBookmark ¶
func RemoveSite ¶
func RootCA ¶
RootCA copies caddy's local CA out of the container so it can be trusted by the host. Until this is trusted, every https://*.test hit shows a warning.
func SiteFiles ¶ added in v0.2.0
SiteFiles lists the project site files present on disk, by project name. The built-in `_services.caddy` is dragonrun's own and never a project.
func TrustCA ¶
TrustCA installs caddy's root into the system keychain. Requires sudo, and deliberately shells out visibly so the password prompt is not a surprise.
func UntrustCA ¶
UntrustCA removes dragonrun's caddy root from the system keychain.
It matches on the certificate's SHA-1 fingerprint, not its name: the label carries a year ("Caddy Local Authority - 2026 ECC Root") and any other Caddy on this machine -- one of the per-project Caddyfiles, say -- produces a root with the same name. Deleting by name could untrust someone else's CA.
func WriteAllSites ¶ added in v0.2.0
WriteAllSites regenerates every registered project's site file.
A site file is a pure function of the registry entry behind it, so rewriting them all is how a change to what dragonrun generates -- a certificate lifetime, say -- reaches projects that were registered by an older binary. Without this they keep whatever `register` wrote, however long ago.
func WriteBookmark ¶
WriteBookmark points pgweb at the project's control database as the cluster superuser, so tenant databases created later are reachable from the UI's database switcher without any further registration.
It connects to postgres directly rather than through pgbouncer: browsing is a session-oriented workload and transaction pooling would only get in the way.
func WriteServiceSites ¶
WriteServiceSites renders the built-in hostnames. One file, rewritten whenever the stack comes up, named with a leading underscore so it can never collide with a project's own site file.
Types ¶
This section is empty.