---
docgen:
  source: npm/rules/security/js/lint.mjs
  crc: f3265f82
---

# lint.mjs — Security: TruffleHog filesystem scan

## Огляд

Файл `npm/rules/security/js/lint.mjs` реалізує CI-крок правила **security** для пошуку секретів у репозиторії. Це обгортка над зовнішнім інструментом [TruffleHog](https://github.com/trufflesecurity/trufflehog), яка запускає сканування всього робочого дерева (`filesystem` mode) і повертає його exit-код як результат лінтингу.

Особливості:

- **Repo-wide, а не per-file.** Модуль свідомо ігнорує перший аргумент `_files` — TruffleHog у режимі `filesystem` обробляє кореневу теку цілком і завжди сканує однаковий набір шляхів, незалежно від того, які саме файли передає рушій правил. Тому пер-файлового різновиду немає; результат однаковий для будь-якого підмножина файлів.
- **Один прохід на сесію.** Сканер виконується синхронно через `spawnSync`, що відповідає правилу «без паралельних лінт-запусків» у монорепо.
- **Контрактний інтерфейс.** Експорт `lint(files, cwd)` сумісний із загальним контрактом per-rule lint-функцій (`(files?, cwd?) => Promise<number>`), що дозволяє інтегрувати security-правило в загальний раннер однаково з іншими.

Файл не має побічних ефектів на момент імпорту: запуск зовнішнього процесу відбувається лише при виклику `lint()`.

## Експорти / API

| Експорт | Тип                       | Призначення                                                                                             |
| ------- | ------------------------- | ------------------------------------------------------------------------------------------------------- |
| `lint`  | `function` (named export) | Запускає TruffleHog filesystem-скан із кореня `cwd` і повертає `Promise<number>` із exit-кодом процесу. |

Default-експорту немає. Імпорт відбувається у вигляді:

```js
import { lint } from './lint.mjs'
```

## Функції

### `lint(_files, cwd?)`

**Сигнатура:**

```js
export function lint(_files, cwd = process.cwd()) => Promise<number>
```

**Параметри:**

| Параметр | Тип                     | Обовʼязковий | За замовчанням  | Опис                                                                                                                                                             |
| -------- | ----------------------- | ------------ | --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `_files` | `string[] \| undefined` | ні           | —               | Список файлів від рушія правил. **Ігнорується**: TruffleHog у `filesystem`-режимі сканує дерево цілком. Префікс `_` у JSDoc сигналізує про навмисне ігнорування. |
| `cwd`    | `string`                | ні           | `process.cwd()` | Робоча тека, у якій запускається TruffleHog. Сканування `.` виконуватиметься відносно неї.                                                                       |

**Повертає:**

`Promise<number>` — exit-код процесу TruffleHog:

- `0` — секретів не знайдено (успіх).
- Будь-яке інше число — або знайдено секрети, що відповідають критеріям `--results=verified,unknown` (через флаг `--fail`), або TruffleHog не зміг запуститись/упав.
- `1` — fallback, який повертається, якщо `r.status` не є числом (наприклад, процес було вбито сигналом і `status === null`).

**Side effects:**

1. Запускає синхронний дочірній процес `trufflehog` через `node:child_process#spawnSync`.
2. `stdio: 'inherit'` — stdout/stderr/stdin успадковуються з батьківського процесу; вивід TruffleHog потрапляє безпосередньо в консоль CI-runner.
3. Блокує event loop до завершення процесу (`spawnSync` синхронний; результат лише обгортається у `Promise.resolve`).
4. Не записує файли, не модифікує env, не змінює стан модуля.

**Внутрішня механіка:**

Викликається TruffleHog із набором аргументів:

| Аргумент                     | Значення                                                                                                                         |
| ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| Команда                      | `trufflehog` (резолвиться через `PATH`)                                                                                          |
| Subcommand                   | `filesystem`                                                                                                                     |
| Шлях                         | `.` (відносно `cwd`)                                                                                                             |
| `--no-update`                | Не намагатися автооновити сам TruffleHog у CI.                                                                                   |
| `--exclude-paths`            | `.trufflehog-exclude` — файл зі шляхами/патернами, які виключити зі сканування. Має лежати в `cwd`.                              |
| `--results=verified,unknown` | Звітувати лише **верифіковані** секрети та секрети **невідомого** статусу верифікації (відсікти `unverified`, щоб зменшити шум). |
| `--fail`                     | Завершуватись із ненульовим exit-кодом, якщо знайдено результати, що відповідають фільтру вище.                                  |

Параметри `spawnSync`:

- `cwd` — переданий або `process.cwd()`.
- `stdio: 'inherit'` — прямий проброс I/O.

Після завершення:

```js
return Promise.resolve(typeof r.status === 'number' ? r.status : 1)
```

— безпечна нормалізація: якщо `status` відсутній (наприклад, процес перерваний сигналом → `r.status === null`, `r.signal === 'SIGTERM'`), функція повертає `1` як індикатор помилки.

**Контрактні нотатки:**

- Функція **не кидає виключення** для звичайних випадків (TruffleHog знайшов секрети або не запустився) — все нормалізується в exit-код через `Promise.resolve`. Якщо `spawnSync` сам кине синхронне виключення (наприклад, ENOENT через відсутність бінарника та некоректну поведінку runtime), воно пробʼється вгору — але стандартна поведінка Node для відсутнього виконуваного файлу — повернути `r.error`, а `r.status === null`, тому функція дасть `1`.
- Поверне `Promise`, навіть якщо все відбулось синхронно — це потрібно для уніфікованого `await` у виклику з рушія правил.

## Залежності

### Зовнішні (npm) бібліотеки

Жодних — модуль не імпортує сторонні пакети.

### Стандартна бібліотека Node.js

- **`node:child_process`** — використовується `spawnSync` для синхронного запуску `trufflehog`. Імпорт із префіксом `node:` обовʼязковий за правилами проекту.

### Системні залежності

- **`trufflehog`** (бінарник) — має бути доступний у `PATH` середовища, де запускається CI-крок. Інакше `spawnSync` поверне об'єкт із `error` (ENOENT) та `status === null`, і функція віддасть `1`.
- **Файл `.trufflehog-exclude`** — очікується у корені `cwd`. Це plaintext-файл із патернами шляхів для виключення (формат TruffleHog `--exclude-paths`). Якщо файл відсутній, TruffleHog може завершитись із ненульовим кодом — це теж буде повернуто як exit-код.

### Внутрішні модулі

- Зовнішніх внутрішньопроєктних імпортів модуль не має. Він самодостатній і викликається рушієм правил security (`npm/rules/security/...`), який інтегрує його у загальний lint-пайплайн.

## Потік виконання / Використання

### Загальний потік

1. Рушій правил (npm-пакет, що оркеструє лінтери) виявляє правило `security` для активного workspace.
2. Викликає `lint(files, cwd)` із `files` (списком змінених/вибраних файлів) та `cwd` (коренем workspace або репо).
3. `lint`:
   - Ігнорує `files`.
   - Викликає `spawnSync('trufflehog', [...], { cwd, stdio: 'inherit' })`.
   - Користувач/CI бачить весь stdout/stderr TruffleHog у реальному часі.
   - Після завершення процесу повертає `Promise<exitCode>`.
4. Рушій правил агрегує exit-коди всіх лінтерів і визначає загальний результат (зазвичай: будь-яке ненульове значення = провал CI).

### Типовий виклик з коду

```js
import { lint } from './lint.mjs'

const exitCode = await lint(undefined, process.cwd())
if (exitCode !== 0) {
  console.error('[security] TruffleHog знайшов секрети або не зміг виконатись')
  process.exitCode = exitCode
}
```

### CI-сценарій

1. CI-runner клонує репозиторій і встановлює бінарник `trufflehog` (через apt/brew/curl/прекомпільований release).
2. Запускається `n-cursor lint` (або еквівалент), який обходить правила.
3. Для правила `security` рушій кличе цю `lint`-функцію.
4. TruffleHog рекурсивно сканує всі файли під `cwd`, окрім перелічених у `.trufflehog-exclude`.
5. Якщо знайдено **верифіковані** або **unknown**-секрети — повертається ненульовий exit-код, флаг `--fail` гарантує цю поведінку.
6. CI завершується із помилкою, кроки нижче не виконуються.

### Граничні випадки

| Ситуація                        | Поведінка                                                                                                                                                                   |
| ------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `trufflehog` відсутній у `PATH` | `spawnSync` повертає `r.status === null`, функція віддає `1`. У stderr (через `inherit`) може зʼявитись повідомлення Node про відсутність бінарника, залежно від платформи. |
| `.trufflehog-exclude` відсутній | TruffleHog зазвичай помиляється з ненульовим кодом — функція поверне його як є.                                                                                             |
| Процес вбито сигналом           | `r.status === null` → повертається `1`.                                                                                                                                     |
| Секретів немає                  | TruffleHog повертає `0` → функція повертає `0`.                                                                                                                             |
| Передано `files=[...]`          | Аргумент проігноровано; сканування все одно зачіпає всю теку `cwd`.                                                                                                         |
| `cwd` не вказано                | Використовується `process.cwd()` поточного Node-процесу.                                                                                                                    |

### Конфігураційні «крутилки»

Самі прапори зашиті в код і не параметризуються через аргументи функції. Якщо потрібно змінити поведінку (інший шлях `--exclude-paths`, інші типи результатів, увімкнути `--update`), правки робляться безпосередньо в `lint.mjs` — це навмисно, щоб уніфіковано тримати security-політику для всього монорепо.

## Rebuild Test

Перевірка контракту (для майбутніх refactor-ів — поведінка має зберігатись):

1. **Експорт** named `lint` присутній; default-експорту немає.
2. **Сигнатура** `lint(_files, cwd = process.cwd())` повертає `Promise<number>`.
3. **Викликана команда** — рівно `trufflehog` із аргументами у точному порядку:
   `filesystem`, `.`, `--no-update`, `--exclude-paths`, `.trufflehog-exclude`, `--results=verified,unknown`, `--fail`.
4. **Options** для `spawnSync`: `{ cwd, stdio: 'inherit' }`.
5. **Нормалізація exit-коду**: число → пробрасується; не число → `1`.
6. **`_files` ігнорується** — наявність/відсутність/вміст не змінює викликаних аргументів TruffleHog.
7. **Імпорт `child_process`** — лише через `node:`-префікс.
8. **Жодних побічних ефектів на імпорті** — `lint` запускає процес лише при виклику.
