def test_avatarAdaptsToRestrictedExecOnlySession(self): # When Conch tries to adapt the SSH server avatar to ISession, it # adapts to a RestrictedExecOnlySession. This means that a # RestrictedExecOnlySession handles any requests to execute a command. session = ISession(self.avatar) self.assertTrue( isinstance(session, RestrictedExecOnlySession), "ISession(avatar) doesn't adapt to ExecOnlySession. " "Got %r instead." % (session, )) self.assertEqual(get_BZR_PLUGIN_PATH_for_subprocess(), session.environment['BZR_PLUGIN_PATH']) self.assertEqual('*****@*****.**' % self.avatar.username, session.environment['BZR_EMAIL']) executable, arguments = session.getCommandToRun( 'bzr serve --inet --directory=/ --allow-writes') interpreter = '%s/bin/py' % config.root self.assertEqual(interpreter, executable) self.assertEqual([ interpreter, get_bzr_path(), 'lp-serve', '--inet', str(self.avatar.user_id) ], list(arguments)) self.assertRaises(ForbiddenCommand, session.getCommandToRun, 'rm -rf /')
def test_avatarAdaptsToRestrictedExecOnlySession(self): # When Conch tries to adapt the SSH server avatar to ISession, it # adapts to a RestrictedExecOnlySession. This means that a # RestrictedExecOnlySession handles any requests to execute a command. session = ISession(self.avatar) self.failUnless( isinstance(session, RestrictedExecOnlySession), "ISession(avatar) doesn't adapt to ExecOnlySession. " "Got %r instead." % (session,)) self.assertEqual( get_BZR_PLUGIN_PATH_for_subprocess(), session.environment['BZR_PLUGIN_PATH']) self.assertEqual( '*****@*****.**' % self.avatar.username, session.environment['BZR_EMAIL']) executable, arguments = session.getCommandToRun( 'bzr serve --inet --directory=/ --allow-writes') interpreter = '%s/bin/py' % config.root self.assertEqual(interpreter, executable) self.assertEqual( [interpreter, get_bzr_path(), 'lp-serve', '--inet', str(self.avatar.user_id)], list(arguments)) self.assertRaises( ForbiddenCommand, session.getCommandToRun, 'rm -rf /')
def setUp(self): bzr_path = get_bzr_path() BZR_PLUGIN_PATH = get_BZR_PLUGIN_PATH_for_subprocess() env = os.environ.copy() env['BZR_PLUGIN_PATH'] = BZR_PLUGIN_PATH # TODO: We probably want to use a random disk path for # forking_daemon_socket, but we need to update config so that # the CodeHosting service can find it. # The main problem is that CodeHostingTac seems to start a tac # server directly from the disk configs, and doesn't use the # in-memory config. So we can't just override the memory # settings, we have to somehow pass it a new config-on-disk to # use. self.socket_path = config.codehosting.forking_daemon_socket command = [ sys.executable, bzr_path, 'launchpad-forking-service', '--path', self.socket_path, '-Derror' ] process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env) self.process = process stderr = [] # The first line should be "Preloading" indicating it is ready stderr.append(process.stderr.readline()) # The next line is the "Listening on socket" line stderr.append(process.stderr.readline()) # Now it should be ready. If there were any errors, let's check, and # report them. if (process.poll() is not None or not stderr[1].strip().startswith('Listening on socket')): if process.poll() is None: time.sleep(1) # Give the traceback a chance to render. os.kill(process.pid, signal.SIGTERM) process.wait() self.process = None # Looks like there was a problem. We cannot use the "addDetail" # method because this class is not a TestCase and does not have # access to one. It runs as part of a layer. A "print" is the # best we can do. That should still be visible on buildbot, which # is where we have seen spurious failures so far. print print "stdout:" print process.stdout.read() print "-" * 70 print "stderr:" print ''.join(stderr) print process.stderr.read() print "-" * 70 raise RuntimeError( 'Bzr server did not start correctly. See stdout and stderr ' 'reported above. Command was "%s". PYTHONPATH was "%s". ' 'BZR_PLUGIN_PATH was "%s".' % (' '.join(command), env.get('PYTHONPATH'), env.get('BZR_PLUGIN_PATH')))
def setUp(self): bzr_path = get_bzr_path() BZR_PLUGIN_PATH = get_BZR_PLUGIN_PATH_for_subprocess() env = os.environ.copy() env['BZR_PLUGIN_PATH'] = BZR_PLUGIN_PATH # TODO: We probably want to use a random disk path for # forking_daemon_socket, but we need to update config so that # the CodeHosting service can find it. # The main problem is that CodeHostingTac seems to start a tac # server directly from the disk configs, and doesn't use the # in-memory config. So we can't just override the memory # settings, we have to somehow pass it a new config-on-disk to # use. self.socket_path = config.codehosting.forking_daemon_socket command = [sys.executable, bzr_path, 'launchpad-forking-service', '--path', self.socket_path, '-Derror'] process = subprocess.Popen( command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env) self.process = process stderr = [] # The first line should be "Preloading" indicating it is ready stderr.append(process.stderr.readline()) # The next line is the "Listening on socket" line stderr.append(process.stderr.readline()) # Now it should be ready. If there were any errors, let's check, and # report them. if (process.poll() is not None or not stderr[1].strip().startswith('Listening on socket')): if process.poll() is None: time.sleep(1) # Give the traceback a chance to render. os.kill(process.pid, signal.SIGTERM) process.wait() self.process = None # Looks like there was a problem. We cannot use the "addDetail" # method because this class is not a TestCase and does not have # access to one. It runs as part of a layer. A "print" is the # best we can do. That should still be visible on buildbot, which # is where we have seen spurious failures so far. print print "stdout:" print process.stdout.read() print "-" * 70 print "stderr:" print ''.join(stderr) print process.stderr.read() print "-" * 70 raise RuntimeError( 'Bzr server did not start correctly. See stdout and stderr ' 'reported above. Command was "%s". PYTHONPATH was "%s". ' 'BZR_PLUGIN_PATH was "%s".' % (' '.join(command), env.get('PYTHONPATH'), env.get('BZR_PLUGIN_PATH')))
def _run_bzr(self, args, retcode=0): """Call run_bzr_subprocess with some common options. We always want to force the subprocess to do its ssh communication with paramiko (because OpenSSH doesn't respect the $HOME environment variable) and we want to load the plugins that are in rocketfuel (mainly so we can test the loom support). """ return self.run_bzr_subprocess( args, env_changes={ 'BZR_SSH': 'paramiko', 'BZR_PLUGIN_PATH': get_BZR_PLUGIN_PATH_for_subprocess() }, allow_plugins=True, retcode=retcode)
def start_bzr_subprocess(self, process_args, env_changes=None, working_dir=None): """Start bzr in a subprocess for testing. Copied and modified from `bzrlib.tests.TestCase.start_bzr_subprocess`. This version removes some of the skipping stuff, some of the irrelevant comments (e.g. about win32) and uses Launchpad's own mechanisms for getting the path to 'bzr'. Comments starting with 'LAUNCHPAD' are comments about our modifications. """ if env_changes is None: env_changes = {} env_changes['BZR_PLUGIN_PATH'] = get_BZR_PLUGIN_PATH_for_subprocess() old_env = {} def cleanup_environment(): for env_var, value in env_changes.iteritems(): old_env[env_var] = osutils.set_or_unset_env(env_var, value) def restore_environment(): for env_var, value in old_env.iteritems(): osutils.set_or_unset_env(env_var, value) cwd = None if working_dir is not None: cwd = osutils.getcwd() os.chdir(working_dir) # LAUNCHPAD: Because of buildout, we need to get a custom Python # binary, not sys.executable. python_path = self.get_python_path() # LAUNCHPAD: We can't use self.get_bzr_path(), since it'll find # lib/bzrlib, rather than the path to sourcecode/bzr/bzr. bzr_path = get_bzr_path() try: cleanup_environment() command = [python_path, bzr_path] command.extend(process_args) process = self._popen( command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) finally: restore_environment() if cwd is not None: os.chdir(cwd) return process