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

# Oso Migrate (Beta)

> Develop on Oso Cloud with confidence using automated comparison and debugging tools.

<Note>
  **Prerequisites:** Oso Dev Server v1.18.0+ and the [development tools setup](/develop/local-dev/env-setup).
</Note>

## Features

* **Parity checking**: Compare authorization decisions side-by-side between your legacy system and Oso Cloud.
* **Request replay**: Replay authorization requests after policy updates.
* **Authorization logging**: View full request history with timestamps, queries, results, and data snapshots.
* **Policy debugger**: Inspect query evaluation in an interactive tree view.
* **Test integration**: Export logged requests into tests with real data snapshots.

## Installation

### Binary (macOS/Linux)

You can download and run the Oso Dev Server binary directly, no additional tooling required.

#### Download the Binary

To download the latest macOS ARM64 build:

```bash theme={null}
curl --location https://oso-local-development-binary.s3.amazonaws.com/latest/oso-local-development-binary-macos-arm64.tar.gz | tar xz && chmod +x standalone && mv standalone oso-dev-server
```

This command fetches the latest tarball, extracts the binary, marks it executable, and renames it to `oso-dev-server`.

**Other Available Builds:**

Replace the platform suffix in the URL to download the appropriate binary for your system:

* `linux-arm64`
* `linux-x86_64`
* `macos-x86_64`

Example:

```bash theme={null}
curl --location https://oso-local-development-binary.s3.amazonaws.com/latest/oso-local-development-binary-linux-x86_64.tar.gz \
  | tar xz && chmod +x standalone && mv standalone oso-dev-server
```

#### Run the Dev Server

**Single policy file:**

```bash theme={null}
./oso-dev-server migrate-ui policy.polar
```

**Multiple policy files with auto-reload:**

```bash theme={null}
./oso-dev-server migrate-ui policy1.polar policy2.polar --watch-for-changes
```

### Docker (Windows/All Platforms)

Use Docker for cross-platform compatibility:

**Single policy file:**

```bash theme={null}
docker run -it -p 8080:8080 \
  --mount type=bind,src=./policy.polar,dst=/app/policy.polar \
  public.ecr.aws/osohq/dev-server:latest migrate-ui /app/policy.polar
```

**Multiple policy files:**

```bash theme={null}
docker run -it -p 8080:8080 \
  --mount type=bind,src=./policies,dst=/app/policies \
  --entrypoint sh \
  public.ecr.aws/osohq/dev-server:latest \
  -c './oso-dev-server migrate-ui /app/policies/*.polar'
```

## Implementation Example

Use `ParityHandle` to compare authorization decisions:

```typescript theme={null}
import { Oso, ParityHandle, Value } from "oso-cloud";

const oso = new Oso(
  "http://localhost:8080",
  "e_0123456789_12345_osotesttoken01xiIn"
);

async function authorizeWithParityCheck(
  userId: string,
  action: string,
  resource: Value
): Promise<boolean> {
  const parityHandle = new ParityHandle();
  const user = { type: "User", id: userId };

  // Run both systems in parallel
  const osoPromise = oso.authorize(user, action, resource, { parityHandle });
  const legacyPromise = legacyAuthorize(userId, action, resource);

  const [_, legacyResult] = await Promise.allSettled([
    osoPromise,
    legacyPromise
  ]);

  // Record expected result for comparison
  parityHandle.expect(legacyResult);

  // Continue using legacy result during migration
  return legacyResult;
}
```

**Flexible integration:** Call `parityHandle.expect()` at any point in the request flow to accommodate non-centralized authorization logic (one call per request).

## Policy Debugger Guide

Understand how the Policy Debugger visualizes authorization queries.

**Query tree structure:**
Each query appears as an expandable tree showing:

* Different ways the query could succeed (OR logic)
* Subconditions required for success (AND logic)
* Current evaluation path you're inspecting

**Reading the interface:**

```text theme={null}
▶  allow(User{"alice"}, "view", Content{"foo"})   ← ● ○ →
```

* **Arrow (▶/▼):** Expand/collapse query
* **Color:** Green = succeeded, Red = failed
* **Dots (● ○):** Different possible resolution paths
* **Solid dot:** Currently viewed path

**Detailed evaluation:**

```text theme={null}
▼  allow(User{"alice"}, "view", Content{"foo"})   ← ● ○ →
   ▼  has_permission(User{"alice"}, "view", Content{"foo"})   ← ○ ● ○ ○ →
      ▼  has_role(User{"alice"}, "CanView", Folder{"foo-folder"})   ●
         ♦ (fact)
      ▼  has_relation(Content{"foo"}, "folder", Folder{"foo-folder"})   ●
         ♦ (fact)
```

**Negation handling:**

* `not` nodes succeed only when all wrapped expressions fail
* Visual indicators show which expressions were true/false

## Advanced Configuration

<AccordionGroup>
  <Accordion title="Local Authorization setup">
    Enable data snapshots for Local Authorization with database connections.

    **Basic setup:**

    ```bash theme={null}
    ./oso-dev-server migrate-ui *.polar\
      --local-authorization-config config.yaml \
      --connection-string postgresql://postgres:password@localhost:5432/postgres  
    ```

    **Supported databases:** PostgreSQL only

    **What you get:**

    * Complete data snapshots from your database
    * Centralized view of authorization data
    * No need to actually centralize your data
  </Accordion>

  <Accordion title="Local Authorization with Dockerized Postgres">
    Some developers prefer running PostgreSQL in a Docker container, especially for local development or integration tests. If you’re using **local authorization snapshotting** with Oso Migrate against a Dockerized Postgres instance, additional setup is required.

    Under the hood, local authorization snapshotting works by having Postgres write a data dump to a temporary directory created by Oso Migrate. For this to work, **both Oso Migrate and the Postgres container must be able to read and write to the same temporary directory**. This requires mounting OS-specific temp paths into the Postgres container.

    > Not using local authorization? You can skip this entire section.

    **macOS/Linux (running Oso Migrate via binary):**

    The temporary directory path depends on your operating system.

    On macOS, temporary directories are created under `/var/folders`. You must mount this path into the Postgres container.

    ```bash theme={null}
    # Start PostgreSQL with volume mount
    docker run -p 5432:5432 \
      -e POSTGRES_PASSWORD=password \
      --volume /var/folders:/var/folders \
      -d postgres:latest

    # Start Oso Migrate (connects to host PostgreSQL)
    ./oso-dev-server migrate-ui policy.polar \
      --connection-string postgresql://postgres:password@localhost:5432/postgres \
      --local-authorization-config config.yaml
    ```

    On Linux, temporary directories are created under `/tmp`. Mount `/tmp` into the Postgres container.

    ```bash theme={null}
    # Start PostgreSQL with volume mount
    docker run -p 5432:5432 \
      -e POSTGRES_PASSWORD=password \
      --volume /tmp:/tmp \
      -d postgres:latest

    # Start Oso Migrate (connects to host PostgreSQL)
    ./oso-dev-server migrate-ui policy.polar \
      --connection-string postgresql://postgres:password@localhost:5432/postgres \
      --local-authorization-config config.yaml  
    ```

    **Windows (running Oso Migrate via Docker):**

    When running both Postgres and Oso Migrate in Docker (common on Windows), you must:

    * Create a shared Docker network
    * Mount `/tmp` into both containers

    This ensures the temporary snapshot directory is shared and the containers can communicate.

    Create a shared network:

    ```bash theme={null}
    docker network create my-app
    ```

    Start Postgres with a shared `/tmp` directory:

    ```bash theme={null}
    docker run -p 5432:5432 \
      -e POSTGRES_PASSWORD=password \
      --volume /tmp:/tmp \
      --network my-app \
      --name postgres \
      -d postgres:latest
    ```

    Start Oso Migrate on the same network with the same `/tmp` volume:

    ```bash theme={null}
    docker run -it -p 8080:8080 \
      --mount type=bind,src=./policy.polar,dst=/app/policy.polar \
      --mount type=bind,src=./config.yaml,dst=/app/config.yaml \
      --volume /tmp:/tmp \
      --network my-app \
      public.ecr.aws/osohq/dev-server:latest migrate-ui /app/policy.polar \
      --connection-string postgresql://postgres:password@postgres:5432/postgres \
      --local-authorization-config /app/config.yaml
    ```

    This configuration ensures that `/tmp` on the host, the Postgres container, and the Oso Migrate container all point to the same directory, allowing snapshotting to function correctly.
  </Accordion>

  <Accordion title="Telemetry and privacy">
    Oso collects anonymous usage analytics to improve the product.

    **What we collect:**

    * Policy update events (with hashed policy content)
    * Usage patterns (anonymous)

    **Your privacy:**

    * We cannot identify you from the analytics
    * All data is anonymized

    **Opt out:**

    ```bash theme={null}
    # Disable telemetry
    ./oso-dev-server analytics off

    # Or set environment variable
    export OSO_DISABLE_TELEMETRY=1
    ```
  </Accordion>
</AccordionGroup>

## Troubleshooting

<AccordionGroup>
  <Accordion title="Migration interface issues">
    **Can't access localhost:8080:**

    * Verify Oso Migrate is running: check terminal for startup messages
    * Check port conflicts: `lsof -i :8080`
    * Try different port: add `--port 9000` to startup command

    **Policy not loading:**

    * Verify file path is correct and accessible
    * Check for syntax errors in Polar policy files
    * Review startup logs for detailed error messages
  </Accordion>

  <Accordion title="Parity checking problems">
    **Expected results not showing:**

    * Ensure `parityHandle.expect()` is called once per request
    * Verify legacy authorization function is returning correct values
    * Check timing - call `expect()` after both systems complete

    **Mismatches not appearing:**

    * Confirm both authorization calls are using the same parameters
    * Verify data consistency between systems
    * Check request context and timing
  </Accordion>

  <Accordion title="Database connection issues">
    **PostgreSQL connection fails:**

    * Verify connection string format and credentials
    * Check database is accessible from Oso Migrate
    * For Docker: ensure network connectivity between containers

    **Snapshots not appearing:**

    * Confirm Local Authorization config file is valid
    * Check database permissions for dump operations
    * Verify temp directory mounting for Docker setups
  </Accordion>
</AccordionGroup>

## Migration resources

* [Set up local development](/develop/local-dev/oso-dev-server) with the Dev Server
* [Write authorization policies](/develop/policies/overview) using Polar
* [Model your data as facts](/develop/facts/overview) for authorization decisions
* [Implement authorization checks](/develop/enforce/authorize-requests) in your application
