diff --git a/src/Runner.Common/Constants.cs b/src/Runner.Common/Constants.cs index a6102ee971e..7a1f1cbb0a1 100644 --- a/src/Runner.Common/Constants.cs +++ b/src/Runner.Common/Constants.cs @@ -178,6 +178,7 @@ public static class Features public static readonly string SendJobLevelAnnotations = "actions_send_job_level_annotations"; public static readonly string EmitCompositeMarkers = "actions_runner_emit_composite_markers"; public static readonly string BatchActionResolution = "actions_batch_action_resolution"; + public static readonly string UseBearerTokenForCodeload = "actions_use_bearer_token_for_codeload"; } // Node version migration related constants diff --git a/src/Runner.Worker/ActionManager.cs b/src/Runner.Worker/ActionManager.cs index 896396cfadd..79c0de5f706 100644 --- a/src/Runner.Worker/ActionManager.cs +++ b/src/Runner.Worker/ActionManager.cs @@ -1367,16 +1367,29 @@ private static string GetDownloadInfoLookupKey(Pipelines.ActionStep action) return $"{repositoryReference.Name}@{repositoryReference.Ref}"; } - private AuthenticationHeaderValue CreateAuthHeader(string token) + private AuthenticationHeaderValue CreateAuthHeader(IExecutionContext executionContext, string downloadUrl, string token) { if (string.IsNullOrEmpty(token)) { return null; } - var base64EncodingToken = Convert.ToBase64String(Encoding.UTF8.GetBytes($"x-access-token:{token}")); - HostContext.SecretMasker.AddValue(base64EncodingToken); - return new AuthenticationHeaderValue("Basic", base64EncodingToken); + if (executionContext.Global.Variables.GetBoolean(Constants.Runner.Features.UseBearerTokenForCodeload) == true && + Uri.TryCreate(downloadUrl, UriKind.Absolute, out var parsedUrl) && + !string.IsNullOrEmpty(parsedUrl?.Host) && + !string.IsNullOrEmpty(parsedUrl?.PathAndQuery) && + (parsedUrl.Host.StartsWith("codeload.", StringComparison.OrdinalIgnoreCase) || parsedUrl.PathAndQuery.StartsWith("/_codeload/", StringComparison.OrdinalIgnoreCase))) + { + Trace.Info("Using Bearer token for action archive download directly to codeload."); + return new AuthenticationHeaderValue("Bearer", token); + } + else + { + Trace.Info("Using Basic token for action archive download."); + var base64EncodingToken = Convert.ToBase64String(Encoding.UTF8.GetBytes($"x-access-token:{token}")); + HostContext.SecretMasker.AddValue(base64EncodingToken); + return new AuthenticationHeaderValue("Basic", base64EncodingToken); + } } private async Task DownloadRepositoryArchive(IExecutionContext executionContext, string downloadUrl, string downloadAuthToken, string archiveFile) @@ -1401,7 +1414,7 @@ private async Task DownloadRepositoryArchive(IExecutionContext executionContext, using (var httpClientHandler = HostContext.CreateHttpClientHandler()) using (var httpClient = new HttpClient(httpClientHandler)) { - httpClient.DefaultRequestHeaders.Authorization = CreateAuthHeader(downloadAuthToken); + httpClient.DefaultRequestHeaders.Authorization = CreateAuthHeader(executionContext, downloadUrl, downloadAuthToken); httpClient.DefaultRequestHeaders.UserAgent.AddRange(HostContext.UserAgents); using (var response = await httpClient.GetAsync(downloadUrl))