diff --git a/src/Agent.Sdk/Knob/AgentKnobs.cs b/src/Agent.Sdk/Knob/AgentKnobs.cs
index 25ff9db01d..e4126e0782 100644
--- a/src/Agent.Sdk/Knob/AgentKnobs.cs
+++ b/src/Agent.Sdk/Knob/AgentKnobs.cs
@@ -779,5 +779,12 @@ public class AgentKnobs
"If true, agent will use sparse checkout in checkout task.",
new RuntimeKnobSource("AGENT_USE_SPARSE_CHECKOUT_IN_CHECKOUT_TASK"),
new BuiltInDefaultKnobSource("false"));
+
+ public static readonly Knob UseSha256InComputeHash = new Knob(
+ nameof(UseSha256InComputeHash),
+ "If true, agent will use SHA256 algorithm in ComputeHash.",
+ new RuntimeKnobSource("AGENT_USE_SHA256_IN_COMPUTE_HASH"),
+ new EnvironmentKnobSource("AGENT_USE_SHA256_IN_COMPUTE_HASH"),
+ new BuiltInDefaultKnobSource("true"));
}
}
diff --git a/src/Agent.Worker/Build/TrackingConfig.cs b/src/Agent.Worker/Build/TrackingConfig.cs
index c9922277e0..022fbd3e2e 100644
--- a/src/Agent.Worker/Build/TrackingConfig.cs
+++ b/src/Agent.Worker/Build/TrackingConfig.cs
@@ -9,6 +9,7 @@
using System.ComponentModel;
using System.Globalization;
using System.IO;
+using Agent.Sdk.Knob;
namespace Microsoft.VisualStudio.Services.Agent.Worker.Build
{
@@ -98,7 +99,7 @@ public TrackingConfig(
}
// Now that we have all the repositories set up, we can compute the config hash
- HashKey = TrackingConfigHashAlgorithm.ComputeHash(CollectionId, DefinitionId, RepositoryTrackingInfo);
+ HashKey = TrackingConfigHashAlgorithm.ComputeHash(CollectionId, DefinitionId, RepositoryTrackingInfo, AgentKnobs.UseSha256InComputeHash.GetValue(executionContext).AsBoolean());
}
[JsonIgnore]
diff --git a/src/Agent.Worker/Build/TrackingConfigHashAlgorithm.cs b/src/Agent.Worker/Build/TrackingConfigHashAlgorithm.cs
index a1aecfea05..bd7c7b46b8 100644
--- a/src/Agent.Worker/Build/TrackingConfigHashAlgorithm.cs
+++ b/src/Agent.Worker/Build/TrackingConfigHashAlgorithm.cs
@@ -16,7 +16,7 @@ public class TrackingConfigHashAlgorithm
///
/// This method returns the hash key that combines repository hash keys.
///
- public static string ComputeHash(string collectionId, string definitionId, IList repositories)
+ public static string ComputeHash(string collectionId, string definitionId, IList repositories, bool UseSha256InComputeHash)
{
// Validate parameters.
ArgUtil.NotNull(collectionId, nameof(collectionId));
@@ -50,22 +50,39 @@ public static string ComputeHash(string collectionId, string definitionId, IList
definitionId,
string.Join(';', repositories.OrderBy(x => x.Identifier).Select(x => $"{x.Identifier}:{x.RepositoryUrl}")));
}
- return CreateHash(hashInput);
+ return CreateHash(hashInput, UseSha256InComputeHash);
}
- private static string CreateHash(string hashInput)
+ private static string CreateHash(string hashInput, bool UseSha256InComputeHash)
{
- using (SHA256 sha256Hash = SHA256.Create())
+ if(UseSha256InComputeHash)
{
- byte[] data = sha256Hash.ComputeHash(Encoding.UTF8.GetBytes(hashInput));
- StringBuilder hexString = new StringBuilder();
- for (int i = 0; i < data.Length; i++)
+ using (SHA256 sha256Hash = SHA256.Create())
{
- hexString.Append(data[i].ToString("x2"));
- }
+ byte[] data = sha256Hash.ComputeHash(Encoding.UTF8.GetBytes(hashInput));
+ StringBuilder hexString = new StringBuilder();
+ for (int i = 0; i < data.Length; i++)
+ {
+ hexString.Append(data[i].ToString("x2"));
+ }
- return hexString.ToString();
+ return hexString.ToString();
+ }
}
+ else
+ {
+ using (SHA1 SHA1 = SHA1.Create())
+ {
+ byte[] data = SHA1.ComputeHash(Encoding.UTF8.GetBytes(hashInput));
+ StringBuilder hexString = new StringBuilder();
+ for (int i = 0; i < data.Length; i++)
+ {
+ hexString.Append(data[i].ToString("x2"));
+ }
+
+ return hexString.ToString();
+ }
+ }
}
}
}
diff --git a/src/Agent.Worker/ExecutionContext.cs b/src/Agent.Worker/ExecutionContext.cs
index d38702e216..fcaf04f43b 100644
--- a/src/Agent.Worker/ExecutionContext.cs
+++ b/src/Agent.Worker/ExecutionContext.cs
@@ -718,8 +718,9 @@ private string GetWorkspaceIdentifier(Pipelines.AgentJobRequestMessage message)
Variables.TryGetValue(Constants.Variables.System.CollectionId, out string collectionId);
Variables.TryGetValue(Constants.Variables.System.DefinitionId, out string definitionId);
var repoTrackingInfos = message.Resources.Repositories.Select(repo => new Build.RepositoryTrackingInfo(repo, "/")).ToList();
- var workspaceIdentifier = Build.TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, repoTrackingInfos);
-
+ // Determine the hash algorithm based on the knob value
+ var workspaceIdentifier = Build.TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, repoTrackingInfos, AgentKnobs.UseSha256InComputeHash.GetValue(_parentExecutionContext).AsBoolean());
+
Trace.Info($"WorkspaceIdentifier '{workspaceIdentifier}' created for repos {String.Join(',', repoTrackingInfos)}");
return workspaceIdentifier;
}
diff --git a/src/Test/L0/Worker/Build/TrackingConfigHashAlgorithmL0.cs b/src/Test/L0/Worker/Build/TrackingConfigHashAlgorithmL0.cs
index 3c0b408e13..e94a5fe58d 100644
--- a/src/Test/L0/Worker/Build/TrackingConfigHashAlgorithmL0.cs
+++ b/src/Test/L0/Worker/Build/TrackingConfigHashAlgorithmL0.cs
@@ -38,7 +38,7 @@ public void ComputeHash_returns_correct_hash()
};
// Act.
- string hashKey = TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { repoInfo });
+ string hashKey = TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { repoInfo }, true);
// Assert.
Assert.Equal("55e3171bf43a983b419387b5d952d3ee7dcb195e262fc4c78d47a92763b6b001", hashKey);
@@ -62,12 +62,12 @@ public void ComputeHash_should_throw_when_parameters_invalid()
string collectionId = "866A5D79-7735-49E3-87DA-02E76CF8D03A";
string definitionId = "123";
- Assert.Throws(() => TrackingConfigHashAlgorithm.ComputeHash(null, null, null));
- Assert.Throws(() => TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, null));
- Assert.Throws(() => TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { new RepositoryTrackingInfo() }));
- Assert.Throws(() => TrackingConfigHashAlgorithm.ComputeHash(null, null, new[] { repo }));
- Assert.Throws(() => TrackingConfigHashAlgorithm.ComputeHash(null, definitionId, new[] { repo }));
- Assert.Throws(() => TrackingConfigHashAlgorithm.ComputeHash(collectionId, null, new[] { repo }));
+ Assert.Throws(() => TrackingConfigHashAlgorithm.ComputeHash(null, null, null, true));
+ Assert.Throws(() => TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, null, true));
+ Assert.Throws(() => TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { new RepositoryTrackingInfo() }, true));
+ Assert.Throws(() => TrackingConfigHashAlgorithm.ComputeHash(null, null, new[] { repo }, true));
+ Assert.Throws(() => TrackingConfigHashAlgorithm.ComputeHash(null, definitionId, new[] { repo }, true));
+ Assert.Throws(() => TrackingConfigHashAlgorithm.ComputeHash(collectionId, null, new[] { repo }, true));
}
}
@@ -96,19 +96,19 @@ public void ComputeHash_with_single_repo_should_return_correct_hash()
string definitionId = "123";
// Make sure that only the coll, def, and url are used in the hash
- Assert.Equal("a42b0f8ccd83cec8294b0c861a8d769e4f7fbc53ad3d3c96d2d1b66afdcdcca7", TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { repo1 }));
- Assert.Equal("a42b0f8ccd83cec8294b0c861a8d769e4f7fbc53ad3d3c96d2d1b66afdcdcca7", TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { repo2 }));
- Assert.Equal(TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { repo1 }), TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { repo1 }));
+ Assert.Equal("a42b0f8ccd83cec8294b0c861a8d769e4f7fbc53ad3d3c96d2d1b66afdcdcca7", TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { repo1 }, true));
+ Assert.Equal("a42b0f8ccd83cec8294b0c861a8d769e4f7fbc53ad3d3c96d2d1b66afdcdcca7", TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { repo2 }, true));
+ Assert.Equal(TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { repo1 }, true), TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { repo1 }, true));
// Make sure that different coll creates different hash
- Assert.Equal("55437a6c3c12ea17847e33c3d96697833a05519e06acbe90fff74a64734fca1c", TrackingConfigHashAlgorithm.ComputeHash("FFFA5D79-7735-49E3-87DA-02E76CF8D03A", definitionId, new[] { repo1 }));
+ Assert.Equal("55437a6c3c12ea17847e33c3d96697833a05519e06acbe90fff74a64734fca1c", TrackingConfigHashAlgorithm.ComputeHash("FFFA5D79-7735-49E3-87DA-02E76CF8D03A", definitionId, new[] { repo1 }, true));
// Make sure that different def creates different hash
- Assert.Equal("72443dbf31971f84922a6f3a6c58052fc0c60d9f1eb17b83a35e6e099098c179", TrackingConfigHashAlgorithm.ComputeHash(collectionId, "321", new[] { repo1 }));
+ Assert.Equal("72443dbf31971f84922a6f3a6c58052fc0c60d9f1eb17b83a35e6e099098c179", TrackingConfigHashAlgorithm.ComputeHash(collectionId, "321", new[] { repo1 }, true));
// Make sure that different url creates different hash
repo1.RepositoryUrl = "https://jpricket@codedev.ms/jpricket/MyFirstProject/_git/new_url";
- Assert.Equal("2b29540cb9d2b68cc068af7afd0593276fc9e0b09af4e5d7b2065cc9021070fc", TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { repo1 }));
+ Assert.Equal("2b29540cb9d2b68cc068af7afd0593276fc9e0b09af4e5d7b2065cc9021070fc", TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { repo1 }, true));
}
}
@@ -160,29 +160,29 @@ public void ComputeHash_with_multi_repos_should_return_correct_hash()
string definitionId = "123";
// Make sure we get the same hash every time
- Assert.Equal("0a7fcd16ea54872456169a3cbf5a7d8e8efda976b755a13278b193fedaeb5784", TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { repo1, repo2 }));
+ Assert.Equal("0a7fcd16ea54872456169a3cbf5a7d8e8efda976b755a13278b193fedaeb5784", TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { repo1, repo2 }, true));
// Make sure that only the coll, def, identifier, and url are used in the hash
Assert.Equal(
- TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { repo1, repo2 }),
- TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { repo1, repo2_newPath }));
+ TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { repo1, repo2 }, true),
+ TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { repo1, repo2_newPath }, true));
// Make sure that different coll creates different hash
- Assert.Equal("b3956a6be8dde823bce2373fdef7358e255107bc4de986a61aeaffd11e253118", TrackingConfigHashAlgorithm.ComputeHash("FFFA5D79-7735-49E3-87DA-02E76CF8D03A", definitionId, new[] { repo1, repo2 }));
+ Assert.Equal("b3956a6be8dde823bce2373fdef7358e255107bc4de986a61aeaffd11e253118", TrackingConfigHashAlgorithm.ComputeHash("FFFA5D79-7735-49E3-87DA-02E76CF8D03A", definitionId, new[] { repo1, repo2 }, true));
// Make sure that different def creates different hash
- Assert.Equal("dff47196d014b4373641e33627901f986cde0815de0122fa76f401abd1140701", TrackingConfigHashAlgorithm.ComputeHash(collectionId, "321", new[] { repo1, repo2 }));
+ Assert.Equal("dff47196d014b4373641e33627901f986cde0815de0122fa76f401abd1140701", TrackingConfigHashAlgorithm.ComputeHash(collectionId, "321", new[] { repo1, repo2 }, true));
// Make sure that different url creates different hash
- Assert.Equal("ce83c8cd4f9b603345d21d2a294f7126e1e37c6d13cf6225516106a69528cc95", TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { repo1_newUrl, repo2 }));
+ Assert.Equal("ce83c8cd4f9b603345d21d2a294f7126e1e37c6d13cf6225516106a69528cc95", TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { repo1_newUrl, repo2 }, true));
// Make sure that different alias creates different hash
- Assert.Equal("2ca4bc7221eb412db850596fc02dc4e5b61c2125c997ea07f11215bffe605d33", TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { repo1_newAlias, repo2 }));
+ Assert.Equal("2ca4bc7221eb412db850596fc02dc4e5b61c2125c997ea07f11215bffe605d33", TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { repo1_newAlias, repo2 }, true));
// Make sure order doesn't change hash
Assert.Equal(
- TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { repo1, repo2 }),
- TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { repo2, repo1 }));
+ TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { repo1, repo2 }, true),
+ TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { repo2, repo1 }, true));
}
}
diff --git a/src/Test/L1/Worker/L1TestBase.cs b/src/Test/L1/Worker/L1TestBase.cs
index db9327fd21..758d81a574 100644
--- a/src/Test/L1/Worker/L1TestBase.cs
+++ b/src/Test/L1/Worker/L1TestBase.cs
@@ -219,7 +219,7 @@ public TrackingConfig GetTrackingConfig(Pipelines.AgentJobRequestMessage message
if (message.Variables.TryGetValue("agent.useWorkspaceId", out _))
{
var repoTrackingInfos = message.Resources.Repositories.Select(repo => new RepositoryTrackingInfo(repo, "/")).ToList();
- var workspaceIdentifier = TrackingConfigHashAlgorithm.ComputeHash(collectionIdVar?.Value, definitionIdVar?.Value, repoTrackingInfos);
+ var workspaceIdentifier = TrackingConfigHashAlgorithm.ComputeHash(collectionIdVar?.Value, definitionIdVar?.Value, repoTrackingInfos, true);
filename = Path.Combine(GetWorkingDirectory(testName),
Constants.Build.Path.SourceRootMappingDirectory,
collectionIdVar.Value,