Skip to content

Commit b5ad3c4

Browse files
fix: composite action input pollution (#2348)
* fix: composite action input pollution * fix run steps * fix missing defaults in post after env cleanup * fix test to make more sense * Add tests and simplify change --------- Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
1 parent b917ecc commit b5ad3c4

File tree

16 files changed

+182
-0
lines changed

16 files changed

+182
-0
lines changed

pkg/runner/action.go

+1
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,7 @@ func runPostStep(step actionStep) common.Executor {
625625
case model.ActionRunsUsingNode12, model.ActionRunsUsingNode16, model.ActionRunsUsingNode20:
626626

627627
populateEnvsFromSavedState(step.getEnv(), step, rc)
628+
populateEnvsFromInput(ctx, step.getEnv(), step.getActionModel(), rc)
628629

629630
containerArgs := []string{"node", path.Join(containerActionDir, action.Runs.Post)}
630631
logger.Debugf("executing remote job container: %s", containerArgs)

pkg/runner/runner_test.go

+2
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,8 @@ func TestRunEvent(t *testing.T) {
242242
// Uses
243243
{workdir, "uses-composite", "push", "", platforms, secrets},
244244
{workdir, "uses-composite-with-error", "push", "Job 'failing-composite-action' failed", platforms, secrets},
245+
{workdir, "uses-composite-check-for-input-collision", "push", "", platforms, secrets},
246+
{workdir, "uses-composite-check-for-input-shadowing", "push", "", platforms, secrets},
245247
{workdir, "uses-nested-composite", "push", "", platforms, secrets},
246248
{workdir, "remote-action-composite-js-pre-with-defaults", "push", "", platforms, secrets},
247249
{workdir, "remote-action-composite-action-ref", "push", "", platforms, secrets},

pkg/runner/step.go

+10
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,16 @@ func mergeEnv(ctx context.Context, step step) {
239239
}
240240

241241
rc.withGithubEnv(ctx, step.getGithubContext(ctx), *env)
242+
243+
if step.getStepModel().Uses != "" {
244+
// prevent uses action input pollution of unset parameters, skip this for run steps
245+
// due to design flaw
246+
for key := range *env {
247+
if strings.Contains(key, "INPUT_") {
248+
delete(*env, key)
249+
}
250+
}
251+
}
242252
}
243253

244254
func isStepEnabled(ctx context.Context, expr string, step step, stage stepStage) (bool, error) {

pkg/runner/step_test.go

+1
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ func TestSetupEnv(t *testing.T) {
139139
JobContainer: cm,
140140
}
141141
step := &model.Step{
142+
Uses: "./",
142143
With: map[string]string{
143144
"STEP_WITH": "with-value",
144145
},
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
name: "Action with pre and post"
2+
description: "Action with pre and post"
3+
4+
inputs:
5+
step:
6+
description: "step"
7+
required: true
8+
cache:
9+
required: false
10+
default: false
11+
12+
runs:
13+
using: "node16"
14+
pre: pre.js
15+
main: main.js
16+
post: post.js
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
const { appendFileSync } = require('fs');
2+
const step = process.env['INPUT_STEP'];
3+
appendFileSync(process.env['GITHUB_ENV'], `TEST=${step}`, { encoding:'utf-8' })
4+
5+
var cache = process.env['INPUT_CACHE']
6+
try {
7+
var cache = JSON.parse(cache)
8+
} catch {
9+
10+
}
11+
if(typeof cache !== 'boolean') {
12+
console.log("Input Polluted boolean true/false expected, got " + cache)
13+
process.exit(1);
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
const { appendFileSync } = require('fs');
2+
const step = process.env['INPUT_STEP'];
3+
appendFileSync(process.env['GITHUB_ENV'], `TEST=${step}-post`, { encoding:'utf-8' })
4+
5+
var cache = process.env['INPUT_CACHE']
6+
try {
7+
var cache = JSON.parse(cache)
8+
} catch {
9+
10+
}
11+
if(typeof cache !== 'boolean') {
12+
console.log("Input Polluted boolean true/false expected, got " + cache)
13+
process.exit(1);
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
console.log('pre');
2+
3+
var cache = process.env['INPUT_CACHE']
4+
try {
5+
var cache = JSON.parse(cache)
6+
} catch {
7+
8+
}
9+
if(typeof cache !== 'boolean') {
10+
console.log("Input Polluted boolean true/false expected, got " + cache)
11+
process.exit(1);
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
name: "Test Composite Action"
2+
description: "Test action uses composite"
3+
4+
inputs:
5+
cache:
6+
default: none
7+
8+
runs:
9+
using: "composite"
10+
steps:
11+
- uses: ./uses-composite-check-for-input-collision/action-with-pre-and-post
12+
with:
13+
step: step1
14+
- uses: ./uses-composite-check-for-input-collision/action-with-pre-and-post
15+
with:
16+
step: step2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
name: uses-composite-with-pre-and-post-steps
2+
on: push
3+
4+
jobs:
5+
test:
6+
runs-on: ubuntu-latest
7+
steps:
8+
- uses: actions/checkout@v4
9+
- run: echo -n "STEP_OUTPUT_TEST=empty" >> $GITHUB_ENV
10+
- uses: ./uses-composite-check-for-input-collision/composite_action
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
name: "Action with pre and post"
2+
description: "Action with pre and post"
3+
4+
inputs:
5+
step:
6+
description: "step"
7+
required: true
8+
cache:
9+
required: false
10+
default: false
11+
12+
runs:
13+
using: "node16"
14+
pre: pre.js
15+
main: main.js
16+
post: post.js
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
const { appendFileSync } = require('fs');
2+
const step = process.env['INPUT_STEP'];
3+
appendFileSync(process.env['GITHUB_ENV'], `TEST=${step}`, { encoding:'utf-8' })
4+
5+
var cache = process.env['INPUT_CACHE']
6+
try {
7+
var cache = JSON.parse(cache)
8+
} catch {
9+
10+
}
11+
if(typeof cache !== 'boolean') {
12+
console.log("Input Polluted boolean true/false expected, got " + cache)
13+
process.exit(1);
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
const { appendFileSync } = require('fs');
2+
const step = process.env['INPUT_STEP'];
3+
appendFileSync(process.env['GITHUB_ENV'], `TEST=${step}-post`, { encoding:'utf-8' })
4+
5+
var cache = process.env['INPUT_CACHE']
6+
try {
7+
var cache = JSON.parse(cache)
8+
} catch {
9+
10+
}
11+
if(typeof cache !== 'boolean') {
12+
console.log("Input Polluted boolean true/false expected, got " + cache)
13+
process.exit(1);
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
console.log('pre');
2+
3+
var cache = process.env['INPUT_CACHE']
4+
try {
5+
var cache = JSON.parse(cache)
6+
} catch {
7+
8+
}
9+
if(typeof cache !== 'boolean') {
10+
console.log("Input Polluted boolean true/false expected, got " + cache)
11+
process.exit(1);
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
name: "Test Composite Action"
2+
description: "Test action uses composite"
3+
4+
inputs:
5+
cache:
6+
default: true
7+
8+
runs:
9+
using: "composite"
10+
steps:
11+
- uses: ./uses-composite-check-for-input-shadowing/action-with-pre-and-post
12+
with:
13+
step: step1
14+
cache: ${{ inputs.cache || 'none' }}
15+
- uses: ./uses-composite-check-for-input-shadowing/action-with-pre-and-post
16+
with:
17+
step: step2
18+
cache: ${{ inputs.cache || 'none' }}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
name: uses-composite-with-pre-and-post-steps
2+
on: push
3+
4+
jobs:
5+
test:
6+
runs-on: ubuntu-latest
7+
steps:
8+
- uses: actions/checkout@v4
9+
- run: echo -n "STEP_OUTPUT_TEST=empty" >> $GITHUB_ENV
10+
- uses: ./uses-composite-check-for-input-shadowing/composite_action
11+
# with:
12+
# cache: other

0 commit comments

Comments
 (0)