diff --git a/.gitignore b/.gitignore index 2556e45e..769e943d 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ node_modules/ test-results/ nexus/__pycache__/ tests/__pycache__/ +.aider* diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 00000000..73ae6989 --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1,5 @@ +@perplexity @Timmy +/nexus/* @Timmy +/hermes/* @perplexity +/timmy-home/* @Rockachopa +/timmy-config/* @Rockachopa diff --git a/README.md b/README.md index a9a791cf..79a271fc 100644 --- a/README.md +++ b/README.md @@ -99,3 +99,26 @@ The browser-facing Nexus must be rebuilt deliberately through the migration back --- *One 3D repo. One migration path. No more ghost worlds.* +# Branch Protection Policy + +**All repositories enforce the following branch protection rules for the `main` branch:** + +1. **Require Pull Request before merge** - All changes must go through PR process +2. **Require 1 approving review** - At least one reviewer must approve before merge +3. **Dismiss stale approvals** - Approvals are automatically dismissed on new commits +4. **Require status checks to pass** - CI/CD must pass before merge (where applicable) +5. **Block force pushes** - Prevents rewriting of commit history +6. **Block branch deletion** - Prevents accidental deletion of main branch + +**Default Reviewers:** +- @perplexity - All repositories +- @Timmy - nexus repository +- @Rockachopa - timmy-home and timmy-config + +**CI/CD Requirements:** +- hermes-agent: Full CI enforcement +- the-nexus: CI disabled (runner issue #915) +- timmy-home: No CI +- timmy-config: No CI + +For CI/CD status, see the [health dashboard](/webhook_health_dashboard) diff --git a/gitea_protect_branch.py b/gitea_protect_branch.py new file mode 100644 index 00000000..a6a421d7 --- /dev/null +++ b/gitea_protect_branch.py @@ -0,0 +1,58 @@ +import os +import requests +from datetime import datetime + +GITEA_TOKEN = os.getenv('GITEA_TOKEN') +GITEA_API = os.getenv('GITEA_API_URL', 'https://forge.alexanderwhitestone.com/api/v1') + +REPOS_PROTECTION = { + 'hermes-agent': { + 'required_pull_request_reviews': {'required_approving_review_count': 1}, + 'required_status_checks': {'strict': True, 'contexts': ['ci/circleci']}, + 'enforce_admins': True, + 'required_linear_history': False, + 'allow_force_push': False, + 'allow_deletions': False + }, + 'the-nexus': { + 'required_pull_request_reviews': {'required_approving_review_count': 1}, + 'required_status_checks': {'strict': False}, + 'enforce_admins': True, + 'required_linear_history': False, + 'allow_force_push': False, + 'allow_deletions': False + }, + 'timmy-home': { + 'required_pull_request_reviews': {'required_approving_review_count': 1}, + 'required_status_checks': {'strict': False}, + 'enforce_admins': True, + 'required_linear_history': False, + 'allow_force_push': False, + 'allow_deletions': False + }, + 'timmy-config': { + 'required_pull_request_reviews': {'required_approving_review_count': 1}, + 'required_status_checks': {'strict': False}, + 'enforce_admins': True, + 'required_linear_history': False, + 'allow_force_push': False, + 'allow_deletions': False + } +} + +def protect_branch(owner, repo, protection): + url = f"{GITEA_API}/repos/{owner}/{repo}/branches/main/protection" + headers = { + 'Authorization': f'token {GITEA_TOKEN}', + 'Content-Type': 'application/json' + } + + response = requests.put(url, json=protection, headers=headers) + if response.status_code == 200: + print(f"Protected {owner}/{repo} main branch") + else: + print(f"Failed to protect {owner}/{repo}: {response.text}") + +if __name__ == "__main__": + for repo, protection in REPOS_PROTECTION.items(): + protect_branch("Timmy_Foundation", repo, protection)