Skip to content

Commit c4c634a

Browse files
committed
Initial commit
0 parents  commit c4c634a

43 files changed

Lines changed: 2872 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.dockerignore

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
**/__pycache__/
2+
**/*.pyc
3+
**/*.pyo
4+
**/*.pyd
5+
.venv/
6+
.env
7+
.git/
8+
.gitignore
9+
README.md
10+
k8s/
11+
scripts/

.gitattributes

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
*.sh text eol=lf

.github/workflows/secret-scan.yml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
name: Secret Scan
2+
3+
on:
4+
pull_request:
5+
push:
6+
branches: ["main"]
7+
8+
permissions:
9+
contents: read
10+
11+
jobs:
12+
gitleaks:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- name: Checkout
16+
uses: actions/checkout@v4
17+
- name: Run gitleaks
18+
uses: gitleaks/gitleaks-action@v2
19+
env:
20+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.gitignore

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
.vscode/
2+
.claude/
3+
.local/
4+
.env*
5+
__pycache__/
6+
*.pyc
7+
*.egg-info/
8+
.DS_Store
9+
.idea/
10+
node_modules/
11+
*.tar
12+
k8s/secrets/*.values.yaml
13+
*.pem
14+
inventory-prod.ini

CONTRIBUTING.md

Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
# Contributing
2+
3+
Merci de contribuer a PatchworkAgent ! Ce guide explique comment ajouter un nouveau provider IA, modifier l'orchestrateur, ou corriger un bug.
4+
5+
---
6+
7+
## Pre-requis
8+
9+
- Docker
10+
- k3s (ou un cluster Kubernetes local)
11+
- `kubectl` configure sur le namespace `ai-bot`
12+
- Python 3.11+ (pour l'orchestrateur)
13+
- Les cles API des providers que vous souhaitez tester
14+
15+
---
16+
17+
## Structure du projet
18+
19+
```
20+
.
21+
├── app/
22+
│ └── app.py # Orchestrateur FastAPI
23+
├── providers/
24+
│ ├── git_workflow.sh # Logique Git partagee (clone, branch, push, PR)
25+
│ ├── claude_code.sh # Provider Claude Code
26+
│ ├── openai.sh # Provider OpenAI Codex
27+
│ └── aider.sh # Provider Aider (OpenRouter)
28+
├── images/
29+
│ ├── orchestrator/Dockerfile # Image orchestrateur
30+
│ ├── worker-claude/ # Image + run.sh worker Claude
31+
│ ├── worker-codex/ # Image + run.sh worker Codex
32+
│ └── worker-aider/ # Image + run.sh worker Aider
33+
├── k8s/
34+
│ ├── namespace-rbac.yaml # Namespace + RBAC
35+
│ ├── orchestrator.yaml # Deployment + Service + Ingress
36+
│ ├── debug-claude.yaml # Job de debug Claude
37+
│ ├── debug-codex.yaml # Job de debug Codex
38+
│ └── debug-aider.yaml # Job de debug Aider
39+
└── README.md
40+
```
41+
42+
---
43+
44+
## Ajouter un nouveau provider IA
45+
46+
Pour ajouter un provider `myprovider` avec le label de declenchement `ai-pr-myprovider` :
47+
48+
### 1. Script provider : `providers/myprovider.sh`
49+
50+
Suivre le pattern existant :
51+
52+
```bash
53+
#!/usr/bin/env bash
54+
set -euo pipefail
55+
56+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
57+
58+
# 1. Verifier le token GitHub
59+
: "${GITHUB_TOKEN:?GITHUB_TOKEN is required}"
60+
61+
# 2. Clone & branch (logique partagee)
62+
source "$SCRIPT_DIR/git_workflow.sh"
63+
git_clone_and_branch
64+
65+
# 3. Appeler le CLI IA
66+
myprovider-cli run "Fix issue #${ISSUE_NUMBER}: ${GITHUB_ISSUE_TITLE:-no title}. ..."
67+
68+
# 4. Push & PR (logique partagee)
69+
git_push_and_pr "Automated PR created by MyProvider for issue #${ISSUE_NUMBER}."
70+
```
71+
72+
Les fonctions `git_clone_and_branch` et `git_push_and_pr` sont dans `providers/git_workflow.sh`. Ne pas dupliquer cette logique.
73+
74+
### 2. Wrapper d'entree : `images/worker-myprovider/run.sh`
75+
76+
```bash
77+
#!/usr/bin/env bash
78+
set -euo pipefail
79+
80+
echo "=== worker start ==="
81+
echo "TIME: $(date -u --iso-8601=seconds)"
82+
echo "AI_PROVIDER=${AI_PROVIDER:-myprovider}"
83+
echo "GITHUB_REPO=${GITHUB_REPO:-}"
84+
echo "GITHUB_ISSUE_NUMBER=${GITHUB_ISSUE_NUMBER:-}"
85+
echo "GITHUB_INSTALLATION_ID=${GITHUB_INSTALLATION_ID:-}"
86+
if [[ "${DEBUG_ENV:-0}" == "1" ]]; then
87+
echo "---- env (whitelist) ----"
88+
printenv | grep -E '^(AI_PROVIDER|GITHUB_REPO|GITHUB_ISSUE_NUMBER|GITHUB_INSTALLATION_ID|NAMESPACE|JOB_IMAGE|HOME|PATH)=' || true
89+
echo "---- end env ----"
90+
fi
91+
92+
exec /app/providers/myprovider.sh
93+
```
94+
95+
### 3. Dockerfile : `images/worker-myprovider/Dockerfile`
96+
97+
```dockerfile
98+
FROM ubuntu:22.04
99+
100+
ENV DEBIAN_FRONTEND=noninteractive
101+
WORKDIR /tmp
102+
103+
RUN apt-get update && apt-get install -y \
104+
curl ca-certificates git bash jq procps \
105+
&& rm -rf /var/lib/apt/lists/*
106+
107+
# Installer les deps specifiques au CLI (Node.js, Go, etc.)
108+
109+
# Creer un user non-root (certains CLIs le requierent)
110+
RUN useradd -m -s /bin/bash worker
111+
USER worker
112+
113+
# Installer le CLI IA
114+
RUN curl -fsSL https://example.com/install.sh | bash
115+
116+
# Copier les scripts
117+
WORKDIR /app
118+
COPY --chown=worker:worker images/worker-myprovider/run.sh /app/run.sh
119+
COPY --chown=worker:worker providers/ /app/providers/
120+
RUN sed -i 's/\r$//' /app/run.sh /app/providers/*.sh \
121+
&& chmod +x /app/run.sh /app/providers/*.sh
122+
123+
ENV PATH="/home/worker/.local/bin:${PATH}"
124+
WORKDIR /work
125+
126+
ENTRYPOINT ["/app/run.sh"]
127+
CMD []
128+
```
129+
130+
### 4. Job de debug : `k8s/debug-myprovider.yaml`
131+
132+
Creer un Job qui :
133+
- Verifie l'installation du CLI (`command -v`, `--version`)
134+
- Verifie la cle API (longueur, presence)
135+
- Execute un test simple (ex: "Quelle est la capitale de la France ?")
136+
- Dort ensuite (`sleep 36000`) pour permettre `kubectl exec`
137+
138+
### 5. Enregistrer le provider dans `app/app.py`
139+
140+
```python
141+
# Ajouter la variable d'image
142+
MYPROVIDER_WORKER_IMAGE = os.getenv("MYPROVIDER_WORKER_IMAGE", "worker-myprovider:latest")
143+
144+
# Ajouter dans PROVIDER_CONFIG
145+
"myprovider": ProviderConfig(
146+
image=MYPROVIDER_WORKER_IMAGE,
147+
ai_provider="myprovider",
148+
api_secret=ProviderSecretRef("MY_API_KEY", "myprovider-api-key", "MY_API_KEY"),
149+
),
150+
```
151+
152+
### 6. Mettre a jour le README.md
153+
154+
- Table des secrets (section 1)
155+
- Table des images (section 2)
156+
- Commandes de build (section 2)
157+
- Section debug jobs (section 3)
158+
- Section "En cas de changement d'image" (section 4)
159+
- Troubleshooting si necessaire (section 5)
160+
161+
### 7. Verification
162+
163+
```shell
164+
# Syntaxe Python
165+
python -c "import ast; ast.parse(open('app/app.py').read())"
166+
167+
# Build de l'image
168+
docker build -f images/worker-myprovider/Dockerfile -t worker-myprovider:latest .
169+
170+
# Import dans k3s
171+
docker save worker-myprovider:latest | sudo k3s ctr images import -
172+
173+
# Lancer le job de debug
174+
kubectl -n ai-bot apply -f k8s/debug-myprovider.yaml
175+
kubectl -n ai-bot logs -f job/debug-myprovider
176+
177+
# Test end-to-end : ajouter le label ai-pr-myprovider sur une issue
178+
```
179+
180+
---
181+
182+
## Modifier l'orchestrateur
183+
184+
L'orchestrateur est dans `app/app.py` (FastAPI).
185+
186+
```shell
187+
# Verifier la syntaxe apres modification
188+
python -c "import ast; ast.parse(open('app/app.py').read())"
189+
190+
# Rebuild + deploiement
191+
docker build -f images/orchestrator/Dockerfile -t ghcr.io/hey-intent/orchestrator:latest .
192+
docker save ghcr.io/hey-intent/orchestrator:latest | sudo k3s ctr images import -
193+
kubectl -n ai-bot rollout restart deployment/orchestrator
194+
195+
# Verifier les logs
196+
kubectl -n ai-bot logs -f deploy/orchestrator --tail=200
197+
```
198+
199+
---
200+
201+
## Conventions
202+
203+
### Scripts shell
204+
205+
- Shebang : `#!/usr/bin/env bash`
206+
- Toujours `set -euo pipefail`
207+
- Fin de ligne Unix (LF). Les Dockerfiles font `sed -i 's/\r$//'` par securite.
208+
- Ne jamais logger de secrets. Utiliser `GIT_ASKPASS` pour les tokens Git.
209+
210+
### Dockerfiles
211+
212+
- Base : `ubuntu:22.04`
213+
- Deps communes : `curl ca-certificates git bash jq procps`
214+
- User non-root `worker` (UID auto)
215+
- `WORKDIR /work` pour l'execution
216+
- `ENTRYPOINT ["/app/run.sh"]`
217+
218+
### Secrets Kubernetes
219+
220+
- Un secret par provider (isolation : compromission d'un secret n'affecte pas les autres)
221+
- Injection via `secretKeyRef` (jamais en clair dans les manifests)
222+
- Convention de nommage : `<provider>-api-key`
223+
224+
### Nommage
225+
226+
| Element | Convention | Exemple |
227+
|---------|-----------|---------|
228+
| Label GitHub | `ai-pr-<provider>` | `ai-pr-claude` |
229+
| Image Docker | `worker-<provider>:latest` | `worker-aider:latest` |
230+
| Secret K8s | `<service>-api-key` | `openrouter-api-key` |
231+
| Script provider | `providers/<provider>.sh` | `providers/aider.sh` |
232+
| Job de debug | `k8s/debug-<provider>.yaml` | `k8s/debug-aider.yaml` |
233+
| Cle dans `PROVIDER_CONFIG` | `<provider>` (suffixe du label) | `"aider"` |
234+
235+
---
236+
237+
## Limitations connues (POC)
238+
239+
Ce projet est un POC. Les contributions pour adresser ces limitations sont bienvenues :
240+
241+
- Concurrence / idempotence (doubles declenchements, collisions de branches/jobs)
242+
- Timeout / cancellation des jobs (pods "zombies")
243+
- Gestion des conflits Git / PR deja existante
244+
- Monitoring / alerting (Prometheus, Grafana)
245+
- Dashboard de suivi des jobs
246+
- Gestion des quotas et du budget tokens par PR / par repo
247+
- Rate limiting sur les webhooks
248+
- Retry / dead-letter queue en cas d'echec
249+
- Traitement des images dans les issues (screenshots, diagrammes)
250+
- Gestion des commentaires dans les issues (contexte additionnel, instructions de suivi)
251+
- Support multi-cluster / haute disponibilite

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2025 PatchworkAgent Contributors
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

0 commit comments

Comments
 (0)