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
58 lines
3.1 KiB
C#
58 lines
3.1 KiB
C#
using SQLInsight.Agent;
|
||
using SQLInsight.Agent.CustomRules;
|
||
using SQLInsight.Connectivity;
|
||
using SQLInsight.Core.CustomRules;
|
||
using SQLInsight.Rules.Lifecycle;
|
||
|
||
namespace SQLInsight.IntegrationTests;
|
||
|
||
/// <summary>Community and local rules run with the agent's least-privilege login against a real SQL Server.</summary>
|
||
[Collection(SqlServerTestGroup.Name)]
|
||
[Trait("Category", "Integration")]
|
||
public class CustomRuleIntegrationTests(SqlServerFixture sql) : IAsyncLifetime
|
||
{
|
||
private readonly string _database = "SQLInsightFk_" + Guid.NewGuid().ToString("N")[..8];
|
||
|
||
public Task InitializeAsync() => sql.ExecuteAsSaAsync($"""
|
||
CREATE DATABASE [{_database}];
|
||
EXEC('USE [{_database}];
|
||
CREATE TABLE dbo.Kunder (Id int PRIMARY KEY);
|
||
CREATE TABLE dbo.Ordrer (Id int PRIMARY KEY, KundeId int CONSTRAINT FK_Ordrer_Kunder REFERENCES dbo.Kunder (Id));
|
||
ALTER TABLE dbo.Ordrer NOCHECK CONSTRAINT FK_Ordrer_Kunder;
|
||
ALTER TABLE dbo.Ordrer CHECK CONSTRAINT FK_Ordrer_Kunder;');
|
||
""");
|
||
|
||
public Task DisposeAsync() => sql.ExecuteAsSaAsync($"ALTER DATABASE [{_database}] SET SINGLE_USER WITH ROLLBACK IMMEDIATE; DROP DATABASE [{_database}];");
|
||
|
||
[Fact]
|
||
public async Task Community_and_local_rules_run_with_least_privilege()
|
||
{
|
||
var local = CustomRuleLoader.Parse("""
|
||
[
|
||
{ "id": "LOCAL-SEC-001", "title": "Databasemail", "severity": "Low", "query": "SELECT name FROM msdb.dbo.sysmail_account",
|
||
"findingTitle": "{name}", "explanation": "x", "recommendation": "y" },
|
||
{ "id": "LOCAL-SEC-002", "title": "Stavefejl", "severity": "Low", "query": "SELECT nosuchcolumn FROM sys.databases",
|
||
"findingTitle": "x", "explanation": "x", "recommendation": "y" }
|
||
]
|
||
""", "local.json", "lokal");
|
||
Assert.Empty(local.Errors);
|
||
var rules = RulePack.Embedded().CommunityRules.Concat(local.Rules).ToList();
|
||
var instance = new MonitoredInstance
|
||
{
|
||
Name = "itest", Server = sql.Server, Authentication = AuthenticationMode.SqlLogin, UserName = SqlServerFixture.AgentLogin,
|
||
Password = SqlServerFixture.AgentPassword, Provider = ConnectionProvider.SqlClient, TrustServerCertificate = true,
|
||
};
|
||
using var output = new StringWriter();
|
||
|
||
var exit = await RuleCommands.TestAsync(rules, instance, new SqlConnectionFactory(), output, CancellationToken.None);
|
||
|
||
var text = output.ToString();
|
||
Assert.Contains("COM-SEC-001: Findings", text, StringComparison.Ordinal);
|
||
Assert.Contains("Det indbyggede login 'sa' er aktivt", text, StringComparison.Ordinal);
|
||
Assert.Contains($"{_database}: fremmednøglen FK_Ordrer_Kunder på dbo.Ordrer er ikke betroet", text, StringComparison.Ordinal);
|
||
Assert.Contains("COM-CFG-001: Passed", text, StringComparison.Ordinal);
|
||
Assert.Contains("LOCAL-SEC-001: NotMeasurable – Agentens login mangler rettigheder", text, StringComparison.Ordinal);
|
||
Assert.Contains("LOCAL-SEC-002: Error", text, StringComparison.Ordinal);
|
||
Assert.Equal(2, exit);
|
||
}
|
||
}
|