> ## Documentation Index
> Fetch the complete documentation index at: https://docs.formal.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Socket

> Proxy public package registries through a Socket Registry Firewall

export const G = ({term, anchor, children}) => {
  const href = anchor ? `/docs/glossary/index#${anchor}` : `/docs/glossary/index`;
  return <a href={href} className="glossary-link" style={{
    textDecoration: "underline",
    textDecorationLine: "underline",
    textDecorationColor: "#6b7280",
    textDecorationThickness: "1px",
    textUnderlineOffset: "2px",
    color: "inherit",
    transition: "text-decoration-color 0.2s ease",
    borderBottom: "none"
  }} onMouseEnter={e => e.target.style.textDecorationColor = "#fff"} onMouseLeave={e => e.target.style.textDecorationColor = "#6b7280"}>
  {children || term}
</a>;
};

## Overview

A Socket resource routes package manager traffic through a Socket Registry
Firewall. Formal applies access policies and sends matching registry requests to
the firewall, which retrieves packages from the upstream registry.

```text theme={"languages":{"custom":["/languages/cel.json","/languages/rego.json"]}}
package manager  →  Formal  →  Socket Registry Firewall  →  origin registry
```

## Configure the Socket Registry Firewall

Configure the firewall to use
[path routing](https://docs.socket.dev/docs/socket-firewall-enterprise-registry-mode-configuration-reference).
Formal maps each supported package registry to the corresponding path:

| Ecosystem | Recognized hostnames                                                             | Expected `path` in `socket.yml` | Example rewrite                                                        |
| --------- | -------------------------------------------------------------------------------- | ------------------------------- | ---------------------------------------------------------------------- |
| npm       | `registry.npmjs.org`, `registry.npmjs.com`, `registry.yarnpkg.com`               | `/npm`                          | `registry.npmjs.org/lodash` → `/npm/lodash`                            |
| PyPI      | `pypi.org`, `pypi.python.org`, `files.pythonhosted.org`                          | `/pypi`                         | `pypi.org/simple/numpy/` → `/pypi/simple/numpy/`                       |
| Maven     | `repo1.maven.org`, `repo.maven.apache.org`                                       | `/maven`                        | `repo1.maven.org/maven2/org/foo` → `/maven/org/foo`                    |
| Cargo     | `crates.io`, `index.crates.io`, `static.crates.io`                               | `/cargo`                        | `crates.io/api/v1/crates/serde/...` → `/cargo/api/v1/crates/serde/...` |
| RubyGems  | `rubygems.org`, `index.rubygems.org`, `bundler.rubygems.org`                     | `/rubygems`                     | `rubygems.org/gems/rake-13.0.6.gem` → `/rubygems/gems/rake-13.0.6.gem` |
| OpenVSX   | `open-vsx.org`, `openvsx.eclipsecontent.org`, `openvsxorg.blob.core.windows.net` | `/openvsx`                      | `open-vsx.org/api/...` → `/openvsx/api/...`                            |
| NuGet     | `api.nuget.org`, `www.nuget.org`, `packages.nuget.org`, `globalcdn.nuget.org`    | `/nuget`                        | `api.nuget.org/v3/...` → `/nuget/v3/...`                               |
| Go        | `proxy.golang.org`                                                               | `/go`                           | `proxy.golang.org/github.com/...` → `/go/github.com/...`               |
| conda     | `repo.anaconda.com`                                                              | `/conda`                        | `repo.anaconda.com/pkgs/main/linux-64/...` → `/conda/linux-64/...`     |

Add a route for each ecosystem you want to proxy:

```yaml theme={"languages":{"custom":["/languages/cel.json","/languages/rego.json"]}}
path_routing:
  enabled: true
  domain: sfw.your_company.com
  routes:
    - path: /npm
      upstream: https://registry.npmjs.org
      registry: npm
    - path: /pypi
      upstream: https://pypi.org
      registry: pypi
    - path: /maven
      upstream: https://repo1.maven.org/maven2
      registry: maven
```

<Warning>
  Formal supports only Socket's
  [recommended path for each registry](https://docs.socket.dev/docs/socket-firewall-enterprise-registry-mode-configuration-reference#path-based-routing).
</Warning>

## Create a Socket Resource

Create a `socket` <G anchor="resource">resource</G> using the firewall's hostname
and port:

```hcl theme={"languages":{"custom":["/languages/cel.json","/languages/rego.json"]}}
resource "formal_resource" "socket_firewall" {
  name       = "socket-registry-firewall"
  technology = "socket"
  hostname   = "sfw.your_company.com"
  port       = 8443
}
```

### Configure Resource TLS

Formal must trust the certificate presented by the Socket Registry Firewall.
Export the CA certificate that issued the firewall's server certificate. If the
server certificate is self-signed, export that certificate instead.

In the Formal Console, add a TLS configuration to the Socket resource, select
**Verify Full**, and add the PEM-encoded certificate to the CA trust store. With
Terraform, use a `formal_resource_tls_configuration` resource:

```hcl theme={"languages":{"custom":["/languages/cel.json","/languages/rego.json"]}}
resource "formal_resource_tls_configuration" "socket_firewall" {
  resource_id       = formal_resource.socket_firewall.id
  tls_config        = "verify-full"
  tls_min_version   = "TLSv1.2"
  tls_ca_truststore = file("${path.module}/socket-firewall-ca.pem")
}
```

The firewall certificate must include the resource hostname in its subject
alternative names. This TLS configuration is used for direct Endpoint
connections and Connector connections. Connectors also use it when running
resource health checks.

See [Resource TLS Configuration](/docs/guides/core-concepts/resources/tls) for
the available verification modes.

If the firewall requires authentication, configure a
[Bearer Token Native User](/docs/guides/core-concepts/resources/http#native-users).

<Warning>
  Native User authentication is supported only when Socket traffic is routed
  through a Formal Connector.
</Warning>

## Route Package Manager Traffic

Create a network rule from the **Socket Registry Firewall** template. Select the
Socket resource, replace `sfw.your_company.com` with the firewall hostname, and
keep only the ecosystems configured in the firewall:

```cel theme={"languages":{"custom":["/languages/cel.json","/languages/rego.json"]}}
{
  "condition": {
    "pre_tls": (socket_ecosystem in ["npm", "pypi"] && !connection_process.is_browser) || hostname == "sfw.your_company.com",
    "post_tls": true
  },
  "outputs": {
    "resource_name": "socket-registry-firewall"
  }
}
```

The ecosystem condition intercepts requests to public package registries. The
hostname condition intercepts package download URLs returned by the firewall.
The browser exclusion prevents ordinary browser traffic to public registry
websites from matching the rule.

### Route Every Supported Ecosystem

Use the **Socket Registry Firewall (All)** template when `socket.yml` configures
every ecosystem listed above. The `is_socket_ecosystem` input matches any
hostname recognized as a supported Socket registry.

Replace `sfw.your_company.com` with your firewall hostname:

```cel theme={"languages":{"custom":["/languages/cel.json","/languages/rego.json"]}}
{
  "condition": {
    "pre_tls": (is_socket_ecosystem && !connection_process.is_browser) || hostname == "sfw.your_company.com",
    "post_tls": true
  },
  "outputs": {
    "resource_name": "socket-registry-firewall"
  }
}
```

<Warning>
  This template matches **all** supported Socket ecosystems. Do not use this template if your Socket firewall does not opt in to all supported ecosystems.
  Use the selective **Socket Registry Firewall** template instead.
</Warning>

### Without a Connector

Use this mode when each workstation running the Formal Endpoint can reach the
Socket Registry Firewall directly:

1. Install and enable the Formal Endpoint transparent proxy.
2. Make the firewall hostname resolvable and reachable from the workstation.
3. Select the Socket resource in the network rule.
4. Leave **Forward To Connector** disabled
   (`"forward_to_connector": false`).

Traffic follows this path:

```text theme={"languages":{"custom":["/languages/cel.json","/languages/rego.json"]}}
package manager  →  Formal Endpoint  →  Socket Registry Firewall
```

<Note>
  The Formal Endpoint does not apply Native User credentials in this mode. The
  firewall must accept the Endpoint's requests without Native User
  authentication.
</Note>

### With a Connector

Use this mode when the firewall is reachable only from the network where a
Formal Connector runs, or when the firewall requires authentication from
package manager clients.

1. Create a listener on the Connector.
2. Add a listener rule that points to the Socket resource.
3. Enable **Forward To Connector** in the network rule
   (`"forward_to_connector": true`).

For example:

```hcl theme={"languages":{"custom":["/languages/cel.json","/languages/rego.json"]}}
resource "formal_connector_listener" "socket_firewall" {
  connector_id = formal_connector.example.id
  name         = "socket-registry-firewall"
  port         = 9443
}

resource "formal_connector_listener_rule" "socket_firewall" {
  connector_listener_id = formal_connector_listener.socket_firewall.id
  type                  = "resource"
  rule                  = formal_resource.socket_firewall.id
}
```

The listener port is the port used to reach the Connector and does not need to
match the firewall resource port.

Traffic follows this path:

```text theme={"languages":{"custom":["/languages/cel.json","/languages/rego.json"]}}
package manager  →  Formal Endpoint  →  Formal Connector  →  Socket Registry Firewall
```

## Policy Evaluation

Socket's response headers are available to response policies through
`input.socket`. For example, the following policy blocks a request when the
firewall reports a fail-open decision:

```rego theme={"languages":{"custom":["/languages/cel.json","/languages/rego.json"]}}
package formal.v2

post_request := {
  "action": "block",
  "type": "block_with_formal_message",
  "reason": "Socket fail-open is not allowed",
} if {
  input.socket.decision == "fail_open"
}
```

### Socket Policy Input

`input.socket` can contain the following fields:

| Field             | Type             | Description                                                        |
| ----------------- | ---------------- | ------------------------------------------------------------------ |
| `ecosystem`       | string           | Package ecosystem for a public registry request                    |
| `decision`        | string           | Socket decision: `allowed`, `blocked`, `fail_open`, or `forbidden` |
| `request_id`      | string           | Socket request identifier                                          |
| `block_reasons`   | array of strings | Reasons Socket blocked the package                                 |
| `warn_reasons`    | array of strings | Reasons Socket warned about the package                            |
| `monitor_reasons` | array of strings | Reasons Socket marked the package for monitoring                   |
| `ignore_reasons`  | array of strings | Reasons Socket ignored findings                                    |
| `unscanned`       | boolean          | Whether Socket skipped scanning the artifact                       |

`ecosystem` is available when Formal classifies a supported public registry.

## Limitations

* Socket resources use the fixed path prefixes listed above. Custom path
  prefixes, domain-based routing, and Artifactory auto-discovery mode are not
  supported.
* Socket response bodies stream through Formal to the package manager and are
  not available to response-body policies. Response header rewrites and blocks
  remain supported.
