Spike: Investigate and capture options on how to integrate, deploy and iterate the GraphQL version of the modal

Description

This spike's goal is to capture our options (and outline the work that is required for each) we have around integrating, deploying, and iterating on the GraphQL migration of the MR- and pipeline security modal.

The following options should be considered and their pros, cons, and rough effort captured:

  1. Build a new modal component
    1. Migrate all functionality to GraphQL and Apollo (including state management, which is currently handled by Vuex)
    2. Copy the existing modal component (including Vuex) and replace parts - for example, the vulnerability details component, which is due to be completed soon)
  2. Iteratively replace components of the existing modal (for example the details component, as mentioned above)

Steps

  1. Capture as much of the current modal's functionality and data, which includes various data sources and differences between the MR widget and pipeline modal (for example the MR modal is fetching vulnerability feedback from a separate endpoint and then adds it to each vulnerability object).
    The output should include diagrams of components, their data flow, and how events propagate through the system. It should also include a list of used REST endpoints and the data that is consumed.
  2. Look at the options listed above and capture their impact
  3. Create a rough roadmap for each option

Raw Findings

Components Overview

Findings_Modal__3<span data-escaped-char>_</span>

Current implementation


1) Vulnerability Details


2) Solution Card

Summary

  • Display's vulnerability.solutionHtml or falls back to vulnerability.solution or vulnerability.remediations\[0\].summary
  • If there is not an existing MR for the given finding and a patch can be downloaded then show an extra message with instructions to create an MR or download the patch

Data dependencies

  • vulnerability.solutionHtml missing but currently not used for vuex modal version or vulnerability.solution - that means for the MVP this should not be needed
  • vulnerability.remediations\[0\] missing
  • vulnerability.hasMergeRequest missing

Endpoints

Pipeline

GET /api/v4/projects/34/vulnerability_findings

MR Widget

Same as Pipeline

Notes

  • There are two versions of the card:
    • ee/app/assets/javascripts/vue_shared/security_reports/components/solution_card.vue
    • ee/app/assets/javascripts/vue_shared/security_reports/components/solution_card_vuex.vue 👈 used on current modal

Screenshots

Without MR instructions

solution_without_instructions

With MR instructions

solution_with_instructions


3) Issue Notes

Summary

  • Displays information about issues that were created for the given finding. This includes the creation date, details about the author and a link to the issue.

Props

feedback

{
      author: {
        id: '1',
        name: 'Dave',
        username: 'davepies',
        path: 'davpies.me',
        is_gitlab_employee: true,
      },
      created_at: '2022-11-17T09:33:07.971Z',
      issue_url: 'http://foo.bar',
      issue_iid: '111',
    }
    

project

{
      url: '/foo/bar',
      value: 'Foo / Bar',
    }
    

Endpoints

  • Pipeline: GET /api/v4/projects/34/vulnerability_findings?pipeline_id=1 -> vulnerability.issue_feedback
  • MR Widget: GET /http://gdk.test:3000/security/security-reports/-/vulnerability_feedback?category=sast (fetches for each category) and GET /security/security-reports/-/merge_requests/5/sast_reports -> Vuex adds the data to what we get from vulnerability_findings from above

Screenshots

Default

issue_notes


4) Merge Request Note

Summary

  • Displays information about MRs that were created for the given finding. This includes the creation date, details about the author, and a link to the MR.
  • Feedback is in vulnerability.merge_request_feedback

Props

feedback

{
      author: {
        id: '1',
        name: 'Dave',
        username: 'davepies',
        path: 'davpies.me',
        is_gitlab_employee: true,
      },
      created_at: '2022-11-17T09:33:07.971Z',
      merge_request_path: '/merge/foo',
      merge_request_iid: 1,
    }
    

project

{
        url: '/foo/bar',
        value: 'Foo / Bar',
    }
    

Endpoints

  • Pipeline: GET /api/v4/projects/34/vulnerability_findings?pipeline_id=1
  • MR Widget: GET /security/security-reports/-/merge_requests/5/sast_reports (for reach report type)

Screenshots

Default

mr_note


5) Dismissal Note

Summary

Displays information about a finding's dismissal (if present). This includes comments and information about the author.

Props

feedback

{
      author: {
        id: 1,
        name: 'Author name',
        username: 'author username',
        path: 'author/path',
        is_git_gitlab_employee: true,
      },
      // optional
      comment_details: {
        comment_author: {
          id: '1',
          name: 'Dave',
          username: 'davepies',
          path: 'davpies.me',
          is_gitlab_employee: true,
        },
        comment_timestamp: '2022-11-17T09:33:07.971Z',
        comment: 'foo is bar!',
      },
      created_at: '2022-11-17T09:33:07.971Z',
      project: {
        url: 'http://foo.bar',
        value: 'project value',
      },
      // optional
      pipeline: {
        id: 1,
        path: 'pipeline/path',
      },
    };
    

project

{
      url: 'http://project/url',
      value: 'project value'
    }
    

Endpoints

  • Pipeline: GET /api/v4/projects/34/vulnerability_findings?pipeline_id=1&scope=dismissed
  • MR Widget: e.g: GET /security/security-reports/-/vulnerability_feedback?category=sast and /security/security-reports/-/merge_requests/5/sast_reports (requests for each report type and data gets combined, like mentioned above)

Screenshots

Without comment

dismissal_without_comment

With comment

dismissal_with_comment


6) Dismissal Comment Box

Summary

  • Renders textbox to enter a dismissal comment
  • Gets displayed when there is a dismissal and no comment yet, or when the existing comment is being edited
  • Lets a user add, edit and delete a comment
  • Displays any error message that might have been triggered when trying to post the comment to the BE

Props

dismissal-comment

The placeholder text:

'this is a comment'
    

is-active

Set to true if the user is currently commenting

true | false
    

Error message

Any messages from errors that happened when trying to fetch or post data.

'message describing what went wrong'
    

Endpoints

Read

  • Pipeline: GET /api/v4/projects/34/vulnerability_findings?pipeline_id=1&scope=dismissed
  • MR Widget: GET /security/security-reports/-/vulnerability_feedback?category=sast and /security/security-reports/-/merge_requests/5/sast_reports (requests for each report type and data gets combined, like mentioned above)

Write (indirectly)

Pipeline:

POST /security/security-reports-fresh/-/vulnerability_feedback

payload

{ "vulnerability_feedback": { "category": "dependency_scanning", "comment": "test", "feedback_type": "dismissal", "pipeline_id": 1420, "project_fingerprint": "a5b166f93b07f2ead1c16552af374ebfda7fc7d0", "finding_uuid": "8b404791-53fc-5801-81c7-05d0d505a04e", "vulnerability_data": { "id": "client_14", "report_type": "dependency_scanning", "name": "Path Traversal in rubyzip", "severity": "critical", "confidence": "unknown", "scanner": { "external_id": "gemnasium", "name": "Gemnasium", "vendor": "GitLab" }, "identifiers": \[ { "external_type": "gemnasium", "external_id": "99f8ccec-097c-4147-9cd0-2a8cd3a354a4", "name": "Gemnasium-99f8ccec-097c-4147-9cd0-2a8cd3a354a4", "url": "``https://gitlab.com/gitlab-org/security-products/gemnasium-db/-/blob/master/gem/rubyzip/CVE-2018-1000544.yml``" }, { "external_type": "cve", "external_id": "CVE-2018-1000544", "name": "CVE-2018-1000544", "url": "``https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-1000544``" } \], "project_fingerprint": "a5b166f93b07f2ead1c16552af374ebfda7fc7d0", "uuid": "8b404791-53fc-5801-81c7-05d0d505a04e", "create_jira_issue_url": null, "false_positive": false, "create_vulnerability_feedback_issue_path": "/security/security-reports-fresh/-/vulnerability_feedback", "create_vulnerability_feedback_merge_request_path": "/security/security-reports-fresh/-/vulnerability_feedback", "create_vulnerability_feedback_dismissal_path": "/security/security-reports-fresh/-/vulnerability_feedback", "project": { "id": 34, "name": "Security Reports - Fresh", "full_path": "/security/security-reports-fresh", "full_name": "Security / Security Reports - Fresh" }, "dismissal_feedback": null, "issue_feedback": { "id": 169, "created_at": "2022-11-24T13:39:31.705Z", "project_id": 34, "author": { "id": 1, "username": "root", "name": "Administrator", "state": "active", "avatar_url": "``https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon``", "web_url": "``http://gdk.test:3000/root``", "show_status": false, "path": "/root" }, "finding_uuid": "8b404791-53fc-5801-81c7-05d0d505a04e", "issue_iid": 1, "issue_url": "``http://gdk.test:3000/security/security-reports-fresh/-/issues/1``", "category": "dependency_scanning", "feedback_type": "issue", "branch": null, "project_fingerprint": "a5b166f93b07f2ead1c16552af374ebfda7fc7d0", "dismissal_reason": null }, "merge_request_feedback": null, "description": "The gem rubyzip contains a Directory Traversal vulnerability in Zip::File component that can result in write arbitrary files to the filesystem. This attack appear to be exploitable via If a site allows uploading of .zip files, an attacker can upload a malicious file that contains symlinks or files with absolute pathnames .. to write arbitrary files to the filesystem.", "description_html": "

The gem rubyzip contains a Directory Traversal vulnerability in Zip::File component that can result in write arbitrary files to the filesystem. This attack appear to be exploitable via If a site allows uploading of .zip files, an attacker can upload a malicious file that contains symlinks or files with absolute pathnames .. to write arbitrary files to the filesystem.", "links": \[{ "url": "``https://nvd.nist.gov/vuln/detail/CVE-2018-1000544``" }\], "location": { "file": "dependency-scanning-files/Gemfile.lock", "dependency": { "package": { "name": "rubyzip" }, "version": "1.2.1" } }, "remediations": null, "solution": "Upgrade to version 1.2.2 or above.", "evidence": null, "request": null, "response": null, "evidence_source": null, "supporting_messages": null, "assets": \[\], "details": { "vulnerablePackage": { "type": "text", "name": "Vulnerable Package", "value": "rubyzip:1.2.1" } }, "state": "detected", "scan": { "type": "dependency_scanning", "status": "success", "start_time": "2022-11-22T08:52:43", "end_time": "2022-11-22T08:52:46" }, "blob_path": "/security/security-reports-fresh/-/blob/225fa090f92d057854a68e9f8e071f86523be984/dependency-scanning-files/Gemfile.lock", "hasIssue": true, "hasMergeRequest": false, "isDismissed": false, "category": "dependency_scanning" } } }

MR Widget

Same as Pipeline

Delete (indirectly)

Pipeline

PATCH /security-reports-fresh/-/vulnerability_feedback/164

MR Widget

Same as Pipeline

Screenshots

Without existing comment

dismissal_box_with_comment

With existing comment

dismissal_box_without_comment


7) Error Alert

Summary

Renders error message that gets displayed when dismissal or comment deletion results in an error.

Endpoints

  • Dismissal and comment deletion

Screenshots

Default

error_alert


8) Dismiss / Undo Dismiss

Summary

Endpoints

Pipeline

Undo: DELETE 0/security/security-reports-fresh/-/vulnerability_feedback/164

MR Widget

Same as pipeline

Screenshots

Dismiss

Screenshot_2022-11-29_at_7.16.34_pm

Undo

Screenshot_2022-11-29_at_7.18.10_pm


9) Create Issue (GitLab / Jira)

Summary

If either a path* for creating a gitlab or jira issue is given, then it renders a "Create Issue" or "Create Jira Issue" button. If both are present then Jira issues take precedence. If there is an existing issue the button also won't render.

\* vulnerability.create_vulnerability_feedback_issue_path / vulnerability.create_jira_issue_url

Endpoints

Pipeline

POST /security/security-reports-fresh/-/vulnerability_feedback

MR Widget

Same as Pipeline

Notes

Both data fields currently missing.

When there are more than one action buttons available, they get moved into a split-button (see screenshots below).

Screenshots

Default Goes here
Simple

create_issue_simple

Split Button (multiple actions)

create_issue_split


10) Download Patch

Summary

Uses the remediation's diff's data * to dynamically create a download link (using: \~/lib/utils/downloader)

\* vulnerability.remediations\[0\].diff

Endpoints

Pipeline

GET /api/v4/projects/34/vulnerability_findings?pipeline_id=1

MR Widget

Same as Pipeline

Simple

download_patch_simple

Split Button (multile actionns)

dowload_patch_split


11) Resolve with MR

Summary

If the given vulnerability is not resolved, doesn't have an existing MR associated and has remedidation data, then the button to create an MR gets shown.

Endpoints

Pipeline

POST /security/security-reports/-/vulnerability_feedback

MR Widget

Same as Pipeline

Simple

resolve_with_mr_simple

Split Button (multiple actions)

resolve_with_mr_split


What do we need for the migration

  • Solution Card
  • Issue notes
  • MR notes
    • Data we need
      • merge_request_feedback (Note: Might be available through the mergeRequest field, noted above)
      • This will be available via mergeRequest field
  • Resolve via MR
    • Mutation we need
      • Create MR that resolves finding (can we use existing one? To investigate)
  • Download Patch
    • Data we need
    • remediations - currently we are using remediations\[0\].diff to dynamically generate a download on the client side
  • Dismissal Notes
    • Data we need
      • dismissal_feedback
  • Dismissal
    • Create - No additional work needed.
      • Notes
        • Existing mutation: securityFindingDismiss
    • Undo
      • Mutation we need
        • Vulnerabilities use vulnerabilityRevertToDetected
      • Undo / delete dismissal
    • Comment
      • Create
        • Notes
          • Existing mutation securityFindingDismiss (via comment field on input)
      • Edit
        • Mutation we need
          • Edit a dismissal comment
      • Delete
        • Mutation we need
          • Delete a dismissal comment
  • Issue Creation
Edited by Jonathan Schafer