Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-10-20 21:09:04 +00:00
parent a3764262c0
commit 40e8ba2fc8
39 changed files with 499 additions and 235 deletions

View File

@ -127,7 +127,7 @@ variables:
# Run with decomposed databases by default
DECOMPOSED_DB: "true"
DOCS_REVIEW_APPS_DOMAIN: "docs.gitlab-review-app"
DOCS_REVIEW_APPS_DOMAIN: "docs.gitlab-review.app"
DOCS_GITLAB_REPO_SUFFIX: "ee"
REVIEW_APPS_IMAGE: "${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images/ruby-3.0:gcloud-383-kubectl-1.23-helm-3.5"

View File

@ -7,7 +7,7 @@ include:
- local: .gitlab/ci/package-and-test/rules.gitlab-ci.yml
- local: .gitlab/ci/package-and-test/variables.gitlab-ci.yml
- project: gitlab-org/quality/pipeline-common
ref: 1.4.0
ref: 1.3.0
file:
- /ci/base.gitlab-ci.yml
- /ci/allure-report.yml

View File

@ -1,6 +1,6 @@
include:
- project: gitlab-org/quality/pipeline-common
ref: 1.4.0
ref: 1.3.0
file:
- /ci/base.gitlab-ci.yml
- /ci/allure-report.yml

View File

@ -1 +1 @@
ef8362fdf1c0eca9c73fb0fa4dc5b45c5c7965d8
3d5bb4cdfd5f31e5e5f0c7506905755e51d0b611

View File

@ -27,6 +27,7 @@ export default {
},
dropdownPopperOpts: {
placement: 'bottom',
positionFixed: true,
},
components: {
CiIcon,

View File

@ -2,6 +2,7 @@
import { GlTableLite } from '@gitlab/ui';
import { __, s__ } from '~/locale';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { durationTimeFormatted } from '~/lib/utils/datetime_utility';
import CiBadge from '~/vue_shared/components/ci_badge_link.vue';
import RunnerTags from '~/runner/components/runner_tags.vue';
import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
@ -47,6 +48,14 @@ export default {
commitPath(job) {
return job.commitPath;
},
duration(job) {
const { duration } = job;
return duration ? durationTimeFormatted(duration) : '';
},
queued(job) {
const { queuedDuration } = job;
return queuedDuration ? durationTimeFormatted(queuedDuration) : '';
},
},
fields: [
tableField({ key: 'status', label: s__('Job|Status') }),
@ -54,6 +63,8 @@ export default {
tableField({ key: 'project', label: __('Project') }),
tableField({ key: 'commit', label: __('Commit') }),
tableField({ key: 'finished_at', label: s__('Job|Finished at') }),
tableField({ key: 'duration', label: s__('Job|Duration') }),
tableField({ key: 'queued', label: s__('Job|Queued') }),
tableField({ key: 'tags', label: s__('Runners|Tags') }),
],
};
@ -84,12 +95,20 @@ export default {
<link-cell :href="commitPath(item)"> {{ commitShortSha(item) }}</link-cell>
</template>
<template #cell(tags)="{ item = {} }">
<runner-tags :tag-list="item.tags" />
</template>
<template #cell(finished_at)="{ item = {} }">
<time-ago v-if="item.finishedAt" :time="item.finishedAt" />
</template>
<template #cell(duration)="{ item = {} }">
{{ duration(item) }}
</template>
<template #cell(queued)="{ item = {} }">
{{ queued(item) }}
</template>
<template #cell(tags)="{ item = {} }">
<runner-tags :tag-list="item.tags" />
</template>
</gl-table-lite>
</template>

View File

@ -25,8 +25,10 @@ query getRunnerJobs($id: CiRunnerID!, $first: Int, $last: Int, $before: String,
}
shortSha
commitPath
tags
finishedAt
duration
queuedDuration
tags
}
pageInfo {
...PageInfo

View File

@ -20,7 +20,7 @@ module WebHooks
unless hook.valid?
self.hooks = relation.select(&:persisted?)
flash[:alert] = hook.errors.full_messages.join.html_safe
flash[:alert] = hook.errors.full_messages.to_sentence.html_safe
end
redirect_to action: :index
@ -64,7 +64,9 @@ module WebHooks
end
def hook_param_names
%i[enable_ssl_verification token url push_events_branch_filter]
param_names = %i[enable_ssl_verification token url push_events_branch_filter]
param_names.push(:branch_filter_strategy) if Feature.enabled?(:enhanced_webhook_support_regex)
param_names
end
def destroy_hook(hook)

View File

@ -3,14 +3,36 @@
class ActiveHookFilter
def initialize(hook)
@hook = hook
@push_events_filter_matcher = RefMatcher.new(@hook.push_events_branch_filter)
end
def matches?(hooks_scope, data)
return true if hooks_scope != :push_hooks
return true unless hooks_scope == :push_hooks
matches_branch?(data)
end
private
def matches_branch?(data)
return true if @hook.push_events_branch_filter.blank?
branch_name = Gitlab::Git.branch_name(data[:ref])
@push_events_filter_matcher.matches?(branch_name)
if Feature.disabled?(:enhanced_webhook_support_regex)
return RefMatcher.new(@hook.push_events_branch_filter).matches?(branch_name)
end
case @hook.branch_filter_strategy
when 'all_branches'
true
when 'wildcard'
RefMatcher.new(@hook.push_events_branch_filter).matches?(branch_name)
when 'regex'
begin
Gitlab::UntrustedRegexp.new(@hook.push_events_branch_filter) === branch_name
rescue RegexpError
false
end
end
end
end

View File

@ -36,11 +36,22 @@ class WebHook < ApplicationRecord
validates :url, public_url: true, unless: ->(hook) { hook.is_a?(SystemHook) }
validates :token, format: { without: /\n/ }
validates :push_events_branch_filter, branch_filter: true
after_initialize :initialize_url_variables
before_validation :set_branch_filter_nil, \
if: -> { branch_filter_strategy_all_branches? && enhanced_webhook_support_regex? }
validates :push_events_branch_filter, \
untrusted_regexp: true, if: -> { branch_filter_strategy_regex? && enhanced_webhook_support_regex? }
validates :push_events_branch_filter, \
"web_hooks/wildcard_branch_filter": true, if: -> { branch_filter_strategy_wildcard? }
validates :url_variables, json_schema: { filename: 'web_hooks_url_variables' }
validate :no_missing_url_variables
after_initialize :initialize_url_variables
enum branch_filter_strategy: {
wildcard: 0,
regex: 1,
all_branches: 2
}, _prefix: true
scope :executable, -> do
next all unless Feature.enabled?(:web_hooks_disable_failed)
@ -224,4 +235,12 @@ class WebHook < ApplicationRecord
errors.add(:url, "Invalid URL template. Missing keys: #{missing}")
end
def enhanced_webhook_support_regex?
Feature.enabled?(:enhanced_webhook_support_regex)
end
def set_branch_filter_nil
self.push_events_branch_filter = nil
end
end

View File

@ -1,37 +0,0 @@
# frozen_string_literal: true
# BranchFilterValidator
#
# Custom validator for branch names. Squishes whitespace and ignores empty
# string. This only checks that a string is a valid git branch name. It does
# not check whether a branch already exists.
#
# Example:
#
# class Webhook < ActiveRecord::Base
# validates :push_events_branch_filter, branch_name: true
# end
#
class BranchFilterValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
value.squish! unless value.nil?
if value.present?
value_without_wildcards = value.tr('*', 'x')
unless Gitlab::GitRefValidator.validate(value_without_wildcards)
record.errors.add(attribute, "is not a valid branch name")
end
unless value.length <= 4000
record.errors.add(attribute, "is longer than the allowed length of 4000 characters.")
end
end
end
private
def contains_wildcard?(value)
value.include?('*')
end
end

View File

@ -0,0 +1,34 @@
# frozen_string_literal: true
# WildcardBranchFilterValidator
#
# Custom validator for wildcard branch filter. Squishes whitespace and ignores
# empty string. This only checks that a string is a valid wildcard git branch
# like "feature/login" and "feature/*". It doesn't check whether a branch already
# exists.
#
# Example:
#
# class Webhook < ActiveRecord::Base
# validates :push_events_branch_filter, "web_hooks/wildcard_branch_filter": true
# end
#
module WebHooks
class WildcardBranchFilterValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
value.squish! unless value.nil?
return unless value.present?
value_without_wildcards = value.tr('*', 'x')
unless Gitlab::GitRefValidator.validate(value_without_wildcards)
record.errors.add(attribute, "is not a valid branch name")
end
return if value.length <= 4000
record.errors.add(attribute, "is longer than the allowed length of 4000 characters.")
end
end
end

View File

@ -9,6 +9,6 @@
.col-lg-8.gl-mb-3
= gitlab_ui_form_for @hook, as: :hook, url: polymorphic_path([@project, :hooks]) do |f|
= render partial: 'shared/web_hooks/form', locals: { form: f, hook: @hook }
= f.submit 'Add webhook', pajamas_button: true
= f.submit _('Add webhook'), pajamas_button: true, data: { qa_selector: "create_webhook_button" }
= render 'shared/web_hooks/index', hooks: @hooks, hook_class: @hook.class

View File

@ -19,12 +19,16 @@
= form.label :url, s_('Webhooks|Trigger'), class: 'label-bold'
%ul.list-unstyled
%li.gl-pb-5
= form.gitlab_ui_checkbox_component :push_events, s_('Webhooks|Push events')
.gl-pl-6
= form.text_field :push_events_branch_filter, class: 'form-control gl-form-input',
placeholder: 'Branch name or wildcard pattern to trigger on (leave blank for all)'
%p.form-text.text-muted.custom-control
= s_('Webhooks|Push to the repository.')
- if Feature.enabled?(:enhanced_webhook_support_regex)
- is_new_hook = hook.id.nil?
.js-vue-push-events{ data: { push_events: hook.push_events.to_s, strategy: hook.branch_filter_strategy, is_new_hook: is_new_hook.to_s, push_events_branch_filter: hook.push_events_branch_filter } }
- else
= form.gitlab_ui_checkbox_component :push_events, s_('Webhooks|Push events')
.gl-pl-6
= form.text_field :push_events_branch_filter, class: 'form-control gl-form-input',
placeholder: 'Branch name or wildcard pattern to trigger on (leave blank for all)'
%p.form-text.text-muted.custom-control
= s_('Webhooks|Push to the repository.')
%li.gl-pb-5
= form.gitlab_ui_checkbox_component :tag_push_events,
s_('Webhooks|Tag push events'),

View File

@ -1,8 +1,8 @@
---
name: cascade_package_forwarding_settings
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/99285
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/375761
milestone: '15.5'
name: enhanced_webhook_support_regex
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/97235
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/375728
milestone: '15.6'
type: development
group: group::package
group: group::integrations
default_enabled: false

View File

@ -0,0 +1,13 @@
- name: "File Type variable expansion in `.gitlab-ci.yml`" # (required) The name of the feature to be deprecated
announcement_milestone: "15.5" # (required) The milestone when this feature was first announced as deprecated.
announcement_date: "2022-10-22" # (required) The date of the milestone release when this feature was first announced as deprecated. This should almost always be the 22nd of a month (YYYY-MM-22), unless you did an out of band blog post.
removal_milestone: "15.7" # (required) The milestone when this feature is planned to be removed
removal_date: # (required) The date of the milestone release when this feature is planned to be removed. This should almost always be the 22nd of a month (YYYY-MM-22), unless you did an out of band blog post.
breaking_change: true # (required) If this deprecation is a breaking change, set this value to true
reporter: DarrenEastman # (required) GitLab username of the person reporting the deprecation
stage: Verify # (required) String value of the stage that the feature was created in. e.g., Growth
issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/29407 # (required) Link to the deprecation issue in GitLab
body: | # (required) Do not modify this line, instead modify the lines below.
Previously, variables that referenced or applied alias file variables expanded the value of the `File` type variable. For example, the file contents. This behavior was incorrect because it did not comply with typical shell variable expansion rules. To leak secrets or sensitive information stored in `File` type variables, a user could run an $echo command with the variable as an input parameter.
This breaking change fixes this issue but could disrupt user workflows that work around the behavior. With this change, job variable expansions that reference or apply alias file variables, expand to the file name or path of the `File` type variable, instead of its value, such as the file contents.

View File

@ -97,6 +97,13 @@ Whenever a project is forked, it copies the settings of the jobs that relate
to it. This means that if you have shared runners set up for a project and
someone forks that project, the shared runners serve jobs of this project.
Because of a [known issue](https://gitlab.com/gitlab-org/gitlab/-/issues/364303), you might encounter the message `An error occurred while forking the project. Please try again.` if the runner settings of the project you are forking does not match the new project namespace.
To work around this issue, you should make sure that the shared runner settings are consistent in the forked project and the new namespace.
- If shared runners are **enabled** on the forked project, then this should also be **enabled** on the new namespace.
- If shared runners are **disabled** on the forked project, then this should also be **disabled** on the new namespace.
### Attack vectors in runners
Mentioned briefly earlier, but the following things of runners can be exploited.

View File

@ -8,23 +8,23 @@ info: To determine the technical writer assigned to the Stage/Group associated w
You accept and agree to the following terms and conditions for Your present and future Contributions submitted to GitLab B.V.. Except for the license granted herein to GitLab B.V. and recipients of software distributed by GitLab B.V., You reserve all right, title, and interest in and to Your Contributions.
- **Definitions:**
"1." **Definitions:**
"You" (or "Your") shall mean the copyright owner or legal entity authorized by the copyright owner that is making this Agreement with GitLab B.V.. For legal entities, the entity making a Contribution and all other entities that control, are controlled by, or are under common control with that entity are considered to be a single Contributor. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
"Contribution" shall mean the code, documentation or other original works of authorship, including any modifications or additions to an existing work, that is submitted by You to GitLab B.V. for inclusion in, or documentation of, any of the products owned or managed by GitLab B.V. (the "Work"). For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to GitLab B.V. or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, GitLab B.V. for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by You as "Not a Contribution."
- **Grant of Copyright License:**
"2." **Grant of Copyright License:**
Subject to the terms and conditions of this Agreement, You hereby grant to GitLab B.V. and to recipients of software distributed by GitLab B.V. a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute Your Contributions and such derivative works.
- **Grant of Patent License:**
"3." **Grant of Patent License:**
Subject to the terms and conditions of this Agreement, You hereby grant to GitLab B.V. and to recipients of software distributed by GitLab B.V. a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by You that are necessarily infringed by Your Contribution(s) alone or by combination of Your Contribution(s) with the Work to which such Contribution(s) was submitted. If any entity institutes patent litigation against You or any other entity (including a cross-claim or counterclaim in a lawsuit) alleging that your Contribution, or the Work to which you have contributed, constitutes direct or contributory patent infringement, then any patent licenses granted to that entity under this Agreement for that Contribution or Work shall terminate as of the date such litigation is filed.
You represent that You are legally entitled to grant the above license. You represent further that each of Your employees is authorized to submit Contributions on Your behalf, but excluding employees that are designated in writing by You as "Not authorized to submit Contributions on behalf of (name of Your corporation here)." Such designations of exclusion for unauthorized employees are to be submitted via email to `legal@gitlab.com`. It is Your responsibility to notify GitLab B.V. when any change is required to the list of designated employees excluded from submitting Contributions on Your behalf. Such notification should also be sent via email to `legal@gitlab.com`.
- **Contributions:**
"4." **Contributions:**
You represent that each of Your Contributions is Your original creation.

View File

@ -8,23 +8,23 @@ info: To determine the technical writer assigned to the Stage/Group associated w
You accept and agree to the following terms and conditions for Your present and future Contributions submitted to GitLab B.V.. Except for the license granted herein to GitLab B.V. and recipients of software distributed by GitLab B.V., You reserve all right, title, and interest in and to Your Contributions.
- **Definitions:**
"1." **Definitions:**
"You" (or "Your") shall mean the copyright owner or legal entity authorized by the copyright owner that is making this Agreement with GitLab B.V.. For legal entities, the entity making a Contribution and all other entities that control, are controlled by, or are under common control with that entity are considered to be a single Contributor. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
"Contribution" shall mean any original work of authorship, including any modifications or additions to an existing work, that is intentionally submitted by You to GitLab B.V. for inclusion in, or documentation of, any of the products owned or managed by GitLab B.V. (the "Work"). For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to GitLab B.V. or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, GitLab B.V. for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by You as "Not a Contribution."
- **Grant of Copyright License:**
"2." **Grant of Copyright License:**
Subject to the terms and conditions of this Agreement, You hereby grant to GitLab B.V. and to recipients of software distributed by GitLab B.V. a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute Your Contributions and such derivative works.
- **Grant of Patent License:**
"3." **Grant of Patent License:**
Subject to the terms and conditions of this Agreement, You hereby grant to GitLab B.V. and to recipients of software distributed by GitLab B.V. a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by You that are necessarily infringed by Your Contribution(s) alone or by combination of Your Contribution(s) with the Work to which such Contribution(s) was submitted. If any entity institutes patent litigation against You or any other entity (including a cross-claim or counterclaim in a lawsuit) alleging that your Contribution, or the Work to which you have contributed, constitutes direct or contributory patent infringement, then any patent licenses granted to that entity under this Agreement for that Contribution or Work shall terminate as of the date such litigation is filed.
You represent that you are legally entitled to grant the above license. If your employer(s) has rights to intellectual property that you create that includes your Contributions, you represent that you have received permission to make Contributions on behalf of that employer, that your employer has waived such rights for your Contributions to GitLab B.V., or that your employer has executed a separate Corporate CLA with GitLab B.V..
- **Contributions:**
"4." **Contributions:**
You represent that each of Your Contributions is Your original creation. You represent that Your Contribution submissions include complete details of any third-party license or other restriction (including, but not limited to, related patents and trademarks) of which you are personally aware and which are associated with any part of Your Contributions.

View File

@ -47,6 +47,22 @@ sole discretion of GitLab Inc.
## Announced in 15.5
<div class="deprecation removal-157 breaking-change">
### File Type variable expansion in `.gitlab-ci.yml`
Planned removal: GitLab <span class="removal-milestone">15.7</span> ()
WARNING:
This is a [breaking change](https://docs.gitlab.com/ee/development/deprecation_guidelines/).
Review the details carefully before upgrading.
Previously, variables that referenced or applied alias file variables expanded the value of the `File` type variable. For example, the file contents. This behavior was incorrect because it did not comply with typical shell variable expansion rules. To leak secrets or sensitive information stored in `File` type variables, a user could run an $echo command with the variable as an input parameter.
This breaking change fixes this issue but could disrupt user workflows that work around the behavior. With this change, job variable expansions that reference or apply alias file variables, expand to the file name or path of the `File` type variable, instead of its value, such as the file contents.
</div>
<div class="deprecation removal-160 breaking-change">
### GraphQL field `confidential` changed to `internal` on notes

View File

@ -10,7 +10,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
Infrastructure as Code (IaC) Scanning scans your IaC configuration files for known vulnerabilities.
Currently, IaC scanning supports configuration files for Terraform, Ansible, AWS CloudFormation, and Kubernetes.
IaC Scanning supports configuration files for Terraform, Ansible, AWS CloudFormation, and Kubernetes.
## Requirements
@ -18,13 +18,13 @@ IaC Scanning runs in the `test` stage, which is available by default. If you red
We recommend a minimum of 4GB RAM to ensure consistent performance.
To run IaC scanning jobs, by default, you need GitLab Runner with the
To run IaC Scanning jobs, by default, you need GitLab Runner with the
[`docker`](https://docs.gitlab.com/runner/executors/docker.html) or
[`kubernetes`](https://docs.gitlab.com/runner/install/kubernetes.html) executor.
If you're using the shared runners on GitLab.com, this is enabled by default.
WARNING:
Our IaC scanning jobs require a Linux/amd64 container type. Windows containers are not yet supported.
Our IaC Scanning jobs require a Linux/amd64 container type. Windows containers are not supported.
WARNING:
If you use your own runners, make sure the Docker version installed
@ -32,9 +32,9 @@ is **not** `19.03.0`. See [troubleshooting information](../sast/index.md#error-r
## Supported languages and frameworks
GitLab IaC scanning supports a variety of IaC configuration files. Our IaC security scanners also feature automatic language detection which works even for mixed-language projects. If any supported configuration files are detected in project source code we automatically run the appropriate IaC analyzers.
GitLab IaC Scanning supports a variety of IaC configuration files. Our IaC security scanners also feature automatic language detection which works even for mixed-language projects. If any supported configuration files are detected in project source code we automatically run the appropriate IaC analyzers.
| Configuration File Type | Scan tool | Introduced in GitLab Version |
| Configuration file type | Scan tool | Introduced in GitLab version |
| ----------------------------------- | ------------------------ | ---------------------------- |
| Ansible | [KICS](https://kics.io/) | 14.5 |
| AWS CloudFormation | [KICS](https://kics.io/) | 14.5 |
@ -45,7 +45,7 @@ GitLab IaC scanning supports a variety of IaC configuration files. Our IaC secur
| OpenAPI | [KICS](https://kics.io/) | 14.5 |
| Terraform <sup>2</sup> | [KICS](https://kics.io/) | 14.5 |
1. IaC scanning can analyze Azure Resource Manager templates in JSON format. If you write templates in the [Bicep](https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/overview) language, you must use [the bicep CLI](https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/bicep-cli) to convert your Bicep files into JSON before GitLab IaC scanning can analyze them.
1. IaC Scanning can analyze Azure Resource Manager templates in JSON format. If you write templates in the [Bicep](https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/overview) language, you must use [the bicep CLI](https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/bicep-cli) to convert your Bicep files into JSON before GitLab IaC Scanning can analyze them.
1. Terraform modules in a custom registry are not scanned for vulnerabilities. You can follow [this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/357004) for the proposed feature.
### Supported distributions
@ -107,7 +107,7 @@ include:
- template: Jobs/SAST-IaC.gitlab-ci.yml
```
The included template creates IaC scanning jobs in your CI/CD pipeline and scans
The included template creates IaC Scanning jobs in your CI/CD pipeline and scans
your project's configuration files for possible vulnerabilities.
The results are saved as a

View File

@ -1,6 +1,6 @@
---
stage: Plan
group: Project Management
group: Product Planning
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---

View File

@ -45,7 +45,7 @@ module API
raise ArgumentError, "Can't find application setting for package_type #{package_type}" unless application_setting_name
if target.present? && Feature.enabled?(:cascade_package_forwarding_settings, target)
if target.present?
target.public_send(application_setting_name) # rubocop:disable GitlabSecurity/PublicSend
else
::Gitlab::CurrentSettings

View File

@ -157,13 +157,7 @@ module Gitlab
signature_value: value
)
if signature.valid?
signature
else
e = SecurityReportParserError.new("Vulnerability tracking signature is not valid: #{signature}")
Gitlab::ErrorTracking.track_exception(e)
nil
end
signature if signature.valid?
end.compact
end

View File

@ -23312,6 +23312,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
msgid "Job|Duration"
msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
@ -23351,6 +23354,9 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
msgid "Job|Queued"
msgstr ""
msgid "Job|Retry"
msgstr ""

View File

@ -106,8 +106,9 @@ RSpec.describe Projects::HooksController do
it 'sets all parameters' do
hook_params = {
enable_ssl_verification: true,
token: "TEST TOKEN",
url: "http://example.com",
token: 'TEST TOKEN',
url: 'http://example.com',
branch_filter_strategy: 'regex',
push_events: true,
tag_push_events: true,
@ -124,13 +125,39 @@ RSpec.describe Projects::HooksController do
url_variables: [{ key: 'token', value: 'some secret value' }]
}
post :create, params: { namespace_id: project.namespace, project_id: project, hook: hook_params }
params = { namespace_id: project.namespace, project_id: project, hook: hook_params }
expect { post :create, params: params }.to change(ProjectHook, :count).by(1)
project_hook = ProjectHook.order_id_desc.take
expect(project_hook).to have_attributes(
**hook_params.merge(url_variables: { 'token' => 'some secret value' })
)
expect(response).to have_gitlab_http_status(:found)
expect(flash[:alert]).to be_blank
end
it 'ignores branch_filter_strategy when flag is disabled' do
stub_feature_flags(enhanced_webhook_support_regex: false)
hook_params = {
url: 'http://example.com',
branch_filter_strategy: 'regex',
push_events: true
}
params = { namespace_id: project.namespace, project_id: project, hook: hook_params }
expect { post :create, params: params }.to change(ProjectHook, :count).by(1)
project_hook = ProjectHook.order_id_desc.take
expect(project_hook).to have_attributes(
url: 'http://example.com',
branch_filter_strategy: 'wildcard'
)
expect(response).to have_gitlab_http_status(:found)
expect(flash[:alert]).to be_blank
expect(ProjectHook.count).to eq(1)
expect(ProjectHook.first).to have_attributes(hook_params.except(:url_variables))
expect(ProjectHook.first).to have_attributes(url_variables: { 'token' => 'some secret value' })
end
it 'alerts the user if the new hook is invalid' do

View File

@ -48,22 +48,47 @@ RSpec.describe 'Projects > Settings > Webhook Settings' do
expect(page).to have_content('Releases events')
end
it 'create webhook', :js do
visit webhooks_path
context 'when feature flag "enhanced_webhook_support_regex" is disabled' do
before do
stub_feature_flags(enhanced_webhook_support_regex: false)
end
fill_in 'URL', with: url
check 'Tag push events'
fill_in 'hook_push_events_branch_filter', with: 'master'
check 'Enable SSL verification'
check 'Job events'
it 'create webhook', :js do
visit webhooks_path
click_button 'Add webhook'
fill_in 'URL', with: url
check 'Tag push events'
fill_in 'hook_push_events_branch_filter', with: 'master'
check 'Enable SSL verification'
check 'Job events'
expect(page).to have_content(url)
expect(page).to have_content('SSL Verification: enabled')
expect(page).to have_content('Push events')
expect(page).to have_content('Tag push events')
expect(page).to have_content('Job events')
click_button 'Add webhook'
expect(page).to have_content(url)
expect(page).to have_content('SSL Verification: enabled')
expect(page).to have_content('Tag push events')
expect(page).to have_content('Job events')
expect(page).to have_content('Push events')
end
end
context 'when feature flag "enhanced_webhook_support_regex" is enabled' do
it 'create webhook', :js do
visit webhooks_path
fill_in 'URL', with: url
check 'Tag push events'
check 'Enable SSL verification'
check 'Job events'
click_button 'Add webhook'
expect(page).to have_content(url)
expect(page).to have_content('SSL Verification: enabled')
expect(page).to have_content('Tag push events')
expect(page).to have_content('Job events')
expect(page).to have_selector('.js-vue-push-events', visible: :all)
end
end
it 'edit existing webhook', :js do

View File

@ -61,6 +61,8 @@ describe('RunnerJobsTable', () => {
__('Project'),
__('Commit'),
s__('Job|Finished at'),
s__('Job|Duration'),
s__('Job|Queued'),
s__('Runners|Tags'),
]);
});
@ -108,6 +110,22 @@ describe('RunnerJobsTable', () => {
expect(findCell({ field: 'finished_at' }).text()).toBe('1 hour ago');
});
it('Formats duration time', () => {
mockJobsCopy[0].duration = 60;
createComponent({ props: { jobs: mockJobsCopy } }, mountExtended);
expect(findCell({ field: 'duration' }).text()).toBe('00:01:00');
});
it('Formats queued time', () => {
mockJobsCopy[0].queuedDuration = 30;
createComponent({ props: { jobs: mockJobsCopy } }, mountExtended);
expect(findCell({ field: 'queued' }).text()).toBe('00:00:30');
});
it('Formats tags', () => {
mockJobsCopy[0].tags = ['tag-1', 'tag-2'];

View File

@ -10,7 +10,7 @@ RSpec.describe API::Helpers::Packages::DependencyProxyHelpers do
include_context 'dependency proxy helpers context'
let_it_be(:group) { create(:group) }
let_it_be(:project) { create(:project, group: group) }
let_it_be_with_reload(:project) { create(:project, group: group) }
let_it_be_with_reload(:package_setting) { create(:namespace_package_setting, namespace: group) }
let(:target) { project }
@ -76,19 +76,6 @@ RSpec.describe API::Helpers::Packages::DependencyProxyHelpers do
end
end
context 'when cascade_package_forwarding_settings is disabled' do
let(:package_type) { forwardable_package_type }
let(:forward_to_registry) { true }
before do
stub_feature_flags(cascade_package_forwarding_settings: false)
allow_fetch_cascade_application_setting(attribute: "#{forwardable_package_type}_package_requests_forwarding", return_value: true)
package_setting.update!("#{forwardable_package_type}_package_requests_forwarding" => false)
end
it_behaves_like 'executing redirect'
end
context 'when no target is present' do
let(:package_type) { forwardable_package_type }
let(:forward_to_registry) { true }

View File

@ -400,28 +400,9 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Common do
end
describe 'parsing tracking' do
let(:tracking_data) do
{
'type' => 'source',
'items' => [
'signatures' => [
{ 'algorithm' => 'hash', 'value' => 'hash_value' },
{ 'algorithm' => 'location', 'value' => 'location_value' },
{ 'algorithm' => 'scope_offset', 'value' => 'scope_offset_value' }
]
]
}
end
context 'with valid tracking information' do
it 'creates signatures for each algorithm' do
finding = report.findings.first
expect(finding.signatures.size).to eq(3)
expect(finding.signatures.map(&:algorithm_type).to_set).to eq(Set['hash', 'location', 'scope_offset'])
end
end
context 'with invalid tracking information' do
let(:finding) { report.findings.first }
let(:number_of_findings) { report.findings.length }
let(:tracking_data) do
{
'type' => 'source',
@ -435,14 +416,26 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Common do
}
end
it 'ignores invalid algorithm types' do
finding = report.findings.first
it 'ignores invalid algorithm types and logs warning' do
expect(finding.signatures.size).to eq(2)
expect(finding.signatures.map(&:algorithm_type).to_set).to eq(Set['hash', 'location'])
end
end
context 'with valid tracking information' do
let(:tracking_data) do
{
'type' => 'source',
'items' => [
'signatures' => [
{ 'algorithm' => 'hash', 'value' => 'hash_value' },
{ 'algorithm' => 'location', 'value' => 'location_value' },
{ 'algorithm' => 'scope_offset', 'value' => 'scope_offset_value' }
]
]
}
end
it 'creates signatures for each signature algorithm' do
finding = report.findings.first
expect(finding.signatures.size).to eq(3)

View File

@ -53,8 +53,6 @@ RSpec.describe ChangePublicProjectsCostFactor, migration: :gitlab_ci do
expect(shared_2.public_projects_minutes_cost_factor).to eq(0)
expect(shared_3.public_projects_minutes_cost_factor).to eq(1)
expect(group_1.public_projects_minutes_cost_factor).to eq(0)
schema_migrate_up!
end
end
end

View File

@ -6,65 +6,102 @@ RSpec.describe ActiveHookFilter do
subject(:filter) { described_class.new(hook) }
describe '#matches?' do
context 'for push event hooks' do
let(:hook) do
create(:project_hook, push_events: true, push_events_branch_filter: branch_filter)
using RSpec::Parameterized::TableSyntax
context 'for various types of branch_filter' do
let_it_be_with_reload(:hook) do
create(:project_hook, push_events: true, issues_events: true)
end
context 'branch filter is specified' do
let(:branch_filter) { 'master' }
it 'returns true if branch matches' do
expect(filter.matches?(:push_hooks, { ref: 'refs/heads/master' })).to be true
end
it 'returns false if branch does not match' do
expect(filter.matches?(:push_hooks, { ref: 'refs/heads/my_branch' })).to be false
end
it 'returns false if ref is nil' do
expect(filter.matches?(:push_hooks, {})).to be false
end
context 'branch filter contains wildcard' do
let(:branch_filter) { 'features/*' }
it 'returns true if branch matches' do
expect(filter.matches?(:push_hooks, { ref: 'refs/heads/features/my-branch' })).to be true
expect(filter.matches?(:push_hooks, { ref: 'refs/heads/features/my-branch/something' })).to be true
end
it 'returns false if branch does not match' do
expect(filter.matches?(:push_hooks, { ref: 'refs/heads/master' })).to be false
end
end
where(:branch_filter_strategy, :branch_filter, :ref, :expected_matches?) do
'all_branches' | 'master' | 'refs/heads/master' | true
'all_branches' | '' | 'refs/heads/master' | true
'all_branches' | nil | 'refs/heads/master' | true
'all_branches' | '.*' | 'refs/heads/master' | true
'wildcard' | 'master' | 'refs/heads/master' | true
'wildcard' | 'master' | 'refs/heads/my_branch' | false
'wildcard' | 'features/*' | 'refs/heads/features/my-branch' | true
'wildcard' | 'features/*' | 'refs/heads/features/my-branch/something' | true
'wildcard' | 'features/*' | 'refs/heads/master' | false
'wildcard' | nil | 'refs/heads/master' | true
'wildcard' | '' | 'refs/heads/master' | true
'regex' | 'master' | 'refs/heads/master' | true
'regex' | 'master' | 'refs/heads/my_branch' | false
'regex' | 'features/*' | 'refs/heads/xxxx/features/my-branch' | true
'regex' | 'features/*' | 'refs/heads/features/' | true
'regex' | 'features/*' | 'refs/heads/features' | true
'regex' | 'features/.*' | 'refs/heads/features/my-branch' | true
'regex' | 'features/.*' | 'refs/heads/features/my-branch/something' | true
'regex' | 'features/.*' | 'refs/heads/master' | false
'regex' | '(feature|dev)' | 'refs/heads/feature' | true
'regex' | '(feature|dev)' | 'refs/heads/dev' | true
'regex' | '(feature|dev)' | 'refs/heads/master' | false
'regex' | nil | 'refs/heads/master' | true
'regex' | '' | 'refs/heads/master' | true
end
context 'branch filter is not specified' do
let(:branch_filter) { nil }
it 'returns true' do
expect(filter.matches?(:push_hooks, { ref: 'refs/heads/master' })).to be true
with_them do
before do
hook.assign_attributes(
push_events_branch_filter: branch_filter,
branch_filter_strategy: branch_filter_strategy
)
end
it { expect(filter.matches?(:push_hooks, { ref: ref })).to be expected_matches? }
it { expect(filter.matches?(:issues_events, { ref: ref })).to be true }
end
context 'branch filter is empty string' do
let(:branch_filter) { '' }
it 'acts like branch is not specified' do
expect(filter.matches?(:push_hooks, { ref: 'refs/heads/master' })).to be true
context 'when the branch filter is a invalid regex' do
let_it_be(:hook) do
create(
:project_hook,
push_events: true,
push_events_branch_filter: 'master',
branch_filter_strategy: 'regex'
)
end
before do
allow(hook).to receive(:push_events_branch_filter).and_return("invalid-regex[")
end
it { expect(filter.matches?(:push_hooks, { ref: 'refs/heads/master' })).to be false }
end
context 'when the branch filter is not properly set to nil' do
let_it_be(:hook) do
create(
:project_hook,
push_events: true,
branch_filter_strategy: 'all_branches'
)
end
before do
allow(hook).to receive(:push_events_branch_filter).and_return("master")
end
it { expect(filter.matches?(:push_hooks, { ref: 'refs/heads/feature1' })).to be true }
end
end
context 'for non-push-events hooks' do
let(:hook) do
create(:project_hook, issues_events: true, push_events: false, push_events_branch_filter: '')
context 'when feature flag is disabled' do
before do
stub_feature_flags(enhanced_webhook_support_regex: false)
end
it 'returns true as branch filters are not yet supported for these' do
expect(filter.matches?(:issues_events, { ref: 'refs/heads/master' })).to be true
let_it_be(:hook) do
create(
:project_hook,
push_events: true,
push_events_branch_filter: '(master)',
branch_filter_strategy: 'regex'
)
end
it { expect(filter.matches?(:push_hooks, { ref: 'refs/heads/master' })).to be false }
it { expect(filter.matches?(:push_hooks, { ref: 'refs/heads/(master)' })).to be true }
end
end
end

View File

@ -113,23 +113,80 @@ RSpec.describe WebHook do
end
describe 'push_events_branch_filter' do
it { is_expected.to allow_values("good_branch_name", "another/good-branch_name").for(:push_events_branch_filter) }
it { is_expected.to allow_values("").for(:push_events_branch_filter) }
it { is_expected.not_to allow_values("bad branch name", "bad~branchname").for(:push_events_branch_filter) }
it 'gets rid of whitespace' do
hook.push_events_branch_filter = ' branch '
hook.save!
expect(hook.push_events_branch_filter).to eq('branch')
before do
subject.branch_filter_strategy = strategy
end
it 'stores whitespace only as empty' do
hook.push_events_branch_filter = ' '
hook.save!
context 'with "all branches" strategy' do
let(:strategy) { 'all_branches' }
expect(hook.push_events_branch_filter).to eq('')
it {
is_expected.to allow_values(
"good_branch_name",
"another/good-branch_name",
"good branch name",
"good~branchname",
"good_branchname(",
"good_branchname[",
""
).for(:push_events_branch_filter)
}
end
context 'with "wildcard" strategy' do
let(:strategy) { 'wildcard' }
it {
is_expected.to allow_values(
"good_branch_name",
"another/good-branch_name",
"good_branch_name(",
""
).for(:push_events_branch_filter)
}
it {
is_expected.not_to allow_values(
"bad branch name",
"bad~branchname",
"bad_branch_name["
).for(:push_events_branch_filter)
}
it 'gets rid of whitespace' do
hook.push_events_branch_filter = ' branch '
hook.save!
expect(hook.push_events_branch_filter).to eq('branch')
end
it 'stores whitespace only as empty' do
hook.push_events_branch_filter = ' '
hook.save!
expect(hook.push_events_branch_filter).to eq('')
end
end
context 'with "regex" strategy' do
let(:strategy) { 'regex' }
it {
is_expected.to allow_values(
"good_branch_name",
"another/good-branch_name",
"good branch name",
"good~branch~name",
""
).for(:push_events_branch_filter)
}
it { is_expected.not_to allow_values("bad_branch_name(", "bad_branch_name[").for(:push_events_branch_filter) }
end
end
it "only consider these branch filter strategies are valid" do
expected_valid_types = %w[all_branches regex wildcard]
expect(described_class.branch_filter_strategies.keys).to contain_exactly(*expected_valid_types)
end
end

View File

@ -2,6 +2,15 @@
module Database
module MultipleDatabases
def run_and_cleanup(example)
# Each example may call `migrate!`, so we must ensure we are migrated down every time
schema_migrate_down!
example.run
delete_from_all_tables!(except: deletion_except_tables)
end
def skip_if_multiple_databases_not_setup
skip 'Skipping because multiple databases not set up' unless Gitlab::Database.has_config?(:ci)
end
@ -22,6 +31,21 @@ module Database
model.establish_connection(new_db_config)
end
def ensure_schema_and_empty_tables
# Ensure all schemas for both databases are migrated back
Gitlab::Database.database_base_models.each do |_, base_model|
with_reestablished_active_record_base do
reconfigure_db_connection(
model: ActiveRecord::Base,
config_model: base_model
)
schema_migrate_up!
delete_from_all_tables!(except: deletion_except_tables)
end
end
end
# The usage of this method switches temporarily used `connection_handler`
# allowing full manipulation of ActiveRecord::Base connections without
# having side effects like:
@ -109,7 +133,13 @@ RSpec.configure do |config|
end
end
config.append_after(:context, :migration) do
recreate_databases_and_seed_if_needed || ensure_schema_and_empty_tables
end
config.around(:each, :migration) do |example|
self.class.use_transactional_tests = false
migration_schema = example.metadata[:migration]
migration_schema = :gitlab_main if migration_schema == true
base_model = Gitlab::Database.schemas_to_base_models.fetch(migration_schema).first
@ -122,11 +152,13 @@ RSpec.configure do |config|
config_model: base_model
)
example.run
run_and_cleanup(example)
end
else
example.run
run_and_cleanup(example)
end
self.class.use_transactional_tests = true
end
end

View File

@ -13,19 +13,6 @@ RSpec.configure do |config|
DatabaseCleaner.clean_with(:deletion)
end
config.append_after(:context, :migration) do
delete_from_all_tables!(except: ['work_item_types'])
# Postgres maximum number of columns in a table is 1600 (https://github.com/postgres/postgres/blob/de41869b64d57160f58852eab20a27f248188135/src/include/access/htup_details.h#L23-L47).
# We drop and recreate the database if any table has more than 1200 columns, just to be safe.
if any_connection_class_with_more_than_allowed_columns?
recreate_all_databases!
# Seed required data as recreating DBs will delete it
TestEnv.seed_db
end
end
config.around(:each, :delete) do |example|
self.class.use_transactional_tests = false
@ -35,14 +22,4 @@ RSpec.configure do |config|
self.class.use_transactional_tests = true
end
config.around(:each, :migration) do |example|
self.class.use_transactional_tests = false
example.run
delete_from_all_tables!(except: ['work_item_types'])
self.class.use_transactional_tests = true
end
end

View File

@ -78,6 +78,19 @@ module DbCleaner
puts "Databases re-creation done in #{Gitlab::Metrics::System.monotonic_time - start}"
end
def recreate_databases_and_seed_if_needed
# Postgres maximum number of columns in a table is 1600 (https://github.com/postgres/postgres/blob/de41869b64d57160f58852eab20a27f248188135/src/include/access/htup_details.h#L23-L47).
# We drop and recreate the database if any table has more than 1200 columns, just to be safe.
return false unless any_connection_class_with_more_than_allowed_columns?
recreate_all_databases!
# Seed required data as recreating DBs will delete it
TestEnv.seed_db
true
end
def force_disconnect_all_connections!
cmd = <<~SQL
SELECT pg_terminate_backend(pg_stat_activity.pid)

View File

@ -87,6 +87,8 @@ module MigrationsHelpers
[ApplicationSetting, SystemHook].each do |model|
model.define_attribute_methods
end
Gitlab.ee { License.define_attribute_methods }
end
def reset_column_information(klass)

View File

@ -19,13 +19,9 @@ RSpec.configure do |config|
# Each example may call `migrate!`, so we must ensure we are migrated down every time
config.before(:each, :migration) do
use_fake_application_settings
schema_migrate_down!
end
config.after(:context, :migration) do
schema_migrate_up!
Gitlab::CurrentSettings.clear_in_memory_application_settings!
end
end

View File

@ -2,7 +2,7 @@
require 'spec_helper'
RSpec.describe BranchFilterValidator do
RSpec.describe WebHooks::WildcardBranchFilterValidator do
let(:validator) { described_class.new(attributes: [:push_events_branch_filter]) }
let(:hook) { build(:project_hook) }