@aalis/plugin-reach 0.0.0-stage → 0.1.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ace Nyan <ace@acenyan.com>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,21 @@
1
- # Temporary Holding Version
1
+ # @aalis/plugin-reach
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ 触及:按一次工具调用签发触及凭据(契约见 `@aalis/api-reach`)。发起类别取权限服务的 `originOf`,房间类别、档位与越界策略、绑定取会话管理里的记录,三张受保护清单在激活时按家目录布局与真实路径算好,交给 `resolveReach` 定上限:只有 owner 在自己的会话里有本地效果,子任务随发起它的那一轮父会话。另管本会话临时区(建、随会话删、定期清扫)、子进程环境(owner 的 login shell 环境,沙箱内去掉凭据)、会话的污点与白纸的来源账本。
4
+
5
+ ## 角色
6
+
7
+ 运行时插件,提供 `reach` 服务。
8
+
9
+ ## 安装
10
+
11
+ ```bash
12
+ pnpm add @aalis/plugin-reach
13
+ ```
14
+
15
+ ## 使用
16
+
17
+ 参考 [docs/plugins/plugin-reach.md](../../docs/plugins/plugin-reach.md) 与 [docs/api/api-reach.md](../../docs/api/api-reach.md)。
18
+
19
+ ## 许可
20
+
21
+ MIT,见本目录 LICENSE。
@@ -0,0 +1,16 @@
1
+ import { type ProvenanceRecord, type Reach, type ReachCredential } from '@aalis/api-reach';
2
+ interface CredentialDeps {
3
+ sessionId: string;
4
+ /** 舞台上放各场所白纸的目录:写进这里的才进来源账本 */
5
+ papers: string;
6
+ /** 操作系统用户的家目录:沙箱里 npm 的用户配置从这里的 .npmrc 去掉凭据行 */
7
+ userHome: string;
8
+ /** 在场所的主目录下取的 login shell 环境 */
9
+ loginEnv(home: string): Promise<Record<string, string>>;
10
+ /** 记进来源账本 */
11
+ record(realPath: string, entry: ProvenanceRecord): void;
12
+ }
13
+ /** current 每次调用都按会话当时的设置与污点算出这次调用的触及 */
14
+ export declare function issueCredential(current: () => Reach, deps: CredentialDeps): ReachCredential;
15
+ export {};
16
+ //# sourceMappingURL=credential.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credential.d.ts","sourceRoot":"","sources":["../src/credential.ts"],"names":[],"mappings":"AAOA,OAAO,EAGL,KAAK,gBAAgB,EAErB,KAAK,KAAK,EAEV,KAAK,eAAe,EAIrB,MAAM,kBAAkB,CAAC;AAG1B,UAAU,cAAc;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,+BAA+B;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,gDAAgD;IAChD,QAAQ,EAAE,MAAM,CAAC;IACjB,gCAAgC;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACxD,aAAa;IACb,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB,GAAG,IAAI,CAAC;CACzD;AAED,wCAAwC;AACxC,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,KAAK,EAAE,IAAI,EAAE,cAAc,GAAG,eAAe,CAkC3F"}
@@ -0,0 +1,88 @@
1
+ // ============================================================
2
+ // 触及凭据:按一次工具调用签发,带品牌符号,冻结
3
+ //
4
+ // 签发时的触及定下命令在哪执行、场所的主目录与白纸、子进程环境;判定、存储兜底、沙箱策略与来源账本每次按当时的触及,
5
+ // 签发之后降档或受污染立即生效。
6
+ // ============================================================
7
+ import { judgeReach, matchesRule, REACH_CREDENTIAL, sandboxPolicyOf, } from '@aalis/api-reach';
8
+ import { sandboxEnv } from './process-env.js';
9
+ /** current 每次调用都按会话当时的设置与污点算出这次调用的触及 */
10
+ export function issueCredential(current, deps) {
11
+ const issued = current();
12
+ const local = issued.exec === 'none' ? undefined : issued;
13
+ const credential = {
14
+ exec: issued.exec,
15
+ ...(local && {
16
+ home: local.home,
17
+ paper: local.paper,
18
+ // 全权档不带:全权不提示,确认卡上也不写来源
19
+ ...(local.tainted && local.tier !== 'full' && { tainted: local.tainted }),
20
+ }),
21
+ async require(request) {
22
+ const reach = current();
23
+ const decision = judgeReach(reach, request);
24
+ return decision.verdict === 'allow'
25
+ ? { allowed: true }
26
+ : { allowed: false, message: explain(decision, request, reach.exec === 'none' ? undefined : reach.tainted) };
27
+ },
28
+ allows: (effect, realPath) => judgeReach(current(), { effect, path: realPath }).verdict === 'allow',
29
+ sandboxPolicy: () => sandboxPolicyOf(current()),
30
+ async processEnv(mode) {
31
+ if (!local)
32
+ throw new Error('这次调用没有本地效果,没有子进程环境');
33
+ const env = await deps.loginEnv(local.home);
34
+ return mode === 'host' ? { ...env } : sandboxEnv(env, local.sessionTmp, deps.userHome);
35
+ },
36
+ noteWrite(realPath) {
37
+ const reach = current();
38
+ if (reach.exec === 'none' || !reach.tainted)
39
+ return;
40
+ if (!matchesRule({ path: deps.papers }, realPath, reach.lists.platform))
41
+ return;
42
+ deps.record(realPath, { sessionId: deps.sessionId, sources: reach.tainted, at: Date.now() });
43
+ },
44
+ };
45
+ // 品牌不可枚举:展开或 Object.assign 复制出来、改了方法再转交的对象不带它
46
+ return Object.freeze(Object.defineProperty(credential, REACH_CREDENTIAL, { value: true }));
47
+ }
48
+ /** 回给模型的话:要做什么、为什么不行、能不能申请 */
49
+ function explain(decision, request, tainted) {
50
+ const subject = subjectOf(request);
51
+ if (decision.verdict === 'ask')
52
+ return `${subject}:${why(decision.reason, tainted)},要 owner 批准,这里没有可用的审批`;
53
+ switch (decision.rule) {
54
+ case 'no-local-effect':
55
+ return `${subject}:这个会话里没有本地效果,读写文件、执行命令只在 owner 自己的会话里可用`;
56
+ case 'control-plane':
57
+ return `${subject}:在宿主控制面里,任何档位都不能写;不可申请,不要尝试绕过`;
58
+ case 'deny-read':
59
+ return `${subject}:在拒读清单里;不可申请,不要尝试绕过`;
60
+ case 'boundary-policy':
61
+ return `${subject}:${why(decision.reason, tainted)},越界策略是直接拒绝`;
62
+ }
63
+ }
64
+ function subjectOf(request) {
65
+ switch (request.effect) {
66
+ case 'read':
67
+ return `读 ${request.path}`;
68
+ case 'write':
69
+ return 'path' in request ? `写 ${request.path}` : `写编排定义 ${request.workflow}`;
70
+ case 'exec':
71
+ return request.host ? '在沙箱外执行命令' : '执行命令';
72
+ case 'network':
73
+ return { url: '访问模型给的网址', command: '执行要联网的命令', provider: '联网' }[request.via];
74
+ }
75
+ }
76
+ function why(reason, tainted) {
77
+ switch (reason.kind) {
78
+ case 'tier':
79
+ return '修改确认档里每一次写与执行都要问';
80
+ case 'boundary':
81
+ return { 'write-path': '超出了可写范围', 'host-exec': '要在沙箱外执行', network: '只读档里联网要问' }[reason.target];
82
+ case 'landing':
83
+ return '这里会被自动执行或用于持久化';
84
+ case 'outbound':
85
+ return `这个会话读进过别人写的内容(${tainted?.join('、')}),这一步会把内容送出会话`;
86
+ }
87
+ }
88
+ //# sourceMappingURL=credential.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credential.js","sourceRoot":"","sources":["../src/credential.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import { type ProtectedLists } from '@aalis/api-reach';
2
+ import type { Logger } from '@aalis/core';
3
+ /** 文件或目录不存在 */
4
+ export declare function isMissing(err: unknown): boolean;
5
+ /** 安装集的形态:下有 packages/ 目录的是源码形态,其余是 npm 形态(create-aalis 生成的项目) */
6
+ export declare function formOf(app: string): Promise<'source' | 'npm'>;
7
+ /** 守护进程的入口文件:启动脚本(process.argv[1])的真实路径;没有或取不到时为 undefined */
8
+ export declare function entryOf(): Promise<string | undefined>;
9
+ /**
10
+ * 清单里以具体路径为根的规则,各个根的真实路径(交给 api-reach 的 withRealRoots):不存在的不记;取不了的(没有权限、
11
+ * 链接成环)记 warn,这一条只按写法拦
12
+ */
13
+ export declare function realRootsOf(lists: ProtectedLists, logger: Pick<Logger, 'warn'>): Promise<Map<string, string>>;
14
+ /**
15
+ * 安装集以外、守护进程加载了代码的目录,归宿主控制面(安装集里的已由清单按安装集的目录覆盖):
16
+ * - 安装集 node_modules 顶层(含 `@scope/` 下)解析到安装集以外的包,整个目录;
17
+ * - 源码形态下 packages/ 里链接到安装集以外的包,与安装集里的包一样只算构建产物与依赖。
18
+ * 断掉的链接不是加载了的代码,跳过
19
+ */
20
+ export declare function codeDirsOf(app: string): Promise<string[]>;
21
+ /**
22
+ * 目录所在仓库的 git 目录(common dir,真实路径):从目录往上找 `.git`。文件形式的 `.git`(worktree、子模块)按里面的
23
+ * gitdir 与 commondir 找到共用的那个。找到的不像 git 目录(没有 HEAD 与 objects)的不算,免得一个 `.git` 把任意目录
24
+ * 指成可写。不在仓库里时为 undefined
25
+ */
26
+ export declare function gitDirOf(dir: string): Promise<string | undefined>;
27
+ //# sourceMappingURL=host-dirs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host-dirs.d.ts","sourceRoot":"","sources":["../src/host-dirs.ts"],"names":[],"mappings":"AAQA,OAAO,EAAe,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACpE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,eAAe;AACf,wBAAgB,SAAS,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAE/C;AASD,kEAAkE;AAClE,wBAAsB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,KAAK,CAAC,CAMnE;AAED,8DAA8D;AAC9D,wBAAsB,OAAO,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAG3D;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAAC,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAcnH;AAED;;;;;GAKG;AACH,wBAAsB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAsB/D;AAED;;;;GAIG;AACH,wBAAsB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAoBvE"}
@@ -0,0 +1,120 @@
1
+ // ============================================================
2
+ // 按磁盘取的几样:安装集的形态与守护进程的入口、安装集以外守护进程加载了代码的目录、清单里各个根的真实路径、
3
+ // 绑定所在仓库的 git 目录
4
+ // ============================================================
5
+ // biome-ignore lint/style/noRestrictedImports: 安装集、入口、链接装进来的包与清单的根取真实路径、从绑定目录往上读 .git,这些路径不在存储根里
6
+ import { lstat, readdir, readFile, realpath, stat } from 'node:fs/promises';
7
+ import { dirname, join, resolve } from 'node:path';
8
+ import { matchesRule } from '@aalis/api-reach';
9
+ /** 文件或目录不存在 */
10
+ export function isMissing(err) {
11
+ return err?.code === 'ENOENT';
12
+ }
13
+ /** 目录里的条目;目录不存在、不是目录(断掉的链接、同名的文件)时为空 */
14
+ const entriesOf = (dir) => readdir(dir).catch(err => {
15
+ if (isMissing(err) || err.code === 'ENOTDIR')
16
+ return [];
17
+ throw err;
18
+ });
19
+ /** 安装集的形态:下有 packages/ 目录的是源码形态,其余是 npm 形态(create-aalis 生成的项目) */
20
+ export async function formOf(app) {
21
+ const packages = await stat(join(app, 'packages')).catch(err => {
22
+ if (isMissing(err))
23
+ return undefined;
24
+ throw err;
25
+ });
26
+ return packages?.isDirectory() ? 'source' : 'npm';
27
+ }
28
+ /** 守护进程的入口文件:启动脚本(process.argv[1])的真实路径;没有或取不到时为 undefined */
29
+ export async function entryOf() {
30
+ const script = process.argv[1];
31
+ return script ? realpath(script).catch(() => undefined) : undefined;
32
+ }
33
+ /**
34
+ * 清单里以具体路径为根的规则,各个根的真实路径(交给 api-reach 的 withRealRoots):不存在的不记;取不了的(没有权限、
35
+ * 链接成环)记 warn,这一条只按写法拦
36
+ */
37
+ export async function realRootsOf(lists, logger) {
38
+ const roots = new Set([...lists.control, ...lists.landing, ...lists.denyRead].flatMap(rule => ('path' in rule ? [rule.path] : [])));
39
+ const real = new Map();
40
+ for (const root of roots) {
41
+ const resolved = await realpath(root).catch(err => {
42
+ if (!isMissing(err) && err.code !== 'ENOTDIR')
43
+ logger.warn(`取不到 ${root} 的真实路径,受保护清单里它只按写法拦:`, err);
44
+ return undefined;
45
+ });
46
+ if (resolved)
47
+ real.set(root, resolved);
48
+ }
49
+ return real;
50
+ }
51
+ /**
52
+ * 安装集以外、守护进程加载了代码的目录,归宿主控制面(安装集里的已由清单按安装集的目录覆盖):
53
+ * - 安装集 node_modules 顶层(含 `@scope/` 下)解析到安装集以外的包,整个目录;
54
+ * - 源码形态下 packages/ 里链接到安装集以外的包,与安装集里的包一样只算构建产物与依赖。
55
+ * 断掉的链接不是加载了的代码,跳过
56
+ */
57
+ export async function codeDirsOf(app) {
58
+ const outsideApp = async (entry) => {
59
+ const real = await realpath(entry).catch(() => undefined);
60
+ return real && !matchesRule({ path: app }, real, process.platform) ? real : undefined;
61
+ };
62
+ const top = join(app, 'node_modules');
63
+ const modules = [];
64
+ for (const name of await entriesOf(top)) {
65
+ if (name.startsWith('.'))
66
+ continue;
67
+ if (name.startsWith('@'))
68
+ modules.push(...(await entriesOf(join(top, name))).map(sub => join(top, name, sub)));
69
+ else
70
+ modules.push(join(top, name));
71
+ }
72
+ const outside = new Set();
73
+ for (const entry of modules) {
74
+ const real = await outsideApp(entry);
75
+ if (real)
76
+ outside.add(real);
77
+ }
78
+ for (const name of await entriesOf(join(app, 'packages'))) {
79
+ const real = await outsideApp(join(app, 'packages', name));
80
+ if (real)
81
+ for (const sub of ['dist', 'node_modules'])
82
+ outside.add(join(real, sub));
83
+ }
84
+ return [...outside];
85
+ }
86
+ /**
87
+ * 目录所在仓库的 git 目录(common dir,真实路径):从目录往上找 `.git`。文件形式的 `.git`(worktree、子模块)按里面的
88
+ * gitdir 与 commondir 找到共用的那个。找到的不像 git 目录(没有 HEAD 与 objects)的不算,免得一个 `.git` 把任意目录
89
+ * 指成可写。不在仓库里时为 undefined
90
+ */
91
+ export async function gitDirOf(dir) {
92
+ for (let at = dir;; at = dirname(at)) {
93
+ const dotGit = join(at, '.git');
94
+ // 读不到(不存在或没有权限)按没有处理:少一个可写目录,不多一个。链接到目录的 .git 按它指向的目录算,不再往上找
95
+ const entry = await lstat(dotGit).catch(() => undefined);
96
+ if (entry?.isDirectory() || entry?.isSymbolicLink())
97
+ return asGitDir(dotGit);
98
+ if (entry?.isFile()) {
99
+ const content = await readFile(dotGit, 'utf8').catch(() => undefined);
100
+ const gitdir = content && /^gitdir:\s*(.+?)\s*$/m.exec(content)?.[1];
101
+ if (!gitdir)
102
+ return undefined;
103
+ const own = resolve(at, gitdir);
104
+ return asGitDir(await readFile(join(own, 'commondir'), 'utf8').then(text => resolve(own, text.trim()), () => own));
105
+ }
106
+ if (dirname(at) === at)
107
+ return undefined;
108
+ }
109
+ }
110
+ async function asGitDir(dir) {
111
+ const real = await realpath(dir).catch(() => undefined);
112
+ if (!real)
113
+ return undefined;
114
+ const [head, objects] = await Promise.all([
115
+ stat(join(real, 'HEAD')).catch(() => undefined),
116
+ stat(join(real, 'objects')).catch(() => undefined),
117
+ ]);
118
+ return head?.isFile() && objects?.isDirectory() ? real : undefined;
119
+ }
120
+ //# sourceMappingURL=host-dirs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host-dirs.js","sourceRoot":"","sources":["../src/host-dirs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import { type HostPaths } from '@aalis/api-host-paths';
2
+ declare const _default: import("@aalis/core").PluginDefinition<{
3
+ provide: import("@aalis/core").ServiceDescriptor<(identity: symbol) => import("@aalis/core").Provide, import("@aalis/core").Provide>;
4
+ events: import("@aalis/core").ServiceDescriptor<(identity: symbol) => import("@aalis/core").Events, import("@aalis/core").Events>;
5
+ lifecycle: import("@aalis/core").ServiceDescriptor<(identity: symbol) => import("@aalis/core").LifecycleCap, import("@aalis/core").LifecycleCap>;
6
+ logger: import("@aalis/core").ServiceDescriptor<(identity: symbol) => import("@aalis/core").Logger, import("@aalis/core").Logger>;
7
+ /** 家目录布局:三张清单、白纸与本会话临时区都按它 */
8
+ paths: import("@aalis/core").ServiceDescriptor<HostPaths, HostPaths>;
9
+ /** 会话记录、绑定,档位与越界策略的生效值 */
10
+ sessionManager: import("@aalis/core").ServiceDescriptor<import("@aalis/api-session-manager").SessionManagerService, import("@aalis/api-session-manager").BoundSessionManager>;
11
+ /** 污点与来源账本落在插件数据里 */
12
+ storage: import("@aalis/core").ServiceDescriptor<import("@aalis/api-storage").StorageService, import("@aalis/api-storage").BoundStorage>;
13
+ /** 发起类别与 owner 判定;缺席时谁都不是 owner,一律没有本地效果 */
14
+ authority: import("@aalis/core").OptionalUse<import("@aalis/api-authority").AuthorityService, import("@aalis/api-authority").AuthorityService>;
15
+ /** 取 owner 的 login shell 环境;缺席时子进程用守护进程的环境 */
16
+ process: import("@aalis/core").OptionalUse<import("@aalis/api-process").ProcessService, import("@aalis/api-process").ProcessService>;
17
+ }>;
18
+ export default _default;
19
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,SAAS,EAAa,MAAM,uBAAuB,CAAC;;;;;;IA2ChE,8BAA8B;;IAE9B,0BAA0B;;IAE1B,qBAAqB;;IAErB,4CAA4C;;IAE5C,8CAA8C;;;AAKhD,wBAOG"}
package/dist/index.js ADDED
@@ -0,0 +1,184 @@
1
+ // biome-ignore lint/style/noRestrictedImports: 安装集与用户家目录取真实路径;本会话临时区按 0700 建、随会话删
2
+ import { mkdir, realpath, rm } from 'node:fs/promises';
3
+ // biome-ignore lint/style/noRestrictedImports: 拒读清单与落点按操作系统用户的家目录生成
4
+ import { homedir } from 'node:os';
5
+ import { join } from 'node:path';
6
+ import { authority } from '@aalis/api-authority';
7
+ import { hostPaths } from '@aalis/api-host-paths';
8
+ import { processService } from '@aalis/api-process';
9
+ import { protectedLists, reach, resolveReach, withRealRoots, } from '@aalis/api-reach';
10
+ import { placePaperId, roomClass, rootSessionOf, sessionManager } from '@aalis/api-session-manager';
11
+ import { storage } from '@aalis/api-storage';
12
+ import { definePlugin, events, lifecycle, logger, optional, provide } from '@aalis/core';
13
+ import { issueCredential } from './credential.js';
14
+ import { codeDirsOf, entryOf, formOf, gitDirOf, realRootsOf } from './host-dirs.js';
15
+ import { loginEnvs } from './process-env.js';
16
+ import { openProvenance } from './provenance.js';
17
+ import { SWEEP_EVERY_MS, sessionTmpOf, sweepSessionTmp } from './session-tmp.js';
18
+ // ════════════════════════════════════════════════════════════
19
+ // plugin-reach —— 触及服务(契约见 @aalis/api-reach)
20
+ //
21
+ // 按一次工具调用签发凭据:发起类别取权限服务的 originOf(只有 owner 本人与 owner 链的延续算 owner,子任务随发起它的那一轮
22
+ // 父会话),房间类别、档位与越界策略(根会话的生效设置)、场所与绑定取会话管理里的记录,仓库的 git 目录按磁盘找,三张清单
23
+ // 在激活时按家目录布局与真实路径算好;交给 api-reach 的 resolveReach 定上限。绑定与 git 目录在签发时取好,其余每次判定时取
24
+ // 当时的,降档与受污染对已签发的凭据立即生效。另管本会话临时区、子进程环境、污点与白纸的来源账本。
25
+ // ════════════════════════════════════════════════════════════
26
+ /** 哪一层都没设时的档位与越界策略 */
27
+ const DEFAULT_TIER = 'workspace';
28
+ const DEFAULT_BOUNDARY = 'ask';
29
+ const uses = {
30
+ provide,
31
+ events,
32
+ lifecycle,
33
+ logger,
34
+ /** 家目录布局:三张清单、白纸与本会话临时区都按它 */
35
+ paths: hostPaths,
36
+ /** 会话记录、绑定,档位与越界策略的生效值 */
37
+ sessionManager,
38
+ /** 污点与来源账本落在插件数据里 */
39
+ storage,
40
+ /** 发起类别与 owner 判定;缺席时谁都不是 owner,一律没有本地效果 */
41
+ authority: optional(authority),
42
+ /** 取 owner 的 login shell 环境;缺席时子进程用守护进程的环境 */
43
+ process: optional(processService),
44
+ };
45
+ export default definePlugin({
46
+ name: '@aalis/plugin-reach',
47
+ displayName: '触及',
48
+ subsystem: 'authority',
49
+ provides: [reach],
50
+ uses,
51
+ apply: run,
52
+ });
53
+ async function run(caps) {
54
+ const { events, lifecycle, logger } = caps;
55
+ const sm = caps.sessionManager.use;
56
+ const lookup = (id) => sm.getSession(id);
57
+ const isOwner = (platform, userId) => caps.authority.present ? caps.authority.use.isOwner(platform, userId) : false;
58
+ // 清单与路径比较一律用真实路径:安装集可能经符号链接给出,用户家目录同理;清单里链接出去的根按真实路径补一份
59
+ const given = caps.paths.use;
60
+ const app = await realpath(given.app);
61
+ const userHome = await realpath(homedir());
62
+ // 业务句柄是转发句柄,展开得不到成员:在它之上只换掉 app,其余沿原型链读
63
+ const paths = Object.assign(Object.create(given), { app });
64
+ const declared = protectedLists({
65
+ paths,
66
+ userHome,
67
+ platform: process.platform,
68
+ form: await formOf(app),
69
+ codeDirs: await codeDirsOf(app),
70
+ entry: await entryOf(),
71
+ });
72
+ const realRoots = await realRootsOf(declared, logger.use);
73
+ const lists = withRealRoots(declared, root => realRoots.get(root));
74
+ const provenance = await openProvenance(caps.storage.use.own, logger.use);
75
+ const loginEnv = loginEnvs({ process: caps.process, userHome, logger: logger.use });
76
+ /** 会话所在场所的白纸目录:白纸 id 由场所键算出,目录名把 `:` 换成 `-`(与白纸插件同一写法) */
77
+ const paperOf = (sessionId) => join(paths.stage.paper, placePaperId(sm.placeOf(sessionId).key).replace(':', '-'));
78
+ /** 每个会话最近一次签发凭据的那一轮的主体:子任务的任务消息发出时,据它定那条消息之后的子任务回合随谁 */
79
+ const lastPrincipal = new Map();
80
+ /** 子会话:发来最近一条任务消息的那一轮父会话的主体 */
81
+ const spawnedBy = new Map();
82
+ /** 删会话时在后台删着的临时区 */
83
+ const deleting = new Map();
84
+ /**
85
+ * 一个会话的触及,返回每次调用都重算的函数:绑定与仓库的 git 目录(按磁盘找,异步)在这里取好;档位与越界策略(子会话不读
86
+ * 自己的,按根会话的生效设置)、房间类别、污点与子任务的父会话在每次调用时取当时的
87
+ */
88
+ async function reachOf(sessionId, platform, principal) {
89
+ const work = rootSessionOf(sm.getSession(sessionId), lookup)?.work;
90
+ const gitDir = work && (await gitDirOf(work.root));
91
+ return () => {
92
+ const info = sm.getSession(sessionId);
93
+ const config = sm.resolveConfig(rootSessionOf(info, lookup)?.id ?? sessionId, platform);
94
+ const paper = paperOf(sessionId);
95
+ return resolveReach({
96
+ principal: typeof principal === 'function' ? { subtaskOf: principal() } : principal,
97
+ roomClass: roomClass(info, lookup, isOwner),
98
+ tier: config.accessTier ?? DEFAULT_TIER,
99
+ onBoundary: config.accessOnBoundary ?? DEFAULT_BOUNDARY,
100
+ tainted: provenance.taintOf(sessionId),
101
+ // 主目录:项目工作区是绑定目录,其余是场所的白纸
102
+ place: { home: work?.root ?? paper, paper },
103
+ binding: work,
104
+ gitDirs: gitDir ? [gitDir] : [],
105
+ sessionTmp: sessionTmpOf(paths.tmp, sessionId),
106
+ othersContent: [],
107
+ localPorts: [],
108
+ lists,
109
+ paths,
110
+ });
111
+ };
112
+ }
113
+ async function principalOf(call) {
114
+ const origin = caps.authority.present ? caps.authority.use.originOf(call) : undefined;
115
+ if (origin === 'subtask') {
116
+ const parentId = sm.getSession(call.sessionId)?.parentId;
117
+ return parentId && spawnedBy.get(call.sessionId) === 'owner'
118
+ ? reachOf(parentId, call.platform, 'owner')
119
+ : 'other';
120
+ }
121
+ const principal = origin === 'owner' || origin === 'owner-chain' ? 'owner' : 'other';
122
+ lastPrincipal.set(call.sessionId, principal);
123
+ return principal;
124
+ }
125
+ const service = {
126
+ async forCall(call) {
127
+ const credential = issueCredential(await reachOf(call.sessionId, call.platform, await principalOf(call)), {
128
+ sessionId: call.sessionId,
129
+ papers: paths.stage.paper,
130
+ userHome,
131
+ loginEnv,
132
+ record: provenance.record,
133
+ });
134
+ if (credential.exec !== 'none') {
135
+ // 同一个 id 的会话删了又建:前一份还在删,先等它删完,免得删掉新建的
136
+ await deleting.get(call.sessionId);
137
+ await mkdir(sessionTmpOf(paths.tmp, call.sessionId), { recursive: true, mode: 0o700 });
138
+ }
139
+ return credential;
140
+ },
141
+ markTainted: provenance.markTainted,
142
+ provenanceOf: provenance.provenanceOf,
143
+ };
144
+ // 子任务插件在父会话的一轮里发出任务消息(source 为 subtask):那一轮的主体就是这条消息之后的子任务回合的主体
145
+ events.use.on('inbound:message', (msg) => {
146
+ if (msg.source !== 'subtask' || !msg.sessionId)
147
+ return;
148
+ const parentId = sm.getSession(msg.sessionId)?.parentId;
149
+ spawnedBy.set(msg.sessionId, (parentId && lastPrincipal.get(parentId)) || 'other');
150
+ });
151
+ // 删会话时在后台删它的临时区,不拖住删会话;删不掉记 warn
152
+ events.use.on('session:deleted', sessionId => {
153
+ lastPrincipal.delete(sessionId);
154
+ spawnedBy.delete(sessionId);
155
+ const dir = sessionTmpOf(paths.tmp, sessionId);
156
+ const done = rm(dir, { recursive: true, force: true })
157
+ .catch(err => logger.use.warn(`删不掉会话 ${sessionId} 的临时区 ${dir}:`, err))
158
+ .finally(() => {
159
+ if (deleting.get(sessionId) === done)
160
+ deleting.delete(sessionId);
161
+ });
162
+ deleting.set(sessionId, done);
163
+ });
164
+ // 清扫在后台排队跑,启动时的那一轮不拖住激活
165
+ let sweeping = Promise.resolve();
166
+ const sweep = () => {
167
+ sweeping = sweeping
168
+ .then(() => sweepSessionTmp(paths.tmp, lookup, Date.now(), logger.use))
169
+ .then(removed => {
170
+ if (removed.length > 0)
171
+ logger.use.debug(`清掉 ${removed.length} 个会话的临时区`);
172
+ })
173
+ .catch(err => logger.use.warn('清扫本会话临时区失败:', err));
174
+ };
175
+ sweep();
176
+ const sweepTimer = setInterval(sweep, SWEEP_EVERY_MS);
177
+ sweepTimer.unref();
178
+ lifecycle.use.onDispose(async () => {
179
+ clearInterval(sweepTimer);
180
+ await Promise.all([sweeping, ...deleting.values(), provenance.flushed()]);
181
+ });
182
+ caps.provide.use(reach, service);
183
+ }
184
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import type { ProcessService } from '@aalis/api-process';
2
+ import type { Logger, ServiceSelection } from '@aalis/core';
3
+ type Env = Record<string, string>;
4
+ /** 按 owner 的 login shell 取环境的入口:同一个主目录取到一次就一直用,同时来的调用共用一次取 */
5
+ export declare function loginEnvs(deps: {
6
+ process: ServiceSelection<ProcessService>;
7
+ userHome: string;
8
+ logger: Logger;
9
+ }): (home: string) => Promise<Env>;
10
+ /**
11
+ * 沙箱里的命令拿到的环境:去掉凭据,注入 npm 的用户配置(去掉凭据行的副本,写在本会话临时区)、本机 Node 的头文件、
12
+ * 浏览器的缓存目录,关掉 pnpm 的构建产物缓存(沙箱里构建出的产物不能被沙箱外的安装直接复用),公开仓库拉取走 HTTPS
13
+ */
14
+ export declare function sandboxEnv(login: Env, sessionTmp: string, userHome: string): Promise<Env>;
15
+ export {};
16
+ //# sourceMappingURL=process-env.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"process-env.d.ts","sourceRoot":"","sources":["../src/process-env.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAG5D,KAAK,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAkClC,8DAA8D;AAC9D,wBAAgB,SAAS,CAAC,IAAI,EAAE;IAAE,OAAO,EAAE,gBAAgB,CAAC,cAAc,CAAC,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,IAuCrG,MAAM,MAAM,KAAG,OAAO,CAAC,GAAG,CAAC,CAcpC;AAED;;;GAGG;AACH,wBAAsB,UAAU,CAAC,KAAK,EAAE,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CA2C/F"}
@@ -0,0 +1,152 @@
1
+ // ============================================================
2
+ // 子进程环境:owner 的 login shell 环境,沙箱内去掉凭据并注入沙箱要的几项
3
+ //
4
+ // 环境在场所的主目录下用 owner 的 login shell 取一次(项目的 .nvmrc、venv 这类按目录选的工具链与 owner 自己的终端一致),
5
+ // 缓存在内存,不落盘;取不到时用守护进程的环境,1 分钟后再取(一次超时不能让这个主目录一直用守护进程的环境)。
6
+ // 宿主执行用完整的环境;沙箱里的命令拿不到凭据:名字像凭据的变量、带密码的网址、AALIS_*、ssh-agent 的 socket 与 git 的
7
+ // 命令行配置一律去掉。
8
+ // ============================================================
9
+ // biome-ignore lint/style/noRestrictedImports: 读用户家目录的 .npmrc、在本会话临时区写去掉凭据的副本(不跟随链接)、按 PATH 找本机 Node 的头文件,这些路径不在存储根里
10
+ import { access, lstat, readFile, realpath, rename, stat, writeFile } from 'node:fs/promises';
11
+ // biome-ignore lint/style/noRestrictedImports: 没有 SHELL 时取操作系统账户登记的 login shell
12
+ import { userInfo } from 'node:os';
13
+ import { delimiter, dirname, join } from 'node:path';
14
+ import { isMissing } from './host-dirs.js';
15
+ /** 取环境的时限:rc 文件卡住(等输入、连网)时按取不到处理 */
16
+ const CAPTURE_TIMEOUT_MS = 10_000;
17
+ /** 取不到时这么久之后再取 */
18
+ const RETRY_AFTER_MS = 60_000;
19
+ /** 这些名字的变量是凭据:AALIS_ 开头的本实例变量,密码管理器的会话令牌(OP_SESSION_ 开头的与 BW_SESSION) */
20
+ const SECRET_NAMES = /^(AALIS_|OP_SESSION_|BW_SESSION$)/;
21
+ /** 名字里含这些词的变量是凭据;webhook 的地址里就带着令牌 */
22
+ const SECRET_WORDS = /TOKEN|SECRET|PASSWORD|PASSWD|PASSPHRASE|CREDENTIAL|APIKEY|SSHPASS|WEBHOOK/i;
23
+ /** 名字按 `_` 分段后有这些段的变量是凭据(KEY 不按包含判:KEYTIMEOUT 这类不是);ssh-agent 的 SSH_AUTH_SOCK 在 AUTH 这一段里 */
24
+ const SECRET_SEGMENTS = new Set(['KEY', 'KEYS', 'PAT', 'PASS', 'AUTH', 'COOKIE']);
25
+ /** 值里带密码的网址(用户名可以为空);只有用户名的照留 */
26
+ const URL_WITH_PASSWORD = /:\/\/[^/\s@:]*:[^/\s@]+@/;
27
+ /** git 的命令行配置:值里可能是凭据(如 extraheader 的认证头),整组不进沙箱,沙箱要的另从 0 编号注入 */
28
+ const GIT_CONFIG_ENV = /^GIT_CONFIG_(COUNT$|PARAMETERS$|KEY_|VALUE_)/;
29
+ /** npm 配置里的凭据行:令牌、用户名与密码、客户端证书与私钥(文件或内联) */
30
+ const NPMRC_SECRET = /(^|:)(_authToken|_auth|_password|username|password|(cert|key)(file)?)\s*=/i;
31
+ /** 公开仓库拉取改走匿名 HTTPS(沙箱里没有 SSH 凭据),推送仍是 SSH(沙箱里推不了,要宿主执行) */
32
+ const HTTPS_HOSTS = ['github.com', 'gitlab.com'];
33
+ function isSecret(name, value) {
34
+ return (SECRET_NAMES.test(name) ||
35
+ SECRET_WORDS.test(name) ||
36
+ name
37
+ .toUpperCase()
38
+ .split('_')
39
+ .some(segment => SECRET_SEGMENTS.has(segment)) ||
40
+ URL_WITH_PASSWORD.test(value));
41
+ }
42
+ /** 按 owner 的 login shell 取环境的入口:同一个主目录取到一次就一直用,同时来的调用共用一次取 */
43
+ export function loginEnvs(deps) {
44
+ const cache = new Map();
45
+ /** 取不到时为 undefined */
46
+ async function capture(home) {
47
+ try {
48
+ if (!deps.process.present)
49
+ throw new Error('没有进程服务');
50
+ const proc = deps.process.use;
51
+ const shell = process.env.SHELL || userInfo().shell;
52
+ if (!shell)
53
+ throw new Error('不知道 owner 的 login shell(没有 SHELL,账户也没登记)');
54
+ // 白纸首次写入时才建:主目录还不在时在用户家目录下取,与新开一个终端相同
55
+ const cwd = await stat(home).then(s => (s.isDirectory() ? home : deps.userHome), () => deps.userHome);
56
+ const mark = `__AALIS_ENV_${crypto.randomUUID()}__`;
57
+ const { stdout } = await proc.execFile(shell, ['-i', '-l', '-c', `printf '%s' '${mark}'; /usr/bin/env -0`], {
58
+ cwd,
59
+ timeout: CAPTURE_TIMEOUT_MS,
60
+ input: '',
61
+ });
62
+ const at = stdout.indexOf(mark);
63
+ if (at < 0)
64
+ throw new Error(`${shell} 的输出里没有环境`);
65
+ return Object.fromEntries(stdout
66
+ .slice(at + mark.length)
67
+ .split('\0')
68
+ .filter(line => line.includes('='))
69
+ .map(line => [line.slice(0, line.indexOf('=')), line.slice(line.indexOf('=') + 1)]));
70
+ }
71
+ catch (err) {
72
+ deps.logger.warn(`没取到 owner 的 login shell 环境(主目录 ${home}),子进程用守护进程的环境,1 分钟后再取:`, err);
73
+ return undefined;
74
+ }
75
+ }
76
+ return (home) => {
77
+ const cached = cache.get(home);
78
+ if (cached && Date.now() < cached.retryAt)
79
+ return cached.env;
80
+ const entry = {
81
+ retryAt: Number.POSITIVE_INFINITY,
82
+ env: capture(home).then(env => {
83
+ if (env)
84
+ return env;
85
+ entry.retryAt = Date.now() + RETRY_AFTER_MS;
86
+ return { ...process.env };
87
+ }),
88
+ };
89
+ cache.set(home, entry);
90
+ return entry.env;
91
+ };
92
+ }
93
+ /**
94
+ * 沙箱里的命令拿到的环境:去掉凭据,注入 npm 的用户配置(去掉凭据行的副本,写在本会话临时区)、本机 Node 的头文件、
95
+ * 浏览器的缓存目录,关掉 pnpm 的构建产物缓存(沙箱里构建出的产物不能被沙箱外的安装直接复用),公开仓库拉取走 HTTPS
96
+ */
97
+ export async function sandboxEnv(login, sessionTmp, userHome) {
98
+ const env = Object.fromEntries(Object.entries(login).filter(([name, value]) => !GIT_CONFIG_ENV.test(name) && !isSecret(name, value)));
99
+ const npmrc = join(sessionTmp, 'npmrc');
100
+ const owned = await readFile(join(userHome, '.npmrc'), 'utf8').catch(err => {
101
+ if (isMissing(err))
102
+ return '';
103
+ throw err;
104
+ });
105
+ // 临时区在沙箱里可写,沙箱里的命令能把 npmrc、甚至临时区本身换成符号链接,骗守护进程去改写别处:临时区本身要是目录,
106
+ // 副本先以随机名独占创建(不跟随链接),再改名盖过去(换掉的是链接本身)
107
+ if (!(await lstat(sessionTmp)).isDirectory()) {
108
+ throw new Error(`本会话临时区 ${sessionTmp} 不是目录(可能被换成了符号链接),不往里写 npm 的用户配置`);
109
+ }
110
+ const staging = join(sessionTmp, `.npmrc-${crypto.randomUUID()}`);
111
+ const kept = owned.split('\n').filter(line => !NPMRC_SECRET.test(line.trim()));
112
+ await writeFile(staging, kept.join('\n'), { mode: 0o600, flag: 'wx' });
113
+ await rename(staging, npmrc);
114
+ const nodeDir = await nodeDirOf(env.PATH);
115
+ const injected = {
116
+ npm_config_userconfig: npmrc,
117
+ npm_config_side_effects_cache: 'false',
118
+ PUPPETEER_CACHE_DIR: join(sessionTmp, 'puppeteer'),
119
+ ...(nodeDir ? { npm_config_nodedir: nodeDir } : {}),
120
+ };
121
+ // npm 的环境变量不分大小写:同名的旧值去掉,免得两份打架
122
+ for (const name of Object.keys(env)) {
123
+ if (Object.keys(injected).some(key => key.toLowerCase() === name.toLowerCase()))
124
+ delete env[name];
125
+ }
126
+ const git = HTTPS_HOSTS.flatMap((host) => [
127
+ [`url.https://${host}/.insteadOf`, `git@${host}:`],
128
+ [`url.https://${host}/.insteadOf`, `ssh://git@${host}/`],
129
+ [`url.git@${host}:.pushInsteadOf`, `git@${host}:`],
130
+ [`url.ssh://git@${host}/.pushInsteadOf`, `ssh://git@${host}/`],
131
+ ]);
132
+ git.forEach(([key, value], i) => {
133
+ env[`GIT_CONFIG_KEY_${i}`] = key;
134
+ env[`GIT_CONFIG_VALUE_${i}`] = value;
135
+ });
136
+ env.GIT_CONFIG_COUNT = String(git.length);
137
+ return { ...env, ...injected };
138
+ }
139
+ /** 这份 PATH 上的 node 所在的安装(带头文件的才算):源码编译原生模块时 node-gyp 用它,不必去下载头文件 */
140
+ async function nodeDirOf(path) {
141
+ for (const dir of (path ?? '').split(delimiter)) {
142
+ if (!dir)
143
+ continue;
144
+ const bin = await realpath(join(dir, 'node')).catch(() => undefined);
145
+ if (!bin)
146
+ continue;
147
+ const prefix = dirname(dirname(bin));
148
+ return access(join(prefix, 'include', 'node', 'node.h')).then(() => prefix, () => undefined);
149
+ }
150
+ return undefined;
151
+ }
152
+ //# sourceMappingURL=process-env.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"process-env.js","sourceRoot":"","sources":["../src/process-env.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { ProvenanceRecord } from '@aalis/api-reach';
2
+ import { type OwnStorage } from '@aalis/api-storage';
3
+ import type { Logger } from '@aalis/core';
4
+ export declare function openProvenance(storage: Pick<OwnStorage, 'readFile' | 'writeFile' | 'uri'>, logger: Logger): Promise<{
5
+ taintOf: (sessionId: string) => readonly string[] | undefined;
6
+ markTainted(sessionId: string, sources: readonly string[]): void;
7
+ record(realPath: string, entry: ProvenanceRecord): void;
8
+ provenanceOf: (realPath: string) => ProvenanceRecord | undefined;
9
+ /** 等排队的写盘落定 */
10
+ flushed: () => Promise<void>;
11
+ }>;
12
+ //# sourceMappingURL=provenance.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provenance.d.ts","sourceRoot":"","sources":["../src/provenance.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,EAAqB,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACxE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AA6B1C,wBAAsB,cAAc,CAAC,OAAO,EAAE,IAAI,CAAC,UAAU,EAAE,UAAU,GAAG,WAAW,GAAG,KAAK,CAAC,EAAE,MAAM,EAAE,MAAM;yBA4BvF,MAAM,KAAG,SAAS,MAAM,EAAE,GAAG,SAAS;2BACpC,MAAM,WAAW,SAAS,MAAM,EAAE,GAAG,IAAI;qBAO/C,MAAM,SAAS,gBAAgB,GAAG,IAAI;6BAI9B,MAAM,KAAG,gBAAgB,GAAG,SAAS;IAC9D,eAAe;;GAGlB"}
@@ -0,0 +1,74 @@
1
+ // ============================================================
2
+ // 污点与来源账本:落在本插件的私有目录里(pluginData:/reach/provenance.json)
3
+ //
4
+ // 污点:每个会话读进过谁的内容(来源称呼),粘在会话上,之后签发的凭据都带着。
5
+ // 来源账本:受污染的会话经凭据写进白纸的文件(真实路径)→ 写入会话、来源称呼与时间。
6
+ // 整份原子写;改动之后排队写盘。文件不存在时从空起步;存在但读不出或形状不对时抛错,插件不激活:
7
+ // 从空起步等于当作谁都没读进过别人的内容,凭据会把受污染的会话当成干净的签发。
8
+ // ============================================================
9
+ import { isStorageNotFound } from '@aalis/api-storage';
10
+ /** 私有目录下的账本文件 */
11
+ const FILE = 'provenance.json';
12
+ const isSources = (value) => Array.isArray(value) && value.length > 0 && value.every(s => typeof s === 'string' && s.trim() !== '');
13
+ const isRecord = (value) => {
14
+ const r = value;
15
+ return typeof r?.sessionId === 'string' && isSources(r.sources) && typeof r.at === 'number';
16
+ };
17
+ function parse(text) {
18
+ const doc = JSON.parse(text);
19
+ const entries = (value) => typeof value === 'object' && value !== null && !Array.isArray(value) ? Object.entries(value) : undefined;
20
+ const taint = entries(doc?.taint);
21
+ const ledger = entries(doc?.ledger);
22
+ if (!taint?.every(([, sources]) => isSources(sources)))
23
+ throw new Error('taint 要是「会话 id → 来源称呼的数组」');
24
+ if (!ledger?.every(([, record]) => isRecord(record))) {
25
+ throw new Error('ledger 要是「真实路径 → { sessionId, sources, at }」');
26
+ }
27
+ return {
28
+ taint: new Map(taint),
29
+ ledger: new Map(ledger),
30
+ };
31
+ }
32
+ export async function openProvenance(storage, logger) {
33
+ const text = await storage.readFile(FILE, 'utf-8').then(data => String(data), err => {
34
+ if (isStorageNotFound(err))
35
+ return undefined;
36
+ throw err;
37
+ });
38
+ let state;
39
+ try {
40
+ state = text === undefined ? { taint: new Map(), ledger: new Map() } : parse(text);
41
+ }
42
+ catch (err) {
43
+ throw new Error(`污点与来源记录 ${storage.uri(FILE)}(家目录的 state/plugins/reach/provenance.json)读不出:${err instanceof Error ? err.message : String(err)}。修好或移走后重启`);
44
+ }
45
+ const { taint, ledger } = state;
46
+ // 写盘排队:每次写当时的整份,失败上报,下一次改动照常再写整份
47
+ let saving = Promise.resolve();
48
+ const save = () => {
49
+ const snapshot = JSON.stringify({ taint: Object.fromEntries(taint), ledger: Object.fromEntries(ledger) });
50
+ saving = saving
51
+ .then(() => storage.writeFile(FILE, snapshot))
52
+ .catch(err => logger.error('污点与来源记录写盘失败(本次运行里照常生效):', err));
53
+ };
54
+ return {
55
+ taintOf: (sessionId) => taint.get(sessionId),
56
+ markTainted(sessionId, sources) {
57
+ if (!isSources(sources))
58
+ throw new Error('污点要带来源称呼:至少一个,且不能是空白');
59
+ const merged = [...new Set([...(taint.get(sessionId) ?? []), ...sources])];
60
+ if (merged.length === taint.get(sessionId)?.length)
61
+ return;
62
+ taint.set(sessionId, merged);
63
+ save();
64
+ },
65
+ record(realPath, entry) {
66
+ ledger.set(realPath, entry);
67
+ save();
68
+ },
69
+ provenanceOf: (realPath) => ledger.get(realPath),
70
+ /** 等排队的写盘落定 */
71
+ flushed: () => saving,
72
+ };
73
+ }
74
+ //# sourceMappingURL=provenance.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provenance.js","sourceRoot":"","sources":["../src/provenance.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,yDAAyD;AACzD,EAAE;AACF,yCAAyC;AACzC,6CAA6C;AAC7C,kDAAkD;AAClD,yCAAyC;AACzC,+DAA+D;AAG/D,OAAO,EAAE,iBAAiB,EAAmB,MAAM,oBAAoB,CAAC;AAGxE,iBAAiB;AACjB,MAAM,IAAI,GAAG,iBAAiB,CAAC;AAE/B,MAAM,SAAS,GAAG,CAAC,KAAc,EAAqB,EAAE,CACtD,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AAEzG,MAAM,QAAQ,GAAG,CAAC,KAAc,EAA6B,EAAE;IAC7D,MAAM,CAAC,GAAG,KAAyC,CAAC;IACpD,OAAO,OAAO,CAAC,EAAE,SAAS,KAAK,QAAQ,IAAI,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,CAAC,EAAE,KAAK,QAAQ,CAAC;AAC9F,CAAC,CAAC;AAEF,SAAS,KAAK,CAAC,IAAY;IACzB,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAiD,CAAC;IAC7E,MAAM,OAAO,GAAG,CAAC,KAAc,EAAE,EAAE,CACjC,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC3G,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAClC,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IACpC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;IACrG,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC;QACrD,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;IAClE,CAAC;IACD,OAAO;QACL,KAAK,EAAE,IAAI,GAAG,CAAC,KAAkC,CAAC;QAClD,MAAM,EAAE,IAAI,GAAG,CAAC,MAA2C,CAAC;KAC7D,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,OAA2D,EAAE,MAAc;IAC9G,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,IAAI,CACrD,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,EACpB,GAAG,CAAC,EAAE;QACJ,IAAI,iBAAiB,CAAC,GAAG,CAAC;YAAE,OAAO,SAAS,CAAC;QAC7C,MAAM,GAAG,CAAC;IACZ,CAAC,CACF,CAAC;IACF,IAAI,KAA+B,CAAC;IACpC,IAAI,CAAC;QACH,KAAK,GAAG,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,GAAG,EAAE,EAAE,MAAM,EAAE,IAAI,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACrF,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CACb,WAAW,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,iDAAiD,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,WAAW,CACzI,CAAC;IACJ,CAAC;IACD,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC;IAEhC,iCAAiC;IACjC,IAAI,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAC/B,MAAM,IAAI,GAAG,GAAG,EAAE;QAChB,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAC1G,MAAM,GAAG,MAAM;aACZ,IAAI,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;aAC7C,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,yBAAyB,EAAE,GAAG,CAAC,CAAC,CAAC;IAChE,CAAC,CAAC;IAEF,OAAO;QACL,OAAO,EAAE,CAAC,SAAiB,EAAiC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC;QACnF,WAAW,CAAC,SAAiB,EAAE,OAA0B;YACvD,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;gBAAE,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;YACjE,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;YAC3E,IAAI,MAAM,CAAC,MAAM,KAAK,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,MAAM;gBAAE,OAAO;YAC3D,KAAK,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;YAC7B,IAAI,EAAE,CAAC;QACT,CAAC;QACD,MAAM,CAAC,QAAgB,EAAE,KAAuB;YAC9C,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;YAC5B,IAAI,EAAE,CAAC;QACT,CAAC;QACD,YAAY,EAAE,CAAC,QAAgB,EAAgC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QACtF,eAAe;QACf,OAAO,EAAE,GAAG,EAAE,CAAC,MAAM;KACtB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { SessionInfo } from '@aalis/api-session-manager';
2
+ import type { Logger } from '@aalis/core';
3
+ export declare const SWEEP_EVERY_MS: number;
4
+ export declare const sessionTmpOf: (tmp: string, sessionId: string) => string;
5
+ /** 清扫一遍,返回删掉的会话 id。逐个临时区处理:一个看不了或删不掉的记 warn(写明目录与原因),不挡别的 */
6
+ export declare function sweepSessionTmp(tmp: string, sessionOf: (sessionId: string) => SessionInfo | undefined, now: number, logger: Pick<Logger, 'warn'>): Promise<string[]>;
7
+ //# sourceMappingURL=session-tmp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-tmp.d.ts","sourceRoot":"","sources":["../src/session-tmp.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAM1C,eAAO,MAAM,cAAc,QAAS,CAAC;AAErC,eAAO,MAAM,YAAY,GAAI,KAAK,MAAM,EAAE,WAAW,MAAM,WACI,CAAC;AAEhE,6DAA6D;AAC7D,wBAAsB,eAAe,CACnC,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,WAAW,GAAG,SAAS,EACzD,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,GAC3B,OAAO,CAAC,MAAM,EAAE,CAAC,CAuBnB"}
@@ -0,0 +1,68 @@
1
+ // ============================================================
2
+ // 本会话临时区:tmp/sessions/<会话 id 的 UTF-8 十六进制>/,0700。十六进制只有小写,大小写不敏感的文件系统上两个会话也不会撞名
3
+ //
4
+ // 有本地效果的调用签发凭据时建好;删会话时删;启动时与每天清扫一次:7 天没有改动、会话也不在运行的删掉。会话表里查不到
5
+ // 的同样按 7 天算,不立即删:会话表读不出(记忆后端暂时连不上)时表是空的,不能当作会话都删了。删除与清扫都在后台跑,
6
+ // 不拖住激活与删会话。
7
+ // 插件自己的临时目录(浏览器截图、代码执行的脚本目录)不在这里,清扫不碰。
8
+ // ============================================================
9
+ // biome-ignore lint/style/noRestrictedImports: 清扫本会话临时区要按 lstat 不跟随链接地看修改时间,存储服务没有这个能力
10
+ import { lstat, readdir, rm } from 'node:fs/promises';
11
+ import { join } from 'node:path';
12
+ import { isMissing } from './host-dirs.js';
13
+ const DAY_MS = 24 * 60 * 60 * 1000;
14
+ /** 这么久没有改动的临时区,会话不在运行时清掉 */
15
+ const STALE_MS = 7 * DAY_MS;
16
+ export const SWEEP_EVERY_MS = DAY_MS;
17
+ export const sessionTmpOf = (tmp, sessionId) => join(tmp, 'sessions', Buffer.from(sessionId).toString('hex'));
18
+ /** 清扫一遍,返回删掉的会话 id。逐个临时区处理:一个看不了或删不掉的记 warn(写明目录与原因),不挡别的 */
19
+ export async function sweepSessionTmp(tmp, sessionOf, now, logger) {
20
+ const root = join(tmp, 'sessions');
21
+ const names = await readdir(root).catch(err => {
22
+ if (isMissing(err))
23
+ return [];
24
+ throw err;
25
+ });
26
+ const removed = [];
27
+ for (const name of names) {
28
+ const sessionId = Buffer.from(name, 'hex').toString();
29
+ // 名字不是某个会话 id 的编码:不是本会话临时区,不动
30
+ if (Buffer.from(sessionId).toString('hex') !== name)
31
+ continue;
32
+ const dir = join(root, name);
33
+ try {
34
+ if (sessionOf(sessionId)?.status === 'active' || (await changedSince(dir, now - STALE_MS)))
35
+ continue;
36
+ // 遍历期间会话可能开了新回合
37
+ if (sessionOf(sessionId)?.status === 'active')
38
+ continue;
39
+ await rm(dir, { recursive: true, force: true });
40
+ removed.push(sessionId);
41
+ }
42
+ catch (err) {
43
+ logger.warn(`清不掉会话 ${sessionId} 的临时区 ${dir}:`, err);
44
+ }
45
+ }
46
+ return removed;
47
+ }
48
+ /** 目录或它下面任何一项在 since 之后改过(不跟随符号链接);遍历中途被删掉的按刚改过算,这一轮不动它 */
49
+ async function changedSince(path, since) {
50
+ try {
51
+ const entry = await lstat(path);
52
+ if (entry.mtimeMs > since)
53
+ return true;
54
+ if (!entry.isDirectory())
55
+ return false;
56
+ for (const name of await readdir(path)) {
57
+ if (await changedSince(join(path, name), since))
58
+ return true;
59
+ }
60
+ return false;
61
+ }
62
+ catch (err) {
63
+ if (isMissing(err))
64
+ return true;
65
+ throw err;
66
+ }
67
+ }
68
+ //# sourceMappingURL=session-tmp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-tmp.js","sourceRoot":"","sources":["../src/session-tmp.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,67 @@
1
1
  {
2
2
  "name": "@aalis/plugin-reach",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.1.0",
4
+ "license": "MIT",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/AalisLabs/Aalis.git",
8
+ "directory": "packages/plugin-reach"
9
+ },
10
+ "author": "Ace Nyan <ace@acenyan.com>",
11
+ "bugs": {
12
+ "url": "https://github.com/AalisLabs/Aalis/issues"
13
+ },
14
+ "homepage": "https://github.com/AalisLabs/Aalis#readme",
15
+ "description": "触及:按一次工具调用签发触及凭据(主体、房间类别、档位、污点与场所定下本机能读写执行什么),管本会话临时区、子进程环境、会话的污点与白纸的来源账本",
16
+ "type": "module",
17
+ "keywords": [
18
+ "aalis",
19
+ "aalis-plugin"
20
+ ],
21
+ "main": "dist/index.js",
22
+ "types": "dist/index.d.ts",
23
+ "files": [
24
+ "dist"
25
+ ],
26
+ "dependencies": {
27
+ "@aalis/api-authority": ">=0.11.0 <1.0.0",
28
+ "@aalis/api-host-paths": ">=0.1.0 <1.0.0",
29
+ "@aalis/api-process": ">=0.9.0 <1.0.0",
30
+ "@aalis/api-reach": ">=0.1.0 <1.0.0",
31
+ "@aalis/api-session-manager": ">=0.11.0 <1.0.0",
32
+ "@aalis/api-storage": ">=0.8.0 <1.0.0",
33
+ "@aalis/schema-message": ">=0.10.0 <1.0.0"
34
+ },
35
+ "devDependencies": {
36
+ "@types/node": "^22.0.0",
37
+ "typescript": "^5.7.0",
38
+ "@aalis/core": "0.20.0"
39
+ },
40
+ "peerDependencies": {
41
+ "@aalis/core": ">=0.20.0 <1.0.0"
42
+ },
43
+ "aalis": {
44
+ "service": {
45
+ "optional": [
46
+ "authority",
47
+ "process"
48
+ ],
49
+ "provides": [
50
+ "reach"
51
+ ],
52
+ "required": [
53
+ "events",
54
+ "host-paths",
55
+ "lifecycle",
56
+ "logger",
57
+ "provide",
58
+ "session-manager",
59
+ "storage"
60
+ ]
61
+ }
62
+ },
63
+ "scripts": {
64
+ "build": "tsc",
65
+ "dev": "tsc --watch"
66
+ }
6
67
  }