mcp-github-crunchtools 1.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mcp_github_crunchtools-1.0.1/.gatehouse-ignore +3 -0
- mcp_github_crunchtools-1.0.1/.github/ISSUE_TEMPLATE/bug_report.yml +79 -0
- mcp_github_crunchtools-1.0.1/.github/ISSUE_TEMPLATE/config.yml +5 -0
- mcp_github_crunchtools-1.0.1/.github/ISSUE_TEMPLATE/feature_request.yml +73 -0
- mcp_github_crunchtools-1.0.1/.github/dependabot.yml +30 -0
- mcp_github_crunchtools-1.0.1/.github/workflows/ci.yml +57 -0
- mcp_github_crunchtools-1.0.1/.github/workflows/constitution.yml +21 -0
- mcp_github_crunchtools-1.0.1/.github/workflows/container.yml +112 -0
- mcp_github_crunchtools-1.0.1/.github/workflows/dependabot-automerge.yml +18 -0
- mcp_github_crunchtools-1.0.1/.github/workflows/gatehouse-retriage.yml +23 -0
- mcp_github_crunchtools-1.0.1/.github/workflows/gatehouse.yml +110 -0
- mcp_github_crunchtools-1.0.1/.github/workflows/publish.yml +29 -0
- mcp_github_crunchtools-1.0.1/.github/workflows/security.yml +140 -0
- mcp_github_crunchtools-1.0.1/.gitignore +95 -0
- mcp_github_crunchtools-1.0.1/.pre-commit-config.yaml +41 -0
- mcp_github_crunchtools-1.0.1/.specify/memory/constitution.md +64 -0
- mcp_github_crunchtools-1.0.1/.specify/specs/000-baseline/spec.md +144 -0
- mcp_github_crunchtools-1.0.1/.specify/templates/plan-template.md +117 -0
- mcp_github_crunchtools-1.0.1/.specify/templates/spec-template.md +91 -0
- mcp_github_crunchtools-1.0.1/CHANGELOG.md +28 -0
- mcp_github_crunchtools-1.0.1/CLAUDE.md +86 -0
- mcp_github_crunchtools-1.0.1/Containerfile +52 -0
- mcp_github_crunchtools-1.0.1/LICENSE +661 -0
- mcp_github_crunchtools-1.0.1/PKG-INFO +263 -0
- mcp_github_crunchtools-1.0.1/README.md +237 -0
- mcp_github_crunchtools-1.0.1/SECURITY.md +219 -0
- mcp_github_crunchtools-1.0.1/gourmand-exceptions.toml +37 -0
- mcp_github_crunchtools-1.0.1/gourmand.toml +14 -0
- mcp_github_crunchtools-1.0.1/pyproject.toml +78 -0
- mcp_github_crunchtools-1.0.1/server.json +21 -0
- mcp_github_crunchtools-1.0.1/src/mcp_github_crunchtools/__init__.py +58 -0
- mcp_github_crunchtools-1.0.1/src/mcp_github_crunchtools/__main__.py +6 -0
- mcp_github_crunchtools-1.0.1/src/mcp_github_crunchtools/client.py +271 -0
- mcp_github_crunchtools-1.0.1/src/mcp_github_crunchtools/config.py +140 -0
- mcp_github_crunchtools-1.0.1/src/mcp_github_crunchtools/errors.py +65 -0
- mcp_github_crunchtools-1.0.1/src/mcp_github_crunchtools/models.py +215 -0
- mcp_github_crunchtools-1.0.1/src/mcp_github_crunchtools/server.py +496 -0
- mcp_github_crunchtools-1.0.1/src/mcp_github_crunchtools/tools/__init__.py +48 -0
- mcp_github_crunchtools-1.0.1/src/mcp_github_crunchtools/tools/actions.py +187 -0
- mcp_github_crunchtools-1.0.1/src/mcp_github_crunchtools/tools/files.py +124 -0
- mcp_github_crunchtools-1.0.1/src/mcp_github_crunchtools/tools/issues.py +224 -0
- mcp_github_crunchtools-1.0.1/src/mcp_github_crunchtools/tools/pull_requests.py +287 -0
- mcp_github_crunchtools-1.0.1/src/mcp_github_crunchtools/tools/search.py +81 -0
- mcp_github_crunchtools-1.0.1/tests/__init__.py +1 -0
- mcp_github_crunchtools-1.0.1/tests/conftest.py +80 -0
- mcp_github_crunchtools-1.0.1/tests/test_tools.py +861 -0
- mcp_github_crunchtools-1.0.1/tests/test_validation.py +175 -0
- mcp_github_crunchtools-1.0.1/uv.lock +2170 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
name: Bug Report
|
|
2
|
+
description: Report a bug or unexpected behavior
|
|
3
|
+
title: "[Bug]: "
|
|
4
|
+
labels: ["bug", "triage"]
|
|
5
|
+
body:
|
|
6
|
+
- type: textarea
|
|
7
|
+
id: description
|
|
8
|
+
attributes:
|
|
9
|
+
label: Bug Description
|
|
10
|
+
description: A clear description of the bug
|
|
11
|
+
placeholder: What happened?
|
|
12
|
+
validations:
|
|
13
|
+
required: true
|
|
14
|
+
|
|
15
|
+
- type: textarea
|
|
16
|
+
id: steps
|
|
17
|
+
attributes:
|
|
18
|
+
label: Steps to Reproduce
|
|
19
|
+
description: How can we reproduce this bug?
|
|
20
|
+
placeholder: |
|
|
21
|
+
1. Call tool '...' with args '...'
|
|
22
|
+
2. Observe error '...'
|
|
23
|
+
validations:
|
|
24
|
+
required: true
|
|
25
|
+
|
|
26
|
+
- type: textarea
|
|
27
|
+
id: expected
|
|
28
|
+
attributes:
|
|
29
|
+
label: Expected Behavior
|
|
30
|
+
description: What did you expect to happen?
|
|
31
|
+
validations:
|
|
32
|
+
required: true
|
|
33
|
+
|
|
34
|
+
- type: textarea
|
|
35
|
+
id: actual
|
|
36
|
+
attributes:
|
|
37
|
+
label: Actual Behavior
|
|
38
|
+
description: What actually happened? Include error messages if available.
|
|
39
|
+
validations:
|
|
40
|
+
required: true
|
|
41
|
+
|
|
42
|
+
- type: dropdown
|
|
43
|
+
id: transport
|
|
44
|
+
attributes:
|
|
45
|
+
label: Transport
|
|
46
|
+
description: How are you running the MCP server?
|
|
47
|
+
options:
|
|
48
|
+
- stdio (uvx / pip)
|
|
49
|
+
- streamable-http (container / systemd)
|
|
50
|
+
- SSE
|
|
51
|
+
validations:
|
|
52
|
+
required: true
|
|
53
|
+
|
|
54
|
+
- type: dropdown
|
|
55
|
+
id: github_instance
|
|
56
|
+
attributes:
|
|
57
|
+
label: GitHub Instance Type
|
|
58
|
+
options:
|
|
59
|
+
- github.com
|
|
60
|
+
- Self-hosted (corporate/private)
|
|
61
|
+
- GitHub Community Edition
|
|
62
|
+
- GitHub Enterprise Edition
|
|
63
|
+
validations:
|
|
64
|
+
required: true
|
|
65
|
+
|
|
66
|
+
- type: input
|
|
67
|
+
id: version
|
|
68
|
+
attributes:
|
|
69
|
+
label: Server Version
|
|
70
|
+
description: Output of `mcp-github-crunchtools --version` or pip show
|
|
71
|
+
placeholder: "0.3.2"
|
|
72
|
+
validations:
|
|
73
|
+
required: true
|
|
74
|
+
|
|
75
|
+
- type: textarea
|
|
76
|
+
id: additional
|
|
77
|
+
attributes:
|
|
78
|
+
label: Additional Context
|
|
79
|
+
description: Any other relevant information (logs, config, environment)
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
name: Feature Request
|
|
2
|
+
description: Suggest a new tool or enhancement
|
|
3
|
+
title: "[Feature]: "
|
|
4
|
+
labels: ["enhancement", "triage"]
|
|
5
|
+
body:
|
|
6
|
+
- type: textarea
|
|
7
|
+
id: problem
|
|
8
|
+
attributes:
|
|
9
|
+
label: Problem Statement
|
|
10
|
+
description: What problem does this feature solve?
|
|
11
|
+
placeholder: I need to...
|
|
12
|
+
validations:
|
|
13
|
+
required: true
|
|
14
|
+
|
|
15
|
+
- type: textarea
|
|
16
|
+
id: solution
|
|
17
|
+
attributes:
|
|
18
|
+
label: Proposed Solution
|
|
19
|
+
description: Describe the tool or change you'd like
|
|
20
|
+
placeholder: |
|
|
21
|
+
Tool name: `do_something`
|
|
22
|
+
GitHub API endpoint: `POST /projects/:id/...`
|
|
23
|
+
Parameters: ...
|
|
24
|
+
validations:
|
|
25
|
+
required: true
|
|
26
|
+
|
|
27
|
+
- type: textarea
|
|
28
|
+
id: alternatives
|
|
29
|
+
attributes:
|
|
30
|
+
label: Alternatives Considered
|
|
31
|
+
description: What alternatives have you considered?
|
|
32
|
+
|
|
33
|
+
- type: dropdown
|
|
34
|
+
id: scope
|
|
35
|
+
attributes:
|
|
36
|
+
label: Tool Category
|
|
37
|
+
description: Which area does this feature belong to?
|
|
38
|
+
options:
|
|
39
|
+
- Projects / Groups
|
|
40
|
+
- Merge Requests
|
|
41
|
+
- Issues
|
|
42
|
+
- Pipelines / Jobs
|
|
43
|
+
- Files / Repository
|
|
44
|
+
- Branches
|
|
45
|
+
- Labels
|
|
46
|
+
- Users
|
|
47
|
+
- Releases
|
|
48
|
+
- Milestones
|
|
49
|
+
- Wiki
|
|
50
|
+
- Snippets
|
|
51
|
+
- Search
|
|
52
|
+
- Security / Config
|
|
53
|
+
- New Category
|
|
54
|
+
validations:
|
|
55
|
+
required: true
|
|
56
|
+
|
|
57
|
+
- type: dropdown
|
|
58
|
+
id: github_api
|
|
59
|
+
attributes:
|
|
60
|
+
label: GitHub API Reference
|
|
61
|
+
description: Does this correspond to an existing GitHub REST API endpoint?
|
|
62
|
+
options:
|
|
63
|
+
- "Yes - documented in GitHub API docs"
|
|
64
|
+
- "No - new behavior / aggregation"
|
|
65
|
+
- "Not sure"
|
|
66
|
+
validations:
|
|
67
|
+
required: true
|
|
68
|
+
|
|
69
|
+
- type: textarea
|
|
70
|
+
id: additional
|
|
71
|
+
attributes:
|
|
72
|
+
label: Additional Context
|
|
73
|
+
description: Any other relevant information, API docs links, or examples
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Canonical Dependabot config for crunchtools Python projects using uv.
|
|
2
|
+
# Drop in as .github/dependabot.yml. See constitution.md Section XV.
|
|
3
|
+
#
|
|
4
|
+
# Covers both ecosystems that go stale silently if left unpinned:
|
|
5
|
+
# - uv: uv.lock (must be committed, never gitignored)
|
|
6
|
+
# - github-actions: `uses: some-action@vX.Y.Z` pins in .github/workflows/
|
|
7
|
+
|
|
8
|
+
version: 2
|
|
9
|
+
updates:
|
|
10
|
+
- package-ecosystem: "uv"
|
|
11
|
+
directory: "/"
|
|
12
|
+
schedule:
|
|
13
|
+
interval: "weekly"
|
|
14
|
+
groups:
|
|
15
|
+
minor-and-patch:
|
|
16
|
+
update-types:
|
|
17
|
+
- "minor"
|
|
18
|
+
- "patch"
|
|
19
|
+
|
|
20
|
+
- package-ecosystem: "github-actions"
|
|
21
|
+
directory: "/"
|
|
22
|
+
schedule:
|
|
23
|
+
interval: "weekly"
|
|
24
|
+
groups:
|
|
25
|
+
minor-and-patch:
|
|
26
|
+
update-types:
|
|
27
|
+
- "minor"
|
|
28
|
+
- "patch"
|
|
29
|
+
ignore:
|
|
30
|
+
- dependency-name: "crunchtools/constitution*"
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
strategy:
|
|
13
|
+
matrix:
|
|
14
|
+
python-version: ["3.10", "3.11", "3.12"]
|
|
15
|
+
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v7
|
|
18
|
+
|
|
19
|
+
- name: Install uv
|
|
20
|
+
uses: astral-sh/setup-uv@v7
|
|
21
|
+
with:
|
|
22
|
+
version: "latest"
|
|
23
|
+
|
|
24
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
25
|
+
run: uv python install ${{ matrix.python-version }}
|
|
26
|
+
|
|
27
|
+
- name: Install dependencies
|
|
28
|
+
run: uv sync --all-extras
|
|
29
|
+
|
|
30
|
+
- name: Run linter
|
|
31
|
+
run: uv run ruff check src tests
|
|
32
|
+
|
|
33
|
+
- name: Run type checker
|
|
34
|
+
run: uv run mypy src
|
|
35
|
+
|
|
36
|
+
- name: Run tests
|
|
37
|
+
run: uv run pytest -v
|
|
38
|
+
env:
|
|
39
|
+
GITHUB_TOKEN: "test_token_for_ci"
|
|
40
|
+
|
|
41
|
+
gourmand:
|
|
42
|
+
name: Code Quality (Gourmand)
|
|
43
|
+
uses: crunchtools/gatehouse/.github/workflows/gourmand.yml@v0.15.2
|
|
44
|
+
|
|
45
|
+
build-container:
|
|
46
|
+
runs-on: ubuntu-latest
|
|
47
|
+
steps:
|
|
48
|
+
- uses: actions/checkout@v7
|
|
49
|
+
|
|
50
|
+
- name: Build container image
|
|
51
|
+
run: |
|
|
52
|
+
docker build -f Containerfile -t mcp-github:test .
|
|
53
|
+
|
|
54
|
+
- name: Verify container
|
|
55
|
+
run: |
|
|
56
|
+
# Just verify it starts (will fail due to no token, but should start)
|
|
57
|
+
timeout 5 docker run --rm mcp-github:test || true
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Drop in as .github/workflows/constitution.yml. See constitution.md VII.
|
|
2
|
+
#
|
|
3
|
+
# The tag below is the constitution version this repo is judged by. It moves
|
|
4
|
+
# together with `Inherits:` in .specify/memory/constitution.md (scripts/fleet-bump.py
|
|
5
|
+
# opens that PR); Dependabot is told to ignore it, see examples/dependabot.yml.
|
|
6
|
+
# Required check: `Constitution / Validate constitution`.
|
|
7
|
+
|
|
8
|
+
name: Constitution
|
|
9
|
+
|
|
10
|
+
on:
|
|
11
|
+
pull_request:
|
|
12
|
+
push:
|
|
13
|
+
branches: [main, master]
|
|
14
|
+
|
|
15
|
+
permissions:
|
|
16
|
+
contents: read
|
|
17
|
+
|
|
18
|
+
jobs:
|
|
19
|
+
constitution:
|
|
20
|
+
name: Constitution
|
|
21
|
+
uses: crunchtools/constitution/.github/workflows/validate.yml@v1.18.0
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
name: Container Build & Push
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
tags: ["v*"]
|
|
7
|
+
pull_request:
|
|
8
|
+
branches: [main]
|
|
9
|
+
workflow_dispatch:
|
|
10
|
+
|
|
11
|
+
env:
|
|
12
|
+
QUAY_IMAGE: quay.io/crunchtools/mcp-github
|
|
13
|
+
GHCR_IMAGE: ghcr.io/crunchtools/mcp-github
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
build-and-push-quay:
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
permissions:
|
|
19
|
+
contents: read
|
|
20
|
+
|
|
21
|
+
steps:
|
|
22
|
+
- name: Checkout repository
|
|
23
|
+
uses: actions/checkout@v7
|
|
24
|
+
|
|
25
|
+
- name: Set up Docker Buildx
|
|
26
|
+
uses: docker/setup-buildx-action@v4
|
|
27
|
+
|
|
28
|
+
- name: Log in to Quay.io
|
|
29
|
+
if: github.event_name != 'pull_request'
|
|
30
|
+
uses: docker/login-action@v4
|
|
31
|
+
with:
|
|
32
|
+
registry: quay.io
|
|
33
|
+
username: ${{ secrets.QUAY_USERNAME }}
|
|
34
|
+
password: ${{ secrets.QUAY_PASSWORD }}
|
|
35
|
+
|
|
36
|
+
- name: Extract metadata
|
|
37
|
+
id: meta
|
|
38
|
+
uses: docker/metadata-action@v6
|
|
39
|
+
with:
|
|
40
|
+
images: ${{ env.QUAY_IMAGE }}
|
|
41
|
+
tags: |
|
|
42
|
+
type=ref,event=branch
|
|
43
|
+
type=ref,event=pr
|
|
44
|
+
type=semver,pattern={{version}}
|
|
45
|
+
type=semver,pattern={{major}}.{{minor}}
|
|
46
|
+
type=raw,value=latest,enable={{is_default_branch}}
|
|
47
|
+
|
|
48
|
+
- name: Build and push
|
|
49
|
+
uses: docker/build-push-action@v7
|
|
50
|
+
with:
|
|
51
|
+
context: .
|
|
52
|
+
file: ./Containerfile
|
|
53
|
+
push: ${{ github.event_name != 'pull_request' }}
|
|
54
|
+
tags: ${{ steps.meta.outputs.tags }}
|
|
55
|
+
labels: ${{ steps.meta.outputs.labels }}
|
|
56
|
+
cache-from: type=gha
|
|
57
|
+
cache-to: type=gha,mode=max
|
|
58
|
+
|
|
59
|
+
- name: Run Trivy vulnerability scanner
|
|
60
|
+
continue-on-error: true
|
|
61
|
+
if: github.event_name != 'pull_request'
|
|
62
|
+
uses: aquasecurity/trivy-action@v0.36.0
|
|
63
|
+
with:
|
|
64
|
+
image-ref: ${{ env.QUAY_IMAGE }}:latest
|
|
65
|
+
format: "table"
|
|
66
|
+
exit-code: "0"
|
|
67
|
+
severity: "CRITICAL,HIGH"
|
|
68
|
+
version: "v0.68.2"
|
|
69
|
+
|
|
70
|
+
build-and-push-ghcr:
|
|
71
|
+
runs-on: ubuntu-latest
|
|
72
|
+
needs: build-and-push-quay
|
|
73
|
+
if: github.event_name != 'pull_request'
|
|
74
|
+
permissions:
|
|
75
|
+
contents: read
|
|
76
|
+
packages: write
|
|
77
|
+
|
|
78
|
+
steps:
|
|
79
|
+
- name: Checkout repository
|
|
80
|
+
uses: actions/checkout@v7
|
|
81
|
+
|
|
82
|
+
- name: Set up Docker Buildx
|
|
83
|
+
uses: docker/setup-buildx-action@v4
|
|
84
|
+
|
|
85
|
+
- name: Log in to GitHub Container Registry
|
|
86
|
+
uses: docker/login-action@v4
|
|
87
|
+
with:
|
|
88
|
+
registry: ghcr.io
|
|
89
|
+
username: ${{ github.repository_owner }}
|
|
90
|
+
password: ${{ github.token }}
|
|
91
|
+
|
|
92
|
+
- name: Extract metadata
|
|
93
|
+
id: meta
|
|
94
|
+
uses: docker/metadata-action@v6
|
|
95
|
+
with:
|
|
96
|
+
images: ${{ env.GHCR_IMAGE }}
|
|
97
|
+
tags: |
|
|
98
|
+
type=ref,event=branch
|
|
99
|
+
type=ref,event=pr
|
|
100
|
+
type=semver,pattern={{version}}
|
|
101
|
+
type=semver,pattern={{major}}.{{minor}}
|
|
102
|
+
type=raw,value=latest,enable={{is_default_branch}}
|
|
103
|
+
|
|
104
|
+
- name: Build and push
|
|
105
|
+
uses: docker/build-push-action@v7
|
|
106
|
+
with:
|
|
107
|
+
context: .
|
|
108
|
+
file: ./Containerfile
|
|
109
|
+
push: true
|
|
110
|
+
tags: ${{ steps.meta.outputs.tags }}
|
|
111
|
+
labels: ${{ steps.meta.outputs.labels }}
|
|
112
|
+
cache-from: type=gha
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Drop in as .github/workflows/dependabot-automerge.yml. See constitution.md XV.
|
|
2
|
+
#
|
|
3
|
+
# Queues green GitHub Actions minor/patch bumps for auto-merge. Needs the repo
|
|
4
|
+
# setting `allow_auto_merge`; the required checks still decide the merge.
|
|
5
|
+
|
|
6
|
+
name: Dependabot auto-merge
|
|
7
|
+
|
|
8
|
+
on:
|
|
9
|
+
pull_request:
|
|
10
|
+
|
|
11
|
+
permissions:
|
|
12
|
+
contents: write
|
|
13
|
+
pull-requests: write
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
automerge:
|
|
17
|
+
name: Dependabot
|
|
18
|
+
uses: crunchtools/constitution/.github/workflows/dependabot-automerge.yml@v1.18.0
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Gatehouse retriage — makes a reply to a finding clear the triage check.
|
|
2
|
+
#
|
|
3
|
+
# Drop this next to examples/gatehouse.yml. A reply re-runs the `Gatehouse`
|
|
4
|
+
# workflow, but that run's checks do not count toward branch rules; only the
|
|
5
|
+
# pull_request_target run's do. When the reply run finishes, this re-runs
|
|
6
|
+
# triage inside the pull_request_target run. `workflow_run` always executes
|
|
7
|
+
# the default-branch copy of this file, so a fork cannot alter it.
|
|
8
|
+
|
|
9
|
+
name: Gatehouse retriage
|
|
10
|
+
|
|
11
|
+
on:
|
|
12
|
+
workflow_run:
|
|
13
|
+
workflows: [Gatehouse] # the `name:` of your gatehouse.yml
|
|
14
|
+
types: [completed]
|
|
15
|
+
|
|
16
|
+
permissions: {} # default-deny
|
|
17
|
+
|
|
18
|
+
jobs:
|
|
19
|
+
retriage:
|
|
20
|
+
if: github.event.workflow_run.event == 'pull_request_review_comment'
|
|
21
|
+
permissions:
|
|
22
|
+
actions: write # re-run the triage job; nothing else
|
|
23
|
+
uses: crunchtools/gatehouse/.github/workflows/retriage.yml@v0.15.2
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# Gatehouse — fork-safe code review + workflow protection, in ONE file.
|
|
2
|
+
#
|
|
3
|
+
# Drop this in your repo at .github/workflows/gatehouse.yml, add a OPENROUTER_API_KEY
|
|
4
|
+
# secret, and you get:
|
|
5
|
+
# • AI review of every PR (including from forks) — posted as a PR review
|
|
6
|
+
# • rejection of untrusted PRs that try to modify your workflow files
|
|
7
|
+
#
|
|
8
|
+
# Nothing is ever checked out from the PR. The fork's change is only ever read as
|
|
9
|
+
# a diff (data); the reviewer logic lives in the pinned gatehouse container; the
|
|
10
|
+
# rules (your styleguide/constitution) are fetched from YOUR base branch, not the
|
|
11
|
+
# PR. The one thing you don't trust — the proposed change — is only ever read.
|
|
12
|
+
#
|
|
13
|
+
# Three jobs with DIFFERENT authority:
|
|
14
|
+
# • guard — a real blocking gate. Mark it a REQUIRED status check so a PR
|
|
15
|
+
# that tampers with your workflow files is rejected.
|
|
16
|
+
# • review — ADVISORY. It posts findings as PR comments and always passes;
|
|
17
|
+
# do NOT mark it required. An LLM reviewer is non-deterministic,
|
|
18
|
+
# so it must never hold merge authority. (Opt into blocking with
|
|
19
|
+
# `blocking: true` below only if you accept that tradeoff — and
|
|
20
|
+
# even then, keep it out of branch protection.)
|
|
21
|
+
# • triage — deterministic. Fails while any finding has no reply
|
|
22
|
+
# (`fixed in <sha>` or `not a bug: <reason>`). Safe to mark
|
|
23
|
+
# REQUIRED: it never judges code, only whether a human answered.
|
|
24
|
+
|
|
25
|
+
name: Gatehouse
|
|
26
|
+
|
|
27
|
+
on:
|
|
28
|
+
pull_request_target:
|
|
29
|
+
types: [opened, synchronize, reopened]
|
|
30
|
+
# A reply rings the doorbell: this run's own checks do not count toward
|
|
31
|
+
# branch rules, so examples/gatehouse-retriage.yml answers it by re-running
|
|
32
|
+
# triage inside the pull_request_target run. Add that file too.
|
|
33
|
+
pull_request_review_comment:
|
|
34
|
+
types: [created, edited, deleted]
|
|
35
|
+
|
|
36
|
+
permissions: {} # default-deny; each job grants only what it needs
|
|
37
|
+
|
|
38
|
+
jobs:
|
|
39
|
+
# ── 1) Protect the workflow files themselves ────────────────────────────────
|
|
40
|
+
# Rejects PRs from forks that touch .github/workflows/. Safe under
|
|
41
|
+
# pull_request_target because it only reads the changed-file LIST via the
|
|
42
|
+
# API — it never checks out or runs your code. And because pull_request_target
|
|
43
|
+
# runs the BASE version of this file, a PR can't edit this job to disable it.
|
|
44
|
+
guard:
|
|
45
|
+
name: Protect workflows
|
|
46
|
+
# Runs on replies too. A job skipped on the reply event reports
|
|
47
|
+
# "skipped", which a required check counts as passing: skipping the
|
|
48
|
+
# guard there would let any comment on a rejected fork PR clear it.
|
|
49
|
+
runs-on: ubuntu-latest
|
|
50
|
+
permissions:
|
|
51
|
+
contents: read
|
|
52
|
+
pull-requests: write
|
|
53
|
+
steps:
|
|
54
|
+
- name: Reject workflow changes from untrusted PRs
|
|
55
|
+
env:
|
|
56
|
+
GH_TOKEN: ${{ github.token }}
|
|
57
|
+
EVENT: ${{ github.event_name }}
|
|
58
|
+
PR: ${{ github.event.pull_request.number }}
|
|
59
|
+
HEAD_REPO: ${{ github.event.pull_request.head.repo.full_name }}
|
|
60
|
+
run: |
|
|
61
|
+
set -euo pipefail
|
|
62
|
+
# Gate on where the branch lives, not on the author's role: a branch
|
|
63
|
+
# pushed into this repo already required write access, and a fork is
|
|
64
|
+
# what pull_request_target actually guards against.
|
|
65
|
+
if [ "$HEAD_REPO" = "$GITHUB_REPOSITORY" ]; then
|
|
66
|
+
echo "Head branch is in $GITHUB_REPOSITORY; allowing."; exit 0
|
|
67
|
+
fi
|
|
68
|
+
# Both sides of a rename: `gh pr diff --name-only` lists only the new
|
|
69
|
+
# path, so a fork could move a workflow out of .github/workflows/ unseen.
|
|
70
|
+
changed="$(gh api --paginate "repos/$GITHUB_REPOSITORY/pulls/$PR/files" \
|
|
71
|
+
--jq '.[] | .filename, (.previous_filename // empty)')"
|
|
72
|
+
if echo "$changed" | grep -qE '^\.github/workflows/'; then
|
|
73
|
+
echo "::error::PR modifies .github/workflows/ — not accepted from external contributors."
|
|
74
|
+
# Explain once, on the PR event; replies re-run the check, not the comment.
|
|
75
|
+
if [ "$EVENT" = "pull_request_target" ]; then
|
|
76
|
+
gh pr comment "$PR" --repo "$GITHUB_REPOSITORY" --body \
|
|
77
|
+
$'🚫 **Workflow changes are not accepted via pull request.** Please open an issue and a maintainer will make the change.'
|
|
78
|
+
fi
|
|
79
|
+
exit 1
|
|
80
|
+
fi
|
|
81
|
+
echo "No workflow files changed."
|
|
82
|
+
|
|
83
|
+
# ── 2) Review the PR diff (no checkout, BYO key) ────────────────────────────
|
|
84
|
+
# The reviewer is maintained centrally in gatehouse's reusable workflow and the
|
|
85
|
+
# pinned container — so security fixes reach you without copying logic around.
|
|
86
|
+
# Scope OPENROUTER_API_KEY to this reusable workflow so only it can read the key.
|
|
87
|
+
review:
|
|
88
|
+
name: Gatehouse review
|
|
89
|
+
if: github.event_name == 'pull_request_target'
|
|
90
|
+
permissions:
|
|
91
|
+
contents: read
|
|
92
|
+
pull-requests: write
|
|
93
|
+
uses: crunchtools/gatehouse/.github/workflows/review.yml@v0.15.2
|
|
94
|
+
# Advisory by default — findings post as comments, the check always passes.
|
|
95
|
+
# Uncomment to let critical/high findings fail the check (still not required):
|
|
96
|
+
# with:
|
|
97
|
+
# blocking: true
|
|
98
|
+
secrets:
|
|
99
|
+
OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
|
|
100
|
+
|
|
101
|
+
# ── 3) Every finding answered ──────────────────────────────────────────────
|
|
102
|
+
# Runs after the review on a push, and alone on a reply (review is skipped
|
|
103
|
+
# then, hence always()). Read-only, no secrets.
|
|
104
|
+
triage:
|
|
105
|
+
name: Gatehouse triage
|
|
106
|
+
needs: review
|
|
107
|
+
if: always()
|
|
108
|
+
permissions:
|
|
109
|
+
pull-requests: read
|
|
110
|
+
uses: crunchtools/gatehouse/.github/workflows/triage.yml@v0.15.2
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
publish:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
permissions:
|
|
12
|
+
id-token: write # Required for trusted publishing
|
|
13
|
+
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v7
|
|
16
|
+
|
|
17
|
+
- name: Install uv
|
|
18
|
+
uses: astral-sh/setup-uv@v7
|
|
19
|
+
with:
|
|
20
|
+
version: "latest"
|
|
21
|
+
|
|
22
|
+
- name: Set up Python
|
|
23
|
+
run: uv python install 3.12
|
|
24
|
+
|
|
25
|
+
- name: Build package
|
|
26
|
+
run: uv build
|
|
27
|
+
|
|
28
|
+
- name: Publish to PyPI
|
|
29
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|