Skip to content

Commit

Permalink
automated commit
Browse files Browse the repository at this point in the history
Signed-off-by: Public copy <41898282+github-actions[bot]@users.noreply.github.com>
  • Loading branch information
github-actions[bot] committed Mar 6, 2025
1 parent 419dd8f commit 0dc797c
Show file tree
Hide file tree
Showing 7 changed files with 318 additions and 9 deletions.
4 changes: 3 additions & 1 deletion images/dotnet/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ variable "target_repository" {
}

module "test-latest" {
source = "./tests"
source = "./tests"
test_repository = var.test_repository

digests = {
sdk = module.sdk.image_ref
runtime = module.runtime.image_ref
Expand Down
68 changes: 68 additions & 0 deletions images/dotnet/tests/keypairs.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#!/bin/bash

set -euo pipefail

cd /data

# make new project
docker run --rm \
-v $VOLUME_ID:/data \
--workdir /data \
--entrypoint dotnet "$SDK_IMAGE" \
new console --name keypair

# copy source into project
cp src/keypair.cs /data/keypair/Program.cs

# build runtime linked executable
docker run --rm \
-v $VOLUME_ID:/data \
--workdir /data/keypair \
--entrypoint dotnet "$SDK_IMAGE" \
publish -c Release -o /data/keypair-runtime

# generate keypair with runtime linked binary
docker run --rm \
-v $VOLUME_ID:/data \
--workdir /data/keypair-runtime \
--entrypoint ./keypair "$RUNTIME_IMAGE" \
keypair

# validate keypair with runtime linked binary
docker run --rm \
-v $VOLUME_ID:/data \
--workdir /data/keypair-runtime \
--entrypoint ./keypair "$RUNTIME_IMAGE" \
validate

# build standalone executable
docker run --rm \
-v $VOLUME_ID:/data \
--workdir /data/keypair \
--entrypoint dotnet "$SDK_IMAGE" \
publish -c Release -r $(cat /tmp/arch) --sc true -p:PublishSingleFile=true -o /data/keypair-standalone

# generate keypair with standalone binary - should work with glibc-dynamic-openssl but needs libz
docker run --rm \
-v $VOLUME_ID:/data \
--workdir /data/keypair-standalone \
--entrypoint ./keypair "$RUNTIME_IMAGE" \
keypair

# validate cert with standalone binary - should work with glibc-dynamic-openssl but needs libz
docker run --rm \
-v $VOLUME_ID:/data \
--workdir /data/keypair-standalone \
--entrypoint ./keypair "$RUNTIME_IMAGE" \
validate

# standalone binary should run in the host container, so why not?
apk add libunwind # dotnet 6 wants this :shrug:
cd /data/keypair-standalone
./keypair keypair
./keypair validate

# check ca_key public key component matches ca_cert public key
openssl pkey -in ca_key.pem -pubout -out ca_key_pub.pem
openssl x509 -in ca_cert.pem -noout -pubkey -out ca_cert_pub.pem
cmp ca_key_pub.pem ca_cert_pub.pem
65 changes: 57 additions & 8 deletions images/dotnet/tests/main.tf
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@

terraform {
required_providers {
oci = { source = "chainguard-dev/oci" }
imagetest = { source = "chainguard-dev/imagetest" }
apko = { source = "chainguard-dev/apko" }
oci = { source = "chainguard-dev/oci" }
}
}

Expand All @@ -12,12 +15,58 @@ variable "digests" {
})
}

data "oci_exec_test" "sdk-runs" {
digest = var.digests.sdk
script = "docker run --rm $IMAGE_NAME dotnet --info > /dev/null"
variable "test_repository" {
description = "The docker repo root to use for sourcing test images."
}

data "imagetest_inventory" "inventory" {}

resource "imagetest_container_volume" "volume" {
name = "container-volume"
inventory = data.imagetest_inventory.inventory
}

resource "imagetest_harness_docker" "docker" {
name = "docker"
inventory = data.imagetest_inventory.inventory

envs = {
SDK_IMAGE : var.digests.sdk
RUNTIME_IMAGE : var.digests.runtime
VOLUME_ID : imagetest_container_volume.volume.id
}

volumes = [
{
source = imagetest_container_volume.volume
destination = "/data"
}
]

mounts = [
{
source = path.module
destination = "/tests"
}
]
}

data "oci_exec_test" "runtime-runs" {
digest = var.digests.runtime
script = "docker run --rm $IMAGE_NAME --info > /dev/null"
}
resource "imagetest_feature" "test" {

Check failure on line 54 in images/dotnet/tests/main.tf

View workflow job for this annotation

GitHub Actions / build (3, dotnet )

failed to test feature: docker-test

module.dotnet.module.test-latest.imagetest_feature.test
name = "docker-test"
harness = imagetest_harness_docker.docker

steps = [
{
name = "setup"
cmd = "/tests/setup.sh"
},
{
name = "build"
cmd = "/tests/keypairs.sh"
},
{
name = "tzdata"
cmd = "/tests/tzdata.sh"
}
]
}
18 changes: 18 additions & 0 deletions images/dotnet/tests/setup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/bin/bash

set -euo pipefail

chmod 777 -R /data
cp -r /tests/* /data

apk add icu tzdata openssl

UNAME=$(uname -m)
if [ "$UNAME" == "x86_64" ]; then
UNAME="linux-x64"
else
UNAME="linux-arm64"
fi

# need this for dotnet 6 to figure out standalone release target
printf "$UNAME" > /tmp/arch
108 changes: 108 additions & 0 deletions images/dotnet/tests/src/keypair.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
using System;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;

class Program
{
static void Main(string[] args)
{
if (args.Length == 0)
{
Console.WriteLine("need an arg: keypair or validate");
Environment.Exit(1);
}

switch (args[0])
{
case "keypair":
CreateKeyPair();
break;
case "validate":
VerifySignature();
break;
default:
Console.WriteLine("missing keypair or validate option");
Environment.Exit(1);
break;
}
}
static void CreateKeyPair()
{
using var ecdsa = ECDsa.Create(ECCurve.NamedCurves.nistP256);

// save pem formatted key
string caKey = ConvertPrivateKeyToPem(ecdsa);
File.WriteAllText("ca_key.pem", caKey);
Console.WriteLine("Private key saved to ca_key.pem");

// make a cert request to self-sign later
string caSubjectName = "CN=CA, O=Chainguard, C=US";
var caRequest = new CertificateRequest(new X500DistinguishedName(caSubjectName), ecdsa, HashAlgorithmName.SHA256);

// add CA extensions
caRequest.CertificateExtensions.Add(new X509BasicConstraintsExtension(true, false, 0, true));
caRequest.CertificateExtensions.Add(new X509KeyUsageExtension(X509KeyUsageFlags.KeyCertSign | X509KeyUsageFlags.CrlSign, true));

// self-signed as CA root cert
DateTimeOffset startDate = DateTimeOffset.UtcNow;
DateTimeOffset expiryDate = startDate.AddDays(2);
using var caCertificate = caRequest.CreateSelfSigned(startDate, expiryDate);

// save pem formatted cert
string caCertPem = ConvertCertToPem("CERTIFICATE", caCertificate.RawData);
File.WriteAllText("ca_cert.pem", caCertPem, Encoding.UTF8);
Console.WriteLine("CA certificate saved to ca_cert.pem");

}

static string ConvertPrivateKeyToPem(ECDsa ecdsa)
{
byte[] privateKeyBytes = ecdsa.ExportECPrivateKey();
string base64 = Convert.ToBase64String(privateKeyBytes, Base64FormattingOptions.InsertLineBreaks);
return $"-----BEGIN EC PRIVATE KEY-----\n{base64}\n-----END EC PRIVATE KEY-----\n";
}
static string ConvertCertToPem(string type, byte[] data)
{
string base64 = Convert.ToBase64String(data, Base64FormattingOptions.InsertLineBreaks);
return $"-----BEGIN {type}-----\n{base64}\n-----END {type}-----\n";
}

static void VerifySignature()
{
// load private CA key
string privateKeyPem = File.ReadAllText("ca_key.pem");
using var caKey = ECDsa.Create();
caKey.ImportFromPem(privateKeyPem);

// load public CA cert
string certPem = File.ReadAllText("ca_cert.pem");
byte[] certDer = Convert.FromBase64String(ExtractBase64FromPem(certPem));
var caCertificate = new X509Certificate2(certDer);

using var certPublicKey = caCertificate.GetECDsaPublicKey();

byte[] certPublicKeyBytes = certPublicKey.ExportSubjectPublicKeyInfo();
byte[] keyPublicKeyBytes = caKey.ExportSubjectPublicKeyInfo();

// Compare the public key byte arrays
bool isValid = certPublicKeyBytes.SequenceEqual(keyPublicKeyBytes);

if (!isValid)
{
Console.WriteLine("CA signature does NOT match the private key");
Environment.Exit(1);
}

Console.WriteLine("cert is signed by private key");

}
static string ExtractBase64FromPem(string pem)
{
return pem.Replace("-----BEGIN CERTIFICATE-----", "")
.Replace("-----END CERTIFICATE-----", "")
.Replace("\n", "")
.Replace("\r", "")
.Trim();
}
}
19 changes: 19 additions & 0 deletions images/dotnet/tests/src/tzdata.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System;

class Program
{
static void Main()
{
try
{
// Try to find the Eastern Standard Time time zone
var timeZone = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
Console.WriteLine($"Time Zone found: {timeZone.DisplayName}");
}
catch (Exception ex)
{
Console.WriteLine("Timezone error: " + ex.Message);
Environment.Exit(1);
}
}
}
45 changes: 45 additions & 0 deletions images/dotnet/tests/tzdata.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#!/bin/bash

set -euo pipefail

cd /data

# make new project
docker run --rm \
-v $VOLUME_ID:/data \
--workdir /data \
--entrypoint dotnet "$SDK_IMAGE" \
new console --name tzdata

# copy source into project
cp src/tzdata.cs /data/tzdata/Program.cs

# build runtime linked executable
docker run --rm \
-v $VOLUME_ID:/data \
--workdir /data/tzdata \
--entrypoint dotnet "$SDK_IMAGE" \
publish -c Release -o /data/tzdata-runtime

# check tzdata with runtime linked executable
docker run --rm \
-v $VOLUME_ID:/data \
--workdir /data/tzdata-runtime \
--entrypoint ./tzdata "$RUNTIME_IMAGE" \

# build standalone executable
docker run --rm \
-v $VOLUME_ID:/data \
--workdir /data/tzdata \
--entrypoint dotnet "$SDK_IMAGE" \
publish -c Release -r $(cat /tmp/arch) --sc true -p:PublishSingleFile=true -o /data/tzdata-standalone

# check tzdata with standalone executable
docker run --rm \
-v $VOLUME_ID:/data \
--workdir /data/tzdata-standalone \
--entrypoint ./tzdata "$RUNTIME_IMAGE" \

# because we can
cd /data/tzdata-standalone
./tzdata

0 comments on commit 0dc797c

Please sign in to comment.