# `Choreo.Infrastructure.Analysis`
[🔗](https://github.com/code-shoily/choreo/blob/v0.14.1/lib/choreo/infrastructure/analysis.ex#L1)

Architectural analysis and security audits for `Choreo.Infrastructure`.

Provides automated audits for common cloud infrastructure configurations:
* Flagging direct internet connections to resources inside private subnets.
* Ensuring managed databases (`:managed_db`) and storage are isolated inside private subnets.
* Ensuring load balancers (`:load_balancer`) are placed within public subnets.
* Detecting compute nodes without subnet assignments.

# `direct_internet_violations`

```elixir
@spec direct_internet_violations(Choreo.Infrastructure.t() | Choreo.t()) :: [
  {Yog.node_id(), Yog.node_id()}
]
```

Returns a list of direct connection edge tuples `{from, to}` between public internet nodes
and private subnet resources.

## Examples

    iex> infra = Choreo.Infrastructure.new()
    iex> infra = infra
    ...>   |> Choreo.Infrastructure.add_internet(:gw)
    ...>   |> Choreo.Infrastructure.add_subnet_private("priv")
    ...>   |> Choreo.Infrastructure.add_compute(:app, cluster: "priv")
    ...>   |> Choreo.Infrastructure.connect(:gw, :app)
    iex> Choreo.Infrastructure.Analysis.direct_internet_violations(infra)
    [{:gw, :app}]

# `isolated_nodes`

```elixir
@spec isolated_nodes(Choreo.Infrastructure.t() | Choreo.t()) :: [Yog.node_id()]
```

Returns nodes with no connections (zero in-degree and out-degree).

## Examples

    iex> infra = Choreo.Infrastructure.new() |> Choreo.Infrastructure.add_compute(:orphan)
    iex> Choreo.Infrastructure.Analysis.isolated_nodes(infra)
    [:orphan]

# `misplaced_databases`

```elixir
@spec misplaced_databases(Choreo.Infrastructure.t() | Choreo.t()) :: [Yog.node_id()]
```

Returns a list of managed database node IDs located outside private subnets.

## Examples

    iex> infra = Choreo.Infrastructure.new() |> Choreo.Infrastructure.add_managed_db(:db)
    iex> Choreo.Infrastructure.Analysis.misplaced_databases(infra)
    [:db]

# `misplaced_load_balancers`

```elixir
@spec misplaced_load_balancers(Choreo.Infrastructure.t() | Choreo.t()) :: [
  Yog.node_id()
]
```

Returns a list of load balancer node IDs located outside public subnets.

## Examples

    iex> infra = Choreo.Infrastructure.new() |> Choreo.Infrastructure.add_load_balancer(:alb)
    iex> Choreo.Infrastructure.Analysis.misplaced_load_balancers(infra)
    [:alb]

# `misplaced_storage`

```elixir
@spec misplaced_storage(Choreo.Infrastructure.t() | Choreo.t()) :: [Yog.node_id()]
```

Returns a list of storage node IDs placed inside public subnets.

## Examples

    iex> infra = Choreo.Infrastructure.new()
    ...>   |> Choreo.Infrastructure.add_subnet_public("pub")
    ...>   |> Choreo.Infrastructure.add_storage(:s3, cluster: "pub")
    iex> Choreo.Infrastructure.Analysis.misplaced_storage(infra)
    [:s3]

# `unassigned_compute`

```elixir
@spec unassigned_compute(Choreo.Infrastructure.t() | Choreo.t()) :: [Yog.node_id()]
```

Returns a list of compute node IDs not assigned to any subnet.

## Examples

    iex> infra = Choreo.Infrastructure.new() |> Choreo.Infrastructure.add_compute(:app)
    iex> Choreo.Infrastructure.Analysis.unassigned_compute(infra)
    [:app]

# `validate`

```elixir
@spec validate(Choreo.Infrastructure.t() | Choreo.t()) :: [
  {:error | :warning, String.t()}
]
```

Runs analysis checks on the topology and returns a list of `{severity, message}` tuples.

## Examples

    iex> infra = Choreo.Infrastructure.new()
    iex> infra = infra
    ...>   |> Choreo.Infrastructure.add_internet(:gateway)
    ...>   |> Choreo.Infrastructure.add_subnet_private("subnet_app")
    ...>   |> Choreo.Infrastructure.add_compute(:api, cluster: "subnet_app")
    ...>   |> Choreo.Infrastructure.connect(:gateway, :api)
    iex> Choreo.Infrastructure.Analysis.validate(infra)
    [{:error, "Private resource 'api' is connected directly to public internet boundary 'gateway'."}]

---

*Consult [api-reference.md](api-reference.md) for complete listing*
