diff --git a/CHANGELOG.md b/CHANGELOG.md index eff1e9a..5ccc108 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [4.7.7] - 2026-08-03 + +### Changed +- Validated and retargeted package and plugin SDK build metadata to OpenClaw `2026.7.1-2`, using that correction release as the install, plugin API, Gateway, and peer dependency floor so both it and stable `2026.7.1` satisfy the declared compatibility contract. +- Confirmed that the OpenClaw correction release's singleton-array npm metadata fix requires no changes to Code Agent tools, callbacks, wake routing, worktree flows, plan approval, or harness model restrictions. +- Pinned patched `fast-uri` and Hono transitive releases, with a machine-checked, exact-version exception that permits only `hono@4.12.34` through the normal 24-hour release-age quarantine and expires after the quarantine clears. + +### Fixed +- Removed the production dependency advisories for `fast-uri` URI authority parsing and Hono CORS-header regular-expression denial of service without weakening the repository-wide release-age policy. + ## [4.7.6] - 2026-07-15 ### Changed diff --git a/README.md b/README.md index 63215c9..131bd8b 100644 --- a/README.md +++ b/README.md @@ -128,7 +128,7 @@ Because worktree isolation defaults to `delegate`, `defaultWorkdir` should norma Chat-launched sessions route updates back to their originating chat thread. For agent-launched tool sessions without an origin route, configure `fallbackChannel` or `agentChannels` in the reference guide. -The current package targets, validates against, and requires OpenClaw `2026.7.1`. Its install, plugin API, Gateway, and peer dependency metadata all use that same minimum so OpenClaw and ClawHub reject older hosts before installation. OpenClaw `2026.7.1` changes Codex app-server, Telegram delivery, cron/session delivery, tool visibility, approval, and plugin update behavior, but `openclaw-code-agent` does not need new SDK imports for those changes: the manifest already declares `contracts.tools`, the plugin still imports only `openclaw/plugin-sdk/plugin-entry`, and its own session store, wake routing, callbacks, worktree flows, and harness model restrictions remain plugin-owned. Current callback behavior around native callback data, routed follow-ups, retryable stale plan approval buttons, and serialized plan decisions remains plugin-owned. +The current package targets and validates against OpenClaw `2026.7.1-2`. Its install, plugin API, Gateway, and peer dependency floor is `2026.7.1-2`, which includes both that numeric correction release and the higher-precedence stable `2026.7.1` release under SemVer ordering. The correction release only fixes singleton-array npm metadata handling for plugin installs and updates, so no host config migration or Code Agent runtime change is required. The manifest still declares `contracts.tools`, the plugin still imports only `openclaw/plugin-sdk/plugin-entry`, and its own session store, wake routing, callbacks, worktree flows, and Codex/Claude model restrictions remain plugin-owned. Current callback behavior around native callback data, routed follow-ups, retryable stale plan approval buttons, and serialized plan decisions remains unchanged. If you use Codex, make sure the local `codex` command or `OPENCLAW_CODEX_APP_SERVER_COMMAND` override is available and authenticated. Codex-specific defaults live under `harnesses.codex`: `reasoningEffort` is sent as `reasoningEffort`, and `fastMode: true` sends `service_tier: "fast"` on Codex App Server thread, resume, and turn payloads. The Codex harness starts the app server with stdio listener args by default, only sends UUID-shaped backend thread IDs to `thread/resume`, and reports startup timeouts with redacted recent stderr. When Codex auth is inconsistent, this is the recommended `~/.codex/config.toml` setting: diff --git a/docs/DEVELOPMENT.md b/docs/DEVELOPMENT.md index 169ee59..b54bbcf 100644 --- a/docs/DEVELOPMENT.md +++ b/docs/DEVELOPMENT.md @@ -81,6 +81,8 @@ Security automation should work like this: - Version maintenance: Dependabot updates the JavaScript dependency set through the npm ecosystem support that covers pnpm projects. - Full snapshot audit: run `pnpm audit` when you need the current advisory set for the full resolved pnpm graph, including dev dependencies. +The 24-hour minimum-release-age policy remains the default for every dependency. If a security-fixed release must be admitted before that quarantine ends, use an exact `package@version` entry in `minimumReleaseAgeExclude` immediately preceded by a `security-exception` comment containing the advisory, publication time, quarantine end, and removal deadline. `pnpm check-static-guardrails` rejects malformed, non-exact, or expired exceptions; remove the entry and comment once the deadline passes. + OpenClaw 2026.7.1 requires Node 22.22.3 or newer when using Node 22; CI and release verification pin that patch floor. Plugin-behavior review should also include: ```bash diff --git a/docs/REFERENCE.md b/docs/REFERENCE.md index 665304d..f40de04 100644 --- a/docs/REFERENCE.md +++ b/docs/REFERENCE.md @@ -28,13 +28,13 @@ Sessions are multi-turn. Active sessions accept follow-up messages via `agent_re Current releases treat persisted session storage as new-schema-only. If startup finds an older or invalid session store, the plugin archives it to a timestamped `.legacy-*.json` backup and starts with a fresh index instead of migrating rows in place. -### OpenClaw 2026.7.1 SDK Readiness +### OpenClaw 2026.7.1-2 SDK Readiness -The current `openclaw-code-agent` package is validated against and requires OpenClaw `2026.7.1`. Package install, plugin API, Gateway, peer dependency, and build metadata now share that minimum so registry and host compatibility checks cannot select the package for an older OpenClaw installation. +The current `openclaw-code-agent` package is validated against OpenClaw `2026.7.1-2`. Exact build metadata and the development dependency record that tested correction release. Package install, plugin API, Gateway, and peer dependency metadata use `2026.7.1-2` as their floor so standard SemVer checks accept the correction release itself as well as the higher-precedence stable `2026.7.1` release, while rejecting older hosts. -Hosts already running OpenClaw `2026.7.1` need no host config change. No new OpenClaw SDK imports were needed for `2026.7.1`: this plugin still depends only on the stable plugin-entry surface. Runtime code still imports only `openclaw/plugin-sdk/plugin-entry` from the OpenClaw SDK, `openclaw.plugin.json` already declares tools through `contracts.tools`, package-level OpenClaw readiness stays in `package.json`, pnpm build policy and overrides live in `pnpm-workspace.yaml`, and code-agent session storage remains plugin-owned. Current callback handling, plan approval, session wake/routing, Codex harness behavior, and worktree follow-through remain plugin-owned compatibility surfaces. +Hosts already running OpenClaw `2026.7.1` need no host config change. OpenClaw `2026.7.1-2` only normalizes singleton-array output from newer `npm view --json` clients and continues to reject ambiguous multi-version arrays. No new SDK imports or Code Agent runtime changes are needed: runtime code still imports only `openclaw/plugin-sdk/plugin-entry`, `openclaw.plugin.json` already declares tools through `contracts.tools`, pnpm build policy and overrides remain in `pnpm-workspace.yaml`, and code-agent session storage remains plugin-owned. Current Start Plan and approval callbacks, Telegram/topic routing, completion and cron/session wakes, Codex and Claude model restrictions, runtime tool visibility, disabled bundled-plugin boundaries, and plan/worktree follow-through remain unchanged. -Configuration guidance for `2026.7.1`: +Configuration guidance for the `2026.7.1-2` compatibility floor and tested correction release: - If `plugins.allow` is present, add `openclaw-code-agent`. OpenClaw treats that allowlist as exclusive, so `tools.allow` cannot make this plugin's tools available when the owning plugin is blocked. - New OpenClaw configs default `plugins.bundledDiscovery` to `allowlist`, so a restrictive `plugins.allow` list can also block omitted bundled provider or runtime plugins. OpenClaw `2026.7.1` continues to discover externally installed channel plugins at Gateway startup, but that host-side discovery does not make those plugins implicitly available to OCA sessions. Disabled or omitted adjacent plugins remain unavailable unless explicitly enabled or auto-enabled by their own OpenClaw contracts. @@ -56,7 +56,7 @@ Configuration guidance for `2026.7.1`: - Installed plugins that register host-trusted pre-tool policies must declare `contracts.trustedToolPolicies`. This plugin does not register trusted pre-tool policies, so no manifest contract is needed beyond the existing `contracts.tools` list. - The removed upstream sender-owner tool gating path does not replace this plugin's auth boundary. Chat commands remain auth-required, and Telegram/Discord callbacks still require authorized senders before `agent_respond`, plan approval, merge, PR, cleanup, or Start Plan actions are applied. OpenClaw's plugin write ownership checks are host-side package safety checks; OCA should not claim ownership of host or adjacent plugin package writes. - Legacy `defaultModel`, `model`, `reasoningEffort`, and global `allowedModels` are compatibility fields only. New configs should not use them. -- Managed external-plugin npm installs now use per-plugin project roots and enforce `openclaw.compat.pluginApi` when selecting compatible package versions. This package aligns that range, its Gateway minimum, and its peer dependency with the release-tested OpenClaw `2026.7.1` host; keep `openclaw.extensions` pointing at the built `dist/index.js` artifact. +- Managed external-plugin npm installs now use per-plugin project roots and enforce `openclaw.compat.pluginApi` when selecting compatible package versions. This package aligns that range, its Gateway minimum, and its peer dependency with the release-tested OpenClaw `2026.7.1-2` correction release; the floor also accepts stable `2026.7.1`. Keep `openclaw.extensions` pointing at the built `dist/index.js` artifact. - OpenClaw `2026.7.1` removes built-in dangerous-code blocking from plugin installs and deprecates `--dangerously-force-unsafe-install`; operators who require a host-specific allow/block decision should configure `security.installPolicy`. OCA's release smoke installs only its freshly packed artifact under an isolated temporary home and does not read or migrate operator state. - `tools.deny` does not disable OpenClaw's `apply_patch` tool by itself in current OpenClaw. To restrict patch edits, configure OpenClaw `tools.exec.applyPatch.enabled`, `tools.exec.applyPatch.workspaceOnly`, or `tools.exec.applyPatch.allowModels`. diff --git a/openclaw.plugin.json b/openclaw.plugin.json index c84b40b..f2daa43 100644 --- a/openclaw.plugin.json +++ b/openclaw.plugin.json @@ -2,7 +2,7 @@ "id": "openclaw-code-agent", "name": "Code Agent", "description": "Multi-session coding-agent orchestration from OpenClaw chat", - "version": "4.7.6", + "version": "4.7.7", "contracts": { "tools": [ "agent_launch", diff --git a/package.json b/package.json index 277605c..1dd8da9 100644 --- a/package.json +++ b/package.json @@ -1,13 +1,13 @@ { "name": "openclaw-code-agent", - "version": "4.7.6", + "version": "4.7.7", "type": "module", "packageManager": "pnpm@11.15.1", "main": "dist/index.js", "scripts": { "audit:prod": "pnpm audit --prod", "build": "esbuild index.ts --bundle --splitting --platform=node --target=node22 --format=esm --outdir=dist --entry-names=index --chunk-names=chunks/[name] --minify --charset=utf8 --pure:console.log --pure:console.warn --pure:console.info --pure:console.debug --external:@anthropic-ai/claude-agent-sdk --external:openclaw/plugin-sdk/plugin-entry", - "check-static-guardrails": "node scripts/check-static-guardrails.mjs", + "check-static-guardrails": "node scripts/check-static-guardrails.mjs && node scripts/check-release-age-exceptions.mjs", "check-plugin-security": "node scripts/check-plugin-security.mjs", "test": "node scripts/run-tests.mjs", "test:integ:crabbox": "node scripts/run-tests.mjs tests/oca-codex-crabbox-integ.test.ts tests/oca-plugin-workflows-integ.test.ts tests/oca-codex-telegram-proof.test.ts tests/oca-codex-proof-app-server.test.ts tests/oca-codex-proof-workflow.test.ts", @@ -33,15 +33,15 @@ "install": { "npmSpec": "openclaw-code-agent", "defaultChoice": "npm", - "minHostVersion": ">=2026.7.1" + "minHostVersion": ">=2026.7.1-2" }, "compat": { - "pluginApi": ">=2026.7.1", - "minGatewayVersion": "2026.7.1" + "pluginApi": ">=2026.7.1-2", + "minGatewayVersion": "2026.7.1-2" }, "build": { - "openclawVersion": "2026.7.1", - "pluginSdkVersion": "2026.7.1" + "openclawVersion": "2026.7.1-2", + "pluginSdkVersion": "2026.7.1-2" } }, "files": [ @@ -58,7 +58,7 @@ "@types/node": "^26.0.1", "esbuild": "^0.28.1", "nanoid": "^6.0.0", - "openclaw": "2026.7.1", + "openclaw": "2026.7.1-2", "tsx": "^4.21.0", "typescript": "^7.0.2" }, @@ -95,7 +95,7 @@ }, "description": "An OpenClaw plugin that orchestrates coding agent sessions as managed background processes. Launch, monitor, and control coding agents (Claude Code, Codex, experimental OpenCode, and more) directly from your AI gateway.", "peerDependencies": { - "openclaw": ">=2026.7.1" + "openclaw": ">=2026.7.1-2" }, "overrides": { "basic-ftp": "5.3.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e614b1a..17e5a1d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -16,9 +16,9 @@ overrides: path-to-regexp@>=8.0.0 <8.4.0: '>=8.4.0' '@anthropic-ai/sdk@<0.93.0': 0.93.0 ip-address@<10.1.1: 10.1.1 - fast-uri@<=3.1.3: 3.1.4 + fast-uri@<3.1.5: 3.1.5 qs@<6.15.2: 6.15.2 - hono@<4.12.27: 4.12.27 + hono@<4.12.34: 4.12.34 '@hono/node-server@<2.0.10': 2.0.10 undici@>=8.0.0 <8.5.0: 8.5.0 @@ -40,11 +40,11 @@ importers: specifier: ^6.0.0 version: 6.0.0 openclaw: - specifier: 2026.7.1 - version: 2026.7.1 + specifier: 2026.7.1-2 + version: 2026.7.1-2 tsx: specifier: ^4.21.0 - version: 4.23.1 + version: 4.23.5 typescript: specifier: ^7.0.2 version: 7.0.2 @@ -324,7 +324,7 @@ packages: resolution: {integrity: sha512-ZcnNVhKTmyDJeg0UlnZjvM73JBsTAuhrH/J4fjwGOw59PwOW51r4J+p6CsKZWXdKSme4MFqU62CZMOsdDrU4CA==} engines: {node: '>=20'} peerDependencies: - hono: 4.12.27 + hono: 4.12.34 '@isaacs/fs-minipass@4.0.1': resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} @@ -385,8 +385,8 @@ packages: resolution: {integrity: sha512-juG5VWh4qAivzTAeMzvY9xs9HY5rAcr2E4I7tiSSCokRFi7XIZCAu92ZkSTsIj1OPceCifL3cpfteP3pDT9/QQ==} engines: {node: '>=14.0.0'} - '@openclaw/ai@2026.7.1': - resolution: {integrity: sha512-FsKy5DXSHf4qyN8Huoz/10HZRgoEwLF4uk8UWaCafaIler+q5Fsl51HcrIqIrEe0S38OT7LOaxnR++MOshAlmw==} + '@openclaw/ai@2026.7.1-2': + resolution: {integrity: sha512-st+NH0cxlQqdbEur//yYqM7WlYBjeEBnop3cztJTSCONKjv6LNoGguI9cH65asZG94FdM/39z857isRGPnZvEw==} engines: {node: '>=22.19.0'} '@openclaw/fs-safe@0.4.1': @@ -430,8 +430,8 @@ packages: '@protobufjs/pool@1.1.0': resolution: {integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==} - '@protobufjs/utf8@1.1.1': - resolution: {integrity: sha512-oOAWABowe8EAbMyWKM0tYDKi8Yaox52D+HWZhAIJqQXbqe0xI/GV7FhLWqlEKreMkfDjshR5FKgi3mnle0h6Eg==} + '@protobufjs/utf8@1.1.2': + resolution: {integrity: sha512-b1UQwcEZ4yCnMCD8DAL1VlbvBJE9/IX4FTIp7BG1xYpf29SLazLSrqUkj4w7Y5y7cCVP6E5tcqqcI0xemPkHug==} '@silvia-odwyer/photon-node@0.3.4': resolution: {integrity: sha512-bnly4BKB3KDTFxrUIcgCLbaeVVS8lrAkri1pEzskpmxu9MdfGQTy8b8EgcD83ywD3RPMsIulY8xJH5Awa+t9fA==} @@ -616,8 +616,8 @@ packages: bignumber.js@9.3.1: resolution: {integrity: sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==} - bn.js@4.12.3: - resolution: {integrity: sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==} + bn.js@4.12.5: + resolution: {integrity: sha512-3aRg6/JxfffFD+OlOjOFR3Vo79l39ooBTFucxx+MT3dhCtzn3EmiUPQo+6/OZuI2jbXi3YKgmiTFBgChQMwIRQ==} body-parser@2.3.0: resolution: {integrity: sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==} @@ -629,9 +629,9 @@ packages: bottleneck@2.19.5: resolution: {integrity: sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==} - brace-expansion@5.0.7: - resolution: {integrity: sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==} - engines: {node: 18 || 20 || >=22} + brace-expansion@5.0.9: + resolution: {integrity: sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==} + engines: {node: 20 || >=22} buffer-equal-constant-time@1.0.1: resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} @@ -845,8 +845,8 @@ packages: resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==} engines: {node: '>=18.0.0'} - express-rate-limit@8.5.2: - resolution: {integrity: sha512-5Kb34ipNX694DH48vN9irak1Qx30nb0PLYHXfJgw4YEjiC3ZEmZJhwOp+VfiCYwFzvFTdB9QkArYS5kXa2cx2A==} + express-rate-limit@8.6.1: + resolution: {integrity: sha512-0D493aP61w0TJ2A0wy27riRsO7FMQ7FK+KUHOKCSfPvYo0R55aiC6emCVgFUeShH0fq0ICPVzNcgoS+BsbXQCA==} engines: {node: '>= 16'} peerDependencies: express: '>= 4.11' @@ -870,8 +870,8 @@ packages: fast-string-width@3.0.2: resolution: {integrity: sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==} - fast-uri@3.1.4: - resolution: {integrity: sha512-8JnbkQ4juDyvYs4mgFGQqg4yCYtFDtUtmp2QIQq11ZZe5CFQ5wcqm1rqDgAh/QdMySuBnPzMUiJUNZG5N/AiQw==} + fast-uri@3.1.5: + resolution: {integrity: sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw==} fast-wrap-ansi@0.2.2: resolution: {integrity: sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==} @@ -912,8 +912,8 @@ packages: function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - gaxios@7.1.5: - resolution: {integrity: sha512-5FZy72Rh8LhtjmvDrKkI+lVhrsQrVKVsItxMoDm5mNQE+xR0WVIIs+jzPSJgBvKVsLi24fZhXJIsNI0bihDzFg==} + gaxios@7.3.0: + resolution: {integrity: sha512-RB5vLV+vvQeoFPCX4QMK6/hjVkbIamPp1QSUD0CiZcnj12qbpiL+pLbYtgD+oZkWl0tl9z+o2Utp+MpM3QRhBA==} engines: {node: '>=18'} gcp-metadata@8.1.2: @@ -940,8 +940,8 @@ packages: resolution: {integrity: sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==} engines: {node: 18 || 20 || >=22} - google-auth-library@10.7.0: - resolution: {integrity: sha512-QpTAbNJ36TliZLx3TTtahR8HG0hN9RllL1e3FymOvQSIKK8JmgV58H924ub2wa2DsS3ANjjP1Aw1N+Ramc8hqQ==} + google-auth-library@10.9.1: + resolution: {integrity: sha512-i1ydyHrqcIxXkWh/uBmVkzCvIuq5yiK2ATndIe5XxKholrG/MTYP9xGYka4sQhrbIAgGjL2B6NOE7rFaiF3fXw==} engines: {node: '>=18'} google-logging-utils@1.1.3: @@ -971,8 +971,8 @@ packages: resolution: {integrity: sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==} engines: {node: '>=12.0.0'} - hono@4.12.27: - resolution: {integrity: sha512-1yrb/+w6HWQJrUCLkJ2IF5jNIPvvFkblV5RNOYl6bV+OA6p9GLcMpHFFGTosSvHvcAUibuUukRqhlYI4z32C7Q==} + hono@4.12.34: + resolution: {integrity: sha512-GqXJqY/xJkJmuloTrnV1ZEXG3fqte+VjkUqoRNZXcrUidiUOP4fMSIHHY4tsqZBK++kVyWmt/AAfSUuy57/eSA==} engines: {node: '>=16.9.0'} hosted-git-info@10.1.1: @@ -997,8 +997,8 @@ packages: resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} engines: {node: '>= 14'} - iconv-lite@0.7.2: - resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} + iconv-lite@0.7.3: + resolution: {integrity: sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==} engines: {node: '>=0.10.0'} ieee754@1.2.1: @@ -1014,8 +1014,8 @@ packages: inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - ip-address@10.2.0: - resolution: {integrity: sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==} + ip-address@10.4.0: + resolution: {integrity: sha512-oSK96Grm3aP6OrS263xVxbNDGVL7rzBtYdpGqlDG8iQdoenDoTs/nkki+DflYbAEE8Xl6o5YxhxlrKvI3nqKXQ==} engines: {node: '>= 12'} ipaddr.js@1.9.1: @@ -1039,8 +1039,8 @@ packages: resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} hasBin: true - jose@6.2.3: - resolution: {integrity: sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw==} + jose@6.2.7: + resolution: {integrity: sha512-hq1OB1bALKfydZNoViyg6hPVGV4i93ny9Op+n4zP5RSf7SCZEXa/TsG2O3IEr7+WlHRTPnpqDmHfMH6qXAD60w==} json-bigint@1.0.0: resolution: {integrity: sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==} @@ -1092,8 +1092,8 @@ packages: long@5.3.2: resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} - lru-cache@11.5.1: - resolution: {integrity: sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==} + lru-cache@11.5.2: + resolution: {integrity: sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==} engines: {node: 20 || >=22} marked@18.0.5: @@ -1105,8 +1105,8 @@ packages: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} - media-typer@1.1.0: - resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} + media-typer@1.1.1: + resolution: {integrity: sha512-yz3xRaG20c6/BOzvYoDaGtPmGscs7YivItZEEqe6GbwNfHuxu9YNmvnEkMzKldAGY4/80pRcQRZSEnhquk9XuQ==} engines: {node: '>= 0.8'} merge-descriptors@2.0.0: @@ -1151,8 +1151,8 @@ packages: resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} engines: {node: '>= 0.6'} - node-addon-api@8.8.0: - resolution: {integrity: sha512-c5Ko1fZJIJmzhFIkhRN76WTq+fC6tWnGy9CXA0fA+XygsWZmEwG8vmbkNqxMyoaa0Tin4djul49NzdVcJJcjeA==} + node-addon-api@8.9.1: + resolution: {integrity: sha512-4eUQWVPCUUUiBjLnHS3cXWeC6ryoPUc0U3rP7IuzapoGbzMqd/r6KKO0clr0b+snQhsrueFEhCZDdK+LK7hxKg==} engines: {node: ^18 || ^20 || >= 21} node-domexception@1.0.0: @@ -1219,8 +1219,8 @@ packages: zod: optional: true - openclaw@2026.7.1: - resolution: {integrity: sha512-ge/Xss99CHAjPL/ikmH/UFoiOrjcxDB4sW3y9mhyCD+dYW3wzV7TKbAVdkrXFgAG2d2BjpJofP97zUZ+umxo8g==} + openclaw@2026.7.1-2: + resolution: {integrity: sha512-ycF3yPcbjN6bUPeaUx6Mh6vze1hQWoD3CT/wWcmD7a8xaHHHRUaAlaq+lFxMHf1ssEgODVAwjlzYqp2twkYZ7g==} engines: {node: '>=22.22.3 <23 || >=24.15.0 <25 || >=25.9.0'} hasBin: true @@ -1304,8 +1304,8 @@ packages: quickjs-wasi@3.0.2: resolution: {integrity: sha512-SyfPzlrfz67/kv0SogmQgW4c2I1klkLcbvj9Y2gc1h7+VylmvuGevFljLXibGKajKJKiJV29d4S6FQLA6Sc80A==} - range-parser@1.2.1: - resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + range-parser@1.3.0: + resolution: {integrity: sha512-hek2mFQpPuI4E1BBKrSto+BU3e3x4xuarsbiwr3+lf7p44juvFMV0XFWQAP3xUyqXA4RrXLIoaSUGbSt056ZMw==} engines: {node: '>= 0.6'} rastermill@0.3.1: @@ -1492,8 +1492,8 @@ packages: resolution: {integrity: sha512-XuELoRpMR+sq8fuWwX7P0bcj+PRNiicOKDEb3fGNURhxWVyykCi9BNq7c4uVz7h7P0sj8qgBsr5SWS6yBClq3g==} engines: {node: '>=16'} - tsx@4.23.1: - resolution: {integrity: sha512-GQHnkIfxyx1wYCOS/wonik5MVRZU9hi1TEZmzGZSCJB1y9YgoZ8H6itNE/u4suE+yLmOzuE4E5S4TZ/ZX2wcWQ==} + tsx@4.23.5: + resolution: {integrity: sha512-rw55FUaqOoI7RvlQwLbhO4nSDApnQ4/CykPuiQ/EPvtrX3WA9Ig55jIt9VvbBJbzJuj12ueRu4PMZ2SxPVbihg==} engines: {node: '>=18.0.0'} hasBin: true @@ -1616,8 +1616,8 @@ packages: resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} engines: {node: '>=8'} - yargs@17.7.2: - resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + yargs@17.7.3: + resolution: {integrity: sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==} engines: {node: '>=12'} zod-to-json-schema@3.25.2: @@ -1781,7 +1781,7 @@ snapshots: '@google/genai@2.10.0(@modelcontextprotocol/sdk@1.29.0(zod@4.4.3))': dependencies: - google-auth-library: 10.7.0 + google-auth-library: 10.9.1 p-retry: 4.6.2 protobufjs: 7.6.3 ws: 8.21.0 @@ -1813,9 +1813,9 @@ snapshots: transitivePeerDependencies: - supports-color - '@hono/node-server@2.0.10(hono@4.12.27)': + '@hono/node-server@2.0.10(hono@4.12.34)': dependencies: - hono: 4.12.27 + hono: 4.12.34 '@isaacs/fs-minipass@4.0.1': dependencies: @@ -1860,7 +1860,7 @@ snapshots: '@modelcontextprotocol/sdk@1.29.0(zod@4.4.3)': dependencies: - '@hono/node-server': 2.0.10(hono@4.12.27) + '@hono/node-server': 2.0.10(hono@4.12.34) ajv: 8.20.0 ajv-formats: 3.0.1(ajv@8.20.0) content-type: 1.0.5 @@ -1869,9 +1869,9 @@ snapshots: eventsource: 3.0.7 eventsource-parser: 3.1.0 express: 5.2.1 - express-rate-limit: 8.5.2(express@5.2.1) - hono: 4.12.27 - jose: 6.2.3 + express-rate-limit: 8.6.1(express@5.2.1) + hono: 4.12.34 + jose: 6.2.7 json-schema-typed: 8.0.2 pkce-challenge: 5.0.1 raw-body: 3.0.2 @@ -1882,7 +1882,7 @@ snapshots: '@mozilla/readability@0.6.0': {} - '@openclaw/ai@2026.7.1(@modelcontextprotocol/sdk@1.29.0(zod@4.4.3))(ws@8.21.0)(zod@4.4.3)': + '@openclaw/ai@2026.7.1-2(@modelcontextprotocol/sdk@1.29.0(zod@4.4.3))(ws@8.21.0)(zod@4.4.3)': dependencies: '@anthropic-ai/sdk': 0.109.1(zod@4.4.3) '@google/genai': 2.10.0(@modelcontextprotocol/sdk@1.29.0(zod@4.4.3)) @@ -1933,7 +1933,7 @@ snapshots: '@protobufjs/pool@1.1.0': {} - '@protobufjs/utf8@1.1.1': {} + '@protobufjs/utf8@1.1.2': {} '@silvia-odwyer/photon-node@0.3.4': {} @@ -2032,7 +2032,7 @@ snapshots: ajv@8.20.0: dependencies: fast-deep-equal: 3.1.3 - fast-uri: 3.1.4 + fast-uri: 3.1.5 json-schema-traverse: 1.0.0 require-from-string: 2.0.2 @@ -2044,7 +2044,7 @@ snapshots: asn1.js@5.4.1: dependencies: - bn.js: 4.12.3 + bn.js: 4.12.5 inherits: 2.0.4 minimalistic-assert: 1.0.1 safer-buffer: 2.1.2 @@ -2055,7 +2055,7 @@ snapshots: bignumber.js@9.3.1: {} - bn.js@4.12.3: {} + bn.js@4.12.5: {} body-parser@2.3.0: dependencies: @@ -2063,7 +2063,7 @@ snapshots: content-type: 2.0.0 debug: 4.4.3 http-errors: 2.0.1 - iconv-lite: 0.7.2 + iconv-lite: 0.7.3 on-finished: 2.4.1 qs: 6.15.2 raw-body: 3.0.2 @@ -2075,7 +2075,7 @@ snapshots: bottleneck@2.19.5: {} - brace-expansion@5.0.7: + brace-expansion@5.0.9: dependencies: balanced-match: 4.0.4 @@ -2269,10 +2269,13 @@ snapshots: dependencies: eventsource-parser: 3.1.0 - express-rate-limit@8.5.2(express@5.2.1): + express-rate-limit@8.6.1(express@5.2.1): dependencies: + debug: 4.4.3 express: 5.2.1 - ip-address: 10.2.0 + ip-address: 10.4.0 + transitivePeerDependencies: + - supports-color express@5.2.1: dependencies: @@ -2297,7 +2300,7 @@ snapshots: parseurl: 1.3.3 proxy-addr: 2.0.7 qs: 6.15.2 - range-parser: 1.2.1 + range-parser: 1.3.0 router: 2.2.0 send: 1.2.1 serve-static: 2.2.1 @@ -2319,7 +2322,7 @@ snapshots: dependencies: fast-string-truncated-width: 3.0.3 - fast-uri@3.1.4: {} + fast-uri@3.1.5: {} fast-wrap-ansi@0.2.2: dependencies: @@ -2368,7 +2371,7 @@ snapshots: function-bind@1.1.2: {} - gaxios@7.1.5: + gaxios@7.3.0: dependencies: extend: 3.0.2 https-proxy-agent: 7.0.6 @@ -2378,7 +2381,7 @@ snapshots: gcp-metadata@8.1.2: dependencies: - gaxios: 7.1.5 + gaxios: 7.3.0 google-logging-utils: 1.1.3 json-bigint: 1.0.0 transitivePeerDependencies: @@ -2412,11 +2415,11 @@ snapshots: minipass: 7.1.3 path-scurry: 2.0.2 - google-auth-library@10.7.0: + google-auth-library@10.9.1: dependencies: base64-js: 1.5.1 ecdsa-sig-formatter: 1.0.11 - gaxios: 7.1.5 + gaxios: 7.3.0 gcp-metadata: 8.1.2 google-logging-utils: 1.1.3 jws: 4.0.1 @@ -2447,11 +2450,11 @@ snapshots: highlight.js@11.11.1: {} - hono@4.12.27: {} + hono@4.12.34: {} hosted-git-info@10.1.1: dependencies: - lru-cache: 11.5.1 + lru-cache: 11.5.2 html-escaper@3.0.3: {} @@ -2479,7 +2482,7 @@ snapshots: transitivePeerDependencies: - supports-color - iconv-lite@0.7.2: + iconv-lite@0.7.3: dependencies: safer-buffer: 2.1.2 @@ -2491,7 +2494,7 @@ snapshots: inherits@2.0.4: {} - ip-address@10.2.0: {} + ip-address@10.4.0: {} ipaddr.js@1.9.1: {} @@ -2505,7 +2508,7 @@ snapshots: jiti@2.7.0: {} - jose@6.2.3: {} + jose@6.2.7: {} json-bigint@1.0.0: dependencies: @@ -2560,13 +2563,13 @@ snapshots: long@5.3.2: {} - lru-cache@11.5.1: {} + lru-cache@11.5.2: {} marked@18.0.5: {} math-intrinsics@1.1.0: {} - media-typer@1.1.0: {} + media-typer@1.1.1: {} merge-descriptors@2.0.0: {} @@ -2580,7 +2583,7 @@ snapshots: minimatch@10.2.5: dependencies: - brace-expansion: 5.0.7 + brace-expansion: 5.0.9 minimist@1.2.8: {} @@ -2596,7 +2599,7 @@ snapshots: negotiator@1.0.0: {} - node-addon-api@8.8.0: {} + node-addon-api@8.9.1: {} node-domexception@1.0.0: {} @@ -2604,7 +2607,7 @@ snapshots: dependencies: https-proxy-agent: 7.0.6 ws: 8.21.0 - yargs: 17.7.2 + yargs: 17.7.3 transitivePeerDependencies: - bufferutil - supports-color @@ -2643,7 +2646,7 @@ snapshots: ws: 8.21.0 zod: 4.4.3 - openclaw@2026.7.1: + openclaw@2026.7.1-2: dependencies: '@agentclientprotocol/sdk': 1.1.0(zod@4.4.3) '@anthropic-ai/sdk': 0.109.1(zod@4.4.3) @@ -2658,7 +2661,7 @@ snapshots: '@mistralai/mistralai': 2.4.0 '@modelcontextprotocol/sdk': 1.29.0(zod@4.4.3) '@mozilla/readability': 0.6.0 - '@openclaw/ai': 2026.7.1(@modelcontextprotocol/sdk@1.29.0(zod@4.4.3))(ws@8.21.0)(zod@4.4.3) + '@openclaw/ai': 2026.7.1-2(@modelcontextprotocol/sdk@1.29.0(zod@4.4.3))(ws@8.21.0)(zod@4.4.3) '@openclaw/fs-safe': 0.4.1 '@openclaw/proxyline': 0.3.3(undici@8.5.0) '@silvia-odwyer/photon-node': 0.3.4 @@ -2743,7 +2746,7 @@ snapshots: path-scurry@2.0.2: dependencies: - lru-cache: 11.5.1 + lru-cache: 11.5.2 minipass: 7.1.3 path-to-regexp@8.4.2: {} @@ -2773,7 +2776,7 @@ snapshots: '@protobufjs/inquire': 1.1.2 '@protobufjs/path': 1.1.2 '@protobufjs/pool': 1.1.0 - '@protobufjs/utf8': 1.1.1 + '@protobufjs/utf8': 1.1.2 '@types/node': 26.1.2 long: 5.3.2 @@ -2794,7 +2797,7 @@ snapshots: quickjs-wasi@3.0.2: {} - range-parser@1.2.1: {} + range-parser@1.3.0: {} rastermill@0.3.1: dependencies: @@ -2804,7 +2807,7 @@ snapshots: dependencies: bytes: 3.1.2 http-errors: 2.0.1 - iconv-lite: 0.7.2 + iconv-lite: 0.7.3 unpipe: 1.0.0 readable-stream@2.3.8: @@ -2856,7 +2859,7 @@ snapshots: mime-types: 3.0.2 ms: 2.1.3 on-finished: 2.4.1 - range-parser: 1.2.1 + range-parser: 1.3.0 statuses: 2.0.2 transitivePeerDependencies: - supports-color @@ -2990,7 +2993,7 @@ snapshots: tree-sitter-bash@0.25.1: dependencies: - node-addon-api: 8.8.0 + node-addon-api: 8.9.1 node-gyp-build: 4.8.4 ts-algebra@2.0.0: {} @@ -2999,7 +3002,7 @@ snapshots: tslog@4.10.2: {} - tsx@4.23.1: + tsx@4.23.5: dependencies: esbuild: 0.28.1 optionalDependencies: @@ -3008,7 +3011,7 @@ snapshots: type-is@2.1.0: dependencies: content-type: 2.0.0 - media-typer: 1.1.0 + media-typer: 1.1.1 mime-types: 3.0.2 typebox@1.3.3: {} @@ -3124,7 +3127,7 @@ snapshots: y18n: 4.0.3 yargs-parser: 18.1.3 - yargs@17.7.2: + yargs@17.7.3: dependencies: cliui: 8.0.1 escalade: 3.2.0 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index a01b328..4af05de 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -9,6 +9,8 @@ allowBuilds: tree-sitter-bash: false minimumReleaseAgeExclude: + # security-exception advisory=GHSA-8j4g-w8fx-2239 published=2026-08-03T02:36:40.543Z quarantineEnds=2026-08-04T02:36:40.543Z expires=2026-08-05T02:36:40.543Z + - hono@4.12.34 - '@anthropic-ai/claude-agent-sdk-darwin-arm64@0.3.216' - '@anthropic-ai/claude-agent-sdk-darwin-x64@0.3.216' - '@anthropic-ai/claude-agent-sdk-linux-arm64-musl@0.3.216' @@ -31,8 +33,8 @@ overrides: path-to-regexp@>=8.0.0 <8.4.0: ">=8.4.0" "@anthropic-ai/sdk@<0.93.0": 0.93.0 ip-address@<10.1.1: 10.1.1 - fast-uri@<=3.1.3: 3.1.4 + fast-uri@<3.1.5: 3.1.5 qs@<6.15.2: 6.15.2 - hono@<4.12.27: 4.12.27 + hono@<4.12.34: 4.12.34 "@hono/node-server@<2.0.10": 2.0.10 undici@>=8.0.0 <8.5.0: 8.5.0 diff --git a/scripts/check-release-age-exceptions.mjs b/scripts/check-release-age-exceptions.mjs new file mode 100644 index 0000000..e59fc2d --- /dev/null +++ b/scripts/check-release-age-exceptions.mjs @@ -0,0 +1,63 @@ +import { readFile } from "node:fs/promises"; + +const marker = /^\s*#\s*security-exception\s+(.+)\s*$/; +const entry = /^\s*-\s*['"]?([^'"\s]+)['"]?\s*$/; +const exactPackageVersion = /^(?:@[^/@]+\/[^/@]+|[^@/]+)@(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-[0-9A-Za-z.-]+)?$/; + +export function parseSecurityExceptions(source) { + const lines = source.split(/\r?\n/); + const exceptions = []; + + for (let index = 0; index < lines.length; index += 1) { + const match = marker.exec(lines[index]); + if (!match) continue; + + const fields = Object.fromEntries( + match[1].split(/\s+/).map((part) => { + const separator = part.indexOf("="); + if (separator < 1) throw new Error(`Malformed security exception field on line ${index + 1}: ${part}`); + return [part.slice(0, separator), part.slice(separator + 1)]; + }), + ); + const packageMatch = entry.exec(lines[index + 1] ?? ""); + if (!packageMatch) throw new Error(`Security exception on line ${index + 1} must immediately precede one package entry`); + exceptions.push({ ...fields, package: packageMatch[1], line: index + 1 }); + } + + return exceptions; +} + +export function validateSecurityExceptions(source, now = new Date()) { + const exceptions = parseSecurityExceptions(source); + for (const exception of exceptions) { + if (!exactPackageVersion.test(exception.package)) { + throw new Error(`Security exception on line ${exception.line} is not an exact package@version: ${exception.package}`); + } + if (!/^GHSA-[0-9a-z-]+$/.test(exception.advisory ?? "")) { + throw new Error(`Security exception on line ${exception.line} requires a GHSA advisory`); + } + + const published = Date.parse(exception.published ?? ""); + const quarantineEnds = Date.parse(exception.quarantineEnds ?? ""); + const expires = Date.parse(exception.expires ?? ""); + if (![published, quarantineEnds, expires].every(Number.isFinite)) { + throw new Error(`Security exception on line ${exception.line} requires valid published, quarantineEnds, and expires timestamps`); + } + if (quarantineEnds !== published + 24 * 60 * 60 * 1000) { + throw new Error(`Security exception on line ${exception.line} must use the repository's 24-hour quarantine`); + } + if (expires <= quarantineEnds) { + throw new Error(`Security exception on line ${exception.line} must expire after quarantine ends`); + } + if (now.getTime() >= expires) { + throw new Error(`Security exception on line ${exception.line} expired at ${exception.expires}; remove it`); + } + } + return exceptions; +} + +if (import.meta.url === `file://${process.argv[1]}`) { + const workspaceFile = new URL("../pnpm-workspace.yaml", import.meta.url); + const exceptions = validateSecurityExceptions(await readFile(workspaceFile, "utf8")); + console.log(`Validated ${exceptions.length} temporary release-age security exception(s).`); +} diff --git a/scripts/validate-release-metadata.mjs b/scripts/validate-release-metadata.mjs index e304b72..2efddf1 100644 --- a/scripts/validate-release-metadata.mjs +++ b/scripts/validate-release-metadata.mjs @@ -5,7 +5,8 @@ import { fileURLToPath } from "node:url"; const scriptPath = fileURLToPath(import.meta.url); const rootDir = dirname(dirname(scriptPath)); -const defaultOpenClawTargetVersion = "2026.7.1"; +const defaultOpenClawTargetVersion = "2026.7.1-2"; +const defaultOpenClawCompatibilityFloor = "2026.7.1-2"; const exactOpenClawVersionPattern = /^\d{4}\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/u; export function normalizeOpenClawTargetVersion(value = defaultOpenClawTargetVersion) { @@ -38,9 +39,13 @@ export function validateReleaseMetadata(options = {}) { const { releaseVersion, openclawTargetVersion = defaultOpenClawTargetVersion, + openclawCompatibilityFloor = defaultOpenClawCompatibilityFloor, baseDir = rootDir, } = options; const normalizedOpenClawTargetVersion = normalizeOpenClawTargetVersion(openclawTargetVersion); + const normalizedOpenClawCompatibilityFloor = normalizeOpenClawTargetVersion( + openclawCompatibilityFloor, + ); const { packageVersion, pluginVersion, @@ -102,7 +107,7 @@ export function validateReleaseMetadata(options = {}) { ); } - const expectedRange = `>=${normalizedOpenClawTargetVersion}`; + const expectedRange = `>=${normalizedOpenClawCompatibilityFloor}`; if (openclawInstall.minHostVersion !== expectedRange) { throw new Error( `OpenClaw install minHostVersion mismatch: expected ${expectedRange}, got ${openclawInstall.minHostVersion}`, @@ -115,9 +120,9 @@ export function validateReleaseMetadata(options = {}) { ); } - if (openclawCompat?.minGatewayVersion !== normalizedOpenClawTargetVersion) { + if (openclawCompat?.minGatewayVersion !== normalizedOpenClawCompatibilityFloor) { throw new Error( - `OpenClaw minGatewayVersion mismatch: expected ${normalizedOpenClawTargetVersion}, got ${openclawCompat?.minGatewayVersion}`, + `OpenClaw minGatewayVersion mismatch: expected ${normalizedOpenClawCompatibilityFloor}, got ${openclawCompat?.minGatewayVersion}`, ); } @@ -140,6 +145,12 @@ export function validateReleaseMetadata(options = {}) { throw new Error(`pnpm-lock.yaml is not pinned to OpenClaw ${openclawVersion}`); } + if (packageJson.devDependencies?.openclaw !== normalizedOpenClawTargetVersion) { + throw new Error( + `OpenClaw dev dependency mismatch: expected ${normalizedOpenClawTargetVersion}, got ${packageJson.devDependencies?.openclaw}`, + ); + } + if (packageJson.packageManager !== "pnpm@11.15.1") { throw new Error(`Unexpected package manager: ${packageJson.packageManager}`); } diff --git a/tests/plugin-entry.test.ts b/tests/plugin-entry.test.ts index 189aed1..3b9f44e 100644 --- a/tests/plugin-entry.test.ts +++ b/tests/plugin-entry.test.ts @@ -72,11 +72,11 @@ describe("plugin entry source", () => { validateReleaseMetadata(); assert.equal(packageVersion, pluginVersion); assert.equal(pluginName, "Code Agent"); - assert.equal(openclawVersion, "2026.7.1"); - assert.equal(pluginSdkVersion, "2026.7.1"); + assert.equal(openclawVersion, "2026.7.1-2"); + assert.equal(pluginSdkVersion, "2026.7.1-2"); assert.equal(openclawInstall.npmSpec, "openclaw-code-agent"); assert.equal(openclawInstall.defaultChoice, "npm"); - assert.equal(openclawInstall.minHostVersion, ">=2026.7.1"); + assert.equal(openclawInstall.minHostVersion, ">=2026.7.1-2"); const cliOutput = execFileSync("node", ["scripts/validate-release-metadata.mjs"], { cwd: rootDir, @@ -85,7 +85,7 @@ describe("plugin entry source", () => { assert.match(cliOutput, /openclaw\.plugin\.name=Code Agent/); assert.match(cliOutput, /openclaw\.install\.npmSpec=openclaw-code-agent/); assert.match(cliOutput, /openclaw\.install\.defaultChoice=npm/); - assert.match(cliOutput, /openclaw\.install\.minHostVersion=>=2026\.7\.1/); + assert.match(cliOutput, /openclaw\.install\.minHostVersion=>=2026\.7\.1-2/); }); it("keeps security audit automation on the pnpm-only path", () => { @@ -109,7 +109,7 @@ describe("plugin entry source", () => { assert.doesNotMatch(activeWorkflowSources, /\bnpm audit\b/); }); - it("requires v2026.7.1 across all public OpenClaw compatibility metadata", () => { + it("uses a correction-release floor that includes v2026.7.1-2 and stable v2026.7.1", () => { const packageJson = JSON.parse(readFileSync(join(rootDir, "package.json"), "utf8")) as { dependencies?: Record; openclaw?: { @@ -124,21 +124,24 @@ describe("plugin entry source", () => { assert.equal(packageJson.dependencies?.["@anthropic-ai/claude-agent-sdk"], "^0.3.216"); assert.equal(packageJson.openclaw?.install?.npmSpec, "openclaw-code-agent"); assert.equal(packageJson.openclaw?.install?.defaultChoice, "npm"); - assert.equal(packageJson.openclaw?.install?.minHostVersion, ">=2026.7.1"); - assert.equal(packageJson.openclaw?.compat?.pluginApi, ">=2026.7.1"); - assert.equal(packageJson.openclaw?.compat?.minGatewayVersion, "2026.7.1"); - assert.equal(packageJson.openclaw?.build?.openclawVersion, "2026.7.1"); - assert.equal(packageJson.openclaw?.build?.pluginSdkVersion, "2026.7.1"); - assert.equal(packageJson.peerDependencies?.openclaw, ">=2026.7.1"); - assert.equal(packageJson.devDependencies?.openclaw, "2026.7.1"); + assert.equal(packageJson.openclaw?.install?.minHostVersion, ">=2026.7.1-2"); + assert.equal(packageJson.openclaw?.compat?.pluginApi, ">=2026.7.1-2"); + assert.equal(packageJson.openclaw?.compat?.minGatewayVersion, "2026.7.1-2"); + assert.equal(packageJson.openclaw?.build?.openclawVersion, "2026.7.1-2"); + assert.equal(packageJson.openclaw?.build?.pluginSdkVersion, "2026.7.1-2"); + assert.equal(packageJson.peerDependencies?.openclaw, ">=2026.7.1-2"); + assert.equal(packageJson.devDependencies?.openclaw, "2026.7.1-2"); assert.doesNotMatch(readFileSync(join(rootDir, "pnpm-lock.yaml"), "utf8"), /uuid@9\.0\.1/); }); it("accepts exact and range-shaped manual OpenClaw release targets", () => { - assert.equal(normalizeOpenClawTargetVersion("2026.7.1"), "2026.7.1"); + assert.equal(normalizeOpenClawTargetVersion("2026.7.1-2"), "2026.7.1-2"); assert.equal(normalizeOpenClawTargetVersion(">=2026.7.1"), "2026.7.1"); assert.doesNotThrow(() => - validateReleaseMetadata({ openclawTargetVersion: ">=2026.7.1" }), + validateReleaseMetadata({ + openclawTargetVersion: "2026.7.1-2", + openclawCompatibilityFloor: ">=2026.7.1-2", + }), ); assert.throws( () => normalizeOpenClawTargetVersion("^2026.7.1"), @@ -442,15 +445,15 @@ describe("plugin entry source", () => { assert.doesNotMatch(apiSource, /openclaw\/plugin-sdk\/discord/); }); - it("documents 2026.7.1 plugin allowlist and apply_patch policy boundaries", () => { + it("documents the 2026.7.1-2 target and 2026.7.1 compatibility boundaries", () => { const reference = readFileSync(join(rootDir, "docs", "REFERENCE.md"), "utf8"); const readme = readFileSync(join(rootDir, "README.md"), "utf8"); const changelog = readFileSync(join(rootDir, "CHANGELOG.md"), "utf8"); - assert.match(reference, /OpenClaw 2026\.7\.1 SDK Readiness/); - assert.match(reference, /validated against and requires OpenClaw `2026\.7\.1`/); - assert.match(readme, /targets, validates against, and requires OpenClaw `2026\.7\.1`/); - assert.match(changelog, /Retargeted the OpenClaw package and plugin SDK validation metadata to `2026\.7\.1`/); + assert.match(reference, /OpenClaw 2026\.7\.1-2 SDK Readiness/); + assert.match(reference, /validated against OpenClaw `2026\.7\.1-2`/); + assert.match(readme, /targets and validates against OpenClaw `2026\.7\.1-2`/); + assert.match(changelog, /retargeted package and plugin SDK build metadata to OpenClaw `2026\.7\.1-2`/i); assert.match(changelog, /Codex app-server, Telegram and topic routing, cron\/session delivery/); assert.match(readme, /retryable stale plan approval buttons/); assert.match(reference, /pnpm-workspace\.yaml/); diff --git a/tests/release-age-exceptions.test.ts b/tests/release-age-exceptions.test.ts new file mode 100644 index 0000000..b8ddbd6 --- /dev/null +++ b/tests/release-age-exceptions.test.ts @@ -0,0 +1,39 @@ +import assert from "node:assert/strict"; +import { describe, it } from "node:test"; + +import { validateSecurityExceptions } from "../scripts/check-release-age-exceptions.mjs"; + +const exception = (packageSpec = "hono@4.12.34", expires = "2026-08-05T02:36:40.543Z") => ` +minimumReleaseAgeExclude: + # security-exception advisory=GHSA-8j4g-w8fx-2239 published=2026-08-03T02:36:40.543Z quarantineEnds=2026-08-04T02:36:40.543Z expires=${expires} + - ${packageSpec} +`; + +describe("release-age security exceptions", () => { + it("accepts a documented exact-version exception before its deadline", () => { + const exceptions = validateSecurityExceptions(exception(), new Date("2026-08-04T12:00:00Z")); + assert.equal(exceptions[0]?.package, "hono@4.12.34"); + }); + + it("rejects a range that could bypass quarantine for later releases", () => { + assert.throws( + () => validateSecurityExceptions(exception("hono@^4.12.34"), new Date("2026-08-04T12:00:00Z")), + /not an exact package@version/, + ); + }); + + it("rejects an expired exception so it cannot become permanent", () => { + assert.throws( + () => validateSecurityExceptions(exception(), new Date("2026-08-05T02:36:40.543Z")), + /expired at/, + ); + }); + + it("rejects a quarantine interval shorter than the repository policy", () => { + const source = exception().replace("2026-08-04T02:36:40.543Z", "2026-08-03T03:36:40.543Z"); + assert.throws( + () => validateSecurityExceptions(source, new Date("2026-08-03T03:00:00Z")), + /24-hour quarantine/, + ); + }); +});