@swifty.js/swifty 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +183 -0
- package/dist/agent-MICFDGUF.js +4 -0
- package/dist/anthropic-JDAGNAPR.js +4 -0
- package/dist/checker-PF3FEOF2.js +4 -0
- package/dist/chunk-4KVSJNS6.js +90 -0
- package/dist/chunk-6ARDOHBL.js +4 -0
- package/dist/chunk-7MHXMDYC.js +35 -0
- package/dist/chunk-F6HLYUZ4.js +355 -0
- package/dist/chunk-FZPTNGTU.js +4 -0
- package/dist/chunk-LPLPMGWW.js +336 -0
- package/dist/chunk-MQ5XOYLD.js +4 -0
- package/dist/chunk-RD3MICOU.js +4 -0
- package/dist/{cleanup-4R3534Z3.js → cleanup-BQJDUOKA.js} +1 -1
- package/dist/glob_addon.node +0 -0
- package/dist/main.js +240 -240
- package/dist/openai-I4WTRNNT.js +26 -0
- package/dist/{server-XPKSROM2.js → server-OGPKL2U2.js} +22 -21
- package/package.json +17 -24
- package/dist/anthropic-737END4X.js +0 -4
- package/dist/chunk-NCPOPA4A.js +0 -4
- package/dist/chunk-SC34YHMX.js +0 -521
- package/dist/chunk-Z3E5YV3P.js +0 -121
- package/dist/openai-4KX74QBZ.js +0 -27
- package/docs/ch1.md +0 -25
- package/docs/ch10.md +0 -122
- package/docs/ch11.md +0 -163
- package/docs/ch12.md +0 -289
- package/docs/ch13.md +0 -320
- package/docs/ch14.md +0 -152
- package/docs/ch15.md +0 -547
- package/docs/ch2.md +0 -273
- package/docs/ch3.md +0 -206
- package/docs/ch4.md +0 -125
- package/docs/ch5.md +0 -165
- package/docs/ch6.md +0 -201
- package/docs/ch7.md +0 -448
- package/docs/ch8.md +0 -217
- package/docs/ch9.md +0 -351
- package/docs/index.css +0 -23
- package/docs/index.md +0 -21
- package/docs/swifty.mdx +0 -7
package/docs/ch5.md
DELETED
|
@@ -1,165 +0,0 @@
|
|
|
1
|
-
# System Prompt
|
|
2
|
-
|
|
3
|
-
## System Prompt
|
|
4
|
-
|
|
5
|
-
system prompt 分为 7 个模块 (section), 按 priority 排序后拼接
|
|
6
|
-
|
|
7
|
-
- agent 的角色 (Identity, priority 0)
|
|
8
|
-
- 系统原则 (System, priority 10)
|
|
9
|
-
- 执行任务规范: 例如是否加注释, 是否拆分组件, 是否重构 (Doing Task, priority 20)
|
|
10
|
-
- 动作规范: 例如禁止猜测 API, plan 模式、auto 模式的执行策略 (Executing Actions, priority 30)
|
|
11
|
-
- 工具调用指南: 例如使用 cat 还是 ReadFile, 多个工具调用串行还是并行 (Using Tools, priority 40)
|
|
12
|
-
- 语气风格: 例如不要使用表情符号 (Tone Style, priority 50)
|
|
13
|
-
- 文本输出: 例如 1-2 sentences 的回复 (TextOutput, priority 60)
|
|
14
|
-
- 环境上下文 (Environment, priority 70)
|
|
15
|
-
|
|
16
|
-
## Prompt 的 7 个来源、3 个字段
|
|
17
|
-
|
|
18
|
-
### 7 个来源
|
|
19
|
-
|
|
20
|
-
| 来源 | 字段 | 原因 |
|
|
21
|
-
| -------------------------------------------- | -------- | --------------------------------------------- |
|
|
22
|
-
| System Prompt | system | 始终生效, 内容稳定可以缓存 |
|
|
23
|
-
| 环境上下文: 操作系统、工作目录... | system | 每个会话确定后不再改变, 可以缓存 |
|
|
24
|
-
| 工具描述: 工具的 description, input_schema | tools | LLM API 规范 |
|
|
25
|
-
| 指令文件: SWIFTY.md / AGENTS.md | messages | 内容可能很长, 放在 system 可能稀释 LLM 注意力 |
|
|
26
|
-
| 自动记忆: agent 自动沉淀的用户偏好和项目知识 | messages | 内容可能变化 |
|
|
27
|
-
| system reminder: 动态注入的上下文 | messages | 特定时机注入 `<system-reminder />` |
|
|
28
|
-
| 对话历史 | messages | LLM API 规范 |
|
|
29
|
-
|
|
30
|
-
> system 字段的优先级最高, 为什么不都设置为 system 字段?
|
|
31
|
-
|
|
32
|
-
1. prompt cache, LLM API 支持 prompt cache, 如果 system 字段的值和上一次请求完全相同, 则 LLM API 会复用缓存, 降低 input token 的计费; system prompt 内容稳定, 每次请求都可以命中缓存
|
|
33
|
-
- 稳定的内容放在 system 字段、变化的内容放在 messages 字段
|
|
34
|
-
- 如果指令文件和自动记忆放在 system 字段, 则会频繁使得 prompt cache 缓存失效
|
|
35
|
-
- 环境上下文每个 session 不同, 但是一个 session 中是稳定的, 可以使用分层缓存: 全局缓存、会话级缓存
|
|
36
|
-
2. system 字段内容太长, 可能会稀释 LLM 注意力
|
|
37
|
-
3. 可压缩性: messages 字段的内容, 后续可以被上下文压缩处理; 但是 system 字段的内容不会被压缩, 每次发送 LLM 请求时都会完整携带; 如果指令文件的内容后期不再需要, /compact 可以压缩或删除, 但是 system 字段的内容不会被上下文压缩处理, 每次请求都会完整携带
|
|
38
|
-
|
|
39
|
-
```js
|
|
40
|
-
function assembleAPIPayload(config, conversationHistory) {
|
|
41
|
-
// system 字段: 稳定的 system prompt + 会话级上下文
|
|
42
|
-
const system = buildSystemPrompt(config);
|
|
43
|
-
|
|
44
|
-
// 环境上下文也放到 system 字段, 使用缓存分层管理
|
|
45
|
-
const envContext = buildEnvironmentContext(config);
|
|
46
|
-
system += "\n\n" + envContext;
|
|
47
|
-
|
|
48
|
-
// message 字段: 存放变化的内容
|
|
49
|
-
const messages = [];
|
|
50
|
-
|
|
51
|
-
// 指令文件 (AGENTS.md, CLAUDE.md, SWIFTY.md)
|
|
52
|
-
const instructions = loadInstructionFiles(config.workDir);
|
|
53
|
-
if (instructions) {
|
|
54
|
-
messages.push(systemReminder(instructions));
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// 自动记忆
|
|
58
|
-
const memories = loadMemories(config);
|
|
59
|
-
if (memories) {
|
|
60
|
-
messages.push(systemReminder(memories));
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// 对话历史
|
|
64
|
-
messages.push(...conversationHistory);
|
|
65
|
-
|
|
66
|
-
// 动态上下文 (MCP Server、可用 skill 列表)
|
|
67
|
-
const dynamicCtx = buildDynamicContext(config);
|
|
68
|
-
if (dynamicCtx) {
|
|
69
|
-
messages.push(systemReminder(dynamicCtx));
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// tools 字段: 工具描述
|
|
73
|
-
const tools = registry.getEnabledToolSchemas();
|
|
74
|
-
|
|
75
|
-
return { system, messages, tools };
|
|
76
|
-
}
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
### 工具描述也是 prompt 工程
|
|
80
|
-
|
|
81
|
-
3 个字段
|
|
82
|
-
|
|
83
|
-
- system
|
|
84
|
-
- messages
|
|
85
|
-
- tools
|
|
86
|
-
|
|
87
|
-
工具描述不是注释, 是 prompt 的一部分; LLM 根据 description 做决策: 什么时候调用这个工具, 如何调用这个工具; 好的工具描述和 system prompt 的「工具调用指南」有重叠, 例如优先 ReadFile 而不是 bash、cat; 重复说明, LLM 遵守的概率会更高
|
|
88
|
-
|
|
89
|
-
### 动态指令注入: `<system-reminder />`
|
|
90
|
-
|
|
91
|
-
#### 信息的来源
|
|
92
|
-
|
|
93
|
-
- system prompt: 会话开始时确定
|
|
94
|
-
- 会话历史: 随会话产生
|
|
95
|
-
- 会话过程中产生, 需要立刻让 LLM 知道: 例如会话过程中, 用户通过配置连接了一个 MCP Server, 这个 MCP Server 提供了多个新工具, Agent 需要立刻知道这些工具的描述; 但是不能修改 system prompt, 修改 system prompt 会使得 prompt cache 失效; 但也不能作为用户消息, 否则 LLM 可能会回复
|
|
96
|
-
|
|
97
|
-
#### 什么是 `<system-reminder />`
|
|
98
|
-
|
|
99
|
-
`<system-reminder />` 是一种特殊的消息标记, 放在 messages 字段中, 以告诉 LLM 这是补充的 system prompt
|
|
100
|
-
|
|
101
|
-
1. 训练阶段, LLM 理解「xml 标签间的内容是一块有语义的单元」
|
|
102
|
-
2. 微调/RLHF 阶段
|
|
103
|
-
|
|
104
|
-
- Anthropic 在微调时使用 `<system-reminder />`
|
|
105
|
-
- OpenAI 在 tokenizer 时使用 `<|im_start|>system<|im_end|>`
|
|
106
|
-
- OpenAI Codex: 使用 `<environment_context>`, `<INSTRUCTIONS>`, `<objective>`
|
|
107
|
-
|
|
108
|
-
LLM 看到 `<system-reminder />`, 就知道标签间的内容是当指令对待, 而不是当用户消息对待; 不回复这段内容, 而是加入到工作上下文
|
|
109
|
-
|
|
110
|
-
#### 典型使用场景
|
|
111
|
-
|
|
112
|
-
- MCP server 上线或下线
|
|
113
|
-
- 可用 skill 列表更新
|
|
114
|
-
- agent 配置更新
|
|
115
|
-
- 温和提醒
|
|
116
|
-
- SWIFTY.md / AGENTS.md 内容注入
|
|
117
|
-
|
|
118
|
-
#### 为什么不能直接改 system prompt
|
|
119
|
-
|
|
120
|
-
1. 改 system prompt 会让 prompt cache 失效
|
|
121
|
-
2. prompt cache 按前缀匹配, 顺序是 tools -> system -> messages, 直接改 system prompt 会导致后面的 message 的缓存全部失效
|
|
122
|
-
3. `<system-reminder />` 和用户消息需要作为独立的 content block, 不能拼在一起; 如果 `<system-reminder />` 的内容包含外部文本, 需要预防 prompt 注入
|
|
123
|
-
|
|
124
|
-
## Pitfall
|
|
125
|
-
|
|
126
|
-
- Prompt 太长, 中间指令被忽略
|
|
127
|
-
- LLM 的注意力不是均匀的, 开头和结尾得到的注意力最多, 中间内容最容易被忽略
|
|
128
|
-
- 使用 markdown 标题; 或者重复说明, 提高 LLM 遵守的概率
|
|
129
|
-
- 前后指令冲突: 在 system prompt 中明确优先级
|
|
130
|
-
- 关键指令重复说明, 提高 LLM 遵守的概率
|
|
131
|
-
|
|
132
|
-
## Prompt 与成本
|
|
133
|
-
|
|
134
|
-
每轮 agent loop turn 都需要调用 LLM API, 每次调用 LLM API 都需要发送 system + tools + messages, 其中 system + tools 的内容几乎不变, messages 的内容随对话增长。
|
|
135
|
-
|
|
136
|
-
usage 字段包含 4 个 token 计数 (Anthropic):
|
|
137
|
-
|
|
138
|
-
<!-- 源码: src/llm/anthropic.ts -->
|
|
139
|
-
|
|
140
|
-
- inputTokens: 未命中 prompt cache 的输入 token 数, 即发送给 LLM 的内容, 即 system_prompt, tools 描述和 messages 中未命中 prompt cache 的输入
|
|
141
|
-
- outputTokens: 输出 token 数, 即 LLM 生成的内容, 输出 token 比输入 token 贵的多
|
|
142
|
-
- cacheReadInputTokens: 命中 prompt cache 的输入 token 数, 价格远低于普通 input_tokens
|
|
143
|
-
- cacheCreationInputTokens: 创建 prompt cache 的输入 token 数, 价格略高于普通 input_tokens
|
|
144
|
-
|
|
145
|
-
简化的成本公式:
|
|
146
|
-
|
|
147
|
-
```txt
|
|
148
|
-
单轮成本 =
|
|
149
|
-
input_tokens * input_price
|
|
150
|
-
+ cache_read_tokens * cache_read_price (通常是 input_price 的 1/10)
|
|
151
|
-
+ cache_creation_tokens * cache_creation_price (通常是 input_price 的 1.25 倍)
|
|
152
|
-
+ output_tokens * output_price
|
|
153
|
-
|
|
154
|
-
input_tokens + cache_read_tokens + cache_creation_tokens
|
|
155
|
-
= system_tokens + tools_tokens + messages_tokens
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
<!-- 源码: src/llm/anthropic.ts (let cacheReadInputTokens = 0; let cacheCreationInputTokens = 0;) -->
|
|
159
|
-
<!-- 源码: src/llm/anthropic.ts (从 message_start.usage 读取 cache_read_input_tokens / cache_creation_input_tokens) -->
|
|
160
|
-
|
|
161
|
-
Prompt 设计在 3 个方面影响成本
|
|
162
|
-
|
|
163
|
-
1. system prompt 的长度: 多轮调用间需要保持不变
|
|
164
|
-
2. output 的长度: 行为准则要求「简洁还是详细」, 影响每轮的 output_tokens
|
|
165
|
-
3. 工具调用的效率: 多个独立任务并发调用工具, 减少 LLM API 请求次数; 每少一次 LLM API 请求, 就少一次完整的 input_tokens 传输, 极大降低 input_tokens 成本
|
package/docs/ch6.md
DELETED
|
@@ -1,201 +0,0 @@
|
|
|
1
|
-
# 权限
|
|
2
|
-
|
|
3
|
-
## 三种攻击
|
|
4
|
-
|
|
5
|
-
- prompt 注入
|
|
6
|
-
- 越权
|
|
7
|
-
- 数据泄露
|
|
8
|
-
|
|
9
|
-
## 多层防御
|
|
10
|
-
|
|
11
|
-
1. 危险命令拦截, 例如 rm -rf / 绝对拒绝
|
|
12
|
-
2. 路径沙箱: 工作目录外的文件操作需要用户确认
|
|
13
|
-
- 计算绝对路径
|
|
14
|
-
- 解析符号链接 TODO
|
|
15
|
-
- 检查路径前缀, 判断是否在工作目录内
|
|
16
|
-
3. 权限规则
|
|
17
|
-
- `allow: ["Bash(git *)"]`
|
|
18
|
-
4. 权限模式
|
|
19
|
-
- plan: 读放行, 写确认, shell 命令确认; 通过 prompt 约束 LLM 行为, 使得 LLM 只读
|
|
20
|
-
- default: 读放行, 写确认, shell 命令确认
|
|
21
|
-
- acceptEdits: 读写放行, shell 命令确认
|
|
22
|
-
- bypassPermissions: 绕过权限, 读/写/ shell 命令全部放行, 但仍然拒绝 rm -rf / 等危险命令
|
|
23
|
-
5. HITL (Human-in-the-Loop): 人在回路, 用户确认
|
|
24
|
-
|
|
25
|
-
## 第 1 层: 危险命令黑名单
|
|
26
|
-
|
|
27
|
-
黑名单只针对 bash 工具; ReadFile, WriteFile 工具有路径沙箱保护, 不需要黑名单
|
|
28
|
-
|
|
29
|
-
```js
|
|
30
|
-
const DANGEROUS_PATTERNS = [
|
|
31
|
-
// 递归强制删除根目录
|
|
32
|
-
{
|
|
33
|
-
re: /rm\s+(-rf?|--recursive)\s+[/~]/,
|
|
34
|
-
reason: "recursive force delete root",
|
|
35
|
-
},
|
|
36
|
-
// 递归强制删除
|
|
37
|
-
{ re: /rm\s+-rf?\s+\*/, reason: "recursive force delete wildcard" },
|
|
38
|
-
// 格式化磁盘
|
|
39
|
-
{ re: /mkfs\./, reason: "format disk" },
|
|
40
|
-
// 直接写磁盘设备
|
|
41
|
-
{ re: /dd\s+if=/, reason: "direct write to disk device" },
|
|
42
|
-
// 覆盖磁盘设备
|
|
43
|
-
{ re: />\s*\/dev\/sd/, reason: "overwrite disk device" },
|
|
44
|
-
// 递归修改根目录权限
|
|
45
|
-
{ re: /chmod\s+-R?\s*777\s+\//, reason: "recursive chmod root" },
|
|
46
|
-
// fork bomb
|
|
47
|
-
{ re: /:\(\)\{\s*:\|\s*:\s*&\s*\}\s*;/, reason: "fork bomb" },
|
|
48
|
-
// 管道执行远程脚本
|
|
49
|
-
{ re: /curl\s+.*\|\s*(ba)?sh/, reason: "pipe remote script" },
|
|
50
|
-
// 管道执行远程脚本
|
|
51
|
-
{ re: /wget\s+.*\|\s*(ba)?sh/, reason: "pipe remote script" },
|
|
52
|
-
{ re: /git\s+push\s+.*--force/, reason: "force push" },
|
|
53
|
-
{ re: /git\s+reset\s+--hard/, reason: "hard reset" },
|
|
54
|
-
{ re: /git\s+clean\s+-f/, reason: "force clean untracked files" },
|
|
55
|
-
{ re: /git\s+checkout\s+\./, reason: "discard all changes" },
|
|
56
|
-
{ re: /git\s+branch\s+-D/, reason: "force delete branch" },
|
|
57
|
-
];
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
## 第 2 层: 路径沙箱
|
|
61
|
-
|
|
62
|
-
<!-- 源码: src/permissions/checker.ts -->
|
|
63
|
-
|
|
64
|
-
- 计算绝对路径 (通过 path.resolve)
|
|
65
|
-
- 解析符号链接
|
|
66
|
-
- 检查路径前缀, 判断是否在允许的目录内
|
|
67
|
-
- 默认允许两个目录
|
|
68
|
-
- 项目根目录 (启动 Agent 的工作目录)
|
|
69
|
-
- 系统临时目录 (`os.tmpdir()`, MacOS 是 /var/folders, /tmp, Linux 是 /tmp, /var/tmp)
|
|
70
|
-
|
|
71
|
-
## 第 3 层: 权限规则
|
|
72
|
-
|
|
73
|
-
权限规则
|
|
74
|
-
|
|
75
|
-
- 允许执行 git push, 但不允许执行 `git push --force`
|
|
76
|
-
- 允许读取 src/ 目录下的文件, 但不允许读取 .env 文件
|
|
77
|
-
- 允许运行 pnpm lint, 但不允许运行 pnpm lint:fix
|
|
78
|
-
|
|
79
|
-
### Claude jsonl 配置
|
|
80
|
-
|
|
81
|
-
```jsonl
|
|
82
|
-
// 权限规则 (json)
|
|
83
|
-
{
|
|
84
|
-
"permissions": {
|
|
85
|
-
"allow": ["Bash(pnpm add *)", "Bash(pnpm dev)"]
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// 权限模式 (json)
|
|
90
|
-
{
|
|
91
|
-
"permissions": {
|
|
92
|
-
"defaultMode": "auto"
|
|
93
|
-
},
|
|
94
|
-
}
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
<!-- 源码: src/permissions/checker.ts -->
|
|
98
|
-
|
|
99
|
-
- 本地规则 .swifty/permissions.local.yaml (优先级最高)
|
|
100
|
-
- 项目规则 .swifty/permissions.yaml
|
|
101
|
-
- 全局规则 ~/.swifty/permissions.yaml (优先级最低)
|
|
102
|
-
|
|
103
|
-
```yaml
|
|
104
|
-
# 权限规则 (yaml)
|
|
105
|
-
- rule: Bash(git *)
|
|
106
|
-
effect: allow
|
|
107
|
-
|
|
108
|
-
- rule: Bash(git push --force*)
|
|
109
|
-
effect: deny
|
|
110
|
-
|
|
111
|
-
- rule: ReadFile(/path/to/src/*)
|
|
112
|
-
effect: allow
|
|
113
|
-
|
|
114
|
-
- rule: ReadFile(*.env*)
|
|
115
|
-
effect: deny
|
|
116
|
-
|
|
117
|
-
- rule: EditFile(*.ts)
|
|
118
|
-
effect: allow
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
```js
|
|
122
|
-
function evaluate(toolName, content) {
|
|
123
|
-
for (const path of [userPath, projectPath, localPath]) {
|
|
124
|
-
const rules = loadRulesFile(path);
|
|
125
|
-
// 从后往前遍历, 后面的规则覆盖前面的规则
|
|
126
|
-
for (let i = rules.length - 1; i >= 0; i--) {
|
|
127
|
-
const r = rules[i];
|
|
128
|
-
if (r.tool !== toolName && r.tool !== "*") continue;
|
|
129
|
-
if (globMatch(r.pattern, content)) {
|
|
130
|
-
return r.effect; // 返回 "allow" 或 "deny"
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
return null; // 无匹配规则
|
|
135
|
-
}
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
## 第 4 层: 权限模式
|
|
139
|
-
|
|
140
|
-
- plan: 读放行, 写确认, shell 命令确认; 通过 prompt 约束 LLM 行为, 使得 LLM 只读
|
|
141
|
-
- default: 读放行, 写确认, shell 命令确认
|
|
142
|
-
- acceptEdits: 读写放行, shell 命令确认
|
|
143
|
-
- bypassPermissions: 绕过权限, 读/写/ shell 命令全部放行, 但仍然拒绝 rm -rf / 等危险命令
|
|
144
|
-
<!-- 源码: src/permissions/checker.ts, modeDecide 函数 -->
|
|
145
|
-
|
|
146
|
-
| 模式 | 只读工具 (read) | 写工具 (write) | 命令工具 (command) |
|
|
147
|
-
| ----------------- | --------------- | -------------- | ------------------ |
|
|
148
|
-
| default | Allow | Ask | Ask |
|
|
149
|
-
| acceptEdits | Allow | Allow | Ask |
|
|
150
|
-
| plan | Allow | Ask | Ask |
|
|
151
|
-
| bypassPermissions | Allow | Allow | Allow |
|
|
152
|
-
|
|
153
|
-
<!-- 源码: src/permissions/checker.ts, acceptEdits 模式 category 为 command 时返回 ask -->
|
|
154
|
-
|
|
155
|
-
## 第 5 层: HITL 人在回路
|
|
156
|
-
|
|
157
|
-
前 4 层都无法确认时, 权限系统会阻塞 agent loop, 弹出对话框让用户确认; 提供「始终允许」选项; 需要确认时, 发送一个权限请求 (permission_request) 事件到事件流, 阻塞等待用户确认; 如果用户选择「始终允许」, 则会将新规则 (CLI 生成) 追加到本地配置文件
|
|
158
|
-
|
|
159
|
-
权限被拒绝时, 将权限拒绝作为一个 `isError: true` 的工具调用结果返回给 LLM, agent loop 继续运行; LLM 在下一轮 agent loop turn 中看到这个工具调用错误, 调整策略
|
|
160
|
-
|
|
161
|
-
## OS 级沙箱
|
|
162
|
-
|
|
163
|
-
- MacOS: seatbelt, 通过一个策略文件定义进程的行为边界
|
|
164
|
-
- Linux: bubblewrap + seccomp, bubblewrap 是一个轻量级的用户空间容器工具, 通过 linux 的 namespace 机制创建一个隔离环境, 通过 bubblewrap 执行命令
|
|
165
|
-
- OS 级沙箱模式默认断网, 防止数据泄漏
|
|
166
|
-
- OS 级沙箱不需要弹权限请求对话框, 用户可以通过 /sandbox 命令在三种模式间切换
|
|
167
|
-
- 开启沙箱 + autoAllow 自动放行
|
|
168
|
-
- 开启沙箱 + 手动确认
|
|
169
|
-
- 关闭沙箱
|
|
170
|
-
|
|
171
|
-
```txt
|
|
172
|
-
(version 1)
|
|
173
|
-
(deny default) ;; 默认拒绝
|
|
174
|
-
(allow process-exec) ;; 允许执行程序
|
|
175
|
-
(allow process-fork) ;; 允许 fork 子进程
|
|
176
|
-
(allow file-read* (subpath "/")) ;; 允许读整个文件系统
|
|
177
|
-
(allow file-write* (subpath "/project")) ;; 只允许写项目目录
|
|
178
|
-
(allow file-write* (subpath "/tmp")) ;; 只允许写临时目录
|
|
179
|
-
(deny file-write* (subpath "/project/.swifty/config.yaml")) ;; 禁止写配置文件
|
|
180
|
-
(deny network*) ;; 禁止访问网络
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
```bash
|
|
184
|
-
bwrap \
|
|
185
|
-
--unshare-user \ # 独立的用户 namespace
|
|
186
|
-
--unshare-pid \ # 独立的进程 namespace
|
|
187
|
-
--ro-bind / / \ # 整个文件系统挂载为只读
|
|
188
|
-
--bind /project /project \ # 项目目录可写
|
|
189
|
-
--ro-bind /project/.swifty/config.yaml /project/.swifty/config.yaml \ # 配置文件挂载为只读
|
|
190
|
-
--unshare-net \ # 独立的网络 namespace, 禁止访问网络
|
|
191
|
-
--proc /proc \ # 独立的 proc
|
|
192
|
-
bash -C "用户命令"
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
seccomp 在系统调用入口过滤: 可以禁止 ptrace 防止调试注入、禁止 mount 防止重新挂载文件系统以逃逸命名空间
|
|
196
|
-
|
|
197
|
-
### 禁止写项目目录内的敏感路径
|
|
198
|
-
|
|
199
|
-
- .swifty/config.yaml
|
|
200
|
-
- .swifty/permissions.local.yaml
|
|
201
|
-
- .swifty/skills
|