Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
004274926a
commit
a551969356
57 changed files with 7497 additions and 576 deletions
|
@ -316,7 +316,6 @@ Style/StringConcatenation:
|
|||
- 'spec/services/verify_pages_domain_service_spec.rb'
|
||||
- 'spec/support/capybara.rb'
|
||||
- 'spec/support/helpers/ci_artifact_metadata_generator.rb'
|
||||
- 'spec/support/helpers/git_helpers.rb'
|
||||
- 'spec/support/helpers/gitaly_setup.rb'
|
||||
- 'spec/support/helpers/javascript_fixtures_helpers.rb'
|
||||
- 'spec/support/helpers/kubernetes_helpers.rb'
|
||||
|
|
2
Gemfile
2
Gemfile
|
@ -338,7 +338,7 @@ gem 'pg_query', '~> 2.1.4'
|
|||
gem 'premailer-rails', '~> 1.10.3'
|
||||
|
||||
# LabKit: Tracing and Correlation
|
||||
gem 'gitlab-labkit', '~> 0.27.0'
|
||||
gem 'gitlab-labkit', '~> 0.28.0'
|
||||
gem 'thrift', '>= 0.16.0'
|
||||
|
||||
# I18n
|
||||
|
|
|
@ -205,7 +205,7 @@
|
|||
{"name":"gitlab-dangerfiles","version":"3.6.1","platform":"ruby","checksum":"f7b69b093d52acb89095d411cb7b8849f5f3b9e76f8baa4c99b5671f1564865f"},
|
||||
{"name":"gitlab-experiment","version":"0.7.1","platform":"ruby","checksum":"166dddb3aa83428bcaa93c35684ed01dc4d61f321fd2ae40b020806dc54a7824"},
|
||||
{"name":"gitlab-fog-azure-rm","version":"1.3.0","platform":"ruby","checksum":"2fef5317d6515f95f803099afa860fe3019ce6e1907bf49f66b5e06468a617b5"},
|
||||
{"name":"gitlab-labkit","version":"0.27.0","platform":"ruby","checksum":"3f30877bc7c07dedc17f1061324c2e123f25c1576d9a892edb85678c9782c75a"},
|
||||
{"name":"gitlab-labkit","version":"0.28.0","platform":"ruby","checksum":"a7ebf52336566f7607d280056acd64f390c9991f152fc3d6b1dd966a372d5654"},
|
||||
{"name":"gitlab-license","version":"2.2.1","platform":"ruby","checksum":"39fcf6be8b2887df8afe01b5dcbae8d08b7c5d937ff56b0fb40484a8c4f02d30"},
|
||||
{"name":"gitlab-mail_room","version":"0.0.9","platform":"ruby","checksum":"6700374b5c0aa9d9ad4e711aeb677f0b7d415a6d01d3baa699efab25349d851c"},
|
||||
{"name":"gitlab-markup","version":"1.8.1","platform":"ruby","checksum":"ab1f9fd016977497c2af25b76341dea670533014f406861834a0bd99f646707b"},
|
||||
|
|
|
@ -569,7 +569,7 @@ GEM
|
|||
fog-json (~> 1.2.0)
|
||||
mime-types
|
||||
ms_rest_azure (~> 0.12.0)
|
||||
gitlab-labkit (0.27.0)
|
||||
gitlab-labkit (0.28.0)
|
||||
actionpack (>= 5.0.0, < 8.0.0)
|
||||
activesupport (>= 5.0.0, < 8.0.0)
|
||||
grpc (>= 1.37)
|
||||
|
@ -1631,7 +1631,7 @@ DEPENDENCIES
|
|||
gitlab-dangerfiles (~> 3.6.1)
|
||||
gitlab-experiment (~> 0.7.1)
|
||||
gitlab-fog-azure-rm (~> 1.3.0)
|
||||
gitlab-labkit (~> 0.27.0)
|
||||
gitlab-labkit (~> 0.28.0)
|
||||
gitlab-license (~> 2.2.1)
|
||||
gitlab-mail_room (~> 0.0.9)
|
||||
gitlab-markup (~> 1.8.0)
|
||||
|
|
|
@ -61,25 +61,13 @@ export default class IssuableBulkUpdateSidebar {
|
|||
// the import/no-unresolved lint rule when FOSS_ONLY=1, even though at
|
||||
// runtime this block won't execute.
|
||||
if (IS_EE) {
|
||||
import('ee_else_ce/vue_shared/components/sidebar/health_status_select/health_status_bundle')
|
||||
.then(({ default: HealthStatusSelect }) => {
|
||||
HealthStatusSelect();
|
||||
import('ee_else_ce/sidebar/mount_sidebar')
|
||||
.then(({ mountEpicDropdown, mountHealthStatusDropdown, mountIterationDropdown }) => {
|
||||
mountEpicDropdown();
|
||||
mountHealthStatusDropdown();
|
||||
mountIterationDropdown();
|
||||
})
|
||||
.catch(() => {});
|
||||
|
||||
import('ee_else_ce/vue_shared/components/sidebar/epics_select/epics_select_bundle')
|
||||
.then(({ default: EpicSelect }) => {
|
||||
EpicSelect();
|
||||
})
|
||||
.catch(() => {});
|
||||
|
||||
import('ee_else_ce/vue_shared/components/sidebar/iterations_dropdown_bundle')
|
||||
.then(({ default: iterationsDropdown }) => {
|
||||
iterationsDropdown();
|
||||
})
|
||||
.catch((e) => {
|
||||
throw e;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -947,12 +947,17 @@ export default {
|
|||
|
||||
<gl-empty-state
|
||||
v-else
|
||||
:description="$options.i18n.noIssuesSignedOutDescription"
|
||||
:title="$options.i18n.noIssuesSignedOutTitle"
|
||||
:svg-path="emptyStateSvgPath"
|
||||
:primary-button-text="$options.i18n.noIssuesSignedOutButtonText"
|
||||
:primary-button-link="signInPath"
|
||||
/>
|
||||
>
|
||||
<template #description>
|
||||
<gl-link :href="issuesHelpPagePath" target="_blank">{{
|
||||
$options.i18n.noIssuesSignedOutDescription
|
||||
}}</gl-link>
|
||||
</template>
|
||||
</gl-empty-state>
|
||||
|
||||
<issuable-by-email v-if="showIssuableByEmail" class="gl-text-center gl-pt-5 gl-pb-7" />
|
||||
</div>
|
||||
|
|
|
@ -46,10 +46,8 @@ export const i18n = {
|
|||
noIssuesSignedInDescription: __('Learn more about issues.'),
|
||||
noIssuesSignedInTitle: __('Use issues to collaborate on ideas, solve problems, and plan work'),
|
||||
noIssuesSignedOutButtonText: __('Register / Sign In'),
|
||||
noIssuesSignedOutDescription: __(
|
||||
'The Issue Tracker is the place to add things that need to be improved or solved in a project. You can register or sign in to create issues for this project.',
|
||||
),
|
||||
noIssuesSignedOutTitle: __('There are no issues to show'),
|
||||
noIssuesSignedOutDescription: __('Learn more about issues.'),
|
||||
noIssuesSignedOutTitle: __('Use issues to collaborate on ideas, solve problems, and plan work'),
|
||||
noSearchResultsDescription: __('To widen your search, change or remove filters above'),
|
||||
noSearchResultsTitle: __('Sorry, your filter produced no results'),
|
||||
relatedMergeRequests: __('Related merge requests'),
|
||||
|
|
|
@ -633,66 +633,6 @@ export const NavigationType = {
|
|||
TYPE_RESERVED: 255,
|
||||
};
|
||||
|
||||
/**
|
||||
* Method to perform case-insensitive search for a string
|
||||
* within multiple properties and return object containing
|
||||
* properties in case there are multiple matches or `null`
|
||||
* if there's no match.
|
||||
*
|
||||
* Eg; Suppose we want to allow user to search using for a string
|
||||
* within `iid`, `title`, `url` or `reference` props of a target object;
|
||||
*
|
||||
* const objectToSearch = {
|
||||
* "iid": 1,
|
||||
* "title": "Error omnis quos consequatur ullam a vitae sed omnis libero cupiditate. &3",
|
||||
* "url": "/groups/gitlab-org/-/epics/1",
|
||||
* "reference": "&1",
|
||||
* };
|
||||
*
|
||||
* Following is how we call searchBy and the return values it will yield;
|
||||
*
|
||||
* - `searchBy('omnis', objectToSearch);`: This will return `{ title: ... }` as our
|
||||
* query was found within title prop we only return that.
|
||||
* - `searchBy('1', objectToSearch);`: This will return `{ "iid": ..., "reference": ..., "url": ... }`.
|
||||
* - `searchBy('https://gitlab.com/groups/gitlab-org/-/epics/1', objectToSearch);`:
|
||||
* This will return `{ "url": ... }`.
|
||||
* - `searchBy('foo', objectToSearch);`: This will return `null` as no property value
|
||||
* matched with our query.
|
||||
*
|
||||
* You can learn more about behaviour of this method by referring to tests
|
||||
* within `spec/frontend/lib/utils/common_utils_spec.js`.
|
||||
*
|
||||
* @param {string} query String to search for
|
||||
* @param {object} searchSpace Object containing properties to search in for `query`
|
||||
*/
|
||||
export const searchBy = (query = '', searchSpace = {}) => {
|
||||
const targetKeys = searchSpace !== null ? Object.keys(searchSpace) : [];
|
||||
|
||||
if (!query || !targetKeys.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const normalizedQuery = query.toLowerCase();
|
||||
const matches = targetKeys
|
||||
.filter((item) => {
|
||||
const searchItem = `${searchSpace[item]}`.toLowerCase();
|
||||
|
||||
return (
|
||||
searchItem.indexOf(normalizedQuery) > -1 ||
|
||||
normalizedQuery.indexOf(searchItem) > -1 ||
|
||||
normalizedQuery === searchItem
|
||||
);
|
||||
})
|
||||
.reduce((acc, prop) => {
|
||||
const match = acc;
|
||||
match[prop] = searchSpace[prop];
|
||||
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
return Object.keys(matches).length ? matches : null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if the given Label has a special syntax `::` in
|
||||
* it's title.
|
||||
|
|
240
app/assets/javascripts/sidebar/components/sidebar_dropdown.vue
Normal file
240
app/assets/javascripts/sidebar/components/sidebar_dropdown.vue
Normal file
|
@ -0,0 +1,240 @@
|
|||
<script>
|
||||
import {
|
||||
GlDropdown,
|
||||
GlDropdownDivider,
|
||||
GlDropdownItem,
|
||||
GlDropdownText,
|
||||
GlLoadingIcon,
|
||||
GlSearchBoxByType,
|
||||
} from '@gitlab/ui';
|
||||
import { kebabCase, snakeCase } from 'lodash';
|
||||
import { IssuableType } from '~/issues/constants';
|
||||
import { __ } from '~/locale';
|
||||
import {
|
||||
defaultEpicSort,
|
||||
dropdowni18nText,
|
||||
epicIidPattern,
|
||||
issuableAttributesQueries,
|
||||
IssuableAttributeState,
|
||||
IssuableAttributeType,
|
||||
IssuableAttributeTypeKeyMap,
|
||||
LocalizedIssuableAttributeType,
|
||||
noAttributeId,
|
||||
} from 'ee_else_ce/sidebar/constants';
|
||||
import { createAlert } from '~/flash';
|
||||
import { PathIdSeparator } from '~/related_issues/constants';
|
||||
|
||||
export default {
|
||||
noAttributeId,
|
||||
i18n: {
|
||||
expired: __('(expired)'),
|
||||
},
|
||||
components: {
|
||||
GlDropdown,
|
||||
GlDropdownItem,
|
||||
GlDropdownText,
|
||||
GlDropdownDivider,
|
||||
GlSearchBoxByType,
|
||||
GlLoadingIcon,
|
||||
},
|
||||
inject: {
|
||||
issuableAttributesQueries: {
|
||||
default: issuableAttributesQueries,
|
||||
},
|
||||
issuableAttributesState: {
|
||||
default: IssuableAttributeState,
|
||||
},
|
||||
widgetTitleText: {
|
||||
default: {
|
||||
[IssuableAttributeType.Milestone]: __('Milestone'),
|
||||
expired: __('(expired)'),
|
||||
none: __('None'),
|
||||
},
|
||||
},
|
||||
},
|
||||
props: {
|
||||
attrWorkspacePath: {
|
||||
required: true,
|
||||
type: String,
|
||||
},
|
||||
currentAttribute: {
|
||||
type: Object,
|
||||
required: false,
|
||||
default: () => ({}),
|
||||
},
|
||||
issuableAttribute: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
issuableType: {
|
||||
type: String,
|
||||
required: true,
|
||||
validator(value) {
|
||||
return [IssuableType.Issue, IssuableType.MergeRequest].includes(value);
|
||||
},
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
attributesList: [],
|
||||
searchTerm: '',
|
||||
skipQuery: true,
|
||||
};
|
||||
},
|
||||
apollo: {
|
||||
attributesList: {
|
||||
query() {
|
||||
const { list } = this.issuableAttributeQuery;
|
||||
const { query } = list[this.issuableType];
|
||||
return query;
|
||||
},
|
||||
variables() {
|
||||
if (!this.isEpic) {
|
||||
return {
|
||||
fullPath: this.attrWorkspacePath,
|
||||
title: this.searchTerm,
|
||||
state: this.issuableAttributesState[this.issuableAttribute],
|
||||
};
|
||||
}
|
||||
|
||||
const variables = {
|
||||
fullPath: this.attrWorkspacePath,
|
||||
state: this.issuableAttributesState[this.issuableAttribute],
|
||||
sort: defaultEpicSort,
|
||||
};
|
||||
|
||||
if (epicIidPattern.test(this.searchTerm)) {
|
||||
const matches = this.searchTerm.match(epicIidPattern);
|
||||
variables.iidStartsWith = matches.groups.iid;
|
||||
} else if (this.searchTerm !== '') {
|
||||
variables.in = 'TITLE';
|
||||
variables.title = this.searchTerm;
|
||||
}
|
||||
|
||||
return variables;
|
||||
},
|
||||
update: (data) => data?.workspace?.attributes?.nodes ?? [],
|
||||
error(error) {
|
||||
createAlert({ message: this.i18n.listFetchError, captureError: true, error });
|
||||
},
|
||||
skip() {
|
||||
if (
|
||||
this.isEpic &&
|
||||
this.searchTerm.startsWith(PathIdSeparator.Epic) &&
|
||||
this.searchTerm.length < 2
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return this.skipQuery;
|
||||
},
|
||||
debounce: 250,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
attributeTypeTitle() {
|
||||
return this.widgetTitleText[this.issuableAttribute];
|
||||
},
|
||||
dropdownText() {
|
||||
return this.currentAttribute ? this.currentAttribute?.title : this.attributeTypeTitle;
|
||||
},
|
||||
emptyPropsList() {
|
||||
return this.attributesList.length === 0;
|
||||
},
|
||||
i18n() {
|
||||
const localizedAttribute =
|
||||
LocalizedIssuableAttributeType[IssuableAttributeTypeKeyMap[this.issuableAttribute]];
|
||||
return dropdowni18nText(localizedAttribute, this.issuableType);
|
||||
},
|
||||
isEpic() {
|
||||
// MV to EE https://gitlab.com/gitlab-org/gitlab/-/issues/345311
|
||||
return this.issuableAttribute === IssuableType.Epic;
|
||||
},
|
||||
issuableAttributeQuery() {
|
||||
return this.issuableAttributesQueries[this.issuableAttribute];
|
||||
},
|
||||
formatIssuableAttribute() {
|
||||
return {
|
||||
kebab: kebabCase(this.issuableAttribute),
|
||||
snake: snakeCase(this.issuableAttribute),
|
||||
};
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
isAttributeChecked(attributeId) {
|
||||
return (
|
||||
attributeId === this.currentAttribute?.id || (!this.currentAttribute?.id && !attributeId)
|
||||
);
|
||||
},
|
||||
isAttributeOverdue(attribute) {
|
||||
return this.issuableAttribute === IssuableAttributeType.Milestone
|
||||
? attribute?.expired
|
||||
: false;
|
||||
},
|
||||
handleShow() {
|
||||
this.skipQuery = false;
|
||||
},
|
||||
setFocus() {
|
||||
this.$refs.search.focusInput();
|
||||
},
|
||||
show() {
|
||||
this.$refs.dropdown.show();
|
||||
},
|
||||
updateAttribute(attribute) {
|
||||
this.$emit('change', attribute);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<gl-dropdown
|
||||
ref="dropdown"
|
||||
block
|
||||
:header-text="i18n.assignAttribute"
|
||||
lazy
|
||||
:text="dropdownText"
|
||||
@show="handleShow"
|
||||
@shown="setFocus"
|
||||
>
|
||||
<gl-search-box-by-type ref="search" v-model="searchTerm" :placeholder="__('Search')" />
|
||||
<gl-dropdown-item
|
||||
:data-testid="`no-${formatIssuableAttribute.kebab}-item`"
|
||||
is-check-item
|
||||
:is-checked="isAttributeChecked($options.noAttributeId)"
|
||||
@click="$emit('change', { id: $options.noAttributeId })"
|
||||
>
|
||||
{{ i18n.noAttribute }}
|
||||
</gl-dropdown-item>
|
||||
<gl-dropdown-divider />
|
||||
<gl-loading-icon
|
||||
v-if="$apollo.queries.attributesList.loading"
|
||||
size="sm"
|
||||
class="gl-py-4"
|
||||
data-testid="loading-icon-dropdown"
|
||||
/>
|
||||
<template v-else>
|
||||
<gl-dropdown-text v-if="emptyPropsList">
|
||||
{{ i18n.noAttributesFound }}
|
||||
</gl-dropdown-text>
|
||||
<slot
|
||||
v-else
|
||||
name="list"
|
||||
:attributes-list="attributesList"
|
||||
:is-attribute-checked="isAttributeChecked"
|
||||
:update-attribute="updateAttribute"
|
||||
>
|
||||
<gl-dropdown-item
|
||||
v-for="attrItem in attributesList"
|
||||
:key="attrItem.id"
|
||||
is-check-item
|
||||
:is-checked="isAttributeChecked(attrItem.id)"
|
||||
:data-testid="`${formatIssuableAttribute.kebab}-items`"
|
||||
@click="updateAttribute(attrItem)"
|
||||
>
|
||||
{{ attrItem.title }}
|
||||
<template v-if="isAttributeOverdue(attrItem)">{{ $options.i18n.expired }}</template>
|
||||
</gl-dropdown-item>
|
||||
</slot>
|
||||
</template>
|
||||
</gl-dropdown>
|
||||
</template>
|
|
@ -1,17 +1,5 @@
|
|||
<script>
|
||||
import {
|
||||
GlLink,
|
||||
GlDropdown,
|
||||
GlDropdownItem,
|
||||
GlDropdownText,
|
||||
GlSearchBoxByType,
|
||||
GlDropdownDivider,
|
||||
GlLoadingIcon,
|
||||
GlIcon,
|
||||
GlTooltipDirective,
|
||||
GlPopover,
|
||||
GlButton,
|
||||
} from '@gitlab/ui';
|
||||
import { GlButton, GlIcon, GlLink, GlPopover, GlTooltipDirective } from '@gitlab/ui';
|
||||
import { kebabCase, snakeCase } from 'lodash';
|
||||
import { createAlert } from '~/flash';
|
||||
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
|
||||
|
@ -22,19 +10,15 @@ import SidebarEditableItem from '~/sidebar/components/sidebar_editable_item.vue'
|
|||
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
import {
|
||||
dropdowni18nText,
|
||||
Tracking,
|
||||
IssuableAttributeState,
|
||||
IssuableAttributeType,
|
||||
LocalizedIssuableAttributeType,
|
||||
IssuableAttributeTypeKeyMap,
|
||||
issuableAttributesQueries,
|
||||
noAttributeId,
|
||||
defaultEpicSort,
|
||||
epicIidPattern,
|
||||
IssuableAttributeType,
|
||||
Tracking,
|
||||
} from 'ee_else_ce/sidebar/constants';
|
||||
import SidebarDropdown from './sidebar_dropdown.vue';
|
||||
|
||||
export default {
|
||||
noAttributeId,
|
||||
i18n: {
|
||||
expired: __('(expired)'),
|
||||
none: __('None'),
|
||||
|
@ -43,17 +27,12 @@ export default {
|
|||
GlTooltip: GlTooltipDirective,
|
||||
},
|
||||
components: {
|
||||
SidebarEditableItem,
|
||||
GlLink,
|
||||
GlDropdown,
|
||||
GlDropdownItem,
|
||||
GlDropdownText,
|
||||
GlDropdownDivider,
|
||||
GlSearchBoxByType,
|
||||
GlIcon,
|
||||
GlLoadingIcon,
|
||||
GlPopover,
|
||||
GlButton,
|
||||
SidebarDropdown,
|
||||
SidebarEditableItem,
|
||||
},
|
||||
mixins: [glFeatureFlagMixin()],
|
||||
inject: {
|
||||
|
@ -63,9 +42,6 @@ export default {
|
|||
issuableAttributesQueries: {
|
||||
default: issuableAttributesQueries,
|
||||
},
|
||||
issuableAttributesState: {
|
||||
default: IssuableAttributeState,
|
||||
},
|
||||
widgetTitleText: {
|
||||
default: {
|
||||
[IssuableAttributeType.Milestone]: __('Milestone'),
|
||||
|
@ -74,7 +50,6 @@ export default {
|
|||
},
|
||||
},
|
||||
},
|
||||
|
||||
props: {
|
||||
issuableAttribute: {
|
||||
type: String,
|
||||
|
@ -134,67 +109,14 @@ export default {
|
|||
});
|
||||
},
|
||||
},
|
||||
attributesList: {
|
||||
query() {
|
||||
const { list } = this.issuableAttributeQuery;
|
||||
const { query } = list[this.issuableType];
|
||||
|
||||
return query;
|
||||
},
|
||||
skip() {
|
||||
if (this.isEpic && this.searchTerm.startsWith('&') && this.searchTerm.length < 2) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return !this.editing;
|
||||
},
|
||||
debounce: 250,
|
||||
variables() {
|
||||
if (!this.isEpic) {
|
||||
return {
|
||||
fullPath: this.attrWorkspacePath,
|
||||
title: this.searchTerm,
|
||||
state: this.issuableAttributesState[this.issuableAttribute],
|
||||
};
|
||||
}
|
||||
|
||||
const variables = {
|
||||
fullPath: this.attrWorkspacePath,
|
||||
state: this.issuableAttributesState[this.issuableAttribute],
|
||||
sort: defaultEpicSort,
|
||||
};
|
||||
|
||||
if (epicIidPattern.test(this.searchTerm)) {
|
||||
const matches = this.searchTerm.match(epicIidPattern);
|
||||
variables.iidStartsWith = matches.groups.iid;
|
||||
} else if (this.searchTerm !== '') {
|
||||
variables.in = 'TITLE';
|
||||
variables.title = this.searchTerm;
|
||||
}
|
||||
|
||||
return variables;
|
||||
},
|
||||
update(data) {
|
||||
if (data?.workspace) {
|
||||
return data?.workspace?.attributes.nodes;
|
||||
}
|
||||
return [];
|
||||
},
|
||||
error(error) {
|
||||
createAlert({ message: this.i18n.listFetchError, captureError: true, error });
|
||||
},
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
searchTerm: '',
|
||||
editing: false,
|
||||
updating: false,
|
||||
selectedTitle: null,
|
||||
currentAttribute: null,
|
||||
hasCurrentAttribute: false,
|
||||
editConfirmation: false,
|
||||
attributesList: [],
|
||||
tracking: {
|
||||
event: Tracking.editEvent,
|
||||
label: Tracking.rightSidebarLabel,
|
||||
|
@ -212,15 +134,9 @@ export default {
|
|||
attributeUrl() {
|
||||
return this.currentAttribute?.webUrl;
|
||||
},
|
||||
dropdownText() {
|
||||
return this.currentAttribute ? this.currentAttribute?.title : this.attributeTypeTitle;
|
||||
},
|
||||
loading() {
|
||||
return this.$apollo.queries.currentAttribute.loading;
|
||||
},
|
||||
emptyPropsList() {
|
||||
return this.attributesList.length === 0;
|
||||
},
|
||||
attributeTypeTitle() {
|
||||
return this.widgetTitleText[this.issuableAttribute];
|
||||
},
|
||||
|
@ -256,16 +172,12 @@ export default {
|
|||
},
|
||||
},
|
||||
methods: {
|
||||
updateAttribute(attributeId) {
|
||||
if (this.currentAttribute === null && attributeId === null) return;
|
||||
if (attributeId === this.currentAttribute?.id) return;
|
||||
updateAttribute({ id }) {
|
||||
if (this.currentAttribute === null && id === null) return;
|
||||
if (id === this.currentAttribute?.id) return;
|
||||
|
||||
this.updating = true;
|
||||
|
||||
const selectedAttribute =
|
||||
Boolean(attributeId) && this.attributesList.find((p) => p.id === attributeId);
|
||||
this.selectedTitle = selectedAttribute ? selectedAttribute.title : this.widgetTitleText.none;
|
||||
|
||||
const { current } = this.issuableAttributeQuery;
|
||||
const { mutation } = current[this.issuableType];
|
||||
|
||||
|
@ -277,8 +189,8 @@ export default {
|
|||
attributeId:
|
||||
this.issuableAttribute === IssuableAttributeType.Milestone &&
|
||||
this.issuableType === IssuableType.Issue
|
||||
? getIdFromGraphQLId(attributeId)
|
||||
: attributeId,
|
||||
? getIdFromGraphQLId(id)
|
||||
: id,
|
||||
iid: this.iid,
|
||||
},
|
||||
})
|
||||
|
@ -298,32 +210,16 @@ export default {
|
|||
})
|
||||
.finally(() => {
|
||||
this.updating = false;
|
||||
this.searchTerm = '';
|
||||
this.selectedTitle = null;
|
||||
});
|
||||
},
|
||||
isAttributeChecked(attributeId = undefined) {
|
||||
return (
|
||||
attributeId === this.currentAttribute?.id || (!this.currentAttribute?.id && !attributeId)
|
||||
);
|
||||
},
|
||||
isAttributeOverdue(attribute) {
|
||||
return this.issuableAttribute === IssuableAttributeType.Milestone
|
||||
? attribute?.expired
|
||||
: false;
|
||||
},
|
||||
showDropdown() {
|
||||
this.$refs.newDropdown.show();
|
||||
},
|
||||
handleOpen() {
|
||||
this.editing = true;
|
||||
this.showDropdown();
|
||||
},
|
||||
handleClose() {
|
||||
this.editing = false;
|
||||
},
|
||||
setFocus() {
|
||||
this.$refs.search.focusInput();
|
||||
this.$refs.dropdown.show();
|
||||
},
|
||||
handlePopoverClose() {
|
||||
this.$refs.popover.$emit('close');
|
||||
|
@ -349,8 +245,7 @@ export default {
|
|||
:tracking="tracking"
|
||||
:should-show-confirmation-popover="shouldShowConfirmationPopover"
|
||||
:loading="updating || loading"
|
||||
@open="handleOpen"
|
||||
@close="handleClose"
|
||||
@open="showDropdown"
|
||||
@edit-confirm="handleEditConfirmation"
|
||||
>
|
||||
<template #collapsed>
|
||||
|
@ -432,58 +327,24 @@ export default {
|
|||
</gl-popover>
|
||||
</template>
|
||||
<template v-else #default>
|
||||
<gl-dropdown
|
||||
ref="newDropdown"
|
||||
lazy
|
||||
:header-text="i18n.assignAttribute"
|
||||
:text="dropdownText"
|
||||
:loading="loading"
|
||||
class="gl-w-full"
|
||||
toggle-class="gl-max-w-100"
|
||||
block
|
||||
@shown="setFocus"
|
||||
<sidebar-dropdown
|
||||
ref="dropdown"
|
||||
:attr-workspace-path="attrWorkspacePath"
|
||||
:current-attribute="currentAttribute"
|
||||
:issuable-attribute="issuableAttribute"
|
||||
:issuable-type="issuableType"
|
||||
@change="updateAttribute"
|
||||
>
|
||||
<gl-search-box-by-type ref="search" v-model="searchTerm" :placeholder="__('Search')" />
|
||||
<gl-dropdown-item
|
||||
:data-testid="`no-${formatIssuableAttribute.kebab}-item`"
|
||||
is-check-item
|
||||
:is-checked="isAttributeChecked($options.noAttributeId)"
|
||||
@click="updateAttribute($options.noAttributeId)"
|
||||
>
|
||||
{{ i18n.noAttribute }}
|
||||
</gl-dropdown-item>
|
||||
<gl-dropdown-divider />
|
||||
<gl-loading-icon
|
||||
v-if="$apollo.queries.attributesList.loading"
|
||||
size="sm"
|
||||
class="gl-py-4"
|
||||
data-testid="loading-icon-dropdown"
|
||||
/>
|
||||
<template v-else>
|
||||
<gl-dropdown-text v-if="emptyPropsList">
|
||||
{{ i18n.noAttributesFound }}
|
||||
</gl-dropdown-text>
|
||||
<template #list="{ attributesList, isAttributeChecked, updateAttribute: update }">
|
||||
<slot
|
||||
v-else
|
||||
name="list"
|
||||
:attributes-list="attributesList"
|
||||
:is-attribute-checked="isAttributeChecked"
|
||||
:update-attribute="updateAttribute"
|
||||
:update-attribute="update"
|
||||
>
|
||||
<gl-dropdown-item
|
||||
v-for="attrItem in attributesList"
|
||||
:key="attrItem.id"
|
||||
is-check-item
|
||||
:is-checked="isAttributeChecked(attrItem.id)"
|
||||
:data-testid="`${formatIssuableAttribute.kebab}-items`"
|
||||
@click="updateAttribute(attrItem.id)"
|
||||
>
|
||||
{{ attrItem.title }}
|
||||
<span v-if="isAttributeOverdue(attrItem)">{{ $options.i18n.expired }}</span>
|
||||
</gl-dropdown-item>
|
||||
</slot>
|
||||
</template>
|
||||
</gl-dropdown>
|
||||
</sidebar-dropdown>
|
||||
</template>
|
||||
</sidebar-editable-item>
|
||||
</template>
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
// This empty file satisfies the import/no-unresolved rule for ee_else_ce imports.
|
|
@ -1 +0,0 @@
|
|||
// This empty file satisfies the import/no-unresolved rule for ee_else_ce imports.
|
|
@ -1 +0,0 @@
|
|||
// This empty file satisfies the import/no-unresolved rule for ee_else_ce imports.
|
|
@ -24,5 +24,7 @@ metadata:
|
|||
description: Operations related to deploy keys
|
||||
- name: deployments
|
||||
description: Operations related to deployments
|
||||
- name: features
|
||||
description: Operations related to managing Flipper-based feature flags
|
||||
- name: release_links
|
||||
description: Operations related to release assets (links)
|
||||
|
|
|
@ -3996,6 +3996,8 @@ trigger-multi-project-pipeline:
|
|||
- In [GitLab 13.5 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/201938), you
|
||||
can use [`when:manual`](#when) in the same job as `trigger`. In GitLab 13.4 and
|
||||
earlier, using them together causes the error `jobs:#{job-name} when should be on_success, on_failure or always`.
|
||||
- You cannot [manually specify CI/CD variables](../jobs/index.md#specifying-variables-when-running-manual-jobs)
|
||||
before running a manual trigger job.
|
||||
- [Manual pipeline variables](../variables/index.md#override-a-defined-cicd-variable)
|
||||
and [scheduled pipeline variables](../pipelines/schedules.md#add-a-pipeline-schedule)
|
||||
are not passed to downstream pipelines by default. Use [trigger:forward](#triggerforward)
|
||||
|
|
|
@ -611,7 +611,8 @@ Payload example:
|
|||
"name": "User1",
|
||||
"username": "user1",
|
||||
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon"
|
||||
}
|
||||
},
|
||||
"detailed_merge_status": "checking"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
@ -947,7 +948,8 @@ Payload example:
|
|||
"type": "ProjectLabel",
|
||||
"group_id": 41
|
||||
}],
|
||||
"action": "open"
|
||||
"action": "open",
|
||||
"detailed_merge_status": "mergeable"
|
||||
},
|
||||
"labels": [{
|
||||
"id": 206,
|
||||
|
@ -1132,6 +1134,7 @@ Payload example:
|
|||
"target_project_id": 1,
|
||||
"state": "opened",
|
||||
"merge_status": "can_be_merged",
|
||||
"detailed_merge_status": "mergeable",
|
||||
"url": "http://192.168.64.1:3005/gitlab-org/gitlab-test/merge_requests/1"
|
||||
},
|
||||
"user":{
|
||||
|
|
|
@ -180,7 +180,7 @@ module.exports = (path, options = {}) => {
|
|||
'^.+\\.vue$': '@vue/vue2-jest',
|
||||
'spec/frontend/editor/schema/ci/yaml_tests/.+\\.(yml|yaml)$':
|
||||
'./spec/frontend/__helpers__/yaml_transformer.js',
|
||||
'^.+\\.(md|zip|png|yml|yaml)$': 'jest-raw-loader',
|
||||
'^.+\\.(md|zip|png|yml|yaml)$': './spec/frontend/__helpers__/raw_transformer.js',
|
||||
},
|
||||
transformIgnorePatterns: [`node_modules/(?!(${transformIgnoreNodeModules.join('|')}))`],
|
||||
timers: 'legacy',
|
||||
|
|
|
@ -173,6 +173,7 @@ module API
|
|||
mount ::API::Appearance
|
||||
mount ::API::DeployKeys
|
||||
mount ::API::Deployments
|
||||
mount ::API::Features
|
||||
mount ::API::Metadata
|
||||
mount ::API::MergeRequestDiffs
|
||||
mount ::API::UserCounts
|
||||
|
@ -230,7 +231,6 @@ module API
|
|||
mount ::API::Events
|
||||
mount ::API::FeatureFlags
|
||||
mount ::API::FeatureFlagsUserLists
|
||||
mount ::API::Features
|
||||
mount ::API::Files
|
||||
mount ::API::FreezePeriods
|
||||
mount ::API::GenericPackages
|
||||
|
|
|
@ -44,8 +44,11 @@ module API
|
|||
end
|
||||
|
||||
resource :features do
|
||||
desc 'Get a list of all features' do
|
||||
desc 'List all features' do
|
||||
detail 'Get a list of all persisted features, with its gate values.'
|
||||
success Entities::Feature
|
||||
is_array true
|
||||
tags %w[features]
|
||||
end
|
||||
get do
|
||||
features = Feature.all
|
||||
|
@ -53,8 +56,11 @@ module API
|
|||
present features, with: Entities::Feature, current_user: current_user
|
||||
end
|
||||
|
||||
desc 'Get a list of all feature definitions' do
|
||||
desc 'List all feature definitions' do
|
||||
detail 'Get a list of all feature definitions.'
|
||||
success Entities::Feature::Definition
|
||||
is_array true
|
||||
tags %w[features]
|
||||
end
|
||||
get :definitions do
|
||||
definitions = ::Feature::Definition.definitions.values.map(&:to_h)
|
||||
|
@ -62,24 +68,30 @@ module API
|
|||
present definitions, with: Entities::Feature::Definition, current_user: current_user
|
||||
end
|
||||
|
||||
desc 'Set the gate value for the given feature' do
|
||||
desc 'Set or create a feature' do
|
||||
detail "Set a feature's gate value. If a feature with the given name doesn't exist yet, it's created. " \
|
||||
"The value can be a boolean, or an integer to indicate percentage of time."
|
||||
success Entities::Feature
|
||||
tags %w[features]
|
||||
end
|
||||
params do
|
||||
requires :value, type: String, desc: '`true` or `false` to enable/disable, a float for percentage of time'
|
||||
optional :key, type: String, desc: '`percentage_of_actors` or the default `percentage_of_time`'
|
||||
requires :value,
|
||||
types: [String, Integer],
|
||||
desc: '`true` or `false` to enable/disable, or an integer for percentage of time'
|
||||
optional :key, type: String, desc: '`percentage_of_actors` or `percentage_of_time` (default)'
|
||||
optional :feature_group, type: String, desc: 'A Feature group name'
|
||||
optional :user, type: String, desc: 'A GitLab username or comma-separated multiple usernames'
|
||||
optional :group,
|
||||
type: String,
|
||||
desc: "A GitLab group's path, such as 'gitlab-org', or comma-separated multiple group paths"
|
||||
desc: "A GitLab group's path, for example `gitlab-org`, or comma-separated multiple group paths"
|
||||
optional :namespace,
|
||||
type: String,
|
||||
desc: "A GitLab group or user namespace path, such as 'john-doe', or comma-separated multiple namespace paths"
|
||||
desc: "A GitLab group or user namespace's path, for example `john-doe`, or comma-separated " \
|
||||
"multiple namespace paths. Introduced in GitLab 15.0."
|
||||
optional :project,
|
||||
type: String,
|
||||
desc: "A projects path, such as `gitlab-org/gitlab-ce`, or comma-separated multiple project paths"
|
||||
optional :force, type: Boolean, desc: 'Skip feature flag validation checks, ie. YAML definition'
|
||||
desc: "A projects path, for example `gitlab-org/gitlab-foss`, or comma-separated multiple project paths"
|
||||
optional :force, type: Boolean, desc: 'Skip feature flag validation checks, such as a YAML definition'
|
||||
|
||||
mutually_exclusive :key, :feature_group
|
||||
mutually_exclusive :key, :user
|
||||
|
@ -135,7 +147,10 @@ module API
|
|||
bad_request!(e.message)
|
||||
end
|
||||
|
||||
desc 'Remove the gate value for the given feature'
|
||||
desc 'Delete a feature' do
|
||||
detail "Removes a feature gate. Response is equal when the gate exists, or doesn't."
|
||||
tags %w[features]
|
||||
end
|
||||
delete ':name' do
|
||||
Feature.remove(params[:name])
|
||||
|
||||
|
|
|
@ -76,7 +76,12 @@ module Gitlab
|
|||
# | /builds/foo/test/something | something |
|
||||
# | /builds/foo/test/ | nil |
|
||||
# | /builds/foo/test | nil |
|
||||
node.split("#{project_path}/", 2)[1]
|
||||
# | D:\builds\foo\bar\app\ | app\ |
|
||||
unixify(node).split("#{project_path}/", 2)[1]
|
||||
end
|
||||
|
||||
def unixify(path)
|
||||
path.tr('\\', '/')
|
||||
end
|
||||
|
||||
def remove_matched_filenames
|
||||
|
|
|
@ -7,14 +7,14 @@ module Gitlab
|
|||
module Validators
|
||||
class SchemaValidator
|
||||
SUPPORTED_VERSIONS = {
|
||||
cluster_image_scanning: %w[14.0.4 14.0.5 14.0.6 14.1.0 14.1.1 14.1.2 14.1.3 15.0.0 15.0.1 15.0.2],
|
||||
container_scanning: %w[14.0.0 14.0.1 14.0.2 14.0.3 14.0.4 14.0.5 14.0.6 14.1.0 14.1.1 14.1.2 14.1.3 15.0.0 15.0.1 15.0.2],
|
||||
coverage_fuzzing: %w[14.0.0 14.0.1 14.0.2 14.0.3 14.0.4 14.0.5 14.0.6 14.1.0 14.1.1 14.1.2 14.1.3 15.0.0 15.0.1 15.0.2],
|
||||
dast: %w[14.0.0 14.0.1 14.0.2 14.0.3 14.0.4 14.0.5 14.0.6 14.1.0 14.1.1 14.1.2 14.1.3 15.0.0 15.0.1 15.0.2],
|
||||
api_fuzzing: %w[14.0.0 14.0.1 14.0.2 14.0.3 14.0.4 14.0.5 14.0.6 14.1.0 14.1.1 14.1.2 14.1.3 15.0.0 15.0.1 15.0.2],
|
||||
dependency_scanning: %w[14.0.0 14.0.1 14.0.2 14.0.3 14.0.4 14.0.5 14.0.6 14.1.0 14.1.1 14.1.2 14.1.3 15.0.0 15.0.1 15.0.2],
|
||||
sast: %w[14.0.0 14.0.1 14.0.2 14.0.3 14.0.4 14.0.5 14.0.6 14.1.0 14.1.1 14.1.2 14.1.3 15.0.0 15.0.1 15.0.2],
|
||||
secret_detection: %w[14.0.0 14.0.1 14.0.2 14.0.3 14.0.4 14.0.5 14.0.6 14.1.0 14.1.1 14.1.2 14.1.3 15.0.0 15.0.1 15.0.2]
|
||||
cluster_image_scanning: %w[14.0.4 14.0.5 14.0.6 14.1.0 14.1.1 14.1.2 14.1.3 15.0.0 15.0.1 15.0.2 15.0.4],
|
||||
container_scanning: %w[14.0.0 14.0.1 14.0.2 14.0.3 14.0.4 14.0.5 14.0.6 14.1.0 14.1.1 14.1.2 14.1.3 15.0.0 15.0.1 15.0.2 15.0.4],
|
||||
coverage_fuzzing: %w[14.0.0 14.0.1 14.0.2 14.0.3 14.0.4 14.0.5 14.0.6 14.1.0 14.1.1 14.1.2 14.1.3 15.0.0 15.0.1 15.0.2 15.0.4],
|
||||
dast: %w[14.0.0 14.0.1 14.0.2 14.0.3 14.0.4 14.0.5 14.0.6 14.1.0 14.1.1 14.1.2 14.1.3 15.0.0 15.0.1 15.0.2 15.0.4],
|
||||
api_fuzzing: %w[14.0.0 14.0.1 14.0.2 14.0.3 14.0.4 14.0.5 14.0.6 14.1.0 14.1.1 14.1.2 14.1.3 15.0.0 15.0.1 15.0.2 15.0.4],
|
||||
dependency_scanning: %w[14.0.0 14.0.1 14.0.2 14.0.3 14.0.4 14.0.5 14.0.6 14.1.0 14.1.1 14.1.2 14.1.3 15.0.0 15.0.1 15.0.2 15.0.4],
|
||||
sast: %w[14.0.0 14.0.1 14.0.2 14.0.3 14.0.4 14.0.5 14.0.6 14.1.0 14.1.1 14.1.2 14.1.3 15.0.0 15.0.1 15.0.2 15.0.4],
|
||||
secret_detection: %w[14.0.0 14.0.1 14.0.2 14.0.3 14.0.4 14.0.5 14.0.6 14.1.0 14.1.1 14.1.2 14.1.3 15.0.0 15.0.1 15.0.2 15.0.4]
|
||||
}.freeze
|
||||
|
||||
VERSIONS_TO_REMOVE_IN_16_0 = [].freeze
|
||||
|
|
|
@ -0,0 +1,984 @@
|
|||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"$id": "https://gitlab.com/gitlab-org/security-products/security-report-schemas/-/raw/master/dist/cluster-image-scanning-report-format.json",
|
||||
"title": "Report format for GitLab Cluster Image Scanning",
|
||||
"description": "This schema provides the the report format for Cluster Image Scanning (https://docs.gitlab.com/ee/user/application_security/cluster_image_scanning/).",
|
||||
"definitions": {
|
||||
"detail_type": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/definitions/named_list"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/list"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/table"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/text"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/url"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/code"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/value"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/diff"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/markdown"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/commit"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/file_location"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/module_location"
|
||||
}
|
||||
]
|
||||
},
|
||||
"text_value": {
|
||||
"type": "string"
|
||||
},
|
||||
"named_field": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"$ref": "#/definitions/text_value",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"description": {
|
||||
"$ref": "#/definitions/text_value"
|
||||
}
|
||||
}
|
||||
},
|
||||
"named_list": {
|
||||
"type": "object",
|
||||
"description": "An object with named and typed fields",
|
||||
"required": [
|
||||
"type",
|
||||
"items"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "named-list"
|
||||
},
|
||||
"items": {
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"^.*$": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/named_field"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/detail_type"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"list": {
|
||||
"type": "object",
|
||||
"description": "A list of typed fields",
|
||||
"required": [
|
||||
"type",
|
||||
"items"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "list"
|
||||
},
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/detail_type"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"table": {
|
||||
"type": "object",
|
||||
"description": "A table of typed fields",
|
||||
"required": [
|
||||
"type",
|
||||
"rows"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "table"
|
||||
},
|
||||
"header": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/detail_type"
|
||||
}
|
||||
},
|
||||
"rows": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/detail_type"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"text": {
|
||||
"type": "object",
|
||||
"description": "Raw text",
|
||||
"required": [
|
||||
"type",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "text"
|
||||
},
|
||||
"value": {
|
||||
"$ref": "#/definitions/text_value"
|
||||
}
|
||||
}
|
||||
},
|
||||
"url": {
|
||||
"type": "object",
|
||||
"description": "A single URL",
|
||||
"required": [
|
||||
"type",
|
||||
"href"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "url"
|
||||
},
|
||||
"text": {
|
||||
"$ref": "#/definitions/text_value"
|
||||
},
|
||||
"href": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"http://mysite.com"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"code": {
|
||||
"type": "object",
|
||||
"description": "A codeblock",
|
||||
"required": [
|
||||
"type",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "code"
|
||||
},
|
||||
"value": {
|
||||
"type": "string"
|
||||
},
|
||||
"lang": {
|
||||
"type": "string",
|
||||
"description": "A programming language"
|
||||
}
|
||||
}
|
||||
},
|
||||
"value": {
|
||||
"type": "object",
|
||||
"description": "A field that can store a range of types of value",
|
||||
"required": [
|
||||
"type",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "value"
|
||||
},
|
||||
"value": {
|
||||
"type": [
|
||||
"number",
|
||||
"string",
|
||||
"boolean"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"diff": {
|
||||
"type": "object",
|
||||
"description": "A diff",
|
||||
"required": [
|
||||
"type",
|
||||
"before",
|
||||
"after"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "diff"
|
||||
},
|
||||
"before": {
|
||||
"type": "string"
|
||||
},
|
||||
"after": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"markdown": {
|
||||
"type": "object",
|
||||
"description": "GitLab flavoured markdown, see https://docs.gitlab.com/ee/user/markdown.html",
|
||||
"required": [
|
||||
"type",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "markdown"
|
||||
},
|
||||
"value": {
|
||||
"$ref": "#/definitions/text_value",
|
||||
"examples": [
|
||||
"Here is markdown `inline code` #1 [test](gitlab.com)\n\n![GitLab Logo](https://about.gitlab.com/images/press/logo/preview/gitlab-logo-white-preview.png)"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"commit": {
|
||||
"type": "object",
|
||||
"description": "A commit/tag/branch within the GitLab project",
|
||||
"required": [
|
||||
"type",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "commit"
|
||||
},
|
||||
"value": {
|
||||
"type": "string",
|
||||
"description": "The commit SHA",
|
||||
"minLength": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
"file_location": {
|
||||
"type": "object",
|
||||
"description": "A location within a file in the project",
|
||||
"required": [
|
||||
"type",
|
||||
"file_name",
|
||||
"line_start"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "file-location"
|
||||
},
|
||||
"file_name": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"line_start": {
|
||||
"type": "integer"
|
||||
},
|
||||
"line_end": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"module_location": {
|
||||
"type": "object",
|
||||
"description": "A location within a binary module of the form module+relative_offset",
|
||||
"required": [
|
||||
"type",
|
||||
"module_name",
|
||||
"offset"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "module-location"
|
||||
},
|
||||
"module_name": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"compiled_binary"
|
||||
]
|
||||
},
|
||||
"offset": {
|
||||
"type": "integer",
|
||||
"examples": [
|
||||
100
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"self": {
|
||||
"version": "15.0.4"
|
||||
},
|
||||
"type": "object",
|
||||
"required": [
|
||||
"scan",
|
||||
"version",
|
||||
"vulnerabilities"
|
||||
],
|
||||
"additionalProperties": true,
|
||||
"properties": {
|
||||
"scan": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"analyzer",
|
||||
"end_time",
|
||||
"scanner",
|
||||
"start_time",
|
||||
"status",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"end_time": {
|
||||
"type": "string",
|
||||
"description": "ISO8601 UTC value with format yyyy-mm-ddThh:mm:ss, representing when the scan finished.",
|
||||
"pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$",
|
||||
"examples": [
|
||||
"2020-01-28T03:26:02"
|
||||
]
|
||||
},
|
||||
"messages": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"description": "Communication intended for the initiator of a scan.",
|
||||
"required": [
|
||||
"level",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"level": {
|
||||
"type": "string",
|
||||
"description": "Describes the severity of the communication. Use info to communicate normal scan behaviour; warn to communicate a potentially recoverable problem, or a partial error; fatal to communicate an issue that causes the scan to halt.",
|
||||
"enum": [
|
||||
"info",
|
||||
"warn",
|
||||
"fatal"
|
||||
],
|
||||
"examples": [
|
||||
"info"
|
||||
]
|
||||
},
|
||||
"value": {
|
||||
"type": "string",
|
||||
"description": "The message to communicate.",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"Permission denied, scanning aborted"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"analyzer": {
|
||||
"type": "object",
|
||||
"description": "Object defining the analyzer used to perform the scan. Analyzers typically delegate to an underlying scanner to run the scan.",
|
||||
"required": [
|
||||
"id",
|
||||
"name",
|
||||
"version",
|
||||
"vendor"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"description": "Unique id that identifies the analyzer.",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"gitlab-dast"
|
||||
]
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "A human readable value that identifies the analyzer, not required to be unique.",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"GitLab DAST"
|
||||
]
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"pattern": "^https?://.+",
|
||||
"description": "A link to more information about the analyzer.",
|
||||
"examples": [
|
||||
"https://docs.gitlab.com/ee/user/application_security/dast"
|
||||
]
|
||||
},
|
||||
"vendor": {
|
||||
"description": "The vendor/maintainer of the analyzer.",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "The name of the vendor.",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"GitLab"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"version": {
|
||||
"type": "string",
|
||||
"description": "The version of the analyzer.",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"1.0.2"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"scanner": {
|
||||
"type": "object",
|
||||
"description": "Object defining the scanner used to perform the scan.",
|
||||
"required": [
|
||||
"id",
|
||||
"name",
|
||||
"version",
|
||||
"vendor"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"description": "Unique id that identifies the scanner.",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"my-sast-scanner"
|
||||
]
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "A human readable value that identifies the scanner, not required to be unique.",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"My SAST Scanner"
|
||||
]
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"description": "A link to more information about the scanner.",
|
||||
"examples": [
|
||||
"https://scanner.url"
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "string",
|
||||
"description": "The version of the scanner.",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"1.0.2"
|
||||
]
|
||||
},
|
||||
"vendor": {
|
||||
"description": "The vendor/maintainer of the scanner.",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "The name of the vendor.",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"GitLab"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"start_time": {
|
||||
"type": "string",
|
||||
"description": "ISO8601 UTC value with format yyyy-mm-ddThh:mm:ss, representing when the scan started.",
|
||||
"pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$",
|
||||
"examples": [
|
||||
"2020-02-14T16:01:59"
|
||||
]
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"description": "Result of the scan.",
|
||||
"enum": [
|
||||
"success",
|
||||
"failure"
|
||||
]
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"description": "Type of the scan.",
|
||||
"enum": [
|
||||
"cluster_image_scanning"
|
||||
]
|
||||
},
|
||||
"primary_identifiers": {
|
||||
"type": "array",
|
||||
"description": "An unordered array containing an exhaustive list of primary identifiers for which the analyzer may return results",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type",
|
||||
"name",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"description": "for example, cve, cwe, osvdb, usn, or an analyzer-dependent type such as gemnasium).",
|
||||
"minLength": 1
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Human-readable name of the identifier.",
|
||||
"minLength": 1
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"description": "URL of the identifier's documentation.",
|
||||
"pattern": "^https?://.+"
|
||||
},
|
||||
"value": {
|
||||
"type": "string",
|
||||
"description": "Value of the identifier, for matching purpose.",
|
||||
"minLength": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"description": "URI pointing to the validating security report schema.",
|
||||
"pattern": "^https?://.+"
|
||||
},
|
||||
"version": {
|
||||
"type": "string",
|
||||
"description": "The version of the schema to which the JSON report conforms.",
|
||||
"pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$"
|
||||
},
|
||||
"vulnerabilities": {
|
||||
"type": "array",
|
||||
"description": "Array of vulnerability objects.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"description": "Describes the vulnerability using GitLab Flavored Markdown",
|
||||
"required": [
|
||||
"id",
|
||||
"identifiers",
|
||||
"location"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"description": "Unique identifier of the vulnerability. This is recommended to be a UUID.",
|
||||
"examples": [
|
||||
"642735a5-1425-428d-8d4e-3c854885a3c9"
|
||||
]
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"maxLength": 255,
|
||||
"description": "The name of the vulnerability. This must not include the finding's specific information."
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"maxLength": 1048576,
|
||||
"description": "A long text section describing the vulnerability more fully."
|
||||
},
|
||||
"severity": {
|
||||
"type": "string",
|
||||
"description": "How much the vulnerability impacts the software. Possible values are Info, Unknown, Low, Medium, High, or Critical. Note that some analyzers may not report all these possible values.",
|
||||
"enum": [
|
||||
"Info",
|
||||
"Unknown",
|
||||
"Low",
|
||||
"Medium",
|
||||
"High",
|
||||
"Critical"
|
||||
]
|
||||
},
|
||||
"solution": {
|
||||
"type": "string",
|
||||
"maxLength": 7000,
|
||||
"description": "Explanation of how to fix the vulnerability."
|
||||
},
|
||||
"identifiers": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"description": "An ordered array of references that identify a vulnerability on internal or external databases. The first identifier is the Primary Identifier, which has special meaning.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type",
|
||||
"name",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"description": "for example, cve, cwe, osvdb, usn, or an analyzer-dependent type such as gemnasium).",
|
||||
"minLength": 1
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Human-readable name of the identifier.",
|
||||
"minLength": 1
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"description": "URL of the identifier's documentation.",
|
||||
"pattern": "^https?://.+"
|
||||
},
|
||||
"value": {
|
||||
"type": "string",
|
||||
"description": "Value of the identifier, for matching purpose.",
|
||||
"minLength": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"links": {
|
||||
"type": "array",
|
||||
"description": "An array of references to external documentation or articles that describe the vulnerability.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"url"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Name of the vulnerability details link."
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"description": "URL of the vulnerability details document.",
|
||||
"pattern": "^https?://.+"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"details": {
|
||||
"$ref": "#/definitions/named_list/properties/items"
|
||||
},
|
||||
"tracking": {
|
||||
"type": "object",
|
||||
"description": "Describes how this vulnerability should be tracked as the project changes.",
|
||||
"oneOf": [
|
||||
{
|
||||
"description": "Declares that a series of items should be tracked using source-specific tracking methods.",
|
||||
"required": [
|
||||
"items"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "source"
|
||||
},
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"description": "An item that should be tracked using source-specific tracking methods.",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"signatures"
|
||||
],
|
||||
"properties": {
|
||||
"file": {
|
||||
"type": "string",
|
||||
"description": "Path to the file where the vulnerability is located."
|
||||
},
|
||||
"start_line": {
|
||||
"type": "number",
|
||||
"description": "The first line of the file that includes the vulnerability."
|
||||
},
|
||||
"end_line": {
|
||||
"type": "number",
|
||||
"description": "The last line of the file that includes the vulnerability."
|
||||
},
|
||||
"signatures": {
|
||||
"type": "array",
|
||||
"description": "An array of calculated tracking signatures for this tracking item.",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"description": "A calculated tracking signature value and metadata.",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"algorithm",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"algorithm": {
|
||||
"type": "string",
|
||||
"description": "The algorithm used to generate the signature."
|
||||
},
|
||||
"value": {
|
||||
"type": "string",
|
||||
"description": "The result of this signature algorithm."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"description": "Each tracking type must declare its own type."
|
||||
}
|
||||
}
|
||||
},
|
||||
"flags": {
|
||||
"description": "Flags that can be attached to vulnerabilities.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"description": "Informational flags identified and assigned to a vulnerability.",
|
||||
"required": [
|
||||
"type",
|
||||
"origin",
|
||||
"description"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"description": "Result of the scan.",
|
||||
"enum": [
|
||||
"flagged-as-likely-false-positive"
|
||||
]
|
||||
},
|
||||
"origin": {
|
||||
"minLength": 1,
|
||||
"description": "Tool that issued the flag.",
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"minLength": 1,
|
||||
"description": "What the flag is about.",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"location": {
|
||||
"type": "object",
|
||||
"description": "Identifies the vulnerability's location.",
|
||||
"required": [
|
||||
"dependency",
|
||||
"image",
|
||||
"kubernetes_resource"
|
||||
],
|
||||
"properties": {
|
||||
"dependency": {
|
||||
"type": "object",
|
||||
"description": "Describes the dependency of a project where the vulnerability is located.",
|
||||
"required": [
|
||||
"package",
|
||||
"version"
|
||||
],
|
||||
"properties": {
|
||||
"package": {
|
||||
"type": "object",
|
||||
"description": "Provides information on the package where the vulnerability is located.",
|
||||
"required": [
|
||||
"name"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Name of the package where the vulnerability is located."
|
||||
}
|
||||
}
|
||||
},
|
||||
"version": {
|
||||
"type": "string",
|
||||
"description": "Version of the vulnerable package."
|
||||
},
|
||||
"iid": {
|
||||
"description": "ID that identifies the dependency in the scope of a dependency file.",
|
||||
"type": "number"
|
||||
},
|
||||
"direct": {
|
||||
"type": "boolean",
|
||||
"description": "Tells whether this is a direct, top-level dependency of the scanned project."
|
||||
},
|
||||
"dependency_path": {
|
||||
"type": "array",
|
||||
"description": "Ancestors of the dependency, starting from a direct project dependency, and ending with an immediate parent of the dependency. The dependency itself is excluded from the path. Direct dependencies have no path.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"iid"
|
||||
],
|
||||
"properties": {
|
||||
"iid": {
|
||||
"type": "number",
|
||||
"description": "ID that is unique in the scope of a parent object, and specific to the resource type."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"operating_system": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"maxLength": 255,
|
||||
"description": "The operating system that contains the vulnerable package."
|
||||
},
|
||||
"image": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"description": "The analyzed Docker image.",
|
||||
"examples": [
|
||||
"index.docker.io/library/nginx:1.21"
|
||||
]
|
||||
},
|
||||
"kubernetes_resource": {
|
||||
"type": "object",
|
||||
"description": "The specific Kubernetes resource that was scanned.",
|
||||
"required": [
|
||||
"namespace",
|
||||
"kind",
|
||||
"name",
|
||||
"container_name"
|
||||
],
|
||||
"properties": {
|
||||
"namespace": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"maxLength": 255,
|
||||
"description": "The Kubernetes namespace the resource that had its image scanned.",
|
||||
"examples": [
|
||||
"default",
|
||||
"staging",
|
||||
"production"
|
||||
]
|
||||
},
|
||||
"kind": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"maxLength": 255,
|
||||
"description": "The Kubernetes kind the resource that had its image scanned.",
|
||||
"examples": [
|
||||
"Deployment",
|
||||
"DaemonSet"
|
||||
]
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"maxLength": 255,
|
||||
"description": "The name of the resource that had its image scanned.",
|
||||
"examples": [
|
||||
"nginx-ingress"
|
||||
]
|
||||
},
|
||||
"container_name": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"maxLength": 255,
|
||||
"description": "The name of the container that had its image scanned.",
|
||||
"examples": [
|
||||
"nginx"
|
||||
]
|
||||
},
|
||||
"agent_id": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"maxLength": 255,
|
||||
"description": "The GitLab ID of the Kubernetes Agent which performed the scan.",
|
||||
"examples": [
|
||||
"1234"
|
||||
]
|
||||
},
|
||||
"cluster_id": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"maxLength": 255,
|
||||
"description": "The GitLab ID of the Kubernetes cluster when using cluster integration.",
|
||||
"examples": [
|
||||
"1234"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"remediations": {
|
||||
"type": "array",
|
||||
"description": "An array of objects containing information on available remediations, along with patch diffs to apply.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"fixes",
|
||||
"summary",
|
||||
"diff"
|
||||
],
|
||||
"properties": {
|
||||
"fixes": {
|
||||
"type": "array",
|
||||
"description": "An array of strings that represent references to vulnerabilities fixed by this remediation.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"description": "Unique identifier of the vulnerability. This is recommended to be a UUID.",
|
||||
"examples": [
|
||||
"642735a5-1425-428d-8d4e-3c854885a3c9"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"summary": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"description": "An overview of how the vulnerabilities were fixed."
|
||||
},
|
||||
"diff": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"description": "A base64-encoded remediation code diff, compatible with git apply."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,916 @@
|
|||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"$id": "https://gitlab.com/gitlab-org/security-products/security-report-schemas/-/raw/master/dist/container-scanning-report-format.json",
|
||||
"title": "Report format for GitLab Container Scanning",
|
||||
"description": "This schema provides the the report format for Container Scanning (https://docs.gitlab.com/ee/user/application_security/container_scanning).",
|
||||
"definitions": {
|
||||
"detail_type": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/definitions/named_list"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/list"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/table"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/text"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/url"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/code"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/value"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/diff"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/markdown"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/commit"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/file_location"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/module_location"
|
||||
}
|
||||
]
|
||||
},
|
||||
"text_value": {
|
||||
"type": "string"
|
||||
},
|
||||
"named_field": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"$ref": "#/definitions/text_value",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"description": {
|
||||
"$ref": "#/definitions/text_value"
|
||||
}
|
||||
}
|
||||
},
|
||||
"named_list": {
|
||||
"type": "object",
|
||||
"description": "An object with named and typed fields",
|
||||
"required": [
|
||||
"type",
|
||||
"items"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "named-list"
|
||||
},
|
||||
"items": {
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"^.*$": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/named_field"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/detail_type"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"list": {
|
||||
"type": "object",
|
||||
"description": "A list of typed fields",
|
||||
"required": [
|
||||
"type",
|
||||
"items"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "list"
|
||||
},
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/detail_type"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"table": {
|
||||
"type": "object",
|
||||
"description": "A table of typed fields",
|
||||
"required": [
|
||||
"type",
|
||||
"rows"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "table"
|
||||
},
|
||||
"header": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/detail_type"
|
||||
}
|
||||
},
|
||||
"rows": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/detail_type"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"text": {
|
||||
"type": "object",
|
||||
"description": "Raw text",
|
||||
"required": [
|
||||
"type",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "text"
|
||||
},
|
||||
"value": {
|
||||
"$ref": "#/definitions/text_value"
|
||||
}
|
||||
}
|
||||
},
|
||||
"url": {
|
||||
"type": "object",
|
||||
"description": "A single URL",
|
||||
"required": [
|
||||
"type",
|
||||
"href"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "url"
|
||||
},
|
||||
"text": {
|
||||
"$ref": "#/definitions/text_value"
|
||||
},
|
||||
"href": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"http://mysite.com"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"code": {
|
||||
"type": "object",
|
||||
"description": "A codeblock",
|
||||
"required": [
|
||||
"type",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "code"
|
||||
},
|
||||
"value": {
|
||||
"type": "string"
|
||||
},
|
||||
"lang": {
|
||||
"type": "string",
|
||||
"description": "A programming language"
|
||||
}
|
||||
}
|
||||
},
|
||||
"value": {
|
||||
"type": "object",
|
||||
"description": "A field that can store a range of types of value",
|
||||
"required": [
|
||||
"type",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "value"
|
||||
},
|
||||
"value": {
|
||||
"type": [
|
||||
"number",
|
||||
"string",
|
||||
"boolean"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"diff": {
|
||||
"type": "object",
|
||||
"description": "A diff",
|
||||
"required": [
|
||||
"type",
|
||||
"before",
|
||||
"after"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "diff"
|
||||
},
|
||||
"before": {
|
||||
"type": "string"
|
||||
},
|
||||
"after": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"markdown": {
|
||||
"type": "object",
|
||||
"description": "GitLab flavoured markdown, see https://docs.gitlab.com/ee/user/markdown.html",
|
||||
"required": [
|
||||
"type",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "markdown"
|
||||
},
|
||||
"value": {
|
||||
"$ref": "#/definitions/text_value",
|
||||
"examples": [
|
||||
"Here is markdown `inline code` #1 [test](gitlab.com)\n\n![GitLab Logo](https://about.gitlab.com/images/press/logo/preview/gitlab-logo-white-preview.png)"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"commit": {
|
||||
"type": "object",
|
||||
"description": "A commit/tag/branch within the GitLab project",
|
||||
"required": [
|
||||
"type",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "commit"
|
||||
},
|
||||
"value": {
|
||||
"type": "string",
|
||||
"description": "The commit SHA",
|
||||
"minLength": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
"file_location": {
|
||||
"type": "object",
|
||||
"description": "A location within a file in the project",
|
||||
"required": [
|
||||
"type",
|
||||
"file_name",
|
||||
"line_start"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "file-location"
|
||||
},
|
||||
"file_name": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"line_start": {
|
||||
"type": "integer"
|
||||
},
|
||||
"line_end": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"module_location": {
|
||||
"type": "object",
|
||||
"description": "A location within a binary module of the form module+relative_offset",
|
||||
"required": [
|
||||
"type",
|
||||
"module_name",
|
||||
"offset"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "module-location"
|
||||
},
|
||||
"module_name": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"compiled_binary"
|
||||
]
|
||||
},
|
||||
"offset": {
|
||||
"type": "integer",
|
||||
"examples": [
|
||||
100
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"self": {
|
||||
"version": "15.0.4"
|
||||
},
|
||||
"type": "object",
|
||||
"required": [
|
||||
"scan",
|
||||
"version",
|
||||
"vulnerabilities"
|
||||
],
|
||||
"additionalProperties": true,
|
||||
"properties": {
|
||||
"scan": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"analyzer",
|
||||
"end_time",
|
||||
"scanner",
|
||||
"start_time",
|
||||
"status",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"end_time": {
|
||||
"type": "string",
|
||||
"description": "ISO8601 UTC value with format yyyy-mm-ddThh:mm:ss, representing when the scan finished.",
|
||||
"pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$",
|
||||
"examples": [
|
||||
"2020-01-28T03:26:02"
|
||||
]
|
||||
},
|
||||
"messages": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"description": "Communication intended for the initiator of a scan.",
|
||||
"required": [
|
||||
"level",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"level": {
|
||||
"type": "string",
|
||||
"description": "Describes the severity of the communication. Use info to communicate normal scan behaviour; warn to communicate a potentially recoverable problem, or a partial error; fatal to communicate an issue that causes the scan to halt.",
|
||||
"enum": [
|
||||
"info",
|
||||
"warn",
|
||||
"fatal"
|
||||
],
|
||||
"examples": [
|
||||
"info"
|
||||
]
|
||||
},
|
||||
"value": {
|
||||
"type": "string",
|
||||
"description": "The message to communicate.",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"Permission denied, scanning aborted"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"analyzer": {
|
||||
"type": "object",
|
||||
"description": "Object defining the analyzer used to perform the scan. Analyzers typically delegate to an underlying scanner to run the scan.",
|
||||
"required": [
|
||||
"id",
|
||||
"name",
|
||||
"version",
|
||||
"vendor"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"description": "Unique id that identifies the analyzer.",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"gitlab-dast"
|
||||
]
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "A human readable value that identifies the analyzer, not required to be unique.",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"GitLab DAST"
|
||||
]
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"pattern": "^https?://.+",
|
||||
"description": "A link to more information about the analyzer.",
|
||||
"examples": [
|
||||
"https://docs.gitlab.com/ee/user/application_security/dast"
|
||||
]
|
||||
},
|
||||
"vendor": {
|
||||
"description": "The vendor/maintainer of the analyzer.",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "The name of the vendor.",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"GitLab"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"version": {
|
||||
"type": "string",
|
||||
"description": "The version of the analyzer.",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"1.0.2"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"scanner": {
|
||||
"type": "object",
|
||||
"description": "Object defining the scanner used to perform the scan.",
|
||||
"required": [
|
||||
"id",
|
||||
"name",
|
||||
"version",
|
||||
"vendor"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"description": "Unique id that identifies the scanner.",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"my-sast-scanner"
|
||||
]
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "A human readable value that identifies the scanner, not required to be unique.",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"My SAST Scanner"
|
||||
]
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"description": "A link to more information about the scanner.",
|
||||
"examples": [
|
||||
"https://scanner.url"
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "string",
|
||||
"description": "The version of the scanner.",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"1.0.2"
|
||||
]
|
||||
},
|
||||
"vendor": {
|
||||
"description": "The vendor/maintainer of the scanner.",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "The name of the vendor.",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"GitLab"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"start_time": {
|
||||
"type": "string",
|
||||
"description": "ISO8601 UTC value with format yyyy-mm-ddThh:mm:ss, representing when the scan started.",
|
||||
"pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$",
|
||||
"examples": [
|
||||
"2020-02-14T16:01:59"
|
||||
]
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"description": "Result of the scan.",
|
||||
"enum": [
|
||||
"success",
|
||||
"failure"
|
||||
]
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"description": "Type of the scan.",
|
||||
"enum": [
|
||||
"container_scanning"
|
||||
]
|
||||
},
|
||||
"primary_identifiers": {
|
||||
"type": "array",
|
||||
"description": "An unordered array containing an exhaustive list of primary identifiers for which the analyzer may return results",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type",
|
||||
"name",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"description": "for example, cve, cwe, osvdb, usn, or an analyzer-dependent type such as gemnasium).",
|
||||
"minLength": 1
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Human-readable name of the identifier.",
|
||||
"minLength": 1
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"description": "URL of the identifier's documentation.",
|
||||
"pattern": "^https?://.+"
|
||||
},
|
||||
"value": {
|
||||
"type": "string",
|
||||
"description": "Value of the identifier, for matching purpose.",
|
||||
"minLength": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"description": "URI pointing to the validating security report schema.",
|
||||
"pattern": "^https?://.+"
|
||||
},
|
||||
"version": {
|
||||
"type": "string",
|
||||
"description": "The version of the schema to which the JSON report conforms.",
|
||||
"pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$"
|
||||
},
|
||||
"vulnerabilities": {
|
||||
"type": "array",
|
||||
"description": "Array of vulnerability objects.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"description": "Describes the vulnerability using GitLab Flavored Markdown",
|
||||
"required": [
|
||||
"id",
|
||||
"identifiers",
|
||||
"location"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"description": "Unique identifier of the vulnerability. This is recommended to be a UUID.",
|
||||
"examples": [
|
||||
"642735a5-1425-428d-8d4e-3c854885a3c9"
|
||||
]
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"maxLength": 255,
|
||||
"description": "The name of the vulnerability. This must not include the finding's specific information."
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"maxLength": 1048576,
|
||||
"description": "A long text section describing the vulnerability more fully."
|
||||
},
|
||||
"severity": {
|
||||
"type": "string",
|
||||
"description": "How much the vulnerability impacts the software. Possible values are Info, Unknown, Low, Medium, High, or Critical. Note that some analyzers may not report all these possible values.",
|
||||
"enum": [
|
||||
"Info",
|
||||
"Unknown",
|
||||
"Low",
|
||||
"Medium",
|
||||
"High",
|
||||
"Critical"
|
||||
]
|
||||
},
|
||||
"solution": {
|
||||
"type": "string",
|
||||
"maxLength": 7000,
|
||||
"description": "Explanation of how to fix the vulnerability."
|
||||
},
|
||||
"identifiers": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"description": "An ordered array of references that identify a vulnerability on internal or external databases. The first identifier is the Primary Identifier, which has special meaning.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type",
|
||||
"name",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"description": "for example, cve, cwe, osvdb, usn, or an analyzer-dependent type such as gemnasium).",
|
||||
"minLength": 1
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Human-readable name of the identifier.",
|
||||
"minLength": 1
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"description": "URL of the identifier's documentation.",
|
||||
"pattern": "^https?://.+"
|
||||
},
|
||||
"value": {
|
||||
"type": "string",
|
||||
"description": "Value of the identifier, for matching purpose.",
|
||||
"minLength": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"links": {
|
||||
"type": "array",
|
||||
"description": "An array of references to external documentation or articles that describe the vulnerability.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"url"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Name of the vulnerability details link."
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"description": "URL of the vulnerability details document.",
|
||||
"pattern": "^https?://.+"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"details": {
|
||||
"$ref": "#/definitions/named_list/properties/items"
|
||||
},
|
||||
"tracking": {
|
||||
"type": "object",
|
||||
"description": "Describes how this vulnerability should be tracked as the project changes.",
|
||||
"oneOf": [
|
||||
{
|
||||
"description": "Declares that a series of items should be tracked using source-specific tracking methods.",
|
||||
"required": [
|
||||
"items"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "source"
|
||||
},
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"description": "An item that should be tracked using source-specific tracking methods.",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"signatures"
|
||||
],
|
||||
"properties": {
|
||||
"file": {
|
||||
"type": "string",
|
||||
"description": "Path to the file where the vulnerability is located."
|
||||
},
|
||||
"start_line": {
|
||||
"type": "number",
|
||||
"description": "The first line of the file that includes the vulnerability."
|
||||
},
|
||||
"end_line": {
|
||||
"type": "number",
|
||||
"description": "The last line of the file that includes the vulnerability."
|
||||
},
|
||||
"signatures": {
|
||||
"type": "array",
|
||||
"description": "An array of calculated tracking signatures for this tracking item.",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"description": "A calculated tracking signature value and metadata.",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"algorithm",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"algorithm": {
|
||||
"type": "string",
|
||||
"description": "The algorithm used to generate the signature."
|
||||
},
|
||||
"value": {
|
||||
"type": "string",
|
||||
"description": "The result of this signature algorithm."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"description": "Each tracking type must declare its own type."
|
||||
}
|
||||
}
|
||||
},
|
||||
"flags": {
|
||||
"description": "Flags that can be attached to vulnerabilities.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"description": "Informational flags identified and assigned to a vulnerability.",
|
||||
"required": [
|
||||
"type",
|
||||
"origin",
|
||||
"description"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"description": "Result of the scan.",
|
||||
"enum": [
|
||||
"flagged-as-likely-false-positive"
|
||||
]
|
||||
},
|
||||
"origin": {
|
||||
"minLength": 1,
|
||||
"description": "Tool that issued the flag.",
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"minLength": 1,
|
||||
"description": "What the flag is about.",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"location": {
|
||||
"type": "object",
|
||||
"description": "Identifies the vulnerability's location.",
|
||||
"required": [
|
||||
"dependency",
|
||||
"operating_system",
|
||||
"image"
|
||||
],
|
||||
"properties": {
|
||||
"dependency": {
|
||||
"type": "object",
|
||||
"description": "Describes the dependency of a project where the vulnerability is located.",
|
||||
"required": [
|
||||
"package",
|
||||
"version"
|
||||
],
|
||||
"properties": {
|
||||
"package": {
|
||||
"type": "object",
|
||||
"description": "Provides information on the package where the vulnerability is located.",
|
||||
"required": [
|
||||
"name"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Name of the package where the vulnerability is located."
|
||||
}
|
||||
}
|
||||
},
|
||||
"version": {
|
||||
"type": "string",
|
||||
"description": "Version of the vulnerable package."
|
||||
},
|
||||
"iid": {
|
||||
"description": "ID that identifies the dependency in the scope of a dependency file.",
|
||||
"type": "number"
|
||||
},
|
||||
"direct": {
|
||||
"type": "boolean",
|
||||
"description": "Tells whether this is a direct, top-level dependency of the scanned project."
|
||||
},
|
||||
"dependency_path": {
|
||||
"type": "array",
|
||||
"description": "Ancestors of the dependency, starting from a direct project dependency, and ending with an immediate parent of the dependency. The dependency itself is excluded from the path. Direct dependencies have no path.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"iid"
|
||||
],
|
||||
"properties": {
|
||||
"iid": {
|
||||
"type": "number",
|
||||
"description": "ID that is unique in the scope of a parent object, and specific to the resource type."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"operating_system": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"description": "The operating system that contains the vulnerable package."
|
||||
},
|
||||
"image": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"description": "The analyzed Docker image."
|
||||
},
|
||||
"default_branch_image": {
|
||||
"type": "string",
|
||||
"maxLength": 255,
|
||||
"description": "The name of the image on the default branch."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"remediations": {
|
||||
"type": "array",
|
||||
"description": "An array of objects containing information on available remediations, along with patch diffs to apply.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"fixes",
|
||||
"summary",
|
||||
"diff"
|
||||
],
|
||||
"properties": {
|
||||
"fixes": {
|
||||
"type": "array",
|
||||
"description": "An array of strings that represent references to vulnerabilities fixed by this remediation.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"description": "Unique identifier of the vulnerability. This is recommended to be a UUID.",
|
||||
"examples": [
|
||||
"642735a5-1425-428d-8d4e-3c854885a3c9"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"summary": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"description": "An overview of how the vulnerabilities were fixed."
|
||||
},
|
||||
"diff": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"description": "A base64-encoded remediation code diff, compatible with git apply."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,874 @@
|
|||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"$id": "https://gitlab.com/gitlab-org/security-products/security-report-schemas/-/raw/master/dist/coverage-fuzzing-report-format.json",
|
||||
"title": "Report format for GitLab Fuzz Testing",
|
||||
"description": "This schema provides the report format for Coverage Guided Fuzz Testing (https://docs.gitlab.com/ee/user/application_security/coverage_fuzzing).",
|
||||
"definitions": {
|
||||
"detail_type": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/definitions/named_list"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/list"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/table"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/text"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/url"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/code"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/value"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/diff"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/markdown"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/commit"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/file_location"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/module_location"
|
||||
}
|
||||
]
|
||||
},
|
||||
"text_value": {
|
||||
"type": "string"
|
||||
},
|
||||
"named_field": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"$ref": "#/definitions/text_value",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"description": {
|
||||
"$ref": "#/definitions/text_value"
|
||||
}
|
||||
}
|
||||
},
|
||||
"named_list": {
|
||||
"type": "object",
|
||||
"description": "An object with named and typed fields",
|
||||
"required": [
|
||||
"type",
|
||||
"items"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "named-list"
|
||||
},
|
||||
"items": {
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"^.*$": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/named_field"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/detail_type"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"list": {
|
||||
"type": "object",
|
||||
"description": "A list of typed fields",
|
||||
"required": [
|
||||
"type",
|
||||
"items"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "list"
|
||||
},
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/detail_type"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"table": {
|
||||
"type": "object",
|
||||
"description": "A table of typed fields",
|
||||
"required": [
|
||||
"type",
|
||||
"rows"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "table"
|
||||
},
|
||||
"header": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/detail_type"
|
||||
}
|
||||
},
|
||||
"rows": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/detail_type"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"text": {
|
||||
"type": "object",
|
||||
"description": "Raw text",
|
||||
"required": [
|
||||
"type",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "text"
|
||||
},
|
||||
"value": {
|
||||
"$ref": "#/definitions/text_value"
|
||||
}
|
||||
}
|
||||
},
|
||||
"url": {
|
||||
"type": "object",
|
||||
"description": "A single URL",
|
||||
"required": [
|
||||
"type",
|
||||
"href"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "url"
|
||||
},
|
||||
"text": {
|
||||
"$ref": "#/definitions/text_value"
|
||||
},
|
||||
"href": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"http://mysite.com"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"code": {
|
||||
"type": "object",
|
||||
"description": "A codeblock",
|
||||
"required": [
|
||||
"type",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "code"
|
||||
},
|
||||
"value": {
|
||||
"type": "string"
|
||||
},
|
||||
"lang": {
|
||||
"type": "string",
|
||||
"description": "A programming language"
|
||||
}
|
||||
}
|
||||
},
|
||||
"value": {
|
||||
"type": "object",
|
||||
"description": "A field that can store a range of types of value",
|
||||
"required": [
|
||||
"type",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "value"
|
||||
},
|
||||
"value": {
|
||||
"type": [
|
||||
"number",
|
||||
"string",
|
||||
"boolean"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"diff": {
|
||||
"type": "object",
|
||||
"description": "A diff",
|
||||
"required": [
|
||||
"type",
|
||||
"before",
|
||||
"after"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "diff"
|
||||
},
|
||||
"before": {
|
||||
"type": "string"
|
||||
},
|
||||
"after": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"markdown": {
|
||||
"type": "object",
|
||||
"description": "GitLab flavoured markdown, see https://docs.gitlab.com/ee/user/markdown.html",
|
||||
"required": [
|
||||
"type",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "markdown"
|
||||
},
|
||||
"value": {
|
||||
"$ref": "#/definitions/text_value",
|
||||
"examples": [
|
||||
"Here is markdown `inline code` #1 [test](gitlab.com)\n\n![GitLab Logo](https://about.gitlab.com/images/press/logo/preview/gitlab-logo-white-preview.png)"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"commit": {
|
||||
"type": "object",
|
||||
"description": "A commit/tag/branch within the GitLab project",
|
||||
"required": [
|
||||
"type",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "commit"
|
||||
},
|
||||
"value": {
|
||||
"type": "string",
|
||||
"description": "The commit SHA",
|
||||
"minLength": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
"file_location": {
|
||||
"type": "object",
|
||||
"description": "A location within a file in the project",
|
||||
"required": [
|
||||
"type",
|
||||
"file_name",
|
||||
"line_start"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "file-location"
|
||||
},
|
||||
"file_name": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"line_start": {
|
||||
"type": "integer"
|
||||
},
|
||||
"line_end": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"module_location": {
|
||||
"type": "object",
|
||||
"description": "A location within a binary module of the form module+relative_offset",
|
||||
"required": [
|
||||
"type",
|
||||
"module_name",
|
||||
"offset"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "module-location"
|
||||
},
|
||||
"module_name": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"compiled_binary"
|
||||
]
|
||||
},
|
||||
"offset": {
|
||||
"type": "integer",
|
||||
"examples": [
|
||||
100
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"self": {
|
||||
"version": "15.0.4"
|
||||
},
|
||||
"type": "object",
|
||||
"required": [
|
||||
"scan",
|
||||
"version",
|
||||
"vulnerabilities"
|
||||
],
|
||||
"additionalProperties": true,
|
||||
"properties": {
|
||||
"scan": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"analyzer",
|
||||
"end_time",
|
||||
"scanner",
|
||||
"start_time",
|
||||
"status",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"end_time": {
|
||||
"type": "string",
|
||||
"description": "ISO8601 UTC value with format yyyy-mm-ddThh:mm:ss, representing when the scan finished.",
|
||||
"pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$",
|
||||
"examples": [
|
||||
"2020-01-28T03:26:02"
|
||||
]
|
||||
},
|
||||
"messages": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"description": "Communication intended for the initiator of a scan.",
|
||||
"required": [
|
||||
"level",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"level": {
|
||||
"type": "string",
|
||||
"description": "Describes the severity of the communication. Use info to communicate normal scan behaviour; warn to communicate a potentially recoverable problem, or a partial error; fatal to communicate an issue that causes the scan to halt.",
|
||||
"enum": [
|
||||
"info",
|
||||
"warn",
|
||||
"fatal"
|
||||
],
|
||||
"examples": [
|
||||
"info"
|
||||
]
|
||||
},
|
||||
"value": {
|
||||
"type": "string",
|
||||
"description": "The message to communicate.",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"Permission denied, scanning aborted"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"analyzer": {
|
||||
"type": "object",
|
||||
"description": "Object defining the analyzer used to perform the scan. Analyzers typically delegate to an underlying scanner to run the scan.",
|
||||
"required": [
|
||||
"id",
|
||||
"name",
|
||||
"version",
|
||||
"vendor"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"description": "Unique id that identifies the analyzer.",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"gitlab-dast"
|
||||
]
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "A human readable value that identifies the analyzer, not required to be unique.",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"GitLab DAST"
|
||||
]
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"pattern": "^https?://.+",
|
||||
"description": "A link to more information about the analyzer.",
|
||||
"examples": [
|
||||
"https://docs.gitlab.com/ee/user/application_security/dast"
|
||||
]
|
||||
},
|
||||
"vendor": {
|
||||
"description": "The vendor/maintainer of the analyzer.",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "The name of the vendor.",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"GitLab"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"version": {
|
||||
"type": "string",
|
||||
"description": "The version of the analyzer.",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"1.0.2"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"scanner": {
|
||||
"type": "object",
|
||||
"description": "Object defining the scanner used to perform the scan.",
|
||||
"required": [
|
||||
"id",
|
||||
"name",
|
||||
"version",
|
||||
"vendor"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"description": "Unique id that identifies the scanner.",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"my-sast-scanner"
|
||||
]
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "A human readable value that identifies the scanner, not required to be unique.",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"My SAST Scanner"
|
||||
]
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"description": "A link to more information about the scanner.",
|
||||
"examples": [
|
||||
"https://scanner.url"
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "string",
|
||||
"description": "The version of the scanner.",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"1.0.2"
|
||||
]
|
||||
},
|
||||
"vendor": {
|
||||
"description": "The vendor/maintainer of the scanner.",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "The name of the vendor.",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"GitLab"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"start_time": {
|
||||
"type": "string",
|
||||
"description": "ISO8601 UTC value with format yyyy-mm-ddThh:mm:ss, representing when the scan started.",
|
||||
"pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$",
|
||||
"examples": [
|
||||
"2020-02-14T16:01:59"
|
||||
]
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"description": "Result of the scan.",
|
||||
"enum": [
|
||||
"success",
|
||||
"failure"
|
||||
]
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"description": "Type of the scan.",
|
||||
"enum": [
|
||||
"coverage_fuzzing"
|
||||
]
|
||||
},
|
||||
"primary_identifiers": {
|
||||
"type": "array",
|
||||
"description": "An unordered array containing an exhaustive list of primary identifiers for which the analyzer may return results",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type",
|
||||
"name",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"description": "for example, cve, cwe, osvdb, usn, or an analyzer-dependent type such as gemnasium).",
|
||||
"minLength": 1
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Human-readable name of the identifier.",
|
||||
"minLength": 1
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"description": "URL of the identifier's documentation.",
|
||||
"pattern": "^https?://.+"
|
||||
},
|
||||
"value": {
|
||||
"type": "string",
|
||||
"description": "Value of the identifier, for matching purpose.",
|
||||
"minLength": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"description": "URI pointing to the validating security report schema.",
|
||||
"pattern": "^https?://.+"
|
||||
},
|
||||
"version": {
|
||||
"type": "string",
|
||||
"description": "The version of the schema to which the JSON report conforms.",
|
||||
"pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$"
|
||||
},
|
||||
"vulnerabilities": {
|
||||
"type": "array",
|
||||
"description": "Array of vulnerability objects.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"description": "Describes the vulnerability using GitLab Flavored Markdown",
|
||||
"required": [
|
||||
"id",
|
||||
"identifiers",
|
||||
"location"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"description": "Unique identifier of the vulnerability. This is recommended to be a UUID.",
|
||||
"examples": [
|
||||
"642735a5-1425-428d-8d4e-3c854885a3c9"
|
||||
]
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"maxLength": 255,
|
||||
"description": "The name of the vulnerability. This must not include the finding's specific information."
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"maxLength": 1048576,
|
||||
"description": "A long text section describing the vulnerability more fully."
|
||||
},
|
||||
"severity": {
|
||||
"type": "string",
|
||||
"description": "How much the vulnerability impacts the software. Possible values are Info, Unknown, Low, Medium, High, or Critical. Note that some analyzers may not report all these possible values.",
|
||||
"enum": [
|
||||
"Info",
|
||||
"Unknown",
|
||||
"Low",
|
||||
"Medium",
|
||||
"High",
|
||||
"Critical"
|
||||
]
|
||||
},
|
||||
"solution": {
|
||||
"type": "string",
|
||||
"maxLength": 7000,
|
||||
"description": "Explanation of how to fix the vulnerability."
|
||||
},
|
||||
"identifiers": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"description": "An ordered array of references that identify a vulnerability on internal or external databases. The first identifier is the Primary Identifier, which has special meaning.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type",
|
||||
"name",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"description": "for example, cve, cwe, osvdb, usn, or an analyzer-dependent type such as gemnasium).",
|
||||
"minLength": 1
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Human-readable name of the identifier.",
|
||||
"minLength": 1
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"description": "URL of the identifier's documentation.",
|
||||
"pattern": "^https?://.+"
|
||||
},
|
||||
"value": {
|
||||
"type": "string",
|
||||
"description": "Value of the identifier, for matching purpose.",
|
||||
"minLength": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"links": {
|
||||
"type": "array",
|
||||
"description": "An array of references to external documentation or articles that describe the vulnerability.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"url"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Name of the vulnerability details link."
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"description": "URL of the vulnerability details document.",
|
||||
"pattern": "^https?://.+"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"details": {
|
||||
"$ref": "#/definitions/named_list/properties/items"
|
||||
},
|
||||
"tracking": {
|
||||
"type": "object",
|
||||
"description": "Describes how this vulnerability should be tracked as the project changes.",
|
||||
"oneOf": [
|
||||
{
|
||||
"description": "Declares that a series of items should be tracked using source-specific tracking methods.",
|
||||
"required": [
|
||||
"items"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "source"
|
||||
},
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"description": "An item that should be tracked using source-specific tracking methods.",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"signatures"
|
||||
],
|
||||
"properties": {
|
||||
"file": {
|
||||
"type": "string",
|
||||
"description": "Path to the file where the vulnerability is located."
|
||||
},
|
||||
"start_line": {
|
||||
"type": "number",
|
||||
"description": "The first line of the file that includes the vulnerability."
|
||||
},
|
||||
"end_line": {
|
||||
"type": "number",
|
||||
"description": "The last line of the file that includes the vulnerability."
|
||||
},
|
||||
"signatures": {
|
||||
"type": "array",
|
||||
"description": "An array of calculated tracking signatures for this tracking item.",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"description": "A calculated tracking signature value and metadata.",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"algorithm",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"algorithm": {
|
||||
"type": "string",
|
||||
"description": "The algorithm used to generate the signature."
|
||||
},
|
||||
"value": {
|
||||
"type": "string",
|
||||
"description": "The result of this signature algorithm."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"description": "Each tracking type must declare its own type."
|
||||
}
|
||||
}
|
||||
},
|
||||
"flags": {
|
||||
"description": "Flags that can be attached to vulnerabilities.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"description": "Informational flags identified and assigned to a vulnerability.",
|
||||
"required": [
|
||||
"type",
|
||||
"origin",
|
||||
"description"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"description": "Result of the scan.",
|
||||
"enum": [
|
||||
"flagged-as-likely-false-positive"
|
||||
]
|
||||
},
|
||||
"origin": {
|
||||
"minLength": 1,
|
||||
"description": "Tool that issued the flag.",
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"minLength": 1,
|
||||
"description": "What the flag is about.",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"location": {
|
||||
"description": "The location of the error",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"crash_address": {
|
||||
"type": "string",
|
||||
"description": "The relative address in memory were the crash occurred.",
|
||||
"examples": [
|
||||
"0xabababab"
|
||||
]
|
||||
},
|
||||
"stacktrace_snippet": {
|
||||
"type": "string",
|
||||
"description": "The stack trace recorded during fuzzing resulting the crash.",
|
||||
"examples": [
|
||||
"func_a+0xabcd\nfunc_b+0xabcc"
|
||||
]
|
||||
},
|
||||
"crash_state": {
|
||||
"type": "string",
|
||||
"description": "Minimised and normalized crash stack-trace (called crash_state).",
|
||||
"examples": [
|
||||
"func_a+0xa\nfunc_b+0xb\nfunc_c+0xc"
|
||||
]
|
||||
},
|
||||
"crash_type": {
|
||||
"type": "string",
|
||||
"description": "Type of the crash.",
|
||||
"examples": [
|
||||
"Heap-Buffer-overflow",
|
||||
"Division-by-zero"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"remediations": {
|
||||
"type": "array",
|
||||
"description": "An array of objects containing information on available remediations, along with patch diffs to apply.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"fixes",
|
||||
"summary",
|
||||
"diff"
|
||||
],
|
||||
"properties": {
|
||||
"fixes": {
|
||||
"type": "array",
|
||||
"description": "An array of strings that represent references to vulnerabilities fixed by this remediation.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"description": "Unique identifier of the vulnerability. This is recommended to be a UUID.",
|
||||
"examples": [
|
||||
"642735a5-1425-428d-8d4e-3c854885a3c9"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"summary": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"description": "An overview of how the vulnerabilities were fixed."
|
||||
},
|
||||
"diff": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"description": "A base64-encoded remediation code diff, compatible with git apply."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,982 @@
|
|||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"$id": "https://gitlab.com/gitlab-org/security-products/security-report-schemas/-/raw/master/dist/dependency-scanning-report-format.json",
|
||||
"title": "Report format for GitLab Dependency Scanning",
|
||||
"description": "This schema provides the the report format for Dependency Scanning analyzers (https://docs.gitlab.com/ee/user/application_security/dependency_scanning).",
|
||||
"definitions": {
|
||||
"detail_type": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/definitions/named_list"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/list"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/table"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/text"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/url"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/code"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/value"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/diff"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/markdown"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/commit"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/file_location"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/module_location"
|
||||
}
|
||||
]
|
||||
},
|
||||
"text_value": {
|
||||
"type": "string"
|
||||
},
|
||||
"named_field": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"$ref": "#/definitions/text_value",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"description": {
|
||||
"$ref": "#/definitions/text_value"
|
||||
}
|
||||
}
|
||||
},
|
||||
"named_list": {
|
||||
"type": "object",
|
||||
"description": "An object with named and typed fields",
|
||||
"required": [
|
||||
"type",
|
||||
"items"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "named-list"
|
||||
},
|
||||
"items": {
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"^.*$": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/named_field"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/detail_type"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"list": {
|
||||
"type": "object",
|
||||
"description": "A list of typed fields",
|
||||
"required": [
|
||||
"type",
|
||||
"items"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "list"
|
||||
},
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/detail_type"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"table": {
|
||||
"type": "object",
|
||||
"description": "A table of typed fields",
|
||||
"required": [
|
||||
"type",
|
||||
"rows"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "table"
|
||||
},
|
||||
"header": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/detail_type"
|
||||
}
|
||||
},
|
||||
"rows": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/detail_type"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"text": {
|
||||
"type": "object",
|
||||
"description": "Raw text",
|
||||
"required": [
|
||||
"type",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "text"
|
||||
},
|
||||
"value": {
|
||||
"$ref": "#/definitions/text_value"
|
||||
}
|
||||
}
|
||||
},
|
||||
"url": {
|
||||
"type": "object",
|
||||
"description": "A single URL",
|
||||
"required": [
|
||||
"type",
|
||||
"href"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "url"
|
||||
},
|
||||
"text": {
|
||||
"$ref": "#/definitions/text_value"
|
||||
},
|
||||
"href": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"http://mysite.com"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"code": {
|
||||
"type": "object",
|
||||
"description": "A codeblock",
|
||||
"required": [
|
||||
"type",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "code"
|
||||
},
|
||||
"value": {
|
||||
"type": "string"
|
||||
},
|
||||
"lang": {
|
||||
"type": "string",
|
||||
"description": "A programming language"
|
||||
}
|
||||
}
|
||||
},
|
||||
"value": {
|
||||
"type": "object",
|
||||
"description": "A field that can store a range of types of value",
|
||||
"required": [
|
||||
"type",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "value"
|
||||
},
|
||||
"value": {
|
||||
"type": [
|
||||
"number",
|
||||
"string",
|
||||
"boolean"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"diff": {
|
||||
"type": "object",
|
||||
"description": "A diff",
|
||||
"required": [
|
||||
"type",
|
||||
"before",
|
||||
"after"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "diff"
|
||||
},
|
||||
"before": {
|
||||
"type": "string"
|
||||
},
|
||||
"after": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"markdown": {
|
||||
"type": "object",
|
||||
"description": "GitLab flavoured markdown, see https://docs.gitlab.com/ee/user/markdown.html",
|
||||
"required": [
|
||||
"type",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "markdown"
|
||||
},
|
||||
"value": {
|
||||
"$ref": "#/definitions/text_value",
|
||||
"examples": [
|
||||
"Here is markdown `inline code` #1 [test](gitlab.com)\n\n![GitLab Logo](https://about.gitlab.com/images/press/logo/preview/gitlab-logo-white-preview.png)"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"commit": {
|
||||
"type": "object",
|
||||
"description": "A commit/tag/branch within the GitLab project",
|
||||
"required": [
|
||||
"type",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "commit"
|
||||
},
|
||||
"value": {
|
||||
"type": "string",
|
||||
"description": "The commit SHA",
|
||||
"minLength": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
"file_location": {
|
||||
"type": "object",
|
||||
"description": "A location within a file in the project",
|
||||
"required": [
|
||||
"type",
|
||||
"file_name",
|
||||
"line_start"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "file-location"
|
||||
},
|
||||
"file_name": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"line_start": {
|
||||
"type": "integer"
|
||||
},
|
||||
"line_end": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"module_location": {
|
||||
"type": "object",
|
||||
"description": "A location within a binary module of the form module+relative_offset",
|
||||
"required": [
|
||||
"type",
|
||||
"module_name",
|
||||
"offset"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "module-location"
|
||||
},
|
||||
"module_name": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"compiled_binary"
|
||||
]
|
||||
},
|
||||
"offset": {
|
||||
"type": "integer",
|
||||
"examples": [
|
||||
100
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"self": {
|
||||
"version": "15.0.4"
|
||||
},
|
||||
"type": "object",
|
||||
"required": [
|
||||
"dependency_files",
|
||||
"scan",
|
||||
"version",
|
||||
"vulnerabilities"
|
||||
],
|
||||
"additionalProperties": true,
|
||||
"properties": {
|
||||
"scan": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"analyzer",
|
||||
"end_time",
|
||||
"scanner",
|
||||
"start_time",
|
||||
"status",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"end_time": {
|
||||
"type": "string",
|
||||
"description": "ISO8601 UTC value with format yyyy-mm-ddThh:mm:ss, representing when the scan finished.",
|
||||
"pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$",
|
||||
"examples": [
|
||||
"2020-01-28T03:26:02"
|
||||
]
|
||||
},
|
||||
"messages": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"description": "Communication intended for the initiator of a scan.",
|
||||
"required": [
|
||||
"level",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"level": {
|
||||
"type": "string",
|
||||
"description": "Describes the severity of the communication. Use info to communicate normal scan behaviour; warn to communicate a potentially recoverable problem, or a partial error; fatal to communicate an issue that causes the scan to halt.",
|
||||
"enum": [
|
||||
"info",
|
||||
"warn",
|
||||
"fatal"
|
||||
],
|
||||
"examples": [
|
||||
"info"
|
||||
]
|
||||
},
|
||||
"value": {
|
||||
"type": "string",
|
||||
"description": "The message to communicate.",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"Permission denied, scanning aborted"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"analyzer": {
|
||||
"type": "object",
|
||||
"description": "Object defining the analyzer used to perform the scan. Analyzers typically delegate to an underlying scanner to run the scan.",
|
||||
"required": [
|
||||
"id",
|
||||
"name",
|
||||
"version",
|
||||
"vendor"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"description": "Unique id that identifies the analyzer.",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"gitlab-dast"
|
||||
]
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "A human readable value that identifies the analyzer, not required to be unique.",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"GitLab DAST"
|
||||
]
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"pattern": "^https?://.+",
|
||||
"description": "A link to more information about the analyzer.",
|
||||
"examples": [
|
||||
"https://docs.gitlab.com/ee/user/application_security/dast"
|
||||
]
|
||||
},
|
||||
"vendor": {
|
||||
"description": "The vendor/maintainer of the analyzer.",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "The name of the vendor.",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"GitLab"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"version": {
|
||||
"type": "string",
|
||||
"description": "The version of the analyzer.",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"1.0.2"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"scanner": {
|
||||
"type": "object",
|
||||
"description": "Object defining the scanner used to perform the scan.",
|
||||
"required": [
|
||||
"id",
|
||||
"name",
|
||||
"version",
|
||||
"vendor"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"description": "Unique id that identifies the scanner.",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"my-sast-scanner"
|
||||
]
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "A human readable value that identifies the scanner, not required to be unique.",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"My SAST Scanner"
|
||||
]
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"description": "A link to more information about the scanner.",
|
||||
"examples": [
|
||||
"https://scanner.url"
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "string",
|
||||
"description": "The version of the scanner.",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"1.0.2"
|
||||
]
|
||||
},
|
||||
"vendor": {
|
||||
"description": "The vendor/maintainer of the scanner.",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "The name of the vendor.",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"GitLab"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"start_time": {
|
||||
"type": "string",
|
||||
"description": "ISO8601 UTC value with format yyyy-mm-ddThh:mm:ss, representing when the scan started.",
|
||||
"pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$",
|
||||
"examples": [
|
||||
"2020-02-14T16:01:59"
|
||||
]
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"description": "Result of the scan.",
|
||||
"enum": [
|
||||
"success",
|
||||
"failure"
|
||||
]
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"description": "Type of the scan.",
|
||||
"enum": [
|
||||
"dependency_scanning"
|
||||
]
|
||||
},
|
||||
"primary_identifiers": {
|
||||
"type": "array",
|
||||
"description": "An unordered array containing an exhaustive list of primary identifiers for which the analyzer may return results",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type",
|
||||
"name",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"description": "for example, cve, cwe, osvdb, usn, or an analyzer-dependent type such as gemnasium).",
|
||||
"minLength": 1
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Human-readable name of the identifier.",
|
||||
"minLength": 1
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"description": "URL of the identifier's documentation.",
|
||||
"pattern": "^https?://.+"
|
||||
},
|
||||
"value": {
|
||||
"type": "string",
|
||||
"description": "Value of the identifier, for matching purpose.",
|
||||
"minLength": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"description": "URI pointing to the validating security report schema.",
|
||||
"pattern": "^https?://.+"
|
||||
},
|
||||
"version": {
|
||||
"type": "string",
|
||||
"description": "The version of the schema to which the JSON report conforms.",
|
||||
"pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$"
|
||||
},
|
||||
"vulnerabilities": {
|
||||
"type": "array",
|
||||
"description": "Array of vulnerability objects.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"description": "Describes the vulnerability using GitLab Flavored Markdown",
|
||||
"required": [
|
||||
"id",
|
||||
"identifiers",
|
||||
"location"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"description": "Unique identifier of the vulnerability. This is recommended to be a UUID.",
|
||||
"examples": [
|
||||
"642735a5-1425-428d-8d4e-3c854885a3c9"
|
||||
]
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"maxLength": 255,
|
||||
"description": "The name of the vulnerability. This must not include the finding's specific information."
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"maxLength": 1048576,
|
||||
"description": "A long text section describing the vulnerability more fully."
|
||||
},
|
||||
"severity": {
|
||||
"type": "string",
|
||||
"description": "How much the vulnerability impacts the software. Possible values are Info, Unknown, Low, Medium, High, or Critical. Note that some analyzers may not report all these possible values.",
|
||||
"enum": [
|
||||
"Info",
|
||||
"Unknown",
|
||||
"Low",
|
||||
"Medium",
|
||||
"High",
|
||||
"Critical"
|
||||
]
|
||||
},
|
||||
"solution": {
|
||||
"type": "string",
|
||||
"maxLength": 7000,
|
||||
"description": "Explanation of how to fix the vulnerability."
|
||||
},
|
||||
"identifiers": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"description": "An ordered array of references that identify a vulnerability on internal or external databases. The first identifier is the Primary Identifier, which has special meaning.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type",
|
||||
"name",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"description": "for example, cve, cwe, osvdb, usn, or an analyzer-dependent type such as gemnasium).",
|
||||
"minLength": 1
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Human-readable name of the identifier.",
|
||||
"minLength": 1
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"description": "URL of the identifier's documentation.",
|
||||
"pattern": "^https?://.+"
|
||||
},
|
||||
"value": {
|
||||
"type": "string",
|
||||
"description": "Value of the identifier, for matching purpose.",
|
||||
"minLength": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"links": {
|
||||
"type": "array",
|
||||
"description": "An array of references to external documentation or articles that describe the vulnerability.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"url"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Name of the vulnerability details link."
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"description": "URL of the vulnerability details document.",
|
||||
"pattern": "^https?://.+"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"details": {
|
||||
"$ref": "#/definitions/named_list/properties/items"
|
||||
},
|
||||
"tracking": {
|
||||
"type": "object",
|
||||
"description": "Describes how this vulnerability should be tracked as the project changes.",
|
||||
"oneOf": [
|
||||
{
|
||||
"description": "Declares that a series of items should be tracked using source-specific tracking methods.",
|
||||
"required": [
|
||||
"items"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "source"
|
||||
},
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"description": "An item that should be tracked using source-specific tracking methods.",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"signatures"
|
||||
],
|
||||
"properties": {
|
||||
"file": {
|
||||
"type": "string",
|
||||
"description": "Path to the file where the vulnerability is located."
|
||||
},
|
||||
"start_line": {
|
||||
"type": "number",
|
||||
"description": "The first line of the file that includes the vulnerability."
|
||||
},
|
||||
"end_line": {
|
||||
"type": "number",
|
||||
"description": "The last line of the file that includes the vulnerability."
|
||||
},
|
||||
"signatures": {
|
||||
"type": "array",
|
||||
"description": "An array of calculated tracking signatures for this tracking item.",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"description": "A calculated tracking signature value and metadata.",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"algorithm",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"algorithm": {
|
||||
"type": "string",
|
||||
"description": "The algorithm used to generate the signature."
|
||||
},
|
||||
"value": {
|
||||
"type": "string",
|
||||
"description": "The result of this signature algorithm."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"description": "Each tracking type must declare its own type."
|
||||
}
|
||||
}
|
||||
},
|
||||
"flags": {
|
||||
"description": "Flags that can be attached to vulnerabilities.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"description": "Informational flags identified and assigned to a vulnerability.",
|
||||
"required": [
|
||||
"type",
|
||||
"origin",
|
||||
"description"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"description": "Result of the scan.",
|
||||
"enum": [
|
||||
"flagged-as-likely-false-positive"
|
||||
]
|
||||
},
|
||||
"origin": {
|
||||
"minLength": 1,
|
||||
"description": "Tool that issued the flag.",
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"minLength": 1,
|
||||
"description": "What the flag is about.",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"location": {
|
||||
"type": "object",
|
||||
"description": "Identifies the vulnerability's location.",
|
||||
"required": [
|
||||
"file",
|
||||
"dependency"
|
||||
],
|
||||
"properties": {
|
||||
"file": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"description": "Path to the manifest or lock file where the dependency is declared (such as yarn.lock)."
|
||||
},
|
||||
"dependency": {
|
||||
"type": "object",
|
||||
"description": "Describes the dependency of a project where the vulnerability is located.",
|
||||
"required": [
|
||||
"package",
|
||||
"version"
|
||||
],
|
||||
"properties": {
|
||||
"package": {
|
||||
"type": "object",
|
||||
"description": "Provides information on the package where the vulnerability is located.",
|
||||
"required": [
|
||||
"name"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Name of the package where the vulnerability is located."
|
||||
}
|
||||
}
|
||||
},
|
||||
"version": {
|
||||
"type": "string",
|
||||
"description": "Version of the vulnerable package."
|
||||
},
|
||||
"iid": {
|
||||
"description": "ID that identifies the dependency in the scope of a dependency file.",
|
||||
"type": "number"
|
||||
},
|
||||
"direct": {
|
||||
"type": "boolean",
|
||||
"description": "Tells whether this is a direct, top-level dependency of the scanned project."
|
||||
},
|
||||
"dependency_path": {
|
||||
"type": "array",
|
||||
"description": "Ancestors of the dependency, starting from a direct project dependency, and ending with an immediate parent of the dependency. The dependency itself is excluded from the path. Direct dependencies have no path.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"iid"
|
||||
],
|
||||
"properties": {
|
||||
"iid": {
|
||||
"type": "number",
|
||||
"description": "ID that is unique in the scope of a parent object, and specific to the resource type."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"remediations": {
|
||||
"type": "array",
|
||||
"description": "An array of objects containing information on available remediations, along with patch diffs to apply.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"fixes",
|
||||
"summary",
|
||||
"diff"
|
||||
],
|
||||
"properties": {
|
||||
"fixes": {
|
||||
"type": "array",
|
||||
"description": "An array of strings that represent references to vulnerabilities fixed by this remediation.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"description": "Unique identifier of the vulnerability. This is recommended to be a UUID.",
|
||||
"examples": [
|
||||
"642735a5-1425-428d-8d4e-3c854885a3c9"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"summary": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"description": "An overview of how the vulnerabilities were fixed."
|
||||
},
|
||||
"diff": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"description": "A base64-encoded remediation code diff, compatible with git apply."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"dependency_files": {
|
||||
"type": "array",
|
||||
"description": "List of dependency files identified in the project.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"path",
|
||||
"package_manager",
|
||||
"dependencies"
|
||||
],
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"package_manager": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"dependencies": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"description": "Describes the dependency of a project where the vulnerability is located.",
|
||||
"required": [
|
||||
"package",
|
||||
"version"
|
||||
],
|
||||
"properties": {
|
||||
"package": {
|
||||
"type": "object",
|
||||
"description": "Provides information on the package where the vulnerability is located.",
|
||||
"required": [
|
||||
"name"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Name of the package where the vulnerability is located."
|
||||
}
|
||||
}
|
||||
},
|
||||
"version": {
|
||||
"type": "string",
|
||||
"description": "Version of the vulnerable package."
|
||||
},
|
||||
"iid": {
|
||||
"description": "ID that identifies the dependency in the scope of a dependency file.",
|
||||
"type": "number"
|
||||
},
|
||||
"direct": {
|
||||
"type": "boolean",
|
||||
"description": "Tells whether this is a direct, top-level dependency of the scanned project."
|
||||
},
|
||||
"dependency_path": {
|
||||
"type": "array",
|
||||
"description": "Ancestors of the dependency, starting from a direct project dependency, and ending with an immediate parent of the dependency. The dependency itself is excluded from the path. Direct dependencies have no path.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"iid"
|
||||
],
|
||||
"properties": {
|
||||
"iid": {
|
||||
"type": "number",
|
||||
"description": "ID that is unique in the scope of a parent object, and specific to the resource type."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,869 @@
|
|||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"$id": "https://gitlab.com/gitlab-org/security-products/security-report-schemas/-/raw/master/dist/sast-report-format.json",
|
||||
"title": "Report format for GitLab SAST",
|
||||
"description": "This schema provides the report format for Static Application Security Testing analyzers (https://docs.gitlab.com/ee/user/application_security/sast).",
|
||||
"definitions": {
|
||||
"detail_type": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/definitions/named_list"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/list"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/table"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/text"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/url"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/code"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/value"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/diff"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/markdown"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/commit"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/file_location"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/module_location"
|
||||
}
|
||||
]
|
||||
},
|
||||
"text_value": {
|
||||
"type": "string"
|
||||
},
|
||||
"named_field": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"$ref": "#/definitions/text_value",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"description": {
|
||||
"$ref": "#/definitions/text_value"
|
||||
}
|
||||
}
|
||||
},
|
||||
"named_list": {
|
||||
"type": "object",
|
||||
"description": "An object with named and typed fields",
|
||||
"required": [
|
||||
"type",
|
||||
"items"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "named-list"
|
||||
},
|
||||
"items": {
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"^.*$": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/named_field"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/detail_type"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"list": {
|
||||
"type": "object",
|
||||
"description": "A list of typed fields",
|
||||
"required": [
|
||||
"type",
|
||||
"items"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "list"
|
||||
},
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/detail_type"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"table": {
|
||||
"type": "object",
|
||||
"description": "A table of typed fields",
|
||||
"required": [
|
||||
"type",
|
||||
"rows"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "table"
|
||||
},
|
||||
"header": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/detail_type"
|
||||
}
|
||||
},
|
||||
"rows": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/detail_type"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"text": {
|
||||
"type": "object",
|
||||
"description": "Raw text",
|
||||
"required": [
|
||||
"type",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "text"
|
||||
},
|
||||
"value": {
|
||||
"$ref": "#/definitions/text_value"
|
||||
}
|
||||
}
|
||||
},
|
||||
"url": {
|
||||
"type": "object",
|
||||
"description": "A single URL",
|
||||
"required": [
|
||||
"type",
|
||||
"href"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "url"
|
||||
},
|
||||
"text": {
|
||||
"$ref": "#/definitions/text_value"
|
||||
},
|
||||
"href": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"http://mysite.com"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"code": {
|
||||
"type": "object",
|
||||
"description": "A codeblock",
|
||||
"required": [
|
||||
"type",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "code"
|
||||
},
|
||||
"value": {
|
||||
"type": "string"
|
||||
},
|
||||
"lang": {
|
||||
"type": "string",
|
||||
"description": "A programming language"
|
||||
}
|
||||
}
|
||||
},
|
||||
"value": {
|
||||
"type": "object",
|
||||
"description": "A field that can store a range of types of value",
|
||||
"required": [
|
||||
"type",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "value"
|
||||
},
|
||||
"value": {
|
||||
"type": [
|
||||
"number",
|
||||
"string",
|
||||
"boolean"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"diff": {
|
||||
"type": "object",
|
||||
"description": "A diff",
|
||||
"required": [
|
||||
"type",
|
||||
"before",
|
||||
"after"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "diff"
|
||||
},
|
||||
"before": {
|
||||
"type": "string"
|
||||
},
|
||||
"after": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"markdown": {
|
||||
"type": "object",
|
||||
"description": "GitLab flavoured markdown, see https://docs.gitlab.com/ee/user/markdown.html",
|
||||
"required": [
|
||||
"type",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "markdown"
|
||||
},
|
||||
"value": {
|
||||
"$ref": "#/definitions/text_value",
|
||||
"examples": [
|
||||
"Here is markdown `inline code` #1 [test](gitlab.com)\n\n![GitLab Logo](https://about.gitlab.com/images/press/logo/preview/gitlab-logo-white-preview.png)"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"commit": {
|
||||
"type": "object",
|
||||
"description": "A commit/tag/branch within the GitLab project",
|
||||
"required": [
|
||||
"type",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "commit"
|
||||
},
|
||||
"value": {
|
||||
"type": "string",
|
||||
"description": "The commit SHA",
|
||||
"minLength": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
"file_location": {
|
||||
"type": "object",
|
||||
"description": "A location within a file in the project",
|
||||
"required": [
|
||||
"type",
|
||||
"file_name",
|
||||
"line_start"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "file-location"
|
||||
},
|
||||
"file_name": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"line_start": {
|
||||
"type": "integer"
|
||||
},
|
||||
"line_end": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"module_location": {
|
||||
"type": "object",
|
||||
"description": "A location within a binary module of the form module+relative_offset",
|
||||
"required": [
|
||||
"type",
|
||||
"module_name",
|
||||
"offset"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "module-location"
|
||||
},
|
||||
"module_name": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"compiled_binary"
|
||||
]
|
||||
},
|
||||
"offset": {
|
||||
"type": "integer",
|
||||
"examples": [
|
||||
100
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"self": {
|
||||
"version": "15.0.4"
|
||||
},
|
||||
"type": "object",
|
||||
"required": [
|
||||
"scan",
|
||||
"version",
|
||||
"vulnerabilities"
|
||||
],
|
||||
"additionalProperties": true,
|
||||
"properties": {
|
||||
"scan": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"analyzer",
|
||||
"end_time",
|
||||
"scanner",
|
||||
"start_time",
|
||||
"status",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"end_time": {
|
||||
"type": "string",
|
||||
"description": "ISO8601 UTC value with format yyyy-mm-ddThh:mm:ss, representing when the scan finished.",
|
||||
"pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$",
|
||||
"examples": [
|
||||
"2020-01-28T03:26:02"
|
||||
]
|
||||
},
|
||||
"messages": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"description": "Communication intended for the initiator of a scan.",
|
||||
"required": [
|
||||
"level",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"level": {
|
||||
"type": "string",
|
||||
"description": "Describes the severity of the communication. Use info to communicate normal scan behaviour; warn to communicate a potentially recoverable problem, or a partial error; fatal to communicate an issue that causes the scan to halt.",
|
||||
"enum": [
|
||||
"info",
|
||||
"warn",
|
||||
"fatal"
|
||||
],
|
||||
"examples": [
|
||||
"info"
|
||||
]
|
||||
},
|
||||
"value": {
|
||||
"type": "string",
|
||||
"description": "The message to communicate.",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"Permission denied, scanning aborted"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"analyzer": {
|
||||
"type": "object",
|
||||
"description": "Object defining the analyzer used to perform the scan. Analyzers typically delegate to an underlying scanner to run the scan.",
|
||||
"required": [
|
||||
"id",
|
||||
"name",
|
||||
"version",
|
||||
"vendor"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"description": "Unique id that identifies the analyzer.",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"gitlab-dast"
|
||||
]
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "A human readable value that identifies the analyzer, not required to be unique.",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"GitLab DAST"
|
||||
]
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"pattern": "^https?://.+",
|
||||
"description": "A link to more information about the analyzer.",
|
||||
"examples": [
|
||||
"https://docs.gitlab.com/ee/user/application_security/dast"
|
||||
]
|
||||
},
|
||||
"vendor": {
|
||||
"description": "The vendor/maintainer of the analyzer.",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "The name of the vendor.",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"GitLab"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"version": {
|
||||
"type": "string",
|
||||
"description": "The version of the analyzer.",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"1.0.2"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"scanner": {
|
||||
"type": "object",
|
||||
"description": "Object defining the scanner used to perform the scan.",
|
||||
"required": [
|
||||
"id",
|
||||
"name",
|
||||
"version",
|
||||
"vendor"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"description": "Unique id that identifies the scanner.",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"my-sast-scanner"
|
||||
]
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "A human readable value that identifies the scanner, not required to be unique.",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"My SAST Scanner"
|
||||
]
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"description": "A link to more information about the scanner.",
|
||||
"examples": [
|
||||
"https://scanner.url"
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "string",
|
||||
"description": "The version of the scanner.",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"1.0.2"
|
||||
]
|
||||
},
|
||||
"vendor": {
|
||||
"description": "The vendor/maintainer of the scanner.",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "The name of the vendor.",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"GitLab"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"start_time": {
|
||||
"type": "string",
|
||||
"description": "ISO8601 UTC value with format yyyy-mm-ddThh:mm:ss, representing when the scan started.",
|
||||
"pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$",
|
||||
"examples": [
|
||||
"2020-02-14T16:01:59"
|
||||
]
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"description": "Result of the scan.",
|
||||
"enum": [
|
||||
"success",
|
||||
"failure"
|
||||
]
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"description": "Type of the scan.",
|
||||
"enum": [
|
||||
"sast"
|
||||
]
|
||||
},
|
||||
"primary_identifiers": {
|
||||
"type": "array",
|
||||
"description": "An unordered array containing an exhaustive list of primary identifiers for which the analyzer may return results",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type",
|
||||
"name",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"description": "for example, cve, cwe, osvdb, usn, or an analyzer-dependent type such as gemnasium).",
|
||||
"minLength": 1
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Human-readable name of the identifier.",
|
||||
"minLength": 1
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"description": "URL of the identifier's documentation.",
|
||||
"pattern": "^https?://.+"
|
||||
},
|
||||
"value": {
|
||||
"type": "string",
|
||||
"description": "Value of the identifier, for matching purpose.",
|
||||
"minLength": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"description": "URI pointing to the validating security report schema.",
|
||||
"pattern": "^https?://.+"
|
||||
},
|
||||
"version": {
|
||||
"type": "string",
|
||||
"description": "The version of the schema to which the JSON report conforms.",
|
||||
"pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$"
|
||||
},
|
||||
"vulnerabilities": {
|
||||
"type": "array",
|
||||
"description": "Array of vulnerability objects.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"description": "Describes the vulnerability using GitLab Flavored Markdown",
|
||||
"required": [
|
||||
"id",
|
||||
"identifiers",
|
||||
"location"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"description": "Unique identifier of the vulnerability. This is recommended to be a UUID.",
|
||||
"examples": [
|
||||
"642735a5-1425-428d-8d4e-3c854885a3c9"
|
||||
]
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"maxLength": 255,
|
||||
"description": "The name of the vulnerability. This must not include the finding's specific information."
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"maxLength": 1048576,
|
||||
"description": "A long text section describing the vulnerability more fully."
|
||||
},
|
||||
"severity": {
|
||||
"type": "string",
|
||||
"description": "How much the vulnerability impacts the software. Possible values are Info, Unknown, Low, Medium, High, or Critical. Note that some analyzers may not report all these possible values.",
|
||||
"enum": [
|
||||
"Info",
|
||||
"Unknown",
|
||||
"Low",
|
||||
"Medium",
|
||||
"High",
|
||||
"Critical"
|
||||
]
|
||||
},
|
||||
"solution": {
|
||||
"type": "string",
|
||||
"maxLength": 7000,
|
||||
"description": "Explanation of how to fix the vulnerability."
|
||||
},
|
||||
"identifiers": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"description": "An ordered array of references that identify a vulnerability on internal or external databases. The first identifier is the Primary Identifier, which has special meaning.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type",
|
||||
"name",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"description": "for example, cve, cwe, osvdb, usn, or an analyzer-dependent type such as gemnasium).",
|
||||
"minLength": 1
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Human-readable name of the identifier.",
|
||||
"minLength": 1
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"description": "URL of the identifier's documentation.",
|
||||
"pattern": "^https?://.+"
|
||||
},
|
||||
"value": {
|
||||
"type": "string",
|
||||
"description": "Value of the identifier, for matching purpose.",
|
||||
"minLength": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"links": {
|
||||
"type": "array",
|
||||
"description": "An array of references to external documentation or articles that describe the vulnerability.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"url"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Name of the vulnerability details link."
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"description": "URL of the vulnerability details document.",
|
||||
"pattern": "^https?://.+"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"details": {
|
||||
"$ref": "#/definitions/named_list/properties/items"
|
||||
},
|
||||
"tracking": {
|
||||
"type": "object",
|
||||
"description": "Describes how this vulnerability should be tracked as the project changes.",
|
||||
"oneOf": [
|
||||
{
|
||||
"description": "Declares that a series of items should be tracked using source-specific tracking methods.",
|
||||
"required": [
|
||||
"items"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "source"
|
||||
},
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"description": "An item that should be tracked using source-specific tracking methods.",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"signatures"
|
||||
],
|
||||
"properties": {
|
||||
"file": {
|
||||
"type": "string",
|
||||
"description": "Path to the file where the vulnerability is located."
|
||||
},
|
||||
"start_line": {
|
||||
"type": "number",
|
||||
"description": "The first line of the file that includes the vulnerability."
|
||||
},
|
||||
"end_line": {
|
||||
"type": "number",
|
||||
"description": "The last line of the file that includes the vulnerability."
|
||||
},
|
||||
"signatures": {
|
||||
"type": "array",
|
||||
"description": "An array of calculated tracking signatures for this tracking item.",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"description": "A calculated tracking signature value and metadata.",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"algorithm",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"algorithm": {
|
||||
"type": "string",
|
||||
"description": "The algorithm used to generate the signature."
|
||||
},
|
||||
"value": {
|
||||
"type": "string",
|
||||
"description": "The result of this signature algorithm."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"description": "Each tracking type must declare its own type."
|
||||
}
|
||||
}
|
||||
},
|
||||
"flags": {
|
||||
"description": "Flags that can be attached to vulnerabilities.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"description": "Informational flags identified and assigned to a vulnerability.",
|
||||
"required": [
|
||||
"type",
|
||||
"origin",
|
||||
"description"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"description": "Result of the scan.",
|
||||
"enum": [
|
||||
"flagged-as-likely-false-positive"
|
||||
]
|
||||
},
|
||||
"origin": {
|
||||
"minLength": 1,
|
||||
"description": "Tool that issued the flag.",
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"minLength": 1,
|
||||
"description": "What the flag is about.",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"location": {
|
||||
"type": "object",
|
||||
"description": "Identifies the vulnerability's location.",
|
||||
"properties": {
|
||||
"file": {
|
||||
"type": "string",
|
||||
"description": "Path to the file where the vulnerability is located."
|
||||
},
|
||||
"start_line": {
|
||||
"type": "number",
|
||||
"description": "The first line of the code affected by the vulnerability."
|
||||
},
|
||||
"end_line": {
|
||||
"type": "number",
|
||||
"description": "The last line of the code affected by the vulnerability."
|
||||
},
|
||||
"class": {
|
||||
"type": "string",
|
||||
"description": "Provides the name of the class where the vulnerability is located."
|
||||
},
|
||||
"method": {
|
||||
"type": "string",
|
||||
"description": "Provides the name of the method where the vulnerability is located."
|
||||
}
|
||||
}
|
||||
},
|
||||
"raw_source_code_extract": {
|
||||
"type": "string",
|
||||
"description": "Provides an unsanitized excerpt of the affected source code."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"remediations": {
|
||||
"type": "array",
|
||||
"description": "An array of objects containing information on available remediations, along with patch diffs to apply.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"fixes",
|
||||
"summary",
|
||||
"diff"
|
||||
],
|
||||
"properties": {
|
||||
"fixes": {
|
||||
"type": "array",
|
||||
"description": "An array of strings that represent references to vulnerabilities fixed by this remediation.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"description": "Unique identifier of the vulnerability. This is recommended to be a UUID.",
|
||||
"examples": [
|
||||
"642735a5-1425-428d-8d4e-3c854885a3c9"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"summary": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"description": "An overview of how the vulnerabilities were fixed."
|
||||
},
|
||||
"diff": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"description": "A base64-encoded remediation code diff, compatible with git apply."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,893 @@
|
|||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"$id": "https://gitlab.com/gitlab-org/security-products/security-report-schemas/-/raw/master/dist/secret-detection-report-format.json",
|
||||
"title": "Report format for GitLab Secret Detection",
|
||||
"description": "This schema provides the the report format for the Secret Detection analyzer (https://docs.gitlab.com/ee/user/application_security/secret_detection)",
|
||||
"definitions": {
|
||||
"detail_type": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/definitions/named_list"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/list"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/table"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/text"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/url"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/code"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/value"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/diff"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/markdown"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/commit"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/file_location"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/module_location"
|
||||
}
|
||||
]
|
||||
},
|
||||
"text_value": {
|
||||
"type": "string"
|
||||
},
|
||||
"named_field": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"$ref": "#/definitions/text_value",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"description": {
|
||||
"$ref": "#/definitions/text_value"
|
||||
}
|
||||
}
|
||||
},
|
||||
"named_list": {
|
||||
"type": "object",
|
||||
"description": "An object with named and typed fields",
|
||||
"required": [
|
||||
"type",
|
||||
"items"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "named-list"
|
||||
},
|
||||
"items": {
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"^.*$": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/named_field"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/detail_type"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"list": {
|
||||
"type": "object",
|
||||
"description": "A list of typed fields",
|
||||
"required": [
|
||||
"type",
|
||||
"items"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "list"
|
||||
},
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/detail_type"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"table": {
|
||||
"type": "object",
|
||||
"description": "A table of typed fields",
|
||||
"required": [
|
||||
"type",
|
||||
"rows"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "table"
|
||||
},
|
||||
"header": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/detail_type"
|
||||
}
|
||||
},
|
||||
"rows": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/detail_type"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"text": {
|
||||
"type": "object",
|
||||
"description": "Raw text",
|
||||
"required": [
|
||||
"type",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "text"
|
||||
},
|
||||
"value": {
|
||||
"$ref": "#/definitions/text_value"
|
||||
}
|
||||
}
|
||||
},
|
||||
"url": {
|
||||
"type": "object",
|
||||
"description": "A single URL",
|
||||
"required": [
|
||||
"type",
|
||||
"href"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "url"
|
||||
},
|
||||
"text": {
|
||||
"$ref": "#/definitions/text_value"
|
||||
},
|
||||
"href": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"http://mysite.com"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"code": {
|
||||
"type": "object",
|
||||
"description": "A codeblock",
|
||||
"required": [
|
||||
"type",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "code"
|
||||
},
|
||||
"value": {
|
||||
"type": "string"
|
||||
},
|
||||
"lang": {
|
||||
"type": "string",
|
||||
"description": "A programming language"
|
||||
}
|
||||
}
|
||||
},
|
||||
"value": {
|
||||
"type": "object",
|
||||
"description": "A field that can store a range of types of value",
|
||||
"required": [
|
||||
"type",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "value"
|
||||
},
|
||||
"value": {
|
||||
"type": [
|
||||
"number",
|
||||
"string",
|
||||
"boolean"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"diff": {
|
||||
"type": "object",
|
||||
"description": "A diff",
|
||||
"required": [
|
||||
"type",
|
||||
"before",
|
||||
"after"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "diff"
|
||||
},
|
||||
"before": {
|
||||
"type": "string"
|
||||
},
|
||||
"after": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"markdown": {
|
||||
"type": "object",
|
||||
"description": "GitLab flavoured markdown, see https://docs.gitlab.com/ee/user/markdown.html",
|
||||
"required": [
|
||||
"type",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "markdown"
|
||||
},
|
||||
"value": {
|
||||
"$ref": "#/definitions/text_value",
|
||||
"examples": [
|
||||
"Here is markdown `inline code` #1 [test](gitlab.com)\n\n![GitLab Logo](https://about.gitlab.com/images/press/logo/preview/gitlab-logo-white-preview.png)"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"commit": {
|
||||
"type": "object",
|
||||
"description": "A commit/tag/branch within the GitLab project",
|
||||
"required": [
|
||||
"type",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "commit"
|
||||
},
|
||||
"value": {
|
||||
"type": "string",
|
||||
"description": "The commit SHA",
|
||||
"minLength": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
"file_location": {
|
||||
"type": "object",
|
||||
"description": "A location within a file in the project",
|
||||
"required": [
|
||||
"type",
|
||||
"file_name",
|
||||
"line_start"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "file-location"
|
||||
},
|
||||
"file_name": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"line_start": {
|
||||
"type": "integer"
|
||||
},
|
||||
"line_end": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"module_location": {
|
||||
"type": "object",
|
||||
"description": "A location within a binary module of the form module+relative_offset",
|
||||
"required": [
|
||||
"type",
|
||||
"module_name",
|
||||
"offset"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "module-location"
|
||||
},
|
||||
"module_name": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"compiled_binary"
|
||||
]
|
||||
},
|
||||
"offset": {
|
||||
"type": "integer",
|
||||
"examples": [
|
||||
100
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"self": {
|
||||
"version": "15.0.4"
|
||||
},
|
||||
"type": "object",
|
||||
"required": [
|
||||
"scan",
|
||||
"version",
|
||||
"vulnerabilities"
|
||||
],
|
||||
"additionalProperties": true,
|
||||
"properties": {
|
||||
"scan": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"analyzer",
|
||||
"end_time",
|
||||
"scanner",
|
||||
"start_time",
|
||||
"status",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"end_time": {
|
||||
"type": "string",
|
||||
"description": "ISO8601 UTC value with format yyyy-mm-ddThh:mm:ss, representing when the scan finished.",
|
||||
"pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$",
|
||||
"examples": [
|
||||
"2020-01-28T03:26:02"
|
||||
]
|
||||
},
|
||||
"messages": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"description": "Communication intended for the initiator of a scan.",
|
||||
"required": [
|
||||
"level",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"level": {
|
||||
"type": "string",
|
||||
"description": "Describes the severity of the communication. Use info to communicate normal scan behaviour; warn to communicate a potentially recoverable problem, or a partial error; fatal to communicate an issue that causes the scan to halt.",
|
||||
"enum": [
|
||||
"info",
|
||||
"warn",
|
||||
"fatal"
|
||||
],
|
||||
"examples": [
|
||||
"info"
|
||||
]
|
||||
},
|
||||
"value": {
|
||||
"type": "string",
|
||||
"description": "The message to communicate.",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"Permission denied, scanning aborted"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"analyzer": {
|
||||
"type": "object",
|
||||
"description": "Object defining the analyzer used to perform the scan. Analyzers typically delegate to an underlying scanner to run the scan.",
|
||||
"required": [
|
||||
"id",
|
||||
"name",
|
||||
"version",
|
||||
"vendor"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"description": "Unique id that identifies the analyzer.",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"gitlab-dast"
|
||||
]
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "A human readable value that identifies the analyzer, not required to be unique.",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"GitLab DAST"
|
||||
]
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"pattern": "^https?://.+",
|
||||
"description": "A link to more information about the analyzer.",
|
||||
"examples": [
|
||||
"https://docs.gitlab.com/ee/user/application_security/dast"
|
||||
]
|
||||
},
|
||||
"vendor": {
|
||||
"description": "The vendor/maintainer of the analyzer.",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "The name of the vendor.",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"GitLab"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"version": {
|
||||
"type": "string",
|
||||
"description": "The version of the analyzer.",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"1.0.2"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"scanner": {
|
||||
"type": "object",
|
||||
"description": "Object defining the scanner used to perform the scan.",
|
||||
"required": [
|
||||
"id",
|
||||
"name",
|
||||
"version",
|
||||
"vendor"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"description": "Unique id that identifies the scanner.",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"my-sast-scanner"
|
||||
]
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "A human readable value that identifies the scanner, not required to be unique.",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"My SAST Scanner"
|
||||
]
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"description": "A link to more information about the scanner.",
|
||||
"examples": [
|
||||
"https://scanner.url"
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "string",
|
||||
"description": "The version of the scanner.",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"1.0.2"
|
||||
]
|
||||
},
|
||||
"vendor": {
|
||||
"description": "The vendor/maintainer of the scanner.",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "The name of the vendor.",
|
||||
"minLength": 1,
|
||||
"examples": [
|
||||
"GitLab"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"start_time": {
|
||||
"type": "string",
|
||||
"description": "ISO8601 UTC value with format yyyy-mm-ddThh:mm:ss, representing when the scan started.",
|
||||
"pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$",
|
||||
"examples": [
|
||||
"2020-02-14T16:01:59"
|
||||
]
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"description": "Result of the scan.",
|
||||
"enum": [
|
||||
"success",
|
||||
"failure"
|
||||
]
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"description": "Type of the scan.",
|
||||
"enum": [
|
||||
"secret_detection"
|
||||
]
|
||||
},
|
||||
"primary_identifiers": {
|
||||
"type": "array",
|
||||
"description": "An unordered array containing an exhaustive list of primary identifiers for which the analyzer may return results",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type",
|
||||
"name",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"description": "for example, cve, cwe, osvdb, usn, or an analyzer-dependent type such as gemnasium).",
|
||||
"minLength": 1
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Human-readable name of the identifier.",
|
||||
"minLength": 1
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"description": "URL of the identifier's documentation.",
|
||||
"pattern": "^https?://.+"
|
||||
},
|
||||
"value": {
|
||||
"type": "string",
|
||||
"description": "Value of the identifier, for matching purpose.",
|
||||
"minLength": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"description": "URI pointing to the validating security report schema.",
|
||||
"pattern": "^https?://.+"
|
||||
},
|
||||
"version": {
|
||||
"type": "string",
|
||||
"description": "The version of the schema to which the JSON report conforms.",
|
||||
"pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$"
|
||||
},
|
||||
"vulnerabilities": {
|
||||
"type": "array",
|
||||
"description": "Array of vulnerability objects.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"description": "Describes the vulnerability using GitLab Flavored Markdown",
|
||||
"required": [
|
||||
"id",
|
||||
"identifiers",
|
||||
"location"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"description": "Unique identifier of the vulnerability. This is recommended to be a UUID.",
|
||||
"examples": [
|
||||
"642735a5-1425-428d-8d4e-3c854885a3c9"
|
||||
]
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"maxLength": 255,
|
||||
"description": "The name of the vulnerability. This must not include the finding's specific information."
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"maxLength": 1048576,
|
||||
"description": "A long text section describing the vulnerability more fully."
|
||||
},
|
||||
"severity": {
|
||||
"type": "string",
|
||||
"description": "How much the vulnerability impacts the software. Possible values are Info, Unknown, Low, Medium, High, or Critical. Note that some analyzers may not report all these possible values.",
|
||||
"enum": [
|
||||
"Info",
|
||||
"Unknown",
|
||||
"Low",
|
||||
"Medium",
|
||||
"High",
|
||||
"Critical"
|
||||
]
|
||||
},
|
||||
"solution": {
|
||||
"type": "string",
|
||||
"maxLength": 7000,
|
||||
"description": "Explanation of how to fix the vulnerability."
|
||||
},
|
||||
"identifiers": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"description": "An ordered array of references that identify a vulnerability on internal or external databases. The first identifier is the Primary Identifier, which has special meaning.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type",
|
||||
"name",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"description": "for example, cve, cwe, osvdb, usn, or an analyzer-dependent type such as gemnasium).",
|
||||
"minLength": 1
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Human-readable name of the identifier.",
|
||||
"minLength": 1
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"description": "URL of the identifier's documentation.",
|
||||
"pattern": "^https?://.+"
|
||||
},
|
||||
"value": {
|
||||
"type": "string",
|
||||
"description": "Value of the identifier, for matching purpose.",
|
||||
"minLength": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"links": {
|
||||
"type": "array",
|
||||
"description": "An array of references to external documentation or articles that describe the vulnerability.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"url"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Name of the vulnerability details link."
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"description": "URL of the vulnerability details document.",
|
||||
"pattern": "^https?://.+"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"details": {
|
||||
"$ref": "#/definitions/named_list/properties/items"
|
||||
},
|
||||
"tracking": {
|
||||
"type": "object",
|
||||
"description": "Describes how this vulnerability should be tracked as the project changes.",
|
||||
"oneOf": [
|
||||
{
|
||||
"description": "Declares that a series of items should be tracked using source-specific tracking methods.",
|
||||
"required": [
|
||||
"items"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "source"
|
||||
},
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"description": "An item that should be tracked using source-specific tracking methods.",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"signatures"
|
||||
],
|
||||
"properties": {
|
||||
"file": {
|
||||
"type": "string",
|
||||
"description": "Path to the file where the vulnerability is located."
|
||||
},
|
||||
"start_line": {
|
||||
"type": "number",
|
||||
"description": "The first line of the file that includes the vulnerability."
|
||||
},
|
||||
"end_line": {
|
||||
"type": "number",
|
||||
"description": "The last line of the file that includes the vulnerability."
|
||||
},
|
||||
"signatures": {
|
||||
"type": "array",
|
||||
"description": "An array of calculated tracking signatures for this tracking item.",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"description": "A calculated tracking signature value and metadata.",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"algorithm",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"algorithm": {
|
||||
"type": "string",
|
||||
"description": "The algorithm used to generate the signature."
|
||||
},
|
||||
"value": {
|
||||
"type": "string",
|
||||
"description": "The result of this signature algorithm."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"description": "Each tracking type must declare its own type."
|
||||
}
|
||||
}
|
||||
},
|
||||
"flags": {
|
||||
"description": "Flags that can be attached to vulnerabilities.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"description": "Informational flags identified and assigned to a vulnerability.",
|
||||
"required": [
|
||||
"type",
|
||||
"origin",
|
||||
"description"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"description": "Result of the scan.",
|
||||
"enum": [
|
||||
"flagged-as-likely-false-positive"
|
||||
]
|
||||
},
|
||||
"origin": {
|
||||
"minLength": 1,
|
||||
"description": "Tool that issued the flag.",
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"minLength": 1,
|
||||
"description": "What the flag is about.",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"location": {
|
||||
"required": [
|
||||
"commit"
|
||||
],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"file": {
|
||||
"type": "string",
|
||||
"description": "Path to the file where the vulnerability is located"
|
||||
},
|
||||
"commit": {
|
||||
"type": "object",
|
||||
"description": "Represents the commit in which the vulnerability was detected",
|
||||
"required": [
|
||||
"sha"
|
||||
],
|
||||
"properties": {
|
||||
"author": {
|
||||
"type": "string"
|
||||
},
|
||||
"date": {
|
||||
"type": "string"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"sha": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
"start_line": {
|
||||
"type": "number",
|
||||
"description": "The first line of the code affected by the vulnerability"
|
||||
},
|
||||
"end_line": {
|
||||
"type": "number",
|
||||
"description": "The last line of the code affected by the vulnerability"
|
||||
},
|
||||
"class": {
|
||||
"type": "string",
|
||||
"description": "Provides the name of the class where the vulnerability is located"
|
||||
},
|
||||
"method": {
|
||||
"type": "string",
|
||||
"description": "Provides the name of the method where the vulnerability is located"
|
||||
}
|
||||
}
|
||||
},
|
||||
"raw_source_code_extract": {
|
||||
"type": "string",
|
||||
"description": "Provides an unsanitized excerpt of the affected source code."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"remediations": {
|
||||
"type": "array",
|
||||
"description": "An array of objects containing information on available remediations, along with patch diffs to apply.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"fixes",
|
||||
"summary",
|
||||
"diff"
|
||||
],
|
||||
"properties": {
|
||||
"fixes": {
|
||||
"type": "array",
|
||||
"description": "An array of strings that represent references to vulnerabilities fixed by this remediation.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"description": "Unique identifier of the vulnerability. This is recommended to be a UUID.",
|
||||
"examples": [
|
||||
"642735a5-1425-428d-8d4e-3c854885a3c9"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"summary": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"description": "An overview of how the vulnerabilities were fixed."
|
||||
},
|
||||
"diff": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"description": "A base64-encoded remediation code diff, compatible with git apply."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -105,6 +105,7 @@ module Gitlab
|
|||
target_project_id: merge_request.target_project_id,
|
||||
state: merge_request.state,
|
||||
merge_status: merge_request.public_merge_status,
|
||||
detailed_merge_status: detailed_merge_status(merge_request),
|
||||
url: Gitlab::UrlBuilder.build(merge_request)
|
||||
}
|
||||
end
|
||||
|
@ -154,6 +155,10 @@ module Gitlab
|
|||
deployment_tier: build.persisted_environment.try(:tier)
|
||||
}
|
||||
end
|
||||
|
||||
def detailed_merge_status(merge_request)
|
||||
::MergeRequests::Mergeability::DetailedMergeStatusService.new(merge_request: merge_request).execute.to_s
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -66,12 +66,19 @@ module Gitlab
|
|||
labels: merge_request.labels_hook_attrs,
|
||||
state: merge_request.state, # This key is deprecated
|
||||
blocking_discussions_resolved: merge_request.mergeable_discussions_state?,
|
||||
first_contribution: merge_request.first_contribution?
|
||||
first_contribution: merge_request.first_contribution?,
|
||||
detailed_merge_status: detailed_merge_status
|
||||
}
|
||||
|
||||
merge_request.attributes.with_indifferent_access.slice(*self.class.safe_hook_attributes)
|
||||
.merge!(attrs)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def detailed_merge_status
|
||||
::MergeRequests::Mergeability::DetailedMergeStatusService.new(merge_request: merge_request).execute.to_s
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -15427,9 +15427,6 @@ msgstr ""
|
|||
msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
|
||||
msgstr ""
|
||||
|
||||
msgid "Epics|Assign Epic"
|
||||
msgstr ""
|
||||
|
||||
msgid "Epics|Leave empty to inherit from milestone dates"
|
||||
msgstr ""
|
||||
|
||||
|
@ -15442,18 +15439,9 @@ msgstr ""
|
|||
msgid "Epics|Remove issue"
|
||||
msgstr ""
|
||||
|
||||
msgid "Epics|Search epics"
|
||||
msgstr ""
|
||||
|
||||
msgid "Epics|Select epic"
|
||||
msgstr ""
|
||||
|
||||
msgid "Epics|Show more"
|
||||
msgstr ""
|
||||
|
||||
msgid "Epics|Something went wrong while assigning issue to epic."
|
||||
msgstr ""
|
||||
|
||||
msgid "Epics|Something went wrong while creating child epics."
|
||||
msgstr ""
|
||||
|
||||
|
@ -15466,18 +15454,12 @@ msgstr ""
|
|||
msgid "Epics|Something went wrong while fetching epics list."
|
||||
msgstr ""
|
||||
|
||||
msgid "Epics|Something went wrong while fetching group epics."
|
||||
msgstr ""
|
||||
|
||||
msgid "Epics|Something went wrong while moving item."
|
||||
msgstr ""
|
||||
|
||||
msgid "Epics|Something went wrong while ordering item."
|
||||
msgstr ""
|
||||
|
||||
msgid "Epics|Something went wrong while removing issue from epic."
|
||||
msgstr ""
|
||||
|
||||
msgid "Epics|Something went wrong while updating epics."
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -237,7 +237,6 @@
|
|||
"jest-environment-jsdom": "^27.5.1",
|
||||
"jest-jasmine2": "^27.5.1",
|
||||
"jest-junit": "^12.0.0",
|
||||
"jest-raw-loader": "^1.0.1",
|
||||
"jest-util": "^27.5.1",
|
||||
"jsonlint": "^1.6.3",
|
||||
"markdownlint-cli": "0.32.2",
|
||||
|
|
|
@ -21,15 +21,17 @@ RSpec.describe "Internal references", :js do
|
|||
sign_in(private_project_user)
|
||||
|
||||
visit(project_issue_path(private_project, private_project_issue))
|
||||
wait_for_requests
|
||||
|
||||
add_note("##{public_project_issue.to_reference(private_project)}")
|
||||
end
|
||||
|
||||
context "when user doesn't have access to private project", quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/257832' do
|
||||
context "when user doesn't have access to private project" do
|
||||
before do
|
||||
sign_in(public_project_user)
|
||||
|
||||
visit(project_issue_path(public_project, public_project_issue))
|
||||
wait_for_requests
|
||||
end
|
||||
|
||||
it { expect(page).not_to have_css(".note") }
|
||||
|
@ -41,6 +43,7 @@ RSpec.describe "Internal references", :js do
|
|||
sign_in(private_project_user)
|
||||
|
||||
visit(project_merge_request_path(private_project, private_project_merge_request))
|
||||
wait_for_requests
|
||||
|
||||
add_note("##{public_project_issue.to_reference(private_project)}")
|
||||
end
|
||||
|
@ -50,9 +53,10 @@ RSpec.describe "Internal references", :js do
|
|||
sign_in(public_project_user)
|
||||
|
||||
visit(project_issue_path(public_project, public_project_issue))
|
||||
wait_for_requests
|
||||
end
|
||||
|
||||
it "doesn't show any references", quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/257832' do
|
||||
it "doesn't show any references" do
|
||||
expect(page).not_to have_text 'Related merge requests'
|
||||
end
|
||||
end
|
||||
|
@ -60,6 +64,7 @@ RSpec.describe "Internal references", :js do
|
|||
context "when user has access to private project" do
|
||||
before do
|
||||
visit(project_issue_path(public_project, public_project_issue))
|
||||
wait_for_requests
|
||||
end
|
||||
|
||||
it "shows references", :sidekiq_might_not_need_inline do
|
||||
|
@ -85,15 +90,17 @@ RSpec.describe "Internal references", :js do
|
|||
sign_in(private_project_user)
|
||||
|
||||
visit(project_issue_path(private_project, private_project_issue))
|
||||
wait_for_requests
|
||||
|
||||
add_note("##{public_project_merge_request.to_reference(private_project)}")
|
||||
end
|
||||
|
||||
context "when user doesn't have access to private project", quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/257832' do
|
||||
context "when user doesn't have access to private project" do
|
||||
before do
|
||||
sign_in(public_project_user)
|
||||
|
||||
visit(project_merge_request_path(public_project, public_project_merge_request))
|
||||
wait_for_requests
|
||||
end
|
||||
|
||||
it { expect(page).not_to have_css(".note") }
|
||||
|
@ -105,6 +112,7 @@ RSpec.describe "Internal references", :js do
|
|||
sign_in(private_project_user)
|
||||
|
||||
visit(project_merge_request_path(private_project, private_project_merge_request))
|
||||
wait_for_requests
|
||||
|
||||
add_note("##{public_project_merge_request.to_reference(private_project)}")
|
||||
end
|
||||
|
@ -114,9 +122,10 @@ RSpec.describe "Internal references", :js do
|
|||
sign_in(public_project_user)
|
||||
|
||||
visit(project_merge_request_path(public_project, public_project_merge_request))
|
||||
wait_for_requests
|
||||
end
|
||||
|
||||
it "doesn't show any references", quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/257832' do
|
||||
it "doesn't show any references" do
|
||||
expect(page).not_to have_text 'Related merge requests'
|
||||
end
|
||||
end
|
||||
|
@ -124,6 +133,7 @@ RSpec.describe "Internal references", :js do
|
|||
context "when user has access to private project" do
|
||||
before do
|
||||
visit(project_merge_request_path(public_project, public_project_merge_request))
|
||||
wait_for_requests
|
||||
end
|
||||
|
||||
it "shows references", :sidekiq_might_not_need_inline do
|
||||
|
|
|
@ -22,9 +22,9 @@ RSpec.describe 'Issues > User sees empty state', :js do
|
|||
it 'user sees empty state' do
|
||||
visit project_issues_path(project)
|
||||
|
||||
expect(page).to have_content('Use issues to collaborate on ideas, solve problems, and plan work')
|
||||
expect(page).to have_content('Learn more about issues.')
|
||||
expect(page).to have_content('Register / Sign In')
|
||||
expect(page).to have_content('The Issue Tracker is the place to add things that need to be improved or solved in a project.')
|
||||
expect(page).to have_content('You can register or sign in to create issues for this project.')
|
||||
end
|
||||
|
||||
it_behaves_like 'empty state with filters'
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'Import/Export - project import integration test', :js do
|
||||
include GitHelpers
|
||||
|
||||
let(:user) { create(:user) }
|
||||
let(:file) { File.join(Rails.root, 'spec', 'features', 'projects', 'import_export', 'test_project_export.tar.gz') }
|
||||
let(:export_path) { "#{Dir.tmpdir}/import_file_spec" }
|
||||
|
|
6
spec/frontend/__helpers__/raw_transformer.js
Normal file
6
spec/frontend/__helpers__/raw_transformer.js
Normal file
|
@ -0,0 +1,6 @@
|
|||
/* eslint-disable import/no-commonjs */
|
||||
module.exports = {
|
||||
process: (content) => {
|
||||
return `module.exports = ${JSON.stringify(content)}`;
|
||||
},
|
||||
};
|
|
@ -601,17 +601,20 @@ describe('CE IssuesListApp component', () => {
|
|||
beforeEach(() => {
|
||||
wrapper = mountComponent({
|
||||
provide: { hasAnyIssues: false, isSignedIn: false },
|
||||
mountFn: mount,
|
||||
});
|
||||
});
|
||||
|
||||
it('shows empty state', () => {
|
||||
expect(findGlEmptyState().props()).toMatchObject({
|
||||
description: IssuesListApp.i18n.noIssuesSignedOutDescription,
|
||||
title: IssuesListApp.i18n.noIssuesSignedOutTitle,
|
||||
svgPath: defaultProvide.emptyStateSvgPath,
|
||||
primaryButtonText: IssuesListApp.i18n.noIssuesSignedOutButtonText,
|
||||
primaryButtonLink: defaultProvide.signInPath,
|
||||
});
|
||||
expect(findGlEmptyState().text()).toContain(
|
||||
IssuesListApp.i18n.noIssuesSignedOutDescription,
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1016,45 +1016,6 @@ describe('common_utils', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('searchBy', () => {
|
||||
const searchSpace = {
|
||||
iid: 1,
|
||||
reference: '&1',
|
||||
title: 'Error omnis quos consequatur ullam a vitae sed omnis libero cupiditate.',
|
||||
url: '/groups/gitlab-org/-/epics/1',
|
||||
};
|
||||
|
||||
it('returns null when `query` or `searchSpace` params are empty/undefined', () => {
|
||||
expect(commonUtils.searchBy('omnis', null)).toBeNull();
|
||||
expect(commonUtils.searchBy('', searchSpace)).toBeNull();
|
||||
expect(commonUtils.searchBy()).toBeNull();
|
||||
});
|
||||
|
||||
it('returns object with matching props based on `query` & `searchSpace` params', () => {
|
||||
// String `omnis` is found only in `title` prop so return just that
|
||||
expect(commonUtils.searchBy('omnis', searchSpace)).toEqual(
|
||||
expect.objectContaining({
|
||||
title: searchSpace.title,
|
||||
}),
|
||||
);
|
||||
|
||||
// String `1` is found in both `iid` and `reference` props so return both
|
||||
expect(commonUtils.searchBy('1', searchSpace)).toEqual(
|
||||
expect.objectContaining({
|
||||
iid: searchSpace.iid,
|
||||
reference: searchSpace.reference,
|
||||
}),
|
||||
);
|
||||
|
||||
// String `/epics/1` is found in `url` prop so return just that
|
||||
expect(commonUtils.searchBy('/epics/1', searchSpace)).toEqual(
|
||||
expect.objectContaining({
|
||||
url: searchSpace.url,
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isScopedLabel', () => {
|
||||
it('returns true when `::` is present in title', () => {
|
||||
expect(commonUtils.isScopedLabel({ title: 'foo::bar' })).toBe(true);
|
||||
|
|
285
spec/frontend/sidebar/components/sidebar_dropdown_spec.js
Normal file
285
spec/frontend/sidebar/components/sidebar_dropdown_spec.js
Normal file
|
@ -0,0 +1,285 @@
|
|||
import {
|
||||
GlDropdown,
|
||||
GlDropdownItem,
|
||||
GlDropdownText,
|
||||
GlFormInput,
|
||||
GlSearchBoxByType,
|
||||
} from '@gitlab/ui';
|
||||
import Vue, { nextTick } from 'vue';
|
||||
import VueApollo from 'vue-apollo';
|
||||
import createMockApollo from 'helpers/mock_apollo_helper';
|
||||
import { mountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import { createAlert } from '~/flash';
|
||||
import { IssuableType } from '~/issues/constants';
|
||||
import SidebarDropdown from '~/sidebar/components/sidebar_dropdown.vue';
|
||||
import { IssuableAttributeType } from '~/sidebar/constants';
|
||||
import projectIssueMilestoneQuery from '~/sidebar/queries/project_issue_milestone.query.graphql';
|
||||
import projectMilestonesQuery from '~/sidebar/queries/project_milestones.query.graphql';
|
||||
import {
|
||||
emptyProjectMilestonesResponse,
|
||||
mockIssue,
|
||||
mockProjectMilestonesResponse,
|
||||
noCurrentMilestoneResponse,
|
||||
} from '../mock_data';
|
||||
|
||||
jest.mock('~/flash');
|
||||
|
||||
describe('SidebarDropdown component', () => {
|
||||
let wrapper;
|
||||
|
||||
const promiseData = { issuableSetAttribute: { issue: { attribute: { id: '123' } } } };
|
||||
const mutationSuccess = () => jest.fn().mockResolvedValue({ data: promiseData });
|
||||
|
||||
const findDropdown = () => wrapper.findComponent(GlDropdown);
|
||||
const findDropdownText = () => wrapper.findComponent(GlDropdownText);
|
||||
const findSearchBox = () => wrapper.findComponent(GlSearchBoxByType);
|
||||
const findAllDropdownItems = () => wrapper.findAllComponents(GlDropdownItem);
|
||||
const findDropdownItemWithText = (text) =>
|
||||
findAllDropdownItems().wrappers.find((x) => x.text() === text);
|
||||
const findAttributeItems = () => wrapper.findByTestId('milestone-items');
|
||||
const findNoAttributeItem = () => wrapper.findByTestId('no-milestone-item');
|
||||
const findLoadingIconDropdown = () => wrapper.findByTestId('loading-icon-dropdown');
|
||||
|
||||
const toggleDropdown = async () => {
|
||||
wrapper.vm.$refs.dropdown.show();
|
||||
findDropdown().vm.$emit('show');
|
||||
|
||||
await nextTick();
|
||||
jest.runOnlyPendingTimers();
|
||||
await waitForPromises();
|
||||
};
|
||||
|
||||
const createComponentWithApollo = ({
|
||||
requestHandlers = [],
|
||||
projectMilestonesSpy = jest.fn().mockResolvedValue(mockProjectMilestonesResponse),
|
||||
currentMilestoneSpy = jest.fn().mockResolvedValue(noCurrentMilestoneResponse),
|
||||
} = {}) => {
|
||||
Vue.use(VueApollo);
|
||||
|
||||
wrapper = mountExtended(SidebarDropdown, {
|
||||
apolloProvider: createMockApollo([
|
||||
[projectMilestonesQuery, projectMilestonesSpy],
|
||||
[projectIssueMilestoneQuery, currentMilestoneSpy],
|
||||
...requestHandlers,
|
||||
]),
|
||||
propsData: {
|
||||
attrWorkspacePath: mockIssue.projectPath,
|
||||
currentAttribute: {},
|
||||
issuableType: IssuableType.Issue,
|
||||
issuableAttribute: IssuableAttributeType.Milestone,
|
||||
},
|
||||
attachTo: document.body,
|
||||
});
|
||||
};
|
||||
|
||||
const createComponent = ({
|
||||
props = {},
|
||||
data = {},
|
||||
mutationPromise = mutationSuccess,
|
||||
queries = {},
|
||||
} = {}) => {
|
||||
wrapper = mountExtended(SidebarDropdown, {
|
||||
propsData: {
|
||||
attrWorkspacePath: mockIssue.projectPath,
|
||||
currentAttribute: {},
|
||||
issuableType: IssuableType.Issue,
|
||||
issuableAttribute: IssuableAttributeType.Milestone,
|
||||
...props,
|
||||
},
|
||||
data() {
|
||||
return data;
|
||||
},
|
||||
mocks: {
|
||||
$apollo: {
|
||||
mutate: mutationPromise(),
|
||||
queries: {
|
||||
currentAttribute: { loading: false },
|
||||
attributesList: { loading: false },
|
||||
...queries,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
describe('when a user can edit', () => {
|
||||
describe('when user is editing', () => {
|
||||
describe('when rendering the dropdown', () => {
|
||||
it('shows a loading spinner while fetching a list of attributes', async () => {
|
||||
createComponent({
|
||||
queries: {
|
||||
attributesList: { loading: true },
|
||||
},
|
||||
});
|
||||
|
||||
await toggleDropdown();
|
||||
|
||||
expect(findLoadingIconDropdown().exists()).toBe(true);
|
||||
});
|
||||
|
||||
describe('GlDropdownItem with the right title and id', () => {
|
||||
const id = 'id';
|
||||
const title = 'title';
|
||||
|
||||
beforeEach(async () => {
|
||||
createComponent({
|
||||
props: { currentAttribute: { id, title } },
|
||||
data: { attributesList: [{ id, title }] },
|
||||
});
|
||||
|
||||
await toggleDropdown();
|
||||
});
|
||||
|
||||
it('does not show a loading spinner', () => {
|
||||
expect(findLoadingIconDropdown().exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('renders title $title', () => {
|
||||
expect(findDropdownItemWithText(title).exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('checks the correct dropdown item', () => {
|
||||
expect(
|
||||
findAllDropdownItems()
|
||||
.filter((w) => w.props('isChecked') === true)
|
||||
.at(0)
|
||||
.text(),
|
||||
).toBe(title);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when no data is assigned', () => {
|
||||
beforeEach(async () => {
|
||||
createComponent();
|
||||
|
||||
await toggleDropdown();
|
||||
});
|
||||
|
||||
it('finds GlDropdownItem with "No milestone"', () => {
|
||||
expect(findNoAttributeItem().text()).toBe('No milestone');
|
||||
});
|
||||
|
||||
it('"No milestone" is checked', () => {
|
||||
expect(findAllDropdownItems('No milestone').at(0).props('isChecked')).toBe(true);
|
||||
});
|
||||
|
||||
it('does not render any dropdown item', () => {
|
||||
expect(findAttributeItems().exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when clicking on dropdown item', () => {
|
||||
describe('when currentAttribute is equal to attribute id', () => {
|
||||
it('does not call setIssueAttribute mutation', async () => {
|
||||
createComponent({
|
||||
props: { currentAttribute: { id: 'id', title: 'title' } },
|
||||
data: { attributesList: [{ id: 'id', title: 'title' }] },
|
||||
});
|
||||
|
||||
await toggleDropdown();
|
||||
|
||||
findDropdownItemWithText('title').vm.$emit('click');
|
||||
|
||||
expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when a user is searching', () => {
|
||||
describe('when search result is not found', () => {
|
||||
describe('when milestone', () => {
|
||||
it('renders "No milestone found"', async () => {
|
||||
createComponent();
|
||||
|
||||
await toggleDropdown();
|
||||
|
||||
findSearchBox().vm.$emit('input', 'non existing milestones');
|
||||
await nextTick();
|
||||
|
||||
expect(findDropdownText().text()).toBe('No milestone found');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('with mock apollo', () => {
|
||||
describe("when issuable type is 'issue'", () => {
|
||||
describe('when dropdown is expanded and user can edit', () => {
|
||||
it('renders the dropdown on clicking edit', async () => {
|
||||
createComponentWithApollo();
|
||||
|
||||
await toggleDropdown();
|
||||
|
||||
expect(findDropdown().isVisible()).toBe(true);
|
||||
});
|
||||
|
||||
it('focuses on the input when dropdown is shown', async () => {
|
||||
createComponentWithApollo();
|
||||
|
||||
await toggleDropdown();
|
||||
|
||||
expect(document.activeElement).toEqual(wrapper.findComponent(GlFormInput).element);
|
||||
});
|
||||
|
||||
describe('milestones', () => {
|
||||
it('should call createAlert if milestones query fails', async () => {
|
||||
createComponentWithApollo({
|
||||
projectMilestonesSpy: jest.fn().mockRejectedValue(new Error()),
|
||||
});
|
||||
|
||||
await toggleDropdown();
|
||||
|
||||
expect(createAlert).toHaveBeenCalledWith({
|
||||
message: wrapper.vm.i18n.listFetchError,
|
||||
captureError: true,
|
||||
error: expect.any(Error),
|
||||
});
|
||||
});
|
||||
|
||||
it('only fetches attributes when dropdown is opened', async () => {
|
||||
const projectMilestonesSpy = jest
|
||||
.fn()
|
||||
.mockResolvedValueOnce(emptyProjectMilestonesResponse);
|
||||
createComponentWithApollo({ projectMilestonesSpy });
|
||||
|
||||
expect(projectMilestonesSpy).not.toHaveBeenCalled();
|
||||
|
||||
await toggleDropdown();
|
||||
|
||||
expect(projectMilestonesSpy).toHaveBeenNthCalledWith(1, {
|
||||
fullPath: mockIssue.projectPath,
|
||||
state: 'active',
|
||||
title: '',
|
||||
});
|
||||
});
|
||||
|
||||
describe('when a user is searching', () => {
|
||||
it('sends a projectMilestones query with the entered search term "foo"', async () => {
|
||||
const mockSearchTerm = 'foobar';
|
||||
const projectMilestonesSpy = jest
|
||||
.fn()
|
||||
.mockResolvedValueOnce(emptyProjectMilestonesResponse);
|
||||
createComponentWithApollo({ projectMilestonesSpy });
|
||||
|
||||
await toggleDropdown();
|
||||
|
||||
findSearchBox().vm.$emit('input', mockSearchTerm);
|
||||
await nextTick();
|
||||
jest.runOnlyPendingTimers(); // Account for debouncing
|
||||
|
||||
expect(projectMilestonesSpy).toHaveBeenNthCalledWith(2, {
|
||||
fullPath: mockIssue.projectPath,
|
||||
state: 'active',
|
||||
title: mockSearchTerm,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,12 +1,4 @@
|
|||
import {
|
||||
GlDropdown,
|
||||
GlDropdownItem,
|
||||
GlDropdownText,
|
||||
GlLink,
|
||||
GlSearchBoxByType,
|
||||
GlFormInput,
|
||||
GlLoadingIcon,
|
||||
} from '@gitlab/ui';
|
||||
import { GlDropdown, GlLink, GlLoadingIcon, GlSearchBoxByType } from '@gitlab/ui';
|
||||
import * as Sentry from '@sentry/browser';
|
||||
import { shallowMount, mount } from '@vue/test-utils';
|
||||
import Vue, { nextTick } from 'vue';
|
||||
|
@ -19,6 +11,7 @@ import { createAlert } from '~/flash';
|
|||
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
|
||||
import { IssuableType } from '~/issues/constants';
|
||||
import { timeFor } from '~/lib/utils/datetime_utility';
|
||||
import SidebarDropdown from '~/sidebar/components/sidebar_dropdown.vue';
|
||||
import SidebarDropdownWidget from '~/sidebar/components/sidebar_dropdown_widget.vue';
|
||||
import SidebarEditableItem from '~/sidebar/components/sidebar_editable_item.vue';
|
||||
import { IssuableAttributeType } from '~/sidebar/constants';
|
||||
|
@ -32,7 +25,6 @@ import {
|
|||
noCurrentMilestoneResponse,
|
||||
mockMilestoneMutationResponse,
|
||||
mockMilestone2,
|
||||
emptyProjectMilestonesResponse,
|
||||
} from '../mock_data';
|
||||
|
||||
jest.mock('~/flash');
|
||||
|
@ -55,20 +47,11 @@ describe('SidebarDropdownWidget', () => {
|
|||
|
||||
const findGlLink = () => wrapper.findComponent(GlLink);
|
||||
const findDateTooltip = () => getBinding(findGlLink().element, 'gl-tooltip');
|
||||
const findDropdown = () => wrapper.findComponent(GlDropdown);
|
||||
const findDropdownText = () => wrapper.findComponent(GlDropdownText);
|
||||
const findSearchBox = () => wrapper.findComponent(GlSearchBoxByType);
|
||||
const findAllDropdownItems = () => wrapper.findAllComponents(GlDropdownItem);
|
||||
const findDropdownItemWithText = (text) =>
|
||||
findAllDropdownItems().wrappers.find((x) => x.text() === text);
|
||||
|
||||
const findSidebarDropdown = () => wrapper.findComponent(SidebarDropdown);
|
||||
const findSidebarEditableItem = () => wrapper.findComponent(SidebarEditableItem);
|
||||
const findEditButton = () => findSidebarEditableItem().find('[data-testid="edit-button"]');
|
||||
const findEditableLoadingIcon = () => findSidebarEditableItem().findComponent(GlLoadingIcon);
|
||||
const findAttributeItems = () => wrapper.findByTestId('milestone-items');
|
||||
const findSelectedAttribute = () => wrapper.findByTestId('select-milestone');
|
||||
const findNoAttributeItem = () => wrapper.findByTestId('no-milestone-item');
|
||||
const findLoadingIconDropdown = () => wrapper.findByTestId('loading-icon-dropdown');
|
||||
|
||||
const waitForDropdown = async () => {
|
||||
// BDropdown first changes its `visible` property
|
||||
|
@ -167,6 +150,8 @@ describe('SidebarDropdownWidget', () => {
|
|||
}),
|
||||
);
|
||||
|
||||
wrapper.vm.$refs.dropdown.show = jest.fn();
|
||||
|
||||
// We need to mock out `showDropdown` which
|
||||
// invokes `show` method of BDropdown used inside GlDropdown.
|
||||
jest.spyOn(wrapper.vm, 'showDropdown').mockImplementation();
|
||||
|
@ -261,86 +246,7 @@ describe('SidebarDropdownWidget', () => {
|
|||
describe('when a user can edit', () => {
|
||||
describe('when user is editing', () => {
|
||||
describe('when rendering the dropdown', () => {
|
||||
it('shows a loading spinner while fetching a list of attributes', async () => {
|
||||
createComponent({
|
||||
queries: {
|
||||
attributesList: { loading: true },
|
||||
},
|
||||
});
|
||||
|
||||
await toggleDropdown();
|
||||
|
||||
expect(findLoadingIconDropdown().exists()).toBe(true);
|
||||
});
|
||||
|
||||
describe('GlDropdownItem with the right title and id', () => {
|
||||
const id = 'id';
|
||||
const title = 'title';
|
||||
|
||||
beforeEach(async () => {
|
||||
createComponent({
|
||||
data: { attributesList: [{ id, title }], currentAttribute: { id, title } },
|
||||
});
|
||||
|
||||
await toggleDropdown();
|
||||
});
|
||||
|
||||
it('does not show a loading spinner', () => {
|
||||
expect(findLoadingIconDropdown().exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('renders title $title', () => {
|
||||
expect(findDropdownItemWithText(title).exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('checks the correct dropdown item', () => {
|
||||
expect(
|
||||
findAllDropdownItems()
|
||||
.filter((w) => w.props('isChecked') === true)
|
||||
.at(0)
|
||||
.text(),
|
||||
).toBe(title);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when no data is assigned', () => {
|
||||
beforeEach(async () => {
|
||||
createComponent();
|
||||
|
||||
await toggleDropdown();
|
||||
});
|
||||
|
||||
it('finds GlDropdownItem with "No milestone"', () => {
|
||||
expect(findNoAttributeItem().text()).toBe('No milestone');
|
||||
});
|
||||
|
||||
it('"No milestone" is checked', () => {
|
||||
expect(findNoAttributeItem().props('isChecked')).toBe(true);
|
||||
});
|
||||
|
||||
it('does not render any dropdown item', () => {
|
||||
expect(findAttributeItems().exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when clicking on dropdown item', () => {
|
||||
describe('when currentAttribute is equal to attribute id', () => {
|
||||
it('does not call setIssueAttribute mutation', async () => {
|
||||
createComponent({
|
||||
data: {
|
||||
attributesList: [{ id: 'id', title: 'title' }],
|
||||
currentAttribute: { id: 'id', title: 'title' },
|
||||
},
|
||||
});
|
||||
|
||||
await toggleDropdown();
|
||||
|
||||
findDropdownItemWithText('title').vm.$emit('click');
|
||||
|
||||
expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when currentAttribute is not equal to attribute id', () => {
|
||||
describe('when error', () => {
|
||||
const bootstrapComponent = (mutationResp) => {
|
||||
|
@ -350,7 +256,7 @@ describe('SidebarDropdownWidget', () => {
|
|||
{ id: '123', title: '123' },
|
||||
{ id: 'id', title: 'title' },
|
||||
],
|
||||
currentAttribute: '123',
|
||||
currentAttribute: { id: '123' },
|
||||
},
|
||||
mutationPromise: mutationResp,
|
||||
});
|
||||
|
@ -366,7 +272,7 @@ describe('SidebarDropdownWidget', () => {
|
|||
|
||||
await toggleDropdown();
|
||||
|
||||
findDropdownItemWithText('title').vm.$emit('click');
|
||||
findSidebarDropdown().vm.$emit('change', { id: 'error' });
|
||||
});
|
||||
|
||||
it(`calls createAlert with "${expectedMsg}"`, async () => {
|
||||
|
@ -382,24 +288,6 @@ describe('SidebarDropdownWidget', () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when a user is searching', () => {
|
||||
describe('when search result is not found', () => {
|
||||
describe('when milestone', () => {
|
||||
it('renders "No milestone found"', async () => {
|
||||
createComponent();
|
||||
|
||||
await toggleDropdown();
|
||||
|
||||
findSearchBox().vm.$emit('input', 'non existing milestones');
|
||||
|
||||
await nextTick();
|
||||
|
||||
expect(findDropdownText().text()).toBe('No milestone found');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -424,18 +312,10 @@ describe('SidebarDropdownWidget', () => {
|
|||
await clickEdit();
|
||||
});
|
||||
|
||||
it('renders the dropdown on clicking edit', async () => {
|
||||
expect(findDropdown().isVisible()).toBe(true);
|
||||
});
|
||||
|
||||
it('focuses on the input when dropdown is shown', async () => {
|
||||
expect(document.activeElement).toEqual(wrapper.findComponent(GlFormInput).element);
|
||||
});
|
||||
|
||||
describe('when currentAttribute is not equal to attribute id', () => {
|
||||
describe('when update is successful', () => {
|
||||
it('calls setIssueAttribute mutation', () => {
|
||||
findDropdownItemWithText(mockMilestone2.title).vm.$emit('click');
|
||||
findSidebarDropdown().vm.$emit('change', { id: mockMilestone2.id });
|
||||
|
||||
expect(milestoneMutationSpy).toHaveBeenCalledWith({
|
||||
iid: mockIssue.iid,
|
||||
|
@ -443,72 +323,6 @@ describe('SidebarDropdownWidget', () => {
|
|||
fullPath: mockIssue.projectPath,
|
||||
});
|
||||
});
|
||||
|
||||
it('sets the value returned from the mutation to currentAttribute', async () => {
|
||||
findDropdownItemWithText(mockMilestone2.title).vm.$emit('click');
|
||||
await nextTick();
|
||||
expect(findSelectedAttribute().text()).toBe(mockMilestone2.title);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('milestones', () => {
|
||||
let projectMilestonesSpy;
|
||||
|
||||
it('should call createAlert if milestones query fails', async () => {
|
||||
await createComponentWithApollo({
|
||||
projectMilestonesSpy: jest.fn().mockRejectedValue(error),
|
||||
});
|
||||
|
||||
await clickEdit();
|
||||
|
||||
expect(createAlert).toHaveBeenCalledWith({
|
||||
message: wrapper.vm.i18n.listFetchError,
|
||||
captureError: true,
|
||||
error: expect.any(Error),
|
||||
});
|
||||
});
|
||||
|
||||
it('only fetches attributes when dropdown is opened', async () => {
|
||||
projectMilestonesSpy = jest.fn().mockResolvedValueOnce(emptyProjectMilestonesResponse);
|
||||
await createComponentWithApollo({ projectMilestonesSpy });
|
||||
|
||||
expect(projectMilestonesSpy).not.toHaveBeenCalled();
|
||||
|
||||
await clickEdit();
|
||||
|
||||
expect(projectMilestonesSpy).toHaveBeenNthCalledWith(1, {
|
||||
fullPath: mockIssue.projectPath,
|
||||
state: 'active',
|
||||
title: '',
|
||||
});
|
||||
});
|
||||
|
||||
describe('when a user is searching', () => {
|
||||
const mockSearchTerm = 'foobar';
|
||||
|
||||
beforeEach(async () => {
|
||||
projectMilestonesSpy = jest
|
||||
.fn()
|
||||
.mockResolvedValueOnce(emptyProjectMilestonesResponse);
|
||||
await createComponentWithApollo({ projectMilestonesSpy });
|
||||
|
||||
await clickEdit();
|
||||
});
|
||||
|
||||
it('sends a projectMilestones query with the entered search term "foo"', async () => {
|
||||
findSearchBox().vm.$emit('input', mockSearchTerm);
|
||||
await nextTick();
|
||||
|
||||
// Account for debouncing
|
||||
jest.runAllTimers();
|
||||
|
||||
expect(projectMilestonesSpy).toHaveBeenNthCalledWith(2, {
|
||||
fullPath: mockIssue.projectPath,
|
||||
state: 'active',
|
||||
title: mockSearchTerm,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Banzai::Filter::RepositoryLinkFilter do
|
||||
include GitHelpers
|
||||
include RepoHelpers
|
||||
|
||||
def filter(doc, contexts = {})
|
||||
|
|
|
@ -8,6 +8,7 @@ RSpec.describe Gitlab::Ci::Parsers::Coverage::SaxDocument do
|
|||
describe '#parse!' do
|
||||
let(:coverage_report) { Gitlab::Ci::Reports::CoverageReport.new }
|
||||
let(:project_path) { 'foo/bar' }
|
||||
let(:windows_path) { 'foo\bar' }
|
||||
let(:paths) { ['app/user.rb'] }
|
||||
|
||||
let(:cobertura) do
|
||||
|
@ -269,6 +270,36 @@ RSpec.describe Gitlab::Ci::Parsers::Coverage::SaxDocument do
|
|||
it_behaves_like 'ignoring sources, project_path, and worktree_paths'
|
||||
end
|
||||
|
||||
context 'and has Windows-style paths' do
|
||||
let(:sources_xml) do
|
||||
<<~EOF_WIN
|
||||
<sources>
|
||||
<source>D:\\builds\\#{windows_path}\\app</source>
|
||||
</sources>
|
||||
EOF_WIN
|
||||
end
|
||||
|
||||
context 'when there is a single <class>' do
|
||||
context 'with a single line' do
|
||||
let(:classes_xml) do
|
||||
<<~EOF
|
||||
<packages><package name="app"><classes>
|
||||
<class filename="user.rb"><lines>
|
||||
<line number="1" hits="2"/>
|
||||
</lines></class>
|
||||
</classes></package></packages>
|
||||
EOF
|
||||
end
|
||||
|
||||
it 'parses XML and returns a single file with the filename relative to project root' do
|
||||
expect { parse_report }.not_to raise_error
|
||||
|
||||
expect(coverage_report.files).to eq({ 'app/user.rb' => { 1 => 2 } })
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'and has multiple sources with a pattern for Go projects' do
|
||||
let(:project_path) { 'local/go' } # Make sure we're not making false positives
|
||||
let(:sources_xml) do
|
||||
|
|
|
@ -103,6 +103,7 @@ RSpec.describe Gitlab::DataBuilder::Pipeline do
|
|||
expect(merge_request_attrs[:target_project_id]).to eq(merge_request.target_project_id)
|
||||
expect(merge_request_attrs[:state]).to eq(merge_request.state)
|
||||
expect(merge_request_attrs[:merge_status]).to eq(merge_request.public_merge_status)
|
||||
expect(merge_request_attrs[:detailed_merge_status]).to eq("mergeable")
|
||||
expect(merge_request_attrs[:url]).to eq("http://localhost/#{merge_request.target_project.full_path}/-/merge_requests/#{merge_request.iid}")
|
||||
end
|
||||
end
|
||||
|
|
|
@ -78,6 +78,7 @@ RSpec.describe Gitlab::HookData::MergeRequestBuilder do
|
|||
state
|
||||
blocking_discussions_resolved
|
||||
first_contribution
|
||||
detailed_merge_status
|
||||
].freeze
|
||||
|
||||
expect(data).to include(*expected_additional_attributes)
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::ImportExport::DesignRepoRestorer do
|
||||
include GitHelpers
|
||||
|
||||
describe 'bundle a design Git repo' do
|
||||
let(:user) { create(:user) }
|
||||
let!(:project_with_design_repo) { create(:project, :design_repo) }
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::ImportExport::RepoRestorer do
|
||||
include GitHelpers
|
||||
|
||||
let_it_be(:project_with_repo) do
|
||||
create(:project, :repository, :wiki_repo, name: 'test-repo-restorer', path: 'test-repo-restorer').tap do |p|
|
||||
p.wiki.create_page('page', 'foobar', :markdown, 'created page')
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::ImportExport::SnippetsRepoRestorer do
|
||||
include GitHelpers
|
||||
|
||||
describe 'bundle a snippet Git repo' do
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:project) { create(:project, namespace: user.namespace) }
|
||||
|
|
|
@ -4,7 +4,6 @@ require 'spec_helper'
|
|||
|
||||
RSpec.describe Repository do
|
||||
include RepoHelpers
|
||||
include GitHelpers
|
||||
|
||||
TestBlob = Struct.new(:path)
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@ require 'spec_helper'
|
|||
|
||||
RSpec.describe Git::BaseHooksService do
|
||||
include RepoHelpers
|
||||
include GitHelpers
|
||||
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:project) { create(:project, :repository) }
|
||||
|
|
|
@ -4,7 +4,6 @@ require 'spec_helper'
|
|||
|
||||
RSpec.describe Git::TagPushService do
|
||||
include RepoHelpers
|
||||
include GitHelpers
|
||||
|
||||
let(:user) { create(:user) }
|
||||
let(:project) { create(:project, :repository) }
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe MergeRequests::SquashService do
|
||||
include GitHelpers
|
||||
|
||||
let(:service) { described_class.new(project: project, current_user: user, params: { merge_request: merge_request }) }
|
||||
let(:user) { project.first_owner }
|
||||
let(:project) { create(:project, :repository) }
|
||||
|
@ -109,11 +107,10 @@ RSpec.describe MergeRequests::SquashService do
|
|||
end
|
||||
|
||||
it 'has the same diff as the merge request, but a different SHA' do
|
||||
rugged = rugged_repo(project.repository)
|
||||
mr_diff = rugged.diff(merge_request.diff_base_sha, merge_request.diff_head_sha)
|
||||
squash_diff = rugged.diff(merge_request.diff_start_sha, squash_sha)
|
||||
mr_diff = project.repository.diff(merge_request.diff_base_sha, merge_request.diff_head_sha)
|
||||
squash_diff = project.repository.diff(merge_request.diff_start_sha, squash_sha)
|
||||
|
||||
expect(squash_diff.patch.length).to eq(mr_diff.patch.length)
|
||||
expect(squash_diff.size).to eq(mr_diff.size)
|
||||
expect(squash_commit.sha).not_to eq(merge_request.diff_head_sha)
|
||||
end
|
||||
|
||||
|
|
|
@ -794,7 +794,7 @@ RSpec.describe MergeRequests::UpdateService, :mailer do
|
|||
end
|
||||
|
||||
it "does not try to mark as unchecked if it's already unchecked" do
|
||||
expect(merge_request).to receive(:unchecked?).and_return(true)
|
||||
allow(merge_request).to receive(:unchecked?).twice.and_return(true)
|
||||
expect(merge_request).not_to receive(:mark_as_unchecked)
|
||||
|
||||
update_merge_request({ target_branch: "target" })
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Projects::HashedStorage::MigrateRepositoryService do
|
||||
include GitHelpers
|
||||
|
||||
let(:gitlab_shell) { Gitlab::Shell.new }
|
||||
let(:project) { create(:project, :legacy_storage, :repository, :wiki_repo, :design_repo) }
|
||||
let(:legacy_storage) { Storage::LegacyProject.new(project) }
|
||||
|
|
|
@ -65,7 +65,6 @@ require_relative('../jh/spec/spec_helper') if Gitlab.jh?
|
|||
# Requires helpers, and shared contexts/examples first since they're used in other support files
|
||||
|
||||
# Load these first since they may be required by other helpers
|
||||
require Rails.root.join("spec/support/helpers/git_helpers.rb")
|
||||
require Rails.root.join("spec/support/helpers/stub_requests.rb")
|
||||
|
||||
# Then the rest
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module GitHelpers
|
||||
def rugged_repo(repository)
|
||||
path = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
|
||||
File.join(TestEnv.repos_path, repository.disk_path + '.git')
|
||||
end
|
||||
|
||||
Rugged::Repository.new(path)
|
||||
end
|
||||
end
|
|
@ -3,8 +3,6 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Projects::AfterImportWorker do
|
||||
include GitHelpers
|
||||
|
||||
subject { worker.perform(project.id) }
|
||||
|
||||
let(:worker) { described_class.new }
|
||||
|
|
|
@ -7563,11 +7563,6 @@ jest-pnp-resolver@^1.2.2:
|
|||
resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c"
|
||||
integrity sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==
|
||||
|
||||
jest-raw-loader@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/jest-raw-loader/-/jest-raw-loader-1.0.1.tgz#ce9f56d54650f157c4a7d16d224ba5d613bcd626"
|
||||
integrity sha1-zp9W1UZQ8VfEp9FtIkul1hO81iY=
|
||||
|
||||
jest-regex-util@^27.5.1:
|
||||
version "27.5.1"
|
||||
resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-27.5.1.tgz#4da143f7e9fd1e542d4aa69617b38e4a78365b95"
|
||||
|
|
Loading…
Reference in a new issue