def test_get_dsn_with_port(self): key = ProjectKey(project_id=1, public_key='public', secret_key='secret') with self.options({'system.url-prefix': 'http://example.com:81'}): self.assertEquals(key.get_dsn(), 'http://*****:*****@example.com:81/1')
def test_get_dsn_with_endpoint_setting(self): key = ProjectKey(project_id=1, public_key="public", secret_key="secret") with self.settings(SENTRY_ENDPOINT="http://endpoint.com"): self.assertEquals(key.get_dsn(), "http://*****:*****@endpoint.com/1")
def test_get_dsn_with_port(self): key = ProjectKey(project_id=1, public_key='public', secret_key='secret') with self.settings(SENTRY_URL_PREFIX='http://example.com:81'): self.assertEquals(key.get_dsn(), 'http://*****:*****@example.com:81/1')
def test_get_dsn_with_endpoint_setting(self): key = ProjectKey(project_id=1, public_key='public', secret_key='secret') with self.settings(SENTRY_ENDPOINT='http://endpoint.com'): self.assertEquals(key.get_dsn(), 'http://*****:*****@endpoint.com/1')
def test_get_dsn_with_port(self): key = ProjectKey(project_id=1, public_key="public", secret_key="secret") with self.options({"system.url-prefix": "http://example.com:81"}): self.assertEquals(key.get_dsn(), "http://*****:*****@example.com:81/1")
def test_get_dsn_with_public_endpoint_setting(self): key = ProjectKey(project_id=1, public_key="public", secret_key="secret") with self.settings( SENTRY_PUBLIC_ENDPOINT="http://public_endpoint.com"): self.assertEqual(key.get_dsn(public=True), "http://public@public_endpoint.com/1")
def test_projectkeys(default_project, task_runner, redis_cache): with task_runner(): deleted_pks = list(ProjectKey.objects.filter(project=default_project)) for key in deleted_pks: key.delete() pk = ProjectKey(project=default_project) pk.save() for key in deleted_pks: # XXX: Ideally we would write `{"disabled": True}` into Redis, however # it's fine if we don't and instead Relay starts hitting the endpoint # which will write this for us. assert not redis_cache.get(key.public_key) (pk_json, ) = redis_cache.get(pk.public_key)["publicKeys"] assert pk_json["publicKey"] == pk.public_key with task_runner(): pk.status = ProjectKeyStatus.INACTIVE pk.save() assert redis_cache.get(pk.public_key)["disabled"] with task_runner(): pk.delete() assert not redis_cache.get(pk.public_key) for key in ProjectKey.objects.filter(project_id=default_project.id): assert not redis_cache.get(key.public_key)
def forwards(self, orm): from sentry.models import ProjectKey for project in orm['sentry.Project'].objects.all(): if orm['sentry.ProjectKey'].objects.filter(project=project, user=None).exists(): continue orm['sentry.ProjectKey'].objects.create( project=project, public_key=ProjectKey.generate_api_key(), secret_key=ProjectKey.generate_api_key(), )
def project_key_from_auth(self, auth): if not auth.public_key: raise APIUnauthorized('Invalid api key') # Make sure the key even looks valid first, since it's # possible to get some garbage input here causing further # issues trying to query it from cache or the database. if not ProjectKey.looks_like_api_key(auth.public_key): raise APIUnauthorized('Invalid api key') try: pk = ProjectKey.objects.get_from_cache(public_key=auth.public_key) except ProjectKey.DoesNotExist: raise APIUnauthorized('Invalid api key') # a secret key may not be present which will be validated elsewhere if not constant_time_compare(pk.secret_key, auth.secret_key or pk.secret_key): raise APIUnauthorized('Invalid api key') if not pk.is_active: raise APIUnauthorized('API key is disabled') if not pk.roles.store: raise APIUnauthorized('Key does not allow event storage access') return pk
def update_organization_config(self, data): # data = {"project_mappings": [[sentry_project_id, vercel_project_id]]} vercel_client = self.get_client() config = self.org_integration.config new_mappings = data["project_mappings"] old_mappings = config.get("project_mappings") or [] for mapping in new_mappings: # skip any mappings that already exist if mapping in old_mappings: continue [sentry_project_id, vercel_project_id] = mapping sentry_project = Project.objects.get(id=sentry_project_id) enabled_dsn = ProjectKey.get_default(project=sentry_project) if not enabled_dsn: raise IntegrationError("You must have an enabled DSN to continue!") source_code_provider = self.get_source_code_provider(vercel_client, vercel_project_id) if not source_code_provider: raise IntegrationError( "You must connect your Vercel project to a Git repository to continue!" ) sentry_project_dsn = enabled_dsn.get_dsn(public=True) uuid = uuid4().hex sentry_app_installation = SentryAppInstallationForProvider.objects.get( organization=sentry_project.organization.id, provider="vercel" ) sentry_auth_token = sentry_app_installation.get_token( self.organization_id, provider="vercel" ) secret_names = [ "SENTRY_ORG_%s" % uuid, "SENTRY_PROJECT_%s" % uuid, "NEXT_PUBLIC_SENTRY_DSN_%s" % uuid, "SENTRY_AUTH_TOKEN_%s" % uuid, ] values = [ sentry_project.organization.slug, sentry_project.slug, sentry_project_dsn, sentry_auth_token, ] env_var_names = [ "SENTRY_ORG", "SENTRY_PROJECT", "NEXT_PUBLIC_SENTRY_DSN", "SENTRY_AUTH_TOKEN", "VERCEL_%s_COMMIT_SHA" % source_code_provider.upper(), ] secrets = [] for name, val in zip(secret_names, values): secrets.append(self.create_secret(vercel_client, vercel_project_id, name, val)) secrets.append("") for secret, env_var in zip(secrets, env_var_names): self.create_env_var(vercel_client, vercel_project_id, env_var, secret) config.update(data) self.org_integration.update(config=config)
def handle(self, request, organization, team, project, key_id): try: key = ProjectKey.objects.get( id=key_id, project=project, ) except ProjectKey.DoesNotExist(): return self.redirect( reverse('sentry-manage-project-keys', args=[project.organization.slug, project.slug])) data = key.get_audit_log_data() key.delete() AuditLogEntry.objects.create( organization=organization, actor=request.user, ip_address=request.META['REMOTE_ADDR'], target_object=key.id, event=AuditLogEntryEvent.PROJECTKEY_REMOVE, data=data, ) messages.add_message( request, messages.SUCCESS, _('The API key (%s) was revoked.') % (key.public_key, )) return self.redirect( reverse('sentry-manage-project-keys', args=[project.organization.slug, project.slug]))
def project_key(self): from sentry.models import ProjectKey if not settings.SENTRY_PROJECT: return None key = None try: if settings.SENTRY_PROJECT_KEY is not None: key = ProjectKey.objects.get( id=settings.SENTRY_PROJECT_KEY, project=settings.SENTRY_PROJECT, ) else: key = ProjectKey.get_default(settings.SENTRY_PROJECT) except Exception as exc: # if the relation fails to query or is missing completely, lets handle # it gracefully self.error_logger.warn('internal-error.unable-to-fetch-project', extra={ 'project_id': settings.SENTRY_PROJECT, 'project_key': settings.SENTRY_PROJECT_KEY, 'error_message': six.text_type(exc), }) if key is None: self.error_logger.warn('internal-error.no-project-available', extra={ 'project_id': settings.SENTRY_PROJECT, 'project_key': settings.SENTRY_PROJECT_KEY, }) return key
def get_project_key(): from sentry.models import ProjectKey if not settings.SENTRY_PROJECT: return None key = None try: if settings.SENTRY_PROJECT_KEY is not None: key = ProjectKey.objects.get(id=settings.SENTRY_PROJECT_KEY, project=settings.SENTRY_PROJECT) else: key = ProjectKey.get_default(settings.SENTRY_PROJECT) except Exception as exc: # if the relation fails to query or is missing completely, lets handle # it gracefully sdk_logger.warning( "internal-error.unable-to-fetch-project", extra={ "project_id": settings.SENTRY_PROJECT, "project_key": settings.SENTRY_PROJECT_KEY, "error_message": str(exc), }, ) if key is None: sdk_logger.warning( "internal-error.no-project-available", extra={ "project_id": settings.SENTRY_PROJECT, "project_key": settings.SENTRY_PROJECT_KEY, }, ) return key
def _get_project_key(self, request): dsn = request.GET.get('dsn') try: key = ProjectKey.from_dsn(dsn) except ProjectKey.DoesNotExist: return return key
def get_dsn_for_project(organization_id, project_id): try: project = Project.objects.get(organization_id=organization_id, id=project_id) except Project.DoesNotExist: raise IntegrationError("No valid project") enabled_dsn = ProjectKey.get_default(project=project) if not enabled_dsn: raise IntegrationError("Project does not have DSN enabled") return enabled_dsn.get_dsn(public=True)
def test_relay_nonexistent_project(call_endpoint, projectconfig_cache_set, task_runner): wrong_public_key = ProjectKey.generate_api_key() with task_runner(): result, status_code = call_endpoint(full_config=True, public_keys=[wrong_public_key]) assert status_code < 400 assert result == {"configs": {wrong_public_key: {"disabled": True}}} assert projectconfig_cache_set == [{str(wrong_public_key): result["configs"][wrong_public_key]}]
def send(self, **kwargs): # Report the issue to an upstream Sentry if active # NOTE: we don't want to check self.is_enabled() like normal, since # is_enabled behavior is overridden in this class. We explicitly # want to check if the remote is active. if self.remote.is_active(): from sentry import options # Append some extra tags that are useful for remote reporting super_kwargs = copy.deepcopy(kwargs) super_kwargs['tags']['install-id'] = options.get( 'sentry:install-id') super(SentryInternalClient, self).send(**super_kwargs) if not is_current_event_safe(): return # These imports all need to be internal to this function as this class # is set up by django while still parsing LOGGING settings and we # cannot import this stuff until settings are finalized. from sentry.models import ProjectKey from sentry.web.api import StoreView from django.test import RequestFactory key = None if settings.SENTRY_PROJECT_KEY is not None: key = ProjectKey.objects.filter( id=settings.SENTRY_PROJECT_KEY, project=settings.SENTRY_PROJECT).first() if key is None: key = ProjectKey.get_default(settings.SENTRY_PROJECT) if key is None: return client_string = 'raven-python/%s' % (raven.VERSION, ) headers = { 'HTTP_X_SENTRY_AUTH': get_auth_header( protocol=self.protocol_version, timestamp=time.time(), client=client_string, api_key=key.public_key, api_secret=key.secret_key, ), 'HTTP_CONTENT_ENCODING': self.get_content_encoding(), } self.request_factory = self.request_factory or RequestFactory() request = self.request_factory.post( '/api/store', data=self.encode(kwargs), content_type='application/octet-stream', **headers) StoreView.as_view()( request, project_id=six.text_type(settings.SENTRY_PROJECT), )
def _get_project_key(self, request): try: dsn = request.GET['dsn'] except KeyError: return try: key = ProjectKey.from_dsn(dsn) except ProjectKey.DoesNotExist: return return key
def send(self, **kwargs): # Report the issue to an upstream Sentry if active # NOTE: we don't want to check self.is_enabled() like normal, since # is_enabled behavior is overridden in this class. We explicitly # want to check if the remote is active. if self.remote.is_active(): from sentry import options # Append some extra tags that are useful for remote reporting super_kwargs = copy.deepcopy(kwargs) super_kwargs['tags']['install-id'] = options.get('sentry:install-id') super(SentryInternalClient, self).send(**super_kwargs) if not is_current_event_safe(): return # These imports all need to be internal to this function as this class # is set up by django while still parsing LOGGING settings and we # cannot import this stuff until settings are finalized. from sentry.models import ProjectKey from sentry.web.api import StoreView from django.test import RequestFactory key = None if settings.SENTRY_PROJECT_KEY is not None: key = ProjectKey.objects.filter( id=settings.SENTRY_PROJECT_KEY, project=settings.SENTRY_PROJECT).first() if key is None: key = ProjectKey.get_default(settings.SENTRY_PROJECT) if key is None: return client_string = 'raven-python/%s' % (raven.VERSION,) headers = { 'HTTP_X_SENTRY_AUTH': get_auth_header( protocol=self.protocol_version, timestamp=time.time(), client=client_string, api_key=key.public_key, api_secret=key.secret_key, ), 'HTTP_CONTENT_ENCODING': self.get_content_encoding(), } self.request_factory = self.request_factory or RequestFactory() request = self.request_factory.post( '/api/store', data=self.encode(kwargs), content_type='application/octet-stream', **headers ) StoreView.as_view()( request, project_id=six.text_type(settings.SENTRY_PROJECT), )
def get(self, request, project): data = options.get('sentry:docs') project_key = ProjectKey.get_default(project) context = { 'platforms': data['platforms'], } if project_key: context['dsn'] = project_key.dsn_private context['dsnPublic'] = project_key.dsn_public return Response(context)
def get(self, request, project, platform): data = load_doc(platform) if not data: raise ResourceDoesNotExist project_key = ProjectKey.get_default(project) return Response({ 'id': data['id'], 'name': data['name'], 'html': replace_keys(data['html'], project_key), 'link': data['link'], })
def get(self, request, project, platform): data = load_doc(platform) if not data: raise ResourceDoesNotExist project_key = ProjectKey.get_default(project) return Response({ "id": data["id"], "name": data["name"], "html": replace_keys(data["html"], project_key), "link": data["link"], })
def dispatch(self, request, pipeline): organization = pipeline.organization # TODO: make project selection part of flow project = Project.objects.filter(organization=organization, platform="node-awslambda").first() if not project: raise IntegrationError("No valid project") enabled_dsn = ProjectKey.get_default(project=project) if not enabled_dsn: raise IntegrationError("Project does not have DSN enabled") sentry_project_dsn = enabled_dsn.get_dsn(public=True) arn = pipeline.fetch_state("arn") aws_external_id = pipeline.fetch_state("aws_external_id") lambda_client = gen_aws_lambda_client(arn, aws_external_id) lambda_functions = filter( lambda x: x.get("Runtime") in SUPPORTED_RUNTIMES, lambda_client.list_functions()["Functions"], ) for function in lambda_functions: name = function["FunctionName"] # TODO: load existing layers and environment and append to them try: lambda_client.update_function_configuration( FunctionName=name, Layers=[options.get("aws-lambda.node-layer-arn")], Environment={ "Variables": { "NODE_OPTIONS": "-r @sentry/serverless/dist/auto", "SENTRY_DSN": sentry_project_dsn, "SENTRY_TRACES_SAMPLE_RATE": "1.0", } }, ) except Exception as e: logger.info( "update_function_configuration.error", extra={ "organization_id": organization.id, "lambda_name": name, "arn": arn, "error": six.text_type(e), }, ) return pipeline.next_step()
def test_relay_disabled_project( call_endpoint, default_project, projectconfig_cache_set, task_runner ): default_project.update(status=ObjectStatus.PENDING_DELETION) wrong_public_key = ProjectKey.generate_api_key() with task_runner(): result, status_code = call_endpoint(full_config=True, public_keys=[wrong_public_key]) assert status_code < 400 assert result == {"configs": {wrong_public_key: {"disabled": True}}} assert projectconfig_cache_set == [{str(wrong_public_key): result["configs"][wrong_public_key]}]
def authenticate_credentials(self, token): try: key = ProjectKey.from_dsn(token) except ProjectKey.DoesNotExist: raise AuthenticationFailed('Invalid token') if not key.is_active: raise AuthenticationFailed('Invalid token') with configure_scope() as scope: scope.set_tag("api_token_type", self.token_name) scope.set_tag("api_project_key", key.id) return (AnonymousUser(), key)
def get(self, request, project): data = load_doc('_platforms') if data is None: raise RuntimeError('Docs not built') project_key = ProjectKey.get_default(project) context = { 'platforms': data['platforms'], } if project_key: context['dsn'] = project_key.dsn_private context['dsnPublic'] = project_key.dsn_public return Response(context)
def authenticate_credentials(self, token): from django.contrib.auth.models import AnonymousUser # Django 1.9 setup issue from sentry.models import ProjectKey # Django 1.9 setup issue try: key = ProjectKey.from_dsn(token) except ProjectKey.DoesNotExist: raise AuthenticationFailed('Invalid token') if not key.is_active: raise AuthenticationFailed('Invalid token') with configure_scope() as scope: scope.set_tag("api_token_type", self.token_name) scope.set_tag("api_project_key", key.id) return (AnonymousUser(), key)
def edit_project_key(request, organization, project, key_id): try: key = ProjectKey.objects.get( id=key_id, project=project, ) except ProjectKey.DoesNotExist(): return HttpResponseRedirect( reverse('sentry-manage-project-keys', args=[project.organization.slug, project.slug])) if not can_edit_project_key(request.user, key): return HttpResponseRedirect( reverse('sentry-manage-project-keys', args=[project.organization.slug, project.slug])) form = EditProjectKeyForm(request.POST or None, instance=key) if form.is_valid(): key = form.save() AuditLogEntry.objects.create( organization=organization, actor=request.user, ip_address=request.META['REMOTE_ADDR'], target_object=key.id, event=AuditLogEntryEvent.PROJECTKEY_EDIT, data=key.get_audit_log_data(), ) messages.add_message( request, messages.SUCCESS, _('Changes to the API key (%s) were saved.') % (key.public_key, )) return HttpResponseRedirect( reverse('sentry-manage-project-keys', args=[project.organization.slug, project.slug])) context = { 'organization': organization, 'team': project.team, 'project': project, 'page': 'keys', 'key': key, 'form': form, } return render_to_response('sentry/projects/edit_key.html', context, request)
def update_organization_config(self, data): # data = {"project_mappings": [[sentry_project_id, vercel_project_id]]} vercel_client = self.get_client() config = self.org_integration.config new_mappings = data["project_mappings"] old_mappings = config.get("project_mappings") or [] for mapping in new_mappings: # skip any mappings that already exist if mapping in old_mappings: continue [sentry_project_id, vercel_project_id] = mapping sentry_project = Project.objects.get(id=sentry_project_id) enabled_dsn = ProjectKey.get_default(project=sentry_project) if not enabled_dsn: raise IntegrationError( "You must have an enabled DSN to continue!") sentry_project_dsn = enabled_dsn.get_dsn(public=True) org_secret = self.create_secret(vercel_client, vercel_project_id, "SENTRY_ORG", sentry_project.organization.slug) project_secret = self.create_secret( vercel_client, vercel_project_id, "SENTRY_PROJECT_%s" % sentry_project_id, sentry_project.slug, ) dsn_secret = self.create_secret( vercel_client, vercel_project_id, "NEXT_PUBLIC_SENTRY_DSN_%s" % sentry_project_id, sentry_project_dsn, ) self.create_env_var(vercel_client, vercel_project_id, "SENTRY_ORG", org_secret) self.create_env_var(vercel_client, vercel_project_id, "SENTRY_PROJECT", project_secret) self.create_env_var(vercel_client, vercel_project_id, "NEXT_PUBLIC_SENTRY_DSN", dsn_secret) config.update(data) self.org_integration.update(config=config)
def test_upgrade_org_config_no_dsn(self): """Test that the function doesn't progress if there is no active DSN""" with self.tasks(): self.assert_setup_flow() project_id = self.project.id org = self.organization data = { "project_mappings": [[project_id, "Qme9NXBpguaRxcXssZ1NWHVaM98MAL6PHDXUs1jPrgiM8H"]] } integration = Integration.objects.get(provider=self.provider.key) installation = integration.get_installation(org.id) dsn = ProjectKey.get_default(project=Project.objects.get(id=project_id)) dsn.update(id=dsn.id, status=ProjectKeyStatus.INACTIVE) with self.assertRaises(ValidationError): installation.update_organization_config(data)
def test_projectkeys(default_project, task_runner, redis_cache): with task_runner(): ProjectKey.objects.filter(project=default_project).delete() pk = ProjectKey(project=default_project) pk.save() (pk_json, ) = redis_cache.get(default_project.id)["publicKeys"] assert pk_json["publicKey"] == pk.public_key assert pk_json["isEnabled"] with task_runner(): pk.delete() assert not redis_cache.get(default_project.id)["publicKeys"]
def test_get_dsn_with_port(self): key = ProjectKey(project_id=1, public_key='public', secret_key='secret') with self.Settings(SENTRY_URL_PREFIX='http://example.com:81'): self.assertEquals(key.get_dsn(), 'http://*****:*****@example.com:81/1')
def test_get_dsn_with_port(self): key = ProjectKey(project_id=1, public_key="public", secret_key="secret") with self.Settings(SENTRY_URL_PREFIX="http://example.com:81"): self.assertEquals(key.get_dsn(), "http://*****:*****@example.com:81/1")
def save(self, *args, **kwargs): if not self.public_key: self.public_key = ProjectKey.generate_api_key() if not self.secret_key: self.secret_key = ProjectKey.generate_api_key() super(ProjectKey, self).save(*args, **kwargs)