fix(skill-release): authenticate pinned clawhub install

This commit is contained in:
David Abutbul
2026-06-15 12:33:13 +03:00
parent 8bc61144c9
commit c14ccea355
4 changed files with 145 additions and 84 deletions
+12 -84
View File
@@ -1685,6 +1685,10 @@ jobs:
contents: read
env:
CLAWHUB_TOKEN: ${{ secrets.CLAWHUB_TOKEN }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_SESSION_TOKEN: ${{ secrets.AWS_SESSION_TOKEN }}
AWS_REGION: eu-north-1
steps:
- name: Check if publishable
if: needs.release-tag.outputs.publish_clawhub != 'true'
@@ -1704,52 +1708,12 @@ jobs:
- name: Install clawhub CLI
if: needs.release-tag.outputs.publish_clawhub == 'true' && env.CLAWHUB_TOKEN != ''
run: |
npm ci --prefix .github/clawhub-cli
echo "${GITHUB_WORKSPACE}/.github/clawhub-cli/node_modules/.bin" >> "$GITHUB_PATH"
run: bash scripts/ci/install_clawhub_cli.sh
- name: Patch clawhub publish payload workaround
# Temporary: clawhub@0.7.0 publish payload is missing acceptLicenseTerms.
if: needs.release-tag.outputs.publish_clawhub == 'true' && env.CLAWHUB_TOKEN != ''
run: |
node <<'NODE'
const fs = require("node:fs");
const path = require("node:path");
const npmRoot = path.join(process.env.GITHUB_WORKSPACE, ".github", "clawhub-cli", "node_modules");
const publishScriptPath = path.join(
npmRoot,
"clawhub",
"dist",
"cli",
"commands",
"publish.js"
);
if (!fs.existsSync(publishScriptPath)) {
throw new Error(`clawhub publish script not found: ${publishScriptPath}`);
}
const original = fs.readFileSync(publishScriptPath, "utf8");
if (original.includes("acceptLicenseTerms: true")) {
console.log(`[patch-clawhub] Already patched: ${publishScriptPath}`);
process.exit(0);
}
const payloadPattern = /changelog,\r?\n(\s*)tags,/;
if (!payloadPattern.test(original)) {
throw new Error(
`[patch-clawhub] Could not find expected publish payload pattern in ${publishScriptPath}`
);
}
const patched = original.replace(
payloadPattern,
(_, indent) => `changelog,\n${indent}acceptLicenseTerms: true,\n${indent}tags,`
);
fs.writeFileSync(publishScriptPath, patched, "utf8");
console.log(`[patch-clawhub] Patched: ${publishScriptPath}`);
NODE
run: node scripts/ci/patch_clawhub_publish_payload.mjs
- name: Login to ClawHub
if: needs.release-tag.outputs.publish_clawhub == 'true' && env.CLAWHUB_TOKEN != ''
@@ -1831,6 +1795,10 @@ jobs:
contents: read
env:
CLAWHUB_TOKEN: ${{ secrets.CLAWHUB_TOKEN }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_SESSION_TOKEN: ${{ secrets.AWS_SESSION_TOKEN }}
AWS_REGION: eu-north-1
steps:
- name: Parse tag
id: parse
@@ -1895,51 +1863,11 @@ jobs:
run: node scripts/ci/validate_skill_install_docs.mjs --skills "${{ steps.parse.outputs.skill_path }}"
- name: Install clawhub CLI
run: |
npm ci --prefix .github/clawhub-cli
echo "${GITHUB_WORKSPACE}/.github/clawhub-cli/node_modules/.bin" >> "$GITHUB_PATH"
run: bash scripts/ci/install_clawhub_cli.sh
- name: Patch clawhub publish payload workaround
# Temporary: clawhub@0.7.0 publish payload is missing acceptLicenseTerms.
run: |
node <<'NODE'
const fs = require("node:fs");
const path = require("node:path");
const npmRoot = path.join(process.env.GITHUB_WORKSPACE, ".github", "clawhub-cli", "node_modules");
const publishScriptPath = path.join(
npmRoot,
"clawhub",
"dist",
"cli",
"commands",
"publish.js"
);
if (!fs.existsSync(publishScriptPath)) {
throw new Error(`clawhub publish script not found: ${publishScriptPath}`);
}
const original = fs.readFileSync(publishScriptPath, "utf8");
if (original.includes("acceptLicenseTerms: true")) {
console.log(`[patch-clawhub] Already patched: ${publishScriptPath}`);
process.exit(0);
}
const payloadPattern = /changelog,\r?\n(\s*)tags,/;
if (!payloadPattern.test(original)) {
throw new Error(
`[patch-clawhub] Could not find expected publish payload pattern in ${publishScriptPath}`
);
}
const patched = original.replace(
payloadPattern,
(_, indent) => `changelog,\n${indent}acceptLicenseTerms: true,\n${indent}tags,`
);
fs.writeFileSync(publishScriptPath, patched, "utf8");
console.log(`[patch-clawhub] Patched: ${publishScriptPath}`);
NODE
run: node scripts/ci/patch_clawhub_publish_payload.mjs
- name: Login to ClawHub
run: |
+32
View File
@@ -0,0 +1,32 @@
#!/usr/bin/env bash
set -euo pipefail
CLI_PREFIX="${CLAWHUB_CLI_PREFIX:-.github/clawhub-cli}"
CODEARTIFACT_DOMAIN="${CODEARTIFACT_DOMAIN:-prompt-security}"
CODEARTIFACT_DOMAIN_OWNER="${CODEARTIFACT_DOMAIN_OWNER:-443370709039}"
CODEARTIFACT_REPOSITORY="${CODEARTIFACT_REPOSITORY:-npm-proxy}"
AWS_REGION="${AWS_REGION:-${AWS_DEFAULT_REGION:-eu-north-1}}"
if ! command -v aws >/dev/null 2>&1; then
echo "::error::aws CLI is required to authenticate npm against CodeArtifact"
exit 1
fi
if ! aws sts get-caller-identity >/dev/null 2>&1; then
echo "::error::AWS credentials are required before installing the CodeArtifact-pinned clawhub CLI"
exit 1
fi
aws codeartifact login \
--tool npm \
--domain "$CODEARTIFACT_DOMAIN" \
--domain-owner "$CODEARTIFACT_DOMAIN_OWNER" \
--repository "$CODEARTIFACT_REPOSITORY" \
--region "$AWS_REGION"
npm ci --prefix "$CLI_PREFIX"
if [ -n "${GITHUB_PATH:-}" ]; then
workspace="${GITHUB_WORKSPACE:-$(pwd)}"
echo "${workspace}/${CLI_PREFIX}/node_modules/.bin" >> "$GITHUB_PATH"
fi
@@ -0,0 +1,35 @@
import fs from "node:fs";
import path from "node:path";
const workspace = process.env.GITHUB_WORKSPACE || process.cwd();
const npmRoot = path.join(workspace, ".github", "clawhub-cli", "node_modules");
const publishScriptPath = path.join(
npmRoot,
"clawhub",
"dist",
"cli",
"commands",
"publish.js",
);
if (!fs.existsSync(publishScriptPath)) {
throw new Error(`clawhub publish script not found: ${publishScriptPath}`);
}
const original = fs.readFileSync(publishScriptPath, "utf8");
if (original.includes("acceptLicenseTerms: true")) {
console.log(`[patch-clawhub] Already patched: ${publishScriptPath}`);
process.exit(0);
}
const payloadPattern = /changelog,\r?\n(\s*)tags,/;
if (!payloadPattern.test(original)) {
throw new Error(`[patch-clawhub] Could not find expected publish payload pattern in ${publishScriptPath}`);
}
const patched = original.replace(
payloadPattern,
(_, indent) => `changelog,\n${indent}acceptLicenseTerms: true,\n${indent}tags,`,
);
fs.writeFileSync(publishScriptPath, patched, "utf8");
console.log(`[patch-clawhub] Patched: ${publishScriptPath}`);
+66
View File
@@ -3,8 +3,12 @@ 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 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 workflow = await readFile(workflowPath, 'utf8');
const ciWorkflow = await readFile(ciWorkflowPath, 'utf8');
const installClawhubCli = await readFile(installClawhubCliPath, 'utf8');
const patchClawhubPayload = await readFile(patchClawhubPayloadPath, 'utf8');
assert.match(
workflow,
@@ -315,6 +319,68 @@ assert.match(
'ClawHub publish must use the resolved ClawHub slug',
);
assert.equal(
workflow.match(/bash scripts\/ci\/install_clawhub_cli\.sh/g)?.length,
2,
'ClawHub publish and republish jobs must share the same pinned CLI installer',
);
assert.equal(
workflow.match(/node scripts\/ci\/patch_clawhub_publish_payload\.mjs/g)?.length,
2,
'ClawHub publish and republish jobs must share the same payload patch helper',
);
assert.doesNotMatch(
workflow,
/npm ci --prefix \.github\/clawhub-cli/,
'ClawHub CLI installation must not be duplicated inline in the workflow',
);
assert.doesNotMatch(
workflow,
/node <<'NODE'[\s\S]*acceptLicenseTerms: true/,
'ClawHub payload patching must not be duplicated inline in the workflow',
);
for (const secret of ['AWS_ACCESS_KEY_ID', 'AWS_SECRET_ACCESS_KEY', 'AWS_SESSION_TOKEN']) {
assert.match(
workflow,
new RegExp(`${secret}: \\$\\{\\{ secrets\\.${secret} \\}\\}`),
`ClawHub jobs must expose ${secret} for CodeArtifact npm authentication`,
);
}
assert.match(
installClawhubCli,
/aws codeartifact login[\s\S]*--domain "\$CODEARTIFACT_DOMAIN"[\s\S]*--domain-owner "\$CODEARTIFACT_DOMAIN_OWNER"[\s\S]*--repository "\$CODEARTIFACT_REPOSITORY"[\s\S]*--region "\$AWS_REGION"/,
'ClawHub CLI installer must authenticate npm against CodeArtifact before npm ci',
);
assert.match(
installClawhubCli,
/npm ci --prefix "\$CLI_PREFIX"/,
'ClawHub CLI installer must install from the committed lockfile prefix',
);
assert.match(
installClawhubCli,
/"\$\{workspace\}\/\$\{CLI_PREFIX\}\/node_modules\/\.bin" >> "\$GITHUB_PATH"/,
'ClawHub CLI installer must expose the pinned clawhub binary on GITHUB_PATH',
);
assert.match(
patchClawhubPayload,
/const payloadPattern = \/changelog,\\r\?\\n\(\\s\*\)tags,\/;/,
'ClawHub payload patch helper must target the expected publish payload shape',
);
assert.match(
patchClawhubPayload,
/acceptLicenseTerms: true/,
'ClawHub payload patch helper must preserve the acceptLicenseTerms workaround',
);
assert.doesNotMatch(
workflow,
/clawhub inspect "\$SKILL_NAME" --version "\$VERSION" --json/,