Skip to content
Merged
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 README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,4 @@ dotnet new function-csharp -n TheFunction -o c:\repos\func
| upbound.io | [Link](https://www.nuget.org/packages/KubernetesCRDModelGen.Models.upbound.io/) |
| vault.upbound.io | [Link](https://www.nuget.org/packages/KubernetesCRDModelGen.Models.vault.upbound.io/) |

- Supports Crossplane v1.17 or greater
- Supports Crossplane v2 or greater
7 changes: 7 additions & 0 deletions src/Function.SDK.CSharp.SourceGenerator/SourceGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,18 @@

namespace Function.SDK.CSharp.SourceGenerator;

/// <summary>
/// Source generator for Function.SDK.CSharp. It reads a Kubernetes Custom Resource Definition (CRD) from an additional text file named "xrd.yaml", processes it, and generates C# code based on the OpenAPI schema defined in the CRD. The generated code is added to the compilation during the build process. The generator also logs diagnostic messages for debugging and error handling purposes.
/// </summary>
[Generator]
public class SourceGenerator : IIncrementalGenerator
{
private static CodeGenerator codeGenerator;

/// <summary>
/// Initializes the source generator. This method is called by the compiler to set up the generator's pipeline.
/// </summary>
/// <param name="context">The context for the incremental generator.</param>
public void Initialize(IncrementalGeneratorInitializationContext context)
{
#if DEBUG
Expand Down Expand Up @@ -82,7 +89,7 @@
{
try
{
var versions = crd.Spec.Versions.Where(x => x.Referenceable);

Check warning on line 92 in src/Function.SDK.CSharp.SourceGenerator/SourceGenerator.cs

View workflow job for this annotation

GitHub Actions / build-test / Build & Test

Dereference of a possibly null reference.

var crossplaneProperties = """
{
Expand Down Expand Up @@ -226,7 +233,7 @@

foreach (var version in versions)
{
var schema = version.Schema.OpenAPIV3Schema;

Check warning on line 236 in src/Function.SDK.CSharp.SourceGenerator/SourceGenerator.cs

View workflow job for this annotation

GitHub Actions / build-test / Build & Test

Dereference of a possibly null reference.

// Append crossplane and status properties to the Composite Resource Model
schema["properties"]["spec"]["properties"]["crossplane"] = JsonNode.Parse(crossplaneProperties)["crossplane"].DeepClone();
Expand Down
42 changes: 17 additions & 25 deletions src/Function.SDK.CSharp/Extensions/RequestExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
using Apiextensions.Fn.Proto.V1;
using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
using k8s;

namespace Function.SDK.CSharp;

Expand Down Expand Up @@ -48,53 +46,46 @@ public static RunFunctionResponse To(this RunFunctionRequest request, Duration t
return resp;
}

public static T GetKubeResource<T>(this Resource resource)
{
var json = JsonFormatter.Default.Format(resource.Resource_);

return KubernetesJson.Deserialize<T>(json);
}

/// <summary>
/// Get Observed Composite Resource from the supplied request.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="request"></param>
/// <returns></returns>
/// <typeparam name="T">The type of the Kubernetes object.</typeparam>
/// <param name="request">The RunFunctionRequest.</param>
/// <returns>The Kubernetes object of the specified type.</returns>
public static T? GetObservedCompositeResource<T>(this RunFunctionRequest request)
{
return request.Observed.Composite.GetKubeResource<T>();
}

/// <summary>
/// Get Observed Composed Resources from the supplied request.
/// Get Observed Resources from the supplied request.
/// </summary>
/// <param name="request">The RunFunctionRequest.</param>
/// <returns>A dictionary mapping resource names to ObservedComposed objects.</returns>
/// <returns>A dictionary mapping resource names to Observed objects.</returns>
/// <exception cref="Exception">Throws if conversion using Resource.AsObject fails.</exception>
public static IDictionary<string, Resource> GetObservedComposedResources(this RunFunctionRequest request)
public static IDictionary<string, Resource> GetObservedResources(this RunFunctionRequest request)
{
return request.Observed.Resources.ToDictionary();
}

/// <summary>
/// Get Desired Composed Resources from the supplied request.
/// Get Desired Resources from the supplied request.
/// </summary>
/// <param name="request">The RunFunctionRequest.</param>
/// <returns>A dictionary mapping resource names to ObservedComposed objects.</returns>
/// <returns>A dictionary mapping resource names to Desired objects.</returns>
/// <exception cref="Exception">Throws if conversion using Resource.AsObject fails.</exception>
public static IDictionary<string, Resource> GetDesiredComposedResources(this RunFunctionRequest request)
public static IDictionary<string, Resource> GetDesiredResources(this RunFunctionRequest request)
{
return request.Desired.Resources.ToDictionary();
}

/// <summary>
/// Get Desired Resource from the supplied request.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="request"></param>
/// <param name="key"></param>
/// <returns></returns>
/// <typeparam name="T">The type of the Kubernetes object.</typeparam>
/// <param name="request">The RunFunctionRequest.</param>
/// <param name="key">The key of the resource.</param>
/// <returns>The Kubernetes object of the specified type, or null if not found.</returns>
public static T? GetDesiredResource<T>(this RunFunctionRequest request, string key)
{
if (request.Desired.Resources.TryGetValue(key, out var resource))
Expand All @@ -108,9 +99,10 @@ public static IDictionary<string, Resource> GetDesiredComposedResources(this Run
/// <summary>
/// Get Observed Resource from the supplied request.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="request"></param>
/// <returns></returns>
/// <typeparam name="T">The type of the Kubernetes object.</typeparam>
/// <param name="request">The RunFunctionRequest.</param>
/// <param name="key">The key of the resource.</param>
/// <returns>The Kubernetes object of the specified type, or null if not found.</returns>
public static T? GetObservedResource<T>(this RunFunctionRequest request, string key)
{
if (request.Observed.Resources.TryGetValue(key, out var resource))
Expand Down
24 changes: 21 additions & 3 deletions src/Function.SDK.CSharp/Extensions/ResourceExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,34 @@
using Apiextensions.Fn.Proto.V1;
using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
using k8s;

namespace Function.SDK.CSharp;

/// <summary>
/// Resource extensions contains utilities for working with Resources.
/// </summary>
public static class ResourceExtensions
{
/// <summary>
/// Converts the Resource to a Kubernetes object of the specified type.
/// </summary>
/// <param name="resource">The Resource to convert.</param>
/// <typeparam name="T">The type of the Kubernetes object.</typeparam>
/// <returns>The Kubernetes object of the specified type.</returns>
public static T GetKubeResource<T>(this Resource resource)
{
var json = JsonFormatter.Default.Format(resource.Resource_);

return KubernetesJson.Deserialize<T>(json);
}
Comment on lines +19 to +24
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add null checks and error handling.

The method lacks defensive checks:

  • No null guard on resource parameter
  • No null check on resource.Resource_
  • No try-catch for deserialization failures (type mismatch, malformed JSON)

These omissions can cause unhandled exceptions at runtime.

🛡️ Proposed fix with null checks and error handling
 public static T GetKubeResource<T>(this Resource resource)
 {
+    if (resource == null)
+        throw new ArgumentNullException(nameof(resource));
+    
+    if (resource.Resource_ == null)
+        throw new InvalidOperationException("Resource.Resource_ is null");
+    
+    try
+    {
         var json = JsonFormatter.Default.Format(resource.Resource_);
-
         return KubernetesJson.Deserialize<T>(json);
+    }
+    catch (Exception ex)
+    {
+        throw new InvalidOperationException($"Failed to deserialize resource to type {typeof(T).Name}", ex);
+    }
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/Function.SDK.CSharp/Extensions/ResourceExtensions.cs` around lines 19 -
24, Add defensive checks and error handling to GetKubeResource<T>: validate the
extension receiver (Resource resource) and resource.Resource_ for null and throw
ArgumentNullException with clear parameter names if null; wrap the
JsonFormatter.Default.Format(...) and KubernetesJson.Deserialize<T>(...) calls
in a try-catch, catching Exception, and rethrow a descriptive
InvalidOperationException (or similar) that includes the target type name
(typeof(T)) and the original exception as innerException so deserialization
errors (malformed JSON or type mismatches) are surfaced with context rather than
causing obscure failures; do not swallow the exception and ensure messages
reference Resource.Resource_ and the failing operation (format/deserialize).


/// <summary>
/// Gets the Resource condition by name
/// </summary>
/// <param name="resource"></param>
/// <param name="conditionType"></param>
/// <returns></returns>
/// <param name="resource">The Resource to get the condition from.</param>
/// <param name="conditionType">The type of the condition to get.</param>
/// <returns>The condition as a Struct, or null if not found.</returns>
public static Struct? GetCondition(this Resource resource, string conditionType)
{
if (resource.Resource_.Fields.TryGetValue("status", out Value? status))
Expand Down
9 changes: 8 additions & 1 deletion src/Function.SDK.CSharp/Extensions/ResponseExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -146,9 +146,16 @@ public static void RequireResources(
rsp.Requirements.Resources[name] = selector;
}

/// <summary>
/// UpdateDesiredReadyStatus iterates through the desired resources in the response and updates their Ready status based on the observed resources in the request.
/// </summary>
/// <param name="response">The RunFunctionResponse containing the desired resources.</param>
/// <param name="request">The RunFunctionRequest containing the observed resources.</param>
/// <param name="_logger">The logger to use for logging information.</param>
/// <param name="ignoreNoReadyCondition">An optional array of resource identifiers to ignore if they have no Ready condition.</param>
public static void UpdateDesiredReadyStatus(this RunFunctionResponse response, RunFunctionRequest request, ILogger _logger, string[]? ignoreNoReadyCondition = null)
{
var observed = request.GetObservedComposedResources();
var observed = request.GetObservedResources();

foreach (var dr in response.Desired.Resources.ToDictionary())
{
Expand Down
17 changes: 13 additions & 4 deletions src/Function.SDK.CSharp/Extensions/StateExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,25 @@

namespace Function.SDK.CSharp;

/// <summary>
/// State extensions contains utilities for working with State objects.
/// </summary>
public static class StateExtensions
{
/// <summary>
/// Adds Resource or merges with an exiting one
/// Adds Resource or merges with an existing one. Sets the ApiVersion and Kind if not set on the object.
/// If the resource with the same key already exists, the existing resource will be merged with the new one using protobuf merge semantics.
/// </summary>
/// <param name="state"></param>
/// <param name="key"></param>
/// <param name="obj"></param>
/// <param name="state">The state to update.</param>
/// <param name="key">The key of the resource.</param>
/// <param name="obj">The Kubernetes object to add or update.</param>
public static void AddOrUpdate(this State state, string key, IKubernetesObject obj)
{
if (string.IsNullOrEmpty(obj.ApiVersion) || string.IsNullOrEmpty(obj.Kind))
{
obj.Initialize();
}

var kubeObj = Struct.Parser.ParseJson(KubernetesJson.Serialize(obj));

if (state.Resources.TryGetValue(key, out Resource? value))
Expand Down
186 changes: 93 additions & 93 deletions src/Function.SDK.CSharp/Models/V1ConversionReview.cs
Original file line number Diff line number Diff line change
@@ -1,94 +1,94 @@
using System.Runtime.Serialization;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace Function.SDK.CSharp.Models;

public sealed class V1ConversionReview
{
public const string KubeApiVersion = "v1";
public const string KubeKind = "ConversionReview";
public const string KubeGroup = "apiextensions.k8s.io";

[JsonPropertyName("apiVersion")]
public string ApiVersion { get; set; } = KubeGroup + "/" + KubeApiVersion;

[JsonPropertyName("kind")]
public string Kind { get; set; } = KubeKind;

[JsonPropertyName("request")]
public V1ConversionReviewRequest Request { get; set; }

[JsonPropertyName("response")]
public V1ConversionReviewResponse Response { get; set; } = new();
}

public sealed class V1ConversionReviewRequest
{
/// <summary>
/// Random uid uniquely identifying this conversion call
/// </summary>
[JsonPropertyName("uid")]
public string Uid { get; set; } = default!;

/// <summary>
/// The API group and version the objects should be converted to
/// </summary>
[JsonPropertyName("desiredAPIVersion")]
public string DesiredApiVersion { get; set; } = default!;

/// <summary>
/// # The list of objects to convert. May contain one or more objects, in one or more versions.
/// </summary>
[JsonPropertyName("objects")]
public JsonElement[] Objects { get; set; } = default!;
}

public sealed class V1ConversionReviewResponse
{
/// <summary>
/// Must match &lt;request.uid&gt;
/// </summary>
[JsonPropertyName("uid")]
public string Uid { get; set; } = "";

/// <summary>
/// Objects must match the order of request.objects, and have apiVersion set to &lt;request.desiredAPIVersion&gt;.
/// kind, metadata.uid, metadata.name, and metadata.namespace fields must not be changed by the webhook.
/// metadata.labels and metadata.annotations fields may be changed by the webhook.
/// All other changes to metadata fields by the webhook are ignored.
/// </summary>
[JsonPropertyName("convertedObjects")]
public List<JsonElement> ConvertedObjects { get; set; } = [];

[JsonPropertyName("result")]
public V1ConversionReviewResponseStatus Result { get; set; } = new();
}

/// <summary>
/// Webhook Response Status
/// </summary>
public enum V1ConversionReviewResponseStatusEnum
{
///<summary>Success</summary>
[EnumMember(Value = "Success"), JsonStringEnumMemberName("Success")]
Success,
///<summary>Failure</summary>
[EnumMember(Value = "Failure"), JsonStringEnumMemberName("Failure")]
Failure,
}

public sealed class V1ConversionReviewResponseStatus
{
[JsonPropertyName("status")]
public V1ConversionReviewResponseStatusEnum Status { get; set; }

[JsonPropertyName("message")]
public string? Message { get; set; }

[JsonPropertyName("reason")]
public string? Reason { get; set; }

[JsonPropertyName("code")]
public int Code { get; set; } = 200;
using System.Runtime.Serialization;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Function.SDK.CSharp.Models;
public sealed class V1ConversionReview

Check warning on line 7 in src/Function.SDK.CSharp/Models/V1ConversionReview.cs

View workflow job for this annotation

GitHub Actions / build-test / Build & Test

Missing XML comment for publicly visible type or member 'V1ConversionReview'

Check warning on line 7 in src/Function.SDK.CSharp/Models/V1ConversionReview.cs

View workflow job for this annotation

GitHub Actions / build-test / Build & Test

Missing XML comment for publicly visible type or member 'V1ConversionReview'
{
public const string KubeApiVersion = "v1";

Check warning on line 9 in src/Function.SDK.CSharp/Models/V1ConversionReview.cs

View workflow job for this annotation

GitHub Actions / build-test / Build & Test

Missing XML comment for publicly visible type or member 'V1ConversionReview.KubeApiVersion'

Check warning on line 9 in src/Function.SDK.CSharp/Models/V1ConversionReview.cs

View workflow job for this annotation

GitHub Actions / build-test / Build & Test

Missing XML comment for publicly visible type or member 'V1ConversionReview.KubeApiVersion'
public const string KubeKind = "ConversionReview";

Check warning on line 10 in src/Function.SDK.CSharp/Models/V1ConversionReview.cs

View workflow job for this annotation

GitHub Actions / build-test / Build & Test

Missing XML comment for publicly visible type or member 'V1ConversionReview.KubeKind'

Check warning on line 10 in src/Function.SDK.CSharp/Models/V1ConversionReview.cs

View workflow job for this annotation

GitHub Actions / build-test / Build & Test

Missing XML comment for publicly visible type or member 'V1ConversionReview.KubeKind'
public const string KubeGroup = "apiextensions.k8s.io";

Check warning on line 11 in src/Function.SDK.CSharp/Models/V1ConversionReview.cs

View workflow job for this annotation

GitHub Actions / build-test / Build & Test

Missing XML comment for publicly visible type or member 'V1ConversionReview.KubeGroup'

Check warning on line 11 in src/Function.SDK.CSharp/Models/V1ConversionReview.cs

View workflow job for this annotation

GitHub Actions / build-test / Build & Test

Missing XML comment for publicly visible type or member 'V1ConversionReview.KubeGroup'
[JsonPropertyName("apiVersion")]
public string ApiVersion { get; set; } = KubeGroup + "/" + KubeApiVersion;

Check warning on line 14 in src/Function.SDK.CSharp/Models/V1ConversionReview.cs

View workflow job for this annotation

GitHub Actions / build-test / Build & Test

Missing XML comment for publicly visible type or member 'V1ConversionReview.ApiVersion'

Check warning on line 14 in src/Function.SDK.CSharp/Models/V1ConversionReview.cs

View workflow job for this annotation

GitHub Actions / build-test / Build & Test

Missing XML comment for publicly visible type or member 'V1ConversionReview.ApiVersion'
[JsonPropertyName("kind")]
public string Kind { get; set; } = KubeKind;

Check warning on line 17 in src/Function.SDK.CSharp/Models/V1ConversionReview.cs

View workflow job for this annotation

GitHub Actions / build-test / Build & Test

Missing XML comment for publicly visible type or member 'V1ConversionReview.Kind'

Check warning on line 17 in src/Function.SDK.CSharp/Models/V1ConversionReview.cs

View workflow job for this annotation

GitHub Actions / build-test / Build & Test

Missing XML comment for publicly visible type or member 'V1ConversionReview.Kind'
[JsonPropertyName("request")]
public V1ConversionReviewRequest Request { get; set; }

Check warning on line 20 in src/Function.SDK.CSharp/Models/V1ConversionReview.cs

View workflow job for this annotation

GitHub Actions / build-test / Build & Test

Non-nullable property 'Request' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable.

Check warning on line 20 in src/Function.SDK.CSharp/Models/V1ConversionReview.cs

View workflow job for this annotation

GitHub Actions / build-test / Build & Test

Missing XML comment for publicly visible type or member 'V1ConversionReview.Request'

Check warning on line 20 in src/Function.SDK.CSharp/Models/V1ConversionReview.cs

View workflow job for this annotation

GitHub Actions / build-test / Build & Test

Non-nullable property 'Request' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Address the non-nullable property initialization warning.

The Request property is declared as non-nullable but has no default value, required modifier, or initializer. While this likely works in practice since JSON deserialization populates it, it violates C#'s nullability contracts and triggers CS8618. Consider one of these approaches:

Proposed fixes

Option 1 (recommended): Use the required modifier to enforce initialization

 [JsonPropertyName("request")]
-public V1ConversionReviewRequest Request { get; set; }
+public required V1ConversionReviewRequest Request { get; set; }

Option 2: Make the property nullable if it's optional

 [JsonPropertyName("request")]
-public V1ConversionReviewRequest Request { get; set; }
+public V1ConversionReviewRequest? Request { get; set; }

Option 3: Add a default value with null-forgiving operator

 [JsonPropertyName("request")]
-public V1ConversionReviewRequest Request { get; set; }
+public V1ConversionReviewRequest Request { get; set; } = default!;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public V1ConversionReviewRequest Request { get; set; }
[JsonPropertyName("request")]
public required V1ConversionReviewRequest Request { get; set; }
🧰 Tools
🪛 GitHub Actions: PR Build & Test / 0_build-test _ Build & Test.txt

[warning] 20-20: CS1591: Missing XML comment for publicly visible type or member 'V1ConversionReview.Request'.


[warning] 20-20: CS8618: Non-nullable property 'Request' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable.

🪛 GitHub Actions: PR Build & Test / build-test _ Build & Test

[warning] 20-20: warning CS8618: Non-nullable property 'Request' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. (net9.0)


[warning] 20-20: warning CS1591: Missing XML comment for publicly visible type or member 'V1ConversionReview.Request' (net9.0)


[warning] 20-20: warning CS8618: Non-nullable property 'Request' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. (net10.0)


[warning] 20-20: warning CS1591: Missing XML comment for publicly visible type or member 'V1ConversionReview.Request' (net10.0)

🪛 GitHub Check: build-test / Build & Test

[warning] 20-20:
Non-nullable property 'Request' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable.


[warning] 20-20:
Missing XML comment for publicly visible type or member 'V1ConversionReview.Request'


[warning] 20-20:
Non-nullable property 'Request' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/Function.SDK.CSharp/Models/V1ConversionReview.cs` at line 20, The
non-nullable property `Request` on `V1ConversionReview` triggers CS8618 because
it has no initializer; update the declaration of `public
V1ConversionReviewRequest Request { get; set; }` to ensure it is always
initialized—preferably add the `required` modifier (e.g., make it `required
V1ConversionReviewRequest Request`) so callers/deserializers must supply it;
alternatively, if it can be absent make the type nullable
(`V1ConversionReviewRequest? Request`) or provide a default using the
null-forgiving operator—choose the `required` approach for strictness.

[JsonPropertyName("response")]
public V1ConversionReviewResponse Response { get; set; } = new();

Check warning on line 23 in src/Function.SDK.CSharp/Models/V1ConversionReview.cs

View workflow job for this annotation

GitHub Actions / build-test / Build & Test

Missing XML comment for publicly visible type or member 'V1ConversionReview.Response'
}
public sealed class V1ConversionReviewRequest
{
/// <summary>
/// Random uid uniquely identifying this conversion call
/// </summary>
[JsonPropertyName("uid")]
public string Uid { get; set; } = default!;
/// <summary>
/// The API group and version the objects should be converted to
/// </summary>
[JsonPropertyName("desiredAPIVersion")]
public string DesiredApiVersion { get; set; } = default!;
/// <summary>
/// # The list of objects to convert. May contain one or more objects, in one or more versions.
/// </summary>
[JsonPropertyName("objects")]
public JsonElement[] Objects { get; set; } = default!;
}
public sealed class V1ConversionReviewResponse
{
/// <summary>
/// Must match &lt;request.uid&gt;
/// </summary>
[JsonPropertyName("uid")]
public string Uid { get; set; } = "";
/// <summary>
/// Objects must match the order of request.objects, and have apiVersion set to &lt;request.desiredAPIVersion&gt;.
/// kind, metadata.uid, metadata.name, and metadata.namespace fields must not be changed by the webhook.
/// metadata.labels and metadata.annotations fields may be changed by the webhook.
/// All other changes to metadata fields by the webhook are ignored.
/// </summary>
[JsonPropertyName("convertedObjects")]
public List<JsonElement> ConvertedObjects { get; set; } = [];
[JsonPropertyName("result")]
public V1ConversionReviewResponseStatus Result { get; set; } = new();
}
/// <summary>
/// Webhook Response Status
/// </summary>
public enum V1ConversionReviewResponseStatusEnum
{
///<summary>Success</summary>
[EnumMember(Value = "Success"), JsonStringEnumMemberName("Success")]
Success,
///<summary>Failure</summary>
[EnumMember(Value = "Failure"), JsonStringEnumMemberName("Failure")]
Failure,
}
public sealed class V1ConversionReviewResponseStatus
{
[JsonPropertyName("status")]
public V1ConversionReviewResponseStatusEnum Status { get; set; }
[JsonPropertyName("message")]
public string? Message { get; set; }
[JsonPropertyName("reason")]
public string? Reason { get; set; }
[JsonPropertyName("code")]
public int Code { get; set; } = 200;
}
Loading
Loading