diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-02-04 06:15:28 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-02-04 06:15:28 +0000 |
commit | 1a1473f44731b3f78a8485337abd3d14833efb4a (patch) | |
tree | f6e650301bc6a85242684518a91b20aee0f5f691 | |
parent | 9f7f0ef116cd8f57446e1e395d8c2d6c88148096 (diff) | |
download | gitlab-ce-1a1473f44731b3f78a8485337abd3d14833efb4a.tar.gz |
Add latest changes from gitlab-org/gitlab@master
37 files changed, 492 insertions, 83 deletions
diff --git a/app/assets/javascripts/security_configuration/components/training_provider_list.vue b/app/assets/javascripts/security_configuration/components/training_provider_list.vue index c289df9f1f4..7a4c0205569 100644 --- a/app/assets/javascripts/security_configuration/components/training_provider_list.vue +++ b/app/assets/javascripts/security_configuration/components/training_provider_list.vue @@ -1,6 +1,8 @@ <script> import { GlAlert, GlCard, GlToggle, GlLink, GlSkeletonLoader } from '@gitlab/ui'; +import * as Sentry from '@sentry/browser'; import { __ } from '~/locale'; +import dismissUserCalloutMutation from '~/graphql_shared/mutations/dismiss_user_callout.mutation.graphql'; import securityTrainingProvidersQuery from '../graphql/security_training_providers.query.graphql'; import configureSecurityTrainingProvidersMutation from '../graphql/configure_security_training_providers.mutation.graphql'; @@ -43,6 +45,7 @@ export default { errorMessage: '', toggleLoading: false, securityTrainingProviders: [], + hasTouchedConfiguration: false, }; }, computed: { @@ -50,7 +53,36 @@ export default { return this.$apollo.queries.securityTrainingProviders.loading; }, }, + created() { + const unwatchConfigChance = this.$watch('hasTouchedConfiguration', () => { + this.dismissFeaturePromotionCallout(); + unwatchConfigChance(); + }); + }, methods: { + async dismissFeaturePromotionCallout() { + try { + const { + data: { + userCalloutCreate: { errors }, + }, + } = await this.$apollo.mutate({ + mutation: dismissUserCalloutMutation, + variables: { + input: { + featureName: 'security_training_feature_promotion', + }, + }, + }); + + // handle errors reported from the backend + if (errors?.length > 0) { + throw new Error(errors[0]); + } + } catch (e) { + Sentry.captureException(e); + } + }, toggleProvider(selectedProviderId) { const toggledProviders = this.securityTrainingProviders.map((provider) => ({ ...provider, @@ -85,6 +117,8 @@ export default { // throwing an error here means we can handle scenarios within the `catch` block below throw new Error(); } + + this.hasTouchedConfiguration = true; } catch { this.errorMessage = this.$options.i18n.configMutationErrorMessage; } finally { diff --git a/app/assets/javascripts/security_configuration/resolver.js b/app/assets/javascripts/security_configuration/resolver.js index 93175d4a3d1..51c02839a47 100644 --- a/app/assets/javascripts/security_configuration/resolver.js +++ b/app/assets/javascripts/security_configuration/resolver.js @@ -32,24 +32,28 @@ export default { Mutation: { configureSecurityTrainingProviders: ( _, - { input: { enabledProviders, primaryProvider } }, + { input: { enabledProviders, primaryProvider, fullPath } }, { cache }, ) => { const sourceData = cache.readQuery({ query: securityTrainingProvidersQuery, + variables: { + fullPath, + }, }); - const data = produce(sourceData.securityTrainingProviders, (draftData) => { + const data = produce(sourceData.project, (draftData) => { /* eslint-disable no-param-reassign */ - draftData.forEach((provider) => { + draftData.securityTrainingProviders.forEach((provider) => { provider.isPrimary = provider.id === primaryProvider; provider.isEnabled = provider.id === primaryProvider || enabledProviders.includes(provider.id); }); }); + return { __typename: 'configureSecurityTrainingProvidersPayload', - securityTrainingProviders: data, + securityTrainingProviders: data.securityTrainingProviders, }; }, }, diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb index 7541247b19f..f90cc85ba67 100644 --- a/app/helpers/application_settings_helper.rb +++ b/app/helpers/application_settings_helper.rb @@ -234,7 +234,9 @@ module ApplicationSettingsHelper :outbound_local_requests_allowlist_raw, :dsa_key_restriction, :ecdsa_key_restriction, + :ecdsa_sk_key_restriction, :ed25519_key_restriction, + :ed25519_sk_key_restriction, :eks_integration_enabled, :eks_account_id, :eks_access_key_id, diff --git a/app/models/application_setting_implementation.rb b/app/models/application_setting_implementation.rb index 25198178f69..4bdeceb7c25 100644 --- a/app/models/application_setting_implementation.rb +++ b/app/models/application_setting_implementation.rb @@ -69,7 +69,9 @@ module ApplicationSettingImplementation domain_allowlist: Settings.gitlab['domain_allowlist'], dsa_key_restriction: 0, ecdsa_key_restriction: 0, + ecdsa_sk_key_restriction: 0, ed25519_key_restriction: 0, + ed25519_sk_key_restriction: 0, eks_access_key_id: nil, eks_account_id: nil, eks_integration_enabled: false, diff --git a/app/workers/loose_foreign_keys/cleanup_worker.rb b/app/workers/loose_foreign_keys/cleanup_worker.rb index c3492fed77b..ecece92ec1b 100644 --- a/app/workers/loose_foreign_keys/cleanup_worker.rb +++ b/app/workers/loose_foreign_keys/cleanup_worker.rb @@ -12,8 +12,6 @@ module LooseForeignKeys idempotent! def perform - return if Feature.disabled?(:loose_foreign_key_cleanup, default_enabled: :yaml) - in_lock(self.class.name.underscore, ttl: ModificationTracker::MAX_RUNTIME, retries: 0) do stats = {} diff --git a/config/feature_flags/development/loose_foreign_key_cleanup.yml b/config/feature_flags/development/loose_foreign_key_cleanup.yml deleted file mode 100644 index 915ed662333..00000000000 --- a/config/feature_flags/development/loose_foreign_key_cleanup.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -name: loose_foreign_key_cleanup -introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/69165 -rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/343545 -milestone: '14.4' -type: development -group: group::sharding -default_enabled: true diff --git a/db/migrate/20220128093756_add_ecdsa_sk_and_ed25519_sk_key_restrictions_to_application_settings.rb b/db/migrate/20220128093756_add_ecdsa_sk_and_ed25519_sk_key_restrictions_to_application_settings.rb new file mode 100644 index 00000000000..1acd9599da4 --- /dev/null +++ b/db/migrate/20220128093756_add_ecdsa_sk_and_ed25519_sk_key_restrictions_to_application_settings.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +class AddEcdsaSkAndEd25519SkKeyRestrictionsToApplicationSettings < Gitlab::Database::Migration[1.0] + enable_lock_retries! + + def change + add_column :application_settings, :ecdsa_sk_key_restriction, :integer, default: 0, null: false + add_column :application_settings, :ed25519_sk_key_restriction, :integer, default: 0, null: false + end +end diff --git a/db/schema_migrations/20220128093756 b/db/schema_migrations/20220128093756 new file mode 100644 index 00000000000..fd24b6cd4cd --- /dev/null +++ b/db/schema_migrations/20220128093756 @@ -0,0 +1 @@ +787b1be4b69ef0eeb049ee6a3d7126dc75094b79fba18f469fffe78b16fce6a3
\ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index 2bc680d509b..f76f7cfd3d2 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -10617,6 +10617,8 @@ CREATE TABLE application_settings ( runner_token_expiration_interval integer, group_runner_token_expiration_interval integer, project_runner_token_expiration_interval integer, + ecdsa_sk_key_restriction integer DEFAULT 0 NOT NULL, + ed25519_sk_key_restriction integer DEFAULT 0 NOT NULL, CONSTRAINT app_settings_container_reg_cleanup_tags_max_list_size_positive CHECK ((container_registry_cleanup_tags_service_max_list_size >= 0)), CONSTRAINT app_settings_dep_proxy_ttl_policies_worker_capacity_positive CHECK ((dependency_proxy_ttl_group_policy_worker_capacity >= 0)), CONSTRAINT app_settings_ext_pipeline_validation_service_url_text_limit CHECK ((char_length(external_pipeline_validation_service_url) <= 255)), diff --git a/doc/administration/auth/oidc.md b/doc/administration/auth/oidc.md index 0a307f4813e..a099b9c76f8 100644 --- a/doc/administration/auth/oidc.md +++ b/doc/administration/auth/oidc.md @@ -461,6 +461,65 @@ To use symmetric key encryption: If after reconfiguring, you see the error `JSON::JWS::VerificationFailed` error message, this means the incorrect secret was specified. +#### Casdoor + +GitLab works with OpenID providers that use HTTPS. To connect to GitLab using OpenID with Casdoor, use HTTPS instead of HTTP. + +For your app, complete the following steps on Casdoor: + +1. Get a client ID and a client secret. +1. Add your GitLab redirect URL. For example, if your GitLab domain is `gitlab.example.com`, ensure the Casdoor app has the following + `Redirect URI`: `https://gitlab.example.com/users/auth/openid_connect/callback`. + +See the [Casdoor documentation](https://casdoor.org/docs/integration/gitlab) for more details. + +Example Omnibus GitLab configuration (file path: `/etc/gitlab/gitlab.rb`): + +```ruby +gitlab_rails['omniauth_providers'] = [ + { + name: "openid_connect", + label: "Casdoor", # optional label for login button, defaults to "Openid Connect" + args: { + name: "openid_connect", + scope: ["openid", "profile", "email"], + response_type: "code", + issuer: "https://<CASDOOR_HOSTNAME>", + client_auth_method: "query", + discovery: true, + uid_field: "sub", + client_options: { + identifier: "<YOUR CLIENT ID>", + secret: "<YOUR CLIENT SECRET>", + redirect_uri: "https://gitlab.example.com/users/auth/openid_connect/callback" + } + } + } +] +``` + +Example installations from source configuration (file path: `config/gitlab.yml`): + +```yaml + - { name: 'openid_connect', + label: 'Casdoor', # optional label for login button, defaults to "Openid Connect" + args: { + name: 'openid_connect', + scope: ['openid','profile','email'], + response_type: 'code', + issuer: 'https://<CASDOOR_HOSTNAME>', + discovery: true, + client_auth_method: 'query', + uid_field: 'sub', + client_options: { + identifier: '<YOUR CLIENT ID>', + secret: '<YOUR CLIENT SECRET>', + redirect_uri: 'https://gitlab.example.com/users/auth/openid_connect/callback' + } + } + } +``` + ## General troubleshooting If you're having trouble, here are some tips: diff --git a/doc/administration/gitaly/configure_gitaly.md b/doc/administration/gitaly/configure_gitaly.md index deb2aba840b..88efd1885db 100644 --- a/doc/administration/gitaly/configure_gitaly.md +++ b/doc/administration/gitaly/configure_gitaly.md @@ -566,12 +566,6 @@ Note the following: - You can configure Gitaly servers with both an unencrypted listening address `listen_addr` and an encrypted listening address `tls_listen_addr` at the same time. This allows you to gradually transition from unencrypted to encrypted traffic if necessary. -- When running Praefect sub-commands such as `dial-nodes` and `list-untracked-repositories` from the command line with Gitaly TLS enabled, you must set - the `SSL_CERT_DIR` or `SSL_CERT_FILE` environment variable so that the Gitaly certificate is trusted. For example: - - ```shell - sudo SSL_CERT_DIR=/etc/gitlab/trusted_certs /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml dial-nodes - ``` To configure Gitaly with TLS: diff --git a/doc/administration/gitaly/praefect.md b/doc/administration/gitaly/praefect.md index e2db30b8358..9b55cbb660c 100644 --- a/doc/administration/gitaly/praefect.md +++ b/doc/administration/gitaly/praefect.md @@ -570,7 +570,7 @@ On the **Praefect** node: edit `/etc/gitlab/gitlab.rb`, remember to run `sudo gitlab-ctl reconfigure` again before trying the `sql-ping` command. -#### Enabling TLS support +#### Enable TLS support > [Introduced](https://gitlab.com/gitlab-org/gitaly/-/issues/1698) in GitLab 13.2. @@ -594,6 +594,13 @@ Note the following: - Hostname, you can either use the Common Name field for this, or add it as a Subject Alternative Name. - IP address, you must add it as a Subject Alternative Name to the certificate. +- When running Praefect sub-commands such as `dial-nodes` and `list-untracked-repositories` from the command line with + [Gitaly TLS enabled](configure_gitaly.md#enable-tls-support), you must set the `SSL_CERT_DIR` or `SSL_CERT_FILE` + environment variable so that the Gitaly certificate is trusted. For example: + + ```shell + sudo SSL_CERT_DIR=/etc/gitlab/trusted_certs /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml dial-nodes + ``` - You can configure Praefect servers with both an unencrypted listening address `listen_addr` and an encrypted listening address `tls_listen_addr` at the same time. diff --git a/doc/api/index.md b/doc/api/index.md index 471fad9443c..589bc0416a1 100644 --- a/doc/api/index.md +++ b/doc/api/index.md @@ -12,6 +12,9 @@ Use the GitLab APIs to automate GitLab. A REST API is available in GitLab. Usage instructions are below. + +For examples, see [How to use the API](#how-to-use-the-api). + For a list of the available resources and their endpoints, see [REST API resources](api_resources.md). @@ -76,7 +79,7 @@ For example, the root of the v4 API is at `/api/v4`. ### Valid API request -If you have a GitLab instance at `gitlab.example.com`: +The following is a basic example of a request to the fictional `gitlab.example.com` endpoint: ```shell curl "https://gitlab.example.com/api/v4/projects" @@ -85,6 +88,10 @@ curl "https://gitlab.example.com/api/v4/projects" The API uses JSON to serialize data. You don't need to specify `.json` at the end of the API URL. +NOTE: +In the example above, replace `gitlab.example.com` with `gitlab.com` to query GitLab.com (GitLab SaaS). +Access can be denied due to authentication. For more information, see [Authentication](#authentication). + ### API request to expose HTTP response headers If you want to expose HTTP response headers, use the `--include` option: diff --git a/doc/api/settings.md b/doc/api/settings.md index b4fe22cf997..4246c7a46f1 100644 --- a/doc/api/settings.md +++ b/doc/api/settings.md @@ -65,6 +65,8 @@ Example response: "dsa_key_restriction": 0, "ecdsa_key_restriction": 0, "ed25519_key_restriction": 0, + "ecdsa_sk_key_restriction": 0, + "ed25519_sk_key_restriction": 0, "first_day_of_week": 0, "enforce_terms": true, "terms": "Hello world!", @@ -166,6 +168,8 @@ Example response: "dsa_key_restriction": 0, "ecdsa_key_restriction": 0, "ed25519_key_restriction": 0, + "ecdsa_sk_key_restriction": 0, + "ed25519_sk_key_restriction": 0, "first_day_of_week": 0, "enforce_terms": true, "terms": "Hello world!", @@ -268,7 +272,9 @@ listed in the descriptions of the relevant settings. | `domain_allowlist` | array of strings | no | Force people to use only corporate emails for sign-up. Default is `null`, meaning there is no restriction. | | `dsa_key_restriction` | integer | no | The minimum allowed bit length of an uploaded DSA key. Default is `0` (no restriction). `-1` disables DSA keys. | | `ecdsa_key_restriction` | integer | no | The minimum allowed curve size (in bits) of an uploaded ECDSA key. Default is `0` (no restriction). `-1` disables ECDSA keys. | +| `ecdsa_sk_key_restriction` | integer | no | The minimum allowed curve size (in bits) of an uploaded ECDSA_SK key. Default is `0` (no restriction). `-1` disables ECDSA_SK keys. | | `ed25519_key_restriction` | integer | no | The minimum allowed curve size (in bits) of an uploaded ED25519 key. Default is `0` (no restriction). `-1` disables ED25519 keys. | +| `ed25519_sk_key_restriction` | integer | no | The minimum allowed curve size (in bits) of an uploaded ED25519_SK key. Default is `0` (no restriction). `-1` disables ED25519_SK keys. | | `eks_access_key_id` | string | no | AWS IAM access key ID. | | `eks_account_id` | string | no | Amazon account ID. | | `eks_integration_enabled` | boolean | no | Enable integration with Amazon EKS. | diff --git a/doc/push_rules/push_rules.md b/doc/push_rules/push_rules.md index 7a3af50af8d..2fb04d98d34 100644 --- a/doc/push_rules/push_rules.md +++ b/doc/push_rules/push_rules.md @@ -172,7 +172,7 @@ Files blocked by this rule are listed below. For a complete list of criteria, se - `id_dsa` - `.id_dsa` -- Private ed25519 SSH keys: +- Private ED25519 SSH keys: - `/ssh/id_ed25519` - `/.ssh/personal_ed25519` @@ -188,6 +188,22 @@ Files blocked by this rule are listed below. For a complete list of criteria, se - `id_ecdsa` - `.id_ecdsa` +- Private ECDSA_SK SSH keys (GitLab 14.8 and later): + + - `/ssh/id_ecdsa_sk` + - `/.ssh/personal_ecdsa_sk` + - `/config/server_ecdsa_sk` + - `id_ecdsa_sk` + - `.id_ecdsa_sk` + +- Private ED25519_SK SSH keys (GitLab 14.8 and later): + + - `/ssh/id_ed25519_sk` + - `/.ssh/personal_ed25519_sk` + - `/config/server_ed25519_sk` + - `id_ed25519_sk` + - `.id_ed25519_sk` + - Any files ending with these suffixes: - `*.pem` diff --git a/doc/security/ssh_keys_restrictions.md b/doc/security/ssh_keys_restrictions.md index 1b3d33c56c7..2e4a737f9aa 100644 --- a/doc/security/ssh_keys_restrictions.md +++ b/doc/security/ssh_keys_restrictions.md @@ -13,9 +13,9 @@ NIST). Some organizations deploying GitLab need to enforce minimum key strength, either to satisfy internal security policy or for regulatory compliance. -Similarly, certain standards groups recommend using RSA, ECDSA, or ED25519 over -the older DSA, and administrators may need to limit the allowed SSH key -algorithms. +Similarly, certain standards groups recommend using RSA, ECDSA, ED25519, +ECDSA_SK, or ED25519_SK over the older DSA, and administrators may need to +limit the allowed SSH key algorithms. GitLab allows you to restrict the allowed SSH key technology as well as specify the minimum key length for each technology: @@ -45,6 +45,8 @@ By default, the GitLab.com and self-managed settings for the - DSA SSH keys are forbidden ([since GitLab 11.0](https://about.gitlab.com/releases/2018/06/22/gitlab-11-0-released/#support-for-dsa-ssh-keys)). - ECDSA SSH keys are allowed. - ED25519 SSH keys are allowed. +- ECDSA_SK SSH keys are allowed (GitLab 14.8 and later). +- ED25519_SK SSH keys are allowed (GitLab 14.8 and later). <!-- ## Troubleshooting diff --git a/doc/security/two_factor_authentication.md b/doc/security/two_factor_authentication.md index aad2af11f2f..e8bb627ccbd 100644 --- a/doc/security/two_factor_authentication.md +++ b/doc/security/two_factor_authentication.md @@ -116,8 +116,10 @@ reactivate 2FA from scratch if they want to use it again. WARNING: This feature might not be available to you. Check the **version history** note above for details. -Two-factor authentication can be enforced for Git over SSH operations. The one-time password (OTP) -verification can be done via a GitLab Shell command: +Two-factor authentication can be enforced for Git over SSH operations. However, we recommend using +[ED25519_SK](../ssh/index.md#ed25519_sk-ssh-keys) or [ECDSA_SK](../ssh/index.md#ecdsa_sk-ssh-keys) SSH keys instead. + +The one-time password (OTP) verification can be done using a command: ```shell ssh git@<hostname> 2fa_verify diff --git a/doc/ssh/index.md b/doc/ssh/index.md index 1991063ade0..35ca9a23179 100644 --- a/doc/ssh/index.md +++ b/doc/ssh/index.md @@ -28,6 +28,8 @@ To view the version of SSH installed on your system, run `ssh -V`. To communicate with GitLab, you can use the following SSH key types: - [ED25519](#ed25519-ssh-keys) +- [ED25519_SK](#ed25519_sk-ssh-keys) (Available in GitLab 14.8 and later.) +- [ECDSA_SK](#ecdsa_sk-ssh-keys) (Available in GitLab 14.8 and later.) - [RSA](#rsa-ssh-keys) - DSA ([Deprecated](https://about.gitlab.com/releases/2018/06/22/gitlab-11-0-released/#support-for-dsa-ssh-keys) in GitLab 11.0.) - ECDSA (As noted in [Practical Cryptography With Go](https://leanpub.com/gocrypto/read#leanpub-auto-ecdsa), the security issues related to DSA also apply to ECDSA.) @@ -42,6 +44,20 @@ suggests that [ED25519](https://ed25519.cr.yp.to/) keys are more secure and perf OpenSSH 6.5 introduced ED25519 SSH keys in 2014 and they should be available on most operating systems. +### ED25519_SK SSH keys + +> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/78934) in GitLab 14.8. + +To use ED25519_SK SSH keys on GitLab, your local client and GitLab server +must have [OpenSSH 8.2](https://www.openssh.com/releasenotes.html#8.2) or later installed. + +### ECDSA_SK SSH keys + +> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/78934) in GitLab 14.8. + +To use ECDSA_SK SSH keys on GitLab, your local client and GitLab server +must have [OpenSSH 8.2](https://www.openssh.com/releasenotes.html#8.2) or later installed. + ### RSA SSH keys Available documentation suggests that ED25519 is more secure than RSA. @@ -64,6 +80,8 @@ Before you create a key pair, see if a key pair already exists. | Algorithm | Public key | Private key | | --------- | ---------- | ----------- | | ED25519 (preferred) | `id_ed25519.pub` | `id_ed25519` | + | ED25519_SK | `id_ed25519_sk.pub` | `id_ed25519_sk` | + | ECDSA_SK | `id_ecdsa_sk.pub` | `id_ecdsa_sk` | | RSA (at least 2048-bit key size) | `id_rsa.pub` | `id_rsa` | | DSA (deprecated) | `id_dsa.pub` | `id_dsa` | | ECDSA | `id_ecdsa.pub` | `id_ecdsa` | @@ -177,6 +195,67 @@ OpenSSH format. ssh-keygen -o -t rsa -b 4096 -C "<comment>" ``` +## Generate an SSH key pair for a FIDO/U2F hardware security key + +To generate ED25519_SK or ECDSA_SK SSH keys, you must use OpenSSH 8.2 or later. + +1. Insert a hardware security key into your computer. +1. Open a terminal. +1. Type `ssh-keygen -t` followed by the key type and an optional comment. + This comment is included in the `.pub` file that's created. + You may want to use an email address for the comment. + + For example, for ED25519_SK: + + ```shell + ssh-keygen -t ed25519-sk -C "<comment>" + ``` + + For ECDSA_SK: + + ```shell + ssh-keygen -t ecdsa-sk -C "<comment>" + ``` + + If your security key supports FIDO2 resident keys, you can enable this when + creating your SSH key: + + ```shell + ssh-keygen -t ed25519-sk -O resident -C "<comment>" + ``` + + `-O resident` indicates that the key should be stored on the FIDO authenticator itself. + Resident key is easier to import to a new computer because it can be loaded directly + from the security key by [`ssh-add -K`](https://man.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man1/ssh-add.1#K) + or [`ssh-keygen -K`](https://man.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man1/ssh-keygen#K). + +1. Select Enter. Output similar to the following is displayed: + + ```plaintext + Generating public/private ed25519-sk key pair. + You may need to touch your authenticator to authorize key generation. + ``` + +1. Touch the button on the hardware security key. + +1. Accept the suggested filename and directory: + + ```plaintext + Enter file in which to save the key (/home/user/.ssh/id_ed25519_sk): + ``` + +1. Specify a [passphrase](https://www.ssh.com/academy/ssh/passphrase): + + ```plaintext + Enter passphrase (empty for no passphrase): + Enter same passphrase again: + ``` + +1. A confirmation is displayed, including information about where your files are stored. + +A public and private key are generated. +[Add the public SSH key to your GitLab account](#add-an-ssh-key-to-your-gitlab-account). + ## Add an SSH key to your GitLab account To use SSH with GitLab, copy your public key to your GitLab account. @@ -210,7 +289,8 @@ To use SSH with GitLab, copy your public key to your GitLab account. 1. On the left sidebar, select **SSH Keys**. 1. In the **Key** box, paste the contents of your public key. If you manually copied the key, make sure you copy the entire key, - which starts with `ssh-ed25519` or `ssh-rsa`, and may end with a comment. + which starts with `ssh-rsa`, `ssh-dss`, `ecdsa-sha2-nistp256`, `ecdsa-sha2-nistp384`, `ecdsa-sha2-nistp521`, + `ssh-ed25519`, `sk-ecdsa-sha2-nistp256@openssh.com`, or `sk-ssh-ed25519@openssh.com`, and may end with a comment. 1. In the **Title** box, type a description, like `Work Laptop` or `Home Workstation`. 1. Optional. In the **Expires at** box, select an expiration date. ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/36243) in GitLab 12.9.) @@ -318,7 +398,8 @@ on the files make them readable to you but not accessible to others. ## Configure two-factor authentication (2FA) You can set up two-factor authentication (2FA) for -[Git over SSH](../security/two_factor_authentication.md#2fa-for-git-over-ssh-operations). +[Git over SSH](../security/two_factor_authentication.md#2fa-for-git-over-ssh-operations). We recommend using +[ED25519_SK](#ed25519_sk-ssh-keys) or [ECDSA_SK](#ecdsa_sk-ssh-keys) SSH keys. ## Use EGit on Eclipse diff --git a/doc/user/admin_area/settings/visibility_and_access_controls.md b/doc/user/admin_area/settings/visibility_and_access_controls.md index a6f7eccffe4..c38b2455a8d 100644 --- a/doc/user/admin_area/settings/visibility_and_access_controls.md +++ b/doc/user/admin_area/settings/visibility_and_access_controls.md @@ -280,7 +280,7 @@ NOTE: SSH clone URLs can be customized in `gitlab.rb` by setting `gitlab_rails['gitlab_ssh_host']` and other related settings. -## Configure defaults for RSA, DSA, ECDSA, ED25519 SSH keys +## Configure defaults for RSA, DSA, ECDSA, ED25519, ECDSA_SK, ED25519_SK SSH keys These options specify the permitted types and lengths for SSH keys. diff --git a/lib/gitlab/audit/runner_registration_token_author.rb b/lib/gitlab/audit/ci_runner_token_author.rb index 53785236f72..cc140a29260 100644 --- a/lib/gitlab/audit/runner_registration_token_author.rb +++ b/lib/gitlab/audit/ci_runner_token_author.rb @@ -2,7 +2,7 @@ module Gitlab module Audit - class RunnerRegistrationTokenAuthor < Gitlab::Audit::NullAuthor + class CiRunnerTokenAuthor < Gitlab::Audit::NullAuthor def initialize(token:, entity_type:, entity_path:) super(id: -1, name: "Registration token: #{token}") diff --git a/lib/gitlab/audit/null_author.rb b/lib/gitlab/audit/null_author.rb index 254d3f1c7ac..64aec51471a 100644 --- a/lib/gitlab/audit/null_author.rb +++ b/lib/gitlab/audit/null_author.rb @@ -14,12 +14,12 @@ module Gitlab # @param [Integer] id # @param [String] name # - # @return [Gitlab::Audit::UnauthenticatedAuthor, Gitlab::Audit::DeletedAuthor, Gitlab::Audit::RunnerRegistrationTokenAuthor] + # @return [Gitlab::Audit::UnauthenticatedAuthor, Gitlab::Audit::DeletedAuthor, Gitlab::Audit::CiRunnerTokenAuthor] def self.for(id, audit_event) name = audit_event[:author_name] || audit_event.details[:author_name] if audit_event.details.include?(:runner_registration_token) - ::Gitlab::Audit::RunnerRegistrationTokenAuthor.new( + ::Gitlab::Audit::CiRunnerTokenAuthor.new( token: audit_event.details[:runner_registration_token], entity_type: audit_event.entity_type || audit_event.details[:entity_type], entity_path: audit_event.entity_path || audit_event.details[:entity_path] diff --git a/lib/gitlab/ssh_public_key.rb b/lib/gitlab/ssh_public_key.rb index 677a2cef73f..8a2f3bbe0ee 100644 --- a/lib/gitlab/ssh_public_key.rb +++ b/lib/gitlab/ssh_public_key.rb @@ -10,7 +10,9 @@ module Gitlab Technology.new(:rsa, SSHData::PublicKey::RSA, [1024, 2048, 3072, 4096], %w(ssh-rsa)), Technology.new(:dsa, SSHData::PublicKey::DSA, [1024, 2048, 3072], %w(ssh-dss)), Technology.new(:ecdsa, SSHData::PublicKey::ECDSA, [256, 384, 521], %w(ecdsa-sha2-nistp256 ecdsa-sha2-nistp384 ecdsa-sha2-nistp521)), - Technology.new(:ed25519, SSHData::PublicKey::ED25519, [256], %w(ssh-ed25519)) + Technology.new(:ed25519, SSHData::PublicKey::ED25519, [256], %w(ssh-ed25519)), + Technology.new(:ecdsa_sk, SSHData::PublicKey::SKECDSA, [256], %w(sk-ecdsa-sha2-nistp256@openssh.com)), + Technology.new(:ed25519_sk, SSHData::PublicKey::SKED25519, [256], %w(sk-ssh-ed25519@openssh.com)) ].freeze def self.technology(name) @@ -98,6 +100,10 @@ module Gitlab key.openssl.group.order.num_bits when :ed25519 256 + when :ecdsa_sk + 256 + when :ed25519_sk + 256 end end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index a52f514af33..d2a5afa4ad8 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -510,6 +510,12 @@ msgstr[1] "" msgid "%{completedWeight} of %{totalWeight} weight completed" msgstr "" +msgid "%{completed} of %{total} issues closed" +msgstr "" + +msgid "%{completed} of %{total} weight completed" +msgstr "" + msgid "%{cores} cores" msgstr "" @@ -858,6 +864,9 @@ msgstr "" msgid "%{openedIssues} open, %{closedIssues} closed" msgstr "" +msgid "%{percentage}%% issues closed" +msgstr "" + msgid "%{percentage}%% weight completed" msgstr "" @@ -1287,6 +1296,9 @@ msgid_plural "- Users" msgstr[0] "" msgstr[1] "" +msgid "- of - issues closed" +msgstr "" + msgid "- of - weight completed" msgstr "" @@ -27709,6 +27721,9 @@ msgstr "" msgid "Progress" msgstr "" +msgid "Progress tracking" +msgstr "" + msgid "Project" msgstr "" @@ -38998,6 +39013,12 @@ msgstr "" msgid "Use hashed storage paths for newly created and renamed repositories. Always enabled since 13.0." msgstr "" +msgid "Use issue count" +msgstr "" + +msgid "Use issue weight" +msgstr "" + msgid "Use one line per URI" msgstr "" diff --git a/spec/factories/keys.rb b/spec/factories/keys.rb index cf52e772ae0..bedfa71207f 100644 --- a/spec/factories/keys.rb +++ b/spec/factories/keys.rb @@ -148,5 +148,24 @@ FactoryBot.define do KEY end end + + factory :ecdsa_sk_key_256 do + key do + <<~KEY.delete("\n") + sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyN + TZAb3BlbnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBDZ+f5tSRhlB7EN39f93SscTN5PUv + bD3UQsNrlE1ZdbwPMMRul2zlPiUvwAvnJitW0jlD/vwZOW2YN+q+iZ5c0MAAAAEc3NoOg== dummy@gitlab.com + KEY + end + end + + factory :ed25519_sk_key_256 do + key do + <<~KEY.delete("\n") + sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tA + AAAIEX/dQ0v4127bEo8eeG1EV0ApO2lWbSnN6RWusn/NjqIAAAABHNzaDo= dummy@gitlab.com + KEY + end + end end end diff --git a/spec/features/admin/admin_settings_spec.rb b/spec/features/admin/admin_settings_spec.rb index 21ef56f4ae4..aa396d10074 100644 --- a/spec/features/admin/admin_settings_spec.rb +++ b/spec/features/admin/admin_settings_spec.rb @@ -85,6 +85,8 @@ RSpec.describe 'Admin updates settings' do select 'Are allowed', from: 'DSA SSH keys' select 'Must be at least 384 bits', from: 'ECDSA SSH keys' select 'Are forbidden', from: 'ED25519 SSH keys' + select 'Are forbidden', from: 'ECDSA_SK SSH keys' + select 'Are forbidden', from: 'ED25519_SK SSH keys' click_on 'Save changes' end @@ -95,6 +97,8 @@ RSpec.describe 'Admin updates settings' do expect(find_field('DSA SSH keys').value).to eq('0') expect(find_field('ECDSA SSH keys').value).to eq('384') expect(find_field('ED25519 SSH keys').value).to eq(forbidden) + expect(find_field('ECDSA_SK SSH keys').value).to eq(forbidden) + expect(find_field('ED25519_SK SSH keys').value).to eq(forbidden) end it 'change Account and Limit Settings' do diff --git a/spec/features/profiles/keys_spec.rb b/spec/features/profiles/keys_spec.rb index b9e59a0239b..fde85a731a1 100644 --- a/spec/features/profiles/keys_spec.rb +++ b/spec/features/profiles/keys_spec.rb @@ -49,7 +49,12 @@ RSpec.describe 'Profile > SSH Keys' do context 'when only DSA and ECDSA keys are allowed' do before do forbidden = ApplicationSetting::FORBIDDEN_KEY_VALUE - stub_application_setting(rsa_key_restriction: forbidden, ed25519_key_restriction: forbidden) + stub_application_setting( + rsa_key_restriction: forbidden, + ed25519_key_restriction: forbidden, + ecdsa_sk_key_restriction: forbidden, + ed25519_sk_key_restriction: forbidden + ) end it 'shows a validation error' do diff --git a/spec/frontend/security_configuration/components/training_provider_list_spec.js b/spec/frontend/security_configuration/components/training_provider_list_spec.js index f225c135d49..ef850c33d6e 100644 --- a/spec/frontend/security_configuration/components/training_provider_list_spec.js +++ b/spec/frontend/security_configuration/components/training_provider_list_spec.js @@ -1,3 +1,4 @@ +import * as Sentry from '@sentry/browser'; import { GlAlert, GlLink, GlToggle, GlCard, GlSkeletonLoader } from '@gitlab/ui'; import { shallowMount } from '@vue/test-utils'; import Vue from 'vue'; @@ -6,8 +7,11 @@ import createMockApollo from 'helpers/mock_apollo_helper'; import TrainingProviderList from '~/security_configuration/components/training_provider_list.vue'; import securityTrainingProvidersQuery from '~/security_configuration/graphql/security_training_providers.query.graphql'; import configureSecurityTrainingProvidersMutation from '~/security_configuration/graphql/configure_security_training_providers.mutation.graphql'; +import dismissUserCalloutMutation from '~/graphql_shared/mutations/dismiss_user_callout.mutation.graphql'; import waitForPromises from 'helpers/wait_for_promises'; import { + dismissUserCalloutResponse, + dismissUserCalloutErrorResponse, securityTrainingProviders, securityTrainingProvidersResponse, testProjectPath, @@ -20,13 +24,18 @@ describe('TrainingProviderList component', () => { let wrapper; let apolloProvider; - const createApolloProvider = ({ resolvers, queryHandler } = {}) => { - const defaultQueryHandler = jest.fn().mockResolvedValue(securityTrainingProvidersResponse); + const createApolloProvider = ({ resolvers, handlers = [] } = {}) => { + const defaultHandlers = [ + [ + securityTrainingProvidersQuery, + jest.fn().mockResolvedValue(securityTrainingProvidersResponse), + ], + ]; - apolloProvider = createMockApollo( - [[securityTrainingProvidersQuery, queryHandler || defaultQueryHandler]], - resolvers, - ); + // make sure we don't have any duplicate handlers to avoid 'Request handler already defined for query` errors + const mergedHandlers = [...new Map([...defaultHandlers, ...handlers])]; + + apolloProvider = createMockApollo(mergedHandlers, resolvers); }; const createComponent = () => { @@ -60,7 +69,7 @@ describe('TrainingProviderList component', () => { const pendingHandler = () => new Promise(() => {}); createApolloProvider({ - queryHandler: pendingHandler, + handlers: [[securityTrainingProvidersQuery, pendingHandler]], }); createComponent(); }); @@ -76,7 +85,20 @@ describe('TrainingProviderList component', () => { describe('with a successful response', () => { beforeEach(() => { - createApolloProvider(); + createApolloProvider({ + handlers: [ + [dismissUserCalloutMutation, jest.fn().mockResolvedValue(dismissUserCalloutResponse)], + ], + resolvers: { + Mutation: { + configureSecurityTrainingProviders: () => ({ + errors: [], + securityTrainingProviders: [], + }), + }, + }, + }); + createComponent(); }); @@ -143,6 +165,37 @@ describe('TrainingProviderList component', () => { }), ); }); + + it('dismisses the callout when the feature gets first enabled', async () => { + // wait for configuration update mutation to complete + await waitForMutationToBeLoaded(); + + // both the config and dismiss mutations have been called + expect(apolloProvider.defaultClient.mutate).toHaveBeenCalledTimes(2); + expect(apolloProvider.defaultClient.mutate).toHaveBeenNthCalledWith( + 2, + expect.objectContaining({ + mutation: dismissUserCalloutMutation, + variables: { + input: { + featureName: 'security_training_feature_promotion', + }, + }, + }), + ); + + toggleFirstProvider(); + await waitForMutationToBeLoaded(); + + // the config mutation has been called again but not the dismiss mutation + expect(apolloProvider.defaultClient.mutate).toHaveBeenCalledTimes(3); + expect(apolloProvider.defaultClient.mutate).toHaveBeenNthCalledWith( + 3, + expect.objectContaining({ + mutation: configureSecurityTrainingProvidersMutation, + }), + ); + }); }); }); @@ -157,7 +210,7 @@ describe('TrainingProviderList component', () => { describe('when fetching training providers', () => { beforeEach(async () => { createApolloProvider({ - queryHandler: jest.fn().mockReturnValue(new Error()), + handlers: [[securityTrainingProvidersQuery, jest.fn().mockRejectedValue()]], }); createComponent(); @@ -200,5 +253,39 @@ describe('TrainingProviderList component', () => { expect(findErrorAlert().text()).toBe(TrainingProviderList.i18n.configMutationErrorMessage); }); }); + + describe.each` + errorType | mutationHandler + ${'backend error'} | ${jest.fn().mockReturnValue(dismissUserCalloutErrorResponse)} + ${'network error'} | ${jest.fn().mockRejectedValue()} + `('when dismissing the callout and a "$errorType" happens', ({ mutationHandler }) => { + beforeEach(async () => { + jest.spyOn(Sentry, 'captureException').mockImplementation(); + + createApolloProvider({ + handlers: [[dismissUserCalloutMutation, mutationHandler]], + resolvers: { + Mutation: { + configureSecurityTrainingProviders: () => ({ + errors: [], + securityTrainingProviders: [], + }), + }, + }, + }); + createComponent(); + + await waitForQueryToBeLoaded(); + toggleFirstProvider(); + }); + + it('logs the error to sentry', async () => { + expect(Sentry.captureException).not.toHaveBeenCalled(); + + await waitForMutationToBeLoaded(); + + expect(Sentry.captureException).toHaveBeenCalled(); + }); + }); }); }); diff --git a/spec/frontend/security_configuration/mock_data.js b/spec/frontend/security_configuration/mock_data.js index 07c292020a3..e47a255fbac 100644 --- a/spec/frontend/security_configuration/mock_data.js +++ b/spec/frontend/security_configuration/mock_data.js @@ -27,3 +27,27 @@ export const securityTrainingProvidersResponse = { }, }, }; + +export const dismissUserCalloutResponse = { + data: { + userCalloutCreate: { + errors: [], + userCallout: { + dismissedAt: '2022-02-02T04:36:57Z', + featureName: 'SECURITY_TRAINING_FEATURE_PROMOTION', + }, + }, + }, +}; + +export const dismissUserCalloutErrorResponse = { + data: { + userCalloutCreate: { + errors: ['Something went wrong'], + userCallout: { + dismissedAt: '', + featureName: 'SECURITY_TRAINING_FEATURE_PROMOTION', + }, + }, + }, +}; diff --git a/spec/helpers/ssh_keys_helper_spec.rb b/spec/helpers/ssh_keys_helper_spec.rb index 1aa604f19be..522331090e4 100644 --- a/spec/helpers/ssh_keys_helper_spec.rb +++ b/spec/helpers/ssh_keys_helper_spec.rb @@ -17,9 +17,9 @@ RSpec.describe SshKeysHelper do end it 'returns only allowed algorithms' do - expect(ssh_key_allowed_algorithms).to match('ed25519') - stub_application_setting(ed25519_key_restriction: ApplicationSetting::FORBIDDEN_KEY_VALUE) - expect(ssh_key_allowed_algorithms).not_to match('ed25519') + expect(ssh_key_allowed_algorithms).to match('rsa') + stub_application_setting(rsa_key_restriction: ApplicationSetting::FORBIDDEN_KEY_VALUE) + expect(ssh_key_allowed_algorithms).not_to match('rsa') end end end diff --git a/spec/lib/gitlab/audit/runner_registration_token_author_spec.rb b/spec/lib/gitlab/audit/ci_runner_token_author_spec.rb index 1c26b7b5857..4d2356fc58e 100644 --- a/spec/lib/gitlab/audit/runner_registration_token_author_spec.rb +++ b/spec/lib/gitlab/audit/ci_runner_token_author_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::Audit::RunnerRegistrationTokenAuthor do +RSpec.describe Gitlab::Audit::CiRunnerTokenAuthor do describe '#initialize' do it 'sets correct attributes' do expect(described_class.new(token: 'abc1234567', entity_type: 'Project', entity_path: 'd/e')) diff --git a/spec/lib/gitlab/audit/null_author_spec.rb b/spec/lib/gitlab/audit/null_author_spec.rb index 8bbe75b10d7..51e4a744111 100644 --- a/spec/lib/gitlab/audit/null_author_spec.rb +++ b/spec/lib/gitlab/audit/null_author_spec.rb @@ -23,14 +23,14 @@ RSpec.describe Gitlab::Audit::NullAuthor do expect(subject.for(-1, audit_event)).to have_attributes(id: -1, name: 'Frank') end - it 'returns an RunnerRegistrationTokenAuthor when details contain runner registration token', :aggregate_failures do + it 'returns a CiRunnerTokenAuthor when details contain runner registration token', :aggregate_failures do allow(audit_event).to receive(:[]).with(:author_name).and_return('cde456') allow(audit_event).to receive(:entity_type).and_return('User') allow(audit_event).to receive(:entity_path).and_return('/a/b') allow(audit_event).to receive(:details) .and_return({ runner_registration_token: 'cde456', author_name: 'cde456', entity_type: 'User', entity_path: '/a/b' }) - expect(subject.for(-1, audit_event)).to be_a(Gitlab::Audit::RunnerRegistrationTokenAuthor) + expect(subject.for(-1, audit_event)).to be_a(Gitlab::Audit::CiRunnerTokenAuthor) expect(subject.for(-1, audit_event)).to have_attributes(id: -1, name: 'Registration token: cde456') end end diff --git a/spec/lib/gitlab/ssh_public_key_spec.rb b/spec/lib/gitlab/ssh_public_key_spec.rb index 131cf572308..cf5d2c3b455 100644 --- a/spec/lib/gitlab/ssh_public_key_spec.rb +++ b/spec/lib/gitlab/ssh_public_key_spec.rb @@ -12,7 +12,7 @@ RSpec.describe Gitlab::SSHPublicKey, lib: true do end where(:name) do - [:rsa, :dsa, :ecdsa, :ed25519] + [:rsa, :dsa, :ecdsa, :ed25519, :ecdsa_sk, :ed25519_sk] end with_them do @@ -24,7 +24,7 @@ RSpec.describe Gitlab::SSHPublicKey, lib: true do describe '.supported_types' do it 'returns array with the names of supported technologies' do expect(described_class.supported_types).to eq( - [:rsa, :dsa, :ecdsa, :ed25519] + [:rsa, :dsa, :ecdsa, :ed25519, :ecdsa_sk, :ed25519_sk] ) end end @@ -35,7 +35,9 @@ RSpec.describe Gitlab::SSHPublicKey, lib: true do [:rsa, [1024, 2048, 3072, 4096]], [:dsa, [1024, 2048, 3072]], [:ecdsa, [256, 384, 521]], - [:ed25519, [256]] + [:ed25519, [256]], + [:ecdsa_sk, [256]], + [:ed25519_sk, [256]] ] end @@ -53,6 +55,8 @@ RSpec.describe Gitlab::SSHPublicKey, lib: true do ssh-dss ecdsa-sha2-nistp256 ecdsa-sha2-nistp384 ecdsa-sha2-nistp521 ssh-ed25519 + sk-ecdsa-sha2-nistp256@openssh.com + sk-ssh-ed25519@openssh.com ) ) end @@ -64,7 +68,9 @@ RSpec.describe Gitlab::SSHPublicKey, lib: true do [:rsa, %w(ssh-rsa)], [:dsa, %w(ssh-dss)], [:ecdsa, %w(ecdsa-sha2-nistp256 ecdsa-sha2-nistp384 ecdsa-sha2-nistp521)], - [:ed25519, %w(ssh-ed25519)] + [:ed25519, %w(ssh-ed25519)], + [:ecdsa_sk, %w(sk-ecdsa-sha2-nistp256@openssh.com)], + [:ed25519_sk, %w(sk-ssh-ed25519@openssh.com)] ] end @@ -122,7 +128,9 @@ RSpec.describe Gitlab::SSHPublicKey, lib: true do rsa_key_8192 dsa_key_2048 ecdsa_key_256 - ed25519_key_256) + ed25519_key_256 + ecdsa_sk_key_256 + ed25519_sk_key_256) end with_them do @@ -201,7 +209,9 @@ RSpec.describe Gitlab::SSHPublicKey, lib: true do [:rsa_key_2048, :rsa], [:dsa_key_2048, :dsa], [:ecdsa_key_256, :ecdsa], - [:ed25519_key_256, :ed25519] + [:ed25519_key_256, :ed25519], + [:ecdsa_sk_key_256, :ecdsa_sk], + [:ed25519_sk_key_256, :ed25519_sk] ] end @@ -231,7 +241,9 @@ RSpec.describe Gitlab::SSHPublicKey, lib: true do [:rsa_key_8192, 8192], [:dsa_key_2048, 2048], [:ecdsa_key_256, 256], - [:ed25519_key_256, 256] + [:ed25519_key_256, 256], + [:ecdsa_sk_key_256, 256], + [:ed25519_sk_key_256, 256] ] end @@ -261,7 +273,9 @@ RSpec.describe Gitlab::SSHPublicKey, lib: true do [:rsa_key_8192, 'fb:53:7f:e9:2f:f7:17:aa:c8:32:52:06:8e:05:e2:82'], [:dsa_key_2048, 'c8:85:1e:df:44:0f:20:00:3c:66:57:2b:21:10:5a:27'], [:ecdsa_key_256, '67:a3:a9:7d:b8:e1:15:d4:80:40:21:34:bb:ed:97:38'], - [:ed25519_key_256, 'e6:eb:45:8a:3c:59:35:5f:e9:5b:80:12:be:7e:22:73'] + [:ed25519_key_256, 'e6:eb:45:8a:3c:59:35:5f:e9:5b:80:12:be:7e:22:73'], + [:ecdsa_sk_key_256, '56:b9:bc:99:3d:2f:cf:63:6b:70:d8:f9:40:7e:09:4c'], + [:ed25519_sk_key_256, 'f9:a0:64:0b:4b:72:72:0e:62:92:d7:04:14:74:1c:c9'] ] end @@ -289,7 +303,9 @@ RSpec.describe Gitlab::SSHPublicKey, lib: true do [:rsa_key_8192, 'SHA256:CtHFQAS+9Hb8z4vrv4gVQPsHjNN0WIZhWODaB1mQLs4'], [:dsa_key_2048, 'SHA256:+a3DQ7cU5GM+gaYOfmc0VWNnykHQSuth3VRcCpWuYNI'], [:ecdsa_key_256, 'SHA256:C+I5k3D+IGeM6k5iBR1ZsphqTKV+7uvL/XZ5hcrTr7g'], - [:ed25519_key_256, 'SHA256:DCKAjzxWrdOTjaGKBBjtCW8qY5++GaiAJflrHPmp6W0'] + [:ed25519_key_256, 'SHA256:DCKAjzxWrdOTjaGKBBjtCW8qY5++GaiAJflrHPmp6W0'], + [:ecdsa_sk_key_256, 'SHA256:N0sNKBgWKK8usPuPegtgzHQQA9vQ/dRhAEhwFDAnLA4'], + [:ed25519_sk_key_256, 'SHA256:U8IKRkIHed6vFMTflwweA3HhIf2DWgZ8EFTm9fgwOUk'] ] end diff --git a/spec/models/audit_event_spec.rb b/spec/models/audit_event_spec.rb index ddf52582dbf..957813ec3a0 100644 --- a/spec/models/audit_event_spec.rb +++ b/spec/models/audit_event_spec.rb @@ -112,13 +112,13 @@ RSpec.describe AuditEvent do context "when a runner_registration_token's present" do let(:audit_event) { build(:project_audit_event, details: { target_id: 678, runner_registration_token: 'abc123' }) } - it 'returns a RunnerRegistrationTokenAuthor' do - expect(::Gitlab::Audit::RunnerRegistrationTokenAuthor).to receive(:new) + it 'returns a CiRunnerTokenAuthor' do + expect(::Gitlab::Audit::CiRunnerTokenAuthor).to receive(:new) .with({ token: 'abc123', entity_type: 'Project', entity_path: audit_event.entity_path }) .and_call_original .once - is_expected.to be_an_instance_of(::Gitlab::Audit::RunnerRegistrationTokenAuthor) + is_expected.to be_an_instance_of(::Gitlab::Audit::CiRunnerTokenAuthor) end it 'name consists of prefix and token' do diff --git a/spec/models/key_spec.rb b/spec/models/key_spec.rb index 19459561edf..6cf73de6cef 100644 --- a/spec/models/key_spec.rb +++ b/spec/models/key_spec.rb @@ -20,6 +20,8 @@ RSpec.describe Key, :mailer do it { is_expected.to allow_value(attributes_for(:dsa_key_2048)[:key]).for(:key) } it { is_expected.to allow_value(attributes_for(:ecdsa_key_256)[:key]).for(:key) } it { is_expected.to allow_value(attributes_for(:ed25519_key_256)[:key]).for(:key) } + it { is_expected.to allow_value(attributes_for(:ecdsa_sk_key_256)[:key]).for(:key) } + it { is_expected.to allow_value(attributes_for(:ed25519_sk_key_256)[:key]).for(:key) } it { is_expected.not_to allow_value('foo-bar').for(:key) } context 'key format' do @@ -187,10 +189,12 @@ RSpec.describe Key, :mailer do forbidden = ApplicationSetting::FORBIDDEN_KEY_VALUE [ - [:rsa_key_2048, 0, true], - [:dsa_key_2048, 0, true], - [:ecdsa_key_256, 0, true], - [:ed25519_key_256, 0, true], + [:rsa_key_2048, 0, true], + [:dsa_key_2048, 0, true], + [:ecdsa_key_256, 0, true], + [:ed25519_key_256, 0, true], + [:ecdsa_sk_key_256, 0, true], + [:ed25519_sk_key_256, 0, true], [:rsa_key_2048, 1024, true], [:rsa_key_2048, 2048, true], @@ -206,10 +210,18 @@ RSpec.describe Key, :mailer do [:ed25519_key_256, 256, true], [:ed25519_key_256, 384, false], - [:rsa_key_2048, forbidden, false], - [:dsa_key_2048, forbidden, false], - [:ecdsa_key_256, forbidden, false], - [:ed25519_key_256, forbidden, false] + [:ecdsa_sk_key_256, 256, true], + [:ecdsa_sk_key_256, 384, false], + + [:ed25519_sk_key_256, 256, true], + [:ed25519_sk_key_256, 384, false], + + [:rsa_key_2048, forbidden, false], + [:dsa_key_2048, forbidden, false], + [:ecdsa_key_256, forbidden, false], + [:ed25519_key_256, forbidden, false], + [:ecdsa_sk_key_256, forbidden, false], + [:ed25519_sk_key_256, forbidden, false] ] end diff --git a/spec/requests/api/settings_spec.rb b/spec/requests/api/settings_spec.rb index 7e940d52a41..ea7fee1c6f0 100644 --- a/spec/requests/api/settings_spec.rb +++ b/spec/requests/api/settings_spec.rb @@ -32,6 +32,8 @@ RSpec.describe API::Settings, 'Settings', :do_not_mock_admin_mode_setting do expect(json_response['dsa_key_restriction']).to eq(0) expect(json_response['ecdsa_key_restriction']).to eq(0) expect(json_response['ed25519_key_restriction']).to eq(0) + expect(json_response['ecdsa_sk_key_restriction']).to eq(0) + expect(json_response['ed25519_sk_key_restriction']).to eq(0) expect(json_response['performance_bar_allowed_group_id']).to be_nil expect(json_response['allow_local_requests_from_hooks_and_services']).to be(false) expect(json_response['allow_local_requests_from_web_hooks_and_services']).to be(false) @@ -111,6 +113,8 @@ RSpec.describe API::Settings, 'Settings', :do_not_mock_admin_mode_setting do dsa_key_restriction: 2048, ecdsa_key_restriction: 384, ed25519_key_restriction: 256, + ecdsa_sk_key_restriction: 256, + ed25519_sk_key_restriction: 256, enforce_terms: true, terms: 'Hello world!', performance_bar_allowed_group_path: group.full_path, @@ -163,6 +167,8 @@ RSpec.describe API::Settings, 'Settings', :do_not_mock_admin_mode_setting do expect(json_response['dsa_key_restriction']).to eq(2048) expect(json_response['ecdsa_key_restriction']).to eq(384) expect(json_response['ed25519_key_restriction']).to eq(256) + expect(json_response['ecdsa_sk_key_restriction']).to eq(256) + expect(json_response['ed25519_sk_key_restriction']).to eq(256) expect(json_response['enforce_terms']).to be(true) expect(json_response['terms']).to eq('Hello world!') expect(json_response['performance_bar_allowed_group_id']).to eq(group.id) diff --git a/spec/views/profiles/keys/_key.html.haml_spec.rb b/spec/views/profiles/keys/_key.html.haml_spec.rb index bb101198ac3..ed8026d2453 100644 --- a/spec/views/profiles/keys/_key.html.haml_spec.rb +++ b/spec/views/profiles/keys/_key.html.haml_spec.rb @@ -90,8 +90,8 @@ RSpec.describe 'profiles/keys/_key.html.haml' do using RSpec::Parameterized::TableSyntax where(:valid, :expiry, :result) do - false | 2.days.from_now | 'Key type is forbidden. Must be DSA, ECDSA, or ED25519' - false | 2.days.ago | 'Key type is forbidden. Must be DSA, ECDSA, or ED25519' + false | 2.days.from_now | 'Key type is forbidden. Must be DSA, ECDSA, ED25519, ECDSA_SK, or ED25519_SK' + false | 2.days.ago | 'Key type is forbidden. Must be DSA, ECDSA, ED25519, ECDSA_SK, or ED25519_SK' true | 2.days.ago | 'Key usable beyond expiration date.' true | 2.days.from_now | '' end diff --git a/spec/workers/loose_foreign_keys/cleanup_worker_spec.rb b/spec/workers/loose_foreign_keys/cleanup_worker_spec.rb index 497f95cf34d..6f4389a7541 100644 --- a/spec/workers/loose_foreign_keys/cleanup_worker_spec.rb +++ b/spec/workers/loose_foreign_keys/cleanup_worker_spec.rb @@ -141,16 +141,6 @@ RSpec.describe LooseForeignKeys::CleanupWorker do end end - context 'when the loose_foreign_key_cleanup feature flag is off' do - before do - stub_feature_flags(loose_foreign_key_cleanup: false) - end - - it 'does nothing' do - expect { described_class.new.perform }.not_to change { LooseForeignKeys::DeletedRecord.status_processed.count } - end - end - describe 'multi-database support' do where(:current_minute, :configured_base_models, :expected_connection) do 2 | { main: ApplicationRecord, ci: Ci::ApplicationRecord } | ApplicationRecord.connection |