Skip to content

fix(deps): patch proxy-addr (critical) and source-map-js (high) (#30) #85

fix(deps): patch proxy-addr (critical) and source-map-js (high) (#30)

fix(deps): patch proxy-addr (critical) and source-map-js (high) (#30) #85

Workflow file for this run

name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
test:
name: Test (${{ matrix.os }})
runs-on: ${{ matrix.os }}
timeout-minutes: 20
# All three OSes are blocking: the native Windows failures (backlog M8-6) were fixed
# in nilhemdot/agent-os#25; WSL2 remains the recommended Windows path for users.
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
defaults:
run:
# windows-latest defaults to pwsh, which cannot parse the bash-array
# security-lint steps (R1.4); bash exists on all three runners.
shell: bash
steps:
- uses: actions/checkout@v7
- name: Setup Node.js
uses: actions/setup-node@v7
with:
node-version-file: source/.nvmrc
cache: 'npm'
cache-dependency-path: source/package-lock.json
- name: Install dependencies
working-directory: source
run: npm ci
- name: Type check
working-directory: source
run: npm run typecheck
- name: Lint
working-directory: source
run: npm run lint
# blocking: M8.18 lint-debt burn-down reached 0 errors; warnings do not fail the step
- name: Security lint - forbid child_process in app/features (R1.4)
working-directory: source
run: |
# R1.4: All subprocess launches must route through runner.ts (spawnSubprocess, run, spawnStream)
# Check for: from imports, require(), and dynamic import() patterns
PATTERNS=(
"from ['\"]child_process['\"]"
"from ['\"]node:child_process['\"]"
"require\(\s*['\"]child_process['\"]\s*\)"
"require\(\s*['\"]node:child_process['\"]\s*\)"
"import\(\s*['\"]child_process['\"]\s*\)"
"import\(\s*['\"]node:child_process['\"]\s*\)"
)
VIOLATIONS=""
for PATTERN in "${PATTERNS[@]}"; do
FOUND=$(grep -rE "$PATTERN" src/app src/features 2>/dev/null || true)
if [ -n "$FOUND" ]; then
VIOLATIONS="$VIOLATIONS$FOUND"$'\n'
fi
done
if [ -n "$VIOLATIONS" ]; then
echo "ERROR: Direct child_process imports found in src/app/** or src/features/** (R1.4 violation)"
echo "$VIOLATIONS"
echo "Use spawnSubprocess/run/spawnStream from @/lib/runner instead"
exit 1
fi
# Blocking job: fails CI immediately on any child_process import in app/features
- name: Security lint - ESLint no-restricted-imports (R1.4, AST-level)
working-directory: source
run: |
# AST-level backstop for the grep check above: catches aliased/re-exported
# static imports and dynamic import() that text patterns can miss.
# Scoped to the R1.4 rule only so the pre-existing lint backlog (M8.18)
# cannot fail this job.
# workspace-relative temp file: /tmp is bash-only on windows runners,
# and node.exe cannot resolve it
npx eslint 'src/app/**/*.{js,jsx,ts,tsx}' 'src/features/**/*.{js,jsx,ts,tsx}' \
--no-error-on-unmatched-pattern --format json > eslint-r14.json || true
node -e "
const results = require('./eslint-r14.json');
const hits = results.flatMap(f => f.messages
.filter(m => m.ruleId === 'no-restricted-imports')
.map(m => f.filePath + ':' + m.line + ' ' + m.message));
if (hits.length) {
console.error('R1.4 ESLint violations:\n' + hits.join('\n'));
process.exit(1);
}
console.log('R1.4 ESLint check clean (' + results.length + ' files)');
"
rm -f eslint-r14.json
- name: Run tests (includes adversarial suite m8-*.test.ts)
working-directory: source
run: npm run test
- name: Run eval
working-directory: source
run: npm run eval
build:
name: Build
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v7
- name: Setup Node.js
uses: actions/setup-node@v7
with:
node-version-file: source/.nvmrc
cache: 'npm'
cache-dependency-path: source/package-lock.json
- name: Cache Next.js build
uses: actions/cache@v6
with:
path: source/.next/cache
key: nextjs-${{ runner.os }}-${{ hashFiles('source/package-lock.json') }}-${{ hashFiles('source/src/**', 'source/next.config.ts') }}
restore-keys: |
nextjs-${{ runner.os }}-${{ hashFiles('source/package-lock.json') }}-
- name: Install dependencies
working-directory: source
run: npm ci
- name: Next.js production build
working-directory: source
run: npm run build
env:
NEXT_TELEMETRY_DISABLED: '1'
security-evidence:
name: Security evidence (SBOM + audit)
runs-on: ubuntu-latest
timeout-minutes: 10
# Evidence only: dependency-review.yml gates PRs and codeql.yml uploads SARIF to code scanning.
steps:
- uses: actions/checkout@v7
- name: Setup Node.js
uses: actions/setup-node@v7
with:
node-version-file: source/.nvmrc
- name: Generate CycloneDX SBOM and npm audit report
working-directory: source
run: |
mkdir -p ../security-evidence
npm sbom --sbom-format cyclonedx --package-lock-only --omit dev > ../security-evidence/sbom.cdx.json
# npm audit exits non-zero when it finds anything; keep the report, don't fail the job
npm audit --json --package-lock-only > ../security-evidence/npm-audit.json || true
# A registry/network failure yields {"error": ...} with no metadata; report it instead of crashing before the upload
node -e "let a; try { a = require('../security-evidence/npm-audit.json'); } catch (e) { a = { error: String(e) }; } console.log('npm audit:', JSON.stringify(a.metadata?.vulnerabilities ?? { error: a.error ?? 'no metadata in report' }))" | tee -a "$GITHUB_STEP_SUMMARY"
- name: Upload security evidence
uses: actions/upload-artifact@v4
with:
name: security-evidence-${{ github.sha }}
path: security-evidence/
retention-days: 90