fix(gateway): every adapter session key goes through one seam (+ lint)
A secondary-owned Yuanbao bot keyed its per-group dispatch queue and RecallGuard entries with the free `build_session_key(source)` — no profile, so `agent:main:` — while `handle_message` popped under `agent:<owner>:`. Two derivations of one identity: the group queue was shared across bots and the RecallGuard entries leaked. Weixin, Telegram's photo batch, Slack's thread key and Raft's wake key each carried their own copy of the call as well. Every adapter-side key now comes from `BasePlatformAdapter._source_session_key` / `_event_session_key` (owner namespace, runner-seeded isolation flags, and — after the RoutingIdentity PR — the pinned identity). Weixin's `_text_batch_key` override is deleted (the base does the same). Slack's thread key reads the isolation flags from the adapter config the runner seeds, not the store's. Lint: pattern P32 in `scripts/ci/profile_scope_patterns.json` flags `build_session_key(` / `SessionSource(` under `gateway/platforms/**` and `plugins/platforms/**` except `platforms/base.py`; the checker gains an optional `path_regex` per pattern. Advisory, like every other pattern. Phase 2 of #88715.
This commit is contained in:
@@ -49,7 +49,9 @@ def load_patterns(path: Path = PATTERNS) -> list[dict]:
|
||||
data = json.loads(path.read_text(encoding="utf-8"))
|
||||
out = []
|
||||
for p in data["patterns"]:
|
||||
out.append({**p, "_rx": re.compile(p["pattern_regex"], re.M)})
|
||||
# ``path_regex`` (optional) restricts a pattern to files whose repo-relative path matches.
|
||||
path_rx = re.compile(p["path_regex"]) if p.get("path_regex") else None
|
||||
out.append({**p, "_rx": re.compile(p["pattern_regex"], re.M), "_path_rx": path_rx})
|
||||
return out
|
||||
|
||||
|
||||
@@ -63,6 +65,9 @@ def scan_text(rel: str, text: str, patterns: list[dict], lines: set[int] | None
|
||||
findings: list[Finding] = []
|
||||
src_lines = text.split("\n")
|
||||
for p in patterns:
|
||||
path_rx = p.get("_path_rx")
|
||||
if path_rx is not None and not path_rx.search(rel):
|
||||
continue
|
||||
for m in p["_rx"].finditer(text):
|
||||
line_no = text.count("\n", 0, m.start()) + 1
|
||||
if lines is not None and line_no not in lines:
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"P24: 62 hits on main",
|
||||
"P26: 252 hits on main"
|
||||
],
|
||||
"usage": "scripts/check_profile_scope_patterns.py --base origin/main [--head HEAD] | --files <paths>"
|
||||
"usage": "scripts/check_profile_scope_patterns.py --base origin/main [--head HEAD] | --files <paths>; optional path_regex restricts a pattern to matching repo-relative paths"
|
||||
},
|
||||
"patterns": [
|
||||
{
|
||||
@@ -158,8 +158,16 @@
|
||||
"id": "P31",
|
||||
"class": "C6",
|
||||
"pattern_regex": "f\"agent:\\{|[\"']agent:[\"']\\s*\\+|session_key\\s*=\\s*f\"[a-z]+:",
|
||||
"scope_hint": "Every adapter-built session key carries the agent:<profile>: namespace (profile 'main' is 'agent:main~'); yuanbao still builds keys with no profile component per the MindDragon probe.",
|
||||
"scope_hint": "Every adapter-built session key carries the agent:<profile>: namespace (profile 'main' is 'agent:main~'); adapters derive keys through _source_session_key / _event_session_key (P32), never a hand-built prefix.",
|
||||
"why": "Rows for a served profile land in the root store; browser/computer_use caches never saw the namespace because turns pass the bare session id."
|
||||
},
|
||||
{
|
||||
"id": "P32",
|
||||
"class": "C4",
|
||||
"path_regex": "^(gateway|plugins)/platforms/(?!base\\.py$).+\\.py$",
|
||||
"pattern_regex": "\\bbuild_session_key\\(|\\bSessionSource\\(",
|
||||
"scope_hint": "Inside an adapter derive every key through self._source_session_key(source) / self._event_session_key(event) (owner-profile namespace, runner-seeded isolation flags) and build sources with self.build_source(...) so the transport provenance is kept; only platforms/base.py owns the free calls.",
|
||||
"why": "Yuanbao keyed its per-group queue and RecallGuard with the free build_session_key() (no profile) while handle_message keyed under agent:<owner>: - two derivations of one identity, one lane shared across bots (#88715)."
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user