Commit 071319d3 authored by GitLab Bot's avatar GitLab Bot

Automatic merge of gitlab-org/gitlab master

parents 68aa8cfe 3fb9262f
...@@ -60,9 +60,32 @@ module Emails ...@@ -60,9 +60,32 @@ module Emails
@project = project @project = project
@alert = alert.present @alert = alert.present
add_project_headers
add_alert_headers
subject_text = "Alert: #{@alert.email_title}" subject_text = "Alert: #{@alert.email_title}"
mail(to: user.notification_email_for(@project.group), subject: subject(subject_text)) mail(to: user.notification_email_for(@project.group), subject: subject(subject_text))
end end
private
def add_alert_headers
return unless @alert
headers['X-GitLab-Alert-ID'] = @alert.id
headers['X-GitLab-Alert-IID'] = @alert.iid
headers['X-GitLab-NotificationReason'] = "alert_#{@alert.state}"
add_incident_headers
end
def add_incident_headers
incident = @alert.issue
return unless incident
headers['X-GitLab-Incident-ID'] = incident.id
headers['X-GitLab-Incident-IID'] = incident.iid
end
end end
end end
......
...@@ -28,8 +28,6 @@ class GroupMember < Member ...@@ -28,8 +28,6 @@ class GroupMember < Member
attr_accessor :last_owner, :last_blocked_owner attr_accessor :last_owner, :last_blocked_owner
self.enumerate_columns_in_select_statements = true
def self.access_level_roles def self.access_level_roles
Gitlab::Access.options_with_owner Gitlab::Access.options_with_owner
end end
......
...@@ -533,7 +533,7 @@ class ProjectPolicy < BasePolicy ...@@ -533,7 +533,7 @@ class ProjectPolicy < BasePolicy
enable :read_project_for_iids enable :read_project_for_iids
end end
rule { ~project_allowed_for_job_token }.prevent_all rule { ~public_project & ~internal_access & ~project_allowed_for_job_token }.prevent_all
rule { can?(:public_access) }.policy do rule { can?(:public_access) }.policy do
enable :read_package enable :read_package
......
...@@ -9,10 +9,6 @@ ...@@ -9,10 +9,6 @@
# statement cache. If a different migration is then run and one of these columns is # statement cache. If a different migration is then run and one of these columns is
# removed in the meantime, the query is invalid. # removed in the meantime, the query is invalid.
ActiveRecord::Base.class_eval do
class_attribute :enumerate_columns_in_select_statements
end
module ActiveRecord module ActiveRecord
module QueryMethods module QueryMethods
private private
...@@ -20,8 +16,6 @@ module ActiveRecord ...@@ -20,8 +16,6 @@ module ActiveRecord
def build_select(arel) def build_select(arel)
if select_values.any? if select_values.any?
arel.project(*arel_columns(select_values.uniq)) arel.project(*arel_columns(select_values.uniq))
elsif klass.enumerate_columns_in_select_statements
arel.project(*klass.column_names.map { |field| table[field] })
else else
arel.project(@klass.arel_table[Arel.star]) arel.project(@klass.arel_table[Arel.star])
end end
......
...@@ -259,7 +259,7 @@ Refer to this feature's version history for more details. ...@@ -259,7 +259,7 @@ Refer to this feature's version history for more details.
You can limit the access scope of a project's CI/CD job token to increase the You can limit the access scope of a project's CI/CD job token to increase the
job token's security. A job token might give extra permissions that aren't necessary job token's security. A job token might give extra permissions that aren't necessary
to access specific resources. Limiting the job token access scope reduces the risk of a leaked to access specific private resources. Limiting the job token access scope reduces the risk of a leaked
token being used to access private data that the user associated to the job can access. token being used to access private data that the user associated to the job can access.
Control the job token access scope with an allowlist of other projects authorized Control the job token access scope with an allowlist of other projects authorized
...@@ -273,7 +273,9 @@ setting at all times, and configure the allowlist for cross-project access if ne ...@@ -273,7 +273,9 @@ setting at all times, and configure the allowlist for cross-project access if ne
For example, when the setting is enabled, jobs in a pipeline in project `A` have For example, when the setting is enabled, jobs in a pipeline in project `A` have
a `CI_JOB_TOKEN` scope limited to project `A`. If the job needs to use the token a `CI_JOB_TOKEN` scope limited to project `A`. If the job needs to use the token
to make an API request to project `B`, then `B` must be added to the allowlist for `A`. to make an API request to a private project `B`, then `B` must be added to the allowlist for `A`.
If project `B` is public or internal, it doesn't need to be added to the allowlist.
The job token scope is only for controlling access to private projects.
To enable and configure the job token scope limit: To enable and configure the job token scope limit:
......
...@@ -3353,6 +3353,50 @@ Coverage output from [child pipelines](../pipelines/parent_child_pipelines.md) i ...@@ -3353,6 +3353,50 @@ Coverage output from [child pipelines](../pipelines/parent_child_pipelines.md) i
or displayed. Check [the related issue](https://gitlab.com/gitlab-org/gitlab/-/issues/280818) or displayed. Check [the related issue](https://gitlab.com/gitlab-org/gitlab/-/issues/280818)
for more details. for more details.
## `dast_configuration` **(ULTIMATE)**
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/5981) in GitLab 14.1.
Use the `dast_configuration` keyword to specify a site profile and scanner profile to be used in a
CI/CD configuration. Both profiles must first have been created in the project. The job's stage must
be `dast`.
**Keyword type**: Job keyword. You can use only as part of a job.
**Possible inputs**: One each of `site_profile` and `scanner_profile`.
- Use `site_profile` to specify the site profile to be used in the job.
- Use `scanner_profile` to specify the scanner profile to be used in the job.
**Example of `dast_configuration`**:
```yaml
stages:
- build
- dast
include:
- template: DAST.gitlab-ci.yml
dast:
dast_configuration:
site_profile: "Example Co"
scanner_profile: "Quick Passive Test"
```
In this example, the `dast` job extends the `dast` configuration added with the `include:` keyword
to select a specific site profile and scanner profile.
**Additional details**:
- Settings contained in either a site profile or scanner profile take precedence over those
contained in the DAST template.
**Related topics**:
- [Site profile](../../user/application_security/dast/index.md#site-profile).
- [Scanner profile](../../user/application_security/dast/index.md#scanner-profile).
### `retry` ### `retry`
> [Introduced](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/3515) in GitLab 11.5, you can control which failures to retry on. > [Introduced](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/3515) in GitLab 11.5, you can control which failures to retry on.
...@@ -4551,50 +4595,6 @@ You can use [CI/CD variables](../variables/index.md) to configure how the runner ...@@ -4551,50 +4595,6 @@ You can use [CI/CD variables](../variables/index.md) to configure how the runner
You can also use variables to configure how many times a runner You can also use variables to configure how many times a runner
[attempts certain stages of job execution](../runners/configure_runners.md#job-stages-attempts). [attempts certain stages of job execution](../runners/configure_runners.md#job-stages-attempts).
## `dast_configuration` **(ULTIMATE)**
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/5981) in GitLab 14.1.
Use the `dast_configuration` keyword to specify a site profile and scanner profile to be used in a
CI/CD configuration. Both profiles must first have been created in the project. The job's stage must
be `dast`.
**Keyword type**: Job keyword. You can use only as part of a job.
**Possible inputs**: One each of `site_profile` and `scanner_profile`.
- Use `site_profile` to specify the site profile to be used in the job.
- Use `scanner_profile` to specify the scanner profile to be used in the job.
**Example of `dast_configuration`**:
```yaml
stages:
- build
- dast
include:
- template: DAST.gitlab-ci.yml
dast:
dast_configuration:
site_profile: "Example Co"
scanner_profile: "Quick Passive Test"
```
In this example, the `dast` job extends the `dast` configuration added with the `include:` keyword
to select a specific site profile and scanner profile.
**Additional details**:
- Settings contained in either a site profile or scanner profile take precedence over those
contained in the DAST template.
**Related topics**:
- [Site profile](../../user/application_security/dast/index.md#site-profile).
- [Scanner profile](../../user/application_security/dast/index.md#scanner-profile).
## YAML-specific features ## YAML-specific features
In your `.gitlab-ci.yml` file, you can use YAML-specific features like anchors (`&`), aliases (`*`), In your `.gitlab-ci.yml` file, you can use YAML-specific features like anchors (`&`), aliases (`*`),
......
...@@ -328,5 +328,12 @@ reason `assigned` has this sentence in the footer: ...@@ -328,5 +328,12 @@ reason `assigned` has this sentence in the footer:
- `You are receiving this email because you have been assigned an item on <configured GitLab hostname>.` - `You are receiving this email because you have been assigned an item on <configured GitLab hostname>.`
NOTE:
Notification of other events is being considered for inclusion in the `X-GitLab-NotificationReason` header. For details, see this [related issue](https://gitlab.com/gitlab-org/gitlab/-/issues/20689). Notification of other events is being considered for inclusion in the `X-GitLab-NotificationReason` header. For details, see this [related issue](https://gitlab.com/gitlab-org/gitlab/-/issues/20689).
For example, an alert notification email can have one of
[the alert's](../../operations/incident_management/alerts.md) statuses:
- `alert_triggered`
- `alert_acknowledged`
- `alert_resolved`
- `alert_ignored`
...@@ -19,7 +19,6 @@ module EE ...@@ -19,7 +19,6 @@ module EE
include FromUnion include FromUnion
self.inheritance_column = :_type_disabled self.inheritance_column = :_type_disabled
self.enumerate_columns_in_select_statements = true
# backported from ApplicationRecord # backported from ApplicationRecord
def self.cached_column_list def self.cached_column_list
......
...@@ -36,6 +36,27 @@ RSpec.describe Emails::Projects do ...@@ -36,6 +36,27 @@ RSpec.describe Emails::Projects do
Notify.prometheus_alert_fired_email(project, user, alert) Notify.prometheus_alert_fired_email(project, user, alert)
end end
it_behaves_like 'an email with X-GitLab headers containing project details'
it 'has expected X-GitLab alert headers', :aggregate_failures do
is_expected.to have_header('X-GitLab-Alert-ID', /#{alert.id}/)
is_expected.to have_header('X-GitLab-Alert-IID', /#{alert.iid}/)
is_expected.to have_header('X-GitLab-NotificationReason', "alert_#{alert.state}")
is_expected.not_to have_header('X-GitLab-Incident-ID', /.+/)
is_expected.not_to have_header('X-GitLab-Incident-IID', /.+/)
end
context 'with incident' do
let(:alert) { create(:alert_management_alert, :with_issue, :from_payload, payload: payload, project: project) }
let(:incident) { alert.issue }
it 'has expected X-GitLab incident headers', :aggregate_failures do
is_expected.to have_header('X-GitLab-Incident-ID', /#{incident.id}/)
is_expected.to have_header('X-GitLab-Incident-IID', /#{incident.iid}/)
end
end
context 'with empty payload' do context 'with empty payload' do
let(:payload) { {} } let(:payload) { {} }
......
...@@ -1419,66 +1419,65 @@ RSpec.describe ProjectPolicy do ...@@ -1419,66 +1419,65 @@ RSpec.describe ProjectPolicy do
end end
describe 'when user is authenticated via CI_JOB_TOKEN', :request_store do describe 'when user is authenticated via CI_JOB_TOKEN', :request_store do
let(:current_user) { developer } using RSpec::Parameterized::TableSyntax
let(:job) { build_stubbed(:ci_build, project: scope_project, user: current_user) }
before do where(:project_visibility, :user_role, :external_user, :scope_project_type, :token_scope_enabled, :result) do
current_user.set_ci_job_token_scope!(job) :private | :reporter | false | :same | true | true
scope_project.update!(ci_job_token_scope_enabled: true) :private | :reporter | false | :same | false | true
:private | :reporter | false | :different | true | false
:private | :reporter | false | :different | false | true
:private | :guest | false | :same | true | true
:private | :guest | false | :same | false | true
:private | :guest | false | :different | true | false
:private | :guest | false | :different | false | true
:internal | :reporter | false | :same | true | true
:internal | :reporter | true | :same | true | true
:internal | :reporter | false | :same | false | true
:internal | :reporter | false | :different | true | true
:internal | :reporter | true | :different | true | false
:internal | :reporter | false | :different | false | true
:internal | :guest | false | :same | true | true
:internal | :guest | true | :same | true | true
:internal | :guest | false | :same | false | true
:internal | :guest | false | :different | true | true
:internal | :guest | true | :different | true | false
:internal | :guest | false | :different | false | true
:public | :reporter | false | :same | true | true
:public | :reporter | false | :same | false | true
:public | :reporter | false | :different | true | true
:public | :reporter | false | :different | false | true
:public | :guest | false | :same | true | true
:public | :guest | false | :same | false | true
:public | :guest | false | :different | true | true
:public | :guest | false | :different | false | true
end end
context 'when accessing a private project' do with_them do
let(:project) { private_project } let(:current_user) { public_send(user_role) }
let(:project) { public_send("#{project_visibility}_project") }
context 'when the job token comes from the same project' do let(:job) { build_stubbed(:ci_build, project: scope_project, user: current_user) }
let(:scope_project) { project }
it { is_expected.to be_allowed(:developer_access) }
end
context 'when the job token comes from another project' do
let(:scope_project) { create(:project, :private) }
before do
scope_project.add_developer(current_user)
end
it { is_expected.to be_disallowed(:guest_access) }
context 'when job token scope is disabled' do
before do
scope_project.update!(ci_job_token_scope_enabled: false)
end
it { is_expected.to be_allowed(:guest_access) } let(:scope_project) do
if scope_project_type == :same
project
else
create(:project, :private)
end end
end end
end
context 'when accessing a public project' do
let(:project) { public_project }
context 'when the job token comes from the same project' do before do
let(:scope_project) { project } current_user.set_ci_job_token_scope!(job)
current_user.external = external_user
it { is_expected.to be_allowed(:developer_access) } scope_project.update!(ci_job_token_scope_enabled: token_scope_enabled)
end end
context 'when the job token comes from another project' do it "enforces the expected permissions" do
let(:scope_project) { create(:project, :private) } if result
is_expected.to be_allowed("#{user_role}_access".to_sym)
before do else
scope_project.add_developer(current_user) is_expected.to be_disallowed("#{user_role}_access".to_sym)
end
it { is_expected.to be_disallowed(:public_access) }
context 'when job token scope is disabled' do
before do
scope_project.update!(ci_job_token_scope_enabled: false)
end
it { is_expected.to be_allowed(:public_access) }
end end
end end
end end
......
...@@ -18,7 +18,7 @@ RSpec.describe API::GenericPackages do ...@@ -18,7 +18,7 @@ RSpec.describe API::GenericPackages do
let_it_be(:project_deploy_token_wo) { create(:project_deploy_token, deploy_token: deploy_token_wo, project: project) } let_it_be(:project_deploy_token_wo) { create(:project_deploy_token, deploy_token: deploy_token_wo, project: project) }
let(:user) { personal_access_token.user } let(:user) { personal_access_token.user }
let(:ci_build) { create(:ci_build, :running, user: user, project: project) } let(:ci_build) { create(:ci_build, :running, user: user) }
let(:snowplow_standard_context_params) { { user: user, project: project, namespace: project.namespace } } let(:snowplow_standard_context_params) { { user: user, project: project, namespace: project.namespace } }
def auth_header def auth_header
......
...@@ -11,7 +11,7 @@ RSpec.describe API::GoProxy do ...@@ -11,7 +11,7 @@ RSpec.describe API::GoProxy do
let_it_be(:base) { "#{Settings.build_gitlab_go_url}/#{project.full_path}" } let_it_be(:base) { "#{Settings.build_gitlab_go_url}/#{project.full_path}" }
let_it_be(:oauth) { create :oauth_access_token, scopes: 'api', resource_owner: user } let_it_be(:oauth) { create :oauth_access_token, scopes: 'api', resource_owner: user }
let_it_be(:job) { create :ci_build, user: user, status: :running, project: project } let_it_be(:job) { create :ci_build, user: user, status: :running }
let_it_be(:pa_token) { create :personal_access_token, user: user } let_it_be(:pa_token) { create :personal_access_token, user: user }
let_it_be(:modules) do let_it_be(:modules) do
......
...@@ -15,7 +15,7 @@ RSpec.describe API::MavenPackages do ...@@ -15,7 +15,7 @@ RSpec.describe API::MavenPackages do
let_it_be(:package_file) { package.package_files.with_file_name_like('%.xml').first } let_it_be(:package_file) { package.package_files.with_file_name_like('%.xml').first }
let_it_be(:jar_file) { package.package_files.with_file_name_like('%.jar').first } let_it_be(:jar_file) { package.package_files.with_file_name_like('%.jar').first }
let_it_be(:personal_access_token) { create(:personal_access_token, user: user) } let_it_be(:personal_access_token) { create(:personal_access_token, user: user) }
let_it_be(:job, reload: true) { create(:ci_build, user: user, status: :running, project: project) } let_it_be(:job, reload: true) { create(:ci_build, user: user, status: :running) }
let_it_be(:deploy_token) { create(:deploy_token, read_package_registry: true, write_package_registry: true) } let_it_be(:deploy_token) { create(:deploy_token, read_package_registry: true, write_package_registry: true) }
let_it_be(:project_deploy_token) { create(:project_deploy_token, deploy_token: deploy_token, project: project) } let_it_be(:project_deploy_token) { create(:project_deploy_token, deploy_token: deploy_token, project: project) }
let_it_be(:deploy_token_for_group) { create(:deploy_token, :group, read_package_registry: true, write_package_registry: true) } let_it_be(:deploy_token_for_group) { create(:deploy_token, :group, read_package_registry: true, write_package_registry: true) }
......
...@@ -78,7 +78,7 @@ RSpec.describe API::NpmProjectPackages do ...@@ -78,7 +78,7 @@ RSpec.describe API::NpmProjectPackages do
context 'with a job token for a different user' do context 'with a job token for a different user' do
let_it_be(:other_user) { create(:user) } let_it_be(:other_user) { create(:user) }
let_it_be_with_reload(:other_job) { create(:ci_build, :running, user: other_user, project: project) } let_it_be_with_reload(:other_job) { create(:ci_build, :running, user: other_user) }
let(:headers) { build_token_auth_header(other_job.token) } let(:headers) { build_token_auth_header(other_job.token) }
......
...@@ -13,7 +13,7 @@ RSpec.describe API::PypiPackages do ...@@ -13,7 +13,7 @@ RSpec.describe API::PypiPackages do
let_it_be(:personal_access_token) { create(:personal_access_token, user: user) } let_it_be(:personal_access_token) { create(:personal_access_token, user: user) }
let_it_be(:deploy_token) { create(:deploy_token, read_package_registry: true, write_package_registry: true) } let_it_be(:deploy_token) { create(:deploy_token, read_package_registry: true, write_package_registry: true) }
let_it_be(:project_deploy_token) { create(:project_deploy_token, deploy_token: deploy_token, project: project) } let_it_be(:project_deploy_token) { create(:project_deploy_token, deploy_token: deploy_token, project: project) }
let_it_be(:job) { create(:ci_build, :running, user: user, project: project) } let_it_be(:job) { create(:ci_build, :running, user: user) }
let(:headers) { {} } let(:headers) { {} }
......
...@@ -811,7 +811,7 @@ RSpec.describe API::Releases do ...@@ -811,7 +811,7 @@ RSpec.describe API::Releases do
end end
context 'when using JOB-TOKEN auth' do context 'when using JOB-TOKEN auth' do
let(:job) { create(:ci_build, user: maintainer, project: project) } let(:job) { create(:ci_build, user: maintainer) }
let(:params) do let(:params) do
{ {
name: 'Another release', name: 'Another release',
......
...@@ -10,7 +10,7 @@ RSpec.describe API::RubygemPackages do ...@@ -10,7 +10,7 @@ RSpec.describe API::RubygemPackages do
let_it_be_with_reload(:project) { create(:project) } let_it_be_with_reload(:project) { create(:project) }
let_it_be(:personal_access_token) { create(:personal_access_token) } let_it_be(:personal_access_token) { create(:personal_access_token) }
let_it_be(:user) { personal_access_token.user } let_it_be(:user) { personal_access_token.user }
let_it_be(:job) { create(:ci_build, :running, user: user, project: project) } let_it_be(:job) { create(:ci_build, :running, user: user) }
let_it_be(:deploy_token) { create(:deploy_token, read_package_registry: true, write_package_registry: true) } let_it_be(:deploy_token) { create(:deploy_token, read_package_registry: true, write_package_registry: true) }
let_it_be(:project_deploy_token) { create(:project_deploy_token, deploy_token: deploy_token, project: project) } let_it_be(:project_deploy_token) { create(:project_deploy_token, deploy_token: deploy_token, project: project) }
let_it_be(:headers) { {} } let_it_be(:headers) { {} }
......
...@@ -12,7 +12,7 @@ RSpec.describe API::Terraform::Modules::V1::Packages do ...@@ -12,7 +12,7 @@ RSpec.describe API::Terraform::Modules::V1::Packages do
let_it_be(:package) { create(:terraform_module_package, project: project) } let_it_be(:package) { create(:terraform_module_package, project: project) }
let_it_be(:personal_access_token) { create(:personal_access_token) } let_it_be(:personal_access_token) { create(:personal_access_token) }
let_it_be(:user) { personal_access_token.user } let_it_be(:user) { personal_access_token.user }
let_it_be(:job) { create(:ci_build, :running, user: user, project: project) } let_it_be(:job) { create(:ci_build, :running, user: user) }
let_it_be(:deploy_token) { create(:deploy_token, read_package_registry: true, write_package_registry: true) } let_it_be(:deploy_token) { create(:deploy_token, read_package_registry: true, write_package_registry: true) }
let_it_be(:project_deploy_token) { create(:project_deploy_token, deploy_token: deploy_token, project: project) } let_it_be(:project_deploy_token) { create(:project_deploy_token, deploy_token: deploy_token, project: project) }
......
...@@ -11,7 +11,7 @@ RSpec.shared_context 'conan api setup' do ...@@ -11,7 +11,7 @@ RSpec.shared_context 'conan api setup' do
let_it_be(:deploy_token) { create(:deploy_token, read_package_registry: true, write_package_registry: true) } let_it_be(:deploy_token) { create(:deploy_token, read_package_registry: true, write_package_registry: true) }
let(:project) { package.project } let(:project) { package.project }
let(:job) { create(:ci_build, :running, user: user, project: project) } let(:job) { create(:ci_build, :running, user: user) }
let(:job_token) { job.token } let(:job_token) { job.token }
let(:auth_token) { personal_access_token.token } let(:auth_token) { personal_access_token.token }
let(:project_deploy_token) { create(:project_deploy_token, deploy_token: deploy_token, project: project) } let(:project_deploy_token) { create(:project_deploy_token, deploy_token: deploy_token, project: project) }
......
...@@ -11,7 +11,7 @@ RSpec.shared_context 'npm api setup' do ...@@ -11,7 +11,7 @@ RSpec.shared_context 'npm api setup' do
let_it_be(:package, reload: true) { create(:npm_package, project: project, name: "@#{group.path}/scoped_package") } let_it_be(:package, reload: true) { create(:npm_package, project: project, name: "@#{group.path}/scoped_package") }
let_it_be(:token) { create(:oauth_access_token, scopes: 'api', resource_owner: user) } let_it_be(:token) { create(:oauth_access_token, scopes: 'api', resource_owner: user) }
let_it_be(:personal_access_token) { create(:personal_access_token, user: user) } let_it_be(:personal_access_token) { create(:personal_access_token, user: user) }
let_it_be(:job, reload: true) { create(:ci_build, user: user, status: :running, project: project) } let_it_be(:job, reload: true) { create(:ci_build, user: user, status: :running) }
let_it_be(:deploy_token) { create(:deploy_token, read_package_registry: true, write_package_registry: true) } let_it_be(:deploy_token) { create(:deploy_token, read_package_registry: true, write_package_registry: true) }
let_it_be(:project_deploy_token) { create(:project_deploy_token, deploy_token: deploy_token, project: project) } let_it_be(:project_deploy_token) { create(:project_deploy_token, deploy_token: deploy_token, project: project) }
......
Markdown is supported
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