Skip to content

feat(marketplace): list shotkit in the starter-series catalog (#55) #133

feat(marketplace): list shotkit in the starter-series catalog (#55)

feat(marketplace): list shotkit in the starter-series catalog (#55) #133

Workflow file for this run

name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_call:
permissions:
contents: read
jobs:
ci:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
# 22 = engines.node floor + the version we publish against.
# 24 = current Active LTS — verify ahead so the eventual bump is free.
node-version: [22, 24]
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Scan for secrets
# Only run once across the matrix — gitleaks reads the repo, not Node.
if: matrix.node-version == 22
env:
# Bump together; checksum from
# https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_checksums.txt
GITLEAKS_VERSION: 8.30.1
GITLEAKS_SHA256: 551f6fc83ea457d62a0d98237cbad105af8d557003051f41f3e7ca7b3f2470eb
run: |
set -euo pipefail
curl -sSfL "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" -o /tmp/gitleaks.tgz
echo "${GITLEAKS_SHA256} /tmp/gitleaks.tgz" | sha256sum -c -
tar xz -C /tmp -f /tmp/gitleaks.tgz
/tmp/gitleaks detect --source . --verbose --redact
- name: Check for large files
if: matrix.node-version == 22
run: |
LARGE=$(find . -not -path './.git/*' -not -path './node_modules/*' -type f -size +5M)
if [ -n "$LARGE" ]; then
echo "::error::Large files detected (>5 MB):"
echo "$LARGE"
exit 1
fi
- uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- name: Install dependencies
run: npm ci --ignore-scripts
- name: Verify package-lock.json is in sync with package.json
if: matrix.node-version == 22
run: |
# Common Dependabot footgun: package.json edited without a matching
# lockfile update (or vice versa). `npm install --package-lock-only`
# rewrites package-lock.json from package.json without touching
# node_modules; if it produces a diff, the two were out of sync.
npm install --package-lock-only --ignore-scripts
if ! git diff --exit-code -- package-lock.json; then
echo "::error::package-lock.json is out of sync with package.json."
echo "Run 'npm install' locally and commit the updated lockfile."
exit 1
fi
- name: Check licenses
if: matrix.node-version == 22
run: npx --yes license-checker --failOn "GPL-2.0;GPL-3.0;AGPL-3.0"
- name: Verify EN/KO docs heading parity
if: matrix.node-version == 22
# Cheap structural check: same number of "## " sections in README.md
# and README.ko.md, same in docs/graduation-from-vibe-coding{,.ko}.md.
# We count only "^## " (h2 with space) to avoid matching shell
# comments inside ```bash``` blocks. Doesn't validate translation
# quality — just catches one-sided additions, which is the most
# common drift mode.
run: |
set -euo pipefail
check_parity() {
local en="$1" ko="$2"
local en_n ko_n
en_n=$(grep -cE '^## ' "$en" || true)
ko_n=$(grep -cE '^## ' "$ko" || true)
if [ "$en_n" != "$ko_n" ]; then
echo "::error file=$ko::Heading count drift: $en has $en_n h2 sections, $ko has $ko_n. One side added or removed a section."
return 1
fi
echo " $en ↔ $ko: $en_n h2 sections (parity OK)"
}
check_parity README.md README.ko.md
check_parity docs/graduation-from-vibe-coding.md docs/graduation-from-vibe-coding.ko.md
- name: Security audit
# `moderate` (not `high`) because package.json#overrides patches the
# transitive hono / ip-address / @hono/node-server moderates that the
# MCP SDK's HTTP-transport branch pulls in. Without the overrides,
# this step would false-positive on transitives we never import.
run: npm audit --audit-level=moderate
- name: Build (tsc — also typechecks)
run: npm run build
- name: Unit tests
run: npm test
- name: Verify CLI bin exists
run: test -f dist/index.js
- name: Scaffold smoke test
run: |
# Verify templates.ts references valid repo names (no typos)
node --input-type=module -e "
import('./dist/templates.js').then(m => {
const ids = m.templates.map(t => t.id);
if (new Set(ids).size !== ids.length) {
console.error('Duplicate template ids');
process.exit(1);
}
for (const t of m.templates) {
if (!t.repo || !t.repo.includes('/')) {
console.error('Invalid repo:', t.id);
process.exit(1);
}
}
console.log('Templates OK:', ids.length);
});
"