diff --git a/docs/jupiterone.md b/docs/jupiterone.md index 041659e..55b3b23 100644 --- a/docs/jupiterone.md +++ b/docs/jupiterone.md @@ -84,6 +84,7 @@ The following entities are created: | ------------- | ---------------------- | --------------------- | | Account | `gitlab_account` | `Account` | | Commit | `gitlab_commit` | `CodeCommit` | +| Finding | `gitlab_finding` | `Finding` | | Group | `gitlab_group` | `Group` | | Merge Request | `gitlab_merge_request` | `CodeReview`, `PR` | | Project | `gitlab_project` | `CodeRepo`, `Project` | @@ -101,6 +102,7 @@ The following relationships are created: | `gitlab_group` | **HAS** | `gitlab_project` | | `gitlab_group` | **HAS** | `gitlab_user` | | `gitlab_merge_request` | **HAS** | `gitlab_commit` | +| `gitlab_project` | **HAS** | `gitlab_finding` | | `gitlab_project` | **HAS** | `gitlab_merge_request` | | `gitlab_project` | **HAS** | `gitlab_user` | | `gitlab_user` | **APPROVED** | `gitlab_merge_request` | diff --git a/src/constants.ts b/src/constants.ts index d66bd63..1c4d2f4 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -7,6 +7,7 @@ export const Steps = { PROJECTS: 'fetch-projects', MERGE_REQUESTS: 'fetch-merge-requests', COMMITS: 'fetch-mr-commits', + FINDINGS: 'fetch-vulnerability-findings', BUILD_ACCOUNT_HAS_PROJECT: 'build-account-project-relationships', BUILD_ACCOUNT_HAS_GROUP: 'build-account-group-relationships', BUILD_PROJECT_HAS_USER: 'build-project-user-relationships', @@ -34,6 +35,11 @@ export const Entities = { _type: 'gitlab_group', _class: 'Group', }, + FINDING: { + resourceName: 'Finding', + _type: 'gitlab_finding', + _class: ['Finding'], + }, MERGE_REQUEST: { resourceName: 'Merge Request', _type: 'gitlab_merge_request', @@ -88,6 +94,12 @@ export const Relationships = { _class: RelationshipClass.HAS, targetType: Entities.PROJECT._type, }, + PROJECT_HAS_FINDING: { + _type: 'gitlab_project_has_finding', + sourceType: Entities.PROJECT._type, + _class: RelationshipClass.HAS, + targetType: Entities.FINDING._type, + }, PROJECT_HAS_PR: { _type: 'gitlab_project_has_merge_request', sourceType: Entities.PROJECT._type, diff --git a/src/converters/index.ts b/src/converters/index.ts index 86e9dda..256e53e 100644 --- a/src/converters/index.ts +++ b/src/converters/index.ts @@ -11,6 +11,7 @@ import { GitLabMergeRequestApproval, GitLabProject, GitLabUser, + GitLabFinding, } from '../provider/types'; import { getCommitWebLinkFromMergeRequest } from '../util/mergeRequest'; @@ -204,3 +205,92 @@ const COMMIT_ID_PREFIX = 'gitlab-commit'; export function createCommitIdentifier(id: number): string { return `${COMMIT_ID_PREFIX}:${id}`; } + +export function createVulnerabilityFindingEntity( + finding: GitLabFinding, +): Entity { + const key = createFindingIdentifier(finding.id); + + // For more Finding data model class required fields info please visit: https://github.com/JupiterOne/data-model/blob/main/src/schemas/Finding.json. + return createIntegrationEntity({ + entityData: { + source: finding, + assign: { + _key: key, + _type: Entities.FINDING._type, + _class: Entities.FINDING._class, + // START: finding data model required fields + category: finding?.report_type, + severity: finding?.severity, + numericSeverity: getNumericSeverity(finding?.severity), + open: finding.state?.toLocaleLowerCase() === 'detected', + // END: finding data model required fields + id: String(finding.id), + reportType: finding.report_type, + name: finding.name, + confidence: finding.confidence, + 'scanner.externalId': finding.scanner?.external_id, + 'scanner.name': finding.scanner?.name, + 'scanner.vendor': finding.scanner?.vendor, + identifiers: finding.identifiers?.map( + (identifier) => identifier.external_id, + ), + projectFingerprint: finding.project_fingerprint, + uuid: finding.uuid, + createJiraIssueUrl: finding.create_jira_issue_url, + falsePositive: finding.false_positive, + createVulnerabilityFeedbackIssuePath: + finding.create_vulnerability_feedback_issue_path, + createVulnerabilityFeedbackMergeRequestPath: + finding.create_vulnerability_feedback_merge_request_path, + createVulnerabilityFeedbackDismissalPath: + finding.create_vulnerability_feedback_dismissal_path, + 'project.id': finding.project?.id, + 'project.name': finding.project?.name, + 'project.fullPath': finding.project?.full_path, + 'project.fullName': finding.project?.full_name, + dismissalFeedback: finding.dismissal_feedback, + issueFeedback: finding.issue_feedback, + mergeRequestFeedback: finding.merge_request_feedback, + description: finding.description, + links: finding.links?.map((link) => link.url), + 'location.file': finding.location?.file, + 'location.startLine': finding.location?.start_line, + 'location.class': finding.location?.class, + 'location.method': finding.location?.method, + 'location.hostname': finding.location?.hostname, + solution: finding.solution, + evidence: finding.evidence, + state: finding.state, + blobPath: finding.blob_path, + 'scan.type': finding.scan?.type, + 'scan.status': finding.scan?.status, + 'scan.startTime': parseTimePropertyValue(finding.scan?.start_time), + 'scan.endTime': parseTimePropertyValue(finding.scan?.end_time), + }, + }, + }); +} + +const FINDING_ID_PREFIX = 'gitlab-finding'; +export function createFindingIdentifier(id: number): string { + return `${FINDING_ID_PREFIX}:${id}`; +} + +export function getNumericSeverity(severity: string | undefined) { + if (!severity) { + return 0; + } else if (/critical/i.test(severity)) { + return 10; + } else if (/high/i.test(severity)) { + return 7; + } else if (/medium/i.test(severity)) { + return 5; + } else if (/low/i.test(severity)) { + return 2; + } else if (/info/i.test(severity)) { + return 1; + } else if (/unknown/i.test(severity)) { + return undefined; + } +} diff --git a/src/provider/GitlabClient.ts b/src/provider/GitlabClient.ts index 8fb27d3..7a1e979 100644 --- a/src/provider/GitlabClient.ts +++ b/src/provider/GitlabClient.ts @@ -11,6 +11,7 @@ import { } from '@jupiterone/integration-sdk-core'; import { + GitLabFinding, GitLabGroup, GitLabMergeRequest, GitLabMergeRequestApproval, @@ -81,6 +82,19 @@ export class GitlabClient { return this.makePaginatedRequest(HttpMethod.GET, '/groups'); } + async iterateProjectVulnerabilities( + projectId: string, + iteratee: ResourceIteratee, + ): Promise { + return this.iterateResources( + `/projects/${projectId}/vulnerability_findings`, + iteratee, + { + params: { severity: ['medium', 'high', 'critical'] }, + }, + ); + } + async iterateOwnedProjects( iteratee: ResourceIteratee, ): Promise { diff --git a/src/provider/types.ts b/src/provider/types.ts index 6e09496..f0329cf 100644 --- a/src/provider/types.ts +++ b/src/provider/types.ts @@ -51,6 +51,70 @@ export interface GitLabGroup { file_template_project_id: number; } +export interface GitLabFinding { + id: number; + report_type?: string; + name?: string; + severity?: string; + confidence?: string; + scanner?: { + external_id?: string; + name?: string; + vendor?: string; + }; + identifiers?: [ + { + external_type: string; + external_id: string; + name: string; + url: string; + }, + ]; + project_fingerprint?: string; + uuid?: string; + create_jira_issue_url?: string; + false_positive?: boolean; + create_vulnerability_feedback_issue_path?: string; + create_vulnerability_feedback_merge_request_path?: string; + create_vulnerability_feedback_dismissal_path?: string; + project?: { + id?: number; + name?: string; + full_path?: string; + full_name?: string; + }; + dismissal_feedback?: string; + issue_feedback?: string; + merge_request_feedback?: string; + description?: null; + links?: [{ url: string }]; + location?: { + file?: string; + start_line?: number; + class?: string; + method?: string; + hostname?: string; + }; + solution?: string; + evidence?: string; + details?: { + urls: { name?: string; type?: string }; + discovered_at?: { + name?: string; + type?: string; + value?: string; + }; + }; + state?: string; + scan?: { + type?: string; + status?: string; + start_time?: string; + end_time?: string; + }; + blob_path?: string; +} + export type GitLabProject = Opaque; export type GitLabMergeRequest = Opaque; diff --git a/src/steps/__recordings__/fetch-vulnerability-findings_3065310133/recording.har b/src/steps/__recordings__/fetch-vulnerability-findings_3065310133/recording.har new file mode 100644 index 0000000..89ded94 --- /dev/null +++ b/src/steps/__recordings__/fetch-vulnerability-findings_3065310133/recording.har @@ -0,0 +1,1414 @@ +{ + "log": { + "_recordingName": "fetch-vulnerability-findings", + "creator": { + "comment": "persister:JupiterOneIntegationFSPersister", + "name": "Polly.JS", + "version": "6.0.5" + }, + "entries": [ + { + "_id": "4c0c3c4f5586254e081147211bb205b6", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 0, + "cookies": [], + "headers": [ + { + "_fromType": "array", + "name": "private-token", + "value": "[REDACTED]" + }, + { + "_fromType": "array", + "name": "accept", + "value": "*/*" + }, + { + "_fromType": "array", + "name": "user-agent", + "value": "node-fetch/1.0 (+https://github.com/bitinn/node-fetch)" + }, + { + "_fromType": "array", + "name": "accept-encoding", + "value": "gzip,deflate" + }, + { + "_fromType": "array", + "name": "connection", + "value": "close" + }, + { + "name": "host", + "value": "gitlab.com" + } + ], + "headersSize": 261, + "httpVersion": "HTTP/1.1", + "method": "GET", + "queryString": [ + { + "name": "page", + "value": "1" + }, + { + "name": "per_page", + "value": "100" + } + ], + "url": "https://gitlab.com/api/v4/groups?page=1&per_page=100" + }, + "response": { + "bodySize": 532, + "content": { + "mimeType": "application/json", + "size": 532, + "text": "[{\"id\":11641867,\"web_url\":\"https://gitlab.com/groups/jupiterone-dev\",\"name\":\"JupiterOne Development\",\"path\":\"jupiterone-dev\",\"description\":\"\",\"visibility\":\"private\",\"share_with_group_lock\":false,\"require_two_factor_authentication\":false,\"two_factor_grace_period\":48,\"project_creation_level\":\"developer\",\"auto_devops_enabled\":null,\"subgroup_creation_level\":\"maintainer\",\"emails_disabled\":null,\"mentions_disabled\":null,\"lfs_enabled\":true,\"default_branch_protection\":2,\"avatar_url\":null,\"request_access_enabled\":true,\"full_name\":\"JupiterOne Development\",\"full_path\":\"jupiterone-dev\",\"created_at\":\"2021-04-07T23:51:04.817Z\",\"parent_id\":null,\"ldap_cn\":null,\"ldap_access\":null,\"marked_for_deletion_on\":null,\"wiki_access_level\":\"enabled\"}]" + }, + "cookies": [ + { + "domain": ".gitlab.com", + "httpOnly": true, + "name": "_cfuvid", + "path": "/", + "sameSite": "None", + "secure": true, + "value": "[REDACTED]" + } + ], + "headers": [ + { + "name": "date", + "value": "Wed, 14 Jun 2023 13:25:56 GMT" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "connection", + "value": "close" + }, + { + "name": "cache-control", + "value": "max-age=0, private, must-revalidate" + }, + { + "name": "content-security-policy", + "value": "default-src 'none'" + }, + { + "name": "etag", + "value": "W/\"5ee1ad37a693c63914691c33ae743593\"" + }, + { + "name": "link", + "value": "; rel=\"first\", ; rel=\"last\"" + }, + { + "name": "vary", + "value": "Origin, Accept-Encoding" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-gitlab-meta", + "value": "{\"correlation_id\":\"264dd77e2eb832ee7b8413e11b5fd21c\",\"version\":\"1\"}" + }, + { + "name": "x-next-page", + "value": "" + }, + { + "name": "x-page", + "value": "1" + }, + { + "name": "x-per-page", + "value": "100" + }, + { + "name": "x-prev-page", + "value": "" + }, + { + "name": "x-request-id", + "value": "264dd77e2eb832ee7b8413e11b5fd21c" + }, + { + "name": "x-runtime", + "value": "0.131158" + }, + { + "name": "x-total", + "value": "1" + }, + { + "name": "x-total-pages", + "value": "1" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000" + }, + { + "name": "referrer-policy", + "value": "strict-origin-when-cross-origin" + }, + { + "name": "ratelimit-observed", + "value": "1" + }, + { + "name": "ratelimit-remaining", + "value": "1999" + }, + { + "name": "ratelimit-reset", + "value": "1686749215" + }, + { + "name": "ratelimit-resettime", + "value": "Wed, 14 Jun 2023 13:26:55 GMT" + }, + { + "name": "ratelimit-limit", + "value": "2000" + }, + { + "name": "gitlab-lb", + "value": "fe-05-lb-gprd" + }, + { + "name": "gitlab-sv", + "value": "localhost" + }, + { + "name": "cf-cache-status", + "value": "MISS" + }, + { + "name": "report-to", + "value": "{\"endpoints\":[{\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v3?s=Vw6BChjxg5XP13yDrh0szXNVck2u1cqSuAxf7JNm9qEUqBOCevkHBmt28yfG6wDaWiZ%2Fx0wC%2FKSQw8VuhVk1LKCL9J5uZFsArwafop1qaUss%2BdWeDXo6KYxM6ZQ%3D\"}],\"group\":\"cf-nel\",\"max_age\":604800}" + }, + { + "name": "nel", + "value": "{\"success_fraction\":0.01,\"report_to\":\"cf-nel\",\"max_age\":604800}" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "[REDACTED]" + }, + { + "name": "server", + "value": "cloudflare" + }, + { + "name": "cf-ray", + "value": "7d72e6eef87c08f1-EZE" + } + ], + "headersSize": 1764, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2023-06-14T13:25:55.410Z", + "time": 447, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 447 + } + }, + { + "_id": "b85c9079f59028069f1522292327d4f0", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 0, + "cookies": [], + "headers": [ + { + "_fromType": "array", + "name": "private-token", + "value": "[REDACTED]" + }, + { + "_fromType": "array", + "name": "accept", + "value": "*/*" + }, + { + "_fromType": "array", + "name": "user-agent", + "value": "node-fetch/1.0 (+https://github.com/bitinn/node-fetch)" + }, + { + "_fromType": "array", + "name": "accept-encoding", + "value": "gzip,deflate" + }, + { + "_fromType": "array", + "name": "connection", + "value": "close" + }, + { + "name": "host", + "value": "gitlab.com" + } + ], + "headersSize": 279, + "httpVersion": "HTTP/1.1", + "method": "GET", + "queryString": [ + { + "name": "page", + "value": "1" + }, + { + "name": "per_page", + "value": "100" + } + ], + "url": "https://gitlab.com/api/v4/groups/11641867/projects?page=1&per_page=100" + }, + "response": { + "bodySize": 2903, + "content": { + "mimeType": "application/json", + "size": 2903, + "text": "[{\"id\":46792443,\"description\":null,\"name\":\"Gaston Vulnerabilities Test\",\"name_with_namespace\":\"JupiterOne Development / Gaston Vulnerabilities Test\",\"path\":\"gaston-vulnerabilities-test\",\"path_with_namespace\":\"jupiterone-dev/gaston-vulnerabilities-test\",\"created_at\":\"2023-06-12T14:49:40.286Z\",\"default_branch\":\"main\",\"tag_list\":[],\"topics\":[],\"ssh_url_to_repo\":\"git@gitlab.com:jupiterone-dev/gaston-vulnerabilities-test.git\",\"http_url_to_repo\":\"https://gitlab.com/jupiterone-dev/gaston-vulnerabilities-test.git\",\"web_url\":\"https://gitlab.com/jupiterone-dev/gaston-vulnerabilities-test\",\"readme_url\":\"https://gitlab.com/jupiterone-dev/gaston-vulnerabilities-test/-/blob/main/README.md\",\"forks_count\":0,\"avatar_url\":null,\"star_count\":0,\"last_activity_at\":\"2023-06-12T14:49:40.286Z\",\"namespace\":{\"id\":11641867,\"name\":\"JupiterOne Development\",\"path\":\"jupiterone-dev\",\"kind\":\"group\",\"full_path\":\"jupiterone-dev\",\"parent_id\":null,\"avatar_url\":null,\"web_url\":\"https://gitlab.com/groups/jupiterone-dev\"},\"container_registry_image_prefix\":\"registry.gitlab.com/jupiterone-dev/gaston-vulnerabilities-test\",\"_links\":{\"self\":\"https://gitlab.com/api/v4/projects/46792443\",\"issues\":\"https://gitlab.com/api/v4/projects/46792443/issues\",\"merge_requests\":\"https://gitlab.com/api/v4/projects/46792443/merge_requests\",\"repo_branches\":\"https://gitlab.com/api/v4/projects/46792443/repository/branches\",\"labels\":\"https://gitlab.com/api/v4/projects/46792443/labels\",\"events\":\"https://gitlab.com/api/v4/projects/46792443/events\",\"members\":\"https://gitlab.com/api/v4/projects/46792443/members\",\"cluster_agents\":\"https://gitlab.com/api/v4/projects/46792443/cluster_agents\"},\"packages_enabled\":true,\"empty_repo\":false,\"archived\":false,\"visibility\":\"private\",\"resolve_outdated_diff_discussions\":false,\"container_expiration_policy\":{\"cadence\":\"1d\",\"enabled\":false,\"keep_n\":10,\"older_than\":\"90d\",\"name_regex\":\".*\",\"name_regex_keep\":null,\"next_run_at\":\"2023-06-13T14:49:40.317Z\"},\"issues_enabled\":true,\"merge_requests_enabled\":true,\"wiki_enabled\":true,\"jobs_enabled\":true,\"snippets_enabled\":true,\"container_registry_enabled\":true,\"service_desk_enabled\":true,\"service_desk_address\":\"contact-project+jupiterone-dev-gaston-vulnerabilities-test-46792443-issue-@incoming.gitlab.com\",\"can_create_merge_request_in\":true,\"issues_access_level\":\"enabled\",\"repository_access_level\":\"enabled\",\"merge_requests_access_level\":\"enabled\",\"forking_access_level\":\"enabled\",\"wiki_access_level\":\"enabled\",\"builds_access_level\":\"enabled\",\"snippets_access_level\":\"enabled\",\"pages_access_level\":\"private\",\"analytics_access_level\":\"enabled\",\"container_registry_access_level\":\"enabled\",\"security_and_compliance_access_level\":\"private\",\"releases_access_level\":\"enabled\",\"environments_access_level\":\"enabled\",\"feature_flags_access_level\":\"enabled\",\"infrastructure_access_level\":\"enabled\",\"monitor_access_level\":\"enabled\",\"emails_disabled\":null,\"shared_runners_enabled\":true,\"lfs_enabled\":true,\"creator_id\":7283719,\"import_url\":null,\"import_type\":null,\"import_status\":\"none\",\"open_issues_count\":0,\"description_html\":\"\",\"updated_at\":\"2023-06-12T15:23:32.810Z\",\"ci_default_git_depth\":20,\"ci_forward_deployment_enabled\":true,\"ci_job_token_scope_enabled\":false,\"ci_separated_caches\":true,\"ci_allow_fork_pipelines_to_run_in_parent_project\":true,\"build_git_strategy\":\"fetch\",\"keep_latest_artifact\":true,\"restrict_user_defined_variables\":false,\"runners_token\":\"GR1348941f1pnX5q5CpzmHAsWcy2Z\",\"runner_token_expiration_interval\":null,\"group_runners_enabled\":true,\"auto_cancel_pending_pipelines\":\"enabled\",\"build_timeout\":3600,\"auto_devops_enabled\":false,\"auto_devops_deploy_strategy\":\"continuous\",\"ci_config_path\":\"\",\"public_jobs\":true,\"shared_with_groups\":[],\"only_allow_merge_if_pipeline_succeeds\":false,\"allow_merge_on_skipped_pipeline\":null,\"request_access_enabled\":true,\"only_allow_merge_if_all_discussions_are_resolved\":false,\"remove_source_branch_after_merge\":true,\"printing_merge_request_link_enabled\":true,\"merge_method\":\"merge\",\"squash_option\":\"default_off\",\"enforce_auth_checks_on_uploads\":true,\"suggestion_commit_message\":null,\"merge_commit_template\":null,\"squash_commit_template\":null,\"issue_branch_template\":null,\"autoclose_referenced_issues\":true,\"approvals_before_merge\":0,\"mirror\":false,\"external_authorization_classification_label\":\"\",\"marked_for_deletion_at\":null,\"marked_for_deletion_on\":null,\"requirements_enabled\":true,\"requirements_access_level\":\"enabled\",\"security_and_compliance_enabled\":true,\"compliance_frameworks\":[],\"issues_template\":null,\"merge_requests_template\":null,\"merge_pipelines_enabled\":false,\"merge_trains_enabled\":false,\"only_allow_merge_if_all_status_checks_passed\":false,\"allow_pipeline_trigger_approve_deployment\":false},{\"id\":25725992,\"description\":\"Learn how to use GitLab to support your software development life cycle.\",\"name\":\"Learn GitLab\",\"name_with_namespace\":\"JupiterOne Development / Learn GitLab\",\"path\":\"learn-gitlab\",\"path_with_namespace\":\"jupiterone-dev/learn-gitlab\",\"created_at\":\"2021-04-07T23:51:16.211Z\",\"default_branch\":\"master\",\"tag_list\":[],\"topics\":[],\"ssh_url_to_repo\":\"git@gitlab.com:jupiterone-dev/learn-gitlab.git\",\"http_url_to_repo\":\"https://gitlab.com/jupiterone-dev/learn-gitlab.git\",\"web_url\":\"https://gitlab.com/jupiterone-dev/learn-gitlab\",\"readme_url\":\"https://gitlab.com/jupiterone-dev/learn-gitlab/-/blob/master/README.md\",\"forks_count\":0,\"avatar_url\":\"https://gitlab.com/uploads/-/system/project/avatar/25725992/Artboard.jpg\",\"star_count\":0,\"last_activity_at\":\"2021-04-07T23:51:16.211Z\",\"namespace\":{\"id\":11641867,\"name\":\"JupiterOne Development\",\"path\":\"jupiterone-dev\",\"kind\":\"group\",\"full_path\":\"jupiterone-dev\",\"parent_id\":null,\"avatar_url\":null,\"web_url\":\"https://gitlab.com/groups/jupiterone-dev\"},\"container_registry_image_prefix\":\"registry.gitlab.com/jupiterone-dev/learn-gitlab\",\"_links\":{\"self\":\"https://gitlab.com/api/v4/projects/25725992\",\"issues\":\"https://gitlab.com/api/v4/projects/25725992/issues\",\"merge_requests\":\"https://gitlab.com/api/v4/projects/25725992/merge_requests\",\"repo_branches\":\"https://gitlab.com/api/v4/projects/25725992/repository/branches\",\"labels\":\"https://gitlab.com/api/v4/projects/25725992/labels\",\"events\":\"https://gitlab.com/api/v4/projects/25725992/events\",\"members\":\"https://gitlab.com/api/v4/projects/25725992/members\",\"cluster_agents\":\"https://gitlab.com/api/v4/projects/25725992/cluster_agents\"},\"packages_enabled\":true,\"empty_repo\":false,\"archived\":false,\"visibility\":\"private\",\"resolve_outdated_diff_discussions\":false,\"container_expiration_policy\":{\"cadence\":\"1d\",\"enabled\":false,\"keep_n\":10,\"older_than\":\"90d\",\"name_regex\":\".*\",\"name_regex_keep\":null,\"next_run_at\":\"2021-04-08T23:51:16.225Z\"},\"issues_enabled\":true,\"merge_requests_enabled\":true,\"wiki_enabled\":true,\"jobs_enabled\":true,\"snippets_enabled\":true,\"container_registry_enabled\":true,\"service_desk_enabled\":true,\"service_desk_address\":\"contact-project+jupiterone-dev-learn-gitlab-25725992-issue-@incoming.gitlab.com\",\"can_create_merge_request_in\":true,\"issues_access_level\":\"enabled\",\"repository_access_level\":\"enabled\",\"merge_requests_access_level\":\"enabled\",\"forking_access_level\":\"enabled\",\"wiki_access_level\":\"enabled\",\"builds_access_level\":\"enabled\",\"snippets_access_level\":\"enabled\",\"pages_access_level\":\"private\",\"analytics_access_level\":\"enabled\",\"container_registry_access_level\":\"enabled\",\"security_and_compliance_access_level\":\"private\",\"releases_access_level\":\"enabled\",\"environments_access_level\":\"enabled\",\"feature_flags_access_level\":\"enabled\",\"infrastructure_access_level\":\"enabled\",\"monitor_access_level\":\"enabled\",\"emails_disabled\":null,\"shared_runners_enabled\":true,\"lfs_enabled\":true,\"creator_id\":8625568,\"import_url\":null,\"import_type\":\"gitlab_project\",\"import_status\":\"finished\",\"open_issues_count\":12,\"description_html\":\"\\u003cp data-sourcepos=\\\"1:1-1:72\\\" dir=\\\"auto\\\"\\u003eLearn how to use GitLab to support your software development life cycle.\\u003c/p\\u003e\",\"updated_at\":\"2023-04-25T23:32:23.663Z\",\"ci_default_git_depth\":50,\"ci_forward_deployment_enabled\":true,\"ci_job_token_scope_enabled\":false,\"ci_separated_caches\":true,\"ci_allow_fork_pipelines_to_run_in_parent_project\":true,\"build_git_strategy\":\"fetch\",\"keep_latest_artifact\":true,\"restrict_user_defined_variables\":false,\"runners_token\":\"GR1348941x6U44hSAvqKjde7Ao1ti\",\"runner_token_expiration_interval\":null,\"group_runners_enabled\":true,\"auto_cancel_pending_pipelines\":\"enabled\",\"build_timeout\":3600,\"auto_devops_enabled\":false,\"auto_devops_deploy_strategy\":\"continuous\",\"ci_config_path\":\"\",\"public_jobs\":true,\"shared_with_groups\":[],\"only_allow_merge_if_pipeline_succeeds\":false,\"allow_merge_on_skipped_pipeline\":null,\"request_access_enabled\":true,\"only_allow_merge_if_all_discussions_are_resolved\":false,\"remove_source_branch_after_merge\":true,\"printing_merge_request_link_enabled\":true,\"merge_method\":\"merge\",\"squash_option\":\"default_off\",\"enforce_auth_checks_on_uploads\":true,\"suggestion_commit_message\":null,\"merge_commit_template\":null,\"squash_commit_template\":null,\"issue_branch_template\":null,\"autoclose_referenced_issues\":true,\"approvals_before_merge\":0,\"mirror\":false,\"external_authorization_classification_label\":\"\",\"marked_for_deletion_at\":null,\"marked_for_deletion_on\":null,\"requirements_enabled\":true,\"requirements_access_level\":\"enabled\",\"security_and_compliance_enabled\":true,\"compliance_frameworks\":[],\"issues_template\":null,\"merge_requests_template\":null,\"merge_pipelines_enabled\":false,\"merge_trains_enabled\":false,\"only_allow_merge_if_all_status_checks_passed\":false,\"allow_pipeline_trigger_approve_deployment\":false},{\"id\":25725991,\"description\":\"\",\"name\":\"test-proj\",\"name_with_namespace\":\"JupiterOne Development / test-proj\",\"path\":\"test-proj\",\"path_with_namespace\":\"jupiterone-dev/test-proj\",\"created_at\":\"2021-04-07T23:51:15.461Z\",\"default_branch\":\"master\",\"tag_list\":[\"python\",\"web\"],\"topics\":[\"python\",\"web\"],\"ssh_url_to_repo\":\"git@gitlab.com:jupiterone-dev/test-proj.git\",\"http_url_to_repo\":\"https://gitlab.com/jupiterone-dev/test-proj.git\",\"web_url\":\"https://gitlab.com/jupiterone-dev/test-proj\",\"readme_url\":\"https://gitlab.com/jupiterone-dev/test-proj/-/blob/master/README.md\",\"forks_count\":0,\"avatar_url\":null,\"star_count\":0,\"last_activity_at\":\"2023-06-09T11:52:57.851Z\",\"namespace\":{\"id\":11641867,\"name\":\"JupiterOne Development\",\"path\":\"jupiterone-dev\",\"kind\":\"group\",\"full_path\":\"jupiterone-dev\",\"parent_id\":null,\"avatar_url\":null,\"web_url\":\"https://gitlab.com/groups/jupiterone-dev\"},\"container_registry_image_prefix\":\"registry.gitlab.com/jupiterone-dev/test-proj\",\"_links\":{\"self\":\"https://gitlab.com/api/v4/projects/25725991\",\"issues\":\"https://gitlab.com/api/v4/projects/25725991/issues\",\"merge_requests\":\"https://gitlab.com/api/v4/projects/25725991/merge_requests\",\"repo_branches\":\"https://gitlab.com/api/v4/projects/25725991/repository/branches\",\"labels\":\"https://gitlab.com/api/v4/projects/25725991/labels\",\"events\":\"https://gitlab.com/api/v4/projects/25725991/events\",\"members\":\"https://gitlab.com/api/v4/projects/25725991/members\",\"cluster_agents\":\"https://gitlab.com/api/v4/projects/25725991/cluster_agents\"},\"packages_enabled\":true,\"empty_repo\":false,\"archived\":false,\"visibility\":\"private\",\"resolve_outdated_diff_discussions\":false,\"container_expiration_policy\":{\"cadence\":\"1d\",\"enabled\":false,\"keep_n\":10,\"older_than\":\"90d\",\"name_regex\":\".*\",\"name_regex_keep\":null,\"next_run_at\":\"2021-04-08T23:51:15.484Z\"},\"issues_enabled\":true,\"merge_requests_enabled\":true,\"wiki_enabled\":true,\"jobs_enabled\":true,\"snippets_enabled\":true,\"container_registry_enabled\":true,\"service_desk_enabled\":true,\"service_desk_address\":\"contact-project+jupiterone-dev-test-proj-25725991-issue-@incoming.gitlab.com\",\"can_create_merge_request_in\":true,\"issues_access_level\":\"enabled\",\"repository_access_level\":\"enabled\",\"merge_requests_access_level\":\"enabled\",\"forking_access_level\":\"enabled\",\"wiki_access_level\":\"enabled\",\"builds_access_level\":\"enabled\",\"snippets_access_level\":\"enabled\",\"pages_access_level\":\"private\",\"analytics_access_level\":\"enabled\",\"container_registry_access_level\":\"enabled\",\"security_and_compliance_access_level\":\"private\",\"releases_access_level\":\"enabled\",\"environments_access_level\":\"enabled\",\"feature_flags_access_level\":\"enabled\",\"infrastructure_access_level\":\"enabled\",\"monitor_access_level\":\"enabled\",\"emails_disabled\":null,\"shared_runners_enabled\":true,\"lfs_enabled\":true,\"creator_id\":8625568,\"import_url\":null,\"import_type\":null,\"import_status\":\"none\",\"open_issues_count\":0,\"description_html\":\"\",\"updated_at\":\"2023-06-09T11:52:57.851Z\",\"ci_default_git_depth\":50,\"ci_forward_deployment_enabled\":true,\"ci_job_token_scope_enabled\":false,\"ci_separated_caches\":true,\"ci_allow_fork_pipelines_to_run_in_parent_project\":true,\"build_git_strategy\":\"fetch\",\"keep_latest_artifact\":true,\"restrict_user_defined_variables\":false,\"runners_token\":\"GR1348941qtATsERHb9Yn1vqthKVx\",\"runner_token_expiration_interval\":null,\"group_runners_enabled\":true,\"auto_cancel_pending_pipelines\":\"enabled\",\"build_timeout\":3600,\"auto_devops_enabled\":false,\"auto_devops_deploy_strategy\":\"continuous\",\"ci_config_path\":\"\",\"public_jobs\":true,\"shared_with_groups\":[],\"only_allow_merge_if_pipeline_succeeds\":false,\"allow_merge_on_skipped_pipeline\":null,\"request_access_enabled\":true,\"only_allow_merge_if_all_discussions_are_resolved\":false,\"remove_source_branch_after_merge\":true,\"printing_merge_request_link_enabled\":true,\"merge_method\":\"merge\",\"squash_option\":\"default_off\",\"enforce_auth_checks_on_uploads\":true,\"suggestion_commit_message\":null,\"merge_commit_template\":null,\"squash_commit_template\":null,\"issue_branch_template\":null,\"autoclose_referenced_issues\":true,\"approvals_before_merge\":0,\"mirror\":false,\"external_authorization_classification_label\":\"\",\"marked_for_deletion_at\":null,\"marked_for_deletion_on\":null,\"requirements_enabled\":true,\"requirements_access_level\":\"enabled\",\"security_and_compliance_enabled\":true,\"compliance_frameworks\":[],\"issues_template\":null,\"merge_requests_template\":null,\"merge_pipelines_enabled\":false,\"merge_trains_enabled\":false,\"only_allow_merge_if_all_status_checks_passed\":false,\"allow_pipeline_trigger_approve_deployment\":false}]" + }, + "cookies": [ + { + "domain": ".gitlab.com", + "httpOnly": true, + "name": "_cfuvid", + "path": "/", + "sameSite": "None", + "secure": true, + "value": "[REDACTED]" + } + ], + "headers": [ + { + "name": "date", + "value": "Wed, 14 Jun 2023 13:25:56 GMT" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "connection", + "value": "close" + }, + { + "name": "cache-control", + "value": "max-age=0, private, must-revalidate" + }, + { + "name": "content-security-policy", + "value": "default-src 'none'" + }, + { + "name": "etag", + "value": "W/\"1d1d2fab81ac583c9e148936a313d361\"" + }, + { + "name": "link", + "value": "; rel=\"first\", ; rel=\"last\"" + }, + { + "name": "vary", + "value": "Origin, Accept-Encoding" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-gitlab-meta", + "value": "{\"correlation_id\":\"50e6a493b1fd0be25d20c35dde9ee962\",\"version\":\"1\"}" + }, + { + "name": "x-next-page", + "value": "" + }, + { + "name": "x-page", + "value": "1" + }, + { + "name": "x-per-page", + "value": "100" + }, + { + "name": "x-prev-page", + "value": "" + }, + { + "name": "x-request-id", + "value": "50e6a493b1fd0be25d20c35dde9ee962" + }, + { + "name": "x-runtime", + "value": "0.321193" + }, + { + "name": "x-total", + "value": "3" + }, + { + "name": "x-total-pages", + "value": "1" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000" + }, + { + "name": "referrer-policy", + "value": "strict-origin-when-cross-origin" + }, + { + "name": "ratelimit-observed", + "value": "2" + }, + { + "name": "ratelimit-remaining", + "value": "1998" + }, + { + "name": "ratelimit-reset", + "value": "1686749216" + }, + { + "name": "ratelimit-resettime", + "value": "Wed, 14 Jun 2023 13:26:56 GMT" + }, + { + "name": "ratelimit-limit", + "value": "2000" + }, + { + "name": "gitlab-lb", + "value": "fe-08-lb-gprd" + }, + { + "name": "gitlab-sv", + "value": "localhost" + }, + { + "name": "cf-cache-status", + "value": "MISS" + }, + { + "name": "report-to", + "value": "{\"endpoints\":[{\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v3?s=TpNbazL%2FXGOWqub0gXqa%2Bv299hotVg6cLMdCnph9dpBTkjNiP%2FGNGz7BeobYUzKEX2A9lstGyro%2FcBfnG02aNS%2BDFRt9FBcTvxIrUft1hY0M8nwQbcCwOt7u14E%3D\"}],\"group\":\"cf-nel\",\"max_age\":604800}" + }, + { + "name": "nel", + "value": "{\"success_fraction\":0.01,\"report_to\":\"cf-nel\",\"max_age\":604800}" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "[REDACTED]" + }, + { + "name": "server", + "value": "cloudflare" + }, + { + "name": "cf-ray", + "value": "7d72e6f1aba11870-EZE" + } + ], + "headersSize": 2180, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2023-06-14T13:25:55.872Z", + "time": 659, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 659 + } + }, + { + "_id": "2db93305f2de0ff04a790468e167ceb4", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 0, + "cookies": [], + "headers": [ + { + "_fromType": "array", + "name": "private-token", + "value": "[REDACTED]" + }, + { + "_fromType": "array", + "name": "accept", + "value": "*/*" + }, + { + "_fromType": "array", + "name": "user-agent", + "value": "node-fetch/1.0 (+https://github.com/bitinn/node-fetch)" + }, + { + "_fromType": "array", + "name": "accept-encoding", + "value": "gzip,deflate" + }, + { + "_fromType": "array", + "name": "connection", + "value": "close" + }, + { + "name": "host", + "value": "gitlab.com" + } + ], + "headersSize": 274, + "httpVersion": "HTTP/1.1", + "method": "GET", + "queryString": [ + { + "name": "owned", + "value": "true" + }, + { + "name": "page", + "value": "1" + }, + { + "name": "per_page", + "value": "100" + } + ], + "url": "https://gitlab.com/api/v4/projects?owned=true&page=1&per_page=100" + }, + "response": { + "bodySize": 2951, + "content": { + "mimeType": "application/json", + "size": 2951, + "text": "[{\"id\":46792443,\"description\":null,\"name\":\"Gaston Vulnerabilities Test\",\"name_with_namespace\":\"JupiterOne Development / Gaston Vulnerabilities Test\",\"path\":\"gaston-vulnerabilities-test\",\"path_with_namespace\":\"jupiterone-dev/gaston-vulnerabilities-test\",\"created_at\":\"2023-06-12T14:49:40.286Z\",\"default_branch\":\"main\",\"tag_list\":[],\"topics\":[],\"ssh_url_to_repo\":\"git@gitlab.com:jupiterone-dev/gaston-vulnerabilities-test.git\",\"http_url_to_repo\":\"https://gitlab.com/jupiterone-dev/gaston-vulnerabilities-test.git\",\"web_url\":\"https://gitlab.com/jupiterone-dev/gaston-vulnerabilities-test\",\"readme_url\":\"https://gitlab.com/jupiterone-dev/gaston-vulnerabilities-test/-/blob/main/README.md\",\"forks_count\":0,\"avatar_url\":null,\"star_count\":0,\"last_activity_at\":\"2023-06-12T14:49:40.286Z\",\"namespace\":{\"id\":11641867,\"name\":\"JupiterOne Development\",\"path\":\"jupiterone-dev\",\"kind\":\"group\",\"full_path\":\"jupiterone-dev\",\"parent_id\":null,\"avatar_url\":null,\"web_url\":\"https://gitlab.com/groups/jupiterone-dev\"},\"container_registry_image_prefix\":\"registry.gitlab.com/jupiterone-dev/gaston-vulnerabilities-test\",\"_links\":{\"self\":\"https://gitlab.com/api/v4/projects/46792443\",\"issues\":\"https://gitlab.com/api/v4/projects/46792443/issues\",\"merge_requests\":\"https://gitlab.com/api/v4/projects/46792443/merge_requests\",\"repo_branches\":\"https://gitlab.com/api/v4/projects/46792443/repository/branches\",\"labels\":\"https://gitlab.com/api/v4/projects/46792443/labels\",\"events\":\"https://gitlab.com/api/v4/projects/46792443/events\",\"members\":\"https://gitlab.com/api/v4/projects/46792443/members\",\"cluster_agents\":\"https://gitlab.com/api/v4/projects/46792443/cluster_agents\"},\"packages_enabled\":true,\"empty_repo\":false,\"archived\":false,\"visibility\":\"private\",\"resolve_outdated_diff_discussions\":false,\"container_expiration_policy\":{\"cadence\":\"1d\",\"enabled\":false,\"keep_n\":10,\"older_than\":\"90d\",\"name_regex\":\".*\",\"name_regex_keep\":null,\"next_run_at\":\"2023-06-13T14:49:40.317Z\"},\"issues_enabled\":true,\"merge_requests_enabled\":true,\"wiki_enabled\":true,\"jobs_enabled\":true,\"snippets_enabled\":true,\"container_registry_enabled\":true,\"service_desk_enabled\":true,\"service_desk_address\":\"contact-project+jupiterone-dev-gaston-vulnerabilities-test-46792443-issue-@incoming.gitlab.com\",\"can_create_merge_request_in\":true,\"issues_access_level\":\"enabled\",\"repository_access_level\":\"enabled\",\"merge_requests_access_level\":\"enabled\",\"forking_access_level\":\"enabled\",\"wiki_access_level\":\"enabled\",\"builds_access_level\":\"enabled\",\"snippets_access_level\":\"enabled\",\"pages_access_level\":\"private\",\"analytics_access_level\":\"enabled\",\"container_registry_access_level\":\"enabled\",\"security_and_compliance_access_level\":\"private\",\"releases_access_level\":\"enabled\",\"environments_access_level\":\"enabled\",\"feature_flags_access_level\":\"enabled\",\"infrastructure_access_level\":\"enabled\",\"monitor_access_level\":\"enabled\",\"emails_disabled\":null,\"shared_runners_enabled\":true,\"lfs_enabled\":true,\"creator_id\":7283719,\"import_url\":null,\"import_type\":null,\"import_status\":\"none\",\"open_issues_count\":0,\"description_html\":\"\",\"updated_at\":\"2023-06-12T15:23:32.810Z\",\"ci_default_git_depth\":20,\"ci_forward_deployment_enabled\":true,\"ci_job_token_scope_enabled\":false,\"ci_separated_caches\":true,\"ci_allow_fork_pipelines_to_run_in_parent_project\":true,\"build_git_strategy\":\"fetch\",\"keep_latest_artifact\":true,\"restrict_user_defined_variables\":false,\"runners_token\":\"GR1348941f1pnX5q5CpzmHAsWcy2Z\",\"runner_token_expiration_interval\":null,\"group_runners_enabled\":true,\"auto_cancel_pending_pipelines\":\"enabled\",\"build_timeout\":3600,\"auto_devops_enabled\":false,\"auto_devops_deploy_strategy\":\"continuous\",\"ci_config_path\":\"\",\"public_jobs\":true,\"shared_with_groups\":[],\"only_allow_merge_if_pipeline_succeeds\":false,\"allow_merge_on_skipped_pipeline\":null,\"request_access_enabled\":true,\"only_allow_merge_if_all_discussions_are_resolved\":false,\"remove_source_branch_after_merge\":true,\"printing_merge_request_link_enabled\":true,\"merge_method\":\"merge\",\"squash_option\":\"default_off\",\"enforce_auth_checks_on_uploads\":true,\"suggestion_commit_message\":null,\"merge_commit_template\":null,\"squash_commit_template\":null,\"issue_branch_template\":null,\"autoclose_referenced_issues\":true,\"approvals_before_merge\":0,\"mirror\":false,\"external_authorization_classification_label\":\"\",\"marked_for_deletion_at\":null,\"marked_for_deletion_on\":null,\"requirements_enabled\":true,\"requirements_access_level\":\"enabled\",\"security_and_compliance_enabled\":true,\"compliance_frameworks\":[],\"issues_template\":null,\"merge_requests_template\":null,\"merge_pipelines_enabled\":false,\"merge_trains_enabled\":false,\"only_allow_merge_if_all_status_checks_passed\":false,\"allow_pipeline_trigger_approve_deployment\":false,\"permissions\":{\"project_access\":null,\"group_access\":{\"access_level\":50,\"notification_level\":3}}},{\"id\":25725992,\"description\":\"Learn how to use GitLab to support your software development life cycle.\",\"name\":\"Learn GitLab\",\"name_with_namespace\":\"JupiterOne Development / Learn GitLab\",\"path\":\"learn-gitlab\",\"path_with_namespace\":\"jupiterone-dev/learn-gitlab\",\"created_at\":\"2021-04-07T23:51:16.211Z\",\"default_branch\":\"master\",\"tag_list\":[],\"topics\":[],\"ssh_url_to_repo\":\"git@gitlab.com:jupiterone-dev/learn-gitlab.git\",\"http_url_to_repo\":\"https://gitlab.com/jupiterone-dev/learn-gitlab.git\",\"web_url\":\"https://gitlab.com/jupiterone-dev/learn-gitlab\",\"readme_url\":\"https://gitlab.com/jupiterone-dev/learn-gitlab/-/blob/master/README.md\",\"forks_count\":0,\"avatar_url\":\"https://gitlab.com/uploads/-/system/project/avatar/25725992/Artboard.jpg\",\"star_count\":0,\"last_activity_at\":\"2021-04-07T23:51:16.211Z\",\"namespace\":{\"id\":11641867,\"name\":\"JupiterOne Development\",\"path\":\"jupiterone-dev\",\"kind\":\"group\",\"full_path\":\"jupiterone-dev\",\"parent_id\":null,\"avatar_url\":null,\"web_url\":\"https://gitlab.com/groups/jupiterone-dev\"},\"container_registry_image_prefix\":\"registry.gitlab.com/jupiterone-dev/learn-gitlab\",\"_links\":{\"self\":\"https://gitlab.com/api/v4/projects/25725992\",\"issues\":\"https://gitlab.com/api/v4/projects/25725992/issues\",\"merge_requests\":\"https://gitlab.com/api/v4/projects/25725992/merge_requests\",\"repo_branches\":\"https://gitlab.com/api/v4/projects/25725992/repository/branches\",\"labels\":\"https://gitlab.com/api/v4/projects/25725992/labels\",\"events\":\"https://gitlab.com/api/v4/projects/25725992/events\",\"members\":\"https://gitlab.com/api/v4/projects/25725992/members\",\"cluster_agents\":\"https://gitlab.com/api/v4/projects/25725992/cluster_agents\"},\"packages_enabled\":true,\"empty_repo\":false,\"archived\":false,\"visibility\":\"private\",\"resolve_outdated_diff_discussions\":false,\"container_expiration_policy\":{\"cadence\":\"1d\",\"enabled\":false,\"keep_n\":10,\"older_than\":\"90d\",\"name_regex\":\".*\",\"name_regex_keep\":null,\"next_run_at\":\"2021-04-08T23:51:16.225Z\"},\"issues_enabled\":true,\"merge_requests_enabled\":true,\"wiki_enabled\":true,\"jobs_enabled\":true,\"snippets_enabled\":true,\"container_registry_enabled\":true,\"service_desk_enabled\":true,\"service_desk_address\":\"contact-project+jupiterone-dev-learn-gitlab-25725992-issue-@incoming.gitlab.com\",\"can_create_merge_request_in\":true,\"issues_access_level\":\"enabled\",\"repository_access_level\":\"enabled\",\"merge_requests_access_level\":\"enabled\",\"forking_access_level\":\"enabled\",\"wiki_access_level\":\"enabled\",\"builds_access_level\":\"enabled\",\"snippets_access_level\":\"enabled\",\"pages_access_level\":\"private\",\"analytics_access_level\":\"enabled\",\"container_registry_access_level\":\"enabled\",\"security_and_compliance_access_level\":\"private\",\"releases_access_level\":\"enabled\",\"environments_access_level\":\"enabled\",\"feature_flags_access_level\":\"enabled\",\"infrastructure_access_level\":\"enabled\",\"monitor_access_level\":\"enabled\",\"emails_disabled\":null,\"shared_runners_enabled\":true,\"lfs_enabled\":true,\"creator_id\":8625568,\"import_url\":null,\"import_type\":\"gitlab_project\",\"import_status\":\"finished\",\"open_issues_count\":12,\"description_html\":\"\\u003cp data-sourcepos=\\\"1:1-1:72\\\" dir=\\\"auto\\\"\\u003eLearn how to use GitLab to support your software development life cycle.\\u003c/p\\u003e\",\"updated_at\":\"2023-04-25T23:32:23.663Z\",\"ci_default_git_depth\":50,\"ci_forward_deployment_enabled\":true,\"ci_job_token_scope_enabled\":false,\"ci_separated_caches\":true,\"ci_allow_fork_pipelines_to_run_in_parent_project\":true,\"build_git_strategy\":\"fetch\",\"keep_latest_artifact\":true,\"restrict_user_defined_variables\":false,\"runners_token\":\"GR1348941x6U44hSAvqKjde7Ao1ti\",\"runner_token_expiration_interval\":null,\"group_runners_enabled\":true,\"auto_cancel_pending_pipelines\":\"enabled\",\"build_timeout\":3600,\"auto_devops_enabled\":false,\"auto_devops_deploy_strategy\":\"continuous\",\"ci_config_path\":\"\",\"public_jobs\":true,\"shared_with_groups\":[],\"only_allow_merge_if_pipeline_succeeds\":false,\"allow_merge_on_skipped_pipeline\":null,\"request_access_enabled\":true,\"only_allow_merge_if_all_discussions_are_resolved\":false,\"remove_source_branch_after_merge\":true,\"printing_merge_request_link_enabled\":true,\"merge_method\":\"merge\",\"squash_option\":\"default_off\",\"enforce_auth_checks_on_uploads\":true,\"suggestion_commit_message\":null,\"merge_commit_template\":null,\"squash_commit_template\":null,\"issue_branch_template\":null,\"autoclose_referenced_issues\":true,\"approvals_before_merge\":0,\"mirror\":false,\"external_authorization_classification_label\":\"\",\"marked_for_deletion_at\":null,\"marked_for_deletion_on\":null,\"requirements_enabled\":true,\"requirements_access_level\":\"enabled\",\"security_and_compliance_enabled\":true,\"compliance_frameworks\":[],\"issues_template\":null,\"merge_requests_template\":null,\"merge_pipelines_enabled\":false,\"merge_trains_enabled\":false,\"only_allow_merge_if_all_status_checks_passed\":false,\"allow_pipeline_trigger_approve_deployment\":false,\"permissions\":{\"project_access\":null,\"group_access\":{\"access_level\":50,\"notification_level\":3}}},{\"id\":25725991,\"description\":\"\",\"name\":\"test-proj\",\"name_with_namespace\":\"JupiterOne Development / test-proj\",\"path\":\"test-proj\",\"path_with_namespace\":\"jupiterone-dev/test-proj\",\"created_at\":\"2021-04-07T23:51:15.461Z\",\"default_branch\":\"master\",\"tag_list\":[\"python\",\"web\"],\"topics\":[\"python\",\"web\"],\"ssh_url_to_repo\":\"git@gitlab.com:jupiterone-dev/test-proj.git\",\"http_url_to_repo\":\"https://gitlab.com/jupiterone-dev/test-proj.git\",\"web_url\":\"https://gitlab.com/jupiterone-dev/test-proj\",\"readme_url\":\"https://gitlab.com/jupiterone-dev/test-proj/-/blob/master/README.md\",\"forks_count\":0,\"avatar_url\":null,\"star_count\":0,\"last_activity_at\":\"2023-06-09T11:52:57.851Z\",\"namespace\":{\"id\":11641867,\"name\":\"JupiterOne Development\",\"path\":\"jupiterone-dev\",\"kind\":\"group\",\"full_path\":\"jupiterone-dev\",\"parent_id\":null,\"avatar_url\":null,\"web_url\":\"https://gitlab.com/groups/jupiterone-dev\"},\"container_registry_image_prefix\":\"registry.gitlab.com/jupiterone-dev/test-proj\",\"_links\":{\"self\":\"https://gitlab.com/api/v4/projects/25725991\",\"issues\":\"https://gitlab.com/api/v4/projects/25725991/issues\",\"merge_requests\":\"https://gitlab.com/api/v4/projects/25725991/merge_requests\",\"repo_branches\":\"https://gitlab.com/api/v4/projects/25725991/repository/branches\",\"labels\":\"https://gitlab.com/api/v4/projects/25725991/labels\",\"events\":\"https://gitlab.com/api/v4/projects/25725991/events\",\"members\":\"https://gitlab.com/api/v4/projects/25725991/members\",\"cluster_agents\":\"https://gitlab.com/api/v4/projects/25725991/cluster_agents\"},\"packages_enabled\":true,\"empty_repo\":false,\"archived\":false,\"visibility\":\"private\",\"resolve_outdated_diff_discussions\":false,\"container_expiration_policy\":{\"cadence\":\"1d\",\"enabled\":false,\"keep_n\":10,\"older_than\":\"90d\",\"name_regex\":\".*\",\"name_regex_keep\":null,\"next_run_at\":\"2021-04-08T23:51:15.484Z\"},\"issues_enabled\":true,\"merge_requests_enabled\":true,\"wiki_enabled\":true,\"jobs_enabled\":true,\"snippets_enabled\":true,\"container_registry_enabled\":true,\"service_desk_enabled\":true,\"service_desk_address\":\"contact-project+jupiterone-dev-test-proj-25725991-issue-@incoming.gitlab.com\",\"can_create_merge_request_in\":true,\"issues_access_level\":\"enabled\",\"repository_access_level\":\"enabled\",\"merge_requests_access_level\":\"enabled\",\"forking_access_level\":\"enabled\",\"wiki_access_level\":\"enabled\",\"builds_access_level\":\"enabled\",\"snippets_access_level\":\"enabled\",\"pages_access_level\":\"private\",\"analytics_access_level\":\"enabled\",\"container_registry_access_level\":\"enabled\",\"security_and_compliance_access_level\":\"private\",\"releases_access_level\":\"enabled\",\"environments_access_level\":\"enabled\",\"feature_flags_access_level\":\"enabled\",\"infrastructure_access_level\":\"enabled\",\"monitor_access_level\":\"enabled\",\"emails_disabled\":null,\"shared_runners_enabled\":true,\"lfs_enabled\":true,\"creator_id\":8625568,\"import_url\":null,\"import_type\":null,\"import_status\":\"none\",\"open_issues_count\":0,\"description_html\":\"\",\"updated_at\":\"2023-06-09T11:52:57.851Z\",\"ci_default_git_depth\":50,\"ci_forward_deployment_enabled\":true,\"ci_job_token_scope_enabled\":false,\"ci_separated_caches\":true,\"ci_allow_fork_pipelines_to_run_in_parent_project\":true,\"build_git_strategy\":\"fetch\",\"keep_latest_artifact\":true,\"restrict_user_defined_variables\":false,\"runners_token\":\"GR1348941qtATsERHb9Yn1vqthKVx\",\"runner_token_expiration_interval\":null,\"group_runners_enabled\":true,\"auto_cancel_pending_pipelines\":\"enabled\",\"build_timeout\":3600,\"auto_devops_enabled\":false,\"auto_devops_deploy_strategy\":\"continuous\",\"ci_config_path\":\"\",\"public_jobs\":true,\"shared_with_groups\":[],\"only_allow_merge_if_pipeline_succeeds\":false,\"allow_merge_on_skipped_pipeline\":null,\"request_access_enabled\":true,\"only_allow_merge_if_all_discussions_are_resolved\":false,\"remove_source_branch_after_merge\":true,\"printing_merge_request_link_enabled\":true,\"merge_method\":\"merge\",\"squash_option\":\"default_off\",\"enforce_auth_checks_on_uploads\":true,\"suggestion_commit_message\":null,\"merge_commit_template\":null,\"squash_commit_template\":null,\"issue_branch_template\":null,\"autoclose_referenced_issues\":true,\"approvals_before_merge\":0,\"mirror\":false,\"external_authorization_classification_label\":\"\",\"marked_for_deletion_at\":null,\"marked_for_deletion_on\":null,\"requirements_enabled\":true,\"requirements_access_level\":\"enabled\",\"security_and_compliance_enabled\":true,\"compliance_frameworks\":[],\"issues_template\":null,\"merge_requests_template\":null,\"merge_pipelines_enabled\":false,\"merge_trains_enabled\":false,\"only_allow_merge_if_all_status_checks_passed\":false,\"allow_pipeline_trigger_approve_deployment\":false,\"permissions\":{\"project_access\":null,\"group_access\":{\"access_level\":50,\"notification_level\":3}}}]" + }, + "cookies": [ + { + "domain": ".gitlab.com", + "httpOnly": true, + "name": "_cfuvid", + "path": "/", + "sameSite": "None", + "secure": true, + "value": "[REDACTED]" + } + ], + "headers": [ + { + "name": "date", + "value": "Wed, 14 Jun 2023 13:25:57 GMT" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "connection", + "value": "close" + }, + { + "name": "cache-control", + "value": "max-age=0, private, must-revalidate" + }, + { + "name": "content-security-policy", + "value": "default-src 'none'" + }, + { + "name": "etag", + "value": "W/\"6b48283f18b55c0899e77523ea701d2e\"" + }, + { + "name": "link", + "value": "; rel=\"first\", ; rel=\"last\"" + }, + { + "name": "vary", + "value": "Origin, Accept-Encoding" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-gitlab-meta", + "value": "{\"correlation_id\":\"6a0e2b851f9e7e43c02a63c83ebfda62\",\"version\":\"1\"}" + }, + { + "name": "x-next-page", + "value": "" + }, + { + "name": "x-page", + "value": "1" + }, + { + "name": "x-per-page", + "value": "100" + }, + { + "name": "x-prev-page", + "value": "" + }, + { + "name": "x-request-id", + "value": "6a0e2b851f9e7e43c02a63c83ebfda62" + }, + { + "name": "x-runtime", + "value": "0.169705" + }, + { + "name": "x-total", + "value": "3" + }, + { + "name": "x-total-pages", + "value": "1" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000" + }, + { + "name": "referrer-policy", + "value": "strict-origin-when-cross-origin" + }, + { + "name": "ratelimit-observed", + "value": "3" + }, + { + "name": "ratelimit-remaining", + "value": "1997" + }, + { + "name": "ratelimit-reset", + "value": "1686749217" + }, + { + "name": "ratelimit-resettime", + "value": "Wed, 14 Jun 2023 13:26:57 GMT" + }, + { + "name": "ratelimit-limit", + "value": "2000" + }, + { + "name": "gitlab-lb", + "value": "fe-12-lb-gprd" + }, + { + "name": "gitlab-sv", + "value": "localhost" + }, + { + "name": "cf-cache-status", + "value": "MISS" + }, + { + "name": "report-to", + "value": "{\"endpoints\":[{\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v3?s=RIBXE0RdPcLspSsOTux4Th1aAQJkf4esg2C6ntwZLeUScAzJyxZXmjJcSn4du8BTWVFjr%2BRMNtm8jUCXOGYRnkbNQh49ycxN6p4ifgU2FwkM7SAOismqHlLn4SY%3D\"}],\"group\":\"cf-nel\",\"max_age\":604800}" + }, + { + "name": "nel", + "value": "{\"success_fraction\":0.01,\"report_to\":\"cf-nel\",\"max_age\":604800}" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "[REDACTED]" + }, + { + "name": "server", + "value": "cloudflare" + }, + { + "name": "cf-ray", + "value": "7d72e6f5c84508c0-EZE" + } + ], + "headersSize": 2134, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2023-06-14T13:25:56.538Z", + "time": 499, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 499 + } + }, + { + "_id": "e2531ffc5077c92b79f5a5ddb3a96d4d", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 0, + "cookies": [], + "headers": [ + { + "_fromType": "array", + "name": "private-token", + "value": "[REDACTED]" + }, + { + "_fromType": "array", + "name": "accept", + "value": "*/*" + }, + { + "_fromType": "array", + "name": "user-agent", + "value": "node-fetch/1.0 (+https://github.com/bitinn/node-fetch)" + }, + { + "_fromType": "array", + "name": "accept-encoding", + "value": "gzip,deflate" + }, + { + "_fromType": "array", + "name": "connection", + "value": "close" + }, + { + "name": "host", + "value": "gitlab.com" + } + ], + "headersSize": 329, + "httpVersion": "HTTP/1.1", + "method": "GET", + "queryString": [ + { + "name": "severity", + "value": "medium,high,critical" + }, + { + "name": "page", + "value": "1" + }, + { + "name": "per_page", + "value": "100" + } + ], + "url": "https://gitlab.com/api/v4/projects/46792443/vulnerability_findings?severity=medium%2Chigh%2Ccritical&page=1&per_page=100" + }, + "response": { + "bodySize": 3451, + "content": { + "mimeType": "application/json", + "size": 3451, + "text": "[{\"id\":6502691148,\"report_type\":\"dast\",\"name\":\"CSP: Wildcard Directive\",\"severity\":\"medium\",\"confidence\":\"unknown\",\"scanner\":{\"external_id\":\"zaproxy\",\"name\":\"OWASP Zed Attack Proxy (ZAP)\",\"vendor\":\"GitLab\"},\"identifiers\":[{\"external_type\":\"ZAProxy_PluginId\",\"external_id\":\"10055\",\"name\":\"CSP: Wildcard Directive\",\"url\":\"https://github.com/zaproxy/zaproxy/blob/w2019-01-14/docs/scanners.md\"},{\"external_type\":\"CWE\",\"external_id\":\"693\",\"name\":\"CWE-693\",\"url\":\"https://cwe.mitre.org/data/definitions/693.html\"}],\"project_fingerprint\":\"da39a3ee5e6b4b0d3255bfef95601890afd80709\",\"uuid\":\"28f712b1-261c-5555-a622-84d90134fb4f\",\"create_jira_issue_url\":null,\"false_positive\":false,\"create_vulnerability_feedback_issue_path\":\"/jupiterone-dev/gaston-vulnerabilities-test/-/vulnerability_feedback\",\"create_vulnerability_feedback_merge_request_path\":\"/jupiterone-dev/gaston-vulnerabilities-test/-/vulnerability_feedback\",\"create_vulnerability_feedback_dismissal_path\":\"/jupiterone-dev/gaston-vulnerabilities-test/-/vulnerability_feedback\",\"project\":{\"id\":46792443,\"name\":\"Gaston Vulnerabilities Test\",\"full_path\":\"/jupiterone-dev/gaston-vulnerabilities-test\",\"full_name\":\"JupiterOne Development / Gaston Vulnerabilities Test\",\"refs_url\":\"/jupiterone-dev/gaston-vulnerabilities-test/refs\"},\"dismissal_feedback\":null,\"issue_feedback\":null,\"merge_request_feedback\":null,\"state_transitions\":[],\"issue_links\":[],\"merge_request_links\":[],\"description\":\"Content Security Policy (CSP) is an added layer of security that helps to detect and mitigate certain types of attacks. Including (but not limited to) Cross Site Scripting (XSS), and data injection attacks. These attacks are used for everything from data theft to site defacement or distribution of malware. CSP provides a set of standard HTTP headers that allow website owners to declare approved sources of content that browsers should be allowed to load on that page — covered types are JavaScript, CSS, HTML frames, fonts, images and embeddable objects such as Java applets, ActiveX, audio and video files.\",\"description_html\":\"\\u003cp data-sourcepos=\\\"1:1-1:612\\\" dir=\\\"auto\\\"\\u003eContent Security Policy (CSP) is an added layer of security that helps to detect and mitigate certain types of attacks. Including (but not limited to) Cross Site Scripting (XSS), and data injection attacks. These attacks are used for everything from data theft to site defacement or distribution of malware. CSP provides a set of standard HTTP headers that allow website owners to declare approved sources of content that browsers should be allowed to load on that page — covered types are JavaScript, CSS, HTML frames, fonts, images and embeddable objects such as Java applets, ActiveX, audio and video files.\\u003c/p\\u003e\",\"links\":[{\"url\":\"http://www.w3.org/TR/CSP2/\"},{\"url\":\"http://www.w3.org/TR/CSP/\"},{\"url\":\"http://caniuse.com/#search=content+security+policy\"},{\"url\":\"http://content-security-policy.com/\"},{\"url\":\"https://github.com/shapesecurity/salvation\"},{\"url\":\"https://developers.google.com/web/fundamentals/security/csp#policy_applies_to_a_wide_variety_of_resources\"}],\"location\":{\"path\":\"\",\"param\":\"\",\"method\":\"\",\"hostname\":\"https://j1-gc-integration-dev-v3.uc.r.appspot.com\"},\"remediations\":[],\"solution\":\"Ensure that your web server, application server, load balancer, etc. is properly configured to set the Content-Security-Policy header.\",\"evidence\":\"default-src 'none'; The following directives either allow wildcard sources (or ancestors), are not defined, or are overly broadly defined: frame-ancestors, form-action The directive(s): frame-ancestors, form-action are among the directives that do not fallback to default-src, missing/excluding them is the same as allowing anything.\",\"request\":{\"headers\":[{\"name\":\"Cache-Control\",\"value\":\"no-cache\"},{\"name\":\"Host\",\"value\":\"j1-gc-integration-dev-v3.uc.r.appspot.com\"},{\"name\":\"Pragma\",\"value\":\"no-cache\"},{\"name\":\"User-Agent\",\"value\":\"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:105.0) Gecko/20100101 Firefox/105.0\"}],\"method\":\"GET\",\"url\":\"https://j1-gc-integration-dev-v3.uc.r.appspot.com/robots.txt\",\"body\":null},\"response\":{\"headers\":[{\"name\":\"Content-Length\",\"value\":\"149\"},{\"name\":\"Content-Security-Policy\",\"value\":\"default-src 'none'\"},{\"name\":\"Content-Type\",\"value\":\"text/html; charset=utf-8\"},{\"name\":\"Date\",\"value\":\"Mon, 12 Jun 2023 15:28:08 GMT\"},{\"name\":\"Server\",\"value\":\"Google Frontend\"},{\"name\":\"Vary\",\"value\":\"Accept-Encoding\"},{\"name\":\"X-Cloud-Trace-Context\",\"value\":\"4b076be4f415003b38f503f19c2237fe\"},{\"name\":\"X-Content-Type-Options\",\"value\":\"nosniff\"},{\"name\":\"X-Powered-By\",\"value\":\"Express\"}],\"reason_phrase\":\"Not Found\",\"status_code\":404,\"body\":null},\"evidence_source\":null,\"supporting_messages\":null,\"assets\":[],\"details\":{\"urls\":{\"name\":\"URLs\",\"type\":\"list\",\"items\":[{\"href\":\"https://j1-gc-integration-dev-v3.uc.r.appspot.com/robots.txt\",\"type\":\"url\"},{\"href\":\"https://j1-gc-integration-dev-v3.uc.r.appspot.com/sitemap.xml\",\"type\":\"url\"}]},\"discovered_at\":{\"name\":\"Discovered at\",\"type\":\"text\",\"value\":\"2023-06-12T15:28:08.239\"}},\"state\":\"detected\",\"scan\":{\"id\":58683244,\"created_at\":\"2023-06-12T15:27:14.059Z\",\"updated_at\":\"2023-06-12T15:28:19.897Z\",\"build_id\":4457936975,\"scan_type\":\"dast\",\"info\":{},\"project_id\":46792443,\"pipeline_id\":897303534,\"latest\":true,\"status\":\"succeeded\",\"findings_partition_number\":64},\"blob_path\":\"\"},{\"id\":6502691149,\"report_type\":\"dast\",\"name\":\"Content Security Policy (CSP) Header Not Set\",\"severity\":\"medium\",\"confidence\":\"unknown\",\"scanner\":{\"external_id\":\"zaproxy\",\"name\":\"OWASP Zed Attack Proxy (ZAP)\",\"vendor\":\"GitLab\"},\"identifiers\":[{\"external_type\":\"ZAProxy_PluginId\",\"external_id\":\"10038\",\"name\":\"Content Security Policy (CSP) Header Not Set\",\"url\":\"https://github.com/zaproxy/zaproxy/blob/w2019-01-14/docs/scanners.md\"},{\"external_type\":\"CWE\",\"external_id\":\"693\",\"name\":\"CWE-693\",\"url\":\"https://cwe.mitre.org/data/definitions/693.html\"}],\"project_fingerprint\":\"da39a3ee5e6b4b0d3255bfef95601890afd80709\",\"uuid\":\"502b3dde-88b5-59ad-8c16-6aae5491f22a\",\"create_jira_issue_url\":null,\"false_positive\":false,\"create_vulnerability_feedback_issue_path\":\"/jupiterone-dev/gaston-vulnerabilities-test/-/vulnerability_feedback\",\"create_vulnerability_feedback_merge_request_path\":\"/jupiterone-dev/gaston-vulnerabilities-test/-/vulnerability_feedback\",\"create_vulnerability_feedback_dismissal_path\":\"/jupiterone-dev/gaston-vulnerabilities-test/-/vulnerability_feedback\",\"project\":{\"id\":46792443,\"name\":\"Gaston Vulnerabilities Test\",\"full_path\":\"/jupiterone-dev/gaston-vulnerabilities-test\",\"full_name\":\"JupiterOne Development / Gaston Vulnerabilities Test\",\"refs_url\":\"/jupiterone-dev/gaston-vulnerabilities-test/refs\"},\"dismissal_feedback\":null,\"issue_feedback\":null,\"merge_request_feedback\":null,\"state_transitions\":[],\"issue_links\":[],\"merge_request_links\":[],\"description\":\"Content Security Policy (CSP) is an added layer of security that helps to detect and mitigate certain types of attacks, including Cross Site Scripting (XSS) and data injection attacks. These attacks are used for everything from data theft to site defacement or distribution of malware. CSP provides a set of standard HTTP headers that allow website owners to declare approved sources of content that browsers should be allowed to load on that page — covered types are JavaScript, CSS, HTML frames, fonts, images and embeddable objects such as Java applets, ActiveX, audio and video files.\",\"description_html\":\"\\u003cp data-sourcepos=\\\"1:1-1:590\\\" dir=\\\"auto\\\"\\u003eContent Security Policy (CSP) is an added layer of security that helps to detect and mitigate certain types of attacks, including Cross Site Scripting (XSS) and data injection attacks. These attacks are used for everything from data theft to site defacement or distribution of malware. CSP provides a set of standard HTTP headers that allow website owners to declare approved sources of content that browsers should be allowed to load on that page — covered types are JavaScript, CSS, HTML frames, fonts, images and embeddable objects such as Java applets, ActiveX, audio and video files.\\u003c/p\\u003e\",\"links\":[{\"url\":\"https://developer.mozilla.org/en-US/docs/Web/Security/CSP/Introducing_Content_Security_Policy\"},{\"url\":\"https://cheatsheetseries.owasp.org/cheatsheets/Content_Security_Policy_Cheat_Sheet.html\"},{\"url\":\"http://www.w3.org/TR/CSP/\"},{\"url\":\"http://w3c.github.io/webappsec/specs/content-security-policy/csp-specification.dev.html\"},{\"url\":\"http://www.html5rocks.com/en/tutorials/security/content-security-policy/\"},{\"url\":\"http://caniuse.com/#feat=contentsecuritypolicy\"},{\"url\":\"http://content-security-policy.com/\"}],\"location\":{\"path\":\"\",\"param\":\"\",\"method\":\"\",\"hostname\":\"https://j1-gc-integration-dev-v3.uc.r.appspot.com\"},\"remediations\":[],\"solution\":\"Ensure that your web server, application server, load balancer, etc. is configured to set the Content-Security-Policy header, to achieve optimal browser support: \\\"Content-Security-Policy\\\" for Chrome 25+, Firefox 23+ and Safari 7+, \\\"X-Content-Security-Policy\\\" for Firefox 4.0+ and Internet Explorer 10+, and \\\"X-WebKit-CSP\\\" for Chrome 14+ and Safari 6+.\",\"evidence\":\"\",\"request\":{\"headers\":[{\"name\":\"Cache-Control\",\"value\":\"no-cache\"},{\"name\":\"Host\",\"value\":\"j1-gc-integration-dev-v3.uc.r.appspot.com\"},{\"name\":\"Pragma\",\"value\":\"no-cache\"},{\"name\":\"User-Agent\",\"value\":\"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:105.0) Gecko/20100101 Firefox/105.0\"}],\"method\":\"GET\",\"url\":\"https://j1-gc-integration-dev-v3.uc.r.appspot.com\",\"body\":null},\"response\":{\"headers\":[{\"name\":\"Content-Length\",\"value\":\"13\"},{\"name\":\"Content-Type\",\"value\":\"text/html; charset=utf-8\"},{\"name\":\"Date\",\"value\":\"Mon, 12 Jun 2023 15:28:08 GMT\"},{\"name\":\"ETag\",\"value\":\"W/\\\"d-lDpwLQbzRZmu4fjajvn3KWAx1pk\\\"\"},{\"name\":\"Server\",\"value\":\"Google Frontend\"},{\"name\":\"X-Cloud-Trace-Context\",\"value\":\"284b480c1b34906c02dc8dfa7ba08599\"},{\"name\":\"X-Powered-By\",\"value\":\"Express\"}],\"reason_phrase\":\"OK\",\"status_code\":200,\"body\":null},\"evidence_source\":null,\"supporting_messages\":null,\"assets\":[],\"details\":{\"urls\":{\"name\":\"URLs\",\"type\":\"list\",\"items\":[{\"href\":\"https://j1-gc-integration-dev-v3.uc.r.appspot.com\",\"type\":\"url\"},{\"href\":\"https://j1-gc-integration-dev-v3.uc.r.appspot.com/\",\"type\":\"url\"}]},\"discovered_at\":{\"name\":\"Discovered at\",\"type\":\"text\",\"value\":\"2023-06-12T15:28:08.317\"}},\"state\":\"detected\",\"scan\":{\"id\":58683244,\"created_at\":\"2023-06-12T15:27:14.059Z\",\"updated_at\":\"2023-06-12T15:28:19.897Z\",\"build_id\":4457936975,\"scan_type\":\"dast\",\"info\":{},\"project_id\":46792443,\"pipeline_id\":897303534,\"latest\":true,\"status\":\"succeeded\",\"findings_partition_number\":64},\"blob_path\":\"\"}]" + }, + "cookies": [ + { + "domain": ".gitlab.com", + "httpOnly": true, + "name": "_cfuvid", + "path": "/", + "sameSite": "None", + "secure": true, + "value": "[REDACTED]" + } + ], + "headers": [ + { + "name": "date", + "value": "Wed, 14 Jun 2023 13:25:57 GMT" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "connection", + "value": "close" + }, + { + "name": "cache-control", + "value": "max-age=0, private, must-revalidate" + }, + { + "name": "content-security-policy", + "value": "default-src 'none'" + }, + { + "name": "etag", + "value": "W/\"ee8e6ed0998b4da94eee90667ef520c6\"" + }, + { + "name": "link", + "value": "; rel=\"first\", ; rel=\"last\"" + }, + { + "name": "vary", + "value": "Origin, Accept-Encoding" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-gitlab-meta", + "value": "{\"correlation_id\":\"44c39d059de6b8a7727810d6c93dca09\",\"version\":\"1\"}" + }, + { + "name": "x-next-page", + "value": "" + }, + { + "name": "x-page", + "value": "1" + }, + { + "name": "x-per-page", + "value": "100" + }, + { + "name": "x-prev-page", + "value": "" + }, + { + "name": "x-request-id", + "value": "44c39d059de6b8a7727810d6c93dca09" + }, + { + "name": "x-runtime", + "value": "0.264318" + }, + { + "name": "x-total", + "value": "2" + }, + { + "name": "x-total-pages", + "value": "1" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000" + }, + { + "name": "referrer-policy", + "value": "strict-origin-when-cross-origin" + }, + { + "name": "ratelimit-observed", + "value": "3" + }, + { + "name": "ratelimit-remaining", + "value": "1997" + }, + { + "name": "ratelimit-reset", + "value": "1686749217" + }, + { + "name": "ratelimit-resettime", + "value": "Wed, 14 Jun 2023 13:26:57 GMT" + }, + { + "name": "ratelimit-limit", + "value": "2000" + }, + { + "name": "gitlab-lb", + "value": "fe-30-lb-gprd" + }, + { + "name": "gitlab-sv", + "value": "localhost" + }, + { + "name": "cf-cache-status", + "value": "MISS" + }, + { + "name": "report-to", + "value": "{\"endpoints\":[{\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v3?s=ITnY90Z%2Buwd7Q%2BHuUzeauR%2B%2FNxq2JYtNg4CRpDfIk%2FY1Lxg4S2P5%2BAwVFPNvlWu0%2BFW6bAytL8VE9D5np%2FHDNo1wxecDSdfr3oDCKdfCaJ1I%2Fj%2B9a3GkADp5nKw%3D\"}],\"group\":\"cf-nel\",\"max_age\":604800}" + }, + { + "name": "nel", + "value": "{\"success_fraction\":0.01,\"report_to\":\"cf-nel\",\"max_age\":604800}" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "[REDACTED]" + }, + { + "name": "server", + "value": "cloudflare" + }, + { + "name": "cf-ray", + "value": "7d72e6f919071870-EZE" + } + ], + "headersSize": 2794, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2023-06-14T13:25:57.042Z", + "time": 589, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 589 + } + }, + { + "_id": "ec3d22db6e5dab128bde6e9c1bf00341", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 0, + "cookies": [], + "headers": [ + { + "_fromType": "array", + "name": "private-token", + "value": "[REDACTED]" + }, + { + "_fromType": "array", + "name": "accept", + "value": "*/*" + }, + { + "_fromType": "array", + "name": "user-agent", + "value": "node-fetch/1.0 (+https://github.com/bitinn/node-fetch)" + }, + { + "_fromType": "array", + "name": "accept-encoding", + "value": "gzip,deflate" + }, + { + "_fromType": "array", + "name": "connection", + "value": "close" + }, + { + "name": "host", + "value": "gitlab.com" + } + ], + "headersSize": 329, + "httpVersion": "HTTP/1.1", + "method": "GET", + "queryString": [ + { + "name": "severity", + "value": "medium,high,critical" + }, + { + "name": "page", + "value": "1" + }, + { + "name": "per_page", + "value": "100" + } + ], + "url": "https://gitlab.com/api/v4/projects/25725992/vulnerability_findings?severity=medium%2Chigh%2Ccritical&page=1&per_page=100" + }, + "response": { + "bodySize": 2, + "content": { + "mimeType": "application/json", + "size": 2, + "text": "[]" + }, + "cookies": [ + { + "domain": ".gitlab.com", + "httpOnly": true, + "name": "_cfuvid", + "path": "/", + "sameSite": "None", + "secure": true, + "value": "[REDACTED]" + } + ], + "headers": [ + { + "name": "date", + "value": "Wed, 14 Jun 2023 13:25:58 GMT" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "content-length", + "value": "2" + }, + { + "name": "connection", + "value": "close" + }, + { + "name": "cache-control", + "value": "max-age=0, private, must-revalidate" + }, + { + "name": "content-security-policy", + "value": "default-src 'none'" + }, + { + "name": "etag", + "value": "W/\"4f53cda18c2baa0c0354bb5f9a3ecbe5\"" + }, + { + "name": "link", + "value": "; rel=\"first\", ; rel=\"last\"" + }, + { + "name": "vary", + "value": "Origin, Accept-Encoding" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-gitlab-meta", + "value": "{\"correlation_id\":\"f00d0d690c7ddf53c7b94b33595e5c1a\",\"version\":\"1\"}" + }, + { + "name": "x-next-page", + "value": "" + }, + { + "name": "x-page", + "value": "1" + }, + { + "name": "x-per-page", + "value": "100" + }, + { + "name": "x-prev-page", + "value": "" + }, + { + "name": "x-request-id", + "value": "f00d0d690c7ddf53c7b94b33595e5c1a" + }, + { + "name": "x-runtime", + "value": "0.164662" + }, + { + "name": "x-total", + "value": "0" + }, + { + "name": "x-total-pages", + "value": "1" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000" + }, + { + "name": "referrer-policy", + "value": "strict-origin-when-cross-origin" + }, + { + "name": "ratelimit-observed", + "value": "2" + }, + { + "name": "ratelimit-remaining", + "value": "1998" + }, + { + "name": "ratelimit-reset", + "value": "1686749218" + }, + { + "name": "ratelimit-resettime", + "value": "Wed, 14 Jun 2023 13:26:58 GMT" + }, + { + "name": "ratelimit-limit", + "value": "2000" + }, + { + "name": "gitlab-lb", + "value": "fe-20-lb-gprd" + }, + { + "name": "gitlab-sv", + "value": "localhost" + }, + { + "name": "cf-cache-status", + "value": "MISS" + }, + { + "name": "accept-ranges", + "value": "bytes" + }, + { + "name": "report-to", + "value": "{\"endpoints\":[{\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v3?s=6l1UT6q091%2FSOtkzB97U15HWjhMh4Pmnng1d49H1jV6s6NCWlfMKcwKo7yyZIP7fC2OPGpUWPta%2Bqrmp8BqG7bx6oEY8CQV5XzM%2B3cfCQjrXLDW%2FpnlymScoPfg%3D\"}],\"group\":\"cf-nel\",\"max_age\":604800}" + }, + { + "name": "nel", + "value": "{\"success_fraction\":0.01,\"report_to\":\"cf-nel\",\"max_age\":604800}" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "[REDACTED]" + }, + { + "name": "server", + "value": "cloudflare" + }, + { + "name": "cf-ray", + "value": "7d72e6fc997208d9-EZE" + } + ], + "headersSize": 2771, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2023-06-14T13:25:57.644Z", + "time": 473, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 473 + } + }, + { + "_id": "f566d199bab2eb578ece60ff96471434", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 0, + "cookies": [], + "headers": [ + { + "_fromType": "array", + "name": "private-token", + "value": "[REDACTED]" + }, + { + "_fromType": "array", + "name": "accept", + "value": "*/*" + }, + { + "_fromType": "array", + "name": "user-agent", + "value": "node-fetch/1.0 (+https://github.com/bitinn/node-fetch)" + }, + { + "_fromType": "array", + "name": "accept-encoding", + "value": "gzip,deflate" + }, + { + "_fromType": "array", + "name": "connection", + "value": "close" + }, + { + "name": "host", + "value": "gitlab.com" + } + ], + "headersSize": 329, + "httpVersion": "HTTP/1.1", + "method": "GET", + "queryString": [ + { + "name": "severity", + "value": "medium,high,critical" + }, + { + "name": "page", + "value": "1" + }, + { + "name": "per_page", + "value": "100" + } + ], + "url": "https://gitlab.com/api/v4/projects/25725991/vulnerability_findings?severity=medium%2Chigh%2Ccritical&page=1&per_page=100" + }, + "response": { + "bodySize": 2, + "content": { + "mimeType": "application/json", + "size": 2, + "text": "[]" + }, + "cookies": [ + { + "domain": ".gitlab.com", + "httpOnly": true, + "name": "_cfuvid", + "path": "/", + "sameSite": "None", + "secure": true, + "value": "[REDACTED]" + } + ], + "headers": [ + { + "name": "date", + "value": "Wed, 14 Jun 2023 13:25:58 GMT" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "content-length", + "value": "2" + }, + { + "name": "connection", + "value": "close" + }, + { + "name": "cache-control", + "value": "max-age=0, private, must-revalidate" + }, + { + "name": "content-security-policy", + "value": "default-src 'none'" + }, + { + "name": "etag", + "value": "W/\"4f53cda18c2baa0c0354bb5f9a3ecbe5\"" + }, + { + "name": "link", + "value": "; rel=\"first\", ; rel=\"last\"" + }, + { + "name": "vary", + "value": "Origin, Accept-Encoding" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-gitlab-meta", + "value": "{\"correlation_id\":\"0b22f4cfc741d591c90df8c05513813b\",\"version\":\"1\"}" + }, + { + "name": "x-next-page", + "value": "" + }, + { + "name": "x-page", + "value": "1" + }, + { + "name": "x-per-page", + "value": "100" + }, + { + "name": "x-prev-page", + "value": "" + }, + { + "name": "x-request-id", + "value": "0b22f4cfc741d591c90df8c05513813b" + }, + { + "name": "x-runtime", + "value": "0.199489" + }, + { + "name": "x-total", + "value": "0" + }, + { + "name": "x-total-pages", + "value": "1" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000" + }, + { + "name": "referrer-policy", + "value": "strict-origin-when-cross-origin" + }, + { + "name": "ratelimit-observed", + "value": "3" + }, + { + "name": "ratelimit-remaining", + "value": "1997" + }, + { + "name": "ratelimit-reset", + "value": "1686749218" + }, + { + "name": "ratelimit-resettime", + "value": "Wed, 14 Jun 2023 13:26:58 GMT" + }, + { + "name": "ratelimit-limit", + "value": "2000" + }, + { + "name": "gitlab-lb", + "value": "fe-09-lb-gprd" + }, + { + "name": "gitlab-sv", + "value": "localhost" + }, + { + "name": "cf-cache-status", + "value": "MISS" + }, + { + "name": "accept-ranges", + "value": "bytes" + }, + { + "name": "report-to", + "value": "{\"endpoints\":[{\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v3?s=StFh4zJUEMLtsmUceu3SWgZjUH6Yuu4p63clsR%2BRB8pJeD60z3N5LKUFGYtbI4TzOgFwZRsfjQNUTK6R5c2jVcKG%2FSQtI6uXI8EUEFzOEA0xoYarkT9K4ZtqPQo%3D\"}],\"group\":\"cf-nel\",\"max_age\":604800}" + }, + { + "name": "nel", + "value": "{\"success_fraction\":0.01,\"report_to\":\"cf-nel\",\"max_age\":604800}" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "[REDACTED]" + }, + { + "name": "server", + "value": "cloudflare" + }, + { + "name": "cf-ray", + "value": "7d72e6ffb81108e9-EZE" + } + ], + "headersSize": 2767, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2023-06-14T13:25:58.123Z", + "time": 513, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 513 + } + } + ], + "pages": [], + "version": "1.2" + } +} diff --git a/src/steps/findings.test.ts b/src/steps/findings.test.ts new file mode 100644 index 0000000..f560457 --- /dev/null +++ b/src/steps/findings.test.ts @@ -0,0 +1,28 @@ +import { + executeStepWithDependencies, + Recording, +} from '@jupiterone/integration-sdk-testing'; + +import { Steps } from '../constants'; +import { getStepTestConfigForStep, setupRecording } from '../../test'; + +describe(Steps.FINDINGS, () => { + let recording: Recording; + afterEach(async () => { + if (recording) await recording.stop(); + }); + + jest.setTimeout(45000); + + test(Steps.FINDINGS, async () => { + recording = setupRecording({ + name: Steps.FINDINGS, + directory: __dirname, + }); + + const stepTestConfig = getStepTestConfigForStep(Steps.FINDINGS); + + const result = await executeStepWithDependencies(stepTestConfig); + expect(result).toMatchStepMetadata(stepTestConfig); + }); +}); diff --git a/src/steps/findings.ts b/src/steps/findings.ts new file mode 100644 index 0000000..a910f4b --- /dev/null +++ b/src/steps/findings.ts @@ -0,0 +1,57 @@ +import { + IntegrationStep, + IntegrationStepExecutionContext, + RelationshipClass, + createDirectRelationship, + getRawData, +} from '@jupiterone/integration-sdk-core'; + +import { Entities, Relationships, Steps } from '../constants'; +import { createGitlabClient } from '../provider'; +import { GitlabIntegrationConfig } from '../types'; +import { GitLabProject } from '../provider/types'; +import { createVulnerabilityFindingEntity } from '../converters'; + +export async function fetchVulnerabilityFindings({ + instance, + jobState, + logger, +}: IntegrationStepExecutionContext) { + const client = createGitlabClient(instance.config, logger); + + await jobState.iterateEntities( + { _type: Entities.PROJECT._type }, + async (projectEntity) => { + const project = getRawData(projectEntity) as GitLabProject; + + await client.iterateProjectVulnerabilities( + project.id, + async (finding) => { + const findingEntity = createVulnerabilityFindingEntity(finding); + + await Promise.all([ + jobState.addEntity(findingEntity), + jobState.addRelationship( + createDirectRelationship({ + _class: RelationshipClass.HAS, + from: projectEntity, + to: findingEntity, + }), + ), + ]); + }, + ); + }, + ); +} + +export const findingSteps: IntegrationStep[] = [ + { + id: Steps.FINDINGS, + name: 'Fetch Vulnerability Findings', + entities: [Entities.FINDING], + relationships: [Relationships.PROJECT_HAS_FINDING], + dependsOn: [Steps.PROJECTS], + executionHandler: fetchVulnerabilityFindings, + }, +]; diff --git a/src/steps/index.ts b/src/steps/index.ts index ae17077..6baf458 100644 --- a/src/steps/index.ts +++ b/src/steps/index.ts @@ -17,6 +17,7 @@ import { mergeRequestSteps } from './merge-requests'; import { projectSteps } from './projects'; import { userSteps } from './users'; import { commitSteps } from './commits'; +import { findingSteps } from './findings'; const integrationSteps: Step< IntegrationStepExecutionContext @@ -25,6 +26,7 @@ const integrationSteps: Step< groupStep, ...projectSteps, ...userSteps, + ...findingSteps, projectUserStep, accountGroupStep, accountProjectStep, diff --git a/test/recording.ts b/test/recording.ts index caf9c42..2c80952 100644 --- a/test/recording.ts +++ b/test/recording.ts @@ -2,11 +2,18 @@ import { mutations, Recording, setupRecording as sdkSetupRecording, + StepTestConfig, } from '@jupiterone/integration-sdk-testing'; +import { invocationConfig } from '../src'; export { Recording } from '@jupiterone/integration-sdk-testing'; type SetupParameters = Parameters[0]; +const configFromEnv = { + baseUrl: process.env.BASE_URL || 'https://gitlab.com', + personalToken: process.env.PERSONAL_TOKEN || 'string-value', +}; + /** * This function is a wrapper around the SDK's setup recording function * that redacts the 'private-token' header. @@ -24,3 +31,13 @@ export function setupRecording({ ...overrides, }); } + +export function getStepTestConfigForStep(stepId: string): StepTestConfig { + return { + stepId, + instanceConfig: configFromEnv, + invocationConfig: { + ...invocationConfig, + } as any, + }; +}