Feature/delta team/epic r04 (#7)
CI / test (push) Canceled after 0s

## Summary

epic r04 - begin refactor

## Change Type

- [x] Cowork feature
- [ ] Bug fix
- [ ] Core AI contribution
- [ ] Test / hardening
- [ ] Performance
- [ ] Documentation

## Related Work

Cowork Task:

Core Repo: http://34.143.229.138/gitea-admin/fsg-ai-core-assets

Core AI Issue:

Core Task:

Related PR:

## Scope

What is intentionally included?

What is intentionally NOT included?

## Validation

- [ ] Unit tests
- [ ] Integration tests
- [ ] Manual verification
- [ ] Regression check

Commands / evidence:

## Security Impact

Permission / credential / network / customer data impact:

## Compatibility

- [ ] No breaking change
- [ ] Breaking change documented

## Reviewer Notes

Anything Cowork reviewers should pay attention to.

---------

Co-authored-by: Anh Tran Nguyen Minh <anhtnm1@fpt.com>
Co-authored-by: Huong Le Thi Thien <huongltt35@fpt.com>
Co-authored-by: Nam Pham Dinh Thanh <nampdt@fpt.com>
Co-authored-by: Vu Dam Tuan <vudt15@fpt.com>
Co-authored-by: Hiep Ha Van <hiephv3@fpt.com>
Co-authored-by: Lam Hoang Van <lamhv7@fpt.com>
Reviewed-on: #7
Co-authored-by: Duy Le Huu <duylh19@fpt.com>
This commit was merged in pull request #7.
This commit is contained in:
2026-08-31 05:15:13 +00:00
committed by gitea-admin
co-authored by anhtnm1 huongltt35 Nam Pham Dinh Thanh vudt15 Hiep Ha Van lamhv7
parent 86c27e2e79
commit f9f6bc01fd
496 changed files with 68421 additions and 19688 deletions
+13 -19
View File
@@ -27,27 +27,12 @@ from __future__ import annotations
import json
import re
from dataclasses import dataclass
from typing import List, Optional
from ..providers.base import Provider
from . import security_rules
class SecurityBlocked(RuntimeError):
"""A guardrail refused an action. ``verdict`` carries the full detail for
the admin alert; ``str(exc)`` is the short, user-facing reason."""
def __init__(self, verdict: "SecurityVerdict"):
super().__init__(verdict.reason or f"Blocked by agent security ({verdict.layer}).")
self.verdict = verdict
@dataclass
class SecurityVerdict:
allowed: bool
reason: str = ""
layer: str = "" # "prompt" | "attachment" | "command"
from .agent_security_alert import notify_admin
from .agent_security_types import SecurityBlocked, SecurityVerdict
def combined_rules_text(config, max_chars: int = 8000, agent_kind: str = "cowork") -> str:
@@ -164,6 +149,10 @@ def _ai_verdict(provider: Provider, system_prompt: str, content: str, layer: str
def validate_prompt(provider: Provider, user_text: str, rules_text: str) -> SecurityVerdict:
"""Nhờ model xét prompt người dùng theo bộ luật an toàn.
Prompt rỗng thì cho qua ngay, khỏi tốn một lượt gọi.
"""
if not (user_text or "").strip():
return SecurityVerdict(True, "", "prompt")
system = _PROMPT_SYSTEM.format(rules=rules_text or "(no additional rules configured)")
@@ -172,6 +161,7 @@ def validate_prompt(provider: Provider, user_text: str, rules_text: str) -> Secu
def validate_attachment(provider: Provider, filename: str, content: str,
rules_text: str) -> SecurityVerdict:
"""Nhờ model xét nội dung một tệp đính kèm theo bộ luật an toàn."""
if not (content or "").strip():
return SecurityVerdict(True, "", "attachment")
system = _ATTACHMENT_SYSTEM.format(rules=rules_text or "(no additional rules configured)")
@@ -180,6 +170,11 @@ def validate_attachment(provider: Provider, filename: str, content: str,
def validate_command(provider: Provider, command: str,
rules_text: str, ai_enabled: bool) -> SecurityVerdict:
"""Nhờ model xét một lệnh shell theo bộ luật an toàn.
``ai_enabled=False`` thì cho qua — người dùng đã tắt lớp xét bằng AI, bộ luật
tĩnh vẫn chạy ở chỗ khác.
"""
if not ai_enabled:
return SecurityVerdict(True, "", "command")
system = _COMMAND_SYSTEM.format(rules=rules_text or "(no additional rules configured)")
@@ -188,6 +183,7 @@ def validate_command(provider: Provider, command: str,
# ---- call-site convenience wrappers (used by chat_agent.py / code_agent.py) --
def _security_conf(config) -> dict:
"""Nhóm cấu hình ``agent_security``; không có config thì trả dict rỗng."""
return (config.data.get("agent_security", {}) if config is not None else {})
@@ -236,7 +232,6 @@ def enforce_prompt(provider: Provider, messages: List[dict], config, emit,
emit({"type": "notice", "level": "warning",
"text": f"🛡 Yêu cầu bị chặn bởi Agent Security: {verdict.reason}"})
from . import audit_log
from .agent_security_alert import notify_admin
audit_log.record("security_block", "prompt", False, verdict.reason)
notify_admin(config, verdict, detail=user_text[:1000])
@@ -266,7 +261,6 @@ def enforce_command(provider: Provider, name: str, args: dict, config, emit,
emit({"type": "notice", "level": "warning",
"text": f"🛡 Lệnh bị chặn bởi Agent Security ({verdict.layer}): {verdict.reason}"})
from . import audit_log
from .agent_security_alert import notify_admin
audit_log.record("security_block", name, False, f"{verdict.layer}: {verdict.reason}")
notify_admin(config, verdict, detail=command)