Compare commits

..

4 Commits

Author SHA1 Message Date
dependabot[bot] 805ede7ac3 chore(deps): bump softprops/action-gh-release from 3.0.0 to 3.0.1
Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 3.0.0 to 3.0.1.
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](https://github.com/softprops/action-gh-release/compare/b4309332981a82ec1c5618f44dd2e27cc8bfbfda...718ea10b132b3b2eba29c1007bb80653f286566b)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-version: 3.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-22 21:34:22 +00:00
davida-ps de28dadd39 fix(release): update ClawHub slug pipeline deps (#277)
* fix(release): update clawhub slug pipeline deps

* fix(release): bump clawhub cli undici lock

* fix(release): guard clawhub publish slug

* fix(release): keep suite slug releasable

* fix(release): harden clawhub slug guard

* fix(release): pass clawhub registry to slug guard
2026-06-22 23:45:24 +03:00
github-actions[bot] f937384104 chore: update NVD/GHSA advisories - 0 NVD new, 27 NVD updated (#276)
Automated update from NVD CVE and GHSA advisory feeds.
Keywords: openclaw, nanoclaw, hermes, picoclaw
Poll window: 2026-06-17T07:45:48Z to 2026-06-21T07:34:32.000Z

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-21 14:32:23 +03:00
github-actions[bot] 8648aad6d7 chore: update NVD/GHSA advisories - 27 NVD new, 20 NVD updated (#274)
* chore: update NVD/GHSA advisories - 27 NVD new, 20 NVD updated

Automated update from NVD CVE and GHSA advisory feeds.
Keywords: openclaw, nanoclaw, hermes, picoclaw
Poll window: 2026-06-14T07:33:37Z to 2026-06-17T07:44:37.000Z

* fix(skill-release): ignore generated advisory mirror updates

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: David Abutbul <David.a@prompt.security>
2026-06-17 17:24:25 +03:00
14 changed files with 2605 additions and 2650 deletions
+3 -3
View File
@@ -384,9 +384,9 @@
}
},
"node_modules/undici": {
"version": "7.27.2",
"resolved": "https://prompt-security-443370709039.d.codeartifact.eu-north-1.amazonaws.com/npm/npm-proxy/undici/-/undici-7.27.2.tgz",
"integrity": "sha512-uZsKNuzQxDMUY6M3pIMvy5tvlGmtq8XJ2oLAkfRKGNu+1VQAIvLy2xIVG5ATZl5wDXl/tddByAWCizRbOme+TA==",
"version": "7.28.0",
"resolved": "https://prompt-security-443370709039.d.codeartifact.eu-north-1.amazonaws.com/npm/npm-proxy/undici/-/undici-7.28.0.tgz",
"integrity": "sha512-cRZYrTDwWznlnRiPjggAGxZXanty6M8RV1ff8Wm4LWXBp7/IG8v5DnOm74DtUBp9OONpK75YlPnIjQqX0dBDtA==",
"engines": {
"node": ">=20.18.1"
}
+32 -3
View File
@@ -7,6 +7,8 @@ on:
pull_request:
paths:
- 'skills/**'
- '!skills/clawsec-feed/advisories/feed.json'
- '!skills/clawsec-feed/advisories/feed.json.sig'
- '.github/workflows/skill-release.yml'
- 'scripts/ci/**'
- 'scripts/test-skill-*.mjs'
@@ -88,6 +90,8 @@ jobs:
touched_skills_file="$(mktemp)"
git diff --name-only "${BASE_SHA}...${HEAD_SHA}" -- \
'skills/*/**' \
':(exclude)skills/clawsec-feed/advisories/feed.json' \
':(exclude)skills/clawsec-feed/advisories/feed.json.sig' \
':(exclude)skills/*/test/**' \
':(exclude)skills/*/tests/**' \
| awk -F/ '
@@ -410,6 +414,8 @@ jobs:
touched_skills_file="$(mktemp)"
git diff --name-only "${BASE_SHA}...${HEAD_SHA}" -- \
'skills/*/**' \
':(exclude)skills/clawsec-feed/advisories/feed.json' \
':(exclude)skills/clawsec-feed/advisories/feed.json.sig' \
':(exclude)skills/*/test/**' \
':(exclude)skills/*/tests/**' \
| awk -F/ 'NF >= 3 {print $1 "/" $2}' \
@@ -1625,7 +1631,7 @@ jobs:
'
- name: Create GitHub Release
uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0
uses: softprops/action-gh-release@718ea10b132b3b2eba29c1007bb80653f286566b # v3.0.1
with:
name: "${{ steps.parse.outputs.skill_name }} ${{ steps.parse.outputs.version }}"
tag_name: ${{ github.ref_name }}
@@ -1711,7 +1717,7 @@ jobs:
run: bash scripts/ci/install_clawhub_cli.sh
- name: Patch clawhub publish payload workaround
# Temporary: clawhub@0.7.0 publish payload is missing acceptLicenseTerms.
# Idempotent compatibility guard: older clawhub@0.7.0 builds omitted acceptLicenseTerms.
if: needs.release-tag.outputs.publish_clawhub == 'true' && env.CLAWHUB_TOKEN != ''
run: node scripts/ci/patch_clawhub_publish_payload.mjs
@@ -1726,6 +1732,18 @@ jobs:
CLAWHUB_DISABLE_TELEMETRY=1 CLAWHUB_SITE="$SITE" CLAWHUB_REGISTRY="$REGISTRY" \
clawhub login --token "$CLAWHUB_TOKEN" --site "$SITE" --no-input
- name: Guard ClawHub slug ownership
if: needs.release-tag.outputs.publish_clawhub == 'true' && env.CLAWHUB_TOKEN != ''
run: |
set -euo pipefail
SITE=${CLAWHUB_SITE:-https://clawhub.ai}
REGISTRY=${CLAWHUB_REGISTRY:-$SITE}
export CLAWHUB_CONFIG_PATH="$HOME/.clawhub-ci/config.json"
export CLAWHUB_SITE="$SITE"
export CLAWHUB_REGISTRY="$REGISTRY"
bash scripts/ci/guard_clawhub_slug_owner.sh \
"${{ needs.release-tag.outputs.clawhub_slug }}"
- name: Guard duplicate ClawHub version
if: needs.release-tag.outputs.publish_clawhub == 'true' && env.CLAWHUB_TOKEN != ''
run: |
@@ -1866,7 +1884,7 @@ jobs:
run: bash scripts/ci/install_clawhub_cli.sh
- name: Patch clawhub publish payload workaround
# Temporary: clawhub@0.7.0 publish payload is missing acceptLicenseTerms.
# Idempotent compatibility guard: older clawhub@0.7.0 builds omitted acceptLicenseTerms.
run: node scripts/ci/patch_clawhub_publish_payload.mjs
- name: Login to ClawHub
@@ -1884,6 +1902,17 @@ jobs:
CLAWHUB_DISABLE_TELEMETRY=1 CLAWHUB_SITE="$SITE" CLAWHUB_REGISTRY="$REGISTRY" \
clawhub login --token "$CLAWHUB_TOKEN" --site "$SITE" --no-input
- name: Guard ClawHub slug ownership
run: |
set -euo pipefail
SITE=${CLAWHUB_SITE:-https://clawhub.ai}
REGISTRY=${CLAWHUB_REGISTRY:-$SITE}
export CLAWHUB_CONFIG_PATH="$HOME/.clawhub-ci/config.json"
export CLAWHUB_SITE="$SITE"
export CLAWHUB_REGISTRY="$REGISTRY"
bash scripts/ci/guard_clawhub_slug_owner.sh \
"${{ steps.publishable.outputs.clawhub_slug }}"
- name: Publish to ClawHub
run: |
set -euo pipefail
+1023 -1194
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1 +1 @@
jPrlTYwicRwoQgTs5Rk3Y3g6Lz78jNRs9ZNf0R09M4jkJokZENxfvhvHphI9MH4u+7wv0sFZ+yZbQtJ42y+hCQ==
K19pfVfv7qB1cqFPFTu69+sKLHIMIrmS7GeK4BZIlHzRvrLfRUuq/KftC8/CIWwvixVlBBm/iZlyfJ5sutoDDw==
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1 +1 @@
M1Jm4YHXsm0msygmd+XCJBRWMrXIjQfv1Y5v7XS8RCachLQwEzUJ1nhhic6CXxItNLmvgmDjVCMPVdHpnOMqDA==
pmw3QutYARGuNH2evzHY/slVqxsrIGU+JrtS1hr1kOSqo1Md1aVBEA0tsNoQ+SkVjNohwGVk/61CcUxeW6WAAA==
+99 -75
View File
@@ -10,7 +10,7 @@
"license": "AGPL-3.0-or-later",
"dependencies": {
"lucide-react": "^0.575.0",
"react": "^19.2.7",
"react": "^19.2.4",
"react-dom": "^19.2.5",
"react-markdown": "^10.1.0",
"react-router-dom": "^7.16.0",
@@ -31,11 +31,12 @@
}
},
"node_modules/@babel/code-frame": {
"version": "7.29.0",
"integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==",
"version": "7.29.7",
"integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-validator-identifier": "^7.28.5",
"@babel/helper-validator-identifier": "^7.29.7",
"js-tokens": "^4.0.0",
"picocolors": "^1.1.1"
},
@@ -44,27 +45,29 @@
}
},
"node_modules/@babel/compat-data": {
"version": "7.29.0",
"integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==",
"version": "7.29.7",
"integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/core": {
"version": "7.29.0",
"integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
"version": "7.29.7",
"integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.29.0",
"@babel/generator": "^7.29.0",
"@babel/helper-compilation-targets": "^7.28.6",
"@babel/helper-module-transforms": "^7.28.6",
"@babel/helpers": "^7.28.6",
"@babel/parser": "^7.29.0",
"@babel/template": "^7.28.6",
"@babel/traverse": "^7.29.0",
"@babel/types": "^7.29.0",
"@babel/code-frame": "^7.29.7",
"@babel/generator": "^7.29.7",
"@babel/helper-compilation-targets": "^7.29.7",
"@babel/helper-module-transforms": "^7.29.7",
"@babel/helpers": "^7.29.7",
"@babel/parser": "^7.29.7",
"@babel/template": "^7.29.7",
"@babel/traverse": "^7.29.7",
"@babel/types": "^7.29.7",
"@jridgewell/remapping": "^2.3.5",
"convert-source-map": "^2.0.0",
"debug": "^4.1.0",
@@ -89,12 +92,13 @@
}
},
"node_modules/@babel/generator": {
"version": "7.29.0",
"integrity": "sha512-vSH118/wwM/pLR38g/Sgk05sNtro6TlTJKuiMXDaZqPUfjTFcudpCOt00IhOfj+1BFAX+UFAlzCU+6WXr3GLFQ==",
"version": "7.29.7",
"integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/parser": "^7.29.0",
"@babel/types": "^7.29.0",
"@babel/parser": "^7.29.7",
"@babel/types": "^7.29.7",
"@jridgewell/gen-mapping": "^0.3.12",
"@jridgewell/trace-mapping": "^0.3.28",
"jsesc": "^3.0.2"
@@ -104,12 +108,13 @@
}
},
"node_modules/@babel/helper-compilation-targets": {
"version": "7.28.6",
"integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==",
"version": "7.29.7",
"integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/compat-data": "^7.28.6",
"@babel/helper-validator-option": "^7.27.1",
"@babel/compat-data": "^7.29.7",
"@babel/helper-validator-option": "^7.29.7",
"browserslist": "^4.24.0",
"lru-cache": "^5.1.1",
"semver": "^6.3.1"
@@ -127,33 +132,36 @@
}
},
"node_modules/@babel/helper-globals": {
"version": "7.28.0",
"integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==",
"version": "7.29.7",
"integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-module-imports": {
"version": "7.28.6",
"integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==",
"version": "7.29.7",
"integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/traverse": "^7.28.6",
"@babel/types": "^7.28.6"
"@babel/traverse": "^7.29.7",
"@babel/types": "^7.29.7"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-module-transforms": {
"version": "7.28.6",
"integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==",
"version": "7.29.7",
"integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-module-imports": "^7.28.6",
"@babel/helper-validator-identifier": "^7.28.5",
"@babel/traverse": "^7.28.6"
"@babel/helper-module-imports": "^7.29.7",
"@babel/helper-validator-identifier": "^7.29.7",
"@babel/traverse": "^7.29.7"
},
"engines": {
"node": ">=6.9.0"
@@ -163,79 +171,84 @@
}
},
"node_modules/@babel/helper-string-parser": {
"version": "7.27.1",
"integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
"version": "7.29.7",
"integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-validator-identifier": {
"version": "7.28.5",
"integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==",
"version": "7.29.7",
"integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-validator-option": {
"version": "7.27.1",
"integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==",
"version": "7.29.7",
"integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helpers": {
"version": "7.28.6",
"integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==",
"version": "7.29.7",
"integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/template": "^7.28.6",
"@babel/types": "^7.28.6"
"@babel/template": "^7.29.7",
"@babel/types": "^7.29.7"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/parser": {
"version": "7.29.0",
"integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==",
"version": "7.29.7",
"integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/types": "^7.29.0"
},
"bin": {
"parser": "bin/babel-parser.js"
"@babel/types": "^7.29.7"
},
"bin": "./bin/babel-parser.js",
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@babel/template": {
"version": "7.28.6",
"integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==",
"version": "7.29.7",
"integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.28.6",
"@babel/parser": "^7.28.6",
"@babel/types": "^7.28.6"
"@babel/code-frame": "^7.29.7",
"@babel/parser": "^7.29.7",
"@babel/types": "^7.29.7"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/traverse": {
"version": "7.29.0",
"integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==",
"version": "7.29.7",
"integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.29.0",
"@babel/generator": "^7.29.0",
"@babel/helper-globals": "^7.28.0",
"@babel/parser": "^7.29.0",
"@babel/template": "^7.28.6",
"@babel/types": "^7.29.0",
"@babel/code-frame": "^7.29.7",
"@babel/generator": "^7.29.7",
"@babel/helper-globals": "^7.29.7",
"@babel/parser": "^7.29.7",
"@babel/template": "^7.29.7",
"@babel/types": "^7.29.7",
"debug": "^4.3.1"
},
"engines": {
@@ -243,12 +256,13 @@
}
},
"node_modules/@babel/types": {
"version": "7.29.0",
"integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==",
"version": "7.29.7",
"integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-string-parser": "^7.27.1",
"@babel/helper-validator-identifier": "^7.28.5"
"@babel/helper-string-parser": "^7.29.7",
"@babel/helper-validator-identifier": "^7.29.7"
},
"engines": {
"node": ">=6.9.0"
@@ -3092,10 +3106,20 @@
"dev": true
},
"node_modules/js-yaml": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
"integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.2.0.tgz",
"integrity": "sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/puzrin"
},
{
"type": "github",
"url": "https://github.com/sponsors/nodeca"
}
],
"license": "MIT",
"dependencies": {
"argparse": "^2.0.1"
@@ -4553,9 +4577,9 @@
"license": "MIT"
},
"node_modules/react": {
"version": "19.2.7",
"resolved": "https://registry.npmjs.org/react/-/react-19.2.7.tgz",
"integrity": "sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==",
"version": "19.2.5",
"resolved": "https://registry.npmjs.org/react/-/react-19.2.5.tgz",
"integrity": "sha512-llUJLzz1zTUBrskt2pwZgLq59AemifIftw4aB7JxOqf1HY2FDaGDxgwpAPVzHU1kdWabH7FauP4i1oEeer2WCA==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
+1 -1
View File
@@ -20,7 +20,7 @@
},
"dependencies": {
"lucide-react": "^0.575.0",
"react": "^19.2.7",
"react": "^19.2.4",
"react-dom": "^19.2.5",
"react-markdown": "^10.1.0",
"react-router-dom": "^7.16.0",
+104
View File
@@ -0,0 +1,104 @@
#!/usr/bin/env bash
set -euo pipefail
usage() {
echo "Usage: $0 <target-clawhub-slug>" >&2
}
if [ "$#" -ne 1 ]; then
usage
exit 2
fi
TARGET_SLUG="$1"
SITE="${CLAWHUB_SITE:-https://clawhub.ai}"
REGISTRY="${CLAWHUB_REGISTRY:-$SITE}"
CONFIG_PATH="${CLAWHUB_CONFIG_PATH:-$HOME/.clawhub-ci/config.json}"
if [[ ! "$TARGET_SLUG" =~ ^[a-z0-9-]+$ ]]; then
echo "::error::Invalid ClawHub slug for ownership guard: ${TARGET_SLUG}"
exit 1
fi
if [ ! -f "$CONFIG_PATH" ]; then
echo "::error::ClawHub config not found at ${CONFIG_PATH}. Run clawhub login before ownership guard."
exit 1
fi
TOKEN="$(jq -r '.token // empty' "$CONFIG_PATH")"
if [ -z "$TOKEN" ]; then
echo "::error::ClawHub token missing from ${CONFIG_PATH}. Run clawhub login before ownership guard."
exit 1
fi
TMP_DIR="$(mktemp -d)"
trap 'rm -rf "$TMP_DIR"' EXIT
api_get() {
local path="$1"
local output_path="$2"
local url="${REGISTRY%/}${path}"
local http_status
local curl_status
set +e
http_status="$(
curl --silent --show-error --location --max-time 15 \
--header "Accept: application/json" \
--header "Authorization: Bearer ${TOKEN}" \
--output "$output_path" \
--write-out "%{http_code}" \
"$url"
)"
curl_status=$?
set -e
if [ "$curl_status" -ne 0 ]; then
echo "::error::Failed to call ClawHub API: ${url}"
return 1
fi
printf '%s\n' "$http_status"
}
whoami_json="$TMP_DIR/whoami.json"
whoami_status="$(api_get "/api/v1/whoami" "$whoami_json")"
if [ "$whoami_status" != "200" ]; then
echo "::error::Failed to verify authenticated ClawHub publisher. HTTP ${whoami_status}."
cat "$whoami_json"
exit 1
fi
publisher_handle="$(jq -r '.user.handle // empty' "$whoami_json")"
if [ -z "$publisher_handle" ]; then
echo "::error::Could not determine authenticated ClawHub publisher handle."
cat "$whoami_json"
exit 1
fi
target_json="$TMP_DIR/target.json"
target_status="$(api_get "/api/v1/skills/${TARGET_SLUG}" "$target_json")"
if [ "$target_status" = "404" ]; then
echo "Target ClawHub slug ${TARGET_SLUG} is not currently published; authenticated publisher ${publisher_handle} may create it."
exit 0
fi
if [ "$target_status" != "200" ]; then
echo "::error::Failed to inspect target ClawHub slug ${TARGET_SLUG}. HTTP ${target_status}."
cat "$target_json"
exit 1
fi
target_owner="$(jq -r '.owner.handle // .owner.displayName // empty' "$target_json")"
if [ -z "$target_owner" ]; then
echo "::error::Could not determine owner for existing ClawHub slug ${TARGET_SLUG}."
echo "target owner: ${target_owner:-unknown}"
exit 1
fi
if [ "$target_owner" != "$publisher_handle" ]; then
echo "::error::Resolved ClawHub slug ${TARGET_SLUG} is already owned by ${target_owner}, but the authenticated publisher is ${publisher_handle}. Transfer or alias the registry slug before publishing."
exit 1
fi
echo "ClawHub slug ownership guard passed: ${TARGET_SLUG} owned by authenticated publisher ${publisher_handle}."
+4 -4
View File
@@ -43,14 +43,14 @@ export function resolveClawHubSlug({ name, platforms = [] }) {
throw new Error(`Invalid skill name for ClawHub slug mapping: ${name}`);
}
if (name.startsWith("clawsec-")) {
return name;
}
if (EXPLICIT_SLUGS.has(name)) {
return EXPLICIT_SLUGS.get(name);
}
if (name.startsWith("clawsec-")) {
return name;
}
if (PLATFORM_KEYS.some((platform) => name.startsWith(`${platform}-`))) {
return `clawsec-${name}`;
}
@@ -143,6 +143,8 @@ function changedSkillDirs({ root, base, head }) {
`${base}...${head}`,
"--",
"skills/*/**",
":(exclude)skills/clawsec-feed/advisories/feed.json",
":(exclude)skills/clawsec-feed/advisories/feed.json.sig",
":(exclude)skills/*/test/**",
":(exclude)skills/*/tests/**",
],
+88 -4
View File
@@ -3,12 +3,16 @@ import { readFile } from 'node:fs/promises';
const workflowPath = new URL('../.github/workflows/skill-release.yml', import.meta.url);
const ciWorkflowPath = new URL('../.github/workflows/ci.yml', import.meta.url);
const validateSkillInstallDocsPath = new URL('./ci/validate_skill_install_docs.mjs', import.meta.url);
const installClawhubCliPath = new URL('./ci/install_clawhub_cli.sh', import.meta.url);
const patchClawhubPayloadPath = new URL('./ci/patch_clawhub_publish_payload.mjs', import.meta.url);
const guardClawhubSlugOwnerPath = new URL('./ci/guard_clawhub_slug_owner.sh', import.meta.url);
const workflow = await readFile(workflowPath, 'utf8');
const ciWorkflow = await readFile(ciWorkflowPath, 'utf8');
const validateSkillInstallDocs = await readFile(validateSkillInstallDocsPath, 'utf8');
const installClawhubCli = await readFile(installClawhubCliPath, 'utf8');
const patchClawhubPayload = await readFile(patchClawhubPayloadPath, 'utf8');
const guardClawhubSlugOwner = await readFile(guardClawhubSlugOwnerPath, 'utf8');
assert.match(
workflow,
@@ -16,6 +20,16 @@ assert.match(
'Skill release workflow must run when any skill package file changes',
);
for (const generatedFeedPath of [
'skills/clawsec-feed/advisories/feed.json',
'skills/clawsec-feed/advisories/feed.json.sig',
]) {
assert.ok(
workflow.includes(` - '!${generatedFeedPath}'`),
`Skill release workflow must not run for generated advisory mirror-only changes to ${generatedFeedPath}`,
);
}
assert.match(
workflow,
/pull_request:[\s\S]*paths:[\s\S]*- '\.github\/workflows\/skill-release\.yml'[\s\S]*- 'scripts\/ci\/\*\*'/,
@@ -34,10 +48,20 @@ assert.ok(
assert.match(
workflow,
/git diff --name-only "\$\{BASE_SHA\}\.\.\.\$\{HEAD_SHA\}" --[\s\S]*'skills\/\*\/\*\*'[\s\S]*':\(exclude\)skills\/\*\/test\/\*\*'[\s\S]*':\(exclude\)skills\/\*\/tests\/\*\*'/,
'Skill release validation must ignore test-only skill changes while inspecting release-relevant skill files',
/git diff --name-only "\$\{BASE_SHA\}\.\.\.\$\{HEAD_SHA\}" --[\s\S]*'skills\/\*\/\*\*'[\s\S]*':\(exclude\)skills\/clawsec-feed\/advisories\/feed\.json'[\s\S]*':\(exclude\)skills\/clawsec-feed\/advisories\/feed\.json\.sig'[\s\S]*':\(exclude\)skills\/\*\/test\/\*\*'[\s\S]*':\(exclude\)skills\/\*\/tests\/\*\*'/,
'Skill release validation must ignore generated clawsec-feed advisory mirror and test-only changes while inspecting release-relevant skill files',
);
for (const generatedFeedPath of [
':(exclude)skills/clawsec-feed/advisories/feed.json',
':(exclude)skills/clawsec-feed/advisories/feed.json.sig',
]) {
assert.ok(
validateSkillInstallDocs.includes(`"${generatedFeedPath}"`),
`Install-doc validation changed-skill detection must ignore generated advisory mirror-only changes to ${generatedFeedPath}`,
);
}
assert.ok(
workflow.includes('name = tolower($NF)')
&& workflow.includes('name ~ /^(test|spec)[_-]/')
@@ -137,8 +161,8 @@ assert.match(
assert.match(
workflow,
/Run release dry-run for changed skills[\s\S]*git diff --name-only "\$\{BASE_SHA\}\.\.\.\$\{HEAD_SHA\}" --[\s\S]*'skills\/\*\/\*\*'[\s\S]*':\(exclude\)skills\/\*\/test\/\*\*'[\s\S]*':\(exclude\)skills\/\*\/tests\/\*\*'/,
'PR dry-run SkillSpector scan must run when any release-relevant skill package file changes',
/Run release dry-run for changed skills[\s\S]*git diff --name-only "\$\{BASE_SHA\}\.\.\.\$\{HEAD_SHA\}" --[\s\S]*'skills\/\*\/\*\*'[\s\S]*':\(exclude\)skills\/clawsec-feed\/advisories\/feed\.json'[\s\S]*':\(exclude\)skills\/clawsec-feed\/advisories\/feed\.json\.sig'[\s\S]*':\(exclude\)skills\/\*\/test\/\*\*'[\s\S]*':\(exclude\)skills\/\*\/tests\/\*\*'/,
'PR dry-run SkillSpector scan must run when any release-relevant skill package file changes except generated advisory mirror files',
);
assert.ok(
@@ -319,6 +343,12 @@ assert.match(
'ClawHub publish must use the resolved ClawHub slug',
);
assert.match(
workflow,
/clawhub publish "\$SKILL_PATH"[\s\S]*--slug "\$CLAWHUB_SLUG"/,
'ClawHub publish must use the resolved ClawHub slug',
);
assert.equal(
workflow.match(/bash scripts\/ci\/install_clawhub_cli\.sh/g)?.length,
2,
@@ -331,6 +361,12 @@ assert.equal(
'ClawHub publish and republish jobs must share the same payload patch helper',
);
assert.equal(
workflow.match(/bash scripts\/ci\/guard_clawhub_slug_owner\.sh/g)?.length,
2,
'ClawHub publish and republish jobs must guard mapped slug ownership before publishing',
);
assert.doesNotMatch(
workflow,
/npm ci --prefix \.github\/clawhub-cli/,
@@ -381,6 +417,54 @@ assert.match(
'ClawHub payload patch helper must preserve the acceptLicenseTerms workaround',
);
assert.match(
patchClawhubPayload,
/Already patched/,
'ClawHub payload patch helper must stay idempotent when the pinned CLI already includes acceptLicenseTerms',
);
assert.match(
guardClawhubSlugOwner,
/api_get "\/api\/v1\/whoami" "\$whoami_json"/,
'ClawHub slug ownership guard must verify the authenticated publisher through the ClawHub API',
);
assert.match(
guardClawhubSlugOwner,
/api_get "\/api\/v1\/skills\/\$\{TARGET_SLUG\}" "\$target_json"/,
'ClawHub slug ownership guard must inspect the resolved publish slug through the ClawHub API',
);
assert.match(
guardClawhubSlugOwner,
/\[ "\$target_status" = "404" \]/,
'ClawHub slug ownership guard must treat HTTP 404 as the structured unpublished-slug signal',
);
assert.match(
guardClawhubSlugOwner,
/\[ "\$target_owner" != "\$publisher_handle" \]/,
'ClawHub slug ownership guard must reject slugs owned by a different authenticated registry publisher',
);
assert.doesNotMatch(
guardClawhubSlugOwner,
/SOURCE_SLUG|source_owner|grep -Eqi[\s\S]*Skill not found/,
'ClawHub slug ownership guard must not inspect raw source names or depend on stderr wording',
);
assert.match(
workflow,
/SITE=\$\{CLAWHUB_SITE:-https:\/\/clawhub\.ai\}[\s\S]*REGISTRY=\$\{CLAWHUB_REGISTRY:-\$SITE\}[\s\S]*export CLAWHUB_CONFIG_PATH="\$HOME\/\.clawhub-ci\/config\.json"[\s\S]*export CLAWHUB_SITE="\$SITE"[\s\S]*export CLAWHUB_REGISTRY="\$REGISTRY"[\s\S]*bash scripts\/ci\/guard_clawhub_slug_owner\.sh[\s\S]*\$\{\{ needs\.release-tag\.outputs\.clawhub_slug \}\}/,
'ClawHub publish job must guard the resolved publish slug with the authenticated ClawHub config path',
);
assert.match(
workflow,
/SITE=\$\{CLAWHUB_SITE:-https:\/\/clawhub\.ai\}[\s\S]*REGISTRY=\$\{CLAWHUB_REGISTRY:-\$SITE\}[\s\S]*export CLAWHUB_CONFIG_PATH="\$HOME\/\.clawhub-ci\/config\.json"[\s\S]*export CLAWHUB_SITE="\$SITE"[\s\S]*export CLAWHUB_REGISTRY="\$REGISTRY"[\s\S]*bash scripts\/ci\/guard_clawhub_slug_owner\.sh[\s\S]*\$\{\{ steps\.publishable\.outputs\.clawhub_slug \}\}/,
'ClawHub republish job must guard the resolved publish slug with the authenticated ClawHub config path',
);
assert.doesNotMatch(
workflow,
/clawhub inspect "\$SKILL_NAME" --version "\$VERSION" --json/,
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1 +1 @@
jPrlTYwicRwoQgTs5Rk3Y3g6Lz78jNRs9ZNf0R09M4jkJokZENxfvhvHphI9MH4u+7wv0sFZ+yZbQtJ42y+hCQ==
K19pfVfv7qB1cqFPFTu69+sKLHIMIrmS7GeK4BZIlHzRvrLfRUuq/KftC8/CIWwvixVlBBm/iZlyfJ5sutoDDw==