fix(manager-core): F-S-001 cap kv/docs/pubsub/queue payload sizes (default 256 KB)
Files (per-file cap), secrets (64 KB default), and email (25 MB default)
already enforce limits; kv::set, docs::create/update, pubsub::publish_durable
and queue::enqueue accepted any JSON value straight to a JSONB column with
no size validation. An anonymous public-HTTP script could fill disk via
queue::enqueue or amplify a single publish into N outbox rows × payload bytes.
Adds four new error variants:
- KvError::ValueTooLarge { limit, actual }
- DocsError::ValueTooLarge { limit, actual }
- PubsubError::MessageTooLarge { limit, actual }
- QueueError::PayloadTooLarge { limit, actual }
Each stateful service grows a `max_value_bytes` field with:
- Conservative 256 KB default (DEFAULT_KV_MAX_VALUE_BYTES etc.).
- New `with_max_*` constructor preserving the old `new()` signature.
- Env-knob reader (`*_max_*_from_env()`) — mirrors SecretsConfig::from_env.
Validation runs at the entry point BEFORE authz so an anonymous DoS doesn't
pay a membership lookup per attempt.
Wired via env knobs:
- PICLOUD_KV_MAX_VALUE_BYTES
- PICLOUD_DOCS_MAX_VALUE_BYTES
- PICLOUD_PUBSUB_MAX_MESSAGE_BYTES
- PICLOUD_QUEUE_MAX_PAYLOAD_BYTES
Documented in CLAUDE.md runtime config table.
New unit test in queue_service verifying the cap fires before authz.
AUDIT.md anchor: F-S-001. Depends on F-Q-004 (Backend variant).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -252,6 +252,11 @@ pub enum DocsError {
|
||||
#[error("forbidden")]
|
||||
Forbidden,
|
||||
|
||||
/// JSON-encoded document data exceeded the per-app `max_value_bytes`
|
||||
/// cap. Configured via `PICLOUD_DOCS_MAX_VALUE_BYTES`.
|
||||
#[error("docs: data too large ({actual} bytes; limit {limit})")]
|
||||
ValueTooLarge { limit: usize, actual: usize },
|
||||
|
||||
/// Anything else — Postgres unavailable, serialization failure,
|
||||
/// etc. The string is safe to surface to a script.
|
||||
#[error("docs backend error: {0}")]
|
||||
|
||||
@@ -133,6 +133,12 @@ pub enum KvError {
|
||||
#[error("forbidden")]
|
||||
Forbidden,
|
||||
|
||||
/// JSON-encoded value exceeded the per-app `max_value_bytes` cap.
|
||||
/// Defends Postgres JSONB columns from anonymous-public-script DoS;
|
||||
/// the limit is configurable via `PICLOUD_KV_MAX_VALUE_BYTES`.
|
||||
#[error("kv: value too large ({actual} bytes; limit {limit})")]
|
||||
ValueTooLarge { limit: usize, actual: usize },
|
||||
|
||||
/// Anything else — Postgres unavailable, serialization failure,
|
||||
/// etc. The string is safe to surface to a script.
|
||||
#[error("kv backend error: {0}")]
|
||||
|
||||
@@ -73,6 +73,13 @@ pub enum PubsubError {
|
||||
#[error("pubsub rejected: {0}")]
|
||||
Rejected(String),
|
||||
|
||||
/// JSON-encoded message exceeded the configured `max_message_bytes`
|
||||
/// cap (`PICLOUD_PUBSUB_MAX_MESSAGE_BYTES`). Defends against an
|
||||
/// anonymous public script amplifying one publish into N outbox rows
|
||||
/// × payload bytes.
|
||||
#[error("pubsub: message too large ({actual} bytes; limit {limit})")]
|
||||
MessageTooLarge { limit: usize, actual: usize },
|
||||
|
||||
/// A `pubsub::subscriber_token` mint was rejected (empty topics,
|
||||
/// unregistered topic, ttl out of range, anonymous caller). The
|
||||
/// string is the full user-facing message; the SDK surfaces it
|
||||
|
||||
@@ -78,6 +78,12 @@ pub enum QueueError {
|
||||
#[error("{0}")]
|
||||
InvalidOpts(String),
|
||||
|
||||
/// JSON-encoded payload exceeded the configured `max_payload_bytes`
|
||||
/// cap (`PICLOUD_QUEUE_MAX_PAYLOAD_BYTES`). Defends against script
|
||||
/// queue::enqueue calls filling disk with multi-MB payloads.
|
||||
#[error("queue: payload too large ({actual} bytes; limit {limit})")]
|
||||
PayloadTooLarge { limit: usize, actual: usize },
|
||||
|
||||
/// Backend failure (Postgres unavailable, etc.). Named `Backend` to
|
||||
/// align with KvError / DocsError / FilesError / SecretsError.
|
||||
#[error("queue backend error: {0}")]
|
||||
|
||||
Reference in New Issue
Block a user