Skip to content

Commit 17a13b1

Browse files
committed
Untrusted inputs
1 parent 455c1a1 commit 17a13b1

File tree

19 files changed

+192
-123
lines changed

19 files changed

+192
-123
lines changed

.github/actions/reports-group/codacy-uploader/action.yml

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -81,11 +81,10 @@ runs:
8181
id: build-outputs
8282
uses: actions/github-script@v7
8383
env:
84-
METADATA: ${{ steps.load-metadata.outputs.metadata }}
84+
REPORTS: ${{ steps.build-uploader-options.outputs.coverage-reports }}
8585
with:
8686
script: |
8787
core.info('Build output');
88-
const {METADATA} = process.env;
89-
90-
const metadata = JSON.parse(METADATA);
91-
core.setOutput('reports', metadata.reportPaths.split(',').join('\n'));
88+
const {REPORTS} = process.env;
89+
90+
core.setOutput('reports', REPORTS.split(',').join('\n'));

.github/actions/reports-group/codecov-uploader/action.yml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -98,15 +98,15 @@ runs:
9898
id: build-outputs
9999
uses: actions/github-script@v7
100100
env:
101-
METADATA: ${{ steps.load-metadata.outputs.metadata }}
101+
REPORT_NAME: ${{ steps.build-uploader-options.outputs.name }}
102+
REPORT_FILES: ${{ steps.build-uploader-options.outputs.files }}
103+
REPORT_FLAGS: ${{ steps.build-uploader-options.outputs.flags }}
102104
with:
103105
script: |
104106
core.info('Build output');
105-
const {METADATA} = process.env;
107+
const {REPORT_NAME, REPORT_FILES, REPORT_FLAGS} = process.env;
106108
107109
const metadata = JSON.parse(METADATA);
108-
core.setOutput('name', metadata.name);
109-
core.setOutput('reports', metadata.reportPaths.split(',').join('\n'));
110-
if (metadata.flags.length > 0) {
111-
core.setOutput('flags', metadata.flags.split(',').join('\n'));
112-
}
110+
core.setOutput('name', REPORT_NAME);
111+
core.setOutput('reports', REPORT_FILES.split(',').join('\n'));
112+
core.setOutput('flags', undefined !== REPORT_FLAGS ? REPORT_FLAGS.split(',').join('\n') : '');

.github/actions/reports-group/create/dist/index.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.github/actions/reports-group/create/dist/index.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.github/actions/reports-group/create/index.js

Lines changed: 35 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4,117 +4,121 @@ const fs = require('fs'); // @TODO move to 'imports from' when moved to TS !
44
const core = require('@actions/core'); // @TODO move to 'imports from' when moved to TS !
55
const io = require('@actions/io'); // @TODO move to 'imports from' when moved to TS !
66

7-
const {path: pathSDK, glob: globSDK, outputs: outputsSDK, CONSTANTS: SDK_CONSTANTS} = require('./node-sdk'); // @TODO move to 'imports from' when moved to TS !
7+
const SDK = require('./node-sdk'); // @TODO move to 'imports from' when moved to TS !
88

99
async function run() {
10+
const trustedPathHelper = SDK.path.trustedPathHelpers();
1011
/** INPUTS **/
11-
const NAME_INPUT = core.getInput('NAME', {required: true});
12+
const NAME_INPUT = core.getInput('name', {required: true});
1213
const FORMAT_INPUT = core.getInput('format', {required: true});
1314
const REPORTS_INPUT = core.getInput('files', {required: true});
1415
// Following inputs are not marked as required by the action but a default value must be there, so using `required` works
1516
const PATH_INPUT = core.getInput('path', {required: true});
1617
const FLAG_LIST_INPUT = core.getMultilineInput('flags', {required: true});
1718
const FOLLOW_SYMLINK_INPUT = core.getBooleanInput('follow-symbolic-links', {required: true});
1819

19-
const groupDirectory = await core.group(
20+
const trustedGroupDirectory = await core.group(
2021
'Resolve group directory path',
2122
async () => {
22-
const res = path.resolve(PATH_INPUT, NAME_INPUT);
23+
const res = trustedPathHelper.trust(path.join(PATH_INPUT, NAME_INPUT));
2324
core.info('group directory=' + res);
2425

2526
return res;
2627
}
2728
);
2829

29-
const originalReportPaths = await core.group(
30+
const trustedOriginalReportPaths = await core.group(
3031
'Resolve reports',
3132
async () => {
3233
const result = [];
33-
for await (const fp of globSDK.lookup(REPORTS_INPUT, {followSymbolicLinks: FOLLOW_SYMLINK_INPUT})) {
34-
const normalizedFp = pathSDK.relativeToGHWorkspace(fp);
34+
for await (const fp of SDK.glob.lookup(REPORTS_INPUT, {followSymbolicLinks: FOLLOW_SYMLINK_INPUT})) {
35+
const normalizedFp = trustedPathHelper.toWorkspaceRelative(fp);
3536
core.info('Found ' + normalizedFp);
3637
result.push(normalizedFp);
3738
}
3839
return result;
3940
}
4041
);
41-
core.debug('reports to copy=' + JSON.stringify(originalReportPaths));
42+
core.debug('reports to copy=' + JSON.stringify(trustedOriginalReportPaths));
4243

43-
if (0 === originalReportPaths.length) {
44+
if (0 === trustedOriginalReportPaths.length) {
4445
core.setFailed('You must provide at least one report !');
4546
}
4647

47-
const reportsMap = await core.group(
48+
const trustedReportsMap = await core.group(
4849
'Build reports map',
4950
async () => {
5051
let counter = 0;
51-
return originalReportPaths.map(filepath => {
52+
return trustedOriginalReportPaths.map(trustedSource => {
5253
// Ensure report files uniqueness while keeping a bit of clarity regarding the mapping with original files !
53-
const filename = path.basename(filepath) + '-report-' + (++counter);
54-
const destination = pathSDK.relativeToGHWorkspace(groupDirectory, filename);
55-
core.info(filepath + ' => ' + destination);
56-
return {source: filepath, filename: filename, dest: destination};
54+
const trustedFilename = path.basename(trustedSource) + '-report-' + (++counter); // Only trusted content !
55+
const trustedDestination = path.join(trustedGroupDirectory, trustedFilename); // Only trusted content !
56+
core.info(trustedSource + ' => ' + trustedDestination);
57+
58+
return {source: trustedSource, filename: trustedFilename, dest: trustedDestination};
5759
});
5860
}
5961
);
60-
core.debug('reports map=' + JSON.stringify(reportsMap));
62+
core.debug('reports map=' + JSON.stringify(trustedReportsMap));
6163

62-
const metadata = await core.group(
64+
const trustedMetadata = await core.group(
6365
'Build group metadata',
6466
async () => {
6567
const res = {
6668
name: NAME_INPUT,
6769
format: FORMAT_INPUT,
68-
reports: reportsMap.map(v => v.filename),
70+
reports: trustedReportsMap.map(v => v.filename),
6971
flags: FLAG_LIST_INPUT
7072
};
7173
core.info('Created');
7274

7375
return res;
7476
}
7577
);
76-
core.debug('metadata=' + JSON.stringify(metadata));
78+
core.debug('metadata=' + JSON.stringify(trustedMetadata));
7779

7880
await core.group('Create group directory', () => {
79-
core.info('Create group directory at ' + groupDirectory);
81+
core.info('Create group directory at ' + trustedGroupDirectory);
8082

81-
return io.mkdirP(groupDirectory)
83+
return io.mkdirP(trustedGroupDirectory)
8284
});
8385

8486
await core.group(
8587
'Copy reports',
86-
async () => reportsMap.map(async ({source, dest}) => {
87-
core.info(source + ' => ' + dest);
88+
async () => trustedReportsMap.map(async (trustedMap) => {
89+
core.info(trustedMap.source + ' => ' + trustedMap.dest);
8890

89-
return io.cp(source, dest);
91+
return io.cp(trustedMap.source, trustedMap.dest);
9092
})
9193
);
9294

9395
await core.group(
9496
'Create metadata file',
9597
async () => {
96-
const filepath = path.join(groupDirectory, SDK_CONSTANTS.METADATA_FILENAME);
97-
core.info('Create metadata file at ' + filepath + ' with: ' + JSON.stringify(metadata));
98-
fs.writeFileSync(filepath, JSON.stringify(metadata));
98+
const trustedFp = trustedPathHelper.trust(path.resolve(trustedGroupDirectory, SDK.METADATA_FILENAME));
99+
core.info('Create metadata file at ' + trustedFp + ' with: ' + JSON.stringify(trustedMetadata));
100+
101+
fs.writeFileSync(trustedFp, JSON.stringify(trustedMetadata));
99102
});
100103

101104
const outputs = await core.group(
102105
'Build action outputs',
103106
async () => {
107+
// Be sure to validate any path returned to the end-user !
104108
const res = {};
105109

106110
core.info("Build 'path' output");
107-
res.path = groupDirectory;
111+
res.path = trustedPathHelper.trust(trustedGroupDirectory);
108112
core.info("Build 'reports' output");
109-
res.reports = metadata.reports.join('\n');
113+
res.reports = trustedMetadata.reports.join('\n');
110114
core.info("Build 'files' output");
111-
res.files = originalReportPaths.join('\n');
115+
res.files = trustedReportsMap.map(v => v.source).join('\n');
112116

113117
return res;
114118
}
115119
);
116120
core.debug('outputs=' + JSON.stringify(outputs));
117-
outputsSDK.bindActionOutputs(outputs);
121+
SDK.outputs.bindFrom(outputs);
118122
}
119123

120124
run();

.github/actions/reports-group/find/dist/index.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.github/actions/reports-group/find/dist/index.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,28 @@
11
const core = require('@actions/core'); // @TODO move to 'imports from' when moved to TS !
22

3-
const {find: findSdk, outputs: outputsSDK} = require('./node-sdk'); // @TODO move to 'imports from' when moved to TS !
3+
const SDK = require('./node-sdk'); // @TODO move to 'imports from' when moved to TS !
44

55
async function run() {
6+
const trustedPathConverter = SDK.path.trustedPathHelpers();
67
/** INPUTS **/
78
const PATH_INPUT = core.getInput('path', {required: true});
89
// Following inputs are not marked as required by the action but a default value must be there, so using `required` works
910
const FORMAT_INPUT = core.getInput('format', {required: true});
1011
const GLUE_STRING_INPUT = core.getInput('glue-string', {required: true, trimWhitespace: false});
1112
const FOLLOW_SYMLINK_INPUT = core.getBooleanInput('follow-symbolic-links', {required: true});
1213

13-
const groupDirPathList = await core.group(
14+
const trustedGroupPaths = await core.group(
1415
'Find groups',
1516
async () => {
16-
const groupDirPathList = await findSdk.groupPaths(PATH_INPUT, {followSymbolicLinks: FOLLOW_SYMLINK_INPUT});
17+
const res = (await SDK.find.trustedGroupPaths(PATH_INPUT, trustedPathConverter.toWorkspaceRelative, {followSymbolicLinks: FOLLOW_SYMLINK_INPUT}));
1718

18-
groupDirPathList.forEach(p => core.info('Found a reports group directory at ' + p));
19+
res.forEach(p => core.info('Found a reports group directory at ' + p));
1920

20-
return groupDirPathList;
21+
return res;
2122
}
2223
);
23-
core.debug('groupDirPathList=' + JSON.stringify(groupDirPathList));
24-
if (0 === groupDirPathList.length) {
24+
core.debug('Group paths=' + JSON.stringify(trustedGroupPaths));
25+
if (0 === trustedGroupPaths.length) {
2526
core.setFailed('Unable to retrieve any group. Something wrong most likely happened !');
2627
}
2728

@@ -31,13 +32,13 @@ async function run() {
3132
const res = {};
3233

3334
core.info("Build 'list' output");
34-
res.list = 'json' === FORMAT_INPUT ? JSON.stringify(groupDirPathList) : groupDirPathList.join(GLUE_STRING_INPUT)
35+
res.list = 'json' === FORMAT_INPUT ? JSON.stringify(trustedGroupPaths) : trustedGroupPaths.join(GLUE_STRING_INPUT)
3536

3637
return res;
3738
}
3839
);
3940
core.debug('outputs=' + JSON.stringify(outputs));
40-
outputsSDK.bindActionOutputs(outputs);
41+
SDK.outputs.bindFrom(outputs);
4142
}
4243

4344
run();

.github/actions/reports-group/load-metadata/dist/index.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.github/actions/reports-group/load-metadata/dist/index.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)