gabriel / musehub public
feat BREAKING task/issue-49-phase4 #1 / 1
AI Agent gabriel · 124 days ago · May 11, 2026 · Diff

feat: bundle push rate limiting and abuse defense (issue #49 phase 4)

- MusehubDailyPushBytes: per-user daily byte counter table, upserted at bundle-presign; resets each calendar day (PK: identity_id + date) - MusehubPushAnomaly: anomaly record table for >10x rolling-average spikes - record_bundle_bytes_uploaded: UPSERT helper with ON CONFLICT increment - check_push_anomaly: computes 30-day rolling average, inserts anomaly row and logs WARNING when today's upload is >10x average; never rejects - bundle-presign route: enforces daily limit (429 with 'daily' in detail); limit disabled when bundle_daily_upload_limit_bytes=0; per-user not global - GET /api/caps: public endpoint returning max_bundle_bytes, daily_upload_limit_bytes, max_commits_per_push, max_objects_per_push - 15 TDD tests in test_bundle_rate_limiting_phase4.py: all green

sha256:29f2935a56feb415c441b14c6a891ec69e63cf5677ea7cb089b7770b2d2c078e sha
+49 ~18 symbols
sha256:4f7e9abded68453838891f0e0fb649e534649d3cd34d18dc59988838834b0160 snapshot
+49
symbols added
~18
symbols modified
0
dead code introduced
Semantic Changes 67 symbols
~ musehub/api/routes/api/caps.py .py 7 symbols added
+ CapsResponse class class CapsResponse L17–21
+ get_caps function async_function get_caps L25–39
+ APIRouter import import APIRouter L9–9
+ BaseModel import import BaseModel L10–10
+ annotations import import annotations L7–7
+ settings import import settings L12–12
+ router variable variable router L14–14
+ _AUTH_CTX variable variable _AUTH_CTX L29–34
+ _AUTH_CTX2 variable variable _AUTH_CTX2 L36–41
+ _today function function _today L97–98
+ client function async_function client L47–61
+ client2 function async_function client2 L65–80
+ ASGITransport import import ASGITransport L19–19
+ AsyncClient import import AsyncClient L19–19
+ AsyncSession import import AsyncSession L21–21
+ MSignContext import import MSignContext L23–23
+ annotations import import annotations L13–13
+ app import import app L26–26
+ datetime import import datetime L15–15
+ db import import db L24–24
+ get_db import import get_db L25–25
+ optional_signed_request import import optional_signed_request L23–23
+ pytest import import pytest L17–17
+ pytest_asyncio import import pytest_asyncio L18–18
+ require_signed_request import import require_signed_request L23–23
+ select import import select L20–20
+ repo function async_function repo L84–92
+ test_anomaly_does_not_block_push function async_function test_anomaly_does_not_block_push L325–347
+ test_caps_endpoint_exists function async_function test_caps_endpoint_exists L355–358
+ test_caps_is_public_no_auth_required function async_function test_caps_is_public_no_auth_required L389–396
+ test_caps_returns_required_fields function async_function test_caps_returns_required_fields L362–370
+ test_caps_values_match_settings function async_function test_caps_values_match_settings L374–385
+ test_check_push_anomaly_does_not_flag_normal_volume function async_function test_check_push_anomaly_does_not_flag_normal_volume L247–275
+ test_check_push_anomaly_flags_spike function async_function test_check_push_anomaly_flags_spike L279–311
+ test_check_push_anomaly_no_history_does_not_flag function async_function test_check_push_anomaly_no_history_does_not_flag L315–321
+ test_daily_limit_allows_push_under_quota function async_function test_daily_limit_allows_push_under_quota L163–176
+ test_daily_limit_blocks_push_over_quota function async_function test_daily_limit_blocks_push_over_quota L180–203
+ test_daily_limit_is_per_user_not_global function async_function test_daily_limit_is_per_user_not_global L207–230
+ test_daily_push_bytes_table_exists function async_function test_daily_push_bytes_table_exists L106–111
+ test_push_anomaly_table_exists function async_function test_push_anomaly_table_exists L238–243
+ test_record_bundle_bytes_accumulates_across_calls function async_function test_record_bundle_bytes_accumulates_across_calls L139–159
+ test_record_bundle_bytes_increments_daily_total function async_function test_record_bundle_bytes_increments_daily_total L115–135
~ musehub/config.py .py 1 symbol modified
~ musehub/db/musehub_models.py .py 3 symbols added, 2 symbols modified
+ MusehubDailyPushBytes class class MusehubDailyPushBytes L2165–2183
+ MusehubPushAnomaly class class MusehubPushAnomaly L2186–2206
+ date import import date L22–22
~ musehub/main.py .py 1 symbol added
+ api_caps_router import import api_caps_router L69–69
~ musehub/services/musehub_wire.py .py 2 symbols added
+ check_push_anomaly function async_function check_push_anomaly L1137–1183
+ record_bundle_bytes_uploaded function async_function record_bundle_bytes_uploaded L1114–1134
← Older Oldest on task/issue-49-phase4
All commits
Newer → Latest on task/issue-49-phase4

0 comments

No comments yet. Be the first to start the discussion.

To add a comment, use the Muse CLI: muse hub commit comment sha256:29f2935a56feb415c441b14c6a891ec69e63cf5677ea7cb089b7770b2d2c078e --body "your comment"