Beispiel #1
0
    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')))
Beispiel #5
0
    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)
Beispiel #6
0
    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