1318 Commits

Author SHA1 Message Date
Prakash Dalai
3d881a7e46 Merge pull request #1015 from pocketpaw/dev
Sync dev into main: security hardening, CI fixes, and bug fixes
v0.4.18
2026-04-29 12:43:35 +05:30
prakashUXtech
80f315be0f chore(release): bump to 0.4.18
Skips 0.4.17 (PyPI prohibits same-version re-uploads). Release notes
will be published with the GH release tag after #1015 merges to main.
2026-04-29 12:28:40 +05:30
Rohit Kushwaha
5e4d82c570 docs: fold per-agent soul routing into enterprise agent chat spec
Current AgentLoop unconditionally observes into the process-global
default PocketPaw soul, so cloud chats with specific agents evolve
the wrong soul. Spec now routes soul observe + self-eval to the
target agent's SoulManager via AgentPool and gates the global
observe behind a per-run flag (default off in OSS).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 13:39:32 +05:30
Rohit Kushwaha
6049e95a49 docs: design for enterprise agent chat endpoint
Separate /cloud/chat/{scope}/{scope_id}/agent SSE endpoint with
scope-aware context (dm/group/pocket), pocket-scoped tools, ripple
pass-through, and WS broadcast of finished messages. Shares the
AgentLoop engine with OSS; /api/v1/chat.py stays untouched.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 13:30:41 +05:30
Rohit Kushwaha
c93e5f0fe4 fix(ci): correct guardian patch target in test_guardian_comprehensive
Same fix as the previous commit — patching pocketpaw.security.guardian.get_settings raises AttributeError because get_settings is imported lazily inside __init__ (circular-import avoidance). Patch pocketpaw.config.get_settings instead. Updates all three occurrences in this file.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 11:48:57 +05:30
Rohit Kushwaha
49ff6da813 fix(ci): correct guardian test patch target and exclude scrub test from secrets scan
Patching pocketpaw.security.guardian.get_settings fails because get_settings is imported lazily inside GuardianAgent.__init__ to avoid a circular import (config → security.url_validators → security/__init__ → guardian). Patch pocketpaw.config.get_settings (the real source) instead.

Also add tests/test_logging_scrub.py to the secrets-scan exclude list alongside test_redact.py and test_pii.py — the xoxb- string is a required scrubber-test fixture, not a real credential.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 11:28:31 +05:30
Rohit Kushwaha
e3a9b725d2 Refactor URL validation logic to allow internal hosts by default and improve dotenv flag reading 2026-04-22 18:15:46 +05:30
Rohit Kushwaha
59e721cde8 Import get_settings in GuardianAgent's constructor for configuration access 2026-04-22 18:10:26 +05:30
Rohit Kushwaha
73bde7e884 Merge pull request #1011 from AMRITESH240304/ak/analytics
feat(analytics): implement integrated tracing, budget enforcement, and health analytics dashboard
2026-04-22 17:44:29 +05:30
Rohit Kushwaha
135ffb7046 Merge branch 'dev' into ak/analytics 2026-04-22 17:40:08 +05:30
Rohit Kushwaha
b3b32b3267 Merge pull request #1013 from TejasriPacharu/feat/pocket-tool-policy
fix: add get_tool_policy/set_tool_policy to AgentBackend protocol
2026-04-22 17:39:54 +05:30
Rohit Kushwaha
62e8b392c9 Merge branch 'dev' into feat/pocket-tool-policy 2026-04-22 17:31:00 +05:30
TejasriPacharu
6a923e3bc5 Merge branch 'feat/pocket-tool-policy' of github.com:TejasriPacharu/pocketpaw into feat/pocket-tool-policy 2026-04-22 16:48:21 +05:30
TejasriPacharu
729b8f71cf fix: use X | Y union syntax in isinstance call 2026-04-22 16:42:14 +05:30
TejasriPacharu
10fd99b78c fix: address PR review feedback on tool policy scoping 2026-04-22 16:32:58 +05:30
Amritesh
061de4be96 fix(config): correct import statement for pydantic fields 2026-04-22 15:47:25 +05:30
Amritesh
3c7fcb7640 feat(analytics): optimize analytics fetching by consolidating trace requests into a single endpoint
feat(budget): improve budget enforcement logic and remove blocking behavior in record method
feat(alerts): ensure internal flags are not exposed in API responses
feat(traces): add session ID validation to prevent path traversal attacks
test: add tests for analytics gap fixes and ensure proper trace cleanup on cancellation
2026-04-22 15:43:41 +05:30
Rohit Kushwaha
58f2bb34f7 Merge branch 'main' into dev 2026-04-22 07:56:28 +05:30
Rohit Kushwaha
8c55d54ec5 Merge branch 'dev' into ak/analytics 2026-04-22 06:48:34 +05:30
Rohit Kushwaha
bc9a55caf2 Merge branch 'dev' into feat/pocket-tool-policy 2026-04-22 06:45:17 +05:30
Rohit Kushwaha
02c15b1dae Merge pull request #1014 from pocketpaw/chore/stale-pr-salvage-2026-04-22
chore: salvage 9 stale community PRs (security, bus, UI, CLI)
2026-04-22 06:45:05 +05:30
Rohit Kushwaha
6fa36f69ba fix(bus): guard shallow-copy fallback against None metadata/media (#732 follow-up)
Code review caught that the shallow-copy fallback in _safe_publish would
raise TypeError when deepcopy failed AND msg.metadata/msg.media was None
(callers can pass None explicitly even though the dataclass default is an
empty container). TypeError would be swallowed by the outer gather's
return_exceptions=True, silently dropping delivery with only a log entry.

Use falsy-safe fallbacks so None/empty both resolve to fresh containers.
2026-04-22 06:36:39 +05:30
Rohit Kushwaha
bd9d6b8879 fix(ci): replace asyncio.get_event_loop() in test_audit + test_deep_work_v2
Same Py 3.12 fix pattern as test_api_chat.py — get_event_loop() no longer
auto-creates a loop in the main thread, causing RuntimeErrors and downstream
pymongo teardown errors when these tests run in the full suite. new_event_loop()
works consistently across Py 3.11/3.12/3.13.

Fixes 5 test_deep_work_v2 failures and 13 test_audit errors exposed when
running without -x.
2026-04-22 06:21:15 +05:30
Rohit Kushwaha
65495670f7 fix(ci): add enforce_scope marker to test_api_v1_files_security
The module tests fail-closed scope enforcement but was missing the
module-level `pytestmark = pytest.mark.enforce_scope`, so the root
conftest's _TESTING_FULL_ACCESS bypass was turned on and all scopeless
API key requests went through, returning 200 instead of the expected
403. Matches the pattern used by test_require_scope_enforcement.py.

Pre-existing dev failure; folding the fix into this branch since the
salvage PR needs green CI.
2026-04-22 06:16:49 +05:30
Rohit Kushwaha
ead95460e3 style: apply ruff format to 9 unformatted files
8 files are pre-existing format drift on dev (ee/widget/*, security/url_validators.py, tests); 1 file (bus/queue.py) is new code from the #732 salvage. Applying ruff format so 'uv run ruff format --check .' passes in CI.
2026-04-22 06:14:52 +05:30
Rohit Kushwaha
0c3ebf1326 fix(ci): unblock dev-inherited CI failures
These failures already exist on `dev` HEAD — rolling the fixes into this
branch so the salvage PR can go green instead of waiting on a separate
cleanup PR.

- tests/test_api_chat.py — replace `asyncio.get_event_loop()` with
  `asyncio.new_event_loop()`. Python 3.12+ removed the implicit
  loop-creation behavior in the main thread, breaking all three
  `test_stream_*` cases with RuntimeError.
- ee/widget/projection.py — drop unused `field` from `dataclasses`
  import (F401).
- tests/test_dos_hardening.py, tests/test_logging_scrub.py — drop
  unused `pytest` imports (F401).
- src/pocketpaw/dashboard.py — remove two duplicated
  `lifespan`/`startup_event`/`shutdown_event` definitions (F811).
  The upper pair was shadowed by the lower redefinitions; the
  post-CORS duplicate was fully dead.
- src/pocketpaw/api/v1/auth.py — move `http_utils` import above
  `router = APIRouter(...)` to satisfy E402.
2026-04-22 06:13:22 +05:30
Rohit Kushwaha
3358c9dfda fix(usage): propagate token_usage metrics to chat API, SSE, and WebSocket (#745)
The backend collected `token_usage` events but only used them to update
the usage tracker — callers never saw them. Each of the three response
paths (chat REST, SSE bridge, WebSocket `stream_end`) returned no usage
data, making it impossible for clients to display per-message cost/token
counts without polling `/api/usage`.

- `AgentLoop._process_message_inner` now captures the most recent
  `token_usage` payload into `last_usage` and attaches it to
  `metadata_out["usage"]` on the final `stream_end` OutboundMessage.
- `WebSocketAdapter._send_to_socket` forwards `metadata["usage"]` on
  the `stream_end` frame.

Rewritten from the original PR, which had two blocking bugs:
- `last_usage` was referenced before initialization (NameError on
  backends that don't emit token_usage).
- `websocket_adapter.py` left stale `send_json` lines after the early
  return, producing dead code.

Drops the original PR's bundled changes:
- `pocketpaw_usage_repro.py` debug scripts (shouldn't ship).
- `tool_bridge.py` empty-properties fix — already in dev.
- `gmail.py` `"required": []` addition — immediately stripped by the
  tool_bridge sanitizer so it's self-defeating.

Co-Authored-By: umarkkhann3 <267705286+umarkkhann3@users.noreply.github.com>
2026-04-22 05:44:49 +05:30
Rohit Kushwaha
9f57491f06 fix(csp): nonce-based CSP, remove unsafe-inline for scripts (#706)
Replace `'unsafe-inline'` in the dashboard's `script-src` with a
per-request nonce generated via `secrets.token_urlsafe(16)` (128 bits).
The nonce is set on `request.state.csp_nonce` and consumed by the
handful of legitimate inline `<script>` blocks in `base.html` via
Jinja template interpolation. External scripts (`<script src="...">`)
are still allowed by the CDN entries already in `script-src`.

`'unsafe-eval'` remains — Alpine.js evaluates attribute directives at
runtime, which requires it. Known trade-off, not a regression.

Also:
- Convert remaining `onclick=` handlers in `plan_approval.html` to
  Alpine.js `@click` so CSP no longer blocks them (inline event
  attributes are not covered by nonces or `unsafe-eval`).
- Move `import secrets` to the top of `dashboard.py` (was shadowed
  import inside the middleware body).
- Drops the unrelated `tests/test_a2a_server.py` change from the
  original PR — separate concern.

Co-Authored-By: anish1301 <145433865+anish1301@users.noreply.github.com>
2026-04-22 05:43:48 +05:30
Rohit Kushwaha
957960cc9d fix(security): tighten IBAN PII pattern to avoid broad false positives (#702 follow-up)
The originally-applied IBAN regex matched arbitrary uppercase strings
(ARNs, UUIDs). Require the 'iban' keyword + 15+ char tail (country code
+ check digits + 11-30 alphanumeric), matching what real IBANs look
like. Addresses reviewer feedback on #702.
2026-04-22 05:43:02 +05:30
Rohit Kushwaha
dd1a0a7f26 fix(security): tighter trust levels + additional PII patterns (#702)
**Trust level corrections**
- `pip_install` (elevated → high): installing arbitrary packages deserves
  a WARNING-level audit entry, not INFO.
- `python_exec` (elevated → critical): running arbitrary Python is a
  CRITICAL-severity action per the registry's severity mapping.
  `elevated` silently mapped to INFO, understating blast radius in the
  audit log.

**PII scanner additions**
- Space-separated SSN (`123 45 6789`).
- Contextual bare 9-digit SSN (`ssn: 123456789`).
- Contextual passport numbers (`passport #ABC12345`).
- IBAN — rewritten from the original PR to require the `iban` keyword
  and 15+ char total length. The original `\b[A-Z]{2}\d{2}[A-Z0-9]{4,30}\b`
  pattern matched arbitrary uppercase strings (ARNs, UUIDs, etc) and
  generated too many false positives.

Drops the original PR's `fetch.py` change — `get_directory_keyboard` no
longer exists in dev (the InlineKeyboardMarkup-None guard is obsolete).

Co-Authored-By: Dhruv18052003-web <177319013+Dhruv18052003-web@users.noreply.github.com>
2026-04-22 05:41:53 +05:30
Rohit Kushwaha
10243f9580 fix(cli): reject --telegram combined with other channel flags (#743)
Telegram is the legacy pairing-only mode; combining it with
--discord/--slack/--whatsapp/etc produced confusing startup state where
the dashboard never came up but the extra channels silently ran. Fail
fast via argparse error so the user gets a clear message.

Uses `getattr(args, flag, False)` so unregistered flags don't crash.
Leaves `_check_extras_installed` and the rest of the main() control
flow untouched (earlier iterations of the PR moved it too early and
broke `doctor`/`status`).

Reduces the original test to the conflict cases only — asserting on the
non-conflict path would require mocking the full startup pipeline.

Co-Authored-By: Aravindavenge <119057955+Aravindavenge@users.noreply.github.com>
2026-04-22 05:41:02 +05:30
Rohit Kushwaha
b0829e7315 fix(bus): prevent metadata/media mutation leakage between subscribers (#732)
When multiple subscribers are registered on the same channel and the
first mutates `msg.metadata` or an item in `msg.media`, later subscribers
in the same `publish_outbound` call received the mutated state. During
streaming responses (token-by-token) this could corrupt metadata seen by
downstream adapters — e.g. WebSocket and Telegram on the same channel.

Deep-copy metadata + media per subscriber so each gets an isolated view.
Skip the deepcopy when both containers are empty (streaming chunks) to
keep the hot path cheap. Fall back to a shallow copy if deepcopy raises
(e.g. unpickleable objects) — still better than sharing references.

Errors from subscriber callbacks are captured via `return_exceptions=True`
in `gather` rather than re-raised, so one failing subscriber (e.g.
disconnected WebSocket) cannot kill delivery to the rest.

Also:
- `broadcast_outbound` now delegates to `publish_outbound` per channel,
  inheriting the same isolation.
- Added regression test `test_outbound_message_isolation`.
- Fix F401/F821 lint nits (unused imports, missing asyncio import).

Co-Authored-By: Vansh0204 <183680538+Vansh0204@users.noreply.github.com>
2026-04-22 05:28:25 +05:30
Rohit Kushwaha
b13d4bb75b fix(credentials): add claude_code_oauth_token + status_api_key to SECRET_FIELDS (#766, #765)
Both fields carry authentication material but were missing from
SECRET_FIELDS, so the `config show` / dashboard config panels could
surface them unredacted and they were not moved to encrypted storage
by the credential migration path.

Scopes the original PR back to just the credential-leak fix. The other
bundled changes (bug-report template deletion, events timezone fix,
Guardian model pinning, AgentLoop settings refactor, etc.) are dropped
per review feedback — each deserves its own PR.

Closes #765.

Co-Authored-By: aboutttmalay <138196355+aboutttmalay@users.noreply.github.com>
2026-04-22 05:27:39 +05:30
Rohit Kushwaha
c92ebe3e53 fix(transparency): handle unknown event types in Activity UI (#864)
The Activity UI dropped unknown `type` values on the floor instead of
showing them, making debugging of agent lifecycle events
(`agent_start`/`agent_end`) effectively impossible.

Render a fallback entry for unrecognized event types with the raw type
label + content so operators can see the full event stream rather than
a filtered subset.

Drops the unrelated `system_manual.md` addition from the original PR
per review feedback — project docs should land in a separate PR.

Co-Authored-By: kaustubh-d-IITR <215634129+kaustubh-d-IITR@users.noreply.github.com>
2026-04-22 05:24:53 +05:30
Rohit Kushwaha
e8ed7ebf44 fix(bootstrap): stale identity cache when mtime unchanged on Windows (#790)
On Windows filesystems the mtime resolution can be coarse enough that a
file edited in-place (with the same size... or different) keeps the same
mtime across edits, causing the identity cache to serve stale content.

Include file size in the cache key so any size change invalidates the
cache even when mtime is unchanged. Keeps the fast path (single stat
call) and the original mtime check.

Fixes ruff E302 (two blank lines before defs) flagged in review.

Co-Authored-By: Ayush-yadav7890 <205494381+Ayush-yadav7890@users.noreply.github.com>
2026-04-22 05:20:53 +05:30
Rohit Kushwaha
1fefb63a89 fix(csp): move highlight.js to CDN already allowed by CSP (#827)
The file-viewer highlight.js assets were loaded from cdnjs.cloudflare.com,
which is not in the dashboard's CSP. The result: highlight.js silently
failed to load and syntax highlighting never ran.

Move to cdn.jsdelivr.net (already allowed in script-src/style-src) —
the npm path for styles and the upstream cdn-release repo for the
minified runtime. Both URLs verified reachable.

Drops the unrelated test_neonize_adapter.py AsyncMock tweak from the
original PR (separate follow-up if still needed).

Co-Authored-By: PrinceSharma402 <202914754+PrinceSharma402@users.noreply.github.com>
2026-04-22 05:19:31 +05:30
Rohit Kushwaha
25ffb1e073 fix(mission-control): expose get_all_notifications to remove private _store access (#923)
Replaces `manager._store._notifications.values()` reach-through in the
`/api/mission-control/notifications` endpoint with a public
`get_all_notifications()` method on `MissionControlManager` and the underlying
store, matching the existing `get_notifications_for_agent()` pattern.

Co-Authored-By: Karan20P <42742074+Karan20P@users.noreply.github.com>
2026-04-22 05:17:19 +05:30
Rohit Kushwaha
64ecc74b4f Merge branch 'dev' into feat/pocket-tool-policy 2026-04-22 04:42:09 +05:30
TejasriPacharu
6125b12ce3 fix: add get_tool_policy/set_tool_policy to AgentBackend protocol 2026-04-22 00:24:48 +05:30
Amritesh
ea019b5f8e feat(analytics): implement tracing, budget enforcement, and health monitoring
Comprehensive implementation of analytics, tracing, and budget enforcement layers:

- Budget Enforcement: Added global and per-agent monthly caps in config.py. Implemented
  point-of-call enforcement in UsageTracker.record() with fail-safe logic for unknown
  models. Added preflight blocking in AgentLoop and support for temporary dashboard overrides.
- Request Tracing: Implemented trace_id propagation across the bus. Added TraceCollector
  to assemble and persist request-level telemetry (tool calls, LLM costs, latency) to
  rotated JSONL storage.
- Analytics API: Created async, non-blocking endpoints for cost (including pro-rata
  tool attribution), performance, usage, and health. Integrated audit-log based
  guardian block rates and ChannelHealthStore uptime metrics.
- Alerting & Monitoring: Implemented AlertManager for periodic threshold checks
  (budget, error spikes, tool degradation) and wired it into the app lifecycle.
- Dashboard UI: Developed a multi-tab Analytics modal (Overview, Budget, Alerts)
  with real-time unread badges, budget bars, cost-by-tool tables, and health timelines.
- Testing: Added 16+ targeted tests covering budget edge cases, alert flag consistency,
  and audit log parsing.
2026-04-21 22:04:19 +05:30
Amritesh
63074f0a68 feat(traces): Implement trace storage utilities for request-level observability
- Added TraceStore class for managing trace data with daily JSONL partitioning.
- Implemented methods for appending, retrieving, and cleaning up traces.
- Introduced helper functions for parsing timestamps and calculating trace costs.
- Created API endpoints for accessing trace data and analytics.

feat(api): Add budget and analytics API endpoints

- Implemented budget status and override management routes.
- Added analytics endpoints for cost, performance, usage, and health metrics.
- Created tests for budget and analytics API functionality.

test(traces): Add comprehensive tests for trace storage and API

- Developed unit tests for trace storage helpers and integration tests for trace propagation.
- Added tests for budget and analytics API endpoints to ensure correct behavior.
- Included tests for trace collector event aggregation and lifecycle management.
2026-04-21 14:50:56 +05:30
Prakash Dalai
16877a8216 Merge pull request #1008 from pocketpaw/fix/sec-e-ssrf-dev
fix(security): SSRF guard on URL config fields (re-targeted to dev)
2026-04-21 13:40:34 +05:30
Prakash-1
435ffd8c89 fix(security): SSRF guard on URL config fields
Closes #703. Seven Settings URL fields were bare str with no validation:
opencode_base_url, litellm_api_base, openai_compatible_base_url,
mem0_ollama_base_url, embedding_base_url, signal_api_url,
mcp_client_metadata_url. An operator (or a compromised settings write
path) pointing any of them at http://169.254.169.254/ would pull cloud
metadata on the next request cycle; pointing at file:///etc/passwd
could read local files depending on the HTTP client's URL handling.

Fix: a new `security/url_validators.py` exposes
`validate_external_url`, a pydantic AfterValidator that rejects

* non-http/https schemes (file://, ftp://, gopher://, ...)
* loopback, RFC1918, link-local (169.254/16 = EC2 metadata),
  carrier-grade NAT, and 0.0.0.0/8 hosts unless
  POCKETPAW_ALLOW_INTERNAL_URLS is set to true

Dev defaults (localhost:4096 opencode, localhost:11434 ollama, etc) rely
on the opt-in flag, which tests flip on via a conftest-level os.environ
default. OSS / production deployments leave it off and get a loud
ValidationError at Settings() construction if anything points inside.

Tests: tests/test_config_url_validation.py — 8 cases covering validator
logic + Settings integration.
2026-04-21 13:40:13 +05:30
Prakash-1
52b7784666 test(security): failing tests for URL config validators (SSRF)
Reproduces #703 — seven URL config fields in pocketpaw.config.Settings
are bare str, no validation. An operator pointing opencode_base_url at
169.254.169.254/ harvests cloud metadata; pointing signal_api_url at
file:/// reads local files.
2026-04-21 13:39:28 +05:30
Prakash Dalai
b1fbf4c3ae Merge pull request #907 from Tanuj26Rajput/fix/fastapi-lifespan
fix: migrate FastAPI on_event to lifespan handlers
2026-04-21 13:34:54 +05:30
Prakash Dalai
b348340679 Merge pull request #906 from Pragatisource08/cleanup/post-merge-main-fixes
fix: add _serve() port-fallback wrapper and correct SO_REUSEADDR docstring
2026-04-21 13:34:49 +05:30
Prakash Dalai
0b8b56ec57 Merge pull request #964 from pocketpaw/fix/sec-f-dos-rate-and-redos
fix(security): lock rate-limiter bucket + bound ReDoS-prone regexes
2026-04-21 13:34:44 +05:30
Prakash Dalai
1ebfa18ac4 Merge pull request #962 from pocketpaw/fix/sec-d-daily-notes-scope
fix(security): scope daily notes by sender_id
2026-04-21 13:34:38 +05:30
Prakash Dalai
ebf2e199c2 Merge pull request #961 from pocketpaw/fix/sec-c-logging-scrub
fix(security): scrub secrets before they reach the audit log or syslog
2026-04-21 13:34:34 +05:30
Prakash Dalai
481d7c41aa Merge pull request #960 from pocketpaw/fix/sec-b-auth-bypass
fix(security): require_scope fails closed + tool_profile raises on typos
2026-04-21 13:34:30 +05:30