< Summary

Information
Class: Orchestrator.Commands.Utility.Snapshots.SnapshotEncryptor
Assembly: Orchestrator
File(s): /home/runner/work/KicktippAi/KicktippAi/src/Orchestrator/Commands/Utility/Snapshots/SnapshotEncryptor.cs
Line coverage
100%
Covered lines: 19
Uncovered lines: 0
Coverable lines: 19
Total lines: 60
Line coverage: 100%
Branch coverage
100%
Covered branches: 2
Total branches: 2
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
GenerateKey()100%11100%
Encrypt(...)100%11100%
ValidateKey(...)100%22100%

File(s)

/home/runner/work/KicktippAi/KicktippAi/src/Orchestrator/Commands/Utility/Snapshots/SnapshotEncryptor.cs

#LineLine coverage
 1using System.Security.Cryptography;
 2using System.Text;
 3
 4namespace Orchestrator.Commands.Utility.Snapshots;
 5
 6/// <summary>
 7/// Provides AES-256-GCM encryption for test fixtures.
 8/// This is a copy of the logic from KicktippIntegration.Tests to avoid a dependency.
 9/// </summary>
 10public static class SnapshotEncryptor
 11{
 12    private const int NonceSize = 12; // 96 bits for GCM
 13    private const int TagSize = 16;   // 128 bits for GCM
 14
 15    /// <summary>
 16    /// Generates a new random AES-256 encryption key.
 17    /// </summary>
 18    /// <returns>Base64-encoded 256-bit key.</returns>
 19    public static string GenerateKey()
 20    {
 121        var keyBytes = RandomNumberGenerator.GetBytes(32);
 122        return Convert.ToBase64String(keyBytes);
 23    }
 24
 25    /// <summary>
 26    /// Encrypts plaintext content using AES-256-GCM.
 27    /// </summary>
 28    /// <param name="plaintext">The content to encrypt.</param>
 29    /// <param name="base64Key">Base64-encoded 256-bit key.</param>
 30    /// <returns>Base64-encoded encrypted data (nonce + ciphertext + tag).</returns>
 31    public static string Encrypt(string plaintext, string base64Key)
 32    {
 133        var key = Convert.FromBase64String(base64Key);
 134        ValidateKey(key);
 35
 136        var plaintextBytes = Encoding.UTF8.GetBytes(plaintext);
 137        var nonce = RandomNumberGenerator.GetBytes(NonceSize);
 138        var ciphertext = new byte[plaintextBytes.Length];
 139        var tag = new byte[TagSize];
 40
 141        using var aes = new AesGcm(key, TagSize);
 142        aes.Encrypt(nonce, plaintextBytes, ciphertext, tag);
 43
 44        // Combine: nonce (12) + ciphertext (variable) + tag (16)
 145        var result = new byte[NonceSize + ciphertext.Length + TagSize];
 146        Buffer.BlockCopy(nonce, 0, result, 0, NonceSize);
 147        Buffer.BlockCopy(ciphertext, 0, result, NonceSize, ciphertext.Length);
 148        Buffer.BlockCopy(tag, 0, result, NonceSize + ciphertext.Length, TagSize);
 49
 150        return Convert.ToBase64String(result);
 151    }
 52
 53    private static void ValidateKey(byte[] key)
 54    {
 155        if (key.Length != 32)
 56        {
 157            throw new ArgumentException($"Key must be 256 bits (32 bytes). Got {key.Length} bytes.");
 58        }
 159    }
 60}