This commit is contained in:
Mateusz Gruszczyński committed 2026-10-28 14:55:35 +01:00
1 parent c7d09077fc
commit f813441bf0
45 files changed
+938 -334

No files matched your search

+1 -1
View File
@@ -1,4 +1,4 @@
THIRD-PARTY NOTICES — MikroTik Backup System 0.0.1
THIRD-PARTY NOTICES — MikroTik Backup System 0.0.2
Generated from the locked Cargo dependency graph for x86_64-unknown-linux-gnu.
This inventory includes build/test dependencies where they occur in that graph.
Original license and notice texts below are reproduced without alteration.
+1 -1
View File
@@ -1,4 +1,4 @@
# Interactive API documentation — 0.0.1
# Interactive API documentation — 0.0.2
## URLs
+2 -7
View File
@@ -1,4 +1,4 @@
# Architecture — release 0.0.1
# Architecture — release 0.0.2
## One process with explicit module boundaries
@@ -101,12 +101,7 @@ operation timeouts or the number of devices require a longer shutdown window.
## Fresh initialization and explicit import
`src/schema.sql` contains the complete current schema. If the database file does not
exist, startup creates a fresh database. If a database file exists, startup first
opens it read-only and validates that it already has the supported schema. An older
or unrelated schema is rejected with instructions to use a fresh installation and
explicit import. Startup does not run `ALTER TABLE`, create upgrade snapshots, add
migration journals, or move backup files.
`src/schema.sql` contains the complete current schema. If the database file does not exist, startup creates a fresh schema v2 database. If a database file exists, startup first validates a private read-only snapshot. Current schema v2 databases are accepted unchanged; the supported Rust 0.0.1 schema v1 is then upgraded transactionally to v2 after storage locking. Unsupported or unrelated schemas are rejected with instructions to use a fresh installation or explicit Python import. Startup schema migration does not move backup files.
The separate `import-python --source DIR [--database PATH] [--backup-root DIR]`
command imports into a new destination. The `import-python.sh` wrapper builds the
+6 -17
View File
@@ -1,8 +1,6 @@
# Fresh installation and explicit Python import
Version **0.0.1** starts with a clean installation. It does not update an old
schema or move existing backup files during startup. Importing data from the
Python/TypeScript application is a separate, explicit operation.
Version **0.0.2** initializes clean installations and automatically migrates the supported Rust 0.0.1 schema to the current schema at startup. It does not import or rewrite a Python/TypeScript installation automatically. Importing data from the Python/TypeScript application remains a separate, explicit operation.
## Choose one installation path
@@ -23,22 +21,13 @@ server**. Starting the server first creates a database, and the importer will
refuse to overwrite or merge it. Use a different new destination if a database
already exists; do not delete a database merely to bypass this check.
## Startup never upgrades an existing database
## Startup migration policy
Startup accepts an existing database only when it has the current `schema_info`
marker, supported format version, required tables and columns, valid integrity,
and the expected user/settings records. An older Python schema, an earlier Rust
work-in-progress schema, an unknown version, or a pre-existing empty database file
is rejected with instructions to select a fresh destination or use the explicit
Python importer. No `ALTER TABLE`, persistent pre-upgrade snapshot, migration
journal, automatic import, or backup relocation is performed.
Startup accepts the current schema and the supported Rust 0.0.1 schema. Before creating storage locks or secrets, the server performs a read-only preflight against a private temporary copy of the database, including committed WAL content.
Before creating storage locks or secrets, the server performs a read-only
preflight. SQLite inspects a private temporary copy of the database and its WAL
or rollback journal, so opening an incompatible database cannot create a source
`-shm` file. The temporary inspection copy is removed afterwards. The schema is
checked again while the server holds its storage locks. Existing current records
and file paths are left unchanged.
After storage locking, a Rust schema v1 database is upgraded transactionally to schema v2 by adding `default_routeros_username` and `default_routeros_password` and advancing `schema_info.schema_version`. The resulting schema is validated before the service starts. A current schema is left unchanged.
Python/TypeScript schemas, unsupported Rust work-in-progress schemas, unknown versions, and pre-existing empty database files are rejected. They are never imported automatically.
## Import command
+6 -10
View File
@@ -1,11 +1,10 @@
# Importing data from the Python/TypeScript release
# Data migration
The current release does not perform automatic data migration and does not expose the
old `migrate` command. The supported path is the explicit, copy-only
`import-python` command. See [data-import.md](data-import.md) for the full source
discovery, validation, rollback, and failure rules.
Version **0.0.2** performs automatic, transactional schema migration for supported Rust databases. A database created by Rust 0.0.1 uses schema v1; on startup 0.0.2 validates it, adds `default_routeros_username` and `default_routeros_password`, updates `schema_info.schema_version` to `2`, validates the resulting schema, and then starts the service. No manual `sqlite3` command is required.
For the standard layout of the supplied legacy project:
The automatic migration applies only to the supported Rust schema. It does not convert the previous Python/TypeScript application database. For that source, use the explicit, copy-only `import-python` command described in [data-import.md](data-import.md).
For the standard legacy Python layout:
```sh
DATA_DIR="$PWD/storage-imported" \
@@ -15,7 +14,4 @@ DATABASE_PATH="$PWD/storage-imported/routeros_backup_next.db" \
--backup-root docker-data
```
Stop the old application first. The destination directory must be new and must not
contain an existing database. The import preserves application records and copies
referenced backup files. It intentionally does not copy external environment secrets,
service-manager files, operating-system permissions, or external SSH host-trust files.
Stop the old Python/TypeScript application first. The import destination must be new and must not contain an existing database.
+2 -2
View File
@@ -1,7 +1,7 @@
# Dependency review — release 0.0.1
# Dependency review — release 0.0.2
The audit documented here was performed on **27 October 2026 for source revision 2**
of release 0.0.1. Its scope was `Cargo.lock`, known public advisories, and the C SSH
of release 0.0.2. Its scope was `Cargo.lock`, known public advisories, and the C SSH
library bundled through `libssh2-sys`. Revision 3 additionally verified the provenance
of local Swagger UI assets. These historical checks are not a claim that a new
advisory scan has been run for revision 4; see [the validation report](validation.md).
+1 -1
View File
@@ -1,6 +1,6 @@
# Import from the previous Python/TypeScript application
The Rust service does not perform automatic data migrations on startup. Use the explicit `import-python` command once, with the previous application stopped.
Rust-to-Rust schema migration is automatic for supported releases: 0.0.2 upgrades a 0.0.1 Rust database at startup. This document covers the separate Python/TypeScript import, which remains explicit. Use `import-python` once, with the previous application stopped.
## What is imported
+1 -1
View File
@@ -2,7 +2,7 @@
"openapi": "3.1.0",
"info": {
"title": "MikroTik Backup System",
"version": "0.0.1",
"version": "0.0.2",
"description": "Documentation for the live API. Use Authorize with your username and password or provide a Bearer token. Try it out performs real operations on the current instance. Registration is disabled by default. Accounts can access their own devices and backups; settings and logs are shared by operators."
},
"servers": [
+5 -10
View File
@@ -1,4 +1,4 @@
# Port coverage matrix — 0.0.1
# Port coverage matrix — 0.0.2
## Scope and source identity
@@ -86,9 +86,7 @@ contains `access_token`, `token_type=bearer`, and `user`.
## Models and source fields
Models are explicitly typed in `src/models.rs`. `src/db.rs` implements persistence,
current-schema validation, and explicit import. `src/schema.sql` is the complete
fresh-install schema. Revision 4 does not run incremental schema migrations at startup.
Models are explicitly typed in `src/models.rs`. `src/db.rs` implements persistence, current-schema validation, automatic migration of the supported Rust v1 schema, and explicit Python import. `src/schema.sql` is the complete fresh-install schema for schema v2.
| Model / group | Preserved or added fields | Notes |
| --- | --- | --- |
@@ -107,9 +105,9 @@ fresh-install schema. Revision 4 does not run incremental schema migrations at s
| StorageStats | `total`, `used`, `free`, `folder_used`, `usage_percent` | `usage_percent` measures the data directory against total disk capacity, matching the source. |
| Settings retention | `backup_retention_days`, `log_retention_days` | 0 means an age threshold of zero days, matching the original retention function; it does not disable cleanup. |
| Settings scheduling | `export_cron`, `binary_cron`, `retention_cron`, `enable_auto_export`, `connection_test_interval_minutes` | Five-field cron, configured timezone, Monday=0 as in APScheduler. |
| Settings device defaults | `global_ssh_key`, `default_switchos_username`, `default_switchos_password` | Revealing the global key requires password verification. |
| Settings device defaults | `global_ssh_key`, `default_routeros_username`, `default_routeros_password`, `default_switchos_username`, `default_switchos_password` | RouterOS user/password fall back to the global defaults when a device field is blank. Revealing the global key requires password verification. |
| Settings notifications | `pushover_token`, `pushover_userkey`, `notify_failures_only`, `smtp_host`, `smtp_port`, `smtp_login`, `smtp_password`, `smtp_notifications_enabled`, `recipient_email` | SMTP, attachments, Pushover, provider tests, and failures-only mode. |
| Settings DTO | `id`, `has_global_ssh_key`, `has_default_switchos_credentials` | Additional `has_smtp_password`, `has_pushover_token`, `has_pushover_userkey`, and `has_default_switchos_password` flags support editing masked secrets. |
| Settings DTO | `id`, `has_global_ssh_key`, `has_default_routeros_credentials`, `has_default_switchos_credentials` | Additional password/token presence flags support editing masked secrets without returning secret values. |
| Diff JSON | `left_backup_id`, `right_backup_id`, `left_file_name`, `right_file_name`, `diff_text`, `stats`, `lines` | Statistics: added/removed/modified/context. Lines: type, left_number/right_number, left_text/right_text. Standalone `diff_html` is generated only by the dedicated HTML endpoint to avoid duplicating large payloads in the browser response. |
| SchedulerStatus | `timezone`, `running`, `jobs` | Job fields: key, label, enabled, cron, description, description_params, valid, next_runs, error. |
@@ -193,10 +191,7 @@ deployment extensions.
- Empty cron expressions disable their schedules. Invalid expressions, invalid
ports, negative retention, and excessive request sizes are rejected. Jobs are
prevented from overlapping themselves.
- Revision 4 initializes only a fresh schema and validates an existing database
before use. There are no startup migrations or backup-layout conversions. Python
import is explicit, reads the source without modifying it, and requires a new
destination. See [data-import.md](data-import.md).
- Version 0.0.2 validates an existing Rust database before use and automatically upgrades supported schema v1 databases to schema v2 in a transaction. Python import remains explicit, reads the source without modifying it, and requires a new destination. See [data-import.md](data-import.md).
- Runtime is one Rust process with SQLite, scheduling, and an embedded interface.
Python, Node, Angular, and nginx are not required application processes.
+1 -1
View File
@@ -1,6 +1,6 @@
# Security and dependency notes
Version 0.0.1 is distributed as source and uses the dependency versions pinned in `Cargo.lock`.
Version 0.0.2 is distributed as source and uses the dependency versions pinned in `Cargo.lock`.
Key controls include:
+1 -1
View File
@@ -43,4 +43,4 @@ Do not treat an HTTP `200` login page as a valid backup.
## Scope
Version 0.0.1 downloads SwOS backups. It does not restore/upload a SwOS configuration or reboot a switch.
Version 0.0.2 downloads SwOS backups. It does not restore/upload a SwOS configuration or reboot a switch.
+1 -1
View File
@@ -1,4 +1,4 @@
# Interface — 0.0.1
# Interface — 0.0.2
The interface uses the application's real API. It does not populate sample devices,
simulate operation results, or present disconnected actions as working features.
+7 -7
View File
@@ -7,7 +7,8 @@ respective source revisions.
| Area | Current result | Scope |
| --- | --- | --- |
| JavaScript syntax | **PASS** | `node --check web/js/*.js` |
| JavaScript unit tests | **16/16 PASS** | `node web/tests/core.test.cjs` |
| JavaScript unit tests | **18/18 PASS** | `node web/tests/core.test.cjs` |
| SQLite schema migration | **PASS** | v1 fixture migrated to v2; existing SwitchOS credentials preserved; migrated `global_settings` column layout matches fresh schema |
| Rust compile/tests | **NOT RUN in this environment** | `cargo` / `rustc` are not installed in the available runtime; no current Rust pass is claimed |
| Browser smoke/live tests | **NOT RUN in this environment** | Playwright is not installed; the test files could not start |
| SwitchOS protocol comparison | **REVIEWED** | Compared directly with the supplied Python `SwosBetaService`; local `requests.HTTPDigestAuth` output was also checked for header formatting |
@@ -21,7 +22,7 @@ resolved on the affected firmware.
---
# Validation report — 0.0.1, revision 4
# Validation report — 0.0.2
Date: **27 October 2026**. This report separates completed revision 4 verification
from historical results. Historical checks are explicitly labeled and are not
@@ -48,7 +49,7 @@ checked-in input files and translates project documentation into English.
| API documentation embedding | **PASS** | `/docs`, `/openapi.json`, local versioned assets, matching content hashes, custom prefix, and English documentation |
| Release-profile check | **PASS** | `cargo check --release --locked --offline` after removing all six previous generated documentation files; no `OUT_DIR/docs.*` files recreated |
| Formatting and static analysis | **PASS** | Package-scoped formatting check and `cargo clippy --all-targets --locked --offline -- -D warnings` |
| JavaScript unit tests | **16/16 PASS** | Existing interface behavior, translations, forms, and credential-source controls |
| JavaScript unit tests | **18/18 PASS** | Existing interface behavior, translations, forms, and credential-source controls |
| Chromium with actual Rust and a SwOS fixture | **8/8 PASS** | Global credentials, backup bytes/layout, HTML rejection, English Swagger rendering, public requests, and OAuth-authorized requests |
| Chromium with actual Rust navigation | **PASS** | Eight routes, settings redirects, responsive layout, CSP, no API/JavaScript errors, and sign-out |
| Dependency integrity | **PASS** | All 91 libssh2 checksum entries and 5 Swagger UI assets verified; Cargo.lock unchanged from the documented historical audit |
@@ -91,8 +92,7 @@ Evidence is recorded in `revision4-release-check.log`, `revision4-rust-tests.log
These are acceptance-environment reports, not files promised in the source archive.
The project contains the Rust, launcher, and interface regression tests.
The installation sequence is documented in [data-import.md](data-import.md).
There is no automatic upgrade, startup conversion, or migration recovery framework.
The installation sequence is documented in [data-import.md](data-import.md). Version 0.0.2 adds automatic transactional migration from the supported Rust schema v1 to v2. Python/TypeScript conversion remains an explicit import.
## Historical revision 3 results
@@ -106,7 +106,7 @@ a revision 3 release build, Docker container, or physical MikroTik acceptance te
| HTTP contract tests | **11/11 PASS** | Actual Axum router and SQLite, authorization, file operations, and SwitchOS credential-source modes |
| OpenAPI/documentation tests | **2/2 PASS** | All 36 operations, route/custom-prefix compatibility, and local Swagger assets without a CDN |
| Total Rust tests | **104/104 PASS** | 91 unit + 11 API + 2 OpenAPI; zero failures or skipped tests |
| JavaScript tests | **16/16 PASS** | UI logic, forms, schedules, translations, and interface regressions |
| JavaScript tests | **18/18 PASS** | UI logic, forms, schedules, translations, and interface regressions |
| Chromium workflow with controlled API | PASS | **113 requests** to a local fixture API, full interface workflow, no JavaScript errors |
| Final formatting | **PASS** | `cargo fmt --package mikrotik-backup -- --check` |
| Final Rust static analysis | **PASS** | `cargo clippy --all-targets --locked -- -D warnings` |
@@ -314,7 +314,7 @@ pairs recognizable commands, and flags selected security/network/service section
Current JavaScript verification in the patch environment:
- `node --test web/tests/core.test.cjs`: **16/16 PASS**.
- `node --test web/tests/core.test.cjs`: **18/18 PASS**.
- `node --check web/js/*.js`: **PASS**.
- Playwright browser acceptance: **NOT RUN** because the Playwright Node module is not installed.
- Rust compiler/tests: **NOT RUN** because `cargo` and `rustc` are unavailable.