%2ze{2DP+4*A
zt~9_;5hlHNGDNh6=-qNR+ciik8Dy3&8rR^K!B02gN*Ws_fYW^Ue41yrN{5frKUwq*
zvIfPLUH2GjHrkfm|BwcqKn^IJ=hK@1n(O+{^u{knLpg?1PDFM0<~F9q_#?3AKn8v%
z{>3Mw4Ry<&WOY~#Eu5)&dE{+5IqlQ?P&eXIiO_@};hRbeeQ+~3G*iwS$des^9_Nw7
zV64O;bB>bRcM5yjK=`!5`)dy^SlHu}SY{c;=ksJ9pw&>zd1-Q*1<0sLMW7z(m))EB
z#?$vLq%Vw+$m1Z+qr?@eq-Q&eS^7M(3bfZ~JY;)+4@-o?w(?>LQ!g?MOUZxF#-x1P
z-~a7KOfS9%h&Cd{MMQpsv>0g7ZFqIAJM3vF$|1S$4Vx@8w|L#2nf~b0PRm+4ZF4p>
za^E9W=7!Cf?=jrlsGrbK+wo!TVt1^$eF}VB4&-Eo-0d$xT}@K^RLl;cIOv>3=S0{GCI*#!KJ3L&A?K~CyrVhK4>;BkX+Tj}mp|93U#aFb8mBktQc
zJj{c3QF|54eeY0|U^^OF0RgSC_7ueD68Fr$
z({#SfVm2E%JkGJi=Qoine|Cpl2l(RfL;n*?1RJ!h()CZ5eqd9A&9SPSwGlnX=Ed{%
zsDVCxWPns3M>{C^Zd#0&=JpIqY>3BYa6hRA@w@?jUn}`YT6QSBMJu{qaVJ|4GIFk!%00?}%tbc}MgCK%Ay!HC_wy8U`w-5z4=QuwFg-
zQW7zEwqQe~=YQYyhxA`hK>8Q+-vt4?`=n2cAWF+Cl>j4d3x!F~z}Y%W`Q1Eud81V?|-Uo;c)bR
zSGV(rca_HCov`iBhmU^am8>cUKv_10ufW=|CJf<(mdnD03{0HGBYm+Th=ZCrpN}Kk
znTKpn*G2*v?otgi`oQ{XOWAgynJ)F0aPOcW2Y2ogT^sqs5BsKt83!!
zyy;One`%DB`@N4`Ls$5RVChE6&4RZ%-&bH;%rgEhv_F6Am}Az5_v!dP+huBwyyT>M
z#4k4fq%ribBLA*WYpetz{(3gk9;eqT6V?~8-FuDx@W1>X4@P^R9Z4h##6|bYTugt#
zr`tr8Y+{#)zjZ6FdqE#ajI5eGzvsJEe~!D3+WtE8MPN;#W#5u-VeHV*uXyKrD)|uH
zuU=fvxe<>1RKe~XNF!E%e|g|`o(8gfq7>PAM>^x&e^!57HtA04Mo7?Q?#)z;%o0ON
zMnEcuDob2thS>*-x(W|D!y*@@=w+OgrL}34l8Y~*Sp57o{%W3|k4q`{jlKG_5^>_7
zlC9m;&Yt7D_H1Y?P@IM>Z)NqY4kqGi6>yPzx0DU_y*ap0RDLv;vJIdet&4?JnaxdN
zI~^79guTJ{%CYFt+qk;L+KZOL<7_M>0@+aXHZA6uMrLe++{pxXz`F&+$g-mG%~jaS
ze^C|s#my6eUY^|pB>NuAUy4b3(uIhPpIvsOfb&6O0+C~oE(2P~G2Zp-{M*d^QYm!U
zeA3CeA*MtOh}S4={l@wCty4TPd|+L>9xM(*-Zh`*lgLX4&1Uh#
zxe97c%famTFYL%0Dz&fPui?mtpxdpRQ^uYufp=!#25D0?L^uQ-Q2jhTBKjp>ve?$7;5qCf1P?&;*{GPC0@9S=MF(c;uU$L!~O
zrJo4&|AKn`qVwR4IARy`T(*{p+)W~qi&*Lga#gJj)QfpzmxctKs4t>>tmKWZt}66c
zKJJOy1r-KJ#*R8dl$OyTBd^3iTx?(mNS1teXl~)lqU$$~tagXpCEFBP%0=H=0YLM83vjD9=c3Do+rOM!N
z4)W;Txp)Fj6GCx+F5FUr$vS>%$NJATD~@GNT;Rb5MT~^^;RoP3qTl^5`yi#O<9K7`
z4>jtbSZvF4d$2=E=yG3Za5`^r^-N&+)q+Uq1D|HY-BrUIt0@ce!cG!U1D#0XhO*!F
zWBn=9xRxCI(L0lzCc>9pJ$%gtJ-WI{1%THOd%njzJXc@C6M_VwXJ3xytq*BhJ2Q`K
zchNTg-Zw^wPbhOpC$9k%;#As0ul6(9es3c=WxSVcSfhbE?~-I~-{Kvq!r=Zi)(X1}
zsyo=o*ShH2XY8%IB6G&r=PZVkSKPYmEPkDee}dc%UQ>6KZ(^5rNPQ{lEpGB@&z_xi
ziZ@VxaA|PnV!h5AyIf3+qk75=B>td;G16uGIBzBI!BpUIKj&fZf(cfV*(i4mxR^PT
zxBnWx-7_)qDck;QbC;egb}wm)0)BI+YglG`j`t5g+I-@ODYnKA-CDqP(ioZo4-b!q
z(@zva(0ZJIcaa%adsrq&+3MnH9^kLqt!vBapQcKg;@$i#ppWaBlj~i%GmdHXUjI!&
zEdi+g#4>?>SadyU#+p%-w!$yin?13dCP`u*^pfs11H{8;zVNdyr0T8nzwcy+>ELu-RgsMSLp=Yexh>Ls9*tMZ`r-Ph)G
zYyyz4`$xIC;Gf%GBaVK*u=BmG6?VQ`eTjU>yC6bKE!L-RhN&Tm2AcO}8z
z;~WC+{d>c21{T~o6u}~5#u$U}S?x2D8#G!e6jZd>(`eCihuMJe`q=s=Lwz;d;bscs
z)H+E=7{f%Xlj&%`Aab|w-}>4YJ=%_VkF^1wlItG`51DN+mCA1Xe;NCE)%x(v`q+E6|>d1GbZudPP;fRP|+
z)rEm>;m;ZIn}O>i*J6*dmBg}`+r*d&ac#5qv_H|%n<4l1iI-oE)V0W^gFvRL^IRU3FZT
z{<_nRkG54=7>&&wHr&S=7`;c6uv6Q1T0GU-L6JLp$9l#7_ehO>N)=3*WAKzZH!R5Z
z-eX;=Kd>q9#oOcUljfiqN3qW~7lHGJ%?28(JkES-oRiqk$-V=oInmWvwvq6sRo}B7
zUSiOcD$i)o3@>6OHJ;H%{+I)qG%A~wzui9V?uSZo
zdUtfJK(!N8zfMM_a7@xgGl&atnod0aT%Mc*2Hz7Z^LR(S;(AN1qbJ>2YEwFBk;sv7
z9#fqpM4@$5wA$F7x%hxHjJ?w4C0!}QRY2ChFdl12=su1D`dO&h*jUi{F4@7^u&F3}G!GLJzD3S3Hy-fAONl({w
zQkt@GNrzk{0EgZ{4+PYf!0+vP_*Nw}K#|A=1^%HA`$c+Nc%Yj?uTI@`Ccg4%=A%C-
zps!uiM$WnuFOgd3-S_KyS|IJ05x}V!mU*MI{857<(bCxPHsD|EsFI(ZY@{D`-@S+$
zR<#{%ZXh$E=sD@!8?KZNQFLqnbImnC=Bz~HyEK=*AgMJefBYS&%)`t@OCnw@EM4)f
z=dXN~D-~~c$M>>8?bY4f%hU1cgGd8b1BFtYHJ<#%
z)+@16owC!&Q(V}`4}J8b1Gjyv}xj@S?b?Zo`UW+VL>(KguWT_S^
z*&NxrrQ%U!%L35f6`A6-PhP~u?J^e3T-9VF#pmTH>s?QdLu!KVk`?BAnc1_3&hBO9
zou6Ov_1xc(M7Fhz1QW>?KZO5CWH+Isi}n#+m~b+&vTmF@x}b>;2%A(@9>EMx?D|=*
z^oc%XUjv+qCBM*=I#CONaP^Y9U+w+g&Fn}YeiQwR3505@3Fe!pw|!U}A^ur{vwP7n
z&tIu$(bHtwzbE5w*TDU=u#g8ER3kfWIppPrCc!sY_7R%*`ZA*IV60HS3AlP^YAQOR%rc0I^4c#T~wv3J9VQ
z`gyXS9>S#^g1LhYIr@4~gsD{QASQ#?Tz^s9~*u$Qfhi@I;DPdBy*47tu+#+!(!l
zGLP7Ao;I3YvS~-Ew_?a4Ifq2>(p+iuA;Z?Z3_?C2{kGhOs8pn+j)
z&sryccSC|E+Jmk%dn=vEPu4xGq#;Eoa3e>R?ha@o?VO&XxRJU!^eKUpV~7;%pY}bv
z&4s5>s+ky3Cp7GO?wdkI#$RhbNKM(tLBLEi?ch#y6);~71Jf%xMA9^Vt`2er%i#}(
zXaQp!v1>Ya1w4N}LrGwa$T)N%l!W)UILP;b6iI
zM7}G5p*YQg@!9sNHgXl%rB3!7&hGfw0W7`rHL`JY`7gUwW0Y3S&e6@ETJ(rp0L?L`
zP`O+*)is-4>U&(3&vJx*+Ef&?5<8kAbAgXhV`W=d6ikH9kOX=To*MT}(|JvtPA&Yp|9r
zSy|u2*|Om!ddH&&n@p!xWPS_Z*RL#E%R-^gtwWNxDE*Mlq;J}Rj$(yDn>`v+*(>XDXY%p*btdYwYexsNHwPetkmXbncEmY4IlD#xroo^WhT(y5$!0@NmP-jL9culMGGn1FsYv{CxcUbh`H=2$(Lha^
zzvqjx*mQJ%yhTna6TgG4*CWfP-V(ySq!_|_ySP^2VEAQ6&MSp0CCf80l<{9;+>r#b
zm`_qa5+gYp6pJV56YZCNw3j5_80CT4a-v~$r^)M>Tn0)>_~&~D6??d?t)fYp!90Y2
zqx_LTJudEZ^o*d~5Mkb%`uKtsG0)lMp^2CzY_y*_fAN>#$K>oGCM4<+(JC}FCgP2E
zR6E&tquRQ2rc2`WIh<(Hf*KFXs;KCxsmI
zv$VC=SYEh&qk`Eb9i%829w~OnSoN#*Vql_6h2cMOATKiFnOG#rN_aWRkC)c4J$pL4
z@O@_Z$4u2M+GzO3_*jU|Npn3PZ4;H
z;0d1)&uMnDO8ZulW#&Z#h2R;IZ&TYj&0U_tN;ERQ;1Y6_{Ym;g^~_;mn=F@-?su8j
zqjd6?cNh;@L+Q@aVMsAA$bNz;<;dy6$mF)}hj;py&z@eI!XLq0x&uOjAw&a{(pi&R
z*p5{rR{&L2N$%-V-H2n<0@_+@YJ0rLV>n49JvwQ5_gygS^BGSq(*S#mB(XxgLc;`Z
z9Y;+YY#f`V=eAOjw^NS0;HQjMSKj8<{(y$pEE-LQwWf7y`E~p`IaW==Q}@Eo
z23-gde;7HHa}YHwl2Z|tBgN&d_W5bTIQ(O<^1Fa3)ftcmvPL>
zvYs*NwwEGLKj(!MuGqc(D({Y*d~w9?P&}M*z^JS)b*$;O6m}K2(NY@#S_r;b5~i`m
zmhwf_gJaN?4BT9Z{FK`BIhQ{}&%JvSsVl8du4+O-YtLQ?)pY;r@UpT!Fdt*=!@jnw
znX;n=@%(oW|I~g??f~0@9N|EEo{G8P^X{vUr|sKRTE*DbT7n)cKD?I|6(XNkq7n>>
zYEyx#EKQCo0Y205mcuEr77{x)+PzfcG-LA+sOxBjbN{=IhSRWMVIHbL`e!5IBL=>$
z@b(!$nbIRRC1+_e<24$mE#14nOr&m{546qVoC0|N`1heRo9*QqEaSWHdu&7B=nkl2QD%25TRjs>XZf*f551AS
zc4`1H3^P%*?O4)K1$&Led6*JY*AAMK>js%@`wI|;4wZ)9t>5=07HOq1O%|7cU1NQv
zR|yHV*Hm2SAJfu-4hAmC-@tNw1`tUtBB34j38Fx#2Wxuxg4k9#15PYY@yH^tr^?6T
z6N@XpW%tu-z3@W8WE>7BLNG#dC|H9FeZV>J4Gd#D=Cn8ptXsQ$GG@)CaK5)Em%w6i
zpU)Yy3Q=Ao3E{j0(|OVv08&4Z(BHo#M8Ya!k{8ZU3;V^;&)E>L)8V+XgH8~tT!Qi+
z*g^#C1Ok?f?Hz_TIxES21DH^v*Jb8I2AD1hs5_;L%dE`3bFynsjH{j*zR-5X+`Mhk
z>lJytTk>Ljwp~YVXz{}i>U9j*D>#;5D`(q9EfkObb?(wk#^!y{Uqote8*a9Ev>k_-
z`|M^dX0w$1R`ax^aiPad9hW0|;^o;9m2)Yz)!ua2RUcrGHcr)uLzeKL16pW8-8dz{
ztG9%_F+}u+X-U<`v0v)qbaJrpe;+T9p1x-Vk-TwE{$&fQ$|_`X9+Sy@4IL{(m|uCH
zvA@3$s%d0Xtel(W@OQ*IB!!+LlTo`xe1FnQ#ecnE$bm_paDb9S>y=E+Kxi=#QR!z5
z7z(bGhW47fgn^?yWeFGxVtK!n2`r;=b=CP>Oufp8Y}~`4&BgRqd)LiG0~#(g!^i-B
zb9{^nm5nB1Qy$>cT`ge|U^Rsn*EaLmoxRtFq{Nb>13{{qX=dA1!_upG^B0=~HH~t7
z7?;pX&-mP@wrvl}Rs@z5iIBdY_yA!Ybr&F7qJeIJQ1{Mv_5P%)3`j4cmL>`%$|XW7)(YIum$KiT5Su}eb<
zs?4sf1JU6sV;am;g6O|QZxVyJF2QXxY@tu|`&Wb5KYwy!2X?Uk>X5_4cWE$!yx{No
zS5&!R7<>w+#r|Izh%I*i7_>c)=|*E%jespFH)(a53JNZ|t9nGFp=Hj=OT>Oa+zYCm
zbzfR5ss|_ZdD#)$u9|hcd{S1BnP&38<3AOem)%~oA-gwGkqSJG`^mqeYOoy(9Q<;?
zP7t6xr0bF_3N`D^DyDOlhiV)2gy!vu!Ol%%m*}0m^CgauPuSw5TgRcl)NsC6Vt&k$
zogHohew4|#ef1~5Wu9VzJZ;`7Jd`gK4f^BBGqWQ?c$vFM#J%?E0($RgdG1|j`ZmcH
zgqU9aH+^w3kcWcy%I_Vke&iMf>;G()|L4{{AB;tjMtWK}ti(Om&sn~(qi)2U9-|j{
zonJjUXG+NfC7PuIu1RI4TI3~WSN#$9WSOWBeqp55me3>W%6>dGlC0ecNdP-Ly~dTQ
zgVRn`7(wNs3NP|d=NP2$xZ?_&L{1nmEGe^_&K1h=`4W>dvvf$1c=nuPsAYQ+Vw5J!
z-!?IVZW{Wd_HY+dY#WhPv+fgNk}FKa_093Ar&kb=t3s*+^Zr2J#q?V1
zwae9@im@MdKLL%ULhlftvdBId>O*RpkqVPs_`F3r`lrvOIzBA>0`-z5hRe|?{l#r3
zaw$UwYg{4ZSA=E>FVuypSeg)uy|v%0q4nJWb(kGWGZj^+fQwHgNqxTl@qQ>ImBcJJ
ziz1AQsrN;KKdJ(c#@tu|m#aanGA+ju3sA?K_Dj!UVZ4dj@YknT5WMet5IE7lmn)}!xLs~(RqRL+$-+b=+!fiHA
z8Eh~WVv>R7C^}3E5Mi@2IM)r<_ei0$EV;UGDM0RcOflJ0DlC$iTm6P8G)Cqgel9*m
zr`$iC^@+tUGiCU)iND-JOAYASjkiOy-^54F{f8^VHZG9^G%wExvJmdo4NB5Z*e0qd&eMS`C#3UO=EAI?+1F1(~palE|Zc=@?_qgaYbSUrBbaK(XP_k5Cj*Jh+tkP
zrvoQrQ{p8m#V4AD;(uAFpQJiOg=EJO{@2>`CfoQl+i6C1NO3$94AGlF!6d_^2I|Hr
z#A1dwqJ~V-`pEA}VRKETl7wwB<|W6Er^Knccb*ayD?Ki{zQfM}hhOo4Z`i
zy+aDZ_W-2I)KF}8)~ts#A{SBv)YjSU9Ff7o#1yyt^X;m@fyK1y;|yv+EYj;qv|@B5
z+JU_20javgkv67cvTWe@kBkE4$(hqVsV4*C
zyD*)zGbvgdzy$v1TgkW$vait-5K6CqYUXw})V@a00DX7`N
z{B4@)D}NQFfAC>{7}1m$F1IN30rLuPBYA+RUq4L6YQM#c9_08zr9U{=WCpq&Lgooy
zPm*s0fB#w>(?c$-FwLDJMEbn1bsM{&3u4O9R4uO{1eB26b{k1~FBy`5@uwxkfoZ*o
z@tnaR^uW6w7TSvvlR)i*be7z0uP4`~u84Ol)}5IeQIlvEC4t>{Do5hDEZy9%>|o7v
zR}pT+;)Q|-vCj<{z2Q;4X06wn?O)oPp{r}}H>7&Z>WzFU0&lnaA0`NyU&^xTwKoA{
z5f3%!+kt){MjoH)5u=x}M}~#&+=%e~_pQeGJB&Fb79=?AI&htXeKGfZQQU9`&=$+9
zj>*>1bIX8(5sJwuH#*uGDnW@Cc}hIdTOjQu3X)xp7!2{Mo}Pxos$}V}$kn(CDO8)(
zc}oBX{Ej$v6P^w_0Zc!g@j=NF@s>H!o>J*(Px-%nozA8_$xkm~Lk3A1`i+{8a1WzG
zb&CH|L&I0
zFZ3JWm^mTcu+jnA7b_-0IJu%J?f&Dol|f
zI#XO6&;;r0i9EDH%I{JTL;_=>+-@H<5M*s(Pjmf|kCywE8a*vpI9Z&~oYg`+
zw~iGKQ$@BKWv{~ZST#%W7;)$%=D&QLn&sB5_Tz6Z&yJQ|mhw<$J!JVu=kzU9bK37gx4w4$6=jgLX_w20-$
z8@9@YA|uXAHz>1=6$odSM7&F>J6#pf?ich5iE|KN`p`zW=20><#A=t%qsb+;ld!E4
zD?amPjKTKg^7TK)lAatT$HoEgVXAwW=j5YyN`ajQ41#{cTlejnH4w&!p89cAw~K6V
zsNpdClw7~vMv9rA=B@Q?TfS5s%aUiI)WS?hc9K$9xqk`;T{-mFg4{_{k9DFjD#j=A
zb-gccU*sVLv_kt9lMxTZjr4eqWQp2ACxKZH^jNslHQ-as2r)JT<>cZf?7n^Yt1hQH
zJdrrZ=s2Jj9V#%(yoM?b=~)dP&$WrjesuF~@!)G_{5?RH`nCEm%X+LF<4-c(7d{6g
z=Z8HmcCx}LJr7a-7!=bJr0c2!bkeQLHkuBtkQ{x7-W0!zA<~m3tyXEj0m#eKLmN`-
z`57RksXRdSJXCgmW~}zJ<|?{mc!+U7gdhpQB37qhQaJR#QQEC-z~=M1AG2bV0$Rkr
zb6Z`Id+|3j{;-W3GXnlN>>)E77OPvE4l3M8WWdQ#6?KEbPo{B@&zx9_qUkk-#)=OgG|H&NWmznk5oO7IqMzI
zaij0QjjSEG1&ak**Yg(^7QRbC0(!)~Wz<#dp47o)eaPMIZ<@%CpMxMG%U||HY<3)8
zXeh3|a@Mee3C>@2M1RAz5*&76Tw!uUc8O
z38-68uG!hFxMfsmcEU`GxpW0ujUY*CwsO{|bXyq$dLB3NMep4tTl$TF3z*)j7!pv~GadWakiZ
z0tL48qC2O)-zAN0uQ^hv@~zpdm;XCnk4N>-s;`768)jk!
z{3QZe_#bIL%kt+baYqNa%N|xKN=2}u9ygjrN5n8^w*W6DU5U5MiCBJ*L0)!{yz5fx
zOh;IUU_wq^q6*pBwXD0SR#A;U@}gC^sY+D3g^sT6z81oZzD{(xroCo%ihQJC(^A#h
zua^|Gzn#E+xBTT9QuJS>CWV{;4d>%AaVw(j(EwuPtw7)Bm1A^9D>z;)??Fc6!Adnf
zV-EV(hhmOw*=4JfMZn$aGi8XUfS}fsz^}<~0p>7^^Okp0gBE2^Qx6yHsmcr-MuA%^
zLtk#VmeW-ukbJ;0AepkZ^0s{~K<+tP>V3mcTZY7yFUjqhx}QDN&c|ymH(U4|IS$~O
z?(PDq>*9jA=jOrU=-&8s-^l0Ed(B8=4CW!MFBcKRs~`V!NPB2FYTj+u+XI;iT.gpg`.
-- Select **View public GPG keys** (**{key}**) in the top right of the user's profile.
-
-GPG verified tags are not supported yet.
-
-See the [further reading](#further-reading) section for more details on GPG.
-
-## How GitLab handles GPG
-
-GitLab uses its own keyring to verify the GPG signature. It does not access any
-public key server.
-
-For a commit to be verified by GitLab:
+For GitLab to consider a commit verified:
- The committer must have a GPG public/private key pair.
-- The committer's public key must have been uploaded to their GitLab
- account.
-- One of the emails in the GPG key must match a **verified** email address
- used by the committer in GitLab. This address will be part of the public key.
- If you want to keep this address private, use the automatically generated
+- The committer's public key must be uploaded to their GitLab account.
+- One of the email addresses in the GPG public key must match a **verified** email address
+ used by the committer in GitLab. To keep this address private, use the automatically generated
[private commit email address](../../../profile/index.md#use-an-automatically-generated-private-commit-email)
GitLab provides in your profile.
- The committer's email address must match the verified email address from the
GPG key.
-## Generating a GPG key
+GitLab uses its own keyring to verify the GPG signature. It does not access any
+public key server.
-If you don't already have a GPG key, the following steps can help you get
-started:
+GPG verified tags are not supported.
-1. [Install GPG](https://www.gnupg.org/download/index.html) for your operating system.
+For more details about GPG, refer to the [related topics list](#related-topics).
+
+## View a user's public GPG key
+
+To view a user's public GPG key, you can either:
+
+- Go to `https://gitlab.example.com/.gpg`. GitLab displays the GPG key,
+ if the user has configured one, or a blank page for users without a configured GPG key.
+- Go to the user's profile (such as `https://gitlab.example.com/`). In the top right
+ of the user's profile, select **View public GPG keys** (**{key}**).
+
+## Configure commit signing
+
+To sign commits, you must configure both your local machine and your GitLab account:
+
+1. [Create a GPG key](#create-a-gpg-key).
+1. [Add a GPG key to your account](#add-a-gpg-key-to-your-account).
+1. [Associate your GPG key with Git](#associate-your-gpg-key-with-git).
+1. [Sign your Git commits](#sign-your-git-commits).
+
+### Create a GPG key
+
+If you don't already have a GPG key, create one:
+
+1. [Install GPG](https://www.gnupg.org/download/) for your operating system.
If your operating system has `gpg2` installed, replace `gpg` with `gpg2` in
- the following commands.
-1. Generate the private/public key pair with the command appropriate for your version
- of `gpg`. This command spawns a series of questions:
+ the commands on this page.
+1. To generate your key pair, run the command appropriate for your version of `gpg`:
```shell
- # Use this command for the default version of gpg, including
+ # Use this command for the default version of GPG, including
# Gpg4win on Windows, and most macOS versions:
gpg --gen-key
@@ -62,73 +73,29 @@ started:
gpg --full-gen-key
```
-1. The first question is which algorithm can be used. Select the kind you want
- or press Enter to choose the default (RSA and RSA):
-
- ```plaintext
- Please select what kind of key you want:
- (1) RSA and RSA (default)
- (2) DSA and Elgamal
- (3) DSA (sign only)
- (4) RSA (sign only)
- Your selection? 1
- ```
-
-1. The next question is key length. We recommend you choose `4096`:
-
- ```plaintext
- RSA keys may be between 1024 and 4096 bits long.
- What keysize do you want? (2048) 4096
- Requested keysize is 4096 bits
- ```
-
-1. Specify the validity period of your key. This is something
- subjective, and you can use the default value, which is to never expire:
-
- ```plaintext
- Please specify how long the key should be valid.
- 0 = key does not expire
- = key expires in n days
- w = key expires in n weeks
- m = key expires in n months
- y = key expires in n years
- Key is valid for? (0) 0
- Key does not expire at all
- ```
-
-1. Confirm that the answers you gave were correct by typing `y`:
-
- ```plaintext
- Is this correct? (y/N) y
- ```
-
-1. Enter your real name, the email address to be associated with this key
- (should match a verified email address you use in GitLab) and an optional
- comment (press Enter to skip):
-
- ```plaintext
- GnuPG needs to construct a user ID to identify your key.
-
- Real name: Mr. Robot
- Email address:
- Comment:
- You selected this USER-ID:
- "Mr. Robot "
-
- Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O
- ```
-
-1. Pick a strong password when asked and type it twice to confirm.
-1. Use the following command to list the private GPG key you just created:
+1. Select the algorithm your key should use, or press Enter to select
+ the default option, `RSA and RSA`.
+1. Select the key length, in bits. GitLab recommends 4096-bit keys.
+1. Specify the validity period of your key. This value is subjective, and the
+ default value is no expiration.
+1. To confirm your answers, enter `y`.
+1. Enter your name.
+1. Enter your email address. It must match a
+ [verified email address](../../../profile/index.md#change-the-email-displayed-on-your-commits)
+ in your GitLab account.
+1. Optional. Enter a comment to display in parentheses after your name.
+1. GPG displays the information you've entered so far. Edit the information or press
+ O (for `Okay`) to continue.
+1. Enter a strong password, then enter it again to confirm it.
+1. To list your private GPG key, run this command, replacing
+ `` with the email address you used when you generated the key:
```shell
- gpg --list-secret-keys --keyid-format LONG
+ gpg --list-secret-keys --keyid-format LONG
```
- Replace `` with the email address you entered above.
-
-1. Copy the GPG key ID that starts with `sec`. In the following example, that's
- `30F2B65B9246B6CA`:
+1. In the output, identify the `sec` line, and copy the GPG key ID. It begins after
+ the `/` character. In this example, the key ID is `30F2B65B9246B6CA`:
```plaintext
sec rsa4096/30F2B65B9246B6CA 2017-08-18 [SC]
@@ -137,49 +104,46 @@ started:
ssb rsa4096/B7ABC0813E4028C0 2017-08-18 [E]
```
-1. Export the public key of that ID (replace your key ID from the previous step):
+1. To show the associated public key, run this command, replacing `` with the
+ GPG key ID from the previous step:
```shell
- gpg --armor --export 30F2B65B9246B6CA
+ gpg --armor --export
```
-1. Finally, copy the public key and [add it in your user settings](#adding-a-gpg-key-to-your-account)
+1. Copy the public key, including the `BEGIN PGP PUBLIC KEY BLOCK` and
+ `END PGP PUBLIC KEY BLOCK` lines. You need this key in the next step.
-## Adding a GPG key to your account
+### Add a GPG key to your account
-NOTE:
-After you add a key, you cannot edit it, only remove it. In case the paste
-didn't work, you have to remove the offending key and re-add it.
-
-You can add a GPG key in your user settings:
+To add a GPG key to your user settings:
+1. Sign in to GitLab.
1. In the top-right corner, select your avatar.
1. Select **Edit profile**.
-1. On the left sidebar, select **GPG Keys**.
-1. Paste your _public_ key in the **Key** text box.
-
- ![Paste GPG public key](img/profile_settings_gpg_keys_paste_pub.png)
-
-1. Select **Add key** to add it to GitLab. You can see the key's fingerprint, the corresponding
- email address, and creation date.
+1. On the left sidebar, select **GPG Keys** (**{key}**).
+1. In **Key**, paste your _public_ key.
+1. To add the key to your account, select **Add key**. GitLab shows the key's
+ fingerprint, email address, and creation date:
![GPG key single page](img/profile_settings_gpg_keys_single_key.png)
-## Associating your GPG key with Git
+After you add a key, you cannot edit it. Instead, remove the offending key and re-add it.
-After you have [created your GPG key](#generating-a-gpg-key) and [added it to
-your account](#adding-a-gpg-key-to-your-account), it's time to tell Git which
-key to use.
+### Associate your GPG key with Git
-1. Use the following command to list the private GPG key you just created:
+After you [create your GPG key](#create-a-gpg-key) and
+[add it to your account](#add-a-gpg-key-to-your-account), you must configure Git
+to use this key:
+
+1. Run this command to list the private GPG key you just created,
+ replacing `` with the email address for your key:
```shell
- gpg --list-secret-keys --keyid-format LONG
+ gpg --list-secret-keys --keyid-format LONG
```
- Replace `` with the email address you entered above.
-
-1. Copy the GPG key ID that starts with `sec`. In the following example, that's
+1. Copy the GPG private key ID that starts with `sec`. In this example, the private key ID is
`30F2B65B9246B6CA`:
```plaintext
@@ -189,114 +153,103 @@ key to use.
ssb rsa4096/B7ABC0813E4028C0 2017-08-18 [E]
```
-1. Tell Git to use that key to sign the commits:
+1. Run this command to configure Git to sign your commits with your key,
+ replacing `` with your GPG key ID:
```shell
- git config --global user.signingkey 30F2B65B9246B6CA
+ git config --global user.signingkey
```
- Replace `30F2B65B9246B6CA` with your GPG key ID.
-
-1. Optional. If Git is using `gpg` and you get errors like `secret key not available`
- or `gpg: signing failed: secret key not available`, run the following command to
- change to `gpg2`:
+1. Optional. If Git uses `gpg` and you get errors like `secret key not available`
+ or `gpg: signing failed: secret key not available`, run this command to
+ use `gpg2` instead:
```shell
git config --global gpg.program gpg2
```
-## Signing commits
+### Sign your Git commits
-After you have [created your GPG key](#generating-a-gpg-key) and [added it to
-your account](#adding-a-gpg-key-to-your-account), you can start signing your
-commits:
+After you [add your public key to your account](#add-a-gpg-key-to-your-account),
+you can sign individual commits manually, or configure Git to default to signed commits:
-1. Commit like you used to, the only difference is the addition of the `-S` flag:
+- Sign individual Git commits manually:
+ 1. Add `-S` flag to any commit you want to sign:
- ```shell
- git commit -S -m "My commit msg"
- ```
+ ```shell
+ git commit -S -m "My commit message"
+ ```
-1. Enter the passphrase of your GPG key when asked.
-1. Push to GitLab and check that your commits [are verified](#verifying-commits).
+ 1. Enter the passphrase of your GPG key when asked.
+ 1. Push to GitLab and check that your commits [are verified](#verify-commits).
+- Sign all Git commits by default by running this command:
-If you don't want to type the `-S` flag every time you commit, you can tell Git
-to sign your commits automatically:
+ ```shell
+ git config --global commit.gpgsign true
+ ```
-```shell
-git config --global commit.gpgsign true
-```
+## Verify commits
-## Verifying commits
+You can review commits for a merge request, or for an entire project:
-1. Within a project or [merge request](../../merge_requests/index.md), navigate to
- the **Commits** tab. Signed commits show a badge containing either
- **Verified** or **Unverified**, depending on the verification status of the GPG
- signature.
+1. To review commits for a project:
+ 1. On the top bar, select **Menu > Projects** and find your project.
+ 1. On the left sidebar, select **Repository > Commits**.
+1. To review commits for a merge request:
+ 1. On the top bar, select **Menu > Projects** and find your project.
+ 1. On the left sidebar, select **Merge requests**, then select your merge request.
+ 1. Select **Commits**.
+1. Identify the commit you want to review. Signed commits show either a **Verified**
+ or **Unverified** badge, depending on the verification status of the GPG
+ signature. Unsigned commits do not display a badge:
![Signed and unsigned commits](img/project_signed_and_unsigned_commits.png)
-1. By clicking on the GPG badge, details of the signature are displayed.
+1. To display the signature details for a commit, select the GPG badge:
![Signed commit with verified signature](img/project_signed_commit_verified_signature.png)
- ![Signed commit with verified signature](img/project_signed_commit_unverified_signature.png)
+ ![Signed commit with unverified signature](img/project_signed_commit_unverified_signature.png)
-## Revoking a GPG key
+## Revoke a GPG key
-Revoking a key **unverifies** already signed commits. Commits that were
-verified by using this key changes to an unverified state. Future commits
-stay unverified after you revoke this key. This action should be used
-in case your key has been compromised.
+If a GPG key becomes compromised, revoke it. Revoking a key changes both future and past commits:
+
+- Past commits signed by this key are marked as unverified.
+- Future commits signed by this key are marked as unverified.
To revoke a GPG key:
1. In the top-right corner, select your avatar.
1. Select **Edit profile**.
-1. On the left sidebar, select **GPG Keys**.
+1. On the left sidebar, select **GPG Keys** (**{key}**).
1. Select **Revoke** next to the GPG key you want to delete.
-## Removing a GPG key
+## Remove a GPG key
-Removing a key **does not unverify** already signed commits. Commits that were
-verified by using this key stay verified. Only unpushed commits stay
-unverified after you remove this key. To unverify already signed commits, you need
-to [revoke the associated GPG key](#revoking-a-gpg-key) from your account.
+When you remove a GPG key from your GitLab account:
+
+- Previous commits signed with this key remain verified.
+- Future commits (including any commits created but not yet pushed) that attempt
+ to use this key are unverified.
To remove a GPG key from your account:
1. In the top-right corner, select your avatar.
1. Select **Edit profile**.
-1. On the left sidebar, select **GPG Keys**.
-1. Select the trash icon (**{remove}**) next to the GPG key you want to delete.
+1. On the left sidebar, select **GPG Keys** (**{key}**).
+1. Select **Remove** (**{remove}**) next to the GPG key you want to delete.
-## Rejecting commits that are not signed **(PREMIUM)**
+If you must unverify both future and past commits,
+[revoke the associated GPG key](#revoke-a-gpg-key) instead.
-You can configure your project to reject commits that aren't GPG-signed
-via [push rules](../push_rules.md).
+## Related topics
-## GPG signing API
-
-Learn how to [get the GPG signature from a commit via API](../../../../api/commits.md#get-gpg-signature-of-a-commit).
-
-## Further reading
-
-For more details about GPG, see:
-
-- [Git Tools - Signing Your Work](https://git-scm.com/book/en/v2/Git-Tools-Signing-Your-Work)
-- [Managing OpenPGP Keys](https://riseup.net/en/security/message-security/openpgp/gpg-keys)
-- [OpenPGP Best Practices](https://riseup.net/en/security/message-security/openpgp/best-practices)
-- [Creating a new GPG key with subkeys](https://www.void.gr/kargig/blog/2013/12/02/creating-a-new-gpg-key-with-subkeys/) (advanced)
-- [Review existing GPG keys in your instance](../../../admin_area/credentials_inventory.md#review-existing-gpg-keys)
-
-
+- [Sign commits and tags with X.509 certificates](../x509_signed_commits/index.md)
+- [Commits API](../../../../api/commits.md)
+- GPG resources:
+ - [Git Tools - Signing Your Work](https://git-scm.com/book/en/v2/Git-Tools-Signing-Your-Work)
+ - [Managing OpenPGP Keys](https://riseup.net/en/security/message-security/openpgp/gpg-keys)
+ - [OpenPGP Best Practices](https://riseup.net/en/security/message-security/openpgp/best-practices)
+ - [Creating a new GPG key with subkeys](https://www.void.gr/kargig/blog/2013/12/02/creating-a-new-gpg-key-with-subkeys/) (advanced)
+ - [Review existing GPG keys in your instance](../../../admin_area/credentials_inventory.md#review-existing-gpg-keys)
diff --git a/doc/user/project/repository/x509_signed_commits/index.md b/doc/user/project/repository/x509_signed_commits/index.md
index f319c1d8fd3..c9cddad1a91 100644
--- a/doc/user/project/repository/x509_signed_commits/index.md
+++ b/doc/user/project/repository/x509_signed_commits/index.md
@@ -20,7 +20,7 @@ The main difference is the way GitLab determines whether or not the developer's
(A trust store is a repository of trusted security certificates.) Combined with
any required intermediate certificates in the signature, the developer's certificate
can be chained back to a trusted root certificate.
-- For GPG, developers [add their GPG key](../gpg_signed_commits/index.md#adding-a-gpg-key-to-your-account)
+- For GPG, developers [add their GPG key](../gpg_signed_commits/index.md#add-a-gpg-key-to-your-account)
to their account.
GitLab uses its own certificate store and therefore defines the
diff --git a/lib/gitlab/gon_helper.rb b/lib/gitlab/gon_helper.rb
index a3c53869789..9f18513f066 100644
--- a/lib/gitlab/gon_helper.rb
+++ b/lib/gitlab/gon_helper.rb
@@ -59,6 +59,7 @@ module Gitlab
push_frontend_feature_flag(:sandboxed_mermaid, default_enabled: :yaml)
push_frontend_feature_flag(:source_editor_toolbar, default_enabled: :yaml)
push_frontend_feature_flag(:gl_avatar_for_all_user_avatars, default_enabled: :yaml)
+ push_frontend_feature_flag(:mr_attention_requests, default_enabled: :yaml)
end
# Exposes the state of a feature flag to the frontend code.
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index cc11367df43..e037fc64d9e 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -984,6 +984,9 @@ msgstr ""
msgid "%{strongOpen}Warning:%{strongClose} SAML group links can cause GitLab to automatically remove members from groups."
msgstr ""
+msgid "%{strongStart}Need your attention%{strongEnd} are the merge requests that need your help to move forward, as an assignee or reviewer."
+msgstr ""
+
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
@@ -4939,12 +4942,6 @@ msgstr ""
msgid "Assign to me"
msgstr ""
-msgid "Assign yourself to these issues"
-msgstr ""
-
-msgid "Assign yourself to this issue"
-msgstr ""
-
msgid "Assigned %{assignee_users_sentence}."
msgstr ""
@@ -34428,6 +34425,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some actions remove attention requests, like a reviewer approving or anyone merging the merge request."
+msgstr ""
+
msgid "Some changes are not shown"
msgstr ""
@@ -38468,6 +38468,9 @@ msgstr ""
msgid "To add the entry manually, provide the following details to the application on your phone."
msgstr ""
+msgid "To ask someone to look at a merge request, select %{strongStart}Request attention%{strongEnd}. Select again to remove the request."
+msgstr ""
+
msgid "To confirm, type %{phrase_code}"
msgstr ""
@@ -44005,6 +44008,12 @@ msgstr ""
msgid "mrWidget|Approved by you and others"
msgstr ""
+msgid "mrWidget|Assign yourself to these issues"
+msgstr ""
+
+msgid "mrWidget|Assign yourself to this issue"
+msgstr ""
+
msgid "mrWidget|Cancel auto-merge"
msgstr ""
diff --git a/scripts/ingest-reports-to-siem b/scripts/ingest-reports-to-siem
index fbd41dc3a8e..86c72e1d7eb 100755
--- a/scripts/ingest-reports-to-siem
+++ b/scripts/ingest-reports-to-siem
@@ -19,15 +19,22 @@ function getMD5HashFromFile(data) {
try {
const file = 'gl-dependency-scanning-report.json'
const data = fs.readFileSync(file)
+
+ const [filename, fileext] = path.basename(file).split('.')
+ const uniqueId = process.env['CI_PIPELINE_ID'] && process.env['CI_JOB_ID'] ?
+ process.env['CI_PIPELINE_ID'] + '-' + process.env['CI_JOB_ID'] :
+ Date.now()
+ const key = path.join('package_hunter_test', filename + '-' + uniqueId + '.' + fileext)
+
const responseData = await s3Client.send(
new PutObjectCommand({
Bucket: 'gl-logs-for-panther-test',
- Key: path.join('package_hunter_test', path.basename(file)),
+ Key: key,
Body: data,
ContentMD5: getMD5HashFromFile(data),
}),
)
- console.log('Successfully uploaded %s', file)
+ console.log('Successfully uploaded %s to %s', file, key)
} catch (err) {
if (err.name === 'CredentialsProviderError' || err.name === 'AuthorizationHeaderMalformed')
console.log('Could not upload the report. Are AWS credentials configured in ~/.aws/credentials?')
diff --git a/spec/features/users/login_spec.rb b/spec/features/users/login_spec.rb
index 062e79ea91a..4d06415e203 100644
--- a/spec/features/users/login_spec.rb
+++ b/spec/features/users/login_spec.rb
@@ -797,6 +797,7 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions do
context 'when 2FA is required for the user' do
before do
+ stub_feature_flags(mr_attention_requests: false)
group = create(:group, require_two_factor_authentication: true)
group.add_developer(user)
end
diff --git a/spec/frontend/attention_requests/components/navigation_popover_spec.js b/spec/frontend/attention_requests/components/navigation_popover_spec.js
new file mode 100644
index 00000000000..d0231afbdc4
--- /dev/null
+++ b/spec/frontend/attention_requests/components/navigation_popover_spec.js
@@ -0,0 +1,86 @@
+import { shallowMount } from '@vue/test-utils';
+import { GlPopover, GlButton, GlSprintf, GlIcon } from '@gitlab/ui';
+import { GlBreakpointInstance as bp } from '@gitlab/ui/dist/utils';
+import NavigationPopover from '~/attention_requests/components/navigation_popover.vue';
+import { makeMockUserCalloutDismisser } from 'helpers/mock_user_callout_dismisser';
+
+let wrapper;
+let dismiss;
+
+function createComponent(provideData = {}, shouldShowCallout = true) {
+ wrapper = shallowMount(NavigationPopover, {
+ provide: {
+ message: ['Test'],
+ observerElSelector: '.js-test',
+ observerElToggledClass: 'show',
+ featureName: 'attention_requests',
+ popoverTarget: '.js-test-popover',
+ ...provideData,
+ },
+ stubs: {
+ UserCalloutDismisser: makeMockUserCalloutDismisser({
+ dismiss,
+ shouldShowCallout,
+ }),
+ GlSprintf,
+ },
+ });
+}
+
+describe('Attention requests navigation popover', () => {
+ beforeEach(() => {
+ setFixtures('');
+ dismiss = jest.fn();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ it('hides popover if callout is disabled', () => {
+ createComponent({}, false);
+
+ expect(wrapper.findComponent(GlPopover).exists()).toBe(false);
+ });
+
+ it('shows popover if callout is enabled', () => {
+ createComponent();
+
+ expect(wrapper.findComponent(GlPopover).exists()).toBe(true);
+ });
+
+ it.each`
+ isDesktop | device | expectedPlacement
+ ${true} | ${'desktop'} | ${'left'}
+ ${false} | ${'mobile'} | ${'bottom'}
+ `(
+ 'sets popover position to $expectedPlacement on $device',
+ ({ isDesktop, expectedPlacement }) => {
+ jest.spyOn(bp, 'isDesktop').mockReturnValue(isDesktop);
+
+ createComponent();
+
+ expect(wrapper.findComponent(GlPopover).props('placement')).toBe(expectedPlacement);
+ },
+ );
+
+ it('calls dismiss when clicking action button', () => {
+ createComponent();
+
+ wrapper
+ .findComponent(GlButton)
+ .vm.$emit('click', { preventDefault() {}, stopPropagation() {} });
+
+ expect(dismiss).toHaveBeenCalled();
+ });
+
+ it('shows icon in text', () => {
+ createComponent({ showAttentionIcon: true, message: ['%{strongStart}Test%{strongEnd}'] });
+
+ const icon = wrapper.findComponent(GlIcon);
+
+ expect(icon.exists()).toBe(true);
+ expect(icon.props('name')).toBe('attention');
+ });
+});
diff --git a/spec/frontend/vue_mr_widget/components/mr_widget_related_links_spec.js b/spec/frontend/vue_mr_widget/components/mr_widget_related_links_spec.js
index 6ea8ca10c02..15522f7ac1d 100644
--- a/spec/frontend/vue_mr_widget/components/mr_widget_related_links_spec.js
+++ b/spec/frontend/vue_mr_widget/components/mr_widget_related_links_spec.js
@@ -1,3 +1,4 @@
+import { GlLink } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import RelatedLinks from '~/vue_merge_request_widget/components/mr_widget_related_links.vue';
@@ -85,13 +86,29 @@ describe('MRWidgetRelatedLinks', () => {
expect(content).toContain('Mentions issues #23 and #42');
});
- it('should have assing issues link', () => {
- createComponent({
- relatedLinks: {
- assignToMe: 'Assign yourself to these issues',
- },
+ describe('should have correct assign issues link', () => {
+ it.each([
+ [1, 'Assign yourself to this issue'],
+ [2, 'Assign yourself to these issues'],
+ ])('when issue count is %s, link displays correct text', (unassignedCount, text) => {
+ const assignToMe = '/assign';
+
+ createComponent({
+ relatedLinks: { assignToMe, unassignedCount },
+ });
+
+ const glLinkWrapper = wrapper.findComponent(GlLink);
+
+ expect(glLinkWrapper.attributes('href')).toBe(assignToMe);
+ expect(glLinkWrapper.text()).toBe(text);
});
- expect(wrapper.text().trim()).toContain('Assign yourself to these issues');
+ it('when no link is present', () => {
+ createComponent({
+ relatedLinks: { assignToMe: '#', unassignedCount: 0 },
+ });
+
+ expect(wrapper.findComponent(GlLink).exists()).toBe(false);
+ });
});
});
diff --git a/spec/presenters/merge_request_presenter_spec.rb b/spec/presenters/merge_request_presenter_spec.rb
index 60296cca058..dbf5af095cb 100644
--- a/spec/presenters/merge_request_presenter_spec.rb
+++ b/spec/presenters/merge_request_presenter_spec.rb
@@ -162,10 +162,19 @@ RSpec.describe MergeRequestPresenter do
end
end
- describe '#assign_to_closing_issues_link' do
+ describe '#assign_to_closing_issues_path' do
subject do
described_class.new(resource, current_user: user)
- .assign_to_closing_issues_link
+ .assign_to_closing_issues_path
+ end
+
+ it { is_expected.to match("#{project.full_path}/-/merge_requests/#{resource.iid}/assign_related_issues") }
+ end
+
+ describe '#assign_to_closing_issues_count' do
+ subject do
+ described_class.new(resource, current_user: user)
+ .assign_to_closing_issues_count
end
before do
@@ -178,33 +187,28 @@ RSpec.describe MergeRequestPresenter do
let(:issue) { create(:issue) }
let(:assignable_issues) { [issue] }
- it 'returns correct link with correct text' do
+ it 'returns correct count' do
is_expected
- .to match("#{project.full_path}/-/merge_requests/#{resource.iid}/assign_related_issues")
-
- is_expected
- .to match("Assign yourself to this issue")
+ .to match(1)
end
end
context 'multiple closing issues' do
- let(:issues) { create_list(:issue, 2) }
+ let(:issues) { build_list(:issue, 2) }
let(:assignable_issues) { issues }
- it 'returns correct link with correct text' do
+ it 'returns correct count' do
is_expected
- .to match("#{project.full_path}/-/merge_requests/#{resource.iid}/assign_related_issues")
-
- is_expected
- .to match("Assign yourself to these issues")
+ .to match(2)
end
end
context 'no closing issue' do
let(:assignable_issues) { [] }
- it 'returns correct link with correct text' do
- is_expected.to be_nil
+ it 'returns correct count' do
+ is_expected
+ .to match(0)
end
end
end
diff --git a/spec/serializers/merge_request_widget_entity_spec.rb b/spec/serializers/merge_request_widget_entity_spec.rb
index 1712df6266c..f0779f1c57c 100644
--- a/spec/serializers/merge_request_widget_entity_spec.rb
+++ b/spec/serializers/merge_request_widget_entity_spec.rb
@@ -59,7 +59,7 @@ RSpec.describe MergeRequestWidgetEntity do
data = described_class.new(resource, request: request, issues_links: true).as_json
expect(data).to include(:issues_links)
- expect(data[:issues_links]).to include(:assign_to_closing, :closing, :mentioned_but_not_closing, :closing_count, :mentioned_count)
+ expect(data[:issues_links]).to include(:assign_to_closing, :assign_to_closing_count, :closing, :mentioned_but_not_closing, :closing_count, :mentioned_count)
end
it 'omits issue links by default' do