Add latest changes from gitlab-org/security/gitlab@17-11-stable-ee

This commit is contained in:
GitLab Bot
2025-06-24 10:01:50 +00:00
parent d51644f12b
commit 0e07c8dbdb
6 changed files with 64 additions and 10 deletions

View File

@ -10,11 +10,11 @@ import {
export const getRoleDropdownItems = roleDropdownItems;
export const getMemberRole = initialSelectedRole;
// The API to update members uses different property names for the access level, depending on if it's a user or a group.
// Users use 'access_level', groups use 'group_access'.
// The API to update members uses different property names for the access level, depending on each member's namespace
const ACCESS_LEVEL_PROPERTY_NAME = {
[MEMBERS_TAB_TYPES.user]: MEMBER_ACCESS_LEVEL_PROPERTY_NAME,
[MEMBERS_TAB_TYPES.group]: GROUP_LINK_ACCESS_LEVEL_PROPERTY_NAME,
[MEMBERS_TAB_TYPES.accessRequest]: MEMBER_ACCESS_LEVEL_PROPERTY_NAME,
};
export const callRoleUpdateApi = async (member, role) => {

View File

@ -2,10 +2,40 @@
class CertificateFingerprintValidator < ActiveModel::EachValidator
FINGERPRINT_PATTERN = /\A([a-zA-Z0-9]{2}[\s\-:]?){16,}\z/
SHA1_FINGERPRINT_PATTERN = /\A(?:(?:[A-Fa-f0-9]{2}[\s:]){19}[A-Fa-f0-9]{2}|[A-Fa-f0-9]{40})\z/
SHA256_FINGERPRINT_PATTERN = /\A(?:(?:[A-Fa-f0-9]{2}[\s:]){31}[A-Fa-f0-9]{2}|[A-Fa-f0-9]{64})\z/
MIN_LENGTH = 40
MAX_LENGTH = 95
def validate_each(record, attribute, value)
# We introduce the new validation logic only for new records and updates that will change the attribute
# in order to limit the impact on existing invalid records.
if record.new_record? || record.will_save_change_to_attribute?(attribute)
validate_sha1_or_sha256_pattern(record, attribute, value)
else
validate_length_and_pattern(record, attribute, value)
end
end
private
def validate_sha1_or_sha256_pattern(record, attribute, value)
unless within_length_limits?(value) && matches_sha1_or_sha256_pattern?(value)
record.errors.add(attribute, "must be 40 or 64 hex characters (with optional colons between pairs)")
end
end
def validate_length_and_pattern(record, attribute, value)
unless value.try(:match, FINGERPRINT_PATTERN)
record.errors.add(attribute, "must be a hash containing only letters, numbers, spaces, : and -")
end
end
def within_length_limits?(value)
value.try(:length) && value.length >= MIN_LENGTH && value.length <= MAX_LENGTH
end
def matches_sha1_or_sha256_pattern?(value)
value.try(:match, SHA1_FINGERPRINT_PATTERN) || value.try(:match, SHA256_FINGERPRINT_PATTERN)
end
end

View File

@ -10,6 +10,8 @@ module API
filename: API::NO_SLASH_URL_PART_REGEX
)
before { authenticate_non_get! }
helpers do
def find_uploads(parent)
uploads = Banzai::UploadsFinder.new(parent: parent).execute

View File

@ -46889,6 +46889,9 @@ msgstr ""
msgid "Project %{code_open}%{source_project}%{code_close} has more restricted access settings than %{code_open}%{target_project}%{code_close}. To avoid exposing private changes, make sure you're submitting changes to the correct project."
msgstr ""
msgid "Project %{project_name} and framework %{framework_name} are not from same namespace."
msgstr ""
msgid "Project %{project_name} and framework are not from same namespace."
msgstr ""

View File

@ -34,11 +34,12 @@ describe('Role details drawer utils', () => {
describe('callRoleUpdateApi', () => {
it.each`
namespace | propertyName
${'user'} | ${'access_level'}
${'group'} | ${'group_access'}
namespace | propertyName
${'user'} | ${'access_level'}
${'group'} | ${'group_access'}
${'accessRequest'} | ${'access_level'}
`(
'calls update API with expected data for $namespace namespace',
'calls update API with expected data for each member.namespace = $namespace',
async ({ namespace, propertyName }) => {
const memberPath = 'member/path/123';
const mockAxios = new MockAdapter(axios);

View File

@ -9,6 +9,8 @@ RSpec.describe API::MarkdownUploads, feature_category: :team_planning do
let_it_be(:project) { create(:project, :private) }
let_it_be(:project_maintainer) { create(:user, maintainer_of: project) }
let_it_be(:public_project) { create(:project, :public) }
let_it_be(:user) { create(:user, guest_of: [project, group]) }
describe "POST /projects/:id/uploads/authorize" do
@ -34,6 +36,16 @@ RSpec.describe API::MarkdownUploads, feature_category: :team_planning do
end
end
context 'with anonymous user on public project' do
let(:project) { public_project }
it "returns 401" do
post api(path), headers: headers
expect(response).to have_gitlab_http_status(:unauthorized)
end
end
context 'with no Workhorse headers' do
it "returns 403" do
post api(path, user)
@ -47,10 +59,6 @@ RSpec.describe API::MarkdownUploads, feature_category: :team_planning do
let(:file) { fixture_file_upload("spec/fixtures/dk.png", "image/png") }
let(:path) { "/projects/#{project.id}/uploads" }
before do
project
end
it "uploads the file through the upload service and returns its info" do
expect(UploadService).to receive(:new).with(project, anything, uploaded_by_user_id: user.id).and_call_original
@ -82,6 +90,16 @@ RSpec.describe API::MarkdownUploads, feature_category: :team_planning do
expect(tempfile.path).to be_nil
expect(File.exist?(path)).to be(false)
end
context 'with anonymous user on public project' do
let(:project) { public_project }
it "returns 401" do
post api(path), params: { file: file }
expect(response).to have_gitlab_http_status(:unauthorized)
end
end
end
shared_examples 'an unauthorized request' do