Skip to content

Commit 05a694c

Browse files
Merge branch 'main' into task/badge-implementation-in-frontend
2 parents fb1e403 + 23861cc commit 05a694c

File tree

156 files changed

+7317
-5887
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

156 files changed

+7317
-5887
lines changed

.github/workflows/run-ci-cd.yaml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ jobs:
276276
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435
277277

278278
- name: Login to Docker Hub
279-
uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1
279+
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef
280280
with:
281281
username: ${{ secrets.DOCKERHUB_USERNAME }}
282282
password: ${{ secrets.DOCKERHUB_TOKEN }}
@@ -377,16 +377,18 @@ jobs:
377377
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
378378

379379
- name: Scan backend image
380+
continue-on-error: true
380381
uses: aquasecurity/trivy-action@b6643a29fecd7f34b3597bc6acb0a98b03d33ff8
381382
with:
382-
exit-code: 0
383+
exit-code: 1
383384
image-ref: owasp/nest:backend-staging
384385
scan-type: image
385386
trivy-config: trivy.yaml
386387
trivyignores: trivyignore.yaml
387388
version: latest
388389

389390
- name: Scan frontend image
391+
continue-on-error: true
390392
uses: aquasecurity/trivy-action@b6643a29fecd7f34b3597bc6acb0a98b03d33ff8
391393
with:
392394
exit-code: 1
@@ -600,7 +602,7 @@ jobs:
600602
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435
601603

602604
- name: Login to Docker Hub
603-
uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1
605+
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef
604606
with:
605607
username: ${{ secrets.DOCKERHUB_USERNAME }}
606608
password: ${{ secrets.DOCKERHUB_TOKEN }}

.github/workflows/run-code-ql.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ jobs:
3131
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
3232

3333
- name: Initialize CodeQL
34-
uses: github/codeql-action/init@192325c86100d080feab897ff886c34abd4c83a3
34+
uses: github/codeql-action/init@e296a935590eb16afc0c0108289f68c87e2a89a5
3535
with:
3636
languages: ${{ matrix.language }}
3737

@@ -55,6 +55,6 @@ jobs:
5555
run: pnpm install --frozen-lockfile
5656

5757
- name: Perform CodeQL analysis
58-
uses: github/codeql-action/analyze@192325c86100d080feab897ff886c34abd4c83a3
58+
uses: github/codeql-action/analyze@e296a935590eb16afc0c0108289f68c87e2a89a5
5959
with:
6060
category: /language:${{ matrix.language }}

.github/workflows/update-nest-test-images.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ jobs:
2323
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435
2424

2525
- name: Login to Docker Hub
26-
uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1
26+
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef
2727
with:
2828
username: ${{ secrets.DOCKERHUB_USERNAME }}
2929
password: ${{ secrets.DOCKERHUB_TOKEN }}

.pre-commit-config.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ repos:
1010
exclude: (.github|pnpm-lock.yaml)
1111

1212
- repo: https://github.com/astral-sh/ruff-pre-commit
13-
rev: v0.13.1
13+
rev: v0.14.0
1414
hooks:
1515
- id: ruff
1616
args:
@@ -83,6 +83,6 @@ repos:
8383
exclude: pnpm-lock.yaml
8484

8585
- repo: https://github.com/tox-dev/pyproject-fmt
86-
rev: v2.6.0
86+
rev: v2.7.0
8787
hooks:
8888
- id: pyproject-fmt

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@
99

1010
[![OWASP](https://img.shields.io/badge/OWASP-Incubator-blue?style=for-the-badge)](https://owasp.org/www-project-nest/) [![OWASP](https://img.shields.io/badge/OWASP-Code-blue?style=for-the-badge)](https://owasp.org/www-project-nest/) [![project-nest](https://img.shields.io/badge/OWASP-%23project--nest-blue?logo=slack&logoColor=white&style=for-the-badge)](https://owasp.slack.com/messages/project-nest)
1111

12-
[![License](https://img.shields.io/github/license/owasp/nest?color=41BE4A&label=License&style=for-the-badge)](https://github.com/OWASP/Nest/blob/main/LICENSE) [![Last Commit](https://img.shields.io/github/last-commit/owasp/nest/main?style=for-the-badge&label=Last%20commit)](https://github.com/OWASP/Nest/commits/main/) [![Contributors](https://img.shields.io/github/contributors/owasp/nest?style=for-the-badge&label=Contributors)](https://github.com/OWASP/Nest/graphs/contributors)
12+
[![License](https://img.shields.io/github/license/owasp/nest?color=blue&label=License&style=for-the-badge)](https://github.com/OWASP/Nest/blob/main/LICENSE) [![Last Commit](https://img.shields.io/github/last-commit/owasp/nest/main?color=blue&style=for-the-badge&label=Last%20commit)](https://github.com/OWASP/Nest/commits/main/) [![Contributors](https://img.shields.io/github/contributors/owasp/nest?style=for-the-badge&label=Contributors&color=blue)](https://github.com/OWASP/Nest/graphs/contributors)
1313

14-
[![CI/CD](https://img.shields.io/github/actions/workflow/status/owasp/nest/run-ci-cd.yaml?branch=main&label=Build&style=for-the-badge)](https://github.com/owasp/nest/actions/workflows/run-ci-cd.yaml?query=branch%3Amain) [![CodeQL](https://img.shields.io/github/actions/workflow/status/owasp/nest/run-code-ql.yaml?branch=main&label=CodeQL&style=for-the-badge)](https://github.com/owasp/nest/actions/workflows/run-code-ql.yaml?query=branch%3Amain) [![Sonarqube](https://img.shields.io/sonar/quality_gate/OWASP_Nest?server=https://sonarcloud.io&style=for-the-badge&label=Sonarqube)](https://sonarcloud.io/summary/new_code?id=OWASP_Nest&branch=main)
14+
[![CI/CD](https://img.shields.io/github/actions/workflow/status/owasp/nest/run-ci-cd.yaml?branch=main&color=blue&label=Build&style=for-the-badge)](https://github.com/owasp/nest/actions/workflows/run-ci-cd.yaml?query=branch%3Amain) [![CodeQL](https://img.shields.io/github/actions/workflow/status/owasp/nest/run-code-ql.yaml?branch=main&color=blue&label=CodeQL&style=for-the-badge)](https://github.com/owasp/nest/actions/workflows/run-code-ql.yaml?query=branch%3Amain) [![Sonarqube](https://img.shields.io/sonar/quality_gate/OWASP_Nest?color=blue&server=https://sonarcloud.io&style=for-the-badge&label=Sonarqube)](https://sonarcloud.io/summary/new_code?id=OWASP_Nest&branch=main)
1515

1616
[![Issues](https://img.shields.io/github/issues/owasp/nest?color=blue&style=for-the-badge&label=Issues)](https://github.com/OWASP/Nest/issues) [![Pull Requests](https://img.shields.io/github/issues-pr/owasp/nest?color=blue&style=for-the-badge&label=Pull%20Requests)](https://github.com/OWASP/Nest/pulls)
1717

backend/apps/api/rest/v0/__init__.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22

33
from django.conf import settings
44
from ninja import NinjaAPI, Swagger
5+
from ninja.pagination import RouterPaginated
56
from ninja.throttling import AuthRateThrottle
67

78
from apps.api.rest.auth.api_key import ApiKey as ApiKey
9+
from apps.api.rest.v0.chapter import router as chapter_router
810
from apps.api.rest.v0.committee import router as committee_router
911
from apps.api.rest.v0.event import router as event_router
1012
from apps.api.rest.v0.issue import router as issue_router
@@ -15,8 +17,6 @@
1517
from apps.api.rest.v0.repository import router as repository_router
1618
from apps.api.rest.v0.sponsor import router as sponsor_router
1719

18-
from .chapter import router as chapter_router
19-
2020
ROUTERS = {
2121
# Chapters.
2222
"/chapters": chapter_router,
@@ -42,11 +42,12 @@
4242

4343
api_settings = {
4444
"auth": ApiKey(), # The `api_key` param name is based on the ApiKey class name.
45+
"default_router": RouterPaginated(),
4546
"description": "Open Worldwide Application Security Project API",
4647
"docs": Swagger(settings={"persistAuthorization": True}),
4748
"throttle": [AuthRateThrottle("10/s")],
4849
"title": "OWASP Nest",
49-
"version": "0.2.3",
50+
"version": "0.2.4",
5051
}
5152

5253
api_settings_customization = {}

backend/apps/api/rest/v0/chapter.py

Lines changed: 38 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -7,78 +7,89 @@
77
from django.conf import settings
88
from django.http import HttpRequest
99
from django.views.decorators.cache import cache_page
10-
from ninja import Field, FilterSchema, Path, Query, Router, Schema
10+
from ninja import Field, FilterSchema, Path, Query, Schema
1111
from ninja.decorators import decorate_view
12-
from ninja.pagination import PageNumberPagination, paginate
12+
from ninja.pagination import RouterPaginated
1313
from ninja.responses import Response
1414

15-
from apps.owasp.models.chapter import Chapter
15+
from apps.owasp.models.chapter import Chapter as ChapterModel
1616

17-
router = Router()
17+
router = RouterPaginated(tags=["Chapters"])
1818

1919

20-
class ChapterErrorResponse(Schema):
21-
"""Chapter error response schema."""
20+
class ChapterBase(Schema):
21+
"""Base schema for Chapter (used in list endpoints)."""
2222

23-
message: str
23+
created_at: datetime
24+
key: str
25+
name: str
26+
updated_at: datetime
2427

28+
@staticmethod
29+
def resolve_key(obj):
30+
"""Resolve key."""
31+
return obj.nest_key
2532

26-
class ChapterFilterSchema(FilterSchema):
27-
"""Filter schema for Chapter."""
2833

29-
country: str | None = Field(None, description="Country of the chapter")
30-
region: str | None = Field(None, description="Region of the chapter")
34+
class Chapter(ChapterBase):
35+
"""Schema for Chapter (minimal fields for list display)."""
3136

3237

33-
class ChapterSchema(Schema):
34-
"""Schema for Chapter."""
38+
class ChapterDetail(ChapterBase):
39+
"""Detail schema for Chapter (used in single item endpoints)."""
3540

3641
country: str
37-
created_at: datetime
38-
name: str
3942
region: str
40-
updated_at: datetime
43+
44+
45+
class ChapterError(Schema):
46+
"""Chapter error schema."""
47+
48+
message: str
49+
50+
51+
class ChapterFilter(FilterSchema):
52+
"""Filter for Chapter."""
53+
54+
country: str | None = Field(None, description="Country of the chapter")
4155

4256

4357
@router.get(
4458
"/",
4559
description="Retrieve a paginated list of OWASP chapters.",
4660
operation_id="list_chapters",
47-
response={200: list[ChapterSchema]},
61+
response=list[Chapter],
4862
summary="List chapters",
49-
tags=["Chapters"],
5063
)
5164
@decorate_view(cache_page(settings.API_CACHE_TIME_SECONDS))
52-
@paginate(PageNumberPagination, page_size=settings.API_PAGE_SIZE)
5365
def list_chapters(
5466
request: HttpRequest,
55-
filters: ChapterFilterSchema = Query(...),
67+
filters: ChapterFilter = Query(...),
5668
ordering: Literal["created_at", "-created_at", "updated_at", "-updated_at"] | None = Query(
5769
None,
5870
description="Ordering field",
5971
),
60-
) -> list[ChapterSchema]:
72+
) -> list[Chapter]:
6173
"""Get chapters."""
62-
return filters.filter(Chapter.active_chapters.order_by(ordering or "-created_at"))
74+
return filters.filter(ChapterModel.active_chapters.order_by(ordering or "-created_at"))
6375

6476

6577
@router.get(
6678
"/{str:chapter_id}",
6779
description="Retrieve chapter details.",
6880
operation_id="get_chapter",
6981
response={
70-
HTTPStatus.NOT_FOUND: ChapterErrorResponse,
71-
HTTPStatus.OK: ChapterSchema,
82+
HTTPStatus.NOT_FOUND: ChapterError,
83+
HTTPStatus.OK: ChapterDetail,
7284
},
7385
summary="Get chapter",
74-
tags=["Chapters"],
7586
)
7687
def get_chapter(
7788
request: HttpRequest,
7889
chapter_id: str = Path(example="London"),
79-
) -> ChapterSchema | ChapterErrorResponse:
90+
) -> ChapterDetail | ChapterError:
8091
"""Get chapter."""
81-
if chapter := Chapter.active_chapters.filter(
92+
if chapter := ChapterModel.active_chapters.filter(
8293
key__iexact=(
8394
chapter_id if chapter_id.startswith("www-chapter-") else f"www-chapter-{chapter_id}"
8495
)

backend/apps/api/rest/v0/committee.py

Lines changed: 34 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,69 +7,81 @@
77
from django.conf import settings
88
from django.http import HttpRequest
99
from django.views.decorators.cache import cache_page
10-
from ninja import Path, Query, Router, Schema
10+
from ninja import Path, Query, Schema
1111
from ninja.decorators import decorate_view
12-
from ninja.pagination import PageNumberPagination, paginate
12+
from ninja.pagination import RouterPaginated
1313
from ninja.responses import Response
1414

15-
from apps.owasp.models.committee import Committee
15+
from apps.owasp.models.committee import Committee as CommitteeModel
1616

17-
router = Router()
17+
router = RouterPaginated(tags=["Committees"])
1818

1919

20-
class CommitteeErrorResponse(Schema):
21-
"""Committee error response schema."""
20+
class CommitteeBase(Schema):
21+
"""Base schema for Committee (used in list endpoints)."""
2222

23-
message: str
23+
created_at: datetime
24+
key: str
25+
name: str
26+
updated_at: datetime
2427

28+
@staticmethod
29+
def resolve_key(obj):
30+
"""Resolve key."""
31+
return obj.nest_key
2532

26-
class CommitteeSchema(Schema):
27-
"""Schema for Committee."""
2833

29-
name: str
34+
class Committee(CommitteeBase):
35+
"""Schema for Committee (minimal fields for list display)."""
36+
37+
38+
class CommitteeDetail(CommitteeBase):
39+
"""Detail schema for Committee (used in single item endpoints)."""
40+
3041
description: str
31-
created_at: datetime
32-
updated_at: datetime
42+
43+
44+
class CommitteeError(Schema):
45+
"""Committee error schema."""
46+
47+
message: str
3348

3449

3550
@router.get(
3651
"/",
3752
description="Retrieve a paginated list of OWASP committees.",
3853
operation_id="list_committees",
39-
response={200: list[CommitteeSchema]},
54+
response=list[Committee],
4055
summary="List committees",
41-
tags=["Committees"],
4256
)
4357
@decorate_view(cache_page(settings.API_CACHE_TIME_SECONDS))
44-
@paginate(PageNumberPagination, page_size=settings.API_PAGE_SIZE)
4558
def list_committees(
4659
request: HttpRequest,
4760
ordering: Literal["created_at", "-created_at", "updated_at", "-updated_at"] | None = Query(
4861
None,
4962
description="Ordering field",
5063
),
51-
) -> list[CommitteeSchema]:
64+
) -> list[Committee]:
5265
"""Get committees."""
53-
return Committee.active_committees.order_by(ordering or "-created_at")
66+
return CommitteeModel.active_committees.order_by(ordering or "-created_at")
5467

5568

5669
@router.get(
5770
"/{str:committee_id}",
5871
description="Retrieve committee details.",
5972
operation_id="get_committee",
6073
response={
61-
HTTPStatus.NOT_FOUND: CommitteeErrorResponse,
62-
HTTPStatus.OK: CommitteeSchema,
74+
HTTPStatus.NOT_FOUND: CommitteeError,
75+
HTTPStatus.OK: CommitteeDetail,
6376
},
6477
summary="Get committee",
65-
tags=["Committees"],
6678
)
6779
def get_chapter(
6880
request: HttpRequest,
6981
committee_id: str = Path(example="project"),
70-
) -> CommitteeSchema | CommitteeErrorResponse:
82+
) -> CommitteeDetail | CommitteeError:
7183
"""Get chapter."""
72-
if committee := Committee.active_committees.filter(
84+
if committee := CommitteeModel.active_committees.filter(
7385
is_active=True,
7486
key__iexact=(
7587
committee_id

0 commit comments

Comments
 (0)