# GitHub Action — `certisigma/census-action@v1`

CertiSigma Census ships a reusable GitHub Action that installs Census from PyPI and runs `scan`, `integrity`, `compare`, or `bulk-scan` in your CI/CD pipeline — with automatic SARIF upload to the GitHub Security tab.

## Quick start

```yaml
- uses: certisigma/census-action@v1
  with:
    command: compare
    target: ./artifacts
    manifest: ./inventory.db
  env:
    CERTISIGMA_API_KEY: ${{ secrets.CERTISIGMA_API_KEY }}
```

Three lines. Results appear in the GitHub Security tab.

## Architecture

The action is a **composite action** (`runs: composite`), not a Docker action:

- Zero container build time
- Uses the runner's Python (configurable via `python-version`)
- Installs Census from PyPI: `pip install certisigma-census`
- No secrets stored in the action — users provide `CERTISIGMA_API_KEY` via repository secrets

## Inputs

| Input | Required | Default | Description |
|-------|----------|---------|-------------|
| `command` | **yes** | — | Census command: `scan`, `integrity`, `compare`, `bulk-scan` |
| `target` | no | `.` | Directory to scan or check |
| `manifest` | no | `.census-manifest.db` | Path to manifest file |
| `api-key` | no | `$CERTISIGMA_API_KEY` | CertiSigma API key (prefer `env:` block) |
| `source` | no | `github-ci` | Source label for attestation |
| `format` | no | auto | Output format: `text`, `json`, `jsonl`, `sarif`. Default: `sarif` for compare, `json` for others. Note: `sarif` only available on `compare`. |
| `upload-sarif` | no | `true` | Auto-upload SARIF to GitHub Security tab |
| `exit-zero` | no | `false` | Report-only mode — always exit 0 |
| `version` | no | latest | Census version to install (e.g. `1.6.1`) |
| `extra-args` | no | — | Additional CLI arguments passed through verbatim |
| `python-version` | no | `3.12` | Python version for the runner |

## Outputs

| Output | Description |
|--------|-------------|
| `exit-code` | Census command exit code |
| `output-file` | Path to the generated report file |
| `sarif-file` | Path to SARIF file (if generated) |

## Workflow examples

### Inventory scan on release

Attest all source files when a release is published:

```yaml
name: Census Inventory Scan
on:
  release:
    types: [published]

jobs:
  scan:
    runs-on: ubuntu-latest
    permissions:
      contents: read
    steps:
      - uses: actions/checkout@v4

      - uses: certisigma/census-action@v1
        with:
          command: scan
          target: ./src
          source: release-${{ github.ref_name }}
        env:
          CERTISIGMA_API_KEY: ${{ secrets.CERTISIGMA_API_KEY }}
```

### Integrity check on every push

Detect unauthorized changes to inventoried files:

```yaml
name: Census Integrity Check
on: [push, pull_request]

jobs:
  integrity:
    runs-on: ubuntu-latest
    permissions:
      contents: read
    steps:
      - uses: actions/checkout@v4

      - uses: certisigma/census-action@v1
        with:
          command: integrity
          manifest: ./inventory.db
```

No API key needed — integrity is 100% local.

### Breach detection with SARIF upload

Compare suspect artifacts and surface results in the Security tab:

```yaml
name: Census Breach Detection
on:
  workflow_dispatch:
    inputs:
      suspect-dir:
        description: "Directory with suspect files"
        required: true
        default: "./artifacts"

jobs:
  compare:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      security-events: write
    steps:
      - uses: actions/checkout@v4

      - uses: certisigma/census-action@v1
        with:
          command: compare
          target: ${{ github.event.inputs.suspect-dir }}
          manifest: ./inventory.db
          upload-sarif: true
        env:
          CERTISIGMA_API_KEY: ${{ secrets.CERTISIGMA_API_KEY }}
```

### Bulk leak detection in CI

Scan a large directory (up to 50K hashes/call) in report-only mode:

```yaml
name: Census Bulk Scan
on:
  schedule:
    - cron: "0 3 * * 1" # every Monday at 3 AM

jobs:
  bulk-scan:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      security-events: write
    steps:
      - uses: actions/checkout@v4

      - uses: certisigma/census-action@v1
        with:
          command: bulk-scan
          target: ./exports
          source: weekly-scan
          exit-zero: true
          upload-sarif: true
        env:
          CERTISIGMA_API_KEY: ${{ secrets.CERTISIGMA_API_KEY }}
```

### Pin Census version for reproducibility

```yaml
- uses: certisigma/census-action@v1
  with:
    command: integrity
    manifest: ./inventory.db
    version: "1.7.1"
```

### Pass extra CLI arguments

```yaml
- uses: certisigma/census-action@v1
  with:
    command: scan
    target: ./src
    extra-args: "--include '*.py' --max-size 50M --workers 4"
  env:
    CERTISIGMA_API_KEY: ${{ secrets.CERTISIGMA_API_KEY }}
```

## Security

- **API key is masked** in workflow logs via `::add-mask::` (before Census runs)
- **No shell injection**: all inputs are passed via `env:` context (never interpolated in `run:` blocks)
- **Permissions**: `contents: read` for checkout and scans; **`security-events: write`** is required when `upload-sarif: true` or the CodeQL upload step fails
- **Format validation**: `format: sarif` with any `command` other than `compare` fails the step with a clear error (SARIF is only implemented on `compare`)
- **`extra-args`**: expanded by the shell — use only static or org-controlled strings, never untrusted PR/issue text
- **Pinnable**: use `certisigma/census-action@v1` for stability, or pin to a commit SHA for maximum supply-chain security

## Step summary

Every run writes a Markdown summary to the GitHub Actions step summary, showing command, target, format, exit code, and result interpretation. Visible directly in the workflow run without opening logs.

## SARIF integration

When `format=sarif` (the default for `compare` only), Census writes SARIF v2.1.0 output. With `upload-sarif: true` (the default), the action uploads it via `github/codeql-action/upload-sarif@v3`. Results appear in the GitHub Security tab alongside other code scanning results.

Required permission: `security-events: write`. `bulk-scan` does not support SARIF; use `json` or `jsonl` for machine-readable bulk output.

## Exit codes

| Command | Exit 0 | Exit 1 |
|---------|--------|--------|
| `scan` | Success | Error |
| `integrity` | All files match | Discrepancies found |
| `compare` | No matches | Matches found (potential exfiltration) |
| `bulk-scan` | No matches | Matches found |

Use `exit-zero: true` to always exit 0 (report-only mode for non-blocking CI).

## Release checklist (maintainers)

1. **Before tag / PyPI** — full suite: `pytest` (includes [`tests/test_action.py`](../../tests/test_action.py) invariants on `action.yml`).
2. **After PyPI** — smoke the published wheel: `./scripts/test-census.sh X.Y.Z` (Docker). Ensures the version users pin in `with: version:` matches a working artifact.
