summaryrefslogtreecommitdiff
path: root/www/wiki/tests/integration/includes/shell/FirejailCommandTest.php
blob: 1e008ee2797269783270a95f7e38dfab61e4fab5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
<?php

use MediaWiki\Shell\FirejailCommand;
use MediaWiki\Shell\Shell;

/**
 * Integration tests to ensure that firejail actually prevents execution.
 * Meant to run on vagrant, although will probably work on other setups
 * as long as firejail and sudo has similar config.
 *
 * @group large
 * @group Shell
 * @covers FirejailCommand
 */
class FirejailCommandIntegrationTest extends PHPUnit\Framework\TestCase {

	public function setUp() {
		parent::setUp();
		if ( Shell::command( 'which', 'firejail' )->execute()->getExitCode() ) {
			$this->markTestSkipped( 'firejail not installed' );
		} elseif ( wfIsWindows() ) {
			$this->markTestSkipped( 'test supports POSIX environments only' );
		}
	}

	public function testSanity() {
		// Make sure that firejail works at all.
		$command = new FirejailCommand( 'firejail' );
		$command
			->unsafeParams( 'ls .' )
			->restrict( Shell::RESTRICT_DEFAULT );
		$result = $command->execute();
		$this->assertSame( 0, $result->getExitCode() );
	}

	/**
	 * @coversNothing
	 * @dataProvider provideExecute
	 */
	public function testExecute( $testCommand, $flag ) {
		if ( preg_match( '/^sudo /', $testCommand ) ) {
			if ( Shell::command( 'sudo', '-n', 'ls', '/' )->execute()->getExitCode() ) {
				$this->markTestSkipped( 'need passwordless sudo' );
			}
		}

		$command = new FirejailCommand( 'firejail' );
		$command
			->unsafeParams( $testCommand )
			// If we don't restrict at all, firejail won't be invoked,
			// so the test will give a false positive if firejail breaks
			// the command for some non-flag-related reason. Instead,
			// set some flag that won't get in the way.
			->restrict( $flag === Shell::NO_NETWORK ? Shell::PRIVATE_DEV : Shell::NO_NETWORK );
		$result = $command->execute();
		$this->assertSame( 0, $result->getExitCode(), 'sanity check' );

		$command = new FirejailCommand( 'firejail' );
		$command
			->unsafeParams( $testCommand )
			->restrict( $flag );
		$result = $command->execute();
		$this->assertNotSame( 0, $result->getExitCode(), 'real check' );
	}

	public function provideExecute() {
		global $IP;
		return [
			[ 'sudo -n ls /', Shell::NO_ROOT ],
			[ 'sudo -n ls /', Shell::SECCOMP ], // not a great test but seems to work
			[ 'ls /dev/cpu', Shell::PRIVATE_DEV ],
			[ 'curl -fsSo /dev/null https://wikipedia.org/', Shell::NO_NETWORK ],
			[ 'exec ls /', Shell::NO_EXECVE ],
			[ "cat $IP/LocalSettings.php", Shell::NO_LOCALSETTINGS ],
		];
	}

}