Commit 2ec389b9 authored by Tom Pillot's avatar Tom Pillot
Browse files

Prevent token leaking in tests, cleanup previous tests before running the tests

parent 2e681c41
Pipeline #10499 passed with stage
in 1 minute and 17 seconds
......@@ -37,4 +37,4 @@ ADD . .
CMD while ! nc -z postgres 5432; do sleep 1; done \
&& ./manage.py migrate \
&& ./manage.py collectstatic --no-input \
# && gunicorn --bind 0.0.0.0 dashboard.wsgi
&& gunicorn --bind 0.0.0.0 dashboard.wsgi
import hmac
import re
import git
from hashlib import sha1
from os import getenv
......@@ -11,6 +14,18 @@ from django.utils.encoding import force_bytes
from rainboard.models import Project, Namespace, Forge
def redact_token(func):
"""Decorator used to prevent git from leaking tokens in exception messages."""
def wrapped_function(*args, **kwargs):
try:
return func(*args, **kwargs)
except git.GitCommandError as e:
e.stderr = re.sub(r'://.*@', '://[REDACTED]@', e.stderr)
raise e
return wrapped_function
class GhTests(TestCase):
@classmethod
def setUpClass(cls):
......@@ -33,12 +48,29 @@ class GhTests(TestCase):
cls.github = cls.project.github()
cls.gitlab = cls.project.gitlab()
# Cleanup previous test
for pr in cls.github.get_pulls(state="open"):
pr.edit(state="closed")
gh_branches = [b.name for b in cls.github.get_branches()]
gl_branches = [b.name for b in cls.gitlab.branches.list()]
for branch_name in gl_branches:
if branch_name.startswith('pr/'):
cls.gitlab.branches.delete(branch_name)
for branch_name in ['test-branch-gitlab', 'test-branch-github']:
if branch_name in gh_branches:
cls.github.get_git_ref(f'heads/{branch_name}').delete()
if branch_name in gl_branches:
cls.gitlab.branches.delete(branch_name)
def assertSync(self, branch):
"""Raise an exception if the branch is not synced between both repos."""
last_commit_github = self.github.get_branch(branch).commit.sha
last_commit_gitlab = self.gitlab.commits.list(ref_name=branch)[0].id
self.assertEqual(last_commit_github, last_commit_gitlab)
@redact_token
def sync(self):
"""Force both repos to be synced."""
for branch in ('master', 'devel'):
......@@ -63,13 +95,14 @@ class GhTests(TestCase):
self.assertSync(branch)
@redact_token
def gh_webhook_event(self, event, last_commit='', branch='master', pr_action='', pr_number='', pr_login=''):
"""Simulate receiving an event from a github webhook."""
data = {
'repository': {
'name': self.project.slug,
'owner': {
'name': self.namespace.slug_github
'login': self.namespace.slug_github
}
},
'ref': f'refs/heads/{branch}',
......@@ -100,6 +133,7 @@ class GhTests(TestCase):
HTTP_X_HUB_SIGNATURE=signature,
HTTP_X_GITHUB_EVENT=event)
@redact_token
def gl_webhook_event(self, event, last_commit='', branch='master', status=''):
"""Simulate receiving an event from a gitlab webhook."""
data = {
......@@ -108,7 +142,7 @@ class GhTests(TestCase):
},
'project': {
'name': self.project.slug,
'namespace': self.namespace.slug_gitlab
'path_with_namespace': f'{self.namespace.slug_gitlab}/{self.project.slug}'
},
'ref': f'refs/heads/{branch}',
'after': last_commit,
......@@ -217,7 +251,6 @@ class GhTests(TestCase):
def push_gitlab(self, branch):
"""Test sync after pushing to the given branch on gitlab."""
self.sync()
git_repo = self.project.git()
last_commit = self.gitlab.commits.list(ref_name=branch)[0].id
# Push a new commit to gitlab
......
......@@ -41,7 +41,7 @@ def pull_request(request: HttpRequest, rep: str) -> HttpResponse:
branch = f'pr/{data["number"]}'
login = slugify(data["pull_request"]["head"]["repo"]["owner"]["login"])
namespace = get_object_or_404(Namespace, slug_github=slugify(data['repository']['owner']['name']))
namespace = get_object_or_404(Namespace, slug_github=slugify(data['repository']['owner']['login']))
project = get_object_or_404(Project, main_namespace=namespace, slug=slugify(data['repository']['name']))
git_repo = project.git()
logger.debug(f'{namespace.slug}/{project.slug}: Pull request on {branch}: {event}')
......@@ -103,9 +103,10 @@ def push(request: HttpRequest, source: SOURCES, rep: str) -> HttpResponse:
data = loads(request.body.decode())
if source == SOURCES.gitlab:
namespace = get_object_or_404(Namespace, slug_gitlab=slugify(data['project']['namespace']))
namespace = get_object_or_404(Namespace,
slug_gitlab=slugify(data['project']['path_with_namespace'].split('/')[0]))
else:
namespace = get_object_or_404(Namespace, slug_github=slugify(data['repository']['owner']['name']))
namespace = get_object_or_404(Namespace, slug_github=slugify(data['repository']['owner']['login']))
project = get_object_or_404(Project, main_namespace=namespace, slug=slugify(data['repository']['name']))
......@@ -173,7 +174,6 @@ def push(request: HttpRequest, source: SOURCES, rep: str) -> HttpResponse:
message = traceback.format_exc()
message = re.sub(r'://.*@', '://[REDACTED]@', message) # Hide access tokens in the mail
mail_admins(f'Forge sync failed for {namespace.slug}/{project.slug}', message)
raise
return HttpResponse(rep)
......@@ -182,7 +182,7 @@ def pipeline(request: HttpRequest, rep: str) -> HttpResponse:
"""Something happened on a Gitlab pipeline. Tell Github if necessary."""
data = loads(request.body.decode())
branch, commit, gl_status, pipeline_id = (data['object_attributes'][key] for key in ['ref', 'sha', 'status', 'id'])
namespace = get_object_or_404(Namespace, slug_gitlab=slugify(data['project']['namespace']))
namespace = get_object_or_404(Namespace, slug_gitlab=slugify(data['project']['path_with_namespace'].split('/')[0]))
project = get_object_or_404(Project, main_namespace=namespace, slug=slugify(data['project']['name']))
gh_repo = project.github()
ci_web_url = project.url_gitlab() + '/pipelines/' + str(pipeline_id)
......
......@@ -5,7 +5,7 @@ from django.db import migrations
def add_namespace(apps, schema_editor):
Namespace = apps.get_model('rainboard', 'Namespace')
Namespace.objects.create(name='tpillot', slug_gitlab='tpillot', slug_github='Ozon2')
Namespace.objects.create(name='tpillot', slug_gitlab='tpillot', slug_github='ozon2')
def add_project(apps, schema_editor):
......@@ -41,6 +41,6 @@ class Migration(migrations.Migration):
]
operations = [
# migrations.RunPython(add_namespace),
# migrations.RunPython(add_project),
migrations.RunPython(add_namespace),
migrations.RunPython(add_project),
]
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment