# Shebang line is present and correct

- **Pattern:** `ab-000658` (`cli-quality.config-distribution.shebang`)
- **Severity:** high
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-000658
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-000658)

## Why it matters

Without `#!/usr/bin/env node` on the first line of `dist/cli.js`, Linux and macOS refuse to execute the file — users see `cannot execute binary file: Exec format error` and have no way to fix it short of prefixing `node` manually. Hardcoding `#!/usr/local/bin/node` is nearly as bad: it breaks on systems using nvm, asdf, volta, Homebrew's Apple Silicon paths, or any container where node lives elsewhere. `env`-based shebangs are the only portable form.

## Severity rationale

High because a missing or hardcoded shebang breaks execution on Unix systems for a large fraction of users.

## Remediation

Ensure the entry file's first line is exactly `#!/usr/bin/env node` (or `#!/usr/bin/env python3`) with no BOM or blank line before it. If you transpile, configure the bundler to preserve it. With tsup or esbuild in `tsup.config.ts`:

```ts
export default defineConfig({
  entry: ['src/cli.ts'],
  banner: { js: '#!/usr/bin/env node' },
})
```

## Detection

- **ID:** `shebang`
- **Severity:** `high`
- **What to look for:** List all executable entry point files. For each, check the CLI entry file (the file referenced by `bin` in `package.json`, or the main script for Python). For Node.js, the first line must be `#!/usr/bin/env node`. For Python, it should be `#!/usr/bin/env python3`. Check that the shebang is on the very first line (no blank lines or BOM before it). Check that the file has executable permissions (or that the build/publish process sets them).
- **Pass criteria:** The CLI entry file has a correct shebang line as its first line. For compiled languages (Go, Rust), this check is not applicable since the binary is compiled — 100% of executable files must start with a valid shebang (#!/usr/bin/env node or equivalent). Report: "X entry point files found, all Y have correct shebang lines."
- **Fail criteria:** No shebang line, incorrect shebang (hardcoded path like `#!/usr/local/bin/node` instead of `#!/usr/bin/env node`), or shebang is not on the first line.
- **Skip (N/A) when:** The CLI is written in a compiled language (Go, Rust) — compiled binaries don't need shebangs. All checks skip when no CLI entry point is detected.
- **Detail on fail:** `"Entry file dist/cli.js has no shebang line — running via 'mytool' will fail with 'cannot execute binary file' on Unix systems"` or `"Shebang uses hardcoded path '#!/usr/local/bin/node' — will fail on systems where node is installed elsewhere"`
- **Remediation:** The shebang line tells the OS which interpreter to use:

  ```ts
  #!/usr/bin/env node
  // ^ This MUST be the very first line of the file

  import { program } from 'commander'
  // rest of your CLI code
  ```

  ```python
  #!/usr/bin/env python3
  # ^ First line of your CLI script

  import click
  ```

  If using TypeScript with a build step, ensure your build tool preserves or adds the shebang. With tsup: `banner: { js: '#!/usr/bin/env node' }`. With esbuild: `banner: { js: '#!/usr/bin/env node' }`.

Taxons: operational-readiness

HTML version: https://auditbuffet.com/patterns/ab-000658
