Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
18f53d3c9e | ||
|
|
273538003e | ||
|
|
4a587ada27 | ||
|
|
182a433782 |
+356
-441
File diff suppressed because it is too large
Load Diff
@@ -32,19 +32,19 @@
|
|||||||
"author": "GitHub Actions",
|
"author": "GitHub Actions",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/glob": "^0.4.0"
|
"@actions/glob": "^0.6.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@stylistic/eslint-plugin": "^5.10.0",
|
"@stylistic/eslint-plugin": "^5.10.0",
|
||||||
"@types/node": "^22.0.0",
|
"@types/node": "^22.0.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.58.1",
|
"@typescript-eslint/eslint-plugin": "^8.58.1",
|
||||||
"@typescript-eslint/parser": "^8.0.0",
|
"@typescript-eslint/parser": "^8.58.1",
|
||||||
"@vercel/ncc": "^0.38.3",
|
"@vercel/ncc": "^0.38.3",
|
||||||
"eslint": "^8.47.0",
|
"eslint": "^8.47.0",
|
||||||
"eslint-plugin-github": "^4.10.2",
|
"eslint-plugin-github": "^4.10.2",
|
||||||
"eslint-plugin-prettier": "^5.0.0",
|
"eslint-plugin-prettier": "^5.0.0",
|
||||||
"husky": "^9.1.7",
|
"husky": "^9.1.7",
|
||||||
"lint-staged": "^15.5.0",
|
"lint-staged": "^16.4.0",
|
||||||
"prettier": "^3.0.3",
|
"prettier": "^3.0.3",
|
||||||
"typescript": "^6.0.2"
|
"typescript": "^6.0.2"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,9 +17,9 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
|
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
<PackageReference Include="System.Security.Cryptography.ProtectedData" Version="8.0.0" />
|
<PackageReference Include="System.Security.Cryptography.ProtectedData" Version="10.0.3" />
|
||||||
<PackageReference Include="System.Text.Encoding.CodePages" Version="8.0.0" />
|
<PackageReference Include="System.Text.Encoding.CodePages" Version="10.0.3" />
|
||||||
<PackageReference Include="System.Threading.Channels" Version="8.0.0" />
|
<PackageReference Include="System.Threading.Channels" Version="10.0.3" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||||
|
|||||||
@@ -22,8 +22,8 @@
|
|||||||
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
|
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
<PackageReference Include="System.IO.FileSystem.AccessControl" Version="5.0.0" />
|
<PackageReference Include="System.IO.FileSystem.AccessControl" Version="5.0.0" />
|
||||||
<PackageReference Include="System.Security.Cryptography.ProtectedData" Version="8.0.0" />
|
<PackageReference Include="System.Security.Cryptography.ProtectedData" Version="10.0.3" />
|
||||||
<PackageReference Include="System.ServiceProcess.ServiceController" Version="8.0.1" />
|
<PackageReference Include="System.ServiceProcess.ServiceController" Version="10.0.3" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||||
|
|||||||
@@ -15,9 +15,9 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="System.Text.Encoding.CodePages" Version="8.0.0" />
|
<PackageReference Include="System.Text.Encoding.CodePages" Version="10.0.3" />
|
||||||
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
|
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
|
||||||
<PackageReference Include="System.Threading.Channels" Version="8.0.0" />
|
<PackageReference Include="System.Threading.Channels" Version="10.0.3" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||||
|
|||||||
@@ -892,15 +892,12 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
Trace.Info("Initializing Job context");
|
Trace.Info("Initializing Job context");
|
||||||
var jobContext = new JobContext();
|
var jobContext = new JobContext();
|
||||||
if (Global.Variables.GetBoolean(Constants.Runner.Features.AddCheckRunIdToJobContext) ?? false)
|
ExpressionValues.TryGetValue("job", out var jobDictionary);
|
||||||
|
if (jobDictionary != null)
|
||||||
{
|
{
|
||||||
ExpressionValues.TryGetValue("job", out var jobDictionary);
|
foreach (var pair in jobDictionary.AssertDictionary("job"))
|
||||||
if (jobDictionary != null)
|
|
||||||
{
|
{
|
||||||
foreach (var pair in jobDictionary.AssertDictionary("job"))
|
jobContext[pair.Key] = pair.Value;
|
||||||
{
|
|
||||||
jobContext[pair.Key] = pair.Value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExpressionValues["job"] = jobContext;
|
ExpressionValues["job"] = jobContext;
|
||||||
|
|||||||
@@ -82,5 +82,69 @@ namespace GitHub.Runner.Worker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string WorkflowRef
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (this.TryGetValue("workflow_ref", out var value) && value is StringContextData str)
|
||||||
|
{
|
||||||
|
return str.Value;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
this["workflow_ref"] = value != null ? new StringContextData(value) : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string WorkflowSha
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (this.TryGetValue("workflow_sha", out var value) && value is StringContextData str)
|
||||||
|
{
|
||||||
|
return str.Value;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
this["workflow_sha"] = value != null ? new StringContextData(value) : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string WorkflowRepository
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (this.TryGetValue("workflow_repository", out var value) && value is StringContextData str)
|
||||||
|
{
|
||||||
|
return str.Value;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
this["workflow_repository"] = value != null ? new StringContextData(value) : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string WorkflowFilePath
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (this.TryGetValue("workflow_file_path", out var value) && value is StringContextData str)
|
||||||
|
{
|
||||||
|
return str.Value;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
this["workflow_file_path"] = value != null ? new StringContextData(value) : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,9 +19,9 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="System.Security.Cryptography.ProtectedData" Version="8.0.0" />
|
<PackageReference Include="System.Security.Cryptography.ProtectedData" Version="10.0.3" />
|
||||||
<PackageReference Include="System.ServiceProcess.ServiceController" Version="8.0.1" />
|
<PackageReference Include="System.ServiceProcess.ServiceController" Version="10.0.3" />
|
||||||
<PackageReference Include="System.Threading.Channels" Version="8.0.0" />
|
<PackageReference Include="System.Threading.Channels" Version="10.0.3" />
|
||||||
<PackageReference Include="YamlDotNet.Signed" Version="5.3.0" />
|
<PackageReference Include="YamlDotNet.Signed" Version="5.3.0" />
|
||||||
<PackageReference Include="Microsoft.DevTunnels.Connections" Version="1.3.16" />
|
<PackageReference Include="Microsoft.DevTunnels.Connections" Version="1.3.16" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
+3
-3
@@ -23,14 +23,14 @@
|
|||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
<PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="6.0.0" />
|
<PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="6.0.0" />
|
||||||
<PackageReference Include="System.Security.Cryptography.Cng" Version="5.0.0" />
|
<PackageReference Include="System.Security.Cryptography.Cng" Version="5.0.0" />
|
||||||
<PackageReference Include="System.Security.Cryptography.Pkcs" Version="10.0.2" />
|
<PackageReference Include="System.Security.Cryptography.Pkcs" Version="10.0.3" />
|
||||||
<PackageReference Include="System.Security.Cryptography.ProtectedData" Version="8.0.0" />
|
<PackageReference Include="System.Security.Cryptography.ProtectedData" Version="10.0.3" />
|
||||||
<PackageReference Include="Minimatch" Version="2.0.0" />
|
<PackageReference Include="Minimatch" Version="2.0.0" />
|
||||||
<PackageReference Include="YamlDotNet.Signed" Version="5.3.0" />
|
<PackageReference Include="YamlDotNet.Signed" Version="5.3.0" />
|
||||||
<PackageReference Include="System.Net.Http" Version="4.3.4" />
|
<PackageReference Include="System.Net.Http" Version="4.3.4" />
|
||||||
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" />
|
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" />
|
||||||
<PackageReference Include="System.Private.Uri" Version="4.3.2" />
|
<PackageReference Include="System.Private.Uri" Version="4.3.2" />
|
||||||
<PackageReference Include="System.Formats.Asn1" Version="10.0.2" />
|
<PackageReference Include="System.Formats.Asn1" Version="10.0.3" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ namespace GitHub.Actions.WorkflowParser.Conversion
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var effectiveMax = explicitMax ?? CreatePermissionsFromPolicy(context, permissionsPolicy, includeIdToken: isTrusted, includeModels: context.GetFeatures().AllowModelsPermission);
|
var effectiveMax = explicitMax ?? CreatePermissionsFromPolicy(context, permissionsPolicy, includeIdToken: isTrusted, includeModels: context.GetFeatures().AllowModelsPermission, includeWorkflows: context.GetFeatures().AllowWorkflowsPermission);
|
||||||
|
|
||||||
if (requested.ViolatesMaxPermissions(effectiveMax, out var permissionLevelViolations))
|
if (requested.ViolatesMaxPermissions(effectiveMax, out var permissionLevelViolations))
|
||||||
{
|
{
|
||||||
@@ -59,7 +59,8 @@ namespace GitHub.Actions.WorkflowParser.Conversion
|
|||||||
TemplateContext context,
|
TemplateContext context,
|
||||||
string permissionsPolicy,
|
string permissionsPolicy,
|
||||||
bool includeIdToken,
|
bool includeIdToken,
|
||||||
bool includeModels)
|
bool includeModels,
|
||||||
|
bool includeWorkflows)
|
||||||
{
|
{
|
||||||
switch (permissionsPolicy)
|
switch (permissionsPolicy)
|
||||||
{
|
{
|
||||||
@@ -70,7 +71,7 @@ namespace GitHub.Actions.WorkflowParser.Conversion
|
|||||||
Packages = PermissionLevel.Read,
|
Packages = PermissionLevel.Read,
|
||||||
};
|
};
|
||||||
case WorkflowConstants.PermissionsPolicy.Write:
|
case WorkflowConstants.PermissionsPolicy.Write:
|
||||||
return new Permissions(PermissionLevel.Write, includeIdToken: includeIdToken, includeAttestations: true, includeModels: includeModels);
|
return new Permissions(PermissionLevel.Write, includeIdToken: includeIdToken, includeAttestations: true, includeModels: includeModels, includeWorkflows: includeWorkflows);
|
||||||
default:
|
default:
|
||||||
throw new ArgumentException($"Unexpected permission policy: '{permissionsPolicy}'");
|
throw new ArgumentException($"Unexpected permission policy: '{permissionsPolicy}'");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1877,7 +1877,7 @@ namespace GitHub.Actions.WorkflowParser.Conversion
|
|||||||
permissionsStr.AssertUnexpectedValue(permissionsStr.Value);
|
permissionsStr.AssertUnexpectedValue(permissionsStr.Value);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return new Permissions(permissionLevel, includeIdToken: true, includeAttestations: true, includeModels: context.GetFeatures().AllowModelsPermission);
|
return new Permissions(permissionLevel, includeIdToken: true, includeAttestations: true, includeModels: context.GetFeatures().AllowModelsPermission, includeWorkflows: context.GetFeatures().AllowWorkflowsPermission);
|
||||||
}
|
}
|
||||||
|
|
||||||
var mapping = token.AssertMapping("permissions");
|
var mapping = token.AssertMapping("permissions");
|
||||||
@@ -1957,6 +1957,24 @@ namespace GitHub.Actions.WorkflowParser.Conversion
|
|||||||
context.Error(key, $"The permission 'models' is not allowed");
|
context.Error(key, $"The permission 'models' is not allowed");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case "workflows":
|
||||||
|
if (context.GetFeatures().AllowWorkflowsPermission)
|
||||||
|
{
|
||||||
|
// Workflows only supports write; downgrade read to none
|
||||||
|
if (permissionLevel == PermissionLevel.Read)
|
||||||
|
{
|
||||||
|
permissions.Workflows = PermissionLevel.NoAccess;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
permissions.Workflows = permissionLevel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
context.Error(key, $"The permission 'workflows' is not allowed");
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Runtime.Serialization;
|
using System.Runtime.Serialization;
|
||||||
using GitHub.Actions.WorkflowParser.Conversion;
|
using GitHub.Actions.WorkflowParser.Conversion;
|
||||||
@@ -17,7 +17,7 @@ namespace GitHub.Actions.WorkflowParser
|
|||||||
public Permissions(Permissions copy)
|
public Permissions(Permissions copy)
|
||||||
{
|
{
|
||||||
Actions = copy.Actions;
|
Actions = copy.Actions;
|
||||||
ArtifactMetadata = copy.ArtifactMetadata;
|
ArtifactMetadata = copy.ArtifactMetadata;
|
||||||
Attestations = copy.Attestations;
|
Attestations = copy.Attestations;
|
||||||
Checks = copy.Checks;
|
Checks = copy.Checks;
|
||||||
Contents = copy.Contents;
|
Contents = copy.Contents;
|
||||||
@@ -32,16 +32,18 @@ namespace GitHub.Actions.WorkflowParser
|
|||||||
SecurityEvents = copy.SecurityEvents;
|
SecurityEvents = copy.SecurityEvents;
|
||||||
IdToken = copy.IdToken;
|
IdToken = copy.IdToken;
|
||||||
Models = copy.Models;
|
Models = copy.Models;
|
||||||
|
Workflows = copy.Workflows;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Permissions(
|
public Permissions(
|
||||||
PermissionLevel permissionLevel,
|
PermissionLevel permissionLevel,
|
||||||
bool includeIdToken,
|
bool includeIdToken,
|
||||||
bool includeAttestations,
|
bool includeAttestations,
|
||||||
bool includeModels)
|
bool includeModels,
|
||||||
|
bool includeWorkflows = false)
|
||||||
{
|
{
|
||||||
Actions = permissionLevel;
|
Actions = permissionLevel;
|
||||||
ArtifactMetadata = permissionLevel;
|
ArtifactMetadata = permissionLevel;
|
||||||
Attestations = includeAttestations ? permissionLevel : PermissionLevel.NoAccess;
|
Attestations = includeAttestations ? permissionLevel : PermissionLevel.NoAccess;
|
||||||
Checks = permissionLevel;
|
Checks = permissionLevel;
|
||||||
Contents = permissionLevel;
|
Contents = permissionLevel;
|
||||||
@@ -59,6 +61,10 @@ namespace GitHub.Actions.WorkflowParser
|
|||||||
Models = includeModels
|
Models = includeModels
|
||||||
? (permissionLevel == PermissionLevel.Write ? PermissionLevel.Read : permissionLevel)
|
? (permissionLevel == PermissionLevel.Write ? PermissionLevel.Read : permissionLevel)
|
||||||
: PermissionLevel.NoAccess;
|
: PermissionLevel.NoAccess;
|
||||||
|
// Workflows is write-only, so only grant it when permissionLevel is Write
|
||||||
|
Workflows = includeWorkflows && permissionLevel == PermissionLevel.Write
|
||||||
|
? PermissionLevel.Write
|
||||||
|
: PermissionLevel.NoAccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static KeyValuePair<string, (PermissionLevel, PermissionLevel)>[] ComparisonKeyMapping(Permissions left, Permissions right)
|
private static KeyValuePair<string, (PermissionLevel, PermissionLevel)>[] ComparisonKeyMapping(Permissions left, Permissions right)
|
||||||
@@ -81,6 +87,7 @@ namespace GitHub.Actions.WorkflowParser
|
|||||||
new KeyValuePair<string, (PermissionLevel, PermissionLevel)>("security-events", (left.SecurityEvents, right.SecurityEvents)),
|
new KeyValuePair<string, (PermissionLevel, PermissionLevel)>("security-events", (left.SecurityEvents, right.SecurityEvents)),
|
||||||
new KeyValuePair<string, (PermissionLevel, PermissionLevel)>("id-token", (left.IdToken, right.IdToken)),
|
new KeyValuePair<string, (PermissionLevel, PermissionLevel)>("id-token", (left.IdToken, right.IdToken)),
|
||||||
new KeyValuePair<string, (PermissionLevel, PermissionLevel)>("models", (left.Models, right.Models)),
|
new KeyValuePair<string, (PermissionLevel, PermissionLevel)>("models", (left.Models, right.Models)),
|
||||||
|
new KeyValuePair<string, (PermissionLevel, PermissionLevel)>("workflows", (left.Workflows, right.Workflows)),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,6 +203,13 @@ namespace GitHub.Actions.WorkflowParser
|
|||||||
set;
|
set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[DataMember(Name = "workflows", EmitDefaultValue = false)]
|
||||||
|
public PermissionLevel Workflows
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
|
||||||
public Permissions Clone()
|
public Permissions Clone()
|
||||||
{
|
{
|
||||||
return new Permissions(this);
|
return new Permissions(this);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
@@ -41,6 +41,13 @@ namespace GitHub.Actions.WorkflowParser
|
|||||||
[DataMember(EmitDefaultValue = false)]
|
[DataMember(EmitDefaultValue = false)]
|
||||||
public bool AllowModelsPermission { get; set; }
|
public bool AllowModelsPermission { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether users may use the "workflows" permission.
|
||||||
|
/// Used during parsing only.
|
||||||
|
/// </summary>
|
||||||
|
[DataMember(EmitDefaultValue = false)]
|
||||||
|
public bool AllowWorkflowsPermission { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a value indicating whether the expression function fromJson performs strict JSON parsing.
|
/// Gets or sets a value indicating whether the expression function fromJson performs strict JSON parsing.
|
||||||
/// Used during evaluation only.
|
/// Used during evaluation only.
|
||||||
@@ -67,6 +74,7 @@ namespace GitHub.Actions.WorkflowParser
|
|||||||
Snapshot = false, // Default to false since this feature is still in an experimental phase
|
Snapshot = false, // Default to false since this feature is still in an experimental phase
|
||||||
StrictJsonParsing = false, // Default to false since this is temporary for telemetry purposes only
|
StrictJsonParsing = false, // Default to false since this is temporary for telemetry purposes only
|
||||||
AllowModelsPermission = false, // Default to false since we want this to be disabled for all non-production environments
|
AllowModelsPermission = false, // Default to false since we want this to be disabled for all non-production environments
|
||||||
|
AllowWorkflowsPermission = false, // Default to false; gated by feature flag for controlled rollout
|
||||||
AllowServiceContainerCommand = false, // Default to false since this feature is gated by actions_service_container_command
|
AllowServiceContainerCommand = false, // Default to false since this feature is gated by actions_service_container_command
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1203,19 +1203,19 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: this test can be deleted when `AddCheckRunIdToJobContext` is fully rolled out
|
// AddCheckRunIdToJobContext is now permanently enabled server-side (hardcoded to "true"
|
||||||
|
// in acquirejobhandler.go). The runner always copies ContextData["job"] entries, so the
|
||||||
|
// flag-disabled test is no longer applicable. Replaced with a test that verifies
|
||||||
|
// check_run_id is always hydrated regardless of the flag value.
|
||||||
[Fact]
|
[Fact]
|
||||||
[Trait("Level", "L0")]
|
[Trait("Level", "L0")]
|
||||||
[Trait("Category", "Worker")]
|
[Trait("Category", "Worker")]
|
||||||
public void InitializeJob_HydratesJobContextWithCheckRunId_FeatureFlagDisabled()
|
public void InitializeJob_HydratesJobContextWithCheckRunId_AlwaysCopied()
|
||||||
{
|
{
|
||||||
using (TestHostContext hc = CreateTestContext())
|
using (TestHostContext hc = CreateTestContext())
|
||||||
{
|
{
|
||||||
// Arrange: Create a job request message and make sure the feature flag is disabled
|
// Arrange: No feature flag set at all
|
||||||
var variables = new Dictionary<string, VariableValue>()
|
var variables = new Dictionary<string, VariableValue>();
|
||||||
{
|
|
||||||
[Constants.Runner.Features.AddCheckRunIdToJobContext] = new VariableValue("false"),
|
|
||||||
};
|
|
||||||
var jobRequest = new Pipelines.AgentJobRequestMessage(new TaskOrchestrationPlanReference(), new TimelineReference(), Guid.NewGuid(), "some job name", "some job name", null, null, null, variables, new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null, null);
|
var jobRequest = new Pipelines.AgentJobRequestMessage(new TaskOrchestrationPlanReference(), new TimelineReference(), Guid.NewGuid(), "some job name", "some job name", null, null, null, variables, new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null, null);
|
||||||
var pagingLogger = new Moq.Mock<IPagingLogger>();
|
var pagingLogger = new Moq.Mock<IPagingLogger>();
|
||||||
var jobServerQueue = new Moq.Mock<IJobServerQueue>();
|
var jobServerQueue = new Moq.Mock<IJobServerQueue>();
|
||||||
@@ -1233,9 +1233,80 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
// Act
|
// Act
|
||||||
ec.InitializeJob(jobRequest, CancellationToken.None);
|
ec.InitializeJob(jobRequest, CancellationToken.None);
|
||||||
|
|
||||||
// Assert
|
// Assert: check_run_id is always copied regardless of flag
|
||||||
Assert.NotNull(ec.JobContext);
|
Assert.NotNull(ec.JobContext);
|
||||||
Assert.Null(ec.JobContext.CheckRunId); // with the feature flag disabled we should not have added a CheckRunId to the JobContext
|
Assert.Equal(123456, ec.JobContext.CheckRunId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
[Trait("Level", "L0")]
|
||||||
|
[Trait("Category", "Worker")]
|
||||||
|
public void InitializeJob_HydratesJobContextWithWorkflowIdentity()
|
||||||
|
{
|
||||||
|
using (TestHostContext hc = CreateTestContext())
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var variables = new Dictionary<string, VariableValue>();
|
||||||
|
var jobRequest = new Pipelines.AgentJobRequestMessage(new TaskOrchestrationPlanReference(), new TimelineReference(), Guid.NewGuid(), "some job name", "some job name", null, null, null, variables, new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null, null);
|
||||||
|
var pagingLogger = new Moq.Mock<IPagingLogger>();
|
||||||
|
var jobServerQueue = new Moq.Mock<IJobServerQueue>();
|
||||||
|
hc.EnqueueInstance(pagingLogger.Object);
|
||||||
|
hc.SetSingleton(jobServerQueue.Object);
|
||||||
|
var ec = new Runner.Worker.ExecutionContext();
|
||||||
|
ec.Initialize(hc);
|
||||||
|
|
||||||
|
// Arrange: Server sends all 4 workflow identity fields
|
||||||
|
var jobContext = new Pipelines.ContextData.DictionaryContextData();
|
||||||
|
jobContext["workflow_ref"] = new StringContextData("my-org/my-repo/.github/workflows/reusable.yml@refs/heads/main");
|
||||||
|
jobContext["workflow_sha"] = new StringContextData("abc123def456");
|
||||||
|
jobContext["workflow_repository"] = new StringContextData("my-org/my-repo");
|
||||||
|
jobContext["workflow_file_path"] = new StringContextData(".github/workflows/reusable.yml");
|
||||||
|
jobRequest.ContextData["job"] = jobContext;
|
||||||
|
jobRequest.ContextData["github"] = new Pipelines.ContextData.DictionaryContextData();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
ec.InitializeJob(jobRequest, CancellationToken.None);
|
||||||
|
|
||||||
|
// Assert: all properties hydrated from server
|
||||||
|
Assert.NotNull(ec.JobContext);
|
||||||
|
Assert.Equal("my-org/my-repo/.github/workflows/reusable.yml@refs/heads/main", ec.JobContext.WorkflowRef);
|
||||||
|
Assert.Equal("abc123def456", ec.JobContext.WorkflowSha);
|
||||||
|
Assert.Equal("my-org/my-repo", ec.JobContext.WorkflowRepository);
|
||||||
|
Assert.Equal(".github/workflows/reusable.yml", ec.JobContext.WorkflowFilePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
[Trait("Level", "L0")]
|
||||||
|
[Trait("Category", "Worker")]
|
||||||
|
public void InitializeJob_WorkflowIdentityNotSet_WhenServerSendsNoData()
|
||||||
|
{
|
||||||
|
using (TestHostContext hc = CreateTestContext())
|
||||||
|
{
|
||||||
|
// Arrange: Server sends no workflow identity in job context
|
||||||
|
var variables = new Dictionary<string, VariableValue>();
|
||||||
|
var jobRequest = new Pipelines.AgentJobRequestMessage(new TaskOrchestrationPlanReference(), new TimelineReference(), Guid.NewGuid(), "some job name", "some job name", null, null, null, variables, new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null, null);
|
||||||
|
var pagingLogger = new Moq.Mock<IPagingLogger>();
|
||||||
|
var jobServerQueue = new Moq.Mock<IJobServerQueue>();
|
||||||
|
hc.EnqueueInstance(pagingLogger.Object);
|
||||||
|
hc.SetSingleton(jobServerQueue.Object);
|
||||||
|
var ec = new Runner.Worker.ExecutionContext();
|
||||||
|
ec.Initialize(hc);
|
||||||
|
|
||||||
|
// Arrange: empty job context
|
||||||
|
jobRequest.ContextData["job"] = new Pipelines.ContextData.DictionaryContextData();
|
||||||
|
jobRequest.ContextData["github"] = new Pipelines.ContextData.DictionaryContextData();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
ec.InitializeJob(jobRequest, CancellationToken.None);
|
||||||
|
|
||||||
|
// Assert: no workflow identity
|
||||||
|
Assert.NotNull(ec.JobContext);
|
||||||
|
Assert.Null(ec.JobContext.WorkflowRef);
|
||||||
|
Assert.Null(ec.JobContext.WorkflowSha);
|
||||||
|
Assert.Null(ec.JobContext.WorkflowRepository);
|
||||||
|
Assert.Null(ec.JobContext.WorkflowFilePath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,5 +34,109 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
ctx.CheckRunId = null;
|
ctx.CheckRunId = null;
|
||||||
Assert.Null(ctx.CheckRunId);
|
Assert.Null(ctx.CheckRunId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void WorkflowRef_SetAndGet_WorksCorrectly()
|
||||||
|
{
|
||||||
|
var ctx = new JobContext();
|
||||||
|
ctx.WorkflowRef = "owner/repo/.github/workflows/ci.yml@refs/heads/main";
|
||||||
|
Assert.Equal("owner/repo/.github/workflows/ci.yml@refs/heads/main", ctx.WorkflowRef);
|
||||||
|
Assert.True(ctx.TryGetValue("workflow_ref", out var value));
|
||||||
|
Assert.IsType<StringContextData>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void WorkflowRef_NotSet_ReturnsNull()
|
||||||
|
{
|
||||||
|
var ctx = new JobContext();
|
||||||
|
Assert.Null(ctx.WorkflowRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void WorkflowRef_SetNull_ClearsValue()
|
||||||
|
{
|
||||||
|
var ctx = new JobContext();
|
||||||
|
ctx.WorkflowRef = "owner/repo/.github/workflows/ci.yml@refs/heads/main";
|
||||||
|
ctx.WorkflowRef = null;
|
||||||
|
Assert.Null(ctx.WorkflowRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void WorkflowSha_SetAndGet_WorksCorrectly()
|
||||||
|
{
|
||||||
|
var ctx = new JobContext();
|
||||||
|
ctx.WorkflowSha = "abc123def456";
|
||||||
|
Assert.Equal("abc123def456", ctx.WorkflowSha);
|
||||||
|
Assert.True(ctx.TryGetValue("workflow_sha", out var value));
|
||||||
|
Assert.IsType<StringContextData>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void WorkflowSha_NotSet_ReturnsNull()
|
||||||
|
{
|
||||||
|
var ctx = new JobContext();
|
||||||
|
Assert.Null(ctx.WorkflowSha);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void WorkflowSha_SetNull_ClearsValue()
|
||||||
|
{
|
||||||
|
var ctx = new JobContext();
|
||||||
|
ctx.WorkflowSha = "abc123def456";
|
||||||
|
ctx.WorkflowSha = null;
|
||||||
|
Assert.Null(ctx.WorkflowSha);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void WorkflowRepository_SetAndGet_WorksCorrectly()
|
||||||
|
{
|
||||||
|
var ctx = new JobContext();
|
||||||
|
ctx.WorkflowRepository = "owner/repo";
|
||||||
|
Assert.Equal("owner/repo", ctx.WorkflowRepository);
|
||||||
|
Assert.True(ctx.TryGetValue("workflow_repository", out var value));
|
||||||
|
Assert.IsType<StringContextData>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void WorkflowRepository_NotSet_ReturnsNull()
|
||||||
|
{
|
||||||
|
var ctx = new JobContext();
|
||||||
|
Assert.Null(ctx.WorkflowRepository);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void WorkflowRepository_SetNull_ClearsValue()
|
||||||
|
{
|
||||||
|
var ctx = new JobContext();
|
||||||
|
ctx.WorkflowRepository = "owner/repo";
|
||||||
|
ctx.WorkflowRepository = null;
|
||||||
|
Assert.Null(ctx.WorkflowRepository);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void WorkflowFilePath_SetAndGet_WorksCorrectly()
|
||||||
|
{
|
||||||
|
var ctx = new JobContext();
|
||||||
|
ctx.WorkflowFilePath = ".github/workflows/ci.yml";
|
||||||
|
Assert.Equal(".github/workflows/ci.yml", ctx.WorkflowFilePath);
|
||||||
|
Assert.True(ctx.TryGetValue("workflow_file_path", out var value));
|
||||||
|
Assert.IsType<StringContextData>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void WorkflowFilePath_NotSet_ReturnsNull()
|
||||||
|
{
|
||||||
|
var ctx = new JobContext();
|
||||||
|
Assert.Null(ctx.WorkflowFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void WorkflowFilePath_SetNull_ClearsValue()
|
||||||
|
{
|
||||||
|
var ctx = new JobContext();
|
||||||
|
ctx.WorkflowFilePath = ".github/workflows/ci.yml";
|
||||||
|
ctx.WorkflowFilePath = null;
|
||||||
|
Assert.Null(ctx.WorkflowFilePath);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user