Files
hunjing/backend/alembic/versions/4e679f11da46_插件沙箱执行记录.py
T
chenxin 99a7789432 ✨ feat: Sandbox Runtime——isolated 插件子进程隔离执行(WP-06/07 收口)
- 迁移 17:plugin_execution(五态、退出码、时长、stdout 摘要、错误留痕)
- 沙箱执行器:独立子进程(代码经 stdin JSON 安全传输,不进命令行)、CPU rlimit + RLIMIT_AS(平台不支持时尽力而为并注明)、墙钟超时强杀、输出限额;runner 仅暴露 input/output 作用域
- 执行端点:isolated_process 形态、已安装且启用后可执行;**未启用沙箱一律 503 fail-closed**(HUNJING_SANDBOX_ENABLED 显式开启,审计记录拒绝原因)——AGENTS 第 6 节"无符合策略的 Sandbox 时拒绝执行"落地
- 每次执行落 plugin_execution + 审计(状态/时长);进程级隔离的边界如实注明(网络/文件系统最小化在 Linux 容器档交付)
- 测试 96 项全绿(+2):echo 真实执行回填、死循环 5s 超时强杀、异常 failed 含 stderr、无沙箱 503
2026-09-12 13:38:41 +08:00

48 lines
1.9 KiB
Python

"""插件沙箱执行记录
Revision ID: 4e679f11da46
Revises: 89a4ed9647ee
Create Date: 2026-09-12 13:33:43.279920
"""
from collections.abc import Sequence
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision: str = '4e679f11da46'
down_revision: str | Sequence[str] | None = '89a4ed9647ee'
branch_labels: str | Sequence[str] | None = None
depends_on: str | Sequence[str] | None = None
def upgrade() -> None:
"""Upgrade schema."""
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('plugin_execution',
sa.Column('id', sa.String(), nullable=False),
sa.Column('installation_id', sa.String(), nullable=False),
sa.Column('status', sa.String(), nullable=False),
sa.Column('exit_code', sa.Integer(), nullable=True),
sa.Column('duration_ms', sa.Integer(), nullable=True),
sa.Column('stdout_excerpt', sa.String(), nullable=True),
sa.Column('error', sa.String(), nullable=True),
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.Column('completed_at', sa.DateTime(timezone=True), nullable=True),
sa.CheckConstraint("status IN ('running', 'succeeded', 'failed', 'timeout', 'killed')", name=op.f('ck_plugin_execution_status_values')),
sa.ForeignKeyConstraint(['installation_id'], ['plugin_installation.id'], name=op.f('fk_plugin_execution_plugin_installation'), ondelete='cascade'),
sa.PrimaryKeyConstraint('id', name=op.f('pk_plugin_execution'))
)
op.create_index(op.f('ix_plugin_execution_installation_id'), 'plugin_execution', ['installation_id'], unique=False)
# ### end Alembic commands ###
def downgrade() -> None:
"""Downgrade schema."""
# ### commands auto generated by Alembic - please adjust! ###
op.drop_index(op.f('ix_plugin_execution_installation_id'), table_name='plugin_execution')
op.drop_table('plugin_execution')
# ### end Alembic commands ###