Fix unguarded codequalityReportsComparer.status access and nil pipeline guard
Everyone can contribute. Help move this issue forward while earning points, leveling up and collecting rewards.
Summary
When a merge request has no diff_head_pipeline, the CodequalityReportsComparerResolver
returns null (per its null: true contract). However, the frontend Apollo update
handler in app/assets/javascripts/diffs/components/app.vue accesses
codequalityReportsComparer.status without optional chaining in the stop-polling
condition, which will throw a TypeError if the field is null.
Details
In app.vue, the stop-polling condition reads:
if (
(sastReport?.status === FINDINGS_STATUS_PARSED || !this.sastReportAvailable) &&
(!this.codequalityReportAvailable ||
codequalityReportsComparer.status === FINDINGS_STATUS_PARSED) // ← unguarded
) {
this.$apollo.queries.getMRCodequalityAndSecurityReports.stopPolling();
}sastReport?.status is consistently protected with ?., but codequalityReportsComparer.status
is not. If codequalityReportAvailable is true and the GraphQL field returns null
(e.g. MR has no pipeline), this throws:
TypeError: Cannot read properties of null (reading 'status')Note: codequalityReportsComparer?.report?.newErrors (a few lines below) is already
correctly guarded — only the stop-polling access is missing the ?..
Fix
Add optional chaining to the unguarded access:
// Before
codequalityReportsComparer.status === FINDINGS_STATUS_PARSED
// After
codequalityReportsComparer?.status === FINDINGS_STATUS_PARSEDWhen null, the expression evaluates to false, keeping polling alive rather than
throwing — consistent with the behaviour for sastReport.
Also add a backend nil-pipeline guard to CodequalityReportsComparerResolver (and
a corresponding spec) so that authorize!(nil) is never reached when diff_head_pipeline
is absent:
def resolve
return unless object.diff_head_pipeline
authorize!(object.diff_head_pipeline)
object.compare_codequality_reports
endContext
Discovered while reviewing c708f68d, which originally included both the backend guard and the frontend fix but they were separated out for a cleaner follow-up.
Related: #458219 (closed)