TideWatch
Security-driven Docker container update manager
What is TideWatch?
TideWatch is a container update manager for homelabbers who got tired of Watchtower's "update everything, ask questions never" approach. It watches your containers for updates, but actually lets you decide what happens nextβapprove, reject, snooze, or let certain policies run automatically.
The real magic is the VulnForge integration. When an update is detected, TideWatch checks if the new image has more or fewer vulnerabilities than what you're running. Set a container to "security" policy and it'll only auto-update when the new version actually improves your security posture.
It reads your docker-compose files directly, tracks updates across Docker Hub, GHCR, and LinuxServer.io registries, and keeps a full history of what changed and when. No more guessing which container updated at 3am and broke everything.
Technology Stack
Backend
- β Python 3.12+ with FastAPI and Granian ASGI server
- β SQLAlchemy 2.x + SQLite (WAL mode) via aiosqlite
- β APScheduler for background jobs with retry logic
- β Multi-registry Docker clients (Docker Hub, GHCR, LSCR)
- β CSRF protection and rate limiting middleware
- β httpx async HTTP with ntfy notifications
- β Prometheus metrics endpoint
Frontend
- β React 19 + TypeScript 5.9 with Vite 7
- β Tailwind CSS 4 with teal/orange dark theme
- β React Router v7 navigation
- β Recharts for metrics visualization
- β Sonner toast notifications
- β date-fns formatting and Lucide icons
Project Statistics
Powered by VulnForge
TideWatch integrates seamlessly with VulnForge to provide vulnerability intelligence for every update decision. When an update is detected, TideWatch queries VulnForge to compare vulnerability counts, identify CVEs fixed or introduced, and generate security recommendations.
This integration enables the security policy enforcement that makes TideWatch unique: containers with a "security" policy will automatically reject updates that increase vulnerability counts, ensuring your security posture never degrades.
Version History
Track the evolution of TideWatch through its version releases. Each release includes new features, improvements, and bug fixes.
v3.1.0 2025-11-28
β¨ Added
- β’ **Multi-Service Notification System** - Support for 7 notification services beyond ntfy β **Gotify** - Self-hosted push notification server support β **Pushover** - Cross-platform push notification service ($5 one-time) β **Slack** - Incoming webhooks for team notifications β **Discord** - Webhook integration for server notifications β **Telegram** - Bot API integration with HTML formatting β **Email** - SMTP support with HTML emails and TLS β All services share unified architecture with abstract base class β Event-based routing via NotificationDispatcher β Per-service enable toggles with validation β Test Connection buttons for all services β Expandable event group UI (Updates, Restarts, System) β Service sub-tabs with enabled indicators (green dot) β Backend: `/backend/app/services/notifications/` (8 files) β Frontend: `/frontend/src/components/notifications/` (9 components) β New API endpoints: `POST /api/v1/settings/test/{service}` for all 7 services β New dependency: `aiosmtplib>=3.0.0` for async SMTP
π Changed
- β’ **Notification Architecture** - Migrated from single-service to multi-service pattern β All notification call sites now use `NotificationDispatcher` instead of direct `NtfyService` β Updated: `update_checker.py`, `update_engine.py`, `restart_service.py`, `restart_scheduler.py`, `scheduler.py` β Removed: `ntfy_service.py` (replaced by notifications module)
π Fixed
- β’ **Update Notification Timing** - Ntfy notifications now sent after database commit β Previously, notifications were sent before `db.commit()` completed β This caused race conditions where users received phone notifications but updates weren't visible in UI β Now commits per-container instead of batching, ensuring notifications match persisted state β Added rollback handling for failed container checks to prevent partial transaction issues
v3.0.0 2025-11-24
π Security
- β’ **CSRF Protection** - Session-based double-submit pattern β SessionMiddleware with secure, HttpOnly cookies β Constant-time token comparison prevents timing attacks β SameSite=Lax for additional protection
- β’ **Rate Limiting** - Endpoint-specific limits β Container operations: 5 req/min (prevents restart spam) β Update operations: 3 req/min (prevents update flooding) β Settings changes: 10 req/min
- β’ **Command Injection Prevention** - Centralized input validation β Container names, service names validated against shell metacharacters β Docker compose commands use whitelist-based validation β List-based subprocess calls (no shell=True)
- β’ **Path Traversal Protection** - Multi-layer path validation β Dangerous pattern detection (`..`, `//`, `\`, null bytes) β Base directory containment checks β Symlink escape prevention β Extension validation for compose files
- β’ **Security Headers** - Comprehensive header implementation β X-Content-Type-Options: nosniff β X-Frame-Options: DENY (clickjacking protection) β X-XSS-Protection: 1; mode=block β Strict-Transport-Security (HTTPS only in production) β Content-Security-Policy
β¨ Added
- β’ **Database Indexes** - Performance optimization for frequently queried columns β Container indexes: policy, update_available, name β Update indexes: status, container_id, created_at, snoozed_until β UpdateHistory indexes: container_id, status, created_at, started_at β Migration 019 adds all indexes on startup
- β’ **Retry Logic** - Exponential backoff for network failures β Decorator utilities for async and sync functions β Configurable max attempts, backoff base, and exceptions β Applied to registry HTTP requests
- β’ **Test Suite** - pytest configuration and initial tests β Validator tests for command injection prevention β Retry logic tests for exponential backoff β API endpoint tests (partial coverage) β Test database isolation with in-memory SQLite
π Fixed
- β’ **CRITICAL: Missing Dependency** - Added `itsdangerous>=2.1.0` β Required by SessionMiddleware but not in dependencies β Application crashed on startup without it
- β’ **Migration 019 Signature** - Fixed function signature mismatch β Migration runner expects `upgrade()` without parameters β Migration had `upgrade(conn: AsyncConnection)` which failed β Now matches existing migration pattern
- β’ **Test Suite Database Path** - Fixed permission errors in tests β Tests tried to create `/data` directory on import β Now sets DATABASE_URL environment variable before importing β Uses in-memory SQLite for test isolation
- β’ **Test Import Errors** - Fixed incorrect retry API usage β test_retry.py used non-existent `with_retry` and `RetryConfig` β Updated to use actual `async_retry` decorator API
π Changed
- β’ **CORS Configuration** - Fixed security issues β Wildcard origins now properly disable credentials β Explicit method whitelist (no wildcards) β Explicit header whitelist β Exposes rate limit headers to frontend β Configurable via CORS_ORIGINS environment variable
- β’ **Database Connection Pooling** - Optimized for SQLite β StaticPool for single persistent connection β WAL mode enabled for concurrent read/write β 64MB cache size, 5-second busy timeout
- β’ **Memory Leak Fixes** - Rate limiter bucket cleanup β Reduced cleanup threshold from 10 to 5 minutes β Hard limit of 10,000 buckets maximum β Aggressive cleanup when limit exceeded
π Dependencies
- β’ Added: `itsdangerous>=2.1.0` (session signing)
- β’ Dev: `pytest>=8.3.0`, `pytest-asyncio>=0.24.0`, `pytest-cov>=4.1.0`, `httpx>=0.27.2`
v2.9.1 2025-11-24
π Fixed
- β’ **Light Theme Visual Issues** - Resolved all remaining hardcoded colors and styling issues β Fixed CSRF token authentication errors in theme switching (ThemeContext now uses settingsApi) β Replaced 106+ instances of hardcoded gray colors with theme-aware variables across all pages β Fixed Flash of Unstyled Content (FOUC) by adding inline script to index.html β Fixed card spacing visibility in light mode (container background now uses `bg-tide-surface-light`) β Fixed black backgrounds on Dashboard, Updates, and History pages β Added borders to all Test Connection buttons in Settings page β Added border to Upload button in Backup & Maintenance section β Updated Statistics cards in About page with accurate line counts
π Changed
- β’ **Navigation Header Text Size** - Increased font sizes for better readability β App title: `text-xl` β `text-2xl` (20px β 24px) β Desktop nav links: `text-sm` β `text-base` (14px β 16px) with 18px icons β Mobile nav links: `text-base` β `text-lg` (16px β 18px) with 20px icons
- β’ **About Page Updates** - Updated project information β Changed author attribution from "Jamey (oaniach)" to "Operator" β Updated statistics to reflect current codebase: β Total Lines: ~16,700 β ~25,600 β Python Backend: ~11,800 β ~17,300 β TypeScript Frontend: ~4,900 β ~8,300
π Technical
- β’ Systematic replacement of hardcoded Tailwind gray classes with CSS custom properties β `bg-gray-950` β `bg-tide-bg`, `bg-gray-700` β `bg-tide-surface`, etc.
- β’ Theme variables properly adapt to both light and dark modes
- β’ All UI components now consistently use semantic color names
v2.9.0 2025-11-24
β¨ Added
- β’ **Light/Dark Theme Toggle** - NEW: Full light and dark theme support using Tailwind 4.1.x @theme feature β Theme toggle in Settings > System tab with Sun/Moon icons β Seamless theme switching with instant visual feedback β Persistent theme preference stored in database with cross-device sync β localStorage caching for instant theme loading (no FOUC) β Semantic CSS variables (`--color-tide-bg`, `--color-tide-surface`, `--color-tide-text`) for maintainability β All UI components support both themes: β Navigation bar, footer, cards, modals β Dashboard charts and analytics β Settings panels and forms β Update cards and history views β Dynamic Sonner toast theming β Scrollbar styling for both themes β Dark theme remains default for existing users β API: `GET/PUT /api/v1/settings/theme` for programmatic theme control
π Fixed
- β’ **Migration System** - Fixed migrations directory structure to match MyGarage pattern β Moved migrations from `/backend/migrations/` to `/backend/app/migrations/` β Auto-migration system now working correctly on container startup β Migration 014 now handles duplicate update records before applying unique constraint
π Changed
- β’ Updated frontend to version 2.9.0
- β’ Updated backend to version 2.9.0
v2.8.0 2025-11-24
β¨ Added
- β’ **HTTP Server Detection** - NEW: Automatically detect and track HTTP servers running in containers β Detects popular web servers: nginx, Apache, Caddy, Traefik, Granian, uvicorn, gunicorn, Node.js, and more β Version detection via command execution (e.g., `nginx -v`, `granian --version`) β Process-based detection with fallback to `/proc` for minimal containers without `ps` β Checks for latest versions from GitHub API (Caddy, Traefik, Granian) β Update availability tracking with severity indicators β New HTTP Servers section in Dependencies tab with stats and server cards β API endpoints: β `GET /api/v1/containers/{id}/http-servers` - Get detected servers β `POST /api/v1/containers/{id}/http-servers/scan` - Scan for servers β Auto-scans when Dependencies tab is opened
- β’ **Dockerfile Dependency Tracking** - COMPLETE: Full end-to-end tracking of Dockerfile base images and build dependencies β **Backend (Phase 1)** β : β Automatically parse Dockerfiles to detect `FROM` statements β Track base images (e.g., `node:22-alpine`, `python:3.14-slim`) as dependencies β Support for multi-stage builds with stage name tracking β Update Detection: Check Docker registries for newer base image versions β Bulk Update Checking: Scan all tracked Dockerfile dependencies for updates β New database table: `dockerfile_dependencies` with migration β New API endpoints: β `GET /api/v1/containers/{id}/dockerfile-dependencies` - Get dependencies β `POST /api/v1/containers/{id}/dockerfile-dependencies/scan` - Scan Dockerfile β `POST /api/v1/dockerfile-dependencies/check-updates` - Check all for updates β Backend service: `DockerfileParser` with full update detection support β Integrates with existing `RegistryClient` for checking Docker Hub, GHCR, LSCR, GCR, Quay β **Frontend UI (Phase 2)** β : β New Dockerfile Dependencies section in Container Modal Dependencies tab β Visual display of base images and build images with update indicators β Statistics cards showing total images and available updates β "Scan Dockerfile" button for manual triggering β Dependency cards showing: β Image name, current tag, and latest tag β Dependency type (Base Image / Build Image) β Stage name for multi-stage builds β Dockerfile path and line number reference β Update availability badges (Update Available / Up to date) β Loading states and empty states with helpful messages β Settings page configuration: β Auto-Scan Dockerfiles toggle β Update check schedule (Disabled / Daily / Weekly) β Info box with feature explanation β **Automation (Phase 3)** β : β Auto-scan Dockerfiles when containers are added via project scanner β Scheduled update checks (daily at 3 AM or weekly on Sundays) β ntfy notifications for Dockerfile dependency updates β Configurable via Settings page β Respects `dockerfile_auto_scan` and `dockerfile_scan_schedule` settings β π― **Solves**: Why Tidewatch didn't notify about Node.js update (now tracks Docker base images!)
- β’ **Automatic Database Migrations** - NEW: Self-managing migration system for zero-downtime upgrades β Automatic migration discovery and execution on startup β Tracks applied migrations in `schema_migrations` table β Prevents re-running already-applied migrations (idempotent) β Runs migrations in chronological order (001, 002, etc.) β Graceful error handling (logs errors but doesn't fail startup) β Same battle-tested system as MyGarage β **Files Created:** β `app/migrations/runner.py` - Migration orchestration engine β `app/migrations/__init__.py` - Python package structure β **Files Modified:** β `app/db.py` - Integrated migration runner into startup sequence β **Benefits:** β No manual migration commands needed β Safe upgrades with automatic rollback on failure β Docker-friendly (just restart container to apply migrations) β Development-friendly (drop `.py` migration files, they auto-run)
- β’ **ESLint Flat Configuration** - Added ESLint 9.x flat config for frontend linting β Created `eslint.config.js` using modern flat config format β Installed `globals` and `typescript-eslint` packages β Configured TypeScript, React, and React Hooks rules β Simplified lint script in package.json: `eslint .`
π Changed
- β’ **Dependencies Tab UI Layout** - Improved layout with two-column masonry design β Left column: HTTP Servers + Dockerfile Dependencies β Right column: Application Dependencies β Reduces wasted vertical space and improves information density β Responsive grid that stacks on mobile devices
- β’ **Application Dependencies Filter** - Changed default filter from "All" to "Updates" β Shows packages with available updates by default for quicker action β Users can still switch to "All" or "Security" filters as needed
- β’ **Dockerfile Dependencies Auto-Scan** - Removed manual "Scan Dockerfile" button β Auto-scans when Dependencies tab is opened (consistent with HTTP Servers and App Dependencies) β Cleaner UI with one less button
- β’ **Node.js Build Environment** - Updated frontend build to use Node.js 22 (from Node.js 20) β Updated Dockerfile: `FROM node:22-alpine` (was `node:20-alpine`) β Required for @vitejs/plugin-react 5.x compatibility (needs Node 20.19+ or 22.12+)
- β’ **Frontend Dependencies** - Updated 8 npm packages to latest versions β @vitejs/plugin-react: 4.7.0 β 5.1.1 (major update with Oxc integration for faster builds) β recharts: 3.4.1 β 3.5.0 (performance improvements for chart rendering) β vite: 7.2.2 β 7.2.4 (bug fixes) β lucide-react: 0.553.0 β 0.554.0 (new icons) β @types/react: 19.2.2 β 19.2.6 (type definition updates) β @types/react-dom: 19.2.2 β 19.2.3 (type definition updates) β @typescript-eslint/eslint-plugin: 8.46.4 β 8.47.0 (new linting rules) β @typescript-eslint/parser: 8.46.4 β 8.47.0 (parser improvements) β Kept eslint-plugin-react-hooks at 7.0.0 (7.0.1 has known regression bugs) β Added globals: ^16.5.0 and typescript-eslint: ^8.47.0 for ESLint 9.x support
π Fixed
- β’ **Vite Build Configuration** - Removed obsolete `react-hot-toast` reference from vite.config.ts β Application uses `sonner` for notifications; `react-hot-toast` was legacy reference β Fixes build error: "Could not resolve entry module 'react-hot-toast'"
- β’ **ESLint Configuration Missing** - Resolved ESLint 9.x compatibility issue β ESLint 9.x requires flat config format (eslint.config.js) β Created proper flat config with all necessary plugins and rules β `npm run lint` now works correctly (reveals 56 pre-existing linting issues to be fixed separately)
- β’ **Dockerfile Dependencies API Errors** - Fixed missing imports preventing application startup β Added missing `DockerfileDependenciesResponse` and `DockerfileDependencySchema` imports to `containers.py` β Added missing `Optional` type import for Dockerfile scan endpoint β Fixes `NameError: name 'schemas' is not defined` and `NameError: name 'Optional' is not defined` β Application now starts successfully with Dockerfile dependency tracking enabled
v2.7.0 2025-11-22
β¨ Added
- β’ **My Projects Auto-Discovery** - Automatically detect dev containers from projects directory β New Settings card: "My Projects Configuration" with enable toggle, projects directory path, auto-scan toggle β Project scanner service automatically discovers containers from `/projects/*/compose.yaml` files β Intelligently identifies main dev container vs infrastructure services (postgres, redis, etc.) β Prefers services ending in `-dev` over other services in multi-service compose files β Manual "Scan Projects Now" button for on-demand scanning β Auto-detected containers automatically marked as "My Project" with `is_my_project = True` β Stale container cleanup: removes "My Project" entries whose compose files no longer exist β Scan results show added, updated, skipped, and removed container counts β Backend: `ProjectScanner` service with `scan_projects_directory()` and `remove_missing_projects()` methods β Frontend: "My Projects Configuration" card follows app theme (yellow star icon, gray-800 background, teal accents) β API endpoint: `POST /api/v1/containers/scan-my-projects` for manual project scanning β Settings: `my_projects_enabled`, `my_projects_auto_scan`, `my_projects_compose_command`, `projects_directory` β Volume mount: `/srv/raid0/docker/build:/projects:ro` for read-only access to project source code β Support for custom docker compose commands for dev containers (e.g., simple `docker compose` vs complex production stacks)
π Changed
- β’ **UI Cleanup and Improvements** β Updated "My Project" toggle description to mention auto-detection: "Dev containers are auto-detected from your projects directory" β Moved "About Docker Settings" info box inside Docker Configuration card for better organization β Removed redundant "Scan Dependencies" button from Dependencies tab (auto-scan already works on tab open) β Updated Dependencies tab header to explain auto-scanning behavior β Improved empty state message in Dependencies tab with clearer explanation
- β’ **Dependencies Tab Auto-Scanning** - Dependencies now scan automatically when tab is opened (no manual button needed)
π Fixed
- β’ **Project Scanner Service Selection Logic** - Fixed scanner picking wrong services from multi-service compose files β Now correctly identifies main dev container instead of first service alphabetically β Skips infrastructure services (postgres, redis, mysql, mariadb, mongodb, rabbitmq, elasticsearch) β Prioritizes services/containers ending with `-dev` suffix β Falls back to first non-infrastructure service if no `-dev` service found β Example: `collectionsync/compose.yaml` now correctly finds `collectionsync-dev` instead of `postgres`
- β’ **Stale Container Cleanup** - Scanner now removes containers that are no longer found in project scans β Tracks which containers were found during scan using a set β Deletes "My Project" containers not found in current scan β Prevents stale entries like `socket-proxy-dev` and `collectionsync-postgres` from lingering
π Technical
- β’ Added database migration `015_add_is_my_project.py` to add `is_my_project` field
- β’ Updated `Container` model and schemas to support `is_my_project` boolean field
- β’ Project scanner uses `ruamel.yaml` for robust YAML parsing (already in dependencies)
- β’ Scanner returns tuple `(result, container_name)` to track found containers
- β’ Conditional UI rendering: My Project toggle only shows if `my_projects_enabled = true`
- β’ Info boxes use consistent styling: `bg-gray-900/50 rounded-lg p-4` for tips sections
v2.6.0 2025-11-21
β¨ Added
- β’ **My Projects Feature** - Mark containers as "My Project" to organize and track them separately β Added `is_my_project` boolean field to containers with database migration β Dashboard now splits containers into "My Projects" (top) and "Other Containers" sections β "My Project" toggle in Container Settings tab with star icon indicator β Only "My Projects" can access the new Dependencies tab
- β’ **Application Dependencies Tracking** - Track and monitor application-level dependencies β New "Dependencies" tab in container modal (only visible for My Projects) β Multi-ecosystem support: npm (Node.js), PyPI (Python), Composer (PHP), Cargo (Rust), Go modules β Automatic dependency file detection (package.json, requirements.txt, composer.json, Cargo.toml, go.mod) β Real-time version checking against package registries β Displays current vs. latest versions with update availability β Security advisory tracking and severity indicators β Socket.dev security scoring integration (ready for future implementation) β Filterable view: All, Updates Available, Security Issues β Manual "Scan Dependencies" button with loading states β Stats cards showing Total, Updates Available, and Security Issues counts β Visual severity badges (Critical, High, Medium, Low, Info) based on semver differences β Ecosystem-specific icons (π¦ npm, π PyPI, π Composer, π¦ Cargo, πΉ Go)
- β’ **Backend Dependency Scanner Service** - Robust multi-ecosystem dependency detection β Automatic project root detection from compose file volume mounts β Parallel scanning across all supported ecosystems β Package registry API integration (npm, PyPI, Packagist, crates.io, Go proxy) β Version comparison and update availability calculation β Severity assessment based on semantic versioning differences β Configurable timeout and error handling for external API calls
- β’ **New API Endpoints** β `GET /api/v1/containers/{id}/app-dependencies` - Get application dependencies with update info β `POST /api/v1/containers/{id}/app-dependencies/scan` - Force rescan of dependencies β Enhanced `PUT /api/v1/containers/{id}` to support `is_my_project` field β Permissions: Dependencies endpoints restricted to containers marked as My Projects
π Changed
- β’ Updated frontend package version to 2.6.0
- β’ Updated backend package version to 2.6.0
- β’ Dashboard container grid now uses conditional rendering for grouped sections
- β’ Container modal tabs conditionally show Dependencies tab based on `is_my_project` status
v2.5.1 2025-11-18
π Security
- β’ Fixed command injection vulnerability in container restart endpoint
- β’ Added path traversal protection for compose file operations
- β’ Fixed URL injection in health check authentication
- β’ Added Docker tag format validation to prevent injection attacks
- β’ Fixed ReDoS vulnerabilities in regex patterns with unbounded repetition
π Fixed
- β’ Added error handling for resource cleanup to prevent connection leaks
- β’ Fixed SQLite connection pool configuration causing database locks
- β’ Fixed race condition in update creation with unique constraint and IntegrityError handling
- β’ Improved error handling in frontend event stream with user notifications
π Changed
- β’ Updated update checker to handle duplicate update creation gracefully
- β’ Database connection pooling now adapts based on database type (SQLite vs PostgreSQL)
- β’ Added comprehensive input validation for container names, file paths, and Docker tags
v2.5.0 2025-11-17
β¨ Added
- β’ **Updates Tab Masonry Layout** - Converted Settings > Updates tab to responsive two-column masonry layout β Uses CSS `columns-1 xl:columns-2` for natural card flow (matching Container Settings pattern from v2.4.1) β Cards maintain natural widths and heights with `break-inside-avoid` property β Single column on mobile/tablet (<1280px), two columns on desktop (β₯1280px) β All 5 settings cards flow naturally into columns based on content height
- β’ **Scheduler Status Display** - Added real-time scheduler status card at top of Updates tab β Shows scheduler running state (β Running / βΈ Paused) with color indicators β Displays next scheduled run time and last check time (relative times using `formatDistanceToNow`) β Auto-refreshes when Updates tab becomes active β Provides visibility into background update checking service
- β’ **Auto-Reload Scheduler on Schedule Change** - Scheduler automatically reloads when cron schedule is updated β Detects changes to `check_schedule` setting in Settings > Updates β Calls `/api/v1/updates/scheduler/reload` endpoint after successful save β Displays success toast: "Scheduler reloaded with new schedule" β Immediately refreshes scheduler status display to show new next run time
- β’ **Reset Settings to Defaults** - Added danger zone with reset button in Settings > System tab β Red-bordered section at bottom of System tab with warning styling β Confirmation dialog: "Reset ALL settings to defaults? Cannot be undone." β Calls `/api/v1/settings/reset` endpoint and reloads all settings after reset β Provides escape hatch for configuration issues
- β’ **Settings Categories Organization (EXPERIMENTAL)** - Settings now grouped by category β Changed `loadSettings()` to try `/api/v1/settings/categories` endpoint first β Falls back to flat `/api/v1/settings/` list if categories endpoint fails β Graceful degradation for backwards compatibility β Note: Backend categories endpoint already existed, now integrated into frontend
- β’ **Security Updates Filter** - Added dedicated filter for security-related updates on Updates page β New filter button with Shield icon: "Security (N)" showing count of CVE-related updates β Red background when active to highlight security-critical updates β Calls `/api/v1/updates/security` endpoint to fetch only updates with CVE fixes β Positioned above status filter tabs (All, Pending, Approved, etc.) β Shield icon provides visual indication of security-related updates
π Changed
- β’ **Container Logs API Migration** - Migrated ContainerModal logs fetching from docker router to containers router β Changed `/api/v1/docker/containers/{id}/logs` β `api.containers.getLogs(id, tail)` β Uses existing containerApi endpoint for consistency β Properly handles log array formatting with `.join('\n')`
ποΈ Removed
- β’ **Docker Router** - Removed unused `/api/v1/docker/` router from backend β Deleted `backend/app/api/docker.py` file (139 lines) β Removed docker router import and registration from `backend/app/api/__init__.py` β Only 1 frontend reference existed (ContainerModal logs), now migrated to containers API β Reduces API surface area and eliminates redundant container endpoints
v2.4.7 2025-11-17
π Fixed
- β’ **Cross-Distro Tag Suggestions** - Fixed variant tag filtering to preserve image variants (alpine vs debian/trixie) β Images like `python:3.12-alpine` now only suggest alpine-based updates (e.g., `3.12.12-alpine`) β Prevents cross-distribution suggestions that would break compatibility (e.g., suggesting `3.12.12-trixie` for `3.12-alpine`) β Updated all registry clients (DockerHub, GHCR, GenericRegistry, Quay) with suffix-matching logic β Closes issue from v2.4.5 where variant filtering was incomplete
- β’ **Python-Style Pre-release Detection** - Added support for Python-style alpha/beta/rc tags β Added patterns `a0`-`a9`, `b0`-`b9`, `rc0`-`rc9` to prerelease indicators β Versions like `3.15.0a1`, `2.1.0b2` now correctly filtered as pre-releases β Applied across all registry clients (DockerHub, GHCR, LSCR, GCR, Quay)
β¨ Added
- β’ **Global Include Pre-releases Setting** - New toggle in Settings > Updates to control pre-release filtering β Users can now globally enable/disable pre-release versions (alpha, beta, rc, nightly) β Acts as default for containers that don't have per-container override β Located in "Update Checks" card where it logically belongs β Prevents confusion with "Exclude Dev Containers" (which only affects stale detection)
v2.4.6 2025-11-17
π Fixed
- β’ **Settings Key Mismatch** - Retry settings (Max Attempts, Backoff Multiplier) now properly applied to updates β Fixed frontend using wrong setting keys (`max_retry_attempts` vs `update_retry_max_attempts`) β Fixed backend never reading settings when creating Update objects β Update objects now use configured retry settings instead of hardcoded defaults (3 retries, 3x backoff)
- β’ **No Manual Intervention for Retrying Updates** - Users can now control updates stuck in retry loops β Added "Cancel Retry" button to reset pending_retry updates back to pending state β Added "Reject" button to dismiss retrying updates permanently β Added "Delete" button as escape hatch to remove problematic updates β Fixed reject endpoint to accept both "pending" and "pending_retry" statuses
- β’ **Retrying Updates Hidden in UI** - Added dedicated "Retrying" filter tab on Updates page β New filter shows only updates in pending_retry status β Shows retry count with rotating icon badge for easy identification β Displays next retry time in error messages
π Changed
- β’ **Settings UI Improvement** - Converted retry settings to sliders matching app theme β Replaced number input fields with teal-colored range sliders β Shows current values in parentheses next to labels (e.g., "Max Attempts (5)") β Consistent with existing slider patterns in Container Modal
v2.4.5 2025-11-16
π Fixed
- β’ **Duplicate Update Entries** - Fixed deduplication query missing `from_tag` check β Added `Update.from_tag == container.current_tag` to deduplication query β Prevents multiple Update records for the same container+version combination
- β’ **PR Tag Detection** - Pull request tags (e.g., `pr-4234`) no longer detected as valid updates β Added `'pr-'` and `'pull-'` to prerelease_indicators across all registry clients β Filters out development PR tags from update candidates
- β’ **Latest Tag Detection** - "latest" tag no longer appears as update target for pinned versions β Added explicit "latest" tag filtering in both DockerHub and other registry clients β Prevents containers pinned to specific versions from showing "latest" as update
- β’ **Variant Tag Filtering** - Image variant suffixes now automatically filtered (future-proof) β Replaced hardcoded suffix list with smart pattern matching β Automatically rejects ANY suffix that's not a standard pre-release (rc, beta, alpha) β Filters `-enterprise`, `-scratch`, `-cluster`, `-oss`, `-alpine`, `-slim`, etc. β No manual updates needed for new variant patterns introduced by upstream projects
v2.4.4 2025-11-15
π Fixed
- β’ **Rollback for Failed Updates** - Failed updates can now be rolled back if a backup exists β Backend now sets `can_rollback = True` for failed updates when backup is available β Removed frontend restriction requiring "success" status for rollback button visibility β Updated rollback API to accept both "success" and "failed" statuses
- β’ **Pre-release Tag Filtering** - Tags containing "master" (e.g., `master-omnibus`) now correctly filtered as pre-releases β Added "master" to `prerelease_indicators` list in all registry clients β Prevents unwanted dev/master tag updates when "Include Prereleases" is disabled
- β’ **Automatic Rollback After Max Retries** - Updates now automatically rollback after 3 failed retry attempts β When max retries reached, system attempts automatic rollback if backup exists β Update status set to "rolled_back" on successful auto-rollback β Provides clear error messages if auto-rollback fails or no backup available
- β’ **Health Check Error Reporting** - Fixed misleading DNS errors masking actual container failures β Health check now reports actual container status (e.g., "Container exited") instead of HTTP/DNS errors β Docker inspect error messages now properly propagated when container has crashed β Separate tracking of HTTP errors vs container runtime errors for better debugging
v2.4.3 2025-11-15
β¨ Added
- β’ **Rollback Option in Overview** - Added rollback card to container Overview tab after successful updates β Appears alongside "Up to Date" status in a split layout (50/50) β Shows previous version and timestamp with yellow accent border β Uses existing rollback functionality from History tab
π Fixed
- β’ **Duplicate Update Cards** - Fixed issue where failed updates would create duplicate cards during retry attempts β Updated deduplication query in `UpdateChecker` to include `pending_retry` and `approved` statuses β Prevents new update records from being created when updates are already in retry or approved state
- β’ **Unknown Status Display** - Fixed `pending_retry` status showing as "Unknown Update" in the UI β Added `pending_retry` status support to `StatusBadge` component with orange styling β Status now displays correctly as "pending_retry" instead of generic unknown state
- β’ **Updates Page Clutter** - Applied updates now hidden from "All" tab to reduce clutter β Applied updates remain accessible via the "Applied" filter tab
- β’ **History Status Colors** - Replaced inline status rendering with StatusBadge component for consistent colors β Ensures both 'completed' and 'success' statuses display green in container history β Added 'rolled_back' status with yellow color for consistency
- β’ **About Page Version Display** - Fixed version showing "1.0.0" instead of actual version (2.4.3) β Improved default state to show "Loading..." while fetching version from API
π Changed
- β’ **Success Status Styling** - Success status badges now display in green for better visual feedback β Changed success status color from gray to green (`bg-green-500/20 text-green-400 border-green-500/30`) β Provides clear visual distinction between successful and failed operations
v2.4.2 2025-11-14
π Fixed
- β’ **Docker Restart Policy Display** - Fixed inaccurate restart policy showing "manual" for all containers β Added `get_restart_policy()` method to `DockerStatsService` to read from Docker runtime β Added `_sync_restart_policies()` to `ComposeParser` to sync policies during container discovery β Now correctly displays actual Docker restart policy (no, on-failure, always, unless-stopped) β Syncs on every container sync operation
β¨ Added
- β’ **TideWatch Auto-Restart Badge** - Visual indicator for intelligent auto-restart feature β Added teal badge with RefreshCw icon to container cards when auto-restart is enabled β Displays alongside Docker restart policy for clear differentiation β Shows "Docker: {policy}" for native Docker restart + "Auto-Restart" badge for TideWatch feature β Helps users quickly identify which containers have intelligent restart management enabled
π Changed
- β’ **Container Card Restart Info** - Improved clarity between Docker and TideWatch restart features β Renamed label from "Restart:" to "Docker:" to clarify it's the Docker native restart policy β Layout now shows both Docker policy (left) and TideWatch badge (right) when both are present β Bottom section only appears if at least one restart feature is configured
v2.4.1 2025-11-14
π Fixed
- β’ **Auto-Restart Disable Bug** - Fixed SQLAlchemy async session error when disabling auto-restart β Added missing `await db.refresh(state)` after commit in disable endpoint β Error was: `MissingGreenlet: greenlet_spawn has not been called` during Pydantic validation β All other endpoints (enable, reset, pause, resume) already had proper refresh logic
π Changed
- β’ **Auto-Restart Slider Styling** - Updated configuration slider colors to teal (`accent-teal-500`) β Applied to Max Attempts, Base Delay, Max Delay, and Success Window sliders
- β’ **Settings Tab Layout** - Converted to responsive CSS columns (masonry-style) layout β Uses `columns-1 xl:columns-2` for natural card flow across columns β Cards maintain their natural widths and heights with `break-inside-avoid` β Single column on mobile/tablet (< 1280px), two columns on desktop (β₯ 1280px) β Cards stack naturally in columns without forced equal widths β All five settings sections (Auto-Restart, Health Check, Release Source, Dependency Management, Update Window) flow into columns based on available space
v2.4.0 2025-11-13
β¨ Added
- β’ **Real-time Event Streaming** - Server-Sent Events (SSE) for live update notifications β EventSource-based SSE client with automatic reconnection and exponential backoff β Toast notifications for update available, update applied, update failed, container restarted, health check failed β Connection status indicator (Live/Reconnecting/Offline) in bottom-right corner β Graceful cleanup and heartbeat ping support β Created `useEventStream` hook for centralized event handling
- β’ **Enhanced Log Viewer** - Powerful log analysis and management features β Search/filter functionality with case-insensitive text matching β Log level syntax highlighting (ERROR in red, WARN in yellow, INFO in blue, DEBUG in gray) β Copy to clipboard button for selected/filtered logs β Download logs as .txt file with timestamp β Follow mode toggle for auto-scrolling to latest logs β Adjustable tail lines selector (100, 500, 1000, All) β Visual feedback for filtered results
- β’ **Better Backup Management UI** - Enhanced backup safety and information display β File size display with both bytes and MB formatting β Relative timestamps ("2 hours ago") with full datetime on hover β Safety backup visual indicators (Shield icon, protected badge) β Delete confirmation modal with backup details (filename, size, date) β Restore preview modal showing backup size vs current database size β Safety backup protection (automatic creation before restore, cannot delete) β Improved UX with detailed warning messages
- β’ **Metrics History Improvements** - Advanced metrics visualization and export β CSV export functionality with timestamp and all metric columns β Multi-metric comparison mode for CPU + Memory (dual Y-axes) β Better axis labels with units (%, MB, MB/s) β Export button with data validation β Comparison toggle for correlating CPU and Memory usage β Enhanced chart tooltips and formatting
π Changed
- β’ **Migrated toast library** from react-hot-toast to sonner for consistency β Unified toast notifications across all pages β Removed react-hot-toast dependency β Updated ContainerModal to use sonner β Improved toast styling with dark theme integration
- β’ **Improved UI/UX polish** across multiple components β Better visual hierarchy with consistent spacing β Enhanced button groups and action controls β Improved modal designs with semantic color coding β Better mobile responsiveness for backup and log viewer
ποΈ Removed
- β’ react-hot-toast dependency (replaced with sonner)
v2.3.0 2025-11-13
β¨ Added
- β’ **Intelligent Auto-Restart Configuration UI** - Complete frontend interface for container restart management β Real-time restart state display (consecutive failures, total restarts, current backoff, max retries status) β Comprehensive configuration panel with backoff strategy selection (exponential/linear/fixed) β Configurable max attempts, base delay, max delay, and success window sliders β Health check integration with timeout configuration β Rollback on health fail toggle β Pause/Resume controls with duration selector β Reset state button to clear failure counters β Visual indicators for paused state and retry limits
- β’ **Dependency Management UI** - Control container update order based on dependencies β Add/remove container dependencies with visual tags β Automatic bidirectional dependency tracking (dependencies β dependents) β Select from all available containers to set as dependencies β Read-only display of containers that depend on this container β Circular dependency prevention via backend validation
- β’ **Update Window Scheduling UI** - Restrict updates to specific time periods β Configure time-based update windows with format validation β Quick preset buttons for common scenarios: β Night Window (02:00-06:00 daily) β Weekends Only (Sat,Sun:00:00-23:59) β Weeknights (Mon-Fri:22:00-06:00) β Weekend Mornings (Sat,Sun:02:00-10:00) β Support for day-specific windows (Mon-Fri, Sat,Sun, etc.) β Support for windows that cross midnight β Clear button to remove restrictions β Format help with examples
- β’ **New API Service Methods** - Frontend API client expanded with: β Complete restart API integration (getState, enable, disable, reset, pause, resume, getHistory, manualRestart, getStats) β Dependency management endpoints (getDependencies, updateDependencies) β Update window endpoints (getUpdateWindow, updateUpdateWindow) β Auto-detection endpoints (detectHealthCheck, detectReleaseSource)
- β’ **TypeScript Type Definitions** - Added comprehensive types for: β RestartState, EnableRestartConfig, RestartLog, RestartStats β DependencyInfo β UpdateWindowInfo β AnalyticsSummary β ServerEvent for future event streaming
π Changed
- β’ Updated Auto-Restart toggle to properly integrate with backend API β Now calls `/restarts/{id}/enable` and `/restarts/{id}/disable` endpoints β Saves complete configuration when enabling β Shows expanded configuration panel when enabled
- β’ Enhanced ContainerModal with new Settings tab sections β Auto-Restart section expanded with state display and configuration β Added Dependency Management section after Release Source β Added Update Window section after Dependency Management
- β’ Improved visual consistency across all new sections β Consistent dark theme (bg-gray-700/50, bg-gray-800, border-gray-600) β Primary color accents for interactive elements β Icon badges for section headers (RotateCw, Network, Calendar)
π Fixed
- β’ Fixed duplicate "Release Source" field in Settings tab β Removed older "Release Notes Source" section (lines 1048-1078) β Kept newer "Release Source" section with auto-fill button
- β’ Fixed Python package discovery issue in pyproject.toml β Added `[tool.setuptools.packages.find]` configuration β Explicitly includes `app*` packages
v2.2.1 2025-11-12
π Fixed
- β’ **CRITICAL:** Fixed event bus race condition causing runtime errors β Added list copy in publish method to prevent modification during iteration β Added proper logging for slow consumer removal
- β’ **Fixed HTTPS mixed content errors** when running behind Traefik with Authentik forward auth β Added trailing slashes to frontend API calls (`/containers/`, `/updates/`, `/history/`) β Prevents FastAPI 307 redirects that were downgrading HTTPS to HTTP β Resolves browser blocking of HTTP resources on HTTPS pages
- β’ Fixed HTTP client resource leaks β Added `__aenter__`/`__aexit__` context managers to RegistryClient, VulnForgeClient, and NtfyService β Ensures proper cleanup of HTTP connections
- β’ Fixed Dashboard N+1 query problem β Replaced O(n*m) `.some()` calls with O(1) Map lookup β Improves performance with large container counts
- β’ Fixed unsafe UTC datetime usage (Python 3.12+ deprecation) β Replaced `datetime.utcnow()` with `datetime.now(timezone.utc)` across codebase
- β’ Fixed missing HTTP client timeout in health check requests
- β’ Fixed useEffect dependency ordering in Dashboard component
β‘ Performance
- β’ **Added registry tag caching** (15-minute TTL) β In-memory cache for all registry clients (DockerHub, GHCR, LSCR, GCR, Quay) β Reduces redundant API calls by up to 90% β Automatic expiration and cleanup β Cache hit/miss logging for debugging
- β’ **Added dependency resolution caching** β MD5-based cache keys for topological sort results β 100-entry LRU eviction policy β Automatic cache invalidation when dependencies change β Significantly improves bulk update ordering performance
- β’ **Migrated Docker CLI to SDK in ContainerMonitorService** β Replaced subprocess `docker inspect` calls with Docker Python SDK β Better error handling and performance β Eliminates shell overhead
- β’ Added database connection pooling β pool_size: 10 concurrent connections β max_overflow: 20 additional connections during peak load β pool_recycle: 3600 seconds (1 hour) β pool_pre_ping: enabled for connection health checks
- β’ Added database indexes to frequently queried columns β Container: `update_available`, `policy`, `last_checked` β Update: `status` β UpdateHistory: `status`, `started_at`, `created_at` β Improves query performance for dashboard and filtering operations
β¨ Added
- β’ **Prometheus metrics endpoint** at `/metrics` β Container metrics: total, with updates, by policy, by registry β Update metrics: pending, approved, rejected, applied, failed β History metrics: success, failed, rolled back β Compatible with standard Prometheus scrapers β Automatically collects current state from database
- β’ **Configurable timing values** for health checks and restarts β `health_check_retry_delay`: Initial delay between health check retries (default: 5s) β `health_check_use_exponential_backoff`: Enable exponential backoff (default: true) β `health_check_max_delay`: Maximum delay for exponential backoff (default: 30s) β `container_startup_delay`: Wait time after container restart before health check (default: 2s)
- β’ **Exponential backoff for health checks** β Implements 5s β 10s β 20s β 30s backoff pattern β Reduces load on failing services during health check retries β Applied to both HTTP exceptions and non-200 status codes β Configurable via settings (can be disabled for fixed delay)
- β’ **Frontend code splitting for large components** β Lazy-loaded ContainerModal component (1204 lines, ~40KB) β Modal only loads when opened, reducing initial bundle size β Added Suspense boundary with loading spinner
- β’ **Container health status** in container details API β Real-time health check using ContainerMonitorService β Returns status: "healthy", "unhealthy", or "stopped" β Includes last health check timestamp
π Improved
- β’ **Type hints coverage** - Added return type hints to 15+ functions β All `__init__` methods now have `-> None` return type β Async context managers (`__aenter__`, `__aexit__`) have proper typing β Utility and service methods include return type annotations β Improves IDE autocomplete and static analysis
π Technical Notes
- β’ See `/srv/raid0/docker/documents/history/tidewatch/2025-11-15-dependency-updates-granian-tailwind-v4-migration.md` for Tailwind v4 migration details
- β’ See `/srv/raid0/docker/documents/history/tidewatch/2025-11-15-endpoint-logging-filter.md` for logging enhancements
v2.2.0 2025-11-12
π Changed
- β’ **MAJOR:** Migrated from Tailwind CSS v3 to v4 β Updated PostCSS configuration to use `@tailwindcss/postcss` plugin β Migrated CSS imports from `@tailwind` directives to `@import "tailwindcss"` β Moved configuration from JavaScript to CSS-based `@theme` directive β Custom color theme (primary/accent) now defined as CSS custom properties
- β’ Updated frontend dependencies: β `react-router-dom`: 7.3.1 β 7.9.6 β `lucide-react`: 0.468.0 β 0.553.0 (now includes 1,647 icons) β `sonner`: 1.7.0 β 2.0.7 β `@typescript-eslint/*`: 8.46.3 β 8.46.4 β `eslint-plugin-react-refresh`: 0.4.16 β 0.4.24 β `autoprefixer`: 10.4.21 β 10.4.22 β `postcss`: 8.4.42 β 8.5.6
- β’ Removed `tailwind.config.js` (no longer needed in Tailwind v4)
- β’ Improved build script by removing `tsc &&` prefix for faster builds
π Technical Notes
- β’ Tailwind v4 requires modern browsers (Safari 16.4+, Chrome 111+, Firefox 128+)
- β’ Theme colors are now CSS variables for better runtime flexibility
v2.1.1 2025-11-12
π Changed
- β’ **MAJOR:** Migrated from uvicorn to Granian ASGI server β Updated `Dockerfile` to use Granian with single worker configuration β Changed logger filter in `app/main.py` from `uvicorn.access` to `granian.access` β Granian provides ~15-20% memory reduction and better async handling
- β’ Updated backend dependencies to latest stable versions: β `fastapi`: 0.115.0 β 0.121.2 β `sqlalchemy`: 2.0.36 β 2.0.44 (improved async support) β `pydantic`: 2.9.0 β 2.12.0 (minor behavior changes in dataclass Field handling) β `apscheduler`: 3.10.4 β 3.11.1 (dependency cleanup) β `docker`: 7.0.0 β 7.1.0
- β’ Updated frontend dependencies: β `typescript`: 5.7.4 β 5.9.3 (stable version) β `eslint-plugin-react-hooks`: 5.1.0 β 7.0.0 (β οΈ avoid 7.0.1 - broken resolution)
β‘ Performance
- β’ Reduced memory footprint with Granian's Rust-based architecture
- β’ Better async request handling and backpressure management
- β’ Auto-tuned thread configuration for optimal performance
π Technical Notes
- β’ Single worker required due to stateful APScheduler service
- β’ Granian is fully ASGI-compliant and a drop-in replacement for uvicorn
v2.1.0 2025-11-11
β¨ Added
- β’ Initial stable release of TideWatch
- β’ Intelligent Docker container update management
- β’ Real-time container monitoring and update tracking
- β’ Integration with VulnForge for security analysis
- β’ Automated update scheduling with configurable policies
- β’ Update history tracking and rollback capabilities
- β’ Comprehensive web UI with dashboard and analytics
π Technical Stack
- β’ Backend: Python 3.14, FastAPI, SQLAlchemy, APScheduler
- β’ Frontend: React 19, TypeScript, Tailwind CSS
- β’ Database: SQLite with async support (aiosqlite)
- β’ Container Management: Docker SDK for Python
- β’ **2.2.1**: Security fixes + performance optimizations
- β’ **2.2.0**: Tailwind v4 migration + dependency updates
- β’ **2.1.1**: Granian migration + backend dependency updates
- β’ **2.1.0**: Initial stable release
Key Features
Update Workflow
Pending updates queue up for review. Approve, reject, or snooze them. See release notes and CVE changes before deciding.
VulnForge Integration
Every update shows vulnerability counts for old vs new images. "Security" policy containers only auto-update when CVEs go down.
Update Policies
Per-container policies: manual (you approve everything), auto (updates immediately), security (only if CVEs decrease), or disabled.
Compose-Aware
Point it at your compose files and it discovers services automatically. Updates use your compose config, not raw docker commands.
Multi-Registry Support
Checks Docker Hub, GitHub Container Registry, and LinuxServer.io for updates. Handles digest-based version tracking.
Dependency Scanning
Scans containers for HTTP servers, Dockerfile base images, and npm/pip packages. Shows what's outdated inside your running containers.
Update History
Full audit trail of every update: what version, when it happened, how long it took, whether it succeeded or failed.
Multi-Service Notifications
Push notifications via ntfy, Gotify, Pushover, Slack, Discord, Telegram, or Email. Event-based routing with per-service configuration.
Light/Dark Theme
Toggle between light and dark themes. Your preference syncs across devices and persists in the database.
Why Not Just Use Watchtower?
You want to review updates first
Watchtower updates everything automatically. TideWatch lets you see what changed and decide if you want it.
You care about security
TideWatch shows CVE counts before and after. You can require updates to actually fix vulnerabilities, not introduce them.
You use docker-compose
TideWatch respects your compose files. It runs `docker compose up -d`, not raw docker commands that ignore your config.
You want to know what happened
Full history of every update with timestamps, durations, and success/failure status. Debug at 3am with actual data.
Screenshots
Dashboard
At-a-glance view of all containers with update frequency stats, CVE resolution tracking, and policy distribution. My Projects section highlights development containers separately from infrastructure.
Updates Management
Review and manage container updates with workflow states (Pending, Approved, Rejected, Stale, Applied). Expandable release notes and CVE fix indicators help make informed update decisions.
Update History
Complete audit trail of all container updates with version transitions, duration tracking, timestamps, and performer attribution for compliance and troubleshooting.