最新资讯
dev.to 我们在 DolphinBench 上测试记忆检索:纯关键词搜索暴露了自身回归 dev.to 别再把 Agent 写成 while 循环,把它建模为状态机 bloomberg.com Rightmove 与 Scout24 借 AI 产品应对低迷房市并上调展望 stackoverflow.blog 欢迎来到芯片时代:半导体制造、AI 数据中心与芯片设计的未来 www.youtube.com AI Agent 总犯同样的错:CentralAgent AI 将记忆重构为经验系统 pub.towardsai.net Netflix 科学家建议重采样 LLM 评判:5 次仅将误差棒缩小 13% pub.towardsai.net Jev 作为 LLM 前的静默层:构建提示感知的模型路由器 reddit.com OpenAI 称 Astra 仅满足 10% 安全任务标准 dev.to FreeToken:在自有 GPU 上运行前沿 MoE 模型及其内存需求 dev.to 当 AI Agent 说“完成”时,究竟完成了什么? dev.to 部署 Underdog Bark 3.0 Pro:逐字转写、自定义后端与分块设置 dev.to 为艰难对话构建 AI:五个 Agent、一条安全正则与一位盲评监督者
多元动态
登录 注册
智能体 dev.to · @Taylor Zhu

固定根路径否则不予合并:Agent 出网失败关闭清单

原文 我的收藏

文章主张在合并 Agent 变更前,必须将其可触及的每个文件系统根、网络主机和可执行文件列入已提交的允许列表,缺失即让流水线失败。作者指出风险不在 LLM 本身,而在接入的 Shell、HTTP、MCP 等工具——它们把建议变成带凭证、工作目录和网络栈的进程,并强调绿色单元测试不能证明 Agent 未越出仓库范围。

AI推荐理由 文章提出面向编码 Agent 的失败关闭式出网清单:文件系统根、网络主机与可执行文件必须列入已提交的允许列表,否则流水线失败。针对 Agent 接入共享 CI 或共享机器的实际风险(Shell、HTTP、MCP 工具带来的凭证与网络暴露),对工程团队有可操作价值;属个人实践总结。

66

正文

You should not merge an agent change until every filesystem root, network host, and executable it can reach is named in a committed allowlist. If that file is missing, the pipeline fails. That is the whole policy. An LLM in a pull request is not the risk by itself. The risk is the tools you wired to it. Shell. HTTP. MCP. Those tools turn a suggestion into a process with credentials, a working directory, and a network stack. This checklist is for teams shipping coding agents into shared CI or a shared box. Copy it. Fail closed. Do not treat a green unit test as proof that the agent stayed inside the repo. What you are actually shipping You are not shipping a prompt. You are shipping a runtime. If the agent can run a command, it can read files the reviewer never opened. If it can fetch a URL, it can leave your VPC with a token sitting in an environment variable. If it can call an MCP server, it can grow new verbs the next time that server updates. Name the boundary. Then prove the run stayed inside it. The merge rule Treat agent egress like a production firewall change: Default deny. Explicit allow. Evidence on the PR. Missing evidence fails the job. Do not negotiate item 4 in Slack. If the packet is incomplete, the merge is incomplete. Copy-paste checklist Use this as a PR template. Every box needs an artifact, not a vibe. 1. Identity of the agent [ ] agent_id is stable across PRs (not tmp or test). [ ] Model, tool host, and MCP server versions are pinned in the same commit as the code. [ ] A human owner is named. Bots do not own allowlists. If the id changes, treat it as a new service. New service, new review. 2. Filesystem roots [ ] workspace_roots lists every directory the agent may read or write. [ ] Roots are repo-relative. No $HOME. No /tmp unless a job-scoped directory is created in CI and destroyed after. [ ] Write roots are a subset of read roots. [ ] Symlink escape is denied: the gate resolves paths before compare. A root of . is acceptable for a docs bot. It is not acceptable for an agent that also mounts secrets. 3. Binaries and argv [ ] binaries is an allowlist of executable basenames, not $PATH. [ ] Shell wrappers (bash -lc, sh -c, python -c) are either forbidden or require a second reviewer. [ ] Package managers (npm, pip, curl | sh) are denied unless the PR is specifically about dependency changes. You do not need a perfect sandbox to start. You need a list you can grep. 4. Network hosts [ ] network.mode is deny or allowlist. Never open. [ ] Hosts are exact names, not *.cloud. [ ] Redirects to a non-listed host fail the run. [ ] Metadata endpoints and link-local addresses are denied by default. Host allowlists are not a full network policy. They are the minimum you can enforce in application CI. 5. Environment and secrets [ ] env_allow names every variable the process may read. [ ] Names matching SECRET, TOKEN, PASSWORD, PRIVATE are denied unless explicitly listed. [ ] The job prints variable names, never values. [ ] Tokens used by the agent are scoped to that job and expire with it. If a secret appears in a tool argument, the run is a failed run. Rotate. Then fix the allowlist. 6. Loop bounds [ ] max_steps is set. [ ] max_wall_clock_sec is set. [ ] max_tool_calls_per_step is set. [ ] On any limit, the agent stops. It does not retry with a wider tool. Unbounded loops are not “research mode” in a merge pipeline. They are an open invoice and an open shell. 7. MCP and plugin graphs [ ] Every MCP server is pinned by name, URL or path, and digest. [ ] The tool list is frozen in the same file. A new tool is a new PR. [ ] Servers that can execute arbitrary commands inherit the binary and root rules above. If the server can add a tool without a digest change, it does not belong in this pipeline. Evidence the PR must attach A checklist without files is theater. Require these paths, or fail: Gate Required file Fail closed when Manifest present agent-egress.yml file missing or empty Schema valid CI validator log unknown keys, empty lists while a capability is enabled Trace exists artifacts/agent-trace.jsonl no file, or zero tool events while tools were enabled Trace in bounds CI comparator log path, host, binary, or env outside the manifest Bounds held trace summary max_steps or wall clock exceeded Secret scan CI log secret-like names in argv or stdout Store the trace next to the manifest. Reviewers should be able to open one folder and see both the policy and the run. Artifact: a fail-closed validator Label: this is a proposed local gate. Run it on a sample manifest before you trust it in a protected branch. agent-egress.yml: version: 1 agent_id: docs-triage owner: platform-ci workspace_roots: - . write_roots: - ./artifacts binaries: - git - python3 network: mode: allowlist hosts: - api.github.com env_allow: - GITHUB_TOKEN - CI max_steps: 20 max_wall_clock_sec: 180 max_tool_calls_per_step: 3 mcp_servers: [] Enter fullscreen mode Exit fullscreen mode ci/check_agent_egress.py: #!/usr/bin/env python3 """Fail closed if the agent egress manifest is missing or incomplete.""" from __future__ import annotations import argparse import sys from pathlib import Path try: import yaml except ImportError: print("MISSING_DEP: PyYAML is required", file=sys.stderr) sys.exit(2) REQUIRED = ( "version", "agent_id", "owner", "workspace_roots", "write_roots", "binaries", "network", "env_allow", "max_steps", "max_wall_clock_sec", "max_tool_calls_per_step", "mcp_servers", ) FORBIDDEN_ROOT_MARKERS = ("$HOME", "~", "/tmp", "/var", "C:\\") def fail(msg: str) -> None: print(f"FAIL: {msg}", file=sys.stderr) sys.exit(1) def main() -> None: parser = argparse.ArgumentParser() parser.add_argument("--manifest", default="agent-egress.yml") parser.add_argument("--fail-closed", action="store_true", default=True) args = parser.parse_args() path = Path(args.manifest) if not path.is_file(): fail(f"manifest not found: {path}") raw = path.read_text(encoding="utf-8").strip() if not raw: fail("manifest is empty") data = yaml.safe_load(raw) if not isinstance(data, dict): fail("manifest must be a mapping") missing = [k for k in REQUIRED if k not in data] if missing: fail(f"missing keys: {missing}") if not data["agent_id"] or data["agent_id"] in {"tmp", "test", "default"}: fail("agent_id must be stable and non-placeholder") roots = data["workspace_roots"] if not roots: fail("workspace_roots must not be empty") for root in roots: if not isinstance(root, str) or any(m in root for m in FORBIDDEN_ROOT_MARKERS): fail(f"refusing root: {root!r}") writes = data["write_roots"] if not writes: fail("write_roots must not be empty") binaries = data["binaries"] if not binaries: fail("binaries allowlist must not be empty") if any(b in {"bash", "sh", "zsh", "cmd", "powershell"} for b in binaries): fail("shell binaries require a separate exception PR") network = data["network"] if network.get("mode") not in {"deny", "allowlist"}: fail("network.mode must be deny or allowlist") if network["mode"] == "allowlist" and not network.get("hosts"): fail("allowlist mode requires hosts") if int(data["max_steps"]) < 1 or int(data["max_wall_clock_sec"]) < 1: fail("loop bounds must be positive") print(f"PASS: {path} agent_id={data['agent_id']}") if __name__ == "__main__": main() Enter fullscreen mode Exit fullscreen mode Run it locally the same way CI will: python3 -m pip install pyyaml python3 ci/check_agent_egress.py --manifest agent-egress.yml --fail-closed echo $? # expected: 0 on a complete file, 1 on any gap Enter fullscreen mode Exit fullscreen mode CI job sketch: name: agent-egress-gate on: pull_request: paths: - "agent-egress.yml" - "ci/check_agent_egress.py" - "**/*agent*" jobs: gate: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: python3 -m pip install pyyaml - run: python3 ci/check_agent_egress.py --manifest agent-egress.yml --fail-closed Enter fullscreen mode Exit fullscreen mode Keep the path filter honest. If your agent code lives outside *agent*, drop the filter. A skipped gate is an open gate. Trace comparator, minimum version The manifest is policy. The trace is evidence. You still need a comparator. Proposed event shape (one JSON object per line): {"ts": "2026-09-11T12:00:00Z", "type": "tool", "name": "run_terminal_cmd", "binary": "git", "argv": ["status"], "cwd": ".", "host": null} Enter fullscreen mode Exit fullscreen mode Comparator rules you can implement in a short script: cwd must resolve under workspace_roots. binary must be in binaries. host must be in network.hosts when not null. Event count must be <= max_steps. Unknown type fails. Do not ignore fields you do not understand. If you cannot produce a trace, you cannot merge. “The vendor UI does not export logs” is a vendor problem, not a reason to skip the gate. Where a coding assistant actually helps Drafting the first allowlist from a recorded trace is tedious. A coding assistant is useful there: it can turn a JSONL file into a candidate YAML. It is not useful as the gate. Disclosure: This article was prepared as part of MonkeyCode's product outreach. If you need a throwaway workspace to generate those traces without pointing the agent at production, MonkeyCode’s free model access and free server option are enough to iterate on the manifest. Keep the validator in your CI. The model does not get a vote. Limitations This checklist does not replace OS sandboxes, seccomp, or a real egress proxy. Path allowlists lose if the process can follow a symlink you did not resolve. Host allowlists lose if a listed host issues a redirect you do not follow in the comparator. MCP pins lose if the server mutates tools behind the same digest. Loop bounds do not stop a single dangerous command. They stop a runaway. You still need binary and argv policy for the dangerous command. The validator above does not parse traces. Ship the comparator before you claim production readiness. Until then, label the gate manifest-only in the PR so reviewers know what they are not seeing. Who should not use this Teams that need the agent to browse the open web. Use a dedicated browsing account and a different pipeline. Teams with no human owner for the allowlist. An unowned file will rot, then someone will set network.mode: open. Regulated workloads that require a named control framework. This is an engineering gate, not an audit certificate. Local experiments on a throwaway clone with no secrets. Do not block research with production ceremony. Do block the merge. Decision you make on every PR Ask one question: if this agent process is still running in ten minutes, which roots, hosts, and binaries can it still touch? If you cannot answer from a file in the repo, do not merge. Pin the roots. Attach the trace. Fail closed.

来源报道 · 1 篇 · 以下链接均前往原始媒体

← 返回精选动态 原文

更多内容