Releases: AurevionSec/openSylab
Release list
OpenSylab v1.1.0 — UX overhaul + hardening
OpenSylab v1.1.0 — post-1.0 hardening + a full UX overhaul + an outward-presentation pass.
Post-1.0 hardening, a full UX overhaul, and an outward-presentation pass. Backed by
multi-agent audits (a 28-finding bug/inconsistency audit, a ~82-finding UX survey,
and a presentation review). 236 backend + 46 frontend + 8 E2E tests, all green in CI.
Added
- Toast notifications on every create / update / delete (writes are no longer silent).
- Read-only detail view (
DetailModal) reachable by every role, including VIEWER. - Responsive sidebar drawer — off-canvas navigation with a hamburger on small screens.
- URL-persisted filters & pagination on all list pages (deep-linkable, back-button-safe).
- Cross-entity navigation — Sample ↔ Order ↔ Result IDs are now links.
- Shared
StatusBadge(rectangular tags) and auseModalA11yfocus-trap hook. - Playwright end-to-end suite (8 tests: login, navigation, API read, mobile drawer) wired into CI.
CITATION.cffand a branded social-preview card.
Changed
- Activated the design-token layer — the project runs Tailwind v4, which ignored
tailwind.config.js; a v4@themeblock now makes the Neo-Clinical palette and the
JetBrains Mono data font actually render. - Accessibility — focus-trapped modals with Esc/restore,
aria-liveerror/status
regions, a skip-to-content link,aria-currentnavigation, associated form labels. - Flat surfaces (borders instead of shadows) per the design language.
- README rewritten — English-only, ISO 15189 wording tightened to "-oriented", a
Scope & limitations disclaimer, live CI/release badges, Docker-first quick start. - Docs de-staled — correct Docker ports, current versions, complete env-var tables,
fixed dead links; newdocs/README.mdindex. Fresh 1.0 screenshots.
Fixed
- Concurrency (critical): serialize the shared SQLite connection with a recursive
mutex +busy_timeout— concurrent request threads could otherwise collide on
transactions and corrupt the audit hash chain. - RBAC: sample → VALIDATED release now requires ADMIN (matching order/result); the
JWT effective role is derived from the live DB user, so role changes apply immediately. - Audit trail: HL7/FHIR exports now log PHI disclosure;
logAuditfails closed
instead of writing a chain-breaking row on HMAC failure. - Data integrity: CSV result import no longer mis-splits quoted fields or coerces
malformed reference bounds to0.0; NaN/inf values are no longer flagged NORMAL; the
result-edit modal recomputes the flag when the value/range changes. - Frontend: user roles normalized (fixes blank badges + an edit-dropdown privilege
hazard); LOGIN_FAILED shown in the audit log; global search routes orders/results
correctly; a stale token no longer blocks login; list-refetch races guarded; fixed the
Tailwind-v4 modal-backdrop regression.
Security
- Externalize Docker Compose secrets to an untracked
.env; fix the Dockerfile
healthcheck; untrack the.vitebuild cache and debug HTML.
Assets
OpenSylab-linux-x86_64— prebuilt backend binary (Linux x86-64, dynamically linked; needs OpenSSL 3.x + SQLite3 at runtime).sbom-frontend.cdx.json— CycloneDX SBOM of the frontend npm dependencies (383 components).sbom-repo.cdx.json— CycloneDX SBOM of the repository / backend dependencies (via Trivy).SHA256SUMS— checksums; verify withsha256sum -c SHA256SUMS.
Docker: git clone … && cp .env.example .env && docker compose up -d → http://localhost:9090 (admin/admin, change immediately).
See the CHANGELOG and docs.
OpenSylab v1.0.0
First 1.0 release of OpenSylab — an open-source, ISO 15189-oriented LIMS for medical diagnostics (C++17 backend + React 19 / TypeScript frontend, MIT).
This release consolidates the post-0.9.0 hardening, governance, architecture, and test work.
Highlights
🔒 Security
- Resolved all open Dependabot (11) and CodeQL (3) alerts;
npm auditclean. - Least-privilege CI permissions; PBKDF2-HMAC-SHA256 in the test-data generator.
🏗️ Architecture
ApiServer.cppGod-function decomposition (Phase A):ApiRouter::handleRequestreduced from 2781 → 440 lines by extracting every inline route into a dedicated per-route handler method via a sharedRouteContext. All ~30 routes (health/openapi, audit, stats, HL7/FHIR, MFA, users, samples/orders/results × GET/POST/PUT/DELETE). Behaviour-preserving, independently reviewed.
📋 Governance & Ops
SECURITY.md,CONTRIBUTING.md,CODE_OF_CONDUCT.md, issue/PR templates.docs/SECRET_ROTATION.md— JWT secret-rotation runbook (with the audit-HMAC-key caveat).
✅ Tests
- 235 unit tests, including new API-layer regression coverage for the ISO 15189 compliance branches (immutability 409, invalid status-transition 409, ADMIN-only VALIDATE 403, delete guards).
Notes
- Default credentials
admin/adminare for development only — change in production. - Configure TLS (
--tls-cert/--tls-key/--force-https) and setOPENSYLAB_JWT_SECRET+OPENSYLAB_AUDIT_HMAC_KEY(≥32 chars) for production.
Full changelog: CHANGELOG.md
v0.9.0 — Architecture Modernization + Security Hardening
v0.9.0 — Architecture Modernization + Security Hardening
Architecture
- nlohmann/json v3.11.3 via FetchContent — replaced hand-rolled JSON parser throughout the API layer
- spdlog v1.14.1 structured logging —
LOG_*macros, JSON output, rotating file sink IDatabaseinterface — pure virtual interface decouples API layer from SQLite implementation- PostgreSQLDatabase stub — implements
IDatabase; production support in v1.1 - Database migration framework —
schema_migrationstable, 3 versioned migrations, runs automatically on startup - OpenAPI 3.0 specification —
docs/openapi.yaml(23 paths), served unauthenticated atGET /api/v1/openapi.yaml - Configuration file —
opensylab.confINI format with 11 settings, search order:--config→ env var → cwd →/etc/opensylab/
Security
- HMAC-SHA256 audit hash chain — mandatory
OPENSYLAB_AUDIT_HMAC_KEY(≥32 chars, hard-fail at startup); tamper-evident chain across all audit entries GET /api/v1/audit/verify— ADMIN-only endpoint returns first broken chain entry on integrity failure- TOTP Base32 enrollment —
POST /auth/mfa/enroll,POST /auth/mfa/verify-enrollment,DELETE /auth/mfa
Bug Fixes (Waves 33–36, 28 confirmed bugs)
iat < pwChangedAt(was<=) — tokens issued before password change are now correctly invalidatedLOGIN_FAILEDaudit action type — failed logins were incorrectly logged asUPDATE- Logout persists to DB first — eliminates crash-window token replay
- TOTP time-step
int64_t— prevents Y2038 integer overflow verifyUserMfanow usesverifyAndConsumeMfaCode— TOTP anti-replay was not enforced in CLI path- HL7/FHIR import endpoints were unreachable — fell into JSON parse block and returned 400/404
Content-Type: application/jsonenforced on all POST/PUT (HTTP 415 if absent)- Negative
Content-Lengthbypass closed (TLS and plain HTTP paths) - Body size capped at 10 MB when
Content-Lengthheader is absent VALIDATEDorder status now requires ADMIN role (OPERATOR could previously set it)- Future
registration_daterejected in API handlers,updateSample, and CSV import createSamplesBatchusesINSERT OR IGNORE— duplicates no longer abort the whole batch; each rejected duplicate gets an ISO 15189 audit entryVALIDATED/REJECTEDTestResult terminal state enforced in CLI edit and validate flows- HL7/FHIR result count capped at 10 000 per import
- CSV
sample_id/patient_idlength enforced (64 chars); result fields enforced (255 chars) - CSV
validateHeaderaccepts extra trailing columns - Logout DB expiry uses token
expclaim instead ofnow + expirationMinutes - Audit chain anchor preserved after retention purge;
verifyAuditChainusesBEGIN DEFERREDfor snapshot isolation
Frontend
- Vitest v2.1.9 + React Testing Library — 46 unit tests (AuthContext, API client, utilities, Login component)
ErrorBoundarycomponent
Test Coverage
228/228 backend unit tests passing. Build: 0 errors, 0 warnings (GCC + Clang).
v0.8.2 — Test-Regression-Fix & Docs
Fehlerbehebungen (Tests & Validierung)
- isValidStatusString / isValidPriorityString: Neue Validierungsmethoden für
SampleundOrder— entkoppeln Input-Validierung von DB-Deserialisierungs-Fallback-Logik - ApiServer.cpp: Query-Parameter-Validierung (
?status=,?priority=) nutzt jetztisValidStatusString/isValidPriorityStringstatt try/catch — verhindert Regression durch Safe-Fallback (bughunt-43) - CsvImport.cpp: Status-Validierung beim CSV-Import prüft via
isValidStatusString— korrumpierter Status erzeugt wieder Fehlermeldung - test_api.cpp:
SerializeResultJson-Assertion an String-Format vonorder_idangepasst - Alle 181 Tests grün (vorher: 177/181)
Dokumentation
- frontend/README.md: Veraltete v0.6.0/v0.6+-Annotationen entfernt, Version auf 0.8.2 aktualisiert
- README.md: Badges auf v0.8.2 / 181 passing aktualisiert
- TODO.md: Aktuelle Version auf v0.8.2, Nächste Version v0.9.0
v0.8.1 — Bug-Hunt & Security Hardening
OpenSylab v0.8.1
Bug-Hunt & Security Hardening — 30+ Fixes, 12 Review-Iterationen, 3 aufeinanderfolgende saubere Passes.
Sicherheit
isApiKeyValidthread-safe refactoriert (optional<string>statt Shared-State)- Rate-Limiter Bypass geschlossen: Query-Strings (
?foo) umgingen/auth/login-Limit - RBAC-Reihenfolge korrigiert: Auth-Check vor JSON-Parse auf User-Routen
verifyPasswordgehärtet: Exception-Handling fürstoi, Iterations-Schranke, Salt-Guardbase64Encode: Integer-Overflow durch implizite Promotion behoben
Backend-Fixes
bindAndListen(): FD-Leak auf Fehlerpfaden geschlossen~ApiServer: Destruktor ergänzt,running_=falsevor Socket-ClosecreateSample:updated_at=0Bug behoben — wird jetzt viastd::time()gebundenevaluateFlag(): Floating-Point-Gleichheitsvergleich entferntstringToStatus/Flag/Priority: Throws durch sichere Fallback-Werte ersetzt- Audit-Export: Tmp-File-Leak + Kollisionsschutz via PID + Sequenz-Zähler
Frontend-Fixes
- Sidebar-Logout navigiert sofort zu
/login AuditLog:cancelRefRace-Condition behoben- Import:
csvError-State (TypeScript-Compilefehler), 5-MB-Guard +reader.onerrorfür alle 3 Import-Typen ResultCreateModal: Auto-Flag überschreibt manuelle Auswahl nicht mehr
Tests & Build
- Doppelte Makrodefinitionen in
test_runner.cppentfernt - HL7/FHIR-Tests nutzen
uniqueDbPath()statt hardcodierten Namen CMakeLists.txt:version.hins Build-Tree, nicht Source-Tree
Dokumentation
README.mdvollständig neu geschrieben: 10 Screenshot-Platzhalter mit Aufnahme-Anweisungen, aktualisierte Feature-Tabellen, API-ÜbersichtCHANGELOG.md: v0.8.1-Eintrag ergänzt
Checksums & Build:
- 75 Unit-Tests passing
- TypeScript strict: 0 Errors
- C++17, CMake 3.15+, OpenSSL, SQLite3
OpenSylab v0.8.0 — Production-Ready Security & Infrastructure
OpenSylab v0.8.0
22 of 28 v0.8 TODO items completed — focused on production-readiness.
Security (P0) — All 5 items completed
- Health endpoint
GET /api/v1/health(unauthenticated) - Rate limiting on
/api/v1/auth/login(10 req/60s per IP, HTTP 429) - Forced password change on first login with
admin/admin --force-https+--tls-cert/--tls-keyflags- API key RBAC hardened (role column, no more hardcoded OPERATOR)
Core Features (P1) — 4 of 8 items
- HL7 v2.5.1 HTTP endpoints:
POST /api/v1/hl7/import,GET /api/v1/hl7/export/{id} - FHIR R4 HTTP endpoints:
POST /api/v1/fhir/import,GET /api/v1/fhir/export/{id} - Audit-Log CSV export button in UI
- Status transition validation enforced in backend (422 on invalid transitions)
UI/UX (P2) — 9 of 10 items
- Import page: tabbed layout for CSV / HL7 v2.5.1 / FHIR R4
- Dashboard stats: priority distribution and critical count from server (not client-side limit:100)
- Results list:
order_idshows string format (e.g.O-2024-001) not numeric FK - Sample responses include
updated_attimestamp - Breadcrumb bug fixed (
/audit-lognow shows "Audit Log") - Search prefix fixed (
O-prefix for orders) canWriteguard on Results create button- Password strength indicator on Profile page
- Sidebar dead code removed (hardcoded badge
'24')
Infrastructure (P3) — 3 of 5 items
- CI/CD:
.github/workflows/ci.yml(backend cmake+tests, frontend tsc+build) - Docker healthcheck enabled (backend uses
/api/v1/health) - CORS origin deduplication (read once at construction)
Quality
- 181/181 unit tests passing
- TypeScript strict: 0 errors
- All changes build cleanly
Remaining for v0.9: opensylab.conf, frontend unit tests (Vitest), OpenAPI/Swagger, DB migration system, single-threaded server improvement
v0.7.0 — Security, RBAC & Production Hardening
OpenSylab v0.7.0
Release Date: 2026-05-11
181 Unit-Tests passing · 0 TypeScript errors · 0 npm vulnerabilities
🔐 Sicherheit
- JWT-Authentifizierung mit HMAC-SHA256 (ersetzt API-Key-Only-Modus vollständig)
- PBKDF2-HMAC-SHA256 Passwort-Hashing, 210.000 Iterationen (OWASP 2023)
- RBAC auf allen Schreib-Endpoints: ADMIN / OPERATOR / VIEWER / CUSTOM
- MFA (TOTP RFC 6238) — vollständiger Zwei-Schritt-Login, ±1 Zeitfenster
- LDAP-Authentifizierung mit lokalem Shadow-Account
- Letzter-Admin-Schutz in
updateUser,deleteUser,assignUserRole— transaktional, TOCTOU-frei - Fehler-Sanitisierung: keine SQLite-Internals in HTTP-Antworten
🧪 Labordaten
- Auto-Flag: NORMAL / LOW / HIGH / CRITICAL (margin-basiert: 50 % des Referenzintervalls)
- Soft-Delete für Proben (ARCHIVED), Aufträge (CANCELLED), Ergebnisse (REJECTED)
- Batch-CSV-Import für Proben und Ergebnisse mit Fehler-Tracking pro Zeile
- HL7 v2.5.1 ORU^R01 Import/Export mit vollständigem Feld-Escaping
- FHIR R4 Bundle Import/Export
- Server-seitige Paginierung auf allen Listen-Endpoints
- Globale Suche im Header navigiert per
?q=zu Samples/Orders
🖥️ Frontend
- TypeScript strict mode — keine
any-Typen - RBAC-Guards auf allen Create/Edit/Delete-Buttons und Sidebar-Einträgen
- Responsive Tabellen (Tablet-optimiert)
- Vollständiger MFA-Login-Flow im UI
- Single Source of Truth für Versionsnummer:
CMakeLists.txt→include/version.h
🐛 Bugfixes
56 Bughunt-Iterationen, 60+ Bugs behoben — darunter:
DELETE /api/v1/users/:idwar durch Routing-Block unerreichbarsqlite3_errmsg()nachROLLBACKlieferte leere Fehlermeldung (43 Stellen)ResultEditModalnutzte numerische PK stattresult_idfür PUT-Requests- Alle Export-Funktionen entfernen Teildateien auf jedem Fehlerpfad
- MFA-403-Interceptor blockierte Login-Flow im Frontend
- TOCTOU-Race in updateUser/deleteUser/assignUserRole
Upgrade von v0.6
git pull origin main
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build --parallel $(nproc)
cd frontend && npm install && npm run buildWichtig: OPENSYLAB_JWT_SECRET Umgebungsvariable setzen — der Dev-Secret löst jetzt eine Warnung aus.
Full Changelog: CHANGELOG.md