< Summary

Information
Class: AsiBackbone.Core.Signing.SigningRequest
Assembly: AsiBackbone.Core
File(s): /home/runner/work/AsiBackbone/AsiBackbone/src/AsiBackbone.Core/Signing/SigningRequest.cs
Line coverage
100%
Covered lines: 34
Uncovered lines: 0
Coverable lines: 34
Total lines: 130
Line coverage: 100%
Branch coverage
80%
Covered branches: 16
Total branches: 20
Branch coverage: 80%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.cctor()100%11100%
.ctor(...)100%11100%
get_HasMetadata()100%11100%
get_SignatureInput()100%22100%
set_SignatureInput(...)50%22100%
get_UsesLegacySignatureInput()100%11100%
NormalizeOptional(...)100%22100%
NormalizeMetadata(...)78.57%1414100%

File(s)

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

#LineLine coverage
 1using System.Collections.ObjectModel;
 2
 3namespace AsiBackbone.Core.Signing;
 4
 5/// <summary>
 6/// Represents a provider-neutral request to sign a precomputed artifact hash.
 7/// </summary>
 8/// <remarks>
 9/// The request is intentionally hash-oriented so production providers can use key-based signing APIs without exposing r
 10/// </remarks>
 11public sealed class SigningRequest
 12{
 13    private readonly byte[]? signatureInput;
 14
 415    private static readonly IReadOnlyDictionary<string, string> EmptyMetadata =
 416        new ReadOnlyDictionary<string, string>(
 417            new Dictionary<string, string>(StringComparer.Ordinal));
 18
 19    /// <summary>
 20    /// Initializes a new instance of the <see cref="SigningRequest" /> class.
 21    /// </summary>
 8522    public SigningRequest(
 8523        string signingHash,
 8524        string? hashAlgorithm = null,
 8525        string? purpose = null,
 8526        string? keyId = null,
 8527        string? keyVersion = null,
 8528        IReadOnlyDictionary<string, string>? metadata = null)
 29    {
 8530        ArgumentException.ThrowIfNullOrWhiteSpace(signingHash);
 31
 8532        SigningHash = signingHash.Trim();
 8533        HashAlgorithm = NormalizeOptional(hashAlgorithm);
 8534        Purpose = NormalizeOptional(purpose);
 8535        KeyId = NormalizeOptional(keyId);
 8536        KeyVersion = NormalizeOptional(keyVersion);
 8537        Metadata = NormalizeMetadata(metadata);
 8538    }
 39
 40    /// <summary>
 41    /// Gets the precomputed artifact hash to sign.
 42    /// </summary>
 43    public string SigningHash { get; }
 44
 45    /// <summary>
 46    /// Gets the hash algorithm or descriptor associated with <see cref="SigningHash" />, when supplied.
 47    /// </summary>
 48    public string? HashAlgorithm { get; }
 49
 50    /// <summary>
 51    /// Gets the host-defined signing purpose, when supplied.
 52    /// </summary>
 53    public string? Purpose { get; }
 54
 55    /// <summary>
 56    /// Gets the requested signing key identifier, when supplied.
 57    /// </summary>
 58    public string? KeyId { get; }
 59
 60    /// <summary>
 61    /// Gets the requested signing key version, when supplied.
 62    /// </summary>
 63    public string? KeyVersion { get; }
 64
 65    /// <summary>
 66    /// Gets additional provider-neutral request metadata.
 67    /// </summary>
 68    public IReadOnlyDictionary<string, string> Metadata { get; }
 69
 70    /// <summary>
 71    /// Gets a value indicating whether metadata is present.
 72    /// </summary>
 173    public bool HasMetadata => Metadata.Count > 0;
 74
 75    /// <summary>
 76    /// Gets the exact bytes the signing provider must sign.
 77    /// </summary>
 78    /// <remarks>
 79    /// <see cref="GovernanceArtifactSigner" /> sets this to the version 1 input from
 80    /// <see cref="GovernanceSignatureInput.CreateV1" />, which binds the canonical descriptors, hash, and signing polic
 81    /// context. Providers must sign these bytes rather than <see cref="SigningHash" />; a provider that signs the hash 
 82    /// produces a signature that fails version 1 verification. When no input was supplied, this returns the pre-6.0 inp
 83    /// from <see cref="GovernanceSignatureInput.CreateLegacy" />. The supplied value is copied.
 84    /// </remarks>
 85    public ReadOnlyMemory<byte> SignatureInput
 86    {
 87#pragma warning disable ASIB902 // Retained internal fallback for pre-6.0 provider-request compatibility.
 5688        get => signatureInput ?? GovernanceSignatureInput.CreateLegacy(SigningHash);
 89#pragma warning restore ASIB902
 2090        init => signatureInput = value.IsEmpty ? null : [.. value.Span];
 91    }
 92
 93    /// <summary>
 94    /// Gets a value indicating whether no explicit signature input was supplied, so <see cref="SignatureInput" /> is th
 95    /// pre-6.0 hash-only input.
 96    /// </summary>
 397    public bool UsesLegacySignatureInput => signatureInput is null;
 98
 99    private static string? NormalizeOptional(string? value)
 100    {
 340101        return string.IsNullOrWhiteSpace(value)
 340102            ? null
 340103            : value.Trim();
 104    }
 105
 106    private static IReadOnlyDictionary<string, string> NormalizeMetadata(
 107        IReadOnlyDictionary<string, string>? metadata)
 108    {
 85109        if (metadata is null || metadata.Count == 0)
 110        {
 62111            return EmptyMetadata;
 112        }
 113
 23114        Dictionary<string, string> normalizedMetadata = new(StringComparer.Ordinal);
 115
 304116        foreach (KeyValuePair<string, string> item in metadata)
 117        {
 129118            if (string.IsNullOrWhiteSpace(item.Key))
 119            {
 120                continue;
 121            }
 122
 128123            normalizedMetadata[item.Key.Trim()] = item.Value?.Trim() ?? string.Empty;
 124        }
 125
 23126        return normalizedMetadata.Count == 0
 23127            ? EmptyMetadata
 23128            : new ReadOnlyDictionary<string, string>(normalizedMetadata);
 129    }
 130}