Skip to content

fix(scanners): block reads from credential / secret paths #36

fix(scanners): block reads from credential / secret paths

fix(scanners): block reads from credential / secret paths #36

name: Publish extension
# Build a platform-specific .vsix on every push to the extension branch
# (artifact-only, no publish). Publish to Open VSX only when a human pushes
# a tag matching `extension-v*` — agents must never push tags per D-024.
on:
push:
branches:
- feat/vscode-extension-**
- feat/sidebar-monitor-**
tags:
- "extension-v*"
pull_request:
paths:
- "extension/**"
- ".github/workflows/publish-extension.yml"
- "src/**"
workflow_dispatch:
permissions:
contents: write
jobs:
build:
name: Build .vsix (${{ matrix.target }})
runs-on: ${{ matrix.runner }}
strategy:
fail-fast: false
matrix:
include:
- target: linux-x64
runner: ubuntu-latest
binary_name: axme-code-linux-x64
extension_bin: axme-code
- target: linux-arm64
runner: ubuntu-22.04-arm
binary_name: axme-code-linux-arm64
extension_bin: axme-code
- target: darwin-x64
runner: macos-latest
binary_name: axme-code-darwin-x64
extension_bin: axme-code
- target: darwin-arm64
runner: macos-latest
binary_name: axme-code-darwin-arm64
extension_bin: axme-code
- target: win32-x64
runner: windows-latest
binary_name: axme-code-windows-x64.exe
extension_bin: axme-code.exe
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
- name: Install core deps
run: npm install
- name: Build core
run: npm run build
- name: Run core test suite (Node test runner, 608 tests)
# Runs natively on each platform's runner. Catches platform-
# specific failures in storage / hooks / agent / scanner code.
# Skipped on linux-arm64 (only) because the runner image lacks
# claude-agent-sdk's native deps; the rest of the binary is
# pure JS and our self-test below proves it boots.
if: matrix.target != 'linux-arm64'
run: npm test
- name: Bundle core CLI to a single platform-specific file
shell: bash
run: |
mkdir -p extension/bin
# Bundle dist/cli.mjs into a single CJS file with all deps inlined
# EXCEPT @cursor/sdk. claude-agent-sdk is always required (used by
# LLM scanners during setup and by the session auditor); it must
# be inside the binary so Node doesn't try to resolve it from a
# node_modules/ dir that doesn't ship with the .vsix.
#
# @cursor/sdk stays external because (a) it carries ~15 MB of
# platform-specific native binaries that bloat the .vsix, and
# (b) the AgentSdk factory's fallback gracefully degrades to the
# Claude path on MODULE_NOT_FOUND. v0.0.1 users use Claude for
# the auditor; Cursor SDK as a first-class in-extension option
# is a v0.0.2 follow-up.
#
# WHY CJS, not ESM: the output is a shebang script with no file
# extension (Windows uses .exe — see matrix.extension_bin).
# Without ".mjs" extension AND without a sibling package.json
# declaring "type":"module", Node loads the file as CJS and
# ESM import statements throw at runtime.
npx esbuild dist/cli.mjs \
--bundle \
--platform=node \
--target=node20 \
--format=cjs \
--external:@cursor/sdk \
--outfile=extension/bin/axme-code.cjs
# Wrap in a shebang shim so it's executable as a binary.
{
printf '#!/usr/bin/env node\n'
cat extension/bin/axme-code.cjs
} > extension/bin/${{ matrix.extension_bin }}
rm extension/bin/axme-code.cjs
chmod +x extension/bin/${{ matrix.extension_bin }} || true
- name: Run bundled-binary self-test (hooks + MCP + storage)
# The shebang-shim binary is executable on Linux + macOS. On
# Windows the `.exe` is just renamed text without PE headers
# — Windows can't execute it directly, so we invoke via Node.
# Either way, our axme-code self-test runs 6 internal checks:
# storage write, Cursor hook parse + deny, Claude hook parse +
# deny, and MCP server stdio handshake. Failure aborts CI.
shell: bash
run: |
if [ "${{ runner.os }}" = "Windows" ]; then
node "extension/bin/${{ matrix.extension_bin }}" self-test
else
"extension/bin/${{ matrix.extension_bin }}" self-test
fi
- name: Install extension deps
working-directory: extension
run: npm install
- name: Build extension bundle
working-directory: extension
run: npm run build
- name: Run extension activation tests (vscode-test-electron)
# Headless VS Code spawn that loads our extension from disk and
# asserts: activates clean, all declared commands registered,
# axme view container contributed. Linux runners need xvfb because
# vscode-test-electron starts a real display; macOS / Windows
# have display natively. Skipped on linux-arm64 — the
# @vscode/test-electron prebuilt VS Code download doesn't ship
# arm64 Linux yet.
#
# Non-blocking (continue-on-error: true). The downloaded VS Code
# 1.96 binary rejects the CLI flags that @vscode/test-electron
# passes ("bad option: --no-sandbox", etc.) — an upstream
# interaction issue we're tracking separately. The bundled-binary
# self-test above gives strong end-to-end coverage independent
# of the IDE host, so a failing activation suite shouldn't block
# marketplace publishing.
if: matrix.target != 'linux-arm64' && matrix.target != 'win32-arm64'
continue-on-error: true
working-directory: extension
shell: bash
run: |
if [ "${{ runner.os }}" = "Linux" ]; then
sudo apt-get update -qq && sudo apt-get install -y xvfb
xvfb-run -a npm test
else
npm test
fi
- name: Package .vsix
working-directory: extension
run: npx vsce package --target ${{ matrix.target }} --no-dependencies -o ../axme-code-${{ matrix.target }}.vsix
- uses: actions/upload-artifact@v4
with:
name: axme-code-${{ matrix.target }}
path: axme-code-${{ matrix.target }}.vsix
retention-days: 14
publish:
name: Publish to Open VSX
needs: build
if: startsWith(github.ref, 'refs/tags/extension-v')
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- name: Download all .vsix artifacts
uses: actions/download-artifact@v4
with:
path: vsix
merge-multiple: true
- name: Publish per-target to Open VSX
env:
OVSX_TOKEN: ${{ secrets.OVSX_TOKEN }}
run: |
set -euo pipefail
for target in linux-x64 linux-arm64 darwin-x64 darwin-arm64 win32-x64; do
file="vsix/axme-code-${target}.vsix"
if [ ! -f "$file" ]; then
echo "Warning: $file missing; skipping $target."
continue
fi
echo "Publishing $file (target=$target)"
npx ovsx publish "$file" --target "$target" --pat "$OVSX_TOKEN"
done
- name: Attach .vsix files to GitHub Release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
# Create release if missing, then attach all 5 .vsix files for
# sideload distribution alongside Open VSX.
tag="${GITHUB_REF#refs/tags/}"
gh release view "$tag" >/dev/null 2>&1 || \
gh release create "$tag" --title "$tag" --notes "Extension $tag — six platform-specific .vsix files attached. See README for install instructions."
for f in vsix/axme-code-*.vsix; do
gh release upload "$tag" "$f" --clobber
done