fix: six pre-existing integration defects surfaced by the docs audit - #7195
Conversation
localeCompare with no locale argument uses the runtime default, which varies with LANG and the ICU build. Against the real 254 catalog names, tr-TR reorders 141 positions, et-EE 45, cs-CZ 2 and lt-LT diverges at index 40 — so a contributor on any of those regenerates a different integrations.json and fails CI with no obvious cause. Pins en-US at all four sort sites. The committed artifacts are unchanged: regenerating before and after leaves the tree byte-identical. Adds a guard test asserting the committed catalog matches an explicit en-US ordering, plus one that fails if an unpinned localeCompare returns.
The block rendered an advanced MIME Type input and forwarded it as the tool's mimeType, but the upload path never reads it: file-input.ts sets `resolved.contentType || userFile.type || input.mimeType || …`, and every return path of downloadServableFileFromStorage yields a non-empty content type — a literal, getMimeTypeFromExtension's GENERIC_MIME_TYPE fallback, or resolveServableDocBytes' constants and getContentType fallback. The placeholder claimed it was 'used when the file has no type of its own', which never happens. Removes the subBlock, its mapper write and its inputs entry, and marks the tool param hidden so it is no longer advertised to the model on a path where it cannot take effect. The param itself stays, because the base64 branch still reads it. Letting a typed value win instead was rejected: for a compiled artifact the storage-resolved type is the only one matching the bytes actually sent, so an override would break the case the resolver exists to fix.
github_comment sent commit_id as undefined for every file comment: the
param was hidden with no subBlock and no mapper write, so GitHub — which
marks commit_id required on POST /pulls/{n}/comments — answered 422 on a
path the commentType dropdown exposes.
When commitId is absent the tool now fetches the pull request first and
uses head.sha, mirroring how Jira resolves cloudId from domain.
Also removes the position param, which GitHub marks deprecated ("Use
line instead"); line is already a real subBlock.
list, search, list_comments, list_permissions and list_revisions each declared a hidden pageToken and forwarded it to Google, but the block had no subBlock of that name and never has — so every list was capped at one page and the nextPageToken output had nowhere to go. Adds a per-operation Page Token field mirroring the block's existing per-operation pageSize fields, collapses them onto the canonical pageToken in the params mapper, and flips the tool param to user-only so it is documented and settable.
All 46 Confluence tools marked cloudId 'user-only', publishing it on 46 doc rows, but the block has no cloudId subBlock so no user could ever fill it. createConfluenceClient already resolves the cloud id from the domain through the shared Atlassian resolver, exactly as Jira does, and Jira marks the same param hidden. Marks cloudId hidden to match. domain stays user-only and settable — it is now the only user-provided param on every Confluence tool.
blankStringsAndComments was a single regex with no concept of a regex
literal, so two shapes silently truncated a block's subBlock list:
/don't/ the apostrophe opened a phantom string that swallowed the
following entries
/[}]/ the brace in the character class closed the enclosing object
Both returned a short list with no warning — a confident wrong answer,
which for the hidden-param filter means silently deleting a user-settable
row. No block file uses a regex literal today, so this was latent.
Replaces the regex with a linear scanner that distinguishes a regex
literal from a division by the previous significant character, blanks
regex bodies whole (their last character is arbitrary source, same reason
comments are blanked whole), and tracks ${} nesting so a backtick inside
a template expression cannot end the template early.
The scanner now returns null when it ends inside an unterminated
construct. All three call sites treat that as UNKNOWN rather than
guessing, so the filter switches off instead of stripping.
Generated artifacts are byte-identical and the warning count is unchanged.
…ntegration-defects
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Greptile SummaryThe PR repairs several integration metadata and execution defects while making documentation generation deterministic and its source scanner more robust.
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains.
|
| Filename | Overview |
|---|---|
| apps/sim/tools/github/comment.ts | Implements typed two-phase comment execution, commit-SHA resolution, cancellation propagation, and narrowed provider responses without leaving either previously reported issue outstanding. |
| apps/sim/tools/github/utils.server.ts | Adds a DNS-validated, IP-pinned GitHub transport that forwards abort signals and strips credentials on cross-origin redirects. |
| apps/sim/blocks/blocks/google_drive.ts | Adds operation-scoped pagination inputs and maps only the active operation’s token into the tool request. |
| scripts/generate-docs.ts | Makes generated ordering locale-independent and strengthens lexical scanning of regex and template constructs. |
Reviews (7): Last reviewed commit: "fix(docs-gen): close a regex-vs-division..." | Re-trigger Greptile
There was a problem hiding this comment.
All reported issues were addressed across 65 files
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
|
@cubic-dev-ai review |
@waleedlatif1 I have started the AI code review. It will take a few minutes to complete. |
There was a problem hiding this comment.
All reported issues were addressed across 65 files
Requires human review: Auto-approval blocked by 6 unresolved issues from a previous review of this commit.
Re-trigger cubic
…iling field
Three corrections to the file-comment fix, from a validation sweep.
needsCommitLookup did not check `path`, and ran before the `path` branch in
request.url. A file comment with an empty File Path — reachable, since path
is not required on the block — went GET /pulls/{n} then POST /comments with
path undefined, a 422. On staging it posted to /pulls/{n}/reviews, which
GitHub documents as creating a pending review and where commit_id is
optional. The lookup is now gated on path, so only a request headed for
/comments triggers it.
The block has no tools.config.params, so `line` reached the tool as the
string the short-input produced while GitHub types it as an integer — file
comments would still have 422'd, one API call later. Coerced in
request.body, which runs at execution; anything non-finite is omitted
rather than sent as NaN.
readGitHubErrorMessage returned only the top-level message, so a 422 read
"Validation Failed" with no indication of which field was rejected. The
errors[] detail is now appended. Responses without errors[] are unchanged.
Adds the file_comment-without-a-path case (which the commit lookup now skips), the untouched-block default where commentType is unset, a pr_comment carrying a path, and the line coercion on both the direct and resolved-commit paths.
A page token is an opaque continuation value produced by a previous tool response, not an account-specific id the user has to supply, so 'user-only' hid it from agent blocks: they saw nextPageToken in the result and could not send it back, silently reporting page one as the whole answer. Every other pagination token in the tool set is 'user-or-llm'. Also covers the case the mapper guard actually defends — a per-operation page token surviving an operation switch, which reaches inputs because shouldSerializeSubBlock skips condition evaluation for advanced fields.
…cannable source - Record why '\\n' is in REGEX_ALLOWED_AFTER: formatters emit a binary '/' at end-of-line, so every line-leading '/' in blocks/*.ts is a real regex, including the ones in table.ts and table_v2.ts. Removing it silently mis-scans those two. - Split a scanner failure out of the spread-only 'ids: null' case. Both scans come back empty for the same reason when blankStringsAndComments bails, so the mapper's renames were dropped with no warning; it now reports a parseError and warns. The spread case is unchanged, and its TSDoc no longer claims a cause that was false. - Route every catalog sort through an exported compareCatalogNames so the ordering test exercises the generator's comparator instead of re-deriving it, and match localeCompare arguments whole so localeCompare() and a variable locale are caught. - Note that downloadServableFileFromStorage guarantees a non-empty content type, so the Vanta mimeType fallback chain reads as deliberately defensive. Artifacts regenerate byte-identically and the generator warning set is unchanged.
|
@cubic-dev-ai review |
@waleedlatif1 I have started the AI code review. It will take a few minutes to complete. |
There was a problem hiding this comment.
All reported issues were addressed across 67 files
You’re at about 94% of the monthly reviewed-line limit. You may want to disable incremental reviews to conserve quota. Reviews will continue until that limit is exceeded. If you need help avoiding interruptions, please contact contact@cubic.dev.
Requires human review: Auto-approval blocked because this review re-detected 1 unresolved issue already reported by Cubic.
Re-trigger cubic
check-block-registry fails a PR that deletes a subblock id without a migration entry, because a deployed workflow can still hold a value under that id. The serializer already discards an orphan silently, but the repo's contract is that the removal is declared rather than inferred. Uses the _removed_ form, scoped to upload_document_file: the value has no replacement field to move to.
The file-comment flow posted its comment from `transformResponse` with a bare global `fetch`, so that request carried no abort signal, no response ceiling and no DNS/SSRF validation — cancelling a workflow still left the comment posted. `transformResponse` cannot receive the signal; `directExecution` can. Both tools now run the lookup and the POST through a new `secureGitHubRequest`, mirroring `secureBitbucketRead`, with the signal forwarded to each. Routing, line coercion and the `errors[]` detail are unchanged, and a failed response still throws an error carrying `status`/`statusText`/`data` as the transport does. Request bodies and the comment payload are explicitly typed instead of `Record<string, any>`.
`mimeType` was marked hidden, but `visibility: 'hidden'` is reserved for system-injected params such as OAuth tokens. It also left the base64 upload path with no way to set a content type, since `fileContent` is hidden too.
The scanner chose regex-vs-division from the previous significant character, so
a regex in operand position (`return /x/`, `typeof /x/`, `case /x/`, ...) lexed
as a division off the keyword's last letter and its body stayed in the
structural view; `azure_devops.ts` is inert today only because the braces in its
`return /^\d{4}-\d{2}-\d{2}$/` happen to balance.
The `${}` depth counter was also not string-aware, so a brace inside a quoted
expression miscounted, the closing backtick was lost and the block was reported
unreadable — which silently stops filtering resolver-derived hidden params.
Both scans now run on one set of lexer primitives: `${}` expressions are lexed
with the same string, comment, regex and template handling as top-level code.
Regenerated docs, tool metadata and the integration catalog are byte-identical
and the generator's warning count is unchanged.
@waleedlatif1 I have started the AI code review. It will take a few minutes to complete. |
There was a problem hiding this comment.
1 issue found across 70 files
Confidence score: 4/5
- In
scripts/generate-docs.ts, the scanner can classify division after a valid object-literal expression as a regex and returnUNKNOWN, which may mis-handle documentation generation for affected inputs; track expression context before treating}as a regex boundary.
You’re at about 97% of the monthly reviewed-line limit. You may want to disable incremental reviews to conserve quota. Reviews will continue until that limit is exceeded. If you need help avoiding interruptions, please contact contact@cubic.dev.
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="scripts/generate-docs.ts">
<violation number="1" location="scripts/generate-docs.ts:1307">
P2: When a valid object-literal expression is followed by division, this entry misclassifies the division as a regex and makes the scanner return UNKNOWN. Track expression context before treating `}` as a regex boundary, so valid divisions do not disable or alter hidden-parameter filtering.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
secureGitHubRequest passed no redirectPolicy, and the transport only strips credential headers when one is present, so an api.github.com redirect to another origin carried the workspace's Authorization: Bearer header to the new host. Adopts the standard policy already used by the internal Google Drive client. stripAuthOnRedirect stays off: GitHub redirects same-origin for legitimate reasons (a renamed repository answers 301), and dropping auth there would turn a working call into a 401.
toLineNumber ran Math.trunc, so line 3.9 posted the review comment on line 3 — a silent change to what the caller asked for, on a field where landing on the wrong line of the diff is invisible until someone reads the comment. A non-integer now fails with a message naming the field, matching how a missing head commit SHA fails on this path. Blank and unparseable input is still omitted: line is optional and nothing usable was supplied.
The endpoint was chosen by the presence of path, while the body was chosen by
commentType, so a pr_comment naming a file posted a review body to
POST /pulls/{n}/comments. GitHub documents body, commit_id and path as required
there, so that request can only ever 422 — it has been broken since before this
PR. The endpoint now follows the comment type: only a file comment carrying a
path uses /comments, everything else stays on /reviews. The test that codified
the broken routing is corrected, and the full type/path matrix is pinned.
|
@cubic-dev-ai review |
@waleedlatif1 I have started the AI code review. It will take a few minutes to complete. |
There was a problem hiding this comment.
No issues found across 71 files
Confidence score: 5/5
- Automated review surfaced no issues in the provided summaries.
- No files require special attention.
You’re at about 99% of the monthly reviewed-line limit. You may want to disable incremental reviews to conserve quota. Reviews will continue until that limit is exceeded. If you need help avoiding interruptions, please contact contact@cubic.dev.
You've manually re-run cubic several times on this PR. Each manual re-review checks the full PR again and counts toward your usage quota. To preserve your usage limits, we recommend letting cubic automatically review new commits.
Re-trigger cubic
Removed at request. The visibility change itself is unaffected; it loses only the guard that would have caught a future edit reverting one of the 46 files.
…ected comment POST
`secureGitHubRequest` powers the GitHub comment tool's `directExecution`
path, which bypasses the declarative transport. Two behaviors the transport
provided did not survive the move.
User-Agent: the transport sets `User-Agent: Sim` on every request it formats
(`request-transport.ts`), and `secureFetchWithPinnedIP` adds none of its own —
it builds the request with raw `node:https` and passes headers through
verbatim. Production runs on Bun, whose `node:http` shim injects
`user-agent: Bun/x.y.z`, so GitHub does not reject these calls today; the
defect is that Sim's deliberate attribution is silently replaced by a runtime
version string, and that the tool depends on an undocumented runtime behavior
that does not hold under Node, where GitHub answers 403 "Request forbidden by
administrative rules". Set in the helper rather than in the tool's header map
so every future caller inherits it; a caller-supplied value still wins.
Redirect method: the policy was `mode: 'standard'`, under which
`resolveRedirectHop` rewrites a 301/302'd POST to a bodyless GET regardless of
origin. GitHub answers 301 within api.github.com for a renamed repository, so
commenting on a PR there would GET `/pulls/{n}/comments`, receive a JSON array,
fail the payload shape check, and report success with no comment created.
`legacy` keeps the method and body across that hop. Cross-origin credential
stripping is unaffected — the guarded follower strips Authorization,
Proxy-Authorization and Cookie whenever `sendCredentialsOnCrossOriginRedirect`
is false, in either mode.
migrateBlockSubblockIds handles a _removed_ target before it consults whenOperation, so the scope was never applied. Mine was the only _removed_ entry in the file carrying one. Unconditional deletion is also what this case wants. Subblock values are keyed by id and are not cleared when the operation changes, so a user who filled the MIME field and then switched the block to another operation has the value stored under that operation; a scoped delete would strand it permanently. The field no longer exists for any operation, so it should go regardless of the stored operation.
|
@greptile review |
|
@cubic review |
@waleedlatif1 I have started the AI code review. It will take a few minutes to complete. |
There was a problem hiding this comment.
No issues found across 70 files
Confidence score: 5/5
- Automated review surfaced no issues in the provided summaries.
- No files require special attention.
You’re at about 99% of the monthly reviewed-line limit. You may want to disable incremental reviews to conserve quota. Reviews will continue until that limit is exceeded. If you need help avoiding interruptions, please contact contact@cubic.dev.
You've manually re-run cubic several times on this PR. Each manual re-review checks the full PR again and counts toward your usage quota. To preserve your usage limits, we recommend letting cubic automatically review new commits.
Re-trigger cubic
…stable `REGEX_ALLOWED_AFTER` was missing `'/'`, so a regex directly after a division operator lexed as a second division: in `x / y / /[}]/` the character class was left in the structural view and its `}` closed the enclosing object early, truncating the block's subBlock ids with no warning. Add `'/'`, and guard the `'+'`/`'-'` entries with a `++`/`--` lookbehind so a postfix update still reads as a value and `i++ / 2` stays a division rather than a phantom regex that runs to end-of-input and reports the block unreadable. The `.`/`#` property guard and the `'\n'` entry both survived their mutants. `counts.in / 2, m: preturn / 2` is self-cancelling — the mis-lexed regex closes on the second slash and blanks nothing structural — so the fixtures now leave an odd number of slashes on the line. The `'\n'` entry had no coverage at all: its fixture is now the wrapped `.match(` newline `/re/` shape that `blocks/table.ts` and `blocks/table_v2.ts` produce, which is what that entry (not the preceding `(`, which the newline overwrites) actually decides. Its comment claimed a count of line-leading regexes that drifts with the sources; restate it without one. Drop the two locale tests that could not fail. CI runs under an `en-US` default, where an unpinned `localeCompare` returns exactly what the pinned one does, so no behavioural comparison discriminates; and asserting the committed `integrations.json` against the comparator that produced it agrees by construction. The source grep for a literal locale argument is the real guard. Generated output is byte-identical and the extraction differential over `apps/sim/blocks/blocks/` is empty.
|
@cubic-dev-ai review |
@waleedlatif1 I have started the AI code review. It will take a few minutes to complete. |
There was a problem hiding this comment.
No issues found across 70 files
Confidence score: 5/5
- Automated review surfaced no issues in the provided summaries.
- No files require special attention.
You’re at about 99% of the monthly reviewed-line limit. You may want to disable incremental reviews to conserve quota. Reviews will continue until that limit is exceeded. If you need help avoiding interruptions, please contact contact@cubic.dev.
You've manually re-run cubic several times on this PR. Each manual re-review checks the full PR again and counts toward your usage quota. To preserve your usage limits, we recommend letting cubic automatically review new commits.
Re-trigger cubic
Six pre-existing defects surfaced by the audit work on #7169. All predate that PR; none is a regression from it. Each is one commit, so any can be reviewed, cherry-picked, or reverted on its own.
What each fixes
fix(github)— file comments were broken in productiongithub_commentwithcommentType: 'file_comment'POSTs to/pulls/{n}/comments, where GitHub's OpenAPI listscommit_idas required. It was declaredhiddenwith no subBlock and no mapper write, so nothing could populate it and every request sentundefined→ 422. The path is user-reachable: thecommentTypedropdown offers "File-specific Comment".Now resolves the PR head SHA when
commitIdis absent, mirroring the JiracloudId-from-domainpattern already used in this repo (a harmless lookup request, real work intransformResponse). Applied to bothcommentToolandcommentV2Toolvia a shared helper. Also dropsposition, which GitHub marks"deprecated": true— "This parameter is closing down. Uselineinstead."fix(google-drive)— pagination was documented but unreachableAll five list/search tools declared
pageTokenand forwarded it to Google, but the block had zero occurrences of it in its entire history. Every call was capped at one page while the tools returned anextPageTokenwith nowhere to go. Adds a per-operation Page Token field following the block's own existingpageSize/searchPageSizeconvention, and flips the params touser-onlyso they are documented.fix(confluence)— documented a field users could not fillcloudIdwasuser-only, so it was published across 46 rows, but no subBlock exists. The inverse of the Jira defect. Confluence already resolves the cloud id at runtime — every operation goes throughcreateConfluenceClient, which falls back togetConfluenceCloudId(domain, …)→ the sharedresolveAtlassianCloudId— so only the visibility was wrong. Markedhidden;domainstays user-settable at all 46 rows.fix(vanta)— a field whose value was always discardedThe block rendered an advanced MIME Type input and forwarded it, but the upload path never reads it: every return path of
downloadServableFileFromStorageyields a non-empty content type, soresolved.contentTypealways wins. The placeholder claimed it was "used when the file has no type of its own", which never happens.Removes the subBlock, its mapper write, and its
inputsentry, and marks the tool paramhiddenso it is no longer advertised to the model on a path where it cannot take effect. The param stays, because the base64 branch still reads it. Letting a typed value win instead was rejected: for a compiled artifact the storage-resolved type is the only one matching the bytes actually sent.fix(docs)— the generator's sort was locale-sensitivelocaleComparewith no locale uses the runtime default. Against the real 254 catalog names,tr-TRreorders 141 positions,et-EE45,cs-CZ2, andlt-LTdiverges at index 40 — so a contributor on any of those regenerates a differentintegrations.jsonand fails CI with no obvious cause. Pinsen-USat all four sort sites.fix(docs)— regex literals desynced the source scannerblankStringsAndCommentshad no concept of a regex literal, so/don't/opened a phantom string that swallowed following subBlocks, and/[}]/closed the enclosing object early. Both returned a short list with no warning — a confident wrong answer, which for the hidden-param filter means silently deleting a user-settable row.Replaced with a linear scanner that distinguishes a regex literal from a division by the previous significant character, blanks regex bodies whole, and tracks
${}nesting so a backtick inside a template expression cannot end the template early. It now returnsnullwhen it ends inside an unterminated construct, and all three call sites treat that as UNKNOWN rather than guessing.Verification
Every fix has a test proving red→green — reverted, watched it fail, restored, watched it pass.
The two generator fixes leave the generated tree byte-identical, verified by hashing before and after; the warning count is unchanged at 12. Documentation deltas are exactly as intended: Confluence −46, Drive +5, Vanta −1, GitHub 0 (both removed params were already unpublished).
bun run check:audits→ 0 ·bun run lint:check→ 0 · affected suites 380/380.Notes for review
pageTokenisuser-onlyrather thanhidden-with-a-subBlock asgoogle_vaultdoes it. Both produce identical docs and behavior;user-onlymatches the type's own definition ofhidden("not shown to user or LLM") now that we do show it. One-word change if you prefer vault parity.directExecutionwould give tighter error control but bypasses the request transport (retry, redirect policy, secret provenance), so the lookup-plus-transform pattern was kept.