前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片NEW
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 业务场景题真实业务问题与追问
  • 查漏补缺常见问题解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
    • AI 定制路线NEW按你的简历现排
    • AI 知识地图NEW串起全站知识点
  • 动态
    • AI 热点NEWAI 每日动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
AI 助手NEW
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片NEW
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 业务场景题真实业务问题与追问
  • 查漏补缺常见问题解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
    • AI 定制路线NEW按你的简历现排
    • AI 知识地图NEW串起全站知识点
  • 动态
    • AI 热点NEWAI 每日动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
AI 助手NEW
旧版
返回 AI 情报前线
All News · 全部资讯8614
  • 让过期的 Agent 上下文直接阻断 CI
  • 昇腾适配 Ling-3.0 并推出 PyPTO
  • 让编程 Agent 用你熟悉的语言写脚本
  • 数据库索引提速背后的写入代价
  • Meta低价模型与可恢复编程Agent登场
  • 如何构建 Agent 难以作弊的评测
  • Claude Code 迁移 OpenCode 踩坑实录
  • RAG向量数据库的真实成本陷阱
  • 编码代理缺失的其实是产品定义
  • 用熔断机制约束失控的 AI Agent
  • 别让 AI 任务止步于聊天记录
  • 人类审核仍漏掉三分之一智能体威胁
  • OpenAI智能体曾秘密协同攻击
  • AI 工作流为何会在无改动时失效
  • 开源本地化求职管理平台 FitPilot
  • 在一次性沙箱中测试编程 Agent 越界
  • 别把系统提示词写成规则仓库
  • Agent 审批卡的盲签名陷阱
  • 为真实项目编写AGENTS.md的经验
  • 用固定语料阻止AI审查能力回退
  • 为AI代码变更建立分阶段权限门禁
  • 别让LLM评测工具测到自身拥塞
  • AI自动扫描将放大密钥泄露风险
  • GPT-5.6 Sol能力升级并扩大免费开放
  • 人脸识别的94%匹配为何不可信
  • 如何测试具备工具权限的完整Agent链路
  • 多Agent共享状态为何会静默丢失
  • 一次失控编程Agent如何烧掉138美元
  • 一条命令统一九类触觉传感器数据
  • VS Code 1.132强化智能体开发体验
  • 用对话式设计Agent生成流水线契约
  • 精简智能体规则文件的实用原则
  • LLM 评审为何不能替代确定性校验
  • 用定时 Codex 任务生成可靠日报
  • 六智能体协作生成并部署游戏
  • GitHub 原生堆叠式 PR 改善评审瓶颈
  • Ollama 加速苹果芯片上的 Qwen3.5
  • Rovo 提示注入可窃取企业敏感数据
  • Prime Agent 开源递归式多智能体框架
  • 构建能识别调用异常的 API 监控 Agent
  • 工程团队的软件选型评估框架
  • 生产级 LLM 字幕翻译的完整工作流
  • 昇腾开源强化学习训推一致方案
  • 批量检测 AI 内容模板残留
  • 用Postgres为Claude Code构建长期记忆
  • 自主 Agent 的三层安全威胁模型
  • 多模型降级不能只替换模型名
  • 本地小模型如何应对MCP工具膨胀
  • GPT-Live全双工语音架构解析
  • Qwen3.8登顶Agentic能力榜单
  • AI智能体协作发动全自动攻击
  • 已加载 51 / 8614
9.0
重磅
AI SCORE
编程提效2026-08-06 19:02

为AI代码变更建立分阶段权限门禁

dev.to · AI#AI编程#权限控制#CI/CD
Editor brief · 编辑速览

文章建议让Agent默认仅具观察权限,将建议、命令执行和写入操作拆成独立阶段,每次权限升级都经过机器可验证的门禁。这样即使模型幻觉、宕机或更换供应商,流水线仍能限制破坏性变更。

文章思维导图
Knowledge map
拖拽缩放
Full translation

完整中文译文

团队里有人把一段 stack trace 粘贴给 assistant,拿到一个看似合理的 diff,然后点击“apply”。二十分钟后,预览环境崩了,却没人说得清是哪次自动化运行改了什么。每当我追查这类事故时,薄弱环节几乎从来都不是模型的推理能力,而是这样一个接缝:一条文本建议悄无声息地继承了 shell、网络和写入权限,却从未被要求证明自己为何需要这些权限。

最近,我把其中一套流程重构成了一条由多个小阶段组成的流水线,每个阶段分别授予权限。核心原则是:assistant 一开始只有观察权限,每一次向变更操作的权限升级,都必须通过机器可检查的 gate。低成本的模型能力非常适合处理高吞吐量的前期阶段,例如起草摘要、提出命令;但 gate 本身必须足够可靠,即使模型宕机、产生幻觉,或者被替换为另一家供应商的模型,它仍然能够守住边界。

从一次真实故障出发,而不是从 prompt 出发

促使我采用这种方案的事故,是一次依赖版本升级,而不是数据库迁移。一个拥有通用“run commands”工具的 assistant 尝试升级某个 package,遇到 peer-dependency 冲突后,又使用 --force 重试,最终让 lockfile 处于这样一种状态:本地测试可以通过,但部署构建失败,registry webhook 返回 422。先后有三次独立的自动化运行修改过 lockfile,却没有任何一次记录是哪个 actor 请求执行了哪条命令。

这最终形成了一套包含五个阶段的流程,每个阶段都有一条不可逾越的规则:

Scan —— assistant 可以读取源代码、测试输出和错误响应正文。此时不存在其他权限。

Draft —— assistant 返回一份结构化的变更提案,其中包括计划进行的编辑,以及它希望执行的确切命令。希望执行不等于实际执行。

Rehearse —— 这些命令会在一个用完即弃、默认拒绝所有权限的 sandbox 中执行。

Commit —— 只有 CI 或指定的人类可以落地变更,并且 actor 的身份会被写入 artifact。

Trace —— 每个 artifact 都携带提案 hash、命令列表,以及允许执行这些操作的权限 grant,因此不可能出现找不到来源的孤儿 artifact。

对于成本低、重复性高的 Scan 和 Draft 阶段,我会让它们运行在低投入的 assistant 环境中,而不是消耗接近生产环境的基础设施。披露:本文是 MonkeyCode 产品推广的一部分。运营方提供的可用性说明称,MonkeyCode 提供免费的模型访问和免费 server 选项;我把这两项都视为可能变化的平台条件——在依赖它们之前,我会确认这些条件是否仍然有效。无论使用哪个价格层级,我都绝不会通过这些服务传输 secrets、客户 payload,或授予任何不可逆的权限。

真正的 artifact:由 sandbox 执行检查的 policy

Prompt 并没有解决我的事故;真正起作用的是一个可强制执行的 policy 对象。这次使用 Python 展示其结构——相同的思路可以移植到任何技术栈:

# policy.py
from dataclasses import dataclass, field
import time

@dataclass
class Grant:
    run_id: str
    role: str                      # 'observer', 'rehearsal', 'committer'
    readable_paths: list[str]
    writable_paths: list[str] = field(default_factory=list)
    allowed_bins: list[str] = field(default_factory=list)
    network_egress: list[str] = field(default_factory=list)
    ttl_seconds: int = 120
    issued_at: float = field(default_factory=time.time)

class PolicyViolation(Exception):
    def __init__(self, code: str, detail: str):
        super().__init__(detail)
        self.code = code

def authorize(grant: Grant, binary: str, workdir: str) -> None:
    if time.time() > grant.issued_at + grant.ttl_seconds:
        raise PolicyViolation("GRANT_STALE", "grant lifetime exceeded")
    if grant.role == "observer" and (grant.writable_paths or "git push" in grant.allowed_bins):
        raise PolicyViolation("OBSERVER_WITH_TEETH", "observer role must hold zero mutation rights")
    if not any(binary.startswith(b) for b in grant.allowed_bins):
        raise PolicyViolation("BINARY_BLOCKED", f"{binary} not on allowlist")
    if not any(workdir.startswith(p) for p in grant.readable_paths):
        raise PolicyViolation("PATH_BLOCKED", f"{workdir} outside granted scope")

这里有两个设计选择承担了关键作用。首先,observer grant 在结构上就不可能包含写入范围——检查会在授权时执行,因此,通过复制粘贴引入的 helper 无法把变更权限偷偷带入读取阶段。其次,grant 的有效期以分钟计算;泄露的 grant 会在能够被利用之前过期。这正是对经典 vibe-coding 事故的解药:draft_change() 和 apply_change() 最终共享了同一个权限过高的 client 对象,仅仅因为二者都“需要访问 repo”。

sandbox wrapper 被刻意设计得非常轻量——所有 policy 都集中在 authorize 中,因此只需审计一个文件:

# sandbox.py
import subprocess
from policy import Grant, authorize

def rehearse(grant: Grant, binary: str, argv: list[str], workdir: str) -> dict:
    authorize(grant, binary, workdir)
    proc = subprocess.run(
        [binary, *argv], cwd=workdir, capture_output=True, text=True, timeout=90,
    )
    return {"run_id": grant.run_id, "cmd": [binary, *argv], "rc": proc.returncode,
            "out": proc.stdout[-4000:], "err": proc.stderr[-4000:]}

让边界在构建阶段大声失败的测试

这些测试运行成本很低,却比花一周时间调优 prompt 更有价值:

# test_policy.py
import pytest
from policy import Grant, authorize, PolicyViolation

def observer_grant(**kw):
    base = dict(run_id="run-9", role="observer",
                readable_paths=["/workspace/repo"],
                allowed_bins=["pytest", "grep"], ttl_seconds=60)
    return Grant(**(base | kw))

def test_observer_may_rehearse_tests():
    authorize(observer_grant(), "pytest", "/workspace/repo/pkg")

def test_observer_cannot_hold_write_scope():
    with pytest.raises(PolicyViolation) as e:
        authorize(observer_grant(writable_paths=["/workspace/repo"]), "pytest", "/workspace/repo")
    assert e.value.code == "OBSERVER_WITH_TEETH"

def test_unlisted_binary_refused():
    with pytest.raises(PolicyViolation) as e:
        authorize(observer_grant(), "curl", "/workspace/repo")
    assert e.value.code == "BINARY_BLOCKED"

def test_expired_grant_refused():
    g = observer_grant(issued_at=0)
    with pytest.raises(PolicyViolation) as e:
        authorize(g, "pytest", "/workspace/repo")
    assert e.value.code == "GRANT_STALE"

如果你把 Rehearse 阶段托管在免费的 server 上,就要把它设计成可随时销毁的消耗品:不放置任何生产凭据,不挂载任何你舍不得失去的 volume,不与任何能够执行 commit 的系统共用 message bus,并配置一个以环境已遭入侵为前提、定期执行拆除的 cron。你购买的是隔离能力和一个干净的重试循环——绝不是信任。

谁可以做什么,以及哪些代码能证明 gate 正常生效

最右侧那一列比看起来更加重要:当问题发生时,你需要的是一个具体的拒绝代码,能够指向确切的阶段,而不是一次耸肩和一份聊天记录。

哪些场景下我不会采用这种模式

对于任何涉及受监管记录、尚未公开的客户源代码、凭据处理、直接修改数据库,或承诺数据保留期限的工作负载,都不要使用免费层级的模型访问和免费 server 容量。如果你的团队还无法明确一项变更究竟由哪一层负责——UI、API、worker 还是 schema——那么也不要采用整套分阶段设计,因为 gate 只会以阻力的形式暴露这种模糊性,却无法替你解决它。如果你无法一次性写出 binary allowlist,那么 assistant 仍然在通过自然语言协商自己的权限,而这正是该模式试图消除的故障根源。

这个理念并不复杂,却很持久:让低成本算力承担重复性的读取、总结和演练循环,把工程精力集中投入到唯一关键的接缝上——生成的文本在这里变成正式提交的变更。如果你构建了这样一条通道,最有价值的反馈是:哪个交接点最先出现了摇摆,以及捕获该问题的具体拒绝代码或 HTTP 状态码。在你的系统中,哪个阶段边界最不稳定?

对于后续操作,你可以考虑屏蔽此人和/或举报滥用行为。

Original source

本文由 AI 翻译整理自 dev.to · AI,原文版权归原作者所有。

阅读英文原文
上一篇
用固定语料阻止AI审查能力回退
下一篇
别让LLM评测工具测到自身拥塞