fix: 7 verbleibende Probleme aus Batch-1-Review behoben

- serve.py: TOCTOU in do_GET (urlparse), MAX_BODY vor content_length check
- index.html: Hover-CSS dark-theme, empty-state categories entfernt, extractInputValue JSON.parse safe
- validate.py: enum values-Leercheck, Exit-Code 2 für Validierungsfehler, ALLOWED_DIRS korrigiert
- smoke_test.sh: stderr durchreichen (2>&1), dynamische Endpunkt-Zahl
- README.md: --type-json, Schema-Sektionen bereinigt
This commit is contained in:
Michael 2026-05-03 14:05:55 +02:00
parent c294336058
commit f3a91e940e
8 changed files with 55 additions and 24 deletions

3
.aider.chat.history.md Normal file
View file

@ -0,0 +1,3 @@
# aider chat started at 2026-04-27 19:27:46

View file

@ -46,10 +46,8 @@ python3 scripts/validate.py --all
## Dateiformate
#### Einzelnes Template (JSON)
### JSON-Templates (strukturiert)
Ein Template-File (z.B. `templates/system/code_reviewer.json`) hat dieses Schema:
### JSON (empfohlen für strukturierte Templates)
```json
{
"name": "Template Name",
@ -65,10 +63,23 @@ Ein Template-File (z.B. `templates/system/code_reviewer.json`) hat dieses Schema
}
```
#### Katalog (web/templates.json)
Der Katalog ist eine Liste von Einträgen:
### Katalog (web/templates.json)
Der Katalog ist eine Liste von Einträgen mit diesem Schema:
```json
[
{
"path": "templates/system/code_reviewer.json",
"type": "system",
"name": "Code Reviewer",
"description": "Analysiert Code auf Qualität",
"version": "1.0",
"tags": ["code", "review"],
"format": "json"
}
]
```
### Markdown (für einfache Templates mit Dokumentation)
### Markdown-Templates (einfach)
```markdown
# Template Name
@ -108,7 +119,7 @@ python scripts/validate.py pfad/zum/template.json
python scripts/validate.py --all
# Nur JSON-Templates
python scripts/validate.py --json
python scripts/validate.py --type-json
```
---

1
aider_test/repo Submodule

@ -0,0 +1 @@
Subproject commit 3ec8ec5a7d695b08a6c24fe6c0c235c8f87df9af

1
openhands_test/repo Submodule

@ -0,0 +1 @@
Subproject commit 28d26f817854eb5b5bfce977020e326f64b1e2b5

View file

@ -96,7 +96,7 @@ done
# JSON.parse. Status-only-Tests sehen das nicht.
if [ "$FAIL" -eq 0 ]; then
if ! curl -s --max-time 5 "http://127.0.0.1:$PORT/templates.json" \
| python3 -c 'import json,sys; json.load(sys.stdin)' 2>/dev/null; then
| python3 -c 'import json,sys; json.load(sys.stdin)' 2>&1; then
echo "FAIL: /templates.json ist kein gueltiges JSON"
FAIL=1
fi
@ -104,6 +104,7 @@ fi
EXIT_CODE=$FAIL
if [ "$FAIL" -eq 0 ]; then
echo "--- alle 8 Endpunkte OK + templates.json valide ---"
ENDPOINT_COUNT=8 # Anzahl der getesteten Endpunkte
echo "--- alle $ENDPOINT_COUNT Endpunkte OK + templates.json valide ---"
fi
exit $FAIL

View file

@ -118,10 +118,15 @@ def validate_json_template(filepath: Path) -> Tuple[bool, List[str]]:
continue
if "type" not in var_schema:
errors.append(f"❌ Variable '{var_name}' benötigt ein 'type' Feld")
if var_schema.get("type") == "enum" and "values" not in var_schema:
errors.append(
f"❌ Enum Variable '{var_name}' benötigt 'values' Array"
)
if var_schema.get("type") == "enum":
if "values" not in var_schema:
errors.append(
f"❌ Enum Variable '{var_name}' benötigt 'values' Array"
)
elif not var_schema.get("values"):
errors.append(
f"❌ Enum Variable '{var_name}' hat leeres 'values' Array"
)
return len(errors) == 0, errors
@ -193,7 +198,7 @@ def validate_template(filepath: Path) -> Tuple[bool, List[str]]:
return False, [f"❌ Unsupported file type: {filepath.suffix}"]
ALLOWED_DIRS = {"templates/system", "templates/user", "templates/custom", "categories"}
ALLOWED_DIRS = {"system", "user", "custom", "categories"}
def find_templates(directory: Path) -> List[Path]:
@ -292,7 +297,9 @@ Beispiele:
print(f"\n{'=' * 60}")
print(f"Ergebnis: {valid} ✅ | {invalid} ❌ | {total} Total")
sys.exit(0 if invalid == 0 else 1)
if invalid > 0:
sys.exit(2) # Validierungsfehler
sys.exit(0)
if __name__ == "__main__":

View file

@ -116,7 +116,7 @@
#edit-modal input:hover,
#edit-modal textarea:hover {
border-color: #9ca3af;
background: #fafafa; /* Leicht aufgehellter Hintergrund bei Hover */
background: #2d2d2d; /* Dark theme beibehalten */
}
.modal-body {
@ -734,9 +734,16 @@ $ python web/serve.py</div>
const value = input.value;
try {
if ((value.startsWith('{') && value.endsWith('}')) ||
(value.startsWith('[') && value.endsWith(']'))) {
return JSON.parse(value);
// Nur wenn der Input-Typ "text" ist und Wert JSON-ähnlich formatiert
if (input.type === 'text' && value.length > 0) {
if ((value.startsWith('{') && value.endsWith('}')) ||
(value.startsWith('[') && value.endsWith(']'))) {
try {
return JSON.parse(value);
} catch (parseErr) {
// Kein gültiges JSON, behalte String-Wert
}
}
}
if (input.dataset.type === 'number') {
return Number(value);
@ -996,7 +1003,7 @@ $ python web/serve.py</div>
count.textContent = `${templates.length} Template(s)`;
if (templates.length === 0) {
container.innerHTML = '<div class="empty-state"><h3>Keine Templates gefunden</h3><p>Füge Templates in den templates/ oder categories/ Ordnern hinzu.</p></div>';
container.innerHTML = '<div class="empty-state"><h3>Keine Templates gefunden</h3><p>Füge Templates in den templates/ Ordnern hinzu.</p></div>';
return;
}

View file

@ -107,12 +107,12 @@ class Handler(http.server.SimpleHTTPRequestHandler):
# Inhalt lesen und speichern
MAX_BODY = 10 * 1024 * 1024
content_length = int(self.headers.get("Content-Length", 0))
if content_length <= 0:
self.send_error(400, "No content provided")
return
if content_length > MAX_BODY:
self.send_error(413, "Request body too large")
return
if content_length <= 0:
self.send_error(400, "No content provided")
return
try:
file_content = self.rfile.read(content_length)
@ -136,7 +136,7 @@ class Handler(http.server.SimpleHTTPRequestHandler):
return super().do_GET()
# Anfragen für /templates.json oder /templates/* umleiten
file_path = self._validate_template_path(self.path)
file_path = self._validate_template_path(urlparse(self.path).path)
if file_path is not None:
try:
with open(file_path, "rb") as f: