Skip to content

Commit 08e8c5f

Browse files
author
GitLab Bot
committed
Add latest changes from gitlab-org/gitlab@master
1 parent 5558389 commit 08e8c5f

File tree

84 files changed

+1299
-251
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

84 files changed

+1299
-251
lines changed

.gitlab/ci/version.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ variables:
1414
NODE_VERSION: "20.12"
1515
OS_VERSION: "bookworm"
1616
RUBY_VERSION_DEFAULT: "3.2.6"
17-
RUBY_VERSION_NEXT: "3.3.6"
17+
RUBY_VERSION_NEXT: "3.3.7"
1818
RUBYGEMS_VERSION: "3.6"
1919
RUST_VERSION: "1.73"
2020
UBI_VERSION: "9.5"

.gitlab/issue_templates/Security developer workflow.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ After your merge request has been approved according to our [approval guidelines
7070
|-------------------------------------|------------|-----------------------------------------------------------|
7171
| Version affected | X.Y | |
7272
| Date introduced on .com | YYYY-MM-DD | #TODO for Engineering - please follow the format |
73+
| MR that introduced the bug | | #TODO for Engineering - Link to the MR that introduced the bug|
7374
| Date detected | YYYY-MM-DD | #TODO for AppSec - please follow the format |
7475
| GitLab EE only | Yes/No | |
7576
| Upgrade notes | | |

app/assets/javascripts/ci/merge_requests/utils.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ export const formatPipelinesGraphQLDataToREST = (project) => {
5151
stuck: pipeline.stuck,
5252
auto_devops: pipeline.configSource === SOURCE_AUTO_DEVOPS,
5353
merge_request: true,
54-
yaml_errors: pipeline.yamlErrors,
54+
yaml_errors: Boolean(pipeline.errorMessages?.nodes?.length),
5555
retryable: pipeline.retryable,
5656
cancelable: pipeline.cancelable,
5757
failure_reason: pipeline.failureReason,

app/assets/javascripts/clusters_list/components/agent_table.vue

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ export default {
9494
{
9595
key: 'name',
9696
label: this.$options.i18n.nameLabel,
97+
isRowHeader: true,
9798
tdClass,
9899
thClass,
99100
},
@@ -260,7 +261,9 @@ export default {
260261
data-testid="cluster-agent-list-table"
261262
>
262263
<template #cell(name)="{ item }">
263-
<div class="gl-flex gl-flex-wrap gl-justify-end gl-gap-3 md:gl-justify-start">
264+
<div
265+
class="gl-flex gl-flex-wrap gl-justify-end gl-gap-3 gl-font-normal md:gl-justify-start"
266+
>
264267
<gl-link :href="item.webPath" data-testid="cluster-agent-name-link">{{
265268
item.name
266269
}}</gl-link

app/assets/javascripts/clusters_list/components/agents_configs_table.vue

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ export default {
4949
{
5050
key: 'configuration',
5151
label: this.$options.i18n.configurationLabel,
52+
isRowHeader: true,
5253
tdClass: `${tdClass} md:gl-w-4/5`,
5354
thClass,
5455
},
@@ -96,7 +97,7 @@ export default {
9697
class="!gl-mb-4"
9798
>
9899
<template #cell(configuration)="{ item }">
99-
<gl-link :href="item.webPath">{{ item.path }}</gl-link>
100+
<gl-link class="gl-font-normal" :href="item.webPath">{{ item.path }}</gl-link>
100101
</template>
101102
102103
<template #cell(actions)="{ item }">

app/assets/javascripts/clusters_list/components/clusters.vue

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ export default {
7676
{
7777
key: 'name',
7878
label: __('Kubernetes cluster'),
79+
isRowHeader: true,
7980
tdClass,
8081
},
8182
{
@@ -252,7 +253,7 @@ export default {
252253
class="gl-flex gl-h-6 gl-w-6 gl-items-center"
253254
/>
254255

255-
<gl-link :href="item.path" class="gl-px-3">
256+
<gl-link :href="item.path" class="gl-px-3 gl-font-normal">
256257
{{ item.name }}
257258
</gl-link>
258259

app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/tags_list_row.vue

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
GlDisclosureDropdown,
88
GlBadge,
99
GlLink,
10+
GlPopover,
1011
} from '@gitlab/ui';
1112
import { localeDateFormat, newDate } from '~/lib/utils/datetime_utility';
1213
import { numberToHumanSize } from '~/lib/utils/number_utils';
@@ -15,6 +16,7 @@ import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
1516
import DetailsRow from '~/vue_shared/components/registry/details_row.vue';
1617
import ListItem from '~/vue_shared/components/registry/list_item.vue';
1718
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
19+
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
1820
import {
1921
REMOVE_TAG_BUTTON_TITLE,
2022
DIGEST_LABEL,
@@ -47,10 +49,12 @@ export default {
4749
TimeAgoTooltip,
4850
DetailsRow,
4951
SignatureDetailsModal,
52+
GlPopover,
5053
},
5154
directives: {
5255
GlTooltip: GlTooltipDirective,
5356
},
57+
mixins: [glFeatureFlagsMixin()],
5458
props: {
5559
tag: {
5660
type: Object,
@@ -157,6 +161,22 @@ export default {
157161
isDockerOrOciMediaType() {
158162
return this.tag.mediaType === DOCKER_MEDIA_TYPE || this.tag.mediaType === OCI_MEDIA_TYPE;
159163
},
164+
isProtected() {
165+
return (
166+
(this.tag.protection?.minimumAccessLevelForDelete != null ||
167+
this.tag.protection?.minimumAccessLevelForPush != null) &&
168+
this.glFeatures.containerRegistryProtectedTags
169+
);
170+
},
171+
tagRowId() {
172+
return `${this.tag.name}_badge`;
173+
},
174+
accessLevelForDelete() {
175+
return this.tag.protection?.minimumAccessLevelForDelete;
176+
},
177+
accessLevelForPush() {
178+
return this.tag.protection?.minimumAccessLevelForPush;
179+
},
160180
},
161181
};
162182
</script>
@@ -183,6 +203,26 @@ export default {
183203
{{ tag.name }}
184204
</div>
185205
206+
<template v-if="isProtected">
207+
<gl-badge
208+
:id="tagRowId"
209+
boundary="viewport"
210+
class="gl-ml-4"
211+
data-testid="protected-badge"
212+
>
213+
{{ __('protected') }}
214+
</gl-badge>
215+
<gl-popover :target="tagRowId" data-testid="protected-popover">
216+
<strong>{{ s__('ContainerRegistry|This tag is protected') }}</strong>
217+
<br />
218+
<br />
219+
<strong>{{ s__('ContainerRegistry|Minimum role to push: ') }}</strong>
220+
{{ accessLevelForPush }}
221+
<strong>{{ s__('ContainerRegistry|Minimum role to delete: ') }}</strong>
222+
{{ accessLevelForDelete }}
223+
</gl-popover>
224+
</template>
225+
186226
<clipboard-button
187227
v-if="tag.location"
188228
:title="$options.i18n.COPY_IMAGE_PATH_TITLE"
@@ -204,7 +244,11 @@ export default {
204244
</template>
205245
206246
<template v-if="signatures.length" #left-after-toggle>
207-
<gl-badge v-gl-tooltip.d0="$options.i18n.SIGNATURE_BADGE_TOOLTIP" class="gl-ml-4">
247+
<gl-badge
248+
v-gl-tooltip.d0="$options.i18n.SIGNATURE_BADGE_TOOLTIP"
249+
class="gl-ml-4"
250+
data-testid="signed-badge"
251+
>
208252
{{ s__('ContainerRegistry|Signed') }}
209253
</gl-badge>
210254
</template>

app/assets/javascripts/packages_and_registries/container_registry/explorer/graphql/queries/get_container_repository_tags.query.graphql

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ query getContainerRepositoryTags(
3939
userPermissions {
4040
destroyContainerRepositoryTag
4141
}
42+
protection {
43+
minimumAccessLevelForPush
44+
minimumAccessLevelForDelete
45+
}
4246
referrers {
4347
artifactType
4448
digest

app/assets/javascripts/packages_and_registries/settings/project/components/container_protection_tag_rule_form.vue

Lines changed: 49 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,12 @@ import {
1010
GlSprintf,
1111
} from '@gitlab/ui';
1212
import createProtectionTagRuleMutation from '~/packages_and_registries/settings/project/graphql/mutations/create_container_protection_tag_rule.mutation.graphql';
13+
import updateProtectionTagRuleMutation from '~/packages_and_registries/settings/project/graphql/mutations/update_container_protection_tag_rule.mutation.graphql';
1314
import {
1415
MinimumAccessLevelOptions,
1516
GRAPHQL_ACCESS_LEVEL_VALUE_MAINTAINER,
1617
} from '~/packages_and_registries/settings/project/constants';
17-
import { s__ } from '~/locale';
18+
import { __, s__ } from '~/locale';
1819
import { InternalEvents } from '~/tracking';
1920
import * as Sentry from '~/sentry/sentry_browser_wrapper';
2021
@@ -31,13 +32,22 @@ export default {
3132
},
3233
mixins: [InternalEvents.mixin()],
3334
inject: ['projectPath'],
35+
props: {
36+
rule: {
37+
type: Object,
38+
required: false,
39+
default: null,
40+
},
41+
},
3442
data() {
3543
return {
3644
alertErrorMessages: [],
3745
protectionRuleFormData: {
38-
tagNamePattern: '',
39-
minimumAccessLevelForPush: GRAPHQL_ACCESS_LEVEL_VALUE_MAINTAINER,
40-
minimumAccessLevelForDelete: GRAPHQL_ACCESS_LEVEL_VALUE_MAINTAINER,
46+
tagNamePattern: this.rule?.tagNamePattern ?? '',
47+
minimumAccessLevelForPush:
48+
this.rule?.minimumAccessLevelForPush ?? GRAPHQL_ACCESS_LEVEL_VALUE_MAINTAINER,
49+
minimumAccessLevelForDelete:
50+
this.rule?.minimumAccessLevelForDelete ?? GRAPHQL_ACCESS_LEVEL_VALUE_MAINTAINER,
4151
},
4252
showValidation: false,
4353
updateInProgress: false,
@@ -47,9 +57,7 @@ export default {
4757
createProtectionRuleMutationInput() {
4858
return {
4959
projectPath: this.projectPath,
50-
tagNamePattern: this.protectionRuleFormData.tagNamePattern,
51-
minimumAccessLevelForPush: this.protectionRuleFormData.minimumAccessLevelForPush,
52-
minimumAccessLevelForDelete: this.protectionRuleFormData.minimumAccessLevelForDelete,
60+
...this.protectionRuleFormData,
5361
};
5462
},
5563
isTagNamePatternValid() {
@@ -64,9 +72,24 @@ export default {
6472
}
6573
return s__('ContainerRegistry|This field is required.');
6674
},
75+
mutation() {
76+
return this.rule ? updateProtectionTagRuleMutation : createProtectionTagRuleMutation;
77+
},
78+
mutationKey() {
79+
return this.rule ? 'updateContainerProtectionTagRule' : 'createContainerProtectionTagRule';
80+
},
6781
tagNamePattern() {
6882
return this.protectionRuleFormData.tagNamePattern;
6983
},
84+
submitButtonText() {
85+
return this.rule ? __('Save changes') : s__('ContainerRegistry|Add rule');
86+
},
87+
updateProtectionTagRuleMutationInput() {
88+
return {
89+
id: this.rule?.id,
90+
...this.protectionRuleFormData,
91+
};
92+
},
7093
},
7194
methods: {
7295
submit() {
@@ -76,25 +99,32 @@ export default {
7699
77100
this.clearAlertErrorMessages();
78101
this.updateInProgress = true;
102+
const input = this.rule
103+
? this.updateProtectionTagRuleMutationInput
104+
: this.createProtectionRuleMutationInput;
79105
80106
this.$apollo
81107
.mutate({
82-
mutation: createProtectionTagRuleMutation,
108+
mutation: this.mutation,
83109
variables: {
84-
input: this.createProtectionRuleMutationInput,
110+
input,
85111
},
86112
})
87113
.then(({ data }) => {
88-
const errorMessages = data?.createContainerProtectionTagRule?.errors ?? [];
114+
const errorMessages = data?.[this.mutationKey]?.errors ?? [];
89115
if (errorMessages?.length) {
90116
this.alertErrorMessages = Array.isArray(errorMessages)
91117
? errorMessages
92118
: [errorMessages];
93119
return;
94120
}
95121
96-
this.$emit('submit', data.createContainerProtectionTagRule.containerProtectionTagRule);
97-
this.trackEvent('container_protection_tag_rule_created');
122+
this.$emit('submit', data[this.mutationKey].containerProtectionTagRule);
123+
if (this.rule) {
124+
this.trackEvent('container_protection_tag_rule_created');
125+
} else {
126+
this.trackEvent('container_protection_tag_rule_updated');
127+
}
98128
})
99129
.catch((error) => {
100130
this.handleError(error);
@@ -174,10 +204,10 @@ export default {
174204
175205
<gl-form-group
176206
:label="s__('ContainerRegistry|Minimum role allowed to push')"
177-
label-for="input-minimum-access-level-for-push"
207+
label-for="select-minimum-access-level-for-push"
178208
>
179209
<gl-form-select
180-
id="input-minimum-access-level-for-push"
210+
id="select-minimum-access-level-for-push"
181211
v-model="protectionRuleFormData.minimumAccessLevelForPush"
182212
:options="$options.minimumAccessLevelOptions"
183213
/>
@@ -192,12 +222,13 @@ export default {
192222
193223
<gl-form-group
194224
:label="s__('ContainerRegistry|Minimum role allowed to delete')"
195-
label-for="input-minimum-access-level-for-delete"
225+
label-for="select-minimum-access-level-for-delete"
196226
>
197227
<gl-form-select
198-
id="input-minimum-access-level-for-delete"
228+
id="select-minimum-access-level-for-delete"
199229
v-model="protectionRuleFormData.minimumAccessLevelForDelete"
200230
:options="$options.minimumAccessLevelOptions"
231+
data-testid="select-minimum-access-level-for-delete"
201232
/>
202233
<template #description>
203234
{{
@@ -213,9 +244,9 @@ export default {
213244
class="js-no-auto-disable"
214245
variant="confirm"
215246
type="submit"
216-
data-testid="add-rule-btn"
247+
data-testid="submit-btn"
217248
:loading="updateInProgress"
218-
>{{ s__('ContainerRegistry|Add rule') }}</gl-button
249+
>{{ submitButtonText }}</gl-button
219250
>
220251
<gl-button type="reset">{{ __('Cancel') }}</gl-button>
221252
</div>

0 commit comments

Comments
 (0)