diff options
30 files changed, 328 insertions, 36 deletions
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/widget/dynamic_content.vue b/app/assets/javascripts/vue_merge_request_widget/components/widget/dynamic_content.vue index 51c2b15668e..cbc7b91922b 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/widget/dynamic_content.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/widget/dynamic_content.vue @@ -72,10 +72,14 @@ export default { :widget-name="widgetName" :header="data.header" :help-popover="data.helpPopover" - :class="{ 'gl-border-top-0': rowIndex === 0 }" + :class="{ + 'gl-border-top-0': rowIndex === 0, + 'gl-align-items-start': data.supportingText, + 'gl-align-items-baseline': !data.supportingText, + }" > <template #body> - <div class="gl-w-full gl-display-flex" :class="{ 'gl-flex-direction-column': level === 1 }"> + <div class="gl-w-full gl-display-flex gl-flex-direction-column"> <div class="gl-display-flex gl-flex-grow-1"> <div class="gl-display-flex gl-flex-grow-1 gl-align-items-baseline"> <div> diff --git a/app/assets/javascripts/vue_merge_request_widget/components/widget/widget_content_row.vue b/app/assets/javascripts/vue_merge_request_widget/components/widget/widget_content_row.vue index bb82da7796a..7413e2237c3 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/widget/widget_content_row.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/widget/widget_content_row.vue @@ -81,8 +81,7 @@ export default { <div class="gl-display-flex" :class="{ - 'gl-border-t gl-py-3 gl-pl-7 gl-align-items-baseline': level === 2, - 'gl-align-items-center': level === 3, + 'gl-border-t gl-py-3 gl-pl-7': level === 2, }" > <status-icon diff --git a/app/controllers/well_known_controller.rb b/app/controllers/well_known_controller.rb new file mode 100644 index 00000000000..9ca38a81b11 --- /dev/null +++ b/app/controllers/well_known_controller.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +# This controller implements /.well-known paths that have no better home. +# +# Other controllers also implement /.well-known/* paths. They can be +# discovered by running `rails routes | grep "well-known"`. +class WellKnownController < ApplicationController # rubocop:disable Gitlab/NamespacedClass -- No relevant product domain exists + skip_before_action :authenticate_user!, :check_two_factor_requirement + feature_category :compliance_management, [:security_txt] + + def security_txt + content = Gitlab::CurrentSettings.current_application_settings.security_txt_content + if content.present? + render plain: content + else + route_not_found + end + end +end diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb index 0c6ab41004a..c21b2aae749 100644 --- a/app/helpers/application_settings_helper.rb +++ b/app/helpers/application_settings_helper.rb @@ -512,7 +512,8 @@ module ApplicationSettingsHelper :gitlab_shell_operation_limit, :namespace_aggregation_schedule_lease_duration_in_seconds, :ci_max_total_yaml_size_bytes, - :project_jobs_api_rate_limit + :project_jobs_api_rate_limit, + :security_txt_content ].tap do |settings| next if Gitlab.com? diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index a33d7e33769..7942b2b9236 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -748,6 +748,10 @@ class ApplicationSetting < MainClusterwide::ApplicationRecord validates :package_registry_allow_anyone_to_pull_option, inclusion: { in: [true, false], message: N_('must be a boolean value') } + validates :security_txt_content, + length: { maximum: 2_048, message: N_('is too long (maximum is %{count} characters)') }, + allow_blank: true + attr_encrypted :asset_proxy_secret_key, mode: :per_attribute_iv, key: Settings.attr_encrypted_db_key_base_truncated, diff --git a/app/models/application_setting_implementation.rb b/app/models/application_setting_implementation.rb index bb1368f6dc1..18db6ee3ba4 100644 --- a/app/models/application_setting_implementation.rb +++ b/app/models/application_setting_implementation.rb @@ -274,7 +274,8 @@ module ApplicationSettingImplementation ci_max_includes: 150, allow_account_deletion: true, gitlab_shell_operation_limit: 600, - project_jobs_api_rate_limit: 600 + project_jobs_api_rate_limit: 600, + security_txt_content: nil }.tap do |hsh| hsh.merge!(non_production_defaults) unless Rails.env.production? end diff --git a/app/models/concerns/enums/vulnerability.rb b/app/models/concerns/enums/vulnerability.rb index dbf05dbc428..f7d35c77648 100644 --- a/app/models/concerns/enums/vulnerability.rb +++ b/app/models/concerns/enums/vulnerability.rb @@ -46,6 +46,30 @@ module Enums dismissed: 2 }.with_indifferent_access.freeze + OWASP_TOP_10 = { + "A1:2017-Injection" => 1, + "A2:2017-Broken Authentication" => 2, + "A3:2017-Sensitive Data Exposure" => 3, + "A4:2017-XML External Entities (XXE)" => 4, + "A5:2017-Broken Access Control" => 5, + "A6:2017-Security Misconfiguration" => 6, + "A7:2017-Cross-Site Scripting (XSS)" => 7, + "A8:2017-Insecure Deserialization" => 8, + "A9:2017-Using Components with Known Vulnerabilities" => 9, + "A10:2017-Insufficient Logging & Monitoring" => 10, + + "A1:2021-Broken Access Control" => 11, + "A2:2021-Cryptographic Failures" => 12, + "A3:2021-Injection" => 13, + "A4:2021-Insecure Design" => 14, + "A5:2021-Security Misconfiguration" => 15, + "A6:2021-Vulnerable and Outdated Components" => 16, + "A7:2021-Identification and Authentication Failures" => 17, + "A8:2021-Software and Data Integrity Failures" => 18, + "A9:2021-Security Logging and Monitoring Failures" => 19, + "A10:2021-Server-Side Request Forgery" => 20 + }.with_indifferent_access.freeze + def self.confidence_levels CONFIDENCE_LEVELS end @@ -73,6 +97,10 @@ module Enums def self.vulnerability_states VULNERABILITY_STATES end + + def self.owasp_top_10 + OWASP_TOP_10 + end end end diff --git a/app/views/admin/application_settings/_security_txt.html.haml b/app/views/admin/application_settings/_security_txt.html.haml new file mode 100644 index 00000000000..3448d5911e6 --- /dev/null +++ b/app/views/admin/application_settings/_security_txt.html.haml @@ -0,0 +1,21 @@ +%section.settings.as-security-txt.no-animate#js-security-txt-settings{ class: ('expanded' if expanded) } + .settings-header + %h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only + = s_('SecurityTxt|Add security contact information') + = render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle' }) do + = expanded ? _('Collapse') : _('Expand') + %p.gl-text-secondary + = s_('SecurityTxt|Configure a %{codeOpen}security.txt%{codeClose} file.').html_safe % {codeOpen: '<code>'.html_safe, codeClose: '</code>'.html_safe} + = link_to _('Learn more.'), help_page_path('administration/settings/security_contact_information'), target: '_blank', rel: 'noopener noreferrer' + .settings-content + + = gitlab_ui_form_for @application_setting, url: general_admin_application_settings_path(anchor: 'js-security-txt-settings'), html: { class: 'fieldset-form', id: 'security-txt-settings' } do |f| + = form_errors(@application_setting) + + .form-group + = f.label :security_txt_content do + = s_("SecurityTxt|Content for security.txt") + = f.text_area :security_txt_content, class: 'form-control gl-form-input', rows: 8 + .form-text.text-muted + = s_('SecurityTxt|When present, this will be publicly available at %{codeOpen}https://gitlab.example.com/.well-known/security.txt%{codeClose}. Maximum 2048 characters.').html_safe % {codeOpen: '<code>'.html_safe, codeClose: '</code>'.html_safe} + = f.submit _('Save changes'), pajamas_button: true diff --git a/app/views/admin/application_settings/general.html.haml b/app/views/admin/application_settings/general.html.haml index 0ba883872a1..39f1ec7056c 100644 --- a/app/views/admin/application_settings/general.html.haml +++ b/app/views/admin/application_settings/general.html.haml @@ -124,3 +124,4 @@ = render_if_exists 'admin/application_settings/ai_powered' - else = render_if_exists 'admin/application_settings/ai_access' += render 'admin/application_settings/security_txt', expanded: expanded_by_default? diff --git a/config/routes/well_known.rb b/config/routes/well_known.rb index 0c48f116da9..09bcae38cff 100644 --- a/config/routes/well_known.rb +++ b/config/routes/well_known.rb @@ -1,3 +1,4 @@ # frozen_string_literal: true get '/.well-known/change-password', to: redirect('-/profile/password/edit'), status: 302 +get '/.well-known/security.txt', to: 'well_known#security_txt' diff --git a/db/migrate/20231129231159_add_security_txt_content_to_application_settings.rb b/db/migrate/20231129231159_add_security_txt_content_to_application_settings.rb new file mode 100644 index 00000000000..1072e8034fb --- /dev/null +++ b/db/migrate/20231129231159_add_security_txt_content_to_application_settings.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +class AddSecurityTxtContentToApplicationSettings < Gitlab::Database::Migration[2.2] + milestone '16.7' + disable_ddl_transaction! + + def up + with_lock_retries do + add_column :application_settings, :security_txt_content, :text, if_not_exists: true + end + + add_text_limit :application_settings, :security_txt_content, 2048 + end + + def down + with_lock_retries do + remove_column :application_settings, :security_txt_content, if_exists: true + end + end +end diff --git a/db/schema_migrations/20231129231159 b/db/schema_migrations/20231129231159 new file mode 100644 index 00000000000..a18a725f9f3 --- /dev/null +++ b/db/schema_migrations/20231129231159 @@ -0,0 +1 @@ +d19b3f17d84675abc76d291814a6cb220d936e56838e71fd01ee01ec218be9ed
\ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index b8b0f57a22e..e70b76c9ae4 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -12278,6 +12278,7 @@ CREATE TABLE application_settings ( can_create_organization boolean DEFAULT true NOT NULL, web_ide_oauth_application_id integer, instance_level_ai_beta_features_enabled boolean DEFAULT false NOT NULL, + security_txt_content text, CONSTRAINT app_settings_container_reg_cleanup_tags_max_list_size_positive CHECK ((container_registry_cleanup_tags_service_max_list_size >= 0)), CONSTRAINT app_settings_container_registry_pre_import_tags_rate_positive CHECK ((container_registry_pre_import_tags_rate >= (0)::numeric)), CONSTRAINT app_settings_dep_proxy_ttl_policies_worker_capacity_positive CHECK ((dependency_proxy_ttl_group_policy_worker_capacity >= 0)), @@ -12329,6 +12330,7 @@ CREATE TABLE application_settings ( CONSTRAINT check_app_settings_namespace_storage_forks_cost_factor_range CHECK (((namespace_storage_forks_cost_factor >= (0)::double precision) AND (namespace_storage_forks_cost_factor <= (1)::double precision))), CONSTRAINT check_app_settings_sentry_clientside_traces_sample_rate_range CHECK (((sentry_clientside_traces_sample_rate >= (0)::double precision) AND (sentry_clientside_traces_sample_rate <= (1)::double precision))), CONSTRAINT check_b8c74ea5b3 CHECK ((char_length(deactivation_email_additional_text) <= 1000)), + CONSTRAINT check_cdfbd99405 CHECK ((char_length(security_txt_content) <= 2048)), CONSTRAINT check_d03919528d CHECK ((char_length(container_registry_vendor) <= 255)), CONSTRAINT check_d820146492 CHECK ((char_length(spam_check_endpoint_url) <= 255)), CONSTRAINT check_e2692d7523 CHECK ((char_length(default_preferred_language) <= 32)), diff --git a/doc/administration/geo/replication/datatypes.md b/doc/administration/geo/replication/datatypes.md index 0a736da8c8e..996238d4161 100644 --- a/doc/administration/geo/replication/datatypes.md +++ b/doc/administration/geo/replication/datatypes.md @@ -214,6 +214,7 @@ successfully, you must replicate their data using some other means. |[Elasticsearch integration](../../../integration/advanced_search/elasticsearch.md) | [Not planned](https://gitlab.com/gitlab-org/gitlab/-/issues/1186) | No | No | No | Not planned because further product discovery is required and Elasticsearch (ES) clusters can be rebuilt. Secondaries use the same ES cluster as the primary. | |[Dependency Proxy Images](../../../user/packages/dependency_proxy/index.md) | [**Yes** (15.7)](https://gitlab.com/groups/gitlab-org/-/epics/8833) | [**Yes** (15.7)](https://gitlab.com/groups/gitlab-org/-/epics/8833) | [**Yes** (15.7)](https://gitlab.com/groups/gitlab-org/-/epics/8833) | [**Yes** (16.4)](object_storage.md) | | |[Vulnerability Export](../../../user/application_security/vulnerability_report/index.md#export-vulnerability-details) | [Not planned](https://gitlab.com/groups/gitlab-org/-/epics/3111) | No | No | No | Not planned because they are ephemeral and sensitive information. They can be regenerated on demand. | +|Packages NPM metadata cache | [Not planned](https://gitlab.com/gitlab-org/gitlab/-/issues/408278) | No | No | No | Not planned because it would not notably improve disaster recovery capabilities nor response times at secondary sites. | <sup>1</sup> Migrated to [self-service framework](../../../development/geo/framework.md) in 15.5. See GitLab issue [#337436](https://gitlab.com/gitlab-org/gitlab/-/issues/337436) for more details. diff --git a/doc/administration/gitaly/monitoring.md b/doc/administration/gitaly/monitoring.md index 0527c846b2d..6ba43575980 100644 --- a/doc/administration/gitaly/monitoring.md +++ b/doc/administration/gitaly/monitoring.md @@ -176,6 +176,20 @@ gitaly_streamcache_filestore_removed_total{dir="/var/opt/gitlab/git-data/reposit gitaly_streamcache_index_entries{dir="/var/opt/gitlab/git-data/repositories/+gitaly/PackObjectsCache"} 1 ``` +## Monitor Gitaly server-side backups + +> [Introduced](https://gitlab.com/gitlab-org/gitaly/-/issues/5358) in GitLab 16.7. + +Monitor [server-side repository backups](configure_gitaly.md#configure-server-side-backups) with the following metrics: + +- `gitaly_backup_latency_seconds`, a histogram measuring the amount of time in seconds that each phase of a server-side + backup takes. The different phases are `refs`, `bundle`, and `custom_hooks` and represent the type of data being + processed at each stage. +- `gitaly_backup_bundle_bytes`, a histogram measuring the upload data rate of Git bundles being pushed to object + storage by the Gitaly backup service. + +Use these metrics especially if your GitLab instance contains large repositories. + ## Queries The following are some queries for monitoring Gitaly: diff --git a/doc/administration/settings/security_contact_information.md b/doc/administration/settings/security_contact_information.md new file mode 100644 index 00000000000..e4d2cf62bdc --- /dev/null +++ b/doc/administration/settings/security_contact_information.md @@ -0,0 +1,42 @@ +--- +stage: Govern +group: Compliance +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 +--- + +# Provide public security contact information **(FREE SELF)** + +> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/433210) in GitLab 16.7. + +Organizations can facilitate the responsible disclosure of security issues by +providing public contact information. GitLab supports using a +[`security.txt`](https://securitytxt.org/) file for this purpose. + +Administrators can add a `security.txt` file using the GitLab UI or the +[REST API](../../api/settings.md#change-application-settings). +Any content added is made available at +`https://gitlab.example.com/.well-known/security.txt`. Authentication is not +required to view this file. + +To configure a `security.txt` file: + +1. On the left sidebar, select **Search or go to**. +1. Select **Admin Area**. +1. Select **Settings > General**. +1. Expand the **Add security contact information** section. +1. In **Content for security.txt**, enter security contact information in the + format documented at <https://securitytxt.org/>. +1. Select **Save changes**. + +For information about how to respond if you receive a report, see +[Responding to security incidents](../../security/responding_to_security_incidents.md). + +## Example `security.txt` file + +The format of this information is documented at <https://securitytxt.org/>. +An example `security.txt` file is: + +```plaintext +Contact: mailto:security@example.com +Expires: 2024-12-31T23:59Z +``` diff --git a/doc/api/groups.md b/doc/api/groups.md index 1643b388d29..eafaf2011ee 100644 --- a/doc/api/groups.md +++ b/doc/api/groups.md @@ -1688,6 +1688,7 @@ To delete the LDAP group link, provide either a `cn` or a `filter`, but not both > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/290367) in GitLab 15.3.0. > - `access_level` type [changed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/95607) from `string` to `integer` in GitLab 15.3.3. +> - `member_role_id` type [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/417201) in GitLab 16.7 [with a flag](../administration/feature_flags.md) named `custom_roles_for_saml_group_links`. Disabled by default. List, get, add, and delete SAML group links. @@ -1711,6 +1712,7 @@ If successful, returns [`200`](rest/index.md#status-codes) and the following res |:-------------------|:--------|:-----------------------------------------------------------------------------| | `[].name` | string | Name of the SAML group | | `[].access_level` | integer | [Role (`access_level`)](members.md#roles) for members of the SAML group. The attribute had a string type from GitLab 15.3.0 to GitLab 15.3.3 | +| `[].member_role_id` | integer | [Member Role ID (`member_role_id`)](member_roles.md) for members of the SAML group. | Example request: @@ -1724,11 +1726,13 @@ Example response: [ { "name": "saml-group-1", - "access_level": 10 + "access_level": 10, + "member_role_id": 12 }, { "name": "saml-group-2", - "access_level": 40 + "access_level": 40, + "member_role_id": 99 } ] ``` @@ -1754,6 +1758,7 @@ If successful, returns [`200`](rest/index.md#status-codes) and the following res |:---------------|:--------|:-----------------------------------------------------------------------------| | `name` | string | Name of the SAML group | | `access_level` | integer | [Role (`access_level`)](members.md#roles) for members of the SAML group. The attribute had a string type from GitLab 15.3.0 to GitLab 15.3.3 | +| `member_role_id` | integer | [Member Role ID (`member_role_id`)](member_roles.md) for members of the SAML group. | Example request: @@ -1766,7 +1771,8 @@ Example response: ```json { "name": "saml-group-1", -"access_level": 10 +"access_level": 10, +"member_role_id": 12 } ``` @@ -1785,6 +1791,7 @@ Supported attributes: | `id` | integer or string | yes | ID or [URL-encoded path of the group](rest/index.md#namespaced-path-encoding) | | `saml_group_name` | string | yes | Name of a SAML group | | `access_level` | integer | yes | [Role (`access_level`)](members.md#roles) for members of the SAML group | +| `member_role_id` | integer | no | [Member Role ID (`member_role_id`)](member_roles.md) for members of the SAML group. | If successful, returns [`201`](rest/index.md#status-codes) and the following response attributes: @@ -1792,11 +1799,12 @@ If successful, returns [`201`](rest/index.md#status-codes) and the following res |:---------------|:--------|:-----------------------------------------------------------------------------| | `name` | string | Name of the SAML group | | `access_level` | integer | [Role (`access_level`)](members.md#roles) for members of the for members of the SAML group. The attribute had a string type from GitLab 15.3.0 to GitLab 15.3.3 | +| `member_role_id` | integer | [Member Role ID (`member_role_id`)](member_roles.md) for members of the SAML group. | Example request: ```shell -curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" --header "Content-Type: application/json" --data '{ "saml_group_name": "<your_saml_group_name`>", "access_level": <chosen_access_level> }' --url "https://gitlab.example.com/api/v4/groups/1/saml_group_links" +curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" --header "Content-Type: application/json" --data '{ "saml_group_name": "<your_saml_group_name`>", "access_level": <chosen_access_level>, "member_role_id": <chosen_member_role_id> }' --url "https://gitlab.example.com/api/v4/groups/1/saml_group_links" ``` Example response: @@ -1804,7 +1812,8 @@ Example response: ```json { "name": "saml-group-1", -"access_level": 10 +"access_level": 10, +"member_role_id": 12 } ``` diff --git a/doc/api/settings.md b/doc/api/settings.md index d0f2b44750f..21812656dc5 100644 --- a/doc/api/settings.md +++ b/doc/api/settings.md @@ -125,7 +125,8 @@ Example response: "silent_mode_enabled": false, "package_registry_allow_anyone_to_pull_option": true, "bulk_import_max_download_file_size": 5120, - "project_jobs_api_rate_limit": 600 + "project_jobs_api_rate_limit": 600, + "security_txt_content": null } ``` @@ -270,7 +271,8 @@ Example response: "security_policy_global_group_approvers_enabled": true, "package_registry_allow_anyone_to_pull_option": true, "bulk_import_max_download_file_size": 5120, - "project_jobs_api_rate_limit": 600 + "project_jobs_api_rate_limit": 600, + "security_txt_content": null } ``` @@ -544,6 +546,7 @@ listed in the descriptions of the relevant settings. | `rsa_key_restriction` | integer | no | The minimum allowed bit length of an uploaded RSA key. Default is `0` (no restriction). `-1` disables RSA keys. | | `session_expire_delay` | integer | no | Session duration in minutes. GitLab restart is required to apply changes. | | `security_policy_global_group_approvers_enabled` | boolean | no | Whether to look up scan result policy approval groups globally or within project hierarchies. | +| `security_txt_content` | string | no | [Public security contact information](../administration/settings/security_contact_information.md). [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/433210) in GitLab 16.7. | | `service_access_tokens_expiration_enforced` | boolean | no | Flag to indicate if token expiry date can be optional for service account users | | `shared_runners_enabled` | boolean | no | (**If enabled, requires:** `shared_runners_text` and `shared_runners_minutes`) Enable shared runners for new projects. | | `shared_runners_minutes` **(PREMIUM ALL)** | integer | required by: `shared_runners_enabled` | Set the maximum number of compute minutes that a group can use on shared runners per month. | diff --git a/doc/security/responding_to_security_incidents.md b/doc/security/responding_to_security_incidents.md index e49903cc5a9..f99a1879b7a 100644 --- a/doc/security/responding_to_security_incidents.md +++ b/doc/security/responding_to_security_incidents.md @@ -9,6 +9,10 @@ info: To determine the technical writer assigned to the Stage/Group associated w When a security incident occurs, you should follow the processes defined by your organization. However, you might consider some additional steps. These suggestions are intended to supplement existing security incident response processes within your organization. +Administrators can choose to +[provide public security contact information](../administration/settings/security_contact_information.md) +to support receiving reports of security issues from security researchers. + ## Suspected compromised user account If you suspect that a user account or bot account has been compromised, consider taking the following steps: diff --git a/doc/user/application_security/container_scanning/index.md b/doc/user/application_security/container_scanning/index.md index 143d7ff3dad..6a18d01a96c 100644 --- a/doc/user/application_security/container_scanning/index.md +++ b/doc/user/application_security/container_scanning/index.md @@ -271,7 +271,8 @@ including a large number of false positives. | `CS_REGISTRY_INSECURE` | `"false"` | Allow access to insecure registries (HTTP only). Should only be set to `true` when testing the image locally. Works with all scanners, but the registry must listen on port `80/tcp` for Trivy to work. | All | | `CS_REGISTRY_PASSWORD` | `$CI_REGISTRY_PASSWORD` | Password for accessing a Docker registry requiring authentication. The default is only set if `$CS_IMAGE` resides at [`$CI_REGISTRY`](../../../ci/variables/predefined_variables.md). Not supported when [FIPS mode](../../../development/fips_compliance.md#enable-fips-mode) is enabled. | All | | `CS_REGISTRY_USER` | `$CI_REGISTRY_USER` | Username for accessing a Docker registry requiring authentication. The default is only set if `$CS_IMAGE` resides at [`$CI_REGISTRY`](../../../ci/variables/predefined_variables.md). Not supported when [FIPS mode](../../../development/fips_compliance.md#enable-fips-mode) is enabled. | All | -| `CS_SEVERITY_THRESHOLD` | `UNKNOWN` | Severity level threshold. The scanner outputs vulnerabilities with severity level higher than or equal to this threshold. Supported levels are `UNKNOWN`, `LOW`, `MEDIUM`, `HIGH`, and `CRITICAL`. | Trivy || `CS_TRIVY_JAVA_DB` | `"ghcr.io/aquasecurity/trivy-java-db"` | Specify an alternate location for the [trivy-java-db](https://github.com/aquasecurity/trivy-java-db) vulnerability database. | Trivy | +| `CS_SEVERITY_THRESHOLD` | `UNKNOWN` | Severity level threshold. The scanner outputs vulnerabilities with severity level higher than or equal to this threshold. Supported levels are `UNKNOWN`, `LOW`, `MEDIUM`, `HIGH`, and `CRITICAL`. | Trivy | +| `CS_TRIVY_JAVA_DB` | `"ghcr.io/aquasecurity/trivy-java-db"` | Specify an alternate location for the [trivy-java-db](https://github.com/aquasecurity/trivy-java-db) vulnerability database. | Trivy | | `SECURE_LOG_LEVEL` | `info` | Set the minimum logging level. Messages of this logging level or higher are output. From highest to lowest severity, the logging levels are: `fatal`, `error`, `warn`, `info`, `debug`. | All | ### Supported distributions diff --git a/doc/user/project/git_attributes.md b/doc/user/project/git_attributes.md index 2a3e98037ce..2a5221e9c84 100644 --- a/doc/user/project/git_attributes.md +++ b/doc/user/project/git_attributes.md @@ -52,13 +52,12 @@ The `.gitattributes` file can be used to define which language to use when syntax highlighting files and diffs. For more information, see [Syntax highlighting](highlighting.md). -## Custom merge drivers +## Custom merge drivers **(FREE SELF)** > Ability to configure custom merge drivers through GitLab introduced in GitLab 15.10. -You can define [custom merge drivers](https://git-scm.com/docs/gitattributes#_defining_a_custom_merge_driver) -in a GitLab configuration file, then use the custom merge drivers in a Git -`.gitattributes` file. +GitLab self-managed instance administrators can define [custom merge drivers](https://git-scm.com/docs/gitattributes#_defining_a_custom_merge_driver) +in a GitLab configuration file, then use the custom merge drivers in a Git `.gitattributes` file. Custom merge drivers are not supported on GitLab.com. You might configure a custom merge driver, for example, if there are certain files that should be ignored during a merge such as build files and configuration files. diff --git a/doc/user/project/merge_requests/approvals/settings.md b/doc/user/project/merge_requests/approvals/settings.md index fb5244a63ec..c3358e0d90f 100644 --- a/doc/user/project/merge_requests/approvals/settings.md +++ b/doc/user/project/merge_requests/approvals/settings.md @@ -114,7 +114,11 @@ When this field is changed, it can affect all open merge requests depending on t ## Require user re-authentication to approve -> SAML authentication for GitLab.com groups [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/5981) in GitLab 16.6. +> Requiring re-authentication by using SAML authentication for GitLab.com groups [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/5981) in GitLab 16.6 [with a flag](../../../../administration/feature_flags.md) named `ff_require_saml_auth_to_approve`. Disabled by default. + +FLAG: +On self-managed GitLab, by default requiring re-authentication by using SAML authentication is not available. To make it available, an administrator can +[enable the feature flag](../../../../administration/feature_flags.md) named `ff_require_saml_auth_to_approve`. On GitLab.com, this feature is not available. You can force potential approvers to first authenticate with either: diff --git a/lib/api/settings.rb b/lib/api/settings.rb index 7ad4ecd88b1..162e24af099 100644 --- a/lib/api/settings.rb +++ b/lib/api/settings.rb @@ -226,6 +226,7 @@ module API end optional :namespace_aggregation_schedule_lease_duration_in_seconds, type: Integer, desc: 'Maximum duration (in seconds) between refreshes of namespace statistics (Default: 300)' optional :project_jobs_api_rate_limit, type: Integer, desc: 'Maximum authenticated requests to /project/:id/jobs per minute' + optional :security_txt_content, type: String, desc: 'Public security contact information made available at https://gitlab.example.com/.well-known/security.txt' Gitlab::SSHPublicKey.supported_types.each do |type| optional :"#{type}_key_restriction", diff --git a/locale/gitlab.pot b/locale/gitlab.pot index af4930a341b..2ce5986d5cf 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -44247,6 +44247,18 @@ msgstr "" msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled." msgstr "" +msgid "SecurityTxt|Add security contact information" +msgstr "" + +msgid "SecurityTxt|Configure a %{codeOpen}security.txt%{codeClose} file." +msgstr "" + +msgid "SecurityTxt|Content for security.txt" +msgstr "" + +msgid "SecurityTxt|When present, this will be publicly available at %{codeOpen}https://gitlab.example.com/.well-known/security.txt%{codeClose}. Maximum 2048 characters." +msgstr "" + msgid "See example DevOps Score page in our documentation." msgstr "" diff --git a/spec/frontend/vue_merge_request_widget/components/widget/__snapshots__/dynamic_content_spec.js.snap b/spec/frontend/vue_merge_request_widget/components/widget/__snapshots__/dynamic_content_spec.js.snap index eb65f790df6..f2a66ad2ff2 100644 --- a/spec/frontend/vue_merge_request_widget/components/widget/__snapshots__/dynamic_content_spec.js.snap +++ b/spec/frontend/vue_merge_request_widget/components/widget/__snapshots__/dynamic_content_spec.js.snap @@ -49,7 +49,7 @@ exports[`~/vue_merge_request_widget/components/widget/dynamic_content.vue render name="MyWidget" /> <div - class="gl-display-flex gl-w-full" + class="gl-display-flex gl-flex-direction-column gl-w-full" > <div class="gl-display-flex gl-flex-grow-1" @@ -88,7 +88,7 @@ exports[`~/vue_merge_request_widget/components/widget/dynamic_content.vue render > <li> <div - class="gl-align-items-center gl-display-flex" + class="gl-align-items-baseline gl-display-flex" > <div class="gl-min-w-0 gl-w-full" @@ -110,7 +110,7 @@ exports[`~/vue_merge_request_widget/components/widget/dynamic_content.vue render class="gl-align-items-baseline gl-display-flex" > <div - class="gl-display-flex gl-w-full" + class="gl-display-flex gl-flex-direction-column gl-w-full" > <div class="gl-display-flex gl-flex-grow-1" diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb index f0b56cb505b..0f786489245 100644 --- a/spec/models/application_setting_spec.rb +++ b/spec/models/application_setting_spec.rb @@ -1714,4 +1714,8 @@ RSpec.describe ApplicationSetting, feature_category: :shared, type: :model do expect(setting.personal_access_tokens_disabled?).to eq(false) end end + + context 'security txt content' do + it { is_expected.to validate_length_of(:security_txt_content).is_at_most(2048) } + end end diff --git a/spec/requests/api/settings_spec.rb b/spec/requests/api/settings_spec.rb index 5656fda7684..46fc61c80d8 100644 --- a/spec/requests/api/settings_spec.rb +++ b/spec/requests/api/settings_spec.rb @@ -205,7 +205,8 @@ RSpec.describe API::Settings, 'Settings', :do_not_mock_admin_mode_setting, featu allow_account_deletion: false, gitlab_shell_operation_limit: 500, namespace_aggregation_schedule_lease_duration_in_seconds: 400, - max_import_remote_file_size: 2 + max_import_remote_file_size: 2, + security_txt_content: nil } expect(response).to have_gitlab_http_status(:ok) @@ -288,6 +289,7 @@ RSpec.describe API::Settings, 'Settings', :do_not_mock_admin_mode_setting, featu expect(json_response['namespace_aggregation_schedule_lease_duration_in_seconds']).to be(400) expect(json_response['max_import_remote_file_size']).to be(2) expect(json_response['bulk_import_max_download_file_size']).to be(1) + expect(json_response['security_txt_content']).to be(nil) end end @@ -1062,5 +1064,19 @@ RSpec.describe API::Settings, 'Settings', :do_not_mock_admin_mode_setting, featu expect(json_response['failed_login_attempts_unlock_period_in_minutes']).to eq(30) end end + + context 'security txt settings' do + let(:content) { "Contact: foo@acme.com" } + + it 'updates the settings' do + put( + api("/application/settings", admin), + params: { security_txt_content: content } + ) + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response['security_txt_content']).to eq(content) + end + end end end diff --git a/spec/requests/well_known_routing_spec.rb b/spec/requests/well_known_routing_spec.rb deleted file mode 100644 index d4e77a06953..00000000000 --- a/spec/requests/well_known_routing_spec.rb +++ /dev/null @@ -1,13 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe 'well-known URLs', feature_category: :system_access do - describe '/.well-known/change-password' do - it 'redirects to edit profile password path' do - get('/.well-known/change-password') - - expect(response).to redirect_to(edit_profile_password_path) - end - end -end diff --git a/spec/requests/well_known_spec.rb b/spec/requests/well_known_spec.rb new file mode 100644 index 00000000000..9db1f63690f --- /dev/null +++ b/spec/requests/well_known_spec.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'well-known URLs', feature_category: :shared do + describe '/.well-known/change-password', feature_category: :system_access do + it 'redirects to edit profile password path' do + get('/.well-known/change-password') + + expect(response).to redirect_to(edit_profile_password_path) + end + end + + describe '/.well-known/security.txt', feature_category: :compliance_management do + let(:action) { get('/.well-known/security.txt') } + + context 'for an authenticated user' do + before do + sign_in(create(:user)) + end + + it 'renders when a security txt is configured' do + stub_application_setting security_txt_content: 'HELLO' + action + expect(response.body).to eq('HELLO') + end + + it 'returns a 404 when a security txt is blank' do + stub_application_setting security_txt_content: '' + action + expect(response).to have_gitlab_http_status(:not_found) + end + + it 'returns a 404 when a security txt is nil' do + stub_application_setting security_txt_content: nil + action + expect(response).to have_gitlab_http_status(:not_found) + end + end + + context 'for an unauthenticated user' do + it 'renders when a security txt is configured' do + stub_application_setting security_txt_content: 'HELLO' + action + expect(response.body).to eq('HELLO') + end + + it 'redirects to sign in' do + stub_application_setting security_txt_content: '' + action + expect(response).to redirect_to(new_user_session_path) + end + end + end +end diff --git a/spec/views/admin/application_settings/_security_txt.html.haml_spec.rb b/spec/views/admin/application_settings/_security_txt.html.haml_spec.rb new file mode 100644 index 00000000000..9f420d018e5 --- /dev/null +++ b/spec/views/admin/application_settings/_security_txt.html.haml_spec.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'admin/application_settings/_security_txt.html.haml', feature_category: :compliance_management do + let(:app_settings) { build(:application_setting) } + + before do + assign(:application_setting, app_settings) + allow(view).to receive(:expanded).and_return(true) + end + + context 'when security contact information is not set' do + it 'renders the form correctly' do + render + + expect(rendered).to have_selector( + 'textarea', + id: 'application_setting_security_txt_content', + exact_text: '' + ) + end + end + + context 'when security contact information is set' do + let(:app_settings) { build(:application_setting, security_txt_content: 'HELLO') } + + it 'renders the form correctly' do + render + + expect(rendered).to have_selector( + 'textarea', + id: 'application_setting_security_txt_content', + exact_text: 'HELLO' + ) + end + end +end |