< Summary

Information
Class: AsiBackbone.Core.Signing.VerificationPolicyOutcome
Assembly: AsiBackbone.Core
File(s): /home/runner/work/AsiBackbone/AsiBackbone/src/AsiBackbone.Core/Signing/VerificationPolicyOutcome.cs
Line coverage
94%
Covered lines: 127
Uncovered lines: 7
Coverable lines: 134
Total lines: 276
Line coverage: 94.7%
Branch coverage
84%
Covered branches: 27
Total branches: 32
Branch coverage: 84.3%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.cctor()100%210%
.ctor(...)50%4495.12%
get_IsVerified()100%11100%
get_Category()100%11100%
get_Action()100%11100%
get_ShouldAllow()100%11100%
get_Status()100%11100%
get_FailureCode()100%11100%
get_FailureMessage()100%11100%
get_ArtifactType()100%11100%
get_ArtifactId()100%11100%
get_SigningHash()100%210%
get_HashAlgorithm()100%210%
get_KeyId()100%11100%
get_KeyVersion()100%11100%
get_SignatureAlgorithm()100%11100%
get_Provider()100%11100%
get_SafeMetadata()100%11100%
Create(...)100%11100%
CreateCore(...)100%22100%
BuildSafeMetadata(...)75%1212100%
AddIfPresent(...)100%22100%
IsSafeSigningMetadataKey(...)100%1010100%
NormalizeOptional(...)100%22100%

File(s)

/home/runner/work/AsiBackbone/AsiBackbone/src/AsiBackbone.Core/Signing/VerificationPolicyOutcome.cs

#LineLine coverage
 1using System.Collections.ObjectModel;
 2
 3namespace AsiBackbone.Core.Signing;
 4
 5/// <summary>
 6/// Represents the host-facing outcome of signature verification policy evaluation.
 7/// </summary>
 8public sealed class VerificationPolicyOutcome
 9{
 010    private static readonly IReadOnlyDictionary<string, string> EmptyMetadata =
 011        new ReadOnlyDictionary<string, string>(
 012            new Dictionary<string, string>(StringComparer.Ordinal));
 13
 7614    private VerificationPolicyOutcome(
 7615        bool isVerified,
 7616        SignatureVerificationCategory category,
 7617        VerificationPolicyAction action,
 7618        string status,
 7619        string? failureCode,
 7620        string? failureMessage,
 7621        string artifactType,
 7622        string artifactId,
 7623        string signingHash,
 7624        string hashAlgorithm,
 7625        string? keyId,
 7626        string? keyVersion,
 7627        string? signatureAlgorithm,
 7628        string? provider,
 7629        IReadOnlyDictionary<string, string> safeMetadata)
 30    {
 7631        ArgumentException.ThrowIfNullOrWhiteSpace(status);
 7632        ArgumentException.ThrowIfNullOrWhiteSpace(artifactType);
 7633        ArgumentException.ThrowIfNullOrWhiteSpace(artifactId);
 7634        ArgumentException.ThrowIfNullOrWhiteSpace(signingHash);
 7635        ArgumentException.ThrowIfNullOrWhiteSpace(hashAlgorithm);
 36
 7637        if (!Enum.IsDefined(category))
 38        {
 039            throw new ArgumentOutOfRangeException(nameof(category), category, "Verification category must be defined.");
 40        }
 41
 7642        if (!Enum.IsDefined(action))
 43        {
 044            throw new ArgumentOutOfRangeException(nameof(action), action, "Verification policy action must be defined.")
 45        }
 46
 7647        IsVerified = isVerified;
 7648        Category = category;
 7649        Action = action;
 7650        Status = status.Trim();
 7651        FailureCode = NormalizeOptional(failureCode);
 7652        FailureMessage = NormalizeOptional(failureMessage);
 7653        ArtifactType = artifactType.Trim();
 7654        ArtifactId = artifactId.Trim();
 7655        SigningHash = signingHash.Trim();
 7656        HashAlgorithm = hashAlgorithm.Trim();
 7657        KeyId = NormalizeOptional(keyId);
 7658        KeyVersion = NormalizeOptional(keyVersion);
 7659        SignatureAlgorithm = NormalizeOptional(signatureAlgorithm);
 7660        Provider = NormalizeOptional(provider);
 7661        SafeMetadata = safeMetadata;
 7662    }
 63
 64    /// <summary>
 65    /// Gets a value indicating whether verification succeeded.
 66    /// </summary>
 4667    public bool IsVerified { get; }
 68
 69    /// <summary>
 70    /// Gets the provider-neutral verification category.
 71    /// </summary>
 6872    public SignatureVerificationCategory Category { get; }
 73
 74    /// <summary>
 75    /// Gets the host-facing action selected by verification policy.
 76    /// </summary>
 10477    public VerificationPolicyAction Action { get; }
 78
 79    /// <summary>
 80    /// Gets a value indicating whether the policy selected the allow action.
 81    /// </summary>
 3682    public bool ShouldAllow => Action is VerificationPolicyAction.Allow;
 83
 84    /// <summary>
 85    /// Gets the provider-neutral verification status.
 86    /// </summary>
 287    public string Status { get; }
 88
 89    /// <summary>
 90    /// Gets the provider-neutral failure code, when verification did not succeed.
 91    /// </summary>
 6492    public string? FailureCode { get; }
 93
 94    /// <summary>
 95    /// Gets the provider-neutral failure message, when verification did not succeed.
 96    /// </summary>
 2497    public string? FailureMessage { get; }
 98
 99    /// <summary>
 100    /// Gets the artifact type that was verified or evaluated.
 101    /// </summary>
 2102    public string ArtifactType { get; }
 103
 104    /// <summary>
 105    /// Gets the artifact identifier that was verified or evaluated.
 106    /// </summary>
 2107    public string ArtifactId { get; }
 108
 109    /// <summary>
 110    /// Gets the signing hash expected for verification.
 111    /// </summary>
 0112    public string SigningHash { get; }
 113
 114    /// <summary>
 115    /// Gets the hash algorithm expected for verification.
 116    /// </summary>
 0117    public string HashAlgorithm { get; }
 118
 119    /// <summary>
 120    /// Gets the signing key identifier, when supplied.
 121    /// </summary>
 4122    public string? KeyId { get; }
 123
 124    /// <summary>
 125    /// Gets the signing key version, when supplied.
 126    /// </summary>
 4127    public string? KeyVersion { get; }
 128
 129    /// <summary>
 130    /// Gets the signature algorithm descriptor, when supplied.
 131    /// </summary>
 2132    public string? SignatureAlgorithm { get; }
 133
 134    /// <summary>
 135    /// Gets the signing provider descriptor, when supplied.
 136    /// </summary>
 2137    public string? Provider { get; }
 138
 139    /// <summary>
 140    /// Gets safe-to-log verification metadata. Signature values and secrets are never included.
 141    /// </summary>
 52142    public IReadOnlyDictionary<string, string> SafeMetadata { get; }
 143
 144    /// <summary>
 145    /// Creates a verification policy outcome.
 146    /// </summary>
 147    public static VerificationPolicyOutcome Create<TArtifact>(
 148        SignedGovernanceArtifact<TArtifact> artifact,
 149        SignatureVerificationResult verificationResult,
 150        VerificationPolicyOptions? options = null)
 151    {
 4152        ArgumentNullException.ThrowIfNull(artifact);
 153
 4154        return CreateCore(
 4155            artifact.ArtifactType,
 4156            artifact.ArtifactId,
 4157            artifact.SigningHash,
 4158            artifact.HashAlgorithm,
 4159            artifact.SigningMetadata,
 4160            verificationResult,
 4161            options);
 162    }
 163
 164    internal static VerificationPolicyOutcome CreateCore(
 165        string artifactType,
 166        string artifactId,
 167        string signingHash,
 168        string hashAlgorithm,
 169        SigningMetadata signingMetadata,
 170        SignatureVerificationResult verificationResult,
 171        VerificationPolicyOptions? options = null)
 172    {
 76173        ArgumentNullException.ThrowIfNull(signingMetadata);
 76174        ArgumentNullException.ThrowIfNull(verificationResult);
 175
 76176        VerificationPolicyOptions effectiveOptions = options ?? VerificationPolicyOptions.Default;
 76177        SignatureVerificationCategory category = VerificationPolicyEvaluator.Categorize(verificationResult);
 76178        VerificationPolicyAction action = effectiveOptions.GetAction(category);
 76179        IReadOnlyDictionary<string, string> safeMetadata = BuildSafeMetadata(
 76180            artifactType,
 76181            artifactId,
 76182            signingHash,
 76183            hashAlgorithm,
 76184            signingMetadata,
 76185            verificationResult,
 76186            category,
 76187            action);
 188
 76189        return new VerificationPolicyOutcome(
 76190            verificationResult.IsValid,
 76191            category,
 76192            action,
 76193            verificationResult.Status,
 76194            verificationResult.FailureCode,
 76195            verificationResult.FailureMessage,
 76196            artifactType,
 76197            artifactId,
 76198            signingHash,
 76199            hashAlgorithm,
 76200            signingMetadata.KeyId,
 76201            signingMetadata.KeyVersion,
 76202            signingMetadata.SignatureAlgorithm,
 76203            signingMetadata.Provider,
 76204            safeMetadata);
 205    }
 206
 207    private static IReadOnlyDictionary<string, string> BuildSafeMetadata(
 208        string artifactType,
 209        string artifactId,
 210        string signingHash,
 211        string hashAlgorithm,
 212        SigningMetadata signingMetadata,
 213        SignatureVerificationResult verificationResult,
 214        SignatureVerificationCategory category,
 215        VerificationPolicyAction action)
 216    {
 76217        Dictionary<string, string> metadata = new(StringComparer.Ordinal)
 76218        {
 76219            ["artifact_id"] = artifactId,
 76220            ["artifact_type"] = artifactType,
 76221            ["category"] = category.ToString(),
 76222            ["hash_algorithm"] = hashAlgorithm,
 76223            ["policy_action"] = action.ToString(),
 76224            ["signing_hash"] = signingHash,
 76225            ["status"] = verificationResult.Status
 76226        };
 227
 76228        AddIfPresent(metadata, "failure_code", verificationResult.FailureCode);
 76229        AddIfPresent(metadata, "key_id", signingMetadata.KeyId);
 76230        AddIfPresent(metadata, "key_version", signingMetadata.KeyVersion);
 76231        AddIfPresent(metadata, "provider", signingMetadata.Provider);
 76232        AddIfPresent(metadata, "signature_algorithm", signingMetadata.SignatureAlgorithm);
 233
 76234        if (signingMetadata.SignedUtc.HasValue)
 235        {
 68236            metadata["signed_utc"] = signingMetadata.SignedUtc.Value.ToString("O", System.Globalization.CultureInfo.Inva
 237        }
 238
 940239        foreach (KeyValuePair<string, string> item in signingMetadata.Metadata)
 240        {
 394241            if (IsSafeSigningMetadataKey(item.Key))
 242            {
 384243                metadata[item.Key.Trim()] = item.Value?.Trim() ?? string.Empty;
 244            }
 245        }
 246
 76247        return metadata.Count == 0
 76248            ? EmptyMetadata
 76249            : new ReadOnlyDictionary<string, string>(metadata);
 250    }
 251
 252    private static void AddIfPresent(Dictionary<string, string> metadata, string key, string? value)
 253    {
 380254        if (!string.IsNullOrWhiteSpace(value))
 255        {
 336256            metadata[key] = value.Trim();
 257        }
 380258    }
 259
 260    private static bool IsSafeSigningMetadataKey(string key)
 261    {
 394262        return !string.IsNullOrWhiteSpace(key)
 394263            && !key.Contains("signature", StringComparison.OrdinalIgnoreCase)
 394264            && !key.Contains("secret", StringComparison.OrdinalIgnoreCase)
 394265            && !key.Contains("token", StringComparison.OrdinalIgnoreCase)
 394266            && !key.Contains("credential", StringComparison.OrdinalIgnoreCase)
 394267            && !key.Contains("private", StringComparison.OrdinalIgnoreCase);
 268    }
 269
 270    private static string? NormalizeOptional(string? value)
 271    {
 456272        return string.IsNullOrWhiteSpace(value)
 456273            ? null
 456274            : value.Trim();
 275    }
 276}

Methods/Properties

.cctor()
.ctor(System.Boolean,AsiBackbone.Core.Signing.SignatureVerificationCategory,AsiBackbone.Core.Signing.VerificationPolicyAction,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.Collections.Generic.IReadOnlyDictionary`2<System.String,System.String>)
get_IsVerified()
get_Category()
get_Action()
get_ShouldAllow()
get_Status()
get_FailureCode()
get_FailureMessage()
get_ArtifactType()
get_ArtifactId()
get_SigningHash()
get_HashAlgorithm()
get_KeyId()
get_KeyVersion()
get_SignatureAlgorithm()
get_Provider()
get_SafeMetadata()
Create(AsiBackbone.Core.Signing.SignedGovernanceArtifact`1<TArtifact>,AsiBackbone.Core.Signing.SignatureVerificationResult,AsiBackbone.Core.Signing.VerificationPolicyOptions)
CreateCore(System.String,System.String,System.String,System.String,AsiBackbone.Core.Signing.SigningMetadata,AsiBackbone.Core.Signing.SignatureVerificationResult,AsiBackbone.Core.Signing.VerificationPolicyOptions)
BuildSafeMetadata(System.String,System.String,System.String,System.String,AsiBackbone.Core.Signing.SigningMetadata,AsiBackbone.Core.Signing.SignatureVerificationResult,AsiBackbone.Core.Signing.SignatureVerificationCategory,AsiBackbone.Core.Signing.VerificationPolicyAction)
AddIfPresent(System.Collections.Generic.Dictionary`2<System.String,System.String>,System.String,System.String)
IsSafeSigningMetadataKey(System.String)
NormalizeOptional(System.String)