diff --git a/containers/backupchecks/src/backend/app/main/__pycache__/routes_customers.cpython-311.pyc b/containers/backupchecks/src/backend/app/main/__pycache__/routes_customers.cpython-311.pyc deleted file mode 100644 index 12e3e86..0000000 Binary files a/containers/backupchecks/src/backend/app/main/__pycache__/routes_customers.cpython-311.pyc and /dev/null differ diff --git a/containers/backupchecks/src/backend/app/main/__pycache__/routes_daily_jobs.cpython-311.pyc b/containers/backupchecks/src/backend/app/main/__pycache__/routes_daily_jobs.cpython-311.pyc deleted file mode 100644 index 2d7e8f7..0000000 Binary files a/containers/backupchecks/src/backend/app/main/__pycache__/routes_daily_jobs.cpython-311.pyc and /dev/null differ diff --git a/containers/backupchecks/src/backend/app/main/__pycache__/routes_inbox.cpython-311.pyc b/containers/backupchecks/src/backend/app/main/__pycache__/routes_inbox.cpython-311.pyc deleted file mode 100644 index 693d55e..0000000 Binary files a/containers/backupchecks/src/backend/app/main/__pycache__/routes_inbox.cpython-311.pyc and /dev/null differ diff --git a/containers/backupchecks/src/backend/app/main/__pycache__/routes_jobs.cpython-311.pyc b/containers/backupchecks/src/backend/app/main/__pycache__/routes_jobs.cpython-311.pyc deleted file mode 100644 index 9f20fc3..0000000 Binary files a/containers/backupchecks/src/backend/app/main/__pycache__/routes_jobs.cpython-311.pyc and /dev/null differ diff --git a/containers/backupchecks/src/backend/app/main/__pycache__/routes_overrides.cpython-311.pyc b/containers/backupchecks/src/backend/app/main/__pycache__/routes_overrides.cpython-311.pyc deleted file mode 100644 index b14f819..0000000 Binary files a/containers/backupchecks/src/backend/app/main/__pycache__/routes_overrides.cpython-311.pyc and /dev/null differ diff --git a/containers/backupchecks/src/backend/app/main/__pycache__/routes_reporting_api.cpython-311.pyc b/containers/backupchecks/src/backend/app/main/__pycache__/routes_reporting_api.cpython-311.pyc deleted file mode 100644 index 8cbaa85..0000000 Binary files a/containers/backupchecks/src/backend/app/main/__pycache__/routes_reporting_api.cpython-311.pyc and /dev/null differ diff --git a/containers/backupchecks/src/backend/app/main/__pycache__/routes_reports.cpython-311.pyc b/containers/backupchecks/src/backend/app/main/__pycache__/routes_reports.cpython-311.pyc deleted file mode 100644 index a29e51e..0000000 Binary files a/containers/backupchecks/src/backend/app/main/__pycache__/routes_reports.cpython-311.pyc and /dev/null differ diff --git a/containers/backupchecks/src/backend/app/main/__pycache__/routes_run_checks.cpython-311.pyc b/containers/backupchecks/src/backend/app/main/__pycache__/routes_run_checks.cpython-311.pyc deleted file mode 100644 index ae26683..0000000 Binary files a/containers/backupchecks/src/backend/app/main/__pycache__/routes_run_checks.cpython-311.pyc and /dev/null differ diff --git a/containers/backupchecks/src/backend/app/main/__pycache__/routes_search.cpython-311.pyc b/containers/backupchecks/src/backend/app/main/__pycache__/routes_search.cpython-311.pyc deleted file mode 100644 index 7569128..0000000 Binary files a/containers/backupchecks/src/backend/app/main/__pycache__/routes_search.cpython-311.pyc and /dev/null differ diff --git a/containers/backupchecks/src/backend/app/main/__pycache__/routes_settings.cpython-311.pyc b/containers/backupchecks/src/backend/app/main/__pycache__/routes_settings.cpython-311.pyc deleted file mode 100644 index 40d00bc..0000000 Binary files a/containers/backupchecks/src/backend/app/main/__pycache__/routes_settings.cpython-311.pyc and /dev/null differ diff --git a/containers/backupchecks/src/backend/app/main/__pycache__/routes_tickets.cpython-311.pyc b/containers/backupchecks/src/backend/app/main/__pycache__/routes_tickets.cpython-311.pyc deleted file mode 100644 index 9560bbf..0000000 Binary files a/containers/backupchecks/src/backend/app/main/__pycache__/routes_tickets.cpython-311.pyc and /dev/null differ diff --git a/docs/changelog-claude.md b/docs/changelog-claude.md index 4fe9e7f..3bd7615 100644 --- a/docs/changelog-claude.md +++ b/docs/changelog-claude.md @@ -36,6 +36,58 @@ This file documents all changes made to this project via Claude Code. - Session status codes documented (D9F00: 2=Failed, 5=Completed, 8=CompletedWithErrors, etc.) - Updated `TODO-cove-data-protection.md` with breakthrough status and next steps +### Changed +- Cove import/link behavior and visibility refinements: + - Fixed Settings → Cove "Run import now" button submission issue caused by nested form markup + - `/cove/accounts` now shows derived fields for faster linking decisions: + - `backup_software` (Cove Data Protection) + - derived `backup_type` (Server, Workstation, Microsoft 365) + - derived `job_name` + - human-readable datasource labels + - `computer_name` visible in matched and unmatched sections + - Linking a Cove account now triggers an immediate import attempt, so latest runs can appear without waiting for interval + - Improved feedback after linking with per-linked-job run delta and clearer reason when no run is created + - Cove run enrichment: + - `JobRun.remark` now stores account/computer/customer/status/last-run summary + - per-datasource run object records now include status detail text and datasource session timestamp + - Cove timestamp fallback for run creation: use `D09F15`, fallback to `D09F09` when needed + +### Fixed +- Cove deduplication scope: + - Dedup check changed from global `external_id` to per-job (`job_id + external_id`) to prevent newly linked/relinked jobs from being blocked by sessions imported under another job +- Navbar compression for split-screen usage: + - Reworked top navigation to reduce horizontal pressure without forced full collapse + - Moved admin-only links into `Admin` dropdown + - Added `More` dropdown for secondary non-admin navigation links + - Kept primary daily operational link (`Run Checks`) directly visible + - Adjusted role-specific visibility: Viewer now has `Customers` and `Jobs` directly visible in navbar + +### Added +- Microsoft Entra SSO implementation (branch `v20260223-07-entra-sso`): + - Authorization code flow routes: + - `GET /auth/entra/login` + - `GET /auth/entra/callback` + - Entra-aware logout flow (redirects through Entra logout endpoint when applicable) + - Login page support for "Sign in with Microsoft" button when SSO is configured/enabled + - Settings-backed Entra configuration fields in `SystemSettings` + migration support: + - `entra_sso_enabled` + - `entra_tenant_id` + - `entra_client_id` + - `entra_client_secret` + - `entra_redirect_uri` + - `entra_allowed_domain` + - `entra_allowed_group_ids` + - `entra_auto_provision_users` + - Optional local auto-provisioning of unknown Entra users as Viewer + - Security-group gate for SSO: + - allowlist by Entra Group Object IDs + - login blocked when token lacks required group context or group overage prevents reliable evaluation +- Documentation updates for Entra SSO: + - Added page `documentation/settings/entra-sso` + - Added navigation entry under Settings + - Marked explicitly as **Untested in Backupchecks** + - Included setup instructions for tenant/client/secret/redirect, group-based access, and troubleshooting + ## [2026-02-19] ### Added diff --git a/docs/technical-notes-codex.md b/docs/technical-notes-codex.md index 3a6d0c1..ae5da3a 100644 --- a/docs/technical-notes-codex.md +++ b/docs/technical-notes-codex.md @@ -1,6 +1,6 @@ # Technical Notes (Internal) -Last updated: 2026-02-23 +Last updated: 2026-02-23 (late) ## Purpose Internal technical snapshot of the `backupchecks` repository for faster onboarding, troubleshooting, and change impact analysis. @@ -73,6 +73,7 @@ File: `containers/backupchecks/src/backend/app/models.py` - `SystemSettings` with Graph/mail settings, import settings, UI timezone, dashboard policy, sandbox flag. - Autotask configuration and cache fields are present. - Cove Data Protection fields: `cove_enabled`, `cove_api_url`, `cove_api_username`, `cove_api_password`, `cove_import_enabled`, `cove_import_interval_minutes`, `cove_partner_id`, `cove_last_import_at`. + - Microsoft Entra SSO fields: `entra_sso_enabled`, `entra_tenant_id`, `entra_client_id`, `entra_client_secret`, `entra_redirect_uri`, `entra_allowed_domain`, `entra_allowed_group_ids`, `entra_auto_provision_users`. - Logging: - `AuditLog` (legacy alias `AdminLog`). - Domain: @@ -208,7 +209,7 @@ Cove (N-able) Data Protection is a cloud backup platform. Backupchecks integrate 4. Admin can: - **Create new job** – creates a `Job` with `backup_software="Cove Data Protection"` and links it. - **Link to existing job** – sets `job.cove_account_id` and `cove_acc.job_id`. -5. On the next import, linked accounts generate `JobRun` records (deduplicated via `external_id`). +5. Linking an account triggers an immediate import attempt; linked accounts then generate `JobRun` records (deduplicated per job via `job_id + external_id`). 6. Per-datasource objects are persisted to `customer_objects`, `job_object_links`, `run_object_links`. ### CoveAccount Model @@ -231,8 +232,26 @@ class CoveAccount(db.Model): ``` ### Deduplication -`external_id = f"cove-{account_id}-{run_ts}"` where `run_ts` is the Unix timestamp from `D09F15`. -Before creating a `JobRun`, check `JobRun.query.filter_by(external_id=external_id).first()`. +`external_id = f"cove-{account_id}-{run_ts}"` where `run_ts` is Unix timestamp from `D09F15` (fallback to `D09F09` when needed). + +Deduplication is enforced per linked job: +- check `JobRun.query.filter_by(job_id=job.id, external_id=external_id).first()` +- this prevents cross-job collisions when accounts are relinked. + +### Run Enrichment +- Cove-created `JobRun.remark` contains account/computer/customer and last status/timestamp summary. +- Per-datasource run object records include: + - mapped Backupchecks status + - readable status details in `error_message` + - datasource-level session timestamp in `observed_at` + +### Cove Accounts UI Notes +- `/cove/accounts` derives display fields to align with existing job logic: + - `backup_software`: `Cove Data Protection` + - `backup_type`: `Server`, `Workstation`, or `Microsoft 365` + - `job_name`: based on Cove account/computer fallback + - readable datasource labels instead of raw `I78` code stream +- `computer_name` is shown in both unmatched and matched account tables. ### Background Thread `cove_importer_service.py` — same pattern as `auto_importer_service.py`: @@ -277,7 +296,38 @@ Settings → Integrations → Cove section: 2. **Autotask Tickets** (job_runs columns) - Created via Run Checks modal → "Create Autotask Ticket" - Stored directly in JobRun columns: `autotask_ticket_id`, `autotask_ticket_number`, etc. - - When created, also creates matching internal ticket for legacy UI compatibility +- When created, also creates matching internal ticket for legacy UI compatibility + +## Microsoft Entra SSO (Current State) + +### Status +- Implemented but marked **Untested in Backupchecks**. + +### Routes +- `GET /auth/entra/login` – starts Entra auth code flow. +- `GET /auth/entra/callback` – exchanges code, maps/provisions local user, logs in session. +- `/auth/logout` – Entra-aware logout redirect when user authenticated via Entra. + +### Access Controls +- Optional tenant/domain restriction (`entra_allowed_domain`). +- Optional Entra security-group allowlist (`entra_allowed_group_ids`) based on group object IDs. +- Group overage / missing groups claim blocks login intentionally when group gate is enabled. + +### Local User Mapping +- Primary mapping by `preferred_username`/UPN/email. +- Optional auto-provision (`entra_auto_provision_users`) creates local Viewer users for unknown identities. + +### Documentation +- Built-in docs page: `/documentation/settings/entra-sso` +- Includes configuration steps and explicit untested warning. + +## Navbar Notes (Latest) + +- To reduce split-screen overflow, nav is compacted by grouping: + - admin-only links under `Admin` dropdown + - secondary non-admin links under `More` dropdown +- Primary operational links remain visible (notably `Run Checks`). +- Viewer role now exposes `Customers` and `Jobs` directly in navbar. - Have `autotask_ticket_deleted_at` field for deletion tracking - Resolution tracked via matching internal ticket's `resolved_at` field - **Auto-propagation**: Linked to new runs via two-strategy approach