Skip to content

Commit 6a0763f

Browse files
Merge branch 'actions:main' into main
2 parents c18009c + a2b2209 commit 6a0763f

12 files changed

Lines changed: 348 additions & 7 deletions

File tree

.devcontainer/devcontainer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"features": {
55
"ghcr.io/devcontainers/features/docker-in-docker:1": {},
66
"ghcr.io/devcontainers/features/dotnet": {
7-
"version": "8.0.417"
7+
"version": "8.0.418"
88
},
99
"ghcr.io/devcontainers/features/node:1": {
1010
"version": "20"

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ We are taking the following steps to better direct requests related to GitHub Ac
3232

3333
2. High Priority bugs can be reported through Community Discussions or you can report these to our support team https://support.github.com/contact/bug-report.
3434

35-
3. Security Issues should be handled as per our [security.md](security.md)
35+
3. Security Issues should be handled as per our [SECURITY.md](https://github.com/actions/runner?tab=security-ov-file)
3636

3737
We will still provide security updates for this project and fix major breaking changes during this time.
3838

src/Misc/externals.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ NODE_ALPINE_URL=https://github.com/actions/alpine_nodejs/releases/download
77
# When you update Node versions you must also create a new release of alpine_nodejs at that updated version.
88
# Follow the instructions here: https://github.com/actions/alpine_nodejs?tab=readme-ov-file#getting-started
99
NODE20_VERSION="20.20.0"
10-
NODE24_VERSION="24.13.0"
10+
NODE24_VERSION="24.13.1"
1111

1212
get_abs_path() {
1313
# exploits the fact that pwd will print abs path when no args

src/Runner.Common/ConfigurationStore.cs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,41 @@ public bool IsHostedServer
7575
{
7676
return UrlUtil.IsHostedServer(new UriBuilder(GitHubUrl));
7777
}
78+
else
79+
{
80+
// feature flag env in case the new logic is wrong.
81+
if (StringUtil.ConvertToBoolean(Environment.GetEnvironmentVariable("GITHUB_ACTIONS_RUNNER_FORCE_EMPTY_GITHUB_URL_IS_HOSTED")))
82+
{
83+
return true;
84+
}
85+
86+
// GitHubUrl will be empty for jit configured runner
87+
// We will try to infer it from the ServerUrl/ServerUrlV2
88+
if (StringUtil.ConvertToBoolean(Environment.GetEnvironmentVariable("GITHUB_ACTIONS_RUNNER_FORCE_GHES")))
89+
{
90+
// Allow env to override and force GHES in case the inference logic is wrong.
91+
return false;
92+
}
93+
94+
if (!string.IsNullOrEmpty(ServerUrl))
95+
{
96+
// pipelines services
97+
var serverUrl = new UriBuilder(ServerUrl);
98+
return serverUrl.Host.EndsWith(".actions.githubusercontent.com", StringComparison.OrdinalIgnoreCase)
99+
|| serverUrl.Host.EndsWith(".codedev.ms", StringComparison.OrdinalIgnoreCase);
100+
}
101+
102+
if (!string.IsNullOrEmpty(ServerUrlV2))
103+
{
104+
// broker-listener
105+
var serverUrlV2 = new UriBuilder(ServerUrlV2);
106+
return serverUrlV2.Host.EndsWith(".actions.githubusercontent.com", StringComparison.OrdinalIgnoreCase)
107+
|| serverUrlV2.Host.EndsWith(".githubapp.com", StringComparison.OrdinalIgnoreCase)
108+
|| serverUrlV2.Host.EndsWith(".ghe.com", StringComparison.OrdinalIgnoreCase)
109+
|| serverUrlV2.Host.EndsWith(".actions.localhost", StringComparison.OrdinalIgnoreCase)
110+
|| serverUrlV2.Host.EndsWith(".ghe.localhost", StringComparison.OrdinalIgnoreCase);
111+
}
112+
}
78113

79114
// Default to true since Hosted runners likely don't have this property set.
80115
return true;

src/Runner.Common/Constants.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,10 @@ public static class NodeMigration
190190
// Feature flags for controlling the migration phases
191191
public static readonly string UseNode24ByDefaultFlag = "actions.runner.usenode24bydefault";
192192
public static readonly string RequireNode24Flag = "actions.runner.requirenode24";
193+
public static readonly string WarnOnNode20Flag = "actions.runner.warnonnode20";
194+
195+
// Blog post URL for Node 20 deprecation
196+
public static readonly string Node20DeprecationUrl = "https://github.blog/changelog/2025-09-19-deprecation-of-node-20-on-github-actions-runners/";
193197
}
194198

195199
public static readonly string InternalTelemetryIssueDataKey = "_internal_telemetry";

src/Runner.Worker/ExecutionContext.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -856,6 +856,9 @@ public void InitializeJob(Pipelines.AgentJobRequestMessage message, Cancellation
856856
// Job level annotations
857857
Global.JobAnnotations = new List<Annotation>();
858858

859+
// Track Node.js 20 actions for deprecation warning
860+
Global.DeprecatedNode20Actions = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
861+
859862
// Job Outputs
860863
JobOutputs = new Dictionary<string, VariableValue>(StringComparer.OrdinalIgnoreCase);
861864

src/Runner.Worker/GlobalContext.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,6 @@ public sealed class GlobalContext
3333
public bool HasActionManifestMismatch { get; set; }
3434
public bool HasDeprecatedSetOutput { get; set; }
3535
public bool HasDeprecatedSaveState { get; set; }
36+
public HashSet<string> DeprecatedNode20Actions { get; set; }
3637
}
3738
}

src/Runner.Worker/Handlers/HandlerFactory.cs

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,20 @@ public IHandler Create(
6565
nodeData.NodeVersion = Common.Constants.Runner.NodeMigration.Node20;
6666
}
6767

68+
// Track Node.js 20 actions for deprecation annotation
69+
if (string.Equals(nodeData.NodeVersion, Constants.Runner.NodeMigration.Node20, StringComparison.InvariantCultureIgnoreCase))
70+
{
71+
bool warnOnNode20 = executionContext.Global.Variables?.GetBoolean(Constants.Runner.NodeMigration.WarnOnNode20Flag) ?? false;
72+
if (warnOnNode20)
73+
{
74+
string actionName = GetActionName(action);
75+
if (!string.IsNullOrEmpty(actionName))
76+
{
77+
executionContext.Global.DeprecatedNode20Actions?.Add(actionName);
78+
}
79+
}
80+
}
81+
6882
// Check if node20 was explicitly specified in the action
6983
// We don't modify if node24 was explicitly specified
7084
if (string.Equals(nodeData.NodeVersion, Constants.Runner.NodeMigration.Node20, StringComparison.InvariantCultureIgnoreCase))
@@ -90,7 +104,8 @@ public IHandler Create(
90104
if (useNode24ByDefault && !requireNode24 && string.Equals(finalNodeVersion, Constants.Runner.NodeMigration.Node24, StringComparison.OrdinalIgnoreCase))
91105
{
92106
string infoMessage = "Node 20 is being deprecated. This workflow is running with Node 24 by default. " +
93-
"If you need to temporarily use Node 20, you can set the ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION=true environment variable.";
107+
"If you need to temporarily use Node 20, you can set the ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION=true environment variable. " +
108+
$"For more information see: {Constants.Runner.NodeMigration.Node20DeprecationUrl}";
94109
executionContext.Output(infoMessage);
95110
}
96111
}
@@ -129,5 +144,25 @@ public IHandler Create(
129144
handler.LocalActionContainerSetupSteps = localActionContainerSetupSteps;
130145
return handler;
131146
}
147+
148+
private static string GetActionName(Pipelines.ActionStepDefinitionReference action)
149+
{
150+
if (action is Pipelines.RepositoryPathReference repoRef)
151+
{
152+
var pathString = string.Empty;
153+
if (!string.IsNullOrEmpty(repoRef.Path))
154+
{
155+
pathString = string.IsNullOrEmpty(repoRef.Name)
156+
? repoRef.Path
157+
: $"/{repoRef.Path}";
158+
}
159+
var repoString = string.IsNullOrEmpty(repoRef.Ref)
160+
? $"{repoRef.Name}{pathString}"
161+
: $"{repoRef.Name}{pathString}@{repoRef.Ref}";
162+
return string.IsNullOrEmpty(repoString) ? null : repoString;
163+
}
164+
165+
return null;
166+
}
132167
}
133168
}

src/Runner.Worker/JobExtension.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -735,6 +735,15 @@ public async Task FinalizeJob(IExecutionContext jobContext, Pipelines.AgentJobRe
735735
context.Global.JobTelemetry.Add(new JobTelemetry() { Type = JobTelemetryType.ConnectivityCheck, Message = $"Fail to check service connectivity. {ex.Message}" });
736736
}
737737
}
738+
739+
// Add deprecation warning annotation for Node.js 20 actions
740+
if (context.Global.DeprecatedNode20Actions?.Count > 0)
741+
{
742+
var sortedActions = context.Global.DeprecatedNode20Actions.OrderBy(a => a, StringComparer.OrdinalIgnoreCase);
743+
var actionsList = string.Join(", ", sortedActions);
744+
var deprecationMessage = $"Node.js 20 actions are deprecated. The following actions are running on Node.js 20 and may not work as expected: {actionsList}. Actions will be forced to run with Node.js 24 by default starting June 2nd, 2026. Please check if updated versions of these actions are available that support Node.js 24. To opt into Node.js 24 now, set the FORCE_JAVASCRIPT_ACTIONS_TO_NODE24=true environment variable on the runner or in your workflow file. Once Node.js 24 becomes the default, you can temporarily opt out by setting ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION=true. For more information see: {Constants.Runner.NodeMigration.Node20DeprecationUrl}";
745+
context.Warning(deprecationMessage);
746+
}
738747
}
739748
catch (Exception ex)
740749
{

0 commit comments

Comments
 (0)