SqlGuard 1.0.0
dotnet add package SqlGuard --version 1.0.0
NuGet\Install-Package SqlGuard -Version 1.0.0
<PackageReference Include="SqlGuard" Version="1.0.0" />
<PackageVersion Include="SqlGuard" Version="1.0.0" />
<PackageReference Include="SqlGuard" />
paket add SqlGuard --version 1.0.0
#r "nuget: SqlGuard, 1.0.0"
#:package SqlGuard@1.0.0
#addin nuget:?package=SqlGuard&version=1.0.0
#tool nuget:?package=SqlGuard&version=1.0.0
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 TABLECREATE 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:
- validate a signed license
- provide a source path, a connection string, or a snapshot
- 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:
BasicSchemaScanJsonReportMarkdownReportTextReportPdfReport
License Validation And Gating
This line:
var validation = await validator.ValidateAsync(licenseJson, publicKeyPem);
does three things in the normal licensed flow:
- parses the JSON license payload
- verifies the RSA signature with the public key
- 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:
StatusPlanEnabledFeaturesDisabledFeatures- descriptive metadata such as
LicensedTo,Email,Version, andExpires
SqlGuard uses that result to gate behavior:
- the scan service checks
EnabledFeaturesbefore running Pro and Enterprise behaviors - report writers can include or hide sections based on the selected report type and plan
DisabledFeaturesshows 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:
StoredProcedureParameterScanStoredProcedureResultSetScanBreakingChangeDetectionHtmlReportOfflineActivationCustomRules
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:
ExcelReportBaselineComparisonFailOnBreakingChangeMultiDatabaseScanScheduledScansCiCdGateTeamReportsCentralDashboard
If You Want Source And Database Comparison
To compare source code and database state, point the package at both:
SourcePathfor the solution, project, or folder you want to scanConnectionStringfor the SQL Server database you want to inspectDatabasefor 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.pemC:\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:
jsontexthtmlpdfmarkdownexcel
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
BasicSchemaScanJsonReportMarkdownReportTextReportPdfReport
Pro
StoredProcedureParameterScanStoredProcedureResultSetScanBreakingChangeDetectionHtmlReportOfflineActivationCustomRules
Enterprise
ExcelReportBaselineComparisonFailOnBreakingChangeMultiDatabaseScanScheduledScansCiCdGateTeamReportsCentralDashboard
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 | Versions 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. |
-
net8.0
- Microsoft.Data.SqlClient (>= 7.0.2)
- SqlGuard.Abstractions (>= 1.0.0)
- SqlGuard.Core (>= 1.0.0)
- SqlGuard.Licensing (>= 1.0.0)
- SqlGuard.Licensing.Abstractions (>= 1.0.0)
- SqlGuard.Reporting (>= 1.0.0)
- SqlGuard.SqlServer (>= 1.0.0)
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 |