feat(cutover): hard legacy cutover — drop projects/stacks/sites/deploys
Build / build (push) Successful in 10m39s
Build / build (push) Successful in 10m39s
The clean-break delete that closes the workload-first refactor arc.
Net diff: ~30 backend files deleted, ~20 modified, ~12k LOC removed
on the Go side; entire /projects /stacks /sites /deploy frontend
trees gone; ~6.7k LOC removed on the Svelte/TypeScript side.
Backend
- API handlers gone: internal/api/{projects,stages,stage_env,stacks,
static_sites,deploys,instances,volume_browser}.go
- Store CRUD + tests gone: internal/store/{projects,stages,stage_env,
stacks,static_sites,static_site_secrets,deploys,poll_state,volumes,
workload_sync}.go (+ _test.go siblings)
- Legacy deployer pipeline gone: internal/deployer/{bluegreen,promote,
rollback,subdomain,resolver_test}.go; deployer.go trimmed to just the
dispatch surface used by the plugin pipeline
- internal/staticsite/{manager,healthcheck}.go and
internal/stack/manager.go gone (the rest of those packages stay as
helpers imported by the static + compose plugins)
- internal/registry/poller.go gone (legacy registry poller)
- internal/volume.ResolvePath gone; ResolveWorkloadPath stays
- internal/webhook: handleWebhook (project) + handleSiteWebhook (site)
gone; only POST /api/webhook/triggers/{secret} remains
- workload-side webhook URL handlers (getWorkloadWebhook +
regenerateWorkloadWebhook + EnsureWorkloadWebhookSecret +
SetWorkloadWebhookSecret + GetWorkloadByWebhookSecret) gone — they
minted URLs that would 404 against the new trigger-only ingress
- cmd/server/main.go: dropped staticsite.Manager, stack.Manager,
staticsite.HealthChecker, registry poller, SetSiteSyncTriggerer,
SetStaticSiteManager, SetStackManager, wireStaticBackend
- store/store.go: idempotent DROP TABLE IF EXISTS for every legacy
table (projects, stages, stage_env, volumes, deploys, deploy_logs,
poll_states, stacks, stack_revisions, stack_deploys, static_sites,
static_site_secrets); FK order children-then-parents
- store/models.go: dropped Project, Stage, Deploy, DeployLog, StageEnv,
Volume, StaticSite, StaticSiteSecret, Stack, StackRevision,
StackDeploy types; kept WorkloadKind constants as documented strings
- internal/store/helpers.go (new): BoolToInt, rowScanner,
GenerateWebhookSecret extracted from deleted CRUD files
- internal/api/secrets.go (new): forwards to store.GenerateWebhookSecret
so api + store paths share one secret-generation impl (no
panic-vs-UUID-fallback divergence)
- internal/reconciler/reconciler.go: dropped legacy stack-by-compose
+ static-site label paths; only canonical tinyforge.workload.id
dispatch remains
- providers (gitea_content/github_provider/gitlab_provider) gained
path-traversal rejection on every tree entry
- internal/webhook ParsedImage / ParseImageRef demoted to package-
private (no external callers)
Frontend
- /projects /stacks /sites /deploy routes deleted (entire trees)
- ProjectCard / InstanceCard / StaleContainerCard components deleted
- api.ts: dropped every project/stage/stack/site/deploy/instance
helper + types (Project, Stage, Stack, StaticSite, Deploy,
Instance, Volume, etc.); kept Workload, Container, App, Settings,
Registry, EventTrigger, LogScanRule, webhook envelopes
- WorkloadWebhook type + getWorkloadWebhook/regenerateWorkloadWebhook
api functions gone (mirror of the backend deletion above)
- web/src/routes/+layout.svelte: dropped /projects /sites /stacks
/deploy nav entries, trimmed quick-nav keymap
- web/src/routes/+page.svelte: dashboard rewrite — reads
listWorkloads + listContainers only; 4-card stat grid
(workloads/running/failed/stale) + recent workloads strip
- navCounts.ts, SystemHealthCard.svelte, ContainerLogs.svelte,
ContainerStats.svelte, StatusBadge.svelte, TagCombobox.svelte,
proxies/+page.svelte, containers/+page.svelte all rewired to the
workload-first surface
- AbortController plumbing on dashboard, nav-counts, stale page,
SystemHealthCard so navigation doesn't leave dangling fetches
- i18n: dropped projects.*, projectDetail.*, envEditor.*,
volumeEditor.*, volumeBrowser.*, quickDeploy.*, sites.*, stacks.*,
instance.*, confirm.* namespaces; en/ru parity preserved (1042
keys each)
Hardening from go-reviewer + security-reviewer + typescript-reviewer
subagent passes (0 CRITICAL across all three; 1 HIGH + ~12 MEDIUM
addressed inline before commit):
- Sec H1: dead-end workload webhook URL handlers (would mint URLs
that 404 the new trigger-only ingress) deleted across backend +
frontend
- Go M1: IsTerminalDeployStatus dropped (no production callers)
- Go M2: ParsedImage/ParseImageRef lowercased (in-package only)
- Go M6: generateWebhookSecret unified — api shim forwards to
store.GenerateWebhookSecret
- Doc/comment freshness: stage_id (no longer FK), ProxyRoute legacy
field names, workloadIDRow rationale, webhook_deliveries.target_type
enum, WebhookDeliveryLog component header
Doc
- WORKLOAD_REFACTOR_TODO: cutover marked DONE; all three Priority 1
items are now shipped. Next focus is Priority 3 polish (apps.* i18n
+ codemap entries) and Priority 4 tests.
Behavioral notes for operators upgrading from a pre-cutover build
- Existing rows in the dropped tables disappear on first boot.
- Legacy webhook URLs at /api/webhook/{secret} and
/api/webhook/sites/{secret} return 404; CI configs must repoint to
/api/webhook/triggers/{secret} (the trigger-split boot backfill
lifted any embedded workload secret onto a Trigger row, so the
secret value itself carries over).
- Frontend routes /projects /stacks /sites /deploy are gone; nav
links replaced with /apps and /triggers.
This commit is contained in:
+38
-209
@@ -16,43 +16,49 @@ import (
|
||||
"github.com/alexei/tinyforge/internal/notify"
|
||||
"github.com/alexei/tinyforge/internal/npm"
|
||||
"github.com/alexei/tinyforge/internal/proxy"
|
||||
"github.com/alexei/tinyforge/internal/stack"
|
||||
"github.com/alexei/tinyforge/internal/stale"
|
||||
"github.com/alexei/tinyforge/internal/staticsite"
|
||||
"github.com/alexei/tinyforge/internal/store"
|
||||
"github.com/alexei/tinyforge/internal/webhook"
|
||||
"github.com/alexei/tinyforge/internal/workload/plugin"
|
||||
)
|
||||
|
||||
// DNSProviderChangedFunc is called when DNS settings change so the caller can
|
||||
// update the provider on the deployer.
|
||||
type DNSProviderChangedFunc func(provider dns.Provider)
|
||||
|
||||
// PluginDispatcher is the subset of the deployer the API layer uses for the
|
||||
// plugin-native dispatch surface (generic-hooks endpoint + workload teardown
|
||||
// + future surfaces). Defined here so the API does not import the deployer
|
||||
// package directly.
|
||||
type PluginDispatcher interface {
|
||||
webhook.PluginDispatcher
|
||||
DispatchTeardown(ctx context.Context, w plugin.Workload) error
|
||||
}
|
||||
|
||||
// Server holds all dependencies for the API layer.
|
||||
type Server struct {
|
||||
store *store.Store
|
||||
docker *docker.Client
|
||||
npm *npm.Client // optional: only for NPM-specific endpoints (certificates)
|
||||
npm *npm.Client // optional: only for NPM-specific endpoints (certificates)
|
||||
proxyProvider proxy.Provider
|
||||
deployer DeployTriggerer
|
||||
deployer PluginDispatcher
|
||||
notifier *notify.Notifier
|
||||
webhook *webhook.Handler
|
||||
eventBus *events.Bus
|
||||
encKey [32]byte
|
||||
localAuth *auth.LocalAuth
|
||||
oidcProvider *auth.OIDCProvider
|
||||
staleScanner *stale.Scanner
|
||||
webhook *webhook.Handler
|
||||
eventBus *events.Bus
|
||||
encKey [32]byte
|
||||
localAuth *auth.LocalAuth
|
||||
oidcProvider *auth.OIDCProvider
|
||||
staleScanner *stale.Scanner
|
||||
|
||||
dnsProviderMu sync.RWMutex
|
||||
dnsProvider dns.Provider
|
||||
onDNSProviderChanged DNSProviderChangedFunc
|
||||
|
||||
staticSiteManager *staticsite.Manager
|
||||
stackManager *stack.Manager
|
||||
backupEngine *backup.Engine
|
||||
sseGate *sseGate
|
||||
logScanReloader LogScanReloader
|
||||
dbPath string
|
||||
shutdownFunc func() // called after restore to trigger graceful shutdown
|
||||
backupEngine *backup.Engine
|
||||
sseGate *sseGate
|
||||
logScanReloader LogScanReloader
|
||||
dbPath string
|
||||
shutdownFunc func() // called after restore to trigger graceful shutdown
|
||||
onBackupSettingsChanged func(enabled bool, intervalHours int) // called when backup settings change
|
||||
onProxyProviderChanged func(provider proxy.Provider) // called when proxy provider changes
|
||||
}
|
||||
@@ -63,7 +69,7 @@ func NewServer(
|
||||
dockerClient *docker.Client,
|
||||
npmClient *npm.Client,
|
||||
proxyProvider proxy.Provider,
|
||||
deployer DeployTriggerer,
|
||||
deployer PluginDispatcher,
|
||||
notifier *notify.Notifier,
|
||||
webhookHandler *webhook.Handler,
|
||||
eventBus *events.Bus,
|
||||
@@ -94,16 +100,6 @@ func NewServer(
|
||||
return s
|
||||
}
|
||||
|
||||
// SetStaticSiteManager sets the static site manager on the server.
|
||||
func (s *Server) SetStaticSiteManager(mgr *staticsite.Manager) {
|
||||
s.staticSiteManager = mgr
|
||||
}
|
||||
|
||||
// SetStackManager sets the docker-compose stack manager on the server.
|
||||
func (s *Server) SetStackManager(mgr *stack.Manager) {
|
||||
s.stackManager = mgr
|
||||
}
|
||||
|
||||
// SetStaleScanner sets the stale scanner on the server.
|
||||
// Called after both the API server and scanner are initialized.
|
||||
func (s *Server) SetStaleScanner(scanner *stale.Scanner) {
|
||||
@@ -218,12 +214,7 @@ func (s *Server) Router() chi.Router {
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Use(auth.Middleware(s.localAuth))
|
||||
|
||||
// Plugin registry inspection + unified ingress (Workload refactor).
|
||||
// /hooks/kinds is informational and visible to any authenticated
|
||||
// caller. /hooks/generic dispatches deploys and is admin-gated —
|
||||
// vendor-specific webhooks (with their own per-target HMAC
|
||||
// secrets) live under /webhook/* and remain the only ingress
|
||||
// reachable by external CI systems until Phase 5 consolidates them.
|
||||
// Plugin registry inspection + unified ingress.
|
||||
r.Get("/hooks/kinds", s.listHookKinds)
|
||||
r.Get("/hooks/kinds/{kind}/schema", s.getHookKindSchema)
|
||||
r.With(auth.AdminOnly).Post("/hooks/generic", s.dispatchGeneric)
|
||||
@@ -234,134 +225,6 @@ func (s *Server) Router() chi.Router {
|
||||
r.Post("/auth/logout", s.logout)
|
||||
r.Get("/proxies", s.listProxyRoutes)
|
||||
r.Get("/docker/unused-images", s.unusedImageStats)
|
||||
// Legacy project/stage/site/stack endpoints carry a Deprecation
|
||||
// header pointing at /api/workloads. Functional behavior is
|
||||
// unchanged until the hard cutover removes them.
|
||||
r.With(deprecated("/api/workloads")).Get("/projects", s.listProjects)
|
||||
r.Route("/projects/{id}", func(r chi.Router) {
|
||||
r.Get("/", s.getProject)
|
||||
r.Get("/stages/{stage}/env", s.listStageEnv)
|
||||
r.Get("/stages/{stage}/instances", s.listInstances)
|
||||
r.Get("/stages/{stage}/instances/{iid}/stats", s.getInstanceStats)
|
||||
r.Get("/stages/{stage}/instances/{iid}/stats/history", s.getInstanceStatsHistory)
|
||||
r.Get("/stages/{stage}/instances/{iid}/logs", s.streamContainerLogs)
|
||||
r.Get("/images", s.listProjectImages)
|
||||
r.Get("/volumes", s.listVolumes)
|
||||
r.Get("/volumes/{volId}/browse", s.browseVolume)
|
||||
r.Get("/volumes/{volId}/download", s.downloadVolume)
|
||||
|
||||
// Admin-only project mutations.
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Use(auth.AdminOnly)
|
||||
r.Put("/", s.updateProject)
|
||||
r.Delete("/", s.deleteProject)
|
||||
|
||||
// Per-project webhook URL management.
|
||||
r.Get("/webhook", s.getProjectWebhook)
|
||||
r.Post("/webhook/regenerate", s.regenerateProjectWebhook)
|
||||
// Inbound HMAC signing — secret rotation + enforcement toggle.
|
||||
r.Post("/webhook/signing-secret/regenerate", s.regenerateProjectSigningSecret)
|
||||
r.Delete("/webhook/signing-secret", s.disableProjectSigningSecret)
|
||||
r.Put("/webhook/require-signature", s.updateProjectSigningRequirement)
|
||||
r.Get("/webhook/deliveries", s.listProjectWebhookDeliveries)
|
||||
|
||||
// Per-project outgoing-webhook signing & test.
|
||||
r.Get("/notification-secret", s.getProjectNotificationSecret)
|
||||
r.Post("/notification-secret/regenerate", s.regenerateProjectNotificationSecret)
|
||||
r.Post("/notification-secret/disable", s.disableProjectNotificationSigning)
|
||||
r.Post("/notification-test", s.projectNotificationTest)
|
||||
|
||||
// Stage endpoints.
|
||||
r.Post("/stages", s.createStage)
|
||||
r.Put("/stages/{stage}", s.updateStage)
|
||||
r.Delete("/stages/{stage}", s.deleteStage)
|
||||
|
||||
// Per-stage outgoing-webhook signing & test.
|
||||
r.Get("/stages/{stage}/notification-secret", s.getStageNotificationSecret)
|
||||
r.Post("/stages/{stage}/notification-secret/regenerate", s.regenerateStageNotificationSecret)
|
||||
r.Post("/stages/{stage}/notification-secret/disable", s.disableStageNotificationSigning)
|
||||
r.Post("/stages/{stage}/notification-test", s.stageNotificationTest)
|
||||
|
||||
// Stage env override endpoints.
|
||||
r.Post("/stages/{stage}/env", s.createStageEnv)
|
||||
r.Put("/stages/{stage}/env/{envId}", s.updateStageEnv)
|
||||
r.Delete("/stages/{stage}/env/{envId}", s.deleteStageEnv)
|
||||
|
||||
// Instance endpoints.
|
||||
r.Post("/stages/{stage}/instances", s.deployInstance)
|
||||
r.Delete("/stages/{stage}/instances/{iid}", s.removeInstance)
|
||||
|
||||
// Instance control endpoints.
|
||||
r.Post("/stages/{stage}/instances/{iid}/stop", s.stopInstance)
|
||||
r.Post("/stages/{stage}/instances/{iid}/start", s.startInstance)
|
||||
r.Post("/stages/{stage}/instances/{iid}/restart", s.restartInstance)
|
||||
|
||||
// Volume endpoints.
|
||||
r.Post("/volumes", s.createVolume)
|
||||
r.Put("/volumes/{volId}", s.updateVolume)
|
||||
r.Delete("/volumes/{volId}", s.deleteVolume)
|
||||
r.Post("/volumes/{volId}/upload", s.uploadToVolume)
|
||||
})
|
||||
})
|
||||
// Stacks (docker-compose).
|
||||
r.With(deprecated("/api/workloads?kind=plugin&source_kind=compose")).Get("/stacks", s.listStacks)
|
||||
r.Route("/stacks/{id}", func(r chi.Router) {
|
||||
r.Get("/", s.getStack)
|
||||
r.Get("/revisions", s.listStackRevisions)
|
||||
r.Get("/revisions/{revId}", s.getStackRevision)
|
||||
r.Get("/services", s.getStackServices)
|
||||
r.Get("/logs", s.getStackLogs)
|
||||
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Use(auth.AdminOnly)
|
||||
r.Put("/", s.updateStack)
|
||||
r.Delete("/", s.deleteStack)
|
||||
r.Post("/revisions", s.createStackRevision)
|
||||
r.Post("/rollback/{revId}", s.rollbackStack)
|
||||
r.Post("/stop", s.stopStack)
|
||||
r.Post("/start", s.startStack)
|
||||
})
|
||||
})
|
||||
r.With(auth.AdminOnly).Post("/stacks", s.createStack)
|
||||
|
||||
// Static sites.
|
||||
r.With(deprecated("/api/workloads?kind=plugin&source_kind=static")).Get("/sites", s.listStaticSites)
|
||||
r.Route("/sites/{id}", func(r chi.Router) {
|
||||
r.Get("/", s.getStaticSite)
|
||||
r.Get("/secrets", s.listStaticSiteSecrets)
|
||||
r.Get("/storage", s.getStaticSiteStorage)
|
||||
r.Get("/logs", s.streamStaticSiteLogs)
|
||||
r.Get("/stats", s.getStaticSiteStats)
|
||||
r.Get("/stats/history", s.getStaticSiteStatsHistory)
|
||||
|
||||
// Admin-only mutations.
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Use(auth.AdminOnly)
|
||||
r.Put("/", s.updateStaticSite)
|
||||
r.Delete("/", s.deleteStaticSite)
|
||||
r.Post("/deploy", s.deployStaticSite)
|
||||
r.Post("/stop", s.stopStaticSite)
|
||||
r.Post("/start", s.startStaticSite)
|
||||
r.Get("/webhook", s.getStaticSiteWebhook)
|
||||
r.Post("/webhook/regenerate", s.regenerateStaticSiteWebhook)
|
||||
r.Post("/webhook/signing-secret/regenerate", s.regenerateStaticSiteSigningSecret)
|
||||
r.Delete("/webhook/signing-secret", s.disableStaticSiteSigningSecret)
|
||||
r.Put("/webhook/require-signature", s.updateStaticSiteSigningRequirement)
|
||||
r.Get("/webhook/deliveries", s.listStaticSiteWebhookDeliveries)
|
||||
|
||||
// Per-site outgoing-webhook signing & test.
|
||||
r.Get("/notification-secret", s.getStaticSiteNotificationSecret)
|
||||
r.Post("/notification-secret/regenerate", s.regenerateStaticSiteNotificationSecret)
|
||||
r.Post("/notification-secret/disable", s.disableStaticSiteNotificationSigning)
|
||||
r.Post("/notification-test", s.staticSiteNotificationTest)
|
||||
r.Post("/secrets", s.createStaticSiteSecret)
|
||||
r.Put("/secrets/{sid}", s.updateStaticSiteSecret)
|
||||
r.Delete("/secrets/{sid}", s.deleteStaticSiteSecret)
|
||||
})
|
||||
})
|
||||
|
||||
r.Get("/deploys", s.listDeploys)
|
||||
r.Get("/deploys/{id}/logs", s.streamDeployLogs)
|
||||
r.Get("/events", s.streamEvents)
|
||||
r.Get("/events/log", s.listEventLog)
|
||||
r.Get("/events/log/stats", s.getEventLogStats)
|
||||
@@ -388,12 +251,9 @@ func (s *Server) Router() chi.Router {
|
||||
// Stale container endpoints (read).
|
||||
r.Get("/containers/stale", s.listStaleContainers)
|
||||
|
||||
// Workload-shaped endpoints (the unifying layer over project /
|
||||
// stack / site). Read endpoints are open to any authenticated
|
||||
// user; create / update / deploy mutate state and are admin-gated.
|
||||
// Plugin-native workloads (source_kind + trigger_kind set) are
|
||||
// created here; legacy project / stack / site mutations remain at
|
||||
// their dedicated endpoints during the cutover.
|
||||
// Workload-shaped endpoints — the canonical surface after the
|
||||
// hard cutover. Reads open to any authenticated user; mutations
|
||||
// admin-gated.
|
||||
r.Get("/workloads", s.listWorkloads)
|
||||
r.With(auth.AdminOnly).Post("/workloads", s.createPluginWorkload)
|
||||
r.Route("/workloads/{id}", func(r chi.Router) {
|
||||
@@ -405,22 +265,17 @@ func (s *Server) Router() chi.Router {
|
||||
r.With(auth.AdminOnly).Post("/deploy", s.deployPluginWorkload)
|
||||
r.With(auth.AdminOnly).Delete("/", s.deletePluginWorkload)
|
||||
|
||||
// Per-workload env vars (analog of legacy stage_env).
|
||||
// Listing is open to authenticated readers; mutations are
|
||||
// admin-gated. Encrypted values are write-only after store.
|
||||
// Per-workload env vars. Listing open to authenticated readers;
|
||||
// mutations admin-gated. Encrypted values are write-only after store.
|
||||
r.Get("/env", s.listWorkloadEnv)
|
||||
r.With(auth.AdminOnly).Put("/env", s.setWorkloadEnv)
|
||||
r.With(auth.AdminOnly).Delete("/env/{envID}", s.deleteWorkloadEnv)
|
||||
|
||||
// Per-workload inbound webhook URL: rotate the secret + fetch
|
||||
// the canonical URL. Mirrors the project / site webhook UX.
|
||||
r.With(auth.AdminOnly).Get("/webhook", s.getWorkloadWebhook)
|
||||
r.With(auth.AdminOnly).Post("/webhook/regenerate", s.regenerateWorkloadWebhook)
|
||||
// Per-workload inbound webhook URL handlers were dropped in
|
||||
// the hard legacy cutover; inbound webhooks are now first-
|
||||
// class Triggers reachable via /api/triggers/{id}/webhook.
|
||||
|
||||
// Per-workload volume mounts (analog of legacy project volumes).
|
||||
// Reads are open to authenticated users; mutations admin-gated.
|
||||
// Source/target paths are validated for traversal safety here;
|
||||
// host-path allow-listing happens at deploy time.
|
||||
// Per-workload volume mounts.
|
||||
r.Get("/volumes", s.listWorkloadVolumes)
|
||||
r.With(auth.AdminOnly).Put("/volumes", s.setWorkloadVolume)
|
||||
r.With(auth.AdminOnly).Delete("/volumes/{volID}", s.deleteWorkloadVolume)
|
||||
@@ -432,8 +287,7 @@ func (s *Server) Router() chi.Router {
|
||||
r.With(auth.AdminOnly).Post("/promote-from/{sourceID}", s.promoteFromWorkload)
|
||||
|
||||
// Trigger bindings on this workload — the symmetric view
|
||||
// of /triggers/{id}/bindings keyed on the workload side
|
||||
// so the workload detail page is one round-trip.
|
||||
// of /triggers/{id}/bindings keyed on the workload side.
|
||||
r.Get("/triggers", s.listBindingsForWorkload)
|
||||
r.With(auth.AdminOnly).Post("/triggers", s.bindTriggerToWorkload)
|
||||
})
|
||||
@@ -453,10 +307,7 @@ func (s *Server) Router() chi.Router {
|
||||
})
|
||||
|
||||
// First-class Triggers (redeploy signal sources). One trigger
|
||||
// (registry / git / webhook / manual / schedule / log_scan)
|
||||
// fans out to many workloads via workload_trigger_bindings.
|
||||
// Reads are open to authenticated users; mutations + secret
|
||||
// rotation are admin-gated.
|
||||
r.Get("/triggers", s.listTriggers)
|
||||
r.Get("/triggers/{id}", s.getTrigger)
|
||||
r.Get("/triggers/{id}/bindings", s.listBindingsForTrigger)
|
||||
@@ -472,10 +323,7 @@ func (s *Server) Router() chi.Router {
|
||||
r.Delete("/bindings/{bid}", s.deleteBinding)
|
||||
})
|
||||
|
||||
// Event triggers: filter+action rules over the event_log
|
||||
// stream. Read endpoints are available to any authenticated
|
||||
// user; mutations + test-dispatch are admin-gated since they
|
||||
// can fire arbitrary outbound webhooks.
|
||||
// Event triggers: filter+action rules over the event_log stream.
|
||||
r.Get("/event-triggers", s.listEventTriggers)
|
||||
r.Get("/event-triggers/{id}", s.getEventTrigger)
|
||||
r.Group(func(r chi.Router) {
|
||||
@@ -486,11 +334,7 @@ func (s *Server) Router() chi.Router {
|
||||
r.Post("/event-triggers/{id}/test", s.testEventTrigger)
|
||||
})
|
||||
|
||||
// Log-scan rules: regex patterns the scanner manager
|
||||
// applies to container log lines. Read endpoints are
|
||||
// available to any authenticated user; mutations are
|
||||
// admin-gated since they can change global observability
|
||||
// behavior across every workload.
|
||||
// Log-scan rules.
|
||||
r.Get("/log-scan-rules", s.listLogScanRules)
|
||||
r.Get("/log-scan-rules/stats", s.getLogScanStats)
|
||||
r.Get("/log-scan-rules/{id}", s.getLogScanRule)
|
||||
@@ -512,7 +356,7 @@ func (s *Server) Router() chi.Router {
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Use(auth.AdminOnly)
|
||||
|
||||
// Config export (reveals project/infra details).
|
||||
// Config export (reveals registry/global details).
|
||||
r.Get("/config/export", s.exportConfig)
|
||||
|
||||
// Event log management.
|
||||
@@ -528,21 +372,6 @@ func (s *Server) Router() chi.Router {
|
||||
r.Put("/auth/users/{uid}/password", s.changePassword)
|
||||
r.Delete("/auth/users/{uid}", s.deleteUser)
|
||||
|
||||
// Project creation.
|
||||
r.Post("/projects", s.createProject)
|
||||
|
||||
// Static site creation and tools.
|
||||
r.Post("/sites", s.createStaticSite)
|
||||
r.Post("/sites/test-connection", s.testStaticSiteConnection)
|
||||
r.Post("/sites/branches", s.listStaticSiteBranches)
|
||||
r.Post("/sites/tree", s.listStaticSiteTree)
|
||||
r.Post("/sites/detect-provider", s.detectStaticSiteProvider)
|
||||
r.Post("/sites/repos", s.listStaticSiteRepos)
|
||||
|
||||
// Quick deploy endpoints.
|
||||
r.Post("/deploy/inspect", s.inspectImage)
|
||||
r.Post("/deploy/quick", s.quickDeploy)
|
||||
|
||||
// Registry creation.
|
||||
r.Post("/registries", s.createRegistry)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user