mirror of
https://github.com/Significant-Gravitas/AutoModerate.git
synced 2026-11-09 13:11:26 -10:00
Security / correctness - Privilege escalation: rule/api-key/project-update routes now gate on can_manage_members instead of is_member; plain members could previously rewrite or disable moderation rules and delete API keys. - Project.is_owner() AttributeError on non-admin API-user deletion (route + template) replaced with user_id comparison. - Flask-Limiter on /auth/login, /auth/register, /auth/change-password, and /api/moderate (per API key id). - Remove silent SECRET_KEY fallback: docker-compose fails hard if unset; production config validator refuses to boot without SECRET_KEY and OPENAI_API_KEY. - Require verified email in Google OAuth auto-link flow. - User-supplied regex now evaluated via the regex package with a 1s timeout, closing the ReDoS vector. - Cap batched AI chunk count (max 40) and concurrent workers (200 -> 10). - openai>=2.32 (from 1.55.3 so reasoning_effort kwarg works); add regex, Flask-Limiter, gunicorn, eventlet, psycogreen; drop the stdlib-shadowing pypi asyncio package. Production runtime - New wsgi.py: eventlet.monkey_patch + psycogreen.patch_psycopg so DB queries cooperate with the event loop; sets SOCKETIO_ASYNC_MODE=eventlet for app startup. - Dockerfiles run as non-root app user and CMD gunicorn with --worker-class eventlet. run.py refuses FLASK_CONFIG=production so a misconfigured deploy fails loudly. - cloudbuild.yaml stops managing env vars/secrets on deploy — it was about to clobber secret-backed env vars with plain ones. Runtime config is now owned by the Cloud Run service. SocketIO async-mode fix (was causing full site lockup during API calls) - async_mode picked via SOCKETIO_ASYNC_MODE env var, default "threading". The previous sys.modules auto-detect false-positived because flask_socketio / python-engineio import eventlet on load whenever it is installed, pinning a non-monkey-patched eventlet server in front of blocking stdlib I/O. Real-time dashboard updates - New content_received WebSocket event fires when the API accepts a submission; UI renders a "Processing…" row immediately and updates it in place when moderation_update arrives. - Fix stale updated_at timestamp in moderation_update payloads. Batched AI rule evaluation - Replace the per-rule parallel fan-out (N OpenAI calls) with a single batched call evaluating all AI-prompt rules at once. On a 6-rule default project this drops safe-content cost from 5-12s to ~1-4s. - response_format=json_object + max_completion_tokens=4000 so the model emits strict JSON and stops at the close-brace. - OPENAI_REASONING_EFFORT config: minimal/low/medium/high for gpt-5 / o-series; accepts "none" on gpt-5.4. Works around the gpt-5-nano case where reasoning tokens ate the full output budget and returned empty responses. Client errors - Malformed / non-UTF-8 JSON bodies now return 400 with a clear message about UTF-8 encoding instead of a generic 500. Logging - Single INFO line per moderation: the existing "Content <id>: decision in Zs" summary. - Per-stage timing, websocket scheduling, and batched-AI call details moved to DEBUG so they are available when diagnosing latency without cluttering steady-state logs.
64 lines
2.1 KiB
YAML
64 lines
2.1 KiB
YAML
steps:
|
|
# Build the container image
|
|
- name: 'gcr.io/cloud-builders/docker'
|
|
args: [
|
|
'build',
|
|
'-f', 'deploy/Dockerfile',
|
|
'-t', 'gcr.io/$PROJECT_ID/automoderate:$BRANCH_NAME-$SHORT_SHA',
|
|
'.'
|
|
]
|
|
|
|
# Push the container image to Container Registry
|
|
- name: 'gcr.io/cloud-builders/docker'
|
|
args: ['push', 'gcr.io/$PROJECT_ID/automoderate:$BRANCH_NAME-$SHORT_SHA']
|
|
|
|
# Deploy container image to Cloud Run.
|
|
#
|
|
# This step intentionally does NOT manage environment variables or secrets.
|
|
# Runtime config is owned by the Cloud Run service itself (console or
|
|
# `gcloud run services update`) so that:
|
|
# 1. Secret-backed env vars (SECRET_KEY, DATABASE_URL, OPENAI_API_KEY,
|
|
# ADMIN_PASSWORD, GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET) set via
|
|
# `--set-secrets` survive every deploy. `--set-env-vars` here would
|
|
# convert them into plain env vars and lose the secret binding.
|
|
# 2. Per-environment values (FLASK_CONFIG=development for the dev service,
|
|
# FLASK_CONFIG=production for the prod service) are configured once on
|
|
# the service and persist across image-only deploys.
|
|
# If a brand-new service is being stood up, configure its env vars and
|
|
# secrets manually via the console before the first cloudbuild run, or
|
|
# extend this step with `--update-env-vars` / `--set-secrets`.
|
|
- name: 'gcr.io/cloud-builders/gcloud'
|
|
args:
|
|
- 'run'
|
|
- 'deploy'
|
|
- 'automoderate-${_ENV}'
|
|
- '--image'
|
|
- 'gcr.io/$PROJECT_ID/automoderate:$BRANCH_NAME-$SHORT_SHA'
|
|
- '--region'
|
|
- '${_REGION}'
|
|
- '--platform'
|
|
- 'managed'
|
|
- '--allow-unauthenticated'
|
|
- '--port'
|
|
- '6217'
|
|
- '--memory'
|
|
- '${_MEMORY}'
|
|
- '--cpu'
|
|
- '${_CPU}'
|
|
- '--max-instances'
|
|
- '${_MAX_INSTANCES}'
|
|
- '--add-cloudsql-instances'
|
|
- '${_CLOUD_SQL_INSTANCE}'
|
|
|
|
substitutions:
|
|
_ENV: 'dev'
|
|
_REGION: 'us-central1'
|
|
_MEMORY: '1Gi'
|
|
_CPU: '1'
|
|
_MAX_INSTANCES: '10'
|
|
# _CLOUD_SQL_INSTANCE must be set in the trigger configuration
|
|
# (format: project:region:instance-name).
|
|
|
|
options:
|
|
logging: CLOUD_LOGGING_ONLY
|