GitHub
08/20/2026, 7:28 AMsource = "db"), there
was no way to roll it back to the values defined in the YAML/env/flags
service configuration without manually editing the database or the YAML
file and restarting. Operators who wanted to discard their UI edits and
return to the seeded config had no self-service path.
Solution
Add a "Revert" button on each edited sink row that flips source back
to "service", then re-syncs the config from the current service
configuration during the next hot-reload — no restart, no YAML editing,
no backend access needed.
How it works
1. Operator clicks "Revert" on a sink row with source = "db".
A confirm dialog explains the config will be re-synced from the
YAML/flags on the next Apply.
2. API: POST /api/v1/log-sinks/{id}/revert calls
LogSinksManager.RevertToService(id) which sets source = "service"
on the row. The config blob is not changed here — only the source
flag. The sync happens in the TLS process which has access to the
resolved service parameters.
3. Operator clicks "Apply changes" — queues a reload-log-sinks
service command to osctrl-tls.
4. TLS hot-reload: the ActionReloadLogSinks handler now calls
Seed(flagParams, ...) before BuildExportersForEnvironments. Since
the reverted row now has source = "service", `seedRow`'s sync step
overwrites the config with the current service-config values
(flags, env vars, or YAML). The exporters are then rebuilt from the
freshly synced rows and atomically swapped in.
5. Seed sinks (source = "service") do not show the Revert button
— there is nothing to revert. The existing seedRow sync keeps
them up to date on every boot and reload.
Changes
Backend
pkg/logsinks/logsinks.go:
• New RevertToService(id uint) error method: flips source from
"db" to "service". No-op if already "service" or legacy
"yaml". Returns ErrSinkNotFound for missing rows.
cmd/tls/main.go — ActionReloadLogSinks handler:
• Added sinksMgr.Seed(flagParams, ...) call before
BuildExportersForEnvironments so reverted rows get their config
re-synced from the current service configuration during the reload.
Previously the reload only read existing DB rows without re-seeding.
cmd/api/handlers/log_sinks.go:
• New LogSinksRevertHandler — POST /api/v1/log-sinks/{id}/revert.
Admin-only, audit-logged. Returns the updated row (secrets redacted).
cmd/api/main.go:
• Registered the revert route alongside the other log-sinks CRUD
routes, gated by serviceConfigEnabled.
Frontend
frontend/src/api/log-sinks.ts:
• New revertLogSink(id) function.
frontend/src/features/log-sinks/LogSinksPage.tsx:
• revertMutation (useMutation) calling revertLogSink.
• "Revert" button in the table row action cell, shown only when
source === 'db'. Styled as a muted secondary action
(text-[color:var(--text-2)] hover:bg-[color:var(--bg-2)]) to
distinguish it from Edit (primary) and Delete (danger).
• Confirm dialog: "Revert '{name}' to service config? The config will
be re-synced from the YAML/flags on the next Apply."
• Tooltip: "Reset this sink back to the service configuration values.
Takes effect on the next Apply."
Tests
pkg/logsinks/logsinks_test.go — `TestRevertToService`:
• Creates a sink (source defaults to "db"), reverts it, verifies
source is now "service". Verifies revert is idempotent (no-op on
already-service rows). Verifies missing row returns
ErrSinkNotFound.
frontend/src/features/log-sinks/LogSinksPage.test.tsx — two new tests:
• "shows a Revert button for edited sinks and calls revertLogSink" —
seeds a source: 'db' row, finds the Revert button, clicks it
(with confirm mocked), verifies revertLogSink was called with
the right ID.
• "does not show a Revert button for seed sinks" — seeds a
source: 'service' row, verifies no Revert button is rendered.
Validation
• Go: 44 packages pass, 0 failures.
• Frontend: 242 tests pass (2 new), type check clean.
• All existing log-sinks tests continue to pass unchanged.
Files
Modified (6 files):
• pkg/logsinks/logsinks.go — RevertToService method
• pkg/logsinks/logsinks_test.go — revert test
• cmd/tls/main.go — re-seed during reload
• cmd/api/handlers/log_sinks.go — revert handler
• cmd/api/main.go — route registration
• frontend/src/api/log-sinks.ts — revertLogSink function
• frontend/src/features/log-sinks/LogSinksPage.tsx — revert button
• frontend/src/features/log-sinks/LogSinksPage.test.tsx — 2 tests
jmpsec/osctrlGitHub
08/20/2026, 9:46 AM