Skip to content

fix(memory): wire scoped api keys into the packaged server entry - #616

Open
akushonkamen wants to merge 1 commit into
MemTensor:mainfrom
akushonkamen:fix/592-scoped-api-key-entry-wiring
Open

akushonkamen wants to merge 1 commit into
MemTensor:mainfrom
akushonkamen:fix/592-scoped-api-key-entry-wiring

Conversation

@akushonkamen

Copy link
Copy Markdown

Fixes #592

问题定位(根因)

打包服务入口 Memory/src/server/index.ts(修复前 117-118 行)把 listenMemoryHttpServer 的 auth 写成二选一:

auth: config.storage.token
    ? { localServiceToken: config.storage.token }
    : { allowAnonymous: true },

而 HTTP 层对 per-agent scoped API key 的强制执行点在 Memory/src/server/http.ts 中本已齐备:MemoryHttpAuthOptions.scopedApiKeys 类型(118 行)、authenticate()(1284 行)、scope 查表 auth?.scopedApiKeys?.[candidate](1312 行)、匿名兜底(1321 行)。因此这是一个纯接线缺口:只配 scoped key、没有 storage token 时,入口直接以匿名模式起服;配了 token 时,scoped key 永远得不到校验(401)。

修改内容

  1. Memory/src/config/index.ts:在 StorageConfig 暴露 storage.scopedApiKeys(新增导出 ScopedApiKeyConfig { namespace, scopes? })。normalizeStorage 经新 helper normalizeScopedApiKeys 归一化:条目必须带非空 namespace.source 与 namespace.profileId;畸形条目直接丢弃,使该 key 以 401 fail-closed;整段 present 但完全畸形仍归一为空记录,防止入口静默回落匿名。
  2. Memory/src/server/index.ts:入口 auth 改为导出的 memoryServiceAuth(config),优先级 localServiceToken > scopedApiKeys > allowAnonymous —— 两种凭证都未配置时才 allowAnonymous。配置了 scoped key 的安装绝不再静默匿名。
  3. 测试:Memory/tests/server-entrypoint.test.ts 新增三例真服务行为测试(memory:read key 读路由 200 / 写路由 memory:add 403 / 无 key 与错误 key 401;token+scoped 共存时 token 200、scoped 200、匿名 401);Memory/tests/config.test.ts 新增 scoped key 归一化用例。
  4. Memory/readme.md:补 per-agent scoped key 的配置示例与语义,含"非 OS 安全边界"声明(回应 issue 中的要求)。

测试证据

  • Memory typecheck:node node_modules/typescript/bin/tsc -p Memory/tsconfig.json --noEmit → exit 0。
  • 红(临时还原入口修复后):cd Memory && ../node_modules/.bin/vitest run --dir tests server-entrypoint -t scoped → 3 failed | 4 skipped,失败点即旧行为(匿名 200、scoped key 401)。
  • 绿(恢复修复后同命令):→ 3 passed | 4 skipped。
  • 相关子集:cd Memory && ../node_modules/.bin/vitest run --dir tests server-entrypoint config.test http-startup server-lock service-restart contract/memory-rest-service → 6 个文件 / 83 个测试全部通过。

说明:Memory 完整 npm run build 未跑(pretest 需要 viewer/integration 资产);issue 中的手工 curl 起服验证由上述三个行为测试等价覆盖(走真实 main() → listenMemoryHttpServer → 127.0.0.1 随机端口 fetch)。


Disclosure: this contribution is prepared with AI assistance (Claude), reviewed and tested by me before submitting.

The packaged service entry built its auth as a strict either-or between
localServiceToken and allowAnonymous, so the per-agent scopedApiKeys
enforcement that already exists in the HTTP layer was unreachable and
installs without a storage token silently served anonymous requests.

Expose validated scopedApiKeys under memmyMemory.storage (entries require
namespace.source and namespace.profileId, malformed entries are dropped so
they fail closed), and assemble entry auth with localServiceToken over
scopedApiKeys over allowAnonymous: anonymous access is only offered when
neither credential type is configured.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Scoped API key authorization exists in HTTP code but is not wired into the packaged server entry point

1 participant