Skip to content

Commit 55addfd

Browse files
Refactor release into separate child workflows with isolated deployment environments (#45)
* Refactor release into multi-workflow architecture Split the monolithic release.yml into dedicated child workflows (release-tag, release-npm, release-codeql) callable independently via workflow_dispatch. Add environment protection gates to all three publish workflows. Isolate CodeQL pack operations from npm publish to prevent .codeql/ and .qlx contamination. Use npm ci instead of npm install in all workflows except release-tag. Also add .codeql exclusion to server/.npmignore as defense-in-depth. * Publish to npmjs.org with OIDC trusted publishing - Rename package to unscoped `codeql-development-mcp-server` - Switch from GitHub Packages to public npmjs.org registry - Use OIDC trusted publishing (no tokens, auto-provenance) - Make release.yml the sole dispatch entry point with configurable publish_npm, publish_codeql_packs, and create_github_release flags - Remove workflow_dispatch from child workflows (release-npm, release-codeql, release-tag) to comply with OIDC validation - Fix release-tag.yml: wire tag_sha output to final-sha step, guard git add -A against staging CodeQL artifacts - Add setup-packs.sh script (shipped in npm package) to install CodeQL pack dependencies from bundled lock files - Update all docs, tests, and SKILL.md references * Update .gitignore for .codeql/ and *.qlx * Release v2.24.1-prerelease: update versions to 2.24.1-prerelease * fixresolve npm publish warnings & prerelease error - Handle prerelease versions in release-npm workflow by detecting semver prerelease identifiers and passing --tag to npm publish (e.g., 2.24.1-beta.1 publishes with --tag beta) - Remove ./ prefix from bin paths in server/package.json to eliminate "script name was invalid and removed" warnings - Normalize repository.url to git+https:// format per npm conventions * Fixes for PR review comments * Fix release-codeql.yml workflow conditionals * Release v2.24.1-beta: update versions to 2.24.1-beta * Release v2.24.1: update versions to 2.24.1 * resolve npm symlinks in entry guard & fix MCP IO The npm/npx installation path was broken by two issues: 1. The import.meta.url entry guard used resolve() which does not follow symlinks. Global npm installs create a symlink (e.g. /opt/homebrew/bin/… → node_modules/.../dist/…), so the paths never matched and main() was never called. The server exited silently. Fix: use realpathSync(resolve(…)) to follow symlinks. 2. dotenv v17 prints a banner to stdout by default, which corrupts the MCP stdio JSON-RPC channel. Fix: pass quiet: true to dotenv.config(). * Release v2.24.1-prerelease: update versions to 2.24.1-prerelease * Release v2.24.1-rc1: update versions to 2.24.1-rc1 * Update client and server README.md docs Updates the user-facing server/README.md to be a useful for external use, where the server/README.md doc is now used as the home paga for published npmjs.com packages for codeql-development-mcp-server. * Release v2.24.1: update versions to 2.24.1 --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
1 parent 2a81e2b commit 55addfd

File tree

20 files changed

+955
-307
lines changed

20 files changed

+955
-307
lines changed

.github/skills/validate-ql-mcp-server-tools-queries/SKILL.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ When the STDIO transport receives an immediate EOF on stdin (e.g., via `</dev/nu
336336

337337
### npm Package Includes Tool Query Source Packs
338338

339-
The published npm package (`@advanced-security/codeql-development-mcp-server`) bundles all tool query source packs under `ql/*/tools/src/`. These are the same `.ql`, `.qll`, `.md`, `codeql-pack.yml`, and `codeql-pack.lock.yml` files — but **never** compiled `.qlx` bytecode (excluded by `server/.npmignore`).
339+
The published npm package (`codeql-development-mcp-server`) bundles all tool query source packs under `ql/*/tools/src/`. These are the same `.ql`, `.qll`, `.md`, `codeql-pack.yml`, and `codeql-pack.lock.yml` files — but **never** compiled `.qlx` bytecode (excluded by `server/.npmignore`).
340340

341341
## Success Criteria
342342

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
name: Release CodeQL - Publish and Bundle CodeQL Packs
2+
3+
on:
4+
workflow_call:
5+
inputs:
6+
publish_codeql_packs:
7+
default: true
8+
description: 'Publish CodeQL tool query packs to GHCR. Disable for pre-release or re-run scenarios where packs already exist.'
9+
required: false
10+
type: boolean
11+
version:
12+
description: 'Release version tag (e.g., vX.Y.Z). Must start with "v".'
13+
required: true
14+
type: string
15+
outputs:
16+
release_name:
17+
description: 'The release name without "v" prefix (e.g., X.Y.Z)'
18+
value: ${{ jobs.publish-codeql-packs.outputs.release_name }}
19+
version:
20+
description: 'The full version string with "v" prefix (e.g., vX.Y.Z)'
21+
value: ${{ jobs.publish-codeql-packs.outputs.version }}
22+
23+
# Note: This workflow is called exclusively via workflow_call from release.yml.
24+
# It does NOT have a workflow_dispatch trigger to keep release.yml as the single
25+
# entry point for all release operations. To re-publish CodeQL packs standalone,
26+
# use workflow_dispatch on release.yml with publish_npm=false and
27+
# create_github_release=false.
28+
29+
permissions:
30+
contents: read
31+
32+
jobs:
33+
publish-codeql-packs:
34+
name: Publish and Bundle CodeQL Packs
35+
runs-on: ubuntu-latest
36+
37+
environment: release-codeql
38+
39+
permissions:
40+
contents: read
41+
packages: write
42+
43+
outputs:
44+
release_name: ${{ steps.version.outputs.release_name }}
45+
version: ${{ steps.version.outputs.version }}
46+
47+
steps:
48+
- name: CodeQL - Validate and parse version
49+
id: version
50+
run: |
51+
VERSION="${{ inputs.version }}"
52+
if [[ ! "${VERSION}" =~ ^v ]]; then
53+
echo "::error::Version '${VERSION}' must start with 'v'"
54+
exit 1
55+
fi
56+
echo "version=${VERSION}" >> $GITHUB_OUTPUT
57+
echo "release_name=${VERSION#v}" >> $GITHUB_OUTPUT
58+
59+
- name: CodeQL - Checkout tag
60+
uses: actions/checkout@v6
61+
with:
62+
ref: refs/tags/${{ steps.version.outputs.version }}
63+
64+
- name: CodeQL - Setup CodeQL environment
65+
uses: ./.github/actions/setup-codeql-environment
66+
with:
67+
add-to-path: true
68+
install-language-runtimes: false
69+
70+
- name: CodeQL - Install CodeQL pack dependencies
71+
run: server/scripts/install-packs.sh
72+
73+
- name: CodeQL - Validate version consistency
74+
run: |
75+
RELEASE_NAME="${{ steps.version.outputs.release_name }}"
76+
echo "Validating all version-bearing files match ${RELEASE_NAME}..."
77+
./server/scripts/update-release-version.sh --check "${RELEASE_NAME}"
78+
79+
- name: CodeQL - Publish CodeQL tool query packs
80+
if: inputs.publish_codeql_packs
81+
env:
82+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
83+
run: |
84+
LANGUAGES="actions cpp csharp go java javascript python ruby swift"
85+
echo "Publishing CodeQL tool query packs..."
86+
for lang in ${LANGUAGES}; do
87+
PACK_DIR="server/ql/${lang}/tools/src"
88+
if [ -d "${PACK_DIR}" ]; then
89+
echo "📦 Publishing ${PACK_DIR}..."
90+
codeql pack publish --threads=-1 -- "${PACK_DIR}"
91+
echo "✅ Published ${lang} tool query pack"
92+
else
93+
echo "⚠️ Skipping ${lang}: ${PACK_DIR} not found"
94+
fi
95+
done
96+
97+
- name: CodeQL - Skip CodeQL tool query pack publishing
98+
if: '!inputs.publish_codeql_packs'
99+
run: echo "⏭️ CodeQL tool query pack publishing disabled via workflow input"
100+
101+
- name: CodeQL - Bundle CodeQL tool query packs
102+
run: |
103+
mkdir -p dist-packs
104+
LANGUAGES="actions cpp csharp go java javascript python ruby swift"
105+
echo "Bundling CodeQL tool query packs..."
106+
for lang in ${LANGUAGES}; do
107+
PACK_DIR="server/ql/${lang}/tools/src"
108+
if [ -d "${PACK_DIR}" ]; then
109+
PACK_NAME="ql-mcp-${lang}-tools-src"
110+
OUTPUT="dist-packs/${PACK_NAME}.tar.gz"
111+
echo "📦 Bundling ${PACK_DIR} -> ${OUTPUT}..."
112+
codeql pack bundle --threads=-1 --output="${OUTPUT}" -- "${PACK_DIR}"
113+
echo "✅ Bundled ${PACK_NAME}"
114+
fi
115+
done
116+
echo "Bundled packs:"
117+
ls -lh dist-packs/
118+
119+
- name: CodeQL - Upload CodeQL pack artifacts
120+
uses: actions/upload-artifact@v6
121+
with:
122+
name: codeql-tool-query-packs-${{ steps.version.outputs.version }}
123+
path: dist-packs/*.tar.gz
124+
125+
- name: CodeQL - Summary
126+
run: |
127+
VERSION="${{ steps.version.outputs.version }}"
128+
RELEASE_NAME="${{ steps.version.outputs.release_name }}"
129+
echo "## CodeQL Packs Summary" >> $GITHUB_STEP_SUMMARY
130+
echo "" >> $GITHUB_STEP_SUMMARY
131+
if [ "${{ inputs.publish_codeql_packs }}" == "true" ]; then
132+
echo "✅ Published CodeQL tool query packs to GHCR" >> $GITHUB_STEP_SUMMARY
133+
else
134+
echo "⏭️ CodeQL tool query pack publishing was disabled" >> $GITHUB_STEP_SUMMARY
135+
fi
136+
echo "✅ Bundled CodeQL tool query packs as artifacts" >> $GITHUB_STEP_SUMMARY
137+
echo "" >> $GITHUB_STEP_SUMMARY
138+
echo "### Published CodeQL Packs" >> $GITHUB_STEP_SUMMARY
139+
echo "| Pack | Version |" >> $GITHUB_STEP_SUMMARY
140+
echo "| ---- | ------- |" >> $GITHUB_STEP_SUMMARY
141+
for lang in actions cpp csharp go java javascript python ruby swift; do
142+
echo "| \`advanced-security/ql-mcp-${lang}-tools-src\` | ${RELEASE_NAME} |" >> $GITHUB_STEP_SUMMARY
143+
done

.github/workflows/release-npm.yml

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
name: Release npm - Publish npm Package
2+
3+
on:
4+
workflow_call:
5+
inputs:
6+
version:
7+
description: 'Release version tag (e.g., vX.Y.Z). Must start with "v".'
8+
required: true
9+
type: string
10+
outputs:
11+
release_name:
12+
description: 'The release name without "v" prefix (e.g., X.Y.Z)'
13+
value: ${{ jobs.publish-npm.outputs.release_name }}
14+
version:
15+
description: 'The full version string with "v" prefix (e.g., vX.Y.Z)'
16+
value: ${{ jobs.publish-npm.outputs.version }}
17+
18+
# Note: This workflow is called exclusively via workflow_call from release.yml.
19+
# It does NOT have a workflow_dispatch trigger because npm Trusted Publishing
20+
# validates the *calling* workflow filename for OIDC. The trusted publisher on
21+
# npmjs.com is configured with workflow "release.yml" and environment
22+
# "release-npm". Direct dispatch would present "release-npm.yml" as the workflow
23+
# name, causing OIDC authentication to fail. To re-publish the npm package
24+
# standalone, use workflow_dispatch on release.yml instead.
25+
26+
permissions:
27+
contents: read
28+
29+
jobs:
30+
publish-npm:
31+
name: Publish npm Package
32+
runs-on: ubuntu-latest
33+
34+
environment: release-npm
35+
36+
permissions:
37+
contents: read
38+
id-token: write
39+
40+
outputs:
41+
release_name: ${{ steps.version.outputs.release_name }}
42+
version: ${{ steps.version.outputs.version }}
43+
44+
steps:
45+
- name: npm - Validate and parse version
46+
id: version
47+
run: |
48+
VERSION="${{ inputs.version }}"
49+
if [[ ! "${VERSION}" =~ ^v ]]; then
50+
echo "::error::Version '${VERSION}' must start with 'v'"
51+
exit 1
52+
fi
53+
echo "version=${VERSION}" >> $GITHUB_OUTPUT
54+
echo "release_name=${VERSION#v}" >> $GITHUB_OUTPUT
55+
56+
- name: npm - Checkout tag
57+
uses: actions/checkout@v6
58+
with:
59+
ref: refs/tags/${{ steps.version.outputs.version }}
60+
61+
- name: npm - Setup Node.js
62+
uses: actions/setup-node@v6
63+
with:
64+
cache: 'npm'
65+
node-version-file: '.node-version'
66+
registry-url: 'https://registry.npmjs.org'
67+
68+
- name: npm - Install dependencies
69+
run: npm ci --include=optional
70+
71+
- name: npm - Build server
72+
run: npm run build -w server
73+
74+
- name: npm - Validate version consistency
75+
run: |
76+
RELEASE_NAME="${{ steps.version.outputs.release_name }}"
77+
echo "Validating all version-bearing files match ${RELEASE_NAME}..."
78+
./server/scripts/update-release-version.sh --check "${RELEASE_NAME}"
79+
80+
- name: npm - Publish npm package
81+
working-directory: server
82+
run: |
83+
RELEASE_NAME="${{ steps.version.outputs.release_name }}"
84+
echo "Publishing codeql-development-mcp-server@${RELEASE_NAME} to npmjs.org via OIDC trusted publishing..."
85+
86+
# Prerelease versions (containing a hyphen) must use a dist-tag other
87+
# than "latest" — npm enforces this to prevent prereleases from being
88+
# installed by default.
89+
if [[ "${RELEASE_NAME}" == *-* ]]; then
90+
# Extract the prerelease identifier before any dot
91+
# e.g., "2.24.1-prerelease" -> "prerelease", "2.24.1-beta.1" -> "beta"
92+
PRERELEASE_ID="${RELEASE_NAME#*-}"
93+
PRERELEASE_ID="${PRERELEASE_ID%%.*}"
94+
echo "Detected prerelease version — publishing with --tag ${PRERELEASE_ID}"
95+
npm publish --tag "${PRERELEASE_ID}"
96+
else
97+
npm publish
98+
fi
99+
echo "✅ Published npm package to npmjs.org (with provenance)"
100+
101+
- name: npm - Upload release build artifact
102+
uses: actions/upload-artifact@v6
103+
with:
104+
name: release-build-${{ steps.version.outputs.version }}
105+
path: |
106+
.node-version
107+
server/dist/
108+
server/ql/
109+
server/package.json
110+
server/scripts/setup-packs.sh
111+
README.md
112+
LICENSE
113+
docs/
114+
115+
- name: npm - Summary
116+
run: |
117+
VERSION="${{ steps.version.outputs.version }}"
118+
RELEASE_NAME="${{ steps.version.outputs.release_name }}"
119+
echo "## npm Package Summary" >> $GITHUB_STEP_SUMMARY
120+
echo "" >> $GITHUB_STEP_SUMMARY
121+
echo "| Detail | Value |" >> $GITHUB_STEP_SUMMARY
122+
echo "| ------ | ----- |" >> $GITHUB_STEP_SUMMARY
123+
echo "| Package | \`codeql-development-mcp-server\` |" >> $GITHUB_STEP_SUMMARY
124+
echo "| Version | ${RELEASE_NAME} |" >> $GITHUB_STEP_SUMMARY
125+
echo "| Registry | npmjs.org |" >> $GITHUB_STEP_SUMMARY
126+
echo "| Tag | ${VERSION} |" >> $GITHUB_STEP_SUMMARY

0 commit comments

Comments
 (0)