fix(confluence): gate the page selector to operations that use it - #6769
fix(confluence): gate the page selector to operations that use it#6769mzxchandra wants to merge 2 commits into
Conversation
The v2 block gated `pageId`/`manualPageId` with a 23-entry `not: true` denylist while its `required` was an allowlist. The two were not complements, so Select Page rendered on operations that consume no page id - most visibly Create Page, where the page id is an output. Replace the denylist with a positive `PAGE_ID_OPERATIONS` allowlist, shared by both `condition` and `required`. The list is the 18 v2 operations whose tool declares a required `pageId`, derived by mapping all 44 operations through `tools.config.tool` to their tool file. The legacy block had no `condition` at all. Give it its own `LEGACY_PAGE_ID_OPERATIONS` (its existing 8-op `required` list), kept separate so a sunset block does not track its replacement. Also drop the now-dead "from page" sentence clause on `delete_comment` and `delete_attachment`, add the `dependsOn` that `manualPageId` was missing, and rename the v2 `Read Page` label to `Get Page`.
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
PR SummaryMedium Risk Overview
The legacy block gets its own Adds Reviewed by Cursor Bugbot for commit 77f8f5b. Bugbot is set up for automated code reviews on this repo. Configure here. |
Greptile SummaryThe PR aligns Confluence page-selector visibility and required-state gating with the operations whose tools require a page ID.
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains; the previously reported regression-test gap is closed by assertions covering both directions of the selector/tool contract.
|
| Filename | Overview |
|---|---|
| apps/sim/blocks/blocks/confluence.test.ts | Adds comprehensive operation-to-tool contract tests; the revised biconditional assertion resolves the previously reported one-direction coverage gap. |
| apps/sim/blocks/blocks/confluence.ts | Uses explicit page-consuming operation allowlists for selector visibility and required state while keeping basic and advanced fields symmetric. |
| apps/sim/lib/integrations/integrations.json | Synchronizes generated integration metadata with the v2 “Get Page” display label. |
Reviews (2): Last reviewed commit: "test(confluence): assert page-selector v..." | Re-trigger Greptile
The contract test returned early when a tool did not require `pageId`, so it only proved that page-consuming operations render the selector. An operation wrongly added to `PAGE_ID_OPERATIONS` still passed unless it also appeared in the separate five-entry hidden list. Assert the biconditional instead: for every operation, the page target renders exactly when its tool requires `pageId`. Injecting `search` into the allowlist now fails the suite.
|
@cursor review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 77f8f5b. Configure here.
The bug
The v2 Confluence block gated its page target (
pageId/manualPageId) with a 23-entrynot: truedenylist, while the same two subblocks declaredrequiredas an 18-entryallowlist. The two lists were not complements, so Select Page rendered on operations that
consume no page id at all. The most visible case is Create Page, where the page id is an
output of the operation, not an input: users were shown a required-looking page picker for the
page they were about to create.
The fix
Both
conditionandrequirednow share one positivePAGE_ID_OPERATIONSallowlist.The list was derived rather than hand-written: every one of the 44 v2 operations was mapped through
the block's own
tools.config.toolswitch to its tool file, and the tool'sparamschecked for apageIdentry. Exactly 18 tools declare a requiredpageId, and those 18 are the allowlist -identical to the
requiredlist that was already there.Newly hidden (5):
create,create_blogpost,update_comment,delete_comment,delete_attachment. None of their tools declarepageId; the two create operations produce a pageid, and the comment/attachment mutations address their own
commentId/attachmentId. No othersubblock depends on the page field for these operations, and
Create Pagekeeps its dedicatedparentIdfield, which is the input people actually wanted there.Legacy block
ConfluenceBlock(hideFromToolbar,sunset.replacedBy: 'confluence_v2') had noconditionatall, so it rendered the page target on all 15 of its operations. It now has its own
LEGACY_PAGE_ID_OPERATIONS, seeded from its existing 8-oprequiredlist and verified the same wayagainst the tools. It is deliberately a separate constant rather than a reference to
PAGE_ID_OPERATIONS: the two blocks expose different operation sets, and a sunset block must notsilently track changes to its replacement. Its labels and sentences are otherwise untouched.
Also in this diff
dependsOnsymmetry.manualPageIdwas missing thedependsOn: ['credential', 'domain']itspageIdtwin has, so the manual field stayed editable while its credential was still unbound.Added. This is UI gating only -
dependsOndoes not affect serialization orrequiredvalidation.delete_commentanddelete_attachment,their canvas sentences' trailing
from pageclause referenced a field that can never render.The repo's
check:canvas-sentencesaudit catches this; the clause is removed on both blocks. Therendered sentence is unchanged, since the clause had nothing to interpolate.
Read PagebecomesGet Page, matching theGet *convention used by the rest ofthe block's single-item reads, plus its canvas sentence and the generated
integrations.jsonentry. The legacy block keeps
Read Page.Deliberate non-change
list_tasksaccepts an optionalpageIdfilter and the block forwards it, but the selector hasalways been hidden, so the filter has never been reachable. Un-hiding it now would make any existing
list_tasksblock that carries a stale storedpageIdsilently start filtering its results. Lefthidden; worth a separate issue.
Compatibility
Operation ids and tool ids are unchanged (
readstill maps toconfluence_retrieve). Only thedisplay label, the visibility conditions, and one
dependsOnarray moved. Stored workflows areunaffected: a saved
pageIdon a now-hidden operation was already being dropped by the tool, andnothing about serialization or
requiredvalidation changed for the 18 operations that use it.Tests
apps/sim/blocks/blocks/confluence.test.ts- 181 tests covering both blocks. They derive theirexpectations from the tool contracts rather than hand-copied operation lists, so adding an operation
whose tool takes a
pageIdfails here until the block's condition is widened to match. A guard testfails if any operation resolves to a tool the file does not import.
The tools are imported directly rather than through
@/tools/registry:vitest.setup.tsmocksthe registry to
{}, so routing through it would make every contract assertion pass vacuously.Mutation-checked: stashing the block change turns 9 of them red, and re-adding a dead sentence
clause turns the new canvas-sentence guard red on both blocks.
Verification
Live end-to-end against a real Confluence site (
sim-testing.atlassian.net):page field in each, 26 do not.
create pageconfirmed to render space / title / content / parentId and no page selector.get pageexecuted successfully, returning real page content.<block.output>reference typed into the manual page field survived save and reloadwithout the selector clobbering it.
Repo gates:
check:canvas-sentences,docs:check,integration-catalog:check,tool-metadata:check,check:api-validation,type-check, and biome all pass. 1711 tests greenacross
blocks/,connectors/,lib/integrations/,lib/oauth/, andlib/workflows/blocks/.Known pre-existing bug, not addressed here
Confluence v2 fails on any operation that has a rendered-but-empty optional field:
The block's
paramsspreads...restunnormalized, so an untouched subblock's storednullreachesa tool param typed
string. It hitscreate(viaparentId) and all 20 list operations (vialimit), plus search / update / upload_attachment. Confirmed pre-existing: reproduced on unmodifiedstaging with this change stashed. It is why
createcould not be executed end to end here, and itis tracked separately - not a regression from this PR.
A separate pre-existing issue also surfaced while validating:
search_in_spacecan never succeed,because its tool and route both require
spaceKeywhile the block's space picker suppliesspaceId.Also out of scope here.