Skip to content

Commit

Permalink
fix: jira importer validations (#3323)
Browse files Browse the repository at this point in the history
* fix: jira importer validations

* dev: update validation for cloud hostname

* dev: update the function to be used externally

* dev: update codeql workflow

* dev: update repository selection api
  • Loading branch information
pablohashescobar committed Jan 8, 2024
1 parent 02a7763 commit 4b0ccea
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 17 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/codeql.yml
Expand Up @@ -2,10 +2,10 @@ name: "CodeQL"

on:
push:
branches: [ 'develop', 'hot-fix', 'stage-release' ]
branches: [ 'develop', 'preview', 'master' ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ 'develop' ]
branches: [ 'develop', 'preview', 'master' ]
schedule:
- cron: '53 19 * * 5'

Expand Down
31 changes: 20 additions & 11 deletions apiserver/plane/app/views/importer.py
Expand Up @@ -35,14 +35,13 @@
ModuleSerializer,
)
from plane.utils.integrations.github import get_github_repo_details
from plane.utils.importers.jira import jira_project_issue_summary
from plane.utils.importers.jira import jira_project_issue_summary, is_allowed_hostname
from plane.bgtasks.importer_task import service_importer
from plane.utils.html_processor import strip_tags
from plane.app.permissions import WorkSpaceAdminPermission


class ServiceIssueImportSummaryEndpoint(BaseAPIView):

def get(self, request, slug, service):
if service == "github":
owner = request.GET.get("owner", False)
Expand Down Expand Up @@ -122,6 +121,7 @@ class ImportServiceEndpoint(BaseAPIView):
permission_classes = [
WorkSpaceAdminPermission,
]

def post(self, request, slug, service):
project_id = request.data.get("project_id", False)

Expand Down Expand Up @@ -174,6 +174,21 @@ def post(self, request, slug, service):
data = request.data.get("data", False)
metadata = request.data.get("metadata", False)
config = request.data.get("config", False)

cloud_hostname = metadata.get("cloud_hostname", False)

if not cloud_hostname:
return Response(
{"error": "Cloud hostname is required"},
status=status.HTTP_400_BAD_REQUEST,
)

if not is_allowed_hostname(cloud_hostname):
return Response(
{"error": "Hostname is not a valid hostname."},
status=status.HTTP_400_BAD_REQUEST,
)

if not data or not metadata:
return Response(
{"error": "Data, config and metadata are required"},
Expand Down Expand Up @@ -221,9 +236,7 @@ def get(self, request, slug):
return Response(serializer.data)

def delete(self, request, slug, service, pk):
importer = Importer.objects.get(
pk=pk, service=service, workspace__slug=slug
)
importer = Importer.objects.get(pk=pk, service=service, workspace__slug=slug)

if importer.imported_data is not None:
# Delete all imported Issues
Expand All @@ -241,9 +254,7 @@ def delete(self, request, slug, service, pk):
return Response(status=status.HTTP_204_NO_CONTENT)

def patch(self, request, slug, service, pk):
importer = Importer.objects.get(
pk=pk, service=service, workspace__slug=slug
)
importer = Importer.objects.get(pk=pk, service=service, workspace__slug=slug)
serializer = ImporterSerializer(importer, data=request.data, partial=True)
if serializer.is_valid():
serializer.save()
Expand Down Expand Up @@ -479,9 +490,7 @@ def post(self, request, slug, project_id, service):
[
ModuleLink(
module=module,
url=module_data.get("link", {}).get(
"url", "https://plane.so"
),
url=module_data.get("link", {}).get("url", "https://plane.so"),
title=module_data.get("link", {}).get(
"title", "Original Issue"
),
Expand Down
22 changes: 20 additions & 2 deletions apiserver/plane/utils/importers/jira.py
Expand Up @@ -2,13 +2,31 @@
from requests.auth import HTTPBasicAuth
from sentry_sdk import capture_exception

from urllib.parse import urlparse

def is_allowed_hostname(hostname):
allowed_lists = ["atl-paas.net", "atlassian.com", "atlassian.net", "jira.com"]
# Extract the base domain from the hostname
parsed_uri = urlparse(f"https://{hostname}") # Add scheme for urlparse to work properly
domain = parsed_uri.netloc.split(":")[0] # Removes port number if included
base_domain = ".".join(domain.split(".")[-2:]) # Extract base domain

# Check if the base domain is in the allowed list
return base_domain in allowed_lists


def jira_project_issue_summary(email, api_token, project_key, hostname):
try:


if not is_allowed_hostname(hostname):
print("Errored Hostname")
return {"error": "Invalid or unauthorized hostname"}

auth = HTTPBasicAuth(email, api_token)
headers = {"Accept": "application/json"}

issue_url = f"https://{hostname}/rest/api/3/search?jql=project={project_key} AND issuetype=Story"
issue_url = f"https://{hostname}/rest/api/3/search?jql=project={project_key} AND issuetype!=Epic"
issue_response = requests.request(
"GET", issue_url, headers=headers, auth=auth
).json()["total"]
Expand All @@ -18,7 +36,7 @@ def jira_project_issue_summary(email, api_token, project_key, hostname):
"GET", module_url, headers=headers, auth=auth
).json()["total"]

status_url = f"https://{hostname}/rest/api/3/status/?jql=project={project_key}"
status_url = f"https://{hostname}/rest/api/3/project/${project_key}/statuses"
status_response = requests.request(
"GET", status_url, headers=headers, auth=auth
).json()
Expand Down
2 changes: 1 addition & 1 deletion web/components/integration/single-integration-card.tsx
Expand Up @@ -139,7 +139,7 @@ export const SingleIntegrationCard: React.FC<Props> = observer(({ integration })
variant="danger"
onClick={() => {
if (!isUserAdmin) return;
handleRemoveIntegration;
handleRemoveIntegration();
}}
disabled={!isUserAdmin}
loading={deletingIntegration}
Expand Down
6 changes: 5 additions & 1 deletion web/services/project/project.service.ts
Expand Up @@ -86,7 +86,11 @@ export class ProjectService extends APIService {
}

async getGithubRepositories(url: string): Promise<GithubRepositoriesResponse> {
return this.request(url)
return this.request({
method: "get",
url,
headers: this.getAccessToken() ? this.getHeaders() : {},
})
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
Expand Down

0 comments on commit 4b0ccea

Please sign in to comment.