fix: code review fixes — auth gap, path traversal, dead code, health-check timeout

- backend/app.py: add Depends(_require_auth) to /api/copilotkit endpoint (critical
  security fix — endpoint was fully unprotected; now requires valid session cookie)
- backend/app.py: move 'from ag_ui.core import RunStartedEvent' from inline function
  body to top-level imports (style consistency)
- backend/auth.py: remove dead AUTH_PASS_HASH module-level constant (verify_password
  already reads from os.environ at call time; the cached binding was unused dead code)
- backend/artifacts.py: add path traversal guards to list_artifacts, get_artifact,
  and save_artifact — resolve paths and verify they stay within ARTIFACTS_DIR
- entrypoint.sh: health-check loop now sets READY flag and exits 1 if amplifierd
  fails to start within 30s (previously fell through silently, causing 502s)
- tests/test_app.py: add TestCopilotKitAuth — verifies unauthenticated requests to
  /api/copilotkit return 401; includes note explaining why streaming is not tested here
- tests/test_structure.sh: update to reflect that Dockerfile and entrypoint.sh now
  exist (created in Tasks 7+8); convert absent-checks to presence-checks

Co-authored-by: Amplifier <amplifier@anthropic.com>
This commit is contained in:
Ken
2026-05-26 18:52:12 +00:00
parent 6be77d1a56
commit 5ba367af2f
6 changed files with 70 additions and 14 deletions
+19
View File
@@ -161,3 +161,22 @@ class TestMCPAppsEndpoint:
"""GET /api/apps/{name} for missing app file → 404."""
response = auth_client.get("/api/apps/nonexistent-app-xyz")
assert response.status_code == 404
# ---------------------------------------------------------------------------
# TestCopilotKitAuth
# ---------------------------------------------------------------------------
# NOTE: /api/copilotkit is not fully tested here because it requires a live
# amplifierd stream. See integration tests (requires container runtime).
# Auth enforcement is tested below.
class TestCopilotKitAuth:
def test_copilotkit_unauthenticated_returns_401(self, client):
"""POST /api/copilotkit without session cookie → 401."""
response = client.post(
"/api/copilotkit",
json={"threadId": "test-thread", "messages": []},
)
assert response.status_code == 401
+17 -2
View File
@@ -44,11 +44,26 @@ check_absent "sites.yaml"
check_absent "app.py"
check_absent "static"
check_absent "results"
check_absent "Dockerfile"
check_absent "entrypoint.sh"
check_absent "pyproject.toml"
check_absent "uv.lock"
echo ""
echo "=== Checking new root-level files exist ==="
if [ -f "$REPO/Dockerfile" ]; then
echo "PASS: 'Dockerfile' exists (Task 7)"
((PASS++))
else
echo "FAIL: 'Dockerfile' should exist (Task 7) but is missing"
((FAIL++))
fi
if [ -f "$REPO/entrypoint.sh" ]; then
echo "PASS: 'entrypoint.sh' exists (Task 8)"
((PASS++))
else
echo "FAIL: 'entrypoint.sh' should exist (Task 8) but is missing"
((FAIL++))
fi
echo ""
echo "=== Checking new directories exist ==="
check_dir "backend"