Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
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
18 changes: 18 additions & 0 deletions src/Sdk/WorkflowParser/Conversion/WorkflowTemplateConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1957,6 +1957,24 @@ private static Permissions ConvertToPermissions(TemplateContext context, Templat
context.Error(key, $"The permission 'models' is not allowed");
}
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;
Comment on lines +1963 to +1970
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

workflows is not currently declared in the workflow schema (src/Sdk/WorkflowParser/workflow-v1.0.json under permissions-mapping.properties). With the current schema, TemplateReader will treat workflows as an unexpected key and skip it, so this case "workflows" block is effectively unreachable even when AllowWorkflowsPermission is enabled. Update the schema to include workflows (and align the allowed value type with the intended behavior, e.g., whether read should be accepted and downgraded or rejected by schema).

Suggested change
// Workflows only supports write; downgrade read to none
if (permissionLevel == PermissionLevel.Read)
{
permissions.Workflows = PermissionLevel.NoAccess;
}
else
{
permissions.Workflows = permissionLevel;
// Workflows only supports write.
if (permissionLevel == PermissionLevel.Write)
{
permissions.Workflows = permissionLevel;
}
else
{
context.Error(key, $"The permission 'workflows' only supports 'write'");

Copilot uses AI. Check for mistakes.
}
}
else
{
context.Error(key, $"The permission 'workflows' is not allowed");
}
break;
default:
break;
}
Expand Down
21 changes: 16 additions & 5 deletions src/Sdk/WorkflowParser/Permissions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using GitHub.Actions.WorkflowParser.Conversion;
Expand All @@ -17,7 +17,7 @@ public Permissions()
public Permissions(Permissions copy)
{
Actions = copy.Actions;
ArtifactMetadata = copy.ArtifactMetadata;
ArtifactMetadata = copy.ArtifactMetadata;
Attestations = copy.Attestations;
Checks = copy.Checks;
Contents = copy.Contents;
Expand All @@ -32,6 +32,7 @@ public Permissions(Permissions copy)
SecurityEvents = copy.SecurityEvents;
IdToken = copy.IdToken;
Models = copy.Models;
Workflows = copy.Workflows;
}

public Permissions(
Expand All @@ -41,7 +42,7 @@ public Permissions(
bool includeModels)
{
Actions = permissionLevel;
ArtifactMetadata = permissionLevel;
ArtifactMetadata = permissionLevel;
Attestations = includeAttestations ? permissionLevel : PermissionLevel.NoAccess;
Checks = permissionLevel;
Contents = permissionLevel;
Expand All @@ -56,9 +57,11 @@ public Permissions(
SecurityEvents = permissionLevel;
IdToken = includeIdToken ? permissionLevel : PermissionLevel.NoAccess;
// Models must not have higher permissions than Read
Models = includeModels
? (permissionLevel == PermissionLevel.Write ? PermissionLevel.Read : permissionLevel)
Models = includeModels
? (permissionLevel == PermissionLevel.Write ? PermissionLevel.Read : permissionLevel)
: PermissionLevel.NoAccess;
// Workflows is excluded from write-all / read-all; must be explicitly requested
Workflows = PermissionLevel.NoAccess;
}

private static KeyValuePair<string, (PermissionLevel, PermissionLevel)>[] ComparisonKeyMapping(Permissions left, Permissions right)
Expand All @@ -81,6 +84,7 @@ public Permissions(
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)>("models", (left.Models, right.Models)),
new KeyValuePair<string, (PermissionLevel, PermissionLevel)>("workflows", (left.Workflows, right.Workflows)),
};
}

Expand Down Expand Up @@ -196,6 +200,13 @@ public PermissionLevel Statuses
set;
}

[DataMember(Name = "workflows", EmitDefaultValue = false)]
public PermissionLevel Workflows
{
get;
set;
}

public Permissions Clone()
{
return new Permissions(this);
Expand Down
10 changes: 9 additions & 1 deletion src/Sdk/WorkflowParser/WorkflowFeatures.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
Expand Down Expand Up @@ -41,6 +41,13 @@ public class WorkflowFeatures
[DataMember(EmitDefaultValue = false)]
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>
/// Gets or sets a value indicating whether the expression function fromJson performs strict JSON parsing.
/// Used during evaluation only.
Expand All @@ -67,6 +74,7 @@ public static WorkflowFeatures GetDefaults()
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
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
};
}
Expand Down
Loading