Skip to content
5 changes: 3 additions & 2 deletions .github/drone.yml
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ steps:
- name: docker-socket
path: /var/run/docker.sock
commands:
- apk add --no-cache docker-cli-compose curl bash
- apk add bash
- echo "========================================"
- echo "本地部署测试 全新部署验证"
- echo "========================================"
Expand Down Expand Up @@ -159,7 +159,7 @@ steps:
- name: docker-socket
path: /var/run/docker.sock
commands:
- apk add --no-cache docker-cli-compose curl bash
- apk add bash
- echo "========================================"
- echo "本地升级测试 旧版 → 新版数据库迁移验证"
- echo "========================================"
Expand Down Expand Up @@ -292,6 +292,7 @@ trigger:
branch:
- main
- release
- ci/test-drone # 临时添加,测试完成后删除

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Remove the temporary Drone branch trigger

When this YAML is merged, pushes to a ci/test-drone branch will run the full pipeline, including save-images and scp-images to /opt/server/clawith-ci/, even though publishing should be limited to main/release. Since the inline note says this was temporary for testing, drop this branch before merging so test branches cannot overwrite CI deployment artifacts.

Useful? React with 👍 / 👎.

event:
- push
- pull_request
Expand Down
9 changes: 9 additions & 0 deletions backend/app/api/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,13 @@ async def register_init(
detail="Username already taken. Please choose a different username.",
)

# Reject registration if the identity exists but has no password set (SSO/synced users)
if identity.password_hash is None:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Email already registered via SSO/sync. Please use password reset to set a password, or log in via SSO.",
)

# Verify password outside transaction
if identity.password_hash and not await verify_password_async(data.password, identity.password_hash):
raise HTTPException(
Expand Down Expand Up @@ -223,6 +230,8 @@ async def register_init(
user.is_active = is_first_user # Active immediately if first user
user.email_verified = identity.email_verified
await session.flush()
else:
user.identity = identity

# 5. Generate token outside transaction
token = create_access_token(str(user.id), user.role)
Expand Down
1 change: 1 addition & 0 deletions backend/app/services/registration_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ async def create_user_with_identity(
"registration_source": registration_source,
"is_active": is_active or identity.is_platform_admin,
})
user.identity = identity

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Reject passwordless identities during registration

When /register/init reuses an Identity whose password_hash is NULL, the check in backend/app/api/auth.py:179 skips password verification entirely; channel/proactive users are created this way with password_hash=None in backend/app/services/channel_user_service.py. This new eager assignment now lets UserOut serialize successfully instead of hitting the DetachedInstanceError, so an attacker who knows such an email can submit any password and receive an access token for the created/reused user. Add an explicit reject/set-password flow before creating or returning a user for passwordless identities.

Useful? React with 👍 / 👎.


# Link to OrgMember if exists
await self.bind_org_member(user)
Expand Down
65 changes: 65 additions & 0 deletions docker-compose.ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# ============================================================
# CI 专用 Docker Compose
# 用于 Drone CI 的本地部署测试和升级测试
# 使用预构建镜像,不构建、不挂载持久化卷
# ============================================================

services:
postgres:
image: postgres:15-alpine
networks:
- default
environment:
POSTGRES_USER: clawith
POSTGRES_PASSWORD: clawith
POSTGRES_DB: clawith
healthcheck:
test: ["CMD-SHELL", "pg_isready -U clawith"]
interval: 5s
timeout: 5s
retries: 5

redis:
image: redis:7-alpine
networks:
- default
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 5s
retries: 5

backend:
image: clawith-backend:${IMAGE_TAG:-new}
environment:
DATABASE_URL: postgresql+asyncpg://clawith:clawith@postgres:5432/clawith
REDIS_URL: redis://redis:6379/0
AGENT_DATA_DIR: /data/agents
AGENT_TEMPLATE_DIR: /app/agent_template
SECRET_KEY: ci-test-secret
JWT_SECRET_KEY: ci-test-jwt-secret
PROCESS_ROLE: all
CORS_ORIGINS: '["*"]'
networks:
- default
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy

frontend:
image: clawith-frontend:${IMAGE_TAG:-new}
ports:
- "3008:3000"
environment:
VITE_API_URL: http://localhost:8000
API_UPSTREAM: backend:8000
Comment on lines +55 to +57

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Set MINIO_UPSTREAM for the CI frontend

The CI compose file starts the frontend, but this environment block omits MINIO_UPSTREAM even though frontend/nginx.conf.template:57 and :60 reference ${MINIO_UPSTREAM} for the /minio/ proxy. In CI, where that variable is not otherwise provided, the nginx template is rendered/parsed with an invalid upstream/Host value (unlike the main compose files, which set ${MINIO_UPSTREAM:-minio:9000}), so the frontend container exits while the deploy test only waits on the backend.

Useful? React with 👍 / 👎.

networks:
- default
depends_on:
- backend

networks:
default:
name: clawith_network