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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ Each secret should expose a key with the same name so it becomes a file in
- `pr-sandbox-pr-installation-id`
- `pr-sandbox-cluster-installation-id`
- `pr-sandbox-mysql-connection-string`
- `pr-sandbox-redis-connection-string`
- `pr-sandbox-argocd-webhook-auth`
- `pr-sandbox-argocd-readonly-user-password`
- `pr-sandbox-extra-configs`
Expand Down
11 changes: 10 additions & 1 deletion app/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import logging
from fastapi import Depends, APIRouter, Header, BackgroundTasks
from fastapi.responses import PlainTextResponse
from redis import Redis
from typing import Annotated
import uuid

Expand All @@ -20,13 +21,20 @@
from app.helpers.constants import GithubActionTypes, GithubEventTypes, CheckRunStatus
from app.helpers.db_utils import SessionDep
from app.helpers.exceptions import ActiveCheckrunNotFoundException, DBOperationException
from app.helpers.validations import validate_signature, validate_request, validate_auth
from app.helpers.utils import get_secret
from app.helpers.validations import (
validate_signature,
validate_request,
validate_auth,
validate_request_not_duplicate,
)
from app.models.request_models import (
GithubWebhookRequest,
GithubWebhookHeader,
ArgoWebhookRequest,
)

redis_client = Redis.from_url(get_secret("pr-sandbox-redis-connection-string"))
logger = logging.getLogger(__name__)

github_webhook_router = APIRouter(
Expand Down Expand Up @@ -181,6 +189,7 @@ def github_handler(
"""
logger.info(headers)
github_event = headers.x_github_event
validate_request_not_duplicate(headers.x_hub_signature_256, redis_client)
validate_request(github_event, request)
handle_github_webhook(github_event, request, db_session, background_tasks)
return {
Expand Down
2 changes: 1 addition & 1 deletion app/helpers/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -318,4 +318,4 @@ class ArgoCDSyncStatus(StrEnum):

PR_SANDBOX_NAME_PATTERN = r"pr-\d*-[0-9a-f]{6}"

DEDUPLICATION_TTL = 300
DEDUPLICATION_TTL = 30
10 changes: 10 additions & 0 deletions app/helpers/validations.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from fastapi import Request, HTTPException
import hmac
import hashlib
from redis import Redis

from app.helpers.conf import config
from app.helpers.constants import (
Expand All @@ -17,6 +18,7 @@
AUTHORIZATION_HEADER,
AUTHORIZATION_PREFIX,
WorkflowType,
DEDUPLICATION_TTL,
)
from app.helpers.exceptions import UnactionableRequestException
from app.helpers.utils import get_secret
Expand Down Expand Up @@ -180,3 +182,11 @@ def validate_request(github_event: GithubEventTypes, request: GithubWebhookReque
raise UnactionableRequestException("The provided installation id is invalid")

_validate_request_actionable(github_event, request)


def validate_request_not_duplicate(unique_id: str, redis_client: Redis):
is_unique = redis_client.set(unique_id, "1", nx=True, ex=DEDUPLICATION_TTL)
if not bool(is_unique):
raise UnactionableRequestException(
f"The request with id {unique_id} is not unique"
)
8 changes: 6 additions & 2 deletions charts/pr-sandbox-automation/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@ apiVersion: v2
name: pr-sandbox-automation
description: Automatically manage Open edX sandbox instances for PRs
type: application
version: 0.1.0
appVersion: "0.1.0"
version: 0.1.1
appVersion: "0.2.0"
dependencies:
- name: mysql
version: 9.14.1
repository: https://charts.bitnami.com/bitnami
condition: mysql.enabled
- name: redis
version: 24.1.3
repository: https://charts.bitnami.com/bitnami
condition: redis.enabled
8 changes: 8 additions & 0 deletions charts/pr-sandbox-automation/templates/_helpers.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,11 @@ app.kubernetes.io/instance: {{ .Release.Name }}
{{- printf "%s-mysql" .Release.Name -}}
{{- end -}}
{{- end -}}

{{- define "pr-sandbox-automation.redisHost" -}}
{{- if .Values.redis.connectionSecret.host -}}
{{- .Values.redis.connectionSecret.host -}}
{{- else -}}
{{- printf "%s-redis-master" .Release.Name -}}
{{- end -}}
{{- end -}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{{- if and .Values.redis.enabled .Values.redis.connectionSecret.create -}}
apiVersion: v1
kind: Secret
metadata:
name: {{ .Values.redis.connectionSecret.name }}
labels:
{{- include "pr-sandbox-automation.labels" . | nindent 4 }}
type: Opaque
stringData:
{{ .Values.redis.connectionSecret.key }}: {{- /*
Construct Redis connection string for the app.
Example: redis://:password@host:6379/0
*/}}
{{- $password := required "redis.auth.password is required when redis.connectionSecret.create is true" .Values.redis.auth.password -}}
{{- $host := include "pr-sandbox-automation.redisHost" . -}}
{{- $port := .Values.redis.connectionSecret.port | default 6379 -}}
{{ printf "redis://:%s@%s:%d/0" $password $host $port | quote }}
{{- end }}
28 changes: 28 additions & 0 deletions charts/pr-sandbox-automation/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ secretMounts:
items:
- key: pr-sandbox-mysql-connection-string
path: pr-sandbox-mysql-connection-string
- secretName: pr-sandbox-redis-connection-string
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess it need to be referenced in the README as well

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is referenced here, unless you meant something else ?

items:
- key: pr-sandbox-redis-connection-string
path: pr-sandbox-redis-connection-string
- secretName: pr-sandbox-argocd-webhook-auth
items:
- key: pr-sandbox-argocd-webhook-auth
Expand Down Expand Up @@ -127,3 +131,27 @@ mysql:
key: pr-sandbox-mysql-connection-string
host: ""
port: 3306

redis:
enabled: false
architecture: standalone
auth:
enabled: true
password: ""
master:
persistence:
enabled: false
size: 1Gi
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "200m"
connectionSecret:
create: true
name: pr-sandbox-redis-connection-string
key: pr-sandbox-redis-connection-string
host: ""
port: 6379
1 change: 1 addition & 0 deletions dev/secrets/pr-sandbox-redis-connection-string
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
redis://dev-redis:6379
9 changes: 9 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ secrets:
file: dev/secrets/pr-sandbox-cluster-installation-id
pr-sandbox-mysql-connection-string:
file: dev/secrets/pr-sandbox-mysql-connection-string
pr-sandbox-redis-connection-string:
file: dev/secrets/pr-sandbox-redis-connection-string
pr-sandbox-argocd-webhook-auth:
file: dev/secrets/pr-sandbox-argocd-webhook-auth
pr-sandbox-argocd-readonly-user-password:
Expand All @@ -30,6 +32,12 @@ services:
volumes:
- db_data:/var/lib/mysql

dev-redis:
container_name: redis-dev
image: redis:8.4
ports:
- "6379:6379"

dev-app:
container_name: pr-sandbox-automation-dev-app
build:
Expand All @@ -45,6 +53,7 @@ services:
- pr-sandbox-pr-installation-id
- pr-sandbox-cluster-installation-id
- pr-sandbox-mysql-connection-string
- pr-sandbox-redis-connection-string
- pr-sandbox-argocd-webhook-auth
- pr-sandbox-argocd-readonly-user-password
- pr-sandbox-extra-configs
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ dependencies = [
"pydantic-settings>=2.11.0",
"pyjwt>=2.10.1",
"pymysql>=1.1.2",
"redis>=7.1.0",
"requests>=2.32.5",
"sqlmodel>=0.0.27",
]
Expand Down
11 changes: 11 additions & 0 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.