Skip to content

ROCK-8640 Forward-port S&S connect gate card fixes to v16 - #8

Merged
stphnlee merged 2 commits into
hotfix-1.16.12from
feature-jw-ROCK8640-CardConnectGate-v16
Aug 17, 2026
Merged

stphnlee merged 2 commits into
hotfix-1.16.12from
feature-jw-ROCK8640-CardConnectGate-v16

Conversation

@jwakefield-secc

@jwakefield-secc jwakefield-secc commented Aug 17, 2026 •

Copy link
Copy Markdown

ROCK-8640 — Forward-port S&S connect gate card fixes to v16

Internal SECC PR. Base: hotfix-1.16.12.

Why

v16 got the connect gate and its server-side enforcement via PR #5 (17acbdfb62).
Two follow-up fixes landed on the 13.7 line eight days later and never reached v16 —
hotfix-1.13.7 and hotfix-1.16.12 share no common ancestor, so nothing merges
across the version lines. This brings v16 to parity with the merged 13.7 tip
(b320d58c0d, PR #7).

Commits

This PR From 13.7 Change
ab1f32cd7b fb451dda1c Hide the ungated Connect action on board cards
70eee0ea45 d20cad2570 Evaluate the gate against the request's own opportunity

Verified

  • Both cherry-picks applied with zero conflicts
  • SeccConnectGateHelper.cs and connectionRequestBoard.js byte-identical to b320d58c0d
  • Gate call sites: Board 3 / Detail 2 — matches 13.7
  • hotfix-1.16.12 is a direct ancestor → fast-forward, nothing reverted
  • No new files; all three touched files already existed on 16.12

jwakefield-secc and others added 2 commits August 17, 2026 11:14
… cards

The kanban card's action menu ("...") renders its Connect item from core
ConnectionRequestService.CanConnect() - placement group assigned, state not
Connected/Inactive, ShowConnectButton - which knows nothing about the S&S
gate. So the item stayed visible on secured opportunities at any status. The
prior commit refuses the postback server-side; this hides the affordance so
the menu matches the gated modal button.

Adds a status-based overload to SeccConnectGateHelper (the request-based
overload now delegates to it) so the board can ask "could this person connect
a request at this status?" per status column. GetUserConnectableStatusIds()
runs that shared gate against every status on the selected opportunity, also
applying the edit-rights check the modal button requires, and the resulting
ids ride both board script payloads. The JavaScript checks membership only -
no gate logic lives client-side.

The helper overload should be carried to hotfix-1.16.12 with the port of this
change so the two branches keep a byte-identical helper.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
(cherry picked from commit fb451dd)
…nity

The Connection Request Board resolved the connect gate's opportunity from the
board's current selection, while the connection request identifier arrives from
the client postback, so the two can disagree. A user with edit rights on an
opportunity that does not require Safety & Security to connect could send a
connect postback carrying the identifier of a request in a gated opportunity:
the gate read SecurityToConnect and ConnectableStatuses from the selected
opportunity, allowed it, and MarkRequestConnected then connected the
client-supplied request.

Resolve the opportunity from the request instead, which is what
ConnectionRequestDetail already does. The selected opportunity is still used
when there is no request in context (modal add mode), since that is the
opportunity the new request is created in, and it is reused directly when it
already matches so the normal path does not take an extra query.

This predates the card gate work - it is present both in the merged 13.7 change
and in hotfix-1.16.12 - so this commit stands on its own and can be
cherry-picked to v16 independently of the card menu change.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
(cherry picked from commit d20cad2)

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Forward-ports the SECC Safety & Security “Connect” gate parity fixes into the v16 Connection Request Board so the card action-menu Connect item is hidden consistently with the modal Connect button, and server-side enforcement evaluates against the request’s actual opportunity.

Changes:

  • Adds a server-computed userConnectableStatusIds payload and applies it client-side to suppress the card menu’s Connect action when gated.
  • Fixes server-side gate evaluation to resolve the opportunity from the request being connected (not just the currently selected board opportunity).
  • Extends SeccConnectGateHelper with a status-based overload so board/status-column evaluation shares the same gate implementation.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
RockWeb/Scripts/Rock/Controls/ConnectionRequestBoard/connectionRequestBoard.js Captures server-provided connectable status IDs and applies them when rendering cards to hide the Connect action item.
RockWeb/Blocks/Connection/ConnectionRequestBoard.ascx.cs Adds gate-aware opportunity resolution and computes per-status connectability list to send to the client.
RockWeb/App_Code/SeccConnectGateHelper.cs Adds a status-based overload and delegates request-based gate checks to it.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +2904 to +2907
return new ConnectionOpportunityService( new RockContext() )
.Queryable()
.AsNoTracking()
.FirstOrDefault( co => co.Id == connectionRequest.ConnectionOpportunityId );

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

Comment on lines +2872 to +2873
connectionRequest,
GetGateConnectionOpportunity( connectionRequest ),

@stphnlee stphnlee left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are some improvements that need to be made, but I'm approving this PR to keep feature parity with our current production environment. We can implement the fixes after the upgrade.

@stphnlee
stphnlee merged commit 010d9f7 into hotfix-1.16.12 Aug 17, 2026
2 checks passed
stphnlee added a commit that referenced this pull request Oct 2, 2026
#19)

* ROCK-9044: Close connect-gate enforcement gaps and fix review findings

Follow-up to the ROCK-8640 Safety & Security connect gate (PR #8). Addresses
all 13 findings from the code review of the v16 port.

Enforcement
- Bulk Update Requests was ungated and could move requests into Connected.
  Add a Safety & Security Role block setting and run the shared gate per
  request, against the target opportunity and status, before any write.
- Card-menu and modal Connect now require the request to be in the selected
  opportunity, since the edit check is evaluated against that opportunity and
  the request id is client-supplied.
- The edit-modal save gates against the opportunity and status the request is
  being saved with, not its pre-save opportunity.

Crashes and feedback
- Resolve and null-check the opportunity before the edit check that
  dereferenced it (yellow screen when the opportunity was deactivated).
- Refused connects now show a message instead of silently doing nothing.

Display
- The card-menu gate list is evaluated with no request in context so one
  request's per-request Edit result no longer applies to every card. This also
  keeps the client options hash stable.
- Clear the cached request after a transfer so the modal gates against the
  new opportunity.
- Re-render the card after a drag-and-drop so Connect reflects the new status.

Cleanup
- Hoist the status-independent half of the gate into
  SeccConnectGateHelper.GetConnectableStatusIds (one evaluation per board
  render instead of one per status) and only LoadAttributes when needed.
- Use the request's ConnectionOpportunity navigation property instead of a
  hand-rolled query on an unowned RockContext.
- Collapse the helper's forwarding wrapper; drop the fabricated Active state.
- JS: capture the gate list before fetchAndRefreshCard's early return.

Cherry-pick: applies cleanly on the ROCK-8640 commit alone. Depends on
secc/ROCK-8640-connect-gate; independent of ROCK-9046 and ROCK-9138.

Config after deploy: set "Safety & Security Role" on the Bulk Update Requests
block instance (fails closed to Rock Administrators until set).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* ROCK-9044: Fix second-round review findings on connect-gate enforcement

Connection Request Board:
- Refuse the modal edit-save when the request is not in the selected
  opportunity, so Edit rights on one opportunity cannot rewrite or
  connect a request in another.
- Refuse the edit-save with a notification when the connect gate
  blocks a Connected state, instead of silently saving the old state.
- Require the request to be in the selected opportunity for the
  view-mode Connect button, matching its click handler.
- Null-guard the selected opportunity inside
  CanUserEditConnectionRequest so every caller fails closed instead
  of throwing when the opportunity is deactivated mid-session.
- Reset the block-level notification box on every postback so a
  refused connect does not leave a persistent banner; title the
  refusal "Not Authorized".
- Drop GetGateConnectionOpportunity; the gate now always evaluates
  the selected opportunity, which every caller already requires to be
  the request's own.

Bulk Update Requests:
- Null-check the target opportunity before the gate so the refusal
  message cannot throw.
- Also gate already-Connected requests being moved into a different
  opportunity with State left blank.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* ROCK-9044: Fix third-round review findings on connect-gate enforcement

- Modal save no longer refuses edits to a request that is already
  Connected; only a transition into Connected is gated (regression
  from the refuse-the-save change).
- Bulk update skips requests already Connected on the target
  opportunity, and gates every other request entering Connected as a
  new connect, so the target's ConnectableStatuses always apply.
- Clear the request modal notification when a request is opened from
  a card or the grid, so a refusal does not carry over.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants