mirror of
https://github.com/freedombox/FreedomBox.git
synced 2026-09-19 04:59:01 +00:00
gitweb: Don't use privileged action feature to run as different user
- Instead implement running specific commands inside the privileged action as a specific user. Tests: - Gitweb functional tests and unit tests work. - Running various operations such as clone, create, set branch, rename, etc. all result in repositories (and all their contents) owned by www-data:www-data. Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org> Reviewed-by: Joseph Nuthalapati <njoseph@riseup.net>
This commit is contained in:
parent
7a4fb9d9f6
commit
87331e7c97
@ -6,6 +6,7 @@ pytest configuration for all tests.
|
|||||||
import importlib
|
import importlib
|
||||||
import os
|
import os
|
||||||
import pathlib
|
import pathlib
|
||||||
|
import subprocess
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
@ -191,6 +192,18 @@ def fixture_mock_privileged(request):
|
|||||||
module.__dict__[name] = wrapper
|
module.__dict__[name] = wrapper
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(name='mock_run_as_user')
|
||||||
|
def fixture_mock_run_as_user():
|
||||||
|
"""A fixture to override action_utils.run_as_user."""
|
||||||
|
|
||||||
|
def _bypass_runuser(*args, username, **kwargs):
|
||||||
|
return subprocess.run(*args, **kwargs)
|
||||||
|
|
||||||
|
with patch('plinth.action_utils.run_as_user') as mock:
|
||||||
|
mock.side_effect = _bypass_runuser
|
||||||
|
yield
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name='splinter_screenshot_dir', scope='session')
|
@pytest.fixture(name='splinter_screenshot_dir', scope='session')
|
||||||
def fixture_splinter_screenshot_dir(request):
|
def fixture_splinter_screenshot_dir(request):
|
||||||
"""Set default screenshot directory to ./screenshots.
|
"""Set default screenshot directory to ./screenshots.
|
||||||
|
|||||||
@ -14,7 +14,7 @@ from plinth.package import Packages
|
|||||||
|
|
||||||
from . import manifest, privileged
|
from . import manifest, privileged
|
||||||
from .forms import is_repo_url
|
from .forms import is_repo_url
|
||||||
from .manifest import GIT_REPO_PATH, REPO_DIR_OWNER
|
from .manifest import GIT_REPO_PATH
|
||||||
|
|
||||||
_description = [
|
_description = [
|
||||||
_('Git is a distributed version-control system for tracking changes in '
|
_('Git is a distributed version-control system for tracking changes in '
|
||||||
@ -217,7 +217,7 @@ def get_repo_list():
|
|||||||
|
|
||||||
def repo_info(repo):
|
def repo_info(repo):
|
||||||
"""Get information about repository."""
|
"""Get information about repository."""
|
||||||
info = privileged.repo_info(repo, _run_as_user=REPO_DIR_OWNER)
|
info = privileged.repo_info(repo)
|
||||||
if info['access'] == 'private':
|
if info['access'] == 'private':
|
||||||
info['is_private'] = True
|
info['is_private'] = True
|
||||||
else:
|
else:
|
||||||
@ -248,5 +248,4 @@ def edit_repo(form_initial, form_cleaned):
|
|||||||
privileged.set_repo_access(repo, 'public')
|
privileged.set_repo_access(repo, 'public')
|
||||||
|
|
||||||
if form_cleaned['default_branch'] != form_initial['default_branch']:
|
if form_cleaned['default_branch'] != form_initial['default_branch']:
|
||||||
privileged.set_default_branch(repo, form_cleaned['default_branch'],
|
privileged.set_default_branch(repo, form_cleaned['default_branch'])
|
||||||
_run_as_user=REPO_DIR_OWNER)
|
|
||||||
|
|||||||
@ -14,12 +14,11 @@ from django.utils.translation import gettext_lazy as _
|
|||||||
from plinth.modules import gitweb
|
from plinth.modules import gitweb
|
||||||
|
|
||||||
from . import privileged
|
from . import privileged
|
||||||
from .manifest import REPO_DIR_OWNER
|
|
||||||
|
|
||||||
|
|
||||||
def _get_branches(repo):
|
def _get_branches(repo):
|
||||||
"""Get all the branches in the repository."""
|
"""Get all the branches in the repository."""
|
||||||
branch_data = privileged.get_branches(repo, _run_as_user=REPO_DIR_OWNER)
|
branch_data = privileged.get_branches(repo)
|
||||||
default_branch = branch_data['default_branch']
|
default_branch = branch_data['default_branch']
|
||||||
branches = branch_data['branches']
|
branches = branch_data['branches']
|
||||||
|
|
||||||
|
|||||||
@ -199,9 +199,11 @@ def _get_default_branch(repo):
|
|||||||
"""Get default branch of the repository."""
|
"""Get default branch of the repository."""
|
||||||
repo_path = GIT_REPO_PATH / repo
|
repo_path = GIT_REPO_PATH / repo
|
||||||
|
|
||||||
return subprocess.check_output(
|
return action_utils.run_as_user(
|
||||||
['git', '-C',
|
['git', '-C',
|
||||||
str(repo_path), 'symbolic-ref', '--short', 'HEAD']).decode().strip()
|
str(repo_path), 'symbolic-ref', '--short', 'HEAD'],
|
||||||
|
username=REPO_DIR_OWNER, check=True,
|
||||||
|
stdout=subprocess.PIPE).stdout.decode().strip()
|
||||||
|
|
||||||
|
|
||||||
def _get_repo_description(repo):
|
def _get_repo_description(repo):
|
||||||
@ -267,11 +269,12 @@ def _set_access_status(repo, status):
|
|||||||
|
|
||||||
def _get_branches(repo):
|
def _get_branches(repo):
|
||||||
"""Return list of the branches in the repository."""
|
"""Return list of the branches in the repository."""
|
||||||
output = subprocess.check_output(
|
process = action_utils.run_as_user(
|
||||||
['git', '-C', repo, 'branch', '--format=%(refname:short)'],
|
['git', '-C', repo, 'branch', '--format=%(refname:short)'],
|
||||||
cwd=GIT_REPO_PATH)
|
cwd=GIT_REPO_PATH, username=REPO_DIR_OWNER, check=True,
|
||||||
|
stdout=subprocess.PIPE)
|
||||||
|
|
||||||
return output.decode().strip().split()
|
return process.stdout.decode().strip().split()
|
||||||
|
|
||||||
|
|
||||||
@privileged
|
@privileged
|
||||||
@ -299,10 +302,9 @@ def set_default_branch(name: str, branch: str):
|
|||||||
if branch not in _get_branches(repo):
|
if branch not in _get_branches(repo):
|
||||||
raise ValueError('No such branch')
|
raise ValueError('No such branch')
|
||||||
|
|
||||||
subprocess.check_call([
|
action_utils.run_as_user(
|
||||||
'git', '-C', repo, 'symbolic-ref', 'HEAD',
|
['git', '-C', repo, 'symbolic-ref', 'HEAD', f'refs/heads/{branch}'],
|
||||||
"refs/heads/{}".format(branch)
|
cwd=GIT_REPO_PATH, check=True, username=REPO_DIR_OWNER)
|
||||||
], cwd=GIT_REPO_PATH)
|
|
||||||
|
|
||||||
|
|
||||||
@privileged
|
@privileged
|
||||||
|
|||||||
@ -16,16 +16,16 @@ REPO_DATA = {
|
|||||||
'access': 'private',
|
'access': 'private',
|
||||||
}
|
}
|
||||||
|
|
||||||
pytestmark = pytest.mark.usefixtures('mock_privileged')
|
pytestmark = pytest.mark.usefixtures('mock_privileged', 'mock_run_as_user')
|
||||||
privileged_modules_to_mock = ['plinth.modules.gitweb.privileged']
|
privileged_modules_to_mock = ['plinth.modules.gitweb.privileged']
|
||||||
git_installed = pytest.mark.skipif(not pathlib.Path('/usr/bin/git').exists(),
|
git_installed = pytest.mark.skipif(not pathlib.Path('/usr/bin/git').exists(),
|
||||||
reason='git is not installed')
|
reason='git is not installed')
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(autouse=True)
|
@pytest.fixture(autouse=True)
|
||||||
def fixture_set_repo_path(tmpdir):
|
def fixture_set_repo_path(tmp_path):
|
||||||
"""Set a repository path in the actions module."""
|
"""Set a repository path in the actions module."""
|
||||||
privileged.GIT_REPO_PATH = tmpdir
|
privileged.GIT_REPO_PATH = tmp_path
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name='existing_repo')
|
@pytest.fixture(name='existing_repo')
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user