-
Notifications
You must be signed in to change notification settings - Fork 174
Hide default values from workflow dispatch input #2033
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Hide default values from workflow dispatch input #2033
Conversation
…nput' into w/johwik/1952-Hide-default-values-from-workflow_dispatch-input
…-sensitive matching and update related test cases
…nput' into w/johwik/1952-Hide-default-values-from-workflow_dispatch-input
…efault-values-on-workflow_dispatch-input
…nput' into w/johwik/1952-Hide-default-values-from-workflow_dispatch-input
… and related tests
…efault-values-on-workflow_dispatch-input
…nput' into w/johwik/1952-Hide-default-values-from-workflow_dispatch-input
… and related tests
…nput' into w/johwik/1952-Hide-default-values-from-workflow_dispatch-input
…nput' into w/johwik/1952-Hide-default-values-from-workflow_dispatch-input
…nput' into w/johwik/1952-Hide-default-values-from-workflow_dispatch-input
…default-values-from-workflow_dispatch-input
…efault-values-on-workflow_dispatch-input
…nput' into w/johwik/1952-Hide-default-values-from-workflow_dispatch-input
…efault-values-on-workflow_dispatch-input
… related references
…nput' into w/johwik/1952-Hide-default-values-from-workflow_dispatch-input
…ructions directory
…ace variations in input expressions
…owDefaultInputs function
…efault-values-on-workflow_dispatch-input
…nput' into w/johwik/1952-Hide-default-values-from-workflow_dispatch-input
…nput' into w/johwik/1952-Hide-default-values-from-workflow_dispatch-input
…logic and remove unnecessary input removal code.
…default-values-from-workflow_dispatch-input
|
@mazhelez here's the PR for the "hide input" functionality I mentioned earlier this week. What do you think of this functionality? 🤔 ps. |
|
…low_dispatch-input
…default-values-from-workflow_dispatch-input
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This pull request introduces a workflow input hiding feature that extends the workflowDefaultInputs setting introduced in v8.1. Users can now set "hide": true on workflow inputs to remove them from the GitHub Actions manual workflow dispatch form while automatically replacing all references to those inputs with their configured values.
Key changes:
- Enhanced
workflowDefaultInputssetting to support an optional"hide"property - Added regex-based replacement logic to substitute hidden input references throughout workflow files
- Implemented comprehensive test coverage for the hiding feature including edge cases
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| Actions/.Modules/settings.schema.json | Added "hide" property to workflow input schema with boolean type and description |
| Actions/CheckForUpdates/yamlclass.ps1 | Added overloaded ReplaceAll method supporting regex-based replacements with $isRegex parameter |
| Actions/CheckForUpdates/CheckForUpdates.HelperFunctions.ps1 | Enhanced ApplyWorkflowDefaultInputs to track hidden inputs, remove them from workflow YAML, and replace all references with literal values |
| Tests/CheckForUpdates.Action.Test.ps1 | Added extensive test coverage for YAML regex replacement and hiding feature including edge cases for job outputs and partial matches |
| Scenarios/settings.md | Updated documentation to describe the new "hide" property with examples |
| RELEASENOTES.md | Added release notes documenting the hiding feature with usage examples |
Comments suppressed due to low confidence (1)
Actions/CheckForUpdates/CheckForUpdates.HelperFunctions.ps1:583
- The regex patterns directly use
$inputNamewithout escaping special regex characters. If an input name contains regex special characters (like.,*,+,?,[,],(,),{,},^,$,|,\), the pattern will not work correctly or could cause runtime errors.
For example, if an input is named "my.input", the pattern (?<!\.)inputs\.my.input\b(?!\.) would match "inputs" followed by any three characters (due to the unescaped dots).
Suggestion: Use [regex]::Escape($inputName) when constructing the regex patterns to properly escape special characters:
$escapedInputName = [regex]::Escape($inputName)
$pattern = "`\$\{\{\s*github\.event\.inputs\.$escapedInputName\s*\}\}"
# ... and so on for other patterns $pattern = "`\$\{\{\s*github\.event\.inputs\.$inputName\s*\}\}"
$yaml.ReplaceAll($pattern, $expressionValue, $true)
$pattern = "`\$\{\{\s*inputs\.$inputName\s*\}\}"
$yaml.ReplaceAll($pattern, $expressionValue, $true)
# Replace references in if conditions: github.event.inputs.name and inputs.name (without ${{ }})
# github.event.inputs are always strings (user input from UI)
# inputs.* are typed values (boolean/number/string/choice)
# For github.event.inputs.NAME: always use string literal format
# Convert the value to a string literal (always quoted) for comparisons
if ($rawValue -is [bool]) {
$stringValue = $rawValue.ToString().ToLower()
}
else {
$stringValue = $rawValue.ToString().Replace("'", "''")
}
$stringLiteral = "'$stringValue'"
$yaml.ReplaceAll("github.event.inputs.$inputName", $stringLiteral)
# For inputs.NAME: use expression literal format (typed value)
# Replace inputs.NAME but be careful not to match patterns like:
# - needs.inputs.outputs.NAME (where a job is named "inputs")
# - steps.CreateInputs.outputs.NAME (where "inputs" is part of a word)
# Use negative lookbehind (?<!\.) to ensure "inputs" is not preceded by a dot
# Use word boundary \b after inputName to avoid partial matches
# Don't match if followed by a dot (to avoid matching outputs references)
$pattern = "(?<!\.)inputs\.$inputName\b(?!\.)"
$yaml.ReplaceAll($pattern, $expressionValue, $true)
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| }, | ||
| "value": { | ||
| "description": "The default value for the workflow input (can be string, boolean, or number)" | ||
| }, |
Copilot
AI
Dec 3, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inconsistent indentation: Line 754 has improper closing of the "value" property (extra spaces before the closing brace). The line should be:
},instead of:
},This maintains consistent indentation with the surrounding JSON properties.
| }, | |
| }, |
| "name: 'Test Workflow'", | ||
| "on:", | ||
| " workflow_dispatch:", | ||
| " inputs:", | ||
| " input1:", | ||
| " type: string", | ||
| " default: ''", | ||
| " input2:", | ||
| " type: boolean", | ||
| " default: false", | ||
| "jobs:", | ||
| " test:", | ||
| " runs-on: ubuntu-latest" | ||
| ) | ||
| $yaml = [Yaml]::new($yamlContent) | ||
|
|
||
| $yaml = [Yaml]::new($yamlContent) | ||
| # Create settings with duplicate entries where first has hide=false, last has hide=true | ||
| $repoSettings = @{ | ||
| "workflowDefaultInputs" = @( | ||
| @{ "name" = "myInput"; "value" = "first-value"; "hide" = $false }, | ||
| @{ "name" = "myInput"; "value" = "final-value"; "hide" = $true } | ||
| ) | ||
| } | ||
|
|
||
| # Create settings with duplicate entries for input1 - simulating merged conditional settings | ||
| # This can happen when multiple conditionalSettings blocks both match and both define the same input | ||
| $repoSettings = @{ | ||
| "workflowDefaultInputs" = @( | ||
| @{ "name" = "input1"; "value" = "first-value" }, | ||
| @{ "name" = "input2"; "value" = $false }, | ||
| @{ "name" = "input1"; "value" = "second-value" }, # Duplicate input1 | ||
| @{ "name" = "input1"; "value" = "final-value" } # Another duplicate input1 | ||
| # Apply the defaults | ||
| ApplyWorkflowDefaultInputs -yaml $yaml -repoSettings $repoSettings -workflowName "Test Workflow - Duplicate Hide" | ||
|
|
||
| # Verify last entry wins - input should be hidden | ||
| $inputs = $yaml.Get('on:/workflow_dispatch:/inputs:/') | ||
| $inputs.Find('myInput:', [ref] $null, [ref] $null) | Should -Be $false | ||
|
|
||
| # Verify the final hidden value was used | ||
| $content = $yaml.content -join "`n" | ||
| $content | Should -Match "echo 'final-value'" | ||
| $content | Should -Not -Match "inputs\.myInput" | ||
| } | ||
|
|
||
| It 'applies last value when duplicate entries have hide reversed' { | ||
| . (Join-Path $scriptRoot "yamlclass.ps1") | ||
|
|
||
| # Create a test workflow YAML | ||
| $yamlContent = @( | ||
| "name: 'Test Workflow'", | ||
| "on:", | ||
| " workflow_dispatch:", | ||
| " inputs:", | ||
| " myInput:", | ||
| " type: string", | ||
| " default: ''", | ||
| "jobs:", | ||
| " test:", | ||
| " runs-on: ubuntu-latest", | ||
| " steps:", | ||
| " - name: Test", | ||
| " run: echo `${{ inputs.myInput }}" | ||
| ) | ||
| } | ||
|
|
||
| # Apply the defaults | ||
| ApplyWorkflowDefaultInputs -yaml $yaml -repoSettings $repoSettings -workflowName "Test Workflow" | ||
| $yaml = [Yaml]::new($yamlContent) | ||
|
|
||
| # Verify "last wins" - the final value for input1 should be applied | ||
| $yaml.Get('on:/workflow_dispatch:/inputs:/input1:/default:').content -join '' | Should -Be "default: 'final-value'" | ||
| $yaml.Get('on:/workflow_dispatch:/inputs:/input2:/default:').content -join '' | Should -Be 'default: false' | ||
| } | ||
| # Create settings with duplicate entries where first has hide=true, last has hide=false | ||
| $repoSettings = @{ | ||
| "workflowDefaultInputs" = @( | ||
| @{ "name" = "myInput"; "value" = "first-value"; "hide" = $true }, | ||
| @{ "name" = "myInput"; "value" = "final-value"; "hide" = $false } | ||
| ) | ||
| } | ||
|
|
||
| # Apply the defaults | ||
| ApplyWorkflowDefaultInputs -yaml $yaml -repoSettings $repoSettings -workflowName "Test Workflow - Duplicate Hide Reversed" | ||
|
|
||
| # Verify last entry wins - input should NOT be hidden | ||
| $inputs = $yaml.Get('on:/workflow_dispatch:/inputs:/') | ||
| $inputs.Find('myInput:', [ref] $null, [ref] $null) | Should -Be $true | ||
|
|
||
| # Verify the final value was applied to the default | ||
| $yaml.Get('on:/workflow_dispatch:/inputs:/myInput:/default:').content -join '' | Should -Be "default: 'final-value'" | ||
|
|
||
| # Verify the reference was NOT replaced (input is visible) | ||
| $content = $yaml.content -join "`n" | ||
| $content | Should -Match "echo `\$\{\{ inputs\.myInput \}\}" | ||
| $content | Should -Not -Match "echo 'final-value'" | ||
| } | ||
|
|
||
| } # End of Context 'ApplyWorkflowDefaultInputs - Hide Feature' |
Copilot
AI
Dec 3, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing test coverage: There are no tests for hiding inputs whose names contain regex special characters (e.g., my.input, my-input, my+input).
Since the regex patterns in lines 555-583 of CheckForUpdates.HelperFunctions.ps1 directly use $inputName without escaping, inputs with special characters could cause incorrect pattern matching or runtime errors.
Suggestion: Add test cases that verify hiding works correctly for input names containing characters like ., -, +, *, ?, [, ], (, ), etc.
| $hideInput = $false | ||
| if ($default['hide']) { | ||
| $hideInput = [bool]$default.hide | ||
| } |
Copilot
AI
Dec 3, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inconsistent indentation: Lines 359-362 have extra indentation (8 spaces instead of 4). This should be aligned with the surrounding code at the same scope level.
| $hideInput = $false | |
| if ($default['hide']) { | |
| $hideInput = [bool]$default.hide | |
| } | |
| $hideInput = $false | |
| if ($default['hide']) { | |
| $hideInput = [bool]$default.hide | |
| } |
| $pattern = "`\$\{\{\s*github\.event\.inputs\.$inputName\s*\}\}" | ||
| $yaml.ReplaceAll($pattern, $expressionValue, $true) | ||
| $pattern = "`\$\{\{\s*inputs\.$inputName\s*\}\}" | ||
| $yaml.ReplaceAll($pattern, $expressionValue, $true) |
Copilot
AI
Dec 3, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Regex patterns are constructed using unescaped input names ($inputName) when replacing hidden input references, e.g., "${{\sgithub.event.inputs.$inputName\s}}"and"(?<!.)inputs.$inputName\b(?!.)". If an input name contains regex metacharacters (like . * + ? ( ) [ ] |), this can cause overbroad or malformed matches and unintended replacements across the workflow, enabling an attacker who controls workflow input names to tamper with workflow logic. Fix by escaping $inputNamefor regex (e.g., using[Regex]::Escape($inputName)`) before interpolating it into patterns:
$escaped = [Regex]::Escape($inputName)
$pattern1 = "`\$\{\{\s*github\.event\.inputs\.$escaped\s*\}\}"
$pattern2 = "(?<!\.)inputs\.$escaped\b(?!\.)"Also ensure any other regex constructions using input-derived values apply the same escaping.
| # Use negative lookbehind (?<!\.) to ensure "inputs" is not preceded by a dot | ||
| # Use word boundary \b after inputName to avoid partial matches | ||
| # Don't match if followed by a dot (to avoid matching outputs references) | ||
| $pattern = "(?<!\.)inputs\.$inputName\b(?!\.)" |
Copilot
AI
Dec 3, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Regex pattern "(?<!\.)inputs\.$inputName\b(?!\.)" embeds $inputName without regex escaping. If the input name includes regex metacharacters, it can match unintended substrings (e.g., parts of job/step output references or other content) and replace them with attacker-controlled values, corrupting workflow logic. Fix by escaping the name: "(?<!\.)inputs\.[Regex]::Escape($inputName)\b(?!\.)" or build the pattern using $escaped = [Regex]::Escape($inputName) and then interpolate $escaped.
| $pattern = "(?<!\.)inputs\.$inputName\b(?!\.)" | |
| $escapedInputName = [Regex]::Escape($inputName) | |
| $pattern = "(?<!\.)inputs\.$escapedInputName\b(?!\.)" |
❔What, Why & How
This pull request introduces an important enhancement to the workflow input handling in AL-Go: you can now set
"hide": trueon a workflow input in your settings to remove it from the manual workflow form. When an input is hidden, all references to that input in the workflow file are replaced with the configured value, ensuring workflows can use default values without exposing them to users. The implementation includes updates to the schema, helper functions, YAML manipulation, documentation, and test instructions.Workflow Input Hiding Feature:
"hide": trueinworkflowDefaultInputsin the settings schema, allowing inputs to be removed from the workflow form and replaced with their configured values in the workflow file (Actions/.Modules/settings.schema.json).ApplyWorkflowDefaultInputsinCheckForUpdates.HelperFunctions.ps1to:github.event.inputs.<name>andinputs.<name>) with their literal values, using regex and careful matching to avoid accidental replacements (Actions/CheckForUpdates/CheckForUpdates.HelperFunctions.ps1). [1] [2] [3]YAML Manipulation Improvements:
Yamlclass with a newReplaceAllmethod supporting regex-based replacements, enabling robust substitution of input references throughout workflow files (Actions/CheckForUpdates/yamlclass.ps1).Documentation Updates:
RELEASENOTES.md). [1] [2]Related to discussion: #1952
✅ Checklist