SqlGuard 1.0.0

dotnet add package SqlGuard --version 1.0.0
                    
NuGet\Install-Package SqlGuard -Version 1.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="SqlGuard" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="SqlGuard" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="SqlGuard" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add SqlGuard --version 1.0.0
                    
#r "nuget: SqlGuard, 1.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package SqlGuard@1.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=SqlGuard&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=SqlGuard&version=1.0.0
                    
Install as a Cake Tool

SqlGuard

SqlGuard is a NuGet library for SQL contract scanning, source-to-database comparison, license-aware feature gating, and report generation.

It is designed to be embedded into your own app, worker, deployment pipeline, or internal tooling when you want to understand what database objects exist, what your source code expects, and where schema drift could break a release.

Current Scope

SqlGuard V1 is focused on:

  • SQL Server live database inspection
  • source scanning for solutions, projects, SQL files, and common .NET code files
  • source-to-database and baseline comparisons
  • report generation and license-based feature gating

SqlGuard V1 does not yet include:

  • PostgreSQL live database scanning
  • a built-in scheduler or background job runner
  • a full compiler/AST-based source analyzer
  • a standalone UI app or dashboard service

What It Does

SqlGuard can:

  • scan SQL source files and .NET source files for contract hints
  • read live SQL Server metadata from a connection string
  • compare source expectations against the live database
  • detect missing objects, object type changes, and other contract drift
  • read stored procedure signatures and result-set metadata
  • generate reports in several formats
  • gate premium features behind a signed license
  • keep community features available even when no license is present

Where To Use It

Use SqlGuard when you want SQL validation and reporting inside:

  • backend services
  • CI/CD and release gates
  • scheduled validation jobs
  • admin portals and internal dashboards
  • database deployment pipelines
  • sample or demo apps that need repeatable SQL reports

Typical teams that benefit from it include:

  • application developers validating schema compatibility
  • DBAs reviewing breaking changes before release
  • DevOps or release engineers generating gate reports
  • platform or compliance teams keeping a paper trail of SQL contract checks

How It Works

At a high level, SqlGuard can compare either:

  • source code and SQL files against a database
  • a live database against a baseline snapshot
  • multiple database snapshots against one baseline

When you point it at source, it looks for:

  • .sln
  • .csproj
  • .sqlproj
  • folders containing source
  • SQL files
  • common code files such as .cs, .vb, .fs, .ts, .tsx, .js, and .jsx

It uses lightweight heuristics to identify things like:

  • EF Core table mappings
  • column mappings
  • CREATE TABLE
  • CREATE PROCEDURE
  • stored procedure calls in code
  • stored procedure parameters
  • stored procedure result-set metadata when a live database is available

When you point it at a live database, it reads metadata from SQL Server and compares that against the source snapshot or baseline snapshot.

Install

dotnet add package SqlGuard

If you are using a local feed or a package source built from this repo, point dotnet at the folder that contains the generated .nupkg.

Basic Usage

The most common pattern is:

  1. validate a signed license
  2. provide a source path, a connection string, or a snapshot
  3. generate the report formats you need
using System.Linq;
using SqlGuard.Abstractions;
using SqlGuard.Core;
using SqlGuard.Licensing;
using SqlGuard.Reporting;
using SqlGuard.SqlServer;

var licenseJson = await File.ReadAllTextAsync(@"C:\keys\sqlguard-license.json");
var publicKeyPem = await File.ReadAllTextAsync(@"C:\keys\public-key.pem");

var validator = new SqlGuardSignedLicenseValidator();
var validation = await validator.ValidateAsync(licenseJson, publicKeyPem);

var scanner = new SqlServerScanService();
var report = await scanner.CreateReportAsync(
    new SqlServerScanOptions
    {
        ConnectionString = "Server=.;Database=SqlGuardDemo;Trusted_Connection=True;TrustServerCertificate=True",
        Database = "SqlGuardDemo",
        SourcePath = @"C:\Repos\MyApp\MyApp.sln",
        FailOnBreakingChange = true,
        TeamName = "Platform",
        ScheduledForUtc = DateTimeOffset.UtcNow.AddHours(2)
    },
    validation);

ISqlGuardReporter reporter = new JsonSqlGuardReporter();
var output = await reporter.WriteAsync(
    report,
    new SqlGuardReportOptions
    {
        OutputDirectory = @".\Deploy\reports",
        Format = "json"
    });

If you do not have a live database yet, you can still use the package with SampleData = true or by supplying your own CurrentSnapshot.

Feature Examples

Free / Community Example

Use this when you want a no-license workflow for basic contract scanning and report generation.

using SqlGuard.Core;
using SqlGuard.Licensing;
using SqlGuard.Reporting;
using SqlGuard.SqlServer;

var validation = SqlGuardSampleData.CreateCommunityLicense();

var service = new SqlServerScanService();
var report = await service.CreateReportAsync(
    new SqlServerScanOptions
    {
        SampleData = true,
        Database = "Demo"
    },
    validation);

ISqlGuardReporter reporter = new JsonSqlGuardReporter();
await reporter.WriteAsync(report, new SqlGuardReportOptions
{
    OutputDirectory = @".\Deploy\reports",
    Format = "json"
});

ISqlGuardReporter markdown = new MarkdownSqlGuardReporter();
await markdown.WriteAsync(report, new SqlGuardReportOptions
{
    OutputDirectory = @".\Deploy\reports",
    Format = "markdown"
});

Best fit features in this tier:

  • BasicSchemaScan
  • JsonReport
  • MarkdownReport
  • TextReport
  • PdfReport

License Validation And Gating

This line:

var validation = await validator.ValidateAsync(licenseJson, publicKeyPem);

does three things in the normal licensed flow:

  1. parses the JSON license payload
  2. verifies the RSA signature with the public key
  3. checks the product name, expiration date, and requested plan/features

If licenseJson is empty or missing, the validator returns community mode instead of failing. That means the free/community feature set stays available.

If the license is valid, the validator returns a SqlGuardLicenseValidationResult with:

  • Status
  • Plan
  • EnabledFeatures
  • DisabledFeatures
  • descriptive metadata such as LicensedTo, Email, Version, and Expires

SqlGuard uses that result to gate behavior:

  • the scan service checks EnabledFeatures before running Pro and Enterprise behaviors
  • report writers can include or hide sections based on the selected report type and plan
  • DisabledFeatures shows you what was not granted by the current license

Example of using the validation result:

if (!validation.IsValid)
{
    throw new InvalidOperationException(validation.Message);
}

if (validation.EnabledFeatures.Contains(SqlGuardFeatures.FailOnBreakingChange))
{
    // Enable release gating logic.
}

Feature Cookbook

Each feature below shows what it means and a minimal code example.

Shared Scan Setup

Most features use the same service.CreateReportAsync(...) entrypoint. The differences come from the SqlServerScanOptions you pass in and from how you read the resulting SqlGuardReport.

var service = new SqlServerScanService();
var report = await service.CreateReportAsync(
    new SqlServerScanOptions
    {
        ConnectionString = "Server=.;Database=SqlGuardDemo;Trusted_Connection=True;TrustServerCertificate=True",
        SourcePath = @"C:\Repos\MyApp\MyApp.sln",
        Database = "SqlGuardDemo"
    },
    validation);

BasicSchemaScan

What it means: scan source files or snapshots for database objects and compare the object list.

// Uses the shared scan setup above.
Console.WriteLine($"Objects scanned: {report.ScanSummary.ObjectsScanned}");

JsonReport

What it means: write the report as JSON for automation or downstream parsing.

ISqlGuardReporter reporter = new JsonSqlGuardReporter();
await reporter.WriteAsync(report, new SqlGuardReportOptions
{
    OutputDirectory = @".\Deploy\reports",
    Format = "json"
});

MarkdownReport

What it means: write a Markdown report for docs or pull requests.

ISqlGuardReporter reporter = new MarkdownSqlGuardReporter();
await reporter.WriteAsync(report, new SqlGuardReportOptions
{
    OutputDirectory = @".\Deploy\reports",
    Format = "markdown"
});

TextReport

What it means: write a plain-text summary for logs or console output.

ISqlGuardReporter reporter = new TextSqlGuardReporter();
await reporter.WriteAsync(report, new SqlGuardReportOptions
{
    OutputDirectory = @".\Deploy\reports",
    Format = "text"
});

PdfReport

What it means: write a PDF report for sharing and sign-off.

ISqlGuardReporter reporter = new PdfSqlGuardReporter();
await reporter.WriteAsync(report, new SqlGuardReportOptions
{
    OutputDirectory = @".\Deploy\reports",
    Format = "pdf"
});

StoredProcedureParameterScan

What it means: check whether stored procedures have parameter metadata.

var parameterIssues = report.Findings
    .Where(f => f.Title.Contains("parameter scan", StringComparison.OrdinalIgnoreCase))
    .ToArray();

If StoredProcedureParameterScan is disabled, this code still runs safely, but the report now includes a visible line saying a valid license is required for that feature.

That helps you tell the difference between “nothing was found” and “this feature is locked by license.”

StoredProcedureResultSetScan

What it means: check whether stored procedures expose result-set metadata.

var resultSetIssues = report.Findings
    .Where(f => f.Title.Contains("result-set scan", StringComparison.OrdinalIgnoreCase))
    .ToArray();

BreakingChangeDetection

What it means: mark missing objects and incompatible contract changes as breaking.

var comparisonReport = await service.CreateReportAsync(
    new SqlServerScanOptions
    {
        CurrentSnapshot = currentSnapshot,
        BaselineSnapshot = baselineSnapshot,
        Database = "SqlGuardDemo"
    },
    validation);

foreach (var change in comparisonReport.BreakingChanges)
{
    Console.WriteLine(change);
}

HtmlReport

What it means: write an HTML report that can be opened in a browser.

ISqlGuardReporter reporter = new HtmlSqlGuardReporter();
await reporter.WriteAsync(report, new SqlGuardReportOptions
{
    OutputDirectory = @".\Deploy\reports",
    Format = "html"
});

OfflineActivation

What it means: validate and use a license file without an always-online activation flow.

var activation = new SqlGuardOfflineActivationManager();
await activation.ActivateAsync(
    @"C:\keys\sqlguard-license.json",
    @"C:\keys\public-key.pem",
    @"C:\keys\SqlGuardInstalled");

var installed = await activation.ValidateInstalledAsync(@"C:\keys\SqlGuardInstalled");

CustomRules

What it means: add your own checks for object names, object types, or text matches.

var customRuleReport = await service.CreateReportAsync(
    new SqlServerScanOptions
    {
        CurrentSnapshot = currentSnapshot,
        BaselineSnapshot = baselineSnapshot,
        CustomRules = new[]
        {
            new SqlGuardCustomRule
            {
                Name = "StoredProcRule",
                AppliesToType = "StoredProcedure",
                ContainsText = "usp_GetCustomer",
                Severity = "Warning",
                Title = "Stored procedure usage check",
                Message = "This procedure is part of the app contract.",
                RecommendedFix = "Verify the signature before release."
            }
        }
    },
    validation);

In this example:

  • Name = "StoredProcRule" gives the rule a friendly internal label.
  • AppliesToType = "StoredProcedure" limits the rule to stored procedure objects.
  • ContainsText = "usp_GetCustomer" makes the rule match objects related to that text.
  • Severity = "Warning" tells SqlGuard how serious the finding should appear.
  • Title = "Stored procedure usage check" is the short label shown in the report.
  • Message = "This procedure is part of the app contract." is the detailed explanation.
  • RecommendedFix = "Verify the signature before release." suggests the next action to take.

This is how you create a team-specific rule that turns your own naming or contract expectations into a report finding.

ExcelReport

What it means: write spreadsheet-friendly output for stakeholders who want a table.

ISqlGuardReporter reporter = new ExcelSqlGuardReporter();
await reporter.WriteAsync(report, new SqlGuardReportOptions
{
    OutputDirectory = @".\Deploy\reports",
    Format = "excel"
});

BaselineComparison

What it means: compare the current contract against a baseline snapshot.

var baselineReport = await service.CreateReportAsync(
    new SqlServerScanOptions
    {
        CurrentSnapshot = currentSnapshot,
        BaselineSnapshot = baselineSnapshot,
        Database = "SqlGuardDemo"
    },
    validation);

FailOnBreakingChange

What it means: turn breaking changes into an explicit release gate result.

var gateReport = await service.CreateReportAsync(
    new SqlServerScanOptions
    {
        CurrentSnapshot = currentSnapshot,
        BaselineSnapshot = baselineSnapshot,
        FailOnBreakingChange = true,
        Database = "SqlGuardDemo"
    },
    validation);

if (gateReport.ReleaseGate is not null && !gateReport.ReleaseGate.Passed)
{
    throw new InvalidOperationException(gateReport.ReleaseGate.Message);
}

MultiDatabaseScan

What it means: aggregate results from multiple databases in one report.

var multiDbReport = await service.CreateReportAsync(
    new SqlServerScanOptions
    {
        Database = "Production",
        DatabaseSnapshots = new Dictionary<string, SqlGuardContractSnapshot>
        {
            ["SalesDb"] = salesSnapshot,
            ["BillingDb"] = billingSnapshot
        }
    },
    validation);

ScheduledScans

What it means: record when the scan is planned to run.

Simple language: this is a note that says “this report belongs to the scan we planned for this time.” SqlGuard does not start the scan by itself; your scheduler or job runner starts the app, and SqlGuard records the planned time in the report.

var scheduledReport = await service.CreateReportAsync(
    new SqlServerScanOptions
    {
        CurrentSnapshot = currentSnapshot,
        BaselineSnapshot = baselineSnapshot,
        ScheduledForUtc = DateTimeOffset.UtcNow.AddHours(4),
        Database = "SqlGuardDemo"
    },
    validation);

CiCdGate

What it means: use the scan result as a pipeline decision point.

Simple language: this is the “pass or fail” check for your build or deploy. If SqlGuard finds breaking changes and FailOnBreakingChange is on, your pipeline can stop and show the report instead of deploying.

if (gateReport.ReleaseGate is not null && !gateReport.ReleaseGate.Passed)
{
    Console.Error.WriteLine(gateReport.ReleaseGate.Message);
    Environment.ExitCode = 1;
}

TeamReports

What it means: tag the report with a team name for ownership and routing.

Simple language: this is a label that says which team owns the report. It helps people sort reports by team, send them to the right group, and track who should act on the findings.

var teamReport = await service.CreateReportAsync(
    new SqlServerScanOptions
    {
        CurrentSnapshot = currentSnapshot,
        BaselineSnapshot = baselineSnapshot,
        TeamName = "Platform",
        Database = "SqlGuardDemo"
    },
    validation);

CentralDashboard

What it means: keep multiple database reports in one summarized payload.

Simple language: this is the “one place to see many databases” view. Instead of reading separate reports for every database, SqlGuard collects them into one summary so you can see the overall health in one screen or file.

foreach (var databaseReport in multiDbReport.DatabaseReports)
{
    Console.WriteLine($"{databaseReport.Database}: {databaseReport.Report.BreakingChanges.Count} breaking changes");
}

Console.WriteLine($"Databases scanned: {multiDbReport.MultiDatabaseSummary?.DatabasesScanned}");

Pro Example

Use Pro when you want source-vs-database comparison plus stored procedure contract validation and custom rules.

using SqlGuard.Core;
using SqlGuard.Licensing;
using SqlGuard.Licensing.Abstractions;
using SqlGuard.Reporting;
using SqlGuard.SqlServer;

var licenseJson = await File.ReadAllTextAsync(@"C:\keys\sqlguard-license.json");
var publicKeyPem = await File.ReadAllTextAsync(@"C:\keys\public-key.pem");

var validator = new SqlGuardSignedLicenseValidator();
SqlGuardLicenseValidationResult validation = await validator.ValidateAsync(licenseJson, publicKeyPem);

var service = new SqlServerScanService();
var report = await service.CreateReportAsync(
    new SqlServerScanOptions
    {
        ConnectionString = "Server=.;Database=SqlGuardDemo;Trusted_Connection=True;TrustServerCertificate=True",
        SourcePath = @"C:\Repos\MyApp\MyApp.sln",
        Database = "SqlGuardDemo",
        CustomRules = new[]
        {
            new SqlGuardCustomRule
            {
                Name = "StoredProcRule",
                AppliesToType = "StoredProcedure",
                ContainsText = "usp_GetCustomer",
                Severity = "Warning",
                Title = "Stored procedure usage check",
                Message = "This procedure is part of the app contract.",
                RecommendedFix = "Verify the procedure signature before release."
            }
        }
    },
    validation);

ISqlGuardReporter reporter = new HtmlSqlGuardReporter();
await reporter.WriteAsync(report, new SqlGuardReportOptions
{
    OutputDirectory = @".\Deploy\reports",
    Format = "html"
});

Best fit features in this tier:

  • StoredProcedureParameterScan
  • StoredProcedureResultSetScan
  • BreakingChangeDetection
  • HtmlReport
  • OfflineActivation
  • CustomRules

Enterprise Example

Use Enterprise when you need baseline comparisons, multi-database reporting, and release gating.

using SqlGuard.Core;
using SqlGuard.Licensing;
using SqlGuard.Licensing.Abstractions;
using SqlGuard.Reporting;
using SqlGuard.SqlServer;

var licenseJson = await File.ReadAllTextAsync(@"C:\keys\sqlguard-license.json");
var publicKeyPem = await File.ReadAllTextAsync(@"C:\keys\public-key.pem");

var validator = new SqlGuardSignedLicenseValidator();
SqlGuardLicenseValidationResult validation = await validator.ValidateAsync(licenseJson, publicKeyPem);

var service = new SqlServerScanService();
var report = await service.CreateReportAsync(
    new SqlServerScanOptions
    {
        Database = "Production",
        DatabaseSnapshots = new Dictionary<string, SqlGuardContractSnapshot>
        {
            ["SalesDb"] = new SqlGuardContractSnapshot
            {
                Objects = new[]
                {
                    new SqlGuardDatabaseObject { Schema = "dbo", Name = "Customers", Type = "Table" }
                }
            },
            ["BillingDb"] = new SqlGuardContractSnapshot
            {
                Objects = new[]
                {
                    new SqlGuardDatabaseObject { Schema = "dbo", Name = "Invoices", Type = "Table" }
                }
            }
        },
        BaselineSnapshot = new SqlGuardContractSnapshot
        {
            Objects = new[]
            {
                new SqlGuardDatabaseObject { Schema = "dbo", Name = "Customers", Type = "Table" }
            }
        },
        FailOnBreakingChange = true,
        TeamName = "Platform",
        ScheduledForUtc = DateTimeOffset.UtcNow.AddHours(4)
    },
    validation);

ISqlGuardReporter reporter = new ExcelSqlGuardReporter();
await reporter.WriteAsync(report, new SqlGuardReportOptions
{
    OutputDirectory = @".\Deploy\reports",
    Format = "excel"
});

Best fit features in this tier:

  • ExcelReport
  • BaselineComparison
  • FailOnBreakingChange
  • MultiDatabaseScan
  • ScheduledScans
  • CiCdGate
  • TeamReports
  • CentralDashboard

If You Want Source And Database Comparison

To compare source code and database state, point the package at both:

  • SourcePath for the solution, project, or folder you want to scan
  • ConnectionString for the SQL Server database you want to inspect
  • Database for the friendly name you want in the report

SqlGuard then compares:

  • source-discovered objects
  • live database objects
  • baseline snapshots if you provide one

If your .NET code calls a stored procedure, SqlGuard looks for stored procedure call patterns such as EXEC dbo.ProcName and common SQL execution helpers. It then compares the discovered procedure name against the live database metadata and can report missing objects or type drift.

License Files On The Consumer Machine

SqlGuard does not silently copy files for you at runtime.

You choose a stable folder on the consumer machine and place the license files there. The examples in this repo use:

  • C:\keys\public-key.pem
  • C:\keys\sqlguard-license.json

If your app uses a different folder, that is fine. Just make sure the paths you configure in your app match the place where you stored the files.

Without a valid license, the free/community features still work.

What It Reports

SqlGuard reports on:

  • discovered objects
  • source scan results
  • live database results
  • schema drift
  • missing objects
  • type changes
  • stored procedure parameters
  • stored procedure result columns
  • breaking changes
  • recommended fixes
  • multi-database comparisons
  • release gate status
  • license status and enabled features

Report Formats

Supported output formats include:

  • json
  • text
  • html
  • pdf
  • markdown
  • excel

The report files are written to the output directory you configure. The default file names follow the sqlguard-report prefix.

Feature Map

Community mode is available even when no license is provided.

Free / Community

  • BasicSchemaScan
  • JsonReport
  • MarkdownReport
  • TextReport
  • PdfReport

Pro

  • StoredProcedureParameterScan
  • StoredProcedureResultSetScan
  • BreakingChangeDetection
  • HtmlReport
  • OfflineActivation
  • CustomRules

Enterprise

  • ExcelReport
  • BaselineComparison
  • FailOnBreakingChange
  • MultiDatabaseScan
  • ScheduledScans
  • CiCdGate
  • TeamReports
  • CentralDashboard

Example Scenarios

  • scan a .NET solution and compare it to a production database before release
  • validate that a stored procedure still returns the columns your code expects
  • detect a missing table or column before a deploy breaks a report
  • run the same contract check across several databases and collect a summary
  • produce a JSON report for automation and a PDF report for stakeholders

Notes

  • This package is intended to be embedded into your own application or automation, not used as a standalone desktop app.
  • Reports are designed to be machine-readable and human-readable.
  • The package is safe to use in free/community mode if you only need the free feature set.
Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0 109 7/3/2026