From c2f3b4223864c65c9eb3710e3638d76541ba0896 Mon Sep 17 00:00:00 2001 From: UJeans Date: Fri, 1 Nov 2024 13:08:36 +0900 Subject: [PATCH 01/10] =?UTF-8?q?[#29]feat:=20error=5Fenum=20=ED=95=9C?= =?UTF-8?q?=EA=B8=80=20->=20=EC=98=81=EC=96=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/web/exception/enum/error_enum.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/app/web/exception/enum/error_enum.py b/app/web/exception/enum/error_enum.py index bdd988b..b2447aa 100644 --- a/app/web/exception/enum/error_enum.py +++ b/app/web/exception/enum/error_enum.py @@ -4,13 +4,14 @@ class ErrorEnum(Enum): # 400 - TASK_FAIL = "CS-400001", "잠시 후 다시 시도 해주세요" - CODE_SYNTAX_ERROR = "CS-400002", "잘못된 문법입니다." - CODE_CORRECT_FAIL = ("CS-400003", "코드 교정에 실패 했습니다.") - UNKNOWN_ERROR = ("CS-400999", "처리가 필요한 에러입니다.") + TASK_FAIL = "CS-400001", "There is a problem with the service login" + CODE_SYNTAX_ERROR = "CS-400002", "The code is incorrect syntax" + CODE_CORRECT_FAIL = ("CS-400003", "code correct fail") + UNKNOWN_ERROR = ("CS-400999", "The unexpected error") - CODE_EXEC_ERROR = "CS-400004", "지원하지 않는 형식입니다." - INPUT_SIZE_MATCHING_ERROR = "CS-400005", "사용자 입력 개수가 일치하지 않습니다." + + CODE_EXEC_ERROR = "CS-400004", "The format is not supported for security reasons" + INPUT_SIZE_MATCHING_ERROR = "CS-400005", "The number of user inputs does not match." CODE_VISUALIZE_ERROR = "CS-400006", "아직 시각화할 수 없는 문법이 포함되어 있습니다." #500 From 50076fb0eaf90218fc468925a6b3789617f470d6 Mon Sep 17 00:00:00 2001 From: UJeans Date: Fri, 1 Nov 2024 14:41:05 +0900 Subject: [PATCH 02/10] =?UTF-8?q?[#29]feat:=20subprocess=EB=A5=BC=20?= =?UTF-8?q?=EC=9D=B4=EC=9A=A9=ED=95=B4=EC=84=9C=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=8B=A4=ED=96=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/main.py | 1 - app/route/execute/router.py | 5 +- app/route/execute/service/execute_service.py | 48 ++++++++++++-------- app/web/logger.py | 2 +- 4 files changed, 34 insertions(+), 22 deletions(-) diff --git a/app/main.py b/app/main.py index d235c45..870286a 100644 --- a/app/main.py +++ b/app/main.py @@ -36,7 +36,6 @@ # 핸들러 등록 exception_handlers.setup_exception_handlers(app) - @app.get("/edupi-assist/health-check", response_class=JSONResponse) def root(): return JSONResponse( diff --git a/app/route/execute/router.py b/app/route/execute/router.py index f5d9626..72877bb 100644 --- a/app/route/execute/router.py +++ b/app/route/execute/router.py @@ -7,8 +7,8 @@ router = APIRouter() - -@router.post("/v1/execute/visualize") +#@router.post("/v1/execute/code") +#@router.post("/v1/execute/visualize") async def visualize(code_request: CodeRequest): # 코드 실행 execute_service.execute_code(code_request.source_code, code_request.input) @@ -27,6 +27,7 @@ async def visualize(code_request: CodeRequest): @router.post("/v1/execute/code") +@router.post("/v1/execute/visualize") async def execute(code_request: CodeRequest): # 코드 실행 execute_result = execute_service.execute_code(code_request.source_code, code_request.input) diff --git a/app/route/execute/service/execute_service.py b/app/route/execute/service/execute_service.py index 13e4465..e131ad2 100644 --- a/app/route/execute/service/execute_service.py +++ b/app/route/execute/service/execute_service.py @@ -6,38 +6,50 @@ from RestrictedPython import compile_restricted, PrintCollector -from app.config.restricted_python_config import RestrictedPythonConfig from app.route.execute.exception.code_execute_error import CodeExecuteError from app.route.execute.exception.code_syntax_error import CodeSyntaxError -from app.route.execute.exception.input_size_matching_error import InputSizeMatchingError from app.web.exception.enum.error_enum import ErrorEnum +FORBIDDEN_IMPORTS = ["os", "sys", "subprocess", "shutil"] + def execute_code(source_code: str, user_input: str): - code = textwrap.dedent(source_code) - restricted_config = RestrictedPythonConfig(user_input) + if _contains_forbidden_imports(source_code): + # 보안상 실행 안함 + raise CodeExecuteError(ErrorEnum.CODE_EXEC_ERROR) try: - byte_code = compile_restricted(code, filename="", mode="exec") - restricted_locals = restricted_config.get_limited_locals() - restricted_globals = restricted_config.get_limited_globals() - - exec(byte_code, restricted_globals, restricted_locals) - - return _get_print_result(restricted_locals) - - except InputSizeMatchingError as e: - raise CodeExecuteError(e.error_enum) - - except SyntaxError as e: - error = _get_error_message(source_code) - raise CodeSyntaxError(ErrorEnum.CODE_SYNTAX_ERROR, {"error": error} if e.args else {}) + process = subprocess.run( + args=["python3", "-c", source_code], + input=user_input, + capture_output=True, # stdout, stderr 별도의 Pipe에서 처리 + timeout=3, # limit child process execute time + check=True, # CalledProcessError exception if return_code is 0 + text=True + ) + return process.stdout + + # 프로세스 실행 중 비정상 종료 + except subprocess.CalledProcessError as e: + raise CodeSyntaxError(ErrorEnum.CODE_SYNTAX_ERROR, {"error": e.stderr}) + + # 실행 시간 초과 + except subprocess.TimeoutExpired as e: + raise CodeSyntaxError(ErrorEnum.TASK_FAIL) except Exception as e: error = _get_error_message(source_code) raise CodeExecuteError(ErrorEnum.CODE_EXEC_ERROR, {"error": error} if e.args else {}) +def _contains_forbidden_imports(code: str) -> bool: + # 금지된 모듈이 코드에 있는지 확인 + for module in FORBIDDEN_IMPORTS: + if re.search(rf'\bimport\s+{module}\b', code): + return True + return False + + def _get_print_result(restricted_locals): """_print 변수가 존재할 경우, 그 결과 반환.""" if "_print" in restricted_locals: diff --git a/app/web/logger.py b/app/web/logger.py index ee7899c..5e8b10c 100644 --- a/app/web/logger.py +++ b/app/web/logger.py @@ -28,7 +28,7 @@ async def log_request(request: Request, call_next): return response -# Response 로깅 미들웨어 +# # Response 로깅 미들웨어 async def log_response(request: Request, call_next): response = await call_next(request) From 15e268587a55c2e4924ad04b5b7d861ca5243a2f Mon Sep 17 00:00:00 2001 From: UJeans Date: Fri, 1 Nov 2024 14:54:57 +0900 Subject: [PATCH 03/10] =?UTF-8?q?[#29]fix:=20flask8=20=EA=B4=80=EB=A0=A8?= =?UTF-8?q?=20=EC=BD=94=EB=93=9C=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/route/execute/service/execute_service.py | 67 +------------------- 1 file changed, 3 insertions(+), 64 deletions(-) diff --git a/app/route/execute/service/execute_service.py b/app/route/execute/service/execute_service.py index e131ad2..a6a18d6 100644 --- a/app/route/execute/service/execute_service.py +++ b/app/route/execute/service/execute_service.py @@ -1,14 +1,11 @@ import os import re import subprocess -import tempfile -import textwrap - -from RestrictedPython import compile_restricted, PrintCollector from app.route.execute.exception.code_execute_error import CodeExecuteError from app.route.execute.exception.code_syntax_error import CodeSyntaxError from app.web.exception.enum.error_enum import ErrorEnum +from app.web.exception.task_fail_exception import TaskFailException FORBIDDEN_IMPORTS = ["os", "sys", "subprocess", "shutil"] @@ -16,7 +13,7 @@ def execute_code(source_code: str, user_input: str): if _contains_forbidden_imports(source_code): # 보안상 실행 안함 - raise CodeExecuteError(ErrorEnum.CODE_EXEC_ERROR) + raise CodeExecuteError(ErrorEnum.CODE_EXEC_SECURITY_ERROR) try: process = subprocess.run( @@ -33,13 +30,8 @@ def execute_code(source_code: str, user_input: str): except subprocess.CalledProcessError as e: raise CodeSyntaxError(ErrorEnum.CODE_SYNTAX_ERROR, {"error": e.stderr}) - # 실행 시간 초과 - except subprocess.TimeoutExpired as e: - raise CodeSyntaxError(ErrorEnum.TASK_FAIL) - except Exception as e: - error = _get_error_message(source_code) - raise CodeExecuteError(ErrorEnum.CODE_EXEC_ERROR, {"error": error} if e.args else {}) + raise TaskFailException(ErrorEnum.CODE_EXEC_SERVER_ERROR, dict(e.args)) def _contains_forbidden_imports(code: str) -> bool: @@ -49,56 +41,3 @@ def _contains_forbidden_imports(code: str) -> bool: return True return False - -def _get_print_result(restricted_locals): - """_print 변수가 존재할 경우, 그 결과 반환.""" - if "_print" in restricted_locals: - if isinstance(restricted_locals["_print"], PrintCollector): - return "".join(restricted_locals["_print"].txt) # 리스트 요소를 합쳐 하나의 문자열로 - - return "" - - -def _get_error_message(code): - """ 잘못된 코드의 에러 메시지를 추출 ex)'1:26: E999 SyntaxError: '(' was never closed' """ - code = textwrap.dedent(code) - temp_file_path = _create_temp_file_with_code(code) - - result = _run_flake8(temp_file_path) - os.remove(temp_file_path) - - if result.returncode != 0: - return _extract_error_message(result.stdout) - - return None - - -def _create_temp_file_with_code(code) -> str: - """ 임시 파일에 코드 저장후, 파일 경로 반환 """ - with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as temp_file: - temp_file.write(code) - return temp_file.name - - -def _run_flake8(temp_file_path: str) -> subprocess.CompletedProcess: - """ Flake8을 실행하여 코드 검사 """ - result = subprocess.run( - ['flake8', temp_file_path], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - text=True - ) - return result - - -def _extract_error_message(error_string) -> str: - # [행:열: error message] 형태로 추출 - pattern = r"(\d+:\d+: [^\n]+)" - - # 정규 표현식을 사용하여 매칭된 부분 추출 - match = re.search(pattern, error_string) - - if match: - return match.group(1) # 매칭된 부분을 반환 - else: - return "No match found." From 6b0efc6855ddef0928058fb1494389fda8891ca5 Mon Sep 17 00:00:00 2001 From: UJeans Date: Fri, 1 Nov 2024 14:55:11 +0900 Subject: [PATCH 04/10] =?UTF-8?q?[#29]feat:=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=8B=A4=ED=96=89=20=EC=A4=91=20=EC=98=88=EC=99=B8=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/web/exception/enum/error_enum.py | 4 +++- app/web/exception/task_fail_exception.py | 14 ++++++++++++++ app/web/exception_handlers.py | 4 +++- 3 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 app/web/exception/task_fail_exception.py diff --git a/app/web/exception/enum/error_enum.py b/app/web/exception/enum/error_enum.py index b2447aa..7bba2bc 100644 --- a/app/web/exception/enum/error_enum.py +++ b/app/web/exception/enum/error_enum.py @@ -9,15 +9,17 @@ class ErrorEnum(Enum): CODE_CORRECT_FAIL = ("CS-400003", "code correct fail") UNKNOWN_ERROR = ("CS-400999", "The unexpected error") - CODE_EXEC_ERROR = "CS-400004", "The format is not supported for security reasons" + CODE_EXEC_SECURITY_ERROR = "CS-400004", "The format is not supported for security reasons" INPUT_SIZE_MATCHING_ERROR = "CS-400005", "The number of user inputs does not match." CODE_VISUALIZE_ERROR = "CS-400006", "아직 시각화할 수 없는 문법이 포함되어 있습니다." #500 + CODE_EXEC_SERVER_ERROR = "CS-503001", "There is a problem with the execute service login" OPENAI_SERVER_ERROR = ("CS-504001", "Open AI internal server error") OPENAI_MAX_TOKEN_LIMIT = ("CS-504002", "Open AI max token limit") + def __init__(self, code, detail): self.code = code self.detail = detail diff --git a/app/web/exception/task_fail_exception.py b/app/web/exception/task_fail_exception.py new file mode 100644 index 0000000..5e22ff8 --- /dev/null +++ b/app/web/exception/task_fail_exception.py @@ -0,0 +1,14 @@ +from starlette import status + +from app.web.exception.base_exception import BaseCustomException +from app.web.exception.enum.error_enum import ErrorEnum + + +class TaskFailException(BaseCustomException): + def __init__(self, error_enum: ErrorEnum, result: dict = None): + super().__init__( + status_code=status.HTTP_503_SERVICE_UNAVAILABLE, + error_enum=error_enum, + result={} if result is None else result + ) + diff --git a/app/web/exception_handlers.py b/app/web/exception_handlers.py index 7f15e5f..a94a763 100644 --- a/app/web/exception_handlers.py +++ b/app/web/exception_handlers.py @@ -12,6 +12,7 @@ from app.web.exception.enum.error_enum import ErrorEnum from app.web.exception.invalid_exception import InvalidException from app.route.advice.exception.openai_exception import OpenaiException +from app.web.exception.task_fail_exception import TaskFailException from app.web.models.error_response import ErrorResponse @@ -29,7 +30,8 @@ async def invalid_exception_handler(request: Request, exc: InvalidException): ) @app.exception_handler(OpenaiException) - async def openai_exception_handler(request: Request, exc: OpenaiException): + @app.exception_handler(TaskFailException) + async def openai_exception_handler(request: Request, exc: OpenaiException | TaskFailException): logger.info( f"{exc.error_enum.code} - {exc.error_enum.detail}\n") From 3b536ec7522871f6d15e992a7a8440781e39051f Mon Sep 17 00:00:00 2001 From: UJeans Date: Fri, 1 Nov 2024 14:57:54 +0900 Subject: [PATCH 05/10] =?UTF-8?q?[#29]chore:=20=EA=B0=9C=EB=B0=9C=20?= =?UTF-8?q?=EB=95=8C=20=EC=9E=A0=EC=8B=9C=20=EB=B3=80=EA=B2=BD=ED=95=9C?= =?UTF-8?q?=EA=B1=B0=20=EB=90=98=EB=8F=8C=EB=A6=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/route/execute/router.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/route/execute/router.py b/app/route/execute/router.py index 72877bb..f5d9626 100644 --- a/app/route/execute/router.py +++ b/app/route/execute/router.py @@ -7,8 +7,8 @@ router = APIRouter() -#@router.post("/v1/execute/code") -#@router.post("/v1/execute/visualize") + +@router.post("/v1/execute/visualize") async def visualize(code_request: CodeRequest): # 코드 실행 execute_service.execute_code(code_request.source_code, code_request.input) @@ -27,7 +27,6 @@ async def visualize(code_request: CodeRequest): @router.post("/v1/execute/code") -@router.post("/v1/execute/visualize") async def execute(code_request: CodeRequest): # 코드 실행 execute_result = execute_service.execute_code(code_request.source_code, code_request.input) From a6e053f13c7c3330f2d38b8bddf27cdeb65eacc7 Mon Sep 17 00:00:00 2001 From: UJeans Date: Fri, 1 Nov 2024 15:11:17 +0900 Subject: [PATCH 06/10] =?UTF-8?q?[#29]chore:=20=EA=B8=B0=EC=A1=B4=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=82=AD=EC=A0=9C=EC=97=90=20=EB=94=B0?= =?UTF-8?q?=EB=A5=B8=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/__init__.py | 0 tests/conftest.py | 0 .../execute/service/test_execute_service.py | 57 ------------------- 3 files changed, 57 deletions(-) delete mode 100644 tests/__init__.py delete mode 100644 tests/conftest.py delete mode 100644 tests/route/execute/service/test_execute_service.py diff --git a/tests/__init__.py b/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tests/conftest.py b/tests/conftest.py deleted file mode 100644 index e69de29..0000000 diff --git a/tests/route/execute/service/test_execute_service.py b/tests/route/execute/service/test_execute_service.py deleted file mode 100644 index a5dbef9..0000000 --- a/tests/route/execute/service/test_execute_service.py +++ /dev/null @@ -1,57 +0,0 @@ -import os - -from app.route.execute.service import execute_service - - -def test__create_temp_file_with_code(): - # 테스트할 코드 샘플 - sample_code = "print('Hello, World!')" - - temp_file_path = execute_service._create_temp_file_with_code(sample_code) - - try: - assert os.path.isfile(temp_file_path) - - # 파일 내용을 확인 - with open(temp_file_path, 'r') as temp_file: - file_content = temp_file.read() - assert file_content == sample_code - finally: - # 테스트 후 임시 파일 삭제 - if os.path.isfile(temp_file_path): - os.remove(temp_file_path) - - -def test__run_flake8_fail(): - sample_code = '\nprint(a)\n' - temp_file_path = execute_service._create_temp_file_with_code(sample_code) - - result = execute_service._run_flake8(temp_file_path) - # 테스트 후 임시 파일 삭제 - if os.path.isfile(temp_file_path): - os.remove(temp_file_path) - - print(result.stdout) - assert result.returncode != 0 - - -def test__run_flake8_success(): - sample_code = '\nprint("hello world")\n' - temp_file_path = execute_service._create_temp_file_with_code(sample_code) - - result = execute_service._run_flake8(temp_file_path) - # 테스트 후 임시 파일 삭제 - if os.path.isfile(temp_file_path): - os.remove(temp_file_path) - - assert result.returncode == 0 - - -def test__extract_error_message(): - origin = "/var/folders/0n/yb899qnj0vddx24q31c2t45h0000gn/T/tmpigduybq_.py:2:7: F821 undefined name 'a'" - - result = execute_service._extract_error_message(origin) - - assert result == "2:7: F821 undefined name 'a'" - - From acab4e7574b67d34dd3d0fefebd3f5f7297489bb Mon Sep 17 00:00:00 2001 From: UJeans Date: Fri, 1 Nov 2024 15:19:47 +0900 Subject: [PATCH 07/10] =?UTF-8?q?[#29]test:=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/route/execute/service/execute_service.py | 1 - tests/conftest.py | 2 ++ tests/route/execute/test_execute_service.py | 7 +++++++ 3 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 tests/conftest.py create mode 100644 tests/route/execute/test_execute_service.py diff --git a/app/route/execute/service/execute_service.py b/app/route/execute/service/execute_service.py index a6a18d6..4c7144c 100644 --- a/app/route/execute/service/execute_service.py +++ b/app/route/execute/service/execute_service.py @@ -1,4 +1,3 @@ -import os import re import subprocess diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..601241a --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,2 @@ +def test_placeholder(): + assert True \ No newline at end of file diff --git a/tests/route/execute/test_execute_service.py b/tests/route/execute/test_execute_service.py new file mode 100644 index 0000000..28c866d --- /dev/null +++ b/tests/route/execute/test_execute_service.py @@ -0,0 +1,7 @@ +from app.route.execute.service.execute_service import _contains_forbidden_imports + + +def test__contains_forbidden_imports(): + code = "import os\n" + + assert _contains_forbidden_imports(code) is True From 5c7398dcd87b6685aaac4ca6b7b7d5cf98cbdca7 Mon Sep 17 00:00:00 2001 From: UJeans Date: Fri, 1 Nov 2024 15:34:09 +0900 Subject: [PATCH 08/10] =?UTF-8?q?[#29]chore:=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/__init__.py | 0 tests/route/execute/test_execute_service.py | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 tests/__init__.py diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/route/execute/test_execute_service.py b/tests/route/execute/test_execute_service.py index 28c866d..6d67928 100644 --- a/tests/route/execute/test_execute_service.py +++ b/tests/route/execute/test_execute_service.py @@ -1,7 +1,7 @@ -from app.route.execute.service.execute_service import _contains_forbidden_imports +from app.route.execute.service import execute_service def test__contains_forbidden_imports(): code = "import os\n" - assert _contains_forbidden_imports(code) is True + assert execute_service._contains_forbidden_imports(code) is True From 723510c0dda12567f85713f17114aaad6286e02c Mon Sep 17 00:00:00 2001 From: UJeans Date: Mon, 4 Nov 2024 13:58:27 +0900 Subject: [PATCH 09/10] =?UTF-8?q?[#29]chore:=20'#'=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/web/logger.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/web/logger.py b/app/web/logger.py index 5e8b10c..ee7899c 100644 --- a/app/web/logger.py +++ b/app/web/logger.py @@ -28,7 +28,7 @@ async def log_request(request: Request, call_next): return response -# # Response 로깅 미들웨어 +# Response 로깅 미들웨어 async def log_response(request: Request, call_next): response = await call_next(request) From a130b3ebf0fec3dc051c71853e713ef98a747aa2 Mon Sep 17 00:00:00 2001 From: UJeans Date: Mon, 4 Nov 2024 14:02:34 +0900 Subject: [PATCH 10/10] =?UTF-8?q?[#29]chore:=20error=5Fenum=20=EC=98=81?= =?UTF-8?q?=EC=96=B4=EB=A1=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/web/exception/enum/error_enum.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/web/exception/enum/error_enum.py b/app/web/exception/enum/error_enum.py index 7bba2bc..b76b9ab 100644 --- a/app/web/exception/enum/error_enum.py +++ b/app/web/exception/enum/error_enum.py @@ -6,18 +6,18 @@ class ErrorEnum(Enum): # 400 TASK_FAIL = "CS-400001", "There is a problem with the service login" CODE_SYNTAX_ERROR = "CS-400002", "The code is incorrect syntax" - CODE_CORRECT_FAIL = ("CS-400003", "code correct fail") - UNKNOWN_ERROR = ("CS-400999", "The unexpected error") + CODE_CORRECT_FAIL = "CS-400003", "code correct fail" + UNKNOWN_ERROR = "CS-400999", "The unexpected error" CODE_EXEC_ERROR = "CS-400004", "The format is not supported for security reasons" CODE_EXEC_SECURITY_ERROR = "CS-400004", "The format is not supported for security reasons" INPUT_SIZE_MATCHING_ERROR = "CS-400005", "The number of user inputs does not match." - CODE_VISUALIZE_ERROR = "CS-400006", "아직 시각화할 수 없는 문법이 포함되어 있습니다." + CODE_VISUALIZE_ERROR = "CS-400006", "It contains syntax that we can't visualize yet." #500 CODE_EXEC_SERVER_ERROR = "CS-503001", "There is a problem with the execute service login" - OPENAI_SERVER_ERROR = ("CS-504001", "Open AI internal server error") - OPENAI_MAX_TOKEN_LIMIT = ("CS-504002", "Open AI max token limit") + OPENAI_SERVER_ERROR = "CS-504001", "Open AI internal server error" + OPENAI_MAX_TOKEN_LIMIT = "CS-504002", "Open AI max token limit" def __init__(self, code, detail):