@@ -1723,7 +1723,7 @@
*bar*
wysiwyg: |-
-
+
*bar*
04_06__leaf_blocks__html_blocks__016:
@@ -2065,7 +2065,7 @@
baz
wysiwyg: |-
Foo
-
+
baz
04_06__leaf_blocks__html_blocks__040:
canonical: |
@@ -2145,7 +2145,7 @@
foo
wysiwyg: |-
[foo]: /url "title"
- foo
+ foo
04_07__leaf_blocks__link_reference_definitions__002:
canonical: |
foo
@@ -2153,7 +2153,7 @@
foo
wysiwyg: |-
[foo]: /url "the title"
- foo
+ foo
04_07__leaf_blocks__link_reference_definitions__003:
canonical: |
Foo*bar]
@@ -2161,7 +2161,7 @@
Foo*bar]
wysiwyg: |-
[foo*bar\]]: my_(url) "title (with parens)"
- Foo*bar]
+ Foo*bar]
04_07__leaf_blocks__link_reference_definitions__004:
canonical: |
Foo bar
@@ -2169,7 +2169,7 @@
Foo bar
wysiwyg: |-
[foo bar]: my url "title"
- Foo bar
+ Foo bar
04_07__leaf_blocks__link_reference_definitions__005:
canonical: |
- foo
wysiwyg: |-
[foo]: /url
- foo
+ foo
04_07__leaf_blocks__link_reference_definitions__008:
canonical: |
[foo]:
@@ -2250,14 +2250,14 @@
foo
wysiwyg: |-
[foo]: /url\bar*baz "foo"bar\baz"
- foo
+ foo
04_07__leaf_blocks__link_reference_definitions__012:
canonical: |
foo
static: |-
foo
wysiwyg: |-
- foo
+ foo
[foo]: url
04_07__leaf_blocks__link_reference_definitions__013:
canonical: |
@@ -2265,7 +2265,7 @@
static: |-
foo
wysiwyg: |-
- foo
+ foo
[foo]: first
[foo]: second
04_07__leaf_blocks__link_reference_definitions__014:
@@ -2275,7 +2275,7 @@
Foo
wysiwyg: |-
[foo]: /url
- Foo
+ Foo
04_07__leaf_blocks__link_reference_definitions__015:
canonical: |
αγω
@@ -2283,7 +2283,7 @@
αγω
wysiwyg: |-
[αγω]: /φου
- αγω
+ αγω
04_07__leaf_blocks__link_reference_definitions__016:
canonical: ""
static: ""
@@ -2367,7 +2367,7 @@
bar
wysiwyg: |-
-
+
[foo]: /url
bar
04_07__leaf_blocks__link_reference_definitions__024:
@@ -2381,7 +2381,7 @@
wysiwyg: |-
[foo]: /url
bar
- foo
+ foo
04_07__leaf_blocks__link_reference_definitions__025:
canonical: |
===
@@ -2392,7 +2392,7 @@
wysiwyg: |-
[foo]: /url
===
- foo
+ foo
04_07__leaf_blocks__link_reference_definitions__026:
canonical: |
foo,
@@ -2406,9 +2406,9 @@
[foo]: /foo-url "foo"
[bar]: /bar-url "bar"
[baz]: /baz-url
- foo,
- bar,
- baz
+ foo,
+ bar,
+ baz
04_07__leaf_blocks__link_reference_definitions__027:
canonical: |
foo
@@ -2419,7 +2419,7 @@
wysiwyg: |-
- foo
+ foo
[foo]: /url
04_07__leaf_blocks__link_reference_definitions__028:
canonical: ""
@@ -4883,7 +4883,7 @@
static: |-
http://example.com?find=\*
wysiwyg: |-
- http://example.com?find=\*
+ http://example.com?find=\*
06_02__inlines__backslash_escapes__010:
canonical: |
@@ -4897,14 +4897,14 @@
static: |-
foo
wysiwyg: |-
- foo
+ foo
06_02__inlines__backslash_escapes__012:
canonical: |
foo
static: |-
foo
wysiwyg: |-
- foo
+ foo
[foo]: /bar* "ti*tle"
06_02__inlines__backslash_escapes__013:
canonical: |
@@ -4987,14 +4987,14 @@
static: |-
foo
wysiwyg: |-
- foo
+ foo
06_03__inlines__entity_and_numeric_character_references__009:
canonical: |
foo
static: |-
foo
wysiwyg: |-
- foo
+ foo
[foo]: /föö "föö"
06_03__inlines__entity_and_numeric_character_references__010:
canonical: |
@@ -5193,7 +5193,7 @@
static: |-
`
wysiwyg: |-
- `
+ `
06_04__inlines__code_spans__018:
canonical: |
<http://foo.bar. baz>`
@@ -5207,7 +5207,7 @@
static: |-
http://foo.bar.`baz`
wysiwyg: |-
- http://foo.bar.`baz`
+ http://foo.bar.`baz`
06_04__inlines__code_spans__020:
canonical: |
```foo``
@@ -5615,7 +5615,7 @@
static: |-
foo bar
wysiwyg: |-
- foo bar
+ foo bar
06_05__inlines__emphasis_and_strong_emphasis__055:
canonical: |
foo
@@ -5723,7 +5723,7 @@
static: |-
foo bar
wysiwyg: |-
- foo bar
+ foo bar
06_05__inlines__emphasis_and_strong_emphasis__070:
canonical: |
** is not an empty emphasis
@@ -5744,7 +5744,7 @@
static: |-
foo bar
wysiwyg: |-
- foo bar
+ foo bar
06_05__inlines__emphasis_and_strong_emphasis__073:
canonical: |
foo
@@ -5827,7 +5827,7 @@
static: |-
foo bar
wysiwyg: |-
- foo bar
+ foo bar
06_05__inlines__emphasis_and_strong_emphasis__084:
canonical: |
__ is not an empty emphasis
@@ -6107,21 +6107,21 @@
static: |-
*bar*
wysiwyg: |-
- *bar*
+ *bar*
06_05__inlines__emphasis_and_strong_emphasis__124:
canonical: |
_foo bar_
static: |-
_foo bar_
wysiwyg: |-
- _foo bar_
+ _foo bar_
06_05__inlines__emphasis_and_strong_emphasis__125:
canonical: |
*![*](foo)
static: |-
*![*](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
wysiwyg: |-
- *![*](http://test.host/foo)
+ *![*](foo)
06_05__inlines__emphasis_and_strong_emphasis__126:
canonical: |
**
@@ -6187,14 +6187,14 @@
static: |-
link
wysiwyg: |-
- link
+ link
06_07__inlines__links__002:
canonical: |
link
static: |-
link
wysiwyg: |-
- link
+ link
06_07__inlines__links__003:
canonical: |
link
@@ -6222,7 +6222,7 @@
static: |-
link
wysiwyg: |-
- link
+ link
06_07__inlines__links__007:
canonical: |
[link](foo
@@ -6247,7 +6247,7 @@
static: |-
a
wysiwyg: |-
- a
+ a
06_07__inlines__links__010:
canonical: |
[link](<foo>)
@@ -6274,35 +6274,35 @@
static: |-
link
wysiwyg: |-
- link
+ link
06_07__inlines__links__013:
canonical: |
link
static: |-
link
wysiwyg: |-
- link
+ link
06_07__inlines__links__014:
canonical: |
link
static: |-
link
wysiwyg: |-
- link
+ link
06_07__inlines__links__015:
canonical: |
link
static: |-
link
wysiwyg: |-
- link
+ link
06_07__inlines__links__016:
canonical: |
link
static: |-
link
wysiwyg: |-
- link
+ link
06_07__inlines__links__017:
canonical: |
link
@@ -6313,30 +6313,30 @@
link
link
wysiwyg: |-
- link
- link
- link
+ link
+ link
+ link
06_07__inlines__links__018:
canonical: |
link
static: |-
link
wysiwyg: |-
- link
+ link
06_07__inlines__links__019:
canonical: |
link
static: |-
link
wysiwyg: |-
- link
+ link
06_07__inlines__links__020:
canonical: |
link
static: |-
link
wysiwyg: |-
- link
+ link
06_07__inlines__links__021:
canonical: |
link
@@ -6347,21 +6347,21 @@
link
link
wysiwyg: |-
- linklinklink
+ linklinklink
06_07__inlines__links__022:
canonical: |
link
static: |-
link
wysiwyg: |-
- link
+ link
06_07__inlines__links__023:
canonical: |
link
static: |-
link
wysiwyg: |-
- link
+ link
06_07__inlines__links__024:
canonical: |
[link](/url "title "and" title")
@@ -6375,14 +6375,14 @@
static: |-
link
wysiwyg: |-
- link
+ link
06_07__inlines__links__026:
canonical: |
link
static: |-
link
wysiwyg: |-
- link
+ link
06_07__inlines__links__027:
canonical: |
[link] (/uri)
@@ -6396,7 +6396,7 @@
static: |-
link [foo [bar]]
wysiwyg: |-
- link [foo [bar]]
+ link [foo [bar]]
06_07__inlines__links__029:
canonical: |
[link] bar](/uri)
@@ -6410,63 +6410,63 @@
static: |-
[link bar
wysiwyg: |-
- [link bar
+ [link bar
06_07__inlines__links__031:
canonical: |
link [bar
static: |-
link [bar
wysiwyg: |-
- link [bar
+ link [bar
06_07__inlines__links__032:
canonical: |
link foo bar #
static: |-
link foo bar #
wysiwyg: |-
- link foo bar#
+ link foo bar#
06_07__inlines__links__033:
canonical: |
![moon](moon.jpg)
static: |-
![moon](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
wysiwyg: |-
- ![moon](http://test.host/moon.jpg)
+ ![moon](moon.jpg)
06_07__inlines__links__034:
canonical: |
[foo bar](/uri)
static: |-
[foo bar](/uri)
wysiwyg: |-
- [foo bar](/uri)
+ [foo bar](/uri)
06_07__inlines__links__035:
canonical: |
[foo [bar baz](/uri)](/uri)
static: |-
[foo [bar baz](/uri)](/uri)
wysiwyg: |-
- [foo [bar baz](/uri)](/uri)
+ [foo [bar baz](/uri)](/uri)
06_07__inlines__links__036:
canonical: |
![[foo](uri2)](uri3)
static: |-
![[foo](uri2)](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
wysiwyg: |-
- ![[foo](uri2)](http://test.host/uri3)
+ ![[foo](uri2)](uri3)
06_07__inlines__links__037:
canonical: |
*foo*
static: |-
*foo*
wysiwyg: |-
- *foo*
+ *foo*
06_07__inlines__links__038:
canonical: |
foo *bar
static: |-
foo *bar
wysiwyg: |-
- foo *bar
+ foo *bar
06_07__inlines__links__039:
canonical: |
foo [bar baz]
@@ -6501,7 +6501,7 @@
static: |-
foo
wysiwyg: |-
- foo
+ foo
[bar]: /url "title"
06_07__inlines__links__044:
canonical: |
@@ -6509,7 +6509,7 @@
static: |-
link [foo [bar]]
wysiwyg: |-
- link [foo [bar]]
+ link [foo [bar]]
[ref]: /uri
06_07__inlines__links__045:
canonical: |
@@ -6517,7 +6517,7 @@
static: |-
link [bar
wysiwyg: |-
- link [bar
+ link [bar
[ref]: /uri
06_07__inlines__links__046:
canonical: |
@@ -6525,7 +6525,7 @@
static: |-
link foo bar #
wysiwyg: |-
- link foo bar#
+ link foo bar#
[ref]: /uri
06_07__inlines__links__047:
canonical: |
@@ -6533,7 +6533,7 @@
static: |-
![moon](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
wysiwyg: |-
- ![moon](http://test.host/moon.jpg)
+ ![moon](moon.jpg)
[ref]: /uri
06_07__inlines__links__048:
canonical: |
@@ -6541,7 +6541,7 @@
static: |-
[foo bar]ref
wysiwyg: |-
- [foo bar]ref
+ [foo bar]ref
[ref]: /uri
06_07__inlines__links__049:
canonical: |
@@ -6549,7 +6549,7 @@
static: |-
[foo bar baz]ref
wysiwyg: |-
- [foo bar baz]ref
+ [foo bar baz]ref
[ref]: /uri
06_07__inlines__links__050:
canonical: |
@@ -6557,7 +6557,7 @@
static: |-
*foo*
wysiwyg: |-
- *foo*
+ *foo*
[ref]: /uri
06_07__inlines__links__051:
canonical: |
@@ -6565,7 +6565,7 @@
static: |-
foo *bar
wysiwyg: |-
- foo *bar
+ foo *bar
[ref]: /uri
06_07__inlines__links__052:
canonical: |
@@ -6597,7 +6597,7 @@
static: |-
foo
wysiwyg: |-
- foo
+ foo
[bar]: /url "title"
06_07__inlines__links__056:
canonical: |
@@ -6605,7 +6605,7 @@
static: |-
Толпой is a Russian word.
wysiwyg: |-
- Толпой is a Russian word.
+ Толпой is a Russian word.
[толпой]: /url
06_07__inlines__links__057:
canonical: |
@@ -6614,14 +6614,14 @@
Baz
wysiwyg: |-
[foo bar]: /url
- Baz
+ Baz
06_07__inlines__links__058:
canonical: |
[foo] bar
static: |-
[foo] bar
wysiwyg: |-
- [foo] bar
+ [foo] bar
[bar]: /url "title"
06_07__inlines__links__059:
canonical: |
@@ -6632,7 +6632,7 @@
bar
wysiwyg: |-
[foo]
- bar
+ bar
[bar]: /url "title"
06_07__inlines__links__060:
canonical: |
@@ -6642,7 +6642,7 @@
wysiwyg: |-
[foo]: /url1
[foo]: /url2
- bar
+ bar
06_07__inlines__links__061:
canonical: |
[bar][foo!]
@@ -6687,7 +6687,7 @@
static: |-
foo
wysiwyg: |-
- foo
+ foo
[ref\[]: /uri
06_07__inlines__links__066:
canonical: |
@@ -6696,7 +6696,7 @@
bar\
wysiwyg: |-
[bar\\]: /uri
- bar\
+ bar\
06_07__inlines__links__067:
canonical: |
[]
@@ -6729,7 +6729,7 @@
static: |-
foo
wysiwyg: |-
- foo
+ foo
[foo]: /url "title"
06_07__inlines__links__070:
canonical: |
@@ -6737,7 +6737,7 @@
static: |-
foo bar
wysiwyg: |-
- foo bar
+ foo bar
[*foo* bar]: /url "title"
06_07__inlines__links__071:
canonical: |
@@ -6745,7 +6745,7 @@
static: |-
Foo
wysiwyg: |-
- Foo
+ Foo
[foo]: /url "title"
06_07__inlines__links__072:
canonical: |
@@ -6755,7 +6755,7 @@
foo
[]
wysiwyg: |-
- foo
+ foo
[]
[foo]: /url "title"
06_07__inlines__links__073:
@@ -6764,7 +6764,7 @@
static: |-
foo
wysiwyg: |-
- foo
+ foo
[foo]: /url "title"
06_07__inlines__links__074:
canonical: |
@@ -6772,7 +6772,7 @@
static: |-
foo bar
wysiwyg: |-
- foo bar
+ foo bar
[*foo* bar]: /url "title"
06_07__inlines__links__075:
canonical: |
@@ -6780,7 +6780,7 @@
static: |-
[foo bar]
wysiwyg: |-
- [foo bar]
+ [foo bar]
[*foo* bar]: /url "title"
06_07__inlines__links__076:
canonical: |
@@ -6788,7 +6788,7 @@
static: |-
[[bar foo
wysiwyg: |-
- [[bar foo
+ [[bar foo
[foo]: /url
06_07__inlines__links__077:
canonical: |
@@ -6796,7 +6796,7 @@
static: |-
Foo
wysiwyg: |-
- Foo
+ Foo
[foo]: /url "title"
06_07__inlines__links__078:
canonical: |
@@ -6804,7 +6804,7 @@
static: |-
foo bar
wysiwyg: |-
- foo bar
+ foo bar
[foo]: /url
06_07__inlines__links__079:
canonical: |
@@ -6821,14 +6821,14 @@
*foo*
wysiwyg: |-
[foo*]: /url
- *foo*
+ *foo*
06_07__inlines__links__081:
canonical: |
foo
static: |-
foo
wysiwyg: |-
- foo
+ foo
[foo]: /url1
[bar]: /url2
06_07__inlines__links__082:
@@ -6837,7 +6837,7 @@
static: |-
foo
wysiwyg: |-
- foo
+ foo
[foo]: /url1
06_07__inlines__links__083:
canonical: |
@@ -6853,7 +6853,7 @@
static: |-
foo(not a link)
wysiwyg: |-
- foo(not a link)
+ foo(not a link)
[foo]: /url1
06_07__inlines__links__085:
canonical: |
@@ -6861,7 +6861,7 @@
static: |-
[foo]bar
wysiwyg: |-
- [foo]bar
+ [foo]bar
[baz]: /url
06_07__inlines__links__086:
canonical: |
@@ -6869,7 +6869,7 @@
static: |-
foobaz
wysiwyg: |-
- foobaz
+ foobaz
[baz]: /url1
[bar]: /url2
06_07__inlines__links__087:
@@ -6878,7 +6878,7 @@
static: |-
[foo]bar
wysiwyg: |-
- [foo]bar
+ [foo]bar
[baz]: /url1
[foo]: /url2
06_08__inlines__images__001:
@@ -6887,14 +6887,14 @@
static: |-
![title foo](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
wysiwyg: |-
- ![title foo](http://test.host/url)
+ ![title foo](/url)
06_08__inlines__images__002:
canonical: |
![train & tracks foo bar](train.jpg)
static: |-
![train & tracks foo bar](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
wysiwyg: |-
- ![train & tracks foo bar](http://test.host/train.jpg)
+ ![train & tracks foo bar](train.jpg)
[foo *bar*]: train.jpg "train & tracks"
06_08__inlines__images__003:
canonical: |
@@ -6902,21 +6902,21 @@
static: |-
![foo bar](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
wysiwyg: |-
- ![foo bar](http://test.host/url2)
+ ![foo bar](/url2)
06_08__inlines__images__004:
canonical: |
![foo bar](/url2)
static: |-
![foo bar](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
wysiwyg: |-
- ![foo bar](http://test.host/url2)
+ ![foo bar](/url2)
06_08__inlines__images__005:
canonical: |
![train & tracks foo bar](train.jpg)
static: |-
![train & tracks foo bar](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
wysiwyg: |-
- ![train & tracks foo bar](http://test.host/train.jpg)
+ ![train & tracks foo bar](train.jpg)
[foo *bar*]: train.jpg "train & tracks"
06_08__inlines__images__006:
canonical: |
@@ -6924,7 +6924,7 @@
static: |-
![train & tracks foo bar](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
wysiwyg: |-
- ![train & tracks foo bar](http://test.host/train.jpg)
+ ![train & tracks foo bar](train.jpg)
[foobar]: train.jpg "train & tracks"
06_08__inlines__images__007:
canonical: |
@@ -6932,35 +6932,35 @@
static: |-
![foo](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
wysiwyg: |-
- ![foo](http://test.host/train.jpg)
+ ![foo](train.jpg)
06_08__inlines__images__008:
canonical: |
My ![title foo bar](/path/to/train.jpg)
static: |-
My ![title foo bar](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
wysiwyg: |-
- My ![title foo bar](http://test.host/path/to/train.jpg)
+ My ![title foo bar](/path/to/train.jpg)
06_08__inlines__images__009:
canonical: |
![foo](url)
static: |-
![foo](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
wysiwyg: |-
- ![foo](http://test.host/url)
+ ![foo](url)
06_08__inlines__images__010:
canonical: |
![](/url)
static: |-
![](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
wysiwyg: |-
- ![](http://test.host/url)
+ ![](/url)
06_08__inlines__images__011:
canonical: |
![foo](/url)
static: |-
![foo](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
wysiwyg: |-
- ![foo](http://test.host/url)
+ ![foo](/url)
[bar]: /url
06_08__inlines__images__012:
canonical: |
@@ -6968,7 +6968,7 @@
static: |-
![foo](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
wysiwyg: |-
- ![foo](http://test.host/url)
+ ![foo](/url)
[bar]: /url
06_08__inlines__images__013:
canonical: |
@@ -6976,7 +6976,7 @@
static: |-
![title foo](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
wysiwyg: |-
- ![title foo](http://test.host/url)
+ ![title foo](/url)
[foo]: /url "title"
06_08__inlines__images__014:
canonical: |
@@ -6984,7 +6984,7 @@
static: |-
![title foo bar](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
wysiwyg: |-
- ![title foo bar](http://test.host/url)
+ ![title foo bar](/url)
[*foo* bar]: /url "title"
06_08__inlines__images__015:
canonical: |
@@ -6992,7 +6992,7 @@
static: |-
![title Foo](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
wysiwyg: |-
- ![title Foo](http://test.host/url)
+ ![title Foo](/url)
[foo]: /url "title"
06_08__inlines__images__016:
canonical: |
@@ -7002,7 +7002,7 @@
[]
wysiwyg: |-
-
+
[]
[foo]: /url "title"
06_08__inlines__images__017:
@@ -7011,7 +7011,7 @@
static: |-
![title foo](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
wysiwyg: |-
- ![title foo](http://test.host/url)
+ ![title foo](/url)
[foo]: /url "title"
06_08__inlines__images__018:
canonical: |
@@ -7019,7 +7019,7 @@
static: |-
![title foo bar](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
wysiwyg: |-
- ![title foo bar](http://test.host/url)
+ ![title foo bar](/url)
[*foo* bar]: /url "title"
06_08__inlines__images__019:
canonical: |
@@ -7037,7 +7037,7 @@
static: |-
![title Foo](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
wysiwyg: |-
- ![title Foo](http://test.host/url)
+ ![title Foo](/url)
[foo]: /url "title"
06_08__inlines__images__021:
canonical: |
@@ -7053,7 +7053,7 @@
static: |-
!foo
wysiwyg: |-
- !foo
+ !foo
[foo]: /url "title"
06_09__inlines__autolinks__001:
canonical: |
@@ -7061,7 +7061,7 @@
static: |-
http://foo.bar.baz
wysiwyg: |-
- http://foo.bar.baz
+ http://foo.bar.baz
06_09__inlines__autolinks__002:
canonical: |
http://foo.bar.baz/test?q=hello&id=22&boolean
@@ -7075,28 +7075,28 @@
static: |-
irc://foo.bar:2233/baz
wysiwyg: |-
- irc://foo.bar:2233/baz
+ irc://foo.bar:2233/baz
06_09__inlines__autolinks__004:
canonical: |
MAILTO:FOO@BAR.BAZ
static: |-
MAILTO:FOO@BAR.BAZ
wysiwyg: |-
- MAILTO:FOO@BAR.BAZ
+ MAILTO:FOO@BAR.BAZ
06_09__inlines__autolinks__005:
canonical: |
a+b+c:d
static: |-
a+b+c:d
wysiwyg: |-
- a+b+c:d
+ a+b+c:d
06_09__inlines__autolinks__006:
canonical: |
made-up-scheme://foo,bar
static: |-
made-up-scheme://foo,bar
wysiwyg: |-
- made-up-scheme://foo,bar
+ made-up-scheme://foo,bar
06_09__inlines__autolinks__007:
canonical: |
http://../
@@ -7110,7 +7110,7 @@
static: |-
localhost:5001/foo
wysiwyg: |-
- localhost:5001/foo
+ localhost:5001/foo
06_09__inlines__autolinks__009:
canonical: |
<http://foo.bar/baz bim>
@@ -7159,7 +7159,7 @@
static: |-
< http://foo.bar >
wysiwyg: |-
- < http://foo.bar >
+ < http://foo.bar >
06_09__inlines__autolinks__016:
canonical: |
<m:abc>
@@ -7180,7 +7180,7 @@
static: |-
http://example.com
wysiwyg: |-
- http://example.com
+ http://example.com
06_09__inlines__autolinks__019:
canonical: |
foo@bar.example.com
@@ -7194,7 +7194,7 @@
static: |-
www.commonmark.org
wysiwyg: |-
- www.commonmark.org
+ www.commonmark.org
06_10__inlines__autolinks_extension__002:
canonical: |
Visit www.commonmark.org/help for more information.
@@ -7210,7 +7210,7 @@
Visit www.commonmark.org.
Visit www.commonmark.org/a.b.
wysiwyg: |-
- Visit www.commonmark.org.
+ Visit www.commonmark.org.
Visit www.commonmark.org/a.b.
06_10__inlines__autolinks_extension__004:
canonical: |
@@ -7262,7 +7262,7 @@
(Visit https://encrypted.google.com/search?q=Markup+(business))
Anonymous FTP is available at ftp://foo.bar.baz.
wysiwyg: |-
- http://commonmark.org
+ http://commonmark.org
(Visit https://encrypted.google.com/search?q=Markup+(business))
Anonymous FTP is available at ftp://foo.bar.baz.
06_10__inlines__autolinks_extension__009:
diff --git a/glfm_specification/example_snapshots/prosemirror_json.yml b/glfm_specification/example_snapshots/prosemirror_json.yml
index 73fcef4dbc0..7f08d4e4a1d 100644
--- a/glfm_specification/example_snapshots/prosemirror_json.yml
+++ b/glfm_specification/example_snapshots/prosemirror_json.yml
@@ -3145,7 +3145,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/bar",
+ "href": "bar",
"target": "_blank",
"class": null,
"title": null,
@@ -3230,7 +3230,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/foo",
+ "href": "foo",
"target": "_blank",
"class": null,
"title": null,
@@ -3748,7 +3748,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/bar",
+ "href": "bar",
"target": "_blank",
"class": null,
"title": null,
@@ -3906,7 +3906,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/url",
+ "href": "/url",
"target": "_blank",
"class": null,
"title": "title",
@@ -3947,7 +3947,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/url",
+ "href": "/url",
"target": "_blank",
"class": null,
"title": "the title",
@@ -3988,7 +3988,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/my_(url)",
+ "href": "my_(url)",
"target": "_blank",
"class": null,
"title": "title (with parens)",
@@ -4029,7 +4029,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/my%20url",
+ "href": "my%20url",
"target": "_blank",
"class": null,
"title": "title",
@@ -4070,7 +4070,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/url",
+ "href": "/url",
"target": "_blank",
"class": null,
"title": "\ntitle\nline1\nline2\n",
@@ -4144,7 +4144,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/url",
+ "href": "/url",
"target": "_blank",
"class": null,
"title": null,
@@ -4274,7 +4274,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/url%5Cbar*baz",
+ "href": "/url%5Cbar*baz",
"target": "_blank",
"class": null,
"title": "foo\"bar\\baz",
@@ -4301,7 +4301,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/url",
+ "href": "url",
"target": "_blank",
"class": null,
"title": null,
@@ -4342,7 +4342,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/first",
+ "href": "first",
"target": "_blank",
"class": null,
"title": null,
@@ -4411,7 +4411,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/url",
+ "href": "/url",
"target": "_blank",
"class": null,
"title": null,
@@ -4452,7 +4452,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/%CF%86%CE%BF%CF%85",
+ "href": "/%CF%86%CE%BF%CF%85",
"target": "_blank",
"class": null,
"title": null,
@@ -4655,7 +4655,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/url",
+ "href": "/url",
"target": "_blank",
"class": null,
"title": null,
@@ -4739,7 +4739,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/url",
+ "href": "/url",
"target": "_blank",
"class": null,
"title": null,
@@ -4784,7 +4784,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/url",
+ "href": "/url",
"target": "_blank",
"class": null,
"title": null,
@@ -4853,7 +4853,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/foo-url",
+ "href": "/foo-url",
"target": "_blank",
"class": null,
"title": "foo",
@@ -4873,7 +4873,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/bar-url",
+ "href": "/bar-url",
"target": "_blank",
"class": null,
"title": "bar",
@@ -4893,7 +4893,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/baz-url",
+ "href": "/baz-url",
"target": "_blank",
"class": null,
"title": null,
@@ -4920,7 +4920,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/url",
+ "href": "/url",
"target": "_blank",
"class": null,
"title": null,
@@ -10683,7 +10683,7 @@
{
"type": "link",
"attrs": {
- "href": "http://example.com/?find=%5C*",
+ "href": "http://example.com?find=%5C*",
"target": "_blank",
"class": null,
"title": null,
@@ -10719,7 +10719,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/bar*",
+ "href": "/bar*",
"target": "_blank",
"class": null,
"title": "ti*tle",
@@ -10746,7 +10746,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/bar*",
+ "href": "/bar*",
"target": "_blank",
"class": null,
"title": "ti*tle",
@@ -10905,7 +10905,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/f%C3%B6%C3%B6",
+ "href": "/f%C3%B6%C3%B6",
"target": "_blank",
"class": null,
"title": "föö",
@@ -10932,7 +10932,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/f%C3%B6%C3%B6",
+ "href": "/f%C3%B6%C3%B6",
"target": "_blank",
"class": null,
"title": "föö",
@@ -11466,7 +11466,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/%60",
+ "href": "`",
"target": "_blank",
"class": null,
"title": null,
@@ -11517,7 +11517,7 @@
{
"type": "link",
"attrs": {
- "href": "http://foo.bar.`baz/",
+ "href": "http://foo.bar.%60baz",
"target": "_blank",
"class": null,
"title": null,
@@ -12673,7 +12673,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/url",
+ "href": "/url",
"target": "_blank",
"class": null,
"title": null,
@@ -13143,7 +13143,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/url",
+ "href": "/url",
"target": "_blank",
"class": null,
"title": null,
@@ -13212,7 +13212,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/url",
+ "href": "/url",
"target": "_blank",
"class": null,
"title": null,
@@ -13571,7 +13571,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/url",
+ "href": "/url",
"target": "_blank",
"class": null,
"title": null,
@@ -14477,7 +14477,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/url",
+ "href": "/url",
"target": "_blank",
"class": null,
"title": null,
@@ -14508,7 +14508,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/url",
+ "href": "/url",
"target": "_blank",
"class": null,
"title": null,
@@ -14536,7 +14536,7 @@
{
"type": "image",
"attrs": {
- "src": "http://test.host/foo",
+ "src": "foo",
"alt": null,
"title": "*",
"uploading": false,
@@ -14764,7 +14764,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/uri",
+ "href": "/uri",
"target": "_blank",
"class": null,
"title": "title",
@@ -14791,7 +14791,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/uri",
+ "href": "/uri",
"target": "_blank",
"class": null,
"title": null,
@@ -14887,7 +14887,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/my%20uri",
+ "href": "/my%20uri",
"target": "_blank",
"class": null,
"title": null,
@@ -14944,7 +14944,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/b)c",
+ "href": "b)c",
"target": "_blank",
"class": null,
"title": null,
@@ -15010,7 +15010,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/(foo)",
+ "href": "(foo)",
"target": "_blank",
"class": null,
"title": null,
@@ -15037,7 +15037,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/foo(and(bar))",
+ "href": "foo(and(bar))",
"target": "_blank",
"class": null,
"title": null,
@@ -15064,7 +15064,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/foo(and(bar)",
+ "href": "foo(and(bar)",
"target": "_blank",
"class": null,
"title": null,
@@ -15091,7 +15091,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/foo(and(bar)",
+ "href": "foo(and(bar)",
"target": "_blank",
"class": null,
"title": null,
@@ -15118,7 +15118,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/foo):",
+ "href": "foo):",
"target": "_blank",
"class": null,
"title": null,
@@ -15145,7 +15145,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/#fragment",
+ "href": "#fragment",
"target": "_blank",
"class": null,
"title": null,
@@ -15166,7 +15166,7 @@
{
"type": "link",
"attrs": {
- "href": "http://example.com/#fragment",
+ "href": "http://example.com#fragment",
"target": "_blank",
"class": null,
"title": null,
@@ -15187,7 +15187,7 @@
{
"type": "link",
"attrs": {
- "href": "http://example.com/?foo=3#frag",
+ "href": "http://example.com?foo=3#frag",
"target": "_blank",
"class": null,
"title": null,
@@ -15214,7 +15214,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/foo%5Cbar",
+ "href": "foo%5Cbar",
"target": "_blank",
"class": null,
"title": null,
@@ -15241,7 +15241,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/foo%20b%C3%A4",
+ "href": "foo%20b%C3%A4",
"target": "_blank",
"class": null,
"title": null,
@@ -15268,7 +15268,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/%22title%22",
+ "href": "%22title%22",
"target": "_blank",
"class": null,
"title": null,
@@ -15295,7 +15295,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/url",
+ "href": "/url",
"target": "_blank",
"class": null,
"title": "title",
@@ -15322,7 +15322,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/url",
+ "href": "/url",
"target": "_blank",
"class": null,
"title": "title \"\"",
@@ -15349,7 +15349,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/url%C2%A0%22title%22",
+ "href": "/url%C2%A0%22title%22",
"target": "_blank",
"class": null,
"title": null,
@@ -15391,7 +15391,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/url",
+ "href": "/url",
"target": "_blank",
"class": null,
"title": "title \"and\" title",
@@ -15418,7 +15418,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/uri",
+ "href": "/uri",
"target": "_blank",
"class": null,
"title": "title",
@@ -15460,7 +15460,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/uri",
+ "href": "/uri",
"target": "_blank",
"class": null,
"title": null,
@@ -15506,7 +15506,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/uri",
+ "href": "/uri",
"target": "_blank",
"class": null,
"title": null,
@@ -15533,7 +15533,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/uri",
+ "href": "/uri",
"target": "_blank",
"class": null,
"title": null,
@@ -15560,7 +15560,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/uri",
+ "href": "/uri",
"target": "_blank",
"class": null,
"title": null,
@@ -15576,7 +15576,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/uri",
+ "href": "/uri",
"target": "_blank",
"class": null,
"title": null,
@@ -15595,7 +15595,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/uri",
+ "href": "/uri",
"target": "_blank",
"class": null,
"title": null,
@@ -15617,7 +15617,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/uri",
+ "href": "/uri",
"target": "_blank",
"class": null,
"title": null,
@@ -15650,7 +15650,7 @@
{
"type": "image",
"attrs": {
- "src": "http://test.host/moon.jpg",
+ "src": "moon.jpg",
"alt": "moon",
"title": null,
"uploading": false,
@@ -15660,7 +15660,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/uri",
+ "href": "/uri",
"target": "_blank",
"class": null,
"title": null,
@@ -15690,7 +15690,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/uri",
+ "href": "/uri",
"target": "_blank",
"class": null,
"title": null,
@@ -15734,7 +15734,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/uri",
+ "href": "/uri",
"target": "_blank",
"class": null,
"title": null,
@@ -15774,7 +15774,7 @@
{
"type": "image",
"attrs": {
- "src": "http://test.host/uri3",
+ "src": "uri3",
"alt": "[foo](uri2)",
"title": null,
"uploading": false,
@@ -15802,7 +15802,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/uri",
+ "href": "/uri",
"target": "_blank",
"class": null,
"title": null,
@@ -15829,7 +15829,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/baz*",
+ "href": "baz*",
"target": "_blank",
"class": null,
"title": null,
@@ -15950,7 +15950,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/url",
+ "href": "/url",
"target": "_blank",
"class": null,
"title": "title",
@@ -15991,7 +15991,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/uri",
+ "href": "/uri",
"target": "_blank",
"class": null,
"title": null,
@@ -16032,7 +16032,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/uri",
+ "href": "/uri",
"target": "_blank",
"class": null,
"title": null,
@@ -16073,7 +16073,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/uri",
+ "href": "/uri",
"target": "_blank",
"class": null,
"title": null,
@@ -16089,7 +16089,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/uri",
+ "href": "/uri",
"target": "_blank",
"class": null,
"title": null,
@@ -16108,7 +16108,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/uri",
+ "href": "/uri",
"target": "_blank",
"class": null,
"title": null,
@@ -16130,7 +16130,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/uri",
+ "href": "/uri",
"target": "_blank",
"class": null,
"title": null,
@@ -16177,7 +16177,7 @@
{
"type": "image",
"attrs": {
- "src": "http://test.host/moon.jpg",
+ "src": "moon.jpg",
"alt": "moon",
"title": null,
"uploading": false,
@@ -16187,7 +16187,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/uri",
+ "href": "/uri",
"target": "_blank",
"class": null,
"title": null,
@@ -16231,7 +16231,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/uri",
+ "href": "/uri",
"target": "_blank",
"class": null,
"title": null,
@@ -16251,7 +16251,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/uri",
+ "href": "/uri",
"target": "_blank",
"class": null,
"title": null,
@@ -16305,7 +16305,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/uri",
+ "href": "/uri",
"target": "_blank",
"class": null,
"title": null,
@@ -16328,7 +16328,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/uri",
+ "href": "/uri",
"target": "_blank",
"class": null,
"title": null,
@@ -16373,7 +16373,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/uri",
+ "href": "/uri",
"target": "_blank",
"class": null,
"title": null,
@@ -16414,7 +16414,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/uri",
+ "href": "/uri",
"target": "_blank",
"class": null,
"title": null,
@@ -16567,7 +16567,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/url",
+ "href": "/url",
"target": "_blank",
"class": null,
"title": "title",
@@ -16608,7 +16608,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/url",
+ "href": "/url",
"target": "_blank",
"class": null,
"title": null,
@@ -16667,7 +16667,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/url",
+ "href": "/url",
"target": "_blank",
"class": null,
"title": null,
@@ -16698,7 +16698,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/url",
+ "href": "/url",
"target": "_blank",
"class": null,
"title": "title",
@@ -16743,7 +16743,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/url",
+ "href": "/url",
"target": "_blank",
"class": null,
"title": "title",
@@ -16812,7 +16812,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/url1",
+ "href": "/url1",
"target": "_blank",
"class": null,
"title": null,
@@ -16940,7 +16940,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/uri",
+ "href": "/uri",
"target": "_blank",
"class": null,
"title": null,
@@ -16995,7 +16995,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/uri",
+ "href": "/uri",
"target": "_blank",
"class": null,
"title": null,
@@ -17070,7 +17070,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/url",
+ "href": "/url",
"target": "_blank",
"class": null,
"title": "title",
@@ -17111,7 +17111,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/url",
+ "href": "/url",
"target": "_blank",
"class": null,
"title": "title",
@@ -17130,7 +17130,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/url",
+ "href": "/url",
"target": "_blank",
"class": null,
"title": "title",
@@ -17171,7 +17171,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/url",
+ "href": "/url",
"target": "_blank",
"class": null,
"title": "title",
@@ -17212,7 +17212,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/url",
+ "href": "/url",
"target": "_blank",
"class": null,
"title": "title",
@@ -17257,7 +17257,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/url",
+ "href": "/url",
"target": "_blank",
"class": null,
"title": "title",
@@ -17298,7 +17298,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/url",
+ "href": "/url",
"target": "_blank",
"class": null,
"title": "title",
@@ -17317,7 +17317,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/url",
+ "href": "/url",
"target": "_blank",
"class": null,
"title": "title",
@@ -17362,7 +17362,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/url",
+ "href": "/url",
"target": "_blank",
"class": null,
"title": "title",
@@ -17381,7 +17381,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/url",
+ "href": "/url",
"target": "_blank",
"class": null,
"title": "title",
@@ -17430,7 +17430,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/url",
+ "href": "/url",
"target": "_blank",
"class": null,
"title": null,
@@ -17471,7 +17471,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/url",
+ "href": "/url",
"target": "_blank",
"class": null,
"title": "title",
@@ -17512,7 +17512,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/url",
+ "href": "/url",
"target": "_blank",
"class": null,
"title": null,
@@ -17604,7 +17604,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/url",
+ "href": "/url",
"target": "_blank",
"class": null,
"title": null,
@@ -17631,7 +17631,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/url2",
+ "href": "/url2",
"target": "_blank",
"class": null,
"title": null,
@@ -17686,7 +17686,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/url1",
+ "href": "/url1",
"target": "_blank",
"class": null,
"title": null,
@@ -17768,7 +17768,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/url1",
+ "href": "/url1",
"target": "_blank",
"class": null,
"title": null,
@@ -17817,7 +17817,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/url",
+ "href": "/url",
"target": "_blank",
"class": null,
"title": null,
@@ -17858,7 +17858,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/url2",
+ "href": "/url2",
"target": "_blank",
"class": null,
"title": null,
@@ -17874,7 +17874,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/url1",
+ "href": "/url1",
"target": "_blank",
"class": null,
"title": null,
@@ -17933,7 +17933,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/url1",
+ "href": "/url1",
"target": "_blank",
"class": null,
"title": null,
@@ -17985,7 +17985,7 @@
{
"type": "image",
"attrs": {
- "src": "http://test.host/url",
+ "src": "/url",
"alt": "foo",
"title": "title",
"uploading": false,
@@ -18006,7 +18006,7 @@
{
"type": "image",
"attrs": {
- "src": "http://test.host/train.jpg",
+ "src": "train.jpg",
"alt": "foo bar",
"title": "train & tracks",
"uploading": false,
@@ -18041,7 +18041,7 @@
{
"type": "image",
"attrs": {
- "src": "http://test.host/url2",
+ "src": "/url2",
"alt": "foo bar",
"title": null,
"uploading": false,
@@ -18062,7 +18062,7 @@
{
"type": "image",
"attrs": {
- "src": "http://test.host/url2",
+ "src": "/url2",
"alt": "foo bar",
"title": null,
"uploading": false,
@@ -18083,7 +18083,7 @@
{
"type": "image",
"attrs": {
- "src": "http://test.host/train.jpg",
+ "src": "train.jpg",
"alt": "foo bar",
"title": "train & tracks",
"uploading": false,
@@ -18118,7 +18118,7 @@
{
"type": "image",
"attrs": {
- "src": "http://test.host/train.jpg",
+ "src": "train.jpg",
"alt": "foo bar",
"title": "train & tracks",
"uploading": false,
@@ -18153,7 +18153,7 @@
{
"type": "image",
"attrs": {
- "src": "http://test.host/train.jpg",
+ "src": "train.jpg",
"alt": "foo",
"title": null,
"uploading": false,
@@ -18178,7 +18178,7 @@
{
"type": "image",
"attrs": {
- "src": "http://test.host/path/to/train.jpg",
+ "src": "/path/to/train.jpg",
"alt": "foo bar",
"title": "title",
"uploading": false,
@@ -18199,7 +18199,7 @@
{
"type": "image",
"attrs": {
- "src": "http://test.host/url",
+ "src": "url",
"alt": "foo",
"title": null,
"uploading": false,
@@ -18220,7 +18220,7 @@
{
"type": "image",
"attrs": {
- "src": "http://test.host/url",
+ "src": "/url",
"alt": "",
"title": null,
"uploading": false,
@@ -18241,7 +18241,7 @@
{
"type": "image",
"attrs": {
- "src": "http://test.host/url",
+ "src": "/url",
"alt": "foo",
"title": null,
"uploading": false,
@@ -18276,7 +18276,7 @@
{
"type": "image",
"attrs": {
- "src": "http://test.host/url",
+ "src": "/url",
"alt": "foo",
"title": null,
"uploading": false,
@@ -18311,7 +18311,7 @@
{
"type": "image",
"attrs": {
- "src": "http://test.host/url",
+ "src": "/url",
"alt": "foo",
"title": "title",
"uploading": false,
@@ -18346,7 +18346,7 @@
{
"type": "image",
"attrs": {
- "src": "http://test.host/url",
+ "src": "/url",
"alt": "foo bar",
"title": "title",
"uploading": false,
@@ -18381,7 +18381,7 @@
{
"type": "image",
"attrs": {
- "src": "http://test.host/url",
+ "src": "/url",
"alt": "Foo",
"title": "title",
"uploading": false,
@@ -18416,7 +18416,7 @@
{
"type": "image",
"attrs": {
- "src": "http://test.host/url",
+ "src": "/url",
"alt": "foo",
"title": "title",
"uploading": false,
@@ -18455,7 +18455,7 @@
{
"type": "image",
"attrs": {
- "src": "http://test.host/url",
+ "src": "/url",
"alt": "foo",
"title": "title",
"uploading": false,
@@ -18490,7 +18490,7 @@
{
"type": "image",
"attrs": {
- "src": "http://test.host/url",
+ "src": "/url",
"alt": "foo bar",
"title": "title",
"uploading": false,
@@ -18549,7 +18549,7 @@
{
"type": "image",
"attrs": {
- "src": "http://test.host/url",
+ "src": "/url",
"alt": "Foo",
"title": "title",
"uploading": false,
@@ -18620,7 +18620,7 @@
{
"type": "link",
"attrs": {
- "href": "http://test.host/url",
+ "href": "/url",
"target": "_blank",
"class": null,
"title": "title",
@@ -18661,7 +18661,7 @@
{
"type": "link",
"attrs": {
- "href": "http://foo.bar.baz/",
+ "href": "http://foo.bar.baz",
"target": "_blank",
"class": null,
"title": null,
@@ -18715,11 +18715,11 @@
{
"type": "link",
"attrs": {
- "href": "irc://foo.bar:2233/baz",
+ "href": null,
"target": "_blank",
"class": null,
"title": null,
- "canonicalSrc": "irc://foo.bar:2233/baz"
+ "canonicalSrc": null
}
}
],
@@ -18742,7 +18742,7 @@
{
"type": "link",
"attrs": {
- "href": "mailto:FOO@BAR.BAZ",
+ "href": "MAILTO:FOO@BAR.BAZ",
"target": "_blank",
"class": null,
"title": null,
@@ -18769,11 +18769,11 @@
{
"type": "link",
"attrs": {
- "href": "a+b+c:d",
+ "href": null,
"target": "_blank",
"class": null,
"title": null,
- "canonicalSrc": "a+b+c:d"
+ "canonicalSrc": null
}
}
],
@@ -18796,11 +18796,11 @@
{
"type": "link",
"attrs": {
- "href": "made-up-scheme://foo,bar",
+ "href": null,
"target": "_blank",
"class": null,
"title": null,
- "canonicalSrc": "made-up-scheme://foo,bar"
+ "canonicalSrc": null
}
}
],
@@ -18850,11 +18850,11 @@
{
"type": "link",
"attrs": {
- "href": "localhost:5001/foo",
+ "href": null,
"target": "_blank",
"class": null,
"title": null,
- "canonicalSrc": "localhost:5001/foo"
+ "canonicalSrc": null
}
}
],
@@ -19047,7 +19047,7 @@
{
"type": "link",
"attrs": {
- "href": "http://foo.bar/",
+ "href": "http://foo.bar",
"target": "_blank",
"class": null,
"title": null,
@@ -19108,7 +19108,7 @@
{
"type": "link",
"attrs": {
- "href": "http://example.com/",
+ "href": "http://example.com",
"target": "_blank",
"class": null,
"title": null,
@@ -19162,7 +19162,7 @@
{
"type": "link",
"attrs": {
- "href": "http://www.commonmark.org/",
+ "href": "http://www.commonmark.org",
"target": "_blank",
"class": null,
"title": null,
@@ -19228,7 +19228,7 @@
{
"type": "link",
"attrs": {
- "href": "http://www.commonmark.org/",
+ "href": "http://www.commonmark.org",
"target": "_blank",
"class": null,
"title": null,
@@ -19504,7 +19504,7 @@
{
"type": "link",
"attrs": {
- "href": "http://commonmark.org/",
+ "href": "http://commonmark.org",
"target": "_blank",
"class": null,
"title": null,
diff --git a/lib/api/helpers/integrations_helpers.rb b/lib/api/helpers/integrations_helpers.rb
index 0b0100c7d7f..6c6cba43155 100644
--- a/lib/api/helpers/integrations_helpers.rb
+++ b/lib/api/helpers/integrations_helpers.rb
@@ -678,6 +678,15 @@ module API
desc: 'Contents of the credentials.json file of your service account, like: { "type": "service_account", "project_id": ... }'
}
],
+ 'pumble' => [
+ {
+ required: true,
+ name: :webhook,
+ type: String,
+ desc: 'The Pumble chat webhook. For example, https://api.pumble.com/workspaces/x/...'
+ },
+ chat_notification_events
+ ].flatten,
'pushover' => [
{
required: true,
diff --git a/lib/api/issue_links.rb b/lib/api/issue_links.rb
index c07c2c1994e..563fb3358ed 100644
--- a/lib/api/issue_links.rb
+++ b/lib/api/issue_links.rb
@@ -37,7 +37,7 @@ module API
requires :target_project_id, type: String, desc: 'The ID of the target project'
requires :target_issue_iid, type: Integer, desc: 'The IID of the target issue'
optional :link_type, type: String, values: IssueLink.link_types.keys,
- desc: 'The type of the relation'
+ desc: 'The type of the relation'
end
# rubocop: disable CodeReuse/ActiveRecord
post ':id/issues/:issue_iid/links' do
diff --git a/lib/api/issues.rb b/lib/api/issues.rb
index 971163c18db..b6ad34424a6 100644
--- a/lib/api/issues.rb
+++ b/lib/api/issues.rb
@@ -16,7 +16,7 @@ module API
optional :labels, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, desc: 'Comma-separated list of label names'
optional :milestone, type: String, desc: 'Milestone title'
optional :milestone_id, types: String, values: %w[Any None Upcoming Started],
- desc: 'Return issues assigned to milestones without the specified timebox value ("Any", "None", "Upcoming" or "Started")'
+ desc: 'Return issues assigned to milestones without the specified timebox value ("Any", "None", "Upcoming" or "Started")'
mutually_exclusive :milestone_id, :milestone
optional :iids, type: Array[Integer], coerce_with: ::API::Validations::Types::CommaSeparatedToIntegerArray.coerce, desc: 'The IID array of issues'
@@ -27,8 +27,8 @@ module API
optional :assignee_id, type: Integer, desc: 'Return issues which are not assigned to the user with the given ID'
optional :assignee_username, type: Array[String], check_assignees_count: true,
- coerce_with: Validations::Validators::CheckAssigneesCount.coerce,
- desc: 'Return issues which are not assigned to the user with the given username'
+ coerce_with: Validations::Validators::CheckAssigneesCount.coerce,
+ desc: 'Return issues which are not assigned to the user with the given username'
mutually_exclusive :assignee_id, :assignee_username
use :negatable_issue_filter_params_ee
@@ -40,7 +40,7 @@ module API
# 'milestone_id' only accepts wildcard values 'Any', 'None', 'Upcoming', 'Started'
# the param has '_id' in the name to keep consistency (ex. assignee_id accepts id and wildcard values).
optional :milestone_id, types: String, values: %w[Any None Upcoming Started],
- desc: 'Return issues assigned to milestones with the specified timebox value ("Any", "None", "Upcoming" or "Started")'
+ desc: 'Return issues assigned to milestones with the specified timebox value ("Any", "None", "Upcoming" or "Started")'
optional :iids, type: Array[Integer], coerce_with: ::API::Validations::Types::CommaSeparatedToIntegerArray.coerce, desc: 'The IID array of issues'
optional :search, type: String, desc: 'Search issues for text present in the title, description, or any combination of these'
optional :in, type: String, desc: '`title`, `description`, or a string joining them with comma'
@@ -51,10 +51,10 @@ module API
mutually_exclusive :author_id, :author_username
optional :assignee_id, types: [Integer, String], integer_none_any: true,
- desc: 'Return issues which are assigned to the user with the given ID'
+ desc: 'Return issues which are assigned to the user with the given ID'
optional :assignee_username, type: Array[String], check_assignees_count: true,
- coerce_with: Validations::Validators::CheckAssigneesCount.coerce,
- desc: 'Return issues which are assigned to the user with the given username'
+ coerce_with: Validations::Validators::CheckAssigneesCount.coerce,
+ desc: 'Return issues which are assigned to the user with the given username'
mutually_exclusive :assignee_id, :assignee_username
optional :created_after, type: DateTime, desc: 'Return issues created after the specified time'
@@ -77,13 +77,13 @@ module API
params :issues_params do
optional :with_labels_details, type: Boolean, desc: 'Return titles of labels and other details', default: false
optional :state, type: String, values: %w[opened closed all], default: 'all',
- desc: 'Return opened, closed, or all issues'
+ desc: 'Return opened, closed, or all issues'
optional :order_by, type: String, values: Helpers::IssuesHelpers.sort_options, default: 'created_at',
- desc: 'Return issues ordered by `created_at`, `due_date`, `label_priority`, `milestone_due`, `popularity`, `priority`, `relative_position`, `title`, or `updated_at` fields.'
+ desc: 'Return issues ordered by `created_at`, `due_date`, `label_priority`, `milestone_due`, `popularity`, `priority`, `relative_position`, `title`, or `updated_at` fields.'
optional :sort, type: String, values: %w[asc desc], default: 'desc',
- desc: 'Return issues sorted in `asc` or `desc` order.'
+ desc: 'Return issues sorted in `asc` or `desc` order.'
optional :due_date, type: String, values: %w[0 any today tomorrow overdue week month next_month_and_previous_two_weeks] << '',
- desc: 'Return issues that have no due date (`0`), or whose due date is this week, this month, between two weeks ago and next month, or which are overdue. Accepts: `overdue`, `week`, `month`, `next_month_and_previous_two_weeks`, `0`'
+ desc: 'Return issues that have no due date (`0`), or whose due date is this week, this month, between two weeks ago and next month, or which are overdue. Accepts: `overdue`, `week`, `month`, `next_month_and_previous_two_weeks`, `0`'
optional :issue_type, type: String, values: WorkItems::Type.allowed_types_for_issues, desc: "The type of the issue. Accepts: #{WorkItems::Type.allowed_types_for_issues.join(', ')}"
use :issues_stats_params
diff --git a/lib/api/labels.rb b/lib/api/labels.rb
index e2d4f5d823a..0a107a96d61 100644
--- a/lib/api/labels.rb
+++ b/lib/api/labels.rb
@@ -23,11 +23,11 @@ module API
end
params do
optional :with_counts, type: Boolean, default: false,
- desc: 'Include issue and merge request counts'
+ desc: 'Include issue and merge request counts'
optional :include_ancestor_groups, type: Boolean, default: true,
- desc: 'Include ancestor groups'
+ desc: 'Include ancestor groups'
optional :search, type: String,
- desc: 'Keyword to filter labels by. This feature was added in GitLab 13.6'
+ desc: 'Keyword to filter labels by. This feature was added in GitLab 13.6'
use :pagination
end
get ':id/labels' do
@@ -40,7 +40,7 @@ module API
end
params do
optional :include_ancestor_groups, type: Boolean, default: true,
- desc: 'Include ancestor groups'
+ desc: 'Include ancestor groups'
end
get ':id/labels/:name' do
get_label(user_project, Entities::ProjectLabel, declared_params)
diff --git a/lib/api/maven_packages.rb b/lib/api/maven_packages.rb
index c2ed23102a5..fb0221ee907 100644
--- a/lib/api/maven_packages.rb
+++ b/lib/api/maven_packages.rb
@@ -283,12 +283,12 @@ module API
''
else
file_params = {
- file: params[:file],
- size: params['file.size'],
+ file: params[:file],
+ size: params['file.size'],
file_name: file_name,
file_type: params['file.type'],
file_sha1: params['file.sha1'],
- file_md5: params['file.md5']
+ file_md5: params['file.md5']
}
::Packages::CreatePackageFileService.new(package, file_params.merge(build: current_authenticated_job)).execute
diff --git a/lib/api/members.rb b/lib/api/members.rb
index 0e93ab5435a..d26fdd09ee7 100644
--- a/lib/api/members.rb
+++ b/lib/api/members.rb
@@ -156,9 +156,9 @@ module API
params do
requires :user_id, type: Integer, desc: 'The user ID of the member'
optional :skip_subresources, type: Boolean, default: false,
- desc: 'Flag indicating if the deletion of direct memberships of the removed member in subgroups and projects should be skipped'
+ desc: 'Flag indicating if the deletion of direct memberships of the removed member in subgroups and projects should be skipped'
optional :unassign_issuables, type: Boolean, default: false,
- desc: 'Flag indicating if the removed member should be unassigned from any issues or merge requests within given group or project'
+ desc: 'Flag indicating if the removed member should be unassigned from any issues or merge requests within given group or project'
end
# rubocop: disable CodeReuse/ActiveRecord
delete ":id/members/:user_id", feature_category: feature_category do
diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb
index 6bd13c48ab1..a8f58e91067 100644
--- a/lib/api/merge_requests.rb
+++ b/lib/api/merge_requests.rb
@@ -159,7 +159,7 @@ module API
params do
use :merge_requests_params
optional :non_archived, type: Boolean, desc: 'Return merge requests from non archived projects',
- default: true
+ default: true
end
get ":id/merge_requests", feature_category: :code_review, urgency: :low do
validate_anonymous_search_access! if declared_params[:search].present?
diff --git a/lib/api/metrics/dashboard/annotations.rb b/lib/api/metrics/dashboard/annotations.rb
index 6fc90da87d4..478adcdce70 100644
--- a/lib/api/metrics/dashboard/annotations.rb
+++ b/lib/api/metrics/dashboard/annotations.rb
@@ -20,11 +20,11 @@ module API
resource annotations_source[:resource] do
params do
requires :starting_at, type: DateTime,
- desc: 'Date time indicating starting moment to which the annotation relates.'
+ desc: 'Date time indicating starting moment to which the annotation relates.'
optional :ending_at, type: DateTime,
- desc: 'Date time indicating ending moment to which the annotation relates.'
+ desc: 'Date time indicating ending moment to which the annotation relates.'
requires :dashboard_path, type: String, coerce_with: -> (val) { CGI.unescape(val) },
- desc: 'The path to a file defining the dashboard on which the annotation should be added'
+ desc: 'The path to a file defining the dashboard on which the annotation should be added'
requires :description, type: String, desc: 'The description of the annotation'
end
diff --git a/lib/api/metrics/user_starred_dashboards.rb b/lib/api/metrics/user_starred_dashboards.rb
index 83d95f8b062..4d5396acccb 100644
--- a/lib/api/metrics/user_starred_dashboards.rb
+++ b/lib/api/metrics/user_starred_dashboards.rb
@@ -13,7 +13,7 @@ module API
params do
requires :dashboard_path, type: String, allow_blank: false, coerce_with: ->(val) { CGI.unescape(val) },
- desc: 'Url encoded path to a file defining the dashboard to which the star should be added'
+ desc: 'Url encoded path to a file defining the dashboard to which the star should be added'
end
post ':id/metrics/user_starred_dashboards' do
@@ -30,7 +30,7 @@ module API
params do
optional :dashboard_path, type: String, allow_blank: false, coerce_with: ->(val) { CGI.unescape(val) },
- desc: 'Url encoded path to a file defining the dashboard from which the star should be removed'
+ desc: 'Url encoded path to a file defining the dashboard from which the star should be removed'
end
delete ':id/metrics/user_starred_dashboards' do
diff --git a/lib/api/milestone_responses.rb b/lib/api/milestone_responses.rb
index d75ed3a48d7..2fd3239b44a 100644
--- a/lib/api/milestone_responses.rb
+++ b/lib/api/milestone_responses.rb
@@ -14,12 +14,12 @@ module API
params :list_params do
optional :state, type: String, values: %w[active closed all], default: 'all',
- desc: 'Return "active", "closed", or "all" milestones'
+ desc: 'Return "active", "closed", or "all" milestones'
optional :iids, type: Array[Integer], coerce_with: ::API::Validations::Types::CommaSeparatedToIntegerArray.coerce, desc: 'The IIDs of the milestones'
optional :title, type: String, desc: 'The title of the milestones'
optional :search, type: String, desc: 'The search criteria for the title or description of the milestone'
optional :include_parent_milestones, type: Grape::API::Boolean, default: false,
- desc: 'Include group milestones from parent and its ancestors'
+ desc: 'Include group milestones from parent and its ancestors'
use :pagination
end
@@ -27,7 +27,7 @@ module API
requires :milestone_id, type: Integer, desc: 'The milestone ID number'
optional :title, type: String, desc: 'The title of the milestone'
optional :state_event, type: String, values: %w[close activate],
- desc: 'The state event of the milestone '
+ desc: 'The state event of the milestone '
use :optional_params
at_least_one_of :title, :description, :start_date, :due_date, :state_event
end
diff --git a/lib/api/notes.rb b/lib/api/notes.rb
index 2a854bd785e..59f57179871 100644
--- a/lib/api/notes.rb
+++ b/lib/api/notes.rb
@@ -30,7 +30,7 @@ module API
optional :sort, type: String, values: %w[asc desc], default: 'desc',
desc: 'Return notes sorted in `asc` or `desc` order.'
optional :activity_filter, type: String, values: UserPreference::NOTES_FILTERS.stringify_keys.keys, default: 'all_notes',
- desc: 'The type of notables which are returned.'
+ desc: 'The type of notables which are returned.'
use :pagination
end
# rubocop: disable CodeReuse/ActiveRecord
diff --git a/lib/api/pages_domains.rb b/lib/api/pages_domains.rb
index 2e7f8475509..34d3a5150da 100644
--- a/lib/api/pages_domains.rb
+++ b/lib/api/pages_domains.rb
@@ -97,7 +97,7 @@ module API
optional :certificate, types: [File, String], desc: 'The certificate', as: :user_provided_certificate
optional :key, types: [File, String], desc: 'The key', as: :user_provided_key
optional :auto_ssl_enabled, allow_blank: false, type: Boolean, default: false,
- desc: "Enables automatic generation of SSL certificates issued by Let's Encrypt for custom domains."
+ desc: "Enables automatic generation of SSL certificates issued by Let's Encrypt for custom domains."
# rubocop:enable Scalability/FileUploads
all_or_none_of :user_provided_certificate, :user_provided_key
end
@@ -123,7 +123,7 @@ module API
optional :certificate, types: [File, String], desc: 'The certificate', as: :user_provided_certificate
optional :key, types: [File, String], desc: 'The key', as: :user_provided_key
optional :auto_ssl_enabled, allow_blank: true, type: Boolean,
- desc: "Enables automatic generation of SSL certificates issued by Let's Encrypt for custom domains."
+ desc: "Enables automatic generation of SSL certificates issued by Let's Encrypt for custom domains."
# rubocop:enable Scalability/FileUploads
end
put ":id/pages/domains/:domain", requirements: PAGES_DOMAINS_ENDPOINT_REQUIREMENTS do
diff --git a/lib/api/project_packages.rb b/lib/api/project_packages.rb
index 79a5ca531e1..21b2b17d234 100644
--- a/lib/api/project_packages.rb
+++ b/lib/api/project_packages.rb
@@ -32,9 +32,9 @@ module API
optional :package_name, type: String,
desc: 'Return packages with this name'
optional :include_versionless, type: Boolean,
- desc: 'Returns packages without a version'
+ desc: 'Returns packages without a version'
optional :status, type: String, values: Packages::Package.statuses.keys,
- desc: 'Return packages with specified status'
+ desc: 'Return packages with specified status'
end
get ':id/packages' do
packages = ::Packages::PackagesFinder.new(
diff --git a/lib/api/project_templates.rb b/lib/api/project_templates.rb
index fe0e837c596..f6e1286d616 100644
--- a/lib/api/project_templates.rb
+++ b/lib/api/project_templates.rb
@@ -37,7 +37,7 @@ module API
params do
requires :name, type: String, desc: 'The name of the template'
optional :source_template_project_id, type: Integer,
- desc: 'The project id where a given template is being stored. This is useful when multiple templates from different projects have the same name'
+ desc: 'The project id where a given template is being stored. This is useful when multiple templates from different projects have the same name'
optional :project, type: String, desc: 'The project name to use when expanding placeholders in the template. Only affects licenses'
optional :fullname, type: String, desc: 'The full name of the copyright holder to use when expanding placeholders in the template. Only affects licenses'
end
diff --git a/lib/api/projects.rb b/lib/api/projects.rb
index 6530887c1c3..6ed480518ee 100644
--- a/lib/api/projects.rb
+++ b/lib/api/projects.rb
@@ -688,11 +688,11 @@ module API
optional :search, type: String, desc: 'Return list of groups matching the search criteria'
optional :skip_groups, type: Array[Integer], coerce_with: ::API::Validations::Types::CommaSeparatedToIntegerArray.coerce, desc: 'Array of group ids to exclude from list'
optional :with_shared, type: Boolean, default: false,
- desc: 'Include shared groups'
+ desc: 'Include shared groups'
optional :shared_visible_only, type: Boolean, default: false,
- desc: 'Limit to shared groups user has access to'
+ desc: 'Limit to shared groups user has access to'
optional :shared_min_access_level, type: Integer, values: Gitlab::Access.all_values,
- desc: 'Limit returned shared groups by minimum access level to the project'
+ desc: 'Limit returned shared groups by minimum access level to the project'
use :pagination
end
get ':id/groups', feature_category: :source_code_management do
diff --git a/lib/api/protected_branches.rb b/lib/api/protected_branches.rb
index a4f5dfefae6..38bafac25b2 100644
--- a/lib/api/protected_branches.rb
+++ b/lib/api/protected_branches.rb
@@ -61,8 +61,8 @@ module API
values: ProtectedBranch::MergeAccessLevel.allowed_access_levels,
desc: 'Access levels allowed to merge (defaults: `40`, maintainer access level)'
optional :allow_force_push, type: Boolean,
- default: false,
- desc: 'Allow force push for all users with push access.'
+ default: false,
+ desc: 'Allow force push for all users with push access.'
use :optional_params_ee
end
diff --git a/lib/api/releases.rb b/lib/api/releases.rb
index aecd6f9eef8..d7e497bddf3 100644
--- a/lib/api/releases.rb
+++ b/lib/api/releases.rb
@@ -23,9 +23,9 @@ module API
params do
requires :id, type: Integer, desc: 'The ID of the group to get releases for'
optional :sort, type: String, values: %w[asc desc], default: 'desc',
- desc: 'Return projects sorted in ascending and descending order by released_at'
+ desc: 'Return projects sorted in ascending and descending order by released_at'
optional :simple, type: Boolean, default: false,
- desc: 'Return only the ID, URL, name, and path of each project'
+ desc: 'Return only the ID, URL, name, and path of each project'
use :pagination
end
@@ -61,7 +61,7 @@ module API
optional :sort, type: String, values: %w[asc desc], default: 'desc',
desc: 'Return releases sorted in `asc` or `desc` order.'
optional :include_html_description, type: Boolean,
- desc: 'If `true`, a response includes HTML rendered markdown of the release description.'
+ desc: 'If `true`, a response includes HTML rendered markdown of the release description.'
end
route_setting :authentication, job_token_allowed: true
get ':id/releases' do
@@ -89,7 +89,7 @@ module API
params do
requires :tag_name, type: String, desc: 'The name of the tag', as: :tag
optional :include_html_description, type: Boolean,
- desc: 'If `true`, a response includes HTML rendered markdown of the release description.'
+ desc: 'If `true`, a response includes HTML rendered markdown of the release description.'
end
route_setting :authentication, job_token_allowed: true
get ':id/releases/:tag_name', requirements: RELEASE_ENDPOINT_REQUIREMENTS do
diff --git a/lib/api/rubygem_packages.rb b/lib/api/rubygem_packages.rb
index e6c54faebd9..85bbd0879b7 100644
--- a/lib/api/rubygem_packages.rb
+++ b/lib/api/rubygem_packages.rb
@@ -109,7 +109,7 @@ module API
).execute(:rubygems, name: ::Packages::Rubygems::TEMPORARY_PACKAGE_NAME)
file_params = {
- file: params[:file],
+ file: params[:file],
file_name: PACKAGE_FILENAME
}
diff --git a/lib/api/sidekiq_metrics.rb b/lib/api/sidekiq_metrics.rb
index bca1376d489..e279e63181d 100644
--- a/lib/api/sidekiq_metrics.rb
+++ b/lib/api/sidekiq_metrics.rb
@@ -22,14 +22,14 @@ module API
def process_metrics
Sidekiq::ProcessSet.new(false).map do |process|
{
- hostname: process['hostname'],
- pid: process['pid'],
- tag: process['tag'],
- started_at: Time.at(process['started_at']),
- queues: process['queues'],
- labels: process['labels'],
+ hostname: process['hostname'],
+ pid: process['pid'],
+ tag: process['tag'],
+ started_at: Time.at(process['started_at']),
+ queues: process['queues'],
+ labels: process['labels'],
concurrency: process['concurrency'],
- busy: process['busy']
+ busy: process['busy']
}
end
end
diff --git a/lib/api/users.rb b/lib/api/users.rb
index d66d86a9055..c93c0f601a0 100644
--- a/lib/api/users.rb
+++ b/lib/api/users.rb
@@ -68,9 +68,9 @@ module API
params :sort_params do
optional :order_by, type: String, values: %w[id name username created_at updated_at],
- default: 'id', desc: 'Return users ordered by a field'
+ default: 'id', desc: 'Return users ordered by a field'
optional :sort, type: String, values: %w[asc desc], default: 'desc',
- desc: 'Return users sorted in ascending and descending order'
+ desc: 'Return users sorted in ascending and descending order'
end
end
@@ -940,7 +940,7 @@ module API
params do
requires :name, type: String, desc: 'The name of the personal access token'
requires :scopes, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, values: ::Gitlab::Auth.all_available_scopes.map(&:to_s),
- desc: 'The array of scopes of the personal access token'
+ desc: 'The array of scopes of the personal access token'
optional :expires_at, type: Date, desc: 'The expiration date in the format YEAR-MONTH-DAY of the personal access token'
end
post feature_category: :authentication_and_authorization do
diff --git a/lib/backup/gitaly_backup.rb b/lib/backup/gitaly_backup.rb
index b777b581ae1..57dd74c7950 100644
--- a/lib/backup/gitaly_backup.rb
+++ b/lib/backup/gitaly_backup.rb
@@ -94,7 +94,7 @@ module Backup
def build_env
{
'SSL_CERT_FILE' => Gitlab::X509::Certificate.default_cert_file,
- 'SSL_CERT_DIR' => Gitlab::X509::Certificate.default_cert_dir
+ 'SSL_CERT_DIR' => Gitlab::X509::Certificate.default_cert_dir
}.merge(ENV)
end
diff --git a/lib/banzai/filter/references/abstract_reference_filter.rb b/lib/banzai/filter/references/abstract_reference_filter.rb
index 521fd7bf4cc..1ca38d2612d 100644
--- a/lib/banzai/filter/references/abstract_reference_filter.rb
+++ b/lib/banzai/filter/references/abstract_reference_filter.rb
@@ -240,11 +240,11 @@ module Banzai
object_parent_type = parent.is_a?(Group) ? :group : :project
{
- original: escape_html_entities(text),
- link: link_content,
- link_reference: link_reference,
+ original: escape_html_entities(text),
+ link: link_content,
+ link_reference: link_reference,
object_parent_type => parent.id,
- object_sym => object.id
+ object_sym => object.id
}
end
diff --git a/lib/banzai/reference_redactor.rb b/lib/banzai/reference_redactor.rb
index c19f992078a..0c031ace977 100644
--- a/lib/banzai/reference_redactor.rb
+++ b/lib/banzai/reference_redactor.rb
@@ -41,8 +41,8 @@ module Banzai
nodes_for_document = entry[:nodes]
doc_data = {
- document: entry[:document],
- total_reference_count: nodes_for_document.count,
+ document: entry[:document],
+ total_reference_count: nodes_for_document.count,
visible_reference_count: nodes_for_document.count
}
diff --git a/lib/gitlab/ci/parsers/security/validators/schema_validator.rb b/lib/gitlab/ci/parsers/security/validators/schema_validator.rb
index 3a6b9ccdc33..c075ada725a 100644
--- a/lib/gitlab/ci/parsers/security/validators/schema_validator.rb
+++ b/lib/gitlab/ci/parsers/security/validators/schema_validator.rb
@@ -38,13 +38,14 @@ module Gitlab
def initialize(report_type, report_version)
@report_type = report_type.to_sym
@report_version = report_version.to_s
+ @supported_versions = SUPPORTED_VERSIONS[@report_type]
end
delegate :validate, to: :schemer
private
- attr_reader :report_type, :report_version
+ attr_reader :report_type, :report_version, :supported_versions
def schemer
JSONSchemer.schema(pathname)
@@ -60,10 +61,24 @@ module Gitlab
report_declared_version = File.join(root_path, report_version, file_name)
return report_declared_version if File.file?(report_declared_version)
+ if latest_vendored_patch_version
+ latest_vendored_patch_version_file = File.join(root_path, latest_vendored_patch_version, file_name)
+ return latest_vendored_patch_version_file if File.file?(latest_vendored_patch_version)
+ end
+
earliest_supported_version = SUPPORTED_VERSIONS[report_type].min
File.join(root_path, earliest_supported_version, file_name)
end
+ def latest_vendored_patch_version
+ ::Security::ReportSchemaVersionMatcher.new(
+ report_declared_version: report_version,
+ supported_versions: supported_versions
+ ).call
+ rescue ArgumentError
+ nil
+ end
+
def file_name
report_type == :api_fuzzing ? "dast-report-format.json" : "#{report_type.to_s.dasherize}-report-format.json"
end
@@ -79,16 +94,80 @@ module Gitlab
@warnings = []
@deprecation_warnings = []
- populate_errors
- populate_warnings
+ populate_schema_version_errors
+ populate_validation_errors
populate_deprecation_warnings
end
- def valid?
- errors.empty?
+ def populate_schema_version_errors
+ add_schema_version_errors if add_schema_version_error?
end
- def populate_errors
+ def add_schema_version_errors
+ if report_version.nil?
+ template = _("Report version not provided,"\
+ " %{report_type} report type supports versions: %{supported_schema_versions}."\
+ " GitLab will attempt to validate this report against the earliest supported versions of this report"\
+ " type, to show all the errors but will not ingest the report")
+ message = format(template, report_type: report_type, supported_schema_versions: supported_schema_versions)
+ else
+ template = _("Version %{report_version} for report type %{report_type} is unsupported, supported versions"\
+ " for this report type are: %{supported_schema_versions}."\
+ " GitLab will attempt to validate this report against the earliest supported versions of this report"\
+ " type, to show all the errors but will not ingest the report")
+ message = format(template, report_version: report_version, report_type: report_type, supported_schema_versions: supported_schema_versions)
+ end
+
+ log_warnings(problem_type: 'using_unsupported_schema_version')
+ add_message_as(level: :error, message: message)
+ end
+
+ def add_schema_version_error?
+ !report_uses_supported_schema_version? &&
+ !report_uses_deprecated_schema_version? &&
+ !report_uses_supported_major_and_minor_schema_version?
+ end
+
+ def report_uses_deprecated_schema_version?
+ DEPRECATED_VERSIONS[report_type].include?(report_version)
+ end
+
+ def report_uses_supported_schema_version?
+ SUPPORTED_VERSIONS[report_type].include?(report_version)
+ end
+
+ def report_uses_supported_major_and_minor_schema_version?
+ if !find_latest_patch_version.nil?
+ add_supported_major_minor_behavior_warning
+ true
+ else
+ false
+ end
+ end
+
+ def find_latest_patch_version
+ ::Security::ReportSchemaVersionMatcher.new(
+ report_declared_version: report_version,
+ supported_versions: SUPPORTED_VERSIONS[report_type]
+ ).call
+ rescue ArgumentError
+ nil
+ end
+
+ def add_supported_major_minor_behavior_warning
+ template = _("This report uses a supported MAJOR.MINOR schema version but the PATCH version doesn't match"\
+ " any vendored schema version. Validation will be attempted against version"\
+ " %{find_latest_patch_version}")
+
+ message = format(template, find_latest_patch_version: find_latest_patch_version)
+
+ add_message_as(
+ level: :warning,
+ message: message
+ )
+ end
+
+ def populate_validation_errors
schema_validation_errors = schema.validate(report_data).map { |error| JSONSchemer::Errors.pretty(error) }
log_warnings(problem_type: 'schema_validation_fails') unless schema_validation_errors.empty?
@@ -96,10 +175,6 @@ module Gitlab
@errors += schema_validation_errors
end
- def populate_warnings
- add_unsupported_report_version_message if !report_uses_supported_schema_version? && !report_uses_deprecated_schema_version?
- end
-
def populate_deprecation_warnings
add_deprecated_report_version_message if report_uses_deprecated_schema_version?
end
@@ -107,10 +182,19 @@ module Gitlab
def add_deprecated_report_version_message
log_warnings(problem_type: 'using_deprecated_schema_version')
- message = "Version #{report_version} for report type #{report_type} has been deprecated, supported versions for this report type are: #{supported_schema_versions}"
+ template = _("Version %{report_version} for report type %{report_type} has been deprecated,"\
+ " supported versions for this report type are: %{supported_schema_versions}."\
+ " GitLab will attempt to parse and ingest this report if valid.")
+
+ message = format(template, report_version: report_version, report_type: report_type, supported_schema_versions: supported_schema_versions)
+
add_message_as(level: :deprecation_warning, message: message)
end
+ def valid?
+ errors.empty?
+ end
+
def log_warnings(problem_type:)
Gitlab::AppLogger.info(
message: 'security report schema validation problem',
@@ -123,30 +207,6 @@ module Gitlab
)
end
- def add_unsupported_report_version_message
- log_warnings(problem_type: 'using_unsupported_schema_version')
-
- handle_unsupported_report_version
- end
-
- def report_uses_deprecated_schema_version?
- DEPRECATED_VERSIONS[report_type].include?(report_version)
- end
-
- def report_uses_supported_schema_version?
- SUPPORTED_VERSIONS[report_type].include?(report_version)
- end
-
- def handle_unsupported_report_version
- if report_version.nil?
- message = "Report version not provided, #{report_type} report type supports versions: #{supported_schema_versions}"
- else
- message = "Version #{report_version} for report type #{report_type} is unsupported, supported versions for this report type are: #{supported_schema_versions}"
- end
-
- add_message_as(level: :error, message: message)
- end
-
def supported_schema_versions
SUPPORTED_VERSIONS[report_type].join(", ")
end
diff --git a/lib/security/report_schema_version_matcher.rb b/lib/security/report_schema_version_matcher.rb
new file mode 100644
index 00000000000..d8eb5b8f490
--- /dev/null
+++ b/lib/security/report_schema_version_matcher.rb
@@ -0,0 +1,42 @@
+# frozen_string_literal: true
+module Security
+ class ReportSchemaVersionMatcher
+ def initialize(report_declared_version:, supported_versions:)
+ @report_version = Gem::Version.new(report_declared_version)
+ @supported_versions = supported_versions.sort.map { |version| Gem::Version.new(version) }
+ end
+
+ attr_reader :report_version, :supported_versions
+
+ def call
+ find_matching_versions
+ end
+
+ private
+
+ def find_matching_versions
+ dependency = Gem::Dependency.new('', approximate_version)
+ matches = supported_versions.map do |supported_version|
+ exact_version = ['', supported_version.to_s]
+ [supported_version.to_s, dependency.match?(*exact_version)]
+ end
+ matches.to_h.select { |_, matches_dependency| matches_dependency == true }.keys.max
+ end
+
+ def approximate_version
+ "~> #{generate_patch_version}"
+ end
+
+ def generate_patch_version
+ # We can't use #approximate_recommendation here because
+ # for "14.0.32" it would yield "~> 14.0" and according to
+ # https://www.rubydoc.info/github/rubygems/rubygems/Gem/Version#label-Preventing+Version+Catastrophe-3A
+ # "~> 3.0" covers [3.0...4.0)
+ # and version 14.1.0 would fall within that range
+ #
+ # Instead we replace the patch number with 0 and get "~> 14.0.0"
+ # Which will work as we want it to
+ (report_version.segments[0...2] << 0).join('.')
+ end
+ end
+end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index a111a33859e..f109bfd7db6 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -31894,6 +31894,12 @@ msgstr ""
msgid "Puma is running with a thread count above 1 and the Rugged service is enabled. This may decrease performance in some environments. See our %{link_start}documentation%{link_end} for details of this issue."
msgstr ""
+msgid "PumbleIntegration|Send notifications about project events to Pumble."
+msgstr ""
+
+msgid "PumbleIntegration|Send notifications about project events to Pumble. %{docs_link}"
+msgstr ""
+
msgid "Purchase more minutes"
msgstr ""
@@ -32837,6 +32843,9 @@ msgstr ""
msgid "Report for the scan has been removed from the database."
msgstr ""
+msgid "Report version not provided, %{report_type} report type supports versions: %{supported_schema_versions}. GitLab will attempt to validate this report against the earliest supported versions of this report type, to show all the errors but will not ingest the report"
+msgstr ""
+
msgid "Report your license usage data to GitLab"
msgstr ""
@@ -40324,6 +40333,9 @@ msgstr ""
msgid "This release was created with a date in the past. Evidence collection at the moment of the release is unavailable."
msgstr ""
+msgid "This report uses a supported MAJOR.MINOR schema version but the PATCH version doesn't match any vendored schema version. Validation will be attempted against version %{find_latest_patch_version}"
+msgstr ""
+
msgid "This repository"
msgstr ""
@@ -42970,6 +42982,12 @@ msgstr ""
msgid "Version"
msgstr ""
+msgid "Version %{report_version} for report type %{report_type} has been deprecated, supported versions for this report type are: %{supported_schema_versions}. GitLab will attempt to parse and ingest this report if valid."
+msgstr ""
+
+msgid "Version %{report_version} for report type %{report_type} is unsupported, supported versions for this report type are: %{supported_schema_versions}. GitLab will attempt to validate this report against the earliest supported versions of this report type, to show all the errors but will not ingest the report"
+msgstr ""
+
msgid "Version %{versionNumber}"
msgstr ""
diff --git a/package.json b/package.json
index 484759d8dea..32ce90c40ee 100644
--- a/package.json
+++ b/package.json
@@ -51,8 +51,8 @@
"@babel/preset-env": "^7.18.2",
"@gitlab/at.js": "1.5.7",
"@gitlab/favicon-overlay": "2.0.0",
- "@gitlab/svgs": "2.33.0",
- "@gitlab/ui": "42.25.0",
+ "@gitlab/svgs": "3.1.0",
+ "@gitlab/ui": "43.5.0",
"@gitlab/visual-review-tools": "1.7.3",
"@rails/actioncable": "6.1.4-7",
"@rails/ujs": "6.1.4-7",
diff --git a/spec/features/invites_spec.rb b/spec/features/invites_spec.rb
index fe804dc52d7..1baa97096d9 100644
--- a/spec/features/invites_spec.rb
+++ b/spec/features/invites_spec.rb
@@ -182,12 +182,14 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures do
context 'email confirmation disabled' do
let(:send_email_confirmation) { false }
- it 'signs up and redirects to the most recent membership activity page with all the projects/groups invitations automatically accepted' do
- fill_in_sign_up_form(new_user)
- fill_in_welcome_form
+ context 'the user signs up for an account with the invitation email address' do
+ it 'redirects to the most recent membership activity page with all the projects/groups invitations automatically accepted' do
+ fill_in_sign_up_form(new_user)
+ fill_in_welcome_form
- expect(page).to have_current_path(activity_group_path(group), ignore_query: true)
- expect(page).to have_content('You have been granted Owner access to group Owned.')
+ expect(page).to have_current_path(activity_group_path(group), ignore_query: true)
+ expect(page).to have_content('You have been granted Owner access to group Owned.')
+ end
end
context 'the user sign-up using a different email address' do
@@ -227,11 +229,13 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures do
end
end
- it 'signs up and redirects to the group activity page with all the project/groups invitation automatically accepted' do
- fill_in_sign_up_form(new_user)
- fill_in_welcome_form
+ context 'the user signs up for an account with the invitation email address' do
+ it 'redirects to the most recent membership activity page with all the projects/groups invitations automatically accepted' do
+ fill_in_sign_up_form(new_user)
+ fill_in_welcome_form
- expect(page).to have_current_path(activity_group_path(group), ignore_query: true)
+ expect(page).to have_current_path(activity_group_path(group), ignore_query: true)
+ end
end
context 'the user sign-up using a different email address' do
diff --git a/spec/features/oauth_registration_spec.rb b/spec/features/oauth_registration_spec.rb
index 18dd10755b1..cb8343b8065 100644
--- a/spec/features/oauth_registration_spec.rb
+++ b/spec/features/oauth_registration_spec.rb
@@ -85,7 +85,46 @@ RSpec.describe 'OAuth Registration', :js, :allow_forgery_protection do
expect(page).to have_content('Please complete your profile with email address')
end
end
+
+ context 'when registering via an invitation email' do
+ let_it_be(:owner) { create(:user) }
+ let_it_be(:group) { create(:group, name: 'Owned') }
+ let_it_be(:project) { create(:project, :repository, namespace: group) }
+
+ let(:invite_email) { generate(:email) }
+ let(:extra_params) { { invite_type: Emails::Members::INITIAL_INVITE } }
+ let(:group_invite) do
+ create(
+ :group_member, :invited,
+ group: group,
+ invite_email: invite_email,
+ created_by: owner
+ )
+ end
+
+ before do
+ project.add_maintainer(owner)
+ group.add_owner(owner)
+ group_invite.generate_invite_token!
+
+ mock_auth_hash(provider, uid, invite_email, additional_info: additional_info)
+ end
+
+ it 'redirects to the activity page with all the projects/groups invitations accepted' do
+ visit invite_path(group_invite.raw_invite_token, extra_params)
+ click_link_or_button "oauth-login-#{provider}"
+ fill_in_welcome_form
+
+ expect(page).to have_content('You have been granted Owner access to group Owned.')
+ expect(page).to have_current_path(activity_group_path(group), ignore_query: true)
+ end
+ end
end
end
end
+
+ def fill_in_welcome_form
+ select 'Software Developer', from: 'user_role'
+ click_button 'Get started!'
+ end
end
diff --git a/spec/frontend/admin/users/components/modals/delete_user_modal_spec.js b/spec/frontend/admin/users/components/modals/delete_user_modal_spec.js
index a5007e18f5f..70ed9eeb3e1 100644
--- a/spec/frontend/admin/users/components/modals/delete_user_modal_spec.js
+++ b/spec/frontend/admin/users/components/modals/delete_user_modal_spec.js
@@ -87,8 +87,8 @@ describe('Delete user modal', () => {
});
it('has disabled buttons', () => {
- expect(findPrimaryButton().attributes('disabled')).toBeTruthy();
- expect(findSecondaryButton().attributes('disabled')).toBeTruthy();
+ expect(findPrimaryButton().attributes('disabled')).toBe('true');
+ expect(findSecondaryButton().attributes('disabled')).toBe('true');
});
});
@@ -105,8 +105,8 @@ describe('Delete user modal', () => {
});
it('has disabled buttons', () => {
- expect(findPrimaryButton().attributes('disabled')).toBeTruthy();
- expect(findSecondaryButton().attributes('disabled')).toBeTruthy();
+ expect(findPrimaryButton().attributes('disabled')).toBe('true');
+ expect(findSecondaryButton().attributes('disabled')).toBe('true');
});
});
@@ -123,8 +123,8 @@ describe('Delete user modal', () => {
});
it('has enabled buttons', () => {
- expect(findPrimaryButton().attributes('disabled')).toBeFalsy();
- expect(findSecondaryButton().attributes('disabled')).toBeFalsy();
+ expect(findPrimaryButton().attributes('disabled')).toBeUndefined();
+ expect(findSecondaryButton().attributes('disabled')).toBeUndefined();
});
describe('when primary action is clicked', () => {
diff --git a/spec/frontend/ci_variable_list/components/legacy_ci_variable_modal_spec.js b/spec/frontend/ci_variable_list/components/legacy_ci_variable_modal_spec.js
index 42c6501dcce..6681ab91a4a 100644
--- a/spec/frontend/ci_variable_list/components/legacy_ci_variable_modal_spec.js
+++ b/spec/frontend/ci_variable_list/components/legacy_ci_variable_modal_spec.js
@@ -58,7 +58,7 @@ describe('Ci variable modal', () => {
});
it('button is disabled when no key/value pair are present', () => {
- expect(findAddorUpdateButton().attributes('disabled')).toBeTruthy();
+ expect(findAddorUpdateButton().attributes('disabled')).toBe('true');
});
});
@@ -71,7 +71,7 @@ describe('Ci variable modal', () => {
});
it('button is enabled when key/value pair are present', () => {
- expect(findAddorUpdateButton().attributes('disabled')).toBeFalsy();
+ expect(findAddorUpdateButton().attributes('disabled')).toBeUndefined();
});
it('Add variable button dispatches addVariable action', () => {
@@ -249,7 +249,7 @@ describe('Ci variable modal', () => {
});
it('disables the submit button', () => {
- expect(findAddorUpdateButton().attributes('disabled')).toBeTruthy();
+ expect(findAddorUpdateButton().attributes('disabled')).toBe('disabled');
});
it('shows the correct error text', () => {
@@ -316,7 +316,7 @@ describe('Ci variable modal', () => {
});
it('does not disable the submit button', () => {
- expect(findAddorUpdateButton().attributes('disabled')).toBeFalsy();
+ expect(findAddorUpdateButton().attributes('disabled')).toBeUndefined();
});
});
});
diff --git a/spec/frontend/content_editor/remark_markdown_processing_spec.js b/spec/frontend/content_editor/remark_markdown_processing_spec.js
index ca552644258..0f9073dc26d 100644
--- a/spec/frontend/content_editor/remark_markdown_processing_spec.js
+++ b/spec/frontend/content_editor/remark_markdown_processing_spec.js
@@ -261,7 +261,7 @@ describe('Client side Markdown processing', () => {
...source(' '),
alt: 'foo',
canonicalSrc: 'bar',
- src: 'http://test.host/bar',
+ src: 'bar',
}),
),
),
@@ -283,7 +283,7 @@ describe('Client side Markdown processing', () => {
image({
...source(' '),
alt: 'foo',
- src: 'http://test.host/bar',
+ src: 'bar',
canonicalSrc: 'bar',
}),
),
@@ -297,7 +297,7 @@ describe('Client side Markdown processing', () => {
link(
{
...source('[GitLab](https://gitlab.com "Go to GitLab")'),
- href: 'https://gitlab.com/',
+ href: 'https://gitlab.com',
canonicalSrc: 'https://gitlab.com',
title: 'Go to GitLab',
},
@@ -316,7 +316,7 @@ describe('Client side Markdown processing', () => {
link(
{
...source('[GitLab](https://gitlab.com "Go to GitLab")'),
- href: 'https://gitlab.com/',
+ href: 'https://gitlab.com',
canonicalSrc: 'https://gitlab.com',
title: 'Go to GitLab',
},
@@ -335,7 +335,7 @@ describe('Client side Markdown processing', () => {
{
...source('www.commonmark.org'),
canonicalSrc: 'http://www.commonmark.org',
- href: 'http://www.commonmark.org/',
+ href: 'http://www.commonmark.org',
},
'www.commonmark.org',
),
@@ -389,7 +389,7 @@ describe('Client side Markdown processing', () => {
sourceMapKey: null,
sourceMarkdown: null,
canonicalSrc: 'https://gitlab.com',
- href: 'https://gitlab.com/',
+ href: 'https://gitlab.com',
},
'https://gitlab.com',
),
@@ -616,7 +616,7 @@ two
...source('![bar](foo.png)'),
alt: 'bar',
canonicalSrc: 'foo.png',
- src: 'http://test.host/foo.png',
+ src: 'foo.png',
}),
),
),
@@ -969,12 +969,12 @@ Paragraph
{
...source('[![moon](moon.jpg)](/uri)'),
canonicalSrc: '/uri',
- href: 'http://test.host/uri',
+ href: '/uri',
},
image({
...source('![moon](moon.jpg)'),
canonicalSrc: 'moon.jpg',
- src: 'http://test.host/moon.jpg',
+ src: 'moon.jpg',
alt: 'moon',
}),
),
@@ -1010,7 +1010,7 @@ Paragraph
{
...source('[moon](moon.jpg)'),
canonicalSrc: 'moon.jpg',
- href: 'http://test.host/moon.jpg',
+ href: 'moon.jpg',
},
'moon',
),
@@ -1021,7 +1021,7 @@ Paragraph
link(
{
...source('[sun](sun.jpg)'),
- href: 'http://test.host/sun.jpg',
+ href: 'sun.jpg',
canonicalSrc: 'sun.jpg',
},
'sun',
@@ -1141,7 +1141,7 @@ _world_.
link(
{
...source('[GitLab][gitlab-url]'),
- href: 'https://gitlab.com/',
+ href: 'https://gitlab.com',
canonicalSrc: 'https://gitlab.com',
title: 'GitLab',
},
@@ -1235,4 +1235,72 @@ body {
expect(tiptapEditor.getHTML()).toEqual(expectedHtml);
},
);
+
+ describe('attribute sanitization', () => {
+ // eslint-disable-next-line no-script-url
+ const protocolBasedInjectionSimpleNoSpaces = "javascript:alert('XSS');";
+ // eslint-disable-next-line no-script-url
+ const protocolBasedInjectionSimpleSpacesBefore = "javascript: alert('XSS');";
+
+ const docWithImageFactory = (urlInput, urlOutput) => {
+ const input = ` `;
+
+ return {
+ input,
+ expectedDoc: doc(
+ paragraph(
+ source(input),
+ image({
+ ...source(input),
+ src: urlOutput,
+ canonicalSrc: urlOutput,
+ }),
+ ),
+ ),
+ };
+ };
+
+ const docWithLinkFactory = (urlInput, urlOutput) => {
+ const input = `foo`;
+
+ return {
+ input,
+ expectedDoc: doc(
+ paragraph(
+ source(input),
+ link({ ...source(input), href: urlOutput, canonicalSrc: urlOutput }, 'foo'),
+ ),
+ ),
+ };
+ };
+
+ it.each`
+ desc | urlInput | urlOutput
+ ${'protocol-based JS injection: simple, no spaces'} | ${protocolBasedInjectionSimpleNoSpaces} | ${null}
+ ${'protocol-based JS injection: simple, spaces before'} | ${"javascript :alert('XSS');"} | ${null}
+ ${'protocol-based JS injection: simple, spaces after'} | ${protocolBasedInjectionSimpleSpacesBefore} | ${null}
+ ${'protocol-based JS injection: simple, spaces before and after'} | ${"javascript : alert('XSS');"} | ${null}
+ ${'protocol-based JS injection: UTF-8 encoding'} | ${'javascript:'} | ${null}
+ ${'protocol-based JS injection: long UTF-8 encoding'} | ${'javascript:'} | ${null}
+ ${'protocol-based JS injection: long UTF-8 encoding without semicolons'} | ${'javascript:alert('XSS')'} | ${null}
+ ${'protocol-based JS injection: hex encoding'} | ${'javascript:'} | ${null}
+ ${'protocol-based JS injection: long hex encoding'} | ${'javascript:'} | ${null}
+ ${'protocol-based JS injection: hex encoding without semicolons'} | ${'javascript:alert('XSS')'} | ${null}
+ ${'protocol-based JS injection: Unicode'} | ${"\u0001java\u0003script:alert('XSS')"} | ${null}
+ ${'protocol-based JS injection: spaces and entities'} | ${" javascript:alert('XSS');"} | ${null}
+ ${'vbscript'} | ${'vbscript:alert(document.domain)'} | ${null}
+ ${'protocol-based JS injection: preceding colon'} | ${":javascript:alert('XSS');"} | ${":javascript:alert('XSS');"}
+ ${'protocol-based JS injection: null char'} | ${"java\0script:alert('XSS')"} | ${"java�script:alert('XSS')"}
+ ${'protocol-based JS injection: invalid URL char'} | ${"java\\script:alert('XSS')"} | ${"java\\script:alert('XSS')"}
+ `('sanitize $desc:\n\tURL "$urlInput" becomes "$urlOutput"', ({ urlInput, urlOutput }) => {
+ const exampleFactories = [docWithImageFactory, docWithLinkFactory];
+
+ exampleFactories.forEach(async (exampleFactory) => {
+ const { input, expectedDoc } = exampleFactory(urlInput, urlOutput);
+ const document = await deserialize(input);
+
+ expect(document.toJSON()).toEqual(expectedDoc.toJSON());
+ });
+ });
+ });
});
diff --git a/spec/frontend/content_editor/services/markdown_serializer_spec.js b/spec/frontend/content_editor/services/markdown_serializer_spec.js
index 55f17727df7..37fe2482123 100644
--- a/spec/frontend/content_editor/services/markdown_serializer_spec.js
+++ b/spec/frontend/content_editor/services/markdown_serializer_spec.js
@@ -1213,47 +1213,47 @@ paragraph
};
it.each`
- mark | markdown | modifiedMarkdown | editAction
- ${'bold'} | ${'**bold**'} | ${'**bold modified**'} | ${defaultEditAction}
- ${'bold'} | ${'__bold__'} | ${'__bold modified__'} | ${defaultEditAction}
- ${'bold'} | ${'bold'} | ${'bold modified'} | ${defaultEditAction}
- ${'bold'} | ${'bold'} | ${'bold modified'} | ${defaultEditAction}
- ${'italic'} | ${'_italic_'} | ${'_italic modified_'} | ${defaultEditAction}
- ${'italic'} | ${'*italic*'} | ${'*italic modified*'} | ${defaultEditAction}
- ${'italic'} | ${'italic'} | ${'italic modified'} | ${defaultEditAction}
- ${'italic'} | ${'italic'} | ${'italic modified'} | ${defaultEditAction}
- ${'link'} | ${'[gitlab](https://gitlab.com)'} | ${'[gitlab modified](https://gitlab.com)'} | ${defaultEditAction}
- ${'link'} | ${'link'} | ${'link modified'} | ${defaultEditAction}
- ${'link'} | ${'link www.gitlab.com'} | ${'modified link www.gitlab.com'} | ${prependContentEditAction}
- ${'link'} | ${'link https://www.gitlab.com'} | ${'modified link https://www.gitlab.com'} | ${prependContentEditAction}
- ${'link'} | ${'link(https://www.gitlab.com)'} | ${'modified link(https://www.gitlab.com)'} | ${prependContentEditAction}
- ${'link'} | ${'link(engineering@gitlab.com)'} | ${'modified link(engineering@gitlab.com)'} | ${prependContentEditAction}
- ${'link'} | ${'link '} | ${'modified link '} | ${prependContentEditAction}
- ${'link'} | ${'link [https://www.gitlab.com>'} | ${'modified link \\[https://www.gitlab.com>'} | ${prependContentEditAction}
- ${'link'} | ${'link '} | ${'modified link [https://www.gitlab.com>](https://www.gitlab.com%3E)'} | ${prependContentEditAction}
- ${'link'} | ${'link https://www.gitlab.com/path'} | ${'modified link https://www.gitlab.com/path'} | ${prependContentEditAction}
- ${'link'} | ${'link https://www.gitlab.com?query=search'} | ${'modified link https://www.gitlab.com?query=search'} | ${prependContentEditAction}
- ${'link'} | ${'link https://www.gitlab.com/#fragment'} | ${'modified link https://www.gitlab.com/#fragment'} | ${prependContentEditAction}
- ${'link'} | ${'link https://www.gitlab.com/?query=search'} | ${'modified link https://www.gitlab.com/?query=search'} | ${prependContentEditAction}
- ${'link'} | ${'link https://www.gitlab.com#fragment'} | ${'modified link https://www.gitlab.com#fragment'} | ${prependContentEditAction}
- ${'link'} | ${'link **https://www.gitlab.com]**'} | ${'modified link [**https://www.gitlab.com\\]**](https://www.gitlab.com%5D)'} | ${prependContentEditAction}
- ${'code'} | ${'`code`'} | ${'`code modified`'} | ${defaultEditAction}
- ${'code'} | ${'code '} | ${'code modified '} | ${defaultEditAction}
- ${'strike'} | ${'~~striked~~'} | ${'~~striked modified~~'} | ${defaultEditAction}
- ${'strike'} | ${'striked'} | ${'striked modified'} | ${defaultEditAction}
- ${'strike'} | ${'striked'} | ${'striked modified'} | ${defaultEditAction}
- ${'strike'} | ${'striked'} | ${'striked modified'} | ${defaultEditAction}
- ${'list'} | ${'- list item'} | ${'- list item modified'} | ${defaultEditAction}
- ${'list'} | ${'* list item'} | ${'* list item modified'} | ${defaultEditAction}
- ${'list'} | ${'+ list item'} | ${'+ list item modified'} | ${defaultEditAction}
- ${'list'} | ${'- list item 1\n- list item 2'} | ${'- list item 1\n- list item 2 modified'} | ${defaultEditAction}
- ${'list'} | ${'2) list item'} | ${'2) list item modified'} | ${defaultEditAction}
- ${'list'} | ${'1. list item'} | ${'1. list item modified'} | ${defaultEditAction}
- ${'taskList'} | ${'2) [ ] task list item'} | ${'2) [ ] task list item modified'} | ${defaultEditAction}
- ${'taskList'} | ${'2) [x] task list item'} | ${'2) [x] task list item modified'} | ${defaultEditAction}
- ${'image'} | ${'![image](image.png)'} | ${'![image](image.png) modified'} | ${defaultEditAction}
- ${'footnoteReference'} | ${'[^1] footnote\n\n[^1]: footnote definition'} | ${'modified [^1] footnote\n\n[^1]: footnote definition'} | ${prependContentEditAction}
+ mark | markdown | modifiedMarkdown | editAction
+ ${'bold'} | ${'**bold**'} | ${'**bold modified**'} | ${defaultEditAction}
+ ${'bold'} | ${'__bold__'} | ${'__bold modified__'} | ${defaultEditAction}
+ ${'bold'} | ${'bold'} | ${'bold modified'} | ${defaultEditAction}
+ ${'bold'} | ${'bold'} | ${'bold modified'} | ${defaultEditAction}
+ ${'italic'} | ${'_italic_'} | ${'_italic modified_'} | ${defaultEditAction}
+ ${'italic'} | ${'*italic*'} | ${'*italic modified*'} | ${defaultEditAction}
+ ${'italic'} | ${'italic'} | ${'italic modified'} | ${defaultEditAction}
+ ${'italic'} | ${'italic'} | ${'italic modified'} | ${defaultEditAction}
+ ${'link'} | ${'[gitlab](https://gitlab.com)'} | ${'[gitlab modified](https://gitlab.com)'} | ${defaultEditAction}
+ ${'link'} | ${'link'} | ${'link modified'} | ${defaultEditAction}
+ ${'link'} | ${'link www.gitlab.com'} | ${'modified link www.gitlab.com'} | ${prependContentEditAction}
+ ${'link'} | ${'link https://www.gitlab.com'} | ${'modified link https://www.gitlab.com'} | ${prependContentEditAction}
+ ${'link'} | ${'link(https://www.gitlab.com)'} | ${'modified link(https://www.gitlab.com)'} | ${prependContentEditAction}
+ ${'link'} | ${'link(engineering@gitlab.com)'} | ${'modified link(engineering@gitlab.com)'} | ${prependContentEditAction}
+ ${'link'} | ${'link '} | ${'modified link '} | ${prependContentEditAction}
+ ${'link'} | ${'link [https://www.gitlab.com>'} | ${'modified link \\[https://www.gitlab.com>'} | ${prependContentEditAction}
+ ${'link'} | ${'link '} | ${'modified link https://www.gitlab.com>'} | ${prependContentEditAction}
+ ${'link'} | ${'link https://www.gitlab.com/path'} | ${'modified link https://www.gitlab.com/path'} | ${prependContentEditAction}
+ ${'link'} | ${'link https://www.gitlab.com?query=search'} | ${'modified link https://www.gitlab.com?query=search'} | ${prependContentEditAction}
+ ${'link'} | ${'link https://www.gitlab.com/#fragment'} | ${'modified link https://www.gitlab.com/#fragment'} | ${prependContentEditAction}
+ ${'link'} | ${'link https://www.gitlab.com/?query=search'} | ${'modified link https://www.gitlab.com/?query=search'} | ${prependContentEditAction}
+ ${'link'} | ${'link https://www.gitlab.com#fragment'} | ${'modified link https://www.gitlab.com#fragment'} | ${prependContentEditAction}
+ ${'link'} | ${'link **https://www.gitlab.com]**'} | ${'modified link **https://www.gitlab.com\\]**'} | ${prependContentEditAction}
+ ${'code'} | ${'`code`'} | ${'`code modified`'} | ${defaultEditAction}
+ ${'code'} | ${'code '} | ${'code modified '} | ${defaultEditAction}
+ ${'strike'} | ${'~~striked~~'} | ${'~~striked modified~~'} | ${defaultEditAction}
+ ${'strike'} | ${'striked'} | ${'striked modified'} | ${defaultEditAction}
+ ${'strike'} | ${'striked'} | ${'striked modified'} | ${defaultEditAction}
+ ${'strike'} | ${'striked'} | ${'striked modified'} | ${defaultEditAction}
+ ${'list'} | ${'- list item'} | ${'- list item modified'} | ${defaultEditAction}
+ ${'list'} | ${'* list item'} | ${'* list item modified'} | ${defaultEditAction}
+ ${'list'} | ${'+ list item'} | ${'+ list item modified'} | ${defaultEditAction}
+ ${'list'} | ${'- list item 1\n- list item 2'} | ${'- list item 1\n- list item 2 modified'} | ${defaultEditAction}
+ ${'list'} | ${'2) list item'} | ${'2) list item modified'} | ${defaultEditAction}
+ ${'list'} | ${'1. list item'} | ${'1. list item modified'} | ${defaultEditAction}
+ ${'taskList'} | ${'2) [ ] task list item'} | ${'2) [ ] task list item modified'} | ${defaultEditAction}
+ ${'taskList'} | ${'2) [x] task list item'} | ${'2) [x] task list item modified'} | ${defaultEditAction}
+ ${'image'} | ${'![image](image.png)'} | ${'![image](image.png) modified'} | ${defaultEditAction}
+ ${'footnoteReference'} | ${'[^1] footnote\n\n[^1]: footnote definition'} | ${'modified [^1] footnote\n\n[^1]: footnote definition'} | ${prependContentEditAction}
`(
'preserves original $mark syntax when sourceMarkdown is available for $markdown',
async ({ markdown, modifiedMarkdown, editAction }) => {
diff --git a/spec/frontend/issues/show/components/app_spec.js b/spec/frontend/issues/show/components/app_spec.js
index 27604b8ccf3..12f9707da04 100644
--- a/spec/frontend/issues/show/components/app_spec.js
+++ b/spec/frontend/issues/show/components/app_spec.js
@@ -119,7 +119,7 @@ describe('Issuable output', () => {
expect(findEdited().exists()).toBe(true);
expect(findEdited().props('updatedByPath')).toMatch(/\/some_user$/);
- expect(findEdited().props('updatedAt')).toBeTruthy();
+ expect(findEdited().props('updatedAt')).toBe(initialRequest.updated_at);
expect(wrapper.vm.state.lock_version).toBe(initialRequest.lock_version);
})
.then(() => {
@@ -133,7 +133,7 @@ describe('Issuable output', () => {
expect(findEdited().exists()).toBe(true);
expect(findEdited().props('updatedByName')).toBe('Other User');
expect(findEdited().props('updatedByPath')).toMatch(/\/other_user$/);
- expect(findEdited().props('updatedAt')).toBeTruthy();
+ expect(findEdited().props('updatedAt')).toBe(secondRequest.updated_at);
});
});
diff --git a/spec/frontend/jira_connect/branches/components/project_dropdown_spec.js b/spec/frontend/jira_connect/branches/components/project_dropdown_spec.js
index 136a5967ee4..b0218a9df12 100644
--- a/spec/frontend/jira_connect/branches/components/project_dropdown_spec.js
+++ b/spec/frontend/jira_connect/branches/components/project_dropdown_spec.js
@@ -148,7 +148,7 @@ describe('ProjectDropdown', () => {
});
it('emits `error` event', () => {
- expect(wrapper.emitted('error')).toBeTruthy();
+ expect(wrapper.emitted('error')).toHaveLength(1);
});
});
diff --git a/spec/frontend/nav/components/top_nav_dropdown_menu_spec.js b/spec/frontend/nav/components/top_nav_dropdown_menu_spec.js
index 70df05a2781..6cfbdb16111 100644
--- a/spec/frontend/nav/components/top_nav_dropdown_menu_spec.js
+++ b/spec/frontend/nav/components/top_nav_dropdown_menu_spec.js
@@ -124,7 +124,7 @@ describe('~/nav/components/top_nav_dropdown_menu.vue', () => {
});
it('clicked on link with view', () => {
- expect(primaryLink.props('menuItem').view).toBeTruthy();
+ expect(primaryLink.props('menuItem').view).toBe(TEST_NAV_DATA.views.projects.namespace);
});
it('changes active view', () => {
diff --git a/spec/frontend/notes/components/noteable_note_spec.js b/spec/frontend/notes/components/noteable_note_spec.js
index 3350609bb90..59e2f15faa4 100644
--- a/spec/frontend/notes/components/noteable_note_spec.js
+++ b/spec/frontend/notes/components/noteable_note_spec.js
@@ -357,7 +357,7 @@ describe('issue_note', () => {
createWrapper();
updateActions();
wrapper.findComponent(NoteBody).vm.$emit('handleFormUpdate', params);
- expect(wrapper.emitted('handleUpdateNote')).toBeTruthy();
+ expect(wrapper.emitted('handleUpdateNote')).toHaveLength(1);
});
it('does not stringify empty position', () => {
diff --git a/spec/frontend/pipelines/components/pipelines_filtered_search_spec.js b/spec/frontend/pipelines/components/pipelines_filtered_search_spec.js
index 6c743f92116..f958f12acd4 100644
--- a/spec/frontend/pipelines/components/pipelines_filtered_search_spec.js
+++ b/spec/frontend/pipelines/components/pipelines_filtered_search_spec.js
@@ -102,7 +102,7 @@ describe('Pipelines filtered search', () => {
it('emits filterPipelines on submit with correct filter', () => {
findFilteredSearch().vm.$emit('submit', mockSearch);
- expect(wrapper.emitted('filterPipelines')).toBeTruthy();
+ expect(wrapper.emitted('filterPipelines')).toHaveLength(1);
expect(wrapper.emitted('filterPipelines')[0]).toEqual([mockSearch]);
});
diff --git a/spec/frontend/prometheus_metrics/custom_metrics_spec.js b/spec/frontend/prometheus_metrics/custom_metrics_spec.js
index fc906194059..a079b0b97fd 100644
--- a/spec/frontend/prometheus_metrics/custom_metrics_spec.js
+++ b/spec/frontend/prometheus_metrics/custom_metrics_spec.js
@@ -50,39 +50,33 @@ describe('PrometheusMetrics', () => {
customMetrics.showMonitoringCustomMetricsPanelState(PANEL_STATE.LOADING);
expect(customMetrics.$monitoredCustomMetricsLoading.hasClass('hidden')).toEqual(false);
- expect(customMetrics.$monitoredCustomMetricsEmpty.hasClass('hidden')).toBeTruthy();
- expect(customMetrics.$monitoredCustomMetricsList.hasClass('hidden')).toBeTruthy();
- expect(
- customMetrics.$monitoredCustomMetricsNoIntegrationText.hasClass('hidden'),
- ).toBeTruthy();
+ expect(customMetrics.$monitoredCustomMetricsEmpty.hasClass('hidden')).toBe(true);
+ expect(customMetrics.$monitoredCustomMetricsList.hasClass('hidden')).toBe(true);
+ expect(customMetrics.$monitoredCustomMetricsNoIntegrationText.hasClass('hidden')).toBe(true);
- expect(customMetrics.$newCustomMetricButton.hasClass('hidden')).toBeTruthy();
- expect(customMetrics.$newCustomMetricText.hasClass('hidden')).toBeTruthy();
+ expect(customMetrics.$newCustomMetricButton.hasClass('hidden')).toBe(true);
+ expect(customMetrics.$newCustomMetricText.hasClass('hidden')).toBe(true);
});
it('should show metrics list when called with `list`', () => {
customMetrics.showMonitoringCustomMetricsPanelState(PANEL_STATE.LIST);
- expect(customMetrics.$monitoredCustomMetricsLoading.hasClass('hidden')).toBeTruthy();
- expect(customMetrics.$monitoredCustomMetricsEmpty.hasClass('hidden')).toBeTruthy();
+ expect(customMetrics.$monitoredCustomMetricsLoading.hasClass('hidden')).toBe(true);
+ expect(customMetrics.$monitoredCustomMetricsEmpty.hasClass('hidden')).toBe(true);
expect(customMetrics.$monitoredCustomMetricsList.hasClass('hidden')).toEqual(false);
- expect(
- customMetrics.$monitoredCustomMetricsNoIntegrationText.hasClass('hidden'),
- ).toBeTruthy();
+ expect(customMetrics.$monitoredCustomMetricsNoIntegrationText.hasClass('hidden')).toBe(true);
expect(customMetrics.$newCustomMetricButton.hasClass('hidden')).toEqual(false);
- expect(customMetrics.$newCustomMetricText.hasClass('hidden')).toBeTruthy();
+ expect(customMetrics.$newCustomMetricText.hasClass('hidden')).toBe(true);
});
it('should show empty state when called with `empty`', () => {
customMetrics.showMonitoringCustomMetricsPanelState(PANEL_STATE.EMPTY);
- expect(customMetrics.$monitoredCustomMetricsLoading.hasClass('hidden')).toBeTruthy();
+ expect(customMetrics.$monitoredCustomMetricsLoading.hasClass('hidden')).toBe(true);
expect(customMetrics.$monitoredCustomMetricsEmpty.hasClass('hidden')).toEqual(false);
- expect(customMetrics.$monitoredCustomMetricsList.hasClass('hidden')).toBeTruthy();
- expect(
- customMetrics.$monitoredCustomMetricsNoIntegrationText.hasClass('hidden'),
- ).toBeTruthy();
+ expect(customMetrics.$monitoredCustomMetricsList.hasClass('hidden')).toBe(true);
+ expect(customMetrics.$monitoredCustomMetricsNoIntegrationText.hasClass('hidden')).toBe(true);
expect(customMetrics.$newCustomMetricButton.hasClass('hidden')).toEqual(false);
expect(customMetrics.$newCustomMetricText.hasClass('hidden')).toEqual(false);
@@ -94,14 +88,12 @@ describe('PrometheusMetrics', () => {
const $metricsListLi = customMetrics.$monitoredCustomMetricsList.find('li');
- expect(customMetrics.$monitoredCustomMetricsLoading.hasClass('hidden')).toBeTruthy();
+ expect(customMetrics.$monitoredCustomMetricsLoading.hasClass('hidden')).toBe(true);
expect(customMetrics.$monitoredCustomMetricsList.hasClass('hidden')).toEqual(false);
- expect(
- customMetrics.$monitoredCustomMetricsNoIntegrationText.hasClass('hidden'),
- ).toBeTruthy();
+ expect(customMetrics.$monitoredCustomMetricsNoIntegrationText.hasClass('hidden')).toBe(true);
expect(customMetrics.$newCustomMetricButton.hasClass('hidden')).toEqual(false);
- expect(customMetrics.$newCustomMetricText.hasClass('hidden')).toBeTruthy();
+ expect(customMetrics.$newCustomMetricText.hasClass('hidden')).toBe(true);
expect($metricsListLi.length).toEqual(metrics.length);
});
@@ -114,10 +106,10 @@ describe('PrometheusMetrics', () => {
false,
);
- expect(customMetrics.$monitoredCustomMetricsLoading.hasClass('hidden')).toBeTruthy();
- expect(customMetrics.$monitoredCustomMetricsList.hasClass('hidden')).toBeTruthy();
- expect(customMetrics.$newCustomMetricButton.hasClass('hidden')).toBeTruthy();
- expect(customMetrics.$newCustomMetricText.hasClass('hidden')).toBeTruthy();
+ expect(customMetrics.$monitoredCustomMetricsLoading.hasClass('hidden')).toBe(true);
+ expect(customMetrics.$monitoredCustomMetricsList.hasClass('hidden')).toBe(true);
+ expect(customMetrics.$newCustomMetricButton.hasClass('hidden')).toBe(true);
+ expect(customMetrics.$newCustomMetricText.hasClass('hidden')).toBe(true);
});
});
});
diff --git a/spec/frontend/prometheus_metrics/prometheus_metrics_spec.js b/spec/frontend/prometheus_metrics/prometheus_metrics_spec.js
index 0df2aad5882..a65cbe1a47a 100644
--- a/spec/frontend/prometheus_metrics/prometheus_metrics_spec.js
+++ b/spec/frontend/prometheus_metrics/prometheus_metrics_spec.js
@@ -54,25 +54,25 @@ describe('PrometheusMetrics', () => {
it('should show loading state when called with `loading`', () => {
prometheusMetrics.showMonitoringMetricsPanelState(PANEL_STATE.LOADING);
- expect(prometheusMetrics.$monitoredMetricsLoading.hasClass('hidden')).toBeFalsy();
- expect(prometheusMetrics.$monitoredMetricsEmpty.hasClass('hidden')).toBeTruthy();
- expect(prometheusMetrics.$monitoredMetricsList.hasClass('hidden')).toBeTruthy();
+ expect(prometheusMetrics.$monitoredMetricsLoading.hasClass('hidden')).toBe(false);
+ expect(prometheusMetrics.$monitoredMetricsEmpty.hasClass('hidden')).toBe(true);
+ expect(prometheusMetrics.$monitoredMetricsList.hasClass('hidden')).toBe(true);
});
it('should show metrics list when called with `list`', () => {
prometheusMetrics.showMonitoringMetricsPanelState(PANEL_STATE.LIST);
- expect(prometheusMetrics.$monitoredMetricsLoading.hasClass('hidden')).toBeTruthy();
- expect(prometheusMetrics.$monitoredMetricsEmpty.hasClass('hidden')).toBeTruthy();
- expect(prometheusMetrics.$monitoredMetricsList.hasClass('hidden')).toBeFalsy();
+ expect(prometheusMetrics.$monitoredMetricsLoading.hasClass('hidden')).toBe(true);
+ expect(prometheusMetrics.$monitoredMetricsEmpty.hasClass('hidden')).toBe(true);
+ expect(prometheusMetrics.$monitoredMetricsList.hasClass('hidden')).toBe(false);
});
it('should show empty state when called with `empty`', () => {
prometheusMetrics.showMonitoringMetricsPanelState(PANEL_STATE.EMPTY);
- expect(prometheusMetrics.$monitoredMetricsLoading.hasClass('hidden')).toBeTruthy();
- expect(prometheusMetrics.$monitoredMetricsEmpty.hasClass('hidden')).toBeFalsy();
- expect(prometheusMetrics.$monitoredMetricsList.hasClass('hidden')).toBeTruthy();
+ expect(prometheusMetrics.$monitoredMetricsLoading.hasClass('hidden')).toBe(true);
+ expect(prometheusMetrics.$monitoredMetricsEmpty.hasClass('hidden')).toBe(false);
+ expect(prometheusMetrics.$monitoredMetricsList.hasClass('hidden')).toBe(true);
});
});
@@ -88,8 +88,8 @@ describe('PrometheusMetrics', () => {
const $metricsListLi = prometheusMetrics.$monitoredMetricsList.find('li');
- expect(prometheusMetrics.$monitoredMetricsLoading.hasClass('hidden')).toBeTruthy();
- expect(prometheusMetrics.$monitoredMetricsList.hasClass('hidden')).toBeFalsy();
+ expect(prometheusMetrics.$monitoredMetricsLoading.hasClass('hidden')).toBe(true);
+ expect(prometheusMetrics.$monitoredMetricsList.hasClass('hidden')).toBe(false);
expect(prometheusMetrics.$monitoredMetricsCount.text()).toEqual(
'3 exporters with 12 metrics were found',
@@ -102,8 +102,8 @@ describe('PrometheusMetrics', () => {
it('should show missing environment variables list', () => {
prometheusMetrics.populateActiveMetrics(missingVarMetrics);
- expect(prometheusMetrics.$monitoredMetricsLoading.hasClass('hidden')).toBeTruthy();
- expect(prometheusMetrics.$missingEnvVarPanel.hasClass('hidden')).toBeFalsy();
+ expect(prometheusMetrics.$monitoredMetricsLoading.hasClass('hidden')).toBe(true);
+ expect(prometheusMetrics.$missingEnvVarPanel.hasClass('hidden')).toBe(false);
expect(prometheusMetrics.$missingEnvVarMetricCount.text()).toEqual('2');
expect(prometheusMetrics.$missingEnvVarPanel.find('li').length).toEqual(2);
@@ -143,12 +143,12 @@ describe('PrometheusMetrics', () => {
prometheusMetrics.loadActiveMetrics();
- expect(prometheusMetrics.$monitoredMetricsLoading.hasClass('hidden')).toBeFalsy();
+ expect(prometheusMetrics.$monitoredMetricsLoading.hasClass('hidden')).toBe(false);
expect(axios.get).toHaveBeenCalledWith(prometheusMetrics.activeMetricsEndpoint);
await waitForPromises();
- expect(prometheusMetrics.$monitoredMetricsLoading.hasClass('hidden')).toBeTruthy();
+ expect(prometheusMetrics.$monitoredMetricsLoading.hasClass('hidden')).toBe(true);
});
it('should show empty state if response failed to load', async () => {
@@ -158,8 +158,8 @@ describe('PrometheusMetrics', () => {
await waitForPromises();
- expect(prometheusMetrics.$monitoredMetricsLoading.hasClass('hidden')).toBeTruthy();
- expect(prometheusMetrics.$monitoredMetricsEmpty.hasClass('hidden')).toBeFalsy();
+ expect(prometheusMetrics.$monitoredMetricsLoading.hasClass('hidden')).toBe(true);
+ expect(prometheusMetrics.$monitoredMetricsEmpty.hasClass('hidden')).toBe(false);
});
it('should populate metrics list once response is loaded', async () => {
diff --git a/spec/graphql/types/projects/service_type_enum_spec.rb b/spec/graphql/types/projects/service_type_enum_spec.rb
index ead69e60f6c..f7256910bb0 100644
--- a/spec/graphql/types/projects/service_type_enum_spec.rb
+++ b/spec/graphql/types/projects/service_type_enum_spec.rb
@@ -35,6 +35,7 @@ RSpec.describe GitlabSchema.types['ServiceType'] do
PIPELINES_EMAIL_SERVICE
PIVOTALTRACKER_SERVICE
PROMETHEUS_SERVICE
+ PUMBLE_SERVICE
PUSHOVER_SERVICE
REDMINE_SERVICE
SHIMO_SERVICE
diff --git a/spec/lib/gitlab/ci/parsers/security/validators/schema_validator_spec.rb b/spec/lib/gitlab/ci/parsers/security/validators/schema_validator_spec.rb
index aaac75e072f..77611c98179 100644
--- a/spec/lib/gitlab/ci/parsers/security/validators/schema_validator_spec.rb
+++ b/spec/lib/gitlab/ci/parsers/security/validators/schema_validator_spec.rb
@@ -68,6 +68,49 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Validators::SchemaValidator do
describe '#valid?' do
subject { validator.valid? }
+ context 'when given a supported MAJOR.MINOR schema version' do
+ let(:report_type) { :dast }
+ let(:report_version) do
+ latest_vendored_version = described_class::SUPPORTED_VERSIONS[report_type].last.split(".")
+ (latest_vendored_version[0...2] << "34").join(".")
+ end
+
+ context 'and the report is valid' do
+ let(:report_data) do
+ {
+ 'version' => report_version,
+ 'vulnerabilities' => []
+ }
+ end
+
+ it { is_expected.to be_truthy }
+ end
+
+ context 'and the report is invalid' do
+ let(:report_data) do
+ {
+ 'version' => report_version
+ }
+ end
+
+ it { is_expected.to be_falsey }
+
+ it 'logs related information' do
+ expect(Gitlab::AppLogger).to receive(:info).with(
+ message: "security report schema validation problem",
+ security_report_type: report_type,
+ security_report_version: report_version,
+ project_id: project.id,
+ security_report_failure: 'schema_validation_fails',
+ security_report_scanner_id: 'gemnasium',
+ security_report_scanner_version: '2.1.0'
+ )
+
+ subject
+ end
+ end
+ end
+
context 'when given a supported schema version' do
let(:report_type) { :dast }
let(:report_version) { described_class::SUPPORTED_VERSIONS[report_type].last }
@@ -320,6 +363,11 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Validators::SchemaValidator do
context 'when given an unsupported schema version' do
let(:report_type) { :dast }
let(:report_version) { "12.37.0" }
+ let(:expected_unsupported_message) do
+ "Version #{report_version} for report type #{report_type} is unsupported, supported versions for this report type are: "\
+ "#{supported_dast_versions}. GitLab will attempt to validate this report against the earliest supported "\
+ "versions of this report type, to show all the errors but will not ingest the report"
+ end
context 'and the report is valid' do
let(:report_data) do
@@ -331,7 +379,7 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Validators::SchemaValidator do
let(:expected_errors) do
[
- "Version 12.37.0 for report type dast is unsupported, supported versions for this report type are: #{supported_dast_versions}"
+ expected_unsupported_message
]
end
@@ -347,7 +395,7 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Validators::SchemaValidator do
let(:expected_errors) do
[
- "Version 12.37.0 for report type dast is unsupported, supported versions for this report type are: #{supported_dast_versions}",
+ expected_unsupported_message,
"root is missing required keys: vulnerabilities"
]
end
@@ -359,6 +407,12 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Validators::SchemaValidator do
context 'when not given a schema version' do
let(:report_type) { :dast }
let(:report_version) { nil }
+ let(:expected_missing_version_message) do
+ "Report version not provided, #{report_type} report type supports versions: #{supported_dast_versions}. GitLab "\
+ "will attempt to validate this report against the earliest supported versions of this report type, to show all "\
+ "the errors but will not ingest the report"
+ end
+
let(:report_data) do
{
'vulnerabilities' => []
@@ -368,7 +422,7 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Validators::SchemaValidator do
let(:expected_errors) do
[
"root is missing required keys: version",
- "Report version not provided, dast report type supports versions: #{supported_dast_versions}"
+ expected_missing_version_message
]
end
@@ -414,9 +468,14 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Validators::SchemaValidator do
end
let(:report_version) { described_class::DEPRECATED_VERSIONS[report_type].last }
+ let(:expected_deprecation_message) do
+ "Version #{report_version} for report type #{report_type} has been deprecated, supported versions for this "\
+ "report type are: #{supported_dast_versions}. GitLab will attempt to parse and ingest this report if valid."
+ end
+
let(:expected_deprecation_warnings) do
[
- "Version V2.7.0 for report type dast has been deprecated, supported versions for this report type are: #{supported_dast_versions}"
+ expected_deprecation_message
]
end
@@ -464,6 +523,62 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Validators::SchemaValidator do
describe '#warnings' do
subject { validator.warnings }
+ context 'when given a supported MAJOR.MINOR schema version' do
+ let(:report_type) { :dast }
+ let(:report_version) do
+ latest_vendored_version = described_class::SUPPORTED_VERSIONS[report_type].last.split(".")
+ (latest_vendored_version[0...2] << "34").join(".")
+ end
+
+ let(:latest_patch_version) do
+ ::Security::ReportSchemaVersionMatcher.new(
+ report_declared_version: report_version,
+ supported_versions: described_class::SUPPORTED_VERSIONS[report_type]
+ ).call
+ end
+
+ let(:message) do
+ "This report uses a supported MAJOR.MINOR schema version but the PATCH version doesn't match"\
+ " any vendored schema version. Validation will be attempted against version"\
+ " #{latest_patch_version}"
+ end
+
+ context 'and the report is valid' do
+ let(:report_data) do
+ {
+ 'version' => report_version,
+ 'vulnerabilities' => []
+ }
+ end
+
+ it { is_expected.to match_array([message]) }
+ end
+
+ context 'and the report is invalid' do
+ let(:report_data) do
+ {
+ 'version' => report_version
+ }
+ end
+
+ it { is_expected.to match_array([message]) }
+
+ it 'logs related information' do
+ expect(Gitlab::AppLogger).to receive(:info).with(
+ message: "security report schema validation problem",
+ security_report_type: report_type,
+ security_report_version: report_version,
+ project_id: project.id,
+ security_report_failure: 'schema_validation_fails',
+ security_report_scanner_id: 'gemnasium',
+ security_report_scanner_version: '2.1.0'
+ )
+
+ subject
+ end
+ end
+ end
+
context 'when given a supported schema version' do
let(:report_type) { :dast }
let(:report_version) { described_class::SUPPORTED_VERSIONS[report_type].last }
diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml
index 0d03f30a6d2..1a270fb8523 100644
--- a/spec/lib/gitlab/import_export/all_models.yml
+++ b/spec/lib/gitlab/import_export/all_models.yml
@@ -597,6 +597,7 @@ project:
- alert_management_alerts
- repository_storage_moves
- freeze_periods
+- pumble_integration
- webex_teams_integration
- build_report_results
- vulnerability_statistic
diff --git a/spec/lib/security/report_schema_version_matcher_spec.rb b/spec/lib/security/report_schema_version_matcher_spec.rb
new file mode 100644
index 00000000000..9c40f0bc6fa
--- /dev/null
+++ b/spec/lib/security/report_schema_version_matcher_spec.rb
@@ -0,0 +1,44 @@
+# frozen_string_literal: true
+require 'spec_helper'
+
+RSpec.describe Security::ReportSchemaVersionMatcher do
+ let(:vendored_versions) { %w[14.0.0 14.0.1 14.0.2 14.1.0] }
+ let(:version_finder) do
+ described_class.new(
+ report_declared_version: report_version,
+ supported_versions: vendored_versions
+ )
+ end
+
+ describe '#call' do
+ subject { version_finder.call }
+
+ context 'when minor version matches' do
+ context 'and report schema patch version does not match any vendored schema versions' do
+ context 'and report version is 14.1.1' do
+ let(:report_version) { '14.1.1' }
+
+ it 'returns 14.1.0' do
+ expect(subject).to eq('14.1.0')
+ end
+ end
+
+ context 'and report version is 14.0.32' do
+ let(:report_version) { '14.0.32' }
+
+ it 'returns 14.0.2' do
+ expect(subject).to eq('14.0.2')
+ end
+ end
+ end
+ end
+
+ context 'when report minor version does not match' do
+ let(:report_version) { '14.2.1' }
+
+ it 'does not return a version' do
+ expect(subject).to be_nil
+ end
+ end
+ end
+end
diff --git a/spec/models/integrations/pumble_spec.rb b/spec/models/integrations/pumble_spec.rb
new file mode 100644
index 00000000000..8b9b5d214c6
--- /dev/null
+++ b/spec/models/integrations/pumble_spec.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+require "spec_helper"
+
+RSpec.describe Integrations::Pumble do
+ it_behaves_like "chat integration", "Pumble" do
+ let(:client_arguments) { webhook_url }
+ let(:payload) do
+ {
+ text: be_present
+ }
+ end
+ end
+end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 05651f7d85a..e2911f2201e 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -44,6 +44,7 @@ RSpec.describe Project, factory_default: :keep do
it { is_expected.to have_one(:mattermost_integration) }
it { is_expected.to have_one(:hangouts_chat_integration) }
it { is_expected.to have_one(:unify_circuit_integration) }
+ it { is_expected.to have_one(:pumble_integration) }
it { is_expected.to have_one(:webex_teams_integration) }
it { is_expected.to have_one(:packagist_integration) }
it { is_expected.to have_one(:pushover_integration) }
diff --git a/spec/requests/api/integrations_spec.rb b/spec/requests/api/integrations_spec.rb
index b2db7f7caef..1e8061f9606 100644
--- a/spec/requests/api/integrations_spec.rb
+++ b/spec/requests/api/integrations_spec.rb
@@ -66,6 +66,7 @@ RSpec.describe API::Integrations do
mattermost: %i[deployment_channel labels_to_be_notified],
mock_ci: %i[enable_ssl_verification],
prometheus: %i[manual_configuration],
+ pumble: %i[branches_to_be_notified notify_only_broken_pipelines],
slack: %i[alert_events alert_channel deployment_channel labels_to_be_notified],
unify_circuit: %i[branches_to_be_notified notify_only_broken_pipelines],
webex_teams: %i[branches_to_be_notified notify_only_broken_pipelines]
diff --git a/vendor/gems/omniauth-cas3/omniauth-cas3.gemspec b/vendor/gems/omniauth-cas3/omniauth-cas3.gemspec
index 05b9115b596..abbcaa268d0 100644
--- a/vendor/gems/omniauth-cas3/omniauth-cas3.gemspec
+++ b/vendor/gems/omniauth-cas3/omniauth-cas3.gemspec
@@ -8,9 +8,8 @@ Gem::Specification.new do |gem|
gem.description = gem.summary
gem.homepage = "https://github.com/tduehr/omniauth-cas3"
- gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
- gem.files = `git ls-files`.split("\n")
- gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
+ gem.files = Dir.glob("lib/**/*.*")
+ gem.test_files = Dir.glob("spec/**/**/*.*")
gem.name = "omniauth-cas3"
gem.require_paths = ["lib"]
gem.version = Omniauth::Cas3::VERSION
diff --git a/yarn.lock b/yarn.lock
index 8820ef33e9d..a4083810bca 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1051,15 +1051,15 @@
stylelint-declaration-strict-value "1.8.0"
stylelint-scss "4.2.0"
-"@gitlab/svgs@2.33.0":
- version "2.33.0"
- resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-2.33.0.tgz#e970ae10ee558e1e2b01116b2fe6ea25161a4609"
- integrity sha512-8B5pGmZ6QnywxmWCmqMTkJfPlETbx4R7AK7si8Jf2DyWZ7Agfg9NOdgBq++IuiVjbxBO7VTQcZbVSavxrce6QA==
+"@gitlab/svgs@3.1.0":
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-3.1.0.tgz#0108498a17e2f79d16158015db0be764b406cc09"
+ integrity sha512-kZ45VTQOgLdwQCLRSj7+aohF+6AUnAaoucR1CFY/6DPDLnNNGeflwsCLN0sFBKwx42HLxFfNwvDmKOMLdSQg5A==
-"@gitlab/ui@42.25.0":
- version "42.25.0"
- resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-42.25.0.tgz#d79873347be9868c4d3d3123295ce1f12967f330"
- integrity sha512-yxSQeLbhrPD4KKQPCo+glarlhoa4cj46j7mgQtTRbJFw2ZWPcpJ4xuujCb8GoyGPlHpWaS8VJyv3l+hwBQs3qg==
+"@gitlab/ui@43.5.0":
+ version "43.5.0"
+ resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-43.5.0.tgz#c0652c99cd7ba9c69cef1cdf75c85b9164536e24"
+ integrity sha512-mbWXKylbnEuCXZuNMVic7K6Dvo8hjwYQkpyVvxdpmTCY+eTOtjxenVHE4HgZ5G/7cjznRnj4WLk0Ot8AquifBQ==
dependencies:
"@popperjs/core" "^2.11.2"
bootstrap-vue "2.20.1"
|