github-interaction-limits-hardening

Lock down public GitHub repositories so only collaborators can interact with issues, PRs, comments, discussions, and other user-generated surfaces using repository interaction limits; includes expiry verification and renewal handling.

5 stars

Best use case

github-interaction-limits-hardening is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Lock down public GitHub repositories so only collaborators can interact with issues, PRs, comments, discussions, and other user-generated surfaces using repository interaction limits; includes expiry verification and renewal handling.

Teams using github-interaction-limits-hardening should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/github-interaction-limits-hardening/SKILL.md --create-dirs "https://raw.githubusercontent.com/vamseeachanta/workspace-hub/main/.agents/skills/github/github-interaction-limits-hardening/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/github-interaction-limits-hardening/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How github-interaction-limits-hardening Compares

Feature / Agentgithub-interaction-limits-hardeningStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Lock down public GitHub repositories so only collaborators can interact with issues, PRs, comments, discussions, and other user-generated surfaces using repository interaction limits; includes expiry verification and renewal handling.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# GitHub Interaction Limits Hardening

## When to Use

Use this skill when a public GitHub repository or a set of repositories should remain readable but prevent outside/non-collaborator interactions, such as issue comments, PRs, discussions, or drive-by solicitation. Typical triggers include spam, paid-work solicitation, unwanted outside PRs, public repo hardening, or a request like "only collaborators can touch issues/code/PRs".

## Class of Task

Repo security hardening across one or more GitHub repositories by applying collaborator-only public interaction limits, verifying the live API state, and creating a renewal path because GitHub requires expiry.

## Key GitHub Constraints

- Repository interaction limits apply to **public repositories**.
- Private repositories return `405 Interaction limits cannot be set for private repositories`; private visibility already gates repo access to collaborators/members with access.
- Interaction limits are **temporary**; GitHub requires an `expiry`.
- Use the longest supported expiry, currently `six_months`, when the intent is durable lock-down.
- Add a renewal reminder or scheduled job before expiry if the setting should remain in force.
- This setting does **not** change repo visibility, collaborators, branch protection, or existing issue/comment history.

## Workflow

### 1. Authenticate and enumerate repos

```bash
gh auth status
gh api user --jq '.login'

OWNER=<owner-or-org>
mkdir -p /tmp/github-interaction-limits
gh repo list "$OWNER" --limit 1000 \
  --json nameWithOwner,visibility,isArchived,defaultBranchRef,hasIssuesEnabled,pushedAt,url \
  > /tmp/github-interaction-limits/repos.json

python3 - <<'PY'
import json
from collections import Counter
repos=json.load(open('/tmp/github-interaction-limits/repos.json'))
print('total', len(repos))
print(Counter((r['visibility'], r['isArchived']) for r in repos))
for r in repos:
    print(f"{r['nameWithOwner']}\t{r['visibility']}\tarchived={r['isArchived']}\tissues={r['hasIssuesEnabled']}")
PY
```

### 2. Create or update a tracking issue

For multi-repo changes, create a tracking issue first. Include:
- trigger / why now
- scope and non-goals
- GitHub API limitation: `six_months` expiry
- acceptance criteria
- verification table requirement

Use a body file to avoid shell quoting problems:

```bash
cat > /tmp/github-interaction-limits/issue-body.md <<'EOF'
## Summary
Lock down public GitHub repository interactions so only collaborators can create/interact with issues, pull requests, comments, discussions, and related user-generated surfaces where GitHub supports that control.

## Scope
- Enumerate target repositories.
- Apply GitHub repository interaction limits with `limit=collaborators_only` to public repos.
- Verify final settings via GitHub API.
- Leave private repos unchanged unless GitHub supports an equivalent setting.

## Non-goals
- Do not delete existing issues/comments.
- Do not remove legitimate collaborators.
- Do not change repository visibility.
- Do not globally disable Issues unless explicitly approved.

## Acceptance criteria
- [ ] Public repos are verified as `collaborators_only`.
- [ ] Private repos are inventoried or explicitly skipped with rationale.
- [ ] Renewal path exists before expiry.
EOF

gh issue create --repo "$OWNER/<tracking-repo>" \
  --title 'chore(security): restrict public repo interactions to collaborators only' \
  --body-file /tmp/github-interaction-limits/issue-body.md
```

### 3. Apply collaborator-only interaction limits to public repos

```bash
python3 - <<'PY'
import json, subprocess, sys, time
from pathlib import Path
repos = json.load(open('/tmp/github-interaction-limits/repos.json'))
results=[]
for r in repos:
    if r['visibility'] != 'PUBLIC':
        continue
    full = r['nameWithOwner']
    row = {'repo': full, 'archived': r['isArchived'], 'url': r['url']}
    before = subprocess.run(['gh','api',f'repos/{full}/interaction-limits'], text=True, capture_output=True)
    row['before'] = before.stdout.strip() or before.stderr.strip()
    setp = subprocess.run([
        'gh','api','-X','PUT',f'repos/{full}/interaction-limits',
        '-f','limit=collaborators_only','-f','expiry=six_months'
    ], text=True, capture_output=True)
    row['set_rc'] = setp.returncode
    row['set_stderr'] = setp.stderr.strip()
    after = subprocess.run(['gh','api',f'repos/{full}/interaction-limits'], text=True, capture_output=True)
    row['after_rc'] = after.returncode
    row['after'] = after.stdout.strip() or after.stderr.strip()
    results.append(row)
    time.sleep(0.15)
Path('/tmp/github-interaction-limits/results.json').write_text(json.dumps(results, indent=2))
for row in results:
    print(f"{row['repo']}\tset_rc={row['set_rc']}\tafter={row['after'][:200]}")
if any(r['set_rc'] != 0 or r['after_rc'] != 0 for r in results):
    sys.exit(1)
PY
```

### 4. Verify final state

```bash
python3 - <<'PY'
import json, subprocess, sys
repos=json.load(open('/tmp/github-interaction-limits/repos.json'))
fail=[]
for r in repos:
    if r['visibility'] != 'PUBLIC':
        continue
    full=r['nameWithOwner']
    p=subprocess.run(['gh','api',f'repos/{full}/interaction-limits'], text=True, capture_output=True, check=True)
    data=json.loads(p.stdout or '{}')
    print(f"{full}: {data.get('limit')} expires {data.get('expires_at')}")
    if data.get('limit') != 'collaborators_only':
        fail.append((full, data))
if fail:
    print('FAIL', fail, file=sys.stderr)
    sys.exit(1)
PY
```

### 5. Check private repos only if needed

If the user asked for "all repos," document that private repos are already visibility-gated. If you attempt the API for uniformity, expect:

```text
405 Interaction limits cannot be set for private repositories.
```

Treat that as confirmation of GitHub's public-only interaction-limit constraint, not as a failure requiring repo changes.

### 6. Post verification and close the tracking issue

```bash
cat > /tmp/github-interaction-limits/verification-comment.md <<'EOF'
## Verification update

Applied and verified GitHub repository interaction limits for all public repositories in scope.

Important GitHub limitation: repository interaction limits require an expiry; the longest supported expiry is `six_months`. A renewal path is required if this should remain durable.

| Repo | Visibility | Archived | Limit | Expires |
|---|---:|---:|---|---|
| ... | PUBLIC | false | `collaborators_only` | `...` |

Private repositories were inventoried but not modified because GitHub interaction limits cannot be set for private repositories; private visibility already restricts access to collaborators/members.
EOF

gh issue comment <issue-number> --repo "$OWNER/<tracking-repo>" --body-file /tmp/github-interaction-limits/verification-comment.md
gh issue close <issue-number> --repo "$OWNER/<tracking-repo>" --reason completed
```

## Renewal Pattern

Because `six_months` expires, create a renewal job/reminder before expiry. A safe cadence is every 150 days.

Renewal job prompt should:
1. verify `gh auth status`
2. list repos
3. re-apply `limit=collaborators_only` / `expiry=six_months` to public repos
4. verify every public repo
5. post a concise verification comment to the tracking issue
6. avoid changing visibility, collaborators, branch protection, repository contents, or issues beyond the verification comment

## Future Follow-Up Issues and Exit Handoff

For emergency/public-repo lockdown tasks, create future issues before exit so the temporary API setting turns into durable governance. Typical follow-ups:

1. **Scheduled renewal / control-plane codification**
   - Move any local/Hermes renewal reminder into the repo's canonical scheduled-task system.
   - Include deterministic script, dry-run mode, verification report, schedule metadata, and tests.
2. **Branch protection / ruleset audit**
   - Audit branch protection, repository rulesets, PR settings, status checks, and enabled public surfaces (Issues, Discussions, Wiki, Projects, Actions).
   - Keep this separate from interaction limits because code-path protection can block workflows and usually needs explicit approval.
3. **External contributor / solicitation response runbook**
   - Document when to ignore, hide, report, or safely route non-collaborator comments, unsolicited paid-help offers, and legitimate contributor requests.
   - Include templates and collaborator-onboarding guardrails.

Exit handoff pattern:
- Write a concise handoff under `docs/handoffs/` or the repo's canonical handoff location.
- Link the completed tracking issue, future issues, verified public repo table, private-repo limitation (`405`), renewal job/reminder, and next-session order.
- Commit the handoff as a narrow docs-only change, push, verify local `HEAD` equals remote, and check the CI run triggered by the handoff commit.
- Post the handoff commit and CI link back to the completed tracking issue.
- Keep unrelated pre-existing working-tree modifications out of the handoff commit.

## Pitfalls

- Do not promise permanent interaction limits; GitHub requires expiry.
- Do not treat private repo 405 responses as errors that need remediation.
- Do not disable Issues as a first response unless the user explicitly approves; interaction limits preserve existing issue workflows for collaborators.
- Use body files for issue bodies/comments to avoid shell quoting and command-substitution bugs.
- Archived public repos can still accept the interaction-limit API; include them in the public-repo pass unless intentionally skipped.
- Do not conflate interaction limits with branch protection/rulesets; create a separate audit/plan for code-path hardening.

## Verification Checklist

- [ ] `gh auth status` passes for the intended owner/admin account.
- [ ] Repo inventory includes visibility and archived state.
- [ ] Every public repo returns `{"limit":"collaborators_only", ...}` from `GET /repos/{owner}/{repo}/interaction-limits`.
- [ ] Private repo behavior is documented as visibility-gated / public-only API constraint.
- [ ] Tracking issue has a verification table.
- [ ] Renewal path exists before `expires_at`.

Related Skills

blender-worktree-test-hardening

5
from vamseeachanta/workspace-hub

Recover and harden digitalmodel Blender automation work in isolated worktrees when uv/editable dependency paths break and local machines lack a Blender executable.

tax-filing-session-setup-with-github-tracking

5
from vamseeachanta/workspace-hub

Structured workflow for preparing and tracking a tax filing session using prepared documents, task checklist, and GitHub issue cross-referencing

tax-filing-session-setup-with-github-traceability

5
from vamseeachanta/workspace-hub

Structured workflow for setting up a multi-file tax filing session with GitHub issue tracking and prepared-file validation

github-issue-structure-for-personal-finance-tracking

5
from vamseeachanta/workspace-hub

Pattern for organizing financial analysis work across multiple repos (data/config vs. logic separation)

post-smoke-ci-plan-boundary-hardening

5
from vamseeachanta/workspace-hub

Harden a CI follow-up plan after an initial smoke/unblock issue lands. Use for post-smoke red workflows where later gates surface broad lint/type debt and the plan must stay bounded, evidence-backed, and review-honest.

iterative-plan-hardening-with-adversarial-waves

5
from vamseeachanta/workspace-hub

Tighten a draft plan through repeated Codex/Gemini adversarial review waves without prematurely advancing it to plan-review.

github-actions-trigger-and-shell-gotchas

5
from vamseeachanta/workspace-hub

Prevent false verification gaps in GitHub Actions by checking push path filters, shell compatibility, and shared CI environment failures before concluding a workflow fix worked or failed.

github-actions-cross-platform-validation-gotchas

5
from vamseeachanta/workspace-hub

Execution-time GitHub Actions pitfalls discovered while fixing cross-platform CI workflows — path-filter non-triggers, Windows shell parsing mismatches, and job-scoped validation.

documentation-contract-plan-hardening

5
from vamseeachanta/workspace-hub

Harden a documentation/contract plan before adversarial review by mapping every issue-scope requirement to independent acceptance criteria and tests, especially for routing/indexing contracts.

canonical-doc-contract-plan-hardening

5
from vamseeachanta/workspace-hub

Harden a documentation or mission-contract plan so adversarial reviewers cannot reject it for vague validator contracts, wrong artifact authority, or semantic drift gaps.

bounded-post-smoke-ci-hardening-plan

5
from vamseeachanta/workspace-hub

Plan post-smoke CI hardening as a bounded blocker-removal tranche instead of overpromising full green. Includes issue-body alignment, follow-up split rules, honest review bookkeeping, and reliable local validation commands.

plan-review-adversarial-hardening

5
from vamseeachanta/workspace-hub

Class-level workflow for plan-review hardening, adversarial review reruns, artifact grounding, approval hygiene, and prompt/path drift recovery.