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
20 changes: 19 additions & 1 deletion Conductor/Client/Models/Task.cs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ public enum StatusEnum
/// <param name="workflowPriority">workflowPriority.</param>
/// <param name="workflowTask">workflowTask.</param>
/// <param name="workflowType">workflowType.</param>
public Task(long? callbackAfterSeconds = default(long?), bool? callbackFromWorker = default(bool?), string correlationId = default(string), string domain = default(string), long? endTime = default(long?), bool? executed = default(bool?), string executionNameSpace = default(string), string externalInputPayloadStoragePath = default(string), string externalOutputPayloadStoragePath = default(string), Dictionary<string, Object> inputData = default(Dictionary<string, Object>), string isolationGroupId = default(string), int? iteration = default(int?), bool? loopOverTask = default(bool?), Dictionary<string, Object> outputData = default(Dictionary<string, Object>), int? pollCount = default(int?), long? queueWaitTime = default(long?), int? rateLimitFrequencyInSeconds = default(int?), int? rateLimitPerFrequency = default(int?), string reasonForIncompletion = default(string), string referenceTaskName = default(string), long? responseTimeoutSeconds = default(long?), bool? retried = default(bool?), string retriedTaskId = default(string), int? retryCount = default(int?), long? scheduledTime = default(long?), int? seq = default(int?), int? startDelayInSeconds = default(int?), long? startTime = default(long?), StatusEnum? status = default(StatusEnum?), string subWorkflowId = default(string), bool? subworkflowChanged = default(bool?), string taskDefName = default(string), TaskDef taskDefinition = default(TaskDef), string taskId = default(string), string taskType = default(string), long? updateTime = default(long?), string workerId = default(string), string workflowInstanceId = default(string), int? workflowPriority = default(int?), WorkflowTask workflowTask = default(WorkflowTask), string workflowType = default(string))
public Task(long? callbackAfterSeconds = default(long?), bool? callbackFromWorker = default(bool?), string correlationId = default(string), string domain = default(string), long? endTime = default(long?), bool? executed = default(bool?), string executionNameSpace = default(string), string externalInputPayloadStoragePath = default(string), string externalOutputPayloadStoragePath = default(string), Dictionary<string, Object> inputData = default(Dictionary<string, Object>), string isolationGroupId = default(string), int? iteration = default(int?), bool? loopOverTask = default(bool?), Dictionary<string, Object> outputData = default(Dictionary<string, Object>), int? pollCount = default(int?), long? queueWaitTime = default(long?), int? rateLimitFrequencyInSeconds = default(int?), int? rateLimitPerFrequency = default(int?), string reasonForIncompletion = default(string), string referenceTaskName = default(string), long? responseTimeoutSeconds = default(long?), bool? retried = default(bool?), string retriedTaskId = default(string), int? retryCount = default(int?), long? scheduledTime = default(long?), int? seq = default(int?), int? startDelayInSeconds = default(int?), long? startTime = default(long?), StatusEnum? status = default(StatusEnum?), string subWorkflowId = default(string), bool? subworkflowChanged = default(bool?), string taskDefName = default(string), TaskDef taskDefinition = default(TaskDef), string taskId = default(string), string taskType = default(string), long? updateTime = default(long?), string workerId = default(string), string workflowInstanceId = default(string), int? workflowPriority = default(int?), WorkflowTask workflowTask = default(WorkflowTask), string workflowType = default(string), Dictionary<string, string> runtimeMetadata = default(Dictionary<string, string>))
{
this.CallbackAfterSeconds = callbackAfterSeconds;
this.CallbackFromWorker = callbackFromWorker;
Expand Down Expand Up @@ -171,6 +171,7 @@ public enum StatusEnum
this.WorkflowPriority = workflowPriority;
this.WorkflowTask = workflowTask;
this.WorkflowType = workflowType;
this.RuntimeMetadata = runtimeMetadata;
}

/// <summary>
Expand Down Expand Up @@ -257,6 +258,14 @@ public enum StatusEnum
[DataMember(Name = "outputData", EmitDefaultValue = false)]
public Dictionary<string, Object> OutputData { get; set; }

/// <summary>
/// Secret values the server resolved for this task at poll time and delivered on the wire
/// only (never persisted). Populated when the task's TaskDef.runtimeMetadata declares secret
/// names the host resolves from its secret store (conductor-oss PR #1255). Empty/absent otherwise.
/// </summary>
[DataMember(Name = "runtimeMetadata", EmitDefaultValue = false)]
public Dictionary<string, string> RuntimeMetadata { get; set; }

/// <summary>
/// Gets or Sets PollCount
/// </summary>
Expand Down Expand Up @@ -436,6 +445,7 @@ public override string ToString()
sb.Append(" Iteration: ").Append(Iteration).Append("\n");
sb.Append(" LoopOverTask: ").Append(LoopOverTask).Append("\n");
sb.Append(" OutputData: ").Append(OutputData).Append("\n");
sb.Append(" RuntimeMetadata: ").Append(RuntimeMetadata).Append("\n");
sb.Append(" PollCount: ").Append(PollCount).Append("\n");
sb.Append(" QueueWaitTime: ").Append(QueueWaitTime).Append("\n");
sb.Append(" RateLimitFrequencyInSeconds: ").Append(RateLimitFrequencyInSeconds).Append("\n");
Expand Down Expand Up @@ -569,6 +579,12 @@ public bool Equals(Task input)
input.OutputData != null &&
this.OutputData.SequenceEqual(input.OutputData)
) &&
(
this.RuntimeMetadata == input.RuntimeMetadata ||
this.RuntimeMetadata != null &&
input.RuntimeMetadata != null &&
this.RuntimeMetadata.SequenceEqual(input.RuntimeMetadata)
) &&
(
this.PollCount == input.PollCount ||
(this.PollCount != null &&
Expand Down Expand Up @@ -743,6 +759,8 @@ public override int GetHashCode()
hashCode = hashCode * 59 + this.LoopOverTask.GetHashCode();
if (this.OutputData != null)
hashCode = hashCode * 59 + this.OutputData.GetHashCode();
if (this.RuntimeMetadata != null)
hashCode = hashCode * 59 + this.RuntimeMetadata.GetHashCode();
if (this.PollCount != null)
hashCode = hashCode * 59 + this.PollCount.GetHashCode();
if (this.QueueWaitTime != null)
Expand Down
53 changes: 53 additions & 0 deletions Tests/Client/TaskRuntimeMetadataTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright 2025 Conductor Authors.
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
using System.Collections.Generic;
using Newtonsoft.Json;
using Xunit;
using ModelTask = Conductor.Client.Models.Task;

namespace Tests.Client
{
/// <summary>
/// The server delivers host-resolved secret values on Task.runtimeMetadata (wire-only, never
/// persisted) when a worker's TaskDef.runtimeMetadata declares secret names (conductor-oss PR
/// #1255). Verify the client model round-trips the field and omits it when empty.
/// </summary>
public class TaskRuntimeMetadataTests
{
[Fact]
public void RuntimeMetadata_RoundTrips()
{
var task = new ModelTask(
taskId: "t1",
runtimeMetadata: new Dictionary<string, string>
{
{ "GITHUB_TOKEN", "ghp_secret" },
{ "GH_APP_ID", "42" }
});

var json = JsonConvert.SerializeObject(task);
Assert.Contains("\"runtimeMetadata\"", json);

var back = JsonConvert.DeserializeObject<ModelTask>(json);
Assert.Equal("ghp_secret", back.RuntimeMetadata["GITHUB_TOKEN"]);
Assert.Equal("42", back.RuntimeMetadata["GH_APP_ID"]);
}

[Fact]
public void RuntimeMetadata_OmittedWhenEmpty()
{
var json = JsonConvert.SerializeObject(new ModelTask(taskId: "t1"));
Assert.DoesNotContain("runtimeMetadata", json);
}
}
}
Loading