# Branch and Tag Protection API

Base URL: `${FORGEJO_URL}/api/v1`

## Branch Protection

### List Branch Protections

```
GET /repos/{owner}/{repo}/branch_protections
```

```bash
curl -s \
  -H "Authorization: token ${FORGEJO_PAT}" \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/branch_protections"
```

**Response:** Array of `BranchProtection` objects (see schema below).

---

### Create Branch Protection

```
POST /repos/{owner}/{repo}/branch_protections
```

### BranchProtection Fields

| Field | Type | Description |
|-------|------|-------------|
| rule_name | string | Protection rule name (supports glob patterns like `release/*`) |
| branch_name | string | **Deprecated.** Use `rule_name` instead |
| enable_push | boolean | Allow pushes to the branch |
| enable_push_whitelist | boolean | Restrict push to whitelisted users/teams |
| push_whitelist_usernames | array | Usernames allowed to push |
| push_whitelist_teams | array | Teams allowed to push |
| push_whitelist_deploy_keys | boolean | Allow deploy keys to push |
| enable_merge_whitelist | boolean | Restrict merging to whitelisted users/teams |
| merge_whitelist_usernames | array | Usernames allowed to merge |
| merge_whitelist_teams | array | Teams allowed to merge |
| required_approvals | integer | Minimum number of approvals required |
| enable_approvals_whitelist | boolean | Restrict who can approve |
| approvals_whitelist_username | array | Usernames whose approvals count |
| approvals_whitelist_teams | array | Teams whose approvals count |
| dismiss_stale_approvals | boolean | Dismiss approvals when new commits are pushed |
| ignore_stale_approvals | boolean | Ignore stale approvals instead of dismissing |
| block_on_rejected_reviews | boolean | Block merge if any review requests changes |
| block_on_outdated_branch | boolean | Block merge if branch is behind base |
| block_on_official_review_requests | boolean | Block merge if official review requests are pending |
| enable_status_check | boolean | Require status checks to pass |
| status_check_contexts | array | Required status check context names |
| require_signed_commits | boolean | Require GPG-signed commits |
| protected_file_patterns | string | Glob patterns for protected files (semicolon-separated) |
| unprotected_file_patterns | string | Glob patterns for unprotected files (semicolon-separated) |
| apply_to_admins | boolean | Apply protection rules to admins too |

### Basic protection with required approvals

```bash
curl -s -X POST \
  -H "Authorization: token ${FORGEJO_PAT}" \
  -H "Content-Type: application/json" \
  -d '{
    "rule_name": "{rule_name}",
    "enable_push": false,
    "required_approvals": 2,
    "dismiss_stale_approvals": true,
    "block_on_rejected_reviews": true,
    "block_on_outdated_branch": true
  }' \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/branch_protections"
```

### Protection with status checks

```bash
curl -s -X POST \
  -H "Authorization: token ${FORGEJO_PAT}" \
  -H "Content-Type: application/json" \
  -d '{
    "rule_name": "{rule_name}",
    "enable_push": false,
    "required_approvals": 1,
    "enable_status_check": true,
    "status_check_contexts": [
      "ci/build",
      "ci/test",
      "ci/lint"
    ],
    "dismiss_stale_approvals": true,
    "block_on_rejected_reviews": true,
    "block_on_outdated_branch": true,
    "require_signed_commits": false,
    "apply_to_admins": false
  }' \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/branch_protections"
```

### Protection with push and merge whitelists

```bash
curl -s -X POST \
  -H "Authorization: token ${FORGEJO_PAT}" \
  -H "Content-Type: application/json" \
  -d '{
    "rule_name": "release/*",
    "enable_push": true,
    "enable_push_whitelist": true,
    "push_whitelist_usernames": ["release-bot"],
    "push_whitelist_teams": ["release-managers"],
    "push_whitelist_deploy_keys": true,
    "enable_merge_whitelist": true,
    "merge_whitelist_usernames": ["lead-dev"],
    "merge_whitelist_teams": ["release-managers"],
    "required_approvals": 2,
    "enable_approvals_whitelist": true,
    "approvals_whitelist_username": ["senior-dev-1", "senior-dev-2"],
    "approvals_whitelist_teams": ["tech-leads"],
    "dismiss_stale_approvals": true,
    "block_on_rejected_reviews": true,
    "block_on_outdated_branch": true,
    "block_on_official_review_requests": true,
    "enable_status_check": true,
    "status_check_contexts": ["ci/build", "ci/test"],
    "apply_to_admins": true
  }' \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/branch_protections"
```

### Protection with file patterns

```bash
curl -s -X POST \
  -H "Authorization: token ${FORGEJO_PAT}" \
  -H "Content-Type: application/json" \
  -d '{
    "rule_name": "{rule_name}",
    "enable_push": true,
    "enable_push_whitelist": true,
    "push_whitelist_usernames": ["admin"],
    "protected_file_patterns": "*.lock;.forgejo/**;Dockerfile",
    "unprotected_file_patterns": "docs/**;README.md",
    "required_approvals": 1
  }' \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/branch_protections"
```

---

### Get Branch Protection

```
GET /repos/{owner}/{repo}/branch_protections/{name}
```

```bash
curl -s \
  -H "Authorization: token ${FORGEJO_PAT}" \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/branch_protections/{rule_name}"
```

---

### Edit Branch Protection

```
PATCH /repos/{owner}/{repo}/branch_protections/{name}
```

All fields from the create body are accepted. Only include fields you want to change.

```bash
curl -s -X PATCH \
  -H "Authorization: token ${FORGEJO_PAT}" \
  -H "Content-Type: application/json" \
  -d '{
    "required_approvals": 3,
    "enable_status_check": true,
    "status_check_contexts": ["ci/build", "ci/test", "ci/security"]
  }' \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/branch_protections/{rule_name}"
```

---

### Delete Branch Protection

```
DELETE /repos/{owner}/{repo}/branch_protections/{name}
```

```bash
curl -s -X DELETE \
  -H "Authorization: token ${FORGEJO_PAT}" \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/branch_protections/{rule_name}"
```

Returns `204 No Content` on success.

---

## Tag Protection

### List Tag Protections

```
GET /repos/{owner}/{repo}/tag_protections
```

```bash
curl -s \
  -H "Authorization: token ${FORGEJO_PAT}" \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/tag_protections"
```

**Response:** Array of `TagProtection` objects:
| Field | Type | Description |
|-------|------|-------------|
| id | integer | Protection rule ID |
| name_pattern | string | Tag name pattern (glob) |
| whitelist_usernames | array | Usernames allowed to create/delete matching tags |
| whitelist_teams | array | Teams allowed to create/delete matching tags |
| created_at | string | Creation timestamp |
| updated_at | string | Last update timestamp |

---

### Create Tag Protection

```
POST /repos/{owner}/{repo}/tag_protections
```

**Request Body (CreateTagProtectionOption):**
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| name_pattern | string | yes | Tag name pattern (supports glob like `v*`) |
| whitelist_usernames | array | no | Allowed usernames |
| whitelist_teams | array | no | Allowed team names |

### Protect all version tags

```bash
curl -s -X POST \
  -H "Authorization: token ${FORGEJO_PAT}" \
  -H "Content-Type: application/json" \
  -d '{
    "name_pattern": "v*",
    "whitelist_usernames": ["release-manager"],
    "whitelist_teams": ["release-team"]
  }' \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/tag_protections"
```

### Protect release candidate tags

```bash
curl -s -X POST \
  -H "Authorization: token ${FORGEJO_PAT}" \
  -H "Content-Type: application/json" \
  -d '{
    "name_pattern": "v*-rc*",
    "whitelist_usernames": ["{ci_username}"],
    "whitelist_teams": ["developers"]
  }' \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/tag_protections"
```

---

### Get Tag Protection

```
GET /repos/{owner}/{repo}/tag_protections/{id}
```

```bash
curl -s \
  -H "Authorization: token ${FORGEJO_PAT}" \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/tag_protections/{protection_id}"
```

---

### Edit Tag Protection

```
PATCH /repos/{owner}/{repo}/tag_protections/{id}
```

**Request Body (EditTagProtectionOption):**
| Field | Type | Description |
|-------|------|-------------|
| name_pattern | string | Updated tag pattern |
| whitelist_usernames | array | Updated allowed usernames |
| whitelist_teams | array | Updated allowed teams |

```bash
curl -s -X PATCH \
  -H "Authorization: token ${FORGEJO_PAT}" \
  -H "Content-Type: application/json" \
  -d '{
    "whitelist_usernames": ["release-manager", "backup-admin"],
    "whitelist_teams": ["release-team", "ops"]
  }' \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/tag_protections/{protection_id}"
```

---

### Delete Tag Protection

```
DELETE /repos/{owner}/{repo}/tag_protections/{id}
```

```bash
curl -s -X DELETE \
  -H "Authorization: token ${FORGEJO_PAT}" \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/tag_protections/{protection_id}"
```

Returns `204 No Content` on success.

---

## Example: Full protection setup for a repository

```bash
OWNER="{owner}"
REPO="{repo}"

# 1. Protect main branch
curl -s -X POST \
  -H "Authorization: token ${FORGEJO_PAT}" \
  -H "Content-Type: application/json" \
  -d '{
    "rule_name": "{rule_name}",
    "enable_push": false,
    "required_approvals": 2,
    "enable_status_check": true,
    "status_check_contexts": ["ci/build", "ci/test"],
    "dismiss_stale_approvals": true,
    "block_on_rejected_reviews": true,
    "block_on_outdated_branch": true,
    "apply_to_admins": true
  }' \
  "${FORGEJO_URL}/api/v1/repos/${OWNER}/${REPO}/branch_protections"

# 2. Protect release branches
curl -s -X POST \
  -H "Authorization: token ${FORGEJO_PAT}" \
  -H "Content-Type: application/json" \
  -d '{
    "rule_name": "release/*",
    "enable_push": true,
    "enable_push_whitelist": true,
    "push_whitelist_teams": ["release-managers"],
    "required_approvals": 1,
    "enable_status_check": true,
    "status_check_contexts": ["ci/build", "ci/test"]
  }' \
  "${FORGEJO_URL}/api/v1/repos/${OWNER}/${REPO}/branch_protections"

# 3. Protect version tags
curl -s -X POST \
  -H "Authorization: token ${FORGEJO_PAT}" \
  -H "Content-Type: application/json" \
  -d '{
    "name_pattern": "v*",
    "whitelist_teams": ["release-managers"]
  }' \
  "${FORGEJO_URL}/api/v1/repos/${OWNER}/${REPO}/tag_protections"

# 4. Verify protections
echo "=== Branch Protections ==="
curl -s \
  -H "Authorization: token ${FORGEJO_PAT}" \
  "${FORGEJO_URL}/api/v1/repos/${OWNER}/${REPO}/branch_protections" | jq '.[].rule_name'

echo "=== Tag Protections ==="
curl -s \
  -H "Authorization: token ${FORGEJO_PAT}" \
  "${FORGEJO_URL}/api/v1/repos/${OWNER}/${REPO}/tag_protections" | jq '.[].name_pattern'
```
