Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
823254ed2f
commit
a5f5c99d4a
|
|
@ -182,7 +182,7 @@ semgrep-appsec-custom-rules:
|
|||
--exclude '*_test.go' --exclude spec --exclude qa --exclude tooling --json > gl-sast-report.json || true
|
||||
|
||||
variables:
|
||||
CUSTOM_RULES_REPOSITORY: https://gitlab.com/gitlab-com/gl-security/appsec/sast-custom-rules.git
|
||||
CUSTOM_RULES_REPOSITORY: https://gitlab.com/gitlab-com/gl-security/product-security/appsec/sast-custom-rules.git
|
||||
artifacts:
|
||||
expire_in: 30 days
|
||||
paths:
|
||||
|
|
@ -234,7 +234,7 @@ ping-appsec-for-sast-findings:
|
|||
extends:
|
||||
- .ping-appsec-for-sast-findings:rules
|
||||
variables:
|
||||
# Project Access Token bot ID for /gitlab-com/gl-security/appsec/sast-custom-rules
|
||||
# Project Access Token bot ID for /gitlab-com/gl-security/product-security/appsec/sast-custom-rules
|
||||
BOT_USER_ID: 19650678
|
||||
needs:
|
||||
- semgrep-appsec-custom-rules
|
||||
|
|
@ -250,7 +250,7 @@ trigger-depsaster:
|
|||
MERGE_REQUEST_PROJECT_ID: $CI_MERGE_REQUEST_PROJECT_ID
|
||||
MERGE_REQUEST_IID: $CI_MERGE_REQUEST_IID
|
||||
trigger:
|
||||
project: "gitlab-com/gl-security/appsec/tooling/depsaster"
|
||||
project: "gitlab-com/gl-security/product-security/appsec/tooling/depsaster"
|
||||
allow_failure: true
|
||||
|
||||
ping-appsec-for-dependency-review:
|
||||
|
|
@ -261,7 +261,7 @@ ping-appsec-for-dependency-review:
|
|||
DISABLE_MENTIONS: "false"
|
||||
DISABLE_SCORING: "true"
|
||||
DISABLE_COMMENTING: "false"
|
||||
DEPENDENCY_REVIEW_BOT_CI_REG: "${CI_REGISTRY}/gitlab-com/gl-security/appsec/tooling/depscore/master"
|
||||
DEPENDENCY_REVIEW_BOT_CI_REG: "${CI_REGISTRY}/gitlab-com/gl-security/product-security/appsec/tooling/depscore/master"
|
||||
extends: [".ping-appsec-for-dependency-review:rules", ".use-docker-in-docker"]
|
||||
before_script:
|
||||
- apk add jq curl
|
||||
|
|
|
|||
|
|
@ -6,10 +6,10 @@ Create this issue under https://gitlab.com/gitlab-org/security/gitlab
|
|||
Set the title to: `Description of the original issue`
|
||||
-->
|
||||
|
||||
## Prior to starting the security release work
|
||||
## Prior to starting the security work
|
||||
|
||||
- [ ] Read the [security process for developers] if you are not familiar with it.
|
||||
- [ ] Make sure the [issue really needs to follow the security release workflow].
|
||||
- [ ] Read the [security process for engineers] if you are not familiar with it.
|
||||
- [ ] Make sure the [issue really needs to follow the security workflow].
|
||||
- [ ] Add a `~severity::x` label to the issue and all associated merge requests.
|
||||
- [ ] Mark this [issue as linked] to the `gitlab-org/gitlab` issue that describes the security vulnerability.
|
||||
- Fill out the [Links section](#links):
|
||||
|
|
@ -20,7 +20,7 @@ Set the title to: `Description of the original issue`
|
|||
|
||||
- [ ] Run `scripts/security-harness` in your local repository to prevent accidentally pushing to any remote besides `gitlab.com/gitlab-org/security`.
|
||||
- [ ] Create a new branch prefixing it with `security-`.
|
||||
- [ ] Create a merge request targeting `master` on `gitlab.com/gitlab-org/security` and use the [Security Release merge request template].
|
||||
- [ ] Create a merge request targeting `master` on `gitlab.com/gitlab-org/security` and use the [Security merge request template].
|
||||
- [ ] If this includes a breaking change, make sure to include a mention of it for the relevant versions in [`doc/update/index.md`](https://gitlab.com/gitlab-org/security/gitlab/-/blob/master/doc/update/index.md#version-specific-upgrading-instructions)
|
||||
- See if the [breaking changes workflow] applies
|
||||
|
||||
|
|
@ -29,10 +29,10 @@ After your merge request has been approved according to our [approval guidelines
|
|||
## Backports
|
||||
|
||||
- [ ] Once the MR is ready to be merged, create MRs targeting the latest 3 stable branches.
|
||||
- The 3 stable branches correspond to the versions in the title of the [Security Release Tracking Issue].
|
||||
- The 3 stable branches correspond to the versions in the title of the [Security Tracking Issue].
|
||||
- At this point, it might be easy to squash the commits from the MR into one
|
||||
- You can use the script `bin/secpick` instead of the following steps, to help you cherry-picking. See the [secpick documentation]
|
||||
- [ ] Create each MR targeting the stable branch `X-Y-stable`, using the [Security Release merge request template].
|
||||
- [ ] Create each MR targeting the stable branch `X-Y-stable`, using the [Security merge request template].
|
||||
- Every merge request will have its own set of to-dos, so make sure to complete those.
|
||||
- [ ] On the "Related merge requests" section, ensure that `4` merge requests are associated: The one targeting `master` and the `3` backports.
|
||||
- [ ] If this issue requires less than `4` merge requests, add the ~"reduced backports" label.
|
||||
|
|
@ -40,8 +40,8 @@ After your merge request has been approved according to our [approval guidelines
|
|||
## Assigning to a release
|
||||
|
||||
- [ ] **IMPORTANT**: When this issue is ready for release (Default branch MR and backports are approved and ready to be merged), apply the ~"security-target" label.
|
||||
- The `gitlab-release-tools-bot` evaluates and links issues with the label to the next planned security release tracking issue. If the bot finds the issue is not ready to be included in the security release, it will leave a comment on the issue explaining what needs to be done.
|
||||
- This issue will only be included in a security release if it is successfully linked to the security release tracking issue.
|
||||
- The `gitlab-release-tools-bot` evaluates and links issues with the label to the active [Security Tracking Issue]. If the bot finds the issue is not ready to be included in the patch release, it will leave a comment on the issue explaining what needs to be done.
|
||||
- This issue will only be included in a patch release if it is successfully linked to the [Security Tracking Issue].
|
||||
|
||||
## Documentation and final details
|
||||
|
||||
|
|
@ -75,13 +75,13 @@ After your merge request has been approved according to our [approval guidelines
|
|||
| Breaking change to UI or public API | Yes/No | <!-- How should the breaking change be communicated? --> |
|
||||
| Thanks | | |
|
||||
|
||||
[security process for developers]: https://gitlab.com/gitlab-org/release/docs/blob/master/general/security/developer.md
|
||||
[security process for engineers]: https://gitlab.com/gitlab-org/release/docs/blob/master/general/security/engineer.md
|
||||
[secpick documentation]: https://gitlab.com/gitlab-org/release/docs/-/blob/master/general/security/utilities/secpick_script.md
|
||||
[security Release merge request template]: https://gitlab.com/gitlab-org/security/gitlab/blob/master/.gitlab/merge_request_templates/Security%20Release.md
|
||||
[security merge request template]: https://gitlab.com/gitlab-org/security/gitlab/blob/master/.gitlab/merge_request_templates/Security%20Fix.md
|
||||
[approval guidelines]: https://docs.gitlab.com/ee/development/code_review.html#approval-guidelines
|
||||
[issue as linked]: https://docs.gitlab.com/ee/user/project/issues/related_issues.html#add-a-linked-issue
|
||||
[issue really needs to follow the security release workflow]: https://gitlab.com/gitlab-org/release/docs/-/blob/master/general/security/developer.md#making-sure-the-issue-needs-to-follow-the-security-release-workflow
|
||||
[issue really needs to follow the security workflow]: https://gitlab.com/gitlab-org/release/docs/-/blob/master/general/security/engineer.md#making-sure-the-issue-needs-to-follow-the-security-release-workflow
|
||||
[breaking changes workflow]: https://gitlab.com/gitlab-org/release/docs/-/blob/master/general/security/far_reaching_impact_fixes_or_breaking_change_fixes.md
|
||||
[Security Release Tracking Issue]: https://gitlab.com/gitlab-org/gitlab/-/issues/?label_name%5B%5D=upcoming%20security%20release
|
||||
[Security Tracking Issue]: https://gitlab.com/gitlab-org/gitlab/-/issues/?label_name%5B%5D=upcoming%20security%20release
|
||||
|
||||
/label ~security ~"security-notifications"
|
||||
|
|
|
|||
|
|
@ -1,26 +1,26 @@
|
|||
[Reverting a security merge request] is not encouraged because it rollbacks a security fix
|
||||
compromising the integrity of GitLab.com and self-managed instances. If a security merge request
|
||||
compromising the integrity of GitLab.com, self-managed and in-house instances. If a security merge request
|
||||
introduced a bug, the next steps will depend on the severity of the security issue, the impact of
|
||||
the bug introduced and the timeline of the security release. Consult the [other ways of mitigating the bug]
|
||||
the bug introduced and the timeline of the patch release. Consult the [other ways of mitigating the bug]
|
||||
before continuing with the revert.
|
||||
|
||||
## Purpose of the revert
|
||||
|
||||
<!-- Please write down the reason why the revert is required, the severity of the security issue
|
||||
and the severity the bug fix and due date of the security release -->
|
||||
and the severity the bug fix and due date of the patch release -->
|
||||
|
||||
* Severity of the security issue: {+ severity +}
|
||||
* Severity of the bug: {+ severity +}
|
||||
* Due date of the [ongoing security release]: {+ yyyy/mm/dd +}
|
||||
* Due date of the [ongoing patch release]: {+ yyyy/mm/dd +}
|
||||
|
||||
## Checklist:
|
||||
|
||||
- [ ] Stage team has contacted AppSec and [release managers] and explained why the revert is necessary.
|
||||
- [ ] The security issue has been removed from the [security release].
|
||||
- [ ] **AppSec Approval: AppSec agrees and understands the vulnerability will be disclosed without being fixed when the security release is published**
|
||||
- [ ] The security issue has been removed from the [patch release].
|
||||
- [ ] **AppSec Approval: AppSec agrees and understands the vulnerability will be disclosed without being fixed when the patch release is published**
|
||||
|
||||
|
||||
[Reverting a security merge request]: https://gitlab.com/gitlab-org/release/docs/-/blob/master/general/security/bugs_introduced_by_security_merge_request.md?ref_type=heads
|
||||
[other ways of mitigating the bug]: https://gitlab.com/gitlab-org/release/docs/-/blob/master/general/security/bugs_introduced_by_security_merge_request.md?ref_type=heads
|
||||
[security release]: https://gitlab.com/gitlab-org/gitlab/-/issues/?label_name%5B%5D=upcoming%20security%20release
|
||||
[patch release]: https://gitlab.com/gitlab-org/gitlab/-/issues/?label_name%5B%5D=upcoming%20security%20release
|
||||
[release managers]: https://about.gitlab.com/community/release-managers/
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
# README first!
|
||||
This MR should be created on `gitlab.com/gitlab-org/security/gitlab`.
|
||||
|
||||
See [the general developer security release guidelines](https://gitlab.com/gitlab-org/release/docs/blob/master/general/security/developer.md).
|
||||
See [the general developer security guidelines](https://gitlab.com/gitlab-org/release/docs/blob/master/general/security/engineer.md).
|
||||
|
||||
-->
|
||||
|
||||
|
|
@ -13,7 +13,7 @@ See [the general developer security release guidelines](https://gitlab.com/gitla
|
|||
## Developer checklist
|
||||
|
||||
- [ ] **On "Related issues" section, write down the [GitLab Security] issue it belongs to (i.e. `Related to <issue_id>`).**
|
||||
- [ ] Familiarize yourself with the latest process to create Security merge requests: https://gitlab.com/gitlab-org/release/docs/blob/master/general/security/developer.md#process
|
||||
- [ ] Familiarize yourself with the latest process to create Security merge requests: https://gitlab.com/gitlab-org/release/docs/blob/master/general/security/engineer.md#process
|
||||
- [ ] Merge request targets `master`, or a versioned stable branch (`X-Y-stable-ee`).
|
||||
- [ ] Title of this merge request is the same as for all backports.
|
||||
- [ ] A [CHANGELOG entry] has been included, with `Changelog` trailer set to `security`.
|
||||
|
|
@ -21,7 +21,7 @@ See [the general developer security release guidelines](https://gitlab.com/gitla
|
|||
- [ ] Assign to a reviewer and maintainer, per our [Code Review process].
|
||||
- [ ] Ensure it's approved according to our [Approval Guidelines].
|
||||
- [ ] Ensure it's approved by an AppSec engineer.
|
||||
- Please see the security release [Code reviews and Approvals] documentation for details on which AppSec team member to ping for approval.
|
||||
- Please see the security [Code reviews and Approvals] documentation for details on which AppSec team member to ping for approval.
|
||||
- Trigger the [`e2e:package-and-test` job]. The docker image generated will be used by the AppSec engineer to validate the security vulnerability has been remediated.
|
||||
- [ ] For a backport MR targeting a versioned stable branch (`X-Y-stable-ee`).
|
||||
- [ ] Ensure it's approved by the same maintainer that reviewed and approved the merge request targeting the default branch.
|
||||
|
|
@ -5,6 +5,6 @@
|
|||
|
||||
[[semgrep.passthrough]]
|
||||
type = "git"
|
||||
value = "https://gitlab.com/gitlab-com/gl-security/appsec/sast-custom-rules.git"
|
||||
value = "https://gitlab.com/gitlab-com/gl-security/product-security/appsec/sast-custom-rules.git"
|
||||
ref = "refs/heads/main"
|
||||
subdir = "gitlab-sast-rules"
|
||||
|
|
|
|||
|
|
@ -1008,7 +1008,6 @@ RSpec/FeatureCategory:
|
|||
- 'ee/spec/models/ee/project_authorization_spec.rb'
|
||||
- 'ee/spec/models/ee/project_group_link_spec.rb'
|
||||
- 'ee/spec/models/ee/project_statistics_spec.rb'
|
||||
- 'ee/spec/models/ee/project_wiki_spec.rb'
|
||||
- 'ee/spec/models/ee/protected_ref_spec.rb'
|
||||
- 'ee/spec/models/ee/release_spec.rb'
|
||||
- 'ee/spec/models/ee/resource_label_event_spec.rb'
|
||||
|
|
|
|||
|
|
@ -604,7 +604,6 @@ RSpec/NamedSubject:
|
|||
- 'ee/spec/models/ee/pages_domain_spec.rb'
|
||||
- 'ee/spec/models/ee/personal_access_token_spec.rb'
|
||||
- 'ee/spec/models/ee/project_spec.rb'
|
||||
- 'ee/spec/models/ee/project_wiki_spec.rb'
|
||||
- 'ee/spec/models/ee/projects/branch_rule_spec.rb'
|
||||
- 'ee/spec/models/ee/protected_branch_spec.rb'
|
||||
- 'ee/spec/models/ee/resource_label_event_spec.rb'
|
||||
|
|
|
|||
|
|
@ -1092,7 +1092,6 @@ Style/InlineDisableAnnotation:
|
|||
- 'config/initializers/fix_local_cache_middleware.rb'
|
||||
- 'config/initializers/fog_core_patch.rb'
|
||||
- 'config/initializers/grape_validators.rb'
|
||||
- 'config/initializers/grpc_patch.rb'
|
||||
- 'config/initializers/kaminari_active_record_relation_methods_with_limit.rb'
|
||||
- 'config/initializers/mail_starttls_patch.rb'
|
||||
- 'config/initializers/postgres_cte_as_materialized.rb'
|
||||
|
|
@ -1705,7 +1704,6 @@ Style/InlineDisableAnnotation:
|
|||
- 'ee/elastic/migrate/20230720000000_reindex_wikis_to_fix_routing.rb'
|
||||
- 'ee/elastic/migrate/20230724070100_backfill_epics.rb'
|
||||
- 'ee/elastic/migrate/20230724151612_backfill_archived_field_in_commits.rb'
|
||||
- 'ee/elastic/migrate/20230724221548_remove_wikis_from_main_index.rb'
|
||||
- 'ee/elastic/migrate/20230821123542_backfill_archived_field_in_blob.rb'
|
||||
- 'ee/elastic/migrate/20230901120542_force_reindex_commits_from_main_index.rb'
|
||||
- 'ee/elastic/migrate/20231019223356_reindex_wikis_to_fix_routing_and_backfill_archived.rb'
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
1b7d24619a5fc750c340254158c2949d58ea774f
|
||||
f0a471cf95e5f057d7d07692710c391d3e3822d4
|
||||
|
|
|
|||
2
Gemfile
2
Gemfile
|
|
@ -595,7 +595,7 @@ gem 'gitaly', '~> 17.0.0.pre.rc2', feature_category: :gitaly
|
|||
# KAS GRPC protocol definitions
|
||||
gem 'kas-grpc', '~> 0.5.0', feature_category: :deployment_management
|
||||
|
||||
gem 'grpc', '~> 1.62', feature_category: :shared
|
||||
gem 'grpc', '~> 1.63', feature_category: :shared
|
||||
|
||||
gem 'google-protobuf', '~> 3.25', '>= 3.25.3' # rubocop:todo Gemfile/MissingFeatureCategory
|
||||
|
||||
|
|
|
|||
|
|
@ -281,15 +281,15 @@
|
|||
{"name":"graphql","version":"2.2.5","platform":"ruby","checksum":"15eeb4b4b29b8502de22e6f2794ea5b7bf75b3a8c0aa5d776f5e614ef543bc7e"},
|
||||
{"name":"graphql-client","version":"0.19.0","platform":"ruby","checksum":"fe699d81976f916bd8f989216155326449cb8475a5d69fa1dd054012a86969c7"},
|
||||
{"name":"graphql-docs","version":"4.0.0","platform":"ruby","checksum":"f68296959263db26e1b7ba7058856d67b641cf508187222268be58f09dfa02d7"},
|
||||
{"name":"grpc","version":"1.62.0","platform":"aarch64-linux","checksum":"da4a327c031408537d573ac8e32c0457f96043382865f246cc5d8707af1d74ce"},
|
||||
{"name":"grpc","version":"1.62.0","platform":"arm64-darwin","checksum":"3bed38060eaec814a9547f88369c49b9bb3d439ff1832ccff30130459af919e0"},
|
||||
{"name":"grpc","version":"1.62.0","platform":"ruby","checksum":"f624d44ce89764ed61bd0d8c585bd6d7ec4b75ad421bdc7b370f09f101f6e80f"},
|
||||
{"name":"grpc","version":"1.62.0","platform":"x64-mingw-ucrt","checksum":"5618e4c7c708c1f10c905fd61689134ebc8b4df066fdd744b94b62d53e9bf5ea"},
|
||||
{"name":"grpc","version":"1.62.0","platform":"x64-mingw32","checksum":"5e2275f8e013342dfa0d7af028f3449849fc9cad163c5fafd8ae4c9be37b50e3"},
|
||||
{"name":"grpc","version":"1.62.0","platform":"x86-linux","checksum":"3e6a37edc951fcb77c14625a83141f39a98baf86f28fa3be0d552a888385d94d"},
|
||||
{"name":"grpc","version":"1.62.0","platform":"x86-mingw32","checksum":"40d42f50877fdaf26cd37836e2388f61d9c896d268f53e7493bb259b3a669806"},
|
||||
{"name":"grpc","version":"1.62.0","platform":"x86_64-darwin","checksum":"22eb3a8d36de1da327045a57c753b45c873c12a82106e8edef40ac0a01f37776"},
|
||||
{"name":"grpc","version":"1.62.0","platform":"x86_64-linux","checksum":"59f052fda776769f12b815495f9e1f2bc9501e5a194646720eb1d73f190e9502"},
|
||||
{"name":"grpc","version":"1.63.0","platform":"aarch64-linux","checksum":"dc75c5fd570b819470781d9512105dddfdd11d984f38b8e60bb946f92d1f79ee"},
|
||||
{"name":"grpc","version":"1.63.0","platform":"arm64-darwin","checksum":"91b93a354508a9d1772f095554f2e4c04358c2b32d7a670e3705b7fc4695c996"},
|
||||
{"name":"grpc","version":"1.63.0","platform":"ruby","checksum":"5f4383c4ee2886e92c31b90422261b7527f26e3baa585d877e9804e715983686"},
|
||||
{"name":"grpc","version":"1.63.0","platform":"x64-mingw-ucrt","checksum":"bbca63f19b45cca5a485f5c5eb363a8684d23a6d0c3421bde5e72e6227291488"},
|
||||
{"name":"grpc","version":"1.63.0","platform":"x64-mingw32","checksum":"fb6251f497c8327eda92c4af293ec07fcaec4ffaa2514d3942a7c31406bfaf5b"},
|
||||
{"name":"grpc","version":"1.63.0","platform":"x86-linux","checksum":"152140fa2c28e384d3c1ded454a66d5e22fb2ff1d2920c2ef2530b2d707de6fd"},
|
||||
{"name":"grpc","version":"1.63.0","platform":"x86-mingw32","checksum":"eed13225b08e705421fef9d986de6c2310ec692df1d80f7a4d407de7c1f98525"},
|
||||
{"name":"grpc","version":"1.63.0","platform":"x86_64-darwin","checksum":"a814414ff178e89ee3ad0cc2a826ce1ca96c68063effb81affe3e5ceff7b44cc"},
|
||||
{"name":"grpc","version":"1.63.0","platform":"x86_64-linux","checksum":"41a90a597f44959c8dbb94619db2b0c0939a768569a5dfad41fffa227eb1287d"},
|
||||
{"name":"grpc-google-iam-v1","version":"1.5.0","platform":"ruby","checksum":"cea356d150dac69751f6a4c71f1571c8022c69d9f4ce9c18139200932c19374e"},
|
||||
{"name":"gssapi","version":"1.3.1","platform":"ruby","checksum":"c51cf30842ee39bd93ce7fc33e20405ff8a04cda9dec6092071b61258284aee1"},
|
||||
{"name":"guard","version":"2.16.2","platform":"ruby","checksum":"71ba7abaddecc8be91ab77bbaf78f767246603652ebbc7b976fda497ebdc8fbb"},
|
||||
|
|
|
|||
|
|
@ -884,7 +884,7 @@ GEM
|
|||
gemoji (~> 3.0)
|
||||
graphql (~> 2.0)
|
||||
html-pipeline (~> 2.14, >= 2.14.3)
|
||||
grpc (1.62.0)
|
||||
grpc (1.63.0)
|
||||
google-protobuf (~> 3.25)
|
||||
googleapis-common-protos-types (~> 1.0)
|
||||
grpc-google-iam-v1 (1.5.0)
|
||||
|
|
@ -2057,7 +2057,7 @@ DEPENDENCIES
|
|||
graphlyte (~> 1.0.0)
|
||||
graphql (~> 2.2.5)
|
||||
graphql-docs (~> 4.0.0)
|
||||
grpc (~> 1.62)
|
||||
grpc (~> 1.63)
|
||||
gssapi (~> 1.3.1)
|
||||
guard-rspec
|
||||
haml_lint (~> 0.57)
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ export default {
|
|||
data-testid="min-size-group"
|
||||
>
|
||||
<template #invalid-feedback>
|
||||
<div class="gl-w-40p">{{ $options.i18n.minSizeMbInvalidFeedback }}</div>
|
||||
<div class="gl-w-2/5">{{ $options.i18n.minSizeMbInvalidFeedback }}</div>
|
||||
</template>
|
||||
<gl-form-text class="gl-mt-0 gl-mb-3 gl-text-body!">
|
||||
{{ $options.i18n.minSizeMbDescription }}
|
||||
|
|
@ -169,7 +169,7 @@ export default {
|
|||
data-testid="delete-after-months-group"
|
||||
>
|
||||
<template #invalid-feedback>
|
||||
<div class="gl-w-30p">{{ $options.i18n.deleteAfterMonthsInvalidFeedback }}</div>
|
||||
<div class="gl-w-3/10">{{ $options.i18n.deleteAfterMonthsInvalidFeedback }}</div>
|
||||
</template>
|
||||
<gl-form-input-group data-testid="delete-after-months-input-group">
|
||||
<gl-form-input
|
||||
|
|
@ -202,7 +202,7 @@ export default {
|
|||
data-testid="send-warning-email-after-months-group"
|
||||
>
|
||||
<template #invalid-feedback>
|
||||
<div class="gl-w-30p">
|
||||
<div class="gl-w-3/10">
|
||||
{{ $options.i18n.sendWarningEmailAfterMonthsInvalidFeedback }}
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ export default {
|
|||
key: 'severity',
|
||||
label: s__('AlertManagement|Severity'),
|
||||
variant: 'secondary',
|
||||
thClass: `gl-w-eighth`,
|
||||
thClass: `gl-w-1/8`,
|
||||
thAttr: TH_TEST_ID,
|
||||
tdClass: `${tdClass} rounded-top text-capitalize sortable-cell`,
|
||||
sortable: true,
|
||||
|
|
@ -62,7 +62,7 @@ export default {
|
|||
key: 'startedAt',
|
||||
label: s__('AlertManagement|Start time'),
|
||||
variant: 'secondary',
|
||||
thClass: `js-started-at w-15p`,
|
||||
thClass: `js-started-at gl-w-3/20`,
|
||||
tdClass: `${tdClass} sortable-cell`,
|
||||
sortable: true,
|
||||
},
|
||||
|
|
@ -82,20 +82,20 @@ export default {
|
|||
{
|
||||
key: 'issue',
|
||||
label: s__('AlertManagement|Incident'),
|
||||
thClass: 'gl-w-15p gl-pointer-events-none',
|
||||
thClass: 'gl-w-3/20 gl-pointer-events-none',
|
||||
tdClass,
|
||||
},
|
||||
{
|
||||
key: 'assignees',
|
||||
label: s__('AlertManagement|Assignees'),
|
||||
thClass: 'gl-w-eighth gl-pointer-events-none',
|
||||
thClass: 'gl-w-1/8 gl-pointer-events-none',
|
||||
tdClass,
|
||||
},
|
||||
{
|
||||
key: 'status',
|
||||
label: s__('AlertManagement|Status'),
|
||||
variant: 'secondary',
|
||||
thClass: `w-15p`,
|
||||
thClass: `gl-w-3/20`,
|
||||
tdClass: `${tdClass} rounded-bottom sortable-cell`,
|
||||
sortable: true,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -151,7 +151,7 @@ export default {
|
|||
</div>
|
||||
|
||||
<div v-for="gitlabField in mappingData" :key="gitlabField.name" class="gl-display-table-row">
|
||||
<div class="gl-display-table-cell gl-py-3 gl-pr-3 gl-w-30p gl-align-middle">
|
||||
<div class="gl-display-table-cell gl-py-3 gl-pr-3 gl-w-3/10 gl-align-middle">
|
||||
<gl-form-input
|
||||
aria-labelledby="gitlabFieldsHeader"
|
||||
disabled
|
||||
|
|
@ -167,7 +167,7 @@ export default {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="gl-display-table-cell gl-py-3 gl-pr-3 gl-w-30p gl-align-middle">
|
||||
<div class="gl-display-table-cell gl-py-3 gl-pr-3 gl-w-3/10 gl-align-middle">
|
||||
<gl-collapsible-listbox
|
||||
:items="dropdownItems(gitlabField.searchTerm, gitlabField.mappingFields)"
|
||||
:selected="selectedValue(gitlabField.mapping)"
|
||||
|
|
@ -188,7 +188,7 @@ export default {
|
|||
</gl-collapsible-listbox>
|
||||
</div>
|
||||
|
||||
<div class="gl-display-table-cell gl-py-3 gl-w-30p">
|
||||
<div class="gl-display-table-cell gl-py-3 gl-w-3/10">
|
||||
<gl-collapsible-listbox
|
||||
v-if="Boolean(gitlabField.numberOfFallbacks)"
|
||||
:items="dropdownItems(gitlabField.fallbackSearchTerm, gitlabField.mappingFields)"
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ import {
|
|||
import TotalTime from './total_time.vue';
|
||||
|
||||
const DEFAULT_WORKFLOW_TITLE_PROPERTIES = {
|
||||
thClass: 'gl-w-half',
|
||||
thClass: 'gl-w-1/2',
|
||||
key: FIELD_KEY_TITLE,
|
||||
sortable: false,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ export default {
|
|||
<gl-search-box-by-type
|
||||
v-model.trim="searchTerm"
|
||||
:aria-label="$options.i18n.search"
|
||||
class="gl-w-half gl-mr-3"
|
||||
class="gl-w-1/2 gl-mr-3"
|
||||
/>
|
||||
<span>
|
||||
<gl-sprintf
|
||||
|
|
@ -93,7 +93,7 @@ export default {
|
|||
:key="group.id"
|
||||
class="shortcut-help-mapping gl-mb-4"
|
||||
>
|
||||
<strong class="shortcut-help-mapping-title gl-w-half gl-display-inline-block">
|
||||
<strong class="shortcut-help-mapping-title gl-w-1/2 gl-display-inline-block">
|
||||
{{ group.name }}
|
||||
</strong>
|
||||
<div
|
||||
|
|
@ -102,10 +102,10 @@ export default {
|
|||
class="gl-display-flex gl-align-items-center"
|
||||
>
|
||||
<shortcut
|
||||
class="gl-w-40p gl-flex-shrink-0 gl-text-right gl-pr-4"
|
||||
class="gl-w-2/5 gl-flex-shrink-0 gl-text-right gl-pr-4"
|
||||
:shortcuts="keybinding.defaultKeys"
|
||||
/>
|
||||
<div class="gl-w-half gl-flex-shrink-0 gl-flex-grow-1">
|
||||
<div class="gl-w-1/2 gl-flex-shrink-0 gl-flex-grow-1">
|
||||
{{ keybinding.description }}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -21,12 +21,12 @@ export const RUNNER_NO_DESCRIPTION = s__('Runners|No description');
|
|||
/* Admin Table constants */
|
||||
/* The field list is based on app/assets/javascripts/jobs/components/table/constants.js */
|
||||
export const DEFAULT_FIELDS_ADMIN = [
|
||||
{ key: 'status', label: __('Status'), columnClass: 'gl-w-15p' },
|
||||
{ key: 'job', label: __('Job'), columnClass: 'gl-w-20p' },
|
||||
{ key: 'project', label: __('Project'), columnClass: 'gl-w-20p' },
|
||||
{ key: 'runner', label: __('Runner'), columnClass: 'gl-w-15p' },
|
||||
{ key: 'pipeline', label: __('Pipeline'), columnClass: 'gl-w-10p' },
|
||||
{ key: 'actions', label: '', columnClass: 'gl-w-10p' },
|
||||
{ key: 'status', label: __('Status'), columnClass: 'gl-w-3/20' },
|
||||
{ key: 'job', label: __('Job'), columnClass: 'gl-w-4/20' },
|
||||
{ key: 'project', label: __('Project'), columnClass: 'gl-w-4/20' },
|
||||
{ key: 'runner', label: __('Runner'), columnClass: 'gl-w-3/20' },
|
||||
{ key: 'pipeline', label: __('Pipeline'), columnClass: 'gl-w-2/20' },
|
||||
{ key: 'actions', label: '', columnClass: 'gl-w-2/20' },
|
||||
];
|
||||
|
||||
export const RAW_TEXT_WARNING_ADMIN = RAW_TEXT_WARNING;
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ export default {
|
|||
/>
|
||||
</span>
|
||||
<span
|
||||
class="gl-w-half gl-pl-8 gl-display-flex gl-align-items-center"
|
||||
class="gl-w-1/2 gl-pl-8 gl-display-flex gl-align-items-center"
|
||||
data-testid="job-artifact-row-name"
|
||||
>
|
||||
<gl-friendly-wrap :text="artifact.name" />
|
||||
|
|
@ -108,11 +108,11 @@ export default {
|
|||
</gl-badge>
|
||||
</span>
|
||||
|
||||
<span class="gl-w-quarter gl-text-right gl-pr-5" data-testid="job-artifact-row-size">
|
||||
<span class="gl-w-1/4 gl-text-right gl-pr-5" data-testid="job-artifact-row-size">
|
||||
{{ artifactSize }}
|
||||
</span>
|
||||
|
||||
<span class="gl-w-quarter gl-text-right gl-pr-5">
|
||||
<span class="gl-w-1/4 gl-text-right gl-pr-5">
|
||||
<gl-button-group>
|
||||
<gl-button
|
||||
category="tertiary"
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ export default {
|
|||
this.canBulkDestroyArtifacts && {
|
||||
key: 'checkbox',
|
||||
label: '',
|
||||
thClass: 'gl-w-5p',
|
||||
thClass: 'gl-w-1/20',
|
||||
},
|
||||
...this.$options.fields,
|
||||
];
|
||||
|
|
@ -328,29 +328,29 @@ export default {
|
|||
{
|
||||
key: 'artifacts',
|
||||
label: I18N_ARTIFACTS,
|
||||
thClass: 'gl-w-eighth',
|
||||
thClass: 'gl-w-1/8',
|
||||
},
|
||||
{
|
||||
key: 'job',
|
||||
label: I18N_JOB,
|
||||
thClass: 'gl-w-35p',
|
||||
thClass: 'gl-w-7/20',
|
||||
},
|
||||
{
|
||||
key: 'size',
|
||||
label: I18N_SIZE,
|
||||
thClass: 'gl-w-15p gl-text-right',
|
||||
thClass: 'gl-w-3/20 gl-text-right',
|
||||
tdClass: 'gl-text-right',
|
||||
},
|
||||
{
|
||||
key: 'created',
|
||||
label: I18N_CREATED,
|
||||
thClass: 'gl-w-eighth gl-text-center',
|
||||
thClass: 'gl-w-1/8 gl-text-center',
|
||||
tdClass: 'gl-text-center',
|
||||
},
|
||||
{
|
||||
key: 'actions',
|
||||
label: '',
|
||||
thClass: 'gl-w-20p',
|
||||
thClass: 'gl-w-4/20',
|
||||
tdClass: 'gl-text-right',
|
||||
},
|
||||
],
|
||||
|
|
|
|||
|
|
@ -60,17 +60,17 @@ export default {
|
|||
{
|
||||
key: 'name',
|
||||
label: s__('CiCatalogComponent|Parameters'),
|
||||
thClass: 'gl-w-40p',
|
||||
thClass: 'gl-w-2/5',
|
||||
},
|
||||
{
|
||||
key: 'default',
|
||||
label: s__('CiCatalogComponent|Default Value'),
|
||||
thClass: 'gl-w-40p',
|
||||
thClass: 'gl-w-2/5',
|
||||
},
|
||||
{
|
||||
key: 'required',
|
||||
label: s__('CiCatalogComponent|Mandatory'),
|
||||
thClass: 'gl-w-20p',
|
||||
thClass: 'gl-w-1/5',
|
||||
},
|
||||
],
|
||||
i18n: {
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ export default {
|
|||
label: s__('CiVariables|Key'),
|
||||
tdClass: 'text-plain',
|
||||
sortable: true,
|
||||
thClass: 'gl-w-40p',
|
||||
thClass: 'gl-w-2/5',
|
||||
},
|
||||
{
|
||||
key: 'value',
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ export default {
|
|||
{
|
||||
key: 'status',
|
||||
label: s__('Pipeline|Status'),
|
||||
columnClass: 'gl-w-15p',
|
||||
columnClass: 'gl-w-3/20',
|
||||
tdClass: this.tdClasses,
|
||||
thAttr: { 'data-testid': 'status-th' },
|
||||
},
|
||||
|
|
@ -83,27 +83,27 @@ export default {
|
|||
key: 'pipeline',
|
||||
label: __('Pipeline'),
|
||||
tdClass: `${this.tdClasses}`,
|
||||
columnClass: 'gl-w-30p',
|
||||
columnClass: 'gl-w-6/20',
|
||||
thAttr: { 'data-testid': 'pipeline-th' },
|
||||
},
|
||||
{
|
||||
key: 'triggerer',
|
||||
label: s__('Pipeline|Created by'),
|
||||
tdClass: `${this.tdClasses} ${HIDE_TD_ON_MOBILE}`,
|
||||
columnClass: 'gl-w-15p',
|
||||
columnClass: 'gl-w-3/20',
|
||||
thAttr: { 'data-testid': 'triggerer-th' },
|
||||
},
|
||||
{
|
||||
key: 'stages',
|
||||
label: s__('Pipeline|Stages'),
|
||||
tdClass: this.tdClasses,
|
||||
columnClass: 'gl-w-quarter',
|
||||
columnClass: 'gl-w-5/20',
|
||||
thAttr: { 'data-testid': 'stages-th' },
|
||||
},
|
||||
{
|
||||
key: 'actions',
|
||||
tdClass: this.tdClasses,
|
||||
columnClass: 'gl-w-20p',
|
||||
columnClass: 'gl-w-4/20',
|
||||
thAttr: { 'data-testid': 'actions-th' },
|
||||
},
|
||||
];
|
||||
|
|
|
|||
|
|
@ -34,34 +34,34 @@ export const DEFAULT_FIELDS = [
|
|||
{
|
||||
key: 'status',
|
||||
label: __('Status'),
|
||||
columnClass: 'gl-w-10p',
|
||||
columnClass: 'gl-w-2/20',
|
||||
},
|
||||
{
|
||||
key: 'job',
|
||||
label: __('Job'),
|
||||
columnClass: 'gl-w-quarter',
|
||||
columnClass: 'gl-w-5/20',
|
||||
},
|
||||
{
|
||||
key: 'pipeline',
|
||||
label: __('Pipeline'),
|
||||
columnClass: 'gl-w-10p',
|
||||
columnClass: 'gl-w-2/20',
|
||||
},
|
||||
{
|
||||
key: 'stage',
|
||||
label: __('Stage'),
|
||||
columnClass: 'gl-w-10p',
|
||||
columnClass: 'gl-w-2/20',
|
||||
},
|
||||
{
|
||||
key: 'coverage',
|
||||
label: __('Coverage'),
|
||||
tdClass: 'gl-display-none! gl-lg-display-table-cell!',
|
||||
columnClass: 'gl-w-10p',
|
||||
columnClass: 'gl-w-2/20',
|
||||
},
|
||||
{
|
||||
key: 'actions',
|
||||
label: '',
|
||||
tdClass: 'gl-text-right',
|
||||
columnClass: 'gl-w-10p',
|
||||
columnClass: 'gl-w-2/20',
|
||||
},
|
||||
];
|
||||
|
||||
|
|
|
|||
|
|
@ -49,23 +49,23 @@ export const DEFAULT_FIELDS = [
|
|||
{
|
||||
key: 'name',
|
||||
label: __('Name'),
|
||||
columnClass: 'gl-w-20p',
|
||||
columnClass: 'gl-w-1/5',
|
||||
},
|
||||
{
|
||||
key: 'stage',
|
||||
label: __('Stage'),
|
||||
columnClass: 'gl-w-20p',
|
||||
columnClass: 'gl-w-1/5',
|
||||
},
|
||||
{
|
||||
key: 'failureMessage',
|
||||
label: __('Failure'),
|
||||
columnClass: 'gl-w-40p',
|
||||
columnClass: 'gl-w-2/5',
|
||||
},
|
||||
{
|
||||
key: 'actions',
|
||||
label: '',
|
||||
tdClass: 'gl-text-right',
|
||||
columnClass: 'gl-w-20p',
|
||||
columnClass: 'gl-w-1/5',
|
||||
},
|
||||
];
|
||||
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ export default {
|
|||
data-testid="stage-column-title"
|
||||
class="stage-column-title gl-display-flex gl-justify-content-space-between gl-relative gl-font-weight-bold gl-pipeline-job-width gl-text-truncate gl-line-height-36 gl-pl-4 gl-mb-n2"
|
||||
>
|
||||
<span :title="name" class="gl-text-truncate gl-pr-3 gl-w-85p">
|
||||
<span :title="name" class="gl-text-truncate gl-pr-3 gl-w-17/20">
|
||||
{{ name }}
|
||||
</span>
|
||||
<action-component
|
||||
|
|
|
|||
|
|
@ -16,37 +16,37 @@ export default {
|
|||
key: 'description',
|
||||
label: s__('PipelineSchedules|Description'),
|
||||
thClass: 'gl-border-t-none!',
|
||||
columnClass: 'gl-w-40p',
|
||||
columnClass: 'gl-w-8/20',
|
||||
},
|
||||
{
|
||||
key: 'target',
|
||||
label: s__('PipelineSchedules|Target'),
|
||||
thClass: 'gl-border-t-none!',
|
||||
columnClass: 'gl-w-10p',
|
||||
columnClass: 'gl-w-2/20',
|
||||
},
|
||||
{
|
||||
key: 'pipeline',
|
||||
label: s__('PipelineSchedules|Last Pipeline'),
|
||||
thClass: 'gl-border-t-none!',
|
||||
columnClass: 'gl-w-10p',
|
||||
columnClass: 'gl-w-2/20',
|
||||
},
|
||||
{
|
||||
key: 'next',
|
||||
label: s__('PipelineSchedules|Next Run'),
|
||||
thClass: 'gl-border-t-none!',
|
||||
columnClass: 'gl-w-15p',
|
||||
columnClass: 'gl-w-3/20',
|
||||
},
|
||||
{
|
||||
key: 'owner',
|
||||
label: s__('PipelineSchedules|Owner'),
|
||||
thClass: 'gl-border-t-none!',
|
||||
columnClass: 'gl-w-10p',
|
||||
columnClass: 'gl-w-2/20',
|
||||
},
|
||||
{
|
||||
key: 'actions',
|
||||
label: '',
|
||||
thClass: 'gl-border-t-none!',
|
||||
columnClass: 'gl-w-15p',
|
||||
columnClass: 'gl-w-3/20',
|
||||
},
|
||||
],
|
||||
components: {
|
||||
|
|
|
|||
|
|
@ -13,10 +13,10 @@ import RunnerStatusCell from './cells/runner_status_cell.vue';
|
|||
import RunnerOwnerCell from './cells/runner_owner_cell.vue';
|
||||
|
||||
const defaultFields = [
|
||||
tableField({ key: 'status', label: s__('Runners|Status'), thClasses: ['gl-w-15p'] }),
|
||||
tableField({ key: 'status', label: s__('Runners|Status'), thClasses: ['gl-w-3/20'] }),
|
||||
tableField({ key: 'summary', label: s__('Runners|Runner configuration') }),
|
||||
tableField({ key: 'owner', label: s__('Runners|Owner'), thClasses: ['gl-w-20p'] }),
|
||||
tableField({ key: 'actions', label: '', thClasses: ['gl-w-15p'] }),
|
||||
tableField({ key: 'owner', label: s__('Runners|Owner'), thClasses: ['gl-w-4/20'] }),
|
||||
tableField({ key: 'actions', label: '', thClasses: ['gl-w-3/20'] }),
|
||||
];
|
||||
|
||||
export default {
|
||||
|
|
|
|||
|
|
@ -43,32 +43,32 @@ export default {
|
|||
{
|
||||
key: 'token',
|
||||
label: s__('Pipelines|Token'),
|
||||
thClass: 'gl-w-60p',
|
||||
thClass: 'gl-w-12/20',
|
||||
tdClass: '!gl-align-middle',
|
||||
},
|
||||
{
|
||||
key: 'description',
|
||||
label: s__('Pipelines|Description'),
|
||||
thClass: 'gl-w-20p',
|
||||
thClass: 'gl-w-4/20',
|
||||
tdClass: '!gl-align-middle',
|
||||
},
|
||||
{
|
||||
key: 'owner',
|
||||
label: s__('Pipelines|Owner'),
|
||||
thClass: 'gl-w-5p',
|
||||
thClass: 'gl-w-1/20',
|
||||
tdClass: '!gl-align-middle',
|
||||
},
|
||||
{
|
||||
key: 'lastUsed',
|
||||
label: s__('Pipelines|Last Used'),
|
||||
thClass: 'gl-w-10p',
|
||||
thClass: 'gl-w-2/20',
|
||||
tdClass: '!gl-align-middle',
|
||||
},
|
||||
{
|
||||
key: 'actions',
|
||||
label: __('Actions'),
|
||||
tdClass: 'gl-text-right gl-white-space-nowrap',
|
||||
thClass: `gl-text-right gl-w-5p`,
|
||||
thClass: `gl-text-right gl-w-1/20`,
|
||||
},
|
||||
],
|
||||
computed: {
|
||||
|
|
|
|||
|
|
@ -264,7 +264,7 @@ export default {
|
|||
<form>
|
||||
<gl-form-group label-for="agent-name">
|
||||
<available-agents-dropdown
|
||||
class="gl-w-70p"
|
||||
class="gl-w-7/10"
|
||||
:is-registering="registering"
|
||||
:available-agents="availableAgents"
|
||||
@agentSelected="setAgentName"
|
||||
|
|
|
|||
|
|
@ -106,28 +106,28 @@ export default {
|
|||
:environment="environment"
|
||||
:loading="isLoading"
|
||||
/>
|
||||
<details-feedback class="gl-mt-6 gl-w-90p" />
|
||||
<details-feedback class="gl-mt-6 gl-w-9/10" />
|
||||
<deployment-approvals
|
||||
v-if="hasApprovalSummary"
|
||||
:approval-summary="deployment.approvalSummary"
|
||||
:deployment="deployment"
|
||||
class="gl-mt-6 gl-w-90p"
|
||||
class="gl-mt-6 gl-w-9/10"
|
||||
@change="$apollo.queries.deployment.refetch()"
|
||||
/>
|
||||
<deployment-deploy-block
|
||||
v-if="isManual"
|
||||
:deployment="deployment"
|
||||
class="gl-w-90p gl-mt-4"
|
||||
class="gl-w-9/10 gl-mt-4"
|
||||
/>
|
||||
<deployment-timeline
|
||||
v-if="hasApprovalSummary"
|
||||
:approval-summary="deployment.approvalSummary"
|
||||
class="gl-w-90p"
|
||||
class="gl-w-9/10"
|
||||
/>
|
||||
<approvals-empty-state
|
||||
v-if="!isLoading"
|
||||
:approval-summary="deployment.approvalSummary"
|
||||
class="gl-w-90p"
|
||||
class="gl-w-9/10"
|
||||
/>
|
||||
</div>
|
||||
<deployment-aside
|
||||
|
|
@ -135,7 +135,7 @@ export default {
|
|||
:loading="isLoading"
|
||||
:deployment="deployment"
|
||||
:environment="environment"
|
||||
class="gl-w-20p"
|
||||
class="gl-w-1/5"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1 +1,3 @@
|
|||
import '../performance_bar';
|
||||
import '~/webpack';
|
||||
import '~/commons';
|
||||
import '~/performance_bar';
|
||||
|
|
|
|||
|
|
@ -7,56 +7,56 @@ export const ENVIRONMENT_DETAILS_TABLE_FIELDS = [
|
|||
{
|
||||
key: 'status',
|
||||
label: __('Status'),
|
||||
columnClass: 'gl-w-10p',
|
||||
columnClass: 'gl-w-2/20',
|
||||
tdClass: '!gl-align-middle',
|
||||
thClass: 'gl-border-t-none!',
|
||||
},
|
||||
{
|
||||
key: 'id',
|
||||
label: __('ID'),
|
||||
columnClass: 'gl-w-5p',
|
||||
columnClass: 'gl-w-1/20',
|
||||
tdClass: '!gl-align-middle',
|
||||
thClass: 'gl-border-t-none!',
|
||||
},
|
||||
{
|
||||
key: 'triggerer',
|
||||
label: __('Triggerer'),
|
||||
columnClass: 'gl-w-10p',
|
||||
columnClass: 'gl-w-2/20',
|
||||
tdClass: '!gl-align-middle',
|
||||
thClass: 'gl-border-t-none!',
|
||||
},
|
||||
{
|
||||
key: 'commit',
|
||||
label: __('Commit'),
|
||||
columnClass: 'gl-w-20p',
|
||||
columnClass: 'gl-w-4/20',
|
||||
tdClass: '!gl-align-middle',
|
||||
thClass: 'gl-border-t-none!',
|
||||
},
|
||||
{
|
||||
key: 'job',
|
||||
label: __('Job'),
|
||||
columnClass: 'gl-w-15p',
|
||||
columnClass: 'gl-w-3/20',
|
||||
tdClass: '!gl-align-middle',
|
||||
thClass: 'gl-border-t-none!',
|
||||
},
|
||||
{
|
||||
key: 'created',
|
||||
label: __('Created'),
|
||||
columnClass: 'gl-w-10p',
|
||||
columnClass: 'gl-w-2/20',
|
||||
tdClass: '!gl-align-middle gl-white-space-nowrap',
|
||||
thClass: 'gl-border-t-none!',
|
||||
},
|
||||
{
|
||||
key: 'deployed',
|
||||
label: __('Deployed'),
|
||||
columnClass: 'gl-w-10p',
|
||||
columnClass: 'gl-w-2/20',
|
||||
tdClass: '!gl-align-middle gl-white-space-nowrap',
|
||||
thClass: 'gl-border-t-none!',
|
||||
},
|
||||
{
|
||||
key: 'actions',
|
||||
label: __('Actions'),
|
||||
columnClass: 'gl-w-15p',
|
||||
columnClass: 'gl-w-3/20',
|
||||
tdClass: '!gl-align-middle gl-white-space-nowrap',
|
||||
thClass: 'gl-border-t-none!',
|
||||
},
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
|
|||
import TrackEventDirective from '~/vue_shared/directives/track_event';
|
||||
import { trackClickErrorLinkToSentryOptions } from '../events_tracking';
|
||||
|
||||
const CARD_CLASS = 'gl-mr-7 gl-w-15p gl-min-w-fit-content';
|
||||
const CARD_CLASS = 'gl-mr-7 gl-w-3/20 gl-min-w-fit-content';
|
||||
const HEADER_CLASS =
|
||||
'gl-p-2 gl-font-weight-bold gl-display-flex gl-justify-content-center gl-align-items-center';
|
||||
const BODY_CLASS =
|
||||
|
|
|
|||
|
|
@ -46,31 +46,31 @@ export default {
|
|||
{
|
||||
key: 'error',
|
||||
label: __('Error'),
|
||||
thClass: 'gl-w-40p',
|
||||
thClass: 'gl-w-8/20',
|
||||
tdClass: `${tableDataClass}`,
|
||||
},
|
||||
{
|
||||
key: 'timeline',
|
||||
label: __('Timeline'),
|
||||
thClass: 'gl-text-center gl-w-20p',
|
||||
thClass: 'gl-text-center gl-w-4/20',
|
||||
tdClass: `${tableDataClass} gl-text-center`,
|
||||
},
|
||||
{
|
||||
key: 'events',
|
||||
label: __('Events'),
|
||||
thClass: 'gl-text-center gl-w-10p',
|
||||
thClass: 'gl-text-center gl-w-2/20',
|
||||
tdClass: `${tableDataClass} gl-text-center`,
|
||||
},
|
||||
{
|
||||
key: 'users',
|
||||
label: __('Users'),
|
||||
thClass: 'gl-text-center gl-w-10p',
|
||||
thClass: 'gl-text-center gl-w-2/20',
|
||||
tdClass: `${tableDataClass} gl-text-center`,
|
||||
},
|
||||
{
|
||||
key: 'lastSeen',
|
||||
label: __('Last seen'),
|
||||
thClass: 'gl-text-center gl-w-10p',
|
||||
thClass: 'gl-text-center gl-w-2/20',
|
||||
tdClass: `${tableDataClass} gl-text-center`,
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -143,13 +143,13 @@ export default {
|
|||
{
|
||||
key: 'webUrl',
|
||||
label: s__('BulkImport|Source group'),
|
||||
thClass: 'gl-pl-0! gl-w-half',
|
||||
thClass: 'gl-pl-0! gl-w-1/2',
|
||||
tdClass: 'gl-pl-0!',
|
||||
},
|
||||
{
|
||||
key: 'importTarget',
|
||||
label: s__('BulkImport|New group'),
|
||||
thClass: `gl-w-half`,
|
||||
thClass: `gl-w-1/2`,
|
||||
},
|
||||
{
|
||||
key: 'progress',
|
||||
|
|
|
|||
|
|
@ -187,10 +187,10 @@ export default {
|
|||
<table class="table gl-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="gl-w-half">
|
||||
<th class="gl-w-1/2">
|
||||
{{ fromHeaderText }}
|
||||
</th>
|
||||
<th class="gl-w-half">
|
||||
<th class="gl-w-1/2">
|
||||
{{ __('To GitLab') }}
|
||||
</th>
|
||||
<th>
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ export default {
|
|||
key: 'severity',
|
||||
label: s__('IncidentManagement|Severity'),
|
||||
variant: 'secondary',
|
||||
thClass: `gl-w-15p`,
|
||||
thClass: `gl-w-3/20`,
|
||||
tdClass: `${tdClass} sortable-cell`,
|
||||
actualSortKey: 'SEVERITY',
|
||||
sortable: true,
|
||||
|
|
@ -70,7 +70,7 @@ export default {
|
|||
key: 'escalationStatus',
|
||||
label: s__('IncidentManagement|Status'),
|
||||
variant: 'secondary',
|
||||
thClass: `gl-w-eighth`,
|
||||
thClass: `gl-w-1/8`,
|
||||
tdClass: `${tdClass} sortable-cell`,
|
||||
actualSortKey: 'ESCALATION_STATUS',
|
||||
sortable: true,
|
||||
|
|
@ -80,7 +80,7 @@ export default {
|
|||
key: 'createdAt',
|
||||
label: s__('IncidentManagement|Date created'),
|
||||
variant: 'secondary',
|
||||
thClass: `gl-w-eighth`,
|
||||
thClass: `gl-w-1/8`,
|
||||
tdClass: `${tdClass} sortable-cell`,
|
||||
actualSortKey: 'CREATED',
|
||||
sortable: true,
|
||||
|
|
@ -90,7 +90,7 @@ export default {
|
|||
key: 'incidentSla',
|
||||
label: s__('IncidentManagement|Time to SLA'),
|
||||
variant: 'secondary',
|
||||
thClass: `gl-text-right gl-w-10p`,
|
||||
thClass: `gl-text-right gl-w-2/20`,
|
||||
tdClass: `${tdClass} gl-text-right`,
|
||||
thAttr: TH_INCIDENT_SLA_TEST_ID,
|
||||
actualSortKey: 'SLA_DUE_AT',
|
||||
|
|
@ -99,7 +99,7 @@ export default {
|
|||
{
|
||||
key: 'assignees',
|
||||
label: s__('IncidentManagement|Assignees'),
|
||||
thClass: 'gl-pointer-events-none gl-w-15',
|
||||
thClass: 'gl-pointer-events-none gl-w-3/20',
|
||||
tdClass,
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -68,7 +68,9 @@ export default {
|
|||
</template>
|
||||
|
||||
<template #default>
|
||||
<!-- This selector is temporarily disabled until the backend adds support for groups -->
|
||||
<list-selector
|
||||
v-show="false"
|
||||
type="groups"
|
||||
class="gl-m-5 gl-p-0!"
|
||||
autofocus
|
||||
|
|
@ -80,6 +82,7 @@ export default {
|
|||
<list-selector
|
||||
type="projects"
|
||||
class="gl-m-5 gl-p-0!"
|
||||
autofocus
|
||||
:selected-items="projectExclusions"
|
||||
@select="handleSelectExclusion"
|
||||
@delete="handleRemoveExclusion"
|
||||
|
|
|
|||
|
|
@ -1,9 +1,22 @@
|
|||
<script>
|
||||
import { GlButton, GlEmptyState } from '@gitlab/ui';
|
||||
import { sortBy, differenceBy } from 'lodash';
|
||||
import { GlButton, GlLoadingIcon, GlEmptyState, GlKeysetPagination } from '@gitlab/ui';
|
||||
import { differenceBy } from 'lodash';
|
||||
import { s__, __, sprintf } from '~/locale';
|
||||
import { createAlert } from '~/alert';
|
||||
import { fetchPolicies } from '~/lib/graphql';
|
||||
import { TYPENAME_PROJECT } from '~/graphql_shared/constants';
|
||||
import { convertToGraphQLId } from '~/graphql_shared/utils';
|
||||
import { capitalizeFirstCharacter } from '~/lib/utils/text_utility';
|
||||
import globalToast from '~/vue_shared/plugins/global_toast';
|
||||
import fetchExclusions from '../graphql/queries/beyond_identity_exclusions.query.graphql';
|
||||
import createExclusion from '../graphql/mutations/create_beyond_identity_exclusion.mutation.graphql';
|
||||
import deleteExclusion from '../graphql/mutations/delete_beyond_identity_exclusion.mutation.graphql';
|
||||
import {
|
||||
BEYOND_IDENTITY_INTEGRATION_NAME,
|
||||
PROJECT_TYPE,
|
||||
GROUP_TYPE,
|
||||
DEFAULT_CURSOR,
|
||||
} from '../constants';
|
||||
import ExclusionsTabs from './exclusions_tabs.vue';
|
||||
import ExclusionsListItem from './exclusions_list_item.vue';
|
||||
import AddExclusionsDrawer from './add_exclusions_drawer.vue';
|
||||
|
|
@ -13,9 +26,11 @@ export default {
|
|||
name: 'ExclusionsList',
|
||||
components: {
|
||||
GlButton,
|
||||
GlLoadingIcon,
|
||||
GlEmptyState,
|
||||
ExclusionsTabs,
|
||||
ExclusionsListItem,
|
||||
GlKeysetPagination,
|
||||
AddExclusionsDrawer,
|
||||
ConfirmRemovalModal,
|
||||
},
|
||||
|
|
@ -25,33 +40,90 @@ export default {
|
|||
isConfirmRemovalModalOpen: false,
|
||||
exclusions: [],
|
||||
exclusionToRemove: null,
|
||||
pageInfo: {},
|
||||
cursor: DEFAULT_CURSOR,
|
||||
};
|
||||
},
|
||||
apollo: {
|
||||
exclusions: {
|
||||
query: fetchExclusions,
|
||||
fetchPolicy: fetchPolicies.CACHE_AND_NETWORK,
|
||||
variables() {
|
||||
return this.cursor;
|
||||
},
|
||||
update({ integrationExclusions }) {
|
||||
this.pageInfo = integrationExclusions?.pageInfo || {};
|
||||
return integrationExclusions?.nodes || [];
|
||||
},
|
||||
error() {
|
||||
this.handleError(this.$options.i18n.errorFetch);
|
||||
},
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
formattedExclusions() {
|
||||
return sortBy(
|
||||
this.exclusions.map((exclusion) => ({
|
||||
...exclusion,
|
||||
icon: exclusion.type,
|
||||
})),
|
||||
'type',
|
||||
'desc',
|
||||
);
|
||||
return this.exclusions.map((exclusion) => {
|
||||
const type = exclusion.project ? PROJECT_TYPE : GROUP_TYPE;
|
||||
return {
|
||||
...exclusion[type],
|
||||
icon: type,
|
||||
type,
|
||||
};
|
||||
});
|
||||
},
|
||||
showPagination() {
|
||||
return this.pageInfo?.hasPreviousPage || this.pageInfo?.hasNextPage;
|
||||
},
|
||||
isLoading() {
|
||||
return this.$apollo.queries.exclusions.loading;
|
||||
},
|
||||
isEmpty() {
|
||||
return !this.isLoading && !this.exclusions.length;
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.loadExclusions();
|
||||
},
|
||||
methods: {
|
||||
loadExclusions() {
|
||||
// TODO: add backend call for GET/Query (follow-up)
|
||||
this.exclusions = [];
|
||||
},
|
||||
handleAddExclusions(exclusions) {
|
||||
async handleAddExclusions(exclusions) {
|
||||
const uniqueList = differenceBy(exclusions, this.exclusions, (v) => [v.id, v.type].join());
|
||||
// TODO: add backend call for POST/Mutate (follow-up)
|
||||
this.exclusions.push(...uniqueList);
|
||||
|
||||
const { data } = await this.$apollo.mutate({
|
||||
mutation: createExclusion,
|
||||
variables: {
|
||||
input: {
|
||||
projectIds: this.extractProjectIds(uniqueList),
|
||||
integrationName: BEYOND_IDENTITY_INTEGRATION_NAME,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
this.isDrawerOpen = false;
|
||||
|
||||
if (data?.integrationExclusionCreate?.errors?.length) {
|
||||
this.handleError(this.$options.i18n.errorCreate);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.pageInfo.hasPreviousPage) {
|
||||
this.resetPagination();
|
||||
} else {
|
||||
this.$apollo.queries.exclusions.refetch();
|
||||
}
|
||||
},
|
||||
extractProjectIds(exclusions) {
|
||||
return exclusions
|
||||
.filter((exclusion) => exclusion.type === PROJECT_TYPE)
|
||||
.map((exclusion) => convertToGraphQLId(TYPENAME_PROJECT, exclusion.id));
|
||||
},
|
||||
nextPage(item) {
|
||||
this.cursor = { after: item, last: null, before: null };
|
||||
},
|
||||
prevPage(item) {
|
||||
this.cursor = { first: null, after: null, before: item };
|
||||
},
|
||||
resetPagination() {
|
||||
this.cursor = DEFAULT_CURSOR;
|
||||
},
|
||||
handleError(message) {
|
||||
createAlert({ message });
|
||||
},
|
||||
showRemoveModal(exclusion) {
|
||||
this.exclusionToRemove = exclusion;
|
||||
|
|
@ -60,10 +132,30 @@ export default {
|
|||
hideRemoveModal() {
|
||||
this.isConfirmRemovalModalOpen = false;
|
||||
},
|
||||
confirmRemoveExclusion() {
|
||||
async confirmRemoveExclusion() {
|
||||
const { exclusionToRemove } = this;
|
||||
// TODO: add backend call for DELETE/Mutate (follow-up)
|
||||
this.exclusions = this.exclusions.filter((item) => item.id !== exclusionToRemove.id);
|
||||
|
||||
const { data } = await this.$apollo.mutate({
|
||||
mutation: deleteExclusion,
|
||||
variables: {
|
||||
input: {
|
||||
projectId: exclusionToRemove.id,
|
||||
integrationName: BEYOND_IDENTITY_INTEGRATION_NAME,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (data?.integrationExclusionDelete?.errors?.length) {
|
||||
this.handleError(this.$options.i18n.errorDelete);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.exclusions.length === 1 && this.pageInfo.hasPreviousPage) {
|
||||
this.prevPage(this.pageInfo.startCursor);
|
||||
} else {
|
||||
this.$apollo.queries.exclusions.refetch();
|
||||
}
|
||||
|
||||
const type = capitalizeFirstCharacter(exclusionToRemove.type);
|
||||
|
||||
globalToast(sprintf(this.$options.i18n.exclusionRemoved, { type }), {
|
||||
|
|
@ -81,12 +173,13 @@ export default {
|
|||
},
|
||||
},
|
||||
i18n: {
|
||||
errorCreate: s__('Integrations|Failed to add the exclusion. Try adding it again.'),
|
||||
errorDelete: s__('Integrations|Failed to remove the exclusion. Try removing it again.'),
|
||||
errorFetch: s__('Integrations|Failed to fetch the exclusions. Try refreshing the page.'),
|
||||
exclusionRemoved: s__('Integrations|%{type} exclusion removed'),
|
||||
emptyText: s__('Integrations|There are no exclusions'),
|
||||
addExclusions: s__('Integrations|Add exclusions'),
|
||||
helpText: s__(
|
||||
'Integrations|Groups and projects in this list no longer require commits to be signed.',
|
||||
),
|
||||
helpText: s__('Integrations|Projects in this list no longer require commits to be signed.'),
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
@ -104,7 +197,7 @@ export default {
|
|||
}}</gl-button>
|
||||
</div>
|
||||
|
||||
<gl-empty-state v-if="!exclusions.length" :title="$options.i18n.emptyText" />
|
||||
<gl-empty-state v-if="isEmpty" :title="$options.i18n.emptyText" />
|
||||
|
||||
<exclusions-list-item
|
||||
v-for="(exclusion, index) in formattedExclusions"
|
||||
|
|
@ -114,6 +207,17 @@ export default {
|
|||
@remove="() => showRemoveModal(exclusion)"
|
||||
/>
|
||||
|
||||
<gl-loading-icon v-if="isLoading" size="lg" class="gl-my-5" />
|
||||
|
||||
<div v-else class="gl-mt-5 gl-display-flex gl-justify-content-center">
|
||||
<gl-keyset-pagination
|
||||
v-if="showPagination"
|
||||
v-bind="pageInfo"
|
||||
@prev="prevPage"
|
||||
@next="nextPage"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<add-exclusions-drawer
|
||||
:is-open="isDrawerOpen"
|
||||
@close="isDrawerOpen = false"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
export const BEYOND_IDENTITY_INTEGRATION_NAME = 'BEYOND_IDENTITY';
|
||||
export const PROJECT_TYPE = 'project';
|
||||
export const GROUP_TYPE = 'group';
|
||||
export const DEFAULT_CURSOR = {
|
||||
after: null,
|
||||
last: null,
|
||||
before: null,
|
||||
};
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
mutation integrationExclusionCreate($input: IntegrationExclusionCreateInput!) {
|
||||
integrationExclusionCreate(input: $input) {
|
||||
exclusions {
|
||||
nodes {
|
||||
project {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
errors
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
mutation integrationExclusionDelete($input: IntegrationExclusionDeleteInput!) {
|
||||
integrationExclusionDelete(input: $input) {
|
||||
exclusion {
|
||||
project {
|
||||
name
|
||||
}
|
||||
}
|
||||
errors
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
#import "~/graphql_shared/fragments/page_info.fragment.graphql"
|
||||
|
||||
query integrationExclusion($before: String, $after: String, $first: Int, $last: Int) {
|
||||
integrationExclusions(
|
||||
integrationName: BEYOND_IDENTITY
|
||||
after: $after
|
||||
before: $before
|
||||
first: $first
|
||||
last: $last
|
||||
) {
|
||||
nodes {
|
||||
project {
|
||||
avatarUrl
|
||||
name
|
||||
id
|
||||
}
|
||||
}
|
||||
pageInfo {
|
||||
...PageInfo
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -30,7 +30,7 @@ export default {
|
|||
{
|
||||
key: 'created_at',
|
||||
label: __('Created on'),
|
||||
tdClass: '!gl-align-middle gl-w-20p',
|
||||
tdClass: '!gl-align-middle gl-w-2/10',
|
||||
},
|
||||
{
|
||||
key: 'actions',
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ export default {
|
|||
id="code-example"
|
||||
readonly
|
||||
:value="$options.codeExample"
|
||||
class="gl-w-70p gl-mx-auto"
|
||||
class="gl-w-7/10 gl-mx-auto"
|
||||
select-on-click
|
||||
>
|
||||
<template #append>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<script>
|
||||
import { GlSprintf, GlBadge, GlResizeObserverDirective } from '@gitlab/ui';
|
||||
import { GlSprintf, GlBadge, GlResizeObserverDirective, GlTooltipDirective } from '@gitlab/ui';
|
||||
import { GlBreakpointInstance } from '@gitlab/ui/dist/utils';
|
||||
import { __, s__, sprintf } from '~/locale';
|
||||
import { formatDate } from '~/lib/utils/datetime_utility';
|
||||
|
|
@ -9,6 +9,7 @@ import { getPackageTypeLabel } from '~/packages_and_registries/package_registry/
|
|||
import MetadataItem from '~/vue_shared/components/registry/metadata_item.vue';
|
||||
import TitleArea from '~/vue_shared/components/registry/title_area.vue';
|
||||
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
|
||||
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
|
||||
export default {
|
||||
name: 'PackageTitle',
|
||||
|
|
@ -22,11 +23,14 @@ export default {
|
|||
},
|
||||
directives: {
|
||||
GlResizeObserver: GlResizeObserverDirective,
|
||||
GlTooltip: GlTooltipDirective,
|
||||
},
|
||||
mixins: [glFeatureFlagsMixin()],
|
||||
inject: ['isGroupPage'],
|
||||
i18n: {
|
||||
lastDownloadedAt: s__('PackageRegistry|Last downloaded %{dateTime}'),
|
||||
packageInfo: __('v%{version} published %{timeAgo}'),
|
||||
badgeProtectedTooltipText: s__('PackageRegistry|A protection rule exists for this package.'),
|
||||
},
|
||||
props: {
|
||||
packageEntity: {
|
||||
|
|
@ -60,6 +64,12 @@ export default {
|
|||
hasTagsToDisplay() {
|
||||
return Boolean(this.packageEntity.tags?.nodes && this.packageEntity.tags?.nodes.length);
|
||||
},
|
||||
showBadgeProtected() {
|
||||
return (
|
||||
Boolean(this.glFeatures.packagesProtectedPackages) &&
|
||||
Boolean(this.packageEntity?.packageProtectionRuleExists)
|
||||
);
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.checkBreakpoints();
|
||||
|
|
@ -79,7 +89,10 @@ export default {
|
|||
:avatar="packageIcon"
|
||||
>
|
||||
<template #sub-header>
|
||||
<div data-testid="sub-header" class="gl-display-flex gl-flex-wrap gl-gap-3">
|
||||
<div
|
||||
data-testid="sub-header"
|
||||
class="gl-display-flex gl-flex-wrap gl-gap-2 gl-align-items-baseline"
|
||||
>
|
||||
<gl-sprintf :message="$options.i18n.packageInfo">
|
||||
<template #version>{{ packageEntity.version }}</template>
|
||||
|
||||
|
|
@ -108,6 +121,16 @@ export default {
|
|||
{{ tag.name }}
|
||||
</gl-badge>
|
||||
</template>
|
||||
|
||||
<gl-badge
|
||||
v-if="showBadgeProtected"
|
||||
v-gl-tooltip="{ title: $options.i18n.badgeProtectedTooltipText }"
|
||||
icon-size="sm"
|
||||
size="sm"
|
||||
variant="neutral"
|
||||
>
|
||||
{{ __('protected') }}
|
||||
</gl-badge>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
|||
|
|
@ -164,6 +164,7 @@ export default {
|
|||
<div v-if="showTags || showBadgeProtected" class="gl-display-flex gl-gap-2">
|
||||
<package-tags
|
||||
v-if="showTags"
|
||||
class="gl-ml-2"
|
||||
:tags="packageEntity.tags.nodes"
|
||||
hide-label
|
||||
:tag-display-limit="1"
|
||||
|
|
@ -172,11 +173,13 @@ export default {
|
|||
<gl-badge
|
||||
v-if="showBadgeProtected"
|
||||
v-gl-tooltip="{ title: $options.i18n.badgeProtectedTooltipText }"
|
||||
class="gl-ml-2"
|
||||
icon-size="sm"
|
||||
size="sm"
|
||||
variant="neutral"
|
||||
>{{ __('protected') }}</gl-badge
|
||||
>
|
||||
{{ __('protected') }}
|
||||
</gl-badge>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ query getPackageDetails($id: PackagesPackageID!) {
|
|||
pypiSetupUrl
|
||||
composerUrl
|
||||
composerConfigRepositoryUrl
|
||||
packageProtectionRuleExists
|
||||
project {
|
||||
id
|
||||
path
|
||||
|
|
|
|||
|
|
@ -85,12 +85,12 @@ export default {
|
|||
tableCell({
|
||||
key: 'source_full_path',
|
||||
label: s__('BulkImport|Source'),
|
||||
thClass: `gl-w-30p`,
|
||||
thClass: `gl-w-3/10`,
|
||||
}),
|
||||
tableCell({
|
||||
key: 'destination_name',
|
||||
label: s__('BulkImport|Destination'),
|
||||
thClass: `gl-w-30p`,
|
||||
thClass: `gl-w-3/10`,
|
||||
}),
|
||||
tableCell({
|
||||
key: 'created_at',
|
||||
|
|
@ -99,7 +99,7 @@ export default {
|
|||
tableCell({
|
||||
key: 'status',
|
||||
label: __('Status'),
|
||||
thClass: `gl-w-quarter`,
|
||||
thClass: `gl-w-1/4`,
|
||||
}),
|
||||
],
|
||||
|
||||
|
|
|
|||
|
|
@ -54,12 +54,12 @@ export default {
|
|||
tableCell({
|
||||
key: 'source',
|
||||
label: s__('BulkImport|Source'),
|
||||
thClass: 'gl-w-30p',
|
||||
thClass: 'gl-w-3/10',
|
||||
}),
|
||||
tableCell({
|
||||
key: 'destination',
|
||||
label: s__('BulkImport|Destination'),
|
||||
thClass: 'gl-w-40p',
|
||||
thClass: 'gl-w-4/10',
|
||||
}),
|
||||
tableCell({
|
||||
key: 'created_at',
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
import '../webpack';
|
||||
|
||||
import { isEmpty } from 'lodash';
|
||||
import Vue from 'vue';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ export default {
|
|||
<branch-dropdown
|
||||
id="branches"
|
||||
v-model="branch"
|
||||
class="gl-w-half"
|
||||
class="gl-w-1/2"
|
||||
:project-path="projectPath"
|
||||
@createWildcard="branch = $event"
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -70,11 +70,11 @@ export default {
|
|||
:class="{ 'gl-border-t-solid': showDivider }"
|
||||
>
|
||||
<div class="gl-display-flex gl-w-full gl-justify-content-space-between gl-align-items-center">
|
||||
<div class="gl-mr-7 gl-w-quarter">{{ title }}</div>
|
||||
<div class="gl-mr-7 gl-w-1/4">{{ title }}</div>
|
||||
|
||||
<gl-avatars-inline
|
||||
v-if="users.length"
|
||||
class="gl-w-quarter!"
|
||||
class="!gl-w-1/4"
|
||||
:avatars="users"
|
||||
:collapsed="true"
|
||||
:max-visible="$options.MAX_VISIBLE_AVATARS"
|
||||
|
|
|
|||
|
|
@ -193,7 +193,7 @@ export default {
|
|||
},
|
||||
},
|
||||
fields: [
|
||||
{ key: 'spentAt', label: __('Date'), tdClass: 'gl-w-quarter' },
|
||||
{ key: 'spentAt', label: __('Date'), tdClass: 'gl-w-1/4' },
|
||||
{ key: 'timeSpent', label: __('Time spent'), tdClass: 'gl-w-15' },
|
||||
{ key: 'user', label: __('User') },
|
||||
{ key: 'summary', label: __('Summary') },
|
||||
|
|
|
|||
|
|
@ -37,12 +37,12 @@ export default {
|
|||
{
|
||||
key: 'storageType',
|
||||
label: PROJECT_TABLE_LABEL_STORAGE_TYPE,
|
||||
thClass: 'gl-w-90p',
|
||||
thClass: 'gl-w-9/10',
|
||||
},
|
||||
{
|
||||
key: 'value',
|
||||
label: PROJECT_TABLE_LABEL_USAGE,
|
||||
thClass: 'gl-w-10p',
|
||||
thClass: 'gl-w-1/10',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ export default {
|
|||
:alert="alert"
|
||||
:sidebar-collapsed="sidebarStatus"
|
||||
text-class="gl-text-gray-500"
|
||||
class="gl-w-70p"
|
||||
class="gl-w-7/10"
|
||||
@toggle-sidebar="$emit('toggle-sidebar')"
|
||||
@alert-error="$emit('alert-error', $event)"
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -193,7 +193,7 @@ export default {
|
|||
|
||||
<template>
|
||||
<div
|
||||
class="alert-assignees gl-py-5 gl-w-70p"
|
||||
class="alert-assignees gl-py-5 gl-w-7/10"
|
||||
:class="{ 'gl-border-b-1 gl-border-b-solid gl-border-b-gray-100': !sidebarCollapsed }"
|
||||
>
|
||||
<template v-if="sidebarCollapsed">
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ export default {
|
|||
'left-secondary-text'
|
||||
]
|
||||
"
|
||||
class="gl-display-flex gl-align-items-center gl-text-gray-500 gl-min-h-6 gl-min-w-0 gl-flex-grow-1 gl-w-70p gl-md-max-w-70p"
|
||||
class="gl-display-flex gl-align-items-center gl-text-gray-500 gl-min-h-6 gl-min-w-0 gl-flex-grow-1 gl-w-7/10 gl-md-max-w-70p"
|
||||
>
|
||||
<slot name="left-secondary-text"></slot>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -35,32 +35,32 @@ export default {
|
|||
{
|
||||
key: 'name',
|
||||
label: __('Name'),
|
||||
thClass: 'gl-w-40p',
|
||||
thClass: 'gl-w-8/20',
|
||||
},
|
||||
{
|
||||
key: 'projectsCount',
|
||||
label: __('Projects'),
|
||||
thClass: 'gl-w-10p',
|
||||
thClass: 'gl-w-2/20',
|
||||
},
|
||||
{
|
||||
key: 'groupCount',
|
||||
label: __('Groups'),
|
||||
thClass: 'gl-w-10p',
|
||||
thClass: 'gl-w-2/20',
|
||||
},
|
||||
{
|
||||
key: 'createdAt',
|
||||
label: __('Created on'),
|
||||
thClass: 'gl-w-15p',
|
||||
thClass: 'gl-w-3/20',
|
||||
},
|
||||
{
|
||||
key: 'lastActivityOn',
|
||||
label: __('Last activity'),
|
||||
thClass: 'gl-w-15p',
|
||||
thClass: 'gl-w-3/20',
|
||||
},
|
||||
{
|
||||
key: 'settings',
|
||||
label: '',
|
||||
thClass: 'gl-w-10p',
|
||||
thClass: 'gl-w-2/20',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ module Projects
|
|||
feature_category :package_registry
|
||||
urgency :low
|
||||
|
||||
before_action :set_feature_flag_packages_protected_packages, only: :index
|
||||
before_action :set_feature_flag_packages_protected_packages, only: [:index, :show]
|
||||
|
||||
def index; end
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,8 @@ class Projects::PipelinesController < Projects::ApplicationController
|
|||
before_action :pipeline, except: [:index, :new, :create, :charts]
|
||||
before_action :set_pipeline_path, only: [:show]
|
||||
before_action :authorize_read_pipeline!
|
||||
before_action :authorize_read_build!, only: [:index, :show]
|
||||
before_action :authorize_read_build!, only: [:index]
|
||||
before_action :authorize_read_build_on_pipeline!, only: [:show]
|
||||
before_action :authorize_read_ci_cd_analytics!, only: [:charts]
|
||||
before_action :authorize_create_pipeline!, only: [:new, :create]
|
||||
before_action :authorize_update_pipeline!, only: [:retry]
|
||||
|
|
@ -321,6 +322,10 @@ class Projects::PipelinesController < Projects::ApplicationController
|
|||
return access_denied! unless can?(current_user, :cancel_pipeline, @pipeline)
|
||||
end
|
||||
|
||||
def authorize_read_build_on_pipeline!
|
||||
return access_denied! unless can?(current_user, :read_build, @pipeline)
|
||||
end
|
||||
|
||||
def limited_pipelines_count(project, scope = nil)
|
||||
finder = Ci::PipelinesFinder.new(project, current_user, index_params.merge(scope: scope))
|
||||
|
||||
|
|
|
|||
|
|
@ -255,7 +255,7 @@ class ActiveSession
|
|||
# Deprecated legacy format. To be removed in 15.0
|
||||
# See: https://gitlab.com/gitlab-org/gitlab/-/issues/30516
|
||||
# Explanation of why this Marshal.load call is OK:
|
||||
# https://gitlab.com/gitlab-com/gl-security/appsec/appsec-reviews/-/issues/124#note_744576714
|
||||
# https://gitlab.com/gitlab-com/gl-security/product-security/appsec/appsec-reviews/-/issues/124#note_744576714
|
||||
# rubocop:disable Security/MarshalLoad
|
||||
Marshal.load(raw_session)
|
||||
# rubocop:enable Security/MarshalLoad
|
||||
|
|
|
|||
|
|
@ -46,7 +46,3 @@ class ProjectWiki < Wiki
|
|||
container.create_wiki_repository!
|
||||
end
|
||||
end
|
||||
|
||||
# TODO: Remove this once we implement ES support for group wikis.
|
||||
# https://gitlab.com/gitlab-org/gitlab/-/issues/207889
|
||||
ProjectWiki.prepend_mod_with('ProjectWiki')
|
||||
|
|
|
|||
|
|
@ -22,6 +22,16 @@ module Ci
|
|||
can?(:read_dependency, @subject.project)
|
||||
end
|
||||
|
||||
condition(:project_allows_read_build) do
|
||||
can?(:read_build, @subject.project)
|
||||
end
|
||||
|
||||
# Allow reading builds for external pipelines regardless of whether CI/CD is disabled
|
||||
overrides :read_build
|
||||
rule { project_allows_read_build | (external_pipeline & can?(:reporter_access)) }.policy do
|
||||
enable :read_build
|
||||
end
|
||||
|
||||
# Disallow users without permissions from accessing internal pipelines
|
||||
rule { ~can?(:read_build) & ~external_pipeline }.policy do
|
||||
prevent :read_pipeline
|
||||
|
|
|
|||
|
|
@ -1,31 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'grpc'
|
||||
|
||||
# grpc v1.42 and up introduced a regression where a non-standard
|
||||
# exception, `GRPC::Core::CallError`, is raised instead of
|
||||
# DeadlineExceeded: https://github.com/grpc/grpc/issues/33283.
|
||||
# This patch applies https://github.com/grpc/grpc/pull/33565.
|
||||
module Gitlab
|
||||
module GRPCPatch
|
||||
module ActiveCall
|
||||
def remote_read
|
||||
super
|
||||
ensure
|
||||
# Ensure we don't attempt to request the initial metadata again
|
||||
# in case an exception occurs.
|
||||
@metadata_received = true # rubocop:disable Gitlab/ModuleWithInstanceVariables
|
||||
end
|
||||
|
||||
def receive_and_check_status
|
||||
super
|
||||
ensure
|
||||
# Ensure we don't attempt to request the initial metadata again
|
||||
# in case an exception occurs.
|
||||
@metadata_received = true # rubocop:disable Gitlab/ModuleWithInstanceVariables
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
GRPC::ActiveCall.prepend Gitlab::GRPCPatch::ActiveCall
|
||||
|
|
@ -1,4 +1,7 @@
|
|||
---
|
||||
filenames:
|
||||
- app/assets/javascripts/integrations/beyond_identity/graphql/mutations/create_beyond_identity_exclusion.mutation.graphql
|
||||
- app/assets/javascripts/integrations/beyond_identity/graphql/mutations/delete_beyond_identity_exclusion.mutation.graphql
|
||||
- app/assets/javascripts/integrations/beyond_identity/graphql/queries/beyond_identity_exclusions.query.graphql
|
||||
- ee/app/assets/javascripts/oncall_schedules/graphql/mutations/update_oncall_schedule_rotation.mutation.graphql
|
||||
- app/assets/javascripts/security_configuration/graphql/set_container_scanning_for_registry.graphql
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
const path = require('path');
|
||||
const plugin = require('tailwindcss/plugin');
|
||||
const tailwindDefaults = require('@gitlab/ui/tailwind.defaults');
|
||||
const { range, round } = require('lodash');
|
||||
|
||||
// Try loading the tailwind css_in_js, in case they exist
|
||||
let utilities = {};
|
||||
|
|
@ -33,6 +34,8 @@ function gitLabUIUtilities({ addUtilities }) {
|
|||
});
|
||||
}
|
||||
|
||||
const widthPercentageScales = [8, 10, 20];
|
||||
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
presets: [tailwindDefaults],
|
||||
|
|
@ -132,6 +135,20 @@ module.exports = {
|
|||
'x0-y2-b4-s0': '0 2px 4px 0 #0000001a',
|
||||
'x0-y0-b3-s1-blue-500': 'inset 0 0 3px 1px var(--blue-500, #1f75cb)',
|
||||
},
|
||||
// TODO: backport these width percentage classes to GitLab UI
|
||||
width: widthPercentageScales.reduce((accumulator1, denominator) => {
|
||||
return {
|
||||
...accumulator1,
|
||||
...range(1, denominator).reduce((accumulator2, numerator) => {
|
||||
const width = (numerator / denominator) * 100;
|
||||
|
||||
return {
|
||||
...accumulator2,
|
||||
[`${numerator}/${denominator}`]: `${round(width, 6)}%`,
|
||||
};
|
||||
}, {}),
|
||||
};
|
||||
}, {}),
|
||||
zIndex: {
|
||||
1: '1',
|
||||
2: '2',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
migration_job_name: RemoveNamespaceFromOsTypeSbomComponents
|
||||
description: Removes namespace from operating system components
|
||||
feature_category: software_composition_analysis
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/151444
|
||||
milestone: '17.0'
|
||||
queued_migration_version: 20240425205205
|
||||
finalize_after: '2024-05-06'
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class BackfillDeploymentApprovalData < Gitlab::Database::Migration[2.2]
|
||||
milestone '17.0'
|
||||
restrict_gitlab_migration gitlab_schema: :gitlab_main
|
||||
disable_ddl_transaction!
|
||||
|
||||
BATCH_SIZE = 500
|
||||
|
||||
def up
|
||||
protected_environments_model = define_batchable_model('protected_environments')
|
||||
|
||||
protected_environments_model.each_batch(of: BATCH_SIZE) do |relation|
|
||||
connection.execute(
|
||||
<<~SQL
|
||||
INSERT INTO protected_environment_approval_rules
|
||||
(protected_environment_id,
|
||||
created_at,
|
||||
updated_at,
|
||||
required_approvals,
|
||||
access_level,
|
||||
user_id,
|
||||
group_id,
|
||||
group_inheritance_type)
|
||||
SELECT protected_environments.id,
|
||||
Now(),
|
||||
Now(),
|
||||
protected_environments.required_approval_count,
|
||||
protected_environment_deploy_access_levels.access_level,
|
||||
protected_environment_deploy_access_levels.user_id,
|
||||
protected_environment_deploy_access_levels.group_id,
|
||||
protected_environment_deploy_access_levels.group_inheritance_type
|
||||
|
||||
FROM
|
||||
protected_environment_deploy_access_levels
|
||||
INNER JOIN protected_environments ON protected_environments.id = protected_environment_deploy_access_levels.protected_environment_id
|
||||
WHERE
|
||||
protected_environments.required_approval_count > 0
|
||||
AND NOT EXISTS (
|
||||
SELECT
|
||||
1
|
||||
FROM
|
||||
protected_environment_approval_rules
|
||||
WHERE
|
||||
protected_environment_id = protected_environments.id
|
||||
)
|
||||
AND protected_environments.id IN (#{relation.select(:id).to_sql})
|
||||
SQL
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def down
|
||||
# noop
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class QueueRemoveNamespaceFromOsTypeSbomComponents < Gitlab::Database::Migration[2.2]
|
||||
milestone '17.0'
|
||||
|
||||
restrict_gitlab_migration gitlab_schema: :gitlab_main
|
||||
|
||||
MIGRATION = "RemoveNamespaceFromOsTypeSbomComponents"
|
||||
DELAY_INTERVAL = 2.minutes
|
||||
BATCH_SIZE = 2000
|
||||
SUB_BATCH_SIZE = 500
|
||||
|
||||
def up
|
||||
queue_batched_background_migration(
|
||||
MIGRATION,
|
||||
:sbom_components,
|
||||
:id,
|
||||
job_interval: DELAY_INTERVAL,
|
||||
batch_size: BATCH_SIZE,
|
||||
sub_batch_size: SUB_BATCH_SIZE
|
||||
)
|
||||
end
|
||||
|
||||
def down
|
||||
delete_batched_background_migration(MIGRATION, :sbom_components, :id, [])
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
e28379ba90924aaa7171e44db9340404e850aa2307a160eb48e99caa813dc98f
|
||||
|
|
@ -0,0 +1 @@
|
|||
238ea0baf71474f54faf19b6e8cdd41c35aa396e0e7641aa1808157ff1fe20ec
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
redirect_to: '../audit_event_types.md'
|
||||
remove_date: '2024-03-22'
|
||||
---
|
||||
|
||||
This document was moved to [another location](../audit_event_types.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <2024-03-22>. -->
|
||||
<!-- Redirects that point to other docs in the same project expire in three months. -->
|
||||
<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
|
||||
|
|
@ -4,7 +4,7 @@ group: Gitaly
|
|||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
# Bundle URI
|
||||
# Bundle URIs
|
||||
|
||||
DETAILS:
|
||||
**Status:** Experiment
|
||||
|
|
@ -20,10 +20,10 @@ is not ready for production use.
|
|||
|
||||
Gitaly supports Git [bundle URIs](https://git-scm.com/docs/bundle-uri). Bundle
|
||||
URIs are locations where Git can download one or more bundles to bootstrap the
|
||||
object database before fetching the remaining objects from a remote. Bundle URI
|
||||
is built in to the Git protocol.
|
||||
object database before fetching the remaining objects from a remote. Bundle URIs
|
||||
are built in to the Git protocol.
|
||||
|
||||
Using Bundle URI can:
|
||||
Using Bundle URIs can:
|
||||
|
||||
- Speed up clones and fetches for users with a poor network connection to the
|
||||
GitLab server. The bundles can be stored on a CDN, making them available
|
||||
|
|
@ -32,15 +32,13 @@ Using Bundle URI can:
|
|||
bundles from somewhere else, the remaining work to incrementally fetch missing
|
||||
objects and references creates a lot less load on the server.
|
||||
|
||||
Prerequisites:
|
||||
## Prerequisites
|
||||
|
||||
- The Git config [`transfer.bundleURI`](https://git-scm.com/docs/git-config#Documentation/git-config.txt-transferbundleURI)
|
||||
- The Git configuration [`transfer.bundleURI`](https://git-scm.com/docs/git-config#Documentation/git-config.txt-transferbundleURI)
|
||||
must be enabled on Git clients.
|
||||
- GitLab Runner 16.6 or later.
|
||||
|
||||
- In CI/CD pipeline configuration, the
|
||||
[default Git strategy](../../ci/pipelines/settings.md#choose-the-default-git-strategy)
|
||||
set to `git clone`.
|
||||
[default Git strategy](../../ci/pipelines/settings.md#choose-the-default-git-strategy) set to `git clone`.
|
||||
|
||||
## Server configuration
|
||||
|
||||
|
|
@ -228,7 +226,7 @@ sudo /opt/gitlab/embedded/bin/gitaly bundle-uri \
|
|||
```
|
||||
|
||||
This command generates the bundle and stores it on the configured storage service.
|
||||
Gitaly does not automatically refresh the generated bundle, so when want to generate
|
||||
Gitaly does not automatically refresh the generated bundle. When want to generate
|
||||
a more recent version of a bundle, you must the run command again.
|
||||
|
||||
You can schedule this command with a tool like `cron(8)`.
|
||||
|
|
@ -261,9 +259,9 @@ Updating files: 100% (71304/71304), done.
|
|||
|
||||
In the above example:
|
||||
|
||||
- When not using Bundle URI, there were 5,271,177 objects received from the
|
||||
- When not using a Bundle URI, there were 5,271,177 objects received from the
|
||||
GitLab server.
|
||||
- When using Bundle URL, there were 1,322,255 objects received from the GitLab
|
||||
- When using a Bundle URI, there were 1,322,255 objects received from the GitLab
|
||||
server.
|
||||
|
||||
This reduction means GitLab needs to pack together fewer objects (in the above
|
||||
|
|
@ -191,10 +191,10 @@ For more information on the other subcommands, run `gitaly --help`.
|
|||
When backing up or syncing repositories using tools other than GitLab, you must [prevent writes](../../administration/backup_restore/backup_gitlab.md#prevent-writes-and-copy-the-git-repository-data)
|
||||
while copying repository data.
|
||||
|
||||
### Bundle URI
|
||||
### Bundle URIs
|
||||
|
||||
You can use Git [bundle URIs](https://git-scm.com/docs/bundle-uri) with Gitaly.
|
||||
For more information, see the [Bundle URI documentation](bundle_uri.md).
|
||||
For more information, see the [Bundle URIs documentation](bundle_uris.md).
|
||||
|
||||
## Gitaly Cluster
|
||||
|
||||
|
|
|
|||
|
|
@ -177,6 +177,7 @@ and alter them as needed:
|
|||
- `10.days.from_now`
|
||||
- `2.weeks.from_now`
|
||||
- `3.months.from_now`
|
||||
- `1.year.from_now`
|
||||
|
||||
Each of the following scripts also limits the search to 50 results with `.limit(50)`, but this number can also be changed as needed:
|
||||
|
||||
|
|
|
|||
|
|
@ -1,16 +0,0 @@
|
|||
---
|
||||
stage: Monitor
|
||||
group: Respond
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
remove_date: '2020-05-22'
|
||||
redirect_to: '../prometheus/index.md'
|
||||
---
|
||||
|
||||
# GitLab Configuration (removed)
|
||||
|
||||
DETAILS:
|
||||
**Tier:** Free, Premium, Ultimate
|
||||
**Offering:** Self-managed
|
||||
|
||||
This feature was [removed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/30786) in GitLab 13.0.
|
||||
Use the [Prometheus integration](../prometheus/index.md) instead.
|
||||
|
|
@ -24,7 +24,7 @@ contribution model in a cellular architecture.
|
|||
A Cells 1.0 is meant to target internal customers that have the following expectations:
|
||||
|
||||
1. They want to use our multi-tenant SaaS solution (GitLab.com) to serve their Organization.
|
||||
1. They accept that they may receive updates later than the rest of GitLab.com. Note that when GitLab does a patch release, the Delivery team makes sure that production (every cell) runs the patch release version before making the release public. This does not mean that outside of a patch release, all the cells run the same version of GitLab. See [this private discussion](https://gitlab.com/gitlab-com/gl-security/appsec/threat-models/-/issues/45#note_1794904358) for more information.
|
||||
1. They accept that they may receive updates later than the rest of GitLab.com. Note that when GitLab does a patch release, the Delivery team makes sure that production (every cell) runs the patch release version before making the release public. This does not mean that outside of a patch release, all the cells run the same version of GitLab. See [this private discussion](https://gitlab.com/gitlab-com/gl-security/product-security/appsec/threat-models/-/issues/45#note_1794904358) for more information.
|
||||
1. They want to use an environment with higher degree of isolation to rest of the system.
|
||||
1. They want to control all users that contribute to their Organization.
|
||||
1. Their groups and projects are meant to be private.
|
||||
|
|
|
|||
|
|
@ -647,7 +647,7 @@ hours, and always reading from two partitions through a routing table. The
|
|||
strategy to partition these tables is well understood, but requires a solid
|
||||
Ruby-based automation to manage the creation and deletion of these partitions.
|
||||
To achieve that we will collaborate with the Database team to adapt
|
||||
[existing database partitioning tools](../../../development/database/table_partitioning.md)
|
||||
[existing database partitioning tools](../../../development/database/partitioning/index.md)
|
||||
to support CI/CD data partitioning.
|
||||
|
||||
## Iterating to reduce the risk
|
||||
|
|
|
|||
|
|
@ -159,6 +159,8 @@ test_job:
|
|||
|
||||
#### Array type
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/407176) in GitLab 16.11.
|
||||
|
||||
The content of the items in an array type can be any valid YAML map, sequence, or scalar. More complex YAML features
|
||||
like [`!reference`](yaml_optimization.md#reference-tags) cannot be used.
|
||||
|
||||
|
|
|
|||
|
|
@ -227,7 +227,7 @@ To add a new audit event type:
|
|||
|
||||
### Generate documentation
|
||||
|
||||
Audit event types documentation is automatically generated and [published](../../administration/audit_event_streaming/audit_event_types.md)
|
||||
Audit event types documentation is automatically generated and [published](../../administration/audit_event_types.md)
|
||||
to the GitLab documentation site.
|
||||
|
||||
If you add a new audit event type, run the
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ EE: true
|
|||
- Any change that introduces a database migration, whether it's regular, post,
|
||||
or data migration, **must** have a changelog entry, even if it is behind a
|
||||
disabled feature flag.
|
||||
- [Security fixes](https://gitlab.com/gitlab-org/release/docs/blob/master/general/security/developer.md)
|
||||
- [Security fixes](https://gitlab.com/gitlab-org/release/docs/blob/master/general/security/engineer.md)
|
||||
**must** have a changelog entry, with `Changelog` trailer set to `security`.
|
||||
- Any user-facing change **must** have a changelog entry. Example: "GitLab now
|
||||
uses system fonts for all text."
|
||||
|
|
|
|||
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
redirect_to: 'partitioning/index.md'
|
||||
remove_date: '2024-04-16'
|
||||
---
|
||||
|
||||
This document was moved to [another location](partitioning/index.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <2024-04-16>. -->
|
||||
<!-- Redirects that point to other docs in the same project expire in three months. -->
|
||||
<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
|
||||
|
|
@ -24,7 +24,7 @@ Complementary reads:
|
|||
|
||||
- [Avoiding required stops](avoiding_required_stops.md)
|
||||
- [Contribute to GitLab](contributing/index.md)
|
||||
- [Security process for developers](https://gitlab.com/gitlab-org/release/docs/blob/master/general/security/developer.md#security-releases-critical-non-critical-as-a-developer)
|
||||
- [Security process for developers](https://gitlab.com/gitlab-org/release/docs/blob/master/general/security/engineer.md#security-releases-critical-non-critical-as-a-developer)
|
||||
- [Patch release process for developers](https://gitlab.com/gitlab-org/release/docs/blob/master/general/patch/process.md#process-for-developers)
|
||||
- [Guidelines for implementing Enterprise Edition features](ee_features.md)
|
||||
- [Adding a new service component to GitLab](adding_service_component.md)
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ DETAILS:
|
|||
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
|
||||
|
||||
You can seed issues specifically for working with the
|
||||
[Insights charts](../user/group/insights/index.md) with the
|
||||
[Insights charts](../user/project/insights/index.md) with the
|
||||
`gitlab:seed:insights:issues` task:
|
||||
|
||||
```shell
|
||||
|
|
|
|||
|
|
@ -17,16 +17,16 @@ For each of the guidelines listed in this document, AppSec aims to have a SAST r
|
|||
|
||||
| Guideline | Rule | Status |
|
||||
|---|---|---|
|
||||
| [Regular Expressions](#regular-expressions-guidelines) | [Link](https://gitlab.com/gitlab-com/gl-security/appsec/sast-custom-rules/-/issues/13) | ⏳ In progress |
|
||||
| [Regular Expressions](#regular-expressions-guidelines) | [Link](https://gitlab.com/gitlab-com/gl-security/product-security/appsec/sast-custom-rules/-/issues/13) | ⏳ In progress |
|
||||
| [ReDOS](#denial-of-service-redos--catastrophic-backtracking) | Pending | ❌ |
|
||||
| [SSRF](#server-side-request-forgery-ssrf) | [1](https://gitlab.com/gitlab-com/gl-security/appsec/sast-custom-rules/-/blob/main/secure-coding-guidelines/ruby_insecure_url.yml), [2](https://gitlab.com/gitlab-com/gl-security/appsec/sast-custom-rules/-/blob/main/secure-coding-guidelines/ruby_insecure_http.yml?ref_type=heads) | ✅ |
|
||||
| [SSRF](#server-side-request-forgery-ssrf) | [1](https://gitlab.com/gitlab-com/gl-security/product-security/appsec/sast-custom-rules/-/blob/main/secure-coding-guidelines/ruby_insecure_url.yml), [2](https://gitlab.com/gitlab-com/gl-security/product-security/appsec/sast-custom-rules/-/blob/main/secure-coding-guidelines/ruby_insecure_http.yml?ref_type=heads) | ✅ |
|
||||
| [XSS](#xss-guidelines) | Pending | ❌ |
|
||||
| [Path traversal](#path-traversal-guidelines) (Ruby) | [Link](https://gitlab.com/gitlab-com/gl-security/appsec/sast-custom-rules/-/blob/main/secure-coding-guidelines/ruby_path_traversal.yml?ref_type=heads) | ✅ |
|
||||
| [Path traversal](#path-traversal-guidelines) (Ruby) | [Link](https://gitlab.com/gitlab-com/gl-security/product-security/appsec/sast-custom-rules/-/blob/main/secure-coding-guidelines/ruby_path_traversal.yml?ref_type=heads) | ✅ |
|
||||
| [Path traversal](#path-traversal-guidelines) (Go) | Pending | ❌ |
|
||||
| [OS command injection](#os-command-injection-guidelines) (Ruby) | [Link](https://gitlab.com/gitlab-com/gl-security/appsec/sast-custom-rules/-/blob/main/secure-coding-guidelines/ruby_command_injection.yml?ref_type=heads) | ✅ |
|
||||
| [OS command injection](#os-command-injection-guidelines) (Ruby) | [Link](https://gitlab.com/gitlab-com/gl-security/product-security/appsec/sast-custom-rules/-/blob/main/secure-coding-guidelines/ruby_command_injection.yml?ref_type=heads) | ✅ |
|
||||
| [OS command injection](#os-command-injection-guidelines) (Go) | Pending | ❌ |
|
||||
| [Insecure TLS ciphers](#tls-minimum-recommended-version) | [Link](https://gitlab.com/gitlab-com/gl-security/appsec/sast-custom-rules/-/blob/main/secure-coding-guidelines/ruby_insecure_ciphers.yml?ref_type=heads) | ✅ |
|
||||
| [Archive operations](#working-with-archive-files) (Ruby) | [Link](https://gitlab.com/gitlab-com/gl-security/appsec/sast-custom-rules/-/blob/main/secure-coding-guidelines/ruby_insecure_archive_operations.yml?ref_type=heads) | ✅ |
|
||||
| [Insecure TLS ciphers](#tls-minimum-recommended-version) | [Link](https://gitlab.com/gitlab-com/gl-security/product-security/appsec/sast-custom-rules/-/blob/main/secure-coding-guidelines/ruby_insecure_ciphers.yml?ref_type=heads) | ✅ |
|
||||
| [Archive operations](#working-with-archive-files) (Ruby) | [Link](https://gitlab.com/gitlab-com/gl-security/product-security/appsec/sast-custom-rules/-/blob/main/secure-coding-guidelines/ruby_insecure_archive_operations.yml?ref_type=heads) | ✅ |
|
||||
| [Archive operations](#working-with-archive-files) (Go) | Pending | ❌ |
|
||||
| [URL spoofing](#url-spoofing) | Pending | ❌ |
|
||||
| [GitLab internal authorization](#gitlab-internal-authorization) | N/A | N/A |
|
||||
|
|
@ -50,7 +50,7 @@ MR. Also add the Guideline to the "SAST Coverage" table above.
|
|||
|
||||
### Creating new semgrep rules
|
||||
|
||||
1. These should go in the [SAST custom rules](https://gitlab.com/gitlab-com/gl-security/appsec/sast-custom-rules/-/tree/main/secure-coding-guidelines) project.
|
||||
1. These should go in the [SAST custom rules](https://gitlab.com/gitlab-com/gl-security/product-security/appsec/sast-custom-rules/-/tree/main/secure-coding-guidelines) project.
|
||||
1. Each rule should have a test file with the name set to `rule_name.rb` or `rule_name.go`.
|
||||
1. Each rule should have a well-defined `message` field in the YAML file, with clear instructions for the developer.
|
||||
1. The severity should be set to `INFO` for low-severity issues not requiring involvement from AppSec, and `WARNING` for issues that require AppSec review. The bot will ping AppSec accordingly.
|
||||
|
|
@ -1239,7 +1239,7 @@ end
|
|||
|
||||
##### Go
|
||||
|
||||
You are encouraged to use the secure archive utilities provided by [LabSec](https://gitlab.com/gitlab-com/gl-security/appsec/labsec) which will handle Zip Slip and symlink vulnerabilities for you. The LabSec utilities are also context aware which makes it possible to cancel or timeout extractions.
|
||||
You are encouraged to use the secure archive utilities provided by [LabSec](https://gitlab.com/gitlab-com/gl-security/product-security/appsec/labsec) which will handle Zip Slip and symlink vulnerabilities for you. The LabSec utilities are also context aware which makes it possible to cancel or timeout extractions.
|
||||
|
||||
In case the LabSec utilities do not fit your needs, here is an example for extracting a zip file with protection against symlink attacks:
|
||||
|
||||
|
|
@ -1379,7 +1379,7 @@ Add the new prefix to:
|
|||
- [`gitlab/app/assets/javascripts/lib/utils/secret_detection.js`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/assets/javascripts/lib/utils/secret_detection.js)
|
||||
- The [GitLab Secret Detection gem](https://gitlab.com/gitlab-org/gitlab/-/tree/master/gems/gitlab-secret_detection)
|
||||
- GitLab [secrets SAST analyzer](https://gitlab.com/gitlab-org/security-products/analyzers/secrets)
|
||||
- [Tokinator](https://gitlab.com/gitlab-com/gl-security/appsec/tokinator/-/blob/main/CONTRIBUTING.md?ref_type=heads) (internal tool / team members only)
|
||||
- [Tokinator](https://gitlab.com/gitlab-com/gl-security/product-security/appsec/tokinator/-/blob/main/CONTRIBUTING.md?ref_type=heads) (internal tool / team members only)
|
||||
- [Token Overview](../security/token_overview.md) documentation
|
||||
|
||||
### Examples
|
||||
|
|
|
|||
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
redirect_to: '../../solutions/cloud/aws/index.md'
|
||||
remove_date: '2024-03-31'
|
||||
---
|
||||
|
||||
This document was moved to [Solutions](../../solutions/cloud/aws/index.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <YYYY-MM-DD>. -->
|
||||
<!-- Redirects that point to other docs in the same project expire in three months. -->
|
||||
<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
redirect_to: '../../solutions/cloud/aws/gitlab_instance_on_aws.md'
|
||||
remove_date: '2024-03-31'
|
||||
---
|
||||
|
||||
This document was moved to [Solutions](../../solutions/cloud/aws/gitlab_instance_on_aws.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <YYYY-MM-DD>. -->
|
||||
<!-- Redirects that point to other docs in the same project expire in three months. -->
|
||||
<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
redirect_to: '../../solutions/cloud/aws/gitaly_sre_for_aws.md'
|
||||
remove_date: '2024-03-31'
|
||||
---
|
||||
|
||||
This document was moved to [Solutions](../../solutions/cloud/aws/gitaly_sre_for_aws.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <YYYY-MM-DD>. -->
|
||||
<!-- Redirects that point to other docs in the same project expire in three months. -->
|
||||
<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
redirect_to: 'index.md'
|
||||
remove_date: '2024-03-31'
|
||||
---
|
||||
|
||||
This document was moved to [AWS](index.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <YYYY-MM-DD>. -->
|
||||
<!-- Redirects that point to other docs in the same project expire in three months. -->
|
||||
<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
|
||||
|
|
@ -50,7 +50,7 @@ Security incidents related to credentials exposure can vary in severity from low
|
|||
#### Event types
|
||||
|
||||
- Review the available [audit events](../administration/audit_event_reports.md) for your group or namespace.
|
||||
- Adversaries may attempt to create tokens, SSH keys, or user accounts to maintain persistence. Look for [audit events](../administration/audit_event_streaming/audit_event_types.md) related to these activities.
|
||||
- Adversaries may attempt to create tokens, SSH keys, or user accounts to maintain persistence. Look for [audit events](../administration/audit_event_types.md) related to these activities.
|
||||
- Focus on CI-related [audit events](../administration/audit_event_types.md#continuous-integration) to identify any modifications to CI/CD variables.
|
||||
- Review [job logs](../administration/job_logs.md) for any pipelines ran by an adversary
|
||||
|
||||
|
|
|
|||
|
|
@ -159,7 +159,7 @@ You and project members with at least the Developer role can view the Insights r
|
|||
## View merge request and issue analytics
|
||||
|
||||
In addition to the Insights reports, you can get detailed analytics on the merge requests and issues of your project.
|
||||
[Merge request analytics](../../user/analytics/merge_request_analytics.md) and [Issue analytics](../../user/analytics/issue_analytics.md) display charts and tables with metrics such as assignees, merge request throughput, and issue status.
|
||||
[Merge request analytics](../../user/analytics/merge_request_analytics.md) and [Issue analytics](../../user/group/issues_analytics/index.md) display charts and tables with metrics such as assignees, merge request throughput, and issue status.
|
||||
|
||||
To view merge request and issue analytics, in the `My website` project, select **Analyze > Merge request analytics** or **Analyze > Issue analytics**.
|
||||
|
||||
|
|
|
|||
|
|
@ -241,7 +241,7 @@ The DORA metrics are displayed on the following charts:
|
|||
|
||||
- [Value Streams Dashboard](value_streams_dashboard.md), which helps you identify trends, patterns, and opportunities for improvement. DORA metrics are displayed in the [metrics comparison panel](value_streams_dashboard.md#devsecops-metrics-comparison-panel) and the [DORA Performers score panel](value_streams_dashboard.md#dora-performers-score-panel).
|
||||
- [CI/CD analytics charts](ci_cd_analytics.md), which show pipeline success rates and duration, and the history of DORA metrics over time.
|
||||
- Insights reports for [groups](../group/insights/index.md) and [projects](../group/value_stream_analytics/index.md), where you can also use [DORA query parameters](../../user/project/insights/index.md#dora-query-parameters) to create custom charts.
|
||||
- Insights reports for [groups](../project/insights/index.md) and [projects](../group/value_stream_analytics/index.md), where you can also use [DORA query parameters](../../user/project/insights/index.md#dora-query-parameters) to create custom charts.
|
||||
|
||||
### DORA metrics data aggregation
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
redirect_to: '../group/issues_analytics/index.md'
|
||||
remove_date: '2024-04-05'
|
||||
---
|
||||
|
||||
This document was moved to [another location](../group/issues_analytics/index.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <2024-04-05>. -->
|
||||
<!-- Redirects that point to other docs in the same project expire in three months. -->
|
||||
<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
|
||||
|
|
@ -290,7 +290,12 @@ triaging. You can group by:
|
|||
- Status
|
||||
- Severity
|
||||
- Tool
|
||||
- OWASP top 10 (latest published)
|
||||
- OWASP top 10 2017
|
||||
|
||||
WARNING:
|
||||
Support for grouping by OWASP top 10 2017 was
|
||||
[deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/458835) in GitLab 17.0 and is planned for
|
||||
removal in 17.3. Support for grouping by OWASP top 10 2021 is proposed in [issue 440182](https://gitlab.com/gitlab-org/gitlab/-/issues/440182) for GitLab 17.3.
|
||||
|
||||
To group vulnerabilities in the vulnerability report:
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
redirect_to: 'index.md#kubernetes-integration-glossary'
|
||||
remove_date: '2024-04-17'
|
||||
---
|
||||
|
||||
This document was moved to [another location](index.md#kubernetes-integration-glossary).
|
||||
|
||||
<!-- This redirect file can be deleted after <2024-04-17>. -->
|
||||
<!-- Redirects that point to other docs in the same project expire in three months. -->
|
||||
<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
|
||||
|
|
@ -118,6 +118,11 @@ There's no exact formula to reliably estimate a migration. However, the average
|
|||
| References | 5 |
|
||||
| Push Rule | 0.1 |
|
||||
|
||||
Though it's difficult to predict migration duration, we've seen:
|
||||
|
||||
- 100 projects (19.9k issues, 83k merge requests, 100k+ pipelines) migrated in 8 hours.
|
||||
- 1926 projects (22k issues, 160k merge requests, 1.1 million pipelines) migrated in 34 hours.
|
||||
|
||||
If you are migrating large projects and encounter problems with timeouts or duration of the migration, see [Reducing migration duration](#reducing-migration-duration).
|
||||
|
||||
## Limits
|
||||
|
|
|
|||
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
redirect_to: '../../project/insights/index.md'
|
||||
remove_date: '2024-04-20'
|
||||
---
|
||||
|
||||
This document was moved to [another location](../../project/insights/index.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <YYYY-MM-DD>. -->
|
||||
<!-- Redirects that point to other docs in the same project expire in three months. -->
|
||||
<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
|
||||
|
|
@ -60,7 +60,7 @@ The following table lists project permissions available for each role:
|
|||
|
||||
| Action | Guest | Reporter | Developer | Maintainer | Owner | Notes |
|
||||
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------|----------|-----------|------------|-------|-------|
|
||||
| [Analytics](analytics/index.md):<br>View [issue analytics](analytics/issue_analytics.md) | ✓ | ✓ | ✓ | ✓ | ✓ | |
|
||||
| [Analytics](analytics/index.md):<br>View [issue analytics](group/issues_analytics/index.md) | ✓ | ✓ | ✓ | ✓ | ✓ | |
|
||||
| [Analytics](analytics/index.md):<br>View [value stream analytics](group/value_stream_analytics/index.md) | ✓ | ✓ | ✓ | ✓ | ✓ | |
|
||||
| [Analytics](analytics/index.md):<br>View [DORA metrics](analytics/ci_cd_analytics.md) | | ✓ | ✓ | ✓ | ✓ | |
|
||||
| [Analytics](analytics/index.md):<br>View [CI/CD analytics](analytics/ci_cd_analytics.md) | | ✓ | ✓ | ✓ | ✓ | |
|
||||
|
|
@ -305,7 +305,7 @@ The following table lists group permissions available for each role:
|
|||
| View [group wiki](project/wiki/group.md) pages | ✓ | ✓ | ✓ | ✓ | ✓ | Guests: In addition, if your group is public or internal, all users who can see the group can also see group wiki pages. |
|
||||
| View [Insights](project/insights/index.md) | ✓ | ✓ | ✓ | ✓ | ✓ | |
|
||||
| View [Insights](project/insights/index.md) charts | ✓ | ✓ | ✓ | ✓ | ✓ | |
|
||||
| View [Issue analytics](analytics/issue_analytics.md) | ✓ | ✓ | ✓ | ✓ | ✓ | |
|
||||
| View [Issue analytics](group/issues_analytics/index.md) | ✓ | ✓ | ✓ | ✓ | ✓ | |
|
||||
| View Contribution analytics | ✓ | ✓ | ✓ | ✓ | ✓ | |
|
||||
| View group [epic](group/epics/index.md) | ✓ | ✓ | ✓ | ✓ | ✓ | |
|
||||
| View value stream analytics | ✓ | ✓ | ✓ | ✓ | ✓ | |
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue