Projects
Mega:23.09
jackson-databind
Sign Up
Log In
Username
Password
We truncated the diff of some files because they were too big. If you want to see the full diff for every file,
click here
.
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 3
View file
_service:tar_scm:jackson-databind.spec
Changed
@@ -1,6 +1,6 @@ Name: jackson-databind Version: 2.9.8 -Release: 9 +Release: 10 Summary: General data-binding package for Jackson (2.x) License: ASL 2.0 and LGPLv2+ URL: https://github.com/FasterXML/jackson-databind/ @@ -48,6 +48,12 @@ Patch0039: CVE-2020-36183.patch Patch0040: CVE-2021-20190.patch Patch0041: CVE-2019-17531.patch +# https://github.com/FasterXML/jackson-databind/commit/fcfc4998ec23f0b1f7f8a9521c2b317b6c25892b +Patch0042: CVE-2020-36518.patch +# https://github.com/FasterXML/jackson-databind/commit/d78d00ee7b5245b93103fef3187f70543d67ca33 +Patch0043: CVE-2022-42003.patch +# https://github.com/FasterXML/jackson-databind/commit/063183589218fec19a9293ed2f17ec53ea80ba88 +Patch0044: CVE-2022-42004.patch BuildRequires: maven-local mvn(com.fasterxml.jackson.core:jackson-annotations) >= %{version} BuildRequires: mvn(com.fasterxml.jackson.core:jackson-core) >= %{version} @@ -100,6 +106,9 @@ %license LICENSE NOTICE %changelog +* Wed Dec 13 2023 yaoxin <yao_xin001@hoperun.com> - 2.9.8-10 +- Fix CVE-2020-36518,CVE-2022-42003 and CVE-2022-42004 + * Fri Mar 11 2022 yaoxin <yaoxin30@huawei.com> - 2.9.8-9 - Fix CVE-2019-17531
View file
_service:tar_scm:CVE-2020-36518.patch
Added
@@ -0,0 +1,346 @@ +From: Markus Koschany <apo@debian.org> +Date: Tue, 15 Nov 2022 12:51:57 +0100 +Subject: CVE-2020-36518 + +Bug-Debian: https://bugs.debian.org/1007109 +Origin: https://github.com/FasterXML/jackson-databind/commit/83b928dab9ba6ef81cf48987fcd12071e1ddb0c9 +Origin: https://github.com/FasterXML/jackson-databind/commit/fcfc4998ec23f0b1f7f8a9521c2b317b6c25892b +--- + .../deser/std/UntypedObjectDeserializer.java | 140 +++++++++++---------- + .../deser/DeepNestingUntypedDeserTest.java | 70 +++++++++++ + 2 files changed, 147 insertions(+), 63 deletions(-) + create mode 100644 src/test/java/com/fasterxml/jackson/databind/deser/DeepNestingUntypedDeserTest.java + +diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/UntypedObjectDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/UntypedObjectDeserializer.java +index 67be238..41f6dd9 100644 +--- a/src/main/java/com/fasterxml/jackson/databind/deser/std/UntypedObjectDeserializer.java ++++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/UntypedObjectDeserializer.java +@@ -220,10 +220,9 @@ public class UntypedObjectDeserializer + */ + @Override + public boolean isCachable() { +- /* 26-Mar-2015, tatu: With respect to databind#735, there are concerns over +- * cachability. It seems like we SHOULD be safe here; but just in case there +- * are problems with false sharing, this may need to be revisited. +- */ ++ // 26-Mar-2015, tatu: With respect to databind#735, there are concerns over ++ // cachability. It seems like we SHOULD be safe here; but just in case there ++ // are problems with false sharing, this may need to be revisited. + return true; + } + +@@ -266,9 +265,8 @@ public class UntypedObjectDeserializer + if (_numberDeserializer != null) { + return _numberDeserializer.deserialize(p, ctxt); + } +- /* Caller may want to get all integral values returned as {@link java.math.BigInteger}, +- * or {@link java.lang.Long} for consistency +- */ ++ // Caller may want to get all integral values returned as {@link java.math.BigInteger}, ++ // or {@link java.lang.Long} for consistency + if (ctxt.hasSomeOfFeatures(F_MASK_INT_COERCIONS)) { + return _coerceIntegral(p, ctxt); + } +@@ -599,10 +597,9 @@ public class UntypedObjectDeserializer + } + + /* +- /********************************************************** +- /* Separate "vanilla" implementation for common case of +- /* no custom deserializer overrides +- /********************************************************** ++ /********************************************************************** ++ /* Separate "vanilla" implementation for common case of no deser overrides ++ /********************************************************************** + */ + + @JacksonStdImpl +@@ -611,11 +608,13 @@ public class UntypedObjectDeserializer + { + private static final long serialVersionUID = 1L; + ++ // Arbitrarily chosen. ++ // Introduced to resolve CVE-2020-36518 and as a temporary hotfix for #2816 ++ private static final int MAX_DEPTH = 1000; ++ + public final static Vanilla std = new Vanilla(); + +- /** +- * @since 2.9 +- */ ++ // @since 2.9 + protected final boolean _nonMerging; + + public Vanilla() { this(false); } +@@ -639,65 +638,77 @@ public class UntypedObjectDeserializer + return _nonMerging ? Boolean.FALSE : null; + } + +- @Override +- public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException ++ @Override ++ public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { ++ return deserialize(p, ctxt, 0); ++ } ++ ++ private Object deserialize(JsonParser p, DeserializationContext ctxt, int depth) throws IOException + { +- switch (p.getCurrentTokenId()) { +- case JsonTokenId.ID_START_OBJECT: +- { ++ switch (p.currentTokenId()) { ++ case JsonTokenId.ID_START_OBJECT: { + JsonToken t = p.nextToken(); + if (t == JsonToken.END_OBJECT) { +- return new LinkedHashMap<String,Object>(2); ++ return new LinkedHashMap<String, Object>(2); + } + } +- case JsonTokenId.ID_FIELD_NAME: +- return mapObject(p, ctxt); +- case JsonTokenId.ID_START_ARRAY: +- { ++ case JsonTokenId.ID_FIELD_NAME: ++ if (depth > MAX_DEPTH) { ++ throw new JsonParseException(p, "JSON is too deeply nested."); ++ } ++ ++ return mapObject(p, ctxt, depth); ++ case JsonTokenId.ID_START_ARRAY: { + JsonToken t = p.nextToken(); + if (t == JsonToken.END_ARRAY) { // and empty one too +- if (ctxt.isEnabled(DeserializationFeature.USE_JAVA_ARRAY_FOR_JSON_ARRAY)) { ++ if (ctxt.isEnabled( ++ DeserializationFeature.USE_JAVA_ARRAY_FOR_JSON_ARRAY)) { + return NO_OBJECTS; + } + return new ArrayList<Object>(2); + } + } +- if (ctxt.isEnabled(DeserializationFeature.USE_JAVA_ARRAY_FOR_JSON_ARRAY)) { +- return mapArrayToArray(p, ctxt); +- } +- return mapArray(p, ctxt); +- case JsonTokenId.ID_EMBEDDED_OBJECT: +- return p.getEmbeddedObject(); +- case JsonTokenId.ID_STRING: +- return p.getText(); + +- case JsonTokenId.ID_NUMBER_INT: +- if (ctxt.hasSomeOfFeatures(F_MASK_INT_COERCIONS)) { +- return _coerceIntegral(p, ctxt); ++ if (depth > MAX_DEPTH) { ++ throw new JsonParseException(p, "JSON is too deeply nested."); + } +- return p.getNumberValue(); // should be optimal, whatever it is + +- case JsonTokenId.ID_NUMBER_FLOAT: +- if (ctxt.isEnabled(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS)) { +- return p.getDecimalValue(); ++ if (ctxt.isEnabled(DeserializationFeature.USE_JAVA_ARRAY_FOR_JSON_ARRAY)) { ++ return mapArrayToArray(p, ctxt, depth); + } +- return p.getNumberValue(); ++ return mapArray(p, ctxt, depth); ++ case JsonTokenId.ID_EMBEDDED_OBJECT: ++ return p.getEmbeddedObject(); ++ case JsonTokenId.ID_STRING: ++ return p.getText(); ++ ++ case JsonTokenId.ID_NUMBER_INT: ++ if (ctxt.hasSomeOfFeatures(F_MASK_INT_COERCIONS)) { ++ return _coerceIntegral(p, ctxt); ++ } ++ return p.getNumberValue(); // should be optimal, whatever it is + +- case JsonTokenId.ID_TRUE: +- return Boolean.TRUE; +- case JsonTokenId.ID_FALSE: +- return Boolean.FALSE; ++ case JsonTokenId.ID_NUMBER_FLOAT: ++ if (ctxt.isEnabled(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS)) { ++ return p.getDecimalValue(); ++ } ++ return p.getNumberValue(); + +- case JsonTokenId.ID_END_OBJECT: +- // 28-Oct-2015, tatu: databind#989 We may also be given END_OBJECT (similar to FIELD_NAME), +- // if caller has advanced to the first token of Object, but for empty Object +- return new LinkedHashMap<String,Object>(2); ++ case JsonTokenId.ID_TRUE: ++ return Boolean.TRUE; ++ case JsonTokenId.ID_FALSE: ++ return Boolean.FALSE; + +- case JsonTokenId.ID_NULL: // 08-Nov-2016, tatu: yes, occurs +- return null; ++ case JsonTokenId.ID_END_OBJECT: ++ // 28-Oct-2015, tatu: databind#989 We may also be given END_OBJECT (similar to FIELD_NAME), ++ // if caller has advanced to the first token of Object, but for empty Object ++ return new LinkedHashMap<String, Object>(2); + +- //case JsonTokenId.ID_END_ARRAY: // invalid +- default: ++ case JsonTokenId.ID_NULL: // 08-Nov-2016, tatu: yes, occurs ++ return null; ++ ++ //case JsonTokenId.ID_END_ARRAY: // invalid ++ default: + } + return ctxt.handleUnexpectedToken(Object.class, p); + } +@@ -806,15 +817,16 @@ public class UntypedObjectDeserializer + return deserialize(p, ctxt); + } + +- protected Object mapArray(JsonParser p, DeserializationContext ctxt) throws IOException ++ protected Object mapArray(JsonParser p, DeserializationContext ctxt, int depth) throws IOException + { +- Object value = deserialize(p, ctxt);
View file
_service:tar_scm:CVE-2022-42003.patch
Added
@@ -0,0 +1,230 @@ +From: Markus Koschany <apo@debian.org> +Date: Mon, 14 Nov 2022 22:40:03 +0100 +Subject: CVE-2022-42003 + +Origin: https://github.com/FasterXML/jackson-databind/commit/d78d00ee7b5245b93103fef3187f70543d67ca33 + +--- + .../databind/deser/std/StdDeserializer.java | 48 ++++++++--- + .../dos/DeepArrayWrappingForDeser3590Test.java | 93 ++++++++++++++++++++++ + 2 files changed, 129 insertions(+), 12 deletions(-) + create mode 100644 src/test/java/com/fasterxml/jackson/databind/deser/dos/DeepArrayWrappingForDeser3590Test.java + +diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/StdDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/StdDeserializer.java +index 9a6f482..cf46afc 100644 +--- a/src/main/java/com/fasterxml/jackson/databind/deser/std/StdDeserializer.java ++++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/StdDeserializer.java +@@ -178,7 +178,9 @@ public abstract class StdDeserializer<T> + } + // databind#381 + if (t == JsonToken.START_ARRAY && ctxt.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)) { +- p.nextToken(); ++ if (p.nextToken() == JsonToken.START_ARRAY) { ++ return (boolean) handleNestedArrayForSingle(p, ctxt); ++ } + final boolean parsed = _parseBooleanPrimitive(p, ctxt); + _verifyEndArrayForSingle(p, ctxt); + return parsed; +@@ -250,7 +252,9 @@ public abstract class StdDeserializer<T> + return 0; + case JsonTokenId.ID_START_ARRAY: + if (ctxt.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)) { +- p.nextToken(); ++ if (p.nextToken() == JsonToken.START_ARRAY) { ++ return (int) handleNestedArrayForSingle(p, ctxt); ++ } + final int parsed = _parseIntPrimitive(p, ctxt); + _verifyEndArrayForSingle(p, ctxt); + return parsed; +@@ -310,7 +314,9 @@ public abstract class StdDeserializer<T> + return 0L; + case JsonTokenId.ID_START_ARRAY: + if (ctxt.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)) { +- p.nextToken(); ++ if (p.nextToken() == JsonToken.START_ARRAY) { ++ return (long) handleNestedArrayForSingle(p, ctxt); ++ } + final long parsed = _parseLongPrimitive(p, ctxt); + _verifyEndArrayForSingle(p, ctxt); + return parsed; +@@ -356,7 +362,9 @@ public abstract class StdDeserializer<T> + return 0.0f; + case JsonTokenId.ID_START_ARRAY: + if (ctxt.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)) { +- p.nextToken(); ++ if (p.nextToken() == JsonToken.START_ARRAY) { ++ return (float) handleNestedArrayForSingle(p, ctxt); ++ } + final float parsed = _parseFloatPrimitive(p, ctxt); + _verifyEndArrayForSingle(p, ctxt); + return parsed; +@@ -417,7 +425,9 @@ public abstract class StdDeserializer<T> + return 0.0; + case JsonTokenId.ID_START_ARRAY: + if (ctxt.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)) { +- p.nextToken(); ++ if (p.nextToken() == JsonToken.START_ARRAY) { ++ return (double) handleNestedArrayForSingle(p, ctxt); ++ } + final double parsed = _parseDoublePrimitive(p, ctxt); + _verifyEndArrayForSingle(p, ctxt); + return parsed; +@@ -498,6 +508,9 @@ public abstract class StdDeserializer<T> + } + } + if (ctxt.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)) { ++ if (t == JsonToken.START_ARRAY) { ++ return (java.util.Date) handleNestedArrayForSingle(p, ctxt); ++ } + final Date parsed = _parseDate(p, ctxt); + _verifyEndArrayForSingle(p, ctxt); + return parsed; +@@ -662,11 +675,11 @@ public abstract class StdDeserializer<T> + } + } + if (ctxt.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)) { +- final T parsed = deserialize(p, ctxt); ++ final T parsed = _deserializeWrappedValue(p, ctxt); + if (p.nextToken() != JsonToken.END_ARRAY) { + handleMissingEndArrayForSingle(p, ctxt); + } +- return parsed; ++ return parsed; + } + } else { + t = p.getCurrentToken(); +@@ -689,12 +702,8 @@ public abstract class StdDeserializer<T> + // 23-Mar-2017, tatu: Let's specifically block recursive resolution to avoid + // either supporting nested arrays, or to cause infinite looping. + if (p.hasToken(JsonToken.START_ARRAY)) { +- String msg = String.format( +-"Cannot deserialize instance of %s out of %s token: nested Arrays not allowed with %s", +- ClassUtil.nameOf(_valueClass), JsonToken.START_ARRAY, +- "DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS"); + @SuppressWarnings("unchecked") +- T result = (T) ctxt.handleUnexpectedToken(_valueClass, p.getCurrentToken(), p, msg); ++ T result = (T) handleNestedArrayForSingle(p, ctxt); + return result; + } + return (T) deserialize(p, ctxt); +@@ -1169,6 +1178,21 @@ handledType().getName()); + // but for now just fall through + } + ++ /** ++ * Helper method called when detecting a deep(er) nesting of Arrays when trying ++ * to unwrap value for {@code DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS}. ++ * ++ * @since 2.14 ++ */ ++ protected Object handleNestedArrayForSingle(JsonParser p, DeserializationContext ctxt) throws IOException ++ { ++ String msg = String.format( ++"Cannot deserialize instance of %s out of %s token: nested Arrays not allowed with %s", ++ ClassUtil.nameOf(_valueClass), JsonToken.START_ARRAY, ++ "DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS"); ++ return ctxt.handleUnexpectedToken(_valueClass, p.currentToken(), p, msg); ++ } ++ + protected void _verifyEndArrayForSingle(JsonParser p, DeserializationContext ctxt) throws IOException + { + JsonToken t = p.nextToken(); +diff --git a/src/test/java/com/fasterxml/jackson/databind/deser/dos/DeepArrayWrappingForDeser3590Test.java b/src/test/java/com/fasterxml/jackson/databind/deser/dos/DeepArrayWrappingForDeser3590Test.java +new file mode 100644 +index 0000000..8dfddcc +--- /dev/null ++++ b/src/test/java/com/fasterxml/jackson/databind/deser/dos/DeepArrayWrappingForDeser3590Test.java +@@ -0,0 +1,93 @@ ++package com.fasterxml.jackson.databind.deser.dos; ++ ++import java.util.Date; ++ ++import com.fasterxml.jackson.databind.*; ++import com.fasterxml.jackson.databind.exc.MismatchedInputException; ++ ++public class DeepArrayWrappingForDeser3590Test extends BaseMapTest ++{ ++ // 05-Sep-2022, tatu: Before fix, failed with 5000 ++ private final static int TOO_DEEP_NESTING = 9999; ++ ++ private final static String TOO_DEEP_DOC = _nestedDoc(TOO_DEEP_NESTING, " ", " ", "123"); ++ ++ public void testArrayWrappingForBoolean() throws Exception ++ { ++ _testArrayWrappingFor(Boolean.class); ++ _testArrayWrappingFor(Boolean.TYPE); ++ } ++ ++ public void testArrayWrappingForByte() throws Exception ++ { ++ _testArrayWrappingFor(Byte.class); ++ _testArrayWrappingFor(Byte.TYPE); ++ } ++ ++ public void testArrayWrappingForShort() throws Exception ++ { ++ _testArrayWrappingFor(Short.class); ++ _testArrayWrappingFor(Short.TYPE); ++ } ++ ++ public void testArrayWrappingForInt() throws Exception ++ { ++ _testArrayWrappingFor(Integer.class); ++ _testArrayWrappingFor(Integer.TYPE); ++ } ++ ++ public void testArrayWrappingForLong() throws Exception ++ { ++ _testArrayWrappingFor(Long.class); ++ _testArrayWrappingFor(Long.TYPE); ++ } ++ ++ public void testArrayWrappingForFloat() throws Exception ++ { ++ _testArrayWrappingFor(Float.class); ++ _testArrayWrappingFor(Float.TYPE); ++ } ++ ++ public void testArrayWrappingForDouble() throws Exception ++ { ++ _testArrayWrappingFor(Double.class); ++ _testArrayWrappingFor(Double.TYPE); ++ } ++ ++ public void testArrayWrappingForDate() throws Exception ++ { ++ _testArrayWrappingFor(Date.class); ++ } ++ ++ private void _testArrayWrappingFor(Class<?> cls) throws Exception
View file
_service:tar_scm:CVE-2022-42004.patch
Added
@@ -0,0 +1,78 @@ +From: Markus Koschany <apo@debian.org> +Date: Mon, 14 Nov 2022 22:40:58 +0100 +Subject: CVE-2022-42004 + +Origin: https://github.com/FasterXML/jackson-databind/commit/063183589218fec19a9293ed2f17ec53ea80ba88 +--- + .../databind/deser/BeanDeserializerBase.java | 6 +-- + .../dos/DeepArrayWrappingForDeser3582Test.java | 44 ++++++++++++++++++++++ + 2 files changed, 47 insertions(+), 3 deletions(-) + create mode 100644 src/test/java/com/fasterxml/jackson/databind/deser/dos/DeepArrayWrappingForDeser3582Test.java + +diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializerBase.java b/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializerBase.java +index 6ce41f7..639d8c9 100644 +--- a/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializerBase.java ++++ b/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializerBase.java +@@ -1440,9 +1440,9 @@ public abstract class BeanDeserializerBase + return bean; + } + if (ctxt.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)) { +- JsonToken t = p.nextToken(); +- if (t == JsonToken.END_ARRAY && ctxt.isEnabled(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT)) { +- return null; ++ if (p.nextToken() == JsonToken.START_ARRAY) { ++ return ctxt.handleUnexpectedToken(handledType(), JsonToken.START_ARRAY, p, ++"Cannot deserialize value of type %s from deeply-nested JSON Array: only single wrapper allowed with DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS"); + } + final Object value = deserialize(p, ctxt); + if (p.nextToken() != JsonToken.END_ARRAY) { +diff --git a/src/test/java/com/fasterxml/jackson/databind/deser/dos/DeepArrayWrappingForDeser3582Test.java b/src/test/java/com/fasterxml/jackson/databind/deser/dos/DeepArrayWrappingForDeser3582Test.java +new file mode 100644 +index 0000000..2147cf1 +--- /dev/null ++++ b/src/test/java/com/fasterxml/jackson/databind/deser/dos/DeepArrayWrappingForDeser3582Test.java +@@ -0,0 +1,44 @@ ++package com.fasterxml.jackson.databind.deser.dos; ++ ++import java.io.IOException; ++import com.fasterxml.jackson.databind.*; ++ ++public class DeepArrayWrappingForDeser3582Test extends BaseMapTest ++{ ++ // 23-Aug-2022, tatu: Before fix, failed with 5000 ++ private final static int TOO_DEEP_NESTING = 9999; ++ ++ public void testArrayWrapping() throws Exception ++ { ++ final String doc = _nestedDoc(TOO_DEEP_NESTING, " ", " ", "{}"); ++ final ObjectMapper MAPPER = new ObjectMapper(); ++ MAPPER.enable(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS); ++ try { ++ MAPPER.readValue(doc, Point.class); ++ fail("Should not pass"); ++ } catch (IOException e) { ++ verifyException(e, "Cannot deserialize"); ++ verifyException(e, "nested JSON Array"); ++ verifyException(e, "only single"); ++ } ++ } ++ ++ private String _nestedDoc(int nesting, String open, String close, String content) { ++ StringBuilder sb = new StringBuilder(nesting * (open.length() + close.length())); ++ for (int i = 0; i < nesting; ++i) { ++ sb.append(open); ++ if ((i & 31) == 0) { ++ sb.append("\n"); ++ } ++ } ++ sb.append("\n").append(content).append("\n"); ++ for (int i = 0; i < nesting; ++i) { ++ sb.append(close); ++ if ((i & 31) == 0) { ++ sb.append("\n"); ++ } ++ } ++ return sb.toString(); ++ } ++ ++}
View file
_service
Changed
@@ -2,7 +2,7 @@ <service name="tar_scm"> <param name="url">git@gitee.com:src-openeuler/jackson-databind.git</param> <param name="scm">git</param> - <param name="revision">openEuler-23.09</param> + <param name="revision">master</param> <param name="exclude">*</param> <param name="extract">*</param> </service>
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.
浙ICP备2022010568号-2