fix(risks): cs-727 deploy-review fixes (acceptance race, approval drift baseline, error surfacing)#3497
Merged
Merged
Conversation
- acceptance create runs in a transaction with a FOR UPDATE row-lock on the subject, so a concurrent residual edit can no longer produce an acceptance frozen at a superseded rating - approve() collects the drift baseline INSIDE the approval transaction (collectPlatformData gained an optional client), so a just-approved document can't immediately read as stale - useAcceptances surfaces ApiResponse.error (apiClient never throws); the acceptance card renders an error + retry state instead of misreporting a failed load as "no acceptance recorded" - acceptance dialog only preselects the owner when they are selectable - RTP submit stays blocked while readiness is loading or failed - methodology matrix intro states score bands AND raw-product bands (the previous wording misattributed raw ranges to the score) - readiness queries extracted to risk-treatment-readiness.ts - acceptance response schemas document authType/authenticatedUser + 500 - comment fixes: 10-column table note, ISO 27001 attribution
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
There was a problem hiding this comment.
cubic analysis
2 issues found across 15 files
Confidence score: 3/5
- In
apps/api/src/isms/documents/data-source.ts, the RTP stale-check runs in a transaction that can see different snapshots under READ COMMITTED, so a just-approved Risk Treatment Plan may be marked stale immediately and trigger incorrect workflow/state transitions — use a single consistent-read strategy (e.g., stronger isolation or locking/statement structure that guarantees one snapshot for the check). - In
apps/api/src/risks/schemas/risk-acceptances.responses.ts, the new 500 schema entries are not connected to the controller decorators, so Swagger omits internal-server-error responses and clients won’t see accurate failure contracts — wire[500]into both risk-acceptance decorators to expose the intended API docs.
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="apps/api/src/isms/documents/data-source.ts">
<violation number="1" location="apps/api/src/isms/documents/data-source.ts:32">
P2: A just-approved Risk Treatment Plan can be marked stale immediately: this transaction client does not guarantee one consistent read snapshot under the repository's default READ COMMITTED isolation, and the RTP rows are read again later in the same transaction. Configuring a repeatable-read/serializable transaction for approval, or otherwise locking the rendered risk/vendor rows, would keep `riskTreatmentFingerprint` aligned with the frozen RTP.</violation>
</file>
<file name="apps/api/src/risks/schemas/risk-acceptances.responses.ts">
<violation number="1" location="apps/api/src/risks/schemas/risk-acceptances.responses.ts:173">
P3: The new 500 response definitions are unreachable from the controller decorators, so Swagger still omits the documented internal-server-error response. Wiring `[500]` into both risk acceptance decorators (and the vendor equivalents) would make this addition effective.</violation>
</file>
Linked issue analysis
Linked issue: CS-727: [Feature] - Risks module updates
| Status | Acceptance criteria | Notes |
|---|---|---|
| ✅ | Row-lock acceptance creation so a fresh acceptance cannot be recorded against an already-superseded residual rating | createForRisk/createForVendor run inside db.$transaction and take a FOR UPDATE row lock before reading and inserting; tests assert the transaction and the FOR UPDATE query. |
| ✅ | Collect the approval drift baseline inside the approval transaction so a just-approved document cannot immediately show as stale | collectPlatformData accepts an optional transaction client and approve() now calls it inside the document-lock transaction; unit spec asserts client threading. |
| ✅ | Surface acceptance-history loading errors in the UI (don’t show a failed load as 'Awaiting acceptance') and offer a Retry | useAcceptances now converts ApiResponse.error into an error for callers; ResidualAcceptanceCard renders an explicit error + Retry instead of treating failure as empty history. |
| ✅ | Acceptance dialog only preselects the owner when they are actually selectable/active | RecordAcceptanceDialog computes a valid default and uses it; prevents silently submitting a deactivated owner. |
| ✅ | Keep 'Submit for approval' blocked while RTP readiness data is loading or failed (so the dialog cannot be completed into a server-side completeness error) | RiskTreatmentPlanClient sets a blockedReason when readiness is loading or errored, rather than allowing the submit dialog to proceed. |
| ✅ | Correct the Risk Assessment Methodology matrix text and preview so score bands and raw-product equivalents are stated consistently | Methodology narrative updated to state normalized score calculation and band mappings; preview text updated to match. |
| ✅ | Extract RTP readiness queries into a focused loader and use it where readiness is checked (refactor to support tx-client usage) | Readiness logic moved to documents/risk-treatment-readiness.ts and isms.service now uses the loader (including tx client) for completeness checks and approval gating. |
Tip: instead of fixing issues one by one fix them all with cubic
Re-trigger cubic
- RTP submit gating fails closed: a load/revalidation error blocks submission even when stale cached readiness data is present - approve() runs REPEATABLE READ (single MVCC snapshot), so the drift baseline and the frozen rows can never observe different data; one retry on a P2034 write conflict re-runs with a fresh snapshot - acceptance row locks are org-scoped, so a foreign-tenant id can never acquire another organization's row lock - 500 responses wired into all four acceptance endpoint decorators - authType documents the 'service' value HybridAuthGuard can return
Contributor
There was a problem hiding this comment.
All reported issues were addressed across 7 files (changes from recent commits).
Reply with feedback, questions, or to request a fix.
Fix all with cubic | Re-trigger cubic
claudfuen
pushed a commit
that referenced
this pull request
Jul 24, 2026
# [3.108.0](v3.107.0...v3.108.0) (2026-07-24) ### Bug Fixes * **device-registration:** set source to device_agent when agent adopts intune device ([#3495](#3495)) ([1071066](1071066)) * **risks:** cs-727 deploy-review fixes (acceptance race, approval drift baseline, error surfacing) ([#3497](#3497)) ([7446c89](7446c89)) ### Features * **risks:** risk acceptance events + ISMS 6.1.2 methodology and 6.1.3 treatment plan documents (CS-727) ([#3493](#3493)) ([8c4b358](8c4b358))
Contributor
|
🎉 This PR is included in version 3.108.0 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #3493 (CS-727): fixes the cubic findings raised on the main→release deploy PR #3496. 13 of 16 findings fixed here; 3 rebutted on their threads (cascade-delete of acceptance history — settled on #3493, published RTP snapshots + AuditLog preserve the trail; the submit-gate TOCTOU — would require serializing every Risk/Vendor write against ISMS submits for an advisory gate; openapi.json regeneration — four-PR precedent, spec pipeline reads main).
Correctness
createForRisk/createForVendornow run in a transaction that takes aFOR UPDATErow-lock on the subject, so a concurrent residual PATCH serializes with the read→freeze→insert sequence — a fresh acceptance can no longer be recorded against an already-superseded rating (and can never be born stale).approve()used to collect the platform snapshot before its transaction while the published rows were loaded inside it — a concurrent edit in that window made a just-approved document immediately show "may be out of date".collectPlatformDatagained an optional transaction client and the approval flow collects the baseline under the document lock, in the same transaction as the frozen rows.UX / client
useAcceptancessurfacesApiResponse.error(theuseApiSWRfetcher never throws on API failures, soswr.erroralone missed forbidden/failed responses); the acceptance card now renders an explicit "Couldn't load the acceptance history" + Retry state instead of misreporting a failed load as "No acceptance recorded yet".Documents / docs
authType/authenticatedUser(which the controllers actually return) and a 500 response, matching the sibling risk schemas.Structure
isms.service.tsintodocuments/risk-treatment-readiness.ts; the service keeps only the thin submit-gate and page-payload wrappers.Verification
bun run --filter '@trycompai/app' buildgreen.