netbox-branch-review


Namenetbox-branch-review JSON
Version 0.2.0 PyPI version JSON
download
home_pageNone
SummaryBranch Review for NetBox
upload_time2025-08-18 17:29:17
maintainerNone
docs_urlNone
authorChris Hale
requires_python>=3.10
licenseNone
keywords netbox plugin change-management branch review approval
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Netbox-Branch-Review
Branch-aware change request & approval workflow for NetBox that can gate branch merges until a Change Request (CR) is approved.

## Features
- Create and track Change Requests linked to branches
- One- or two-level approvals (configurable)
- Merge gate: blocks merges until CR is approved or scheduled
- Simple UI actions: Approve and Merge from the CR detail page
- API serializers/viewset for integration
- Optional peer review action & audit log of approvals / merge events
 - Revoke (undo) approvals before implementation, resetting status to Pending

## Requirements
- NetBox 4.x
- Netbox-Branching plugin for branch operations (the merge gate integrates with it)
- Python 3.10+

## Installation
1) Install the plugin:
```sh
pip install netbox-branch-review 
```

2) Enable in NetBox configuration.py:
```python
PLUGINS = [
    "netbox_branch_review",
    "netbox_branching",
]

PLUGINS_CONFIG = {
    "netbox_branch_review": {
        # Require two approvals before merge (default: True)
        "require_two_approvals": True,
        # Enforce branching integration (default: True)
        "enforce_branching": True,
    # Approval implies branch changes are acceptable; merge button appears once approved.
    }
}
```

3) Migrate:
```sh
python manage.py migrate
```

4) Restart NetBox.

### Quick Start (Groups & Permissions)
Run the management command to create/sync default groups and permissions:
```bash
python manage.py sync_change_review
```
This will ensure:
- Group "Change Managers" gets approve / merge / peer review permissions.
- Group "Change Reviewers" gets only the peer review permission.

Customize names:
```bash
python manage.py sync_change_review --managers "My Managers" --reviewers "My Reviewers"
```
Skip peer group creation:
```bash
python manage.py sync_change_review --no-peer-group
```

## Usage
- Navigate to Plugins → Change Requests (menu declared in [`menu.py`](netbox_branch_review/menu.py))
- Create a CR (form: [`ChangeRequestForm`](netbox_branch_review/forms.py))
- The CR form includes an optional Ticket field for referencing external systems.
- From the CR page, Approve and Merge using the actions in the header
  - Template: [`templates/.../includes/changerequest_header.html`](netbox_branch_review/templates/netbox_branch_review/includes/changerequest_header.html)

See also: [Quick Tour with screenshots](docs/QUICKSTART.md).

### Approval & Peer Review Flow
Config key: `require_two_approvals` (default True)
Self full approval: `allow_self_full_approval` (default True) lets the CR creator (who has approval permission) fully approve in one action even when two approvals are normally required (records both levels in audit with an implicit second approval entry).

| Scenario               | Action 1                                                                      | Action 2                                                                     | Status progression                                                  |
| ---------------------- | ----------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | ------------------------------------------------------------------- |
| Two approvals required | First approval (different user recorded, or creator self-approval if allowed) | Second approval (must be different user unless self full approval triggered) | Pending → In review → Approved (or direct to Approved if self full) |
| Single approval mode   | First approval                                                                | (Further approvals blocked for same user)                                    | Pending → Approved                                                  |

Peer Review (optional): A user with only `peer_review_changerequest` can record a peer review before approval. Peer reviews do NOT change status; they are logged for audit & visibility.

Merge sets status to “Implemented”. Duplicate approvals or attempts after final approval are logged and safely ignored.

The merge gate validator [`require_cr_approved_before_merge`](netbox_branch_review/validators.py) enforces:
- Two approvals when configured
- Status must be Approved or Scheduled

## Permissions & Suggested Groups
Custom permissions defined on the model: [`ChangeRequest.Meta.permissions`](netbox_branch_review/models.py)

| Codename                  | Purpose                                        |
| ------------------------- | ---------------------------------------------- |
| approve_changerequest     | Perform L1/L2 approvals (depending on config)  |
| merge_changerequest       | Execute merge / implement action               |
| peer_review_changerequest | Record a peer review (no status change)        |
| revoke_changerequest      | Revoke existing approvals (pre-implementation) |

Because NetBox’s Group UI currently only lists standard model permissions in the multiselect, custom codenames may not appear for manual selection. The plugin’s `post_migrate` signal ensures they are created; you can assign them via shell if needed.

Suggested groups:
- Change Managers: `approve_changerequest`, `merge_changerequest` (optionally also `peer_review_changerequest`).
- Change Reviewers: `peer_review_changerequest` (and `view_changerequest` if not already provided globally).

Example shell assignment:
```bash
python manage.py shell -c "from django.contrib.auth.models import Group,Permission; mgr,_=Group.objects.get_or_create(name='Change Managers'); rev,_=Group.objects.get_or_create(name='Change Reviewers'); mgr.permissions.add(*Permission.objects.filter(codename__in=['approve_changerequest','merge_changerequest','peer_review_changerequest'])); rev.permissions.add(Permission.objects.get(codename='peer_review_changerequest'))"
```

Check a user’s effective perms:
```bash
python manage.py shell -c "from django.contrib.auth import get_user_model; u=get_user_model().objects.get(username='alice'); print([p for p in sorted(u.get_all_permissions()) if p.startswith('netbox_branch_review.')])"
```

## Audit Log
Each approval, peer review, merge, revoke, or blocked duplicate attempt writes an entry to `ChangeRequestAudit` (displayed on the CR detail page). The last 10 entries render as badges; extend as needed.

### Revoking Approvals (Undo)
Users with `revoke_changerequest` can revert a Change Request back to Pending (prior to implementation). This:
1. Creates audit entries for each revoked level (L2 then L1) plus a summary revoke_full entry.
2. Clears `approver_1`, `approver_2` and their timestamps.
3. Sets status to `pending`.

Limitations:
- Can't revoke after status reaches Implemented.
- Self full approvals (implicit level 2) will be fully cleared in one revoke action.

UI: A Revoke Approvals button appears when (a) the user has the permission, (b) the CR isn't implemented, and (c) at least one approval exists.

## API
- Serializer: [`ChangeRequestSerializer`](netbox_branch_review/api/serializers.py)
- ViewSet: [`ChangeRequestViewSet`](netbox_branch_review/api/views.py)

Note: Expose routes via the NetBox plugin API router as needed. The serializer exposes all CR fields, including ticket.

## Project layout
```
netbox-branch-review/
├── pyproject.toml
├── README.md
└── netbox_branch_review/
    ├── __init__.py
    # (plugin.py not used; configuration lives in __init__.py)
    ├── models.py
    ├── choices.py
    ├── forms.py
    ├── filtersets.py
    ├── tables.py
    ├── navigation.py
    ├── menu.py
    ├── urls.py
    ├── views.py
    ├── signals.py
    ├── validators.py
    ├── api/
    │   ├── __init__.py
    │   ├── serializers.py
    │   └── views.py
    ├── templates/
    │   └── netbox_branch_review/
    │       ├── changerequest_list.html
    │       ├── changerequest.html
    │       └── includes/
    │           └── changerequest_header.html
    └── migrations/
    ├── 0001_initial.py
    ├── 0002_add_description.py
    ├── 0003_merge.py
    └── 0004_add_comments.py
```

## Notes
- The plugin registers the merge gate during `ready()` by calling `register_pre_merge_validator()` if available (see [`__init__.py`](netbox_branch_review/__init__.py)). If the branching plugin is not present, merge enforcement gracefully no-ops, and UI will warn when branch data
- Default groups may also be auto-created during `post_migrate` based on plugin settings (see `__init__.py` and `signals.py`), but the management command provides a clear, repeatable onboarding step.

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "netbox-branch-review",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.10",
    "maintainer_email": null,
    "keywords": "netbox, plugin, change-management, branch, review, approval",
    "author": "Chris Hale",
    "author_email": null,
    "download_url": "https://files.pythonhosted.org/packages/12/bb/08dd5b9f73fdafc3c339ebc845ae9d18c80f71099b8f3793f89ef70b702f/netbox_branch_review-0.2.0.tar.gz",
    "platform": null,
    "description": "# Netbox-Branch-Review\nBranch-aware change request & approval workflow for NetBox that can gate branch merges until a Change Request (CR) is approved.\n\n## Features\n- Create and track Change Requests linked to branches\n- One- or two-level approvals (configurable)\n- Merge gate: blocks merges until CR is approved or scheduled\n- Simple UI actions: Approve and Merge from the CR detail page\n- API serializers/viewset for integration\n- Optional peer review action & audit log of approvals / merge events\n - Revoke (undo) approvals before implementation, resetting status to Pending\n\n## Requirements\n- NetBox 4.x\n- Netbox-Branching plugin for branch operations (the merge gate integrates with it)\n- Python 3.10+\n\n## Installation\n1) Install the plugin:\n```sh\npip install netbox-branch-review \n```\n\n2) Enable in NetBox configuration.py:\n```python\nPLUGINS = [\n    \"netbox_branch_review\",\n    \"netbox_branching\",\n]\n\nPLUGINS_CONFIG = {\n    \"netbox_branch_review\": {\n        # Require two approvals before merge (default: True)\n        \"require_two_approvals\": True,\n        # Enforce branching integration (default: True)\n        \"enforce_branching\": True,\n    # Approval implies branch changes are acceptable; merge button appears once approved.\n    }\n}\n```\n\n3) Migrate:\n```sh\npython manage.py migrate\n```\n\n4) Restart NetBox.\n\n### Quick Start (Groups & Permissions)\nRun the management command to create/sync default groups and permissions:\n```bash\npython manage.py sync_change_review\n```\nThis will ensure:\n- Group \"Change Managers\" gets approve / merge / peer review permissions.\n- Group \"Change Reviewers\" gets only the peer review permission.\n\nCustomize names:\n```bash\npython manage.py sync_change_review --managers \"My Managers\" --reviewers \"My Reviewers\"\n```\nSkip peer group creation:\n```bash\npython manage.py sync_change_review --no-peer-group\n```\n\n## Usage\n- Navigate to Plugins \u2192 Change Requests (menu declared in [`menu.py`](netbox_branch_review/menu.py))\n- Create a CR (form: [`ChangeRequestForm`](netbox_branch_review/forms.py))\n- The CR form includes an optional Ticket field for referencing external systems.\n- From the CR page, Approve and Merge using the actions in the header\n  - Template: [`templates/.../includes/changerequest_header.html`](netbox_branch_review/templates/netbox_branch_review/includes/changerequest_header.html)\n\nSee also: [Quick Tour with screenshots](docs/QUICKSTART.md).\n\n### Approval & Peer Review Flow\nConfig key: `require_two_approvals` (default True)\nSelf full approval: `allow_self_full_approval` (default True) lets the CR creator (who has approval permission) fully approve in one action even when two approvals are normally required (records both levels in audit with an implicit second approval entry).\n\n| Scenario               | Action 1                                                                      | Action 2                                                                     | Status progression                                                  |\n| ---------------------- | ----------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | ------------------------------------------------------------------- |\n| Two approvals required | First approval (different user recorded, or creator self-approval if allowed) | Second approval (must be different user unless self full approval triggered) | Pending \u2192 In review \u2192 Approved (or direct to Approved if self full) |\n| Single approval mode   | First approval                                                                | (Further approvals blocked for same user)                                    | Pending \u2192 Approved                                                  |\n\nPeer Review (optional): A user with only `peer_review_changerequest` can record a peer review before approval. Peer reviews do NOT change status; they are logged for audit & visibility.\n\nMerge sets status to \u201cImplemented\u201d. Duplicate approvals or attempts after final approval are logged and safely ignored.\n\nThe merge gate validator [`require_cr_approved_before_merge`](netbox_branch_review/validators.py) enforces:\n- Two approvals when configured\n- Status must be Approved or Scheduled\n\n## Permissions & Suggested Groups\nCustom permissions defined on the model: [`ChangeRequest.Meta.permissions`](netbox_branch_review/models.py)\n\n| Codename                  | Purpose                                        |\n| ------------------------- | ---------------------------------------------- |\n| approve_changerequest     | Perform L1/L2 approvals (depending on config)  |\n| merge_changerequest       | Execute merge / implement action               |\n| peer_review_changerequest | Record a peer review (no status change)        |\n| revoke_changerequest      | Revoke existing approvals (pre-implementation) |\n\nBecause NetBox\u2019s Group UI currently only lists standard model permissions in the multiselect, custom codenames may not appear for manual selection. The plugin\u2019s `post_migrate` signal ensures they are created; you can assign them via shell if needed.\n\nSuggested groups:\n- Change Managers: `approve_changerequest`, `merge_changerequest` (optionally also `peer_review_changerequest`).\n- Change Reviewers: `peer_review_changerequest` (and `view_changerequest` if not already provided globally).\n\nExample shell assignment:\n```bash\npython manage.py shell -c \"from django.contrib.auth.models import Group,Permission; mgr,_=Group.objects.get_or_create(name='Change Managers'); rev,_=Group.objects.get_or_create(name='Change Reviewers'); mgr.permissions.add(*Permission.objects.filter(codename__in=['approve_changerequest','merge_changerequest','peer_review_changerequest'])); rev.permissions.add(Permission.objects.get(codename='peer_review_changerequest'))\"\n```\n\nCheck a user\u2019s effective perms:\n```bash\npython manage.py shell -c \"from django.contrib.auth import get_user_model; u=get_user_model().objects.get(username='alice'); print([p for p in sorted(u.get_all_permissions()) if p.startswith('netbox_branch_review.')])\"\n```\n\n## Audit Log\nEach approval, peer review, merge, revoke, or blocked duplicate attempt writes an entry to `ChangeRequestAudit` (displayed on the CR detail page). The last 10 entries render as badges; extend as needed.\n\n### Revoking Approvals (Undo)\nUsers with `revoke_changerequest` can revert a Change Request back to Pending (prior to implementation). This:\n1. Creates audit entries for each revoked level (L2 then L1) plus a summary revoke_full entry.\n2. Clears `approver_1`, `approver_2` and their timestamps.\n3. Sets status to `pending`.\n\nLimitations:\n- Can't revoke after status reaches Implemented.\n- Self full approvals (implicit level 2) will be fully cleared in one revoke action.\n\nUI: A Revoke Approvals button appears when (a) the user has the permission, (b) the CR isn't implemented, and (c) at least one approval exists.\n\n## API\n- Serializer: [`ChangeRequestSerializer`](netbox_branch_review/api/serializers.py)\n- ViewSet: [`ChangeRequestViewSet`](netbox_branch_review/api/views.py)\n\nNote: Expose routes via the NetBox plugin API router as needed. The serializer exposes all CR fields, including ticket.\n\n## Project layout\n```\nnetbox-branch-review/\n\u251c\u2500\u2500 pyproject.toml\n\u251c\u2500\u2500 README.md\n\u2514\u2500\u2500 netbox_branch_review/\n    \u251c\u2500\u2500 __init__.py\n    # (plugin.py not used; configuration lives in __init__.py)\n    \u251c\u2500\u2500 models.py\n    \u251c\u2500\u2500 choices.py\n    \u251c\u2500\u2500 forms.py\n    \u251c\u2500\u2500 filtersets.py\n    \u251c\u2500\u2500 tables.py\n    \u251c\u2500\u2500 navigation.py\n    \u251c\u2500\u2500 menu.py\n    \u251c\u2500\u2500 urls.py\n    \u251c\u2500\u2500 views.py\n    \u251c\u2500\u2500 signals.py\n    \u251c\u2500\u2500 validators.py\n    \u251c\u2500\u2500 api/\n    \u2502   \u251c\u2500\u2500 __init__.py\n    \u2502   \u251c\u2500\u2500 serializers.py\n    \u2502   \u2514\u2500\u2500 views.py\n    \u251c\u2500\u2500 templates/\n    \u2502   \u2514\u2500\u2500 netbox_branch_review/\n    \u2502       \u251c\u2500\u2500 changerequest_list.html\n    \u2502       \u251c\u2500\u2500 changerequest.html\n    \u2502       \u2514\u2500\u2500 includes/\n    \u2502           \u2514\u2500\u2500 changerequest_header.html\n    \u2514\u2500\u2500 migrations/\n    \u251c\u2500\u2500 0001_initial.py\n    \u251c\u2500\u2500 0002_add_description.py\n    \u251c\u2500\u2500 0003_merge.py\n    \u2514\u2500\u2500 0004_add_comments.py\n```\n\n## Notes\n- The plugin registers the merge gate during `ready()` by calling `register_pre_merge_validator()` if available (see [`__init__.py`](netbox_branch_review/__init__.py)). If the branching plugin is not present, merge enforcement gracefully no-ops, and UI will warn when branch data\n- Default groups may also be auto-created during `post_migrate` based on plugin settings (see `__init__.py` and `signals.py`), but the management command provides a clear, repeatable onboarding step.\n",
    "bugtrack_url": null,
    "license": null,
    "summary": "Branch Review for NetBox",
    "version": "0.2.0",
    "project_urls": {
        "Homepage": "https://github.com/chale1342/netbox-branch-review",
        "Issues": "https://github.com/chale1342/netbox-branch-review/issues",
        "Source": "https://github.com/chale1342/netbox-branch-review"
    },
    "split_keywords": [
        "netbox",
        " plugin",
        " change-management",
        " branch",
        " review",
        " approval"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "9ca16a7d5bbcf8ccff61c17e186521ab2224695009109dfbff6cf5f739859415",
                "md5": "862e21320b477a90ed5dba26cabe1c6a",
                "sha256": "8f846f1e489a62bc907a2d18bddd3f68391ae4854e738e52108cd646e7c555bb"
            },
            "downloads": -1,
            "filename": "netbox_branch_review-0.2.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "862e21320b477a90ed5dba26cabe1c6a",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.10",
            "size": 27217,
            "upload_time": "2025-08-18T17:29:16",
            "upload_time_iso_8601": "2025-08-18T17:29:16.895822Z",
            "url": "https://files.pythonhosted.org/packages/9c/a1/6a7d5bbcf8ccff61c17e186521ab2224695009109dfbff6cf5f739859415/netbox_branch_review-0.2.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "12bb08dd5b9f73fdafc3c339ebc845ae9d18c80f71099b8f3793f89ef70b702f",
                "md5": "e2b45a33d271ec8e41394f54e404df50",
                "sha256": "0fe521f4cd9da237c13164b6a48885b4741df2488cb6a5e16887a87ebb7afcb1"
            },
            "downloads": -1,
            "filename": "netbox_branch_review-0.2.0.tar.gz",
            "has_sig": false,
            "md5_digest": "e2b45a33d271ec8e41394f54e404df50",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.10",
            "size": 22304,
            "upload_time": "2025-08-18T17:29:17",
            "upload_time_iso_8601": "2025-08-18T17:29:17.979104Z",
            "url": "https://files.pythonhosted.org/packages/12/bb/08dd5b9f73fdafc3c339ebc845ae9d18c80f71099b8f3793f89ef70b702f/netbox_branch_review-0.2.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-08-18 17:29:17",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "chale1342",
    "github_project": "netbox-branch-review",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "netbox-branch-review"
}
        
Elapsed time: 1.95766s