Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/update-nest-test-images.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@ jobs:
cache-to: |
type=gha,compression=zstd
type=registry,ref=owasp/nest:test-fuzz-backend-cache
context: backend/docker
file: Dockerfile.fuzz
context: backend
file: docker/backend/Dockerfile.fuzz
platforms: linux/amd64
push: true
tags: owasp/nest:test-fuzz-backend-latest
Expand Down
32 changes: 23 additions & 9 deletions backend/apps/common/management/commands/dump_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

from django.conf import settings
from django.core.management.base import BaseCommand, CommandError
from psycopg2 import ProgrammingError, connect, sql
from psycopg2 import OperationalError, ProgrammingError, connect, sql

DEFAULT_DATABASE = settings.DATABASES["default"]
DB_HOST = DEFAULT_DATABASE.get("HOST", "localhost")
Expand Down Expand Up @@ -52,7 +52,14 @@ def handle(self, *args, **options):

temp_db = f"temp_{DB_NAME}"
try:
self._execute_sql("postgres", [f"CREATE DATABASE {temp_db} TEMPLATE {DB_NAME};"])
self._execute_sql(
"postgres",
[
sql.SQL("CREATE DATABASE {temp_db} TEMPLATE {DB_NAME};").format(
temp_db=sql.Identifier(temp_db), DB_NAME=sql.Identifier(DB_NAME)
)
],
)

self.stdout.write(self.style.SUCCESS(f"Created temporary DB: {temp_db}"))

Expand Down Expand Up @@ -86,20 +93,27 @@ def handle(self, *args, **options):
raise CommandError(message) from e
finally:
try:
self._execute_sql("postgres", [f"DROP DATABASE IF EXISTS {temp_db};"])
except CalledProcessError:
self._execute_sql(
"postgres",
[
sql.SQL("DROP DATABASE IF EXISTS {temp_db};").format(
temp_db=sql.Identifier(temp_db)
)
],
)
except (ProgrammingError, OperationalError):
self.stderr.write(
self.style.WARNING(f"Failed to drop temp DB {temp_db} (ignored).")
)

def _table_list_query(self) -> str:
return """
def _table_list_query(self) -> sql.Composable:
return sql.SQL("""
SELECT table_name
FROM information_schema.columns
WHERE table_schema = 'public' AND column_name = 'email';
"""
""")

def _remove_emails(self, tables: list[str]) -> list[str]:
def _remove_emails(self, tables: list[str]) -> list[sql.Composable]:
return [
sql.SQL("UPDATE {table} SET email = '';").format(table=sql.Identifier(table))
for table in tables
Expand All @@ -108,7 +122,7 @@ def _remove_emails(self, tables: list[str]) -> list[str]:
def _execute_sql(
self,
dbname: str,
sql_queries: list[str],
sql_queries: list[sql.Composable],
):
connection = connect(
dbname=dbname,
Expand Down
2 changes: 1 addition & 1 deletion backend/apps/github/api/internal/nodes/pull_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,4 @@ def repository_name(self, root: PullRequest) -> str | None:
@strawberry_django.field
def url(self, root: PullRequest) -> str:
"""Resolve URL."""
return root.url or ""
return root.url
2 changes: 1 addition & 1 deletion backend/apps/github/api/internal/queries/issue.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def recent_issues(
"""Resolve recent issues with optional filtering.

Args:
distinct (bool): Whether to return unique issues per author and repository.
distinct (bool): Whether to return unique issues per author.
limit (int): Maximum number of issues to return.
login (str, optional): Filter issues by a specific author's login.
organization (str, optional): Filter issues by a specific organization's login.
Expand Down
2 changes: 1 addition & 1 deletion backend/apps/github/api/internal/queries/pull_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def recent_pull_requests(
"""Resolve recent pull requests.

Args:
distinct (bool): Whether to return unique pull requests per author and repository.
distinct (bool): Whether to return unique pull requests per author.
limit (int): Maximum number of pull requests to return.
login (str, optional): Filter pull requests by a specific author's login.
organization (str, optional): Filter pull requests by a specific organization's login.
Expand Down
2 changes: 1 addition & 1 deletion backend/apps/github/api/internal/queries/release.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def recent_releases(
"""Resolve recent releases with optional distinct filtering.

Args:
distinct (bool): Whether to return unique releases per author and repository.
distinct (bool): Whether to return unique releases per author.
limit (int): Maximum number of releases to return.
login (str, optional): Filter releases by a specific author's login.
organization (str, optional): Filter releases by a specific organization's login.
Expand Down
4 changes: 3 additions & 1 deletion backend/apps/github/api/internal/queries/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ def top_contributed_repositories(
.order_by("-contributions_count")
]

@strawberry_django.field(select_related=["owasp_profile", "user_badges__badge"])
@strawberry_django.field(
select_related=["owasp_profile"], prefetch_related=["user_badges__badge"]
)
def user(
self,
login: str,
Expand Down
2 changes: 1 addition & 1 deletion backend/apps/owasp/api/internal/nodes/committee.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ def contributors_count(self, root: Committee) -> int:
return root.owasp_repository.contributors_count if root.owasp_repository else 0

@strawberry_django.field
def created_at(self, root: Committee) -> float:
def created_at(self, root: Committee) -> float | None:
"""Resolve created at."""
return root.idx_created_at

Expand Down
2 changes: 1 addition & 1 deletion backend/apps/owasp/api/internal/queries/post.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@ class PostQuery:

@strawberry_django.field
def recent_posts(self, limit: int = 5) -> list[PostNode]:
"""Return the 5 most recent posts."""
"""Return the most recent posts."""
return Post.recent_posts()[:limit] if (limit := min(limit, MAX_LIMIT)) > 0 else []
2 changes: 1 addition & 1 deletion backend/apps/owasp/models/project_health_metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ def owasp_page_last_update_days_requirement(self) -> int:
@cached_property
def project_requirements(self) -> ProjectHealthRequirements | None:
"""Get the project health requirements for the project's level."""
return ProjectHealthRequirements.objects.get(level=self.project.level)
return ProjectHealthRequirements.objects.filter(level=self.project.level).first()

@staticmethod
def bulk_save(metrics: list, fields: list | None = None) -> None: # type: ignore[override]
Expand Down
30 changes: 19 additions & 11 deletions backend/tests/apps/common/management/commands/dump_data_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from django.core.management import call_command
from django.test import override_settings
from psycopg2 import sql

DATABASES = {
"default": {
Expand All @@ -20,8 +21,7 @@ class TestDumpDataCommand:
@patch("apps.common.management.commands.dump_data.run")
@patch("apps.common.management.commands.dump_data.connect")
@patch("apps.common.management.commands.dump_data.Path")
@patch("apps.common.management.commands.dump_data.sql")
def test_dump_data(self, mock_sql, mock_path, mock_connect, mock_run):
def test_dump_data(self, mock_path, mock_connect, mock_run):
# Mock psycopg2 connection/cursor
mock_conn = MagicMock()
mock_cursor = MagicMock()
Expand All @@ -30,7 +30,6 @@ def test_dump_data(self, mock_sql, mock_path, mock_connect, mock_run):
mock_cursor.fetchall.return_value = [("public.users",), ("public.members",)]
mock_resolve = MagicMock()
mock_path.return_value.resolve.return_value = mock_resolve
mock_sql.SQL.return_value.format.return_value = "UPDATE public.users SET email = '';"
call_command(
"dump_data",
"--output",
Expand All @@ -48,18 +47,23 @@ def test_dump_data(self, mock_sql, mock_path, mock_connect, mock_run):
port="5432",
)
mock_cursor.execute.assert_any_call(
f"CREATE DATABASE {expected_temp_db} TEMPLATE db-name;"
sql.SQL("CREATE DATABASE {temp_db} TEMPLATE {DB_NAME};").format(
temp_db=sql.Identifier(expected_temp_db),
DB_NAME=sql.Identifier("db-name"),
)
)
executed_sql = [str(c.args[0]) for c in mock_cursor.execute.call_args_list]
assert "UPDATE public.users SET email = '';" in executed_sql
assert any(
"""
assert (
str(
sql.SQL(
"""
SELECT table_name
FROM information_schema.columns
WHERE table_schema = 'public' AND column_name = 'email';
""".strip()
in str(query).strip()
for query in executed_sql
"""
)
)
in executed_sql
)

assert [
Expand Down Expand Up @@ -87,6 +91,10 @@ def test_dump_data(self, mock_sql, mock_path, mock_connect, mock_run):
str(mock_resolve),
] == mock_run.call_args[0][0]
# Ensure DROP DATABASE executed at the end
mock_cursor.execute.assert_any_call(f"DROP DATABASE IF EXISTS {expected_temp_db};")
mock_cursor.execute.assert_any_call(
sql.SQL("DROP DATABASE IF EXISTS {temp_db};").format(
temp_db=sql.Identifier(expected_temp_db)
)
)
mock_path.return_value.resolve.assert_called_once()
mock_resolve.parent.mkdir.assert_called_once_with(parents=True, exist_ok=True)
Original file line number Diff line number Diff line change
Expand Up @@ -88,12 +88,3 @@ def test_url_with_url(self):
field = self._get_field_by_name("url", PullRequestNode)
result = field.base_resolver.wrapped_func(None, mock_pr)
assert result == "https://github.com/test-org/test-repo/pull/123"

def test_url_without_url(self):
"""Test url field when URL doesn't exist."""
mock_pr = Mock()
mock_pr.url = None

field = self._get_field_by_name("url", PullRequestNode)
result = field.base_resolver.wrapped_func(None, mock_pr)
assert result == ""
4 changes: 2 additions & 2 deletions frontend/.env.e2e.example
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
NEXTAUTH_SECRET=<your-nextauth-secret>
NEXTAUTH_URL=http://localhost:3000/
NEXT_PUBLIC_API_URL=http://localhost:9000/
NEXT_PUBLIC_CSRF_URL=http://localhost:9000/csrf/
NEXT_PUBLIC_ENVIRONMENT=local
Expand All @@ -12,5 +14,3 @@ NEXT_SERVER_DISABLE_SSR=false
NEXT_SERVER_GITHUB_CLIENT_ID=your-github-client-id
NEXT_SERVER_GITHUB_CLIENT_SECRET=your-github-client-secret
NEXT_SERVER_GRAPHQL_URL=http://localhost:9000/graphql/
NEXTAUTH_SECRET=<your-nextauth-secret>
NEXTAUTH_URL=http://localhost:3000/
4 changes: 2 additions & 2 deletions frontend/.env.example
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
NEXTAUTH_SECRET=<your-nextauth-secret>
NEXTAUTH_URL=http://localhost:3000/
NEXT_PUBLIC_API_URL=http://localhost:8000/
NEXT_PUBLIC_CSRF_URL=http://localhost:8000/csrf/
NEXT_PUBLIC_ENVIRONMENT=local
Expand All @@ -12,5 +14,3 @@ NEXT_SERVER_DISABLE_SSR=false
NEXT_SERVER_GITHUB_CLIENT_ID=your-github-client-id
NEXT_SERVER_GITHUB_CLIENT_SECRET=your-github-client-secret
NEXT_SERVER_GRAPHQL_URL=http://backend:8000/graphql/
NEXTAUTH_SECRET=<your-nextauth-secret>
NEXTAUTH_URL=http://localhost:3000/
Loading