# Connect a git repository

Point Opafra at a repository so plans, scripts and templates are owned by git and changes go through review before they reach production.

Source: https://opafra.com/docs/security/connect-a-repository

---

Connecting a repository makes it the source of truth for plans, scripts and config
templates. Synced plans become read-only in the builder, so changes go through a pull
request instead of an edit box.

## Before you begin

You need the **Operator** role or above, and a repository containing at least one plan
file. Sync is one-way: Opafra reads and never writes back, so nothing you do here can
modify the repository.

## 1. Lay the repository out

Opafra reads three directories. Create the ones you need:

```text
plans/          plans
scripts/        shell scripts a plan can upload and run
templates/      config templates
```

These are the defaults and each can be changed. Blanking one stops that kind syncing at
all.

## 2. Add the source

Open **Git sources**, then add a source. Give it the repository URL, the branch, and how
Opafra authenticates:

```text
Repository   git@github.com:acme/infra-plans.git
Branch       main
Auth         GitHub App
```

Choose **GitHub App** where it is available. Clone credentials are then minted fresh for
each clone and expire on their own, so no long-lived token sits at rest. A personal access
token is stored encrypted and works everywhere.

## 3. Choose a sync mode

```text
Manual     syncs when you ask
Webhook    the repository notifies Opafra on push
Poll       Opafra checks periodically
```

Webhook is the right default for an active repository. It is authenticated with a shared
secret, so an unsigned request cannot trigger a sync.

## 4. Run the first sync

Trigger a sync from the source. Opafra clones the branch, hashes each file, and creates
what it finds.

## Verify it worked

The source shows the commit it synced and a summary of what changed:

```text title="git sources"
infra-plans (main)    synced    a1b2c3d    created 4, updated 0, removed 0
```

Open **Plans**. The synced plans are listed and marked as managed, and the builder shows
them as read-only. Editing is only possible through the repository.

Then confirm a re-sync is a no-op. Sync again without changing anything:

```text title="second sync"
infra-plans (main)    synced    a1b2c3d    created 0, updated 0, removed 0
```

Zeros are the proof that hashing works and that a sync will not churn your plans. A file
that failed to parse is reported by name rather than as a count, and does not stop the
rest of the sync.

## Next steps

- [Git sync](/docs/security/git-sync) for orphaned files, grouping and what is recorded
- [Plan structure](/docs/plans/structure) for what a plan file contains
