Skip to content
Snippets Groups Projects
Commit 0a0e82d1 authored by GitLab Bot's avatar GitLab Bot
Browse files

Add latest changes from gitlab-org/gitlab@master

parent f82d5dca
No related branches found
No related tags found
No related merge requests found
Showing
with 176 additions and 107 deletions
Loading
Loading
@@ -12,23 +12,24 @@ Set the title to: `Security Release: 12.2.X, 12.1.X, and 12.0.X`
 
## Version issues:
 
* 12.2.X: {release task link}
* 12.1.X: {release task link}
* 12.0.X: {release task link}
12.2.X, 12.1.X, 12.0.X: {release task link}
 
## Issues in GitLab Security
 
* {https://gitlab.com/gitlab-org/security/gitlab/issues/ link}
To include your issue and merge requests in this Security Release, please mark
your security issues as related to this release tracking issue. You can do this
in the "Linked issues" section below this issue description.
 
| Version | MR |
|---------|----|
| 12.2 | {https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests link} |
| 12.1 | {https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests link} |
| 12.0 | {https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests link} |
| master | {https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests link} |
:warning: If your security issues are not marked as related to this release
tracking issue, their merge requests may not be included in the security
release.
 
## Issues in Omnibus-GitLab
 
Omnibus security fixes need to be added manually to this issue description
using and below the following template:
```markdown
* {https://gitlab.com/gitlab-org/security/gitlab/issues/ link}
 
| Version | MR |
Loading
Loading
@@ -37,6 +38,7 @@ Set the title to: `Security Release: 12.2.X, 12.1.X, and 12.0.X`
| 12.1 | {https://dev.gitlab.org/gitlab/omnibus-gitlab/merge_requests/ link} |
| 12.0 | {https://dev.gitlab.org/gitlab/omnibus-gitlab/merge_requests/ link} |
| master | {https://dev.gitlab.org/gitlab/omnibus-gitlab/merge_requests/ link} |
```
 
## QA
{QA issue link}
Loading
Loading
@@ -49,5 +51,5 @@ GitLab.com: {https://gitlab.com/gitlab-com/www-gitlab-com/merge_requests/ link}
## Email notification
{https://gitlab.com/gitlab-com/marketing/general/issues/ link}
 
/label ~security
/label ~security ~"upcoming security release"
/confidential
Loading
Loading
@@ -26,36 +26,7 @@ class ListIssue {
}
 
refreshData(obj, defaultAvatar) {
this.id = obj.id;
this.iid = obj.iid;
this.title = obj.title;
this.confidential = obj.confidential;
this.dueDate = obj.due_date;
this.sidebarInfoEndpoint = obj.issue_sidebar_endpoint;
this.referencePath = obj.reference_path;
this.path = obj.real_path;
this.toggleSubscriptionEndpoint = obj.toggle_subscription_endpoint;
this.project_id = obj.project_id;
this.timeEstimate = obj.time_estimate;
this.assignableLabelsEndpoint = obj.assignable_labels_endpoint;
this.blocked = obj.blocked;
if (obj.project) {
this.project = new IssueProject(obj.project);
}
if (obj.milestone) {
this.milestone = new ListMilestone(obj.milestone);
this.milestone_id = obj.milestone.id;
}
if (obj.labels) {
this.labels = obj.labels.map(label => new ListLabel(label));
}
if (obj.assignees) {
this.assignees = obj.assignees.map(a => new ListAssignee(a, defaultAvatar));
}
boardsStore.refreshIssueData(this, obj, defaultAvatar);
}
 
addLabel(label) {
Loading
Loading
Loading
Loading
@@ -12,6 +12,10 @@ import axios from '~/lib/utils/axios_utils';
import { mergeUrlParams } from '~/lib/utils/url_utility';
import eventHub from '../eventhub';
import { ListType } from '../constants';
import IssueProject from '../models/project';
import ListLabel from '../models/label';
import ListAssignee from '../models/assignee';
import ListMilestone from '../models/milestone';
 
const boardsStore = {
disabled: false,
Loading
Loading
@@ -593,6 +597,38 @@ const boardsStore = {
clearMultiSelect() {
this.multiSelect.list = [];
},
refreshIssueData(issue, obj, defaultAvatar) {
issue.id = obj.id;
issue.iid = obj.iid;
issue.title = obj.title;
issue.confidential = obj.confidential;
issue.dueDate = obj.due_date;
issue.sidebarInfoEndpoint = obj.issue_sidebar_endpoint;
issue.referencePath = obj.reference_path;
issue.path = obj.real_path;
issue.toggleSubscriptionEndpoint = obj.toggle_subscription_endpoint;
issue.project_id = obj.project_id;
issue.timeEstimate = obj.time_estimate;
issue.assignableLabelsEndpoint = obj.assignable_labels_endpoint;
issue.blocked = obj.blocked;
if (obj.project) {
issue.project = new IssueProject(obj.project);
}
if (obj.milestone) {
issue.milestone = new ListMilestone(obj.milestone);
issue.milestone_id = obj.milestone.id;
}
if (obj.labels) {
issue.labels = obj.labels.map(label => new ListLabel(label));
}
if (obj.assignees) {
issue.assignees = obj.assignees.map(a => new ListAssignee(a, defaultAvatar));
}
},
};
 
BoardsStoreEE.initEESpecific(boardsStore);
Loading
Loading
Loading
Loading
@@ -522,7 +522,7 @@ export default {
 
<div v-if="!showEmptyState">
<graph-group
v-for="(groupData, index) in dashboard.panel_groups"
v-for="(groupData, index) in dashboard.panelGroups"
:key="`${groupData.group}.${groupData.priority}`"
:name="groupData.group"
:show-panels="showPanels"
Loading
Loading
Loading
Loading
@@ -28,10 +28,10 @@ export default {
...mapState('monitoringDashboard', ['dashboard']),
...mapGetters('monitoringDashboard', ['metricsWithData']),
charts() {
if (!this.dashboard || !this.dashboard.panel_groups) {
if (!this.dashboard || !this.dashboard.panelGroups) {
return [];
}
const groupWithMetrics = this.dashboard.panel_groups.find(group =>
const groupWithMetrics = this.dashboard.panelGroups.find(group =>
group.panels.find(chart => this.chartHasData(chart)),
) || { panels: [] };
 
Loading
Loading
Loading
Loading
@@ -51,9 +51,11 @@ export const requestMetricsDashboard = ({ commit }) => {
commit(types.REQUEST_METRICS_DATA);
};
export const receiveMetricsDashboardSuccess = ({ commit, dispatch }, { response, params }) => {
commit(types.SET_ALL_DASHBOARDS, response.all_dashboards);
commit(types.RECEIVE_METRICS_DATA_SUCCESS, response.dashboard);
commit(types.SET_ENDPOINTS, convertObjectPropsToCamelCase(response.metrics_data));
const { all_dashboards, dashboard, metrics_data } = response;
commit(types.SET_ALL_DASHBOARDS, all_dashboards);
commit(types.RECEIVE_METRICS_DATA_SUCCESS, dashboard);
commit(types.SET_ENDPOINTS, convertObjectPropsToCamelCase(metrics_data));
 
return dispatch('fetchPrometheusMetrics', params);
};
Loading
Loading
@@ -149,16 +151,16 @@ export const fetchPrometheusMetric = ({ commit }, { metric, params }) => {
step,
};
 
commit(types.REQUEST_METRIC_RESULT, { metricId: metric.metric_id });
commit(types.REQUEST_METRIC_RESULT, { metricId: metric.metricId });
 
return fetchPrometheusResult(metric.prometheus_endpoint_path, queryParams)
return fetchPrometheusResult(metric.prometheusEndpointPath, queryParams)
.then(result => {
commit(types.RECEIVE_METRIC_RESULT_SUCCESS, { metricId: metric.metric_id, result });
commit(types.RECEIVE_METRIC_RESULT_SUCCESS, { metricId: metric.metricId, result });
})
.catch(error => {
Sentry.captureException(error);
 
commit(types.RECEIVE_METRIC_RESULT_FAILURE, { metricId: metric.metric_id, error });
commit(types.RECEIVE_METRIC_RESULT_FAILURE, { metricId: metric.metricId, error });
// Continue to throw error so the dashboard can notify using createFlash
throw error;
});
Loading
Loading
@@ -168,7 +170,7 @@ export const fetchPrometheusMetrics = ({ state, commit, dispatch, getters }, par
commit(types.REQUEST_METRICS_DATA);
 
const promises = [];
state.dashboard.panel_groups.forEach(group => {
state.dashboard.panelGroups.forEach(group => {
group.panels.forEach(panel => {
panel.metrics.forEach(metric => {
promises.push(dispatch('fetchPrometheusMetric', { metric, params }));
Loading
Loading
Loading
Loading
@@ -11,7 +11,7 @@ const metricsIdsInPanel = panel =>
* states in all the metric in the dashboard or group.
*/
export const getMetricStates = state => groupKey => {
let groups = state.dashboard.panel_groups;
let groups = state.dashboard.panelGroups;
if (groupKey) {
groups = groups.filter(group => group.key === groupKey);
}
Loading
Loading
@@ -43,7 +43,7 @@ export const getMetricStates = state => groupKey => {
* filtered by group key.
*/
export const metricsWithData = state => groupKey => {
let groups = state.dashboard.panel_groups;
let groups = state.dashboard.panelGroups;
if (groupKey) {
groups = groups.filter(group => group.key === groupKey);
}
Loading
Loading
import Vue from 'vue';
import pick from 'lodash/pick';
import { slugify } from '~/lib/utils/text_utility';
import * as types from './mutation_types';
import { normalizeMetric, normalizeQueryResult } from './utils';
import { mapToDashboardViewModel, normalizeQueryResult } from './utils';
import { BACKOFF_TIMEOUT } from '../../lib/utils/common_utils';
import { metricStates } from '../constants';
import httpStatusCodes from '~/lib/utils/http_status';
 
const normalizePanelMetrics = (metrics, defaultLabel) =>
metrics.map(metric => ({
...normalizeMetric(metric),
label: metric.label || defaultLabel,
}));
/**
* Locate and return a metric in the dashboard by its id
* as generated by `uniqMetricsId()`.
Loading
Loading
@@ -21,10 +14,10 @@ const normalizePanelMetrics = (metrics, defaultLabel) =>
*/
const findMetricInDashboard = (metricId, dashboard) => {
let res = null;
dashboard.panel_groups.forEach(group => {
dashboard.panelGroups.forEach(group => {
group.panels.forEach(panel => {
panel.metrics.forEach(metric => {
if (metric.metric_id === metricId) {
if (metric.metricId === metricId) {
res = metric;
}
});
Loading
Loading
@@ -86,27 +79,9 @@ export default {
state.showEmptyState = true;
},
[types.RECEIVE_METRICS_DATA_SUCCESS](state, dashboard) {
state.dashboard = {
...dashboard,
panel_groups: dashboard.panel_groups.map((group, i) => {
const key = `${slugify(group.group || 'default')}-${i}`;
let { panels = [] } = group;
// each panel has metric information that needs to be normalized
panels = panels.map(panel => ({
...panel,
metrics: normalizePanelMetrics(panel.metrics, panel.y_label),
}));
return {
...group,
panels,
key,
};
}),
};
state.dashboard = mapToDashboardViewModel(dashboard);
 
if (!state.dashboard.panel_groups.length) {
if (!state.dashboard.panelGroups.length) {
state.emptyState = 'noData';
}
},
Loading
Loading
@@ -206,7 +181,7 @@ export default {
state.showErrorBanner = enabled;
},
[types.SET_PANEL_GROUP_METRICS](state, payload) {
const panelGroup = state.dashboard.panel_groups.find(pg => payload.key === pg.key);
const panelGroup = state.dashboard.panelGroups.find(pg => payload.key === pg.key);
panelGroup.panels = payload.panels;
},
[types.SET_ENVIRONMENTS_FILTER](state, searchTerm) {
Loading
Loading
Loading
Loading
@@ -15,7 +15,7 @@ export default () => ({
showEmptyState: true,
showErrorBanner: true,
dashboard: {
panel_groups: [],
panelGroups: [],
},
allDashboards: [],
 
Loading
Loading
import { omit } from 'lodash';
import { slugify } from '~/lib/utils/text_utility';
import createGqClient, { fetchPolicies } from '~/lib/graphql';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
 
Loading
Loading
@@ -9,6 +9,13 @@ export const gqClient = createGqClient(
},
);
 
/**
* Metrics loaded from project-defined dashboards do not have a metric_id.
* This method creates a unique ID combining metric_id and id, if either is present.
* This is hopefully a temporary solution until BE processes metrics before passing to fE
* @param {Object} metric - metric
* @returns {Object} - normalized metric with a uniqueID
*/
export const uniqMetricsId = metric => `${metric.metric_id}_${metric.id}`;
 
/**
Loading
Loading
@@ -41,22 +48,75 @@ export const parseEnvironmentsResponse = (response = [], projectPath) =>
});
 
/**
* Metrics loaded from project-defined dashboards do not have a metric_id.
* This method creates a unique ID combining metric_id and id, if either is present.
* This is hopefully a temporary solution until BE processes metrics before passing to fE
* @param {Object} metric - metric
* @returns {Object} - normalized metric with a uniqueID
* Maps metrics to its view model
*
* This function difers from other in that is maps all
* non-define properties as-is to the object. This is not
* advisable as it could lead to unexpected side-effects.
*
* Related issue:
* https://gitlab.com/gitlab-org/gitlab/issues/207198
*
* @param {Array} metrics - Array of prometheus metrics
* @param {String} defaultLabel - Default label for metrics
* @returns {Object}
*/
const mapToMetricsViewModel = (metrics, defaultLabel) =>
metrics.map(({ label, id, metric_id, query_range, prometheus_endpoint_path, ...metric }) => ({
label: label || defaultLabel,
queryRange: query_range,
prometheusEndpointPath: prometheus_endpoint_path,
metricId: uniqMetricsId({ metric_id, id }),
 
export const normalizeMetric = (metric = {}) =>
omit(
{
...metric,
metric_id: uniqMetricsId(metric),
metricId: uniqMetricsId(metric),
},
'id',
);
// `metric_id` is used by embed.vue, keeping this duplicated.
// https://gitlab.com/gitlab-org/gitlab/issues/37492
metric_id: uniqMetricsId({ metric_id, id }),
...metric,
}));
/**
* Maps a metrics panel to its view model
*
* @param {Object} panel - Metrics panel
* @returns {Object}
*/
const mapToPanelViewModel = ({ title = '', type, y_label, metrics = [] }) => {
return {
title,
type,
y_label,
metrics: mapToMetricsViewModel(metrics, y_label),
};
};
/**
* Maps a metrics panel group to its view model
*
* @param {Object} panelGroup - Panel Group
* @returns {Object}
*/
const mapToPanelGroupViewModel = ({ group = '', panels = [] }, i) => {
return {
key: `${slugify(group || 'default')}-${i}`,
group,
panels: panels.map(mapToPanelViewModel),
};
};
/**
* Maps a dashboard json object to its view model
*
* @param {Object} dashboard - Dashboard object
* @param {String} dashboard.dashboard - Dashboard name object
* @param {Array} dashboard.panel_groups - Panel groups array
* @returns {Object}
*/
export const mapToDashboardViewModel = ({ dashboard = '', panel_groups = [] }) => {
return {
dashboard,
panelGroups: panel_groups.map(mapToPanelGroupViewModel),
};
};
 
export const normalizeQueryResult = timeSeries => {
let normalizedResult = {};
Loading
Loading
Loading
Loading
@@ -7,7 +7,7 @@ import {
 
/**
* This method is used to validate if the graph data format for a chart component
* that needs a time series as a response from a prometheus query (query_range) is
* that needs a time series as a response from a prometheus query (queryRange) is
* of a valid format or not.
* @param {Object} graphData the graph data response from a prometheus request
* @returns {boolean} whether the graphData format is correct
Loading
Loading
Loading
Loading
@@ -17,7 +17,7 @@ module Groups
serializer = ContainerRepositoriesSerializer
.new(current_user: current_user)
 
if Feature.enabled?(:vue_container_registry_explorer)
if Feature.enabled?(:vue_container_registry_explorer, group)
render json: serializer.with_pagination(request, response)
.represent_read_only(@images)
else
Loading
Loading
Loading
Loading
@@ -17,7 +17,7 @@ module Projects
serializer = ContainerRepositoriesSerializer
.new(project: project, current_user: current_user)
 
if Feature.enabled?(:vue_container_registry_explorer)
if Feature.enabled?(:vue_container_registry_explorer, project.group)
render json: serializer.with_pagination(request, response).represent(@images)
else
render json: serializer.represent(@images)
Loading
Loading
Loading
Loading
@@ -4,7 +4,7 @@
%section
.row.registry-placeholder.prepend-bottom-10
.col-12
- if Feature.enabled?(:vue_container_registry_explorer, @project)
- if Feature.enabled?(:vue_container_registry_explorer, @project.group)
#js-container-registry{ data: { endpoint: project_container_registry_index_path(@project),
project_path: @project.full_path,
"help_page_path" => help_page_path('user/packages/container_registry/index'),
Loading
Loading
---
title: Add confidential attribute to notes table
merge_request:
author:
type: other
---
title: Moves refreshData from issue model to board store
merge_request: 21409
author: nuwe1
type: other
# frozen_string_literal: true
class AddConfidentialToNote < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
with_lock_retries do
add_column :notes, :confidential, :boolean
end
end
end
Loading
Loading
@@ -2806,6 +2806,7 @@ ActiveRecord::Schema.define(version: 2020_02_24_163804) do
t.text "change_position"
t.boolean "resolved_by_push"
t.bigint "review_id"
t.boolean "confidential"
t.index ["author_id"], name: "index_notes_on_author_id"
t.index ["commit_id"], name: "index_notes_on_commit_id"
t.index ["created_at"], name: "index_notes_on_created_at"
Loading
Loading
Loading
Loading
@@ -20,7 +20,7 @@ alternative.
## Serialized Data Is Less Powerful
 
When using a relational database you have the ability to query individual
fields, change the schema, index data and so forth. When you use serialized data
fields, change the schema, index data, and so forth. When you use serialized data
all of that becomes either very difficult or downright impossible. While
PostgreSQL does offer the ability to query JSON fields it is mostly meant for
very specialized use cases, and not for more general use. If you use YAML in
Loading
Loading
Loading
Loading
@@ -215,4 +215,4 @@ When importing, GitLab would execute the following command, passing the `import_
git clone file://git:/tmp/lol
```
 
Git would simply ignore the `git:` part, interpret the path as `file:///tmp/lol` and import the repository into the new project, in turn potentially giving the attacker access to any repository in the system, whether private or not.
Git would simply ignore the `git:` part, interpret the path as `file:///tmp/lol`, and import the repository into the new project. This action could potentially give the attacker access to any repository in the system, whether private or not.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment