Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 76 additions & 0 deletions .github/workflows/publish-cli.yml
Original file line number Diff line number Diff line change
Expand Up @@ -375,3 +375,79 @@ jobs:
chmod +x "$TMP_DIR/volcano-linux-amd64"
"$TMP_DIR/volcano-linux-amd64" --help
"$TMP_DIR/volcano-linux-amd64" --version

publish-npm:
name: Publish npm package
runs-on: ubuntu-latest # Trusted publishing requires GitHub-hosted runners
needs: [resolve-release, publish-github-release]
# Publish to npm only for stable releases (skip main/nightly prereleases).
# This job runs npm publish directly in the release-triggered run, so npm's
# OIDC trusted publisher must be configured with this workflow's filename
# (publish-cli.yml). Dispatched/reusable workflows are not supported.
if: needs.resolve-release.outputs.prerelease == 'false'
permissions:
contents: read
id-token: write # REQUIRED for npm trusted publishing (OIDC)
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: "24"
registry-url: "https://registry.npmjs.org"

# Trusted publishing requires npm >= 11.5.1; pin to the npm 11 line for
# reproducibility rather than tracking npm@latest across major versions.
- name: Upgrade npm
run: npm install -g npm@11

- name: Resolve npm version
id: npm_version
env:
CLI_VERSION: ${{ needs.resolve-release.outputs.cli_version }}
run: |
set -euo pipefail
VERSION="${CLI_VERSION#v}"
if [[ ! "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "Refusing to publish non-stable version to npm: ${CLI_VERSION}"
exit 1
fi
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"

- name: Set package version
run: |
npm version "${{ steps.npm_version.outputs.version }}" \
--no-git-tag-version --allow-same-version

- name: Verify release assets exist
env:
VERSION: ${{ steps.npm_version.outputs.version }}
run: |
set -euo pipefail
base="https://github.com/${GITHUB_REPOSITORY}/releases/download/v${VERSION}"
# Ranged GET (first byte) confirms each asset is actually downloadable,
# which is what the package's postinstall does.
for target in linux-amd64 linux-arm64 macos-amd64 macos-arm64 windows-amd64; do
asset="volcano-${target}"
if [ "$target" = "windows-amd64" ]; then
asset="${asset}.exe"
fi
echo "Checking ${base}/${asset}"
curl -fsSL --retry 6 --retry-delay 15 --retry-all-errors -r 0-0 -o /dev/null "${base}/${asset}"
done
echo "Checking ${base}/SHA256SUMS"
curl -fsSL --retry 6 --retry-delay 15 --retry-all-errors -r 0-0 -o /dev/null "${base}/SHA256SUMS"

# OIDC trusted publishing: npm detects the id-token and authenticates
# automatically; provenance is generated for public repos. No NPM_TOKEN.
# VOLCANO_SKIP_DOWNLOAD stops the postinstall fetching a binary in CI.
#
# BOOTSTRAP: until an npm admin does the first manual publish and sets the
# OIDC trusted publisher (workflow file: publish-cli.yml), this step fails
# with ENEEDAUTH. continue-on-error keeps the release green meanwhile --
# REMOVE it once trusted publishing is live so real failures surface.
- name: Publish to npm
continue-on-error: true
env:
VOLCANO_SKIP_DOWNLOAD: "1"
run: npm publish
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
/volcano
/dist/
# Downloaded platform binaries fetched by the npm postinstall (keep bin/volcano.js)
/bin/volcano-*
node_modules/
/.env
/.env.local
/.env.*
Expand Down
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,18 @@ Install the latest published release:
curl -fsSL https://github.com/Kong/volcano-cli/releases/latest/download/install.sh | bash
```

Or install from npm:

```bash
npm install -g @kong/volcano-cli
volcano --help
```

The npm package is a thin wrapper: its `postinstall` step downloads the
platform-specific binary from the matching GitHub Release and verifies it
against that release's `SHA256SUMS`. Set `VOLCANO_SKIP_DOWNLOAD=1` to skip the
download (it is fetched on first run instead).

Build from source:

```bash
Expand Down
56 changes: 56 additions & 0 deletions bin/volcano.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#!/usr/bin/env node
'use strict';

// Launcher shim: exec the platform-specific Volcano CLI binary, forwarding all
// arguments, stdio, and the exit code. If the binary is missing (e.g. install
// ran with --ignore-scripts, or the postinstall download failed) it is fetched
// and verified on demand.

const fs = require('fs');
const { spawn } = require('child_process');
const { binaryPath, ensureBinary } = require('../scripts/npm/download.js');

async function resolveBinary() {
try {
const bin = binaryPath();
if (fs.existsSync(bin)) {
return bin;
}
return await ensureBinary();
} catch (err) {
// Covers both download failures and unsupported platforms: binaryPath() ->
// resolveTarget() throws for e.g. Windows arm64, which passes the
// package.json os/cpu gate but has no published binary.
console.error(`volcano: could not obtain the CLI binary: ${err.message}`);
console.error(
'Install it manually from https://github.com/Kong/volcano-cli/releases ' +
'or re-install the package.'
);
process.exit(1);
}
}

async function main() {
const bin = await resolveBinary();
const child = spawn(bin, process.argv.slice(2), { stdio: 'inherit' });

child.on('error', (err) => {
console.error(`volcano: failed to launch binary: ${err.message}`);
process.exit(1);
});

child.on('exit', (code, signal) => {
if (signal) {
// Re-raise the signal so the parent reflects the child's termination.
process.kill(process.pid, signal);
return;
}
process.exit(code == null ? 1 : code);
});
}

main().catch((err) => {
// Last-resort guard so failures never surface as an unhandled rejection.
console.error(`volcano: ${err.message}`);
process.exit(1);
});
46 changes: 46 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"name": "@kong/volcano-cli",
"version": "0.0.0",
"description": "Command-line client for Volcano, Kong's hosting platform.",
"keywords": [
"volcano",
"kong",
"cli"
],
"homepage": "https://github.com/Kong/volcano-cli#readme",
"bugs": {
"url": "https://github.com/Kong/volcano-cli/issues"
},
"license": "Apache-2.0",
"type": "commonjs",
"repository": {
"type": "git",
"url": "git+https://github.com/Kong/volcano-cli.git"
},
"bin": {
"volcano": "bin/volcano.js"
},
"files": [
"bin/volcano.js",
"scripts/npm/"
],
"scripts": {
"postinstall": "node scripts/npm/install.js",
"prepublishOnly": "node -e \"if (require('./package.json').version === '0.0.0') { console.error('Refusing to publish version 0.0.0; set the real version first (npm version <x.y.z>).'); process.exit(1); }\""
},
"engines": {
"node": ">=18"
},
"os": [
"linux",
"darwin",
"win32"
],
"cpu": [
"x64",
"arm64"
],
"publishConfig": {
"access": "public"
}
}
Loading
Loading