wip: 修改了大量漏洞
This commit is contained in:
parent
3a8b1e4054
commit
3cf2411c4a
|
|
@ -1,9 +1,31 @@
|
|||
待解决问题
|
||||
---
|
||||
## 问题栏
|
||||
#### 🔴 核心缺陷与修复 (Bug Fixes & Stability)
|
||||
- [ ] /pretor/core/individual每个template进行优化
|
||||
- [ ] /pretor/worker_individual待完善复合子个体和基础子个体
|
||||
|
||||
#### 🛡️ 安全与合规 (Security & Auth)
|
||||
|
||||
|
||||
#### ⚡ 性能与资源优化 (Performance & Scalability)
|
||||
- [ ] 增加对应全workflow的情况追踪,使得在任务运行中人机交互更加自然方便
|
||||
|
||||
#### 🏗️ 架构演进 (Architecture & Refactoring)
|
||||
- [ ] 使用fastapi-users完善用户系统
|
||||
- [x] /pretor/api的接口函数进行重构
|
||||
- [ ] /dockerfile待完善
|
||||
|
||||
---
|
||||
## 日志
|
||||
#### 2026/4/12
|
||||
- [ ] /pretor/tool_plugin/approval/approval.py的approval函数event改为依赖注入
|
||||
- [x] /pretor/api的接口函数进行重构
|
||||
- [ ] /pretor/core/individual每个template进行优化
|
||||
- [ ] /pretor/worker_individual待完善复合子个体和基础子个体
|
||||
- [ ] /pretor/api待完善
|
||||
- [ ] /dockerfile待完善
|
||||
- [ ] /dockerfile待完善
|
||||
|
||||
#### 2026/4/16
|
||||
- [ ] 发布v0.1.0正式版
|
||||
- [ ] 增加对应全workflow的情况追踪,使得在任务运行中人机交互更加自然方便
|
||||
- [ ] 使用fastapi-users完善用户系统
|
||||
|
|
@ -12,7 +12,7 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
from typing import Union
|
||||
|
||||
from pretor.utils.ray_hook import ray_actor_hook
|
||||
from fastapi import APIRouter, Request, Depends
|
||||
from pydantic import BaseModel
|
||||
from pretor.utils.access import Accessor, TokenData
|
||||
|
|
@ -30,22 +30,21 @@ class AgentLocalRegister(BaseModel):
|
|||
|
||||
@agent_router.post("")
|
||||
async def load_agent(agent_register: Union[AgentRegister, AgentLocalRegister],
|
||||
request: Request,
|
||||
_: TokenData = Depends(Accessor.get_current_user)):
|
||||
global_state_machine = request.app.state.global_state_machine
|
||||
global_state_machine = ray_actor_hook("global_state_machine")
|
||||
if isinstance(agent_register, AgentLocalRegister):
|
||||
pass
|
||||
|
||||
elif isinstance(agent_register, AgentRegister):
|
||||
match agent_register.individual_title:
|
||||
case "supervisory_node":
|
||||
node = request.app.state.supervisory_node
|
||||
node = ray_actor_hook("supervisory_node")
|
||||
node.create_agent.remote(global_state_machine,agent_register.provider_title,agent_register.model_id)
|
||||
case "consciousness_node":
|
||||
node = request.app.state.consciousness_node
|
||||
node = ray_actor_hook("consciousness_node")
|
||||
node.create_agent.remote(global_state_machine,agent_register.provider_title,agent_register.model_id)
|
||||
case "control_node":
|
||||
node = request.app.state.control_node
|
||||
node = ray_actor_hook("control_node")
|
||||
node.create_agent.remote(global_state_machine,agent_register.provider_title,agent_register.model_id)
|
||||
case _:
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -12,10 +12,11 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from fastapi import APIRouter, Request
|
||||
from fastapi import APIRouter
|
||||
from pydantic import BaseModel
|
||||
from pretor.utils.access import Accessor
|
||||
from fastapi.concurrency import run_in_threadpool
|
||||
from pretor.utils.ray_hook import ray_actor_hook
|
||||
|
||||
auth_router = APIRouter(prefix="/api/v1/auth", tags=["auth"])
|
||||
|
||||
|
|
@ -24,10 +25,10 @@ class UserRegister(BaseModel):
|
|||
password: str
|
||||
|
||||
@auth_router.post("/register")
|
||||
async def create_user(user_register: UserRegister, request: Request):
|
||||
postgres_database = request.app.state.postgres_database
|
||||
async def create_user(user_register: UserRegister):
|
||||
postgres_database = ray_actor_hook("postgres_database")
|
||||
hashed_password = await run_in_threadpool(Accessor.hash_password, user_register.password)
|
||||
user = await postgres_database.auth_database.add_user.remote(user_register.user_name, hashed_password)
|
||||
user = await postgres_database.add_user.remote(user_register.user_name, hashed_password)
|
||||
return {"message": "success", "user_id": user.user_id}
|
||||
|
||||
class UserLogin(BaseModel):
|
||||
|
|
@ -35,9 +36,9 @@ class UserLogin(BaseModel):
|
|||
password: str
|
||||
|
||||
@auth_router.post("/login")
|
||||
async def login_user(user_login: UserLogin, request: Request):
|
||||
postgres_database = request.app.state.postgres_database
|
||||
user = await postgres_database.auth_database.login_user.remote(user_login.user_name)
|
||||
async def login_user(user_login: UserLogin):
|
||||
postgres_database = ray_actor_hook("postgres_database")
|
||||
user = await postgres_database.login_user.remote(user_login.user_name)
|
||||
if user.user_name != user_login.user_name:
|
||||
pass
|
||||
token = await run_in_threadpool(Accessor.login_hashed_password, user, user_login.password)
|
||||
|
|
|
|||
|
|
@ -14,10 +14,10 @@
|
|||
|
||||
from fastapi import APIRouter, Request, Depends, HTTPException, status, WebSocket, WebSocketDisconnect
|
||||
from pydantic import BaseModel
|
||||
|
||||
from pretor.utils.access import Accessor, TokenData
|
||||
from pretor.api.platform.event import PretorEvent
|
||||
from loguru import logger
|
||||
from pretor.utils.ray_hook import ray_actor_hook
|
||||
|
||||
client_router = APIRouter(prefix="/api/v1/adapter/client", tags=["client"])
|
||||
|
||||
|
|
@ -26,7 +26,6 @@ class Message(BaseModel):
|
|||
|
||||
@client_router.post("")
|
||||
async def create_message(message: Message,
|
||||
request: Request,
|
||||
token_data: TokenData = Depends(Accessor.get_current_user)):
|
||||
logger.info("收到消息,来源:客户端")
|
||||
logger.debug(f"消息内容:{message.message}")
|
||||
|
|
@ -34,11 +33,11 @@ async def create_message(message: Message,
|
|||
user_id=str(token_data.user_id),
|
||||
user_name=token_data.user_name,
|
||||
message=message.message)
|
||||
supervisory_node = request.app.state.supervisory_node
|
||||
supervisory_node = ray_actor_hook("supervisor_node")
|
||||
message = await supervisory_node.working.remote(event)
|
||||
if message == "任务已创建":
|
||||
global_state_machine = request.app.state.global_state_machine
|
||||
global_state_machine.add.remote(event)
|
||||
global_state_machine = ray_actor_hook("global_state_machine")
|
||||
global_state_machine.add_event.remote(event)
|
||||
return {"message": event.event_id}
|
||||
elif message == "未知相应类型":
|
||||
raise HTTPException(
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ from typing import Literal
|
|||
from pretor.utils.access import TokenData, Accessor
|
||||
from typing import Dict
|
||||
from pretor.core.global_state_machine.model_provider.base_provider import Provider
|
||||
|
||||
from pretor.utils.ray_hook import ray_actor_hook
|
||||
|
||||
provider_router = APIRouter(prefix="/api/v1/provider", tags=["provider"])
|
||||
|
||||
|
|
@ -30,9 +30,8 @@ class ProviderRegister(BaseModel):
|
|||
|
||||
@provider_router.post("")
|
||||
async def create_provider(provider_register: ProviderRegister,
|
||||
request: Request,
|
||||
token_data: TokenData = Depends(Accessor.get_current_user)) -> None:
|
||||
global_state_machine = request.app.state.global_state_machine
|
||||
global_state_machine = ray_actor_hook("global_state_machine")
|
||||
await global_state_machine.add_provider.remote(provider_type=provider_register.provider_type,
|
||||
provider_title=provider_register.provider_title,
|
||||
provider_url=provider_register.provider_url,
|
||||
|
|
@ -41,8 +40,7 @@ async def create_provider(provider_register: ProviderRegister,
|
|||
|
||||
|
||||
@provider_router.get("/list")
|
||||
async def get_provider_list(request: Request,
|
||||
_: TokenData = Depends(Accessor.get_current_user)) -> Dict[str, Provider]:
|
||||
global_state_machine = request.app.state.global_state_machine
|
||||
async def get_provider_list(_: TokenData = Depends(Accessor.get_current_user)) -> Dict[str, Provider]:
|
||||
global_state_machine = ray_actor_hook("global_state_machine")
|
||||
provider_list: Dict[str, Provider] = await global_state_machine.get_provider_list.remote()
|
||||
return {"provider_list": provider_list}
|
||||
|
|
@ -28,6 +28,8 @@ async def create_workflow_template(workflow_template: WorkflowTemplate,
|
|||
await global_state_machine.workflow_template_generate.remote(workflow_template)
|
||||
return {"message": "创建成功"}
|
||||
|
||||
|
||||
|
||||
class Skill(BaseModel):
|
||||
repo_url: str
|
||||
path: str | None
|
||||
|
|
@ -36,6 +38,7 @@ class Skill(BaseModel):
|
|||
async def install_skill(skill: Skill,
|
||||
_: TokenData = Depends(Accessor.get_current_user)):
|
||||
global_state_machine = ray_actor_hook("global_state_machine")
|
||||
# noinspection PyUnresolvedReferences
|
||||
await viceroy.install_skill_async(url = skill.repo_url,
|
||||
path = skill.path,
|
||||
output = "./pretor/plugin/tool_plugin")
|
||||
|
|
|
|||
|
|
@ -38,12 +38,6 @@ class PretorGateway:
|
|||
self.app = FastAPI()
|
||||
self.gateway = {}
|
||||
|
||||
self.app.state.postgres_database = postgres_database
|
||||
self.app.state.global_state_machine = global_state_machine
|
||||
self.app.state.supervisory_node = supervisory_node
|
||||
self.app.state.consciousness_node = consciousness_node
|
||||
self.app.state.control_node = control_node
|
||||
|
||||
self.app.include_router(client_router)
|
||||
self.app.include_router(auth_router)
|
||||
self.app.include_router(provider_router)
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ class AuthDatabase:
|
|||
@database_exception
|
||||
async def add_user(self, user_name: str, hashed_password: str) -> User:
|
||||
user = User(user_name=user_name, hashed_password=hashed_password)
|
||||
async with self.async_session_maker as session:
|
||||
async with self.async_session_maker() as session:
|
||||
session.add(user)
|
||||
await session.commit()
|
||||
await session.refresh(user)
|
||||
|
|
|
|||
|
|
@ -37,12 +37,26 @@ class PostgresDatabase:
|
|||
self.auth_database = AuthDatabase(self.async_session_maker)
|
||||
self.provider_database = ProviderDatabase(self.async_session_maker)
|
||||
|
||||
async def init_db(self) -> None:
|
||||
async with self.async_engine.begin() as conn:
|
||||
await conn.run_sync(SQLModel.metadata.create_all)
|
||||
|
||||
# provider_database操作
|
||||
async def get_providers(self):
|
||||
return await self.provider_database.get_provider()
|
||||
|
||||
async def add_provider(self, **kwargs):
|
||||
return await self.provider_database.add_provider(**kwargs)
|
||||
|
||||
async def init_db(self) -> None:
|
||||
async with self.async_engine.begin() as conn:
|
||||
await conn.run_sync(SQLModel.metadata.create_all)
|
||||
# auth_database操作
|
||||
async def add_user(self, **kwargs):
|
||||
return await self.auth_database.add_user(**kwargs)
|
||||
|
||||
async def change_password(self, **kwargs):
|
||||
return await self.auth_database.change_password(**kwargs)
|
||||
|
||||
async def delete_user(self, **kwargs):
|
||||
return await self.auth_database.delete_user(**kwargs)
|
||||
|
||||
async def login_user(self, **kwargs):
|
||||
return await self.auth_database.login_user(**kwargs)
|
||||
|
|
@ -158,7 +158,7 @@ class GlobalStateMachine:
|
|||
|
||||
|
||||
###以下为workflow_template_manager方法
|
||||
def workflow_template_generator(self, workflow_template: WorkflowTemplate) -> None:
|
||||
def workflow_template_generate(self, workflow_template: WorkflowTemplate) -> None:
|
||||
self.global_workflow_template_manager.generate_workflow_template(workflow_template)
|
||||
|
||||
###以下为skill_manager方法
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@ class WorkflowEngine:
|
|||
"""工作流:当前WorkflowEngine待执行的workflow"""
|
||||
self._steps_by_id: Dict[int, WorkStep] = {step.step: step for step in self.workflow.work_link}
|
||||
"""步骤表:将当前workflow的步骤序号和步骤内容存放"""
|
||||
|
||||
self.consciousness_node = consciousness_node
|
||||
"""意识节点"""
|
||||
self.control_node = control_node
|
||||
|
|
@ -238,6 +237,9 @@ class WorkflowRunningEngine:
|
|||
}
|
||||
self.workflow_queue = asyncio.Queue()
|
||||
|
||||
async def put_workflow(self, workflow: PretorWorkflow) -> None:
|
||||
await self.workflow_queue.put(workflow)
|
||||
|
||||
async def runner(self, i: int) -> None:
|
||||
"""
|
||||
runner方法,从self.workflow_queue中不断取出任务并执行
|
||||
|
|
|
|||
|
|
@ -19,18 +19,20 @@ from typing import Optional
|
|||
from fastapi import HTTPException, status, Request
|
||||
from pydantic import BaseModel, ValidationError
|
||||
from pretor.core.database.table.user import User
|
||||
from passlib.context import CryptContext
|
||||
from pwdlib import PasswordHash
|
||||
from pwdlib.hashers.bcrypt import BcryptHasher
|
||||
|
||||
|
||||
class TokenData(BaseModel):
|
||||
user_id: str
|
||||
username: Optional[str] = None
|
||||
exp: Optional[int] = None
|
||||
|
||||
|
||||
SECRET_KEY = os.getenv("SECRET_KEY")
|
||||
ALGORITHM = "HS256"
|
||||
ACCESS_TOKEN_EXPIRE_MINUTES = 60 * 24 # 默认有效期 1 天
|
||||
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
|
||||
ACCESS_TOKEN_EXPIRE_MINUTES = 60 * 24
|
||||
|
||||
password_hasher = PasswordHash.recommended()
|
||||
|
||||
|
||||
class Accessor:
|
||||
|
|
@ -54,19 +56,16 @@ class Accessor:
|
|||
detail="无效的认证凭证",
|
||||
)
|
||||
|
||||
|
||||
|
||||
@staticmethod
|
||||
def _create_access_token(data: dict) -> str:
|
||||
to_encode = data.copy()
|
||||
expire = datetime.now(timezone.utc) + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
|
||||
to_encode.update({"exp": int(expire.timestamp())})
|
||||
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
|
||||
return encoded_jwt
|
||||
return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
|
||||
|
||||
@staticmethod
|
||||
def _verify_password(plain_password: str, hashed_password: str) -> bool:
|
||||
return pwd_context.verify(plain_password, hashed_password)
|
||||
return password_hasher.verify(plain_password, hashed_password)
|
||||
|
||||
@staticmethod
|
||||
def get_current_user(request: Request) -> TokenData:
|
||||
|
|
@ -92,8 +91,8 @@ class Accessor:
|
|||
detail="用户名或密码错误",
|
||||
)
|
||||
token_payload = {
|
||||
"user_id": str(user.id), # 确保是字符串格式
|
||||
"username": user.username
|
||||
"user_id": str(user.user_id),
|
||||
"username": user.user_name
|
||||
}
|
||||
return Accessor._create_access_token(data=token_payload)
|
||||
|
||||
|
|
@ -103,4 +102,4 @@ class Accessor:
|
|||
raise ValueError("密码不能为空")
|
||||
if len(password) < 6:
|
||||
raise ValueError("密码长度不能小于 6 位")
|
||||
return pwd_context.hash(password)
|
||||
return password_hasher.hash(password)
|
||||
|
|
@ -11,8 +11,8 @@ dependencies = [
|
|||
"httpx>=0.28.1",
|
||||
"jinja2>=3.1.6",
|
||||
"loguru>=0.7.3",
|
||||
"passlib[bcrypt]>=1.7.4",
|
||||
"pretor-viceroy>=0.2.0",
|
||||
"pwdlib[bcrypt]>=0.3.0",
|
||||
"pydantic-ai>=1.73.0",
|
||||
"pyfiglet>=1.0.4",
|
||||
"python-ulid>=3.1.0",
|
||||
|
|
|
|||
32
uv.lock
32
uv.lock
|
|
@ -2915,20 +2915,6 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/42/32/658973117bf0fd82a24abbfb94fe73a5e86216e49342985e10acce54775a/partial_json_parser-0.2.1.1.post7-py3-none-any.whl", hash = "sha256:145119e5eabcf80cbb13844a6b50a85c68bf99d376f8ed771e2a3c3b03e653ae", size = 10877, upload-time = "2025-11-17T07:27:40.457Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "passlib"
|
||||
version = "1.7.4"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/b6/06/9da9ee59a67fae7761aab3ccc84fa4f3f33f125b370f1ccdb915bf967c11/passlib-1.7.4.tar.gz", hash = "sha256:defd50f72b65c5402ab2c573830a6978e5f202ad0d984793c8dde2c4152ebe04", size = 689844, upload-time = "2020-10-08T19:00:52.121Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/3b/a4/ab6b7589382ca3df236e03faa71deac88cae040af60c071a78d254a62172/passlib-1.7.4-py2.py3-none-any.whl", hash = "sha256:aa6bca462b8d8bda89c70b382f0c298a20b5560af6cbfa2dce410c0a2fb669f1", size = 525554, upload-time = "2020-10-08T19:00:49.856Z" },
|
||||
]
|
||||
|
||||
[package.optional-dependencies]
|
||||
bcrypt = [
|
||||
{ name = "bcrypt" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pathable"
|
||||
version = "0.5.0"
|
||||
|
|
@ -3025,8 +3011,8 @@ dependencies = [
|
|||
{ name = "httpx" },
|
||||
{ name = "jinja2" },
|
||||
{ name = "loguru" },
|
||||
{ name = "passlib", extra = ["bcrypt"] },
|
||||
{ name = "pretor-viceroy" },
|
||||
{ name = "pwdlib", extra = ["bcrypt"] },
|
||||
{ name = "pydantic-ai", version = "1.75.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.14'" },
|
||||
{ name = "pydantic-ai", version = "1.84.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.14'" },
|
||||
{ name = "pyfiglet" },
|
||||
|
|
@ -3055,8 +3041,8 @@ requires-dist = [
|
|||
{ name = "httpx", specifier = ">=0.28.1" },
|
||||
{ name = "jinja2", specifier = ">=3.1.6" },
|
||||
{ name = "loguru", specifier = ">=0.7.3" },
|
||||
{ name = "passlib", extras = ["bcrypt"], specifier = ">=1.7.4" },
|
||||
{ name = "pretor-viceroy", specifier = ">=0.2.0" },
|
||||
{ name = "pwdlib", extras = ["bcrypt"], specifier = ">=0.3.0" },
|
||||
{ name = "pydantic-ai", specifier = ">=1.73.0" },
|
||||
{ name = "pyfiglet", specifier = ">=1.0.4" },
|
||||
{ name = "python-ulid", specifier = ">=3.1.0" },
|
||||
|
|
@ -3245,6 +3231,20 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/8c/c7/7bb2e321574b10df20cbde462a94e2b71d05f9bbda251ef27d104668306a/psutil-7.2.2-cp37-abi3-win_arm64.whl", hash = "sha256:8c233660f575a5a89e6d4cb65d9f938126312bca76d8fe087b947b3a1aaac9ee", size = 134617, upload-time = "2026-01-28T18:15:36.514Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pwdlib"
|
||||
version = "0.3.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/5f/41/a7c0d8a003c36ce3828ae3ed0391fe6a15aad65f082dbd6bec817ea95c0b/pwdlib-0.3.0.tar.gz", hash = "sha256:6ca30f9642a1467d4f5d0a4d18619de1c77f17dfccb42dd200b144127d3c83fc", size = 215810, upload-time = "2025-10-25T12:44:24.395Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/62/0c/9086a357d02a050fbb3270bf5043ac284dbfb845670e16c9389a41defc9e/pwdlib-0.3.0-py3-none-any.whl", hash = "sha256:f86c15c138858c09f3bba0a10984d4f9178158c55deaa72eac0210849b1a140d", size = 8633, upload-time = "2025-10-25T12:44:23.406Z" },
|
||||
]
|
||||
|
||||
[package.optional-dependencies]
|
||||
bcrypt = [
|
||||
{ name = "bcrypt" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "py-cpuinfo"
|
||||
version = "9.0.0"
|
||||
|
|
|
|||
Loading…
Reference in New Issue