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: 1 addition & 3 deletions app.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@


from app.factory import create_app
from hexactf.factory import create_app

app = create_app()

Expand Down
Binary file removed app/__pycache__/__init__.cpython-310.pyc
Binary file not shown.
Binary file removed app/__pycache__/__init__.cpython-39.pyc
Binary file not shown.
Binary file removed app/__pycache__/factory.cpython-310.pyc
Binary file not shown.
Binary file removed app/__pycache__/factory.cpython-39.pyc
Binary file not shown.
32 changes: 0 additions & 32 deletions app/extensions/db/repository_test.py

This file was deleted.

9 changes: 0 additions & 9 deletions app/extensions/kafka/__init__.py

This file was deleted.

Binary file removed app/monitoring/__pycache__/__init__.cpython-310.pyc
Binary file not shown.
Binary file removed app/monitoring/__pycache__/__init__.cpython-39.pyc
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File renamed without changes.
Binary file added hexactf/__pycache__/__init__.cpython-310.pyc
Binary file not shown.
Binary file added hexactf/__pycache__/config.cpython-310.pyc
Binary file not shown.
Binary file not shown.
Binary file added hexactf/__pycache__/factory.cpython-310.pyc
Binary file not shown.
File renamed without changes.
Binary file added hexactf/api/__pycache__/__init__.cpython-310.pyc
Binary file not shown.
Binary file not shown.
12 changes: 4 additions & 8 deletions app/api/challenge.py → hexactf/api/challenge_api.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
from json import JSONDecodeError
from logging import log
import sys
from app.monitoring.ctf_metrics_collector import ChallengeMetricsCollector
from flask import Blueprint, jsonify, request

from app.exceptions.api import InvalidRequest
from app.exceptions.userchallenge import UserChallengeCreationError, UserChallengeDeletionError, UserChallengeNotFoundError
from app.extensions.db.repository import UserChallengesRepository
from app.extensions.k8s.client import K8sClient
from app.monitoring.ctf_metrics_collector import challenge_metrics_collector
from hexactf.exceptions.api_exceptions import InvalidRequest
from hexactf.exceptions.userchallenge_exceptions import UserChallengeCreationError, UserChallengeDeletionError, UserChallengeNotFoundError
from hexactf.extensions.db.repository import UserChallengesRepository
from hexactf.extensions.k8s.client import K8sClient

challenge_bp = Blueprint('challenge', __name__)

Expand Down Expand Up @@ -69,7 +66,6 @@ def get_userchallenge_status():
try:
# Challenge 관련 정보 가져오기
res = request.get_json()
# print(f"/status : {res}",file=sys.stderr)
if not res:
raise InvalidRequest(error_msg="Request body is empty or not valid JSON")

Expand Down
File renamed without changes.
File renamed without changes.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

from app.exceptions.base import CustomBaseException
from app.exceptions.error_types import ApiErrorTypes
from hexactf.exceptions.base_exceptions import CustomBaseException
from hexactf.exceptions.error_types import ApiErrorTypes


class APIException(CustomBaseException):
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# app/utils/exceptions.py

from app.exceptions.error_types import ApiErrorTypes
from hexactf.exceptions.error_types import ApiErrorTypes

class CustomBaseException(Exception):
"""
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from app.exceptions.base import CustomBaseException
from app.exceptions.error_types import ApiErrorTypes
from hexactf.exceptions.base_exceptions import CustomBaseException
from hexactf.exceptions.error_types import ApiErrorTypes


class ChallengeException(CustomBaseException):
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from flask import jsonify

from app.exceptions.base import CustomBaseException
from hexactf.exceptions.base_exceptions import CustomBaseException

def register_error_handler(app):
"""CustomBaseException을 처리하는 에러 핸들러"""
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from app.exceptions.base import CustomBaseException
from app.exceptions.error_types import ApiErrorTypes
from hexactf.exceptions.base_exceptions import CustomBaseException
from hexactf.exceptions.error_types import ApiErrorTypes

class QueueException(CustomBaseException):
"""Queue(Kafka) 관련 기본 예외"""
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

from app.exceptions.base import CustomBaseException
from app.exceptions.error_types import ApiErrorTypes
from hexactf.exceptions.base_exceptions import CustomBaseException
from hexactf.exceptions.error_types import ApiErrorTypes

class UserChallengeException(CustomBaseException):
"""UserChallenge 관련 기본 예외"""
Expand Down
File renamed without changes.
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
__all__ = ['MariaDBConfig']

from flask_sqlalchemy import SQLAlchemy
from app.extensions.db.config import MariaDBConfig
from hexactf.extensions.db.config import MariaDBConfig
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from datetime import datetime, timedelta
from app.extensions_manager import db
from hexactf.extensions_manager import db
from sqlalchemy import ForeignKey
from sqlalchemy.orm import relationship

Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
import logging
from sqlite3 import OperationalError
from typing import List, Optional
from typing import Optional
from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy.orm import Session, load_only
from sqlalchemy.sql import text
from contextlib import contextmanager
from app.exceptions.api import InternalServerError
from app.extensions_manager import db
from app.extensions.db.models import Challenges, UserChallenges
from hexactf.exceptions.api_exceptions import InternalServerError
from hexactf.extensions_manager import db
from hexactf.extensions.db.models import Challenges, UserChallenges

class UserChallengesRepository:
def __init__(self, session=None):
Expand Down Expand Up @@ -76,13 +73,9 @@ def update_status(self, challenge: UserChallenges, new_status: str) -> bool:
fresh_challenge = self.session.merge(challenge)
self.session.refresh(fresh_challenge)
fresh_challenge.status = new_status
# self.session.add(challenge) # Add this line to track the object
# self.session.flush()
self.session.commit()
return True
except SQLAlchemyError as e:
# logger.error(f"Error updating challenge status: {e}")

self.session.rollback()
raise InternalServerError(error_msg=f"Error updating challenge status: {e}") from e

Expand Down Expand Up @@ -139,16 +132,6 @@ def get_status(self, challenge_id, username) -> Optional[dict]:
return {'status': challenge.status, 'port': int(challenge.port)}
return {'status': challenge.status}

# class ChallengeRepository:
# def __init__(self):
# self.db_session = db.session

# def get_challenge_name(self, challenge_id: int) -> Optional[str]:
# """챌린지 ID로 챌린지 조회"""
# with self.get_session() as session:
# challenge = session.query(Challenges).get(challenge_id)
# return challenge.title if challenge else None


class ChallengeRepository:
@staticmethod
Expand Down
File renamed without changes.
Binary file not shown.
Binary file not shown.
16 changes: 4 additions & 12 deletions app/extensions/k8s/client.py → hexactf/extensions/k8s/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@

from kubernetes import client, config

from app.exceptions.challenge import ChallengeNotFound
from app.exceptions.userchallenge import UserChallengeCreationError, UserChallengeDeletionError
from app.extensions.db.repository import ChallengeRepository, UserChallengesRepository
from app.monitoring.loki_logger import FlaskLokiLogger
from hexactf.exceptions.challenge_exceptions import ChallengeNotFound
from hexactf.exceptions.userchallenge_exceptions import UserChallengeCreationError, UserChallengeDeletionError
from hexactf.extensions.db.repository import ChallengeRepository, UserChallengesRepository


MAX_RETRIES = 3
Expand Down Expand Up @@ -148,19 +147,12 @@ def _normalize_k8s_name(self, name: str) -> str:
if not name or len(name) > 253:
raise ValueError("이름이 비어있거나 길이가 253자를 초과함")

# 1. 소문자로 변환
name = name.lower()

# 2. 공백 및 비허용 문자 (`[^a-z0-9-]`)를 `-`로 변환
name = re.sub(r'[^a-z0-9-]+', '-', name)

# 3. 하이픈(-)이 연속적으로 나오면 하나로 줄이기
name = re.sub(r'-+', '-', name)

# 4. 앞뒤의 하이픈 제거
name = name.strip('-')

# 5. 최종 길이 검사 (1~253자)
# 최종 길이 검사 (1~253자)
if not name or len(name) > 253:
raise ValueError(f"변환 후에도 유효하지 않은 Kubernetes 리소스 이름: {name}")

Expand Down
9 changes: 9 additions & 0 deletions hexactf/extensions/kafka/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
__version__ = '1.0.0'

__all__ = [
'KafkaEventConsumer',
'KafkaConfig',
]

from hexactf.extensions.kafka.config import KafkaConfig
from hexactf.extensions.kafka.consumer import KafkaEventConsumer
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from typing import Any, Dict
from kafka import KafkaConsumer
import json
from app.exceptions.kafka import QueueProcessingError
from hexactf.exceptions.kafka_exceptions import QueueProcessingError


class StatusMessage:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import logging
from typing import Any, Dict
from app.exceptions.kafka import QueueProcessingError
from app.extensions.db.repository import UserChallengesRepository
from hexactf.exceptions.kafka_exceptions import QueueProcessingError
from hexactf.extensions.db.repository import UserChallengesRepository

logger = logging.getLogger(__name__)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from typing import Optional, Callable
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from app.extensions.kafka import KafkaConfig, KafkaEventConsumer
from hexactf.extensions.kafka import KafkaConfig, KafkaEventConsumer

class FlaskKafkaConsumer:
"""Flask 애플리케이션에서 Kafka 메시지 소비를 관리하는 클래스"""
Expand Down
39 changes: 21 additions & 18 deletions app/factory.py → hexactf/factory.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,16 @@
import os
import sys

from requests import Response
from app.monitoring.ctf_metrics_collector import ChallengeMetricsCollector
from app.monitoring.loki_logger import FlaskLokiLogger
from app.monitoring.system_metrics_collector import SystemMetricsCollector
# from hexactf.monitoring.system_metrics_collector import SystemMetricsCollector
from flask import Flask, g, request
import threading
from datetime import datetime
from typing import Any, Dict, Type
from prometheus_client import REGISTRY, generate_latest, CONTENT_TYPE_LATEST

from app.api.challenge import challenge_bp
from app.config import Config
from app.exceptions.base import CustomBaseException
from app.exceptions.handlers import register_error_handler
from app.extensions.kafka.handler import MessageHandler
from app.extensions_manager import kafka_consumer, db
from hexactf.api.challenge_api import challenge_bp
from hexactf.config import Config
from hexactf.exceptions.base_exceptions import CustomBaseException
from hexactf.extensions.kafka.handler import MessageHandler
from hexactf.extensions_manager import kafka_consumer, db

def start_kafka_consumer(app):
"""Start Kafka consumer in a separate thread"""
Expand All @@ -26,15 +21,22 @@ class FlaskApp:
def __init__(self, config_class: Type[Config] = Config):
self.app = Flask(__name__)
self.app.config.from_object(config_class)

self.logger = FlaskLokiLogger(app_name="challenge-api", loki_url=self.app.config['LOKI_URL']).logger

if os.getenv("TEST_MODE") != "true":
from hexactf.monitoring.loki_logger import FlaskLokiLogger
self.logger = FlaskLokiLogger(app_name="challenge-api", loki_url=self.app.config['LOKI_URL']).logger
else:
self.logger = self.app.logger # Use Flask default logger

# 초기 설정
self._init_extensions()
self._setup_middleware()
self._register_error_handlers()
self._setup_blueprints()
self._init_metrics_collector()

# self._init_metrics_collector()
def _init_extensions(self):
"""Extensions 초기화"""
# Kafka 초기화
Expand All @@ -46,11 +48,12 @@ def _init_extensions(self):
with self.app.app_context():
db.create_all()

def _init_metrics_collector(self):
# @NOTE : 추후 제거 예정
# def _init_metrics_collector(self):

# System 메트릭 수집기 초기화
system_collector = SystemMetricsCollector(self.app)
system_collector.start_collecting()
# # System 메트릭 수집기 초기화
# system_collector = SystemMetricsCollector(self.app)
# system_collector.start_collecting()


def _setup_middleware(self):
Expand Down
File renamed without changes.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
import time
import json
import logging
import sys
import traceback

from app.monitoring.async_handler import AsyncHandler
from hexactf.monitoring.async_handler import AsyncHandler
from logging_loki import LokiHandler



class FlaskLokiLogger:
def __init__(self, app_name,loki_url: str):
self.app_name = app_name
Expand Down
2 changes: 2 additions & 0 deletions pytest.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[pytest]
pythonpath = .
4 changes: 2 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ SQLAlchemy==2.0.20
pymysql==1.0.3
kubernetes==26.1.0
Flask-SQLAlchemy==3.0.2
mariadb>=1.0.11
# mariadb>=1.0.11
prometheus-client==0.19.0
python-logging-loki==0.3.1
flask-prometheus-metrics==1.0.0
psutil==5.9.8
psutil
2 changes: 2 additions & 0 deletions tests/units/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.pytest_cache
__pycache__/
Empty file added tests/units/__init__.py
Empty file.
Empty file added tests/units/db/__init__.py
Empty file.
Loading