< 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
 3414    private VerificationPolicyOutcome(
 3415        bool isVerified,
 3416        SignatureVerificationCategory category,
 3417        VerificationPolicyAction action,
 3418        string status,
 3419        string? failureCode,
 3420        string? failureMessage,
 3421        string artifactType,
 3422        string artifactId,
 3423        string signingHash,
 3424        string hashAlgorithm,
 3425        string? keyId,
 3426        string? keyVersion,
 3427        string? signatureAlgorithm,
 3428        string? provider,
 3429        IReadOnlyDictionary<string, string> safeMetadata)
 30    {
 3431        ArgumentException.ThrowIfNullOrWhiteSpace(status);
 3432        ArgumentException.ThrowIfNullOrWhiteSpace(artifactType);
 3433        ArgumentException.ThrowIfNullOrWhiteSpace(artifactId);
 3434        ArgumentException.ThrowIfNullOrWhiteSpace(signingHash);
 3435        ArgumentException.ThrowIfNullOrWhiteSpace(hashAlgorithm);
 36
 3437        if (!Enum.IsDefined(category))
 38        {
 039            throw new ArgumentOutOfRangeException(nameof(category), category, "Verification category must be defined.");
 40        }
 41
 3442        if (!Enum.IsDefined(action))
 43        {
 044            throw new ArgumentOutOfRangeException(nameof(action), action, "Verification policy action must be defined.")
 45        }
 46
 3447        IsVerified = isVerified;
 3448        Category = category;
 3449        Action = action;
 3450        Status = status.Trim();
 3451        FailureCode = NormalizeOptional(failureCode);
 3452        FailureMessage = NormalizeOptional(failureMessage);
 3453        ArtifactType = artifactType.Trim();
 3454        ArtifactId = artifactId.Trim();
 3455        SigningHash = signingHash.Trim();
 3456        HashAlgorithm = hashAlgorithm.Trim();
 3457        KeyId = NormalizeOptional(keyId);
 3458        KeyVersion = NormalizeOptional(keyVersion);
 3459        SignatureAlgorithm = NormalizeOptional(signatureAlgorithm);
 3460        Provider = NormalizeOptional(provider);
 3461        SafeMetadata = safeMetadata;
 3462    }
 63
 64    /// <summary>
 65    /// Gets a value indicating whether verification succeeded.
 66    /// </summary>
 2367    public bool IsVerified { get; }
 68
 69    /// <summary>
 70    /// Gets the provider-neutral verification category.
 71    /// </summary>
 3272    public SignatureVerificationCategory Category { get; }
 73
 74    /// <summary>
 75    /// Gets the host-facing action selected by verification policy.
 76    /// </summary>
 4677    public VerificationPolicyAction Action { get; }
 78
 79    /// <summary>
 80    /// Gets a value indicating whether the policy selected the allow action.
 81    /// </summary>
 1482    public bool ShouldAllow => Action is VerificationPolicyAction.Allow;
 83
 84    /// <summary>
 85    /// Gets the provider-neutral verification status.
 86    /// </summary>
 187    public string Status { get; }
 88
 89    /// <summary>
 90    /// Gets the provider-neutral failure code, when verification did not succeed.
 91    /// </summary>
 3092    public string? FailureCode { get; }
 93
 94    /// <summary>
 95    /// Gets the provider-neutral failure message, when verification did not succeed.
 96    /// </summary>
 1097    public string? FailureMessage { get; }
 98
 99    /// <summary>
 100    /// Gets the artifact type that was verified or evaluated.
 101    /// </summary>
 1102    public string ArtifactType { get; }
 103
 104    /// <summary>
 105    /// Gets the artifact identifier that was verified or evaluated.
 106    /// </summary>
 1107    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>
 2122    public string? KeyId { get; }
 123
 124    /// <summary>
 125    /// Gets the signing key version, when supplied.
 126    /// </summary>
 2127    public string? KeyVersion { get; }
 128
 129    /// <summary>
 130    /// Gets the signature algorithm descriptor, when supplied.
 131    /// </summary>
 1132    public string? SignatureAlgorithm { get; }
 133
 134    /// <summary>
 135    /// Gets the signing provider descriptor, when supplied.
 136    /// </summary>
 1137    public string? Provider { get; }
 138
 139    /// <summary>
 140    /// Gets safe-to-log verification metadata. Signature values and secrets are never included.
 141    /// </summary>
 26142    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    {
 2152        ArgumentNullException.ThrowIfNull(artifact);
 153
 2154        return CreateCore(
 2155            artifact.ArtifactType,
 2156            artifact.ArtifactId,
 2157            artifact.SigningHash,
 2158            artifact.HashAlgorithm,
 2159            artifact.SigningMetadata,
 2160            verificationResult,
 2161            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    {
 34173        ArgumentNullException.ThrowIfNull(signingMetadata);
 34174        ArgumentNullException.ThrowIfNull(verificationResult);
 175
 34176        VerificationPolicyOptions effectiveOptions = options ?? VerificationPolicyOptions.Default;
 34177        SignatureVerificationCategory category = VerificationPolicyEvaluator.Categorize(verificationResult);
 34178        VerificationPolicyAction action = effectiveOptions.GetAction(category);
 34179        IReadOnlyDictionary<string, string> safeMetadata = BuildSafeMetadata(
 34180            artifactType,
 34181            artifactId,
 34182            signingHash,
 34183            hashAlgorithm,
 34184            signingMetadata,
 34185            verificationResult,
 34186            category,
 34187            action);
 188
 34189        return new VerificationPolicyOutcome(
 34190            verificationResult.IsValid,
 34191            category,
 34192            action,
 34193            verificationResult.Status,
 34194            verificationResult.FailureCode,
 34195            verificationResult.FailureMessage,
 34196            artifactType,
 34197            artifactId,
 34198            signingHash,
 34199            hashAlgorithm,
 34200            signingMetadata.KeyId,
 34201            signingMetadata.KeyVersion,
 34202            signingMetadata.SignatureAlgorithm,
 34203            signingMetadata.Provider,
 34204            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    {
 34217        Dictionary<string, string> metadata = new(StringComparer.Ordinal)
 34218        {
 34219            ["artifact_id"] = artifactId,
 34220            ["artifact_type"] = artifactType,
 34221            ["category"] = category.ToString(),
 34222            ["hash_algorithm"] = hashAlgorithm,
 34223            ["policy_action"] = action.ToString(),
 34224            ["signing_hash"] = signingHash,
 34225            ["status"] = verificationResult.Status
 34226        };
 227
 34228        AddIfPresent(metadata, "failure_code", verificationResult.FailureCode);
 34229        AddIfPresent(metadata, "key_id", signingMetadata.KeyId);
 34230        AddIfPresent(metadata, "key_version", signingMetadata.KeyVersion);
 34231        AddIfPresent(metadata, "provider", signingMetadata.Provider);
 34232        AddIfPresent(metadata, "signature_algorithm", signingMetadata.SignatureAlgorithm);
 233
 34234        if (signingMetadata.SignedUtc.HasValue)
 235        {
 30236            metadata["signed_utc"] = signingMetadata.SignedUtc.Value.ToString("O", System.Globalization.CultureInfo.Inva
 237        }
 238
 418239        foreach (KeyValuePair<string, string> item in signingMetadata.Metadata)
 240        {
 175241            if (IsSafeSigningMetadataKey(item.Key))
 242            {
 170243                metadata[item.Key.Trim()] = item.Value?.Trim() ?? string.Empty;
 244            }
 245        }
 246
 34247        return metadata.Count == 0
 34248            ? EmptyMetadata
 34249            : new ReadOnlyDictionary<string, string>(metadata);
 250    }
 251
 252    private static void AddIfPresent(Dictionary<string, string> metadata, string key, string? value)
 253    {
 170254        if (!string.IsNullOrWhiteSpace(value))
 255        {
 150256            metadata[key] = value.Trim();
 257        }
 170258    }
 259
 260    private static bool IsSafeSigningMetadataKey(string key)
 261    {
 175262        return !string.IsNullOrWhiteSpace(key)
 175263            && !key.Contains("signature", StringComparison.OrdinalIgnoreCase)
 175264            && !key.Contains("secret", StringComparison.OrdinalIgnoreCase)
 175265            && !key.Contains("token", StringComparison.OrdinalIgnoreCase)
 175266            && !key.Contains("credential", StringComparison.OrdinalIgnoreCase)
 175267            && !key.Contains("private", StringComparison.OrdinalIgnoreCase);
 268    }
 269
 270    private static string? NormalizeOptional(string? value)
 271    {
 204272        return string.IsNullOrWhiteSpace(value)
 204273            ? null
 204274            : 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)