Files
at-container-registry/config-appview.example.yaml
T
Evan JarrettandClaude Opus 5 9d8bd513da appview: render the install scripts from config instead of shipping ATCR's
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
2026-09-02 21:38:10 -05:00

181 lines
8.9 KiB
YAML

# ATCR AppView Configuration
# Generated with defaults — edit as needed.
# Configuration format version.
version: "0.1"
# Log level: debug, info, warn, error.
log_level: info
# Remote log shipping settings.
log_shipper:
# Log shipping backend: "victoria", "opensearch", or "loki". Empty disables shipping.
backend: ""
# Remote log service endpoint, e.g. "http://victorialogs:9428".
url: ""
# Number of log entries to buffer before flushing to the remote service.
batch_size: 100
# Maximum time between flushes, even if batch is not full.
flush_interval: 5s
# Basic auth username for the log service (optional).
username: ""
# Basic auth password for the log service (optional).
password: ""
# HTTP server and identity settings.
server:
# Listen address, e.g. ":5000" or "127.0.0.1:5000".
addr: :5000
# Public-facing URL for OAuth callbacks and JWT realm. Auto-detected if empty.
base_url: ""
# Allows HTTP (not HTTPS) for DID resolution and uses transition:generic OAuth scope.
test_mode: false
# Display name shown on OAuth authorization screens.
client_name: AT Container Registry
# Short name used in page titles and browser tabs.
client_short_name: ATCR
# Separate domains for OCI registry API (e.g. ["buoy.cr"]). First is primary. Browser visits redirect to BaseURL.
registry_domains: [127.0.0.1:5000, atcr.io]
# DIDs of holds this appview manages billing for (REQUIRED). The first entry is the default blob-storage hold. Tier updates are pushed to these holds.
managed_holds:
- did:web:172.28.0.3%3A8080
# Web UI settings.
ui:
# SQLite/libSQL database for OAuth sessions, stars, pull counts, and device approvals.
database_path: /var/lib/atcr/ui.db
# Visual theme name (e.g. "seamark"). Empty uses default atcr.io branding.
theme: "seamark"
# libSQL sync URL (libsql://...). Works with Turso cloud or self-hosted libsql-server. Leave empty for local-only SQLite.
libsql_sync_url: ""
# Auth token for libSQL sync. Required if libsql_sync_url is set.
libsql_auth_token: ""
# How often to sync with remote libSQL server. Default: 60s.
libsql_sync_interval: 1m0s
# Source code URL displayed in the footer "Source" link. Defaults to the upstream ATCR project.
source_url: https://tangled.org/evan.jarrett.net/at-container-registry
# Bluesky handle or DID linked from the footer. Prefer a DID: handles can change. Defaults to the ATCR project account. Set to "" in YAML to hide the link (an empty env var will not do it: Viper treats it as unset).
bluesky_profile: did:plc:wfj5kyialpmcv2fzk6uqwsln
# Health check and cache settings.
health:
# How long to cache hold health check results.
cache_ttl: 15m0s
# How often to refresh hold health checks.
check_interval: 15m0s
# Leader election for background workers. Required when running more than one AppView instance.
leases:
# Elect a single instance to run background workers. Required when running more than one AppView instance.
enabled: true
# How long a lease survives without renewal before another instance may take it. Must exceed any plausible clock skew between instances.
ttl: 1m0s
# How often the holder renews its lease, and how often waiting instances retry. Must be well under ttl.
renew_interval: 20s
# ATProto Jetstream event stream settings.
jetstream:
# Jetstream WebSocket endpoints, tried in order on failure.
urls:
- wss://jetstream2.us-west.bsky.network/subscribe
- wss://jetstream1.us-west.bsky.network/subscribe
- wss://jetstream2.us-east.bsky.network/subscribe
- wss://jetstream1.us-east.bsky.network/subscribe
# Sync existing records from PDS on startup.
backfill_enabled: true
# How often to re-run backfill to catch missed events. Set to 0 to only backfill on startup.
backfill_interval: 24h0m0s
# Endpoints used for backfill. MUST support com.atproto.sync.listReposByCollection. Tried in order on failure.
relay_endpoints:
- https://relay1.us-east.bsky.network
- https://relay1.us-west.bsky.network
# JWT authentication settings.
auth:
# X.509 certificate matching the JWT signing key (auto-generated on each boot from the JWT key in the database).
cert_path: /var/lib/atcr/auth/private-key.crt
# Credential helper branding and download settings.
credential_helper:
# Tangled repository URL for credential helper downloads. Defaults to the upstream ATCR release repo.
tangled_repo: ""
# Credential helper brand: the docker credHelpers value, the docker-credential-<name> binary suffix, and the ~/.<name> config directory. Defaults to "atcr".
name: ""
# Legal page customization for self-hosted instances.
legal:
# Organization name for Terms of Service and Privacy Policy. Defaults to server.client_name.
company_name: ""
# Governing law jurisdiction for legal terms.
jurisdiction: ""
# AI-powered image advisor settings.
ai:
# Anthropic API key for AI Image Advisor. Also reads CLAUDE_API_KEY env var as fallback.
api_key: ""
# ATProto labeler for content moderation (DMCA takedowns).
labeler:
# DID of the ATProto labeler (did:plc:... or did:web:...). Empty disables label filtering.
did: ""
# Stripe billing integration (requires -tags billing build).
billing:
# Stripe secret key. Can also be set via STRIPE_SECRET_KEY env var (takes precedence). Billing is enabled automatically when set.
stripe_secret_key: ""
# Stripe webhook signing secret. Can also be set via STRIPE_WEBHOOK_SECRET env var (takes precedence).
webhook_secret: ""
# ISO 4217 currency code (e.g. "usd").
currency: usd
# Redirect URL after successful checkout. Use {base_url} placeholder.
success_url: '{base_url}/settings/billing'
# Redirect URL after cancelled checkout. Use {base_url} placeholder.
cancel_url: '{base_url}/settings/billing'
# Subscription tiers ordered by rank (lowest to highest).
tiers:
- # Tier name. Position in list determines rank (0-based).
name: Free
# Short description shown on the plan card.
description: Get started with basic storage
# List of features included in this tier.
features: []
# Stripe price ID for monthly billing. Empty = free tier.
stripe_price_monthly: ""
# Stripe price ID for yearly billing.
stripe_price_yearly: ""
# Maximum webhooks for this tier (-1 = unlimited).
max_webhooks: 1
# Allow all webhook trigger types (not just first-scan).
webhook_all_triggers: false
# Enable AI Image Advisor for this tier.
ai_advisor: false
# Show supporter badge on user profiles for subscribers at this tier.
supporter_badge: false
- # Tier name. Position in list determines rank (0-based).
name: Supporter
# Short description shown on the plan card.
description: Get started with basic storage
# List of features included in this tier.
features: []
# Stripe price ID for monthly billing. Empty = free tier.
stripe_price_monthly: ""
# Stripe price ID for yearly billing.
stripe_price_yearly: "price_1SmK1mRROAC4bYmSwhTQ7RY9"
# Stripe product ID for this tier. Entitlements resolve on this, so changing a price does not remove features from existing subscribers. Falls back to the price IDs when empty.
stripe_product: "prod_TjndpygrZWXHzS"
# Maximum webhooks for this tier (-1 = unlimited).
max_webhooks: 1
# Allow all webhook trigger types (not just first-scan).
webhook_all_triggers: true
# Enable AI Image Advisor for this tier.
ai_advisor: true
# Show supporter badge on user profiles for subscribers at this tier.
supporter_badge: true
- # Tier name. Position in list determines rank (0-based).
name: Pro
# Short description shown on the plan card.
description: More storage with scan-on-push
# List of features included in this tier.
features: []
# Stripe price ID for monthly billing. Empty = free tier.
stripe_price_monthly: "price_1SmK4QRROAC4bYmSxpr35HUl"
# Stripe price ID for yearly billing.
stripe_price_yearly: "price_1SmJuLRROAC4bYmSUgVCwZWo"
# Stripe product ID for this tier. Entitlements resolve on this, so changing a price does not remove features from existing subscribers. Falls back to the price IDs when empty.
stripe_product: "prod_TjnVZ1HcRm3dLL"
# Maximum webhooks for this tier (-1 = unlimited).
max_webhooks: 10
# Allow all webhook trigger types (not just first-scan).
webhook_all_triggers: true
# Enable AI Image Advisor for this tier.
ai_advisor: true
# Show supporter badge on user profiles for subscribers at this tier.
supporter_badge: true