Commit 468a11fc authored by GitLab Release Tools Bot's avatar GitLab Release Tools Bot
Browse files

Merge remote-tracking branch 'dev/12-6-stable' into 12-6-stable

parents c3e911be 114d26c6
Please view this file on the master branch, on stable branches it's out of date.
 
## 12.6.5
- No changes.
## 12.6.4
 
- No changes.
......
......@@ -2,6 +2,38 @@
documentation](doc/development/changelog.md) for instructions on adding your own
entry.
 
## 12.6.6
### Security (1 change)
- Update workhorse to v8.20.0.
## 12.6.5
### Security (19 changes, 1 of them is from the community)
- Update rack-cors to 1.0.6.
- Update rdoc to 6.1.2.
- Bump rubyzip to 2.0.0. (Utkarsh Gupta)
- Cleanup todos for users from a removed linked group.
- Disable access to last_pipeline in commits API for users without read permissions.
- Add constraint to group dependency proxy endpoint param.
- Limit number of AsciiDoc includes per document.
- Prevent API access for unconfirmed users.
- Enforce permission check when counting activity events.
- Prevent gafana integration token from being displayed as a plain text to other project maintainers, by only displaying a masked version of it.
- Fix xss on frequent groups dropdown.
- Fix XSS vulnerability on custom project templates form.
- Protect internal CI builds from external overrides.
- ImportExport::ExportService to require admin_project permission.
- Make sure that only system notes where all references are visible to user are exposed in GraphQL API.
- Disable caching of repository/files/:file_path/raw API endpoint.
- Make cross-repository comparisons happen in the source repository.
- Update excon to 0.71.1 to fix CVE-2019-16779.
- Add workhorse request verification to package upload endpoints.
## 12.6.4
 
### Security (1 change)
......
......@@ -65,7 +65,7 @@ gem 'u2f', '~> 0.2.1'
 
# GitLab Pages
gem 'validates_hostname', '~> 1.0.6'
gem 'rubyzip', '~> 1.3.0', require: 'zip'
gem 'rubyzip', '~> 2.0.0', require: 'zip'
# GitLab Pages letsencrypt support
gem 'acme-client', '~> 2.0.2'
 
......@@ -142,7 +142,7 @@ gem 'gitlab-markup', '~> 1.7.0'
gem 'github-markup', '~> 1.7.0', require: 'github/markup'
gem 'commonmarker', '~> 0.20'
gem 'RedCloth', '~> 4.3.2'
gem 'rdoc', '~> 6.0'
gem 'rdoc', '~> 6.1.2'
gem 'org-ruby', '~> 0.9.12'
gem 'creole', '~> 0.5.0'
gem 'wikicloth', '0.8.1'
......
......@@ -260,7 +260,7 @@ GEM
et-orbi (1.2.1)
tzinfo
eventmachine (1.2.7)
excon (0.62.0)
excon (0.71.1)
execjs (2.6.0)
expression_parser (0.9.0)
extended-markdown-filter (0.6.0)
......@@ -763,7 +763,8 @@ GEM
rack (>= 0.4)
rack-attack (6.2.0)
rack (>= 1.0, < 3)
rack-cors (1.0.2)
rack-cors (1.0.6)
rack (>= 1.6.0)
rack-oauth2 (1.9.3)
activesupport
attr_required
......@@ -820,7 +821,7 @@ GEM
ffi (>= 1.0.6)
msgpack (>= 0.4.3)
optimist (>= 3.0.0)
rdoc (6.0.4)
rdoc (6.1.2)
re2 (1.1.1)
recaptcha (4.13.1)
json
......@@ -929,7 +930,7 @@ GEM
sexp_processor (~> 4.9)
rubyntlm (0.6.2)
rubypants (0.2.0)
rubyzip (1.3.0)
rubyzip (2.0.0)
rugged (0.28.4.1)
safe_yaml (1.0.4)
sanitize (4.6.6)
......@@ -1299,7 +1300,7 @@ DEPENDENCIES
raindrops (~> 0.18)
rblineprof (~> 0.3.6)
rbtrace (~> 0.4)
rdoc (~> 6.0)
rdoc (~> 6.1.2)
re2 (~> 1.1.1)
recaptcha (~> 4.11)
redis (~> 4.0)
......@@ -1323,7 +1324,7 @@ DEPENDENCIES
ruby-prof (~> 1.0.0)
ruby-progressbar
ruby_parser (~> 3.8)
rubyzip (~> 1.3.0)
rubyzip (~> 2.0.0)
rugged (~> 0.28)
sanitize (~> 4.6)
sassc-rails (~> 2.1.0)
......
......@@ -5,7 +5,7 @@ import AccessorUtilities from '~/lib/utils/accessor';
import eventHub from '../event_hub';
import store from '../store/';
import { FREQUENT_ITEMS, STORAGE_KEY } from '../constants';
import { isMobile, updateExistingFrequentItem } from '../utils';
import { isMobile, updateExistingFrequentItem, sanitizeItem } from '../utils';
import FrequentItemsSearchInput from './frequent_items_search_input.vue';
import FrequentItemsList from './frequent_items_list.vue';
import frequentItemsMixin from './frequent_items_mixin';
......@@ -64,7 +64,9 @@ export default {
this.fetchFrequentItems();
}
},
logItemAccess(storageKey, item) {
logItemAccess(storageKey, unsanitizedItem) {
const item = sanitizeItem(unsanitizedItem);
if (!AccessorUtilities.isLocalStorageAccessSafe()) {
return false;
}
......
<script>
import FrequentItemsListItem from './frequent_items_list_item.vue';
import frequentItemsMixin from './frequent_items_mixin';
import { sanitizeItem } from '../utils';
 
export default {
components: {
......@@ -48,6 +49,9 @@ export default {
? this.translations.itemListErrorMessage
: this.translations.itemListEmptyMessage;
},
sanitizedItems() {
return this.items.map(sanitizeItem);
},
},
};
</script>
......@@ -59,7 +63,7 @@ export default {
{{ listEmptyMessage }}
</li>
<frequent-items-list-item
v-for="item in items"
v-for="item in sanitizedItems"
v-else
:key="item.id"
:item-id="item.id"
......
import _ from 'underscore';
import bp from '~/breakpoints';
import sanitize from 'sanitize-html';
import { FREQUENT_ITEMS, HOUR_IN_MS } from './constants';
 
export const isMobile = () => {
......@@ -47,3 +48,9 @@ export const updateExistingFrequentItem = (frequentItem, item) => {
lastAccessedOn: accessedOverHourAgo ? Date.now() : frequentItem.lastAccessedOn,
};
};
export const sanitizeItem = item => ({
...item,
name: sanitize(item.name.toString(), { allowedTags: [] }),
namespace: sanitize(item.namespace.toString(), { allowedTags: [] }),
});
import $ from 'jquery';
import axios from './lib/utils/axios_utils';
import Api from './api';
import { escape } from 'lodash';
import { normalizeHeaders } from './lib/utils/common_utils';
import { __ } from '~/locale';
 
......@@ -75,10 +76,12 @@ const groupsSelect = () => {
}
},
formatResult(object) {
return `<div class='group-result'> <div class='group-name'>${object.full_name}</div> <div class='group-path'>${object.full_path}</div> </div>`;
return `<div class='group-result'> <div class='group-name'>${escape(
object.full_name,
)}</div> <div class='group-path'>${object.full_path}</div> </div>`;
},
formatSelection(object) {
return object.full_name;
return escape(object.full_name);
},
dropdownCssClass: 'ajax-groups-dropdown select2-infinite',
// we do not want to escape markup since we are displaying html in results
......
......@@ -5,6 +5,7 @@ require 'fogbugz'
 
class ApplicationController < ActionController::Base
include Gitlab::GonHelper
include Gitlab::NoCacheHeaders
include GitlabRoutingHelper
include PageLayoutHelper
include SafeParamsHelper
......@@ -54,7 +55,6 @@ class ApplicationController < ActionController::Base
# Adds `no-store` to the DEFAULT_CACHE_CONTROL, to prevent security
# concerns due to caching private data.
DEFAULT_GITLAB_CACHE_CONTROL = "#{ActionDispatch::Http::Cache::Response::DEFAULT_CACHE_CONTROL}, no-store"
DEFAULT_GITLAB_CONTROL_NO_CACHE = "#{DEFAULT_GITLAB_CACHE_CONTROL}, no-cache"
 
rescue_from Encoding::CompatibilityError do |exception|
log_exception(exception)
......@@ -246,9 +246,9 @@ class ApplicationController < ActionController::Base
end
 
def no_cache_headers
headers['Cache-Control'] = DEFAULT_GITLAB_CONTROL_NO_CACHE
headers['Pragma'] = 'no-cache' # HTTP 1.0 compatibility
headers['Expires'] = 'Fri, 01 Jan 1990 00:00:00 GMT'
DEFAULT_GITLAB_NO_CACHE_HEADERS.each do |k, v|
headers[k] = v
end
end
 
def default_headers
......
......@@ -19,7 +19,7 @@ class DashboardController < Dashboard::ApplicationController
 
format.json do
load_events
pager_json("events/_events", @events.count)
pager_json('events/_events', @events.count { |event| event.visible_to_user?(current_user) })
end
end
end
......@@ -37,6 +37,7 @@ class DashboardController < Dashboard::ApplicationController
@events = EventCollection
.new(projects, offset: params[:offset].to_i, filter: event_filter)
.to_a
.map(&:present)
 
Events::RenderService.new(current_user).execute(@events)
end
......
......@@ -91,7 +91,7 @@ class GroupsController < Groups::ApplicationController
 
format.json do
load_events
pager_json("events/_events", @events.count)
pager_json("events/_events", @events.count { |event| event.visible_to_user?(current_user) })
end
end
end
......@@ -209,8 +209,9 @@ class GroupsController < Groups::ApplicationController
.includes(:namespace)
 
@events = EventCollection
.new(projects, offset: params[:offset].to_i, filter: event_filter, groups: groups)
.to_a
.new(projects, offset: params[:offset].to_i, filter: event_filter, groups: groups)
.to_a
.map(&:present)
 
Events::RenderService
.new(current_user)
......
......@@ -119,7 +119,7 @@ class ProjectsController < Projects::ApplicationController
format.html
format.json do
load_events
pager_json('events/_events', @events.count)
pager_json('events/_events', @events.count { |event| event.visible_to_user?(current_user) })
end
end
end
......@@ -340,6 +340,7 @@ class ProjectsController < Projects::ApplicationController
@events = EventCollection
.new(projects, offset: params[:offset].to_i, filter: event_filter)
.to_a
.map(&:present)
 
Events::RenderService.new(current_user).execute(@events, atom_request: request.format.atom?)
end
......
......@@ -368,8 +368,8 @@ module ProjectsHelper
@project.grafana_integration&.grafana_url
end
 
def grafana_integration_token
@project.grafana_integration&.token
def grafana_integration_masked_token
@project.grafana_integration&.masked_token
end
 
def grafana_integration_enabled?
......
# frozen_string_literal: true
 
class GenericCommitStatus < CommitStatus
EXTERNAL_STAGE_IDX = 1_000_000
before_validation :set_default_values
 
validates :target_url, addressable_url: true,
length: { maximum: 255 },
allow_nil: true
validate :name_uniqueness_across_types, unless: :importing?
 
# GitHub compatible API
alias_attribute :context, :name
......@@ -13,7 +16,7 @@ class GenericCommitStatus < CommitStatus
def set_default_values
self.context ||= 'default'
self.stage ||= 'external'
self.stage_idx ||= 1000000
self.stage_idx ||= EXTERNAL_STAGE_IDX
end
 
def tags
......@@ -25,4 +28,14 @@ class GenericCommitStatus < CommitStatus
.new(self, current_user)
.fabricate!
end
private
def name_uniqueness_across_types
return if !pipeline || name.blank?
if pipeline.statuses.by_name(name).where.not(type: type).exists?
errors.add(:name, :taken)
end
end
end
......@@ -8,11 +8,13 @@ class GrafanaIntegration < ApplicationRecord
algorithm: 'aes-256-gcm',
key: Settings.attr_encrypted_db_key_base_32
 
before_validation :check_token_changes
validates :grafana_url,
length: { maximum: 1024 },
addressable_url: { enforce_sanitization: true, ascii_only: true }
 
validates :token, :project, presence: true
validates :encrypted_token, :project, presence: true
 
validates :enabled, inclusion: { in: [true, false] }
 
......@@ -23,4 +25,28 @@ class GrafanaIntegration < ApplicationRecord
 
@client ||= ::Grafana::Client.new(api_url: grafana_url.chomp('/'), token: token)
end
def masked_token
mask(encrypted_token)
end
def masked_token_was
mask(encrypted_token_was)
end
private
def token
decrypt(:token, encrypted_token)
end
def check_token_changes
return unless [encrypted_token_was, masked_token_was].include?(token)
clear_attribute_changes [:token, :encrypted_token, :encrypted_token_iv]
end
def mask(token)
token&.squish&.gsub(/./, '*')
end
end
......@@ -551,7 +551,8 @@ class Note < ApplicationRecord
# if they are not equal, then there are private/confidential references as well
user_visible_reference_count > 0 && user_visible_reference_count == total_reference_count
else
referenced_mentionables(user).any?
refs = all_references(user)
refs.all.any? && refs.stateful_not_visible_counter == 0
end
end
 
......
......@@ -2333,6 +2333,10 @@ class Project < ApplicationRecord
end
end
 
def template_source?
false
end
private
 
def closest_namespace_setting(name)
......
......@@ -21,6 +21,14 @@ class BasePolicy < DeclarativePolicy::Base
with_options scope: :user, score: 0
condition(:deactivated) { @user&.deactivated? }
 
desc "User email is unconfirmed or user account is locked"
with_options scope: :user, score: 0
condition(:inactive) do
Feature.enabled?(:inactive_policy_condition, default_enabled: true) &&
@user &&
!@user&.active_for_authentication?
end
with_options scope: :user, score: 0
condition(:external_user) { @user.nil? || @user.external? }
 
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment