From f0176efd955a1299a7f8efe6dc4d7f954491f450 Mon Sep 17 00:00:00 2001 From: 2GT-Rich <107219997+2GT-Rich@users.noreply.github.com> Date: Wed, 29 Jul 2026 15:38:08 -0700 Subject: [PATCH] fix(config-history): only auto-snapshot devices with SSH configured; add settings UI (v0.17.4-beta) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resolves #86 — MikroTik Manager was attempting SSH connections to devices that have no SSH credentials configured, flooding RouterOS logs with failed logins. Cause: config snapshots (a separate feature from scheduled backups, enabled by default, hourly) capture `/export` over SSH via BackupService.exportConfig, which silently falls back to the API credentials for the SSH login. On devices where SSH was never set up, that auth fails every interval (and on each restart), and there was no UI switch to turn it off. - PollerService.processConfigSnapJob now skips devices without SSH credentials, so no SSH connection is attempted where SSH isn't configured. Manual "Capture snapshot" / backup actions are unchanged (user-initiated, with error feedback). - Add a "Configuration Snapshots" section to Settings → General: enable toggle, interval, and retention (the feature was on-by-default with no UI control), with a note that it runs over SSH and only on devices that have SSH creds. Co-Authored-By: Claude Opus 4.8 --- README.md | 2 +- backend/package.json | 2 +- backend/src/services/PollerService.ts | 6 +++ frontend/package.json | 2 +- frontend/src/pages/SettingsPage.tsx | 58 +++++++++++++++++++++++++++ frontend/src/version.ts | 2 +- 6 files changed, 68 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 97b467e..7be65d3 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ A self-hosted, full-stack network management platform for MikroTik devices. Monitor, configure, and manage your entire MikroTik infrastructure — routers, switches, and wireless access points — from a single web interface. -![Version](https://img.shields.io/badge/version-0.17.3_Beta-blue) +![Version](https://img.shields.io/badge/version-0.17.4_Beta-blue) ![License](https://img.shields.io/badge/license-AGPLv3-blue) ![Docker](https://img.shields.io/badge/docker-compose-2496ED?logo=docker&logoColor=white) ![TypeScript](https://img.shields.io/badge/TypeScript-5.3-3178C6?logo=typescript&logoColor=white) diff --git a/backend/package.json b/backend/package.json index 3394b0c..da499b2 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "mikrotik-manager-backend", - "version": "0.17.3-beta", + "version": "0.17.4-beta", "description": "Mikrotik Network Management Platform - Backend API", "main": "dist/index.js", "scripts": { diff --git a/backend/src/services/PollerService.ts b/backend/src/services/PollerService.ts index 8ea54b0..ed74da6 100644 --- a/backend/src/services/PollerService.ts +++ b/backend/src/services/PollerService.ts @@ -691,6 +691,12 @@ export class PollerService { const device = await this.getDevice(data.deviceId); if (!device) return; + // Config snapshots capture `/export` over SSH. Only attempt this automatically + // when SSH credentials are actually configured — otherwise we'd repeatedly try + // (and fail) SSH auth using the API credentials, flooding the device logs on + // devices where SSH was never set up. Manual "Capture snapshot" is unaffected. + if (!device.ssh_username || !device.ssh_password_encrypted) return; + const collector = new DeviceCollector(device); try { await collector.connect(); diff --git a/frontend/package.json b/frontend/package.json index 0af62b7..0986947 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "mikrotik-manager-frontend", - "version": "0.17.3-beta", + "version": "0.17.4-beta", "private": true, "type": "module", "scripts": { diff --git a/frontend/src/pages/SettingsPage.tsx b/frontend/src/pages/SettingsPage.tsx index 1cf23bd..5434b5c 100644 --- a/frontend/src/pages/SettingsPage.tsx +++ b/frontend/src/pages/SettingsPage.tsx @@ -667,6 +667,64 @@ export default function SettingsPage() { + {/* Configuration Snapshots */} +
+

Configuration Snapshots

+

+ Periodically captures each device's /export for the Config History / drift detection feature. + This runs over SSH, so it only executes on devices that have SSH credentials configured — devices without them are skipped (no connection is attempted). +

+
+
+
Enable config snapshots
+ +
+
+
+
Snapshot interval
+
minutes
+
+ updateSettingsMutation.mutate({ config_snapshot_interval_min: parseInt(e.target.value) })} + min="15" + step="15" + disabled={!isAdmin || settings['config_snapshot_enabled'] === false} + /> +
+
+
+
Retention
+
snapshots kept per device
+
+ updateSettingsMutation.mutate({ config_snapshot_retention: parseInt(e.target.value) })} + min="1" + step="1" + disabled={!isAdmin || settings['config_snapshot_enabled'] === false} + /> +
+
+
+ {/* Reverse DNS */}

Reverse DNS Lookup

diff --git a/frontend/src/version.ts b/frontend/src/version.ts index 0f2cac6..2bfadc5 100644 --- a/frontend/src/version.ts +++ b/frontend/src/version.ts @@ -1 +1 @@ -export const APP_VERSION = 'v0.17.3 Beta'; +export const APP_VERSION = 'v0.17.4 Beta';