Share via


Klientbibliotek för Azure Confidential Ledger för Python – version 1.1.1

Azure Confidential Ledger tillhandahåller en tjänst för loggning till ett oföränderligt, manipuleringssäkert transaktionsregister. Som en del av Portföljen för konfidentiell databehandling i Azure körs Azure Confidential Ledger i säkra, maskinvarubaserade, betrodda körningsmiljöer, även kallade enklaver. Den bygger på Microsoft Researchs Confidential Consortium Framework.

| KällkodPaket (PyPI) | Paket (Conda) | API-referensdokumentation | Produktdokumentation

Komma igång

Installera paket

Installera azure-confidentialledger och azure-identity med pip:

pip install azure-identity azure-confidentialledger

azure-identity används för Azure Active Directory-autentisering enligt nedan.

Förutsättningar

  • En Azure-prenumeration
  • Python 3.6 eller senare
  • En instans av Azure Confidential Ledger som körs.
  • En registrerad användare i det konfidentiella transaktionsregistret, som vanligtvis tilldelas när ARM-resursen skapas, med Administrator behörigheter.

Autentisera klienten

Använda Azure Active Directory

Det här dokumentet visar hur du använder DefaultAzureCredential för att autentisera till det konfidentiella transaktionsregistret via Azure Active Directory. Accepterar dock ConfidentialLedgerClient alla azure-identity-autentiseringsuppgifter . Mer information om andra autentiseringsuppgifter finns i dokumentationen om azure-identity .

Använda ett klientcertifikat

Som ett alternativ till Azure Active Directory kan klienter välja att använda ett klientcertifikat för att autentisera via ömsesidig TLS. azure.confidentialledger.ConfidentialLedgerCertificateCredential kan användas för detta ändamål.

Skapa en klient

DefaultAzureCredential hanterar automatiskt de flesta Azure SDK-klientscenarier. Kom igång genom att ange miljövariabler för AAD-identiteten som registrerats med ditt konfidentiella transaktionsregister.

export AZURE_CLIENT_ID="generated app id"
export AZURE_CLIENT_SECRET="random password"
export AZURE_TENANT_ID="tenant id"

DefaultAzureCredential Sedan kan autentisera ConfidentialLedgerClient.

När du skapar klienten krävs även ditt konfidentiella transaktionsregisters URL och ID, som du kan hämta från Azure CLI eller Azure-portalen. När du har hämtat dessa värden ersätter du instanser av "my-ledger-id" och "https://my-ledger-id.confidential-ledger.azure.com" i exemplen nedan. Du kan också behöva ersätta "https://identity.confidential-ledger.core.azure.com" med värdnamnet från identityServiceUri i ARM-beskrivningen för ditt transaktionsregister.

Eftersom konfidentiella transaktionsregister använder självsignerade certifikat som genererats på ett säkert sätt och lagras i en enklav, måste signeringscertifikatet för varje konfidentiellt transaktionsregister först hämtas från den konfidentiella transaktionsregisteridentitetstjänsten.

from azure.confidentialledger import ConfidentialLedgerClient
from azure.confidentialledger.certificate import ConfidentialLedgerCertificateClient
from azure.identity import DefaultAzureCredential

identity_client = ConfidentialLedgerCertificateClient()
network_identity = identity_client.get_ledger_identity(
    ledger_id="my-ledger-id"
)

ledger_tls_cert_file_name = "ledger_certificate.pem"
with open(ledger_tls_cert_file_name, "w") as cert_file:
    cert_file.write(network_identity["ledgerTlsCertificate"])

credential = DefaultAzureCredential()
ledger_client = ConfidentialLedgerClient(
    endpoint="https://my-ledger-id.confidential-ledger.azure.com",
    credential=credential,
    ledger_certificate_path=ledger_tls_cert_file_name
)

Enkelt ConfidentialLedgerClient hämtar konstruktorn transaktionsregistrets TLS-certifikat (och skriver det till den angivna filen) om det finns en obefintlig fil. Användaren ansvarar för att ta bort den skapade filen efter behov.

from azure.confidentialledger import ConfidentialLedgerClient
from azure.identity import DefaultAzureCredential

credential = DefaultAzureCredential()
ledger_client = ConfidentialLedgerClient(
    endpoint="https://my-ledger-id.confidential-ledger.azure.com",
    credential=credential,
    ledger_certificate_path="ledger_certificate.pem"
)

# The ledger TLS certificate is written to `ledger_certificate.pem`.

För att göra det tydligt att en fil används för TLS-transaktionsregistrets TLS-certifikat, kommer efterföljande exempel uttryckligen att skriva TLS-transaktionsregistrets certifikat till en fil.

Viktiga begrepp

Transaktionsregisterposter och transaktioner

Varje skrivning till Azure Confidential Ledger genererar en oföränderlig transaktionsregisterpost i tjänsten. Skrivningar, även kallade transaktioner, identifieras unikt med transaktions-ID:t som ökar med varje skrivning. När transaktionsregistret har skrivits kan de hämtas när som helst.

Samlingar

De flesta användningsfall omfattar bara en samling per konfidentiellt transaktionsregister, men vi tillhandahåller funktionen samlings-ID om semantiskt eller logiskt olika grupper av data måste lagras i samma konfidentiella transaktionsregister.

Transaktionsregisterposter hämtas av deras collectionId. Det konfidentiella transaktionsregistret förutsätter alltid en konstant, tjänstbestämd collectionId för poster som skrivits utan angivet collectionId .

Användare

Användare hanteras direkt med det konfidentiella transaktionsregistret i stället för via Azure. Användarna kan vara AAD-baserade, identifieras med sitt AAD-objekt-ID eller certifikatbaserade, som identifieras med pem-certifikatets fingeravtryck.

Kvitton

För att framtvinga garantier för transaktionsintegritet använder ett Konfidentiellt transaktionsregister en [Merkle-träd][merkle_tree_wiki]-datastruktur för att registrera hashen för alla transaktionsblock som läggs till i det oföränderliga transaktionsregistret. När en skrivtransaktion har checkats in kan Azure Confidential Ledger-användare få ett kryptografiskt Merkle-bevis, eller kvitto, över posten som genereras i ett konfidentiellt transaktionsregister för att verifiera att skrivåtgärden har sparats korrekt. Ett kvitto för skrivtransaktionen är ett bevis på att systemet har checkat in motsvarande transaktion och kan användas för att verifiera att posten har lagts till i transaktionsregistret.

Mer information om transaktionskvitton för skrivning av Azure Confidential Ledger finns i följande artikel .

Kvittoverifiering

När du har fått ett kvitto för en skrivtransaktion kan Azure Confidential Ledger-användare verifiera innehållet i det hämtade kvittot efter en verifieringsalgoritm. Verifieringen är ett bevis på att skrivåtgärden som är kopplad till kvittot har lagts till korrekt i det oföränderliga transaktionsregistret.

Se följande artikel för mer information om verifieringsprocessen för Azure Confidential Ledgers skrivtransaktionskvitton.

Programanspråk

Azure Confidential Ledger-program kan bifoga godtyckliga data, så kallade programanspråk, för att skriva transaktioner. Dessa anspråk representerar de åtgärder som utförs under en skrivåtgärd. Vid anslutning till en transaktion inkluderas SHA-256-sammandraget av anspråksobjektet i transaktionsregistret och checkas in som en del av skrivtransaktionen. Detta garanterar att sammanfattningen är inloggad och inte kan manipuleras.

Senare kan programanspråk visas i osammandraget format i kvittonyttolasten som motsvarar samma transaktion där de lades till. På så sätt kan användarna använda informationen i kvittot för att beräkna om samma anspråkssammandrag som kopplades och loggades in av Azure Confidential Ledger-instansen under transaktionen. Anspråkssammandraget kan användas som en del av verifieringsprocessen för skrivning av transaktionskvitton, vilket ger ett offline-sätt för användare att fullständigt verifiera äktheten för de registrerade anspråken.

Mer information om programmets anspråksformat och algoritmen för sammandragsberäkning finns på följande länkar:

Mer information om CCF-programanspråk finns på följande CCF-dokumentationssidor:

Konfidentiell databehandling

Med konfidentiell databehandling i Azure kan du isolera och skydda dina data medan de bearbetas i molnet. Azure Confidential Ledger körs på virtuella Azure Confidential Computing-datorer, vilket ger ett starkare dataskydd med kryptering av data som används.

Konfidentiellt konsortiumramverk

Azure Confidential Ledger bygger på Microsoft Researchs Confidential Consortium Framework (CCF) med öppen källkod. Under CCF hanteras ansökningar av ett konsortium av medlemmar med möjlighet att lämna in förslag för att ändra och styra programåtgärden. I Azure Confidential Ledger äger Microsoft Azure en medlemsidentitet för operatör som gör att den kan utföra styrnings- och underhållsåtgärder som att ersätta noder med feltillstånd i det konfidentiella transaktionsregistret och uppgradera enklavkoden.

Exempel

Det här avsnittet innehåller kodfragment som omfattar vanliga uppgifter, inklusive:

Lägg till post

Data som måste lagras oföränderligt på ett manipuleringssäkert sätt kan sparas i Azure Confidential Ledger genom att lägga till en post i transaktionsregistret.

Eftersom Konfidentiellt transaktionsregister är ett distribuerat system kan sällsynta tillfälliga fel göra att skrivningar går förlorade. För poster som måste bevaras är det lämpligt att kontrollera att skrivningen blev beständig. För mindre viktiga skrivningar där högre klientdataflöde föredras kan väntesteget hoppas över.

from azure.confidentialledger import ConfidentialLedgerClient
from azure.confidentialledger.certificate import ConfidentialLedgerCertificateClient
from azure.identity import DefaultAzureCredential

identity_client = ConfidentialLedgerCertificateClient()
network_identity = identity_client.get_ledger_identity(
    ledger_id="my-ledger-id"
)

ledger_tls_cert_file_name = "ledger_certificate.pem"
with open(ledger_tls_cert_file_name, "w") as cert_file:
    cert_file.write(network_identity["ledgerTlsCertificate"])

credential = DefaultAzureCredential()
ledger_client = ConfidentialLedgerClient(
    endpoint="https://my-ledger-id.confidential-ledger.azure.com",
    credential=credential,
    ledger_certificate_path=ledger_tls_cert_file_name
)

post_entry_result = ledger_client.create_ledger_entry(
        {"contents": "Hello world!"}
    )
transaction_id = post_entry_result["transactionId"]

wait_poller = ledger_client.begin_wait_for_commit(transaction_id)
wait_poller.wait()
print(f'Ledger entry at transaction id {transaction_id} has been committed successfully')

Alternativt kan klienten vänta på incheckning när en transaktionsregisterpost skrivs.

from azure.confidentialledger import ConfidentialLedgerClient
from azure.confidentialledger.certificate import ConfidentialLedgerCertificateClient
from azure.identity import DefaultAzureCredential

identity_client = ConfidentialLedgerCertificateClient()
network_identity = identity_client.get_ledger_identity(
    ledger_id="my-ledger-id"
)

ledger_tls_cert_file_name = "ledger_certificate.pem"
with open(ledger_tls_cert_file_name, "w") as cert_file:
    cert_file.write(network_identity["ledgerTlsCertificate"])

credential = DefaultAzureCredential()
ledger_client = ConfidentialLedgerClient(
    endpoint="https://my-ledger-id.confidential-ledger.azure.com",
    credential=credential,
    ledger_certificate_path=ledger_tls_cert_file_name
)

post_poller = ledger_client.begin_create_ledger_entry(
    {"contents": "Hello world again!"}
)
new_post_result = post_poller.result()
print(
    'The new ledger entry has been committed successfully at transaction id '
    f'{new_post_result["transactionId"]}'
)

Hämtar transaktionsregisterposter

Det kan ta lite tid att hämta transaktionsregisterposter som är äldre än den senaste eftersom tjänsten läser in historiska poster, så en poller tillhandahålls.

Transaktionsregisterposter hämtas av en samling. Det returnerade värdet är det värde som finns i den angivna samlingen vid den tidpunkt som identifierats av transaktions-ID:t.

from azure.confidentialledger import ConfidentialLedgerClient
from azure.confidentialledger.certificate import ConfidentialLedgerCertificateClient
from azure.identity import DefaultAzureCredential

identity_client = ConfidentialLedgerCertificateClient()
network_identity = identity_client.get_ledger_identity(
    ledger_id="my-ledger-id"
)

ledger_tls_cert_file_name = "ledger_certificate.pem"
with open(ledger_tls_cert_file_name, "w") as cert_file:
    cert_file.write(network_identity["ledgerTlsCertificate"])

credential = DefaultAzureCredential()
ledger_client = ConfidentialLedgerClient(
    endpoint="https://my-ledger-id.confidential-ledger.azure.com",
    credential=credential,
    ledger_certificate_path=ledger_tls_cert_file_name
)

post_poller = ledger_client.begin_create_ledger_entry(
    {"contents": "Original hello"}
)
post_result = post_poller.result()

post_transaction_id = post_result["transactionId"]

latest_entry = ledger_client.get_current_ledger_entry()
print(
    f'Current entry (transaction id = {latest_entry["transactionId"]}) '
    f'in collection {latest_entry["collectionId"]}: {latest_entry["contents"]}'
)

post_poller = ledger_client.begin_create_ledger_entry(
    {"contents": "Hello!"}
)
post_result = post_poller.result()

get_entry_poller = ledger_client.begin_get_ledger_entry(post_transaction_id)
older_entry = get_entry_poller.result()
print(
    f'Contents of {older_entry["entry"]["collectionId"]} at {post_transaction_id}: {older_entry["entry"]["contents"]}'
)

Skapa en intervallfråga

Transaktionsregisterposter kan hämtas över ett intervall med transaktions-ID:t. Poster returneras endast från standardsamlingen eller den angivna samlingen.

from azure.confidentialledger import ConfidentialLedgerClient
from azure.confidentialledger.certificate import ConfidentialLedgerCertificateClient
from azure.identity import DefaultAzureCredential

identity_client = ConfidentialLedgerCertificateClient()
network_identity = identity_client.get_ledger_identity(
    ledger_id="my-ledger-id"
)

ledger_tls_cert_file_name = "ledger_certificate.pem"
with open(ledger_tls_cert_file_name, "w") as cert_file:
    cert_file.write(network_identity["ledgerTlsCertificate"])

credential = DefaultAzureCredential()
ledger_client = ConfidentialLedgerClient(
    endpoint="https://my-ledger-id.confidential-ledger.azure.com",
    credential=credential,
    ledger_certificate_path=ledger_tls_cert_file_name
)

post_poller = ledger_client.begin_create_ledger_entry(
    {"contents": "First message"}
)
first_transaction_id = post_poller.result()["transactionId"]

for i in range(10):
    ledger_client.create_ledger_entry(
        {"contents": f"Message {i}"}
    )

post_poller = ledger_client.begin_create_ledger_entry(
    {"contents": "Last message"}
)
last_transaction_id = post_poller.result()["transactionId"]

ranged_result = ledger_client.list_ledger_entries(
    from_transaction_id=first_transaction_id,
    to_transaction_id=last_transaction_id,
)
for entry in ranged_result:
    print(f'Contents at {entry["transactionId"]}: {entry["contents"]}')

Hantera användare

Användare med Administrator behörighet kan hantera användare av det konfidentiella transaktionsregistret direkt med själva det konfidentiella transaktionsregistret. Tillgängliga roller är Reader (skrivskyddade), Contributor (läsa och skriva) och Administrator (läsa, skriva och lägga till eller ta bort användare).

from azure.confidentialledger import ConfidentialLedgerClient
from azure.confidentialledger.certificate import ConfidentialLedgerCertificateClient
from azure.identity import DefaultAzureCredential

identity_client = ConfidentialLedgerCertificateClient()
network_identity = identity_client.get_ledger_identity(
    ledger_id="my-ledger-id"
)

ledger_tls_cert_file_name = "ledger_certificate.pem"
with open(ledger_tls_cert_file_name, "w") as cert_file:
    cert_file.write(network_identity["ledgerTlsCertificate"])

credential = DefaultAzureCredential()
ledger_client = ConfidentialLedgerClient(
    endpoint="https://my-ledger-id.confidential-ledger.azure.com",
    credential=credential,
    ledger_certificate_path=ledger_tls_cert_file_name
)

user_id = "some AAD object id"
user = ledger_client.create_or_update_user(
    user_id, {"assignedRole": "Contributor"}
)
# A client may now be created and used with AAD credentials (i.e. AAD-issued JWT tokens) for the user identified by `user_id`.

user = ledger_client.get_user(user_id)
assert user["userId"] == user_id
assert user["assignedRole"] == "Contributor"

ledger_client.delete_user(user_id)

# For a certificate-based user, their user ID is the fingerprint for their PEM certificate.
user_id = "PEM certificate fingerprint"
user = ledger_client.create_or_update_user(
    user_id, {"assignedRole": "Reader"}
)

user = ledger_client.get_user(user_id)
assert user["userId"] == user_id
assert user["assignedRole"] == "Reader"

ledger_client.delete_user(user_id)

Använda certifikatautentisering

Klienter kan autentisera med ett klientcertifikat i ömsesidig TLS i stället för via en Azure Active Directory-token. ConfidentialLedgerCertificateCredential tillhandahålls för sådana klienter.

from azure.confidentialledger import (
    ConfidentialLedgerCertificateCredential,
    ConfidentialLedgerClient,
)
from azure.confidentialledger.certificate import ConfidentialLedgerCertificateClient

identity_client = ConfidentialLedgerCertificateClient()
network_identity = identity_client.get_ledger_identity(
    ledger_id="my-ledger-id"
)

ledger_tls_cert_file_name = "ledger_certificate.pem"
with open(ledger_tls_cert_file_name, "w") as cert_file:
    cert_file.write(network_identity["ledgerTlsCertificate"])

credential = ConfidentialLedgerCertificateCredential(
    certificate_path="Path to user certificate PEM file"
)
ledger_client = ConfidentialLedgerClient(
    endpoint="https://my-ledger-id.confidential-ledger.azure.com",
    credential=credential,
    ledger_certificate_path=ledger_tls_cert_file_name
)

Verifiera skrivning av transaktionskvitton

Klienter kan använda kvittoverifieringsbiblioteket i SDK:t för att verifiera skrivning av transaktionskvitton som utfärdats av Azure Confidential Legder-instanser. Verktyget kan användas för att fullständigt verifiera kvitton offline eftersom verifieringsalgoritmen inte behöver vara ansluten till en konfidentiell transaktionsregister eller någon annan Azure-tjänst.

När en ny post har lagts till i transaktionsregistret (se det här exemplet) kan du få ett kvitto för den checkade skrivtransaktionen.

from azure.confidentialledger import ConfidentialLedgerClient
from azure.confidentialledger.certificate import ConfidentialLedgerCertificateClient
from azure.identity import DefaultAzureCredential

# Replace this with the Confidential Ledger ID 
ledger_id = "my-ledger-id"

# Setup authentication
credential = DefaultAzureCredential()

# Create a Ledger Certificate client and use it to
# retrieve the service identity for our ledger
identity_client = ConfidentialLedgerCertificateClient()
network_identity = identity_client.get_ledger_identity(
    ledger_id=ledger_id
)

# Save ledger service certificate into a file for later use
ledger_tls_cert_file_name = "ledger_certificate.pem"
with open(ledger_tls_cert_file_name, "w") as cert_file:
    cert_file.write(network_identity["ledgerTlsCertificate"])

# Create Confidential Ledger client
ledger_client = ConfidentialLedgerClient(
    endpoint=f"https://{ledger_id}.confidential-ledger.azure.com",
    credential=credential,
    ledger_certificate_path=ledger_tls_cert_file_name
)

# The method begin_get_receipt returns a poller that
# we can use to wait for the receipt to be available for retrieval 
get_receipt_poller = ledger_client.begin_get_receipt(transaction_id)
get_receipt_result = get_receipt_poller.result()

print(f"Write receipt for transaction id {transaction_id} was successfully retrieved: {get_receipt_result}")

När du har hämtat ett kvitto för en skrivtransaktion kan du anropa verify_receipt funktionen för att kontrollera att kvittot är giltigt. Funktionen kan acceptera en valfri lista över programanspråk för att verifiera mot kvittoanspråkens sammandrag.

from azure.confidentialledger.receipt import (
    verify_receipt,
)

# Read contents of service certificate file saved in previous step.
with open(ledger_tls_cert_file_name, "r") as service_cert_file:
    service_cert_content = service_cert_file.read()

# Optionally read application claims, if any
application_claims = get_receipt_result.get("applicationClaims", None) 

try:
    # Verify the contents of the receipt.
    verify_receipt(get_receipt_result["receipt"], service_cert_content, application_claims=application_claims)
    print(f"Receipt for transaction id {transaction_id} successfully verified")
except ValueError:
    print(f"Receipt verification for transaction id {transaction_id} failed")

Ett fullständigt Python-exempelprogram som visar hur du lägger till en ny post i en konfidentiell transaktionsinstans som körs, hämtar ett kvitto för den checkade transaktionen och kontrollerar att kvittoinnehållet finns under mappen samples : get_and_verify_receipt.py.

Async API

Det här biblioteket innehåller ett fullständigt asynkront API som stöds i Python 3.5+. Om du vill använda den måste du först installera en asynkron transport, till exempel aiohttp. Mer information finns i dokumentationen om azure-core .

En asynkron klient hämtas från azure.confidentialledger.aio. Metoderna har samma namn och signaturer som den synkrona klienten. Exempel kan hittas här.

Felsökning

Allmänt

Konfidentiella transaktionsregisterklienter genererar undantag som definierats i azure-core. Om du till exempel försöker hämta en transaktion som inte finns ConfidentialLedgerClient genererar ResourceNotFoundError:

from azure.core.exceptions import ResourceNotFoundError
from azure.confidentialledger import ConfidentialLedgerClient
from azure.confidentialledger.certificate import ConfidentialLedgerCertificateClient
from azure.identity import DefaultAzureCredential

identity_client = ConfidentialLedgerCertificateClient()
network_identity = identity_client.get_ledger_identity(
    ledger_id="my-ledger-id"
)

ledger_tls_cert_file_name = "ledger_certificate.pem"
with open(ledger_tls_cert_file_name, "w") as cert_file:
    cert_file.write(network_identity["ledgerTlsCertificate"])

credential = DefaultAzureCredential()
ledger_client = ConfidentialLedgerClient(
    endpoint="https://my-ledger-id.confidential-ledger.azure.com",
    credential=credential,
    ledger_certificate_path=ledger_tls_cert_file_name
)

try:
    ledger_client.begin_get_ledger_entry(
        transaction_id="10000.100000"  # Using a very high id that probably doesn't exist in the ledger if it's relatively new.
    )
except ResourceNotFoundError as e:
    print(e.message)

Loggning

Det här biblioteket använder standardloggningsbiblioteket för loggning. Grundläggande information om HTTP-sessioner (URL:er, rubriker osv.) loggas på INFO-nivå.

Detaljerad loggning på FELSÖKNINGsnivå, inklusive begärande-/svarskroppar och oredigerade huvuden, kan aktiveras på en klient med logging_enable argumentet :

import logging
import sys

from azure.confidentialledger import ConfidentialLedgerClient
from azure.confidentialledger.certificate import ConfidentialLedgerCertificateClient
from azure.identity import DefaultAzureCredential

# Create a logger for the 'azure' SDK
logger = logging.getLogger('azure')
logger.setLevel(logging.DEBUG)

# Configure a console output
handler = logging.StreamHandler(stream=sys.stdout)
logger.addHandler(handler)

identity_client = ConfidentialLedgerCertificateClient()
network_identity = identity_client.get_ledger_identity(
    ledger_id="my-ledger-id"
)

ledger_tls_cert_file_name = "ledger_certificate.pem"
with open(ledger_tls_cert_file_name, "w") as cert_file:
    cert_file.write(network_identity["ledgerTlsCertificate"])

credential = DefaultAzureCredential()

# This client will log detailed information about its HTTP sessions, at DEBUG level.
ledger_client = ConfidentialLedgerClient(
    endpoint="https://my-ledger-id.confidential-ledger.azure.com",
    credential=credential,
    ledger_certificate_path=ledger_tls_cert_file_name,
    logging_enable=True,
)

logging_enable På samma sätt kan du aktivera detaljerad loggning för en enda åtgärd, även om den inte är aktiverad för klienten:

ledger_client.get_current_ledger_entry(logging_enable=True)

Nästa steg

Mer exempelkod

De här kodexemplen visar vanliga scenarioåtgärder med Azure Confidential Ledger-klientbiblioteket.

Vanliga scenarier

Avancerade scenarier

Ytterligare dokumentation

Mer omfattande dokumentation om Azure Confidential Ledger finns i API-referensdokumentationen. Du kan också läsa mer om Microsoft Researchs konfidentiella konsortiumramverk med öppen källkod.

Bidra

Det här projektet välkomnar bidrag och förslag. Merparten av bidragen kräver att du godkänner ett licensavtal för bidrag, där du deklarerar att du har behörighet att bevilja oss rättigheten att använda ditt bidrag, och att du dessutom uttryckligen gör så. Mer information finns på https://cla.microsoft.com.

När du skickar en pull-förfrågan avgör en CLA-robot automatiskt om du måste tillhandahålla ett licensavtal för bidrag med lämplig PR (t.ex. etikett eller kommentar). Följ bara robotens anvisningar. Du behöver bara göra detta en gång för alla repor som använder vårt licensavtal för bidrag.

Det här projektet använder sig av Microsofts uppförandekod för öppen källkod. Du hittar mer information i Vanliga frågor om uppförandekod eller kontakta opencode@microsoft.com för ytterligare frågor eller kommentarer.