diff --git a/install/03_create_config_tables.sql b/install/03_create_config_tables.sql index dde59ef3..cc6781e8 100644 --- a/install/03_create_config_tables.sql +++ b/install/03_create_config_tables.sql @@ -712,6 +712,72 @@ BEGIN ); END; + /* + Create config.remediation_action_log — durable, append-only audit trail for the + approval-gated "Apply Fix" feature (B3). One row per apply/unapply attempt + (success/skip/error/abort) for every privileged mutation the Dashboard issues + against a monitored server: sys.sp_query_store_(un)force_plan (PLAN_REGRESSION), + ALTER DATABASE SET (always-safe DB-config + RCSI), or DBCC FREEPROCCACHE + (CLEAR_PLAN). Force-plan rows carry query_id/plan_id; the others leave those NULL + and record the prior state in prior_value. consent_acknowledged marks a DESTRUCTIVE + apply (RCSI) that passed the informed-consent gate (0 otherwise). Lives in config + alongside the other operational logs. Created here (in the install scripts, not the + upgrade folder) so a FRESH install gets it; the installer re-runs the install scripts + on upgrade too, so existing databases get it as well. + */ + IF OBJECT_ID(N'config.remediation_action_log', N'U') IS NULL + BEGIN + IF @debug = 1 + BEGIN + RAISERROR(N'Creating config.remediation_action_log table', 0, 1) WITH NOWAIT; + END; + + CREATE TABLE + config.remediation_action_log + ( + action_id bigint IDENTITY(1, 1) NOT NULL, + applied_utc datetime2(7) NOT NULL + CONSTRAINT df_remediation_action_log_applied_utc + DEFAULT (SYSUTCDATETIME()), + operator_identity nvarchar(256) NULL, /* app / OS identity that clicked Apply */ + executing_login sysname NULL, /* SUSER_SNAME() actually used on the target */ + used_elevated_cred bit NOT NULL + CONSTRAINT df_remediation_action_log_used_elevated_cred + DEFAULT (0), /* always 0 in v1 (no in-app elevation); reserved */ + target_server nvarchar(256) NULL, + target_database sysname NOT NULL, + finding_fact_key varchar(64) NOT NULL, /* e.g. 'PLAN_REGRESSION' | 'DB_CONFIG' | 'RCSI' | 'CLEAR_PLAN' */ + query_id bigint NULL, /* force-plan only; NULL otherwise */ + plan_id bigint NULL, /* force-plan only; NULL otherwise */ + action varchar(32) NOT NULL, /* 'force'|'unforce'|'set_auto_shrink_off'|'set_auto_close_off'|'set_page_verify_checksum'|'set_read_committed_snapshot_on'|'clear_cached_plan' */ + prior_value nvarchar(128) NULL, /* prior state for manual reversal; NULL for force-plan */ + generated_sql nvarchar(max) NULL, /* the previewed statement, recorded only — never executed */ + result varchar(16) NOT NULL, /* 'success' | 'skipped' | 'error' | 'aborted' */ + error_message nvarchar(max) NULL, + source_alert_ref nvarchar(256) NULL, /* metric_name / story hash for traceback */ + consent_acknowledged bit NOT NULL + CONSTRAINT df_remediation_action_log_consent_acknowledged + DEFAULT (0), /* destructive apply (RCSI) passed the consent gate; 0 otherwise */ + CONSTRAINT pk_remediation_action_log PRIMARY KEY CLUSTERED (action_id) WITH (DATA_COMPRESSION = PAGE) + ); + + SET @tables_created = @tables_created + 1; + + INSERT INTO + config.collection_log + ( + collector_name, + collection_status, + error_message + ) + VALUES + ( + N'ensure_config_tables', + N'TABLE_CREATED', + N'Created config.remediation_action_log table' + ); + END; + /* Log final summary */ diff --git a/upgrades/2.11.0-to-2.12.0/02_create_remediation_action_log.sql b/upgrades/2.11.0-to-2.12.0/02_create_remediation_action_log.sql deleted file mode 100644 index 9ff63faa..00000000 --- a/upgrades/2.11.0-to-2.12.0/02_create_remediation_action_log.sql +++ /dev/null @@ -1,99 +0,0 @@ -/* -Copyright 2026 Darling Data, LLC -https://www.erikdarling.com/ - -Upgrade from 2.11.0 to 2.12.0 -Creates config.remediation_action_log — the durable, append-only audit trail for -the approval-gated "Apply Fix" feature (B3). One row is written per apply/unapply -attempt (success, skip, error, or abort), so every privileged mutation the -Dashboard issues against a monitored server (sys.sp_query_store_force_plan for a -plan regression, or ALTER DATABASE SET for an always-safe DB-config fix) is -recorded with who/what/when/where/result. Force-plan rows carry query_id/plan_id; -DB_CONFIG rows leave those NULL and record the prior setting in prior_value. - -Lives in the config schema alongside the other operational logs -(config.collection_log, config.installation_history). Idempotent: guarded by -OBJECT_ID so a re-run is a no-op. - -B3 is coupled to this 2.12.0 schema: the Dashboard hard-blocks Apply on any -server where this table does not yet exist (no mutation is attempted), so an -un-upgraded server can never produce an applied-but-unlogged action. -*/ - -SET ANSI_NULLS ON; -SET ANSI_PADDING ON; -SET ANSI_WARNINGS ON; -SET ARITHABORT ON; -SET CONCAT_NULL_YIELDS_NULL ON; -SET QUOTED_IDENTIFIER ON; -SET NUMERIC_ROUNDABORT OFF; -SET IMPLICIT_TRANSACTIONS OFF; -SET STATISTICS TIME, IO OFF; -GO - -USE PerformanceMonitor; -GO - -IF OBJECT_ID(N'config.remediation_action_log', N'U') IS NULL -BEGIN - CREATE TABLE - config.remediation_action_log - ( - action_id bigint IDENTITY(1, 1) NOT NULL - CONSTRAINT pk_remediation_action_log - PRIMARY KEY CLUSTERED, - applied_utc datetime2(7) NOT NULL - CONSTRAINT df_remediation_action_log_applied_utc - DEFAULT (SYSUTCDATETIME()), - operator_identity nvarchar(256) NULL, /* app / OS identity that clicked Apply */ - executing_login sysname NULL, /* SUSER_SNAME() actually used on the target */ - used_elevated_cred bit NOT NULL - CONSTRAINT df_remediation_action_log_used_elevated_cred - DEFAULT (0), /* always 0 in v1 (no in-app elevation); reserved */ - target_server nvarchar(256) NULL, - target_database sysname NOT NULL, - finding_fact_key varchar(64) NOT NULL, /* e.g. 'PLAN_REGRESSION' | 'DB_CONFIG' */ - query_id bigint NULL, /* force-plan only; NULL for DB_CONFIG rows */ - plan_id bigint NULL, /* force-plan only; NULL for DB_CONFIG rows */ - action varchar(32) NOT NULL, /* 'force' | 'unforce' | 'set_auto_shrink_off' | 'set_auto_close_off' | 'set_page_verify_checksum' */ - prior_value nvarchar(128) NULL, /* DB_CONFIG prior value for manual reversal ('ON' | 'NONE' | 'TORN_PAGE_DETECTION'); NULL for force-plan */ - generated_sql nvarchar(max) NULL, /* the previewed statement, recorded only — never executed */ - result varchar(16) NOT NULL, /* 'success' | 'skipped' | 'error' | 'aborted' */ - error_message nvarchar(max) NULL, - source_alert_ref nvarchar(256) NULL /* metric_name / story hash for traceback */ - ); - - PRINT 'Created config.remediation_action_log'; -END; -ELSE -BEGIN - PRINT 'config.remediation_action_log already exists — no action taken'; -END; -GO - -/* -B3 Phase 3 (consent_acknowledged): idempotent guarded ALTER, NOT a create-body amend. -The CREATE above is guarded by IF OBJECT_ID(...) IS NULL, so adding the column inside -that block would only land on servers where the table does not yet exist; servers that -already ran an earlier 2.11.0-to-2.12.0/02_ (incl. multi-machine test servers) would -keep the column-less table and turn EVERY audit INSERT into "invalid column name". -This COL_LENGTH-guarded ALTER is correct on BOTH fresh and pre-existing tables. - -consent_acknowledged records that a DESTRUCTIVE apply (RCSI) passed the informed-consent -(acknowledge-each-risk) gate. Always 0 for the always-safe DB-config and force-plan rows. -*/ -IF COL_LENGTH(N'config.remediation_action_log', N'consent_acknowledged') IS NULL -BEGIN - ALTER TABLE - config.remediation_action_log - ADD consent_acknowledged bit NOT NULL - CONSTRAINT df_remediation_action_log_consent_acknowledged - DEFAULT (0); - - PRINT 'Added config.remediation_action_log.consent_acknowledged'; -END; -ELSE -BEGIN - PRINT 'config.remediation_action_log.consent_acknowledged already exists — no action taken'; -END; -GO diff --git a/upgrades/2.11.0-to-2.12.0/03_make_other_process_cpu_nullable.sql b/upgrades/2.11.0-to-2.12.0/02_make_other_process_cpu_nullable.sql similarity index 100% rename from upgrades/2.11.0-to-2.12.0/03_make_other_process_cpu_nullable.sql rename to upgrades/2.11.0-to-2.12.0/02_make_other_process_cpu_nullable.sql diff --git a/upgrades/2.11.0-to-2.12.0/upgrade.txt b/upgrades/2.11.0-to-2.12.0/upgrade.txt index 4218c2d6..dc2756ff 100644 --- a/upgrades/2.11.0-to-2.12.0/upgrade.txt +++ b/upgrades/2.11.0-to-2.12.0/upgrade.txt @@ -1,3 +1,2 @@ 01_extend_blocked_process_report_columns.sql -02_create_remediation_action_log.sql -03_make_other_process_cpu_nullable.sql +02_make_other_process_cpu_nullable.sql