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
14 changes: 13 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,20 @@ on:

permissions:
contents: write
id-token: write # Required for npm OIDC trusted publishing.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== release.yml context =="
if [ -f .github/workflows/release.yml ]; then
  nl -ba .github/workflows/release.yml | sed -n '1,140p'
else
  echo "missing .github/workflows/release.yml"
fi

echo
echo "== all workflow permissions snippets =="
python3 - <<'PY'
from pathlib import Path
import re
for p in sorted(Path('.github/workflows').glob('*')):
    if p.is_file() and p.suffix in {'.yml','.yaml'}:
        text=p.read_text()
        lines=text.splitlines()
        for i,l in enumerate(lines,1):
            if 'id-token:' in l or 'permissions:' in l:
                start=max(1,i-3); end=min(len(lines),i+8)
                print(f"-- {p}:{start}-{end} --")
                for n in range(start,end+1):
                    print(f"{n:4}: {lines[n-1]}")
PY

Repository: sommio/qwen-omni-mcp

Length of output: 224


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== release.yml context =="
if [ -f .github/workflows/release.yml ]; then
  nl -ba .github/workflows/release.yml | sed -n '1,140p'
else
  echo "missing .github/workflows/release.yml"
fi

echo
 echo "== all workflow permissions snippets =="
python3 - <<'PY'
from pathlib import Path
import re
for p in sorted(Path('.github/workflows').glob('*')):
    if p.is_file() and p.suffix in {'.yml','.yaml'}:
        text=p.read_text()
        lines=text.splitlines()
        for i,l in enumerate(lines,1):
            if 'id-token:' in l or 'permissions:' in l:
                start=max(1,i-3); end=min(len(lines),i+8)
                print(f"-- {p}:{start}-{end} --")
                for n in range(start,end+1):
                    print(f"{n:4}: {lines[n-1]}")
PY

Repository: sommio/qwen-omni-mcp

Length of output: 224


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== release.yml context =="
if [ -f .github/workflows/release.yml ]; then
  awk '{printf "%5d\t%s\n", NR, $0}' .github/workflows/release.yml | sed -n '1,160p'
else
  echo "missing .github/workflows/release.yml"
fi

echo
echo "== workflow permission snippets =="
python3 - <<'PY'
from pathlib import Path
for p in sorted(Path('.github/workflows').glob('*')):
    if not p.is_file() or p.suffix not in {'.yml','.yaml'}:
        continue
    text = p.read_text()
    lines = text.splitlines()
    hits = [i for i,l in enumerate(lines,1) if 'id-token:' in l or 'permissions:' in l]
    if not hits:
        continue
    print(f"-- {p} --")
    for n in hits:
        start=max(1,n-3); end=min(len(lines),n+8)
        for num in range(start,end+1):
            print(f"{num:4}: {lines[num-1]}")
PY

echo
echo "== structural parse with Python-safe yml-ish scan =="
python3 - <<'PY'
from pathlib import Path
import re
p = Path('.github/workflows/release.yml')
if p.exists():
    text = p.read_text()
    print("contains workflow-id-token:", bool(re.search(r'^\s*id-token:\s*write\s*(#.*)?$', text, re.M)))
    print("contains release job block:", bool(re.search(r'^\s*release:\s*$', text, re.M)))
    m = re.search(r'^\s*id-token:\s*write\s*(#.*)?$', text, re.M)
    if m:
        line=m.group(0).splitlines()[0]
        pos=line.find('id-token')
        indent=' ' * (len(m.group(0))-len(m.group(0).lstrip(' ')))
        print(f"top-level id-token indent count: {len(indent)}")
PY

Repository: sommio/qwen-omni-mcp

Length of output: 5464


Scope the OIDC permission to the release job.

id-token: write is currently workflow-scoped, so it applies to every job in this workflow. Move it under jobs.release.permissions and give the publishing job only the permissions it requires; the rest of the workflow can keep contents scoped appropriately.

🧰 Tools
🪛 zizmor (1.28.0)

[error] 10-10: overly broad permissions (excessive-permissions): id-token: write is overly broad at the workflow level

(excessive-permissions)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/release.yml at line 10, Move id-token: write from
workflow-level permissions into jobs.release.permissions, limiting OIDC access
to the release publishing job. Keep contents permission scoped appropriately and
ensure other jobs do not inherit id-token access.

Source: Linters/SAST tools


jobs:
release:
runs-on: ubuntu-latest
environment: release # Matches the npm trusted publisher binding; enables a manual approval gate.
steps:
- uses: actions/checkout@v4

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== workflow excerpt =="
sed -n '1,80p' .github/workflows/release.yml 2>/dev/null || true

echo
echo "== action refs in workflow =="
grep -nE 'uses:\s*[^#]+@[A-Za-z0-9_.-]+' .github/workflows/release.yml || true

echo
echo "== npm publish related lines in workflow =="
grep -nE 'npm|publish|setup-node|checkout' .github/workflows/release.yml || true

Repository: sommio/qwen-omni-mcp

Length of output: 4290


🌐 Web query:

GitHub Actions security hardening use immutable full length SHA pins instead of mutable tags for third-party actions

💡 Result:

Pinning GitHub Actions to an immutable full-length commit SHA (Secure Hash Algorithm) is a critical security best practice for hardening CI/CD pipelines [1][2][3]. Unlike tags (e.g., @v4) or branch references (e.g., @main), which are mutable and can be force-updated by maintainers or attackers to point to malicious code, a commit SHA provides a cryptographically verifiable, content-addressed reference to a specific version of an action [4][5][6][7]. Why SHA pinning is required for security: 1. Mitigation of Mutable Ref Attacks: Tags and branches are merely pointers that can be moved. If an action's repository is compromised, an attacker can re-point a popular tag (like @v4) to a malicious commit [4][6][7]. Because GitHub Actions resolve tags at runtime, any workflow using that tag will automatically execute the malicious code, potentially exfiltrating secrets, tokens, or modifying repository code [1][2][8]. SHA pinning renders this attack impossible because the workflow will continue to execute the exact, reviewed commit hash you specified [6][7]. 2. Immutable Reproducibility: Pinning to a SHA ensures that your workflow behavior remains consistent and reproducible over time, regardless of changes made to the upstream repository [9][5][8]. Best Practices for Implementation: * Use Full-Length SHAs: Always use the full 40-character commit SHA, not a short SHA, to ensure unique identification of the Git object [1][5][3]. * Keep Human-Readable Labels: Maintain the version number as a trailing comment (e.g., uses: actions/checkout@b4ffde6 # v4.1.1) [4][5][2]. This allows dependency management tools like Dependabot or Renovate to track updates and open pull requests for new releases while maintaining the security of an immutable pin [4][5][10]. * Enforce via Policy: GitHub allows organization and repository administrators to enforce SHA pinning through "Allowed actions" policies [1][9]. When enabled, workflows attempting to use a tag or branch will fail, ensuring compliance across the organization [9][5]. * Complement with Other Controls: SHA pinning should be part of a broader security strategy, including: * Applying the principle of least privilege to the GITHUB_TOKEN [2][11]. * Using dependency update tools (Dependabot/Renovate) to manage and review updates to pinned actions [4][5][11]. * Adopting "cooldown" periods before updating to new action versions to allow community detection of potential supply chain compromises [12]. In summary, treating tags as mutable discovery labels rather than trust anchors is essential [8]. By pinning to immutable commit SHAs, you ensure that your CI pipeline runs only the specific, audited code you intend, significantly reducing the blast radius of upstream supply chain compromises [2][6][8].

Citations:


Pin release workflow actions to immutable commit SHAs.

This workflow has contents: write and id-token: write before running npm publish. actions/checkout@v4, actions/setup-node@v4, oven-sh/setup-bun@v2, and softprops/action-gh-release@v2 are tag references; use full commit SHAs with version comments so publish-time action code cannot move unexpectedly.

🧰 Tools
🪛 zizmor (1.28.0)

[warning] 17-17: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


[error] 17-17: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/release.yml at line 17, Update the release workflow action
references for actions/checkout, actions/setup-node, oven-sh/setup-bun, and
softprops/action-gh-release to immutable full commit SHAs, retaining comments
that identify each pinned version. Do not leave any of these actions referenced
by mutable version tags.

Source: Linters/SAST tools


🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== workflow files =="
git ls-files '.github/workflows/*'

echo
echo "== release workflow =="
if [ -f .github/workflows/release.yml ]; then
  nl -ba .github/workflows/release.yml | sed -n '1,220p'
fi

echo
echo "== package scripts references =="
if [ -f package.json ]; then
  node -e 'const p=require("./package.json"); console.log(JSON.stringify({scripts:p.scripts, repository:p.repository}, null, 2))'
fi

echo
echo "== repository scripts/runnable files mentions in workflow =="
if [ -f .github/workflows/release.yml ]; then
  rg -n "npm|npx|run|shell:|permissions:|pull_request|push|release" .github/workflows/release.yml
fi

Repository: sommio/qwen-omni-mcp

Length of output: 367


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== release workflow lines using awk =="
if [ -f .github/workflows/release.yml ]; then
  awk '{printf "%7d: %s\n", NR, $0}' .github/workflows/release.yml | sed -n '1,220p'
fi

echo
echo "== package scripts if present =="
if [ -f package.json ]; then
  awk 'BEGIN{s=0} {if(/"scripts"/) s=1; if(s) print} END{}' package.json | sed -n '1,220p'
fi

echo
echo "== all workflow mentions of npm/npx/scripts/repository files =="
grep -RInE 'npm|npx|scripts|shell:|pull_request|push|release|permissions:' .github/workflows || true

Repository: sommio/qwen-omni-mcp

Length of output: 7412


Disable checkout credential persistence.

actions/checkout persists the GitHub token by default, and this release job later executes repository scripts via npm ci (which runs the configured prepare script), lint/test/build commands, and publishes to npm. Set persist-credentials: false unless checkout-provided credentials are explicitly needed by a later step.

Proposed fix
       - uses: actions/checkout@v4
+        with:
+          persist-credentials: false
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- uses: actions/checkout@v4
- uses: actions/checkout@v4
with:
persist-credentials: false
🧰 Tools
🪛 zizmor (1.28.0)

[warning] 17-17: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


[error] 17-17: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/release.yml at line 17, Update the actions/checkout@v4
step in the release workflow to disable credential persistence by setting
persist-credentials to false, since no later release step requires
checkout-provided credentials.

Source: Linters/SAST tools


- uses: actions/setup-node@v4
with:
node-version: 20
node-version: 22 # Trusted publishing requires Node >=22.14.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== workflow snippets =="
sed -n '1,80p' .github/workflows/release.yml 2>/dev/null || true

echo
echo "== related node setup lines =="
rg -n "node-version|trusted publishing|setup-node|npm" .github/workflows release -S 2>/dev/null || true

echo
echo "== package metadata if present =="
for f in package.json .nvmrc .node-version; do
  [ -f "$f" ] && { echo "--- $f"; cat "$f"; }
done

Repository: sommio/qwen-omni-mcp

Length of output: 6776


🌐 Web query:

npm trusted publishing Node version 22.14.0 npm 11.5.1 documentation

💡 Result:

Trusted publishing for npm packages is a security feature that allows you to publish packages directly from CI/CD workflows using OpenID Connect (OIDC) authentication [1]. This mechanism eliminates the need for long-lived npm tokens, significantly reducing the security risks associated with storing, rotating, or accidentally exposing such tokens [1][2][3]. Requirements: To use trusted publishing, you must use npm CLI version 11.5.1 or later and Node.js version 22.14.0 or higher [1][3]. Key Benefits and Functionality: - Automated Authentication: The npm CLI automatically detects OIDC environments and uses them to authenticate during the publish or stage operations, without requiring an NPM_TOKEN [1][3]. - Provenance Attestations: When utilizing trusted publishing, npm automatically generates and publishes provenance attestations for your package, providing a verifiable link to the source code and build instructions [2][4]. The --provenance flag is no longer required when using this method [2][4]. - Supported Providers: Trusted publishing currently supports cloud-hosted runners on platforms including GitHub Actions, GitLab CI/CD, and CircleCI [1][4]. Configuration: - Management: You can configure trusted publishing via the npm website in your package settings or by using the npm trust command in the CLI [1][5]. - Setup: When configuring a trusted publisher, you establish a trust relationship by specifying the required OIDC claims for your CI/CD provider (e.g., repository, workflow file, environment) [1][2]. The npm trust command provides a way to manage these relationships and specify permissions, such as --allow-publish or --allow-stage-publish [5]. - Limitations: This feature is intended for cloud-hosted runners; support for self-hosted runners is not currently available [1]. Each package can have only one configured trusted publisher at a time [1].

Citations:


Pin the Node.js floor used for trusted publishing.

node-version: 22 allows latest Node 22 releases and the comment does not make the required 22.14.0+ floor explicit. Set this step to a tested 22.14.0+ version or add an explicit runtime check for the npm/trusted-publishing minimum.

Proposed fix
-          node-version: 22
+          node-version: '22.14.0'
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
node-version: 22 # Trusted publishing requires Node >=22.14.
node-version: '22.14.0' # Trusted publishing requires Node >=22.14.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/release.yml at line 21, Update the release workflow’s
node-version setting to an explicitly tested Node.js 22.14.0-or-newer version so
trusted publishing always runs above the required floor; keep the existing
release setup unchanged.

cache: npm

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== release workflow =="
cat -n .github/workflows/release.yml

echo
echo "== relevant setup-node/npm usage =="
rg -n "setup-node|setup-javascript|npm|cache:|permissions:|id-token|npm publish|trusted-publish|oidc" .github/workflows/release.yml .github/workflows 2>/dev/null || true

echo
echo "== git status/diff summary =="
git diff --stat || true
git diff .github/workflows/release.yml --unified=200 || true

Repository: sommio/qwen-omni-mcp

Length of output: 7407


🌐 Web query:

github actions setup-node cache npm trusted publishing npm publish disable cache trusted-publishing

💡 Result:

When using GitHub Actions to publish packages to npm via Trusted Publishing (OIDC), it is recommended to disable automatic dependency caching in the setup-node action to enhance security and prevent potential cache poisoning [1][2][3]. To disable caching, set the package-manager-cache input to false in your workflow file [1][3]: - uses: actions/setup-node@v7 with: node-version: '24' registry-url: 'https://registry.npmjs.org' package-manager-cache: false # Disable automatic npm dependency caching The primary reasons for disabling caching in this context are: 1. Security: Automatic caching for npm is enabled by default if your package.json defines a packageManager field [4][5][3]. In publishing workflows, a poisoned cache can potentially expose sensitive information or OIDC tokens to attacker-controlled code [1]. 2. OIDC Compatibility: Trusted Publishing (OIDC) does not use the NODE_AUTH_TOKEN secret [4][2]. If registry-url is specified, setup-node may attempt to configure authentication in a way that conflicts with OIDC flows if not configured correctly, leading to E404 or ENEEDAUTH errors [6][7]. Explicitly disabling cache and ensuring your environment does not accidentally rely on legacy auth tokens helps maintain a clean OIDC publishing flow [1][2]. Requirements for Trusted Publishing: - npm version 11.5.1 or newer is required [1][8]. - Your workflow must include the id-token: write permission [1][2][8]. - You must configure a Trusted Publisher in npm for your package/scope that precisely matches your repository, workflow file, and optional environment [1][2]. If you are using Node.js 24 or newer, it will generally include the required npm version by default [1][8]. Always verify that your workflow filename exactly matches the one registered in your npm Trusted Publisher settings, as mismatches can cause publishing failures [1][2].

Citations:


🌐 Web query:

npm docs trusted publishing package cache setup-node cache: npm disable

💡 Result:

When using trusted publishing (OpenID Connect) for npm packages within GitHub Actions, you should explicitly disable automatic npm caching in the setup-node action to mitigate security risks such as cache poisoning [1][2][3]. To disable automatic caching, set the package-manager-cache input to false in your workflow file [1][4][5]: - uses: actions/setup-node@v7 with: node-version: '24' package-manager-cache: false The setup-node action enables npm caching by default if your package.json contains a packageManager or devEngines.packageManager field set to npm [4][5][6]. Disabling this is recommended for workflows with elevated privileges, such as publishing, because a poisoned cache could expose sensitive information or credentials—including OIDC tokens—to attacker-controlled code [1][2][5]. While trusted publishing itself does not use long-lived npm tokens (like NODE_AUTH_TOKEN) [4][7], disabling the cache remains a security best practice for any high-permission release workflow to ensure a clean environment [2][3].

Citations:


Disable npm caching in the trusted-publishing release job.

This workflow has id-token: write, install/test/build scripts, and publishes to npm via OIDC. Remove cache: npm so poisoned package-manager cache input cannot affect the privileged release path.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/release.yml at line 22, Remove the cache: npm setting from
the trusted-publishing release job in the workflow, while leaving its OIDC
permissions and install, test, build, and publish steps unchanged.

Source: Linters/SAST tools

registry-url: https://registry.npmjs.org

- name: Install (skip husky in CI)
run: npm ci
Expand All @@ -31,6 +34,15 @@ jobs:
- run: npm test
- run: npm run build

# Trusted publishing (OIDC) requires npm CLI >=11.5.1; Node 22 ships npm 10.
- name: Upgrade npm
run: npm install -g npm@latest

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== workflow excerpt =="
if [ -f .github/workflows/release.yml ]; then
  nl -ba .github/workflows/release.yml | sed -n '1,90p'
else
  echo "missing .github/workflows.release.yml"
fi

echo
echo "== package files =="
for f in package.json .github/workflows/release.yml; do
  if [ -f "$f" ]; then
    echo "--- $f ---"
    nl -ba "$f" | sed -n '1,120p'
  fi
done

echo
echo "== npm-related workflow/package references =="
rg -n "npm(`@latest`|@[0-9]|publish|NODE_VERSION|engine|engines|trusted-publishers|npm-cli|npm@)" .github package.json 2>/dev/null || true

echo
echo "== package lock publish-related metadata, if present =="
if [ -f package-lock.json ]; then
  node - <<'JS'
const fs=require('fs');
const lock=JSON.parse(fs.readFileSync('package-lock.json','utf8'));
console.log("packageManager:", lock.packages?.[""]?.packageManager);
console.log("npm version:", lock.packages?.[""].version);
console.log("engines node:", lock.packages?.[""]?.engines?.node);
for (const [k,v] of Object.entries(lock.packages || {}).slice(0,5)) {
  if ((k === "" || k.includes("npm") || k.includes("pkg")) && (v.version || v.engines)) {
    console.log(k, v.version || "", v.engines || "");
  }
}
JS
else
  echo "missing package-lock.json"
fi

echo
echo "== Node 22/11 npm compatibility references (local docs or CI config) =="
rg -n "346|node:22|NODE_VERSION=22|npm@latest|npm@11|trusted-publishers|npm 11" .github package.json README.md package-lock.json 2>/dev/null || true

echo
echo "== current npm latest resolve =="
node - <<'JS'
const https = require('https');
https.get('https://registry.npmjs.org/npm/latest', {timeout: 10000}, (res) => {
  let body = '';
  res.on('data', c => body += c);
  res.on('end', () => {
    try {
      const json = JSON.parse(body);
      console.log("npm latest resolved version:", json.version);
      console.log("engines:", json.engines ? json.engines.node : null);
      if (json.dist && json.dist.integrity) console.log("tarball integrity sample:", json.dist.integrity.slice(0,80));
    } catch (e) {
      console.log("parse/error:", e.message, body.slice(0,200));
    }
  });
}).on('error', e => console.log("request error:", e.message));
JS

Repository: sommio/qwen-omni-mcp

Length of output: 221


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== workflow excerpt =="
if [ -f .github/workflows/release.yml ]; then
  awk '{printf "%6d\t%s\n", NR, $0}' .github/workflows/release.yml | sed -n '1,100p'
else
  echo "missing .github/workflows/release.yml"
fi

echo
echo "== package files =="
for f in package.json .github/workflows/release.yml; do
  if [ -f "$f" ]; then
    echo "--- $f ---"
    awk '{printf "%6d\t%s\n", NR, $0}' "$f" | sed -n '1,140p'
  fi
done

echo
echo "== npm-related workflow/package references =="
rg -n "npm(`@latest`|@[0-9]|publish|NODE_VERSION|engine|engines|trusted-publishers|npm-cli|npm@)" .github package.json 2>/dev/null || true

echo
echo "== package lock publish-related metadata, if present =="
if [ -f package-lock.json ]; then
  node - <<'JS'
const fs=require('fs');
const lock=JSON.parse(fs.readFileSync('package-lock.json','utf8'));
console.log("packageManager:", lock.packages?.[""]?.packageManager);
root = lock.packages?.[""] || {};
console.log("root version:", root.version);
console.log("root engines:", root.engines);
console.log("root integrity:", root.integrity);
JS
else
  echo "missing package-lock.json"
fi

echo
echo "== Node 22/11 npm compatibility references (local docs or CI config) =="
rg -n "346|node:22|NODE_VERSION=22|npm@latest|npm@11|trusted-publishers|npm 11" .github package.json README.md package-lock.json 2>/dev/null || true

echo
echo "== current npm latest resolve =="
node - <<'JS'
const https = require('https');
https.get('https://registry.npmjs.org/npm/latest', {timeout: 10000}, (res) => {
  let body = '';
  res.on('data', c => body += c);
  res.on('end', () => {
    try {
      const json = JSON.parse(body);
      console.log("npm latest resolved version:", json.version);
      console.log("engines:", json.engines ? json.engines.node : null);
    } catch (e) {
      console.log("parse/error:", e.message, body.slice(0,200));
    }
  });
}).on('error', e => console.log("request error:", e.message));
JS

Repository: sommio/qwen-omni-mcp

Length of output: 9762


Pin the npm CLI version used for publishing.

The workflow uses npm install -g npm@latest, which resolves a mutable registry tag at release time. Pin an exact npm version at or above npm@11.5.1 used with Node 22, then review upgrades deliberately before publishing with trusted publishing.

🧰 Tools
🪛 zizmor (1.28.0)

[warning] 39-39: ad-hoc installation of packages (adhoc-packages): installs a package outside of a lockfile

(adhoc-packages)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/release.yml at line 39, Update the npm installation
command in the release workflow to pin an exact npm CLI version compatible with
Node 22 and at least 11.5.1, replacing the mutable latest tag. Keep future
version changes explicit and deliberate for trusted publishing.

Source: Linters/SAST tools


- name: Publish to npm
# No NODE_AUTH_TOKEN: npm CLI auto-detects the OIDC environment and
# obtains a short-lived token from the trusted publisher binding.
run: npm publish --provenance --access public
Comment on lines +41 to +44

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== workflow files =="
find .github/workflows -maxdepth 1 -type f -name '*.yml' -o -name '*.yaml' 2>/dev/null | sort

echo "== release workflow relevant lines =="
if [ -f .github/workflows/release.yml ]; then
  nl -ba .github/workflows/release.yml | sed -n '1,220p'
else
  echo "missing .github/workflows/release.yml"
fi

echo "== package metadata publishing scripts =="
for f in package.json; do
  [ -f "$f" ] && nl -ba "$f" | sed -n '1,220p'
done

Repository: sommio/qwen-omni-mcp

Length of output: 380


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== release workflow =="
awk '{ printf "%6d\t%s\n", NR, $0 }' .github/workflows/release.yml | sed -n '1,240p'

echo "== search publish and release jobs =="
awk '
  /^  [a-zA-Z_][a-zA-Z0-9_-]*:|^      - name: npm publish|npm publish|--archive|--upload-release-asset|gh release/ { print NR": "$0 }
' .github/workflows/release.yml

echo "== package.json metadata scripts =="
awk '{ printf "%6d\t%s\n", NR, $0 }' package.json | sed -n '1,200p'

Repository: sommio/qwen-omni-mcp

Length of output: 5722


Publish after release artifact generation succeeds.

In the current release workflow, npm publish runs before cross-compilation and the action-gh-release upload. If the subsequent release artifact build or upload fails, this npm version is permanently consumed and cannot be republished under the same version. Move publishing to the final release step/job so it only runs after artifacts are generated and uploaded successfully.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/release.yml around lines 41 - 44, Move the “Publish to
npm” step from its current position to the final release step or job, after
cross-compilation completes and action-gh-release successfully uploads all
artifacts. Preserve the existing npm publish command and OIDC/provenance
configuration, ensuring publishing occurs only after artifact generation and
upload succeed.


- uses: oven-sh/setup-bun@v2

- name: Read version
Expand Down
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,12 @@
},
"files": [
"dist",
"README.md",
"AGENTS.md"
"README.md"
],
"publishConfig": {
"access": "public",
"provenance": true
},
"scripts": {
"build": "tsc -p tsconfig.build.json",
"dev": "tsx src/index.ts",
Expand Down
Loading