mirror of
https://tangled.org/evan.jarrett.net/at-container-registry
synced 2026-09-24 19:24:16 +00:00
seamark.dev's /install and /settings/devices told users to pipe
seamark.dev/static/install.sh into bash. That file was the unmodified ATCR
script: it announced itself as the "ATCR Credential Helper Installer",
installed docker-credential-atcr, and finished by telling the user to configure
credHelpers for atcr.io, the wrong registry for that deployment. Anyone
following the documented setup ended up pointed at another service. The
templates hardcoded docker-credential-atcr, "atcr" and ~/.atcr/device.json
alongside a correctly themed {{ .RegistryURL }}.
The scripts are now rendered from config by a handler, rather than forked per
brand. A theme overlay was the alternative and was worse: it needed a full copy
of both install.sh and install.ps1 per brand, four scripts to keep in sync, and
the operator asked for these values to come from config.
credential_helper.name is the single knob. Docker resolves a credHelpers value
x by exec'ing docker-credential-x, so the credHelpers value, the binary suffix
and the config directory are genuinely one word, not three that can drift. It
is validated against a strict pattern because it is interpolated into a shell
script.
install.sh renders byte-identical to the deleted static file under the atcr
default, so existing installs are unaffected. install.ps1 differs by one line,
where a stale usage comment named a path the script is not served at.
Two behaviour changes worth noting: these two URLs drop from a one-year
Cache-Control to five minutes, since the body now depends on deployment config;
and credential_helper.tangled_repo becomes a real overridable default. It was
previously assigned over unconditionally and read by nothing, while the shipped
script used a different URL form.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PDqoCE1j3njokkZ9b1C5n9
75 lines
2.7 KiB
Go
75 lines
2.7 KiB
Go
package handlers
|
|
|
|
import (
|
|
"database/sql"
|
|
"html/template"
|
|
"slices"
|
|
|
|
"atcr.io/pkg/appview/db"
|
|
"atcr.io/pkg/appview/holdhealth"
|
|
"atcr.io/pkg/appview/installscript"
|
|
"atcr.io/pkg/appview/readme"
|
|
"atcr.io/pkg/appview/webhooks"
|
|
"atcr.io/pkg/auth/oauth"
|
|
"atcr.io/pkg/billing"
|
|
indigooauth "github.com/bluesky-social/indigo/atproto/auth/oauth"
|
|
"github.com/bluesky-social/indigo/atproto/identity"
|
|
)
|
|
|
|
// BaseUIHandler contains all dependencies for UI handlers.
|
|
// Handlers embed this and use whatever fields they need.
|
|
// Route registration becomes simply &Handler{base} for everything.
|
|
type BaseUIHandler struct {
|
|
// Display
|
|
Templates *template.Template
|
|
RegistryURL string // Primary Docker registry domain (e.g., "buoy.cr" or "atcr.io")
|
|
RegistryDomains []string // All configured registry domains; users may pick one as their default
|
|
SiteURL string // Website domain (e.g., "seamark.dev" or "atcr.io")
|
|
|
|
// Database (handlers choose which to use)
|
|
DB *sql.DB // Write access
|
|
ReadOnlyDB *sql.DB // Read-only access
|
|
|
|
// Services
|
|
Refresher *oauth.Refresher
|
|
HealthChecker *holdhealth.Checker
|
|
ReadmeFetcher *readme.Fetcher
|
|
Directory identity.Directory
|
|
BillingManager *billing.Manager
|
|
WebhookDispatcher *webhooks.Dispatcher
|
|
OAuthClientApp *indigooauth.ClientApp
|
|
|
|
// Stores
|
|
SessionStore *db.SessionStore
|
|
DeviceStore *db.DeviceStore
|
|
OAuthStore *db.OAuthStore
|
|
|
|
// Config
|
|
DefaultHoldDID string
|
|
ManagedHolds []string // DIDs of holds this appview operates (server.managed_holds)
|
|
CompanyName string
|
|
Jurisdiction string
|
|
ClientName string // Full name: "AT Container Registry"
|
|
ClientShortName string // Short name: "ATCR"
|
|
AIAdvisorEnabled bool // True when billing is fully configured AND Claude API key is set
|
|
BillingEnabled bool // True when the billing build is compiled in and Stripe is configured
|
|
SourceURL string // Source code URL for the footer "Source" link
|
|
BlueskyProfile string // Bluesky handle or DID for the footer link ("" hides it)
|
|
|
|
// CredHelper is this deployment's credential helper identity: the Docker
|
|
// credHelpers value, the docker-credential-<name> binary and the ~/.<name>
|
|
// config directory. Templates and the rendered install scripts read it
|
|
// from here so a rebranded deployment never names atcr's helper.
|
|
CredHelper installscript.Brand
|
|
}
|
|
|
|
// IsManagedHold reports whether a hold DID is one of the appview's managed
|
|
// holds. An empty holdDID counts as managed: the user has no explicit default
|
|
// hold and falls back to the operator's primary managed hold.
|
|
func (h *BaseUIHandler) IsManagedHold(holdDID string) bool {
|
|
if holdDID == "" {
|
|
return true
|
|
}
|
|
return slices.Contains(h.ManagedHolds, holdDID)
|
|
}
|