Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 11 additions & 7 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,16 +86,20 @@ env-scope, created-if-missing, and never mutated by `sync:app`.
### Audit is scope-first too (`audit` / `audit:environment` / `audit:app`)

Read-only counterpart to `sync` with the same scope split. `audit <env>` queries every resource tagged
`yolo:environment=<env>` via the Resource Groups Tagging API, classifies each as `ok` / `drift` / `rogue`, and
renders them grouped by scope. Sync stamps a positive ownership marker on everything it creates —
`yolo:app=<app>` for App-scope, `yolo:scope=env`/`=account` for shared infra — so the three statuses mean:
`yolo:environment=<env>` via the Resource Groups Tagging API, classifies each as `ok` or `unexpected`, and
renders them grouped by scope. Audit is an ownership/inventory check, **not** a config check — it reads tags, the
ARN service and whether the owning app's cluster is live, and never compares a resource's attributes against the
manifest (that's `sync`'s job, where "drift" means attribute mismatch). Sync stamps a positive ownership marker
on everything it creates — `yolo:app=<app>` for App-scope, `yolo:scope=env`/`=account` for shared infra — so:

- `ok` — `yolo:app` points at a live app, or `yolo:scope=env`/`=account` is present (declared shared infra)
- `drift` — `yolo:app` points at an app whose Fargate cluster is gone
- `rogue` — has `yolo:environment` but no YOLO ownership marker (alpha-era debris, or hand-rolled infra in the env namespace)
- `unexpected` — found in the env's tag namespace but not accounted for; a `reason` column says why:
- `no ownership tag` — no `yolo:app`/`yolo:scope` marker (hand-rolled, or alpha-era debris)
- `service no longer provisioned` — YOLO-owned but of an AWS service with no `Resources/` class, so sync would never recreate it (e.g. the DynamoDB sessions table left behind after DynamoDB support was removed). Surfaced via `Audit::SERVICE_BY_RESOURCE_GROUP`, whose keys mirror the `src/Resources/*` dirs (enforced by a test), so dropping a service dir auto-surfaces its leftovers and adding one fails until catalogued — no managed service is ever false-flagged
- `app cluster gone` — YOLO-owned, managed service, but `yolo:app` points at an app whose Fargate cluster is gone

`audit:environment <env>` narrows to env-tier rows; `audit:app <env> <app>` narrows to one app. `--drift` is a
universal flag — a no-op on `audit:environment` since env-scope resources never carry `yolo:app`.
`audit:environment <env>` narrows to env-tier rows; `audit:app <env> <app>` narrows to one app. `--unexpected`
is a universal flag that filters to just the rows needing attention.

### Steps (`src/Steps/`)

Expand Down
19 changes: 14 additions & 5 deletions docs/guide/provisioning.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,26 +124,35 @@ Writes that land in the fallback store during an outage are **not** synced back

## Auditing what's deployed

`yolo audit` is the read-only counterpart to `sync`. It queries every resource tagged `yolo:environment=<env>` and classifies each one:
`yolo audit` is the read-only counterpart to `sync`. It's an **ownership/inventory** check — it queries every resource tagged `yolo:environment=<env>` and asks "is this accounted for?". It does **not** inspect a resource's configuration; comparing live attributes against the manifest is `sync`'s job (and `sync`'s "drift" — config superseded — is a different thing from anything here).

```bash
yolo audit production
```

There are two statuses, and a **Reason** column explains every `unexpected` row:

| Status | Meaning |
|---|---|
| `ok` | Accounted for — `yolo:app` points at a live app, or it carries a `yolo:scope=env`/`=account` marker (declared shared infra). |
| `drift` | `yolo:app` points at an app whose ECS cluster is gone — leftover resources from a removed app. |
| `rogue` | Tagged for the environment but with **no** YOLO ownership marker — hand-rolled infrastructure or alpha-era debris in the environment's namespace. |
| `unexpected` | In the environment's tag namespace but not accounted for. See the Reason. |

| Reason (on `unexpected`) | Meaning |
|---|---|
| `no ownership tag` | **No** YOLO ownership marker (`yolo:app`/`yolo:scope`) — hand-rolled infrastructure, or alpha-era debris in the namespace. |
| `service no longer provisioned` | YOLO-owned, but of an AWS service YOLO no longer provisions — there's no `Resources/` class for it, so a sync would never create it. Left behind when support for a service is removed (the DynamoDB sessions table after DynamoDB sessions were dropped is the canonical case). Safe to delete once confirmed. |
| `app cluster gone` | YOLO-owned, managed service, but `yolo:app` points at an app whose ECS cluster no longer exists — leftover resources from a removed app. |

The `service no longer provisioned` check is driven by the catalogue of services YOLO has resource classes for, which mirrors the `src/Resources/*` directories. That makes it correct by construction: a managed service is never false-flagged, and the day a service is dropped its leftover resources surface automatically — no allow-list to keep in sync by hand.

::: tip The per-app dashboard isn't audited
`sync:app` also generates a CloudWatch dashboard (`yolo-<env>-<app>-dashboard`) panelling the app's ECS service, ALB, SQS queues, CloudFront, S3 and logs, plus an RDS panel derived from `DB_HOST`. CloudWatch dashboards can't carry tags, so it's a read-only convenience that **won't** show up in `yolo audit`.
:::

Like sync, audit is scope-grouped — narrow it with `audit:environment <env>` or `audit:app <env> <app>`, and add `--drift` to show only the drifted rows:
Like sync, audit is scope-grouped — narrow it with `audit:environment <env>` or `audit:app <env> <app>`, and add `--unexpected` to show only the rows needing attention:

```bash
yolo audit production --drift
yolo audit production --unexpected
yolo audit:app production myapp
```

Expand Down
20 changes: 10 additions & 10 deletions docs/reference/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Every YOLO command, with its arguments and options. Run `vendor/bin/yolo` with n
| [`sync:account <env>`](#yolo-sync-account) | Provision account-global resources |
| [`sync:environment <env>`](#yolo-sync-environment) | Provision environment-shared resources |
| [`sync:app <env>`](#yolo-sync-app) | Provision one app's resources |
| [`audit <env>`](#yolo-audit) | Audit tagged resources and flag drift |
| [`audit <env>`](#yolo-audit) | Audit tagged resources and flag anything unexpected |
| [`audit:environment <env>`](#yolo-audit-environment) | Audit environment-tier resources |
| [`audit:app <env> <app>`](#yolo-audit-app) | Audit one app's resources |

Expand Down Expand Up @@ -274,10 +274,10 @@ When a [`tasks.web.autoscaling`](/reference/manifest#tasks-web-autoscaling) bloc

## `yolo audit`

Audit YOLO-tagged resources for an environment (account → environment → app) and flag unexplained drift. Read-only.
Audit YOLO-tagged resources for an environment (account → environment → app) and flag anything not accounted for. Read-only.

```bash
yolo audit <environment> [--drift]
yolo audit <environment> [--unexpected]
```

| Argument | Required | Description |
Expand All @@ -286,9 +286,9 @@ yolo audit <environment> [--drift]

| Option | Value | Description |
|---|---|---|
| `--drift` | flag | Only show drift — resources tagged for an app that is no longer live. |
| `--unexpected` | flag | Only show unexpected resources — anything not accounted for by YOLO. |

Queries the Resource Groups Tagging API for everything tagged `yolo:environment=<env>` and classifies each resource as **`ok`**, **`drift`**, or **`rogue`** (see [Provisioning › Auditing](/guide/provisioning#auditing-what-s-deployed)). Results are grouped by scope, drift-first within a scope, with clickable AWS Console links where the terminal supports them.
Queries the Resource Groups Tagging API for everything tagged `yolo:environment=<env>` and classifies each resource as **`ok`** or **`unexpected`**, with a **Reason** explaining each unexpected row — `no ownership tag`, `service no longer provisioned`, or `app cluster gone` (see [Provisioning › Auditing](/guide/provisioning#auditing-what-s-deployed)). Audit is an ownership/inventory check; it does not inspect a resource's configuration (that's `sync`'s job). Results are grouped by scope, unexpected-first within a scope, with clickable AWS Console links where the terminal supports them.

---

Expand All @@ -297,10 +297,10 @@ Queries the Resource Groups Tagging API for everything tagged `yolo:environment=
Audit only the environment-tier resources for the given environment.

```bash
yolo audit:environment <environment> [--drift]
yolo audit:environment <environment> [--unexpected]
```

Arguments and options as [`audit`](#yolo-audit). Filters to environment-scope rows. Environment-scope resources never carry `yolo:app`, so `--drift` is a no-op here — drift is an app-scope concept.
Arguments and options as [`audit`](#yolo-audit). Filters to environment-scope rows. Environment-scope resources never carry `yolo:app`, but they can still be `unexpected` (an untagged resource in the namespace, or a leftover of a service YOLO no longer provisions), so `--unexpected` is meaningful here.

---

Expand All @@ -309,7 +309,7 @@ Arguments and options as [`audit`](#yolo-audit). Filters to environment-scope ro
Audit a single app's resources for the given environment.

```bash
yolo audit:app <environment> <app> [--drift]
yolo audit:app <environment> <app> [--unexpected]
```

| Argument | Required | Description |
Expand All @@ -319,6 +319,6 @@ yolo audit:app <environment> <app> [--drift]

| Option | Value | Description |
|---|---|---|
| `--drift` | flag | Only show drift for this app. |
| `--unexpected` | flag | Only show unexpected resources for this app. |

Filters the environment-wide report to rows whose `yolo:app` tag matches `<app>`, so only `ok` and `drift` rows for that app appear (a `rogue` resource has no `yolo:app`, so it never shows here).
Filters the environment-wide report to rows whose `yolo:app` tag matches `<app>`, so only `ok` and `unexpected` rows for that app appear (a resource with no `yolo:app` marker never shows here).
2 changes: 0 additions & 2 deletions docs/reference/manifest.md
Original file line number Diff line number Diff line change
Expand Up @@ -273,8 +273,6 @@ session:

On a web app, omitting `session` gives you the `redis` default; set a driver to override it. On a non-web app, `SESSION_DRIVER` is left to your `.env`.

> DynamoDB is no longer a supported session backend. A manifest still setting `session.driver: dynamodb` hard-fails validation with a pointer to `redis`.

---

## `tasks.web.*`
Expand Down
Loading