Skip to content

fix(frontend): retire four dead settings API paths, stop a fifth calling admin-gated settings from non-admin surfaces (#16481) - #16484

Merged
mrveiss merged 1 commit into
mainfrom
issue-16481-retire-settings-dead-paths
Sep 14, 2026
Merged

mrveiss merged 1 commit into
mainfrom
issue-16481-retire-settings-dead-paths

Conversation

@mrveiss

@mrveiss mrveiss commented Sep 12, 2026 •

Copy link
Copy Markdown
Owner

Thinking Path

Sub-issue of #16465 (see #16481 for why this is a separate issue rather than a PR branched directly off #16465: a branch made via gh issue develop auto-closes its issue on merge regardless of the PR body's wording, and #16465 as a whole isn't fully delivered until #16245 resolves SettingsPanel.vue).

#16240 made the core backend /api/settings routes admin-only. Five frontend paths into those routes turned out to have zero real callers (#16465). This PR covers the four fully retirable with parity evidence. Per dead-code-review discipline, checked git history + exhaustive caller grep for each:

  • useApi.ts's useSettingsApi — already marked @deprecated file-wide with a GH#7446 audit note ("zero active callers... do not add new callers"). Superseded: rebasing onto 2b found useApi.ts itself already retired whole-file by chore(frontend): retire useApi.ts, the deprecated useApiWithState composable family (#15025) #16424 (batch 2b); this PR's own hunk against it is dropped, nothing left to do here.
  • SystemRepository.ts's getSettings/updateSettings/getBackendSettings/saveBackendSettings — zero callers anywhere (grepped both autobot-frontend and autobot-slm-frontend for the /backend piece specifically; no equivalent exists for it anywhere). Retired.
  • services/api.ts's getSettings/updateSettings/saveSettings — retired with parity evidence: utils/ApiClient.ts's getSettings()/saveSettings() are the live, mounted, superseding implementation (AgentSettingsPanel.vue, BatchApiService.ts).
  • services/CacheService.ts's warmup() — zero callers, and never functional in the first place (only ever wrote a placeholder into the local cache, never actually fetched any of its commonEndpoints).

Not touched: components/settings/SettingsPanel.vue. Unlike the other four, its capability isn't fully served elsewhere — #16245 (open) already owns relocating its detailed system-health and Redis-service-management parts into the SLM before removing this component's entry points. Added a doc comment cross-referencing #16245/#16465/#16481 rather than force a premature retirement.

Investigating the services/api.ts parity evidence surfaced a live violation of #16465's own AC2 ("No frontend path calls the core /api/settings routes from a surface a non-admin can reach"): BatchApiService.ts's fallbackChatInitialization() called ApiClient.getSettings() unconditionally on every /chat page load — reachable by any signed-in user — and the result was never read anywhere by its only real caller (ChatInterface.vue's initializeChatInterface). Fetched only to be discarded, and always failing for non-admins since #16240.

Checked the other plausible violation (AgentSettingsPanel.vue, at /agents/registry, also not an admin-gated route) and found it's not actually a violation: AgentRegistryView.vue:354 already gates <AgentSettingsPanel /> behind v-if="isAdmin" client-side, so it never mounts (and never calls the endpoint) for a non-admin.

What Changed

Closes #16481
Refs #16465

Verification

  • Exhaustive caller grep for every removed symbol across the whole frontend (and autobot-slm-frontend for the /backend-specific claim), confirming zero remaining references outside the files changed here.
  • Traced AgentRegistryView.vue's v-if="isAdmin" gate directly to rule out a false-positive AC2 violation before touching anything there.
  • Traced BatchApiService.ts's settings/user_preferences result all the way to ChatInterface.vue's initializeChatInterface to confirm it was never read, before removing the call rather than rerouting it.
  • Pre-push hook: vue-tsc/vitest skipped locally (no node_modules) — CI is authoritative for frontend type-checking and tests.
  • Pre-commit hooks (hardcoded-values, secret detection, frontend canonical checks) all passed.

Model Used

Claude Sonnet 5

@mrveiss mrveiss added this to the v0.9.0 milestone Sep 12, 2026
@mrveiss mrveiss self-assigned this Sep 12, 2026
@coderabbitai

coderabbitai Bot commented Sep 12, 2026 •

Copy link
Copy Markdown
Contributor

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Advanced

Run ID: f3517e7a-0ae5-4f3a-82e4-e5f9b8ffa6ae


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown
Contributor

Notice: 29 open PRs — past the runaway threshold (25)

There is no PR queue limit, and this is not a request to defer this PR. Work proceeds one issue at a time without a cap on open PRs; review capacity is the constraint.

This notice only means the count is high enough to be worth a glance for a runaway — something opening PRs in a loop, or a merge pipeline that has stalled so nothing is draining.

Currently open:

If the queue is draining normally, ignore this. Otherwise:

  1. Check whether CI is dispatching at all — see the ci-dispatch-watchdog status on these PRs
  2. Merge the ones whose CI has finished and review has passed: gh pr merge <number> --squash --delete-branch
  3. Look for a loop opening near-identical PRs

Warn-only runaway detector — .github/workflows/pr-queue-gate.yml. It never blocks a merge.

@github-actions

Copy link
Copy Markdown
Contributor

✅ SSOT Configuration Compliance: Passing

🎉 No new hardcoded values of either class — ssot and other both block.

Known backlog in pipeline-scripts/hardcoded_values_baseline.txt is suppressed and tracked in #14371.

@mrveiss

mrveiss commented Sep 12, 2026

Copy link
Copy Markdown
Owner Author

Review: approved. It merges on a settled green after #16487.

  • The backend routes remain, and they're admin-gated: settings_config.py still serves GET/POST / and GET/POST /backend, both behind require_settings_admin. Only the dead frontend paths are retired, and the live AgentSettingsPanel caller through ApiClient is intact.
  • Zero remaining callers in either frontend for useSettingsApi, the four SystemRepository methods, api.ts's getSettings/updateSettings/saveSettings, CacheService.warmup() or BatchApiService.loadChatInitData().
  • The fifth path is verified: fallbackChatInitialization() no longer fetches settings it never used, and nothing reads .settings from the init result.
  • SettingsPanel.vue is correctly left alone for tech-debt(frontend): move SettingsPanel's detailed system health and Redis service management into the SLM #16245. It isn't mounted anywhere.
  • Closing refs are [16481], all four of its items delivered. Refs #16465 is correct.

Follow-up, outside this diff: useAsyncOperation.examples.md still shows api.saveSettings(...). Filed along with the #16486 leftovers.

This was referenced Sep 14, 2026
@mrveiss
mrveiss merged commit 6b00c3e into main Sep 14, 2026
58 checks passed
@mrveiss
mrveiss deleted the issue-16481-retire-settings-dead-paths branch September 14, 2026 12:19
mrveiss added a commit that referenced this pull request Sep 23, 2026
… it on three leftovers (#16912, #16513, #16494, #16704) (#17321)

* fix(frontend-tooling): give a worktree a resolvable node_modules and stop a skipped check reading as a pass (#16912)

A frontend change made in a worktree had no local verification at all: no
node_modules to resolve, so neither vitest nor vue-tsc could run, and pre-push
said "skipping" and pushed anyway.

Four causes, all four fixed:

1. post-checkout now links autobot-frontend/ and autobot-slm-frontend/
   node_modules to the main checkout's install when it runs in a linked
   worktree -- the same shape as the backend symlink it already restores.
   Nothing is installed, and a real install in the worktree always wins.
2. autobot-slm-frontend/.gitignore pinned `node_modules/`, a directory-only
   pattern that does not match a symlink, so the link above showed up as an
   untracked file. Verified with git status before and after.
3. pre-push reports both frontend checks through could_not_run() when
   node_modules does not resolve, so "could not look" is no longer spelled
   the same way as "looked and found nothing" (MEASUREMENT_DISCIPLINE). The
   vitest branch had no else at all and fell through silently.
4. dependency-floor-reporter.ts could never load: it imported createLogger
   from @/utils/debugUtils, which re-exports from @autobot/ui, whose index
   pulls in .vue SFCs that fail to compile in the reporter-loading context,
   and it default-exported an instance where vitest calls `new`. Either one
   takes the whole run down at startup, and vitest.config.ts only registers
   this reporter when CI is unset -- so it broke local runs exclusively.
   Both fixed; the banner now prints for the first time.

Evidence, all from inside a worktree: vitest 4.1.9 and vue-tsc 5.9.3 resolve;
`npx vitest run` (the exact invocation pre-push uses) starts and passes 13/13;
vue-tsc --noEmit over autobot-frontend reports 0 errors; the hook was run for
real with the links removed first and recreated both.

* fix(frontend): clear the three leftovers from the settings-path and SecretVault retirements (#16513)

- useAsyncOperation.examples.md showed api.saveSettings() in two examples, an
  API #16484 removed (api.ts:247 records the removal). Both now use
  apiClient.saveSettings() from utils/ApiClient, which is live, and the AFTER
  example gains the import a reader would copy.
- security.secretsManager.scopeUser / scopeSession went unreferenced when
  #16486 dropped those scopes from the Scope select to match ChatSecretScope.
  Removed from all 11 locales, brace-matched to the secretsManager block so
  the unrelated secrets.vault.scopeSession survives -- asserted per file, as
  is each file re-parsing as JSON. No dynamic key construction reaches them:
  every reference in the component is a literal $t('...scopeGeneral') form.
- SecretsManager's virtual-list wiring had no test. The new spec covers the
  seam that was uncovered -- the FILTERED set reaching displayedSecrets, list
  mode positioning each row from the virtual item's offset, grid mode
  rendering the same set unpositioned -- not useVirtualList's own maths.

3/3 pass locally (worktree vitest, now that #16912 makes that possible).

* fix(frontend): gate the three admin-only surfaces the UI still offered everyone (#16494)

Each of these let a non-admin see and attempt an action the backend already
refuses. Verified against the backend before changing anything, because it
sets the severity: api/feature_flags.py has Depends(require_admin) on 8 of 8
routes, POST /api/settings/telemetry has Depends(check_admin_permission) (the
GET is public on purpose), and api/themes.py gates install and uninstall the
same way. So these are confusing dead-ends, not privilege escalation -- no
data was reachable, only 403s.

- SettingsView: the Feature Flags tab button and its section, gated on
  userStore.isAdmin.
- TelemetrySettingsPanel: the toggle only. The state it shows comes from the
  public GET, so everyone keeps seeing whether telemetry is on; only an admin
  is offered the control that changes it.
- ThemeManagerView: upload and uninstall. The listing GETs are open, so the
  installed-theme list stays visible.

The issue's fourth item needed no change: #16442 merged and #16426 is closed,
and SecretsManager.vue already gates both the infrastructure-hosts category
and its quick-add button on userStore.isAdmin.

v-if with the existing userStore.isAdmin pattern, matching App.vue and
UsageView; no v-permission, since each of these is a plain admin/non-admin
binary. No new UI strings, so no locale changes.

vue-tsc --noEmit over autobot-frontend: 0 errors.

* refactor(slm-frontend): finish #16239's consolidation — move ToolsView onto useFleetTools (#16704)

ToolsView is the view FleetToolsTab was extracted from, and it never adopted
the composable its own extraction produced: #16702's merge-conflict
reconciliation kept main's independent copy of this one file. The split was an
artifact, not a decision -- nothing anywhere records an intent for these two
views to diverge on shared logic.

- activeTool/loading/error/result, the tool-specific state, nodes and
  selectedNodeDetails, selectTool/closeTool now come from useFleetTools(),
  with the two names this view has always used renamed at the destructure
  (shellCommand: ansibleCommand, runShellCommand: runAnsibleCommand) so
  FleetToolsTab and the composable are untouched.
- The local runRedisCommand/runAnsibleCommand bodies are gone; they were the
  composable's own implementations inlined, down to the redis-node fallback
  and the message keys.
- runNetworkTest, runHealthCheck, serviceAction and getServiceLogs stay here
  -- this view alone offers them -- rebuilt on the shared runTool/requireInput
  the way FleetToolsTab already builds getServiceLogs.

666 -> 545 lines. The three remaining rawRequest calls are exactly the three
tools this view alone offers. serviceAction keeps a local normalisation: its
fallback message interpolates {action} and runTool's fallback key cannot take
a parameter, so a non-Error throw still reads as it did before.

Verification, stated exactly: NOT run locally. autobot-slm-frontend's
node_modules in this machine's main checkout is mode drw-r--r-- -- no execute
bit, so nothing inside it is reachable and neither vitest nor vue-tsc can run
for the SLM app from any tree. The existing src/views/ToolsView.test.ts and
FleetToolsTab.logsError.test.ts therefore run in CI only for this change.

The SLM duplication count drops with this change. SLM_MAX_DUP_LINES ('2945')
lives in .github/workflows/duplication-guard.yml, which this PR does not own;
the gate passes when under the pin and prints the figure to lower it to.

* fix(frontend-tooling): select changed .spec.ts files for the pre-push vitest run too (#16912)

A fifth cause of the same defect, found while pushing this branch: the hook
selected changed test files with `grep -E '\.test\.ts$'`, so a changed
`.spec.ts` was never run. 51 of autobot-frontend's 246+51 test files are
named that way -- including the SecretsManager virtual-list spec added in
this branch, which is exactly how it surfaced.

A test file that is silently not selected is the same failure as a check that
could not run: nothing in the output distinguishes it from a clean pass.

* docs(changelog): add the fragment for the admin-only UI gates (#16494)

* test(frontend): mount ThemeManagerView with its store, and cover the admin gate it gained (#16494, #16912)

The #16494 gate made this view call useUserStore(), and its existing test
mounted it with no pinia active: "[pinia]: getActivePinia() was called but
there was no active Pinia". That is my regression and CI caught it -- but it
was reproduced locally in seconds rather than through a CI round trip, which
is what #16912 in this same branch is for.

The store is mocked with a per-test admin flag rather than backed by a real
pinia, matching the pattern the SecretsManager spec uses, and the regression
is turned into the coverage the gate did not have: the listing stays visible
to a non-admin while the file input and the uninstall button do not, and an
admin sees both.

Full autobot-frontend suite after this fix: 297 files, 3408 passed, 1 skipped,
0 failed, in 149s -- run in the worktree.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

retire useSettingsApi/SystemRepository/services-api.ts/CacheService.ts dead settings paths

1 participant