first commit
This commit is contained in:
commit
32a7ba8e8f
168 files changed
+123856
No files matched your search
@@ -0,0 +1,329 @@
|
||||
# Validation report — revision 5 working copy
|
||||
|
||||
Date: **28 October 2026**. This section applies to the revision 5 changes only; the
|
||||
older revision 4 and revision 3 results below remain historical evidence for their
|
||||
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` |
|
||||
| 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 |
|
||||
| Physical SwitchOS device | **NOT TESTED** | Requires the user's device/firmware for final acceptance |
|
||||
|
||||
The revision 5 patch changes SwitchOS authentication/probing, settings layout, and
|
||||
RSC diff payload/rendering. Digest handling now accepts a changed nonce/challenge for
|
||||
`/backup.swb` after homepage authentication and re-signs redirects for their final URI.
|
||||
A physical-device check remains required to confirm the original 502 scenario is
|
||||
resolved on the affected firmware.
|
||||
|
||||
---
|
||||
|
||||
# Validation report — 0.0.1, revision 4
|
||||
|
||||
Date: **27 October 2026**. This report separates completed revision 4 verification
|
||||
from historical results. Historical checks are explicitly labeled and are not
|
||||
presented as newly executed revision 4 checks.
|
||||
|
||||
The distribution contains **source only**: Rust code, `Cargo.lock`, interface sources,
|
||||
tests, and the patched library under `vendor/`. It does not ship an executable or
|
||||
`bin/`, `target/`, or `storage/` directories. The input archives contained no production
|
||||
database or device credentials.
|
||||
|
||||
## Current revision 4 results
|
||||
|
||||
Revision 4 replaces automatic schema/data/layout conversion with fresh initialization
|
||||
and an explicit Python importer. It also embeds API documentation directly from
|
||||
checked-in input files and translates project documentation into English.
|
||||
|
||||
| Area | Result | Evidence and scope |
|
||||
| --- | --- | --- |
|
||||
| Rust dev/test build and suite | **111/111 PASS** | 95 unit tests, 11 API contract tests, 3 import-launcher tests, and 2 OpenAPI tests; no failures or skipped tests |
|
||||
| Fresh installation and incompatible database | **PASS** | Fresh schema creation and restart; old/foreign/empty existing databases rejected without conversion or backup relocation |
|
||||
| Explicit Python importer | **PASS** | Unit regressions plus six actual CLI/HTTP acceptance scenarios; source selection, unchanged originals, preserved records/files, and refusal to overwrite a destination |
|
||||
| Import launcher | **3/3 PASS** | Validation before build, argument/path preservation including spaces and CDPATH, and import failure propagation |
|
||||
| Source launchers and ignore rules | **16/16 PASS** | Isolated Cargo/Docker stubs, build-before-start, errors, arguments, working directories, target-directory overrides, and private/generated file exclusions |
|
||||
| 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 |
|
||||
| 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 |
|
||||
| Release executable build | Not performed for revision 4 | The deployment launcher builds release source on the target host |
|
||||
| Docker / systemd execution | Not performed for revision 4 | No container or service-manager execution result claimed |
|
||||
|
||||
The actual import acceptance run used a generated database matching the supplied
|
||||
Python SQLAlchemy models and the original Compose directory layout. Its Passlib
|
||||
PBKDF2-SHA256 password hash was generated independently with Python's standard
|
||||
library. The run verified:
|
||||
|
||||
1. Startup rejects that original database without changing any source file or
|
||||
moving a backup.
|
||||
2. Explicit import discovers the Compose database and creates a separate target;
|
||||
it neither executes nor copies the source `.env`.
|
||||
3. IDs, ownership, password hashes, database secrets, logs, filenames, checksums,
|
||||
and every backup's bytes are preserved in the current schema and layout.
|
||||
4. A second import refuses the existing target without overwriting it.
|
||||
5. The imported account can sign in and download all three fixture backups after
|
||||
the first start and a subsequent restart.
|
||||
6. Ordinary startup in another fresh directory creates an empty installation,
|
||||
without importing the nearby Python data.
|
||||
|
||||
Unit regressions additionally retain committed WAL data with an existing or
|
||||
missing source SHM file, compare source sidecar bytes before/after import, reject
|
||||
ambiguous or overlapping paths, and verify validation precedes secret/lock writes.
|
||||
No production database was used. Filesystem interruption and synchronization
|
||||
failures remain subject to the explicit cleanup limits in [data-import.md](data-import.md).
|
||||
|
||||
The browser run executed public `/health` and an authenticated device-list request
|
||||
through the actual English Swagger UI. All documentation assets stayed on the
|
||||
same origin, with no JavaScript or CSP errors. The build/profile check and tests
|
||||
ran with the old generated documentation files removed; the updated documentation
|
||||
handler embeds checked-in input files directly.
|
||||
|
||||
Evidence is recorded in `revision4-release-check.log`, `revision4-rust-tests.log`,
|
||||
`revision4-clippy.log`, `revision4-format.log`, `revision4-ui-core.log`,
|
||||
`revision4-live-import.json`, `revision4-live-switchos.json`, `revision4-ui-live.log`,
|
||||
`revision4-source-start-checks.json`, and `revision4-vendor-verification.json`.
|
||||
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.
|
||||
|
||||
## Historical revision 3 results
|
||||
|
||||
Revision 3 used actual dev/test builds with Rust 1.99.1, edition 2024. It did not run
|
||||
a revision 3 release build, Docker container, or physical MikroTik acceptance test.
|
||||
|
||||
| Area | Historical revision 3 result | Scope and method |
|
||||
| --- | --- | --- |
|
||||
| Dev/test compilation | PASS | Actual application and test compilation with Rust 1.99.1, edition 2024 |
|
||||
| Rust unit tests | **91/91 PASS** | Data, then-current migrations, security, files, diff, cron, adapters, and notifications |
|
||||
| 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 |
|
||||
| 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` |
|
||||
| Chromium + actual Rust, Swagger UI, and SwOS | **8/8 PASS** | Browser, running backend, SQLite, and an independent local HTTP Digest SwOS fixture |
|
||||
| Chromium + actual Rust navigation | **PASS** | Eight routes, old-route redirects, responsiveness, CSP, no API/JS errors, and sign-out |
|
||||
| Vendored integrity recheck | **PASS** | All **91 entries** in `vendor/libssh2-sys/SHA256SUMS` and **5 Swagger UI files** matched; `Cargo.lock` unchanged |
|
||||
| Revision 3 release build | Not performed | The deployment launcher builds release on the target host |
|
||||
| Revision 3 Docker execution | Not performed | No image/container execution result established |
|
||||
|
||||
These results were recorded in `revision3-rust-tests.log`, `revision3-ui-core.log`,
|
||||
`revision3-ui-workflow.log`, `revision3-ui-live.log`, `revision3-live-switchos.json`,
|
||||
`revision3-clippy.log`, `revision3-format.log`, and
|
||||
`revision3-vendor-verification.json` in the acceptance tooling directory. These are
|
||||
verification-environment logs, not files promised as part of the source archive.
|
||||
The Rust and JavaScript test sources are included in the project.
|
||||
|
||||
### Historical migration, file, and concurrency checks
|
||||
|
||||
**The automatic migration behavior in this subsection belonged to revision 3 and
|
||||
has been removed in revision 4.** It is retained here only to identify the scope of
|
||||
the historical 91-unit-test result.
|
||||
|
||||
Those tests preserved IDs, ownership, password hashes, settings, and secrets while
|
||||
upgrading old schemas. Migration 002 kept
|
||||
`use_global_switchos_credentials = null` for existing devices. Migration 003 added
|
||||
a persistent backup-layout journal. Fresh backups, imports, and startup conversions
|
||||
used `DATA_DIR/backups/binary/<router_id>/` and
|
||||
`DATA_DIR/backups/exports/<router_id>/`; renaming a device did not change the directory
|
||||
ID, and the original `file_name` was preserved.
|
||||
|
||||
Checks covered a database snapshot before path changes, file copying before metadata
|
||||
transactions, SHA-256, and idempotent restart. Fault cases interrupted the logical
|
||||
process after plan persistence, after verified copying, and between file publication
|
||||
and journal acknowledgement. Restart did not overwrite unrelated files, even with
|
||||
identical bytes. Missing/modified sources, corrupted copies, tampered journal paths,
|
||||
and snapshot symlinks prevented partial activation of changed records.
|
||||
|
||||
Separate cases covered source-preserving import, target conflicts, storage/database
|
||||
locks, symlinks outside the selected source, and a dangling destination database
|
||||
symlink. **Sixteen threads** concurrently created initial device/type directories;
|
||||
a directory encountered after a race was checked again for symlinks.
|
||||
|
||||
Retention and deletion operated on active files and preserved originals retained by
|
||||
that revision, even if the newer active copy was absent. Tests forced both a SQLite
|
||||
DELETE rejection and a failed compensating rename; the remaining copy had to survive
|
||||
as a recovery file. Code review also examined directory synchronization after imported
|
||||
database publication and backup preservation following a later failure. No final
|
||||
fsync failure, physical power loss, or storage hardware failure was injected.
|
||||
|
||||
Revision 4 uses a new destination and an explicit import instead of this startup
|
||||
conversion mechanism. Historical results do not validate the replacement until its
|
||||
own checks have completed.
|
||||
|
||||
### Historical credentials, SwOS adapter, and HTTP contract checks
|
||||
|
||||
Revision 3 API tests covered all three SwitchOS credential modes: a complete global
|
||||
pair, a complete local pair, and legacy field-by-field fallback. Cases included
|
||||
creation, partial PUT, ordinary saves that preserve legacy semantics, global changes
|
||||
without rewriting device records, and returning from global mode to local mode
|
||||
without losing the stored password. They verified no implicit fallback in explicit
|
||||
modes, a clear missing-username error, empty-password support, and masked responses.
|
||||
|
||||
Adapter tests used **local HTTP servers with controlled responses**. They covered
|
||||
Digest, Basic, and authentication retries when a public HTML page did not return a
|
||||
401 challenge. Checks included the correct system and backup endpoints, the Digest
|
||||
request URI, a global credential pair, explicit URL ports, and actual response-byte
|
||||
transfer and validation. HTML/login pages could neither be saved as backups nor
|
||||
produce a positive availability result. A missing endpoint could not be replaced
|
||||
with a public homepage; redirects did not forward credentials; the timeout covered
|
||||
the whole operation. These were adapter/protocol tests, not hardware acceptance for
|
||||
a particular SwOS model.
|
||||
|
||||
Other repeated cases covered authorization, ownership, JSON/form login, preferences,
|
||||
password changes, and the bounded password-operation pool. Independent fixtures
|
||||
verified Passlib/Werkzeug passwords and HS256 compatibility, invalid `exp`/`nbf`
|
||||
rejection, secret preservation/clearing, download bytes, RSC previews, and ZIP.
|
||||
Unified diff passed **32 Python difflib fixtures**. Local SMTP and Pushover tests did
|
||||
not send to production recipients; the SMTP fixture did not establish STARTTLS
|
||||
compatibility with an external provider.
|
||||
|
||||
The two documentation tests covered all **36 API operations**, actual route coverage,
|
||||
a custom prefix, and documentation assets served without a CDN. A completed Chromium
|
||||
run against an actual Rust process loaded all 36 operations, executed public
|
||||
`/health`, signed in through **Authorize**, and fetched an authenticated device list.
|
||||
There were no external-server requests, JavaScript errors, or CSP violations.
|
||||
|
||||
That same run created a SwitchOS device through the form using global credentials
|
||||
without copying secrets into the device. The connection test and backup used Digest
|
||||
with a `/sys.b` challenge and the correct `/backup.swb` URI. Downloaded bytes, SHA-256,
|
||||
and `backups/binary/<router_id>/` were checked, including valid bytes mislabeled
|
||||
`text/html`. Rotating the global username/password took effect without editing the
|
||||
device. Actual HTML was rejected with HTTP 502, no backup record was added, and the
|
||||
connection test did not report availability. The fixture device, backups, and global
|
||||
test credentials were removed afterward.
|
||||
|
||||
### Historical revision 3 interface checks
|
||||
|
||||
The mocked-API Chromium workflow made **113 requests**. It covered login and
|
||||
registration, device forms, secret preservation, the global → local → global → local
|
||||
sequence, saving legacy `null` mode, downloads, binary upload, and bulk deletion.
|
||||
It checked RSC-only diff actions, hidden SwitchOS export/unsupported actions,
|
||||
toast errors, log filters, preferences, and password changes through the form.
|
||||
|
||||
Checks also covered flat daily/weekly/custom automation controls, old-route redirects,
|
||||
responsive layout, themes, escaping, and sign-out. A separate actual-Rust run visited
|
||||
`/devices`, `/files`, `/diff-configs`, `/logs`, `/settings`, `/schedule`,
|
||||
`/change-password`, and `/`. It confirmed the automation and account redirects,
|
||||
the flat automation layout, a mobile view without horizontal page scrolling, and
|
||||
sign-out. Neither workflow had JavaScript errors; the live-server run also had no
|
||||
API or CSP errors.
|
||||
|
||||
## Historical revision 2 checks
|
||||
|
||||
These separate runs are **not described as rerun in revision 3 or revision 4**.
|
||||
The ordinary test suite reran its included SSH unit tests during revision 3; the five
|
||||
scenarios below were a separate acceptance run with an actual application process.
|
||||
|
||||
| Area | Historical revision 2 result | Scope |
|
||||
| --- | --- | --- |
|
||||
| SSH trust over an actual local protocol | **5/5 PASS** | Default `accept-new`, repeated pin verification, changed-key rejection, invalid private key after host verification, and four concurrent first contacts |
|
||||
| Launchers and project rules | **16/16 PASS** | Bash with isolated Cargo/Docker substitutes; build-before-start, errors, arguments, paths with spaces, `CARGO_TARGET_DIR`, Compose, `.env`; 31 ignored paths and 25 retained source paths |
|
||||
| Chromium + actual Rust | PASS | Eight then-current routes, responsive layout, CSP, sign-out, password change through Settings, and signing in again |
|
||||
| RustSec audit | PASS | **270 dependencies, 0 reported vulnerabilities, 0 warnings**, no ignored advisories |
|
||||
| Vendor integrity | PASS | All **91 SHA256SUMS entries** matched |
|
||||
|
||||
Revision 3's `Cargo.lock` was unchanged from that audit. This does not mean the
|
||||
advisory database was fetched again or a new scan was performed. The historical scan
|
||||
and its metadata remain in [dependency-audit.json](dependency-audit.json) and
|
||||
[dependency-audit-metadata.json](dependency-audit-metadata.json).
|
||||
|
||||
SSH cases used loopback, generated test keys, and real handshake/authentication.
|
||||
Launcher checks used substitute CLIs; **they neither built release nor ran Docker**.
|
||||
|
||||
## Historical initial acceptance — before revision 2
|
||||
|
||||
Initial acceptance included a release build and actual local SSH/SFTP/SCP sessions
|
||||
emulating RouterOS responses. It covered password, own-key and global-key
|
||||
authentication, identity/resource, exports, binary backup, download, upload, SHA-256,
|
||||
and remote temporary-file cleanup. Truncated SCP, negative ACK, and nonzero final
|
||||
exit status were rejected. These runs are not new revision 3 or revision 4 tests.
|
||||
|
||||
A historical scheduler check removed a controlled expired file and its SQLite record.
|
||||
Other checks covered restart, persistence, `healthcheck`, `check-config`, rejecting
|
||||
a second instance, and SIGTERM during an incomplete request; SQLite reported
|
||||
`integrity_check = ok`. A separate libssh2 C test exercised short/oversized AES-GCM
|
||||
blocks and overflowing username lengths against earlier debug and release archives.
|
||||
Patch reproduction confirmed all seven modified C files matched.
|
||||
|
||||
At that time, the launcher could run a bundled executable without Cargo. **That path
|
||||
has been removed.** Current `start.sh` builds the source; the historical release
|
||||
artifact is not included in this source archive. Backport details are in
|
||||
[dependency-security.md](dependency-security.md).
|
||||
|
||||
## Limits and reproduction
|
||||
|
||||
- **Hardware and data:** no physical MikroTik or unavailable production database was
|
||||
tested. Local fixtures do not establish compatibility with every model/firmware.
|
||||
- **Network:** local SMTP/Pushover checks do not verify external provider accounts
|
||||
or STARTTLS. The ICMP test permits an explicit socket-permission failure; PASS
|
||||
alone does not prove an echo reply when the environment denied socket creation.
|
||||
- **Deployment:** no revision 4 release executable was linked or run, and Docker
|
||||
and systemd were not executed. The release-profile check, dev/test compilation,
|
||||
and live debug-server acceptance are separate completed checks.
|
||||
- **Dependency security:** the historical RustSec result applies to a specific
|
||||
advisory set, date, and lockfile, not every possible vulnerability. System
|
||||
OpenSSL, zlib, and glibc updates and new advisories remain relevant.
|
||||
|
||||
To reproduce local verification gates:
|
||||
|
||||
```bash
|
||||
cargo fmt --package mikrotik-backup -- --check
|
||||
cargo clippy --all-targets --locked -- -D warnings
|
||||
cargo test --locked
|
||||
cargo check --release --locked
|
||||
node web/tests/core.test.cjs
|
||||
```
|
||||
|
||||
Run `cargo audit --file Cargo.lock --json` for a new dependency scan. Running
|
||||
`./start.sh` builds release and starts the application on the deployment host.
|
||||
`cargo check --release` checks the release profile but does not produce a tested
|
||||
release executable. These commands are instructions, not additional recorded passes.
|
||||
[ui.md](ui.md) describes browser checks. Fixture servers and acceptance tools are
|
||||
not required for normal application operation.
|
||||
## Revision 6 targeted SwitchOS change
|
||||
|
||||
The source adds a regression fixture for a SwitchOS server that sends a Digest
|
||||
challenge together with `Set-Cookie` and returns an HTML login page if the cookie is
|
||||
missing from the authenticated `/backup.swb` retry. The adapter now preserves that
|
||||
cookie, drains the challenge response before retrying, forces HTTP/1.x, and starts the
|
||||
backup request with fresh authentication state.
|
||||
|
||||
The current execution environment does not contain `cargo`, `rustc`, or `rustfmt`, so
|
||||
the Rust test suite and compiler checks were **not executed for revision 6 here**. The
|
||||
new test is included for execution on the build/deployment host with `cargo test --locked`.
|
||||
|
||||
|
||||
## Revision 7 targeted UI, diff, container, and importer review
|
||||
|
||||
The browser diff now requests a compact JSON response that omits the duplicated unified
|
||||
text and HTML documents. The UI renders at most 200 structured rows per page, filters
|
||||
before rendering, and fetches the full unified `.diff` text only when the user explicitly
|
||||
downloads it. Semantic RSC analysis is included alongside the line diff; it ignores
|
||||
comments/export metadata and command ordering, groups changes by RouterOS section,
|
||||
pairs recognizable commands, and flags selected security/network/service sections.
|
||||
|
||||
Current JavaScript verification in the patch environment:
|
||||
|
||||
- `node --test web/tests/core.test.cjs`: **16/16 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.
|
||||
- Docker build/runtime: **NOT RUN** because the Docker CLI/daemon is unavailable.
|
||||
|
||||
The supplied Python/TypeScript SQLAlchemy models were compared with `src/schema.sql`.
|
||||
All legacy columns in `users`, `routers`, `backups`, `operation_logs`, and
|
||||
`global_settings` are represented in the Rust schema; the Rust `routers` table adds
|
||||
`use_global_switchos_credentials`. The importer copies supported source columns into
|
||||
a new target, validates referenced backup files and recorded checksums, and publishes
|
||||
the database last. No production database was supplied, so this is a source/schema
|
||||
review plus existing importer regression coverage, not a production-data migration run.
|
||||
Reference in new issue
Block a user