מדיניות SOAPMessageValidation

מדיניות רגילה

הדף הזה רלוונטי ל-Apigee ול-Apigee Hybrid.

לעיון במסמכי התיעוד של Apigee Edge

המדיניות SOAPMessageValidation מבצעת את הפעולות הבאות:

  • מאמת כל הודעת XML מול סכימות ה-XSD שלה
  • אימות של הודעות SOAP מול הגדרת WSDL
  • קובע אם הודעות JSON ו-XML הן בפורמט תקין

למרות שהשם של המדיניות הזו בממשק המשתמש הוא SOAPMessageValidation, המדיניות מאמתת יותר מסתם הודעות SOAP. בקטע הזה, המדיניות נקראת MessageValidation policy.

אימות ההודעות מספק את היתרונות הבאים:

  • מודיע באופן מיידי למפתחי אפליקציות שמשתמשים ב-API שלכם אם הבקשות שלהם לא תואמות או לא מלאות.
  • מציין בעיות בבקשות, כמו תגי XML שלא נסגרו בצורה תקינה.
  • הגנה על שירותי קצה עורפי על ידי חסימת הודעות XML או SOAP עם מבנים שעלולים לגרום להתנהגות בלתי צפויה.
  • קיצור הזמן שמוקדש לפתרון בעיות, לחיפוש בפורומים או להתייעצות עם תמיכה טכנית.
  • מעודד מפתחים להכיר את הגדרת סכימת ה-XML של WSDL כדי למנוע שגיאות אימות, ולכן סכימות XML מובנות היטב הן רכיב מרכזי במאמרי העזרה של ה-API.

המדיניות הזו היא מדיניות רגילה ואפשר לפרוס אותה בכל סוג של סביבה. מידע על סוגי המדיניות והזמינות שלהם בכל סוג סביבה זמין במאמר סוגי מדיניות.

סרטונים

כדי לקבל מידע נוסף על מדיניות MessageValidation, כדאי לצפות בסרטונים הבאים:

וידאו תיאור
אימות בקשת XML כדי לאמת בקשת XML עבור API, משתמשים במדיניות MessageValidation.
אימות בקשת JSON כדי לאמת בקשת JSON ל-API, משתמשים במדיניות MessageValidation.

רכיב <MessageValidation>

הגדרת המדיניות MessageValidation.

ערך ברירת המחדל מידע נוסף מופיע בכרטיסייה מדיניות ברירת המחדל שבהמשך.
חובה? אופציונלי
סוג אובייקט מורכב
רכיב אב לא רלוונטי
רכיבי צאצא <DisplayName>
<Element>
<ResourceURL>
<SOAPMessage>
<Source>

תחביר

רכיב <MessageValidation> משתמש בתחביר הבא:

<MessageValidation
  continueOnError="[false|true]"
  enabled="[true|false]"
  name="policy_name"
>
    <!-- All MessageValidation child elements are optional -->
    <DisplayName>policy_display_name</DisplayName>
    <Element namespace="element_namespace">element_to_validate</Element>
    <SOAPMessage version="[ 1.1 | 1.2 | 1.1/1.2 ]"/>
    <Source>message_to_validate</Source>
    <ResourceURL>validation_WSDL_or_XSD</ResourceURL>

</MessageValidation>

מדיניות ברירת המחדל

בדוגמה הבאה מוצגות הגדרות ברירת המחדל כשמוסיפים מדיניות MessageValidation לתהליך בממשק המשתמש של Apigee:

<MessageValidation continueOnError="false" enabled="true" name="SOAP-Message-Validation-1">
  <DisplayName>SOAP Message Validation-1</DisplayName>
  <Properties/>
  <Element namespace="http://sample.com">sampleObject</Element>
  <SOAPMessage/>
  <Source>request</Source>
  <ResourceURL>wsdl://SOAP-Message-Validation-1.wsdl</ResourceURL>
</MessageValidation>

此元素具有所有政策中常见的以下属性:

属性 默认 是否必需? 说明
name 不适用 必需

政策的内部名称。name 属性的值可以包含字母、数字、空格、连字符、下划线和英文句点。此值不能超过 255 个字符。

(可选)使用 <DisplayName> 元素在管理界面代理编辑器中给政策添加不同的自然语言名称标签。

continueOnError false 可选 设置为 false 可在政策失败时返回错误。这是大多数政策的预期行为。设置为 true,即使在政策失败后,仍可以继续执行流。另请参阅:
enabled true 可选 设置为 true 可实施政策。 设为 false 可关闭政策。即使政策仍附加到某个流,也不会强制执行该政策。
async   false 已弃用 此属性已弃用。

דוגמאות

בדוגמאות הבאות אפשר לראות כמה מהדרכים שבהן אפשר להשתמש במדיניות MessageValidation:

‫1: אימות XSD

אפשר להשתמש במדיניות של אימות הודעות כדי לאמת את מטען הייעודי (payload) של בקשת הודעת XML מול סכימת XSD.

  1. יוצרים קובץ משאבים חדש מסוג XSD. לדוגמה, note-schema.xsd:
    <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
      <xs:element name="note">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="to" type="xs:string"/>
            <xs:element name="from" type="xs:string"/>
            <xs:element name="heading" type="xs:string"/>
            <xs:element name="body" type="xs:string"/>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
    </xs:schema>
  2. מוסיפים את מדיניות האימות של הודעות SOAP ל-pre-flow של נקודת הקצה של ה-proxy:
    1. מציינים את המיקום של קובץ משאבי ה-XSD באמצעות הרכיב <ResourceURL>. לדוגמה:
      ...
        <ResourceURL>xsd://note-schema.xsd</ResourceURL>
      ...
    2. מסירים את הרכיבים <SOAPMessage> ו-<Element> מהגדרת המדיניות.

    הגדרת המדיניות צריכה להיראות כך:

    <MessageValidation continueOnError="false"
        enabled="true" name="validateXMLRequest">
      <DisplayName>My XML Validator</DisplayName>
      <Properties/>
      <Source>request</Source>
      <ResourceURL>xsd://note-schema.xsd</ResourceURL>
    </MessageValidation>
  3. שולחים בקשת POST ל-proxy ל-API עם ה-XML בתור המטען הייעודי (payload) של ההודעה, כמו בדוגמה הבאה:
    curl -v -X POST -H 'Content-Type: application/xml' http://my-test.apigee.net/v1/xsd-mock
      -d '<note>
      <to>Fred Rogers</to>
      <from>Nick Danger</from>
      <heading>Greetings from my neighborhood</heading>
      <body>Just writing to say hello.</body>
    </note>'

    שימו לב שהכותרת Content-type מוגדרת ל-application/xml.

    אפשר גם ליצור קובץ נתונים בשביל המטען הייעודי (payload) ולהפנות אליו באמצעות פקודה שדומה לפקודה הבאה:

    curl -v -X POST -H 'Content-type: application/xml' http://my-test.apigee.net/v1/xsd-mock
      --data '@../examples/note-payload.xml'

אמורה להתקבל תגובה HTTP 200. בהתאם לנקודת הקצה של היעד, יכול להיות שתקבלו פרטים נוספים על הבקשה. לדוגמה, אם משתמשים ב-http://httpbin.org/post כנקודת הקצה של היעד ומציינים פלט -v (מפורט), התגובה אמורה להיות דומה לזו:

< HTTP/1.1 200 OK
< Date: Wed, 16 May 2018 21:24:54 GMT
< Content-Type: application/xml
< Content-Length: 431
< Connection: keep-alive
< Server: gunicorn/19.8.1
< Access-Control-Allow-Origin: *
< Access-Control-Allow-Credentials: true
< Via: 1.1 vegur
{
  "args":{},
  "data":"<note><to>fred</to><from>nick</from><heading>hello</heading>
    <body>Just writing to say hello.</body></note>",
  "files":{},
  "form":{},
  "headers": {
    "Accept":"*/*",
    "Connection":"close",
    "Content-Length":"106",
    "Content-Type":"application/xml",
    "Host":"httpbin.org",
    "User-Agent":"curl/7.58.0"
  },
  "json":null,
  "origin":"10.1.1.1, 104.154.179.1",
  "url":"http://httpbin.org/post"
}

כדי לוודא שאימות ה-XSD פועל, נסו להוסיף עוד תג לגוף הבקשה. לדוגמה:

curl -v -X POST -H 'Content-Type: application/xml' http://my-test.apigee.net/v1/xsd-mock
  -d '<note>
  <to>Fred Rogers</to>
  <from>Nick Danger</from>
  <heading>Greetings from my neighborhood</heading>
  <body>Just writing to say hello.</body>
  <badTag>Not good</badTag>
</note>'

אמורה להופיע שגיאת אימות.

‫2: אימות SOAP

אפשר להשתמש במדיניות Message Validation כדי לאמת את מטען הייעודי (payload) של בקשת הודעת SOAP מול WSDL.

  1. יוצרים קובץ משאבים חדש של WSDL. לדוגמה, "example-wsdl.wsdl":
  2. מוסיפים את מדיניות האימות של הודעות SOAP ל-pre-flow של נקודת הקצה של ה-proxy:
    1. מגדירים את מאפיין version של רכיב <SOAPMessage> לגרסה של פרוטוקול SOAP שרוצים לבצע אימות מולה. לדוגמה, ‎"1.1":
      ...
        <SOAPMessage version="1.1"/>
      ...
    2. מגדירים את הערך של רכיב <Element> לרכיב שרוצים לאמת:
      ...
        <Element namespace="https://example.com/gateway">getID</Element>
      ...

      ‫<Element> מציין את הצאצא הראשון באלמנט <Body> במעטפה של בקשת SOAP.

      מגדירים את מאפיין namespace למרחב השמות של הנכס המשני.

    3. מציינים את המיקום של קובץ משאב ה-WSDL באמצעות הרכיב <ResourceURL>. לדוגמה:
      ...
        <ResourceURL>wsdl://example-wsdl.wsdl</ResourceURL>
      ...

    הגדרת המדיניות צריכה להיראות כך:

    <MessageValidation continueOnError="false"
        enabled="true" name="validateSOAPRequest">
      <DisplayName>My SOAP Validator</DisplayName>
      <Properties/>
      <Source>request</Source>
      <SOAPMessage version="1.1"/>
      <Element namespace="https://example.com/gateway">getID</Element>
      <ResourceURL>wsdl://example-wsdl.wsdl</ResourceURL>
    </MessageValidation>
  3. שולחים בקשת POST ל-proxy ל-API עם מעטפת ה-SOAP כמטען הייעודי (payload) של ההודעה, כמו בדוגמה הבאה:
    curl -v -X POST -H 'Content-Type: application/xml' http://my-test.apigee.net/v1/xsd-mock
      -d '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
        xmlns:prox="https://example.com/gateway" xmlns:typ="https://example.com/gateway/types">
      <soapenv:Header/>
      <soapenv:Body>
        <prox:getID>
          <typ:MyType>
            <typ:ID>42</typ:ID>
          </typ:MyType>
        </prox:getID>
      </soapenv:Body>
    </soapenv:Envelope>'

    שימו לב שהכותרת Content-type מוגדרת לערך application/xml.

    אפשר גם ליצור קובץ נתונים בשביל המטען הייעודי (payload) ולהפנות אליו באמצעות פקודה שדומה לפקודה הבאה:

    curl -v -X POST -H 'Content-type: application/xml' http://my-test.apigee.net/v1/xsd-mock
      --data '@../examples/soap-payload.xml'

אמורה להתקבל תגובה HTTP 200. בהתאם לנקודת הקצה של היעד, יכול להיות שתקבלו פרטים נוספים על הבקשה. לדוגמה, אם משתמשים ב-http://httpbin.org/post כנקודת הקצה לטירגוט, התגובה צריכה להיות דומה לזו:

< HTTP/1.1 200 OK
< Date: Wed, 16 May 2018 21:24:54 GMT
< Content-Type: application/xml
< Content-Length: 431
< Connection: keep-alive
< Server: gunicorn/19.8.1
< Access-Control-Allow-Origin: *
< Access-Control-Allow-Credentials: true
< Via: 1.1 vegur
{
  "args":{},
  "data":"<note><to>fred</to><from>nick</from><heading>hello</heading>
    <body>Just writing to say hello.</body></note>",
  "files":{},
  "form":{},
  "headers": {
    "Accept":"*/*",
    "Connection":"close",
    "Content-Length":"106",
    "Content-Type":"application/xml",
    "Host":"httpbin.org",
    "User-Agent":"curl/7.58.0"
  },
  "json":null,
  "origin":"10.1.1.1, 104.154.179.1",
  "url":"http://httpbin.org/post"
}

‫3: XML/JSON תקין

אתם יכולים להשתמש במדיניות של אימות הודעות כדי לוודא שמטען ייעודי (payload) של הודעת JSON או XML הוא בפורמט תקין (לא מדובר באימות). המדיניות מבטיחה שהמבנה והתוכן יעמדו בסטנדרטים המקובלים, כולל:

  • יש רכיב בסיס יחיד
  • התוכן לא מכיל תווים לא חוקיים
  • האובייקטים והתגים מוטמעים בצורה נכונה
  • תגי הפתיחה והסגירה זהים

כדי לבדוק אם מטען ייעודי (payload) של XML או JSON מעוצב בצורה תקינה:

  1. מוסיפים את מדיניות האימות של הודעות SOAP ל-pre-flow של נקודת הקצה של ה-proxy.
  2. מסירים את הרכיבים <ResourceURL>, <SOAPMessage> ו-<Element> מהגדרת המדיניות.

    הגדרת המדיניות צריכה להיראות כך:

    <MessageValidation async="false" continueOnError="false"
        enabled="true" name="validateXMLRequest">
      <DisplayName>My JSON Checker</DisplayName>
      <Properties/>
      <Source>request</Source>
    </MessageValidation>
  3. שולחים בקשת POST ל-proxy ל-API, כמו בדוגמה הבאה:
    curl -v -X POST -H 'Content-Type: application/json' http://my-test.apigee.net/v1/xsd-mock
      -d '{
    "note": {
      "to": "Fred Rogers",
      "from": "Nick Danger",
      "header": "Greetings from my neighborhood",
      "body": "Just writing to say hello."
      }
    }'

    שימו לב שהכותרת Content-type מוגדרת ל-application/json.

    כדי לבדוק אם קובץ XML בנוי בצורה תקינה, משתמשים ב-XML כמטען הייעודי (payload) של ההודעה ומגדירים את Content-type לערך application/xml.

אמורה להתקבל תגובה HTTP 200. כששולחים מטען ייעודי (payload) של הודעה שלא מכיל XML או JSON בפורמט תקין, אמורה להתקבל שגיאת steps.messagevalidation.Failed.

הפניה לרכיב צאצא

בקטע הזה מתוארים רכיבי הבן של <MessageValidation>.

<DisplayName>

אפשר להשתמש במאפיין הזה בנוסף למאפיין name כדי לתת למדיניות שם אחר, שנשמע יותר טבעי, ב-UI של עורך ה-proxy לניהול.

הרכיב <DisplayName> משותף לכל סוגי המדיניות.

ערך ברירת המחדל לא רלוונטי
חובה? זה שינוי אופציונלי. אם לא מציינים את <DisplayName>, המערכת משתמשת בערך של מאפיין name של המדיניות.
סוג String
רכיב אב <PolicyElement>
רכיבי צאצא ללא

רכיב <DisplayName> משתמש בתחביר הבא:

תחביר

<PolicyElement>
  <DisplayName>POLICY_DISPLAY_NAME</DisplayName>
  ...
</PolicyElement>

דוגמה

<PolicyElement>
  <DisplayName>My Validation Policy</DisplayName>
</PolicyElement>

לרכיב <DisplayName> אין מאפיינים או רכיבי צאצא.

<Element>

מציינים את הרכיב בהודעה שרוצים לאמת. זהו רכיב הצאצא הראשון מתחת לאלמנט <Body> במעטפה של בקשת ה-SOAP.

ערך ברירת המחדל sampleObject
חובה? אופציונלי
סוג String
רכיב אב <MessageValidation>
רכיבי צאצא ללא

רכיב <Element> משתמש בתחביר הבא:

תחביר

...
  <Element namespace="element_namespace">element_to_validate</Element>
...

דוגמה 1

בדוגמה הבאה מוגדר רכיב יחיד לאימות:

...
<Element namespace="https://example.com/gateway">getID</Element>
...

דוגמה 2

אפשר לציין יותר מרכיב אחד לאימות על ידי הוספה של כמה רכיבי <Element>:

...
<Element namespace="https://example.com/gateway">getID</Element>
<Element namespace="https://example.com/gateway">getDetails</Element>
...

לרכיב <Element> יש את המאפיינים הבאים:

מאפיין ברירת מחדל חובה? תיאור
namespace ‪"http://sample.com" אופציונלי המאפיין מגדיר את מרחב השמות של הרכיב שצריך לאמת.

<ResourceURL>

מציין את סכימת ה-XSD או את הגדרת ה-WSDL שישמשו לאימות הודעת המקור.

ערך ברירת המחדל wsdl://display_name.wsdl
חובה? אופציונלי
סוג String
רכיב אב <MessageValidation>
רכיבי צאצא ללא

רכיב <ResourceURL> משתמש בתחביר הבא:

תחביר

...
  <ResourceURL>[wsdl|xsd]://validation_WSDL_or_XSD</ResourceURL>
...

דוגמאות

לקובץ XML:

...
<ResourceURL>xsd://note-schema.xsd</ResourceURL>
...

ל-WSDL:

...
<ResourceURL>wsdl://example-wsdl.wsdl</ResourceURL>
...

הערך של <ResourceURL> צריך להפנות אל קובץ משאבים ב-proxy ל-API. אי אפשר להפנות למשאבים חיצוניים באמצעות HTTP או HTTPS.

אם לא מציינים ערך ל-<ResourceURL>, המערכת בודקת אם ההודעה היא בפורמט JSON תקין או בפורמט XML תקין, בהתאם לערך של הכותרת Content-type: application/json או application/xml.

לרכיב <ResourceURL> אין רכיבי צאצא או מאפיינים.

שימוש ב-XSD לאימות

אם מטען ה-XML שאתם מאמתים באמצעות מדיניות MessageValidation מפנה לסכימה אחרת, אתם צריכים להוסיף את הקידומת xsd לקובץ ה-XSD הכלול במאפיין schemaLocation.

סכימת הדוגמה הבאה מורכבת מכמה קובצי XSD:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
    elementFormDefault="qualified" attributeFormDefault="unqualified">
  <xs:include schemaLocation="xsd://note-schema.xsd"/>
  <xs:include schemaLocation="xsd://letter-schema.xsd"/>
  <xs:include schemaLocation="xsd://user-schema.xsd"/>
</xs:schema>

שימוש בקובצי WSDL לאימות

קובץ WSDL חייב להגדיר סכימה אחת לפחות. אם הוא לא מפנה לסכימה אחת לפחות, המדיניות MessageValidation נכשלת.

עומק הייבוא המקסימלי של סכימה הוא 10. אם חורגים ממספר הייבוא המקסימלי, המדיניות MessageValidation נכשלת.

<SOAPMessage>

ההגדרה הזו מגדירה את גרסת ה-SOAP שבה המדיניות MessageValidation מאמתת.

ערך ברירת המחדל לא רלוונטי
חובה? אופציונלי
סוג לא רלוונטי
רכיב אב <MessageValidation>
רכיבי צאצא ללא

רכיב <SOAPMessage> משתמש בתחביר הבא:

תחביר

...
  <SOAPMessage version="[ 1.1 | 1.2 | 1.1/1.2 ]"/>
...

דוגמה

...
<SOAPMessage version="1.1"/>
...

לרכיב <SOAPMessage> יש את המאפיינים הבאים:

מאפיין ברירת מחדל חובה? תיאור
version ללא אופציונלי גרסת ה-SOAP שבה המדיניות הזו משתמשת כדי לאמת הודעות SOAP.

הערכים החוקיים הם:

  • ‫"1.1"
  • ‫"1.2"
  • ‪"1.1/1.2"

מידע נוסף זמין במאמר From SOAP/1.1 to SOAP Version 1.2 in 9 points (מ-SOAP/1.1 ל-SOAP גרסה 1.2 ב-9 נקודות).

<Source>

מזהה את הודעת המקור שצריך לאמת. הערך של הרכיב הזה הוא שם ההודעה שרוצים לאמת.

אם לא מגדירים את <Source>, מדיניות ברירת המחדל היא message, שמתייחסת להודעת הבקשה המלאה (בתהליך בקשה) או להודעת התשובה (בתהליך תשובה), כולל מטען ייעודי כלשהו. אפשר גם להגדיר אותו באופן מפורש ל-request או ל-response כדי להפנות לבקשה או לתשובה.

ערך ברירת המחדל בקשה
חובה? אופציונלי
סוג String
רכיב אב <MessageValidation>
רכיבי צאצא ללא

רכיב <Source> משתמש בתחביר הבא:

תחביר

...
  <Source>message_to_validate</Source>
...

דוגמה

...
<Source>request</Source>
...

בנוסף ל-message,‏ request ו-response, אפשר להגדיר את הערך של <Source> לשם של כל הודעה בתהליך. עם זאת, אם תעשו את זה, תצטרכו ליצור הודעה בהתאמה אישית עם השם הזה בתהליך העבודה לפני שהמדיניות הזו תופעל. אחרת, תקבלו שגיאה.

אם אי אפשר לפתור את הערך של <Source> בזרימת ההודעות או שהוא נפתר כסוג שאינו הודעה, מתרחש אחד מהמקרים הבאים:

  • אם הערך הוא null:‏ Apigee מחזיר שגיאת steps.messagevalidation.SourceMessageNotAvailable.
  • אם הסוג הוא לא הודעה: Apigee יציג שגיאת steps.messagevalidation.NonMessageVariable.

לרכיב <Source> אין מאפיינים או רכיבי צאצא.

קודי שגיאה

בקטע הזה מתוארים קודי התקלה והודעות השגיאה שמוחזרים, ומשתני התקלה שמוגדרים על ידי Apigee כשמדיניות כזו מפעילה שגיאה. חשוב לדעת את המידע הזה אם אתם מפתחים כללי תקלות לטיפול בתקלות. מידע נוסף על שגיאות שקשורות למדיניות ועל טיפול בשגיאות

שגיאות זמן ריצה

השגיאות האלה יכולות להתרחש כשהמדיניות מופעלת.

קוד תקלה סטטוס HTTP מטרה תיקון
steps.messagevalidation.SourceMessageNotAvailable 500

השגיאה הזו מתרחשת אם משתנה שצוין ברכיב <Source> של המדיניות הוא אחד מהבאים:

  • מחוץ להיקף (לא זמין בתהליך הספציפי שבו המדיניות מופעלת)
  • או
  • לא ניתן לפתור (לא מוגדר)
steps.messagevalidation.NonMessageVariable 500

השגיאה הזו מתרחשת אם הרכיב <Source> במדיניות SOAPMessageValidation מוגדר למשתנה שלא שייך לסוג message.

משתני סוג ההודעה מייצגים בקשות ותגובות מלאות של HTTP. המשתנים המובנים של Apigee flow‏ request, response ו-message הם מסוג message. מידע נוסף על משתני הודעות זמין במאמר בנושא משתנים.

steps.messagevalidation.Failed 500 השגיאה הזו מתרחשת אם המדיניות SOAPMessageValidation לא מצליחה לאמת את מטען הייעודי (payload) של הודעת הקלט מול סכימת ה-XSD או הגדרת ה-WSDL. היא תתרחש גם אם יש JSON או XML לא תקינים בהודעת המטען הייעודי (payload).

שגיאות בהטמעה

השגיאות האלה יכולות להתרחש כשפורסים שרת proxy שמכיל את המדיניות הזו.

שם השגיאה מטרה תיקון
InvalidResourceType הרכיב <ResourceURL> במדיניות SOAPMessageValidation מוגדר לסוג משאב שלא נתמך על ידי המדיניות.
ResourceCompileFailed סקריפט המשאב שאליו יש הפניה ברכיב <ResourceURL> של מדיניות SOAPMessageValidation מכיל שגיאה שמונעת את ההידור שלו.
RootElementNameUnspecified הרכיב <Element> במדיניות SOAPMessageValidation לא מכיל את שם רכיב הבסיס.
InvalidRootElementName האלמנט <Element> במדיניות SOAPMessageValidation מכיל שם של רכיב בסיס שלא עומד בכללי ה-XML לגבי שמות תקינים של רכיבים.

סכימות

כל סוג מדיניות מוגדר על ידי סכימת XML ‏ (.xsd). סכימות מדיניות זמינות ב-GitHub.

נושאים קשורים