Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-10-18 03:10:30 +00:00
parent 90e7f31698
commit 14facaa466
20 changed files with 140 additions and 80 deletions

View file

@ -100,7 +100,7 @@ export const initNewAccessTokenApp = () => {
export const initTokensApp = () => {
const el = document.getElementById('js-tokens-app');
if (!el) return false;
if (!el) return null;
const tokensData = convertObjectPropsToCamelCase(JSON.parse(el.dataset.tokensData), {
deep: true,

View file

@ -17,6 +17,9 @@ module Routable
def self.find_by_full_path(path, follow_redirects: false, route_scope: Route, redirect_route_scope: RedirectRoute)
return unless path.present?
# Convert path to string to prevent DB error: function lower(integer) does not exist
path = path.to_s
# Case sensitive match first (it's cheaper and the usual case)
# If we didn't have an exact match, we perform a case insensitive search
#

View file

@ -781,9 +781,9 @@ Gitlab.ee do
Settings.cron_jobs['security_orchestration_policy_rule_schedule_worker'] ||= Settingslogic.new({})
Settings.cron_jobs['security_orchestration_policy_rule_schedule_worker']['cron'] ||= '*/15 * * * *'
Settings.cron_jobs['security_orchestration_policy_rule_schedule_worker']['job_class'] = 'Security::OrchestrationPolicyRuleScheduleWorker'
Settings.cron_jobs['security_findings_cleanup_worker'] ||= Settingslogic.new({})
Settings.cron_jobs['security_findings_cleanup_worker']['cron'] ||= '0 */4 * * 6,0'
Settings.cron_jobs['security_findings_cleanup_worker']['job_class'] = 'Security::Findings::CleanupWorker'
Settings.cron_jobs['security_scans_purge_worker'] ||= Settingslogic.new({})
Settings.cron_jobs['security_scans_purge_worker']['cron'] ||= '0 */4 * * 6,0'
Settings.cron_jobs['security_scans_purge_worker']['job_class'] = 'Security::Scans::PurgeWorker'
Settings.cron_jobs['app_sec_dast_profile_schedule_worker'] ||= Settingslogic.new({})
Settings.cron_jobs['app_sec_dast_profile_schedule_worker']['cron'] ||= '7-59/15 * * * *'
Settings.cron_jobs['app_sec_dast_profile_schedule_worker']['job_class'] = 'AppSec::Dast::ProfileScheduleWorker'

View file

@ -453,14 +453,14 @@
- 1
- - security_auto_fix
- 1
- - security_findings_delete_by_job_id
- 1
- - security_orchestration_policy_rule_schedule_namespace
- 1
- - security_process_scan_result_policy
- 1
- - security_scans
- 2
- - security_scans_purge_by_job_id
- 1
- - security_sync_scan_policies
- 1
- - self_monitoring_project_create

View file

@ -0,0 +1,16 @@
# frozen_string_literal: true
class MigrateSecurityFindingsDeleteQueues < Gitlab::Database::Migration[2.0]
restrict_gitlab_migration gitlab_schema: :gitlab_main
disable_ddl_transaction!
def up
sidekiq_queue_migrate 'security_findings_delete_by_job_id', to: 'security_scans_purge_by_job_id'
sidekiq_queue_migrate 'cronjob:security_findings_cleanup', to: 'cronjob:security_scans_purge'
end
def down
sidekiq_queue_migrate 'security_scans_purge_by_job_id', to: 'security_findings_delete_by_job_id'
sidekiq_queue_migrate 'cronjob:security_scans_purge', to: 'cronjob:security_findings_cleanup'
end
end

View file

@ -0,0 +1 @@
c5ef65edf6e87495bc4dc16c636b2f2d8cbd63f3903cf5ed1364206b83411ba9

View file

@ -19,9 +19,9 @@ POST /import/github
| `personal_access_token` | string | yes | GitHub personal access token |
| `repo_id` | integer | yes | GitHub repository ID |
| `new_name` | string | no | New repository name |
| `target_namespace` | string | yes | Namespace to import repository into. Supports subgroups like `/namespace/subgroup`. |
| `target_namespace` | string | yes | Namespace to import repository into. Supports subgroups like `/namespace/subgroup` |
| `github_hostname` | string | no | Custom GitHub Enterprise hostname. Do not set for GitHub.com. |
| `optional_stages` | object | no | [Additional items to import](../user/project/import/github.md#select-additional-items-to-import)|
| `optional_stages` | object | no | [Additional items to import](../user/project/import/github.md#select-additional-items-to-import). [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/373705) in GitLab 15.5 |
```shell
curl --request POST \

View file

@ -365,7 +365,8 @@ Example response:
"last_activity_on": "2021-01-27",
"membership_type": "group_member",
"removable": true,
"created_at": "2021-01-03T12:16:02.000Z"
"created_at": "2021-01-03T12:16:02.000Z",
"last_login_at": "2022-10-09T01:33:06.000Z"
},
{
"id": 2,
@ -378,7 +379,8 @@ Example response:
"last_activity_on": "2021-01-25",
"membership_type": "group_member",
"removable": true,
"created_at": "2021-01-04T18:46:42.000Z"
"created_at": "2021-01-04T18:46:42.000Z",
"last_login_at": "2022-09-29T22:18:46.000Z"
},
{
"id": 3,
@ -390,7 +392,8 @@ Example response:
"last_activity_on": "2021-01-20",
"membership_type": "group_invite",
"removable": false,
"created_at": "2021-01-09T07:12:31.000Z"
"created_at": "2021-01-09T07:12:31.000Z",
"last_login_at": "2022-10-10T07:28:56.000Z"
}
]
```

View file

@ -823,19 +823,38 @@ needed in the GitLab test suite (under `app/assets/javascripts/locale/**/app.js`
and `public/assets`).
- If the package URL returns a 404:
1. It runs `bin/rake gitlab:assets:compile`, so that the GitLab assets are compiled.
1. It then creates an archive which contains the assets and upload it [as a generic package](https://gitlab.com/gitlab-org/gitlab/-/packages/).
1. It runs `bin/rake gitlab:assets:compile`, so that the GitLab assets are compiled.
1. It then creates an archive which contains the assets and uploads it [as a generic package](https://gitlab.com/gitlab-org/gitlab/-/packages/).
The package version is set to the assets folders' hash sum.
- Otherwise, if the package already exists, it exits the job successfully.
#### `compile-*-assets`
We also changed the `compile-test-assets`, `compile-test-assets as-if-foss`,
and `compile-production-assets` jobs to:
1. First download the GitLab assets generic package build and uploaded by `cache-assets:*`.
1. If the package is retrieved successfully, assets aren't compiled.
1. If the package URL returns a 404, the behavior doesn't change compared to the current one: the GitLab assets are compiled as part of `bin/rake gitlab:assets:compile`.
1. First download the "native" cache assets, which contain:
- The [compiled assets](https://gitlab.com/gitlab-org/gitlab/-/blob/a6910c9086bb28e553f5e747ec2dd50af6da3c6b/.gitlab/ci/global.gitlab-ci.yml#L86-87).
- A [`cached-assets-hash.txt` file](https://gitlab.com/gitlab-org/gitlab/-/blob/a6910c9086bb28e553f5e747ec2dd50af6da3c6b/.gitlab/ci/global.gitlab-ci.yml#L85)
containing the `SHA256` hexdigest of all the source files on which the assets depend on.
This list of files is a pessimistic list and the assets might not depend on
some of these files. At worst we compile the assets more often, which is better than
using outdated assets.
NOTE:
The version of the package is the assets folders hash sum.
The file is [created after assets are compiled](https://gitlab.com/gitlab-org/gitlab/-/blob/a6910c9086bb28e553f5e747ec2dd50af6da3c6b/.gitlab/ci/frontend.gitlab-ci.yml#L83).
1. We then we compute the `SHA256` hexdigest of all the source files the assets depend on, **for the current checked out branch**. We [store the hexdigest in the `GITLAB_ASSETS_HASH` variable](https://gitlab.com/gitlab-org/gitlab/-/blob/a6910c9086bb28e553f5e747ec2dd50af6da3c6b/.gitlab/ci/frontend.gitlab-ci.yml#L27).
1. If `$CACHE_ASSETS_AS_PACKAGE == "true"`, we download the generic package built and uploaded by [`cache-assets:*`](#cache-assets).
- If the cache is up-to-date for the checked out branch, we download the native cache
**and** the cache package. We could optimize that by not downloading
the genetic package but the native cache is actually very often outdated because it's
rebuilt only every 2 hours.
1. We [run the `assets_compile_script` function](https://gitlab.com/gitlab-org/gitlab/-/blob/a6910c9086bb28e553f5e747ec2dd50af6da3c6b/.gitlab/ci/frontend.gitlab-ci.yml#L35),
which [itself runs](https://gitlab.com/gitlab-org/gitlab/-/blob/c023191ef412e868ae957f3341208a41ca678403/scripts/utils.sh#L76)
the [`assets:compile` Rake task](https://gitlab.com/gitlab-org/gitlab/-/blob/c023191ef412e868ae957f3341208a41ca678403/lib/tasks/gitlab/assets.rake#L80-109).
This task is responsible for deciding if assets need to be compiled or not.
It [compares the `HEAD` `SHA256` hexdigest from `$GITLAB_ASSETS_HASH` with the `master` hexdigest from `cached-assets-hash.txt`](https://gitlab.com/gitlab-org/gitlab/-/blob/c023191ef412e868ae957f3341208a41ca678403/lib/tasks/gitlab/assets.rake#L86).
1. If the hashes are the same, we don't compile anything. If they're different, we compile the assets.
### Pre-clone step

View file

@ -120,6 +120,8 @@ your GitLab account and sign in again, or revoke the older personal access token
### Select additional items to import
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/373705) in GitLab 15.5.
To make imports as fast as possible, the following items aren't imported from GitHub by default:
- Issue and pull request events. For example, _opened_ or _closed_, _renamed_, and _labeled_ or _unlabeled_.

View file

@ -20,6 +20,8 @@ module API
use :pagination
use :event_filter_params
use :sort_params
optional :scope, type: String, desc: 'Include all events across a user\'s projects',
documentation: { example: 'all' }
end
get do

View file

@ -18,6 +18,7 @@ module API
API_TOKEN_ENV = 'gitlab.api.token'
API_EXCEPTION_ENV = 'gitlab.api.exception'
API_RESPONSE_STATUS_CODE = 'gitlab.api.response_status_code'
INTEGER_ID_REGEX = /^-?\d+$/.freeze
def declared_params(options = {})
options = { include_parent_namespaces: false }.merge(options)
@ -139,7 +140,7 @@ module API
projects = Project.without_deleted.not_hidden
if id.is_a?(Integer) || id =~ /^\d+$/
if id.is_a?(Integer) || id =~ INTEGER_ID_REGEX
projects.find_by(id: id)
elsif id.include?("/")
projects.find_by_full_path(id)
@ -168,7 +169,7 @@ module API
# rubocop: disable CodeReuse/ActiveRecord
def find_group(id)
if id.to_s =~ /^\d+$/
if id.to_s =~ INTEGER_ID_REGEX
Group.find_by(id: id)
else
Group.find_by_full_path(id)
@ -203,7 +204,7 @@ module API
# rubocop: disable CodeReuse/ActiveRecord
def find_namespace(id)
if id.to_s =~ /^\d+$/
if id.to_s =~ INTEGER_ID_REGEX
Namespace.without_project_namespaces.find_by(id: id)
else
find_namespace_by_path(id)

View file

@ -6,7 +6,7 @@ module API
extend Grape::API::Helpers
params :event_filter_params do
optional :action, type: String, values: Event.actions, desc: 'Event action to filter on'
optional :action, type: String, values: Event.actions.keys, desc: 'Event action to filter on'
optional :target_type, type: String, values: Event.target_types, desc: 'Event target type to filter on'
optional :before, type: Date, desc: 'Include only events created before this date'
optional :after, type: Date, desc: 'Include only events created after this date'

View file

@ -3,6 +3,8 @@
module QA
module Resource
class ProjectImportedFromGithub < Resource::Project
attr_accessor :issue_events_import, :full_notes_import, :attachments_import
attribute :github_repo_id do
github_client.repository(github_repository_path).id
end
@ -51,7 +53,12 @@ module QA
new_name: name,
target_namespace: @personal_namespace || group.full_path,
personal_access_token: github_personal_access_token,
ci_cd_only: false
ci_cd_only: false,
optional_stages: {
single_endpoint_issue_events_import: issue_events_import,
single_endpoint_notes_import: full_notes_import,
attachments_import: attachments_import
}
}
end

View file

@ -21,6 +21,8 @@ module QA
project.github_personal_access_token = Runtime::Env.github_access_token
project.github_repository_path = 'gitlab-qa-github/import-test'
project.api_client = Runtime::API::Client.new(user: user)
project.issue_events_import = true
project.full_notes_import = true
end
end

View file

@ -199,13 +199,11 @@ module QA
project.github_repository_path = github_repo
project.personal_namespace = user.username
project.api_client = Runtime::API::Client.new(user: user)
project.issue_events_import = true
project.full_notes_import = true
end
end
before do
Runtime::Feature.enable(:github_importer_single_endpoint_issue_events_import)
end
after do |example|
next unless defined?(@import_time)

View file

@ -1,7 +1,4 @@
/* eslint-disable vue/require-prop-types */
/* eslint-disable vue/one-component-per-file */
import { createWrapper } from '@vue/test-utils';
import Vue from 'vue';
import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
import {
@ -10,10 +7,11 @@ import {
initNewAccessTokenApp,
initTokensApp,
} from '~/access_tokens';
import * as AccessTokenTableApp from '~/access_tokens/components/access_token_table_app.vue';
import AccessTokenTableApp from '~/access_tokens/components/access_token_table_app.vue';
import ExpiresAtField from '~/access_tokens/components/expires_at_field.vue';
import * as NewAccessTokenApp from '~/access_tokens/components/new_access_token_app.vue';
import * as TokensApp from '~/access_tokens/components/tokens_app.vue';
import NewAccessTokenApp from '~/access_tokens/components/new_access_token_app.vue';
import TokensApp from '~/access_tokens/components/tokens_app.vue';
import { FORM_SELECTOR } from '~/access_tokens/components/constants';
import { FEED_TOKEN, INCOMING_EMAIL_TOKEN, STATIC_OBJECT_TOKEN } from '~/access_tokens/constants';
import { __, sprintf } from '~/locale';
@ -30,25 +28,6 @@ describe('access tokens', () => {
const accessTokenTypePlural = 'personal access tokens';
const initialActiveAccessTokens = [{ revoked_path: '1' }];
const FakeAccessTokenTableApp = Vue.component('FakeComponent', {
inject: [
'accessTokenType',
'accessTokenTypePlural',
'initialActiveAccessTokens',
'noActiveTokensMessage',
'showRole',
],
props: [
'accessTokenType',
'accessTokenTypePlural',
'initialActiveAccessTokens',
'noActiveTokensMessage',
'showRole',
],
render: () => null,
});
AccessTokenTableApp.default = FakeAccessTokenTableApp;
it('mounts the component and provides required values', () => {
setHTMLFixture(
`<div id="js-access-token-table-app"
@ -60,19 +39,18 @@ describe('access tokens', () => {
);
const vueInstance = initAccessTokenTableApp();
wrapper = createWrapper(vueInstance);
const component = wrapper.findComponent(FakeAccessTokenTableApp);
const component = wrapper.findComponent({ name: 'AccessTokenTableRoot' });
expect(component.exists()).toBe(true);
expect(component.props()).toMatchObject({
expect(wrapper.findComponent(AccessTokenTableApp).vm).toMatchObject({
// Required value
accessTokenType,
accessTokenTypePlural,
initialActiveAccessTokens,
// Default values
information: undefined,
noActiveTokensMessage: sprintf(__('This user has no active %{accessTokenTypePlural}.'), {
accessTokenTypePlural,
}),
@ -81,12 +59,14 @@ describe('access tokens', () => {
});
it('mounts the component and provides all values', () => {
const information = 'Additional information';
const noActiveTokensMessage = 'This group has no active access tokens.';
setHTMLFixture(
`<div id="js-access-token-table-app"
data-access-token-type="${accessTokenType}"
data-access-token-type-plural="${accessTokenTypePlural}"
data-initial-active-access-tokens=${JSON.stringify(initialActiveAccessTokens)}
data-information="${information}"
data-no-active-tokens-message="${noActiveTokensMessage}"
data-show-role
>
@ -94,15 +74,15 @@ describe('access tokens', () => {
);
const vueInstance = initAccessTokenTableApp();
wrapper = createWrapper(vueInstance);
const component = wrapper.findComponent(FakeAccessTokenTableApp);
const component = wrapper.findComponent({ name: 'AccessTokenTableRoot' });
expect(component.exists()).toBe(true);
expect(component.props()).toMatchObject({
expect(component.findComponent(AccessTokenTableApp).vm).toMatchObject({
accessTokenType,
accessTokenTypePlural,
initialActiveAccessTokens,
information,
noActiveTokensMessage,
showRole: true,
});
@ -157,23 +137,16 @@ describe('access tokens', () => {
it('mounts the component and sets `accessTokenType` prop', () => {
const accessTokenType = 'personal access token';
setHTMLFixture(
`<div id="js-new-access-token-app" data-access-token-type="${accessTokenType}"></div>`,
`<div id="js-new-access-token-app" data-access-token-type="${accessTokenType}"></div>
<form id="${FORM_SELECTOR.slice(1)}"></form>`,
);
const FakeNewAccessTokenApp = Vue.component('FakeComponent', {
inject: ['accessTokenType'],
props: ['accessTokenType'],
render: () => null,
});
NewAccessTokenApp.default = FakeNewAccessTokenApp;
const vueInstance = initNewAccessTokenApp();
wrapper = createWrapper(vueInstance);
const component = wrapper.findComponent(FakeNewAccessTokenApp);
const component = wrapper.findComponent({ name: 'NewAccessTokenRoot' });
expect(component.exists()).toBe(true);
expect(component.props('accessTokenType')).toEqual(accessTokenType);
expect(component.findComponent(NewAccessTokenApp).vm).toMatchObject({ accessTokenType });
});
it('returns `null`', () => {
@ -192,20 +165,12 @@ describe('access tokens', () => {
`<div id="js-tokens-app" data-tokens-data=${JSON.stringify(tokensData)}></div>`,
);
const FakeTokensApp = Vue.component('FakeComponent', {
inject: ['tokenTypes'],
props: ['tokenTypes'],
render: () => null,
});
TokensApp.default = FakeTokensApp;
const vueInstance = initTokensApp();
wrapper = createWrapper(vueInstance);
const component = wrapper.findComponent(FakeTokensApp);
const component = wrapper.findComponent(TokensApp);
expect(component.exists()).toBe(true);
expect(component.props('tokenTypes')).toEqual(tokensData);
expect(component.vm).toMatchObject({ tokenTypes: tokensData });
});
it('returns `null`', () => {

View file

@ -110,6 +110,13 @@ RSpec.describe API::Helpers do
end
end
context 'when ID is a negative number' do
let(:existing_id) { project.id }
let(:non_existing_id) { -1 }
it_behaves_like 'project finder'
end
context 'when project is pending delete' do
let(:project_pending_delete) { create(:project, pending_delete: true) }
@ -325,6 +332,13 @@ RSpec.describe API::Helpers do
it_behaves_like 'group finder'
end
context 'when ID is a negative number' do
let(:existing_id) { group.id }
let(:non_existing_id) { -1 }
it_behaves_like 'group finder'
end
end
end
@ -421,6 +435,13 @@ RSpec.describe API::Helpers do
it_behaves_like 'namespace finder'
end
context 'when ID is a negative number' do
let(:existing_id) { namespace.id }
let(:non_existing_id) { -1 }
it_behaves_like 'namespace finder'
end
end
shared_examples 'user namespace finder' do

View file

@ -23,6 +23,12 @@ RSpec.shared_examples 'routable resource' do
end.not_to exceed_all_query_limit(control_count)
end
context 'when path is a negative number' do
it 'returns nil' do
expect(described_class.find_by_full_path(-1)).to be_nil
end
end
context 'with redirect routes' do
let_it_be(:redirect_route) { create(:redirect_route, source: record) }

View file

@ -1166,6 +1166,20 @@ RSpec.describe User do
'ORDER BY "users"."last_activity_on" ASC NULLS FIRST, "users"."id" DESC')
end
end
describe '.order_recent_sign_in' do
it 'sorts users by current_sign_in_at in descending order' do
expect(described_class.order_recent_sign_in.to_sql).to include(
'ORDER BY "users"."current_sign_in_at" DESC NULLS LAST')
end
end
describe '.order_oldest_sign_in' do
it 'sorts users by current_sign_in_at in ascending order' do
expect(described_class.order_oldest_sign_in.to_sql).to include(
'ORDER BY "users"."current_sign_in_at" ASC NULLS LAST')
end
end
end
context 'strip attributes' do