+
### The `direction` GraphQL argument for `ciJobTokenScopeRemoveProject` is deprecated
@@ -559,7 +573,7 @@ The `Project.services` GraphQL field is deprecated. A `Project.integrations` fie
The `direction` GraphQL argument for the `ciJobTokenScopeRemoveProject` mutation is deprecated. Following the [default CI/CD job token scope change](https://docs.gitlab.com/ee/update/deprecations.html#default-cicd-job-token-ci_job_token-scope-changed) announced in GitLab 15.9, the `direction` argument will default to `INBOUND` and `OUTBOUND` will no longer be valid in GitLab 17.0. We will remove the `direction` argument in GitLab 18.0.
-If you are using `OUTBOUND` with the `direction` argument to control the direction of your project's token access, your pipeline that use job tokens risk failing authentication. To ensure pipelines continue to run as expected, you will need to explicitly [add the other projects to your project's allowlist](https://docs.gitlab.com/ee/ci/jobs/ci_job_token.html#add-a-project-to-the-job-token-allowlist).
+If you are using `OUTBOUND` with the `direction` argument to control the direction of your project's token access, your pipeline that use job tokens risk failing authentication. To ensure pipelines continue to run as expected, you will need to explicitly [add the other projects to your project's allowlist](https://docs.gitlab.com/ee/ci/jobs/ci_job_token.html#add-a-group-or-project-to-the-job-token-allowlist).
@@ -2064,20 +2078,6 @@ Due to limited customer usage and capabilities, the Visual Reviews feature for R
-
### The `gitlab-runner exec` command is deprecated
@@ -2442,7 +2442,7 @@ Any API calls to change the rate limits for `user_email_lookup_limit` must use `
- To discuss this change or learn more, see the [deprecation issue](https://gitlab.com/gitlab-org/gitlab/-/issues/420678).
-Starting in 16.6, projects that are **public** or **internal** will no longer authorize job token requests from projects that are **not** on the project's allowlist when [**Limit access to this project**](https://docs.gitlab.com/ee/ci/jobs/ci_job_token.html#add-a-project-to-the-job-token-allowlist) is enabled.
+Starting in 16.6, projects that are **public** or **internal** will no longer authorize job token requests from projects that are **not** on the project's allowlist when [**Limit access to this project**](https://docs.gitlab.com/ee/ci/jobs/ci_job_token.html#add-a-group-or-project-to-the-job-token-allowlist) is enabled.
If you have [public or internal](https://docs.gitlab.com/ee/user/public_access.html#change-project-visibility) projects with the **Limit access to this project** setting enabled, you must add any projects which make job token requests to your project's allowlist for continued authorization.
@@ -2892,7 +2892,7 @@ These three variables will be removed in GitLab 16.0.
In GitLab 14.4 we introduced the ability to [limit your project's CI/CD job token](https://docs.gitlab.com/ee/ci/jobs/ci_job_token.html#limit-your-projects-job-token-access) (`CI_JOB_TOKEN`) access to make it more secure. You can prevent job tokens **from your project's** pipelines from being used to **access other projects**. When enabled with no other configuration, your pipelines cannot access other projects. To use the job token to access other projects from your pipeline, you must list those projects explicitly in the **Limit CI_JOB_TOKEN access** setting's allowlist, and you must be a maintainer in all the projects.
-The job token functionality was updated in 15.9 with a better security setting to [allow access to your project with a job token](https://docs.gitlab.com/ee/ci/jobs/ci_job_token.html#add-a-project-to-the-job-token-allowlist). When enabled with no other configuration, job tokens **from other projects** cannot **access your project**. Similar to the older setting, you can optionally allow other projects to access your project with a job token if you list those projects explicitly in the **Allow access to this project with a CI_JOB_TOKEN** setting's allowlist. With this new setting, you must be a maintainer in your own project, but only need to have the Guest role in the other projects.
+The job token functionality was updated in 15.9 with a better security setting to [allow access to your project with a job token](https://docs.gitlab.com/ee/ci/jobs/ci_job_token.html#add-a-group-or-project-to-the-job-token-allowlist). When enabled with no other configuration, job tokens **from other projects** cannot **access your project**. Similar to the older setting, you can optionally allow other projects to access your project with a job token if you list those projects explicitly in the **Allow access to this project with a CI_JOB_TOKEN** setting's allowlist. With this new setting, you must be a maintainer in your own project, but only need to have the Guest role in the other projects.
As a result, the **Limit** setting is deprecated in preference of the better **Allow access** setting. In GitLab 16.0 the **Limit** setting will be disabled by default for all new projects. In projects with this setting currently enabled, it will continue to function as expected, but you will not be able to add any more projects to the allowlist. If the setting is disabled in any project, it will not be possible to re-enable this setting in 16.0 or later.
diff --git a/doc/user/packages/dependency_proxy/index.md b/doc/user/packages/dependency_proxy/index.md
index 3905500b0aa..cf08f98ee4d 100644
--- a/doc/user/packages/dependency_proxy/index.md
+++ b/doc/user/packages/dependency_proxy/index.md
@@ -319,7 +319,7 @@ services:
### Issues when authenticating to the Dependency Proxy from CI/CD jobs
-GitLab Runner authenticates automatically to the Dependency Proxy. However, the underlying Docker engine is still subject to its [authorization resolving process](https://gitlab.com/gitlab-org/gitlab-runner/-/blob/main/docs/configuration/advanced-configuration.md#precedence-of-docker-authorization-resolving).
+GitLab Runner authenticates automatically to the Dependency Proxy. However, the underlying Docker engine is still subject to its [authorization resolving process](https://docs.gitlab.com/runner/configuration/advanced-configuration.html#precedence-of-docker-authorization-resolving).
Misconfigurations in the authentication mechanism may cause `HTTP Basic: Access denied` and `403: Access forbidden` errors.
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 0e07d1c7c2d..f09bfe523a6 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -11098,6 +11098,9 @@ msgstr ""
msgid "CiVariables|CI/CD Variables"
msgstr ""
+msgid "CiVariables|Can be seen in job logs."
+msgstr ""
+
msgid "CiVariables|Cancel"
msgstr ""
@@ -11137,10 +11140,10 @@ msgstr ""
msgid "CiVariables|Key"
msgstr ""
-msgid "CiVariables|Mask variable"
+msgid "CiVariables|Masked"
msgstr ""
-msgid "CiVariables|Masked"
+msgid "CiVariables|Masked in job logs but value can be revealed in CI/CD settings. Requires values to meet regular expressions requirements."
msgstr ""
msgid "CiVariables|Maximum number of Inherited Group CI variables loaded (2000)"
@@ -11218,9 +11221,6 @@ msgstr ""
msgid "CiVariables|Variable value will be evaluated as raw string."
msgstr ""
-msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
-msgstr ""
-
msgid "CiVariables|Variables"
msgstr ""
@@ -11239,6 +11239,9 @@ msgstr ""
msgid "CiVariables|Variables store information that you can use in job scripts. Each %{entity} can define a maximum of %{limit} variables."
msgstr ""
+msgid "CiVariables|Visible"
+msgstr ""
+
msgid "CiVariables|You can use CI/CD variables with the same name in different places, but the variables might overwrite each other. %{linkStart}What is the order of precedence for variables?%{linkEnd}"
msgstr ""
@@ -57109,6 +57112,9 @@ msgstr ""
msgid "Violation"
msgstr ""
+msgid "Visibility"
+msgstr ""
+
msgid "Visibility and access controls"
msgstr ""
diff --git a/spec/frontend/ci/ci_variable_list/components/ci_variable_drawer_spec.js b/spec/frontend/ci/ci_variable_list/components/ci_variable_drawer_spec.js
index 9bf73f50a58..fa0a5867214 100644
--- a/spec/frontend/ci/ci_variable_list/components/ci_variable_drawer_spec.js
+++ b/spec/frontend/ci/ci_variable_list/components/ci_variable_drawer_spec.js
@@ -8,6 +8,8 @@ import {
GlLink,
GlModal,
GlSprintf,
+ GlFormRadio,
+ GlFormRadioGroup,
} from '@gitlab/ui';
import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { helpPagePath } from '~/helpers/help_page_helper';
@@ -89,7 +91,8 @@ describe('CI Variable Drawer', () => {
const findExpandedCheckbox = () => wrapper.findByTestId('ci-variable-expanded-checkbox');
const findFlagsDocsLink = () => wrapper.findByTestId('ci-variable-flags-docs-link');
const findKeyField = () => wrapper.findComponent(GlFormCombobox);
- const findMaskedCheckbox = () => wrapper.findByTestId('ci-variable-masked-checkbox');
+ const findMaskedRadioButtons = () => wrapper.findAllComponents(GlFormRadio);
+ const findMaskedRadioGroup = () => wrapper.findByTestId('ci-variable-masked');
const findProtectedCheckbox = () => wrapper.findByTestId('ci-variable-protected-checkbox');
const findValueField = () => wrapper.findByTestId('ci-variable-value');
const findValueLabel = () => wrapper.findByTestId('ci-variable-value-label');
@@ -190,6 +193,35 @@ describe('CI Variable Drawer', () => {
});
});
+ describe('visibility section', () => {
+ it('renders radio buttons for Variable masking', () => {
+ createComponent({ stubs: { GlFormRadioGroup, GlFormRadio } });
+
+ expect(findMaskedRadioButtons()).toHaveLength(2);
+ });
+
+ describe('masked radio', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('is false by default', () => {
+ expect(findMaskedRadioGroup().attributes('checked')).toBeUndefined();
+ });
+
+ it('inherits value of selected variable when editing', () => {
+ createComponent({
+ props: {
+ selectedVariable: mockProjectVariableFileType,
+ mode: EDIT_VARIABLE_ACTION,
+ },
+ });
+
+ expect(findMaskedRadioGroup().attributes('checked')).toBe('true');
+ });
+ });
+ });
+
describe('protected flag', () => {
beforeEach(() => {
createComponent();
@@ -217,27 +249,6 @@ describe('CI Variable Drawer', () => {
});
});
- describe('masked flag', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('is false by default', () => {
- expect(findMaskedCheckbox().attributes('checked')).toBeUndefined();
- });
-
- it('inherits value of selected variable when editing', () => {
- createComponent({
- props: {
- selectedVariable: mockProjectVariableFileType,
- mode: EDIT_VARIABLE_ACTION,
- },
- });
-
- expect(findMaskedCheckbox().attributes('checked')).toBeDefined();
- });
- });
-
describe('expanded flag', () => {
beforeEach(() => {
createComponent();
@@ -388,7 +399,7 @@ describe('CI Variable Drawer', () => {
trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
findKeyField().vm.$emit('input', 'NEW_VARIABLE');
findValueField().vm.$emit('input', value);
- findMaskedCheckbox().vm.$emit('input', true);
+ findMaskedRadioGroup().vm.$emit('input', true);
});
itif(canSubmit)(`can submit when value is ${value}`, () => {
@@ -436,7 +447,7 @@ describe('CI Variable Drawer', () => {
it('only sends the tracking event once', async () => {
trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
await findKeyField().vm.$emit('input', 'NEW_VARIABLE');
- await findMaskedCheckbox().vm.$emit('input', true);
+ await findMaskedRadioGroup().vm.$emit('input', true);
expect(trackingSpy).toHaveBeenCalledTimes(0);
@@ -488,7 +499,7 @@ describe('CI Variable Drawer', () => {
await findKeyField().vm.$emit('input', 'NEW_VARIABLE');
await findProtectedCheckbox().vm.$emit('input', false);
await findExpandedCheckbox().vm.$emit('input', true);
- await findMaskedCheckbox().vm.$emit('input', true);
+ await findMaskedRadioGroup().vm.$emit('input', true);
await findValueField().vm.$emit('input', 'NEW_VALUE');
findConfirmBtn().vm.$emit('click');
diff --git a/spec/graphql/mutations/design_management/upload_spec.rb b/spec/graphql/mutations/design_management/upload_spec.rb
index dd08586f313..1a84d9c9b4a 100644
--- a/spec/graphql/mutations/design_management/upload_spec.rb
+++ b/spec/graphql/mutations/design_management/upload_spec.rb
@@ -15,7 +15,9 @@ RSpec.describe Mutations::DesignManagement::Upload do
def run_mutation(files_to_upload = files, project_path = project.full_path, iid = issue.iid)
mutation = described_class.new(object: nil, context: { current_user: user }, field: nil)
- mutation.resolve(project_path: project_path, iid: iid, files: files_to_upload)
+ Gitlab::ExclusiveLease.skipping_transaction_check do
+ mutation.resolve(project_path: project_path, iid: iid, files: files_to_upload)
+ end
end
describe "#resolve" do
@@ -65,9 +67,19 @@ RSpec.describe Mutations::DesignManagement::Upload do
end
describe 'running requests in parallel' do
- it 'does not cause errors', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/442468' do
+ it 'does not cause errors' do
+ # max_concurrency is set to be less than the LOCK_RETRY_COUNT to avoid
+ # Gitlab::ExclusiveLeaseHelpers::FailedToObtainLockError.
+ #
+ # When the number of processes attempting to obtain the lock exceeds the number of retries
+ # permitted, at least 1 process will reach the retry limit and raise the error.
creates_designs do
- run_parallel(files.map { |f| -> { run_mutation([f]) } })
+ run_parallel(
+ files.map { |f| -> { run_mutation([f]) } },
+ # We reduce by 2 for more allowance as the delay between the initial few retries are very small.
+ # The retry delays are 0.2, 0.4, 0.8, 1.6, 3.2 seconds.
+ max_concurrency: DesignManagement::Version::LOCK_RETRY_COUNT - 2
+ )
end
end
end
diff --git a/spec/support/shared_examples/features/variable_list_drawer_shared_examples.rb b/spec/support/shared_examples/features/variable_list_drawer_shared_examples.rb
index edae2c695c6..421d0cd5885 100644
--- a/spec/support/shared_examples/features/variable_list_drawer_shared_examples.rb
+++ b/spec/support/shared_examples/features/variable_list_drawer_shared_examples.rb
@@ -113,7 +113,7 @@ RSpec.shared_examples 'variable list drawer' do
fill_variable('EDITED_KEY', 'EDITED_VALUE', 'EDITED_DESCRIPTION')
toggle_protected
- toggle_masked
+ set_visible
toggle_expanded
find_by_testid('ci-variable-confirm-button').click
@@ -127,7 +127,8 @@ RSpec.shared_examples 'variable list drawer' do
# form is NOT reset (unlike when adding a variable)
expect(find('[data-testid="ci-variable-protected-checkbox"]')).to be_checked
- expect(find('[data-testid="ci-variable-masked-checkbox"]')).not_to be_checked
+ expect(find('[data-testid="ci-variable-visible-radio"]')).to be_checked
+ expect(find('[data-testid="ci-variable-masked-radio"]')).not_to be_checked
expect(find('[data-testid="ci-variable-expanded-checkbox"]')).not_to be_checked
expect(page).to have_field(s_('CiVariables|Key'), with: 'EDITED_KEY')
expect(page).to have_field(s_('CiVariables|Description'), with: 'EDITED_DESCRIPTION')
@@ -194,7 +195,7 @@ RSpec.shared_examples 'variable list drawer' do
it 'shows validation error for unmaskable values' do
open_drawer
- toggle_masked
+ set_masked
fill_variable('EMPTY_MASK_KEY', '???')
expect(page).to have_content('This value cannot be masked because it contains the following characters: ?.')
@@ -290,15 +291,21 @@ RSpec.shared_examples 'variable list drawer' do
end
end
- def toggle_masked
- page.within('[data-testid="ci-variable-drawer"]') do
- find('[data-testid="ci-variable-masked-checkbox"]').click
- end
- end
-
def toggle_expanded
page.within('[data-testid="ci-variable-drawer"]') do
find('[data-testid="ci-variable-expanded-checkbox"]').click
end
end
+
+ def set_masked
+ page.within('[data-testid="ci-variable-drawer"]') do
+ find('[data-testid="ci-variable-masked-radio"]').click
+ end
+ end
+
+ def set_visible
+ page.within('[data-testid="ci-variable-drawer"]') do
+ find('[data-testid="ci-variable-visible-radio"]').click
+ end
+ end
end