Correct Aphlict websocket URI construction after PHP8 compatibility changes
[phabricator.git] / src / applications / diffusion / protocol / DiffusionMercurialCommandEngine.php
blobdc898f81d4f08ff980521d303ec233121a60886a
1 <?php
3 final class DiffusionMercurialCommandEngine
4 extends DiffusionCommandEngine {
6 protected function canBuildForRepository(
7 PhabricatorRepository $repository) {
8 return $repository->isHg();
11 protected function newFormattedCommand($pattern, array $argv) {
12 $args = array();
14 // Crudely blacklist commands which look like they may contain command
15 // injection via "--config" or "--debugger". See T13012. To do this, we
16 // print the whole command, parse it using shell rules, then examine each
17 // argument to see if it looks like "--config" or "--debugger".
19 $test_command = call_user_func_array(
20 'csprintf',
21 array_merge(array($pattern), $argv));
22 $test_args = id(new PhutilShellLexer())
23 ->splitArguments($test_command);
25 foreach ($test_args as $test_arg) {
26 if (preg_match('/^--(config|debugger)/i', $test_arg)) {
27 throw new DiffusionMercurialFlagInjectionException(
28 pht(
29 'Mercurial command appears to contain unsafe injected "--config" '.
30 'or "--debugger": %s',
31 $test_command));
35 // NOTE: Here, and in Git and Subversion, we override the SSH command even
36 // if the repository does not use an SSH remote, since our SSH wrapper
37 // defuses an attack against older versions of Mercurial, Git and
38 // Subversion (see T12961) and it's possible to execute this attack
39 // in indirect ways, like by using an SSH subrepo inside an HTTP repo.
41 $pattern = "hg --config ui.ssh=%s {$pattern}";
42 $args[] = $this->getSSHWrapper();
44 return array($pattern, array_merge($args, $argv));
47 protected function newCustomEnvironment() {
48 $env = array();
50 // NOTE: This overrides certain configuration, extensions, and settings
51 // which make Mercurial commands do random unusual things.
52 $env['HGPLAIN'] = 1;
54 return $env;
57 /**
58 * Sanitize output of an `hg` command invoked with the `--debug` flag to make
59 * it usable.
61 * @param string Output from `hg --debug ...`
62 * @return string Usable output.
64 public static function filterMercurialDebugOutput($stdout) {
65 // When hg commands are run with `--debug` and some config file isn't
66 // trusted, Mercurial prints out a warning to stdout, twice, after Feb 2011.
68 // http://selenic.com/pipermail/mercurial-devel/2011-February/028541.html
70 // After Jan 2015, it may also fail to write to a revision branch cache.
72 // Separately, it may fail to write to a different branch cache, and may
73 // encounter issues reading the branch cache.
75 // When Mercurial repositories are hosted on external systems with
76 // multi-user environments it's possible that the branch cache is computed
77 // on a revision which does not end up being published. When this happens it
78 // will recompute the cache but also print out "invalid branch cache".
80 // https://www.mercurial-scm.org/pipermail/mercurial/2014-June/047239.html
82 // When observing a repository which uses largefiles, the debug output may
83 // also contain extraneous output about largefile changes.
85 // At some point Mercurial added/improved support for pager used when
86 // command output is large. It includes printing out debug information that
87 // the pager is being started for a command. This seems to happen despite
88 // the output of the command being piped/read from another process.
90 // When printing color output Mercurial may run into some issue with the
91 // terminal info. This should never happen in Phabricator since color
92 // output should be turned off, however in the event it shows up we should
93 // filter it out anyways.
95 $ignore = array(
96 'ignoring untrusted configuration option',
97 "couldn't write revision branch cache:",
98 "couldn't write branch cache:",
99 'invalid branchheads cache',
100 'invalid branch cache',
101 'updated patterns: .hglf',
102 'starting pager for command',
103 'no terminfo entry for',
106 foreach ($ignore as $key => $pattern) {
107 $ignore[$key] = preg_quote($pattern, '/');
110 $ignore = '('.implode('|', $ignore).')';
112 $lines = preg_split('/(?<=\n)/', $stdout);
113 $regex = '/'.$ignore.'.*\n$/';
115 foreach ($lines as $key => $line) {
116 $lines[$key] = preg_replace($regex, '', $line);
119 return implode('', $lines);