setup-php 2.36.0 → 2.37.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/README.md +15 -12
  2. package/lib/config.js +5 -2
  3. package/lib/config.js.map +1 -1
  4. package/lib/core.d.ts +8 -0
  5. package/lib/core.js +55 -0
  6. package/lib/core.js.map +1 -0
  7. package/lib/extensions.js +9 -8
  8. package/lib/extensions.js.map +1 -1
  9. package/lib/fetch.js +25 -70
  10. package/lib/fetch.js.map +1 -1
  11. package/lib/install.js +3 -3
  12. package/lib/install.js.map +1 -1
  13. package/lib/tools.d.ts +50 -21
  14. package/lib/tools.js +211 -150
  15. package/lib/tools.js.map +1 -1
  16. package/lib/utils.d.ts +3 -0
  17. package/lib/utils.js +62 -26
  18. package/lib/utils.js.map +1 -1
  19. package/package.json +20 -20
  20. package/src/config.ts +5 -2
  21. package/src/configs/brew_extensions +19 -0
  22. package/src/configs/composer-gh-auth-no-op +3 -0
  23. package/src/configs/composer-gh-auth-warn +1 -0
  24. package/src/configs/os_releases.csv +4 -1
  25. package/src/core.ts +112 -0
  26. package/src/extensions.ts +16 -15
  27. package/src/fetch.ts +28 -42
  28. package/src/install.ts +6 -3
  29. package/src/scripts/darwin.sh +12 -6
  30. package/src/scripts/extensions/couchbase.sh +13 -2
  31. package/src/scripts/extensions/firebird.sh +6 -23
  32. package/src/scripts/extensions/gearman.sh +1 -1
  33. package/src/scripts/extensions/http.ps1 +7 -5
  34. package/src/scripts/extensions/phalcon.ps1 +3 -21
  35. package/src/scripts/extensions/phalcon.sh +2 -0
  36. package/src/scripts/extensions/relay.sh +5 -2
  37. package/src/scripts/extensions/source.sh +3 -1
  38. package/src/scripts/extensions/sqlsrv.ps1 +2 -0
  39. package/src/scripts/extensions/sqlsrv.sh +2 -0
  40. package/src/scripts/linux.sh +49 -9
  41. package/src/scripts/tools/add_tools.ps1 +75 -27
  42. package/src/scripts/tools/add_tools.sh +67 -23
  43. package/src/scripts/tools/blackfire.sh +1 -1
  44. package/src/scripts/tools/brew.sh +130 -0
  45. package/src/scripts/tools/grpc_php_plugin.sh +2 -2
  46. package/src/scripts/tools/ppa.sh +5 -1
  47. package/src/scripts/unix.sh +7 -3
  48. package/src/scripts/win32.ps1 +17 -11
  49. package/src/tools.ts +349 -203
  50. package/src/utils.ts +81 -34
package/src/utils.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import fs from 'fs';
2
2
  import * as path from 'path';
3
- import * as core from '@actions/core';
3
+ import * as core from './core';
4
4
  import * as fetch from './fetch';
5
5
 
6
6
  /**
@@ -62,15 +62,31 @@ export async function getManifestURLS(): Promise<string[]> {
62
62
  */
63
63
  export async function parseVersion(version: string): Promise<string> {
64
64
  switch (true) {
65
- case /^(latest|lowest|highest|nightly|\d+\.x)$/.test(version):
65
+ case /^pre(-installed)?$/.test(version):
66
+ return 'pre';
67
+ case /^(latest|lowest|highest|nightly|master|\d+\.x)$/.test(version):
66
68
  for (const manifestURL of await getManifestURLS()) {
67
69
  const fetchResult = await fetch.fetch(manifestURL);
68
70
  if (fetchResult['data'] ?? false) {
69
- return JSON.parse(fetchResult['data'])[version];
71
+ const resolved: string | undefined = JSON.parse(fetchResult['data'])[
72
+ version
73
+ ];
74
+ if (resolved === undefined) {
75
+ throw new Error(`Invalid PHP version: ${version.slice(0, 20)}`);
76
+ }
77
+ if (!/^\d+\.\d+$/.test(resolved)) {
78
+ throw new Error(
79
+ `Invalid PHP version in manifest: ${resolved.slice(0, 10)}`
80
+ );
81
+ }
82
+ return resolved;
70
83
  }
71
84
  }
72
85
  throw new Error(`Could not fetch the PHP version manifest.`);
73
86
  default:
87
+ if (!/^\d+(\.\d+){0,2}$/.test(version)) {
88
+ throw new Error(`Invalid PHP version: ${version.slice(0, 20)}`);
89
+ }
74
90
  switch (true) {
75
91
  case version.length > 1:
76
92
  return version.slice(0, 3);
@@ -86,20 +102,16 @@ export async function parseVersion(version: string): Promise<string> {
86
102
  * @param ini_file
87
103
  */
88
104
  export async function parseIniFile(ini_file: string): Promise<string> {
89
- switch (true) {
90
- case /^(production|development|none)$/.test(ini_file):
91
- return ini_file;
92
- case /php\.ini-(production|development)$/.test(ini_file):
93
- return ini_file.split('-')[1];
94
- default:
95
- return 'production';
105
+ if (/^(production|development|none)$/.test(ini_file)) {
106
+ return ini_file;
96
107
  }
108
+ const match = ini_file.match(/php\.ini-(production|development)$/);
109
+ return match ? match[1] : 'production';
97
110
  }
98
111
 
99
112
  /**
100
- * Async foreach loop
113
+ * Async foreach loop using modern for...of pattern
101
114
  *
102
- * @author https://github.com/Atinux
103
115
  * @param array
104
116
  * @param callback
105
117
  */
@@ -111,8 +123,8 @@ export async function asyncForEach(
111
123
  array: Array<string>
112
124
  ) => Promise<void>
113
125
  ): Promise<void> {
114
- for (let index = 0; index < array.length; index++) {
115
- await callback(array[index], index, array);
126
+ for (const [index, element] of array.entries()) {
127
+ await callback(element, index, array);
116
128
  }
117
129
  }
118
130
 
@@ -173,10 +185,10 @@ export async function log(
173
185
  export async function stepLog(message: string, os: string): Promise<string> {
174
186
  switch (os) {
175
187
  case 'win32':
176
- return 'Step-Log "' + message + '"';
188
+ return 'Step-Log "' + escapeForShell(message, os) + '"';
177
189
  case 'linux':
178
190
  case 'darwin':
179
- return 'step_log "' + message + '"';
191
+ return 'step_log "' + escapeForShell(message, os) + '"';
180
192
  default:
181
193
  return await log('Platform ' + os + ' is not supported', os, 'error');
182
194
  }
@@ -195,17 +207,40 @@ export async function addLog(
195
207
  message: string,
196
208
  os: string
197
209
  ): Promise<string> {
210
+ const sub = escapeForShell(subject, os);
211
+ const msg = escapeForShell(message, os);
198
212
  switch (os) {
199
213
  case 'win32':
200
- return 'Add-Log "' + mark + '" "' + subject + '" "' + message + '"';
214
+ return `Add-Log "${mark}" "${sub}" "${msg}"`;
201
215
  case 'linux':
202
216
  case 'darwin':
203
- return 'add_log "' + mark + '" "' + subject + '" "' + message + '"';
217
+ return `add_log "${mark}" "${sub}" "${msg}"`;
204
218
  default:
205
219
  return await log('Platform ' + os + ' is not supported', os, 'error');
206
220
  }
207
221
  }
208
222
 
223
+ export function escapeForShell(value: string, os: string): string {
224
+ if (os === 'win32') {
225
+ return value.replace(/[`$"]/g, '`$&');
226
+ }
227
+ return value.replace(/[\\`$"]/g, '\\$&');
228
+ }
229
+
230
+ export function safeArg(value: string, os: string): string {
231
+ if (!/^[a-zA-Z0-9_./:@+,~^-]*$/.test(value)) {
232
+ return '"' + escapeForShell(value, os) + '"';
233
+ }
234
+ return value;
235
+ }
236
+
237
+ export function sanitizeShellInput(value: string, strict = false): string {
238
+ const pattern = strict
239
+ ? /[$`"';|&(){}[\]\\<>*?\n\r\t]/g
240
+ : /[$`"';|&(){}[\]\\\n\r\t]/g;
241
+ return value.replace(pattern, '');
242
+ }
243
+
209
244
  /**
210
245
  * Function to break extension csv into an array
211
246
  *
@@ -225,11 +260,11 @@ export async function extensionArray(
225
260
  .split(',')
226
261
 
227
262
  .map(function (extension: string) {
263
+ extension = extension.trim().replace(/^\\\s*/, '');
228
264
  if (/.+-.+\/.+@.+/.test(extension)) {
229
265
  return extension;
230
266
  }
231
267
  return extension
232
- .trim()
233
268
  .toLowerCase()
234
269
  .replace(/^(:)?(php[-_]|none|zend )|(-[^-]*)-/, '$1$3');
235
270
  })
@@ -432,22 +467,35 @@ export async function parseExtensionSource(
432
467
  );
433
468
  }
434
469
 
470
+ const VERSION_INPUT_REGEX =
471
+ /^(latest|lowest|highest|nightly|master|pre|pre-installed|\d+\.x|\d+(\.\d+){0,2})$/;
472
+
473
+ function validatePHPVersionInput(version: string, source: string): string {
474
+ if (!VERSION_INPUT_REGEX.test(version)) {
475
+ throw new Error(
476
+ `Invalid PHP version in ${source}: ${version.slice(0, 20)}`
477
+ );
478
+ }
479
+ return version;
480
+ }
481
+
435
482
  /**
436
483
  * Read php version from input or file
437
484
  */
438
485
  export async function readPHPVersion(): Promise<string> {
439
486
  const version = await getInput('php-version', false);
440
487
  if (version) {
441
- return version;
488
+ return validatePHPVersionInput(version, 'php-version input');
442
489
  }
443
490
  const versionFile =
444
491
  (await getInput('php-version-file', false)) || '.php-version';
445
492
  if (fs.existsSync(versionFile)) {
446
493
  const contents: string = fs.readFileSync(versionFile, 'utf8');
447
- const match: RegExpMatchArray | null = contents.match(
448
- /^(?:php\s)?(\d+\.\d+\.\d+)$/m
494
+ const match = contents.match(/^(?:php\s)?(\d+\.\d+\.\d+)$/m);
495
+ return validatePHPVersionInput(
496
+ match ? match[1] : contents.trim(),
497
+ versionFile
449
498
  );
450
- return match ? match[1] : contents.trim();
451
499
  } else if (versionFile !== '.php-version') {
452
500
  throw new Error(`Could not find '${versionFile}' file.`);
453
501
  }
@@ -457,11 +505,11 @@ export async function readPHPVersion(): Promise<string> {
457
505
  if (fs.existsSync(composerLock)) {
458
506
  const lockFileContents = JSON.parse(fs.readFileSync(composerLock, 'utf8'));
459
507
  /* istanbul ignore next */
460
- if (
461
- lockFileContents['platform-overrides'] &&
462
- lockFileContents['platform-overrides']['php']
463
- ) {
464
- return lockFileContents['platform-overrides']['php'];
508
+ if (lockFileContents['platform-overrides']?.['php']) {
509
+ return validatePHPVersionInput(
510
+ lockFileContents['platform-overrides']['php'],
511
+ 'composer.lock platform-overrides.php'
512
+ );
465
513
  }
466
514
  }
467
515
 
@@ -471,12 +519,11 @@ export async function readPHPVersion(): Promise<string> {
471
519
  fs.readFileSync(composerJson, 'utf8')
472
520
  );
473
521
  /* istanbul ignore next */
474
- if (
475
- composerFileContents['config'] &&
476
- composerFileContents['config']['platform'] &&
477
- composerFileContents['config']['platform']['php']
478
- ) {
479
- return composerFileContents['config']['platform']['php'];
522
+ if (composerFileContents['config']?.['platform']?.['php']) {
523
+ return validatePHPVersionInput(
524
+ composerFileContents['config']['platform']['php'],
525
+ 'composer.json config.platform.php'
526
+ );
480
527
  }
481
528
  }
482
529