Guardian Gate — CI/CD Gate & Baseline Manager
Guardian Gate is the CI/CD enforcement point of the CipherShift365 platform. It blocks builds that introduce quantum-vulnerable cryptography by comparing project findings against a cryptographically signed, versioned baseline.
Table of Contents
- What It Does
- Why It's Needed
- Architecture Overview
- Installation
- How to Run / Use
- User Manual
- Developer Manual
- Code Examples
- API Reference
- Configuration Options
- Value Showcase
What It Does
Guardian Gate sits in your CI/CD pipeline and performs an automated cryptographic compliance check before deployment:
| Capability | Description |
|---|---|
| CI/CD Gate | Analyzes a project for crypto assets and fails the build if violations are found |
| Signed Baseline | Cryptographically signs accepted risks so tampering is detectable |
| Baseline Manager | Full lifecycle: creation, signing, verification, versioning, export/import for distribution |
| Policy Enforcement | Two modes: Absolute (block all non-QuantumSafe) and BaselineAware (block only new/worsened findings) |
| Bootstrap Mode | Operates in Absolute mode when no baseline exists, with a warning in the verdict |
| Exit Code Contract | Standardized exit codes (0 = pass, 1 = violation, 2 = error) for CI/CD systems |
| Distribution | Signed baselines can be serialized for distribution across teams and pipelines |
All decisions are backed by the shared Analysis Engine, Knowledge Base, Policy Engine, and Identity Service from the CipherShift365 Core.
Why It's Needed
The Problem
Organizations migrating to post-quantum cryptography face a recurring challenge: how do you prevent developers from accidentally (or intentionally) introducing quantum-vulnerable cryptography after a security baseline has been established?
Without a gate:
- New
RSAorECDSAusage can slip into code unnoticed - Previously accepted risks (e.g., legacy
AES-128) can regress without detection - Auditors cannot prove that the deployed code matches the approved baseline
- Manual crypto reviews don't scale across CI/CD pipelines
The Value Proposition
| Stakeholder | Benefit |
|---|---|
| Security Architects | Define once; enforce everywhere. Sign the baseline, distribute it, and trust the gate. |
| DevOps Engineers | Drop-in CI/CD integration with standard exit codes. No custom scripting required. |
| Compliance Officers | Tamper-evident baselines provide cryptographic proof of what was approved and when. |
| Penetration Testers | Baseline-aware mode surfaces only new risks, eliminating alert fatigue from accepted exceptions. |
Guardian Gate compresses a multi-week manual crypto audit into a sub-second automated gate that runs on every commit.
Architecture Overview
Data Flow
- The pipeline invokes
CiGate.RunAsync()with a project path, policy mode, and optional signed baseline - Guardian Gate verifies the baseline signature (if provided) — tampered baselines are fail-closed
- The Analysis Engine scans for cryptographic assets (Roslyn source analysis + dependency detection)
- The Policy Engine evaluates findings against the selected mode
- A
GateResultis produced with pass/fail, a detailed verdict, and the full analysis report - The
CiGatewrapper translates this into a standard exit code
Installation
Guardian Gate is part of the CipherShift365.Guardian NuGet package:
dotnet add package CipherShift365.Guardian
Dependencies
<PackageReference Include="CipherShift365.Guardian" Version="1.0.0" />
Transitive dependencies:
| Package | Purpose |
|---|---|
CipherShift365.Core.Runtime |
Types, contracts, identity, policy engine, knowledge base |
CipherShift365.Core.Analysis |
Analysis engine, Roslyn source detectors, dependency detectors |
Microsoft.CodeAnalysis.CSharp |
C# source code analysis |
Microsoft.CodeAnalysis.CSharp.Workspaces |
Roslyn workspace support |
Target Framework
- net10.0 (build)
- Runtime libraries support net8.0 and net10.0
How to Run / Use
1. Create a CI/CD Console App
using CipherShift365.Guardian;
using CipherShift365.Core.Runtime;
using CipherShift365.Core.Analysis;
// Bootstrap dependencies
var signer = new HmacSigner(signingKey);
var verifier = new HmacVerifier(signingKey);
var identity = new IdentityService();
var riskModel = new RiskModel();
var kb = new SignedKnowledgeBase(content);
var analysisEngine = new AnalysisEngine(riskModel);
var policyEngine = new PolicyEngine(riskModel);
// Create the gate
var gate = new GuardianGate(analysisEngine, policyEngine, kb, identity, verifier);
var ciGate = new CiGate(gate);
// Run the gate
int exitCode = await ciGate.RunAsync(
projectPath: ".",
mode: PolicyMode.BaselineAware,
signedBaseline: loadedBaseline);
Environment.Exit(exitCode);
2. Integrate with Azure DevOps
- task: DotNetCoreCLI@2
displayName: 'PQC Guardian Gate'
inputs:
command: run
arguments: '--project ./src --mode BaselineAware --baseline ./baseline.csb'
condition: always()
3. Integrate with GitHub Actions
- name: PQC Guardian Gate
run: dotnet run --project ./tools/Gate -- ./src --mode BaselineAware --baseline ./baseline.csb
4. Integrate with Jenkins
stage('PQC Guardian Gate') {
steps {
sh 'dotnet run --project ./tools/Gate -- ./src --mode Absolute'
}
post {
failure {
emailext subject: "PQC Gate failed", body: "Violations detected. See logs."
}
}
}
User Manual
Creating a Baseline
A baseline is a snapshot of accepted cryptographic findings at a point in time. It tells the gate: "these specific crypto assets are known and approved."
// Step 1: Run analysis to discover findings
var context = new AnalysisContext(".", kb, identity);
var analysis = await analysisEngine.AnalyzeAsync(context);
// Step 2: Review findings and accept the ones you're comfortable with
var acceptedFindings = analysis.Findings.Where(f => /* your review logic */).ToList();
// Step 3: Create the baseline
var baseline = new Baseline(kb.Version, DateTimeOffset.UtcNow, acceptedFindings.AsReadOnly(),
Description: "Initial PQC baseline for my-service v2.1");
// Step 4: Sign it
var manager = new BaselineManager(signer, verifier);
var signedBaseline = manager.ApproveAndSign(baseline, "security-architect", kb.Version,
approvedBy: "alice@example.com");
// Step 5: Export for distribution (to other teams/pipelines)
byte[] distributable = manager.ExportForDistribution(signedBaseline);
File.WriteAllBytes("baseline.csb", distributable);
Verifying a Baseline Before Use
// Load from distribution
byte[] data = File.ReadAllBytes("baseline.csb");
var sb = BaselineManager.ImportFromDistribution(data, verifier);
if (sb is null)
{
Console.WriteLine("BASELINE REJECTED: signature invalid or tampered.");
return;
}
Console.WriteLine($"Baseline v{sb.BaselineVersion} verified. Signed by {sb.SignerId}.");
Policy Modes
| Mode | Behavior | Use Case |
|---|---|---|
Absolute |
Every finding must be QuantumSafe. All others are violations. |
First scan, greenfield projects, maximum security posture |
BaselineAware |
Only findings not in the baseline, or with worsened risk/confidence, are violations | Incremental enforcement after baseline is established |
| Bootstrap | Triggered when BaselineAware is requested but no baseline exists. Runs Absolute mode with a warning. |
Transitional, prevents accidental leniency |
Interpreting Gate Output
PASS (exit 0): All findings are QuantumSafe, OR all new findings match the baseline.
VIOLATION (exit 1): One or more violations found. Review the GateResult for details.
ERROR (exit 2): Analysis failed, baseline tampered, or system error. Do NOT proceed.
Developer Manual
Class Hierarchy
GuardianGate
├── Constructor: IAnalysisEngine, IPolicyEngine, IKnowledgeBase, IIdentityService, IVerifier?
├── EvaluateAsync() → GateResult
└── (private) GateFailure()
CiGate
├── Constructor: GuardianGate
├── RunAsync() → int (exit code)
└── Constants: ExitPass=0, ExitViolation=1, ExitError=2
GateResult
├── Passed : bool
├── Verdict : PolicyVerdict
└── Analysis : AnalysisResult?
BaselineManager
├── ApproveAndSign() → SignedBaseline
├── GetCurrent() / GetVersion()
├── VerifySignature() → VerificationResult
├── LoadAndVerify() → (bool Valid, string? Error)
├── ExportForDistribution() → byte[]
└── ImportFromDistribution() → SignedBaseline?
SignedBaseline
├── Baseline, BaselineVersion, SignerId, SignedAt, Signature, KbVersion, ApprovedBy
├── Create() (static factory with signing)
└── Verify() (static signature verification)
The Evaluation Pipeline
The GuardianGate.EvaluateAsync() method follows a strict pipeline:
Baseline Resolution: If a
SignedBaselineis provided, verify its HMAC signature. Tampered baselines returnGateFailureimmediately (fail-closed).Analysis: Run the shared
IAnalysisEngine.AnalyzeAsync()to discover crypto assets. If analysis fails, return error.Policy Evaluation: Run
IPolicyEngine.Evaluate()with the selected mode.Result Assembly: Wrap the policy verdict and analysis result into a
GateResult.
Adding a New Policy Mode
// 1. Add enum member
public enum PolicyMode { Absolute, BaselineAware, Custom }
// 2. Add case in PolicyEngine.Evaluate()
case PolicyMode.Custom => EvaluateCustom(findings, baseline);
// 3. Guardian Gate passes it through automatically
var result = await gate.EvaluateAsync(".", PolicyMode.Custom, baseline: myBaseline);
Thread Safety
GuardianGateis thread-safe for concurrent reads of the same projectBaselineManager._versionsuses aDictionary<int, SignedBaseline>— not thread-safe for concurrent writes; wrap in a lock if needed- All public methods accept
CancellationTokenfor cooperative cancellation
Code Examples
Example 1: Simple Absolute Gate
var gate = new GuardianGate(analysisEngine, policyEngine, kb, identity);
var result = await gate.EvaluateAsync("./src/MyApp", PolicyMode.Absolute);
if (!result.Passed)
{
Console.WriteLine($"FAILED: {result.Verdict.Summary}");
foreach (var v in result.Verdict.Violations)
Console.WriteLine($" - {v.Algorithm} ({v.Role}): {v.Risk}");
}
Example 2: Baseline-Aware Gate with Verification
var verifier = new HmacVerifier(loadSigningKey());
var gate = new GuardianGate(analysisEngine, policyEngine, kb, identity, verifier);
var signedBaseline = SignedBaseline.Create(myBaseline, 1, "admin", kb.Version, signer);
var result = await gate.EvaluateAsync(
projectPath: "./src/MyApp",
mode: PolicyMode.BaselineAware,
signedBaseline: signedBaseline);
Console.WriteLine(result.Passed ? "PASS" : "FAIL");
Console.WriteLine(result.Verdict.Summary);
Console.WriteLine($"System risk score: {result.Verdict.SystemScore:F2}");
Example 3: Baseline Lifecycle with Distribution
var manager = new BaselineManager(signer, verifier);
// Architect approves and signs a baseline
var signed = manager.ApproveAndSign(baseline, "architect@corp", kbV2,
approvedBy: "jane@corp");
Console.WriteLine($"Baseline v{signed.BaselineVersion} created, signed at {signed.SignedAt}");
// Export to a file for distribution
byte[] exported = manager.ExportForDistribution(signed);
File.WriteAllBytes(@"\\shared\pqc-baselines\my-service-v3.csb", exported);
// Pipeline agent imports and verifies
byte[] imported = File.ReadAllBytes(@"\\shared\pqc-baselines\my-service-v3.csb");
var verified = BaselineManager.ImportFromDistribution(imported, verifier);
if (verified is null)
throw new SecurityException("Baseline tampered or unsigned. Build aborted.");
// Use the verified baseline in the gate
var result = await gate.EvaluateAsync(".", PolicyMode.BaselineAware,
signedBaseline: verified);
Example 4: CI/CD Pipeline Entry Point
// Complete console program for CI/CD use
public static async Task<int> Main(string[] args)
{
if (args.Length < 2)
{
Console.Error.WriteLine("Usage: gate <project-path> <Absolute|BaselineAware> [baseline-path]");
return 2; // Error
}
var projectPath = args[0];
var mode = Enum.Parse<PolicyMode>(args[1], ignoreCase: true);
SignedBaseline? baseline = args.Length >= 3
? BaselineManager.ImportFromDistribution(File.ReadAllBytes(args[2]), _verifier)
: null;
var ciGate = new CiGate(_gate);
var exitCode = await ciGate.RunAsync(projectPath, mode, signedBaseline: baseline);
Console.WriteLine(exitCode == 0 ? "PASS" : exitCode == 1 ? "VIOLATION" : "ERROR");
return exitCode;
}
API Reference
GuardianGate
| Member | Type | Description |
|---|---|---|
GuardianGate(IAnalysisEngine, IPolicyEngine, IKnowledgeBase, IIdentityService, IVerifier?) |
Constructor | Creates a gate. IVerifier is required for signed baselines. |
EvaluateAsync(string projectPath, PolicyMode mode, Baseline? baseline, SignedBaseline? signedBaseline, CancellationToken ct) |
Method | Runs the gate. Returns GateResult. |
CiGate
| Member | Type | Description |
|---|---|---|
ExitPass = 0 |
Constant | All findings compliant |
ExitViolation = 1 |
Constant | One or more policy violations |
ExitError = 2 |
Constant | Analysis failure, tampered baseline, or system error |
CiGate(GuardianGate) |
Constructor | Wraps a GuardianGate for CLI usage |
RunAsync(string, PolicyMode, Baseline?, SignedBaseline?, CancellationToken) |
Method | Returns exit code (0, 1, or 2) |
GateResult
| Property | Type | Description |
|---|---|---|
Passed |
bool |
true if compliant |
Verdict |
PolicyVerdict |
Detailed policy evaluation |
Analysis |
AnalysisResult? |
Full analysis report (null on error) |
BaselineManager
| Member | Type | Description |
|---|---|---|
BaselineManager(ISigner, IVerifier) |
Constructor | Requires matching signer/verifier pair |
ApproveAndSign(Baseline, string signerId, KbVersion, string? approvedBy) |
Method | Increments version, signs, stores. Returns SignedBaseline. |
GetCurrent() |
Method | Returns the most recent signed baseline, or null |
GetVersion(int) |
Method | Returns a specific version, or null |
VerifySignature(SignedBaseline) |
Method | Returns VerificationResult |
LoadAndVerify(SignedBaseline) |
Method | Returns (bool Valid, string? Error) |
ExportForDistribution(SignedBaseline) |
Method | Serializes to byte[] for sharing |
ImportFromDistribution(byte[], IVerifier) |
Static Method | Deserializes and verifies. Returns null if invalid. |
SignedBaseline
| Property | Type | Description |
|---|---|---|
Baseline |
Baseline |
The underlying baseline data |
BaselineVersion |
int |
Monotonically increasing version number |
SignerId |
string |
Identity of the signer |
SignedAt |
DateTimeOffset |
UTC timestamp of signing |
Signature |
byte[] |
HMAC-SHA256 signature bytes |
KbVersion |
KbVersion |
Knowledge Base version at signing time |
ApprovedBy |
string? |
Optional human approver identifier |
| Static Method | Description |
|---|---|
Create(Baseline, int, string, KbVersion, ISigner, string?) |
Signs and creates a SignedBaseline |
Verify(SignedBaseline, IVerifier) |
Verifies the HMAC signature. Returns VerificationResult. |
Baseline (from Core)
| Property | Type | Description |
|---|---|---|
KbVersion |
KbVersion |
KB version this baseline was created with |
CreatedAt |
DateTimeOffset |
Baseline creation timestamp |
AcceptedFindings |
IReadOnlyList<Finding> |
Findings accepted as known/approved |
Description |
string? |
Optional human-readable description |
PolicyVerdict (from Core)
| Property | Type | Description |
|---|---|---|
IsCompliant |
bool |
Overall pass/fail |
Mode |
PolicyMode |
Mode used for evaluation |
Violations |
IReadOnlyList<Finding> |
Findings that violated policy |
SystemScore |
double |
Risk score (0.0 = safe, higher = more risk) |
Summary |
string? |
Human-readable summary |
Configuration Options
Baseline Signing Configuration
| Parameter | Requirement | Notes |
|---|---|---|
| Signing key length | ≥ 16 bytes | 32 bytes recommended for HMAC-SHA256 |
| Key storage | Secure (HSM, key vault, or secure file) | Never commit signing keys to source control |
| Key rotation | Per baseline version cycle | Use BaselineManager to manage versioning |
Policy Configuration
| Setting | Values | Default | Description |
|---|---|---|---|
PolicyMode |
Absolute, BaselineAware |
— (required) | Enforcement strategy |
baseline |
Baseline? |
null |
Unsigned baseline (for BaselineAware mode) |
signedBaseline |
SignedBaseline? |
null |
Signed baseline (verified before use) |
CI/CD Integration
| Integration Point | Recommended Approach |
|---|---|
| Pull Request | Run in BaselineAware mode to catch new violations only |
| Nightly Build | Run in Absolute mode for comprehensive audit |
| Release Branch | Run with a signed baseline from a shared secure location |
| Air-Gapped Environments | Distribute the baseline file via approved media; loaded with ImportFromDistribution |
Fail-Open vs Fail-Closed
Guardian Gate is fail-closed by design:
- If the baseline verifier is not configured but a signed baseline is provided → fail (error)
- If the signed baseline's HMAC is invalid → fail (tampered)
- If the analysis engine throws an exception → fail (error)
- If deserialization of a distributed baseline fails → null (rejected)
There is no configuration to make the gate fail-open. This is an intentional security decision.
Value Showcase
Before Guardian Gate
Q: "Is the codebase using any non-approved cryptography?"
A: "We ran a manual review 6 months ago. Probably fine."
Risk: HIGH — no enforcement, no audit trail, no tamper protection
After Guardian Gate
Q: "Is the codebase using any non-approved cryptography?"
A: "Gate passed on commit a3f2b1e. Baseline v12 signed by security-architect@corp.
0 violations. Analysis took 1.2 seconds."
Risk: LOW — automated, cryptographically enforced, reproducible
Quantitative Impact
| Metric | Before | After Guardian Gate |
|---|---|---|
| Crypto review cadence | Quarterly manual review | Every commit |
| Mean time to detect a violation | ~90 days | <5 seconds |
| Audit evidence | Spreadsheets, email approvals | Cryptographically signed baseline artifacts |
| Baseline tampering detection | None (manual comparison) | HMAC-SHA256 verification, fail-closed |
| Cross-team baseline consistency | Ad-hoc, version skew common | Single signed artifact, distributed via ImportFromDistribution |
Compliance Alignment
| Framework | How Guardian Gate Helps |
|---|---|
| CNSA 2.0 | Enforces approved algorithm list; violates on excluded/broken algorithms |
| NSM-10 / NSM-8 | Provides automated enforcement of quantum-safe requirements |
| NIST SP 800-53 (SI-7) | Tamper-evident baselines provide software integrity verification |
| ISO 27001 A.14.2.5 | Secure development lifecycle with automated security gates |
| FedRAMP | Continuous monitoring with cryptographic evidence |
Next: See Guardian Runtime for continuous runtime drift detection.