v0.7.8: security hardening, code hygiene, MSFT oauth provider, new atlassian assets and google calendar tools#5088
v0.7.8: security hardening, code hygiene, MSFT oauth provider, new atlassian assets and google calendar tools#5088waleedlatif1 wants to merge 23 commits into
Conversation
…5060) * fix(providers): pin Azure OpenAI/Anthropic endpoints to validated IP (TOCTOU SSRF) * fix(providers): fail closed when Azure endpoint validates without a pinnable IP * refactor(security): drop pinned-fetch agent pool, keep per-call dispatcher * refactor(security): make createPinnedFetch the single pinned-fetch source * refactor(security): drop pinned-fetch agent pool; keep per-call dispatcher
…cern modules (#5069) * refactor(table): extract row ordering, executions, and tx helpers from service.ts Move the row position/fractional-ordering internals to rows/ordering.ts, the row-execution (workflow-group result) internals to rows/executions.ts, and the shared tx-timeout helpers to tx.ts. Pure code-motion — verbatim bodies, identical behavior. service.ts: 5324 -> 4442 lines. * refactor(table): extract row CRUD and query into rows/service.ts Move insert/update/upsert/delete/replace/batch row writes, queryRows/ getRowById reads, and findRowMatches into rows/service.ts. Verbatim bodies; consumers repointed; @/lib/table barrel re-exports the new module so callers are unchanged. service.ts: 4442 -> 2788 lines. * refactor(table): extract column/schema management into columns/service.ts Move add/rename/delete column ops and column-type/constraint updates into columns/service.ts. addTableColumnsWithTx stays in service.ts (table-creation primitive) to avoid a cycle. Verbatim bodies; barrel re-exports the module. service.ts: 2788 -> 2149 lines. * refactor(table): extract job state machine and export jobs into jobs/service.ts Move tableJobs reads/mapping, the job lifecycle state machine, and export-job queries into jobs/service.ts. service.ts imports latestJob* one-way for table metadata enrichment (no cycle). Import-data orchestration helpers stay in service.ts for now. Verbatim bodies. service.ts: 2149 -> 1791 lines. * refactor(table): extract workflow-group management into workflow-groups/service.ts Move add/update/delete workflow groups + outputs and pruneStale into workflow-groups/service.ts, preserving the dynamic backfill-runner import (cycle-breaker). Verbatim bodies; no cycle. service.ts: 1791 -> 851 lines. * refactor(table): extract import-job data ops into import-data.ts Move bulk insert, schema setup, and append/replace import operations into import-data.ts (consumed by import-runner + import route). service.ts is now the pure table-entity module (root CRUD + shared lock/column primitives). Verbatim bodies; no cycle. service.ts: 851 -> 664 lines (5324 at start). * refactor(table): restore private visibility and drop dead helpers post-split Un-export DerivedJobFields/JOB_PROJECTION/mapJobRow (file-local in jobs/service.ts, were private pre-split) so they no longer leak into the @/lib/table barrel. Remove dead code carried into the new modules: countTables (createTable does its own inline count check) and the unused buildOrderedRowValues/OrderedRowValue pair. * refactor(table): use absolute imports throughout and fix an orphaned TSDoc Normalize all relative imports under lib/table to absolute @/lib/table/... per the project import rule (the split modules and a few pre-existing holdouts), and relocate the getTableById TSDoc that had drifted above applyColumnOrderToSchema. Comment/import-only; zero behavior change.
…5074) GET /api/credential-sets/invitations returned every pending, unexpired link-only (null-email) invitation across all organizations, including the bearer token. Any authenticated user could enumerate and accept another org's invitation, joining its credential set (cross-tenant access). Scope the listing strictly to invitations addressed to the caller's own email. Open-link invites remain redeemable only via the out-of-band /credential-account/[token] URL.
…ment (#5072) * feat(jsm): add Atlassian Assets (Insight/CMDB) tools for asset management Add nine JSM Assets tools so workflows can read and write Atlassian Assets (Insight/CMDB) objects — the foundation for keeping JSM asset tables in sync for software/hardware asset management. Tools (wired into the Jira Service Management block): - jsm_list_object_schemas, jsm_get_object_schema - jsm_list_object_types, jsm_get_object_type_attributes - jsm_search_objects_aql (AQL search with pagination) - jsm_get_object, jsm_create_object, jsm_update_object, jsm_delete_object Each tool proxies through an internal route that resolves the Jira cloudId and the Assets workspaceId, then calls the Assets API via the OAuth 2.0 (3LO) gateway form (/ex/jira/{cloudId}/jsm/assets/workspace/{workspaceId}/v1). Adds the CMDB OAuth scopes to the jira provider (read/write/delete cmdb-object, read cmdb-schema/type/attribute) with descriptions, contract schemas for each route, and block operations/subBlocks/outputs. Bumps the API-validation route baseline for the nine new routes. * refactor(jsm): harden Assets param coercion and response typing - Add toOptionalInt helper so non-numeric pagination inputs never emit NaN into the Assets query string (startAt/maxResults/page/resultsPerPage) - Replace Record<string, any> in mapAssetObject with typed Raw* interfaces * fix(jsm): validate Assets workspaceId and honor `last` pagination flag Address review findings on the Assets tools: - Add validateAssetsWorkspaceId and guard the workspaceId in every Assets route before it is interpolated into the API path (mirrors the existing cloudId guard) — prevents a crafted workspaceId from escaping the workspace-scoped path - Object schema list now falls back to the `last` flag when `isLast` is absent, so pagination doesn't stop early * feat(jsm): allow overriding the auto-resolved Assets workspace Atlassian provisions one Assets workspace per site, so workspace discovery uses values[0] by design. For the rare multi-workspace site, expose an advanced "Assets Workspace ID" override on the block that flows through to every Assets operation, and document the single-workspace assumption. * refactor(jsm): include Assets responses in the JsmResponse union Append the nine Assets tool response types to JsmResponse for completeness and consistency with the rest of the JSM tool surface.
* fix(uploads): authorize internal file URLs before download downloadFileFromUrl treated any URL containing /api/files/serve/ as trusted-internal and read the object straight from storage by key with no access check, while every other resolution path in the file calls verifyFileAccess. Reachable during workflow execution via file[] inputs (type: 'url'), letting an authenticated user read arbitrary storage objects across tenants by supplying a storage key. Thread the caller's userId into downloadFileFromUrl and run verifyFileAccess(key, userId, undefined, context, false) on the resolved key before downloadFile; fail closed when no userId is present. Update all callers (execution file inputs, tool file outputs, KB ingestion); webhook and chat inputs already thread userId via processExecutionFiles. * chore(uploads): log denied internal file downloads for rollout telemetry * fix(uploads): derive internal file context from key, not query param Cursor Bugbot flagged a context-spoofing bypass: downloadFileFromUrl resolved context via parseInternalFileUrl, which honors a caller-controlled ?context= query param. An attacker could label a private storage key with a world-readable context (profile-pictures/og-images/workspace-logos) so verifyFileAccess short-circuits to granted while downloadFile still reads the private object. Infer context from the key only (inferContextFromKey), mirroring how /api/files/serve resolves it; ignore the query param. Also move the userId guard ahead of key resolution so auth failures surface first. * docs(uploads): move context-derivation rationale into TSDoc * fix(uploads): match internal file marker in URL path only isInternalFileUrl matched the /api/files/serve/ substring anywhere in the string, so a crafted URL could carry it in a query string or fragment and skip DNS/SSRF validation. Match it in the path component only. The raw path is checked without URL normalization on purpose: the files parse route relies on traversal sequences surviving this check (an absolute https://host/api/files/serve/../.. URL must classify as internal so the '..' check rejects it, rather than being normalized to /etc/... and waved through as external). Host is intentionally not gated — cross-tenant reads are prevented at the storage sink by verifyFileAccess, and host-allowlisting would break self-hosted/multi-domain deployments. Adds unit tests. * consolidate access, billing principals --------- Co-authored-by: Vikhyath Mondreti <vikhyath@simstudio.ai>
* feat(auth): OAuth-only signup with Microsoft provider - Remove email/password form from /signup — Google, Microsoft, GitHub OAuth only - Add Microsoft as a social provider (MICROSOFT_CLIENT_ID / MICROSOFT_CLIENT_SECRET / DISABLE_MICROSOFT_AUTH) - Wire microsoftAvailable through provider checker, API contract, providers route, and all auth UI - Hide "Continue with email" in auth modal signup view; login view unchanged - Fix MicrosoftIcon SVG to use official brand colors and proportions * fix(auth): remove unused useSession, guard invalid-callback warn with ref * feat(auth): gate email signup via DISABLE_EMAIL_SIGNUP flag * feat(auth): restore signup email form gated by NEXT_PUBLIC_DISABLE_EMAIL_SIGNUP * refactor(auth): single DISABLE_EMAIL_SIGNUP env var controls both ui and backend * fix(config): restore isHosted hostname check
* feat(db): zero-downtime migration safety lint + db-migrate skill Add scripts/check-migrations-safety.ts (check:migrations), a CI gate that classifies statements in newly-added migrations into hard errors (rewrite), annotate-to-acknowledge contract ops (`-- migration-safe: <reason>`), and backfill warnings. Wire it into test-build.yml. Add the /db-migrate skill as the judgment half (expand/contract phasing, app-code cross-ref, annotation authoring). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(skills): run cleanup and db-migrate safety checks in /ship * fix(db): address review — DROP INDEX lock symmetry, RENAME CONSTRAINT false-positive, alter-type literal match - Non-concurrent DROP INDEX is now a hard error (ACCESS EXCLUSIVE lock), symmetric with CREATE INDEX; DROP INDEX CONCURRENTLY after a COMMIT passes clean. Removes the false-confidence annotate path. - RENAME rule narrowed to RENAME COLUMN / table RENAME TO; RENAME CONSTRAINT and ALTER INDEX ... RENAME (metadata-only) no longer flagged. - alter-type regex now requires TYPE to follow the column identifier, so it no longer matches TYPE inside a string default. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(db): enforce IF EXISTS on DROP INDEX CONCURRENTLY for replay idempotency Symmetric with the CREATE INDEX CONCURRENTLY rule: a post-COMMIT DROP INDEX CONCURRENTLY replays from the top on failure, so without IF EXISTS it aborts re-dropping an already-gone index. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * improvement(skills): gate /ship cleanup on UI changes; default migration base to staging - /ship runs /cleanup only when the diff touches UI code (.tsx or apps/sim/components|hooks|stores); the six passes are React-only. - /ship runs check:migrations against origin/staging (the PR base). - check:migrations default baseRef is now origin/staging instead of origin/main. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(db-migrate): add contract-pending TODO convention for deferred drops Establishes a durable, greppable marker (`contract-pending(<precondition>): ...`) left on the legacy column in schema.ts when an expand defers a drop, so the contract phase doesn't rot. The outstanding-work list is `grep -rn contract-pending`; the contract PR's `-- migration-safe:` annotation references the expand and deletes the marker. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(webhooks): cap request body size on public webhook receivers Public, unauthenticated webhook endpoints read the entire request body into memory before any lookup or signature verification, letting a caller exhaust pod memory with arbitrarily large bodies. Bound the body via the existing size-limited stream reader (content-length guard + streamed cap) and return 413 on oversize. Applies to parseWebhookBody (trigger receiver) and the agentmail route. Cap defaults to 10 MB, overridable via WEBHOOK_MAX_REQUEST_BYTES. * refactor(webhooks): extract shared body-size cap to constants module Address review feedback: hoist WEBHOOK_MAX_BODY_BYTES into a single lib/webhooks/constants.ts so the trigger receiver and AgentMail route share one source of truth instead of recomputing the env-derived cap (prevents drift). Also drop the redundant request clone when the body stream is null. * refactor(webhooks): drop redundant null-body branch in capped readers Both capped body readers had an `if (!stream)` fallback to an uncapped `.text()`/empty string. `readStreamToBufferWithLimit` already returns an empty buffer for a null stream, so the branch is redundant and the `.text()` fallback was a theoretical bypass (chunked request, no content-length, null body). Collapse both to a single capped read. * chore(webhooks): drop inline comments from capped body readers
Validate the user-supplied vLLM endpoint (request.azureEndpoint) against the central SSRF guard and pin the connection to the resolved IP before issuing any request, mirroring the Azure OpenAI/Anthropic providers. The operator-configured VLLM_BASE_URL stays trusted and unvalidated.
Pass allowHttp to validateUrlWithDNS so plain-HTTP self-hosted vLLM endpoints are permitted. This only relaxes the protocol check; the private/reserved-IP blocklist and blocked-port checks still apply, so SSRF protection is unchanged.
* feat(feature-flags): AppConfig-backed gated feature flags * fix(ci): repoint 'Validate feature flags' step to env-flags.ts after rename * improvement(feature-flags): drop in-code defaults; fallback resolves a per-flag secret, gating is AppConfig-only * improvement(feature-flags): make flag names a closed set so every flag requires a fallback secret * improvement(feature-flags): single FEATURE_FLAGS registry — each entry defines name, description, and fallback in one place * improvement(feature-flags): fallback is the env secret key (keyof typeof env), resolved to a boolean
…ct-point tools (#5082) * feat(grafana): validate integration and add folder, health, and contact-point tools - Require alert-rule title/ruleGroup/data in the block (create would 400 without them) - Trim UID path params across dashboard and alert-rule tools to avoid copy-paste 404s - Use Grafana brand color for the block background - Surface previously-unsettable list params (limit, starred, annotation type) - Add get/update/delete folder, check data source health, get health, and create contact point tools - Strip non-TSDoc comments; regenerate docs and integrations.json * fix(grafana): scope block param remaps per operation to prevent cross-operation leaks
* refactor(connectors): split client metadata from server runtime + cover node:net in client bundle The browser build broke with `Cannot find module 'node:net'`. Server-only SSRF code in `input-validation.server.ts` (`dns/promises`, and since PR #5060 `undici` → `node:net`/`node:tls`) is statically reachable from the client bundle via the tool/connector registries, which the workflow editor imports for metadata. Node networking builtins have no browser shim, so Turbopack cannot compile them for the client. Two changes: 1. Split each connector's client-safe declarative metadata into a sibling `meta.ts` (`<name>ConnectorMeta`), mirroring the `XBlockMeta` / `BLOCK_META_REGISTRY` pattern. `connectors/registry.ts` is now the client-safe `CONNECTOR_META_REGISTRY` (+ `getConnectorMeta` / `getAllConnectorMeta`); the full registry with runtime fns moves to `connectors/registry.server.ts`. Client components consume the meta registry; the sync engine and knowledge API routes consume the server registry. This removes connectors from the client's server-only graph. Connector metadata is byte-for-byte identical before/after; runtime fns are untouched. 2. Extend the existing #4899 `turbopack.resolveAlias` browser stub — which already mapped `dns`/`dns/promises` to an empty module for the browser — to also cover `net`/`tls` (+ `node:` variants), since `undici` now pulls those in. The remaining tool/provider definitions still reach `input-validation.server` server-side; the browser-only stub keeps those Node builtins out of the client bundle while the real modules stay on the server, so SSRF validation and IP pinning are unaffected. Connector authoring/validation skills updated to teach the meta.ts split. * fix(icons): use Square logo glyph only, drop wordmark * fix(connectors): share Discord max-messages default across meta and runtime Discord defined DEFAULT_MAX_MESSAGES separately in meta.ts (config placeholder) and discord.ts (sync behavior), which could drift. Export it from meta.ts and import it in the runtime, matching the single-source pattern used by the other connectors (e.g. gmail, intercom). * refactor(tools): route grafana/agiloft egress server-side, drop SSRF browser shim Move the server-only SSRF-pinned fetch out of the grafana (update_dashboard, update_alert_rule) and agiloft (11 record/search tools) definitions and into internal API routes, the same pattern the rest of the server-side tools (and agiloft's own attach/retrieve) already use. The tool definitions are now purely declarative (request → internal route), so they no longer import `input-validation.server` and the tools registry is fully client-safe. With connectors (meta split) and these tools no longer reaching server-only code from the client bundle, the browser no longer pulls in `dns`/`net`/`tls`: - Add `import 'server-only'` to `input-validation.server.ts` so any future client import fails loudly at build time instead of silently bloating the bundle. - Remove the `turbopack.resolveAlias` browser stub and delete `empty-node-fallback.browser.ts` — the root cause is fixed, the shim is gone. Behavior is unchanged: each route runs the exact merge/validation/fetch logic the tool ran before (every header, param branch, JSON-parse guard, error string, and SSRF pinning preserved); only the location of execution moved from the client- bundled definition to a server route. * fix(connectors): move onedrive tagDefinitions into meta; drop server-only guard - onedrive's tagDefinitions lived in the runtime file, so the client meta registry returned undefined for it and the add-connector tag opt-out section stopped rendering for onedrive. Move it into meta.ts like the other connectors so client and server see identical metadata (verified across all 50). - Remove the 'server-only' import from input-validation.server.ts: the meta/route split already keeps it out of the client bundle, and blocks/tools registries don't use the guard either. * fix(grafana): surface upstream error when the prefetch GET fails Check response.ok on the existing-resource GET in both update routes and return the upstream status/body, matching how the tool framework surfaced GET errors before the move to internal routes (the framework checks response.ok before transformResponse). Without this, a failed prefetch produced a generic 'Failed to fetch existing ...' message and dropped Grafana's error detail. * fix(grafana): reject invalid panels JSON instead of silently ignoring it Grafana's dashboard API treats panels as a required array and returns 400 on invalid JSON; this route already errors on every other JSON param. Return 'Invalid JSON for panels parameter' instead of swallowing the parse error and proceeding with a misleading success. * fix(grafana): trim dashboard/alert-rule UID in route URLs (carry over #5082) PR #5082 added .trim() on dashboardUid/alertRuleUid in the original tool URL builders. Those tools now build their URLs in the internal routes, so apply the same trim there to preserve that behavior. * fix(grafana): route update_folder egress server-side (carry over #5082) #5082 added a grafana update_folder tool that does SSRF-pinned fetch in its postProcess, re-introducing the client-bundle leak. Convert it to the internal API route pattern like the other update tools so the def is declarative and input-validation.server stays out of the client bundle. * fix(grafana): surface route failures in transformResponse instead of masking them The grafana update tools' transformResponse hardcoded success: true and dropped the route's error, so an upstream/validation failure (HTTP 200 with { success: false, error }) was reported to the workflow as a success. Forward data.success and data.error (matching the agiloft tools) so failures propagate as before the move to internal routes.
…flags (#5086) * feat(feature-flags): migrate 3 env-flags to AppConfig-backed runtime flags * fix(feature-flags): hardcode workflow-columns on, fix feature-flags tests * chore(feature-flags): document mothership-beta userId targeting limitation
…lendar + sharing tools (#5084) * feat(google-calendar): wire freebusy, align tools with API v3, add calendar + sharing tools * fix(google-calendar): address review — trust offset timezones, make list_acl showDeleted usable, harden unshare error parse, clarify update attendees * fix(google-calendar): wire list q/pageToken into block, harden invite PUT error parse * fix(google-calendar): make list orderBy user-selectable, clarify update timeZone applies to start/end * fix(google-calendar): require timeZone for recurring timed events, clarify recurrence replace semantics * fix(google-calendar): validate grantee before building share ACL body Throw a clear error when scopeType is user/group/domain but scopeValue is missing or blank, instead of POSTing a scope-type-only body that the Calendar ACL API rejects with an opaque error.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
PR SummaryHigh Risk Overview Platform structure shifts deploy-time booleans from CI adds a non-blocking companion PR workflow for cross-repo lockstep merges and a Reviewed by Cursor Bugbot for commit b7d30c8. Configure here. |
|
#5070) * improvement(perm-groups): allow workspace filter for permission groups * show errors correctly * address comments * address concurrent edit concern * address locks * address comments" * index migration safety * address at route level
Uh oh!
There was an error while loading. Please reload this page.