npm package: @science-and-humans/science-and-humans-ci-config
Description: Centralized CI quality standards, shared configs, and reusable GitHub Actions workflows for Science & Humans
Latest version: 2.0.4

# Science & Humans — CI Platform

Centralized CI quality standards, shared configs, and reusable GitHub Actions workflows.

## Architecture

```
┌─────────────────────────────────────┐
│  policies/standards.yml             │  Defines WHAT to enforce
│  Language-agnostic, tool-agnostic   │
├─────────────────────────────────────┤
│  .github/workflows/ci-node.yml     │  HOW to enforce (Node.js)
│  9 mandatory checks, all blocking   │
├─────────────────────────────────────┤
│  Consumer repo calls workflow       │  WHERE it runs
│  ~5 lines of YAML                   │  GitHub Actions in caller's context
└─────────────────────────────────────┘
```

## Quick Start

Add `.github/workflows/ci.yml` to your repo:

```yaml
name: CI Quality Gate

on:
  push:
    branches: [main, release]
  pull_request:
    branches: [main, release]

jobs:
  quality:
    uses: Science-and-Humans/science-and-humans-ci-configs/.github/workflows/ci-node.yml@v2
    with:
      node-version: '22'
```

## What It Checks

| #   | Check          | Tool                 | Default                                   | Severity       |
| --- | -------------- | -------------------- | ----------------------------------------- | -------------- |
| 1   | Commit message | Conventional Commits | `type(scope): subject` (max 100 chars)    | error (blocks) |
| 2   | Format         | Prettier             | `--check "**/*.{js,ts,json,md,yaml,yml}"` | error (blocks) |
| 3   | Lint           | ESLint               | `--max-warnings=0`                        | error (blocks) |
| 4   | Unit tests     | Jest / Vitest        | Auto-detects framework and coverage cmd   | error (blocks) |
| 5   | Coverage       | Jest / Vitest / lcov | `>= 70%` line coverage                    | error (blocks) |
| 6   | Security       | npm audit            | `--production --audit-level=high`         | error (blocks) |
| 7   | License        | license-checker      | MIT, ISC, Apache-2.0, BSD, etc.           | error (blocks) |
| 8   | Outdated       | npm-check-updates    | excludes @types, eslint, prettier         | error (blocks) |
| 9   | Trivy FS       | Trivy                | CRITICAL + HIGH severity, ignore unfixed  | error (blocks) |

All checks are **error** severity — pipeline fails if any check fails. No exceptions.

## Inputs

All inputs are optional. Most repos only need `node-version`:

| Input                      | Type   | Default                           | Description                             |
| -------------------------- | ------ | --------------------------------- | --------------------------------------- |
| `node-version`             | string | `'20'`                            | Node.js version                         |
| `working-directory`        | string | `'.'`                             | Directory with package.json             |
| `audit-level`              | string | `'high'`                          | npm audit severity level                |
| `lint-max-warnings`        | number | `0`                               | Max ESLint warnings                     |
| `format-file-patterns`     | string | `'**/*.{js,ts,json,md,yaml,yml}'` | Prettier glob                           |
| `allowed-licenses`         | string | `'MIT;ISC;...'`                   | Semicolon-separated SPDX IDs            |
| `coverage-threshold`       | number | `70`                              | Min line coverage %                     |
| `trivy-severity`           | string | `'CRITICAL,HIGH'`                 | Trivy scan severity levels              |
| `outdated-exclude-pattern` | string | `'/^(@types\|eslint\|prettier)/'` | Packages to exclude from outdated check |

## Outputs

Each check exposes its outcome (`success`, `failure`, or `skipped`):

| Output                   | Description                  |
| ------------------------ | ---------------------------- |
| `commit-message-outcome` | Commit message format result |
| `format-outcome`         | Prettier result              |
| `lint-outcome`           | ESLint result                |
| `test-outcome`           | Unit test result             |
| `coverage-outcome`       | Coverage threshold result    |
| `security-outcome`       | npm audit result             |
| `license-outcome`        | License compliance result    |
| `outdated-outcome`       | Outdated packages result     |
| `trivy-fs-outcome`       | Trivy filesystem scan result |

Use outputs in downstream jobs:

```yaml
jobs:
  quality:
    uses: Science-and-Humans/science-and-humans-ci-configs/.github/workflows/ci-node.yml@v2
    with:
      node-version: '22'

  docker-build:
    needs: [quality]
    runs-on: ubuntu-latest
    steps:
      # Quality gate passed — safe to build and deploy
```

## What Your Repo Needs

The workflow expects these to exist in your repo:

1. **`package.json`** with a `lint` script (e.g., `"lint": "eslint ."`)
2. **`package-lock.json`** (for `npm ci` and caching)
3. **A Prettier config** (`.prettierrc`, `prettier.config.cjs`, etc.)
4. **An ESLint config** (`eslint.config.mjs`, `.eslintrc.cjs`, etc.)
5. **A test script** — one of these:
   - `test:coverage` in package.json (preferred)
   - `test:cov` in package.json
   - Jest or Vitest in devDependencies (auto-detected as fallback)

The workflow uses **your repo's configs** — it just runs them consistently.

## Commit Message Format

All commits must follow [Conventional Commits](https://www.conventionalcommits.org/):

```
type(scope): subject
```

**Allowed types:** `feat`, `fix`, `chore`, `docs`, `refactor`, `test`, `ci`, `style`, `perf`, `build`, `revert`

**Examples:**

```
feat(auth): add JWT refresh token rotation
fix(scheduler): handle timezone offset in booking
chore(deps): update eslint to v9
docs(readme): add deployment instructions
refactor(chr): extract patient service from controller
test(api): add integration tests for orders endpoint
ci(pipeline): update workflow to use Node 22
```

**Rules:**

- Scope is optional: `feat: add login` is valid
- Max 100 characters for the subject line
- Merge commits are skipped automatically

## Shared ESLint & Prettier Configs (npm package)

Install the package:

```bash
npm install -D @science-and-humans/science-and-humans-ci-config
```

### ESLint — Flat Config (Recommended)

**Backend repos** (NestJS, Express, Node.js):

```js
// eslint.config.mjs
import config from '@science-and-humans/science-and-humans-ci-config/eslint-flat';
export default config({ tsconfigRootDir: import.meta.dirname });
```

**Frontend repos** (Next.js, React):

```js
// eslint.config.mjs
import config from '@science-and-humans/science-and-humans-ci-config/eslint-flat-frontend';
export default config({ tsconfigRootDir: import.meta.dirname });
```

**With custom ignores or overrides:**

```js
// eslint.config.mjs
import config from '@science-and-humans/science-and-humans-ci-config/eslint-flat';
export default [
  ...config({ tsconfigRootDir: import.meta.dirname, ignores: ['generated/'] }),
  {
    rules: { '@typescript-eslint/no-explicit-any': 'error' },
  },
];
```

### ESLint — Legacy Config (for repos still on .eslintrc)

```js
// .eslintrc.cjs (backend)
module.exports = {
  extends: [require.resolve('@science-and-humans/science-and-humans-ci-config/eslint')],
};

// .eslintrc.cjs (frontend)
module.exports = {
  extends: [require.resolve('@science-and-humans/science-and-humans-ci-config/eslint-full')],
};
```

### Prettier (all repos)

```js
// prettier.config.cjs
module.exports = require('@science-and-humans/science-and-humans-ci-config/prettier');
```

### Available Exports

| Export                   | Format            | Use case                                |
| ------------------------ | ----------------- | --------------------------------------- |
| `./eslint-flat`          | ESM flat config   | Backend repos with `eslint.config.mjs`  |
| `./eslint-flat-frontend` | ESM flat config   | Frontend repos with `eslint.config.mjs` |
| `./eslint`               | CJS legacy config | Backend repos with `.eslintrc.cjs`      |
| `./eslint-full`          | CJS legacy config | Frontend repos with `.eslintrc.cjs`     |
| `./prettier`             | CJS               | All repos                               |

### What the configs enforce

**ESLint (backend):**

- `eslint:recommended`
- `@typescript-eslint/recommendedTypeChecked`
- `eslint-plugin-prettier/recommended`
- `no-explicit-any`: off
- `no-floating-promises`: warn
- `no-unsafe-argument`: warn
- Globals: node, jest

**ESLint (frontend):**
Everything above plus:

- `react` plugin
- `react-hooks/recommended` rules
- `react-in-jsx-scope`: off
- Globals: browser, node, jest

**Prettier (`./prettier`):**

- Single quotes
- Semicolons
- Trailing commas (all)
- Print width: 100
- Tab width: 2

## Integrating With Existing Deploy Workflows

Replace the old `install`, `lint`, `test`, `security-audits`, and `trivy-fs-scan` jobs with a single quality gate call:

```yaml
# Before: 5 separate jobs (~190 lines)
# After: 1 reusable workflow call

jobs:
  quality:
    uses: Science-and-Humans/science-and-humans-ci-configs/.github/workflows/ci-node.yml@v2
    with:
      node-version: '22'

  # docker-build now depends on quality instead of lint + test + security-audits
  docker-build:
    needs: [quality]
    runs-on: ubuntu-latest
    steps:
      # ... existing docker build steps

  # Everything downstream stays the same
  deploy-to-gke:
    needs: [docker-build]
    # ...
```

## Adding a New Language

See [docs/ADDING_LANGUAGE.md](docs/ADDING_LANGUAGE.md).

## Versioning

- Consumer repos pin to `@v2` (gets minor/patch updates automatically)
- Breaking changes bump to `@v3`
- Same pattern as `actions/checkout@v6`

## Repo Structure

```
├── policies/
│   └── standards.yml              # Quality standards (language-agnostic)
├── configs/
│   └── node/
│       ├── eslint.base.cjs        # Shared ESLint base config
│       ├── eslint.config.cjs      # Backend ESLint config (extends base)
│       ├── eslint.frontend.cjs    # Frontend ESLint config (extends base)
│       └── prettier.config.cjs    # Shared Prettier config
├── .github/
│   └── workflows/
│       ├── ci-node.yml            # Reusable workflow for Node.js repos
│       ├── publish.yml            # Auto-publish npm package on version tags
│       └── self-test.yml          # Tests the platform itself
├── test-fixtures/
│   └── node/                      # Minimal project for self-testing
├── docs/
│   ├── CONSUMER_GUIDE.md          # Step-by-step onboarding guide
│   └── ADDING_LANGUAGE.md         # How to add Java/Python/Go support
├── CODEOWNERS                     # Required reviewers for all changes
└── package.json                   # npm package config
```