# OpenSCM Policy Store

Curated compliance policies for [OpenSCM](https://github.com/yarivha/OpenSCM).
The SaaS edition's **Policy Store** (`/store` sidebar entry) fetches the
index file from this repo and lets editors install, update, or re-install
any policy with one click.

## Contents

Sorted by (category, name) to match what the SaaS Policy Store renders
under each tab.

### Antivirus

| File | Source | Tests |
|---|---|---|
| `cis-defender-l1.json` | CIS Microsoft Defender Antivirus Benchmark v1.0.0 — Level 1 | 55 |

### Database

| File | Source | Tests |
|---|---|---|
| `cis-cassandra-4.0-l1.json` | CIS Apache Cassandra 4.0 Benchmark v1.3.0 — Level 1 | 6 |

### Linux

| File | Source | Tests |
|---|---|---|
| `cis-amazon-2-l1-server.json` | CIS Amazon Linux 2 Benchmark v4.0.0 — Level 1 Server | 224 |
| `cis-amazon-2023-l1-server.json` | CIS Amazon Linux 2023 Benchmark v1.0.0 — Level 1 Server | 79 |
| `cis-debian-11-l1-server.json` | CIS Debian Linux 11 (Bullseye) Benchmark v2.0.0 — Level 1 Server | 129 |
| `cis-debian-12-l1-server.json` | CIS Debian Linux 12 (Bookworm) Benchmark v1.1.0 — Level 1 Server | 134 |
| `cis-debian-13-l1-server.json` | CIS Debian Linux 13 Benchmark v1.0.0 — Level 1 Server | 141 |
| `cis-mint-22-l1-workstation.json` | CIS Linux Mint 22 Benchmark v1.0.0 — Level 1 Workstation | 111 |
| `cis-rhel-9-l1-server.json` | CIS Red Hat Enterprise Linux 9 Benchmark v2.0.0 — Level 1 Server | 123 |
| `cis-rhel-10-l1-server.json` | CIS Red Hat Enterprise Linux 10 Benchmark v1.0.1 — Level 1 Server | 135 |
| `cis-rocky-10-l1-server.json` | CIS Rocky Linux 10 Benchmark v1.0.0 — Level 1 Server | 135 |
| `cis-suse-15-l1-server.json` | CIS SUSE Linux Enterprise 15 Benchmark v2.0.1 — Level 1 Server | 131 |
| `cis-suse-16-l1-server.json` | CIS SUSE Linux Enterprise 16 Benchmark v1.0.0 — Level 1 Server | 133 |
| `cis-ubuntu-2404-l1-server.json` | CIS Ubuntu 24.04 LTS Benchmark v1.0.0 — Level 1 Server | 135 |
| `cis-ubuntu-2204-l1-server.json` | CIS Ubuntu Linux 22.04 LTS (Jammy) Benchmark v3.0.0 — Level 1 Server | 133 |
| `stig-ubuntu-2404-v1r5.json` | DISA STIG — Ubuntu 24.04 LTS V1R5 | 194 |

### Utility

| File | Source | Tests |
|---|---|---|
| `patch-management.json` | OpenSCM Team — missing security updates across distros | 5 |

### Web

| File | Source | Tests |
|---|---|---|
| `cis-apache-2.4-l1.json` | CIS Apache HTTP Server 2.4 Benchmark v2.3.0 — Level 1 | 15 |

### Windows

| File | Source | Tests |
|---|---|---|
| `cis-windows-10-enterprise-l1.json` | CIS Microsoft Windows 10 Enterprise Benchmark v4.0.0 — Level 1 | 343 |
| `cis-windows-11-enterprise-l1.json` | CIS Microsoft Windows 11 Enterprise Benchmark v5.0.1 — Level 1 | 348 |
| `stig-windows-server-2019-v3r8.json` | DISA STIG — Windows Server 2019 V3R8 | 171 |

## How the SaaS Policy Store consumes this repo

1. SaaS reads `index.json` from
   `https://repo.openscm.io/stable/policystore/index.json`
   (cached in-process for 5 minutes; the `Refresh` button on `/store`
   bypasses the cache).
2. Each policy card shows install status (Not installed / Installed /
   Update available) by comparing the index entry's `external_id` +
   `version` against the tenant's existing policies.
3. Clicking **Install** / **Update** / **Re-install** fetches the
   corresponding JSON file referenced by `file` and hands it to CE's
   shared `apply_policy_import` helper — same per-test upsert / unlink
   semantics as a manual file import.

A defensive check in the SaaS install handler rejects mismatches between
the entry's `external_id` and the payload's `policy.external_id`, so
**the two must line up** for any new policy added here.

## `index.json` schema

```json
{
  "version": 1,
  "updated_at": "ISO-8601 timestamp",
  "policies": [
    {
      "external_id": "<32-char hex — must match policy.external_id in the JSON file>",
      "name":         "<human-readable name>",
      "version":      "<semantic version>",
      "author":       "<organisation>",
      "description":  "<short description>",
      "category":     "Linux | Windows | Web | ...",
      "test_count":   <int>,
      "file":         "<filename relative to this directory>"
    }
  ]
}
```

`version`, `external_id`, `name`, and `file` are required. Everything
else is optional but recommended for richer cards in the UI.

### Category taxonomy

The `category` field controls how the SaaS Policy Store groups
policies in its UI (tab strip at the top of `/store`). Use one of:

| Category   | When to use |
| :---       | :--- |
| `Linux`    | OS hardening for Linux distros (Ubuntu, Debian, RHEL, SUSE, Amazon, etc.) |
| `Windows`  | OS hardening for Microsoft Windows |
| `macOS`    | OS hardening for Apple macOS |
| `Web`      | Web server / proxy software (Apache, Nginx, IIS, HAProxy) |
| `Database` | Database engines (MySQL, PostgreSQL, MongoDB, Cassandra, etc.) |
| `Network`  | Routers, switches, firewalls (Cisco, Juniper, Palo Alto) |
| `Container`| Docker, Kubernetes, OCI runtimes |
| `Cloud`    | AWS / Azure / GCP control-plane hardening |
| `Antivirus`| Endpoint AV / EDR products (Defender, etc.) |
| `Utility`  | Cross-platform OpenSCM-authored helper policies |

Unknown values still render (cards fall into a default tab) but won't
get their own tab — pick from the list above unless adding a new top-
level category that should appear in the UI.

## Adding a new policy

1. Drop the policy JSON file at the top level of this repo. Its
   `format_version` must be `3` and its top-level shape must follow the
   OpenSCM export format (see CE's `PolicyExport` struct).
2. Pick or generate an `external_id` for the policy — 32 lowercase
   hex chars. Use a deterministic seed (`md5("source-policy-name")`)
   so re-runs produce the same id.
3. Add the entry to `index.json`. Bump `updated_at`.
4. Verify with the cross-check script:
   ```bash
   python3 - <<'EOF'
   import json
   idx = json.load(open('index.json'))
   for e in idx['policies']:
       f = json.load(open(e['file']))
       assert f['policy']['external_id'] == e['external_id'], e['file']
       assert len(f['tests']) == e['test_count'], e['file']
   print("OK")
   EOF
   ```
5. Commit and push.

## Source material & converters

The CIS / STIG policies above were machine-converted from upstream PDFs
or JSON sources. Conversion scripts live separately for now (in `/tmp/`
during the original session); they can be moved into a `scripts/`
subdirectory of this repo if we want to regenerate from source without
re-extracting text each time.

Caveats from those automated conversions:

- **`cmd_enabled = true` is required on agents** for the bulk of the
  Linux CIS / STIG tests — most are `CMD`-element checks (sysctl,
  auditctl, find pipelines, etc.) which return `NA` unless the agent
  opts in.
- The OpenSCM tests check the **primary** condition per recommendation;
  the original CIS audit blocks are usually multi-step scripts that
  also verify secondary signals (e.g. "module blacklisted AND install
  → /bin/false AND not loaded"). The single-check approximation catches
  the obvious failure case but may pass on edge configurations that the
  upstream script would flag.
- Severities are uniformly `Medium` on the generated policies; CIS
  doesn't categorise severity, and we kept it neutral. Adjust per-test
  after import where you want different tiers.

## Repo layout

```
.
├── index.json                          # what the Policy Store fetches
├── README.md
├── stig-*.json                         # DISA STIG-derived policies
├── cis-*.json                          # CIS Benchmark-derived policies
└── patch-management.json               # OpenSCM-authored utility policies
```

Flat layout (no `stable/cis/`, `stable/stig/` subdirs) — chosen so the
public CDN URL stays short:
`repo.openscm.io/stable/policystore/<file>`.

## License & attribution

Policy content derived from CIS Benchmarks is © Center for Internet
Security and subject to the [CIS SecureSuite terms of
use](https://www.cisecurity.org/cis-securesuite/cis-securesuite-membership-terms-of-use/).
DISA STIG content is © U.S. Department of Defense and is in the public
domain.

OpenSCM-authored policies (e.g. `patch-management.json`) are released
under the same license as OpenSCM itself.
