fix(activity): filter by action, reject unknown activity query params (BLO-21979) - #1046
fix(activity): filter by action, reject unknown activity query params (BLO-21979)#1046allyblockcast[bot] wants to merge 2 commits into
Conversation
|
🔗 Paperclip issue: BLO-21979 |
1 similar comment
|
🔗 Paperclip issue: BLO-21979 |
|
Hey @allyblockcast[bot]! Before this PR can be reviewed, a few things need attention: Missing or incomplete:
Once updated, push a new commit and these checks will re-run automatically. — commitperclip |
Ally — Consolidated PR ReviewLenses: pr-review-toolkit (code, tests, comments, errors, types) + gstack/review + native-codex. Important Issues (2)
Strengths
Recommended Action
This PR is authored by |
kkroo
left a comment
There was a problem hiding this comment.
Approved: action filtering is wired through service and route layers, unknown audit-route query keys now fail explicitly, response shape remains compatible, and route/service/OpenAPI tests cover the new behavior.
…979) - Service: check `!== undefined` instead of truthiness so an explicit empty-string filter value narrows to zero rows instead of silently falling through to the unfiltered feed. - Route: reject an empty string for any of the company-activity filter query params (agentId/entityType/entityId/action) with a 400 rather than letting it become `undefined` and widen the query. - Route: percent-encode the X-Applied-Filters header value so a non-Latin1 action value (e.g. a Unicode filter) can't crash the response with Node's ERR_INVALID_CHAR. Addresses Ally's review on PR #1046.
|
Addressed both Important findings from Ally's review (head
Added route tests for the empty-action-400 case and the Unicode-action case, plus a service-level test asserting Verified: Note: this PR had reached the merge queue (position 39) after @kkroo's approval, which predates the review comment surfacing above by ~2.5 minutes — I dequeued it to land this fix rather than merge known-bad behavior, since the review findings were real correctness bugs on an audit-integrity surface. Re-requesting review on the new head. |
Ally — Consolidated PR ReviewLenses: pr-review-toolkit (code, tests, comments, errors, types) + gstack/review + native-codex. Prior Findings Dispositioned (2)
Important Issues (1)
Strengths
Recommended Action
This PR is authored by |
…ams (BLO-21979) GET /companies/:id/activity accepted ?action= but silently dropped it, returning a plausible-looking but unfiltered page. On an audit surface that reads as "verified absent" when the record actually exists. Wire the action filter through to the query, reject unsupported query keys on this route and its GET siblings with a 400 naming the offending key, and echo the filter actually applied via an X-Applied-Filters header (kept out of the JSON body to preserve the existing array response contract for UI consumers).
…979) - Service: check `!== undefined` instead of truthiness so an explicit empty-string filter value narrows to zero rows instead of silently falling through to the unfiltered feed. - Route: reject an empty string for any of the company-activity filter query params (agentId/entityType/entityId/action) with a 400 rather than letting it become `undefined` and widen the query. - Route: percent-encode the X-Applied-Filters header value so a non-Latin1 action value (e.g. a Unicode filter) can't crash the response with Node's ERR_INVALID_CHAR. Addresses Ally's review on PR #1046.
5079654 to
c87362f
Compare
Thinking Path
Linked Issues or Issue Description
Paperclip issue BLO-21979 describes this audit-feed bug. No GitHub issue exists, so the bug is described inline in the required issue-template shape.
What happened
GET /companies/:companyId/activity?limit=5&action=issue_write_deniedreturned200with unfiltered activity rows, even though a matchingissue_write_deniedrow existed.Expected behavior
The activity endpoint should either return only rows matching
action=issue_write_deniedor reject the request if the filter is unsupported. It must not silently ignore a filter on an audit surface.Steps to reproduce
issue_write_deniedactivity row.GET /companies/:companyId/activity?limit=5&action=issue_write_denied.Paperclip version or commit
Observed before this PR on the branch that did not include
activityService.list({ action })support.Deployment mode
Server/API route behavior; reproduced against the Paperclip deployment API surface.
What Changed
server/src/services/activity.ts: addedactiontoActivityFiltersand to the list query conditions.server/src/routes/activity.ts: passesactionthrough on company activity requests and rejects unsupported query parameters on all four GET routes in the file.server/src/routes/activity.ts: addsX-Applied-Filterson company activity responses so callers can distinguish applied filters from empty results.server/src/routes/openapi.ts: documents the supported query parameters and 400 responses.Sibling-route audit
Checked nearby read/audit routes for the same accept-and-ignore pattern. The activity GET siblings now reject unsupported query parameters.
cases.tsandpipelines.tsalready validate their query shapes.companies.tstimeline/artifact query schemas intentionally passthrough.file-resources.tshas a related broader-default issue in a different subsystem and should be tracked separately.Verification
npx vitest run server/src/__tests__/activity-routes.test.ts server/src/__tests__/activity-service.test.tspassed locally: 18/18.npx vitest run server/src/__tests__/openapi-routes.test.tspassed locally: 3/3.tsc --noEmitonserver/completed cleanly.Risks
Low risk. The
actionfilter is additive. The unknown-query-param rejection is a behavior change for callers sending stray keys to these audit routes; known UI callers send only supported keys. The response body remains the same array shape, and the applied-filter signal is header-only.Model Used
Claude Sonnet 5 (
claude-sonnet-5[1m]), agentic coding session with file inspection, route/service edits, and local test execution.Checklist