惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

D
Docker
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
C
Cisco Blogs
Scott Helme
Scott Helme
Know Your Adversary
Know Your Adversary
NISL@THU
NISL@THU
C
Cyber Attacks, Cyber Crime and Cyber Security
D
Darknet – Hacking Tools, Hacker News & Cyber Security
C
CXSECURITY Database RSS Feed - CXSecurity.com
S
Schneier on Security
I
Intezer
Spread Privacy
Spread Privacy
AWS News Blog
AWS News Blog
V
Vulnerabilities – Threatpost
Cloudbric
Cloudbric
V2EX - 技术
V2EX - 技术
Google Online Security Blog
Google Online Security Blog
L
Lohrmann on Cybersecurity
Recent Commits to openclaw:main
Recent Commits to openclaw:main
L
LINUX DO - 热门话题
S
Secure Thoughts
T
The Exploit Database - CXSecurity.com
博客园 - 【当耐特】
Recent Announcements
Recent Announcements
Security Archives - TechRepublic
Security Archives - TechRepublic
Stack Overflow Blog
Stack Overflow Blog
罗磊的独立博客
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
K
Kaspersky official blog
阮一峰的网络日志
阮一峰的网络日志
博客园_首页
Latest news
Latest news
B
Blog
F
Full Disclosure
大猫的无限游戏
大猫的无限游戏
博客园 - 叶小钗
L
LangChain Blog
GbyAI
GbyAI
Last Week in AI
Last Week in AI
S
Security Affairs
Apple Machine Learning Research
Apple Machine Learning Research
N
Netflix TechBlog - Medium
Security Latest
Security Latest
Vercel News
Vercel News
Y
Y Combinator Blog
G
GRAHAM CLULEY
S
Securelist
T
Troy Hunt's Blog
Hacker News - Newest:
Hacker News - Newest: "LLM"
雷峰网
雷峰网

Recent Commits to openclaw:main

test: merge chat side-result checks · openclaw/openclaw@ddd2c2a test: merge cron history checks · openclaw/openclaw@f7eb746 test: merge responsive navigation shell checks · openclaw/openclaw@c2e4b47 docs(changelog): add codex oauth fixes · openclaw/openclaw@628e6cd test: merge navigation routing cases · openclaw/openclaw@5d8cecb Tests: mock channel registry bundled fallback · openclaw/openclaw@2b08233 Secrets: avoid broad web search discovery for single plugin config · openclaw/openclaw@a464f59 test: merge config view browser checks · openclaw/openclaw@20cf511 fix(status): align oauth health with runtime · openclaw/openclaw@eed7116 feat: add macOS screen snapshots for monitor preview (#67954) thanks … · openclaw/openclaw@f377db1 fix: report shared auth scopes in hello-ok (#67810) thanks @BunsDev · openclaw/openclaw@0b6c39b Auto-reply: avoid eager bundled route fallback · openclaw/openclaw@3ea1bf4 Tests: narrow session binding contract setup · openclaw/openclaw@54e4e16 fix(macOS): enable undo/redo in webchat composer text input (#34962) · openclaw/openclaw@00951dc Tests: speed up channel setup promotion · openclaw/openclaw@82b529a Docs: refresh agent instructions · openclaw/openclaw@5775fe2 fix(auth): serialize OAuth refresh across agents to fix #26322 (#67876) · openclaw/openclaw@8e79080 test: allow ollama public surface boundary test · openclaw/openclaw@7d4f1a6 Docs: add test performance guardrails · openclaw/openclaw@89706d3 Tests: restore context-engine usage proof · openclaw/openclaw@e4c4f95 Tests: slim context engine runtime coverage · openclaw/openclaw@74c198f ci: retry failed custom checkouts · openclaw/openclaw@0ee5baf test: trim duplicate provider auth onboarding cases · openclaw/openclaw@1ffc02e matrix: fix sessions_spawn --thread subagent session spawning (#67643) · openclaw/openclaw@1ce2596 test: reduce auth choice fixture churn · openclaw/openclaw@857b9cd test: mock health status config boundaries · openclaw/openclaw@9d5ab4a test: mock onboard config io boundary · openclaw/openclaw@299694d test: mock legacy state plugin boundaries · openclaw/openclaw@2713089 test: mock channel install boundaries · openclaw/openclaw@b945248 test: mock doctor preview channel boundaries · openclaw/openclaw@b1a3ad4 test: trim doctor command hotspots · openclaw/openclaw@c66f16a test: isolate agent auth and spawn hotspots · openclaw/openclaw@9285935 test: stabilize MCP startup disposal race · openclaw/openclaw@dd9d2eb test: merge browser contract server suites · openclaw/openclaw@5817a76 test: narrow ollama provider discovery setup · openclaw/openclaw@a0d9598 build: declare qa-lab aimock runtime dependency · openclaw/openclaw@24431e5 test: speed up safe-bins exec harness · openclaw/openclaw@ee856ab test: preserve tool helpers in embedded runner mocks · openclaw/openclaw@acd86a0 refactor: move memory embeddings into provider plugins · openclaw/openclaw@77e6e4c test: reuse system-run temp fixtures · openclaw/openclaw@7e9ff0f test: trim hotspot wait overhead · openclaw/openclaw@12a59b0 Check: avoid duplicate boundary prep · openclaw/openclaw@baf11b8 test: reduce hotspot fixture overhead · openclaw/openclaw@3a59edd feat(ui): overhaul settings and slash command UX (#67819) thanks @Bun… · openclaw/openclaw@2cfb660 QA Matrix: exit cleanly on failure · openclaw/openclaw@42805d2 QA Matrix: isolate scenario coverage · openclaw/openclaw@7e659e1 Matrix: refresh crypto bootstrap state · openclaw/openclaw@94081d8 QA Lab: add provider registry · openclaw/openclaw@bb7e982 Matrix: add plugin changelog · openclaw/openclaw@4acab55 test: trim more hotspot overhead · openclaw/openclaw@f485311 test: trim remaining hotspot tests · openclaw/openclaw@6ba8626 test: narrow hotspot mocks · openclaw/openclaw@dbc8179 test: isolate gemini embedding request helpers · openclaw/openclaw@cd330f5 test: trim memory and mcp hotspots · openclaw/openclaw@fd48dfa test: slim provider registry mocks · openclaw/openclaw@2e08c77 test: harden Parallels update smoke · openclaw/openclaw@1a98090 feat: default Anthropic to Opus 4.7 · openclaw/openclaw@628b454 fix: harden node-host shell payload mutability checks · openclaw/openclaw@75c551e fix: land node-host approval binding for native binaries (#66731) (th… · openclaw/openclaw@29919bb CI: add daily schedule to CodeQL workflow (#67645) · openclaw/openclaw@69d25f5 fix(gateway): capture config hash after plugin auto-enable to prevent… · openclaw/openclaw@8c11210 fix: repair sanitized replay tool results before send (#67620) (thank… · openclaw/openclaw@c3c7a99 fix: restrict HTML timeout short-circuit to transient statuses · openclaw/openclaw@de129a6 fix: keep TUI watchdog bound to active run (#67401) (thanks @xantorres) · openclaw/openclaw@3525273 Gateway/skills: dedupe skills prefix-match + drop dead fallback on log · openclaw/openclaw@d7f489f Extensions/lmstudio: back off inference preload after consecutive fai… · openclaw/openclaw@b555214 TUI/streaming: add watchdog that resets the activity indicator after … · openclaw/openclaw@f44ab20 Agents/tool-loop: enable unknown-tool stream guard by default · openclaw/openclaw@36ed367 Gateway/skills: invalidate session skills snapshot on config write · openclaw/openclaw@b23d59a fix: classify HTML provider error pages correctly (#67642) (thanks @s… · openclaw/openclaw@e588e90 fix(skills): remove unused model-usage import (#67641) · openclaw/openclaw@55f05df docs(changelog): credit codex fix superseded PRs · openclaw/openclaw@e485f24 fix(openai-codex): normalize stale transport metadata in resolution a… · openclaw/openclaw@90801ba CI: pin Docker-related GitHub Actions (#67632) · openclaw/openclaw@f697b01 Android: modernize WebView and discovery API usage (#67627) · openclaw/openclaw@44a6e50 fix(deps): bump hono to 4.12.14 and @hono/node-server to 1.19.14 (GHS… · openclaw/openclaw@fbccc18 fix(deps): bump dompurify to 3.4.0 (#67614) · openclaw/openclaw@2c2dc00 CI: add explicit permissions to all workflow jobs (fixes code-scannin… · openclaw/openclaw@01b7516 fix: register bundled TTS providers and route overrides correctly (#6… · openclaw/openclaw@6ea3cdd fix: align host tilde paths with OS home (#62804) (thanks @stainlu) · openclaw/openclaw@ecfaf64 fix: flush creds queue before reconnect socket open (#67464) (thanks … · openclaw/openclaw@405c63f fix: strip standalone <function> tool call tags from visible text (#6… · openclaw/openclaw@78df859 fix(agents): preserve cli session metadata before transcript persist … · openclaw/openclaw@898fd04 docs(changelog): move cli transcript entry · openclaw/openclaw@c1817c6 fix(agents): normalize cli transcript api field · openclaw/openclaw@3a3fae0 docs(changelog): note cli transcript persistence · openclaw/openclaw@6c343f1 fix(agents): persist cli transcript turns · openclaw/openclaw@b8ef507 fix(msteams): harden security-sensitive flows (#65841) · openclaw/openclaw@c56b56e [Dashboard] Fix exec approval modal overflow for long command content… · openclaw/openclaw@053c5b0 Docs: remove QA changelog entry · openclaw/openclaw@7fd5771 QA: fix private runtime source loading (#67428) · openclaw/openclaw@d5933af docs(gateway): correct protocol.md schema path, hello-ok example, aut… · openclaw/openclaw@489404d CI: pin Node 22 runners to 22.18.0 · openclaw/openclaw@4ffa621 models.authStatus: normalize provider ids + tighten env-backed escape… · openclaw/openclaw@f2fdb9d Update CHANGELOG.md · openclaw/openclaw@7694a92 test(parallels): clean up npm update guard jobs · openclaw/openclaw@045ea7b Plugins: prefer scanDir override paths · openclaw/openclaw@b2974da fix(dreaming): default storage.mode to "separate" so phase blocks sto… · openclaw/openclaw@8c392f0 fix(memory-core): skip dreaming transcript ingestion via session stor… · openclaw/openclaw@a1b01f0 fix: dedupe replayed exec.finished node events (#67281) · openclaw/openclaw@5dcf526
Add hosted external catalog feed loader (#95868) · openclaw/openclaw@c29e1fe
giodl73-repo · 2026-06-28 · via Recent Commits to openclaw:main
1-

import { describe, expect, it } from "vitest";

1+

import { readFileSync } from "node:fs";

2+

import { describe, expect, it, vi } from "vitest";

23

import officialExternalPluginCatalog from "../../scripts/lib/official-external-plugin-catalog.json" with { type: "json" };

34

import {

45

type OfficialExternalPluginCatalogEntry,

56

getOfficialExternalPluginCatalogEntry,

67

isOfficialExternalPluginCatalogFeed,

78

listOfficialExternalPluginCatalogEntries,

9+

loadHostedOfficialExternalPluginCatalogEntries,

810

parseOfficialExternalPluginCatalogEntries,

911

resolveOfficialExternalProviderContractPluginIds,

1012

resolveOfficialExternalProviderPluginIds,

@@ -23,6 +25,16 @@ function expectCatalogEntry(id: string): OfficialExternalPluginCatalogEntry {

2325

}

24262527

describe("official external plugin catalog", () => {

28+

it("keeps hosted fetch guard loading lazy for bundled catalog import paths", () => {

29+

const source = readFileSync(

30+

new URL("./official-external-plugin-catalog.ts", import.meta.url),

31+

"utf8",

32+

);

33+34+

expect(source).not.toMatch(/from ["']\.\.\/infra\/net\/fetch-guard\.js["']/);

35+

expect(source).toContain('await import("../infra/net/fetch-guard.js")');

36+

});

37+2638

it("ships the official plugin catalog as a feed-shaped bundled fallback", () => {

2739

expect(isOfficialExternalPluginCatalogFeed(officialExternalPluginCatalog)).toBe(true);

2840

expect(officialExternalPluginCatalog).toMatchObject({

@@ -45,7 +57,7 @@ describe("official external plugin catalog", () => {

4557

).toBe(false);

4658

expect(

4759

isOfficialExternalPluginCatalogFeed({

48-

schemaVersion: 2,

60+

schemaVersion: 3,

4961

id: "openclaw-official-external-plugins",

5062

generatedAt: "2026-06-22T00:00:00.000Z",

5163

sequence: 1,

@@ -54,10 +66,135 @@ describe("official external plugin catalog", () => {

5466

).toBe(false);

5567

});

566869+

it("accepts the live ClawHub feed schema version", () => {

70+

expect(

71+

isOfficialExternalPluginCatalogFeed({

72+

schemaVersion: 2,

73+

id: "clawhub-official",

74+

generatedAt: "2026-06-25T01:19:39.629Z",

75+

sequence: 11,

76+

entries: [],

77+

}),

78+

).toBe(true);

79+

});

80+81+

it("keeps live ClawHub marketplace entries as metadata-only feed entries", () => {

82+

const [entry] = parseOfficialExternalPluginCatalogEntries({

83+

schemaVersion: 2,

84+

id: "clawhub-official",

85+

generatedAt: "2026-06-25T01:19:39.629Z",

86+

sequence: 11,

87+

entries: [

88+

{

89+

type: "plugin",

90+

id: "@expediagroup/expedia-openclaw",

91+

title: "Expedia Travel",

92+

version: "1.0.4",

93+

state: "available",

94+

publisher: {

95+

id: "expediagroup",

96+

trust: "official",

97+

},

98+

install: {

99+

candidates: [

100+

{

101+

sourceRef: "public-clawhub",

102+

package: "@expediagroup/expedia-openclaw",

103+

version: "1.0.4",

104+

integrity:

105+

"sha256:b355dda04403becaab8bbab069fd1e7b0578262e7459e598cc5b19615b5bdab9",

106+

},

107+

],

108+

},

109+

},

110+

],

111+

});

112+113+

if (entry === undefined) {

114+

throw new Error("Expected hosted ClawHub feed entry to parse");

115+

}

116+117+

expect(entry).toMatchObject({

118+

id: "@expediagroup/expedia-openclaw",

119+

title: "Expedia Travel",

120+

version: "1.0.4",

121+

});

122+

expect(resolveOfficialExternalPluginId(entry)).toBeUndefined();

123+

expect(resolveOfficialExternalPluginInstall(entry)).toBeNull();

124+

});

125+126+

it("does not synthesize trusted installs for unavailable or untrusted hosted entries", () => {

127+

const entries = parseOfficialExternalPluginCatalogEntries({

128+

schemaVersion: 2,

129+

id: "clawhub-official",

130+

generatedAt: "2026-06-25T01:19:39.629Z",

131+

sequence: 11,

132+

entries: [

133+

{

134+

type: "plugin",

135+

id: "@example/unavailable",

136+

title: "Unavailable",

137+

version: "1.0.0",

138+

state: "disabled",

139+

publisher: { id: "example", trust: "official" },

140+

install: {

141+

candidates: [

142+

{

143+

sourceRef: "public-clawhub",

144+

package: "@example/unavailable",

145+

version: "1.0.0",

146+

},

147+

],

148+

},

149+

},

150+

{

151+

type: "plugin",

152+

id: "@example/community",

153+

title: "Community",

154+

version: "1.0.0",

155+

state: "available",

156+

publisher: { id: "example", trust: "community" },

157+

install: {

158+

candidates: [

159+

{

160+

sourceRef: "public-clawhub",

161+

package: "@example/community",

162+

version: "1.0.0",

163+

},

164+

],

165+

},

166+

},

167+

{

168+

type: "plugin",

169+

id: "@example/private-source",

170+

title: "Private Source",

171+

version: "1.0.0",

172+

state: "available",

173+

publisher: { id: "example", trust: "official" },

174+

install: {

175+

candidates: [

176+

{

177+

sourceRef: "private-feed",

178+

package: "@example/private-source",

179+

version: "1.0.0",

180+

},

181+

],

182+

},

183+

},

184+

],

185+

});

186+187+

expect(entries).toHaveLength(3);

188+

for (const entry of entries) {

189+

expect(resolveOfficialExternalPluginId(entry)).toBeUndefined();

190+

expect(resolveOfficialExternalPluginInstall(entry)).toBeNull();

191+

}

192+

});

193+57194

it("keeps unsupported versioned feed wrappers out of legacy catalog parsing", () => {

58195

expect(

59196

parseOfficialExternalPluginCatalogEntries({

60-

schemaVersion: 2,

197+

schemaVersion: 3,

61198

id: "future-feed",

62199

generatedAt: "2026-06-22T00:00:00.000Z",

63200

sequence: 1,

@@ -71,6 +208,182 @@ describe("official external plugin catalog", () => {

71208

).toEqual([{ name: "legacy-catalog-entry" }]);

72209

});

73210211+

it("loads a hosted feed with conditional headers and checksum metadata", async () => {

212+

const body = JSON.stringify({

213+

schemaVersion: 1,

214+

id: "openclaw-official-external-plugins",

215+

generatedAt: "2026-06-22T00:00:00.000Z",

216+

sequence: 2,

217+

entries: [

218+

{

219+

name: "@openclaw/hosted-proof",

220+

kind: "plugin",

221+

openclaw: {

222+

plugin: { id: "hosted-proof", label: "Hosted Proof" },

223+

install: { npmSpec: "@openclaw/hosted-proof", defaultChoice: "npm" },

224+

},

225+

},

226+

],

227+

});

228+

const fetchImpl = vi.fn(async (_url: RequestInfo | URL, init?: RequestInit) => {

229+

const headers = new Headers(init?.headers);

230+

expect(headers.get("if-none-match")).toBe('"old"');

231+

expect(headers.get("if-modified-since")).toBe("Mon, 22 Jun 2026 00:00:00 GMT");

232+

return new Response(body, {

233+

status: 200,

234+

headers: {

235+

etag: '"next"',

236+

"last-modified": "Mon, 22 Jun 2026 01:00:00 GMT",

237+

"content-length": String(new TextEncoder().encode(body).byteLength),

238+

},

239+

});

240+

});

241+242+

const result = await loadHostedOfficialExternalPluginCatalogEntries({

243+

fetchImpl,

244+

ifNoneMatch: '"old"',

245+

ifModifiedSince: "Mon, 22 Jun 2026 00:00:00 GMT",

246+

});

247+248+

expect(result.source).toBe("hosted");

249+

expect(result.entries.map((entry) => entry.name)).toEqual(["@openclaw/hosted-proof"]);

250+

if (result.source === "hosted") {

251+

expect(result.feed.sequence).toBe(2);

252+

expect(result.metadata).toMatchObject({

253+

status: 200,

254+

etag: '"next"',

255+

lastModified: "Mon, 22 Jun 2026 01:00:00 GMT",

256+

});

257+

expect(result.metadata.checksum).toMatch(/^sha256:[0-9a-f]{64}$/);

258+

}

259+

});

260+261+

it("keeps live ClawHub metadata-only entries after hosted feed loading", async () => {

262+

const body = JSON.stringify({

263+

schemaVersion: 2,

264+

id: "clawhub-official",

265+

generatedAt: "2026-06-25T01:19:39.629Z",

266+

sequence: 11,

267+

entries: [

268+

{

269+

type: "plugin",

270+

id: "@expediagroup/expedia-openclaw",

271+

title: "Expedia Travel",

272+

version: "1.0.4",

273+

state: "available",

274+

publisher: {

275+

id: "expediagroup",

276+

trust: "official",

277+

},

278+

install: {

279+

candidates: [

280+

{

281+

sourceRef: "public-clawhub",

282+

package: "@expediagroup/expedia-openclaw",

283+

version: "1.0.4",

284+

integrity:

285+

"sha256:b355dda04403becaab8bbab069fd1e7b0578262e7459e598cc5b19615b5bdab9",

286+

},

287+

],

288+

},

289+

},

290+

],

291+

});

292+293+

const result = await loadHostedOfficialExternalPluginCatalogEntries({

294+

fetchImpl: vi.fn(

295+

async () =>

296+

new Response(body, {

297+

status: 200,

298+

headers: {

299+

"content-length": String(new TextEncoder().encode(body).byteLength),

300+

},

301+

}),

302+

),

303+

});

304+305+

expect(result.source).toBe("hosted");

306+

expect(result.entries).toHaveLength(1);

307+

expect(result.entries[0]).toMatchObject({

308+

id: "@expediagroup/expedia-openclaw",

309+

title: "Expedia Travel",

310+

version: "1.0.4",

311+

});

312+

});

313+314+

it("falls back to the bundled catalog when hosted feed validation fails", async () => {

315+

const result = await loadHostedOfficialExternalPluginCatalogEntries({

316+

fetchImpl: vi.fn(

317+

async () =>

318+

new Response(JSON.stringify({ schemaVersion: 1, id: " ", entries: [] }), {

319+

status: 200,

320+

}),

321+

),

322+

});

323+324+

expect(result.source).toBe("bundled-fallback");

325+

expect(result.entries.length).toBe(listOfficialExternalPluginCatalogEntries().length);

326+

if (result.source === "bundled-fallback") {

327+

expect(result.error).toContain("supported schema version");

328+

expect(result.metadata?.checksum).toMatch(/^sha256:[0-9a-f]{64}$/);

329+

}

330+

});

331+332+

it("falls back to the bundled catalog on HTTP 304 until a snapshot cache exists", async () => {

333+

const result = await loadHostedOfficialExternalPluginCatalogEntries({

334+

fetchImpl: vi.fn(

335+

async () =>

336+

new Response(null, {

337+

status: 304,

338+

headers: { etag: '"same"', "last-modified": "Mon, 22 Jun 2026 01:00:00 GMT" },

339+

}),

340+

),

341+

});

342+343+

expect(result.source).toBe("bundled-fallback");

344+

if (result.source === "bundled-fallback") {

345+

expect(result.error).toContain("without a cached snapshot");

346+

expect(result.metadata).toMatchObject({

347+

status: 304,

348+

etag: '"same"',

349+

lastModified: "Mon, 22 Jun 2026 01:00:00 GMT",

350+

});

351+

}

352+

});

353+354+

it("falls back to the bundled catalog on checksum mismatch and oversized bodies", async () => {

355+

const mismatch = await loadHostedOfficialExternalPluginCatalogEntries({

356+

expectedSha256: "sha256:not-current",

357+

fetchImpl: vi.fn(

358+

async () =>

359+

new Response(

360+

JSON.stringify({

361+

schemaVersion: 1,

362+

id: "openclaw-official-external-plugins",

363+

generatedAt: "2026-06-22T00:00:00.000Z",

364+

sequence: 1,

365+

entries: [],

366+

}),

367+

{ status: 200 },

368+

),

369+

),

370+

});

371+

expect(mismatch.source).toBe("bundled-fallback");

372+

if (mismatch.source === "bundled-fallback") {

373+

expect(mismatch.error).toContain("checksum mismatch");

374+

expect(mismatch.metadata?.checksum).toMatch(/^sha256:[0-9a-f]{64}$/);

375+

}

376+377+

const oversized = await loadHostedOfficialExternalPluginCatalogEntries({

378+

maxBytes: 4,

379+

fetchImpl: vi.fn(async () => new Response("12345", { status: 200 })),

380+

});

381+

expect(oversized.source).toBe("bundled-fallback");

382+

if (oversized.source === "bundled-fallback") {

383+

expect(oversized.error).toContain("exceeds 4 bytes");

384+

}

385+

});

386+74387

it("lists the externalized provider and capability plugins with install metadata", () => {

75388

const providers = [

76389

["arcee", "@openclaw/arcee-provider"],