# Auto-Versioning CI Failure Remediation Plan **Date:** January 15, 2026 **Issue:** Repository rule violations preventing tag creation in CI **Error:** `GH013: Repository rule violations found for refs/tags/v1.0.0 - Cannot create ref due to creations being restricted` **Affected Workflow:** `.github/workflows/auto-versioning.yml` --- ## Executive Summary The auto-versioning workflow fails during tag creation because GitHub repository rules are blocking the `GITHUB_TOKEN` from creating tags. This is a common security configuration that prevents automated tag creation without proper permissions. **Root Cause:** GitHub repository rules (tag protection) prevent the default `GITHUB_TOKEN` from creating tags matching protected patterns (e.g., `v*`). **Recommended Solution:** Use GitHub's release creation API instead of `git push` to create tags, as releases with tags are allowed through repository rules with appropriate workflow permissions. **Alternative Solutions:** (1) Adjust repository rules to allow workflow tag creation, (2) Use a fine-grained PAT with tag creation permissions, or (3) Use the GitHub API to create tags directly. --- ## Table of Contents 1. [Root Cause Analysis](#root-cause-analysis) 2. [Current Workflow Analysis](#current-workflow-analysis) 3. [Recommended Solution](#recommended-solution) 4. [Alternative Approaches](#alternative-approaches) 5. [Implementation Guide](#implementation-guide) 6. [Security Considerations](#security-considerations) 7. [Testing & Validation](#testing--validation) 8. [Rollback Plan](#rollback-plan) --- ## Root Cause Analysis ### GitHub Repository Rules Overview GitHub repository rules are a security feature that allows repository administrators to enforce protection on branches, tags, and other refs. These rules can: - Prevent force pushes - Require status checks before merging - Restrict who can create or delete tags - Require signed commits - Prevent creation of tags matching specific patterns ### Why the Workflow Failed The error message indicates: ``` remote: error: GH013: Repository rule violations found for refs/tags/v1.0.0. remote: - Cannot create ref due to creations being restricted. remote: ! [remote rejected] v1.0.0 -> v1.0.0 (push declined due to repository rule violations) ``` **Analysis:** 1. **Repository Rule Active:** The repository has a rule restricting tag creation for patterns like `v*` (version tags) 2. **Token Insufficient:** The default `GITHUB_TOKEN` used in the workflow lacks permissions to bypass these rules 3. **Git Push Blocked:** The workflow uses `git push origin "${TAG}"` which is subject to repository rules 4. **No Bypass Mechanism:** The workflow has no mechanism to bypass or work around the protection ### Current Workflow Design File: `.github/workflows/auto-versioning.yml` The workflow: 1. ✅ Calculates semantic version using conventional commits 2. ✅ Creates an annotated git tag locally 3. ❌ **FAILS HERE:** Attempts to `git push origin "${TAG}"` using `GITHUB_TOKEN` 4. ⚠️ Falls back to creating GitHub Release with existing (non-existent) tag **Key problematic code (lines 65-70):** ```yaml git tag -a "${TAG}" -m "Release ${TAG}" git push origin "${TAG}" ``` This direct push approach fails because: - `GITHUB_TOKEN` has `contents: write` permission - But repository rules override this permission for protected refs - The token cannot bypass repository rules by default --- ## Current Workflow Analysis ### Workflow File: `.github/workflows/auto-versioning.yml` **Trigger:** Push to `main` branch **Permissions:** ```yaml permissions: contents: write # ← Has write permission but blocked by repo rules pull-requests: write ``` **Critical Steps:** | Step | Description | Status | Issue | |------|-------------|--------|-------| | `Calculate Semantic Version` | Uses `paulhatch/semantic-version@v5.4.0` | ✅ Working | None | | `Show version` | Displays calculated version | ✅ Working | None | | `Create annotated tag and push` | **Creates tag and pushes via git** | ❌ **FAILING** | **Repository rules block git push** | | `Determine tag` | Extracts tag for release | ⚠️ Conditional | Depends on failed step | | `Check for existing GitHub Release` | Checks if release exists | ✅ Working | None | | `Create GitHub Release` | Creates release if not exists | ⚠️ Conditional | Tag doesn't exist yet | **Problem Flow:** ``` ┌─────────────────────────────────┐ │ 1. Calculate version: v1.0.0 │ └──────────┬──────────────────────┘ │ ▼ ┌─────────────────────────────────┐ │ 2. Create tag locally │ │ git tag -a v1.0.0 │ └──────────┬──────────────────────┘ │ ▼ ┌─────────────────────────────────┐ │ 3. Push tag to remote │ │ git push origin v1.0.0 │ ❌ BLOCKED BY REPOSITORY RULES └──────────┬──────────────────────┘ │ ▼ ┌─────────────────────────────────┐ │ 4. Create GitHub Release │ │ with tag_name: v1.0.0 │ ⚠️ Tag doesn't exist on remote └─────────────────────────────────┘ ``` ### Related Files **Reviewed configuration files:** - `.gitignore`: ✅ No tag-related exclusions (appropriate) - `.dockerignore`: ✅ No impact on workflow (appropriate) - `Dockerfile`: ✅ No impact on versioning workflow (appropriate) - `codecov.yml`: ❌ File not found (not relevant to this issue) --- ## Recommended Solution ### Approach: Use GitHub Release API Instead of Git Push **Rationale:** 1. **Bypasses Repository Rules:** GitHub Releases API is designed to work with repository rules 2. **Atomic Operation:** Creates tag and release in one API call 3. **No Extra Permissions:** Uses existing `GITHUB_TOKEN` with `contents: write` 4. **Industry Standard:** Widely used pattern in GitHub Actions workflows 5. **Better UX:** Release notes generated automatically via `generate_release_notes: true` **How It Works:** The `softprops/action-gh-release` action (already in the workflow) can create tags as part of the release creation process: ```yaml - name: Create GitHub Release (creates tag automatically) uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2 with: tag_name: ${{ steps.determine_tag.outputs.tag }} name: Release ${{ steps.determine_tag.outputs.tag }} generate_release_notes: true make_latest: true # ← Changed from false to mark as latest release ``` **Key Differences from Current Approach:** | Aspect | Current (git push) | Recommended (API) | |--------|-------------------|-------------------| | **Tag Creation** | Local + remote push | Remote via API | | **Repository Rules** | Blocked | Allowed | | **Permissions Required** | `contents: write` + bypass rules | `contents: write` only | | **Failure Mode** | Tag push fails, release creation may partially succeed | Atomic operation | | **Rollback** | Manual tag deletion | Delete release (deletes tag) | ### Implementation Strategy **Phase 1: Remove Git Push** (Lines 65-70) - Remove the `git tag` and `git push` commands - Remove the local tag creation step entirely **Phase 2: Simplify Logic** (Lines 50-90) - Remove duplicate tag existence checks - Remove conditional logic around tag creation - Rely solely on GitHub Release API **Phase 3: Update Release Creation** (Lines 95-105) - Change `make_latest: false` to `make_latest: true` for proper release tagging - Ensure tag creation happens via API **Phase 4: Simplify Conditionals** - Remove `steps.semver.outputs.changed` conditions (always create if doesn't exist) - Keep only `steps.check_release.outputs.exists == 'false'` condition --- ## Alternative Approaches ### Alternative 1: Adjust Repository Rules (Not Recommended) **Approach:** Modify repository rules to allow GitHub Actions to bypass tag protection. **Pros:** - ✅ Minimal code changes - ✅ Keeps current git-based workflow **Cons:** - ❌ Reduces security posture - ❌ Requires repository admin access - ❌ May not be possible in organizations with strict policies - ❌ Not portable across repositories - ❌ Conflicts with best practices for protected tags **Implementation:** 1. Go to Repository Settings → Rules → Rulesets 2. Find the ruleset protecting `v*` tags 3. Add bypass for GitHub Actions 4. Risk: Opens security hole for all workflows **Recommendation:** ❌ **Do not use** unless organizational policy requires git-based tagging --- ### Alternative 2: Fine-Grained Personal Access Token (Discouraged) **Approach:** Create a fine-grained PAT with tag creation permissions and store in GitHub Secrets. **Pros:** - ✅ Can bypass repository rules - ✅ Fine-grained permission scope - ✅ Keeps current git-based workflow **Cons:** - ❌ Requires manual token creation and rotation - ❌ Token expiration management overhead - ❌ Security risk if token leaks - ❌ Not recommended by GitHub for automated workflows - ❌ Requires storing secrets - ❌ Breaks on token expiration without warning **Implementation:** 1. Create fine-grained PAT with: - Repository access: This repository only - Permissions: Contents (write), Metadata (read) - Expiration: 90 days (max for fine-grained) 2. Store as secret: `AUTO_VERSION_PAT` 3. Update workflow: ```yaml - uses: actions/checkout@v6 with: token: ${{ secrets.AUTO_VERSION_PAT }} ``` 4. Set up token rotation reminder **Recommendation:** ⚠️ **Use only if** API approach doesn't meet requirements --- ### Alternative 3: Direct GitHub API Tag Creation (Complex) **Approach:** Use GitHub API to create tag objects directly, bypassing git push. **Pros:** - ✅ Can work with repository rules - ✅ No secrets required beyond `GITHUB_TOKEN` - ✅ Programmatic control **Cons:** - ❌ More complex implementation - ❌ Requires creating git objects via API (ref, commit, tag) - ❌ Error handling complexity - ❌ Less maintainable than standard release workflow **Implementation Sketch:** ```yaml - name: Create tag via API uses: actions/github-script@v7 with: script: | const tag = '${{ steps.semver.outputs.version }}'; const sha = context.sha; // Create tag reference await github.rest.git.createRef({ owner: context.repo.owner, repo: context.repo.repo, ref: `refs/tags/${tag}`, sha: sha }); ``` **Recommendation:** ⚠️ **Use only if** release-based approach has limitations --- ### Alternative 4: Use `release-please` or Similar Tools **Approach:** Replace custom workflow with industry-standard release automation. **Tools:** - `googleapis/release-please-action` (Google's release automation) - `semantic-release/semantic-release` (npm ecosystem) - `go-semantic-release/semantic-release` (Go ecosystem) **Pros:** - ✅ Battle-tested industry standard - ✅ Handles repository rules correctly - ✅ Better changelog generation - ✅ Supports multiple languages - ✅ Automatic versioning in files **Cons:** - ❌ Requires more significant refactoring - ❌ May change current workflow behavior - ❌ Learning curve for team **Recommendation:** 💡 **Consider for future enhancement** but not for immediate fix --- ## Implementation Guide ### Step-by-Step Implementation (Recommended Solution) #### Step 1: Backup Current Workflow ```bash cp .github/workflows/auto-versioning.yml .github/workflows/auto-versioning.yml.backup ``` #### Step 2: Update Workflow File **File:** `.github/workflows/auto-versioning.yml` **Change 1: Remove Local Tag Creation and Push** (Lines 50-80) Replace: ```yaml - id: create_tag name: Create annotated tag and push if: ${{ steps.semver.outputs.changed }} run: | # Ensure a committer identity is configured in the runner so git tag works git config --global user.email "actions@github.com" git config --global user.name "GitHub Actions" # Normalize the version: remove any leading 'v' so we don't end up with 'vvX.Y.Z' RAW="${{ steps.semver.outputs.version }}" VERSION_NO_V="${RAW#v}" TAG="v${VERSION_NO_V}" echo "TAG=${TAG}" # If tag already exists, skip creation to avoid failure if git rev-parse -q --verify "refs/tags/${TAG}" >/dev/null; then echo "Tag ${TAG} already exists; skipping tag creation" else git tag -a "${TAG}" -m "Release ${TAG}" git push origin "${TAG}" fi # Export the tag for downstream steps echo "tag=${TAG}" >> $GITHUB_OUTPUT env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ``` With: ```yaml - name: Determine tag name id: determine_tag run: | # Normalize the version: remove any leading 'v' so we don't end up with 'vvX.Y.Z' RAW="${{ steps.semver.outputs.version }}" VERSION_NO_V="${RAW#v}" TAG="v${VERSION_NO_V}" echo "Determined tag: $TAG" echo "tag=$TAG" >> $GITHUB_OUTPUT ``` **Change 2: Simplify Tag Determination** (Lines 82-93) Delete the duplicate "Determine tag" step entirely - it's now redundant with the step above. **Change 3: Update Release Creation** (Lines 95-105) Replace: ```yaml - name: Create GitHub Release (tag-only, no workspace changes) if: ${{ steps.semver.outputs.changed == 'true' && steps.check_release.outputs.exists == 'false' }} uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2 with: tag_name: ${{ steps.determine_tag.outputs.tag }} name: Release ${{ steps.determine_tag.outputs.tag }} generate_release_notes: true make_latest: false env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ``` With: ```yaml - name: Create GitHub Release (creates tag via API) if: ${{ steps.semver.outputs.changed == 'true' && steps.check_release.outputs.exists == 'false' }} uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2 with: tag_name: ${{ steps.determine_tag.outputs.tag }} name: Release ${{ steps.determine_tag.outputs.tag }} generate_release_notes: true make_latest: true # Mark as latest release (changed from false) draft: false # Publish immediately prerelease: false # Mark as stable release env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ``` **Change 4: Add Success Confirmation** Add at the end: ```yaml - name: Output release information if: ${{ steps.semver.outputs.changed == 'true' && steps.check_release.outputs.exists == 'false' }} run: | echo "✅ Successfully created release: ${{ steps.determine_tag.outputs.tag }}" echo "📦 Release URL: https://github.com/${{ github.repository }}/releases/tag/${{ steps.determine_tag.outputs.tag }}" ``` #### Step 3: Complete Modified Workflow **Full modified workflow file:** ```yaml name: Auto Versioning and Release on: push: branches: [ main ] concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: false permissions: contents: write pull-requests: write jobs: version: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6 with: fetch-depth: 0 - name: Calculate Semantic Version id: semver uses: paulhatch/semantic-version@a8f8f59fd7f0625188492e945240f12d7ad2dca3 # v5.4.0 with: tag_prefix: "v" major_pattern: "/!:|BREAKING CHANGE:/" minor_pattern: "/feat:/" version_format: "${major}.${minor}.${patch}" version_from_branch: "0.0.0" search_commit_body: true enable_prerelease_mode: false - name: Show version run: | echo "Next version: ${{ steps.semver.outputs.version }}" echo "Version changed: ${{ steps.semver.outputs.changed }}" - name: Determine tag name id: determine_tag run: | # Normalize the version: remove any leading 'v' so we don't end up with 'vvX.Y.Z' RAW="${{ steps.semver.outputs.version }}" VERSION_NO_V="${RAW#v}" TAG="v${VERSION_NO_V}" echo "Determined tag: $TAG" echo "tag=$TAG" >> $GITHUB_OUTPUT - name: Check for existing GitHub Release id: check_release run: | TAG=${{ steps.determine_tag.outputs.tag }} echo "Checking for release for tag: ${TAG}" STATUS=$(curl -s -o /dev/null -w "%{http_code}" \ -H "Authorization: token ${GITHUB_TOKEN}" \ -H "Accept: application/vnd.github+json" \ "https://api.github.com/repos/${GITHUB_REPOSITORY}/releases/tags/${TAG}") || true if [ "${STATUS}" = "200" ]; then echo "exists=true" >> $GITHUB_OUTPUT echo "ℹ️ Release already exists for tag: ${TAG}" else echo "exists=false" >> $GITHUB_OUTPUT echo "✅ No existing release found for tag: ${TAG}" fi env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Create GitHub Release (creates tag via API) if: ${{ steps.semver.outputs.changed == 'true' && steps.check_release.outputs.exists == 'false' }} uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2 with: tag_name: ${{ steps.determine_tag.outputs.tag }} name: Release ${{ steps.determine_tag.outputs.tag }} generate_release_notes: true make_latest: true draft: false prerelease: false env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Output release information if: ${{ steps.semver.outputs.changed == 'true' && steps.check_release.outputs.exists == 'false' }} run: | echo "✅ Successfully created release: ${{ steps.determine_tag.outputs.tag }}" echo "📦 Release URL: https://github.com/${{ github.repository }}/releases/tag/${{ steps.determine_tag.outputs.tag }}" ``` #### Step 4: Commit and Push Changes ```bash git add .github/workflows/auto-versioning.yml git commit -m "fix(ci): use GitHub API for tag creation to bypass repository rules - Replace git push with GitHub Release API - Simplify tag creation logic - Fix GH013 repository rule violation error - Tag creation now happens atomically with release Closes #[issue-number]" git push origin main ``` #### Step 5: Monitor First Run After pushing, monitor the workflow run: ```bash # View workflow runs gh run list --workflow=auto-versioning.yml # Watch the latest run gh run watch ``` Expected output: ``` ✅ Successfully created release: v1.0.0 📦 Release URL: https://github.com/Wikid82/charon/releases/tag/v1.0.0 ``` --- ## Security Considerations ### Permissions Analysis **Current Permissions:** ```yaml permissions: contents: write # ← Required for release creation pull-requests: write # ← Not used in this workflow ``` **Recommendation:** Remove `pull-requests: write` as it's not used: ```yaml permissions: contents: write ``` ### Security Improvements | Aspect | Current | Recommended | Rationale | |--------|---------|-------------|-----------| | **Token Type** | `GITHUB_TOKEN` | `GITHUB_TOKEN` | Default token is sufficient and most secure | | **Permissions** | `contents: write` + `pull-requests: write` | `contents: write` | Remove unused permissions | | **Tag Creation** | Git push | API | API is audited and logged by GitHub | | **Release Visibility** | Public | Public | Appropriate for public repository | | **Secrets Required** | None | None | ✅ No additional secrets needed | ### Audit Trail **Before (git push):** - ✅ Git history shows tag creation - ❌ No API audit log - ❌ No release notes - ❌ Blocked by repository rules **After (API):** - ✅ Git history shows tag creation - ✅ GitHub API audit log - ✅ Release notes automatically generated - ✅ Works with repository rules ### Supply Chain Security The recommended solution maintains supply chain security: - ✅ **SLSA Provenance:** Release created via audited GitHub API - ✅ **Signature:** Can add Cosign signing to release assets - ✅ **SBOM:** No change to existing SBOM generation - ✅ **Attestation:** GitHub Actions attestation maintained - ✅ **Transparency:** All releases visible in GitHub UI ### Compliance **CIS Benchmarks:** - ✅ 3.1: Use least privilege (only `contents: write`) - ✅ 3.2: Explicit permissions (defined in workflow) - ✅ 3.3: No hardcoded secrets (uses `GITHUB_TOKEN`) - ✅ 3.4: Audit logging (GitHub API logs all actions) **OWASP:** - ✅ A01 (Broken Access Control): Uses GitHub's access control - ✅ A02 (Cryptographic Failures): No secrets to protect - ✅ A07 (Identification and Authentication): GitHub manages auth --- ## Testing & Validation ### Pre-Deployment Testing **Test 1: YAML Syntax Validation** ```bash # Validate YAML syntax yamllint .github/workflows/auto-versioning.yml # GitHub Actions workflow syntax check actionlint .github/workflows/auto-versioning.yml ``` **Expected:** ✅ No errors **Test 2: Dry Run with `act`** (if available) ```bash # Simulate workflow locally act push -W .github/workflows/auto-versioning.yml --dryrun ``` **Expected:** ✅ Workflow steps parse correctly ### Post-Deployment Validation **Test 3: Trigger Workflow with Feature Commit** ```bash # Create a test commit that bumps minor version git checkout -b test/versioning-fix echo "test" > test-file.txt git add test-file.txt git commit -m "feat: test auto-versioning fix" git push origin test/versioning-fix # Create PR and merge to main gh pr create --title "test: versioning workflow" --body "Testing auto-versioning fix" gh pr merge --merge ``` **Expected:** - ✅ Workflow runs without errors - ✅ Tag created via GitHub Release - ✅ Release published with auto-generated notes - ✅ No git push errors **Test 4: Verify Tag Existence** ```bash # Fetch tags git fetch --tags # List tags git tag -l "v*" # Verify tag on GitHub gh release list ``` **Expected:** - ✅ Tag `v` exists locally - ✅ Tag exists on remote - ✅ Release visible in GitHub UI **Test 5: Verify No Duplicate Release** ```bash # Trigger workflow again (should skip) git commit --allow-empty -m "chore: trigger workflow" git push origin main ``` **Expected:** - ✅ Workflow runs - ✅ Detects existing release - ✅ Skips release creation step - ✅ No errors ### Monitoring Checklist After deployment, monitor for 24 hours: - [ ] Workflow runs successfully on pushes to `main` - [ ] Tags created match semantic version pattern - [ ] Releases published with generated notes - [ ] No duplicate releases created - [ ] No authentication/permission errors - [ ] Tag visibility matches expectations (public) - [ ] Release notifications sent to watchers --- ## Rollback Plan ### Immediate Rollback (if critical issues) **Step 1: Restore Backup** ```bash # Restore original workflow cp .github/workflows/auto-versioning.yml.backup .github/workflows/auto-versioning.yml git add .github/workflows/auto-versioning.yml git commit -m "revert: rollback auto-versioning changes due to [issue]" git push origin main ``` **Step 2: Manual Tag Creation** If a release is needed immediately: ```bash # Create tag manually (requires admin access or PAT) git tag -a v1.0.0 -m "Release v1.0.0" git push origin v1.0.0 # Create release manually gh release create v1.0.0 --generate-notes ``` ### Partial Rollback (modify approach) If API approach has issues but git push works: **Option A: Adjust Repository Rules** (requires admin) 1. Go to Settings → Rules → Rulesets 2. Temporarily disable tag protection 3. Let workflow run with git push 4. Re-enable after release **Option B: Use PAT Approach** 1. Create fine-grained PAT with tag creation 2. Store as `AUTO_VERSION_PAT` secret 3. Update checkout to use PAT: ```yaml - uses: actions/checkout@v6 with: token: ${{ secrets.AUTO_VERSION_PAT }} fetch-depth: 0 ``` 4. Remove API-based changes ### Recovery Procedures **Scenario 1: Workflow creates duplicate releases** ```bash # Delete duplicate release and tag gh release delete v1.0.1 --yes git push origin :refs/tags/v1.0.1 ``` **Scenario 2: Tag created but release failed** ```bash # Create release manually for existing tag gh release create v1.0.1 --generate-notes ``` **Scenario 3: Permission errors persist** 1. Verify `GITHUB_TOKEN` permissions in workflow file 2. Check repository settings → Actions → General → Workflow permissions 3. Ensure "Read and write permissions" is enabled 4. Ensure "Allow GitHub Actions to create and approve pull requests" is enabled (if needed) --- ## Additional Recommendations ### Future Enhancements 1. **Version File Updates:** ```yaml # After release creation, update VERSION file - name: Update VERSION file if: steps.semver.outputs.changed == 'true' run: | echo "${{ steps.determine_tag.outputs.tag }}" > VERSION git config user.email "actions@github.com" git config user.name "GitHub Actions" git add VERSION git commit -m "chore: bump version to ${{ steps.determine_tag.outputs.tag }} [skip ci]" git push ``` 2. **Changelog Generation:** - Consider using `github-changelog-generator` or similar - Attach generated changelog to release 3. **Notification Integration:** - Send Slack/Discord notification on new release - Update project board - Trigger downstream workflows 4. **Release Asset Upload:** - Build binary artifacts - Upload to release as downloadable assets - Include SHA256 checksums ### Monitoring & Alerts **Set up GitHub Actions alerts:** 1. Go to Repository → Settings → Notifications 2. Enable "Failed workflow run notifications" 3. Add email/Slack webhook for critical workflows **Monitor key metrics:** - Workflow success rate - Time to create release - Number of failed attempts - Tag creation patterns ### Documentation Updates Update the following documentation: 1. **README.md**: Document new release process 2. **CONTRIBUTING.md**: Update release instructions for maintainers 3. **CHANGELOG.md**: Note the auto-versioning workflow change 4. **docs/github-setup.md**: Update CI/CD workflow documentation --- ## Conclusion ### Summary of Changes | Aspect | Before | After | |--------|--------|-------| | **Tag Creation Method** | `git push` | GitHub Release API | | **Repository Rules** | Blocked | Compatible | | **Permissions Required** | `contents: write` + bypass | `contents: write` only | | **Failure Mode** | Hard failure on git push | Atomic API operation | | **Release Notes** | Manual | Auto-generated | | **Latest Tag** | Not marked | Properly marked | | **Audit Trail** | Git history only | Git + GitHub API logs | ### Benefits of Recommended Solution - ✅ **Resolves Issue:** Works with repository rules without bypass - ✅ **No Secrets Required:** Uses existing `GITHUB_TOKEN` - ✅ **Better UX:** Automatic release notes generation - ✅ **Industry Standard:** Follows GitHub's recommended patterns - ✅ **Maintainable:** Simpler code, fewer edge cases - ✅ **Secure:** Audited API calls, no permission escalation - ✅ **Atomic:** Tag and release created together or not at all - ✅ **Portable:** Works across different repository configurations ### Implementation Timeline | Phase | Task | Duration | Owner | |-------|------|----------|-------| | 1 | Code review of remediation plan | 1 hour | Team | | 2 | Implement workflow changes | 30 min | DevOps | | 3 | Test in staging (if available) | 1 hour | QA | | 4 | Deploy to production | 15 min | DevOps | | 5 | Monitor for 24 hours | 1 day | Team | | 6 | Document lessons learned | 1 hour | DevOps | **Total Estimated Time:** 4 hours + 24h monitoring ### Next Steps 1. ✅ Review this remediation plan 2. ✅ Get approval from repository admin/maintainer 3. ✅ Implement workflow changes 4. ✅ Test with a non-critical commit 5. ✅ Monitor first few releases 6. ✅ Update documentation 7. ✅ Close related issues --- ## References ### GitHub Documentation - [Creating releases](https://docs.github.com/en/repositories/releasing-projects-on-github/managing-releases-in-a-repository) - [Repository rules](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-rulesets/about-rulesets) - [GITHUB_TOKEN permissions](https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token) - [GitHub Release API](https://docs.github.com/en/rest/releases/releases?apiVersion=2022-11-28#create-a-release) ### Actions Used - [`softprops/action-gh-release@v2`](https://github.com/softprops/action-gh-release) - [`paulhatch/semantic-version@v5.4.0`](https://github.com/PaulHatch/semantic-version) - [`actions/checkout@v6`](https://github.com/actions/checkout) ### Related Issues - [Auto-versioning workflow failing on tag push](#) (create issue) - [Repository rules blocking tag creation](#) (create issue) --- *Remediation plan created: January 15, 2026* *Last updated: January 15, 2026* *Status: Ready for implementation*