@clawos-dev/clawd 0.2.540 → 0.2.541
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/dist/cli.cjs +8 -7
- package/dist/deploy-kit/.secrets/aliyun.env.example +5 -2
- package/dist/deploy-kit/.secrets/aliyun.env.local.example +7 -10
- package/dist/deploy-kit/scripts/ensure-credentials.sh +21 -21
- package/dist/deploy-kit/scripts/ensure-credentials.spec.ts +31 -17
- package/dist/deploy-kit/scripts/publish.sh +1 -1
- package/dist/deploy-kit/scripts/remove-extension.sh +1 -1
- package/dist/persona-defaults/persona-app-builder/CLAUDE.md +6 -5
- package/dist/persona-defaults/persona-app-builder/extension-kit/README.md +2 -2
- package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/README.md +2 -2
- package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/config.env +1 -1
- package/dist/secrets/README.md +5 -2
- package/package.json +1 -1
- package/dist/deploy-kit/.secrets/aliyun.env +0 -7
package/dist/cli.cjs
CHANGED
|
@@ -50195,11 +50195,12 @@ var DEFAULT_PERSONAS = [
|
|
|
50195
50195
|
// 与 app-builder 对齐"调用阿里云的工作方式"(owner 2026-06-17 要求):开发型 profile —— 放开文件/web
|
|
50196
50196
|
// 工具 + node/pnpm 工具链精确路径 + 出站 TLD 通配白名单。html-slides 需要联网(git clone frontend-slides
|
|
50197
50197
|
// skill、调阿里云 CLI/SDK)。
|
|
50198
|
-
// 阿里云凭证:**复用共享 deploy-kit 单源**($HOME/.clawd/deploy-kit/.secrets/aliyun.env
|
|
50199
|
-
//
|
|
50200
|
-
//
|
|
50201
|
-
// deploy-kit/.secrets/aliyun.env; set +a`
|
|
50202
|
-
//
|
|
50198
|
+
// 阿里云凭证:**复用共享 deploy-kit 单源**($HOME/.clawd/deploy-kit/.secrets/aliyun.env.local,使用者自己写、
|
|
50199
|
+
// 全 FC persona 共用;bundle 不再 ship AK,见 specs/2026-09-18-aliyun-ak-leak-rotate-design.md),不在 persona
|
|
50200
|
+
// 目录另存一份。app-builder 的 FC 部署走 daemon 侧脚本(沙箱外)故其 profile 无需 carve 这个路径;html-slides
|
|
50201
|
+
// 没有 daemon 侧流程、要在 cc 沙箱内直接 `set -a; . $HOME/.clawd/deploy-kit/.secrets/aliyun.env.local; set +a`
|
|
50202
|
+
// 后调 aliyun CLI(env 凭证绕过沙箱外的 ~/.aliyun/),所以这里**额外**把这两个凭证文件加进 allowRead
|
|
50203
|
+
// (denyRead '~/' 之上的精确凿洞,单文件、最小暴露,同 ~/.npmrc 先例;aliyun.env 是老机器上的遗留文件)。
|
|
50203
50204
|
// excludedCommands: ['aliyun *'] —— 额外把 aliyun CLI 放沙箱外跑(逃出 seatbelt 直接用宿主凭证/网络),
|
|
50204
50205
|
// 与上面沙箱内 env 凭证方案并存,按运行时实际命令前缀匹配生效。
|
|
50205
50206
|
sandboxProfile: {
|
|
@@ -50209,7 +50210,7 @@ var DEFAULT_PERSONAS = [
|
|
|
50209
50210
|
},
|
|
50210
50211
|
sandbox: {
|
|
50211
50212
|
filesystem: {
|
|
50212
|
-
allowRead: ["~/.npmrc", "~/Library/Preferences/pnpm", "~/.nvm", "~/Library/pnpm", "~/.local/share/pnpm", "~/.local/state/pnpm", "~/.npm", "~/.pnpm-store", "~/.clawd/deploy-kit/.secrets/aliyun.env"],
|
|
50213
|
+
allowRead: ["~/.npmrc", "~/Library/Preferences/pnpm", "~/.nvm", "~/Library/pnpm", "~/.local/share/pnpm", "~/.local/state/pnpm", "~/.npm", "~/.pnpm-store", "~/.clawd/deploy-kit/.secrets/aliyun.env", "~/.clawd/deploy-kit/.secrets/aliyun.env.local"],
|
|
50213
50214
|
allowWrite: ["~/Library/pnpm", "~/.local/share/pnpm", "~/.local/state/pnpm", "~/.npm", "~/.pnpm-store"]
|
|
50214
50215
|
},
|
|
50215
50216
|
network: {
|
|
@@ -70910,7 +70911,7 @@ function computeMethodAccess(args) {
|
|
|
70910
70911
|
}
|
|
70911
70912
|
|
|
70912
70913
|
// src/version.ts
|
|
70913
|
-
var version = "0.2.
|
|
70914
|
+
var version = "0.2.541".length > 0 ? "0.2.541" : "dev";
|
|
70914
70915
|
|
|
70915
70916
|
// src/cli-probe/probe.ts
|
|
70916
70917
|
var fs78 = __toESM(require("fs"), 1);
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
#
|
|
2
|
-
# aliyun.env
|
|
1
|
+
# 阿里云 RAM AccessKey(publish.sh / remove-extension.sh 经 ensure-credentials.sh source)。
|
|
2
|
+
# clawd 不随包 ship 任何一把 AK:把自己的 AK/SK 写进同目录的 aliyun.env.local(推荐,永不被 OTA 覆盖)
|
|
3
|
+
# 或 aliyun.env;两个都不进 git(clawd/.gitignore 只放行 *.example)。云上不用文件,gateway 经 env 注入。
|
|
4
|
+
# 需要权限(按 90 天 ActionTrail 反推):FC(cn-hangzhou)+ SLS 的 serverless-cn-hangzhou-* project + 证书只读;
|
|
5
|
+
# 没见到 OSS 调用(大代码包是否走 OSS 中转未验证,缺了 s deploy 会在 ActionTrail 里报 NoPermission)。
|
|
3
6
|
ALIBABA_CLOUD_ACCESS_KEY_ID=replace-me
|
|
4
7
|
ALIBABA_CLOUD_ACCESS_KEY_SECRET=replace-me
|
|
@@ -1,15 +1,12 @@
|
|
|
1
|
-
# 阿里云 RAM AccessKey
|
|
1
|
+
# 阿里云 RAM AccessKey(本机专用)
|
|
2
2
|
#
|
|
3
|
-
# 复制这份为同目录下 aliyun.env.local,填自己的 AK/SK
|
|
4
|
-
# source
|
|
3
|
+
# 复制这份为同目录下 aliyun.env.local,填自己的 AK/SK。publish.sh / remove-extension.sh 会依次
|
|
4
|
+
# source aliyun.env(如果有)→ aliyun.env.local,后者的值覆盖前者。
|
|
5
5
|
#
|
|
6
|
-
# .local 后缀由 daemon refreshDeployKit 特判:**永远不会被 OTA
|
|
7
|
-
# (每次 daemon 启动会被 defaults 里的新版覆盖)是两回事。
|
|
6
|
+
# .local 后缀由 daemon refreshDeployKit 特判:**永远不会被 OTA 覆盖**。
|
|
8
7
|
#
|
|
9
|
-
#
|
|
10
|
-
# -
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
# 不需要用 .local 时(大部分情况):删掉这个 .local 文件、直接跑 clawd defaults,OTA 后自动拿到新 demo 凭证。
|
|
8
|
+
# 2026-09-18 起 clawd 不再随包 ship 共享 demo AK(上一把随 npm 包发出去 69 秒就被 TruffleHog 收割,
|
|
9
|
+
# 主账号被阿里云风控锁;见 specs/2026-09-18-aliyun-ak-leak-rotate-design.md)——本机发布必须配这份。
|
|
10
|
+
# 老机器上 OTA 留下的 aliyun.env 里那把 AK 已泄露、不可再用,不用删,配了 .local 就会盖过它。
|
|
14
11
|
ALIBABA_CLOUD_ACCESS_KEY_ID=replace-me
|
|
15
12
|
ALIBABA_CLOUD_ACCESS_KEY_SECRET=replace-me
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
# 被 `source` 进来,再调 ensure_credentials。跟 ensure-toolchain.sh 是一对:
|
|
5
5
|
# 那个管「命令在不在」,这个管「命令拿什么身份跑」。
|
|
6
6
|
#
|
|
7
|
-
# 硬约束:**全程不碰用户全局 ~/.s**。clawd 发布用的是
|
|
8
|
-
#
|
|
9
|
-
#
|
|
7
|
+
# 硬约束:**全程不碰用户全局 ~/.s**。clawd 发布用的是 deploy-kit 自己那份 AK(本机 .secrets/
|
|
8
|
+
# 下使用者写的文件,云上是 gateway 注入的 env),而 ~/.s/access.yaml 里的 default 是用户自己账号的
|
|
9
|
+
# Serverless Devs 凭证——它是用户的东西,不是我们的。做法对齐本 kit 处理 aliyun CLI 的方式(凭证只进本次进程的 env,
|
|
10
10
|
# 全局 ~/.aliyun/ 一个字节不碰):把 Serverless Devs 的配置家目录整个指到 deploy-kit
|
|
11
11
|
# 名下,access.yaml 写在那里。
|
|
12
12
|
# ============================================================
|
|
@@ -18,27 +18,27 @@
|
|
|
18
18
|
# 里的 access 字段,本改动前 scaffold 的老项目(s.yaml 写着 default)照样走这条。
|
|
19
19
|
S_ACCESS_ALIAS=clawd-fc
|
|
20
20
|
|
|
21
|
-
# 分层加载阿里云 AK 进 env
|
|
21
|
+
# 分层加载阿里云 AK 进 env,三层平铺、后读的覆盖先读的:
|
|
22
|
+
# 1. `$KIT_DIR/.secrets/aliyun.env` —— 使用者自己写的(或 2026-09-18 之前 OTA 留下的旧文件);
|
|
23
|
+
# 2. `$KIT_DIR/.secrets/aliyun.env.local` —— 使用者自己写的,refreshDeployKit 永不覆盖;
|
|
24
|
+
# 3. 进程 env 里已有的 `ALIBABA_CLOUD_ACCESS_KEY_ID/_SECRET` —— 云上容器那条路:Pod 里没有
|
|
25
|
+
# `.secrets/`(`cloud-host/provision/build-image.mjs` 刻意把它剔出镜像层——镜像要分发,凭据
|
|
26
|
+
# 进层就洗不掉了),AK 由 gateway 经 **MCP server 的 per-server env** 交到调用本脚本的那个
|
|
27
|
+
# 进程里(M1b Step 9)。不落盘是有意的:写成文件的话 agent 一个 `cat` 就看见了。
|
|
22
28
|
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
# - 云上容器:没有 `.secrets/`(`cloud-host/provision/build-image.mjs` 刻意把它剔出镜像层
|
|
26
|
-
# ——镜像要分发,凭据进层就洗不掉了),AK 由 gateway 经 **MCP server 的 per-server env**
|
|
27
|
-
# 交到调用本脚本的那个进程里(M1b Step 9)。这条分支不落盘是有意的:写成文件的话
|
|
28
|
-
# agent 一个 `cat` 就看见了,而 env 只有这个子进程有。
|
|
29
|
+
# clawd **不再随包 ship 任何一把 AK**(2026-09-18 起,见 specs/2026-09-18-aliyun-ak-leak-rotate-design.md:
|
|
30
|
+
# 上一把随 npm 包发出去 69 秒就被 TruffleHog 收割,主账号被风控锁)。三层都空 = 使用者还没配,fail-loud。
|
|
29
31
|
ensure_aliyun_env() {
|
|
30
32
|
local kit="${KIT_DIR:?ensure_aliyun_env 需要调用方先设 KIT_DIR}"
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
set -a; . "$kit/.secrets/aliyun.env.local"; set +a
|
|
33
|
+
local f
|
|
34
|
+
# 写成 if 而不是 `[ -f ] && { }`:后者在函数末尾会把「文件不存在」变成函数返回 1,调用方 set -e 直接中止。
|
|
35
|
+
for f in "$kit/.secrets/aliyun.env" "$kit/.secrets/aliyun.env.local"; do
|
|
36
|
+
if [ -f "$f" ]; then
|
|
37
|
+
set -a; . "$f"; set +a
|
|
37
38
|
fi
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
echo "❌ 缺 $kit/.secrets/aliyun.env(clawd ship 的共享 demo 凭证,OTA 自动刷新),env 里也没有 ALIBABA_CLOUD_ACCESS_KEY_ID/_SECRET。参考 .secrets/aliyun.env.example 填写。" >&2
|
|
39
|
+
done
|
|
40
|
+
if [ -z "${ALIBABA_CLOUD_ACCESS_KEY_ID:-}" ] || [ -z "${ALIBABA_CLOUD_ACCESS_KEY_SECRET:-}" ]; then
|
|
41
|
+
echo "❌ 没有阿里云 AK:把自己的 AK/SK 写进 $kit/.secrets/aliyun.env.local(参考同目录 aliyun.env.local.example;这个文件不会被 OTA 覆盖),云上则由 gateway 经 env 注入。" >&2
|
|
42
42
|
return 1
|
|
43
43
|
fi
|
|
44
44
|
export ALIBABA_CLOUD_REGION_ID="${REGION:?config.env 缺 REGION}"
|
|
@@ -80,7 +80,7 @@ ensure_s_access() {
|
|
|
80
80
|
# 把 CLI 原文摆出来,让读的人按原文判断。
|
|
81
81
|
echo "❌ aliyun sts GetCallerIdentity 失败,拿不到 AccountId。aliyun 原文:" >&2
|
|
82
82
|
echo "$ident" >&2
|
|
83
|
-
echo " 排查顺序:① 上面这行 CLI 原文说的是什么 ② $kit/.secrets/aliyun.env
|
|
83
|
+
echo " 排查顺序:① 上面这行 CLI 原文说的是什么 ② $kit/.secrets/aliyun.env.local(或 aliyun.env)里的 AK 是否有效——2026-09-18 之前 OTA 发的那把已泄露、不可再用,得换自己的 ③ config.env 的 REGION" >&2
|
|
84
84
|
return 1
|
|
85
85
|
}
|
|
86
86
|
# 用 node 不用 python3:目标机器保证有 node(clawd 本身就是 node 跑的),不保证有 python
|
|
@@ -78,11 +78,12 @@ beforeEach(() => {
|
|
|
78
78
|
mkdirSync(join(home, '.s'), { recursive: true })
|
|
79
79
|
mkdirSync(bin, { recursive: true })
|
|
80
80
|
|
|
81
|
-
// 真脚本进沙箱 kit
|
|
81
|
+
// 真脚本进沙箱 kit。.secrets 按生产形状:bundle 只带 *.example(2026-09-18 起 AK 不再随包
|
|
82
|
+
// 分发,见 specs/2026-09-18-aliyun-ak-leak-rotate-design.md),本机凭证是使用者自己写的 .local。
|
|
82
83
|
cpSync(SCRIPTS_DIR, join(kit, 'scripts'), { recursive: true })
|
|
83
84
|
writeFileSync(
|
|
84
|
-
join(kit, '.secrets', 'aliyun.env'),
|
|
85
|
-
'ALIBABA_CLOUD_ACCESS_KEY_ID=LTAI-
|
|
85
|
+
join(kit, '.secrets', 'aliyun.env.local'),
|
|
86
|
+
'ALIBABA_CLOUD_ACCESS_KEY_ID=LTAI-MY-OWN\nALIBABA_CLOUD_ACCESS_KEY_SECRET=my-own-secret\n',
|
|
86
87
|
)
|
|
87
88
|
writeFileSync(join(home, '.s', 'access.yaml'), USER_ACCESS_YAML)
|
|
88
89
|
writeAliyunShim(bin)
|
|
@@ -127,8 +128,8 @@ describe('ensure_credentials', () => {
|
|
|
127
128
|
runInKit('ensure_credentials')
|
|
128
129
|
const yaml = kitAccessYaml()
|
|
129
130
|
expect(yaml).toContain("AccountID: '5566778899001122'")
|
|
130
|
-
expect(yaml).toContain('AccessKeyID: LTAI-
|
|
131
|
-
expect(yaml).toContain('AccessKeySecret:
|
|
131
|
+
expect(yaml).toContain('AccessKeyID: LTAI-MY-OWN')
|
|
132
|
+
expect(yaml).toContain('AccessKeySecret: my-own-secret')
|
|
132
133
|
})
|
|
133
134
|
|
|
134
135
|
it('profile 名是 clawd-fc 而不是 default', () => {
|
|
@@ -151,14 +152,26 @@ describe('ensure_credentials', () => {
|
|
|
151
152
|
expect(mode.toString(8)).toBe('600')
|
|
152
153
|
})
|
|
153
154
|
|
|
154
|
-
|
|
155
|
+
// 存量机器:OTA 停发 aliyun.env 之后 refreshDeployKit 不再覆盖也不删它,旧文件会留在盘上。
|
|
156
|
+
// 有 .local 时 .local 必须盖过它(否则老用户配了自己的 AK 还在用那把已停用的)。
|
|
157
|
+
it('legacy aliyun.env 仍被读,但 .local 覆盖它', () => {
|
|
155
158
|
writeFileSync(
|
|
156
|
-
join(box.kit, '.secrets', 'aliyun.env
|
|
157
|
-
'ALIBABA_CLOUD_ACCESS_KEY_ID=LTAI-
|
|
159
|
+
join(box.kit, '.secrets', 'aliyun.env'),
|
|
160
|
+
'ALIBABA_CLOUD_ACCESS_KEY_ID=LTAI-STALE-OTA\nALIBABA_CLOUD_ACCESS_KEY_SECRET=stale-ota-secret\n',
|
|
158
161
|
)
|
|
159
162
|
runInKit('ensure_credentials')
|
|
160
163
|
expect(kitAccessYaml()).toContain('AccessKeyID: LTAI-MY-OWN')
|
|
161
|
-
expect(kitAccessYaml()).toContain('
|
|
164
|
+
expect(kitAccessYaml()).not.toContain('LTAI-STALE-OTA')
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
it('只有 aliyun.env 没有 .local 也能用(使用者直接写 aliyun.env 的老习惯)', () => {
|
|
168
|
+
rmSync(join(box.kit, '.secrets', 'aliyun.env.local'))
|
|
169
|
+
writeFileSync(
|
|
170
|
+
join(box.kit, '.secrets', 'aliyun.env'),
|
|
171
|
+
'ALIBABA_CLOUD_ACCESS_KEY_ID=LTAI-PLAIN-FILE\nALIBABA_CLOUD_ACCESS_KEY_SECRET=plain-file-secret\n',
|
|
172
|
+
)
|
|
173
|
+
runInKit('ensure_credentials')
|
|
174
|
+
expect(kitAccessYaml()).toContain('AccessKeyID: LTAI-PLAIN-FILE')
|
|
162
175
|
})
|
|
163
176
|
|
|
164
177
|
it('调 aliyun 时显式传 AK 和 region,不靠环境变量的隐式优先级', () => {
|
|
@@ -169,8 +182,8 @@ describe('ensure_credentials', () => {
|
|
|
169
182
|
writeAliyunShim(box.bin, '5566778899001122', log)
|
|
170
183
|
runInKit('ensure_credentials')
|
|
171
184
|
const argv = readFileSync(log, 'utf8')
|
|
172
|
-
expect(argv).toContain('--access-key-id LTAI-
|
|
173
|
-
expect(argv).toContain('--access-key-secret
|
|
185
|
+
expect(argv).toContain('--access-key-id LTAI-MY-OWN')
|
|
186
|
+
expect(argv).toContain('--access-key-secret my-own-secret')
|
|
174
187
|
expect(argv).toContain('--region cn-hangzhou')
|
|
175
188
|
})
|
|
176
189
|
|
|
@@ -182,17 +195,17 @@ describe('ensure_credentials', () => {
|
|
|
182
195
|
expect(kitAccessYaml()).toContain("AccountID: '5566778899001122'")
|
|
183
196
|
})
|
|
184
197
|
|
|
185
|
-
it('
|
|
186
|
-
rmSync(join(box.kit, '.secrets', 'aliyun.env'))
|
|
187
|
-
expect(() => runInKit('ensure_credentials')).toThrow()
|
|
198
|
+
it('aliyun.env / .local 都没有、env 里也没有 AK 时 fail-loud,文案指到 .local', () => {
|
|
199
|
+
rmSync(join(box.kit, '.secrets', 'aliyun.env.local'))
|
|
200
|
+
expect(() => runInKit('ensure_credentials')).toThrow(/aliyun\.env\.local/)
|
|
188
201
|
expect(existsSync(join(box.kit, '.s-home', '.s', 'access.yaml'))).toBe(false)
|
|
189
202
|
})
|
|
190
203
|
|
|
191
204
|
// 云上分支(persona 上云 M1b Step 9):容器里没有 `.secrets/`——`build-image.mjs` 刻意把它
|
|
192
205
|
// 剔出镜像层(镜像要分发,凭据进层洗不掉)。AK 由 gateway 经 **MCP server 的 per-server env**
|
|
193
206
|
// 交到调用本脚本的那个子进程里,不落文件:写成文件的话 agent 一个 `cat` 就看见了。
|
|
194
|
-
it('没有 .secrets/
|
|
195
|
-
rmSync(join(box.kit, '.secrets', 'aliyun.env'))
|
|
207
|
+
it('没有 .secrets/ 凭证文件但 env 里有 AK 时用 env(云上容器那条路)', () => {
|
|
208
|
+
rmSync(join(box.kit, '.secrets', 'aliyun.env.local'))
|
|
196
209
|
const out = execFileSync(
|
|
197
210
|
'bash',
|
|
198
211
|
[
|
|
@@ -221,7 +234,7 @@ printf 'ok %s\\n' "$ALIBABA_CLOUD_ACCESS_KEY_ID"`,
|
|
|
221
234
|
expect(userAccessYaml()).toContain('LTAI-USER-OWN-KEY')
|
|
222
235
|
})
|
|
223
236
|
|
|
224
|
-
it('文件在就优先用文件(云上那条只是兜底,不能反过来盖掉本机
|
|
237
|
+
it('文件在就优先用文件(云上那条只是兜底,不能反过来盖掉本机 .local 凭证)', () => {
|
|
225
238
|
const out = execFileSync(
|
|
226
239
|
'bash',
|
|
227
240
|
[
|
|
@@ -244,6 +257,7 @@ printf 'id=%s\\n' "$ALIBABA_CLOUD_ACCESS_KEY_ID"`,
|
|
|
244
257
|
encoding: 'utf8',
|
|
245
258
|
},
|
|
246
259
|
)
|
|
260
|
+
expect(out).toContain('id=LTAI-MY-OWN')
|
|
247
261
|
expect(out).not.toContain('LTAI-FROM-ENV')
|
|
248
262
|
})
|
|
249
263
|
})
|
|
@@ -58,7 +58,7 @@ if ! grep -qxF 's.*.yaml' "$EXT_DIR/.gitignore" 2>/dev/null; then
|
|
|
58
58
|
echo " 📝 .gitignore 补 s.*.yaml (渲出的 s.int.yaml / s.prod.yaml 含 key,不进仓库;记得把 .gitignore 推上去)"
|
|
59
59
|
fi
|
|
60
60
|
|
|
61
|
-
# 2) 工具链 +
|
|
61
|
+
# 2) 工具链 + 阿里云凭证(使用者自己的 .secrets/aliyun.env.local,云上是 env;见 ensure-credentials.sh)
|
|
62
62
|
source "$KIT_DIR/scripts/ensure-toolchain.sh"
|
|
63
63
|
ensure_toolchain
|
|
64
64
|
source "$KIT_DIR/scripts/ensure-credentials.sh"
|
|
@@ -28,7 +28,7 @@ TABLE_PREFIX_INT="${TABLE_PREFIX}int_"
|
|
|
28
28
|
source "$KIT_DIR/scripts/ensure-toolchain.sh"
|
|
29
29
|
ensure_toolchain
|
|
30
30
|
|
|
31
|
-
#
|
|
31
|
+
# 阿里云凭证(使用者自己的 .secrets/aliyun.env.local,云上是 env)+ deploy-kit 私有的 s profile
|
|
32
32
|
source "$KIT_DIR/scripts/ensure-credentials.sh"
|
|
33
33
|
ensure_credentials
|
|
34
34
|
|
|
@@ -111,12 +111,13 @@
|
|
|
111
111
|
- 工具链 `aliyun` CLI + Serverless Devs(`s`)由 `deploy-kit/scripts/ensure-toolchain.sh` 在 publish / remove 前自动检测 + 安装,接管发布失败时**不必再排查「CLI 没装」**
|
|
112
112
|
- 实时推送用 Supabase Realtime(FC 不维持长连接)
|
|
113
113
|
|
|
114
|
-
##
|
|
114
|
+
## 阿里云凭证:使用者自带,放共享 deploy-kit 的 `.secrets/`
|
|
115
115
|
|
|
116
|
-
AK/SK
|
|
116
|
+
clawd **不随包 ship 任何一把 AK**。AK/SK 放在 `$HOME/.clawd/deploy-kit/.secrets/`、全 FC persona 共用,不在系统环境变量里:
|
|
117
117
|
|
|
118
|
-
- **`aliyun.env`** —
|
|
119
|
-
- **`aliyun.env
|
|
118
|
+
- **`aliyun.env.local`** — 使用者自己的 AK,永远不被 OTA 覆盖。复制 `aliyun.env.local.example` → `aliyun.env.local` 填值
|
|
119
|
+
- **`aliyun.env`**(可有可无)— 也会被读,`.local` 覆盖它。老机器上 2026-09-18 之前 OTA 留下的这份里的 AK 已泄露、不可再用
|
|
120
|
+
- 云上没有这两个文件,AK 由 gateway 经 MCP server 的 env 注入
|
|
120
121
|
|
|
121
122
|
手动排障要跑 `aliyun` / `s` 命令时,在**同一条 Bash** 里加载再用(shell 变量不跨调用留存):
|
|
122
123
|
|
|
@@ -129,7 +130,7 @@ aliyun_ak fc GET /2023-03-30/custom-domains # aliyun 一律走 aliyun_a
|
|
|
129
130
|
s deploy -y -t s.int.yaml --access "$S_ACCESS_ALIAS" # s 一律显式带 profile + 指明哪个环境的 s 文件(s.int.yaml / s.prod.yaml)
|
|
130
131
|
```
|
|
131
132
|
|
|
132
|
-
**红线**:绝不写用户全局 `~/.s/access.yaml`(那里是用户自己账号的凭证,盖上去不可恢复);绝不 `echo` / 打印 / 写进日志或提交记录里暴露 SK;绝不把 `.secrets/`
|
|
133
|
+
**红线**:绝不写用户全局 `~/.s/access.yaml`(那里是用户自己账号的凭证,盖上去不可恢复);绝不 `echo` / 打印 / 写进日志或提交记录里暴露 SK;绝不把 `.secrets/` 拷进项目代码;`ensure_credentials` 报「没有阿里云 AK」就停下提醒老板配 `aliyun.env.local`,别自己去找别的 AK 填。
|
|
133
134
|
|
|
134
135
|
## 任务分级与节奏
|
|
135
136
|
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
FC 对应用只有一条要求:**一个监听 `$PORT` 的 HTTP server**。所以固化的是「发布管道」,不是技术栈。
|
|
8
8
|
|
|
9
|
-
- **共享 deploy-kit(凭证 + 脚本骨架 + bootstrap,全 FC persona 一份)**:`$HOME/.clawd/deploy-kit/`(`scripts/` + `contract/bootstrap` + `.secrets/aliyun.env`)
|
|
9
|
+
- **共享 deploy-kit(凭证 + 脚本骨架 + bootstrap,全 FC persona 一份)**:`$HOME/.clawd/deploy-kit/`(`scripts/` + `contract/bootstrap` + `.secrets/aliyun.env.local`)
|
|
10
10
|
- **persona 特化(本目录)**:`config.env`(注入值) + `contract/s.yaml.tmpl`(占位符清单) + `examples/`(默认 `nestjs-react`)
|
|
11
11
|
|
|
12
12
|
## 目录
|
|
@@ -14,7 +14,7 @@ FC 对应用只有一条要求:**一个监听 `$PORT` 的 HTTP server**。所以
|
|
|
14
14
|
```
|
|
15
15
|
# 共享 deploy-kit($HOME/.clawd/deploy-kit/,daemon 维护,全 persona 共用)
|
|
16
16
|
deploy-kit/
|
|
17
|
-
├── .secrets/aliyun.env
|
|
17
|
+
├── .secrets/aliyun.env.local 阿里云凭证(单源,使用者自己写;bundle 只带 *.example)
|
|
18
18
|
├── contract/bootstrap FC 启动入口(Node 参考实现:find node + cd + exec)
|
|
19
19
|
└── scripts/
|
|
20
20
|
├── new-extension.sh 从示例生成新 extension(纯 copy,daemon 自动跑)
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
FC 对应用只有一条要求:**一个监听 `$PORT` 的 HTTP server**。所以固化的是「发布管道」,不是技术栈。
|
|
8
8
|
|
|
9
|
-
- **共享 deploy-kit(凭证 + 脚本骨架 + bootstrap,全 FC persona 一份)**:`$HOME/.clawd/deploy-kit/`(`scripts/` + `contract/bootstrap` + `.secrets/aliyun.env`)
|
|
9
|
+
- **共享 deploy-kit(凭证 + 脚本骨架 + bootstrap,全 FC persona 一份)**:`$HOME/.clawd/deploy-kit/`(`scripts/` + `contract/bootstrap` + `.secrets/aliyun.env.local`)
|
|
10
10
|
- **persona 特化(本目录)**:`config.env`(dataclaw 注入值) + `contract/s.yaml.tmpl`(占位符清单) + `hooks/pre-deploy.sh`(发布前置) + `examples/`(默认 `nestjs-react`)
|
|
11
11
|
|
|
12
12
|
## 目录
|
|
@@ -14,7 +14,7 @@ FC 对应用只有一条要求:**一个监听 `$PORT` 的 HTTP server**。所以
|
|
|
14
14
|
```
|
|
15
15
|
# 共享 deploy-kit($HOME/.clawd/deploy-kit/,daemon 维护,全 persona 共用)
|
|
16
16
|
deploy-kit/
|
|
17
|
-
├── .secrets/aliyun.env
|
|
17
|
+
├── .secrets/aliyun.env.local 阿里云凭证(单源,使用者自己写;bundle 只带 *.example)
|
|
18
18
|
├── contract/bootstrap FC 启动入口(Node 参考实现:find node + cd + exec)
|
|
19
19
|
└── scripts/
|
|
20
20
|
├── new-extension.sh 从示例生成新 extension(纯 copy,daemon 自动跑)
|
package/dist/secrets/README.md
CHANGED
|
@@ -17,8 +17,11 @@ agent 主进程 env 一条都不放。读法与合并顺序见 `../deploy/secret
|
|
|
17
17
|
|
|
18
18
|
## 信任层级:这里的每一把 key 都等于公开
|
|
19
19
|
|
|
20
|
-
本目录随 npm 包 ship
|
|
21
|
-
|
|
20
|
+
本目录随 npm 包 ship 给所有用户。判断风险时按「这把 key 落在所有用户手上」算——不是比喻:
|
|
21
|
+
deploy-kit 的阿里云 AK 曾经也这么 ship,随 npm 包发出去 **69 秒**就被 TruffleHog 收割、90 天内被
|
|
22
|
+
100+ 个境外 IP 验证约 600 次,最后主账号被阿里云风控锁;2026-09-18 起它不再随包分发
|
|
23
|
+
(`specs/2026-09-18-aliyun-ak-leak-rotate-design.md`)。这里的 supabase 三件套(含 service-role)
|
|
24
|
+
仍在 ship,是同一类风险。把 service-role key 换成受限 role 的收敛方向记在 glossary,
|
|
22
25
|
不在 M1b 范围。
|
|
23
26
|
|
|
24
27
|
## 本机覆盖
|
package/package.json
CHANGED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
# 阿里云 RAM AccessKey — clawd ship 的共享 demo 凭证(publish.sh 先 source 这个)
|
|
2
|
-
# 归属 RAM 用户 clawd-fc-developer(独立收敛权限用户,跟 owner 主账号解耦)
|
|
3
|
-
# 每次 daemon 启动 refreshDeployKit 会用 defaults 里的最新版覆盖本文件(OTA 即升级)。
|
|
4
|
-
# 想用自己的 AK 覆盖:复制 aliyun.env.local.example → aliyun.env.local 并填自己的值。
|
|
5
|
-
# 需要权限:AliyunFCFullAccess + AliyunSTSAssumeRoleAccess
|
|
6
|
-
ALIBABA_CLOUD_ACCESS_KEY_ID=LTAI5tAi7P7oySa3ohAzaYbj
|
|
7
|
-
ALIBABA_CLOUD_ACCESS_KEY_SECRET=NS470lOWTLeeAP9RUADXkpKNOrH5QX
|