dlt-community-sources v0.6.0: rest_api 移行とサプライチェーンセキュリティ
dlt-community-sources の v0.6.0 をリリースした。アーキテクチャを大きく変えたので書いておく。
Breaking Changes
2つの破壊的変更がある。
- 全ソースのカスタム
client.pyクラスを廃止した。AppStoreConnectClient、NextDNSClient、TwilioClientを直接インポートしていた場合は動かなくなる - NextDNS の
_profile_idフィールドを_profiles_idにリネームした。dlt のinclude_from_parentの命名規則に合わせた
rest_api への全面移行
v0.5.0 まで、各ソースは独自の HTTP クライアントクラス(client.py)で API を叩いていた。v0.6.0 では dlt の宣言的 rest_api ソースに移行した。
App Store Connect、NextDNS、Twilio の3ソースすべてが対象。標準的な REST エンドポイントは RESTAPIConfig の辞書で定義し、rest_api_resources() へ渡す形になった。
config: RESTAPIConfig = {
"client": {
"base_url": "https://api.example.com/v1/",
"auth": MyAuth(),
},
"resources": [
{
"name": "apps",
"endpoint": {"path": "apps"},
},
{
"name": "builds",
"endpoint": {
"path": "builds",
"params": {"filter[app]": "{resources.apps.id}"},
},
"include_from_parent": ["id"],
},
],
}
カスタムの @dlt.resource 関数が残っているのは、rest_api では対応できないケースだけ。
- App Store Connect の Sales/Finance/Analytics Reports(TSV / gzip バイナリのダウンロード)
- NextDNS の Series リソース(レスポンスの時系列データを平坦化する変換が必要)
- Twilio の一部リソース(RFC 2822 形式の日付を ISO 8601 に変換する必要がある)
なぜ移行したか
カスタムクライアントの問題点はいくつかあった。
- ページネーション、リトライ、認証をソースごとに自前で実装していた
- テストもクライアント単体のモックテストになりがちで、実際のパイプライン動作を検証しにくかった
- ソースを追加するたびに似たようなクライアントコードを書く必要があった
rest_api に移行すると、エンドポイントの定義が辞書になるので追加・変更が楽になる。ページネーションやリトライは dlt 側が面倒を見てくれる。テストも _rest_api_config() が正しい辞書を返すかを検証するだけでよくなった。
認証まわりの工夫
App Store Connect は JWT 認証で、トークンの有効期限が20分と短い。rest_api の認証は BearerTokenAuth を拡張して、リクエストごとに JWT を再生成する仕組みにした。
@configspec
class AppStoreConnectAuth(BearerTokenAuth):
key_id: str = None
issuer_id: str = None
private_key: str = None
def __call__(self, request):
self.token = self._generate_jwt()
return super().__call__(request)
@configspec デコレータとクラスレベルのフィールド宣言が必要で、これがないと dlt の rest_api 設定バリデーションを通らなかった。
HTTP クライアントの統一
カスタムリソースでは requests.Session を直接使っていたが、dlt の dlt.sources.helpers.requests.Client に置き換えた。429/5xx の自動リトライと指数バックオフが入っているので、rest_api 側のリソースと同じリトライ挙動になる。
from dlt.sources.helpers import requests as req
def _make_client(auth) -> req.Client:
client = req.Client()
client.session.auth = auth
return client
サプライチェーンセキュリティの強化
PyPI パッケージを公開しているので、サプライチェーン攻撃への対策を入れた。
SLSA Provenance
publish ワークフローに SLSA Provenance attestation を追加した。パッケージがどのコミットから、どの CI 環境でビルドされたかを暗号的に証明できる。pip install 時に --require-hashes を使えば検証も可能。
Dependency Review
PR に対して dependency-review-action を走らせている。新しい依存関係に既知の脆弱性がないかを CI でチェックする。
その他
CODEOWNERSファイルの追加- ブランチ保護(レビュー必須、ステータスチェック必須)
- Dependabot の脆弱性アラートとセキュリティアップデートの有効化
- プライベート脆弱性報告の有効化
AI ルールとスキルの整備
開発体験の改善として、AI アシスタント向けのルールとスキルも整備した。
.ai/rules.md を唯一の原本として管理している。同期スクリプトが Claude Code(CLAUDE.md)、Cursor(.cursor/rules/)、Gemini CLI(GEMINI.md)、Codex CLI(AGENTS.md)向けのファイルを自動生成するので、メンテするのは .ai/rules.md だけで済む。
スキルとしては add-source(新しいソースの追加手順)と add-resource(既存ソースへのリソース追加手順)を用意している。v0.6.0 に合わせて rest_api ファーストのワークフローに書き直した。
さらに dltHub AI workbench も統合した。dlt ai init と dlt ai toolkit install で dlt エコシステムのコンテキスト(rest-api-pipeline のスキル群)が入る。プロジェクト固有のルールが上書きする二層構造にしてある。