Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
7580728fc2
commit
bcd0f3a2f6
18 changed files with 624 additions and 91 deletions
|
@ -16,15 +16,23 @@
|
|||
- source scripts/utils.sh
|
||||
- source scripts/prepare_build.sh
|
||||
|
||||
.rails-cache:
|
||||
.setup-test-env-cache:
|
||||
cache:
|
||||
key: "rails-v3"
|
||||
key: "setup-test-env-v1"
|
||||
paths:
|
||||
- vendor/ruby/
|
||||
- vendor/gitaly-ruby/
|
||||
- .go/pkg/mod/
|
||||
policy: pull
|
||||
|
||||
.rails-cache:
|
||||
cache:
|
||||
key: "rails-v4"
|
||||
paths:
|
||||
- vendor/ruby/
|
||||
- vendor/gitaly-ruby/
|
||||
policy: pull
|
||||
|
||||
.static-analysis-cache:
|
||||
cache:
|
||||
key: "static-analysis-v2"
|
||||
|
|
|
@ -141,6 +141,7 @@
|
|||
setup-test-env:
|
||||
extends:
|
||||
- .rails-job-base
|
||||
- .setup-test-env-cache
|
||||
- .rails:rules:default-refs-code-backstage-qa
|
||||
- .use-pg11
|
||||
stage: prepare
|
||||
|
@ -180,14 +181,20 @@ setup-test-env:
|
|||
- tmp/tests/second_storage/
|
||||
when: always
|
||||
|
||||
update-rails-cache:
|
||||
update-setup-test-env-cache:
|
||||
extends:
|
||||
- setup-test-env
|
||||
- .shared:rules:update-cache
|
||||
artifacts: {} # This job's purpose is only to update the cache.
|
||||
artifacts:
|
||||
paths: [] # This job's purpose is only to update the cache.
|
||||
cache:
|
||||
policy: push # We want to rebuild the cache from scratch to ensure stale dependencies are cleaned up.
|
||||
|
||||
update-rails-cache:
|
||||
extends:
|
||||
- update-setup-test-env-cache
|
||||
- .rails-cache
|
||||
|
||||
.coverage-base:
|
||||
extends:
|
||||
- .default-retry
|
||||
|
|
|
@ -1 +1 @@
|
|||
aeec1e34a8f0fc6b453b7f091e3712f17956b580
|
||||
827531393ddfbafcdd89c09f1798772f6f087ba8
|
||||
|
|
|
@ -26,7 +26,7 @@ class ApplicationExperiment < Gitlab::Experiment
|
|||
private
|
||||
|
||||
def resolve_variant_name
|
||||
return variant_names.first if Feature.enabled?(name, self, type: :experiment)
|
||||
return variant_names.first if Feature.enabled?(name, self, type: :experiment, default_enabled: :yaml)
|
||||
|
||||
nil # Returning nil vs. :control is important for not caching and rollouts.
|
||||
end
|
||||
|
|
5
changelogs/unreleased/reset-admin-password-rake-task.yml
Normal file
5
changelogs/unreleased/reset-admin-password-rake-task.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add rake task to reset user password
|
||||
merge_request: 52347
|
||||
author:
|
||||
type: added
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
name: deploy_tokens_api
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/25219
|
||||
rollout_issue_url:
|
||||
milestone: '12.9'
|
||||
type: development
|
||||
group: group::package
|
||||
default_enabled: true
|
|
@ -5502,6 +5502,81 @@ type DastOnDemandScanCreatePayload {
|
|||
pipelineUrl: String
|
||||
}
|
||||
|
||||
"""
|
||||
Represents a DAST Profile
|
||||
"""
|
||||
type DastProfile {
|
||||
"""
|
||||
The associated scanner profile.
|
||||
"""
|
||||
dastScannerProfile: DastScannerProfile
|
||||
|
||||
"""
|
||||
The associated site profile.
|
||||
"""
|
||||
dastSiteProfile: DastSiteProfile
|
||||
|
||||
"""
|
||||
The description of the scan.
|
||||
"""
|
||||
description: String
|
||||
|
||||
"""
|
||||
Relative web path to the edit page of a profile.
|
||||
"""
|
||||
editPath: String
|
||||
|
||||
"""
|
||||
ID of the profile.
|
||||
"""
|
||||
id: DastProfileID!
|
||||
|
||||
"""
|
||||
The name of the profile.
|
||||
"""
|
||||
name: String
|
||||
}
|
||||
|
||||
"""
|
||||
The connection type for DastProfile.
|
||||
"""
|
||||
type DastProfileConnection {
|
||||
"""
|
||||
A list of edges.
|
||||
"""
|
||||
edges: [DastProfileEdge]
|
||||
|
||||
"""
|
||||
A list of nodes.
|
||||
"""
|
||||
nodes: [DastProfile]
|
||||
|
||||
"""
|
||||
Information to aid in pagination.
|
||||
"""
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
"""
|
||||
An edge in a connection.
|
||||
"""
|
||||
type DastProfileEdge {
|
||||
"""
|
||||
A cursor for use in pagination.
|
||||
"""
|
||||
cursor: String!
|
||||
|
||||
"""
|
||||
The item at the end of the edge.
|
||||
"""
|
||||
node: DastProfile
|
||||
}
|
||||
|
||||
"""
|
||||
Identifier of Dast::Profile.
|
||||
"""
|
||||
scalar DastProfileID
|
||||
|
||||
enum DastScanTypeEnum {
|
||||
"""
|
||||
Active DAST scan. This scan will make active attacks against the target site.
|
||||
|
@ -18195,7 +18270,32 @@ type Project {
|
|||
createdAt: Time
|
||||
|
||||
"""
|
||||
The DAST scanner profiles associated with the project
|
||||
DAST Profiles associated with the project. Always returns no nodes if `dast_saved_scans` is disabled.
|
||||
"""
|
||||
dastProfiles(
|
||||
"""
|
||||
Returns the elements in the list that come after the specified cursor.
|
||||
"""
|
||||
after: String
|
||||
|
||||
"""
|
||||
Returns the elements in the list that come before the specified cursor.
|
||||
"""
|
||||
before: String
|
||||
|
||||
"""
|
||||
Returns the first _n_ elements from the list.
|
||||
"""
|
||||
first: Int
|
||||
|
||||
"""
|
||||
Returns the last _n_ elements from the list.
|
||||
"""
|
||||
last: Int
|
||||
): DastProfileConnection
|
||||
|
||||
"""
|
||||
The DAST scanner profiles associated with the project.
|
||||
"""
|
||||
dastScannerProfiles(
|
||||
"""
|
||||
|
@ -18220,7 +18320,7 @@ type Project {
|
|||
): DastScannerProfileConnection
|
||||
|
||||
"""
|
||||
DAST Site Profile associated with the project
|
||||
DAST Site Profile associated with the project.
|
||||
"""
|
||||
dastSiteProfile(
|
||||
"""
|
||||
|
@ -18230,7 +18330,7 @@ type Project {
|
|||
): DastSiteProfile
|
||||
|
||||
"""
|
||||
DAST Site Profiles associated with the project
|
||||
DAST Site Profiles associated with the project.
|
||||
"""
|
||||
dastSiteProfiles(
|
||||
"""
|
||||
|
@ -18255,8 +18355,8 @@ type Project {
|
|||
): DastSiteProfileConnection
|
||||
|
||||
"""
|
||||
DAST Site Validations associated with the project. Will always return no nodes
|
||||
if `security_on_demand_scans_site_validation` is disabled
|
||||
DAST Site Validations associated with the project. Always returns no nodes if
|
||||
`security_on_demand_scans_site_validation` is disabled.
|
||||
"""
|
||||
dastSiteValidations(
|
||||
"""
|
||||
|
|
|
@ -15047,6 +15047,229 @@
|
|||
"enumValues": null,
|
||||
"possibleTypes": null
|
||||
},
|
||||
{
|
||||
"kind": "OBJECT",
|
||||
"name": "DastProfile",
|
||||
"description": "Represents a DAST Profile",
|
||||
"fields": [
|
||||
{
|
||||
"name": "dastScannerProfile",
|
||||
"description": "The associated scanner profile.",
|
||||
"args": [
|
||||
|
||||
],
|
||||
"type": {
|
||||
"kind": "OBJECT",
|
||||
"name": "DastScannerProfile",
|
||||
"ofType": null
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "dastSiteProfile",
|
||||
"description": "The associated site profile.",
|
||||
"args": [
|
||||
|
||||
],
|
||||
"type": {
|
||||
"kind": "OBJECT",
|
||||
"name": "DastSiteProfile",
|
||||
"ofType": null
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "description",
|
||||
"description": "The description of the scan.",
|
||||
"args": [
|
||||
|
||||
],
|
||||
"type": {
|
||||
"kind": "SCALAR",
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "editPath",
|
||||
"description": "Relative web path to the edit page of a profile.",
|
||||
"args": [
|
||||
|
||||
],
|
||||
"type": {
|
||||
"kind": "SCALAR",
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "id",
|
||||
"description": "ID of the profile.",
|
||||
"args": [
|
||||
|
||||
],
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "SCALAR",
|
||||
"name": "DastProfileID",
|
||||
"ofType": null
|
||||
}
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "name",
|
||||
"description": "The name of the profile.",
|
||||
"args": [
|
||||
|
||||
],
|
||||
"type": {
|
||||
"kind": "SCALAR",
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
}
|
||||
],
|
||||
"inputFields": null,
|
||||
"interfaces": [
|
||||
|
||||
],
|
||||
"enumValues": null,
|
||||
"possibleTypes": null
|
||||
},
|
||||
{
|
||||
"kind": "OBJECT",
|
||||
"name": "DastProfileConnection",
|
||||
"description": "The connection type for DastProfile.",
|
||||
"fields": [
|
||||
{
|
||||
"name": "edges",
|
||||
"description": "A list of edges.",
|
||||
"args": [
|
||||
|
||||
],
|
||||
"type": {
|
||||
"kind": "LIST",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "OBJECT",
|
||||
"name": "DastProfileEdge",
|
||||
"ofType": null
|
||||
}
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "nodes",
|
||||
"description": "A list of nodes.",
|
||||
"args": [
|
||||
|
||||
],
|
||||
"type": {
|
||||
"kind": "LIST",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "OBJECT",
|
||||
"name": "DastProfile",
|
||||
"ofType": null
|
||||
}
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "pageInfo",
|
||||
"description": "Information to aid in pagination.",
|
||||
"args": [
|
||||
|
||||
],
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "OBJECT",
|
||||
"name": "PageInfo",
|
||||
"ofType": null
|
||||
}
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
}
|
||||
],
|
||||
"inputFields": null,
|
||||
"interfaces": [
|
||||
|
||||
],
|
||||
"enumValues": null,
|
||||
"possibleTypes": null
|
||||
},
|
||||
{
|
||||
"kind": "OBJECT",
|
||||
"name": "DastProfileEdge",
|
||||
"description": "An edge in a connection.",
|
||||
"fields": [
|
||||
{
|
||||
"name": "cursor",
|
||||
"description": "A cursor for use in pagination.",
|
||||
"args": [
|
||||
|
||||
],
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "SCALAR",
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
}
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "node",
|
||||
"description": "The item at the end of the edge.",
|
||||
"args": [
|
||||
|
||||
],
|
||||
"type": {
|
||||
"kind": "OBJECT",
|
||||
"name": "DastProfile",
|
||||
"ofType": null
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
}
|
||||
],
|
||||
"inputFields": null,
|
||||
"interfaces": [
|
||||
|
||||
],
|
||||
"enumValues": null,
|
||||
"possibleTypes": null
|
||||
},
|
||||
{
|
||||
"kind": "SCALAR",
|
||||
"name": "DastProfileID",
|
||||
"description": "Identifier of Dast::Profile.",
|
||||
"fields": null,
|
||||
"inputFields": null,
|
||||
"interfaces": null,
|
||||
"enumValues": null,
|
||||
"possibleTypes": null
|
||||
},
|
||||
{
|
||||
"kind": "ENUM",
|
||||
"name": "DastScanTypeEnum",
|
||||
|
@ -53583,9 +53806,62 @@
|
|||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "dastProfiles",
|
||||
"description": "DAST Profiles associated with the project. Always returns no nodes if `dast_saved_scans` is disabled.",
|
||||
"args": [
|
||||
{
|
||||
"name": "after",
|
||||
"description": "Returns the elements in the list that come after the specified cursor.",
|
||||
"type": {
|
||||
"kind": "SCALAR",
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
},
|
||||
"defaultValue": null
|
||||
},
|
||||
{
|
||||
"name": "before",
|
||||
"description": "Returns the elements in the list that come before the specified cursor.",
|
||||
"type": {
|
||||
"kind": "SCALAR",
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
},
|
||||
"defaultValue": null
|
||||
},
|
||||
{
|
||||
"name": "first",
|
||||
"description": "Returns the first _n_ elements from the list.",
|
||||
"type": {
|
||||
"kind": "SCALAR",
|
||||
"name": "Int",
|
||||
"ofType": null
|
||||
},
|
||||
"defaultValue": null
|
||||
},
|
||||
{
|
||||
"name": "last",
|
||||
"description": "Returns the last _n_ elements from the list.",
|
||||
"type": {
|
||||
"kind": "SCALAR",
|
||||
"name": "Int",
|
||||
"ofType": null
|
||||
},
|
||||
"defaultValue": null
|
||||
}
|
||||
],
|
||||
"type": {
|
||||
"kind": "OBJECT",
|
||||
"name": "DastProfileConnection",
|
||||
"ofType": null
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "dastScannerProfiles",
|
||||
"description": "The DAST scanner profiles associated with the project",
|
||||
"description": "The DAST scanner profiles associated with the project.",
|
||||
"args": [
|
||||
{
|
||||
"name": "after",
|
||||
|
@ -53638,7 +53914,7 @@
|
|||
},
|
||||
{
|
||||
"name": "dastSiteProfile",
|
||||
"description": "DAST Site Profile associated with the project",
|
||||
"description": "DAST Site Profile associated with the project.",
|
||||
"args": [
|
||||
{
|
||||
"name": "id",
|
||||
|
@ -53665,7 +53941,7 @@
|
|||
},
|
||||
{
|
||||
"name": "dastSiteProfiles",
|
||||
"description": "DAST Site Profiles associated with the project",
|
||||
"description": "DAST Site Profiles associated with the project.",
|
||||
"args": [
|
||||
{
|
||||
"name": "after",
|
||||
|
@ -53718,7 +53994,7 @@
|
|||
},
|
||||
{
|
||||
"name": "dastSiteValidations",
|
||||
"description": "DAST Site Validations associated with the project. Will always return no nodes if `security_on_demand_scans_site_validation` is disabled",
|
||||
"description": "DAST Site Validations associated with the project. Always returns no nodes if `security_on_demand_scans_site_validation` is disabled.",
|
||||
"args": [
|
||||
{
|
||||
"name": "normalizedTargetUrls",
|
||||
|
|
|
@ -878,6 +878,19 @@ Autogenerated return type of DastOnDemandScanCreate.
|
|||
| `errors` | String! => Array | Errors encountered during execution of the mutation. |
|
||||
| `pipelineUrl` | String | URL of the pipeline that was created. |
|
||||
|
||||
### DastProfile
|
||||
|
||||
Represents a DAST Profile.
|
||||
|
||||
| Field | Type | Description |
|
||||
| ----- | ---- | ----------- |
|
||||
| `dastScannerProfile` | DastScannerProfile | The associated scanner profile. |
|
||||
| `dastSiteProfile` | DastSiteProfile | The associated site profile. |
|
||||
| `description` | String | The description of the scan. |
|
||||
| `editPath` | String | Relative web path to the edit page of a profile. |
|
||||
| `id` | DastProfileID! | ID of the profile. |
|
||||
| `name` | String | The name of the profile. |
|
||||
|
||||
### DastScannerProfile
|
||||
|
||||
Represents a DAST scanner profile.
|
||||
|
@ -2745,10 +2758,11 @@ Autogenerated return type of PipelineRetry.
|
|||
| `containerRepositories` | ContainerRepositoryConnection | Container repositories of the project |
|
||||
| `containerRepositoriesCount` | Int! | Number of container repositories in the project |
|
||||
| `createdAt` | Time | Timestamp of the project creation |
|
||||
| `dastScannerProfiles` | DastScannerProfileConnection | The DAST scanner profiles associated with the project |
|
||||
| `dastSiteProfile` | DastSiteProfile | DAST Site Profile associated with the project |
|
||||
| `dastSiteProfiles` | DastSiteProfileConnection | DAST Site Profiles associated with the project |
|
||||
| `dastSiteValidations` | DastSiteValidationConnection | DAST Site Validations associated with the project. Will always return no nodes if `security_on_demand_scans_site_validation` is disabled |
|
||||
| `dastProfiles` | DastProfileConnection | DAST Profiles associated with the project. Always returns no nodes if `dast_saved_scans` is disabled. |
|
||||
| `dastScannerProfiles` | DastScannerProfileConnection | The DAST scanner profiles associated with the project. |
|
||||
| `dastSiteProfile` | DastSiteProfile | DAST Site Profile associated with the project. |
|
||||
| `dastSiteProfiles` | DastSiteProfileConnection | DAST Site Profiles associated with the project. |
|
||||
| `dastSiteValidations` | DastSiteValidationConnection | DAST Site Validations associated with the project. Always returns no nodes if `security_on_demand_scans_site_validation` is disabled. |
|
||||
| `description` | String | Short description of the project |
|
||||
| `descriptionHtml` | String | The GitLab Flavored Markdown rendering of `description` |
|
||||
| `environment` | Environment | A single environment of the project |
|
||||
|
|
|
@ -6,7 +6,7 @@ disqus_identifier: 'https://docs.gitlab.com/ee/user/project/pipelines/schedules.
|
|||
type: reference, howto
|
||||
---
|
||||
|
||||
# Pipeline schedules
|
||||
# Pipeline schedules **(FREE)**
|
||||
|
||||
> - Introduced in GitLab 9.1 as [Trigger Schedule](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/10533).
|
||||
> - [Renamed to Pipeline Schedule](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/10853) in GitLab 9.2.
|
||||
|
@ -83,7 +83,7 @@ job:
|
|||
- make build
|
||||
```
|
||||
|
||||
### Advanced configuration
|
||||
### Advanced configuration **(FREE SELF)**
|
||||
|
||||
The pipelines are not executed exactly on schedule because schedules are handled by
|
||||
Sidekiq, which runs according to its interval.
|
||||
|
|
|
@ -493,6 +493,7 @@ request, be sure to start the `dont-interrupt-me` job before pushing.
|
|||
1. We currently have several different caches defined in
|
||||
[`.gitlab/ci/global.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/blob/master/.gitlab/ci/global.gitlab-ci.yml),
|
||||
with fixed keys:
|
||||
- `.setup-test-env-cache`.
|
||||
- `.rails-cache`.
|
||||
- `.static-analysis-cache`.
|
||||
- `.coverage-cache`
|
||||
|
@ -500,6 +501,7 @@ request, be sure to start the `dont-interrupt-me` job before pushing.
|
|||
- `.yarn-cache`.
|
||||
- `.assets-compile-cache` (the key includes `${NODE_ENV}` so it's actually two different caches).
|
||||
1. Only 6 specific jobs, running in 2-hourly scheduled pipelines, are pushing (i.e. updating) to the caches:
|
||||
- `update-setup-test-env-cache`, defined in [`.gitlab/ci/rails.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/blob/master/.gitlab/ci/rails.gitlab-ci.yml).
|
||||
- `update-rails-cache`, defined in [`.gitlab/ci/rails.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/blob/master/.gitlab/ci/rails.gitlab-ci.yml).
|
||||
- `update-static-analysis-cache`, defined in [`.gitlab/ci/rails.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/blob/master/.gitlab/ci/rails.gitlab-ci.yml).
|
||||
- `update-coverage-cache`, defined in [`.gitlab/ci/rails.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/blob/master/.gitlab/ci/rails.gitlab-ci.yml).
|
||||
|
@ -642,6 +644,7 @@ that are scoped to a single [configuration keyword](../ci/yaml/README.md#job-key
|
|||
|------------------|-------------|
|
||||
| `.default-retry` | Allows a job to [retry](../ci/yaml/README.md#retry) upon `unknown_failure`, `api_failure`, `runner_system_failure`, `job_execution_timeout`, or `stuck_or_timeout_failure`. |
|
||||
| `.default-before_script` | Allows a job to use a default `before_script` definition suitable for Ruby/Rails tasks that may need a database running (e.g. tests). |
|
||||
| `.setup-test-env-cache` | Allows a job to use a default `cache` definition suitable for setuping test environment for subsequent Ruby/Rails tasks. |
|
||||
| `.rails-cache` | Allows a job to use a default `cache` definition suitable for Ruby/Rails tasks. |
|
||||
| `.static-analysis-cache` | Allows a job to use a default `cache` definition suitable for static analysis tasks. |
|
||||
| `.coverage-cache` | Allows a job to use a default `cache` definition suitable for coverage tasks. |
|
||||
|
|
|
@ -7,70 +7,91 @@ type: howto
|
|||
|
||||
# How to reset user password
|
||||
|
||||
To reset the password of a user, first log into your server with root privileges.
|
||||
There are a few ways to reset the password of a user.
|
||||
|
||||
Start a Ruby on Rails console with this command:
|
||||
## Rake Task
|
||||
|
||||
GitLab provides a Rake Task to reset passwords of users using their usernames,
|
||||
which can be invoked by the following command:
|
||||
|
||||
```shell
|
||||
gitlab-rails console -e production
|
||||
sudo gitlab-rake "gitlab:password:reset"
|
||||
```
|
||||
|
||||
Wait until the console has loaded.
|
||||
You will be asked for username, password, and password confirmation. Upon giving
|
||||
proper values for them, the password of the specified user will be updated.
|
||||
|
||||
## Find the user
|
||||
|
||||
There are multiple ways to find your user. You can search by email or user ID number.
|
||||
The Rake task also takes the username as an argument, as shown in the example
|
||||
below:
|
||||
|
||||
```shell
|
||||
user = User.where(id: 7).first
|
||||
sudo gitlab-rake "gitlab:password:reset[johndoe]"
|
||||
```
|
||||
|
||||
or
|
||||
NOTE:
|
||||
To reset the default admin password, run this Rake task with the username
|
||||
`root`, which is the default username of that admin account.
|
||||
|
||||
```shell
|
||||
user = User.find_by(email: 'user@example.com')
|
||||
```
|
||||
## Rails console
|
||||
|
||||
## Reset the password
|
||||
The Rake task is capable of finding users via their usernames. However, if only
|
||||
user ID or email ID of the user is known, Rails console can be used to find user
|
||||
using user ID and then change password of the user manually.
|
||||
|
||||
Now you can change your password:
|
||||
1. Start a Rails console
|
||||
|
||||
```shell
|
||||
user.password = 'secret_pass'
|
||||
user.password_confirmation = 'secret_pass'
|
||||
```
|
||||
```shell
|
||||
sudo gitlab-rails console -e production
|
||||
```
|
||||
|
||||
It's important that you change both password and password_confirmation to make it work.
|
||||
1. Find the user either by user ID or email ID:
|
||||
|
||||
When using this method instead of the [Users API](../api/users.md#user-modification), GitLab sends an email to the user stating that the user changed their password.
|
||||
```ruby
|
||||
user = User.find(123)
|
||||
|
||||
If the password was changed by an administrator, execute the following command to notify the user by email:
|
||||
#or
|
||||
|
||||
```shell
|
||||
user.send_only_admin_changed_your_password_notification!
|
||||
```
|
||||
user = User.find_by(email: 'user@example.com')
|
||||
```
|
||||
|
||||
Don't forget to save the changes.
|
||||
1. Reset the password
|
||||
|
||||
```shell
|
||||
user.save!
|
||||
```
|
||||
```ruby
|
||||
user.password = 'secret_pass'
|
||||
user.password_confirmation = 'secret_pass'
|
||||
```
|
||||
|
||||
Exit the console, and then try to sign in with your new password.
|
||||
1. When using this method instead of the [Users API](../api/users.md#user-modification),
|
||||
GitLab sends an email to the user stating that the user changed their
|
||||
password. If the password was changed by an administrator, execute the
|
||||
following command to notify the user by email:
|
||||
|
||||
```ruby
|
||||
user.send_only_admin_changed_your_password_notification!
|
||||
```
|
||||
|
||||
1. Save the changes:
|
||||
|
||||
```ruby
|
||||
user.save!
|
||||
```
|
||||
|
||||
1. Exit the console, and then try to sign in with your new password.
|
||||
|
||||
NOTE:
|
||||
You can also reset passwords by using the [Users API](../api/users.md#user-modification).
|
||||
|
||||
### Reset your root password
|
||||
## Reset your root password
|
||||
|
||||
The previously described steps can also be used to reset the root password. First,
|
||||
identify the root user, with an `id` of `1`. To do so, run the following command:
|
||||
The previously described steps can also be used to reset the root password.
|
||||
|
||||
```shell
|
||||
user = User.where(id: 1).first
|
||||
```
|
||||
In normal installations where the username of root account hasn't been changed
|
||||
manually, the Rake task can be used with username `root` to reset the root
|
||||
password.
|
||||
|
||||
After finding the user, follow the steps mentioned in the [Reset the password](#reset-the-password) section to reset the password of the root user.
|
||||
If the username was changed to something else and has been forgotten, one
|
||||
possible way is to reset the password using Rails console with user ID `1` (in
|
||||
almost all the cases, the first user will be the default admin account).
|
||||
|
||||
<!-- ## Troubleshooting
|
||||
|
||||
|
|
|
@ -28,8 +28,6 @@ module API
|
|||
use :pagination
|
||||
end
|
||||
get 'deploy_tokens' do
|
||||
service_unavailable! unless Feature.enabled?(:deploy_tokens_api, default_enabled: true)
|
||||
|
||||
authenticated_as_admin!
|
||||
|
||||
present paginate(DeployToken.all), with: Entities::DeployToken
|
||||
|
@ -39,10 +37,6 @@ module API
|
|||
requires :id, type: String, desc: 'The ID of a project'
|
||||
end
|
||||
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
|
||||
before do
|
||||
service_unavailable! unless Feature.enabled?(:deploy_tokens_api, user_project, default_enabled: true)
|
||||
end
|
||||
|
||||
params do
|
||||
use :pagination
|
||||
end
|
||||
|
@ -102,10 +96,6 @@ module API
|
|||
requires :id, type: String, desc: 'The ID of a group'
|
||||
end
|
||||
resource :groups, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
|
||||
before do
|
||||
service_unavailable! unless Feature.enabled?(:deploy_tokens_api, user_group, default_enabled: true)
|
||||
end
|
||||
|
||||
params do
|
||||
use :pagination
|
||||
end
|
||||
|
|
|
@ -66,6 +66,18 @@ module Gitlab
|
|||
answer
|
||||
end
|
||||
|
||||
# Prompt the user to input a password
|
||||
#
|
||||
# message - custom message to display before input
|
||||
def prompt_for_password(message = 'Enter password: ')
|
||||
unless STDIN.tty?
|
||||
print(message)
|
||||
return STDIN.gets.chomp
|
||||
end
|
||||
|
||||
STDIN.getpass(message)
|
||||
end
|
||||
|
||||
# Runs the given command and matches the output against the given pattern
|
||||
#
|
||||
# Returns nil if nothing matched
|
||||
|
|
31
lib/tasks/gitlab/password.rake
Normal file
31
lib/tasks/gitlab/password.rake
Normal file
|
@ -0,0 +1,31 @@
|
|||
# frozen_string_literal: true
|
||||
namespace :gitlab do
|
||||
namespace :password do
|
||||
desc "GitLab | Password | Reset a user's password"
|
||||
task :reset, [:username] => :environment do |_, args|
|
||||
username = args[:username] || Gitlab::TaskHelpers.prompt('Enter username: ')
|
||||
abort('Username can not be empty.') if username.blank?
|
||||
|
||||
user = User.find_by(username: username)
|
||||
abort("Unable to find user with username #{username}.") unless user
|
||||
|
||||
password = Gitlab::TaskHelpers.prompt_for_password
|
||||
password_confirm = Gitlab::TaskHelpers.prompt_for_password('Confirm password: ')
|
||||
|
||||
user.password = password
|
||||
user.password_confirmation = password_confirm
|
||||
user.send_only_admin_changed_your_password_notification!
|
||||
|
||||
unless user.save
|
||||
message = <<~EOF
|
||||
Unable to change password of the user with username #{username}.
|
||||
#{user.errors.full_messages.to_sentence}
|
||||
EOF
|
||||
|
||||
abort(message)
|
||||
end
|
||||
|
||||
puts "Password successfully updated for user with username #{username}."
|
||||
end
|
||||
end
|
||||
end
|
|
@ -5,6 +5,14 @@ require 'spec_helper'
|
|||
RSpec.describe ApplicationExperiment, :experiment do
|
||||
subject { described_class.new(:stub) }
|
||||
|
||||
let(:feature_definition) { { name: 'stub', type: 'experiment', group: 'group::adoption', default_enabled: false } }
|
||||
|
||||
around do |example|
|
||||
Feature::Definition.definitions[:stub] = Feature::Definition.new('stub.yml', feature_definition)
|
||||
example.run
|
||||
Feature::Definition.definitions.delete(:stub)
|
||||
end
|
||||
|
||||
before do
|
||||
allow(subject).to receive(:enabled?).and_return(true)
|
||||
end
|
||||
|
@ -105,6 +113,12 @@ RSpec.describe ApplicationExperiment, :experiment do
|
|||
end
|
||||
|
||||
describe "variant resolution" do
|
||||
it "uses the default value as specified in the yaml" do
|
||||
expect(Feature).to receive(:enabled?).with('stub', subject, type: :experiment, default_enabled: :yaml)
|
||||
|
||||
expect(subject.variant.name).to eq('control')
|
||||
end
|
||||
|
||||
it "returns nil when not rolled out" do
|
||||
stub_feature_flags(stub: false)
|
||||
|
||||
|
|
|
@ -10,24 +10,12 @@ RSpec.describe API::DeployTokens do
|
|||
let!(:deploy_token) { create(:deploy_token, projects: [project]) }
|
||||
let!(:group_deploy_token) { create(:deploy_token, :group, groups: [group]) }
|
||||
|
||||
shared_examples 'with feature flag disabled' do
|
||||
context 'disabled feature flag' do
|
||||
before do
|
||||
stub_feature_flags(deploy_tokens_api: false)
|
||||
end
|
||||
|
||||
it { is_expected.to have_gitlab_http_status(:service_unavailable) }
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET /deploy_tokens' do
|
||||
subject do
|
||||
get api('/deploy_tokens', user)
|
||||
response
|
||||
end
|
||||
|
||||
it_behaves_like 'with feature flag disabled'
|
||||
|
||||
context 'when unauthenticated' do
|
||||
let(:user) { nil }
|
||||
|
||||
|
@ -81,8 +69,6 @@ RSpec.describe API::DeployTokens do
|
|||
project.add_maintainer(user)
|
||||
end
|
||||
|
||||
it_behaves_like 'with feature flag disabled'
|
||||
|
||||
it { is_expected.to have_gitlab_http_status(:ok) }
|
||||
|
||||
it 'returns all deploy tokens for the project' do
|
||||
|
@ -128,8 +114,6 @@ RSpec.describe API::DeployTokens do
|
|||
group.add_maintainer(user)
|
||||
end
|
||||
|
||||
it_behaves_like 'with feature flag disabled'
|
||||
|
||||
it { is_expected.to have_gitlab_http_status(:ok) }
|
||||
|
||||
it 'returns all deploy tokens for the group' do
|
||||
|
|
76
spec/tasks/gitlab/password_rake_spec.rb
Normal file
76
spec/tasks/gitlab/password_rake_spec.rb
Normal file
|
@ -0,0 +1,76 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rake_helper'
|
||||
|
||||
RSpec.describe 'gitlab:password rake tasks' do
|
||||
let_it_be(:user_1) { create(:user, username: 'foobar', password: 'initial_password') }
|
||||
|
||||
def stub_username(username)
|
||||
allow(Gitlab::TaskHelpers).to receive(:prompt).with('Enter username: ').and_return(username)
|
||||
end
|
||||
|
||||
def stub_password(password, confirmation = nil)
|
||||
confirmation ||= password
|
||||
allow(Gitlab::TaskHelpers).to receive(:prompt_for_password).and_return(password)
|
||||
allow(Gitlab::TaskHelpers).to receive(:prompt_for_password).with('Confirm password: ').and_return(confirmation)
|
||||
end
|
||||
|
||||
before do
|
||||
Rake.application.rake_require 'tasks/gitlab/password'
|
||||
|
||||
stub_username('foobar')
|
||||
stub_password('secretpassword')
|
||||
end
|
||||
|
||||
describe ':reset' do
|
||||
context 'when all inputs are correct' do
|
||||
it 'updates the password properly' do
|
||||
run_rake_task('gitlab:password:reset', user_1.username)
|
||||
expect(user_1.reload.valid_password?('secretpassword')).to eq(true)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when username is not provided' do
|
||||
it 'asks for username' do
|
||||
expect(Gitlab::TaskHelpers).to receive(:prompt).with('Enter username: ')
|
||||
|
||||
run_rake_task('gitlab:password:reset')
|
||||
end
|
||||
|
||||
context 'when username is empty' do
|
||||
it 'aborts with an error' do
|
||||
stub_username('')
|
||||
expect { run_rake_task('gitlab:password:reset') }.to raise_error(/Username can not be empty./)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when username is passed as argument' do
|
||||
it 'does not ask for username' do
|
||||
expect(Gitlab::TaskHelpers).not_to receive(:prompt)
|
||||
|
||||
run_rake_task('gitlab:password:reset', 'foobar')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when passwords do not match' do
|
||||
before do
|
||||
stub_password('randompassword', 'differentpassword')
|
||||
end
|
||||
|
||||
it 'aborts with an error' do
|
||||
expect { run_rake_task('gitlab:password:reset') }.to raise_error(%r{Unable to change password of the user with username foobar.\nPassword confirmation doesn't match Password})
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user cannot be found' do
|
||||
before do
|
||||
stub_username('nonexistentuser')
|
||||
end
|
||||
|
||||
it 'aborts with an error' do
|
||||
expect { run_rake_task('gitlab:password:reset') }.to raise_error(/Unable to find user with username nonexistentuser./)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue