次の方法で共有


Python 用 Azure Confidential Ledger クライアント ライブラリ - バージョン 1.1.1

Azure Confidential Ledger は、不変の改ざん防止台帳にログを記録するためのサービスを提供します。 Azure Confidential Computing ポートフォリオの一部として、Azure Confidential Ledger は、セキュリティで保護されたハードウェアベースの信頼された実行環境 (エンクレーブとも呼ばれます) で実行されます。 これは、Microsoft Research の Confidential Consortium Framework に基づいて構築されています。

ソースコード | パッケージ (PyPI) | パッケージ (Conda) | API リファレンス ドキュメント | 製品ドキュメント

作業の開始

パッケージをインストールする

pip を使用して azure-confidentialledgerazure-identity をインストールします。

pip install azure-identity azure-confidentialledger

azure-identity は、次に示すように、Azure Active Directory 認証に使用されます。

前提条件

  • Azure サブスクリプション
  • Python 3.6 以降
  • Azure Confidential Ledger の実行インスタンス。
  • Confidential Ledger に登録されているユーザー。通常は 、ARM リソースの作成時に特権を持つ Administrator 割り当てられます。

クライアントを認証する

Azure Active Directory の使用

このドキュメントでは、 DefaultAzureCredential を使用して、Azure Active Directory 経由で Confidential Ledger に対する認証を行う方法について説明します。 ただし、 ConfidentialLedgerClient任意の azure-identity 資格情報を 受け入れます。 その他の資格情報の詳細については、 azure-identity のドキュメントを参照してください。

クライアント証明書の使用

Azure Active Directory の代わりに、クライアントはクライアント証明書を使用して相互 TLS 経由で認証することを選択できます。 azure.confidentialledger.ConfidentialLedgerCertificateCredential は、この目的に使用できます。

クライアントの作成

DefaultAzureCredential は、ほとんどの Azure SDK クライアント シナリオを自動的に処理します。 まず、Confidential Ledger に登録されている AAD ID の環境変数を設定します。

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

その後、 DefaultAzureCredential を認証 ConfidentialLedgerClientできるようになります。

クライアントを構築するには、Confidential Ledger の URL と ID も必要です。これは、Azure CLI または Azure Portal から取得できます。 これらの値を取得したら、次の例の と "https://my-ledger-id.confidential-ledger.azure.com""my-ledger-id"インスタンスを置き換えてください。 を、台帳の ARM 説明の の identityServiceUri ホスト名に置き換える"https://identity.confidential-ledger.core.azure.com"必要がある場合もあります。

Confidential Ledger は安全に生成され、エンクレーブに格納された自己署名証明書を使用するため、各 Confidential Ledger の署名証明書は、まず Confidential Ledger Identity Service から取得する必要があります。

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
)

コンストラクターは ConfidentialLedgerClient 、存在しないファイルが指定されている場合は、台帳 TLS 証明書をフェッチ (および指定されたファイルに書き込む) のが便利です。 ユーザーは、必要に応じて作成されたファイルを削除する必要があります。

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`.

台帳 TLS 証明書にファイルが使用されていることを明確にするために、後続の例では、台帳 TLS 証明書をファイルに明示的に書き込みます。

主要な概念

台帳エントリとトランザクション

Azure Confidential Ledger へのすべての書き込みでは、サービスに不変の台帳エントリが生成されます。 書き込み (トランザクションとも呼ばれます) は、書き込みごとにインクリメントされるトランザクション ID によって一意に識別されます。 書き込まれた台帳エントリは、いつでも取得できます。

コレクション

ほとんどのユース ケースには Confidential Ledger ごとに 1 つのコレクションだけが含まれますが、意味的または論理的に異なるデータ グループを同じ Confidential Ledger に格納する必要がある場合に備えて、コレクション ID 機能を提供します。

台帳エントリは、 によって collectionId取得されます。 Confidential Ledger は常に、 を指定せずに書き込まれたエントリに対してサービスによって決定される collectionId 定数を collectionId 想定します。

ユーザー

ユーザーは、Azure ではなく Confidential Ledger を使用して直接管理されます。 ユーザーは、AAD ベースであり、AAD オブジェクト ID で識別されるか、PEM 証明書フィンガープリントによって識別される証明書ベースである場合があります。

Receipts

トランザクションの整合性を保証するために、Azure Confidential Ledger は [Merkle ツリー][merkle_tree_wiki] データ構造を使用して、変更できない台帳に追加されるすべてのトランザクション ブロックのハッシュを記録します。 書き込みトランザクションがコミットされた後、Azure Confidential Ledger ユーザーは Confidential Ledger で生成されたエントリに対して暗号化されたマークル証明 (レシート) を取得して、書き込み操作が正しく保存されたことを確認できます。 書き込みトランザクション レシートは、対応するトランザクションがシステムでコミットされたことの証明であり、エントリが実質的に台帳に追加されたことを確認するために使用できます。

Azure Confidential Ledger 書き込みトランザクションの領収書の詳細については、次の 記事 を参照してください。

領収書の確認

書き込みトランザクションの領収書を受け取った後、Azure Confidential Ledger ユーザーは、検証アルゴリズムに従ってフェッチされたレシートの内容を確認できます。 検証の成功は、レシートに関連付けられている書き込み操作が変更できない台帳に正しく追加されたことを証明するものです。

Azure Confidential Ledger 書き込みトランザクションレシートの検証プロセスの詳細については、次の 記事 を参照してください。

アプリケーション要求

Azure Confidential Ledger アプリケーションは、アプリケーション要求と呼ばれる任意のデータをアタッチすることで、トランザクションを書き込むことができます。 これらの要求は、書き込み操作中に実行されるアクションを表しています。 トランザクションにアタッチすると、要求オブジェクトの SHA-256 ダイジェストが台帳に追加され、書き込みトランザクションの一部としてコミットされます。 これにより、ダイジェストがインプレースでサインインし、改ざんできないことが保証されます。

後で、アプリケーション要求は、追加されたのと同じトランザクションに対応するレシート ペイロードで、ダイジェストされていない形式で表示できます。 これにより、ユーザーはレシートの情報を利用して、トランザクション中に Azure Confidential Ledger インスタンスによってアタッチおよびサインインされたのと同じクレーム ダイジェストを再計算できます。 要求ダイジェストは、書き込みトランザクションのレシート検証プロセスの一環として使用でき、ユーザーは記録された要求の信頼性に対する検証をオフラインで完全に行うことができます。

アプリケーション要求形式とダイジェスト計算アルゴリズムの詳細については、次のリンクを参照してください。

CCF アプリケーション要求の詳細については、次の CCF ドキュメント ページを参照してください。

コンフィデンシャル コンピューティング

Azure Confidential Computing を使用すると、クラウドで処理されている間にデータを分離して保護できます。 Azure Confidential Ledger は Azure Confidential Computing 仮想マシン上で実行されるため、使用中のデータの暗号化によるデータ保護が強化されます。

Confidential Consortium Framework

Azure Confidential Ledger は、Microsoft Research のオープンソースの Confidential Consortium Framework (CCF) 上に構築されています。 CCF では、アプリケーションはメンバーのコンソーシアムによって管理され、アプリケーション操作を変更および管理するための提案を送信できます。 Azure Confidential Ledger では、Microsoft Azure はオペレーター メンバー ID を所有しています。これにより、Confidential Ledger 内の異常なノードの置き換えやエンクレーブ コードのアップグレードなど、ガバナンスとメンテナンスのアクションを実行できます。

このセクションには、次の一般的なタスクをカバーするコード スニペットが含まれています。

追加エントリ

改ざん防止の方法で不変に格納する必要があるデータは、エントリを台帳に追加することで、Azure Confidential Ledger に保存できます。

Confidential Ledger は分散システムであるため、まれな一時的な障害によって書き込みが失われる可能性があります。 保持する必要があるエントリの場合は、書き込みが永続的になったことを確認することをお勧めします。 より高いクライアント スループットが推奨される重要度の低い書き込みでは、待機ステップがスキップされる可能性があります。

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')

または、台帳エントリを書き込むときに、クライアントがコミットを待つ場合があります。

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"]}'
)

台帳エントリの取得

最新より古い台帳エントリを取得するには、サービスが履歴エントリを読み込むので、ポーリングャーが提供されるため、時間がかかる場合があります。

台帳エントリはコレクションによって取得されます。 戻り値は、トランザクション ID で識別される時点で、指定されたコレクションに含まれる値です。

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"]}'
)

範囲指定クエリの作成

台帳エントリは、一連のトランザクション ID で取得できます。 エントリは、既定または指定されたコレクションからのみ返されます。

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"]}')

ユーザーの管理

特権を持つ Administrator ユーザーは、Confidential Ledger 自体を使用して Confidential Ledger のユーザーを直接管理できます。 使用可能なロールは Reader 、(読み取り専用) Contributor 、(読み取りおよび書き込み)、および Administrator (ユーザーの読み取り、書き込み、追加または削除) です。

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)

証明書認証の使用

クライアントは、Azure Active Directory トークンではなく、相互 TLS でクライアント証明書を使用して認証できます。 ConfidentialLedgerCertificateCredential は、このようなクライアントに提供されます。

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
)

トランザクション レシートの書き込みを検証する

クライアントは SDK のレシート検証ライブラリを利用して、Azure Confidential Legder インスタンスによって発行された書き込みトランザクションレシートを検証できます。 検証アルゴリズムは Confidential 台帳やその他の Azure サービスに接続する必要がないため、ユーティリティを使用して、オフラインで領収書を完全に検証できます。

新しいエントリが台帳に追加されると ( この例を参照してください)、コミットされた書き込みトランザクションの領収書を取得できます。

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}")

書き込みトランザクションのレシートをフェッチした後、 関数を verify_receipt 呼び出して、レシートが有効であることを確認できます。 この関数は、受信要求ダイジェストに対して検証するアプリケーション要求の省略可能な一覧を受け取ることができます。

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")

実行中の Confidential Ledger インスタンスに新しいエントリを追加し、コミットされたトランザクションの領収書を取得し、レシートの内容が samples フォルダー (get_and_verify_receipt.py) にあることを確認する方法を示す完全なサンプル Python プログラム。

非同期 API

このライブラリには、Python 3.5 以降でサポートされている完全な非同期 API が含まれています。 これを使用するには、まず、 aiohttp などの非同期トランスポートをインストールする必要があります。 詳細については、 azure-core のドキュメント を参照してください。

非同期クライアントは から azure.confidentialledger.aio取得されます。 メソッドの名前とシグネチャは同期クライアントと同じです。 サンプルについては、 こちらを参照してください

トラブルシューティング

全般

Confidential Ledger クライアントは 、azure-core で定義されている例外を発生させます。 たとえば、存在しないトランザクションを取得しようとすると、 ConfidentialLedgerClientResourceNotFoundError が発生します。

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)

ログの記録

このライブラリでは、ログ記録に標準 のログ ライブラリが使用されます。 HTTP セッションに関する基本情報 (URL、ヘッダーなど) は INFO レベルでログに記録されます。

要求/応答本文、未変換ヘッダーなど、詳細な DEBUG レベルのログは、 引数を使用してクライアントで logging_enable 有効にすることができます。

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 は、詳細なログ記録がクライアントで有効になっていない場合でも、1 回の操作のために有効にすることができます。

ledger_client.get_current_ledger_entry(logging_enable=True)

次のステップ

その他のサンプル コード

これらのコード サンプルは、Azure Confidential Ledger クライアント ライブラリでの一般的なシナリオ操作を示しています。

一般的なシナリオ

高度なシナリオ

その他のドキュメント

Azure Confidential Ledger の詳細なドキュメントについては、 API リファレンス ドキュメントを参照してください。 また、Microsoft Research のオープンソースの Confidential Consortium Framework の詳細を参照することもできます。

共同作成

このプロジェクトでは、共同作成と提案を歓迎しています。 ほとんどの共同作成では、共同作成者使用許諾契約書 (CLA) にご同意いただき、ご自身の共同作成内容を使用する権利を Microsoft に供与する権利をお持ちであり、かつ実際に供与することを宣言していただく必要があります。 詳細については、 https://cla.microsoft.com を参照してください。

pull request を送信すると、CLA を提供して PR (ラベル、コメントなど) を適宜装飾する必要があるかどうかを CLA ボットが自動的に決定します。 ボットによって提供される手順にそのまま従ってください。 この操作は、Microsoft の CLA を使用するすべてのリポジトリについて、1 回だけ行う必要があります。

このプロジェクトでは、Microsoft オープン ソースの倫理規定を採用しています。 詳細については、倫理規定についてよくあるご質問を参照するか、opencode@microsoft.com 宛てにご質問またはコメントをお送りください。