Commit graph

35 commits

Author SHA1 Message Date
66ed4e11b3 Review 1.4: AX 3.0/4.0 local times in the AX time zone, with its DST rules
Axapta 3.0 and AX 4.0 store batch and cleanup times as a local date plus
seconds. They were turned into UTC with the SQL Server's offset at collection
time, so every time from the other side of a DST change was an hour off (a job
planned 01:50 CET on the spring night looked 70 minutes late at 03:00 CEST),
and a SQL Server running UTC behind a CET AOS shifted every time.

AxLocalTime converts with the rules of the AX time zone on that date:
SQLInsight:DynamicsAx:LocalTimeZone (Windows or IANA id), else the agent's own
zone when its offset matches the SQL Server's, else the server's offset (to the
nearest quarter hour) with a Danish data note. The skipped spring hour and the
repeated autumn hour get standard time (deterministic, never throws, never a
false "late"); seconds outside 0..86400 are unknown and 86400 is midnight. The
AX 3.0 cleanup time is local by version, also when LATESTCLEANTIME is missing.
AX 2009+ UTC times are untouched. Also: remaining numbers cannot overflow for
HIGHEST = Int64.MaxValue, and run keys use the invariant culture.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-02 14:19:17 +02:00
36ad4c0656 Repository and agent: Dynamics AX history (migration 0017), seeding, hub opt-in
0017_dynamics_ax adds insight.AxBatchRuns (completed batch runs, EventDays
retention) and insight.AxSequenceSamples (one NEXTREC/NEXTVAL sample per
sequence per day, HourlyDays retention). The agent reads them back after a
restart so job comparisons and forecasts continue, takes its thresholds from
SQLInsight:DynamicsAx, and only sends findings of the built-in SQLI-AX rules
to the hub for databases with the AX opt-in ticked; AX rule reasons (which
can name tables, logins and GRANT text) are replaced by a fixed text.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-02 13:53:34 +02:00
12cf5a1e94 Review 1.3: a request that fails in an unexpected way is completed as failed, not left Running
HandleAsync only turned a few exception types into the request's error; anything
else (a lock or command timeout, a JSON or argument error) escaped, leaving the
row Running and the page waiting until housekeeping failed it minutes later.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-02 13:22:43 +02:00
a6a72661e7 Review 1.3: a routine discovery that could not be stored is not retried every 2 seconds
When saving a discovery failed in the repository (deadlock victim, lock timeout,
connection), LastDiscoveryAt stayed unset and the next round 2 seconds later
listed the same instance's databases again, loading the customer's server. The
agent now waits at least 15 minutes between routine discoveries of an instance.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-02 13:22:42 +02:00
f5ff42ca83 Review 1.3: an unreadable agent key file is kept, not overwritten
LoadOrCreate replaced a key file it could not decrypt, which made the old key
unrecoverable even when only the machine (DPAPI) had changed and the file could
have been put back. The file is now moved aside as credential-key.bin.unreadable-*
and the RSA object of the failed import is disposed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-02 13:22:42 +02:00
29e1909e98 Review 1.3: one implementation of a service account's SQL login
RepositorySetup.LoginFor/IsLocal duplicated Core's ServiceAccounts, which the web
uses for the GRANT script. Setup now uses ServiceAccounts too, so the login the
installer grants and the one the web shows cannot drift apart.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-02 13:22:41 +02:00
5ad9355130 Docs: Servere og databaser (1.3)
New docs/servere-og-databaser.md (on the community site too): adding servers,
who may change it (AdminGroups), connection test and GRANT script run by the
agent, database choice, configuration file servers, how SQL login passwords are
sealed and why, the repository grants, and the API. Installation, integration
(scope config:write) and data processing (AX findings to the hub are off by
default) point to it; AdminGroups in the web's appsettings.json.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-02 13:22:41 +02:00
81b8376026 Agent: instances from the repository, request queue, sealed passwords, AX hub opt-in
The agent mirrors SQLInsight:Instances into the repository at start (read-only
"fra konfigurationsfil" rows, every database monitored as before) and reads the
configuration on every tick: instances added, paused, removed or changed in
SQLInsight Web, and database choices, take effect without a restart. If the
repository cannot be read before the first load, the configuration file alone
is used.

AgentRequestService runs connection tests (with the permission check), database
discovery and instance discovery (SQL Server Browser, registry) as the agent's
own identity, and refreshes every instance's database list hourly. The agent
keeps an RSA key (DPAPI LocalMachine, restricted folder) and publishes its public
key and identity; SQL login passwords sealed by the web UI are opened only here.

Dynamics AX findings and AX rule outcomes are sent to SQLInsight Hub only for
databases where it is turned on (default off).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-02 13:22:41 +02:00
6cc65e3c75 Index usage over time and never-updated statistics (8g, F)
The index collector now sums index reads and writes between collections
across restarts of SQL Server (and of the agent, by seeding from the
stored snapshot) and keeps them per day in insight.IndexUsageDaily
(migration 0015, HourlyDays). SQLI-IDX-002 judges an index once it has
been followed for 7 days instead of needing 7 days of uptime.
GET /api/v1/instances/{name}/index-usage lists usage per index.

SQLI-STAT-001 also reports statistics that were never updated on tables
with rows; statistic rows now come from the table's heap or clustered
index, as a never-updated statistic has no row count of its own.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-02 10:55:22 +02:00
4d18d20ab0 tempdb and version store (8c)
A five-minute collector reads tempdb space (free, version store, user and
internal objects, whether files can grow), the 'Version Store Size (KB)'
counter, the sessions using most tempdb, the oldest snapshot transaction
and, only when the version store is large, the databases generating
versions. Trend and heavy sessions survive restarts; used space and the
version store become metrics with explanation and assessment.

Rules SQLI-TEMP-001 (version store > 1 GB or steadily growing),
SQLI-TEMP-002 (nearly full and cannot grow) and SQLI-TEMP-003 (session
above 1 GB for 15 minutes), configurable under SQLInsight:Tempdb.
"tempdb lige nu" on the instance page; GET /api/v1/instances/{name}/tempdb.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-02 10:42:38 +02:00
6f7839d011 Long and large transactions and long-running statements (8b, 8d)
A one-minute collector reads open user transactions (age, log bytes used
and reserved, database, session, login, program, statement) and user
requests running longer than the threshold, leaving out the agent's own
and system sessions, BACKUP/RESTORE/DBCC (long operations) and requests
waiting on purpose. Transactions open a minute or holding 100 MB are kept
in insight.LongTransactions (migration 0014, RawDays).

Rules SQLI-TRAN-001 (open > 10 min, High at 6x), SQLI-TRAN-002 (> 1 GB
log) and SQLI-REQ-001 (statement > 15 min), configurable under
SQLInsight:Activity. Shown "right now" on the instance page and in the
time window analysis and PDF; GET /api/v1/instances/{name}/activity and
the analysis JSON leave logins and statements out.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-02 10:36:41 +02:00
e6840e40d7 SQL Server error log without elevated rights (8a)
A five-minute collector reads important error log entries from the best
source the agent's rights allow: the error log itself (xp_readerrorlog,
only with securityadmin), the default trace's ErrorLog and Audit Login
Failed events (optional ALTER TRACE), or the exception and connectivity
ring buffers (VIEW SERVER STATE: numbers and severity, failed logins).
Repetitions are summed per error; the watermark is the newest entry
read, because the default trace is buffered. Stored in
insight.ErrorLogEvents (migration 0013, EventDays), resumed after restart.

Rules SQLI-LOG-001..006: corruption 823/824/825, I/O over 15 s (833),
severe errors (17+), login failure bursts (configurable), stack dumps and
AG errors; rules needing the log text are "not measurable" with the
right to grant. Page /instanser/{navn}/fejllog (menu Overvågning) and
GET /api/v1/instances/{name}/error-log with messages redacted.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-02 10:30:41 +02:00
f3551b1bf0 Support cases through the API: create, read and close
- POST/GET /api/v1/support-cases[/{id}] and POST .../{id}/close in
  SQLInsight Web, sharing the /support form's logic: same checks, finding
  prefill without sensitive evidence, Idempotency-Key as the request id,
  202 Accepted with Location, problem+json 403 without the support:write
  scope or a support license. RequestedBy is the Windows user or
  token:<name>.
- Closing: "Luk sag" on /support and the API record CloseRequested
  (migration 0012, column-level UPDATE for the read-only web login); the
  agent sends it to the hub with backoff and sets Closed when confirmed;
  a pending case is closed once it has a number; an older hub list never
  turns CloseRequested back to Open.
- Hub: POST /api/v1/cases/{reference}/close for the license's own cases
  (others 404), idempotent, ClosedBy/ClosedComment (EF migration
  CaseClosedBy). Portal closing records "SEOSoft: <user>"; the customer
  page shows who closed and why; the support report and CSV get "Lukket af".

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-02 09:47:58 +02:00
384e1f154f Long operations, full-text rules and statement activity
- Long operations: a one-minute collector reads operations with progress
  from sys.dm_exec_requests (BACKUP, RESTORE, DBCC, REORGANIZE, SHRINK,
  ROLLBACK): command, database, start, percent, expected end, login.
  Stored in insight.LongOperations (migration 0011, RawDays), shown on
  the instance page, in the time window analysis and its PDF. The last
  10 durations per command and database survive restarts; SQLI-OPS-001
  flags a backup/restore running over twice the median.
- Full-text community rules COM-FT-001..005 (metadata only, 2005 syntax):
  disk-full or paused/throttled catalogs, stale manual/off change
  tracking indexes and disabled indexes.
- Statement activity (CPU time / time in plan cache): column in top SQL
  and SQLI-CPU-002 when above SQLInsight:TopSql:ActivityThresholdPercent
  (default 50) for at least an hour. Never clears the plan cache.
- BuiltInCollectors.Create takes a CollectorSettings record.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-02 09:07:29 +02:00
20671bfb06 Wait type drill-down with active session sampling
A new light collector samples sys.dm_exec_requests every 15 seconds:
waiting user sessions (not the agent's own) by wait type, database and
statement (same key as top SQL), with blocking. Sampling-only cycles
reuse the last probe and skip rule evaluation. Stored in
insight.ActiveWaitSamples (migration 0010) for RawDays.

Wait types on the instance page and in the analysis link to
/instanser/{navn}/ventetyper/{type}: Danish explanation from a new
knowledge base (shared with the SQLI-WAIT rules, with Dynamics AX notes),
trend over time, the statements that waited with share and estimated
wait, a link to the full text (/instanser/{navn}/sql) and, for lock
waits, to blocking in the same window. SQL Server 2005 compatible.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-02 08:50:31 +02:00
4ba7e5195e Privilege audit: sysadmin and server roles with AD unfolding
Collects members of the fixed server roles and CONTROL SERVER every 15
minutes with login type, disabled state and SQL login password policy.
Windows groups are unfolded recursively through Active Directory on a
Windows agent (cached, 20 s timeout, failures shown with the reason).
Changes since the previous collection are logged, and who/when is read
from the default trace (event 108) when the agent has the optional
ALTER TRACE; authors that only reach the buffered trace later are filled
in at the next collection. The first collection is the baseline.

New rules SQLI-SEC-001 (new privilege, High for sysadmin/securityadmin/
CONTROL SERVER) and SQLI-SEC-002 (more sysadmins than the limit, default
3). Names are sensitive evidence and never in titles or subjects.

Web: /instanser/{navn}/rettigheder and /rettigheder with change log by
period, alert banner on the instance page and overview, and an audit
PDF (/rapporter/rettigheder.pdf) linked from Rapporter.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-02 08:39:56 +02:00
ab8cfcad97 Configuration page with change log
- new collector instance-config: collation, edition, version, services and
  accounts (sys.dm_server_services, 2008 R2 SP1+), Instant File
  Initialization and Lock Pages in Memory (where the build has the
  columns), tempdb files, default paths; plus a fingerprint of the whole
  setup (sp_configure, trace flags, services, version, tempdb files)
- changes are computed against the previous collection, which the agent
  restores from the repository after a restart; migration 0008 keeps them
  in insight.ConfigurationChanges (as long as resolved findings)
- SQLI-CFG-013 "Konfiguration ændret": information for a day when
  sp_configure, a trace flag or a service account changes (account names
  are sensitive evidence)
- page /instanser/{navn}/konfiguration: instance, CPU and memory, services,
  tempdb, trace flags, non-default sp_configure (default vs. in use vs.
  configured) and the change log; linked from the instance page
- the management report lists configuration changes in the period
- trace flag reading shared by trace-flags and instance-config

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-02 08:12:26 +02:00
244153e9e4 Rules the version does not support are "not applicable", not "not measurable"
On SQL Server 2005 twenty rules stood as "not measurable" (Query Store,
system_health, memory columns …) between the real gaps, and counted in the
overview's "regler ikke målbare". They are not gaps: the version simply
lacks what they look at.

- New RuleOutcome.NotApplicable (last in the enum: outcomes are stored as
  numbers, so existing rows keep their meaning).
- A rule or collector missing only capabilities inherent to the instance
  (version-gated, plan cache memory columns, or Azure-managed) is not
  applicable, with the version each needs: "Ikke relevant for SQL Server
  2005: kræver QueryStore (fra SQL Server 2016)". Missing settings or rights
  (HADR not enabled …), collector failures and permission errors stay
  "not measurable". CollectedData.MarkNotApplicable carries this from
  collectors to the rules that use their data; community rules below their
  minimumVersion are not applicable too.
- Counts are unchanged in shape: the overview, KPI, JSON API and Prometheus
  count outcomes 2 and 3 only. The instance page lists the rest in a
  collapsed "Ikke relevant for SQL Server 2005 (n)" (details/summary, no
  JS) after the real gaps. Report controls whose core rule does not apply
  count neither as met nor as not measured.

Tests: engine (version vs. setting vs. collected data), inherent
capabilities, the existing version tests now expect not applicable, report
control status, and the web page and overview count.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-01 16:05:39 +02:00
50bc878776 Customers file support cases in SQLInsight Web and follow their status
- Repository migration 0005: insight.SupportCases. The web UI has only
  db_datareader, so INSERT on this one table is granted to public.
- Web: /support (menu "Support") lists the customer's cases and, with
  Hub sync on and a Professional/Enterprise license, a form (title,
  description, contact; contact prefilled from the Windows user).
  /support?fund=<id> prefills from a finding: instance, rule, severity,
  explanation and non-sensitive measurements.
- "Opret supportsag" on findings: right-click a finding link or a
  finding's heading (support-menu.js, a static file within the CSP;
  Shift+F10/context key, Escape closes), and a visible button on the
  finding page that works without JavaScript. Only when support is
  available.
- Agent: sends pending requests to POST /api/v1/cases, stores the case
  number, backs off on failures and gives up on 400/401/403/422; fetches
  the customer's cases every 5 minutes (at once after sending).
- Docs: support.md (also on the community site), databehandling.md
  (contact details are sent to the hub).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-01 11:34:06 +02:00
6d755aa3d0 Installer creates the repository database, logins and rights itself
Some checks failed
deploy community / deploy (push) Successful in 1s
deploy hub / deploy (push) Successful in 19s
CI / Build og unit tests (push) Successful in 8s
CI / MSI-installer (push) Successful in 15s
CI / Integration (mcr.microsoft.com/mssql/server:2017-latest) (push) Has been cancelled
CI / Integration (mcr.microsoft.com/mssql/server:2019-latest) (push) Has been cancelled
CI / Integration (mcr.microsoft.com/mssql/server:2022-latest) (push) Has been cancelled
CI / Integration (mcr.microsoft.com/mssql/server:2025-latest) (push) Has been cancelled
Entering a connection string in the installer is now enough: the new
command `SQLInsight.Agent.exe setup-repository` runs as a deferred custom
action after the services exist and sqlinsight.ini is written, and before
they start. It runs as the installing user on purpose (SQL Server must see
a person with rights, not SYSTEM) and:

- creates the database from Database=... if it is missing
- creates logins/users for the service accounts: agent db_owner, web
  db_datareader. NT SERVICE\... accounts arrive at another computer as
  DOMAIN\COMPUTER$, which then gets the login instead
- runs the schema migrations
- with MONITOR_SERVER: creates the agent's login there and applies
  grant-least-privilege.sql (embedded). A failure there is a warning only

A repository failure stops the installation; the reason goes to the
Application event log with a Danish hint (login, rights, certificate,
unreachable). SKIP_REPOSITORY_SETUP=1 leaves it to a DBA. Safe to rerun.

verify-msi.py allows this one action to impersonate and checks its
placement, Return=check and condition. Tested against a local SQL
Express (twice, idempotent) and with an unreachable server. Version 1.0.1.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-01 08:18:26 +02:00
b9afc30436 Ship SEOSoft's license key k20261001; agent defaults to the real hub
Some checks are pending
CI / Integration (mcr.microsoft.com/mssql/server:2017-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2019-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2022-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2025-latest) (push) Blocked by required conditions
CI / Build og unit tests (push) Successful in 1m13s
deploy community / deploy (push) Successful in 0s
deploy hub / deploy (push) Successful in 20s
CI / MSI-installer (push) Successful in 43s
- trusted-keys.json: the public key from keygen (k20261001). The hub and
  every agent built from now on verify licenses with it; no
  TrustedKeys configuration is needed any more.
- The test that required an empty key file now checks what it was
  guarding against: every embedded key must be keygen output (id
  k<yyyyMMdd>, P-256 public key), never a test key.
- Agent: default Hub:Url https://hub.sqlinsight.seosoft.dk/ (was
  hub.seosoft.dk, which does not exist).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-01 07:15:47 +02:00
Claude
d764552c2c
MSI installer for Agent and Web
Some checks are pending
CI / Integration (mcr.microsoft.com/mssql/server:2019-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2022-latest) (push) Blocked by required conditions
CI / Build og unit tests (push) Waiting to run
CI / MSI-installer (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2017-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2025-latest) (push) Blocked by required conditions
installer/SQLInsight.wxs (WiX 3 syntax) builds on Linux with wixl
(installer/build-msi.sh) and in Forgejo CI on every v* tag. Agent and Web
are installed self-contained as Windows services under virtual service
accounts (or a gMSA), with a settings page in the wizard or MSI
properties for silent installs; the values go to sqlinsight.ini, read
after appsettings.json. The data folder is locked to SYSTEM,
Administrators and the agent account, the event log source is
registered, the web port is opened in the firewall, and the automatic
update task is an optional feature. Upgrades happen in place, keep
edited settings and the chosen features; uninstall keeps the settings.

msi-tables.py writes what wixl lacks (component and feature conditions,
Permanent/NeverOverwrite, vital services, REG_EXPAND_SZ) and
verify-msi.py checks the result (sequencing, deferred actions, ASCII
only). test-msi-wine.sh runs install, upgrade and uninstall under Wine.
Installations made with the MSI get new versions as MSI packages run by
the update task, so Windows Installer stays in charge of the files.
The example instance is removed from the shipped appsettings.json, and
the CLI writes UTF-8 to the console.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E3EExwndy8Z22EK2Qpt6BK
2026-09-29 11:31:28 +00:00
Claude
4269f6f9e8
Fase 4: experience across customers
Some checks are pending
CI / Build og unit tests (push) Waiting to run
CI / Integration (mcr.microsoft.com/mssql/server:2017-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2019-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2022-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2025-latest) (push) Blocked by required conditions
The hub records when an instance changes build and works out which
findings went away within three days of an update and which were still
there a week later (version rules excluded). Staff see every effect in
the portal; effects seen at three or more customers, resolved more
often than not, are served to licensed agents as anonymous counts
(rule, major version, build, CU, customers, instances). The agent
fetches them every six hours and the web UI shows them on matching
findings: 'at 3 customers this went away after updating to CU21'.
Data processing documentation covers the aggregation.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E3EExwndy8Z22EK2Qpt6BK
2026-09-29 10:33:37 +00:00
Claude
7f640e74e5
Fase 4: community and local rules written as SQL
Some checks are pending
CI / Build og unit tests (push) Waiting to run
CI / Integration (mcr.microsoft.com/mssql/server:2017-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2019-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2022-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2025-latest) (push) Blocked by required conditions
Rules can now be data: a JSON file with one read-only SELECT where every
row is a finding, with {column} templates, server or per-database scope,
minimum version, sensitive columns and references. Community rules live
in rules/community (reviewed via pull request), ship with every build
and with the signed rule pack; local rules are read from the agent's
data folder every five minutes. Queries are checked for anything that
could write, run with the least-privilege login, and a missing
permission makes the rule not measurable rather than failing. The
rule engine picks up catalog changes without a restart. Authors get
'rules validate' and 'rules test --instance'. Four example community
rules (sa active, orphaned database owners, default trace off,
untrusted foreign keys).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E3EExwndy8Z22EK2Qpt6BK
2026-09-29 10:23:01 +00:00
Claude
d238580614
Fase 4: management and compliance reports as PDF
Some checks are pending
CI / Build og unit tests (push) Waiting to run
CI / Integration (mcr.microsoft.com/mssql/server:2017-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2019-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2022-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2025-latest) (push) Blocked by required conditions
A PDF report for management and auditors (PDFsharp/MigraDoc, MIT, with
the Inter font embedded): key figures, a plain-language summary,
compliance controls backed by rules (met, not met, not measured),
instances and the critical and high findings. Downloadable from the
web UI (/rapporter) and mailed monthly by the agent with the PDF
attached, once per month, across daylight saving changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E3EExwndy8Z22EK2Qpt6BK
2026-09-29 10:09:10 +00:00
Claude
0e2146ef6d
Fase 4: integration with Prometheus, Grafana, SCOM and scripts
Some checks are pending
CI / Build og unit tests (push) Waiting to run
CI / Integration (mcr.microsoft.com/mssql/server:2017-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2019-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2022-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2025-latest) (push) Blocked by required conditions
Read-only JSON API (/api/v1/instances, /api/v1/findings) and a
Prometheus endpoint (/metrics) in the web UI, with bearer tokens for
machines (only their SHA-256 is configured; a token only opens the API,
never the pages; sensitive evidence left out unless enabled). A
Grafana dashboard and Prometheus scrape example. A Windows Event Log
notification channel with fixed event ids for SCOM, exempt from the
hourly cap.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E3EExwndy8Z22EK2Qpt6BK
2026-09-29 09:56:01 +00:00
Claude
19fbb02045
Fase 3: data processing, hub retention and deployment
Some checks are pending
CI / Build og unit tests (push) Waiting to run
CI / Integration (mcr.microsoft.com/mssql/server:2017-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2019-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2022-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2025-latest) (push) Blocked by required conditions
Hub: nightly retention of resolved findings, the submission log and
silent instances; delete-customer erases a customer's data and blocks
its licenses; persistent data protection keys and trusted reverse
proxies. Docker image and compose file with PostgreSQL. The agent
refuses to send the license to a non-https hub. Documentation for the
hub, for data processing (GDPR basis for a data processing agreement)
and the README roadmap for phase 3.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E3EExwndy8Z22EK2Qpt6BK
2026-09-29 09:29:20 +00:00
Claude
3121b598f9
Fase 3: signed updates of rule packs and the application
Some checks are pending
CI / Build og unit tests (push) Waiting to run
CI / Integration (mcr.microsoft.com/mssql/server:2017-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2019-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2022-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2025-latest) (push) Blocked by required conditions
Rule packs (support dates and newest CU per release) are published in a
signed feed and hot-loaded without a restart; the verified pack is
reloaded at startup. New versions are announced (Notify) or downloaded
and staged by the unprivileged agent (Automatic), and installed by a
privileged apply-update task that re-verifies signature and hash in an
admin-only folder, keeps appsettings/web.config, health-checks the
services and rolls back on failure. Stable and preview channels,
manifest expiry and rollback protection, https or folder/share feeds
for offline sites. Vendor tool gains rulepack and publish; the Hub can
serve the feed; the web UI gets a System page with update, rule pack,
license and exactly what is sent to the Hub.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E3EExwndy8Z22EK2Qpt6BK
2026-09-29 09:19:41 +00:00
Claude
bfb27778d2
Fase 3: findings sync from agent to hub (queue, retry, data minimization)
Some checks are pending
CI / Build og unit tests (push) Waiting to run
CI / Integration (mcr.microsoft.com/mssql/server:2017-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2019-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2022-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2025-latest) (push) Blocked by required conditions
- Evidence can be marked sensitive (query text, logins, hosts, programs,
  job error messages); rules mark it. Sensitive values and the server
  name are sent as [udeladt] unless the customer allows them.
- Full-state submission contract (all active findings and rule outcomes
  per instance), idempotent by submission id
- Local outbound queue in the repository (migration 0002): newest state
  per instance only, exponential backoff up to an hour, permanent
  rejections (bad license, bad request) are given up, sent items purged
- Hub status (license state, last sent, last error) for the web UI
- Sync runs only with a valid license (or in grace); monitoring never
  depends on it

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E3EExwndy8Z22EK2Qpt6BK
2026-09-29 08:35:22 +00:00
Claude
edb7410f76
Fase 2: Azure SQL Managed Instance, docs and rule catalog test
Some checks are pending
CI / Integration (mcr.microsoft.com/mssql/server:2017-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2019-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2022-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2025-latest) (push) Blocked by required conditions
CI / Build og unit tests (push) Waiting to run
- Managed Instance reports 12.0.2000.8 but is evergreen: treated as the
  newest engine with all capabilities; new SelfManagedInfrastructure
  capability so backup, CHECKDB, files, tempdb, memory, patch level and
  lifecycle rules report 'handled by Azure' instead of false findings
- Microsoft Entra ID login (managed identity, service principal, default
  credential chain) via SqlConnection.AccessTokenCallback
- Least-privilege script recognizes Managed Instance; deadlock collector
  falls back to the ring buffer when event files cannot be read
- Web UI shows the right release for Managed Instance
- README and installation docs: notifications and Managed Instance
- Catalog test: 61 rules with unique, well-formed ids

Integration suite green on SQL Server 2017 and 2022.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E3EExwndy8Z22EK2Qpt6BK
2026-09-29 08:23:40 +00:00
Claude
eac799a1f1
Fase 2: notifications by e-mail, Teams and webhook
Some checks are pending
CI / Integration (mcr.microsoft.com/mssql/server:2019-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2022-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2025-latest) (push) Blocked by required conditions
CI / Build og unit tests (push) Waiting to run
CI / Integration (mcr.microsoft.com/mssql/server:2017-latest) (push) Blocked by required conditions
- Repository reports which findings opened and resolved per evaluation
- Agent notifies on new and resolved findings and on instance
  unreachable/recovered transitions, with links to the web UI
- Channels: e-mail (MailKit, HTML-encoded), Microsoft Teams Workflows
  webhook (Adaptive Card), generic JSON webhook signed with HMAC-SHA256
- Per-channel minimum severity (outages always sent), one message per
  batch, hourly cap per channel; a failing channel never stops monitoring
- Tested with a real SMTP server (Mailpit) and the real agent pipeline

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E3EExwndy8Z22EK2Qpt6BK
2026-09-29 08:08:06 +00:00
Claude
d84cf8c2b6
Fase 2: baselines and anomaly detection
Some checks are pending
CI / Integration (mcr.microsoft.com/mssql/server:2017-latest) (push) Blocked by required conditions
CI / Build og unit tests (push) Waiting to run
CI / Integration (mcr.microsoft.com/mssql/server:2019-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2022-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2025-latest) (push) Blocked by required conditions
Baselines per hour of the week (with neighbouring hours) from four weeks
of hourly aggregates, computed in C# (independent of DATEFIRST) and
refreshed by the agent each hour. SQLI-ANOM-001 compares current load
with what is normal at this time: CPU far above normal, batch requests
far above or collapsed (application down?), page life expectancy
collapse. Not measurable until enough history exists.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E3EExwndy8Z22EK2Qpt6BK
2026-09-29 08:01:11 +00:00
Claude
5bb1c37fef
Fase 1: on-prem web UI (IIS or Windows service), light design system
Some checks are pending
CI / Integration (mcr.microsoft.com/mssql/server:2019-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2022-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2017-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2025-latest) (push) Blocked by required conditions
CI / Build og unit tests (push) Waiting to run
- ASP.NET Core Blazor static SSR: overview with KPI tiles, instance page
  (findings, CPU/batch/PLE trends, top waits, file latency, blocking,
  deadlocks with .xdl download, not-measurable rules, resolved), finding
  detail with explanation, evidence, fix script and references
- Light-first design (sidebar, cards, self-hosted Inter, teal accent),
  optional dark theme via toggle; strict CSP, no inline styles
- Windows authentication (Negotiate/IIS) with optional group restriction;
  refuses to run without authentication outside Development
- Hosting: IIS (in-process ASP.NET Core Module), Windows service with
  Kestrel, or systemd; web reads the repository with db_datareader only
- docs/installation.md for repository, permissions, agent and web
- Fix: CPU used by other processes is not derived on Linux (SystemIdle is
  unreliable there); deadlocks are not re-reported or stored twice after
  an agent restart; Dapper sends datetime2 so time comparisons are exact

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E3EExwndy8Z22EK2Qpt6BK
2026-09-29 06:58:51 +00:00
Claude
005a4f9663
Fase 1: agent scheduler wiring collectors, rules and repository
Some checks are pending
CI / Build og unit tests (push) Waiting to run
CI / Integration (mcr.microsoft.com/mssql/server:2017-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2019-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2022-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2025-latest) (push) Blocked by required conditions
Each instance runs its due collectors over one hardened connection per
cycle, keeps previous results for deltas, evaluates all rules and stores
findings, rule states and time series. Instances run in parallel with a
limit; a slow or failing instance never delays the others. The
repository is migrated at startup with retry, and maintenance runs hourly.
End-to-end test against SQL Server with the least-privilege login.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E3EExwndy8Z22EK2Qpt6BK
2026-09-29 06:26:01 +00:00
Claude
f8aa0c307b
Fase 0: solution structure, capability model, rule engine, least-privilege script
Some checks are pending
CI / Build og unit tests (push) Waiting to run
CI / Integration (mcr.microsoft.com/mssql/server:2017-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2019-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2022-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2025-latest) (push) Blocked by required conditions
- .NET 10 solution with Core, Connectivity, Rules, Contracts, Agent, Web and Hub
- Capability model gating collectors and rules by SQL Server version (2000 and later);
  rules that cannot run are reported as not measurable, never as passed
- Connectivity via Microsoft.Data.SqlClient with ODBC fallback for legacy instances,
  hardened monitoring session settings valid back to SQL Server 2000
- Support lifecycle rule (SQLI-VER-001) with lifecycle data shipped as a rule pack
- Version-aware least-privilege permissions script, verified by integration tests
  against SQL Server in Docker (reads monitoring sources, cannot read customer data)
- Forgejo Actions CI, contributing guide, code of conduct, issue templates,
  legacy version notes

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E3EExwndy8Z22EK2Qpt6BK
2026-09-29 05:40:49 +00:00