Share
## https://sploitus.com/exploit?id=AFB1D80C-48C2-5C6A-8F2E-2512DDEB2E4D
# GRC-OSCAL โ€” continuous compliance, demonstrated

A working proof of concept for **continuous, auditable compliance automation**.
It takes a real regulatory control all the way from a machine-readable catalog
through to a boardroom-ready statement โ€” fully automated, fully traceable,
100% open source, on a single VM or a single `docker compose up`.

---

## Why this matters

Traditional GRC runs on Word documents, screenshots and quarterly panic
cycles. This demo shows a different operating model:

- **Controls as code.** The control is written once, in OSCAL โ€” NIST's
  machine-readable grammar for risk and compliance. No ambiguity between what
  the policy says, what the auditor reads, and what the machine checks.
- **Evidence on demand.** A script pulls live configuration straight from the
  tenant in seconds. No ticket queue, no screenshot, no stale artefact.
- **Traceable by construction.** Every run produces a valid OSCAL Assessment
  Result. From regulator clause to executive statement every step is an
  auditable artefact with a UUID and a timestamp.
- **Boardroom-friendly.** The dashboard speaks plain language, but every tile
  on it is backed by the underlying OSCAL trace. Technical and non-technical
  stakeholders look at the same screen.
- **Always on.** The pipeline runs on demand, on a schedule, or on every
  commit to your infrastructure โ€” audit becomes a query, not a project.

Built around **one** sample control so the value is legible without drowning
in scope. The same pattern scales to a full control library.

---

## What you see

One ISO 27001 control โ€” **Annex A 8.5 ยท Secure authentication** โ€” narrowed
to a concrete objective:

> **Guest users accessing our resources must be protected by MFA.**

The demo pulls Conditional Access policies from Microsoft Entra via Microsoft
Graph, evaluates them against the control's criteria, writes the result as a
valid OSCAL Assessment Results document, stores it in Postgres with full
history, and renders the outcome in a fixed-viewport dashboard where every
stage of the pipeline is visible.

The **OSCAL chain** the demo produces and validates end-to-end:

```
 catalog   โ†’   profile   โ†’    SSP     โ†’   assessment plan   โ†’   assessment results
  the         the            the            how the             what happened,
 control     controls       system         control is            why, and
 library     we care        we are         evaluated             linked to
             about          assessing                            every policy
```

Three scenarios ship in the box:

| Scenario              | Evidence source        | Expected outcome                                |
|-----------------------|------------------------|-------------------------------------------------|
| Compliant (mock)      | bundled fixture        | pass ยท low risk                                 |
| Non-compliant (mock)  | bundled fixture        | fail ยท high risk ยท points at the disabled policy |
| Live tenant           | Microsoft Graph        | whatever your real Entra configuration says     |

---

## Quick start

Two supported paths. **Use Docker if you just want to see it work.** The native
path is there if you want to iterate on the code.

### 1. Recommended โ€” Docker only

Requirements: Docker Engine with the Compose v2 plugin. Nothing else.

```bash
git clone https://github.com/yopazerbot/grc-demo-poc-oscal.git
cd grc-demo-poc-oscal
cp .env.example .env                          # edit POSTGRES_PASSWORD (required)
docker compose --profile full up -d --build   # builds the API image, starts Postgres + API
```

The `--build` flag ensures Compose builds the image locally instead of
trying to pull `grc-oscal-api` from a registry (it isn't published). The
`Makefile` target `make compose-up` already does this; only include
`--build` when running `docker compose` directly.

Open [http://127.0.0.1:8000](http://127.0.0.1:8000).

Seed one compliant and one non-compliant run so the dashboard has history:

```bash
docker compose exec api bash scripts/run_pipeline.sh --mock-pass
docker compose exec api bash scripts/run_pipeline.sh --mock-fail
```

Stop:

```bash
docker compose --profile full down
```

### 2. Native โ€” install on a Linux VM

Requirements: Ubuntu 24.04 (or similar) with sudo access. Convenient when you
want hot-reload while editing Python, React, or OSCAL JSON.

```bash
sudo mkdir -p /opt/grc-lab && sudo chown "$USER:$USER" /opt/grc-lab
git clone https://github.com/yopazerbot/grc-demo-poc-oscal.git /opt/grc-lab/repo
cd /opt/grc-lab/repo

sudo bash scripts/bootstrap.sh        # installs Docker, Python venv, oscal-cli
cp .env.example .env                  # edit POSTGRES_PASSWORD
make demo                             # builds SPA, seeds pass + fail, starts the UI
```

Open [http://127.0.0.1:8000](http://127.0.0.1:8000). Run `make` with no target
for the full command menu.

---

## Configuration

Every secret and host-specific value lives in `.env` (gitignored). The only
required value is `POSTGRES_PASSWORD` โ€” everything else has a sensible default.

### Optional โ€” live Microsoft Graph mode

To run the pipeline against a real Entra tenant instead of the bundled
fixtures, you need an app registration with **`Policy.Read.All`** (application
permission) and admin consent:

1. **Entra ID โ†’ App registrations โ†’ New registration** (any name).
2. Note the **Application (client) ID** and the **Directory (tenant) ID**.
3. **Certificates & secrets โ†’ New client secret** โ€” copy the *value*.
4. **API permissions โ†’ Microsoft Graph โ†’ Application permissions โ†’
   `Policy.Read.All` โ†’ Grant admin consent**.

You can supply those three values **either way**:

- **Durable** โ€” put them in `.env` (persists across restarts):
  ```
  AZURE_TENANT_ID=...
  AZURE_CLIENT_ID=...
  AZURE_CLIENT_SECRET=...
  ```
- **In-session** โ€” click the **โš™ gear icon** in the dashboard header to open
  the **Settings drawer**, paste them in, hit *Save*. Values live only in the
  API process memory for the current session and are gone on restart.
  Useful during a live demo or when you don't want credentials on disk yet.
  The secret is never echoed back by the API; it can only be overwritten or
  cleared.

The header pill flips from **`mocks only`** to **`live ready`** once all three
Azure keys are set (from either source). `POSTGRES_*` is intentionally **not**
editable at runtime โ€” changing DB creds mid-flight would desync the API from
the database.

No tenant? Skip this section. The `mock-pass` and `mock-fail` scenarios are
deterministic and travel in the repo; the evaluator takes the identical code
path for live and mock evidence.

---

## Repository layout

```
grc-demo-poc-oscal/
โ”œโ”€โ”€ catalog/                 OSCAL catalog (one ISO 27001 control)
โ”œโ”€โ”€ profile/                 OSCAL profile (selects a-8-5 from the catalog)
โ”œโ”€โ”€ ssp/                     System Security Plan (Demo Intranet + Entra ID)
โ”œโ”€โ”€ assessment/              assessment plan + generated results (gitignored)
โ”œโ”€โ”€ evidence/
โ”‚   โ”œโ”€โ”€ mock/                bundled compliant + non-compliant fixtures
โ”‚   โ””โ”€โ”€ runs/                live evidence captures (gitignored)
โ”œโ”€โ”€ scripts/                 collect, evaluate, generate, store, api, pipeline
โ”œโ”€โ”€ dashboard/               React 19 + Vite 6 + Tailwind v4 SPA
โ”œโ”€โ”€ docker-compose.yml       postgres (default) + full-stack API (profile)
โ”œโ”€โ”€ Dockerfile               multi-stage build: SPA + Python + oscal-cli
โ””โ”€โ”€ Makefile                 one-word commands for the whole demo
```

---

## The pipeline

Four stages, wrapped by one command:

```
 collect evidence  โ†’  evaluate  โ†’  generate OSCAL AR  โ†’  store in Postgres
```

Run it once:

```bash
# Docker path
docker compose exec api bash scripts/run_pipeline.sh --mock-pass
docker compose exec api bash scripts/run_pipeline.sh --mock-fail
docker compose exec api bash scripts/run_pipeline.sh --live

# Native path
make run          # mock-pass
make run-fail     # mock-fail
make run-live     # live
```

Exit codes: `0` = control passed, `1` = control failed (control is
non-compliant โ€” the pipeline itself was healthy), `>1` = infrastructure
error. Re-runs are idempotent on `run_id`; the row is upserted, never
duplicated.

### OSCAL validation

Every artefact is validated strictly through
[compliance-trestle](https://github.com/IBM/compliance-trestle)'s pydantic
models. When NIST [`oscal-cli`](https://github.com/usnistgov/oscal-cli) is
available, it runs as a second opinion against the official metaschema.

```bash
make validate              # native
make compose-validate      # Docker
```

A failure leaves the file on disk for inspection and surfaces the first
schema violation.

---

## The dashboard

Fixed-viewport single-page app (React 19 ยท Vite 6 ยท Tailwind v4 ยท
framer-motion). Seven panels on a 4ร—2 grid:

| Row | Panels                                                           |
|-----|------------------------------------------------------------------|
| 1   | Control ยท Evidence ยท Evaluation ยท OSCAL                          |
| 2   | Decision ยท Runtime (spans 2 cols) ยท Executive                    |

Highlights:

- **FlowTimeline** at the top shows the current stage of the pipeline; clickable,
  with left-to-right filling connectors and a pulsing active indicator.
- **ScenarioSwitcher** flips between compliant-mock, non-compliant-mock, and
  live in one click.
- **Settings drawer** (โš™ in the header) โ€” paste Azure credentials (and display
  labels like `ORG_NAME` / `TENANT_LABEL`) into the UI without editing `.env`
  or restarting. Values are held in the API process memory for the current
  session. The header pill reports **`live ready`** as soon as all three Azure
  keys are present (from the drawer or `.env`).
- **Abstracted code visibility** โ€” each panel carries a small 4-6 line code
  snippet card with `input โ†’` / `output โ†’` chips, so the audience sees the
  logic behind each stage without a firehose of source.
- **Keyboard**: `R` run ยท `โ†` / `โ†’` step through stages ยท `0` reset ยท `T` theme.

### API routes

The SPA is driven by a small FastAPI backend, bound to `127.0.0.1` only.

| Route                         | Purpose                                                                      |
|-------------------------------|------------------------------------------------------------------------------|
| `GET    /api/health`          | liveness + DB reachability                                                   |
| `GET    /api/artifacts`       | compact metadata for every OSCAL artefact in the chain                       |
| `GET    /api/runs?limit=N`    | recent rows from `assessment_runs`                                           |
| `GET    /api/runs/latest`     | latest row                                                                   |
| `GET    /api/runs/{run_id}`   | full row with raw evidence + OSCAL Assessment Results                        |
| `POST   /api/runs`            | trigger the full pipeline (body: `{ "mode": "mock-pass\|mock-fail\|live" }`) |
| `GET    /api/settings`        | per-key status of runtime-adjustable env vars (no secret values echoed)      |
| `PUT    /api/settings`        | set / clear runtime env overrides (body: `{ "values": { KEY: "value", ... } }`) |
| `DELETE /api/settings`        | wipe every runtime env override                                              |

---

## Auto-start on boot (native path only)

Two systemd units under `scripts/systemd/` make the stack come up on reboot:

```bash
sudo bash scripts/install-services.sh     # idempotent
systemctl status grc-postgres grc-api
journalctl -u grc-api -f

sudo bash scripts/uninstall-services.sh   # clean removal (keeps DB + .env)
```

The installer templates the units with `$SUDO_USER` and `$GRC_LAB_DIR`, so
the same scripts work whether you installed under `/opt/grc-lab` or a custom
path. Not needed with Docker โ€” `docker compose`'s `restart: unless-stopped`
already handles it.

---

## Command reference

```bash
make                      # show the full target list
```

Frequent targets:

| Target                | What it does                                         |
|-----------------------|------------------------------------------------------|
| `make demo`           | Build SPA, seed pass + fail, start the UI (native)   |
| `make compose-up`     | Full stack in containers                             |
| `make run` / `run-fail` / `run-live` | One pipeline run                      |
| `make validate`       | Validate every OSCAL artefact                        |
| `make history`        | Recent assessment runs from Postgres                 |
| `make status`         | systemd + docker + recent runs at a glance           |
| `make reset`          | Drop DB volume + generated artefacts (destructive)   |

---

## Design principles

- **Everything via `.env`.** No secret or host-specific value is committed.
- **Idempotent by default.** Every script can be re-run without worry. No
  duplicate rows, no half-written artefacts.
- **Same code path for mock and live.** The evaluator does not know whether
  evidence came from Microsoft Graph or a bundled fixture.
- **Portable.** Scripts resolve the Python interpreter in order: `$GRC_PY` โ†’
  `./.venv` โ†’ `${GRC_LAB_DIR}/.venv` โ†’ `PATH`. OSCAL artefacts reference each
  other with relative paths.
- **One codebase, two deployment shapes.** Docker-only and native installation
  share the same scripts, artefacts, and dashboard.

---

## Extending the demo

Adding a second control is a few targeted edits, not a rewrite:

1. Append the control to `catalog/iso-27001-2022-subset.json`.
2. Select it in `profile/demo-profile.json`.
3. Implement it in `ssp/demo-intranet.json` (new `implemented-requirement` +
   `statement`).
4. Add per-criterion checks + an evaluator wrapper in `scripts/evaluate.py`.
5. Add a scenario in `dashboard/src/data/scenarios.ts`.

The pipeline and the dashboard generalise over the set; the OSCAL chain stays
coherent because every step is strictly validated.

---

## Reference

- **OSCAL** โ€” [https://pages.nist.gov/OSCAL/](https://pages.nist.gov/OSCAL/)
- **compliance-trestle** โ€” [https://github.com/IBM/compliance-trestle](https://github.com/IBM/compliance-trestle)
- **NIST oscal-cli** โ€” [https://github.com/usnistgov/oscal-cli](https://github.com/usnistgov/oscal-cli)
- **Microsoft Graph โ€” Conditional Access** โ€”
  [https://learn.microsoft.com/graph/api/resources/conditionalaccesspolicy](https://learn.microsoft.com/graph/api/resources/conditionalaccesspolicy)