Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ jobs:
- name: Setup .NET SDK
uses: actions/setup-dotnet@87b7050bc53ea08284295505d98d2aa94301e852 # v4.2.0
with:
dotnet-version: 8.0.x
dotnet-version: 10.0.x
- name: Execute Functional Tests
run: |
set -xe
Expand Down
10 changes: 5 additions & 5 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
# Contrast Security, Inc licenses this file to you under the Apache 2.0 License.
# See the LICENSE file in the project root for more information.

FROM mcr.microsoft.com/dotnet/aspnet:8.0.22-bookworm-slim AS base
FROM mcr.microsoft.com/dotnet/aspnet:10.0.0-noble AS base

# To aid in debugging.
RUN set -xe \
&& apt-get update \
&& apt-get install -y --no-install-recommends curl jq \
&& apt-get clean && rm -rf /var/lib/apt/lists/*

FROM mcr.microsoft.com/dotnet/sdk:8.0.416-bookworm-slim AS build
FROM mcr.microsoft.com/dotnet/sdk:10.0.100-noble AS build
WORKDIR /source

# Restore
Expand All @@ -33,8 +33,8 @@ FROM base AS final
WORKDIR /app

RUN set -xe \
&& addgroup --gid 1000 operator-group \
&& useradd -G operator-group --uid 1000 operator-user
&& groupadd --gid 1001 operator-group \
&& useradd -G operator-group --uid 1001 operator-user

COPY src/get-info.sh /get-info.sh
COPY --from=build /app .
Expand All @@ -43,7 +43,7 @@ RUN set -xe \
&& chown operator-user:operator-group -R . \
&& chmod +x /get-info.sh

USER 1000
USER 1001

ENV ASPNETCORE_URLS=https://+:5001 \
ASPNETCORE_ENVIRONMENT=Production \
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<LangVersion>11.0</LangVersion>
<nullable>enable</nullable>
<IsPackable>false</IsPackable>
Expand Down Expand Up @@ -37,14 +37,11 @@
</PackageReference>

<PackageReference Include="Sigil" Version="5.0.0" />
<PackageReference Include="KubeOps.Operator.Web" Version="9.5.0" />
<PackageReference Include="KubeOps.Generator" Version="9.5.0">
<PackageReference Include="KubeOps.Operator.Web" Version="10.0.0" />
<PackageReference Include="KubeOps.Generator" Version="10.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>

<!--https://github.com/dotnet/runtime/issues/60393 (can remove after .NET 9)-->
<PackageReference Include="HexMate" Version="0.0.3" />
</ItemGroup>


Expand Down
33 changes: 33 additions & 0 deletions src/Contrast.K8s.AgentOperator/Core/HashHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Contrast Security, Inc licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information.

using System;
using System.Security.Cryptography;
using System.Text;

namespace Contrast.K8s.AgentOperator.Core;

public static class HashHelper
{
public static string GetShortHash(string text)
{
using var sha256 = SHA256.Create();
var bytes = Encoding.UTF8.GetBytes(text);
var hash = sha256.ComputeHash(bytes);
return Convert.ToHexStringLower(hash, 0, 8);
}

public static string Sha256(string text)
{
using var sha256 = SHA256.Create();
var bytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(text));
return Convert.ToHexStringLower(bytes);
}

public static string Sha256(byte[] data)
{
using var sha256 = SHA256.Create();
var bytes = sha256.ComputeHash(data);
return Convert.ToHexStringLower(bytes);
}
}
30 changes: 0 additions & 30 deletions src/Contrast.K8s.AgentOperator/Core/HexConverter.cs

This file was deleted.

This file was deleted.

39 changes: 39 additions & 0 deletions src/Contrast.K8s.AgentOperator/Core/Kube/EntityMetadataCache.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Contrast Security, Inc licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information.

using k8s.Models;
using KubeOps.Abstractions.Entities;
using System;
using System.Collections.Concurrent;
using System.Reflection;

namespace Contrast.K8s.AgentOperator.Core.Kube;

public static class EntityMetadataCache
{
private static readonly ConcurrentDictionary<Type, EntityMetadata> MetadataCache = new();

public static EntityMetadata GetMetadata<TEntity>()
{
var type = typeof(TEntity);
return MetadataCache.GetOrAdd(type, CreateMetadata);
}

private static EntityMetadata CreateMetadata(Type resourceType)
{
var attribute = resourceType.GetCustomAttribute<KubernetesEntityAttribute>();
if (attribute == null)
{
throw new ArgumentException($"The Type {resourceType} does not have the kubernetes entity attribute.");
}

var kind = string.IsNullOrWhiteSpace(attribute.Kind) ? resourceType.Name : attribute.Kind;
var version = string.IsNullOrWhiteSpace(attribute.ApiVersion) ? "v1" : attribute.ApiVersion;

return new EntityMetadata(
kind,
version,
attribute.Group,
attribute.PluralName);
}
}
Original file line number Diff line number Diff line change
@@ -1,25 +1,24 @@
// Contrast Security, Inc licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information.

using k8s;
using k8s.Models;
using KubeOps.KubernetesClient;
using System;
using System.Collections.Generic;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using k8s;
using k8s.Models;
using KubeOps.KubernetesClient;

namespace Contrast.K8s.AgentOperator.Core.Kube;

public static class KubernetesClientExtensions
{
public static async ValueTask Patch<T>(this IKubernetesClient client, T resource, JsonNode patchDocument, string fieldManager)
public static async ValueTask PatchEntity<T>(this IKubernetesClient client, T resource, string patch, string fieldManager)
where T : IKubernetesObject<V1ObjectMeta>
{
var apiClient = client.ApiClient;
var crd = resource.CreateResourceDefinition();
var crPatch = new V1Patch(patchDocument.ToJsonString(), V1Patch.PatchType.JsonPatch);
var crd = EntityMetadataCache.GetMetadata<T>();
var crPatch = new V1Patch(patch, V1Patch.PatchType.JsonPatch);

if (string.IsNullOrWhiteSpace(resource.Metadata.NamespaceProperty))
{
Expand All @@ -46,38 +45,6 @@ public static async ValueTask Patch<T>(this IKubernetesClient client, T resource
}
}

public static async ValueTask PatchStatus<T>(this IKubernetesClient client, T resource, JsonNode patchDocument, string fieldManager)
where T : IKubernetesObject<V1ObjectMeta>
{
var apiClient = client.ApiClient;
var crd = resource.CreateResourceDefinition();
var crPatch = new V1Patch(patchDocument.ToString(), V1Patch.PatchType.JsonPatch);

if (string.IsNullOrWhiteSpace(resource.Metadata.NamespaceProperty))
{
using var result = await apiClient.CustomObjects.PatchClusterCustomObjectStatusWithHttpMessagesAsync(
crPatch,
crd.Group,
crd.Version,
crd.Plural,
resource.Metadata.Name,
fieldManager: fieldManager
);
}
else
{
using var result = await apiClient.CustomObjects.PatchNamespacedCustomObjectStatusWithHttpMessagesAsync(
crPatch,
crd.Group,
crd.Version,
resource.Metadata.NamespaceProperty,
crd.Plural,
resource.Metadata.Name,
fieldManager: fieldManager
);
}
}

public static async ValueTask PatchStatus<T>(this IKubernetesClient client,
string name,
string? @namespace,
Expand All @@ -86,24 +53,7 @@ public static async ValueTask PatchStatus<T>(this IKubernetesClient client,
where T : IKubernetesObject<V1ObjectMeta>
{
var apiClient = client.ApiClient;
var crd = CustomEntityDefinitionExtensions.CreateResourceDefinition<T>();

//var headers = new Dictionary<string, IReadOnlyList<string>>();
//if (typeof(T).Assembly == typeof(V1Pod).Assembly)
//{
// headers.Add("content-type", new List<string>
// {
// "application/strategic-merge-patch+json"
// });
//}
//else
//{
// // Strategic merge patch is only support for core types.
// headers.Add("content-type", new List<string>
// {
// "application/merge-patch+json"
// });
//}
var crd = EntityMetadataCache.GetMetadata<T>();

var body = new StrategicMergePatchBase
{
Expand Down
Loading
Loading