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
13 changes: 9 additions & 4 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,16 @@ jobs:

# The repo's `postinstall` runs `scripts/generate-data.ts` to write
# `packages/nuxt-cli/src/data/*.ts` that the build then bundles. uppt's
# default install path uses `--ignore-scripts`, which would skip it
# and produce a stale or broken nuxi tarball, so we install ourselves
# and pass `install: false` to uppt/pack.
# default install path never runs it, which would produce a stale or
# broken nuxi tarball, so we install and build ourselves and pass
# `install: false` to uppt/pack.
- name: 📦 Install dependencies
run: pnpm install --frozen-lockfile
run: pnpm install --frozen-lockfile --ignore-scripts

- name: 🔨 Generate data and build
run: pnpm run postinstall
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Comment on lines +82 to +83

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 | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -eu

printf '%s\n' '--- workflow context ---'
sed -n '1,130p' .github/workflows/release.yml

printf '%s\n' '--- tracked package manifests ---'
git ls-files '*package.json' '*pnpm-lock.yaml' | sed -n '1,120p'

printf '%s\n' '--- lifecycle and token references ---'
rg -n --hidden --glob '!node_modules' --glob '!dist' --glob '!build' \
  'GITHUB_TOKEN|generate-data|postinstall|preinstall|prepare' .

Repository: nuxt/cli

Length of output: 9652


🏁 Script executed:

#!/bin/bash
set -eu

printf '%s\n' '--- root package manifest ---'
cat -n package.json | sed -n '1,110p'

printf '%s\n' '--- generator and token consumer ---'
fd -t f -a 'generate-data.ts|starter-templates.ts|fetch.ts' .
for f in $(fd -t f -a 'generate-data.ts|starter-templates.ts|fetch.ts' .); do
  printf '\n--- %s ---\n' "$f"
  wc -l "$f"
  cat -n "$f" | sed -n '1,240p'
done

printf '%s\n' '--- package-manager configuration and versions ---'
fd -t f -a -i 'pnpm*|*.npmrc|package.json' . | sed -n '1,160p'
rg -n --hidden --glob '!node_modules' \
  'packageManager|engine-strict|ignore-scripts|onlyBuiltDependencies|neverBuiltDependencies|approve-builds|supportedArchitectures' \
  package.json pnpm-workspace.yaml .npmrc .github scripts packages 2>/dev/null || true

Repository: nuxt/cli

Length of output: 29321


🏁 Script executed:

#!/bin/bash
set -eu

python3 - <<'PY'
from pathlib import Path
import json
import re

workflow = Path(".github/workflows/release.yml").read_text()
manifest = json.loads(Path("package.json").read_text())
generator = Path("scripts/generate-data.ts").read_text()
templates = Path("packages/nuxt-cli/src/utils/starter-templates.ts").read_text()

assert "permissions: {}" in workflow
install = re.search(
    r"- name: 📦 Install dependencies(?P<body>.*?)(?=\n\s{6}- id: pack\b)",
    workflow,
    re.S,
)
assert install, "pack install step not found"
install_body = install.group("body")
assert "run: pnpm install --frozen-lockfile" in install_body
assert "GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}" in install_body
assert "--ignore-scripts" not in install_body

postinstall = manifest["scripts"]["postinstall"]
assert "scripts/generate-data.ts" in postinstall
assert "pnpm build" in postinstall
assert "fetchTemplates" in generator
assert "process.env.GITHUB_TOKEN" in templates
assert "authorization: `token ${process.env.GITHUB_TOKEN}`" in templates

safe_sequence = [
    "pnpm install --frozen-lockfile --ignore-scripts",
    "node --experimental-strip-types ./scripts/generate-data.ts",
    "pnpm build",
]
assert all(command in postinstall or command in safe_sequence for command in safe_sequence)

print("pack install passes GITHUB_TOKEN to pnpm without --ignore-scripts")
print("root postinstall runs generator and build")
print("generator reaches token-backed GitHub API requests")
print("safe split requires install --ignore-scripts, generator, then build")
PY

Repository: nuxt/cli

Length of output: 373


Do not expose GITHUB_TOKEN during dependency installation.

Run pnpm install --frozen-lockfile --ignore-scripts, then run generate-data.ts with the token in a separate step, followed by pnpm build without the token. The current postinstall runs both commands. The install-scoped token is inherited by allowed dependency lifecycle scripts. permissions: {} does not prevent token exfiltration.

🤖 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 79 - 80, Update the release
workflow so the install step runs pnpm install --frozen-lockfile
--ignore-scripts without GITHUB_TOKEN, then invoke generate-data.ts in a
separate token-scoped step, and run pnpm build in a step without the token.
Remove or bypass the current postinstall flow that combines generation and
building during dependency installation, while preserving the required command
order.


- id: pack
uses: danielroe/uppt/pack@7bcfb5397c37202ef882363f755423130419d28a # v0.5.5
Expand Down
23 changes: 18 additions & 5 deletions scripts/generate-data.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
/** generate completion data from nitropack and Nuxt starter repo */

import { existsSync } from 'node:fs'
import { mkdir, writeFile } from 'node:fs/promises'
import { dirname, join } from 'node:path'
import process from 'node:process'
import { pathToFileURL } from 'node:url'
import { resolveModulePath } from 'exsolve'
import { isCI } from 'std-env'

import { fetchTemplates } from '../packages/nuxt-cli/src/utils/starter-templates.ts'

Expand All @@ -14,21 +16,32 @@ interface PresetMeta {

const dataDir = new URL('../packages/nuxt-cli/src/data/', import.meta.url)

const templatesFile = new URL('templates.ts', dataDir)

export async function generateCompletionData() {
const [nitroPresets, templates] = await Promise.all([
getNitroPresets(),
fetchTemplates(),
fetchTemplates().catch(keepExistingTemplates),
])

await mkdir(dataDir, { recursive: true })
await writeFile(
new URL('nitro-presets.ts', dataDir),
`export const nitroPresets = ${JSON.stringify(nitroPresets, null, 2)} as const`,
)
await writeFile(
new URL('templates.ts', dataDir),
`export const templates = ${JSON.stringify(templates, null, 2)} as const`,
)
if (templates) {
await writeFile(
templatesFile,
`export const templates = ${JSON.stringify(templates, null, 2)} as const`,
)
}
}

function keepExistingTemplates(error: unknown): undefined {
if (isCI || !existsSync(templatesFile)) {
throw error
}
console.warn(`Could not fetch starter templates, keeping the ones already generated: ${error}`)
}

async function getNitroPresets() {
Expand Down
Loading