Commit d47f9d23 authored by GitLab Bot's avatar GitLab Bot

Add latest changes from gitlab-org/gitlab@master

parent c158fa8d
...@@ -36,6 +36,8 @@ class GroupMembersFinder < UnionFinder ...@@ -36,6 +36,8 @@ class GroupMembersFinder < UnionFinder
relations << descendant_members relations << descendant_members
end end
return GroupMember.none if relations.empty?
members = find_union(relations, GroupMember) members = find_union(relations, GroupMember)
filter_members(members, params) filter_members(members, params)
end end
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
class Epic < ApplicationRecord class Epic < ApplicationRecord
include IgnorableColumns include IgnorableColumns
ignore_column :milestone_id, remove_after: '2019-12-15', remove_with: '12.7' ignore_column :milestone_id, remove_after: '2020-02-01', remove_with: '12.8'
def self.link_reference_pattern def self.link_reference_pattern
nil nil
......
...@@ -1325,7 +1325,7 @@ class Project < ApplicationRecord ...@@ -1325,7 +1325,7 @@ class Project < ApplicationRecord
end end
def has_active_hooks?(hooks_scope = :push_hooks) def has_active_hooks?(hooks_scope = :push_hooks)
hooks.hooks_for(hooks_scope).any? || SystemHook.hooks_for(hooks_scope).any? || Gitlab::Plugin.any? hooks.hooks_for(hooks_scope).any? || SystemHook.hooks_for(hooks_scope).any? || Gitlab::FileHook.any?
end end
def has_active_services?(hooks_scope = :push_hooks) def has_active_services?(hooks_scope = :push_hooks)
......
...@@ -14,8 +14,12 @@ class Snippet < ApplicationRecord ...@@ -14,8 +14,12 @@ class Snippet < ApplicationRecord
include Editable include Editable
include Gitlab::SQL::Pattern include Gitlab::SQL::Pattern
include FromUnion include FromUnion
include IgnorableColumns
extend ::Gitlab::Utils::Override extend ::Gitlab::Utils::Override
ignore_column :storage_version, remove_with: '12.9', remove_after: '2020-03-22'
cache_markdown_field :title, pipeline: :single_line cache_markdown_field :title, pipeline: :single_line
cache_markdown_field :description cache_markdown_field :description
cache_markdown_field :content cache_markdown_field :content
......
...@@ -14,7 +14,7 @@ class SystemHooksService ...@@ -14,7 +14,7 @@ class SystemHooksService
hook.async_execute(data, 'system_hooks') hook.async_execute(data, 'system_hooks')
end end
Gitlab::Plugin.execute_all_async(data) Gitlab::FileHook.execute_all_async(data)
end end
private private
......
...@@ -11,4 +11,4 @@ ...@@ -11,4 +11,4 @@
= render 'shared/web_hooks/index', hooks: @hooks, hook_class: @hook.class = render 'shared/web_hooks/index', hooks: @hooks, hook_class: @hook.class
= render 'shared/plugins/index' = render 'shared/file_hooks/index'
- plugins = Gitlab::Plugin.files - file_hooks = Gitlab::FileHook.files
.row.prepend-top-default .row.prepend-top-default
.col-lg-4 .col-lg-4
%h4.prepend-top-0 %h4.prepend-top-0
Plugins = _('File Hooks')
%p %p
#{link_to 'Plugins', help_page_path('administration/plugins')} are similar to = _('File hooks are similar to system hooks but are executed as files instead of sending data to a URL.')
system hooks but are executed as files instead of sending data to a URL. = link_to _('For more information, see the File Hooks documentation.'), help_page_path('administration/file_hooks')
.col-lg-8.append-bottom-default .col-lg-8.append-bottom-default
- if plugins.any? - if file_hooks.any?
.card .card
.card-header .card-header
Plugins (#{plugins.count}) = _('File Hooks (%{count})') % { count: file_hooks.count }
%ul.content-list %ul.content-list
- plugins.each do |file| - file_hooks.each do |file|
%li %li
.monospace .monospace
= File.basename(file) = File.basename(file)
- else - else
.card.bg-light.text-center .card.bg-light.text-center
.nothing-here-block No plugins found. .nothing-here-block= _('No file hooks found.')
...@@ -158,7 +158,7 @@ ...@@ -158,7 +158,7 @@
- pages - pages
- pages_domain_verification - pages_domain_verification
- pages_domain_ssl_renewal - pages_domain_ssl_renewal
- plugin - file_hook
- post_receive - post_receive
- process_commit - process_commit
- project_cache - project_cache
......
# frozen_string_literal: true # frozen_string_literal: true
class PluginWorker class FileHookWorker
include ApplicationWorker include ApplicationWorker
sidekiq_options retry: false sidekiq_options retry: false
feature_category :integrations feature_category :integrations
def perform(file_name, data) def perform(file_name, data)
success, message = Gitlab::Plugin.execute(file_name, data) success, message = Gitlab::FileHook.execute(file_name, data)
unless success unless success
Gitlab::PluginLogger.error("Plugin Error => #{file_name}: #{message}") Gitlab::FileHookLogger.error("File Hook Error => #{file_name}: #{message}")
end end
true true
......
---
title: 'Resolve Design View: Left/Right keyboard arrows through Designs'
merge_request: 22870
author:
type: added
---
title: Add returning relation from GroupMembersFinder if called on root group with
only inherited param
merge_request: 23161
author:
type: fixed
---
title: Allow Unicode 11 emojis in project names
merge_request: 22776
author: Harm Berntsen
type: changed
---
title: Added Conan installation instructions to Conan package details page
merge_request: 22390
author:
type: added
---
title: Rename GitLab Plugins feature to GitLab File Hooks
merge_request: 22979
author:
type: changed
---
title: Remove storage_version column from snippets
merge_request: 23004
author:
type: changed
---
title: Remove milestone_id from epics
merge_request: 20539
author: Lee Tickett
type: other
...@@ -76,7 +76,7 @@ ...@@ -76,7 +76,7 @@
- [pages_domain_ssl_renewal, 1] - [pages_domain_ssl_renewal, 1]
- [object_storage_upload, 1] - [object_storage_upload, 1]
- [object_storage, 1] - [object_storage, 1]
- [plugin, 1] - [file_hook, 1]
- [pipeline_background, 1] - [pipeline_background, 1]
- [repository_update_remote_mirror, 1] - [repository_update_remote_mirror, 1]
- [repository_remove_remote, 1] - [repository_remove_remote, 1]
......
# frozen_string_literal: true
class RemoveMilestoneIdFromEpics < ActiveRecord::Migration[5.2]
DOWNTIME = false
def up
remove_column :epics, :milestone_id
end
def down
add_column :epics, :milestone_id, :integer
end
end
# frozen_string_literal: true
class RemoveStorageVersionColumnFromSnippets < ActiveRecord::Migration[5.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
return unless column_exists?(:snippets, :storage_version)
remove_column :snippets, :storage_version
end
def down
add_column_with_default( # rubocop:disable Migration/AddColumnWithDefault
:snippets,
:storage_version,
:integer,
default: 2,
allow_null: false
)
end
end
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 2020_01_14_180546) do ActiveRecord::Schema.define(version: 2020_01_14_113341) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "pg_trgm" enable_extension "pg_trgm"
...@@ -1538,7 +1538,6 @@ ActiveRecord::Schema.define(version: 2020_01_14_180546) do ...@@ -1538,7 +1538,6 @@ ActiveRecord::Schema.define(version: 2020_01_14_180546) do
end end
create_table "epics", id: :serial, force: :cascade do |t| create_table "epics", id: :serial, force: :cascade do |t|
t.integer "milestone_id"
t.integer "group_id", null: false t.integer "group_id", null: false
t.integer "author_id", null: false t.integer "author_id", null: false
t.integer "assignee_id" t.integer "assignee_id"
...@@ -1577,7 +1576,6 @@ ActiveRecord::Schema.define(version: 2020_01_14_180546) do ...@@ -1577,7 +1576,6 @@ ActiveRecord::Schema.define(version: 2020_01_14_180546) do
t.index ["end_date"], name: "index_epics_on_end_date" t.index ["end_date"], name: "index_epics_on_end_date"
t.index ["group_id"], name: "index_epics_on_group_id" t.index ["group_id"], name: "index_epics_on_group_id"
t.index ["iid"], name: "index_epics_on_iid" t.index ["iid"], name: "index_epics_on_iid"
t.index ["milestone_id"], name: "index_milestone"
t.index ["parent_id"], name: "index_epics_on_parent_id" t.index ["parent_id"], name: "index_epics_on_parent_id"
t.index ["start_date"], name: "index_epics_on_start_date" t.index ["start_date"], name: "index_epics_on_start_date"
t.index ["start_date_sourcing_epic_id"], name: "index_epics_on_start_date_sourcing_epic_id", where: "(start_date_sourcing_epic_id IS NOT NULL)" t.index ["start_date_sourcing_epic_id"], name: "index_epics_on_start_date_sourcing_epic_id", where: "(start_date_sourcing_epic_id IS NOT NULL)"
...@@ -3838,6 +3836,7 @@ ActiveRecord::Schema.define(version: 2020_01_14_180546) do ...@@ -3838,6 +3836,7 @@ ActiveRecord::Schema.define(version: 2020_01_14_180546) do
t.string "encrypted_secret_token_iv", limit: 255 t.string "encrypted_secret_token_iv", limit: 255
t.boolean "secret", default: false, null: false t.boolean "secret", default: false, null: false
t.string "repository_storage", limit: 255, default: "default", null: false t.string "repository_storage", limit: 255, default: "default", null: false
t.integer "storage_version", default: 2, null: false
t.index ["author_id"], name: "index_snippets_on_author_id" t.index ["author_id"], name: "index_snippets_on_author_id"
t.index ["content"], name: "index_snippets_on_content_trigram", opclass: :gin_trgm_ops, using: :gin t.index ["content"], name: "index_snippets_on_content_trigram", opclass: :gin_trgm_ops, using: :gin
t.index ["created_at"], name: "index_snippets_on_created_at" t.index ["created_at"], name: "index_snippets_on_created_at"
...@@ -4590,7 +4589,6 @@ ActiveRecord::Schema.define(version: 2020_01_14_180546) do ...@@ -4590,7 +4589,6 @@ ActiveRecord::Schema.define(version: 2020_01_14_180546) do
add_foreign_key "epics", "epics", column: "start_date_sourcing_epic_id", name: "fk_9d480c64b2", on_delete: :nullify add_foreign_key "epics", "epics", column: "start_date_sourcing_epic_id", name: "fk_9d480c64b2", on_delete: :nullify
add_foreign_key "epics", "milestones", column: "due_date_sourcing_milestone_id", name: "fk_3c1fd1cccc", on_delete: :nullify add_foreign_key "epics", "milestones", column: "due_date_sourcing_milestone_id", name: "fk_3c1fd1cccc", on_delete: :nullify
add_foreign_key "epics", "milestones", column: "start_date_sourcing_milestone_id", name: "fk_1fbed67632", on_delete: :nullify add_foreign_key "epics", "milestones", column: "start_date_sourcing_milestone_id", name: "fk_1fbed67632", on_delete: :nullify
add_foreign_key "epics", "milestones", on_delete: :nullify
add_foreign_key "epics", "namespaces", column: "group_id", name: "fk_f081aa4489", on_delete: :cascade add_foreign_key "epics", "namespaces", column: "group_id", name: "fk_f081aa4489", on_delete: :cascade
add_foreign_key "epics", "users", column: "assignee_id", name: "fk_dccd3f98fc", on_delete: :nullify add_foreign_key "epics", "users", column: "assignee_id", name: "fk_dccd3f98fc", on_delete: :nullify
add_foreign_key "epics", "users", column: "author_id", name: "fk_3654b61b03", on_delete: :cascade add_foreign_key "epics", "users", column: "author_id", name: "fk_3654b61b03", on_delete: :cascade
......
...@@ -107,7 +107,7 @@ recorded: ...@@ -107,7 +107,7 @@ recorded:
- Started/stopped user impersonation - Started/stopped user impersonation
It is possible to filter particular actions by choosing an audit data type from It is possible to filter particular actions by choosing an audit data type from
the filter drop-down. You can further filter by specific group, project or user the filter dropdown box. You can further filter by specific group, project or user
(for authentication events). (for authentication events).
![audit log](img/audit_log.png) ![audit log](img/audit_log.png)
......
# File hooks
> Introduced in GitLab 10.6.
> Until 12.8 the feature name was Plugins.
With custom file hooks, GitLab administrators can introduce custom integrations
without modifying GitLab's source code.
NOTE: **Note:**
Instead of writing and supporting your own file hook you can make changes
directly to the GitLab source code and contribute back upstream. This way we can
ensure functionality is preserved across versions and covered by tests.
NOTE: **Note:**
File hooks must be configured on the filesystem of the GitLab server. Only GitLab
server administrators will be able to complete these tasks. Explore
[system hooks] or [webhooks] as an option if you do not have filesystem access.
A file hook will run on each event so it's up to you to filter events or projects
within a file hook code. You can have as many file hooks as you want. Each file hook will
be triggered by GitLab asynchronously in case of an event. For a list of events
see the [system hooks] documentation.
## Setup
The file hooks must be placed directly into the `plugins` directory, subdirectories
will be ignored. There is an
[`example` directory inside `plugins`](https://gitlab.com/gitlab-org/gitlab/tree/master/plugins/examples)
where you can find some basic examples.
Follow the steps below to set up a custom hook:
1. On the GitLab server, navigate to the plugin directory.
For an installation from source the path is usually
`/home/git/gitlab/plugins/`. For Omnibus installs the path is
usually `/opt/gitlab/embedded/service/gitlab-rails/plugins`.
For [highly available] configurations, your hook file should exist on each
application server.
1. Inside the `plugins` directory, create a file with a name of your choice,
without spaces or special characters.
1. Make the hook file executable and make sure it's owned by the Git user.
1. Write the code to make the file hook function as expected. That can be
in any language, and ensure the 'shebang' at the top properly reflects the
language type. For example, if the script is in Ruby the shebang will
probably be `#!/usr/bin/env ruby`.
1. The data to the file hook will be provided as JSON on STDIN. It will be exactly
same as for [system hooks]
That's it! Assuming the file hook code is properly implemented, the hook will fire
as appropriate. The file hooks file list is updated for each event, there is no
need to restart GitLab to apply a new file hook.
If a file hook executes with non-zero exit code or GitLab fails to execute it, a
message will be logged to:
- `gitlab-rails/plugin.log` in an Omnibus installation.
- `log/plugin.log` in a source installation.
## Creating file hooks
Below is an example that will only response on the event `project_create` and
will inform the admins from the GitLab instance that a new project has been created.
```ruby
# By using the embedded ruby version we eliminate the possibility that our chosen language
# would be unavailable from
#!/opt/gitlab/embedded/bin/ruby
require 'json'
require 'mail'
# The incoming variables are in JSON format so we need to parse it first.
ARGS = JSON.parse(STDIN.read)
# We only want to trigger this file hook on the event project_create
return unless ARGS['event_name'] == 'project_create'
# We will inform our admins of our gitlab instance that a new project is created
Mail.deliver do
from 'info@gitlab_instance.com'
to 'admin@gitlab_instance.com'
subject "new project " + ARGS['name']
body ARGS['owner_name'] + 'created project ' + ARGS['name']
end
```
## Validation
Writing your own file hook can be tricky and it's easier if you can check it
without altering the system. A rake task is provided so that you can use it
in a staging environment to test your file hook before using it in production.
The rake task will use a sample data and execute each of file hook. The output
should be enough to determine if the system sees your file hook and if it was
executed without errors.
```bash
# Omnibus installations
sudo gitlab-rake file_hooks:validate
# Installations from source
cd /home/git/gitlab
bundle exec rake file_hooks:validate RAILS_ENV=production
```
Example of output:
```
Validating file hooks from /plugins directory
* /home/git/gitlab/plugins/save_to_file.clj succeed (zero exit code)
* /home/git/gitlab/plugins/save_to_file.rb failure (non-zero exit code)
```
[system hooks]: ../system_hooks/system_hooks.md
[webhooks]: ../user/project/integrations/webhooks.md
[highly available]: ./high_availability/README.md
...@@ -245,7 +245,7 @@ To add a Prometheus dashboard for a single server GitLab setup: ...@@ -245,7 +245,7 @@ To add a Prometheus dashboard for a single server GitLab setup:
1. Create a new data source in Grafana. 1. Create a new data source in Grafana.
1. Name your data source i.e GitLab. 1. Name your data source i.e GitLab.
1. Select `Prometheus` in the type drop down. 1. Select `Prometheus` in the type dropdown box.
1. Add your Prometheus listen address as the URL and set access to `Browser`. 1. Add your Prometheus listen address as the URL and set access to `Browser`.
1. Set the HTTP method to `GET`. 1. Set the HTTP method to `GET`.
1. Save & Test your configuration to verify that it works. 1. Save & Test your configuration to verify that it works.
......
# GitLab Plugin system ---
redirect_to: 'file_hooks.md'
---
> Introduced in GitLab 10.6. This document was moved to [File Hooks](file_hooks.md), after the Plugins feature was renamed to File Hooks.
With custom plugins, GitLab administrators can introduce custom integrations
without modifying GitLab's source code.
NOTE: **Note:**
Instead of writing and supporting your own plugin you can make changes
directly to the GitLab source code and contribute back upstream. This way we can
ensure functionality is preserved across versions and covered by tests.
NOTE: **Note:**
Plugins must be configured on the filesystem of the GitLab server. Only GitLab
server administrators will be able to complete these tasks. Explore
[system hooks] or [webhooks] as an option if you do not have filesystem access.
A plugin will run on each event so it's up to you to filter events or projects
within a plugin code. You can have as many plugins as you want. Each plugin will
be triggered by GitLab asynchronously in case of an event. For a list of events
see the [system hooks] documentation.
## Setup
The plugins must be placed directly into the `plugins` directory, subdirectories
will be ignored. There is an
[`example` directory inside `plugins`](https://gitlab.com/gitlab-org/gitlab/tree/master/plugins/examples)
where you can find some basic examples.
Follow the steps below to set up a custom hook:
1. On the GitLab server, navigate to the plugin directory.
For an installation from source the path is usually
`/home/git/gitlab/plugins/`. For Omnibus installs the path is
usually `/opt/gitlab/embedded/service/gitlab-rails/plugins`.
For [highly available] configurations, your hook file should exist on each
application server.
1. Inside the `plugins` directory, create a file with a name of your choice,
without spaces or special characters.
1. Make the hook file executable and make sure it's owned by the Git user.
1. Write the code to make the plugin function as expected. That can be
in any language, and ensure the 'shebang' at the top properly reflects the
language type. For example, if the script is in Ruby the shebang will
probably be `#!/usr/bin/env ruby`.
1. The data to the plugin will be provided as JSON on STDIN. It will be exactly
same as for [system hooks]
That's it! Assuming the plugin code is properly implemented, the hook will fire
as appropriate. The plugins file list is updated for each event, there is no
need to restart GitLab to apply a new plugin.
If a plugin executes with non-zero exit code or GitLab fails to execute it, a
message will be logged to:
- `gitlab-rails/plugin.log` in an Omnibus installation.
- `log/plugin.log` in a source installation.
## Creating plugins
Below is an example that will only response on the event `project_create` and
will inform the admins from the GitLab instance that a new project has been created.
```ruby
# By using the embedded ruby version we eliminate the possibility that our chosen language
# would be unavailable from
#!/opt/gitlab/embedded/bin/ruby
require 'json'
require 'mail'
# The incoming variables are in JSON format so we need to parse it first.
ARGS = JSON.parse(STDIN.read)
# We only want to trigger this plugin on the event project_create
return unless ARGS['event_name'] == 'project_create'
# We will inform our admins of our gitlab instance that a new project is created
Mail.deliver do
from 'info@gitlab_instance.com'
to 'admin@gitlab_instance.com'
subject "new project " + ARGS['name']
body ARGS['owner_name'] + 'created project ' + ARGS['name']
end
```
## Validation
Writing your own plugin can be tricky and it's easier if you can check it
without altering the system. A rake task is provided so that you can use it
in a staging environment to test your plugin before using it in production.
The rake task will use a sample data and execute each of plugin. The output
should be enough to determine if the system sees your plugin and if it was
executed without errors.
```bash
# Omnibus installations
sudo gitlab-rake plugins:validate
# Installations from source
cd /home/git/gitlab
bundle exec rake plugins:validate RAILS_ENV=production
```
Example of output:
```
Validating plugins from /plugins directory
* /home/git/gitlab/plugins/save_to_file.clj succeed (zero exit code)
* /home/git/gitlab/plugins/save_to_file.rb failure (non-zero exit code)
```
[system hooks]: ../system_hooks/system_hooks.md
[webhooks]: ../user/project/integrations/webhooks.md
[highly available]: ./high_availability/README.md
...@@ -44,7 +44,7 @@ To enable or disable GitLab CI/CD Pipelines in your project: ...@@ -44,7 +44,7 @@ To enable or disable GitLab CI/CD Pipelines in your project:
- **Private**: Only project members can access pipelines. - **Private**: Only project members can access pipelines.
- **Internal** or **Public**: Pipelines can be set to either **Only Project Members** - **Internal** or **Public**: Pipelines can be set to either **Only Project Members**
or **Everyone With Access** via the drop-down box. or **Everyone With Access** via the dropdown box.
Press **Save changes** for the settings to take effect. Press **Save changes** for the settings to take effect.
......
...@@ -244,7 +244,7 @@ Once the database is created, connect to your new RDS instance to verify access ...@@ -244,7 +244,7 @@ Once the database is created, connect to your new RDS instance to verify access
and to install a required extension. and to install a required extension.
You can find the host or endpoint by selecting the instance you just created and You can find the host or endpoint by selecting the instance you just created and
after the details drop down you'll find it labeled as 'Endpoint'. Do not to after the details dropdown menu you'll find it labeled as 'Endpoint'. Do not to
include the colon and port number: include the colon and port number:
```sh ```sh
......
...@@ -226,7 +226,7 @@ connections: ...@@ -226,7 +226,7 @@ connections:
![Azure - Add inbound security rules - HTTP](img/azure-add-inbound-sec-rule-http.png) ![Azure - Add inbound security rules - HTTP](img/azure-add-inbound-sec-rule-http.png)
1. Enter **"HTTP"** in the `Name` field 1. Enter **"HTTP"** in the `Name` field
1. Select **HTTP** from the options in the `Service` drop-down 1. Select **HTTP** from the options in the `Service` dropdown list
1. Make sure the `Action` is set to **Allow** 1. Make sure the `Action` is set to **Allow**
1. Click **"OK"** 1. Click **"OK"**
...@@ -238,7 +238,7 @@ accept [SSH] connections: ...@@ -238,7 +238,7 @@ accept [SSH] connections:
![Azure - Add inbound security rules - SSH](img/azure-add-inbound-sec-rule-ssh.png) ![Azure - Add inbound security rules - SSH](img/azure-add-inbound-sec-rule-ssh.png)
1. Enter **"SSH"** in the `Name` field 1. Enter **"SSH"** in the `Name` field
1. Select **SSH** from the options in the `Service` drop-down 1. Select **SSH** from the options in the `Service` dropdown list
1. Make sure the `Action` is set to **Allow** 1. Make sure the `Action` is set to **Allow**
1. Click **"OK"** 1. Click **"OK"**
......
...@@ -269,6 +269,15 @@ it highlighted: ...@@ -269,6 +269,15 @@ it highlighted:
} }
], ],
"remediations": [ "remediations": [
{
"fixes": [
{
"cve": "debian:9:apt:CVE-2019-3462"
}
],
"summary": "Upgrade apt from 1.4.8 to 1.4.9",
"diff": "YXB0LWdldCB1cGRhdGUgJiYgYXB0LWdldCB1cGdyYWRlIC15IGFwdA=="
}
] ]
} }
``` ```
...@@ -305,7 +314,11 @@ the report JSON unless stated otherwise. Presence of optional fields depends on ...@@ -305,7 +314,11 @@ the report JSON unless stated otherwise. Presence of optional fields depends on
| `vulnerabilities[].links` | An array of references to external documentation pieces or articles that describe the vulnerability further. Optional. | | `vulnerabilities[].links` | An array of references to external documentation pieces or articles that describe the vulnerability further. Optional. |
| `vulnerabilities[].links[].name` | Name of the vulnerability details link. Optional. | | `vulnerabilities[].links[].name` | Name of the vulnerability details link. Optional. |
| `vulnerabilities[].links[].url` | URL of the vulnerability details document. Optional. | | `vulnerabilities[].links[].url` | URL of the vulnerability details document. Optional. |
| `remediations` | Not supported yet. | | `remediations` | An array of objects containing information on cured vulnerabilities along with patch diffs to apply. Empty if no remediations provided by an underlying analyzer. |
| `remediations[].fixes` | An array of strings that represent references to vulnerabilities fixed by this particular remediation. |
| `remediations[].fixes[].cve` | A string value that describes a fixed vulnerability occurrence in the same format as `vulnerabilities[].cve`. |
| `remediations[].summary` | Overview of how the vulnerabilities have been fixed. |
| `remediations[].diff` | base64-encoded remediation code diff, compatible with [`git apply`](https://git-scm.com/docs/git-format-patch#_discussion). |
## Troubleshooting ## Troubleshooting
......
...@@ -71,6 +71,8 @@ Designs cannot be added if the issue has been moved, or its ...@@ -71,6 +71,8 @@ Designs cannot be added if the issue has been moved, or its
## Viewing designs ## Viewing designs
Images on the Design Management page can be enlarged by clicking on them. Images on the Design Management page can be enlarged by clicking on them.
You can navigate through designs by clicking on the navigation buttons on the
top-right corner or with <kbd>Left</kbd>/<kbd>Right</kbd> keyboard buttons.
The number of comments on a design — if any — is listed to the right The number of comments on a design — if any — is listed to the right
of the design filename. Clicking on this number enlarges the design of the design filename. Clicking on this number enlarges the design
......
...@@ -9,8 +9,7 @@ module Gitlab ...@@ -9,8 +9,7 @@ module Gitlab
include SelfMonitoring::Helpers include SelfMonitoring::Helpers
steps :validate_self_monitoring_project_exists, steps :validate_self_monitoring_project_exists,
:destroy_project_owner, :destroy_project
:delete_project_id
def initialize def initialize
super(nil) super(nil)
...@@ -30,29 +29,16 @@ module Gitlab ...@@ -30,29 +29,16 @@ module Gitlab
success(result) success(result)
end end
def destroy_project_owner(result) def destroy_project(result)
return success(result) unless project_created? return success(result) unless project_created?
if self_monitoring_project.owner.destroy if self_monitoring_project.destroy
success(result) success(result)
else else
log_error(self_monitoring_project.errors.full_messages) log_error(self_monitoring_project.errors.full_messages)
error(_('Error deleting project. Check logs for error details.')) error(_('Error deleting project. Check logs for error details.'))
end end
end end
def delete_project_id(result)
update_result = application_settings.update(
instance_administration_project_id: nil
)
if update_result
success(result)
else
log_error("Could not delete self monitoring project ID, errors: %{errors}" % { errors: application_settings.errors.full_messages })
error(_('Could not delete project ID'))
end
end
end end
end end
end end
......
# frozen_string_literal: true # frozen_string_literal: true
module Gitlab module Gitlab
module Plugin module FileHook
def self.any? def self.any?
plugin_glob.any? { |entry| File.file?(entry) } plugin_glob.any? { |entry| File.file?(entry) }
end end
...@@ -17,7 +17,7 @@ module Gitlab ...@@ -17,7 +17,7 @@ module Gitlab
def self.execute_all_async(data) def self.execute_all_async(data)
args = files.map { |file| [file, data] } args = files.map { |file| [file, data] }
PluginWorker.bulk_perform_async(args) FileHookWorker.bulk_perform_async(args)
end end
def self.execute(file, data) def self.execute(file, data)
......
# frozen_string_literal: true # frozen_string_literal: true
module Gitlab module Gitlab
class PluginLogger < Gitlab::Logger class FileHookLogger < Gitlab::Logger
def self.file_name_noext def self.file_name_noext
'plugin' 'plugin'
end end
......
...@@ -5,7 +5,7 @@ module Gitlab ...@@ -5,7 +5,7 @@ module Gitlab
extend self extend self
def project_name_regex def project_name_regex
@project_name_regex ||= /\A[\p{Alnum}\u{00A9}-\u{1f9c0}_][\p{Alnum}\p{Pd}\u{00A9}-\u{1f9c0}_\. ]*\z/.freeze @project_name_regex ||= /\A[\p{Alnum}\u{00A9}-\u{1f9ff}_][\p{Alnum}\p{Pd}\u{00A9}-\u{1f9ff}_\. ]*\z/.freeze
end end
def project_name_regex_message def project_name_regex_message
......
namespace :plugins do namespace :file_hooks do
desc 'Validate existing plugins' desc 'Validate existing plugins'
task validate: :environment do task validate: :environment do
puts 'Validating plugins from /plugins directory' puts 'Validating file hooks from /plugins directory'
Gitlab::Plugin.files.each do |file| Gitlab::FileHook.files.each do |file|
success, message = Gitlab::Plugin.execute(file, Gitlab::DataBuilder::Push::SAMPLE_DATA) success, message = Gitlab::FileHook.execute(file, Gitlab::DataBuilder::Push::SAMPLE_DATA)
if success if success
puts "* #{file} succeed (zero exit code)." puts "* #{file} succeed (zero exit code)."
......
...@@ -5187,9 +5187,6 @@ msgstr "" ...@@ -5187,9 +5187,6 @@ msgstr ""
msgid "Could not delete chat nickname %{chat_name}." msgid "Could not delete chat nickname %{chat_name}."
msgstr "" msgstr ""
msgid "Could not delete project ID"
msgstr ""
msgid "Could not fetch projects" msgid "Could not fetch projects"
msgstr "" msgstr ""
...@@ -7992,6 +7989,12 @@ msgstr "" ...@@ -7992,6 +7989,12 @@ msgstr ""
msgid "Fetching licenses failed. You are not permitted to perform this action." msgid "Fetching licenses failed. You are not permitted to perform this action."
msgstr "" msgstr ""
msgid "File Hooks"
msgstr ""
msgid "File Hooks (%{count})"
msgstr ""
msgid "File added" msgid "File added"
msgstr "" msgstr ""
...@@ -8001,6 +8004,9 @@ msgstr "" ...@@ -8001,6 +8004,9 @@ msgstr ""
msgid "File deleted" msgid "File deleted"
msgstr "" msgstr ""
msgid "File hooks are similar to system hooks but are executed as files instead of sending data to a URL."
msgstr ""
msgid "File mode changed from %{a_mode} to %{b_mode}" msgid "File mode changed from %{a_mode} to %{b_mode}"
msgstr "" msgstr ""
...@@ -8166,6 +8172,9 @@ msgstr "" ...@@ -8166,6 +8172,9 @@ msgstr ""
msgid "For more information, please review %{link_start_tag}Jaeger's configuration doc%{link_end_tag}" msgid "For more information, please review %{link_start_tag}Jaeger's configuration doc%{link_end_tag}"
msgstr "" msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
msgid "For more information, see the documentation on %{deactivating_usage_ping_link_start}deactivating the usage ping%{deactivating_usage_ping_link_end}." msgid "For more information, see the documentation on %{deactivating_usage_ping_link_start}deactivating the usage ping%{deactivating_usage_ping_link_end}."
msgstr "" msgstr ""
...@@ -12203,6 +12212,9 @@ msgstr "" ...@@ -12203,6 +12212,9 @@ msgstr ""
msgid "No file chosen" msgid "No file chosen"
msgstr "" msgstr ""
msgid "No file hooks found."
msgstr ""
msgid "No file selected" msgid "No file selected"
msgstr "" msgstr ""
...@@ -12775,6 +12787,18 @@ msgstr "" ...@@ -12775,6 +12787,18 @@ msgstr ""
msgid "Package was removed" msgid "Package was removed"
msgstr "" msgstr ""
msgid "PackageRegistry|Add Conan Remote"
msgstr ""
msgid "PackageRegistry|Conan Command"
msgstr ""
msgid "PackageRegistry|Copy Conan Command"
msgstr ""
msgid "PackageRegistry|Copy Conan Setup Command"
msgstr ""
msgid "PackageRegistry|Copy Maven XML" msgid "PackageRegistry|Copy Maven XML"
msgstr "" msgstr ""
...@@ -12805,6 +12829,9 @@ msgstr "" ...@@ -12805,6 +12829,9 @@ msgstr ""
msgid "PackageRegistry|Delete package" msgid "PackageRegistry|Delete package"
msgstr "" msgstr ""
msgid "PackageRegistry|For more information on the Conan registry, %{linkStart}see the documentation%{linkEnd}."
msgstr ""
msgid "PackageRegistry|For more information on the Maven registry, %{linkStart}see the documentation%{linkEnd}." msgid "PackageRegistry|For more information on the Maven registry, %{linkStart}see the documentation%{linkEnd}."
msgstr "" msgstr ""
...@@ -18642,6 +18669,9 @@ msgstr "" ...@@ -18642,6 +18669,9 @@ msgstr ""
msgid "There was an error while fetching cycle analytics duration data." msgid "There was an error while fetching cycle analytics duration data."
msgstr "" msgstr ""
msgid "There was an error while fetching cycle analytics duration median data."
msgstr ""
msgid "There was an error while fetching cycle analytics summary data." msgid "There was an error while fetching cycle analytics summary data."
msgstr "" msgstr ""
......
...@@ -28,11 +28,11 @@ describe 'Admin::Hooks' do ...@@ -28,11 +28,11 @@ describe 'Admin::Hooks' do
end end
it 'renders plugins list as well' do it 'renders plugins list as well' do
allow(Gitlab::Plugin).to receive(:files).and_return(['foo.rb', 'bar.clj']) allow(Gitlab::FileHook).to receive(:files).and_return(['foo.rb', 'bar.clj'])
visit admin_hooks_path visit admin_hooks_path
expect(page).to have_content('Plugins') expect(page).to have_content('File Hooks')
expect(page).to have_content('foo.rb') expect(page).to have_content('foo.rb')
expect(page).to have_content('bar.clj') expect(page).to have_content('bar.clj')
end end
......
...@@ -59,8 +59,8 @@ describe 'Projects > Settings > User renames a project' do ...@@ -59,8 +59,8 @@ describe 'Projects > Settings > User renames a project' do
context 'with emojis' do context 'with emojis' do
it 'shows error for invalid project name' do it 'shows error for invalid project name' do
change_name(project, '🚀 foo bar ☁️') change_name(project, '🧮 foo bar ☁️')
expect(page).to have_field 'Project name', with: '🚀 foo bar ☁️' expect(page).to have_field 'Project name', with: '🧮 foo bar ☁️'
expect(page).not_to have_content "Name can contain only letters, digits, emojis '_', '.', dash and space. It must start with letter, digit, emoji or '_'." expect(page).not_to have_content "Name can contain only letters, digits, emojis '_', '.', dash and space. It must start with letter, digit, emoji or '_'."
end end
end end
......
...@@ -57,6 +57,14 @@ describe GroupMembersFinder, '#execute' do ...@@ -57,6 +57,14 @@ describe GroupMembersFinder, '#execute' do
expect(result.to_a).to match_array([member1]) expect(result.to_a).to match_array([member1])
end end
it 'does not return nil if `inherited only` relation is requested on root group' do
group.add_developer(user2)
result = described_class.new(group).execute(include_relations: [:inherited])
expect(result).not_to be_nil
end
it 'returns members for descendant groups if requested' do it 'returns members for descendant groups if requested' do
member1 = group.add_maintainer(user2) member1 = group.add_maintainer(user2)
member2 = group.add_maintainer(user1) member2 = group.add_maintainer(user1)
...@@ -71,25 +79,41 @@ describe GroupMembersFinder, '#execute' do ...@@ -71,25 +79,41 @@ describe GroupMembersFinder, '#execute' do
it 'returns searched members if requested' do it 'returns searched members if requested' do
group.add_maintainer(user2) group.add_maintainer(user2)
nested_group.add_maintainer(user2) group.add_developer(user3)
nested_group.add_maintainer(user3)
nested_group.add_maintainer(user4)
member = group.add_maintainer(user1) member = group.add_maintainer(user1)
result = described_class.new(group).execute(include_relations: [:direct, :descendants], params: { search: user1.name }) result = described_class.new(group).execute(params: { search: user1.name })
expect(result.to_a).to match_array([member]) expect(result.to_a).to match_array([member])
end end
it 'returns nothing if search only in inherited relation' do
group.add_maintainer(user2)
group.add_developer(user3)
group.add_maintainer(user1)
result = described_class.new(group).execute(include_relations: [:inherited], params: { search: user1.name })
expect(result.to_a).to match_array([])
end
it 'returns searched member only from nested_group if search only in inherited relation' do
group.add_maintainer(user2)
group.add_developer(user3)
nested_group.add_maintainer(create(:user, name: user1.name))
member = group.add_maintainer(user1)
result = described_class.new(nested_group).execute(include_relations: [:inherited], params: { search: member.user.name })
expect(result.to_a).to contain_exactly(member)
end
it 'returns members with two-factor auth if requested by owner' do it 'returns members with two-factor auth if requested by owner' do
group.add_owner(user2) group.add_owner(user2)
group.add_maintainer(user1) group.add_maintainer(user1)
nested_group.add_maintainer(user2)
nested_group.add_maintainer(user3)
nested_group.add_maintainer(user4)
member = group.add_maintainer(user5) member = group.add_maintainer(user5)
result = described_class.new(group, user2).execute(include_relations: [:direct, :descendants], params: { two_factor: 'enabled' }) result = described_class.new(group, user2).execute(params: { two_factor: 'enabled' })
expect(result.to_a).to contain_exactly(member) expect(result.to_a).to contain_exactly(member)
end end
...@@ -97,14 +121,11 @@ describe GroupMembersFinder, '#execute' do ...@@ -97,14 +121,11 @@ describe GroupMembersFinder, '#execute' do
it 'returns members without two-factor auth if requested by owner' do it 'returns members without two-factor auth if requested by owner' do
member1 = group.add_owner(user2) member1 = group.add_owner(user2)
member2 = group.add_maintainer(user1) member2 = group.add_maintainer(user1)
nested_group.add_maintainer(user2)
member3 = nested_group.add_maintainer(user3)
member4 = nested_group.add_maintainer(user4)
member_with_2fa = group.add_maintainer(user5) member_with_2fa = group.add_maintainer(user5)
result = described_class.new(group, user2).execute(include_relations: [:direct, :descendants], params: { two_factor: 'disabled' }) result = described_class.new(group, user2).execute(params: { two_factor: 'disabled' })
expect(result.to_a).not_to include(member_with_2fa) expect(result.to_a).not_to include(member_with_2fa)
expect(result.to_a).to match_array([member1, member2, member3, member4]) expect(result.to_a).to match_array([member1, member2])
end end
end end
...@@ -4,12 +4,8 @@ require 'spec_helper' ...@@ -4,12 +4,8 @@ require 'spec_helper'
describe Gitlab::DatabaseImporters::SelfMonitoring::Project::DeleteService do describe Gitlab::DatabaseImporters::SelfMonitoring::Project::DeleteService do
describe '#execute' do describe '#execute' do
let!(:application_setting) { create(:application_setting) }
let(:result) { subject.execute } let(:result) { subject.execute }
let(:application_setting) { Gitlab::CurrentSettings.current_application_settings }
before do
allow(ApplicationSetting).to receive(:current_without_cache) { application_setting }
end
context 'when project does not exist' do context 'when project does not exist' do
it 'returns error' do it 'returns error' do
...@@ -21,24 +17,16 @@ describe Gitlab::DatabaseImporters::SelfMonitoring::Project::DeleteService do ...@@ -21,24 +17,16 @@ describe Gitlab::DatabaseImporters::SelfMonitoring::Project::DeleteService do
end end
end end
context 'with project destroyed but ID still present in application settings' do
before do
application_setting.instance_administration_project_id = 1
end
it 'deletes project ID from application settings' do
subject.execute
expect(application_setting.instance_administration_project_id).to be_nil
end
end
context 'when self monitoring project exists' do context 'when self monitoring project exists' do
let(:group) { create(:group) } let(:group) { create(:group) }
let(:project) { create(:project, namespace: group) } let(:project) { create(:project, namespace: group) }
before do let(:application_setting) do
application_setting.instance_administration_project = project create(
:application_setting,
instance_administration_project_id: project.id,
instance_administrators_group_id: group.id
)
end end
it 'destroys project' do it 'destroys project' do
...@@ -50,7 +38,13 @@ describe Gitlab::DatabaseImporters::SelfMonitoring::Project::DeleteService do ...@@ -50,7 +38,13 @@ describe Gitlab::DatabaseImporters::SelfMonitoring::Project::DeleteService do
it 'deletes project ID from application settings' do it 'deletes project ID from application settings' do
subject.execute subject.execute
expect(application_setting.instance_administration_project_id).to be_nil expect(application_setting.reload.instance_administration_project_id).to be_nil
end
it 'does not delete group' do
subject.execute
expect(application_setting.instance_administrators_group).to eq(group)
end end
end end
end end
......
...@@ -2,11 +2,11 @@ ...@@ -2,11 +2,11 @@
require 'spec_helper' require 'spec_helper'
describe Gitlab::Plugin do describe Gitlab::FileHook do
let(:plugin) { Rails.root.join('plugins', 'test.rb') } let(:file_hook) { Rails.root.join('plugins', 'test.rb') }
let(:tmp_file) { Tempfile.new('plugin-dump') } let(:tmp_file) { Tempfile.new('file_hook-dump') }
let(:plugin_source) do let(:file_hook_source) do
<<~EOS <<~EOS
#!/usr/bin/env ruby #!/usr/bin/env ruby
x = STDIN.read x = STDIN.read
...@@ -14,13 +14,13 @@ describe Gitlab::Plugin do ...@@ -14,13 +14,13 @@ describe Gitlab::Plugin do
EOS EOS
end end
context 'with plugins present' do context 'with file_hooks present' do
before do before do
File.write(plugin, plugin_source) File.write(file_hook, file_hook_source)
end end
after do after do
FileUtils.rm(plugin) FileUtils.rm(file_hook)
end end
describe '.any?' do describe '.any?' do
...@@ -30,13 +30,13 @@ describe Gitlab::Plugin do ...@@ -30,13 +30,13 @@ describe Gitlab::Plugin do
end end
describe '.files?' do describe '.files?' do
it 'returns a list of plugins' do it 'returns a list of file_hooks' do
expect(described_class.files).to match_array([plugin.to_s]) expect(described_class.files).to match_array([file_hook.to_s])
end end
end end
end end
context 'without any plugins' do context 'without any file_hooks' do
describe '.any?' do describe '.any?' do
it 'returns false' do it 'returns false' do
expect(described_class.any?).to be false expect(described_class.any?).to be false
...@@ -52,21 +52,21 @@ describe Gitlab::Plugin do ...@@ -52,21 +52,21 @@ describe Gitlab::Plugin do
describe '.execute' do describe '.execute' do
let(:data) { Gitlab::DataBuilder::Push::SAMPLE_DATA } let(:data) { Gitlab::DataBuilder::Push::SAMPLE_DATA }
let(:result) { described_class.execute(plugin.to_s, data) } let(:result) { described_class.execute(file_hook.to_s, data) }
let(:success) { result.first } let(:success) { result.first }
let(:message) { result.last } let(:message) { result.last }
before do before do
File.write(plugin, plugin_source) File.write(file_hook, file_hook_source)
end end
after do after do
FileUtils.rm(plugin) FileUtils.rm(file_hook)
end end
context 'successful execution' do context 'successful execution' do
before do before do
File.chmod(0o777, plugin) File.chmod(0o777, file_hook)
end end
after do after do
...@@ -76,7 +76,7 @@ describe Gitlab::Plugin do ...@@ -76,7 +76,7 @@ describe Gitlab::Plugin do
it { expect(success).to be true } it { expect(success).to be true }
it { expect(message).to be_empty } it { expect(message).to be_empty }
it 'ensures plugin received data via stdin' do it 'ensures file_hook received data via stdin' do
result result
expect(File.read(tmp_file.path)).to eq(data.to_json) expect(File.read(tmp_file.path)).to eq(data.to_json)
...@@ -89,7 +89,7 @@ describe Gitlab::Plugin do ...@@ -89,7 +89,7 @@ describe Gitlab::Plugin do
end end
context 'non-zero exit' do context 'non-zero exit' do
let(:plugin_source) do let(:file_hook_source) do
<<~EOS <<~EOS
#!/usr/bin/env ruby #!/usr/bin/env ruby
exit 1 exit 1
...@@ -97,7 +97,7 @@ describe Gitlab::Plugin do ...@@ -97,7 +97,7 @@ describe Gitlab::Plugin do
end end
before do before do
File.chmod(0o777, plugin) File.chmod(0o777, file_hook)
end end
it { expect(success).to be false } it { expect(success).to be false }
......
...@@ -4745,7 +4745,7 @@ describe Project do ...@@ -4745,7 +4745,7 @@ describe Project do
end end
it 'returns true when a plugin exists' do it 'returns true when a plugin exists' do
expect(Gitlab::Plugin).to receive(:any?).twice.and_return(true) expect(Gitlab::FileHook).to receive(:any?).twice.and_return(true)
expect(project.has_active_hooks?(:merge_request_events)).to be_truthy expect(project.has_active_hooks?(:merge_request_events)).to be_truthy
expect(project.has_active_hooks?).to be_truthy expect(project.has_active_hooks?).to be_truthy
......
...@@ -2,25 +2,25 @@ ...@@ -2,25 +2,25 @@
require 'spec_helper' require 'spec_helper'
describe PluginWorker do describe FileHookWorker do
include RepoHelpers include RepoHelpers
let(:filename) { 'my_plugin.rb' } let(:filename) { 'my_file_hook.rb' }
let(:data) { { 'event_name' => 'project_create' } } let(:data) { { 'event_name' => 'project_create' } }
subject { described_class.new } subject { described_class.new }
describe '#perform' do describe '#perform' do
it 'executes Gitlab::Plugin with expected values' do it 'executes Gitlab::FileHook with expected values' do
allow(Gitlab::Plugin).to receive(:execute).with(filename, data).and_return([true, '']) allow(Gitlab::FileHook).to receive(:execute).with(filename, data).and_return([true, ''])
expect(subject.perform(filename, data)).to be_truthy expect(subject.perform(filename, data)).to be_truthy
end end
it 'logs message in case of plugin execution failure' do it 'logs message in case of file_hook execution failure' do
allow(Gitlab::Plugin).to receive(:execute).with(filename, data).and_return([false, 'permission denied']) allow(Gitlab::FileHook).to receive(:execute).with(filename, data).and_return([false, 'permission denied'])
expect(Gitlab::PluginLogger).to receive(:error) expect(Gitlab::FileHookLogger).to receive(:error)
expect(subject.perform(filename, data)).to be_truthy expect(subject.perform(filename, data)).to be_truthy
end end
end end
......
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