From 676ea0d1a0e591e94e1a330929aae3c81088030f Mon Sep 17 00:00:00 2001 From: HadhemiDD <43783545+HadhemiDD@users.noreply.github.com> Date: Thu, 23 Apr 2026 11:01:58 +0200 Subject: [PATCH 1/7] Github Async Client (#22734) * Async Client * lint * lint * remove rate limit handeling and fix tests * cleanup * fix lint * fix lint * optimization * extract only needed data * fix lint * fix lint * Critical security and functionality fixes * Code Quality : add type annotations and document ressource management * new implmentation * fix lint * remove respx * fix tests * fix lint * fix test * lint --- ddev/changelog.d/22734.added | 1 + ddev/src/ddev/utils/github_async.py | 414 +++++++++++++++++++++++++ ddev/tests/utils/test_github_async.py | 428 ++++++++++++++++++++++++++ 3 files changed, 843 insertions(+) create mode 100644 ddev/changelog.d/22734.added create mode 100644 ddev/src/ddev/utils/github_async.py create mode 100644 ddev/tests/utils/test_github_async.py diff --git a/ddev/changelog.d/22734.added b/ddev/changelog.d/22734.added new file mode 100644 index 0000000000000..beea8fa40b485 --- /dev/null +++ b/ddev/changelog.d/22734.added @@ -0,0 +1 @@ +Add async GitHub API client with generic request method, automatic pagination, and Python 3.13 type parameter syntax \ No newline at end of file diff --git a/ddev/src/ddev/utils/github_async.py b/ddev/src/ddev/utils/github_async.py new file mode 100644 index 0000000000000..7bfac9a3539e6 --- /dev/null +++ b/ddev/src/ddev/utils/github_async.py @@ -0,0 +1,414 @@ +"""Async GitHub API client for triggering and monitoring GitHub Actions workflows""" + +import re +from collections.abc import AsyncIterator +from contextlib import asynccontextmanager +from dataclasses import dataclass +from typing import Any, Literal, Self + +import httpx +from pydantic import BaseModel, ConfigDict, Field + +GITHUB_API_VERSION = "2022-11-28" +DEFAULT_BASE_URL = "https://api.github.com" + +_LINK_RE = re.compile(r'<([^>]+)>;\s*rel="([^"]+)"') + + +# --------------------------------------------------------------------------- +# Pagination +# --------------------------------------------------------------------------- + + +@dataclass +class PaginationData: + """Parsed pagination links from a GitHub API Link header.""" + + first: str | None = None + prev: str | None = None + next: str | None = None + last: str | None = None + + @classmethod + def from_header(cls, header: str | None) -> Self: + """Parse a Link header value and return a PaginationData instance.""" + if not header: + return cls() + links: dict[str, str] = {} + for url, rel in _LINK_RE.findall(header): + links[rel] = url + return cls( + first=links.get("first"), + prev=links.get("prev"), + next=links.get("next"), + last=links.get("last"), + ) + + +# --------------------------------------------------------------------------- +# Response and domain models +# --------------------------------------------------------------------------- + + +class GitHubResponse[T](BaseModel): + """Generic wrapper for a GitHub API response.""" + + model_config = ConfigDict(arbitrary_types_allowed=True) + + data: T = Field(...) + headers: dict[str, str] = Field(default_factory=dict) + + +class WorkflowRun(BaseModel): + """A GitHub Actions workflow run.""" + + model_config = ConfigDict(extra="ignore") + + id: int + name: str | None = None + status: str + conclusion: str | None = None + html_url: str | None = None + created_at: str | None = None + updated_at: str | None = None + + +class Artifact(BaseModel): + """A GitHub Actions artifact.""" + + model_config = ConfigDict(extra="ignore") + + id: int + name: str + size_in_bytes: int | None = None + url: str | None = None + archive_download_url: str | None = None + expired: bool + + +class ArtifactsList(BaseModel): + """A list of artifacts with a total count.""" + + model_config = ConfigDict(extra="ignore") + + total_count: int + artifacts: list[Artifact] + + +class IssueComment(BaseModel): + """A GitHub issue (or PR) comment.""" + + model_config = ConfigDict(extra="ignore") + + id: int + body: str + user: dict[str, Any] | None = None + created_at: str | None = None + updated_at: str | None = None + html_url: str | None = None + + +class PullRequestReviewComment(BaseModel): + """An inline review comment on a pull request diff.""" + + model_config = ConfigDict(extra="ignore") + + id: int + body: str + path: str + commit_id: str + html_url: str | None = None + created_at: str | None = None + updated_at: str | None = None + user: dict[str, Any] | None = None + + +# --------------------------------------------------------------------------- +# Client +# --------------------------------------------------------------------------- + + +class AsyncGitHubClient: + """ + Async HTTP client for the GitHub REST API. + + Uses a shared httpx.AsyncClient for connection pooling. Call `aclose()` when + finished to release resources, or use the `async_github_client` context manager. + """ + + def __init__( + self, + token: str, + default_timeout: float = 30.0, + transport: httpx.AsyncBaseTransport | None = None, + ) -> None: + if not token: + raise ValueError("GitHub token must not be empty.") + + self._default_timeout = default_timeout + self._headers = { + "Authorization": f"Bearer {token}", + "X-GitHub-Api-Version": GITHUB_API_VERSION, + "Accept": "application/vnd.github+json", + } + self._client = httpx.AsyncClient( + base_url=DEFAULT_BASE_URL, + headers=self._headers, + timeout=default_timeout, + transport=transport, + ) + + async def aclose(self) -> None: + """Close the underlying HTTP client and release connections.""" + await self._client.aclose() + + # ------------------------------------------------------------------ + # Internal helpers + # ------------------------------------------------------------------ + + async def _request( + self, + method: str, + endpoint: str, + timeout: float | None = None, + **kwargs: Any, + ) -> httpx.Response: + effective_timeout = timeout if timeout is not None else self._default_timeout + try: + response = await self._client.request(method, endpoint, timeout=effective_timeout, **kwargs) + except httpx.TransportError as exc: + raise type(exc)(f"{method} {endpoint}: {exc}") from exc + response.raise_for_status() + return response + + async def _paginated_request( + self, + method: str, + endpoint: str, + timeout: float | None = None, + **kwargs: Any, + ) -> AsyncIterator[httpx.Response]: + """Yield one httpx.Response per page, following Link headers.""" + url: str | None = endpoint + first = True + while url is not None: + if first: + response = await self._request(method, url, timeout=timeout, **kwargs) + first = False + else: + # Subsequent pages: use the absolute next URL, no extra kwargs + response = await self._request(method, url, timeout=timeout) + yield response + pagination = PaginationData.from_header(response.headers.get("link")) + url = pagination.next + + @staticmethod + def _parse_response[T: BaseModel](response: httpx.Response, model: type[T]) -> GitHubResponse[T]: + """Validate the response body against *model* and wrap it in a GitHubResponse.""" + return GitHubResponse[T].model_validate( + {"data": model.model_validate(response.json()), "headers": dict(response.headers)} + ) + + # ------------------------------------------------------------------ + # Endpoint methods + # ------------------------------------------------------------------ + + async def create_workflow_dispatch( + self, + owner: str, + repo: str, + workflow_id: str | int, + ref: str, + inputs: dict[str, str] | None = None, + timeout: float | None = None, + ) -> GitHubResponse[None]: + """ + Calls the GitHub API to trigger a workflow dispatch event. + + GitHub API Documentation: + https://docs.github.com/en/rest/actions/workflows#create-a-workflow-dispatch-event + + Args: + owner: Repository owner (user or organisation). + repo: Repository name. + workflow_id: Workflow file name or numeric ID. + ref: Branch or tag name to run the workflow on. + inputs: Optional key/value inputs forwarded to the workflow. + timeout: Optional timeout for this specific request. Defaults to the client's default_timeout. + + Returns: + GitHubResponse[None]: Empty response (204 No Content) with headers. + """ + body: dict[str, Any] = {"ref": ref} + if inputs is not None: + body["inputs"] = inputs + response = await self._request( + "POST", + f"/repos/{owner}/{repo}/actions/workflows/{workflow_id}/dispatches", + timeout=timeout, + json=body, + ) + return GitHubResponse[None].model_validate({"data": None, "headers": dict(response.headers)}) + + async def get_workflow_run( + self, + owner: str, + repo: str, + run_id: int, + timeout: float | None = None, + ) -> GitHubResponse[WorkflowRun]: + """ + Calls the GitHub API to get a single workflow run. + + GitHub API Documentation: + https://docs.github.com/en/rest/actions/workflow-runs#get-a-workflow-run + + Args: + owner: Repository owner (user or organisation). + repo: Repository name. + run_id: Numeric ID of the workflow run. + timeout: Optional timeout for this specific request. Defaults to the client's default_timeout. + + Returns: + GitHubResponse[WorkflowRun]: The validated workflow run data and headers. + """ + response = await self._request("GET", f"/repos/{owner}/{repo}/actions/runs/{run_id}", timeout=timeout) + return self._parse_response(response, WorkflowRun) + + async def list_workflow_run_artifacts( + self, + owner: str, + repo: str, + run_id: int, + per_page: int = 30, + timeout: float | None = None, + ) -> AsyncIterator[GitHubResponse[ArtifactsList]]: + """ + Calls the GitHub API to list artifacts for a workflow run (paginated). + + GitHub API Documentation: + https://docs.github.com/en/rest/actions/artifacts#list-workflow-run-artifacts + + Args: + owner: Repository owner (user or organisation). + repo: Repository name. + run_id: Numeric ID of the workflow run. + per_page: Number of artifacts per page (default 30, max 100). + timeout: Optional timeout for this specific request. Defaults to the client's default_timeout. + + Returns: + AsyncIterator[GitHubResponse[ArtifactsList]]: One page of artifacts per iteration. + """ + endpoint = f"/repos/{owner}/{repo}/actions/runs/{run_id}/artifacts" + async for response in self._paginated_request("GET", endpoint, timeout=timeout, params={"per_page": per_page}): + yield self._parse_response(response, ArtifactsList) + + async def create_issue_comment( + self, + owner: str, + repo: str, + issue_number: int, + body: str, + timeout: float | None = None, + ) -> GitHubResponse[IssueComment]: + """ + Calls the GitHub API to create a comment on an issue or pull request. + + GitHub API Documentation: + https://docs.github.com/en/rest/issues/comments#create-an-issue-comment + + Args: + owner: Repository owner (user or organisation). + repo: Repository name. + issue_number: Issue or pull request number. + body: Markdown body text of the comment. + timeout: Optional timeout for this specific request. Defaults to the client's default_timeout. + + Returns: + GitHubResponse[IssueComment]: The validated comment data and headers. + """ + response = await self._request( + "POST", + f"/repos/{owner}/{repo}/issues/{issue_number}/comments", + timeout=timeout, + json={"body": body}, + ) + return self._parse_response(response, IssueComment) + + async def create_pr_review_comment( + self, + owner: str, + repo: str, + pull_number: int, + body: str, + commit_id: str, + path: str, + position: int | None = None, + line: int | None = None, + side: Literal["LEFT", "RIGHT"] | None = None, + timeout: float | None = None, + ) -> GitHubResponse[PullRequestReviewComment]: + """ + Calls the GitHub API to create an inline review comment on a pull request diff. + + GitHub API Documentation: + https://docs.github.com/en/rest/pulls/comments#create-a-review-comment-for-a-pull-request + + Args: + owner: Repository owner (user or organisation). + repo: Repository name. + pull_number: Pull request number. + body: Markdown body text of the review comment. + commit_id: SHA of the commit to comment on. + path: Relative path of the file to comment on. + position: Line index in the diff (deprecated but still supported by the API). + line: Line number in the file to comment on (used with `side`). + side: Side of the diff to comment on — ``"LEFT"`` or ``"RIGHT"``. + timeout: Optional timeout for this specific request. Defaults to the client's default_timeout. + + Returns: + GitHubResponse[PullRequestReviewComment]: The validated review comment data and headers. + """ + payload: dict[str, Any] = {"body": body, "commit_id": commit_id, "path": path} + if position is not None: + payload["position"] = position + if line is not None: + payload["line"] = line + if side is not None: + payload["side"] = side + response = await self._request( + "POST", + f"/repos/{owner}/{repo}/pulls/{pull_number}/comments", + timeout=timeout, + json=payload, + ) + return self._parse_response(response, PullRequestReviewComment) + + +# --------------------------------------------------------------------------- +# Context manager helper +# --------------------------------------------------------------------------- + + +@asynccontextmanager +async def async_github_client( + token: str, + default_timeout: float = 30.0, + transport: httpx.AsyncBaseTransport | None = None, +) -> AsyncIterator[AsyncGitHubClient]: + """ + Async context manager that creates an AsyncGitHubClient and ensures it is closed on exit. + + Args: + token: GitHub personal access token or app token. + default_timeout: Default request timeout in seconds. + transport: Optional custom HTTPX transport (useful for testing with MockTransport). + + Yields: + AsyncGitHubClient: A ready-to-use async GitHub client. + """ + client = AsyncGitHubClient(token=token, default_timeout=default_timeout, transport=transport) + try: + yield client + finally: + await client.aclose() diff --git a/ddev/tests/utils/test_github_async.py b/ddev/tests/utils/test_github_async.py new file mode 100644 index 0000000000000..6b02f9f8cec57 --- /dev/null +++ b/ddev/tests/utils/test_github_async.py @@ -0,0 +1,428 @@ +"""Tests for the async GitHub API client.""" + +from __future__ import annotations + +import dataclasses +import json +from typing import Any + +import httpx +import pytest + +from ddev.utils.github_async import ( + GITHUB_API_VERSION, + ArtifactsList, + AsyncGitHubClient, + GitHubResponse, + IssueComment, + PaginationData, + PullRequestReviewComment, + WorkflowRun, + async_github_client, +) + +# --------------------------------------------------------------------------- +# Helpers +# --------------------------------------------------------------------------- + +TOKEN = "ghp_test_token" + + +def _json_response(data: Any, status_code: int = 200, headers: dict[str, str] | None = None) -> httpx.Response: + all_headers = {"content-type": "application/json"} + if headers: + all_headers.update(headers) + return httpx.Response(status_code, json=data, headers=all_headers) + + +def _make_client(handler: httpx.MockTransport | None = None) -> AsyncGitHubClient: + transport = handler or httpx.MockTransport(lambda r: httpx.Response(200)) + return AsyncGitHubClient(token=TOKEN, transport=transport) + + +def _artifact(idx: int) -> dict[str, Any]: + return { + "id": idx, + "name": f"artifact-{idx}", + "size_in_bytes": 100 * idx, + "url": f"https://api.github.com/artifact/{idx}", + "archive_download_url": f"https://api.github.com/artifact/{idx}/zip", + "expired": False, + } + + +def _workflow_run_payload() -> dict[str, Any]: + return { + "id": 42, + "name": "CI", + "status": "completed", + "conclusion": "success", + "html_url": "https://github.com/owner/repo/actions/runs/42", + "created_at": "2024-01-01T00:00:00Z", + "updated_at": "2024-01-01T01:00:00Z", + } + + +def _issue_comment_payload() -> dict[str, Any]: + return { + "id": 1, + "body": "Hello world", + "user": {"login": "octocat"}, + "created_at": "2024-01-01T00:00:00Z", + "updated_at": "2024-01-01T00:00:00Z", + "html_url": "https://github.com/owner/repo/issues/1#issuecomment-1", + } + + +def _pr_review_comment_payload() -> dict[str, Any]: + return { + "id": 10, + "body": "Nice change", + "path": "src/foo.py", + "commit_id": "abc123", + "html_url": "https://github.com/owner/repo/pull/1#discussion_r10", + "created_at": "2024-01-01T00:00:00Z", + "updated_at": "2024-01-01T00:00:00Z", + "user": {"login": "reviewer"}, + } + + +# --------------------------------------------------------------------------- +# PaginationData +# --------------------------------------------------------------------------- + +_BASE = "https://api.github.com" + + +@pytest.mark.parametrize( + ("header", "expected"), + [ + (None, PaginationData()), + ("", PaginationData()), + (f'<{_BASE}/page2>; rel="next"', PaginationData(next=f"{_BASE}/page2")), + (f'<{_BASE}/page10>; rel="last"', PaginationData(last=f"{_BASE}/page10")), + ( + f'<{_BASE}/page2>; rel="next", <{_BASE}/page5>; rel="last"', + PaginationData(next=f"{_BASE}/page2", last=f"{_BASE}/page5"), + ), + ( + f'<{_BASE}/page1>; rel="first", <{_BASE}/page1>; rel="prev",' + f' <{_BASE}/page3>; rel="next", <{_BASE}/page5>; rel="last"', + PaginationData(first=f"{_BASE}/page1", prev=f"{_BASE}/page1", next=f"{_BASE}/page3", last=f"{_BASE}/page5"), + ), + ( + f'<{_BASE}/page1>; rel="prev", <{_BASE}/page5>; rel="last"', + PaginationData(prev=f"{_BASE}/page1", last=f"{_BASE}/page5"), + ), + (f'<{_BASE}/page1>; rel="first"', PaginationData(first=f"{_BASE}/page1")), + ], + ids=["none", "blank", "next_only", "last_only", "next_and_last", "all_links", "prev_and_last", "first_only"], +) +def test_pagination_data_from_header(header: str | None, expected: PaginationData) -> None: + p = PaginationData.from_header(header) + for f in dataclasses.fields(expected): + assert getattr(p, f.name) == getattr(expected, f.name) + + +# --------------------------------------------------------------------------- +# AsyncGitHubClient construction +# --------------------------------------------------------------------------- + + +def test_client_empty_token_raises() -> None: + with pytest.raises(ValueError, match="token"): + AsyncGitHubClient(token="") + + +def test_client_valid_token_builds_client() -> None: + client = AsyncGitHubClient(token=TOKEN) + assert isinstance(client._client, httpx.AsyncClient) + assert "Bearer ghp_test_token" in client._client.headers.get("authorization", "") # must not raise + + +@pytest.mark.asyncio +async def test_client_request_headers() -> None: + captured: httpx.Headers | None = None + + def handler(request: httpx.Request) -> httpx.Response: + nonlocal captured + captured = request.headers + return _json_response(_workflow_run_payload()) + + client = _make_client(httpx.MockTransport(handler)) + await client.get_workflow_run("o", "r", 42) + + assert captured is not None + assert captured["authorization"] == f"Bearer {TOKEN}" + assert captured["x-github-api-version"] == GITHUB_API_VERSION + assert captured["accept"] == "application/vnd.github+json" + + +# --------------------------------------------------------------------------- +# async_github_client context manager +# --------------------------------------------------------------------------- + + +@pytest.mark.asyncio +async def test_context_manager_yields_client() -> None: + async with async_github_client(token=TOKEN) as client: + assert not client._client.is_closed + + +@pytest.mark.asyncio +async def test_context_manager_closes_on_exit() -> None: + async with async_github_client(token=TOKEN) as client: + inner = client._client + # After exit the underlying client is closed; a new request would fail + assert inner.is_closed + + +# --------------------------------------------------------------------------- +# create_workflow_dispatch +# --------------------------------------------------------------------------- + + +@pytest.mark.asyncio +async def test_create_workflow_dispatch_success() -> None: + def handler(request: httpx.Request) -> httpx.Response: + assert request.method == "POST" + assert "/actions/workflows/my-workflow.yml/dispatches" in request.url.path + body = json.loads(request.content) + assert body["ref"] == "main" + assert "inputs" not in body + return httpx.Response(204, headers={"x-ratelimit-remaining": "59"}) + + client = _make_client(httpx.MockTransport(handler)) + result = await client.create_workflow_dispatch("owner", "repo", "my-workflow.yml", "main") + assert isinstance(result, GitHubResponse) + assert result.data is None + assert result.headers.get("x-ratelimit-remaining") == "59" + + +@pytest.mark.asyncio +async def test_create_workflow_dispatch_with_inputs() -> None: + def handler(request: httpx.Request) -> httpx.Response: + body = json.loads(request.content) + assert body["inputs"] == {"env": "prod"} + return httpx.Response(204) + + client = _make_client(httpx.MockTransport(handler)) + await client.create_workflow_dispatch("o", "r", 123, "main", inputs={"env": "prod"}) + + +@pytest.mark.asyncio +async def test_create_workflow_dispatch_http_error_raises() -> None: + client = _make_client(httpx.MockTransport(lambda r: httpx.Response(422))) + with pytest.raises(httpx.HTTPStatusError) as exc_info: + await client.create_workflow_dispatch("o", "r", "wf.yml", "main") + assert exc_info.value.response.status_code == 422 + + +# --------------------------------------------------------------------------- +# get_workflow_run +# --------------------------------------------------------------------------- + + +@pytest.mark.asyncio +async def test_get_workflow_run_success() -> None: + def handler(request: httpx.Request) -> httpx.Response: + assert request.method == "GET" + assert "/actions/runs/42" in request.url.path + return _json_response(_workflow_run_payload()) + + client = _make_client(httpx.MockTransport(handler)) + result = await client.get_workflow_run("owner", "repo", 42) + assert isinstance(result.data, WorkflowRun) + assert result.data.id == 42 + assert result.data.status == "completed" + + +@pytest.mark.asyncio +async def test_get_workflow_run_headers_forwarded() -> None: + def handler(_: httpx.Request) -> httpx.Response: + return _json_response(_workflow_run_payload(), headers={"x-ratelimit-remaining": "50"}) + + client = _make_client(httpx.MockTransport(handler)) + result = await client.get_workflow_run("o", "r", 42) + assert result.headers.get("x-ratelimit-remaining") == "50" + + +@pytest.mark.asyncio +async def test_get_workflow_run_http_error_raises() -> None: + client = _make_client(httpx.MockTransport(lambda r: httpx.Response(404))) + with pytest.raises(httpx.HTTPStatusError) as exc_info: + await client.get_workflow_run("o", "r", 99) + assert exc_info.value.response.status_code == 404 + + +# --------------------------------------------------------------------------- +# list_workflow_run_artifacts (pagination) +# --------------------------------------------------------------------------- + + +@pytest.mark.asyncio +async def test_list_workflow_run_artifacts_single_page() -> None: + artifacts = [_artifact(1), _artifact(2)] + + def handler(_: httpx.Request) -> httpx.Response: + return _json_response({"total_count": 2, "artifacts": artifacts}) + + client = _make_client(httpx.MockTransport(handler)) + pages = [] + async for page in client.list_workflow_run_artifacts("owner", "repo", 1): + pages.append(page) + + assert len(pages) == 1 + assert isinstance(pages[0].data, ArtifactsList) + assert pages[0].data.total_count == 2 + assert len(pages[0].data.artifacts) == 2 + + +@pytest.mark.asyncio +async def test_list_workflow_run_artifacts_two_pages() -> None: + page1_artifacts = [_artifact(1)] + page2_artifacts = [_artifact(2)] + call_count = 0 + + def handler(request: httpx.Request) -> httpx.Response: + nonlocal call_count + call_count += 1 + if call_count == 1: + link = f'<{request.url.scheme}://{request.url.host}/page2>; rel="next"' + return _json_response( + {"total_count": 2, "artifacts": page1_artifacts}, + headers={"link": link}, + ) + return _json_response({"total_count": 2, "artifacts": page2_artifacts}) + + client = _make_client(httpx.MockTransport(handler)) + pages = [] + async for page in client.list_workflow_run_artifacts("owner", "repo", 1): + pages.append(page) + + assert len(pages) == 2 + assert pages[0].data.artifacts[0].id == 1 + assert pages[1].data.artifacts[0].id == 2 + + +@pytest.mark.asyncio +async def test_list_workflow_run_artifacts_pagination_stops_when_no_next() -> None: + def handler(_: httpx.Request) -> httpx.Response: + return _json_response({"total_count": 1, "artifacts": [_artifact(1)]}) + + client = _make_client(httpx.MockTransport(handler)) + count = 0 + async for _ in client.list_workflow_run_artifacts("owner", "repo", 1): + count += 1 + assert count == 1 + + +@pytest.mark.asyncio +async def test_list_workflow_run_artifacts_http_error_raises() -> None: + client = _make_client(httpx.MockTransport(lambda r: httpx.Response(403))) + with pytest.raises(httpx.HTTPStatusError) as exc_info: + async for _ in client.list_workflow_run_artifacts("o", "r", 1): + pass + assert exc_info.value.response.status_code == 403 + + +@pytest.mark.asyncio +async def test_list_workflow_run_artifacts_per_page_forwarded() -> None: + def handler(request: httpx.Request) -> httpx.Response: + assert request.url.params["per_page"] == "100" + return _json_response({"total_count": 0, "artifacts": []}) + + client = _make_client(httpx.MockTransport(handler)) + async for _ in client.list_workflow_run_artifacts("owner", "repo", 1, per_page=100): + pass + + +# --------------------------------------------------------------------------- +# create_issue_comment +# --------------------------------------------------------------------------- + + +@pytest.mark.asyncio +async def test_create_issue_comment_success() -> None: + def handler(request: httpx.Request) -> httpx.Response: + assert request.method == "POST" + assert "/issues/7/comments" in request.url.path + body = json.loads(request.content) + assert body["body"] == "LGTM" + return _json_response({**_issue_comment_payload(), "body": "LGTM"}, status_code=201) + + client = _make_client(httpx.MockTransport(handler)) + result = await client.create_issue_comment("owner", "repo", 7, "LGTM") + assert isinstance(result.data, IssueComment) + assert result.data.body == "LGTM" + + +@pytest.mark.asyncio +async def test_create_issue_comment_http_error_raises() -> None: + client = _make_client(httpx.MockTransport(lambda r: httpx.Response(404))) + with pytest.raises(httpx.HTTPStatusError) as exc_info: + await client.create_issue_comment("o", "r", 1, "hi") + assert exc_info.value.response.status_code == 404 + + +# --------------------------------------------------------------------------- +# create_pr_review_comment +# --------------------------------------------------------------------------- + + +@pytest.mark.asyncio +async def test_create_pr_review_comment_success_with_position() -> None: + def handler(request: httpx.Request) -> httpx.Response: + assert "/pulls/3/comments" in request.url.path + body = json.loads(request.content) + assert body["commit_id"] == "abc123" + assert body["path"] == "src/foo.py" + assert body["position"] == 5 + assert "line" not in body + return _json_response(_pr_review_comment_payload(), status_code=201) + + client = _make_client(httpx.MockTransport(handler)) + result = await client.create_pr_review_comment( + "owner", "repo", 3, "Nice change", "abc123", "src/foo.py", position=5 + ) + assert isinstance(result.data, PullRequestReviewComment) + assert result.data.commit_id == "abc123" + + +@pytest.mark.asyncio +async def test_create_pr_review_comment_success_with_line_and_side() -> None: + def handler(request: httpx.Request) -> httpx.Response: + body = json.loads(request.content) + assert body["line"] == 10 + assert body["side"] == "RIGHT" + assert "position" not in body + return _json_response(_pr_review_comment_payload(), status_code=201) + + client = _make_client(httpx.MockTransport(handler)) + result = await client.create_pr_review_comment("o", "r", 1, "comment", "abc123", "file.py", line=10, side="RIGHT") + assert isinstance(result.data, PullRequestReviewComment) + + +@pytest.mark.asyncio +async def test_create_pr_review_comment_http_error_raises() -> None: + client = _make_client(httpx.MockTransport(lambda r: httpx.Response(422))) + with pytest.raises(httpx.HTTPStatusError) as exc_info: + await client.create_pr_review_comment("o", "r", 1, "body", "sha", "path") + assert exc_info.value.response.status_code == 422 + + +# --------------------------------------------------------------------------- +# Custom timeout per request +# --------------------------------------------------------------------------- + + +@pytest.mark.asyncio +async def test_per_request_timeout_forwarded() -> None: + """Ensure per-request timeout reaches the transport without raising.""" + + def handler(request: httpx.Request) -> httpx.Response: + return _json_response(_workflow_run_payload()) + + client = AsyncGitHubClient(token=TOKEN, default_timeout=5.0, transport=httpx.MockTransport(handler)) + result = await client.get_workflow_run("o", "r", 42, timeout=2.0) + assert result.data.id == 42 From dda3ca2878617bae93e482f3f9d705007b6143f4 Mon Sep 17 00:00:00 2001 From: Juanpe Araque Date: Thu, 23 Apr 2026 11:03:33 +0200 Subject: [PATCH 2/7] Add central workflow_run poster for PR comments (#23415) * Add central workflow_run-triggered PR comment poster Introduces .github/workflows/post-pr-comment.yml and its trust policy. The workflow runs on workflow_run from the default branch so fork PRs cannot modify it. It consumes a well-known pr-comment artifact contract (body.md + meta.json) produced by upstream workflows, resolves the PR number from the event (not the artifact), validates the comment marker, exchanges OIDC via dd-octo-sts, and posts or updates the comment. The STS policy pins event_name=workflow_run, ref=refs/heads/master, ref_protected=true, and job_workflow_ref to this workflow on master, so only the master-committed version can ever mint the token. Scope is limited to issues: write (PR conversation comments use the Issues API). * Own the comment marker inside post-pr-comment.yml The marker that find-comment uses to locate a previously posted comment is now derived from github.event.workflow_run.name (slugified) instead of read from an artifact file. The central workflow prepends the marker to body.md before posting, so the find/post pair is consistent by construction and producers cannot misconfigure it. Also scopes find-comment to the dd-octo-sts[bot] author so a contributor comment cannot be hijacked even if it happens to contain the marker string. Artifact contract shrinks to just body.md (meta.json is gone). * Pre-check artifact existence so missing uploads skip cleanly Previously the download step used continue-on-error to tolerate runs that produced no artifact, which left the step marked as failed in the UI even though the job succeeded. Replace it with a gh api pre-check: if the pr-comment artifact is absent we set an output that gates every downstream step, and the download step itself only runs when we know the artifact is there. A real download failure now surfaces as a real failure, and the no-artifact case is a quiet, clean skip. * Use the STS token end-to-end in post-pr-comment.yml Move the dd-octo-sts exchange to the first step and route every API call (artifact list, artifact download, commits/pulls lookup, find and post comment) through the resulting ephemeral token. The workflow's ambient permissions shrink to just id-token: write, which is the prerequisite for minting the OIDC token; GITHUB_TOKEN itself now carries no scopes. The STS policy grows to cover the additional reads the workflow needs: actions: read for the artifact, pull_requests: read for the PR lookup. issues: write is unchanged. --- ...self.post-pr-comment.workflow-run.sts.yaml | 52 ++++++ .github/workflows/post-pr-comment.yml | 162 ++++++++++++++++++ 2 files changed, 214 insertions(+) create mode 100644 .github/chainguard/self.post-pr-comment.workflow-run.sts.yaml create mode 100644 .github/workflows/post-pr-comment.yml diff --git a/.github/chainguard/self.post-pr-comment.workflow-run.sts.yaml b/.github/chainguard/self.post-pr-comment.workflow-run.sts.yaml new file mode 100644 index 0000000000000..307212edf368c --- /dev/null +++ b/.github/chainguard/self.post-pr-comment.workflow-run.sts.yaml @@ -0,0 +1,52 @@ +# Trust policy for the central PR-comment poster in DataDog/integrations-core +# +# This policy grants a scoped, ephemeral token for posting comments to pull +# requests. It is only reachable from the post-pr-comment.yml workflow +# committed to master; workflow_run always runs the default-branch version +# of the workflow, so fork-PR modifications cannot reach this policy. +# +# Naming convention: +# self: Only this repository (DataDog/integrations-core) can use this policy +# post-pr-comment: Central poster workflow +# workflow-run: Triggered by workflow_run events +# +# Security model: +# - event_name pinned to workflow_run (runs on master by design). +# - ref / ref_protected pinned to master so a rogue fork PR cannot mint this token +# even if it manages to invoke something else. +# - job_workflow_ref pinned to post-pr-comment.yml on master so unrelated +# workflow_run-triggered workflows cannot reuse this policy. +# +# Permissions granted: +# - issues: write - Create and update PR conversation comments +# (PR conversation comments use the Issues API, which is +# why the GitHub App scope is issues, not pull_requests). +# - actions: read - List and download the pr-comment artifact from the +# triggering workflow_run. +# - pull_requests: read - Resolve the open PR number from the workflow_run +# head SHA (commits/{sha}/pulls endpoint). +# +# Granting reads to the STS token means the workflow uses a single ephemeral +# credential end-to-end and never relies on GITHUB_TOKEN. +# +# Usage in workflows: +# - uses: DataDog/dd-octo-sts-action@96a25462dbcb10ebf0bfd6e2ccc917d2ab235b9a # v1.0.4 +# with: +# scope: DataDog/integrations-core +# policy: self.post-pr-comment.workflow-run + +issuer: https://token.actions.githubusercontent.com + +subject: repo:DataDog/integrations-core:ref:refs/heads/master + +claim_pattern: + event_name: workflow_run + ref: refs/heads/master + ref_protected: "true" + job_workflow_ref: DataDog/integrations-core/\.github/workflows/post-pr-comment\.yml@refs/heads/master + repository: DataDog/integrations-core + +permissions: + issues: write + actions: read + pull_requests: read diff --git a/.github/workflows/post-pr-comment.yml b/.github/workflows/post-pr-comment.yml new file mode 100644 index 0000000000000..093a09be4592d --- /dev/null +++ b/.github/workflows/post-pr-comment.yml @@ -0,0 +1,162 @@ +name: 'Post PR comment' + +# Central privileged poster for PR comments produced by fork-safe upstream +# workflows. +# +# Why this exists: +# pull_request events from forks cannot safely mint a writable token +# (attacker can modify the workflow YAML, exchange OIDC via dd-octo-sts, +# and get the policy-scoped token). workflow_run, in contrast, always +# runs the version of *this* workflow that lives on the default branch +# and is therefore invulnerable to fork-PR modification. The dd-octo-sts +# policy for this workflow pins ref=refs/heads/master, so only the +# master-committed version of this file can ever exchange for a token. +# +# Artifact contract (producer uploads; this workflow consumes): +# name: pr-comment +# files: +# body.md Markdown body to post. Treated as opaque, attacker-controlled text. +# +# This workflow owns the hidden marker that lets find-comment locate the +# previously-posted comment. The marker is derived from the triggering +# workflow's display name (slugified), so producers cannot misconfigure it +# and there is no attacker-controlled metadata to validate. The marker is +# prepended to body.md before the comment is posted. +# +# Trust boundaries enforced here: +# - PR number comes from the workflow_run event (head_sha -> commits/pulls +# API), never from the artifact. Prevents cross-PR comment injection. +# - Marker is derived from github.event.workflow_run.name (trusted GitHub +# event data), never from the artifact. +# - body.md is written directly to a file and passed via body-path. +# It is never shell-interpolated. +# - find-comment is scoped to the dd-octo-sts[bot] author so a contributor +# comment cannot be hijacked even if it happens to contain the marker. +# +# Credentials: +# A single ephemeral dd-octo-sts token is used for every API call +# (artifact list/download, PR lookup, comment find/post). The workflow's +# only ambient permission is id-token: write, which is the prerequisite +# to minting the STS token; GITHUB_TOKEN itself carries no scopes. +# +# Onboarding a new producer: +# 1) Append the producer's workflow display name to on.workflow_run.workflows. +# 2) Producer uploads a 'pr-comment' artifact containing body.md. +# 3) Pick a workflow display name that slugifies to a stable, unique id; +# the derived marker is "". + +on: + workflow_run: + workflows: + - 'Validate skip QA label' + types: [completed] + +permissions: + id-token: write # required to call the OIDC endpoint for dd-octo-sts + +jobs: + post: + if: github.event.workflow_run.conclusion == 'success' + runs-on: ubuntu-latest + steps: + # Mint the STS token first so every API call below uses a single + # ephemeral, scoped credential. The policy grants actions: read + + # pull_requests: read + issues: write, covering all of: listing and + # downloading the artifact, resolving the PR number, finding and + # updating the comment. + - name: Get token via dd-octo-sts + uses: DataDog/dd-octo-sts-action@96a25462dbcb10ebf0bfd6e2ccc917d2ab235b9a # v1.0.4 + id: octo-sts + with: + scope: DataDog/integrations-core + policy: self.post-pr-comment.workflow-run + + # A successful upstream run may legitimately not produce an artifact + # (e.g. the skip-qa producer only uploads when a comment is actually + # needed). Pre-check so the download step only runs when we know the + # artifact exists; that way a missing artifact is a clean skip rather + # than a failed step, and a real download failure remains a real + # failure we want to see. + - name: Check for comment artifact + id: check + env: + GH_TOKEN: ${{ steps.octo-sts.outputs.token }} + RUN_ID: ${{ github.event.workflow_run.id }} + REPO: ${{ github.repository }} + run: | + set -euo pipefail + count=$(gh api "repos/${REPO}/actions/runs/${RUN_ID}/artifacts" \ + --jq '[.artifacts[] | select(.name == "pr-comment")] | length') + if [[ "$count" -eq 0 ]]; then + echo "Upstream run ${RUN_ID} did not upload a pr-comment artifact. Nothing to post." + echo "skip=true" >> "$GITHUB_OUTPUT" + fi + + - name: Download comment artifact + if: steps.check.outputs.skip != 'true' + uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0 + with: + name: pr-comment + run-id: ${{ github.event.workflow_run.id }} + github-token: ${{ steps.octo-sts.outputs.token }} + path: pr-comment + + - name: Derive marker and prepend to body + if: steps.check.outputs.skip != 'true' + id: marker + env: + WORKFLOW_NAME: ${{ github.event.workflow_run.name }} + run: | + set -euo pipefail + slug=$(printf '%s' "$WORKFLOW_NAME" \ + | tr '[:upper:]' '[:lower:]' \ + | sed -E 's/[^a-z0-9]+/-/g; s/^-+|-+$//g' \ + | cut -c1-64) + if [[ -z "$slug" ]]; then + echo "Workflow name did not produce a usable slug: ${WORKFLOW_NAME}" >&2 + exit 1 + fi + marker="" + { + printf '%s\n\n' "$marker" + cat pr-comment/body.md + } > pr-comment/posted-body.md + echo "value=$marker" >> "$GITHUB_OUTPUT" + + - name: Resolve PR number from head SHA + if: steps.check.outputs.skip != 'true' + id: pr + env: + GH_TOKEN: ${{ steps.octo-sts.outputs.token }} + HEAD_SHA: ${{ github.event.workflow_run.head_sha }} + REPO: ${{ github.repository }} + run: | + set -euo pipefail + number=$(gh api "repos/${REPO}/commits/${HEAD_SHA}/pulls" \ + --jq '[.[] | select(.state == "open")][0].number // empty') + if [[ -z "$number" ]]; then + echo "No open PR matches head SHA ${HEAD_SHA}; nothing to post." >&2 + echo "skip=true" >> "$GITHUB_OUTPUT" + else + echo "number=$number" >> "$GITHUB_OUTPUT" + fi + + - name: Find existing comment + if: steps.check.outputs.skip != 'true' && steps.pr.outputs.skip != 'true' + uses: peter-evans/find-comment@b30e6a3c0ed37e7c023ccd3f1db5c6c0b0c23aad # v4.0.0 + id: find_comment + with: + token: ${{ steps.octo-sts.outputs.token }} + issue-number: ${{ steps.pr.outputs.number }} + body-includes: ${{ steps.marker.outputs.value }} + comment-author: 'dd-octo-sts[bot]' + + - name: Post comment + if: steps.check.outputs.skip != 'true' && steps.pr.outputs.skip != 'true' + uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5.0.0 + with: + token: ${{ steps.octo-sts.outputs.token }} + issue-number: ${{ steps.pr.outputs.number }} + body-path: pr-comment/posted-body.md + comment-id: ${{ steps.find_comment.outputs.comment-id }} + edit-mode: replace From 8571f62fb60896d658a209a2a7255c192dc74ee0 Mon Sep 17 00:00:00 2001 From: Juanpe Araque Date: Thu, 23 Apr 2026 11:06:34 +0200 Subject: [PATCH 3/7] Add eula validation to the validate all orchestrator (#23346) * Add eula validation to the validate all orchestrator The eula validation is needed by marketplace but was missing from the orchestrator's VALIDATIONS dict, so ddev validate all would skip it. * Add changelog entry * Fix validate all tests to mock _load_validations --- ddev/changelog.d/23346.added | 1 + ddev/src/ddev/cli/validate/all/orchestrator.py | 3 +++ ddev/tests/cli/validate/all/test_command.py | 15 ++++++++++++--- 3 files changed, 16 insertions(+), 3 deletions(-) create mode 100644 ddev/changelog.d/23346.added diff --git a/ddev/changelog.d/23346.added b/ddev/changelog.d/23346.added new file mode 100644 index 0000000000000..e82be3e098d04 --- /dev/null +++ b/ddev/changelog.d/23346.added @@ -0,0 +1 @@ +Add eula validation to the validate all orchestrator diff --git a/ddev/src/ddev/cli/validate/all/orchestrator.py b/ddev/src/ddev/cli/validate/all/orchestrator.py index 4729f5660ad4b..9a6c7e8c8ba04 100644 --- a/ddev/src/ddev/cli/validate/all/orchestrator.py +++ b/ddev/src/ddev/cli/validate/all/orchestrator.py @@ -58,6 +58,9 @@ class ValidationConfig: description="Verify dependency pins are consistent and Agent-compatible", repo_wide=True, ), + "eula": ValidationConfig( + description="Validate EULA definition files", + ), "http": ValidationConfig( description="Validate integrations use the HTTP wrapper correctly", ), diff --git a/ddev/tests/cli/validate/all/test_command.py b/ddev/tests/cli/validate/all/test_command.py index 847de9d1eef95..5395b51c7daa0 100644 --- a/ddev/tests/cli/validate/all/test_command.py +++ b/ddev/tests/cli/validate/all/test_command.py @@ -23,7 +23,10 @@ def fake_run(cmd, **kwargs): invoked.append(cmd[-1]) return completed_process(returncode=0, stdout="ok") - with patch("subprocess.run", side_effect=fake_run): + with ( + patch("ddev.cli.validate.all._load_validations", return_value=VALIDATIONS), + patch("subprocess.run", side_effect=fake_run), + ): result = ddev("validate", "all", *FAST_ORCHESTRATOR_OPTS) assert result.exit_code == 0, result.output @@ -68,7 +71,10 @@ def fake_run(cmd, **kwargs): captured[cmd[-1] if cmd[-1] != "changed" else cmd[-2]] = list(cmd) return completed_process(returncode=0, stdout="ok") - with patch("subprocess.run", side_effect=fake_run): + with ( + patch("ddev.cli.validate.all._load_validations", return_value=VALIDATIONS), + patch("subprocess.run", side_effect=fake_run), + ): result = ddev("validate", "all", "changed", *FAST_ORCHESTRATOR_OPTS) assert result.exit_code == 0, result.output @@ -88,7 +94,10 @@ def fake_run(cmd, **kwargs): captured[name] = list(cmd) return completed_process(returncode=0, stdout="ok") - with patch("subprocess.run", side_effect=fake_run): + with ( + patch("ddev.cli.validate.all._load_validations", return_value=VALIDATIONS), + patch("subprocess.run", side_effect=fake_run), + ): result = ddev("validate", "all", "--fix", *FAST_ORCHESTRATOR_OPTS) assert result.exit_code == 0, result.output From 125a5792728a799d708d16c4a5a1bc438882d105 Mon Sep 17 00:00:00 2001 From: NouemanKHAL Date: Thu, 23 Apr 2026 11:53:35 +0200 Subject: [PATCH 4/7] Suppress "already exists" noise in ddev release tag output (#22883) * suppress already exists noise in ddev release tag output * add a summary log message for better visibility * changelog * address feedback * improve repo_root handling to be properly set and unset at each test * test(ddev): mock git_tag_list in release tag test CI checkouts don't include historical release tags, so every integration was counted as "new" and the summary line read "Tagged N" instead of "Tagged 2". Snapshot the current release tags before bumping and patch git_tag_list so the assertion is independent of the checkout's tag state. * test(ddev): assert skipped count in release tag test Exercise the mix new + skipped path in a single run. --- datadog_checks_dev/changelog.d/22883.added | 1 + .../dev/tooling/commands/release/tag.py | 28 +++--- .../tooling/commands/release/test_tag.py | 86 +++++++++++++++++++ 3 files changed, 104 insertions(+), 11 deletions(-) create mode 100644 datadog_checks_dev/changelog.d/22883.added create mode 100644 datadog_checks_dev/tests/tooling/commands/release/test_tag.py diff --git a/datadog_checks_dev/changelog.d/22883.added b/datadog_checks_dev/changelog.d/22883.added new file mode 100644 index 0000000000000..6514f806321eb --- /dev/null +++ b/datadog_checks_dev/changelog.d/22883.added @@ -0,0 +1 @@ +Suppress "already exists" noise in `ddev release tag` output. diff --git a/datadog_checks_dev/datadog_checks/dev/tooling/commands/release/tag.py b/datadog_checks_dev/datadog_checks/dev/tooling/commands/release/tag.py index 42fe506b0c369..6e993c9276ee3 100644 --- a/datadog_checks_dev/datadog_checks/dev/tooling/commands/release/tag.py +++ b/datadog_checks_dev/datadog_checks/dev/tooling/commands/release/tag.py @@ -6,6 +6,7 @@ from datadog_checks.dev.tooling.commands.console import ( CONTEXT_SETTINGS, abort, + echo_debug, echo_info, echo_success, echo_waiting, @@ -58,7 +59,8 @@ def tag(check, version, push, dry_run, skip_prerelease, fetch): checks = [check] # Check for any new tags - tagged = False + tagged = 0 + skipped = 0 # Fetch all tags from the remote if fetch: echo_info('Fetching all tags from remote...') @@ -69,28 +71,30 @@ def tag(check, version, push, dry_run, skip_prerelease, fetch): existing_tags = git_tag_list() for check in checks: - echo_info(f'{check}:') - # get the current version if not version: version = get_version_string(check) if skip_prerelease and version == PRERELEASE: - echo_warning('skipping prerelease version') + echo_debug(f'{check}: skipping prerelease version {version}') version = None continue # get the tag name release_tag = get_release_tag_string(check, version) + + if release_tag in existing_tags: + echo_debug(f'{check}: {release_tag} already exists') + skipped += 1 + version = None + continue + + echo_info(f'{check}:') echo_waiting(f'Tagging HEAD with {release_tag}... ', indent=True, nl=False) if dry_run: - # Get latest tag for check - if release_tag in existing_tags: - echo_warning('already exists (dry-run)') - else: - tagged = True - echo_success("success! (dry-run)") + tagged += 1 + echo_success("success! (dry-run)") version = None continue @@ -101,11 +105,13 @@ def tag(check, version, push, dry_run, skip_prerelease, fetch): elif result.code != 0: abort(f'\n{result.stdout}{result.stderr}', code=result.code) else: - tagged = True + tagged += 1 echo_success('success!') # Reset version version = None + echo_info(f'Tagged {tagged} release(s), skipped {skipped} already-tagged release(s).') + if not tagged: abort(code=2) diff --git a/datadog_checks_dev/tests/tooling/commands/release/test_tag.py b/datadog_checks_dev/tests/tooling/commands/release/test_tag.py new file mode 100644 index 0000000000000..64f18da71c890 --- /dev/null +++ b/datadog_checks_dev/tests/tooling/commands/release/test_tag.py @@ -0,0 +1,86 @@ +# (C) Datadog, Inc. 2024-present +# All rights reserved +# Licensed under a 3-clause BSD style license (see LICENSE) +import re +import subprocess +from pathlib import Path +from unittest.mock import patch + +from click.testing import CliRunner + +from datadog_checks.dev.tooling.commands import console +from datadog_checks.dev.tooling.commands.release.tag import tag +from datadog_checks.dev.tooling.constants import get_root, set_root +from datadog_checks.dev.tooling.release import get_release_tag_string +from datadog_checks.dev.tooling.utils import get_valid_checks, get_version_string + +REPO_ROOT = str(Path(__file__).parents[5]) + + +def test_new_version_appears_in_output(): + activemq_about = Path(f'{REPO_ROOT}/activemq/datadog_checks/activemq/__about__.py') + btrfs_about = Path(f'{REPO_ROOT}/btrfs/datadog_checks/btrfs/__about__.py') + original_activemq = activemq_about.read_text() + original_btrfs = btrfs_about.read_text() + original_root = get_root() + set_root(REPO_ROOT) + # Snapshot current release tags before bumping so the mocked set reflects pre-bump state. + existing_tags = {get_release_tag_string(c, get_version_string(c)) for c in get_valid_checks()} + activemq_about.write_text(re.sub(r"(?<=__version__ = ')[^']+", '99.99.99', original_activemq)) + btrfs_about.write_text(re.sub(r"(?<=__version__ = ')[^']+", '99.99.99', original_btrfs)) + try: + runner = CliRunner() + with patch('datadog_checks.dev.tooling.commands.release.tag.git_tag_list', return_value=existing_tags): + result = runner.invoke(tag, ['--no-fetch', '--no-push', '--dry-run', 'all'], catch_exceptions=False) + finally: + set_root(original_root) + activemq_about.write_text(original_activemq) + btrfs_about.write_text(original_btrfs) + + assert result.exit_code == 0 + assert 'activemq-99.99.99' in result.output + assert 'btrfs-99.99.99' in result.output + assert f'Tagged 2 release(s), skipped {len(existing_tags) - 2} already-tagged release(s).' in result.output + + +def test_existing_tag_silent_by_default(): + activemq_about = Path(f'{REPO_ROOT}/activemq/datadog_checks/activemq/__about__.py') + original = activemq_about.read_text() + activemq_about.write_text(re.sub(r"(?<=__version__ = ')[^']+", '99.99.99', original)) + subprocess.run( + ['git', '-C', REPO_ROOT, '-c', 'tag.gpgsign=false', 'tag', 'activemq-99.99.99'], check=True, capture_output=True + ) + original_root = get_root() + set_root(REPO_ROOT) + try: + result = CliRunner().invoke(tag, ['--no-fetch', '--no-push', '--dry-run', 'activemq'], catch_exceptions=False) + finally: + set_root(original_root) + activemq_about.write_text(original) + subprocess.run(['git', '-C', REPO_ROOT, 'tag', '-d', 'activemq-99.99.99'], check=True, capture_output=True) + + assert result.exit_code == 2 + assert 'Tagged 0 release(s), skipped 1 already-tagged release(s).' in result.output + + +def test_existing_tag_debug_message(): + activemq_about = Path(f'{REPO_ROOT}/activemq/datadog_checks/activemq/__about__.py') + original = activemq_about.read_text() + activemq_about.write_text(re.sub(r"(?<=__version__ = ')[^']+", '99.99.99', original)) + subprocess.run( + ['git', '-C', REPO_ROOT, '-c', 'tag.gpgsign=false', 'tag', 'activemq-99.99.99'], check=True, capture_output=True + ) + original_root = get_root() + set_root(REPO_ROOT) + console.set_debug() + try: + result = CliRunner().invoke(tag, ['--no-fetch', '--no-push', '--dry-run', 'activemq'], catch_exceptions=False) + finally: + set_root(original_root) + console.DEBUG_OUTPUT = False + activemq_about.write_text(original) + subprocess.run(['git', '-C', REPO_ROOT, 'tag', '-d', 'activemq-99.99.99'], check=True, capture_output=True) + + assert result.exit_code == 2 + assert 'activemq-99.99.99 already exists' in result.output + assert 'Tagged 0 release(s), skipped 1 already-tagged release(s).' in result.output From 6861a0b2a2c28bc8f04964a6c1edd24d977c465b Mon Sep 17 00:00:00 2001 From: Juanpe Araque Date: Thu, 23 Apr 2026 12:44:06 +0200 Subject: [PATCH 5/7] Fix post-pr-comment policy to request pull_requests:write (#23445) --- ...self.post-pr-comment.workflow-run.sts.yaml | 19 +++++++++++-------- .github/workflows/post-pr-comment.yml | 6 +++--- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/.github/chainguard/self.post-pr-comment.workflow-run.sts.yaml b/.github/chainguard/self.post-pr-comment.workflow-run.sts.yaml index 307212edf368c..d27eac2373bc3 100644 --- a/.github/chainguard/self.post-pr-comment.workflow-run.sts.yaml +++ b/.github/chainguard/self.post-pr-comment.workflow-run.sts.yaml @@ -18,16 +18,20 @@ # workflow_run-triggered workflows cannot reuse this policy. # # Permissions granted: -# - issues: write - Create and update PR conversation comments -# (PR conversation comments use the Issues API, which is -# why the GitHub App scope is issues, not pull_requests). +# - pull_requests: write - Create and update PR conversation comments. Although +# PR conversation comments are served by the Issues API +# endpoint (/repos/.../issues/{n}/comments), the endpoint +# accepts either issues:write or pull_requests:write, and +# we only ever comment on pull requests, never on plain +# issues. pull_requests:write is also what works in +# practice for the DD Octo STS installation in this repo. # - actions: read - List and download the pr-comment artifact from the # triggering workflow_run. -# - pull_requests: read - Resolve the open PR number from the workflow_run -# head SHA (commits/{sha}/pulls endpoint). # # Granting reads to the STS token means the workflow uses a single ephemeral -# credential end-to-end and never relies on GITHUB_TOKEN. +# credential end-to-end and never relies on GITHUB_TOKEN. pull_requests:write +# also subsumes the PR-number lookup (commits/{sha}/pulls) previously covered +# by pull_requests:read. # # Usage in workflows: # - uses: DataDog/dd-octo-sts-action@96a25462dbcb10ebf0bfd6e2ccc917d2ab235b9a # v1.0.4 @@ -47,6 +51,5 @@ claim_pattern: repository: DataDog/integrations-core permissions: - issues: write + pull_requests: write actions: read - pull_requests: read diff --git a/.github/workflows/post-pr-comment.yml b/.github/workflows/post-pr-comment.yml index 093a09be4592d..cc9982694a14d 100644 --- a/.github/workflows/post-pr-comment.yml +++ b/.github/workflows/post-pr-comment.yml @@ -61,9 +61,9 @@ jobs: steps: # Mint the STS token first so every API call below uses a single # ephemeral, scoped credential. The policy grants actions: read + - # pull_requests: read + issues: write, covering all of: listing and - # downloading the artifact, resolving the PR number, finding and - # updating the comment. + # pull_requests: write, covering all of: listing and downloading the + # artifact, resolving the PR number, and finding and updating the + # comment. - name: Get token via dd-octo-sts uses: DataDog/dd-octo-sts-action@96a25462dbcb10ebf0bfd6e2ccc917d2ab235b9a # v1.0.4 id: octo-sts From 06dc694dcdb9e9090ad9cab8b50705de0f1e96c5 Mon Sep 17 00:00:00 2001 From: mwdd146980 <96082814+mwdd146980@users.noreply.github.com> Date: Thu, 23 Apr 2026 06:58:21 -0400 Subject: [PATCH 6/7] Fix traefik_mesh: version metadata never submitted due to get_version() TypeError (#23435) * Fix traefik_mesh get_version() unused url parameter Co-Authored-By: Claude Opus 4.6 (1M context) * Add changelog for traefik_mesh get_version fix Co-Authored-By: Claude Opus 4.6 (1M context) * Add test_get_version to catch get_version() TypeError bug Co-Authored-By: Claude Sonnet 4.6 (1M context) * Fix changelog filename to match PR #23435 Co-Authored-By: Claude Sonnet 4.6 (1M context) * Use dd_run_check + assert_metadata in test_get_version Co-Authored-By: Claude Sonnet 4.6 (1M context) * Fix ruff 0.11.10 formatting: split long call arguments Co-Authored-By: Claude Sonnet 4.6 (1M context) --------- Co-authored-by: Claude Opus 4.6 (1M context) --- traefik_mesh/changelog.d/23435.fixed | 1 + .../datadog_checks/traefik_mesh/check.py | 2 +- traefik_mesh/tests/test_unit.py | 31 +++++++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 traefik_mesh/changelog.d/23435.fixed diff --git a/traefik_mesh/changelog.d/23435.fixed b/traefik_mesh/changelog.d/23435.fixed new file mode 100644 index 0000000000000..78cc53549adff --- /dev/null +++ b/traefik_mesh/changelog.d/23435.fixed @@ -0,0 +1 @@ +Fix `get_version()` signature so version metadata is actually submitted. diff --git a/traefik_mesh/datadog_checks/traefik_mesh/check.py b/traefik_mesh/datadog_checks/traefik_mesh/check.py index a1e1549f9c566..0495315e963c1 100644 --- a/traefik_mesh/datadog_checks/traefik_mesh/check.py +++ b/traefik_mesh/datadog_checks/traefik_mesh/check.py @@ -84,7 +84,7 @@ def get_mesh_ready_status(self): return node_status - def get_version(self, url): + def get_version(self): """Fetches Traefik Proxy version from the Proxy API""" version_url = urljoin(self.traefik_proxy_api_endpoint, PROXY_VERSION) diff --git a/traefik_mesh/tests/test_unit.py b/traefik_mesh/tests/test_unit.py index 6a7cb29d2507f..012efd1574bcb 100644 --- a/traefik_mesh/tests/test_unit.py +++ b/traefik_mesh/tests/test_unit.py @@ -108,6 +108,37 @@ def test_invalid_controller_service_check(aggregator, mock_http_response): aggregator.assert_service_check('traefik_mesh.controller.ready', ServiceCheck.CRITICAL) +def test_get_version(datadog_agent, dd_run_check, mock_http_response_per_endpoint): + from datadog_checks.dev.http import MockResponse + + instance = { + 'openmetrics_endpoint': 'http://localhost:8080/metrics', + 'traefik_proxy_api_endpoint': 'http://localhost:8080', + 'tags': ['test:traefik_mesh'], + } + check = TraefikMeshCheck('traefik_mesh', {}, [instance]) + check.check_id = 'test:123' + + mock_http_response_per_endpoint( + { + 'http://localhost:8080/metrics': [MockResponse(file_path=get_fixture_path('traefik_proxy.txt'))], + 'http://localhost:8080/api/version': [MockResponse(file_path=get_fixture_path('mesh_proxy_version.json'))], + } + ) + dd_run_check(check) + + datadog_agent.assert_metadata( + 'test:123', + { + 'version.raw': '2.5.7', + 'version.scheme': 'semver', + 'version.major': '2', + 'version.minor': '5', + 'version.patch': '7', + }, + ) + + def test_submit_version(datadog_agent, dd_run_check, mock_http_response): check = TraefikMeshCheck('traefik_mesh', {}, [OM_MOCKED_INSTANCE]) mock_http_response(file_path=get_fixture_path('traefik_proxy.txt')) From 2c390e4e599dc6ba1cef1d5e820e8196770f4b66 Mon Sep 17 00:00:00 2001 From: Kyle Neale Date: Thu, 23 Apr 2026 09:47:39 -0400 Subject: [PATCH 7/7] build: bump OpenSSL from 3.6.1 to 3.6.2 in all builder images (#23215) * build: bump OpenSSL to 3.6.2 in all builder images * Update dependency resolution --------- Co-authored-by: dd-agent-integrations-bot[bot] --- .builders/images/linux-aarch64/Dockerfile | 4 +- .builders/images/linux-x86_64/Dockerfile | 4 +- .builders/images/macos/builder_setup.sh | 4 +- .builders/images/windows-x86_64/Dockerfile | 4 +- .../images/windows-x86_64/build_script.ps1 | 2 +- .deps/builder_inputs.toml | 6 +-- .deps/image_digests.json | 6 +-- .deps/resolved/linux-aarch64_3.13.txt | 38 +++++++++---------- .deps/resolved/linux-x86_64_3.13.txt | 38 +++++++++---------- .deps/resolved/macos-aarch64_3.13.txt | 30 +++++++-------- .deps/resolved/macos-x86_64_3.13.txt | 30 +++++++-------- .deps/resolved/windows-x86_64_3.13.txt | 34 ++++++++--------- 12 files changed, 100 insertions(+), 100 deletions(-) diff --git a/.builders/images/linux-aarch64/Dockerfile b/.builders/images/linux-aarch64/Dockerfile index 85cc9a048b8e1..00b9506d5e98e 100644 --- a/.builders/images/linux-aarch64/Dockerfile +++ b/.builders/images/linux-aarch64/Dockerfile @@ -19,8 +19,8 @@ ENV LDFLAGS="-Wl,-rpath,'\$\$ORIGIN' -Wl,--strip-debug" RUN yum install -y perl-IPC-Cmd perl-CPANPLUS perl-core && \ cpanp -i List::Util 1.66 && \ DOWNLOAD_URL="https://www.openssl.org/source/openssl-{{version}}.tar.gz" \ - VERSION="3.6.1" \ - SHA256="b1bfedcd5b289ff22aee87c9d600f515767ebf45f77168cb6d64f231f518a82e" \ + VERSION="3.6.2" \ + SHA256="aaf51a1fe064384f811daeaeb4ec4dce7340ec8bd893027eee676af31e83a04f" \ RELATIVE_PATH="openssl-{{version}}" \ # https://docs.python.org/3/using/unix.html#custom-openssl INSTALL_COMMAND="make install_sw" \ diff --git a/.builders/images/linux-x86_64/Dockerfile b/.builders/images/linux-x86_64/Dockerfile index ce75485d38678..1455252b42a62 100644 --- a/.builders/images/linux-x86_64/Dockerfile +++ b/.builders/images/linux-x86_64/Dockerfile @@ -19,8 +19,8 @@ ENV LDFLAGS="-Wl,-rpath,'\$\$ORIGIN' -Wl,--strip-debug" RUN yum install -y perl-IPC-Cmd perl-CPANPLUS perl-core && \ cpanp -i List::Util 1.66 && \ DOWNLOAD_URL="https://www.openssl.org/source/openssl-{{version}}.tar.gz" \ - VERSION="3.6.1" \ - SHA256="b1bfedcd5b289ff22aee87c9d600f515767ebf45f77168cb6d64f231f518a82e" \ + VERSION="3.6.2" \ + SHA256="aaf51a1fe064384f811daeaeb4ec4dce7340ec8bd893027eee676af31e83a04f" \ RELATIVE_PATH="openssl-{{version}}" \ # https://docs.python.org/3/using/unix.html#custom-openssl INSTALL_COMMAND="make install_sw" \ diff --git a/.builders/images/macos/builder_setup.sh b/.builders/images/macos/builder_setup.sh index 74df25381da4f..9861d47937b8d 100644 --- a/.builders/images/macos/builder_setup.sh +++ b/.builders/images/macos/builder_setup.sh @@ -23,8 +23,8 @@ cp -R /opt/mqm "${DD_PREFIX_PATH}" # openssl DOWNLOAD_URL="https://www.openssl.org/source/openssl-{{version}}.tar.gz" \ -VERSION="3.6.1" \ -SHA256="b1bfedcd5b289ff22aee87c9d600f515767ebf45f77168cb6d64f231f518a82e" \ +VERSION="3.6.2" \ +SHA256="aaf51a1fe064384f811daeaeb4ec4dce7340ec8bd893027eee676af31e83a04f" \ RELATIVE_PATH="openssl-{{version}}" \ CONFIGURE_SCRIPT="./config" \ install-from-source \ diff --git a/.builders/images/windows-x86_64/Dockerfile b/.builders/images/windows-x86_64/Dockerfile index 4a797271be2b8..af3b6735d7838 100644 --- a/.builders/images/windows-x86_64/Dockerfile +++ b/.builders/images/windows-x86_64/Dockerfile @@ -127,11 +127,11 @@ RUN Get-RemoteFile ` Add-ToPath -Append "C:\nasm\nasm-$Env:NASM_VERSION" && ` Remove-Item "nasm-$Env:NASM_VERSION-win64.zip" -ENV OPENSSL_VERSION="3.6.1" +ENV OPENSSL_VERSION="3.6.2" RUN Get-RemoteFile ` -Uri https://www.openssl.org/source/openssl-$Env:OPENSSL_VERSION.tar.gz ` -Path openssl-$Env:OPENSSL_VERSION.tar.gz ` - -Hash 'b1bfedcd5b289ff22aee87c9d600f515767ebf45f77168cb6d64f231f518a82e'; ` + -Hash 'aaf51a1fe064384f811daeaeb4ec4dce7340ec8bd893027eee676af31e83a04f'; ` 7z x openssl-$Env:OPENSSL_VERSION.tar.gz -r -y && ` 7z x openssl-$Env:OPENSSL_VERSION.tar -oC:\openssl_3 && ` cd C:\openssl_3\openssl-$Env:OPENSSL_VERSION && ` diff --git a/.builders/images/windows-x86_64/build_script.ps1 b/.builders/images/windows-x86_64/build_script.ps1 index 7e3a6642320d5..6684875dadb45 100644 --- a/.builders/images/windows-x86_64/build_script.ps1 +++ b/.builders/images/windows-x86_64/build_script.ps1 @@ -24,7 +24,7 @@ Remove-Item "librdkafka-${kafka_version}.tar.gz" $triplet = "x64-windows" $vcpkg_dir = "C:\vcpkg" $librdkafka_dir = "C:\librdkafka\librdkafka-${kafka_version}" -$desired_commit = "48cfe1e0e928341709d97fc3d2eff10ad6262c96" +$desired_commit = "36118ef68885436fd2a999188216337365856ad4" # Clone and configure vcpkg if (-Not (Test-Path -Path "$vcpkg_dir\.git")) { diff --git a/.deps/builder_inputs.toml b/.deps/builder_inputs.toml index 2dfbe5a814928..7b53a49f2d03a 100644 --- a/.deps/builder_inputs.toml +++ b/.deps/builder_inputs.toml @@ -11,6 +11,6 @@ # .builders/inputs_hash.py plus everything under .builders/images//. [inputs] -linux-aarch64 = "e48bf769667a4f30addf317d2b889aea045e025b981276a5cbfdf5b53ae86ca8" -linux-x86_64 = "5e769b5c5678a0c578bbaf2289a8359ade8f3420de2a7f7ed3c09217866014c7" -windows-x86_64 = "beba3774e0929bc4f9377cabcde2f797a83309d88be329154b3e099961c95884" +linux-aarch64 = "e3b9a63fa95c9d58a54926fd42d1a20ae738a6c05ff8338d995b8cd9c5497ef2" +linux-x86_64 = "58a8e70bf5f870e210d586662843cdc9948b5d90638e3487f1e07a2b10f27f19" +windows-x86_64 = "130572854fdcd9ca5d021af13087afa7384b1e659959087db21c77ac144ad313" diff --git a/.deps/image_digests.json b/.deps/image_digests.json index a40766f7f01f8..e67d22ca236fe 100644 --- a/.deps/image_digests.json +++ b/.deps/image_digests.json @@ -1,5 +1,5 @@ { - "linux-aarch64": "sha256:223fa103a2f1b67c98d2c15a250a9eec39b6b1768011096260f6e12cef1870c4", - "linux-x86_64": "sha256:7dca4137ffe24807e2e5ffafb4d50dbd9a201534c1c5e072618075d378e9b975", - "windows-x86_64": "sha256:ee9772fc71d78c232f6315e9609cf78a78213200ca24bcc55040f18d8e63313f" + "linux-aarch64": "sha256:bced710c0b1812c224caaa951b412ba3fbf2d299dcb4cb001b58898cd9e119ae", + "linux-x86_64": "sha256:82a4605484daf57ff3edfc2c4a10d19cb3ee592ba5cdf6a53605c99a76856ae3", + "windows-x86_64": "sha256:7ebc2f51eca870f551f663159b399e2cd98a15830f2a495a775dfd124f7f859b" } diff --git a/.deps/resolved/linux-aarch64_3.13.txt b/.deps/resolved/linux-aarch64_3.13.txt index 2e705db7d6fed..986b71d1407a1 100644 --- a/.deps/resolved/linux-aarch64_3.13.txt +++ b/.deps/resolved/linux-aarch64_3.13.txt @@ -1,30 +1,30 @@ -aerospike @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/aerospike/aerospike-7.1.1-20260418125217-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl#sha256=a1de7c7019b1dd5363cdd1a838ba92185418a114be9b59f902e8aef66326c4ea -botocore @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/botocore/botocore-1.42.72-20260421082705-py3-none-any.whl#sha256=f1933a8ca6c1108ed23f7b01f82577327fc254e330025887fdd4ba17db03e8e2 +aerospike @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/aerospike/aerospike-7.1.1-20260421153433-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl#sha256=13e750c0fbc8fd5f41810e5b3e72be2d132124e47a148dd147352a84b90fc614 +botocore @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/botocore/botocore-1.42.72-20260421153126-py3-none-any.whl#sha256=f1933a8ca6c1108ed23f7b01f82577327fc254e330025887fdd4ba17db03e8e2 cm-client @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/cm-client/cm_client-45.0.4-20260326173357-py3-none-manylinux2014_aarch64.whl#sha256=0bbcf2766028850c26a917deef3704a096cc9ba0c25220d45ff424334d25dcd7 -confluent-kafka @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/confluent-kafka/confluent_kafka-2.13.2-20260421095908-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl#sha256=65e0d489118fa94ca54abea65610fa3f5d116c67fd84bc5561f741adade2b40a -cryptography @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/cryptography/cryptography-46.0.6-20260421095911-cp313-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl#sha256=e3b8dc89254638fe20fda837433092b2b4f89e1a683710f9d05a4419dfbf39f7 +confluent-kafka @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/confluent-kafka/confluent_kafka-2.13.2-20260421153443-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl#sha256=033107872bd70d3f96b0c6d0c91cc8cad173f143cefd74387538dc75f980448d +cryptography @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/cryptography/cryptography-46.0.6-20260421153446-cp313-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl#sha256=e55c7befde32fd6ce7e378b4c343ecc50490df8eee3e9ee8dc59d77ab7ef9772 ddtrace @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/ddtrace/ddtrace-3.19.5-20260417115249-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl#sha256=a4f8d07adccdd43908156ab2c143dbb6261ed9a3c43ba58a3bb6bd1b6ef94734 foundationdb @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/foundationdb/foundationdb-6.3.25-20260326173358-py3-none-manylinux2014_aarch64.whl#sha256=d34180500220db4458e57505c774de0363456d4129f0e3fe98c9e99e8eef77c2 -gssapi @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/gssapi/gssapi-1.11.1-20260420112228-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl#sha256=95e5e8521bb191907748a7360ffd025398aa861cb47014c551384380d52be412 -keystoneauth1 @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/keystoneauth1/keystoneauth1-5.13.1-20260421083930-py3-none-any.whl#sha256=a15092187950de965ff6096e203d31e461c61cfd47ec1f5249a0e2955187cba2 -krb5 @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/krb5/krb5-0.9.0-20260420112240-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl#sha256=9700f818130cf996f844203d60c9e41b95700a90916c9ef39b008166ba6c9f71 -openstacksdk @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/openstacksdk/openstacksdk-4.10.0-20260421083943-py3-none-any.whl#sha256=88abe8f44e3b8c5c25b1093de735c700aa727a7ac408e273aa855d6db6ba38bf -os-service-types @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/os-service-types/os_service_types-1.8.2-20260421083957-py3-none-any.whl#sha256=758ccaa020eea0edd84bcf4123746ddd060d1dbaeef63d04d76bd2e0ae6f91d8 -pbr @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/pbr/pbr-7.0.3-20260421084012-py2.py3-none-any.whl#sha256=1544652b80307f0b4c491bd66f58f969cb0656994e632365f90e8e044c223b4e +gssapi @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/gssapi/gssapi-1.11.1-20260421153448-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl#sha256=861b3cde93aec1b05a5e9ac917780dbac66d773bd427834bdf738825e559d197 +keystoneauth1 @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/keystoneauth1/keystoneauth1-5.13.1-20260421153141-py3-none-any.whl#sha256=a15092187950de965ff6096e203d31e461c61cfd47ec1f5249a0e2955187cba2 +krb5 @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/krb5/krb5-0.9.0-20260421153455-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl#sha256=f6dd9d9a2d81b129b52ace318104ea9c04c1e7a5e11724aede73ba7c12f7fcac +openstacksdk @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/openstacksdk/openstacksdk-4.10.0-20260421153148-py3-none-any.whl#sha256=88abe8f44e3b8c5c25b1093de735c700aa727a7ac408e273aa855d6db6ba38bf +os-service-types @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/os-service-types/os_service_types-1.8.2-20260421153155-py3-none-any.whl#sha256=758ccaa020eea0edd84bcf4123746ddd060d1dbaeef63d04d76bd2e0ae6f91d8 +pbr @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/pbr/pbr-7.0.3-20260421153201-py2.py3-none-any.whl#sha256=1544652b80307f0b4c491bd66f58f969cb0656994e632365f90e8e044c223b4e psutil @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/psutil/psutil-6.0.0-20260326173401-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl#sha256=22e075e3cbc57b5da0d93f72f691746c5198ce88c5aea6fdb54186b3e8c46832 -psycopg-c @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/psycopg-c/psycopg_c-3.3.3-20260418125308-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl#sha256=e9a6db500356a67b07cf971b394b92445797d608578961cd2c931ec1d61567b9 +psycopg-c @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/psycopg-c/psycopg_c-3.3.3-20260421153515-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl#sha256=0bee628a33b6d05bae2f8ba97995e4f6c95ae6a6bb4c7b27160a17b7fb21c8ec pymongo @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/pymongo/pymongo-4.8.0-20260415154515-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl#sha256=30d8af4ef8fda85d1a865bdb254e6b2e3988f26b723eb39a4843c766371ff517 pyodbc @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/pyodbc/pyodbc-5.3.0-20260415154516-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl#sha256=91a4191cf30930755d82e8edd6ac861443dfb6fbbf7915753b73209038ad5ad2 -pysnmp-mibs @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/pysnmp-mibs/pysnmp_mibs-0.1.6-20260421084027-py2.py3-none-any.whl#sha256=0cc4610711208cdc64361464a23d1f2dce88ec5990a12b4bdce4f13b6a169810 +pysnmp-mibs @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/pysnmp-mibs/pysnmp_mibs-0.1.6-20260421153209-py2.py3-none-any.whl#sha256=0cc4610711208cdc64361464a23d1f2dce88ec5990a12b4bdce4f13b6a169810 pyvmomi @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/pyvmomi/pyvmomi-8.0.3.0.1-20260326173403-py2.py3-none-manylinux2014_aarch64.whl#sha256=dd71476b7308286ed4219373ca9523e4f06bfed3f5932f60e5c67d8d5a673e1e -requests-unixsocket2 @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/requests-unixsocket2/requests_unixsocket2-1.0.1-20260421084042-py3-none-any.whl#sha256=aae3f1743ab60955ea91e9a095d54997ea56b956bab652bf194379ef4dc6fa7f -securesystemslib @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/securesystemslib/securesystemslib-0.28.0-20260421084056-py3-none-any.whl#sha256=861ab6f8c1930e0c05915f32a34f1c4ae1d76ee542ad2b424121e3e26a9fb1dd -setuptools @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/setuptools/setuptools-82.0.1-20260421084111-py3-none-any.whl#sha256=b020c62c9ea6c1c3e7a29a8e385967909ceb85a77398f7fbe3c63e2abab52e87 +requests-unixsocket2 @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/requests-unixsocket2/requests_unixsocket2-1.0.1-20260421153216-py3-none-any.whl#sha256=aae3f1743ab60955ea91e9a095d54997ea56b956bab652bf194379ef4dc6fa7f +securesystemslib @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/securesystemslib/securesystemslib-0.28.0-20260421153223-py3-none-any.whl#sha256=861ab6f8c1930e0c05915f32a34f1c4ae1d76ee542ad2b424121e3e26a9fb1dd +setuptools @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/setuptools/setuptools-82.0.1-20260421153230-py3-none-any.whl#sha256=b020c62c9ea6c1c3e7a29a8e385967909ceb85a77398f7fbe3c63e2abab52e87 simplejson @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/simplejson/simplejson-3.20.2-20260326173404-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl#sha256=cb739020a718c2e32041a0fa0a3f79398f45c067347fe8f286c8222fa777bc5d -stevedore @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/stevedore/stevedore-5.7.0-20260421084126-py3-none-any.whl#sha256=0cf2a7cb9c915eddc77a591df48e8ab78f93167e8ac77d0efb04eb375f91d8b2 -supervisor @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/supervisor/supervisor-4.3.0-20260421084140-py2.py3-none-any.whl#sha256=81d63e968a5133203a334102b8e6e72b1f5ecfc9673c1af7680f9f7e0db8d4fd -vertica-python @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/vertica-python/vertica_python-1.4.0-20260421084155-py3-none-any.whl#sha256=df8d667b7bd070532a72c25f37e7259d3673c1908ae726fdfb3087d777caa9da -websocket-client @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/websocket-client/websocket_client-1.9.0-20260421084209-py3-none-any.whl#sha256=b628876a9b1eed1d49f1a230bf4b1c21fa3cd9163594f9f9628c8a8b22f97e10 +stevedore @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/stevedore/stevedore-5.7.0-20260421153237-py3-none-any.whl#sha256=0cf2a7cb9c915eddc77a591df48e8ab78f93167e8ac77d0efb04eb375f91d8b2 +supervisor @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/supervisor/supervisor-4.3.0-20260421153243-py2.py3-none-any.whl#sha256=81d63e968a5133203a334102b8e6e72b1f5ecfc9673c1af7680f9f7e0db8d4fd +vertica-python @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/vertica-python/vertica_python-1.4.0-20260421153250-py3-none-any.whl#sha256=df8d667b7bd070532a72c25f37e7259d3673c1908ae726fdfb3087d777caa9da +websocket-client @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/websocket-client/websocket_client-1.9.0-20260421153257-py3-none-any.whl#sha256=b628876a9b1eed1d49f1a230bf4b1c21fa3cd9163594f9f9628c8a8b22f97e10 annotated-types @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/external/annotated-types/annotated_types-0.7.0-py3-none-any.whl#sha256=1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53 attrs @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/external/attrs/attrs-26.1.0-py3-none-any.whl#sha256=c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309 aws-msk-iam-sasl-signer-python @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/external/aws-msk-iam-sasl-signer-python/aws_msk_iam_sasl_signer_python-1.0.2-py2.py3-none-any.whl#sha256=310eb2db9ca0ff55ed06a24212739b87533e7f1cf6f34e43aabbd97a3b21290e diff --git a/.deps/resolved/linux-x86_64_3.13.txt b/.deps/resolved/linux-x86_64_3.13.txt index c9c03fa08e90e..80cc9c1137912 100644 --- a/.deps/resolved/linux-x86_64_3.13.txt +++ b/.deps/resolved/linux-x86_64_3.13.txt @@ -1,31 +1,31 @@ -aerospike @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/aerospike/aerospike-7.1.1-20260418130014-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=611776d7bc950a342e16b75973aadc0bf11280666055d4d868bac6d160e7164d -botocore @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/botocore/botocore-1.42.72-20260421100323-py3-none-any.whl#sha256=f1933a8ca6c1108ed23f7b01f82577327fc254e330025887fdd4ba17db03e8e2 +aerospike @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/aerospike/aerospike-7.1.1-20260421153120-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=aba4253796375b00ed7850c6cab414673bdf429861ecdb4338208665ea9df767 +botocore @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/botocore/botocore-1.42.72-20260421153126-py3-none-any.whl#sha256=f1933a8ca6c1108ed23f7b01f82577327fc254e330025887fdd4ba17db03e8e2 cm-client @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/cm-client/cm_client-45.0.4-20260326173305-py3-none-manylinux2014_x86_64.whl#sha256=0bbcf2766028850c26a917deef3704a096cc9ba0c25220d45ff424334d25dcd7 -confluent-kafka @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/confluent-kafka/confluent_kafka-2.13.2-20260421100447-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=dacc5df49c3e15ddf4f7384660f0feac760d9ba089e1ac3a73322523f2bd9c1f -cryptography @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/cryptography/cryptography-46.0.6-20260421100449-cp313-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=547c00f19b05f938443269e99707d4bfdb397109f24c3fdf324edd5f9fdd6331 +confluent-kafka @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/confluent-kafka/confluent_kafka-2.13.2-20260421153130-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=9a9dd7e8d4a0cbf46fd66f378c0189672853740ffdc025aaf23004d892889bc8 +cryptography @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/cryptography/cryptography-46.0.6-20260421153133-cp313-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=7770e7cd9dba207af90ef793df2de6544dd445d2c0489457fd208ab3e60bc72d ddtrace @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/ddtrace/ddtrace-3.19.5-20260417115349-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl#sha256=e0aa298cfd1947902fed35d8fa6129c90f6d5e687328b0cba6fe137714198608 foundationdb @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/foundationdb/foundationdb-6.3.25-20260326173307-py3-none-manylinux2014_x86_64.whl#sha256=d34180500220db4458e57505c774de0363456d4129f0e3fe98c9e99e8eef77c2 -gssapi @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/gssapi/gssapi-1.11.1-20260418130032-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=9cf9e44ae3c9adbf681ab815511ce6c274f6403f106fc8e8e73eaa9268a0913f -keystoneauth1 @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/keystoneauth1/keystoneauth1-5.13.1-20260421100330-py3-none-any.whl#sha256=a15092187950de965ff6096e203d31e461c61cfd47ec1f5249a0e2955187cba2 -krb5 @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/krb5/krb5-0.9.0-20260418130041-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=082536495ab7afb814a87311d3f5000b1d85b5afe19c5f52e8ea98c1da9c0df0 -openstacksdk @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/openstacksdk/openstacksdk-4.10.0-20260421100335-py3-none-any.whl#sha256=88abe8f44e3b8c5c25b1093de735c700aa727a7ac408e273aa855d6db6ba38bf -os-service-types @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/os-service-types/os_service_types-1.8.2-20260421100341-py3-none-any.whl#sha256=758ccaa020eea0edd84bcf4123746ddd060d1dbaeef63d04d76bd2e0ae6f91d8 -pbr @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/pbr/pbr-7.0.3-20260421100347-py2.py3-none-any.whl#sha256=1544652b80307f0b4c491bd66f58f969cb0656994e632365f90e8e044c223b4e +gssapi @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/gssapi/gssapi-1.11.1-20260421153134-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=b0eefba08d72fa793402e49072b61c84e8414c9fdeda2b80dfa8a47c3865dc66 +keystoneauth1 @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/keystoneauth1/keystoneauth1-5.13.1-20260421153141-py3-none-any.whl#sha256=a15092187950de965ff6096e203d31e461c61cfd47ec1f5249a0e2955187cba2 +krb5 @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/krb5/krb5-0.9.0-20260421153142-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=1814588e913f80e3f81753b2cb601eb1fce0001d33749cdc78b6134c20f1382a +openstacksdk @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/openstacksdk/openstacksdk-4.10.0-20260421153148-py3-none-any.whl#sha256=88abe8f44e3b8c5c25b1093de735c700aa727a7ac408e273aa855d6db6ba38bf +os-service-types @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/os-service-types/os_service_types-1.8.2-20260421153155-py3-none-any.whl#sha256=758ccaa020eea0edd84bcf4123746ddd060d1dbaeef63d04d76bd2e0ae6f91d8 +pbr @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/pbr/pbr-7.0.3-20260421153201-py2.py3-none-any.whl#sha256=1544652b80307f0b4c491bd66f58f969cb0656994e632365f90e8e044c223b4e psutil @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/psutil/psutil-6.0.0-20260326173308-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=af8dd07e6f1bf1d41381ad59dff0a0a36153c7dd5a69becc765010329f17db01 -psycopg-c @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/psycopg-c/psycopg_c-3.3.3-20260418130105-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=1381485b44a98283661adeee3aae934dc1275eef8f62c8cedce46ffa750708d2 +psycopg-c @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/psycopg-c/psycopg_c-3.3.3-20260421153202-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=e7eafc789e999ae259d825fc9425655f627584bc1ff76c8c0847d53e236df6cf pymongo @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/pymongo/pymongo-4.8.0-20260415154630-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=a0bc69dc57d3ba6db1fc23ac471ddd5edeeef737fef8e912b0b96126f0b13a8c pymqi @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/pymqi/pymqi-1.12.13-20260326173310-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=20b5e67134719cae77a2b6c20da5219931b3735e30538567fb2b73e34219203b pyodbc @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/pyodbc/pyodbc-5.3.0-20260415154630-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=80d6bdc8ba09a778205c68493fa72a44a599fd8c31803a4f4d4e3bcf1f2284fe -pysnmp-mibs @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/pysnmp-mibs/pysnmp_mibs-0.1.6-20260421100353-py2.py3-none-any.whl#sha256=0cc4610711208cdc64361464a23d1f2dce88ec5990a12b4bdce4f13b6a169810 +pysnmp-mibs @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/pysnmp-mibs/pysnmp_mibs-0.1.6-20260421153209-py2.py3-none-any.whl#sha256=0cc4610711208cdc64361464a23d1f2dce88ec5990a12b4bdce4f13b6a169810 pyvmomi @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/pyvmomi/pyvmomi-8.0.3.0.1-20260326173310-py2.py3-none-manylinux2014_x86_64.whl#sha256=dd71476b7308286ed4219373ca9523e4f06bfed3f5932f60e5c67d8d5a673e1e -requests-unixsocket2 @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/requests-unixsocket2/requests_unixsocket2-1.0.1-20260421100359-py3-none-any.whl#sha256=aae3f1743ab60955ea91e9a095d54997ea56b956bab652bf194379ef4dc6fa7f -securesystemslib @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/securesystemslib/securesystemslib-0.28.0-20260421100405-py3-none-any.whl#sha256=861ab6f8c1930e0c05915f32a34f1c4ae1d76ee542ad2b424121e3e26a9fb1dd -setuptools @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/setuptools/setuptools-82.0.1-20260421100411-py3-none-any.whl#sha256=b020c62c9ea6c1c3e7a29a8e385967909ceb85a77398f7fbe3c63e2abab52e87 +requests-unixsocket2 @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/requests-unixsocket2/requests_unixsocket2-1.0.1-20260421153216-py3-none-any.whl#sha256=aae3f1743ab60955ea91e9a095d54997ea56b956bab652bf194379ef4dc6fa7f +securesystemslib @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/securesystemslib/securesystemslib-0.28.0-20260421153223-py3-none-any.whl#sha256=861ab6f8c1930e0c05915f32a34f1c4ae1d76ee542ad2b424121e3e26a9fb1dd +setuptools @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/setuptools/setuptools-82.0.1-20260421153230-py3-none-any.whl#sha256=b020c62c9ea6c1c3e7a29a8e385967909ceb85a77398f7fbe3c63e2abab52e87 simplejson @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/simplejson/simplejson-3.20.2-20260326173311-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=dec16958f71ce93ac1c2fdc212800892ca22a9e90efcab5b5e01d121146cc5cc -stevedore @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/stevedore/stevedore-5.7.0-20260421100416-py3-none-any.whl#sha256=0cf2a7cb9c915eddc77a591df48e8ab78f93167e8ac77d0efb04eb375f91d8b2 -supervisor @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/supervisor/supervisor-4.3.0-20260421100422-py2.py3-none-any.whl#sha256=81d63e968a5133203a334102b8e6e72b1f5ecfc9673c1af7680f9f7e0db8d4fd -vertica-python @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/vertica-python/vertica_python-1.4.0-20260421100428-py3-none-any.whl#sha256=df8d667b7bd070532a72c25f37e7259d3673c1908ae726fdfb3087d777caa9da -websocket-client @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/websocket-client/websocket_client-1.9.0-20260421100434-py3-none-any.whl#sha256=b628876a9b1eed1d49f1a230bf4b1c21fa3cd9163594f9f9628c8a8b22f97e10 +stevedore @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/stevedore/stevedore-5.7.0-20260421153237-py3-none-any.whl#sha256=0cf2a7cb9c915eddc77a591df48e8ab78f93167e8ac77d0efb04eb375f91d8b2 +supervisor @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/supervisor/supervisor-4.3.0-20260421153243-py2.py3-none-any.whl#sha256=81d63e968a5133203a334102b8e6e72b1f5ecfc9673c1af7680f9f7e0db8d4fd +vertica-python @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/vertica-python/vertica_python-1.4.0-20260421153250-py3-none-any.whl#sha256=df8d667b7bd070532a72c25f37e7259d3673c1908ae726fdfb3087d777caa9da +websocket-client @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/websocket-client/websocket_client-1.9.0-20260421153257-py3-none-any.whl#sha256=b628876a9b1eed1d49f1a230bf4b1c21fa3cd9163594f9f9628c8a8b22f97e10 annotated-types @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/external/annotated-types/annotated_types-0.7.0-py3-none-any.whl#sha256=1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53 attrs @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/external/attrs/attrs-26.1.0-py3-none-any.whl#sha256=c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309 aws-msk-iam-sasl-signer-python @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/external/aws-msk-iam-sasl-signer-python/aws_msk_iam_sasl_signer_python-1.0.2-py2.py3-none-any.whl#sha256=310eb2db9ca0ff55ed06a24212739b87533e7f1cf6f34e43aabbd97a3b21290e diff --git a/.deps/resolved/macos-aarch64_3.13.txt b/.deps/resolved/macos-aarch64_3.13.txt index 68eecc6f9b6ec..b787cd6baf8ac 100644 --- a/.deps/resolved/macos-aarch64_3.13.txt +++ b/.deps/resolved/macos-aarch64_3.13.txt @@ -1,28 +1,28 @@ -botocore @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/botocore/botocore-1.42.72-20260421082705-py3-none-any.whl#sha256=f1933a8ca6c1108ed23f7b01f82577327fc254e330025887fdd4ba17db03e8e2 +botocore @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/botocore/botocore-1.42.72-20260421133609-py3-none-any.whl#sha256=f1933a8ca6c1108ed23f7b01f82577327fc254e330025887fdd4ba17db03e8e2 cm-client @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/cm-client/cm_client-45.0.4-20260326173218-py3-none-macosx_12_0_universal2.whl#sha256=0bbcf2766028850c26a917deef3704a096cc9ba0c25220d45ff424334d25dcd7 -confluent-kafka @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/confluent-kafka/confluent_kafka-2.13.2-20260419053453-cp313-cp313-macosx_12_0_arm64.whl#sha256=344f33861abc0c7392317debd7386086022672d25c978cec64fc8dcf285c542b +confluent-kafka @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/confluent-kafka/confluent_kafka-2.13.2-20260421152810-cp313-cp313-macosx_12_0_arm64.whl#sha256=dacd007c85a087687bd5f1a42e05a435a5f61ab24848fe002028abe00b5e629e ddtrace @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/ddtrace/ddtrace-3.19.5-20260417115301-cp313-cp313-macosx_12_0_arm64.whl#sha256=1274db819aa41b189135f83ad2b8e37c6e26b8d2f25c60a725a01637ebd63ee4 foundationdb @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/foundationdb/foundationdb-6.3.25-20260326173219-py3-none-macosx_12_0_universal2.whl#sha256=d34180500220db4458e57505c774de0363456d4129f0e3fe98c9e99e8eef77c2 gssapi @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/gssapi/gssapi-1.11.1-20260326173323-cp311-abi3-macosx_11_0_arm64.whl#sha256=b5f5ac28470db99338814e4285a491dc218b9bee3f8d20bfa219274e84bd87c4 -keystoneauth1 @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/keystoneauth1/keystoneauth1-5.13.1-20260421083930-py3-none-any.whl#sha256=a15092187950de965ff6096e203d31e461c61cfd47ec1f5249a0e2955187cba2 +keystoneauth1 @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/keystoneauth1/keystoneauth1-5.13.1-20260421133627-py3-none-any.whl#sha256=a15092187950de965ff6096e203d31e461c61cfd47ec1f5249a0e2955187cba2 krb5 @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/krb5/krb5-0.9.0-20260326173323-cp311-abi3-macosx_11_0_arm64.whl#sha256=47f731bebe725962f7b644e7238a4c68eca2879f6c35842babda9140f263c615 -openstacksdk @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/openstacksdk/openstacksdk-4.10.0-20260421083943-py3-none-any.whl#sha256=88abe8f44e3b8c5c25b1093de735c700aa727a7ac408e273aa855d6db6ba38bf -os-service-types @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/os-service-types/os_service_types-1.8.2-20260421083957-py3-none-any.whl#sha256=758ccaa020eea0edd84bcf4123746ddd060d1dbaeef63d04d76bd2e0ae6f91d8 -pbr @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/pbr/pbr-7.0.3-20260421084012-py2.py3-none-any.whl#sha256=1544652b80307f0b4c491bd66f58f969cb0656994e632365f90e8e044c223b4e +openstacksdk @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/openstacksdk/openstacksdk-4.10.0-20260421133641-py3-none-any.whl#sha256=88abe8f44e3b8c5c25b1093de735c700aa727a7ac408e273aa855d6db6ba38bf +os-service-types @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/os-service-types/os_service_types-1.8.2-20260421133656-py3-none-any.whl#sha256=758ccaa020eea0edd84bcf4123746ddd060d1dbaeef63d04d76bd2e0ae6f91d8 +pbr @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/pbr/pbr-7.0.3-20260421133710-py2.py3-none-any.whl#sha256=1544652b80307f0b4c491bd66f58f969cb0656994e632365f90e8e044c223b4e psutil @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/psutil/psutil-6.0.0-20260326173324-cp38-abi3-macosx_11_0_arm64.whl#sha256=33472398d3e6da655a430b106920164b04f036f891bd0ea803a4309ed2a80ef9 -psycopg-c @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/psycopg-c/psycopg_c-3.3.3-20260418125458-cp313-cp313-macosx_12_0_arm64.whl#sha256=2c853472bed5a003bdcfbec159bf7849d1ac7a2a3867055d0005d1aa647549cf +psycopg-c @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/psycopg-c/psycopg_c-3.3.3-20260421152837-cp313-cp313-macosx_12_0_arm64.whl#sha256=bfe56ecdab4dce0ae8442ef05e1a37df4b1d63741f7188f66f9005fc11bfd013 pymongo @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/pymongo/pymongo-4.8.0-20260326173325-cp313-cp313-macosx_12_0_arm64.whl#sha256=7c94a2b73c148f84ab217ea2084d07e01e834d49244dec026b473e889016f556 pymqi @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/pymqi/pymqi-1.12.13-20260326173325-cp313-cp313-macosx_12_0_arm64.whl#sha256=482b0d2593868c595ec53db794a61a792c0e1fcad04aee86db96afaadf986baf -pysnmp-mibs @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/pysnmp-mibs/pysnmp_mibs-0.1.6-20260421084027-py2.py3-none-any.whl#sha256=0cc4610711208cdc64361464a23d1f2dce88ec5990a12b4bdce4f13b6a169810 +pysnmp-mibs @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/pysnmp-mibs/pysnmp_mibs-0.1.6-20260421133727-py2.py3-none-any.whl#sha256=0cc4610711208cdc64361464a23d1f2dce88ec5990a12b4bdce4f13b6a169810 pyvmomi @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/pyvmomi/pyvmomi-8.0.3.0.1-20260326173224-py2.py3-none-macosx_12_0_universal2.whl#sha256=dd71476b7308286ed4219373ca9523e4f06bfed3f5932f60e5c67d8d5a673e1e -requests-unixsocket2 @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/requests-unixsocket2/requests_unixsocket2-1.0.1-20260421084042-py3-none-any.whl#sha256=aae3f1743ab60955ea91e9a095d54997ea56b956bab652bf194379ef4dc6fa7f -securesystemslib @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/securesystemslib/securesystemslib-0.28.0-20260421084056-py3-none-any.whl#sha256=861ab6f8c1930e0c05915f32a34f1c4ae1d76ee542ad2b424121e3e26a9fb1dd -setuptools @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/setuptools/setuptools-82.0.1-20260421084111-py3-none-any.whl#sha256=b020c62c9ea6c1c3e7a29a8e385967909ceb85a77398f7fbe3c63e2abab52e87 +requests-unixsocket2 @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/requests-unixsocket2/requests_unixsocket2-1.0.1-20260421133742-py3-none-any.whl#sha256=aae3f1743ab60955ea91e9a095d54997ea56b956bab652bf194379ef4dc6fa7f +securesystemslib @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/securesystemslib/securesystemslib-0.28.0-20260421133756-py3-none-any.whl#sha256=861ab6f8c1930e0c05915f32a34f1c4ae1d76ee542ad2b424121e3e26a9fb1dd +setuptools @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/setuptools/setuptools-82.0.1-20260421133811-py3-none-any.whl#sha256=b020c62c9ea6c1c3e7a29a8e385967909ceb85a77398f7fbe3c63e2abab52e87 simplejson @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/simplejson/simplejson-3.20.2-20260326173326-cp313-cp313-macosx_11_0_arm64.whl#sha256=fc3c4e9feecd85f1831fb0983b04e7170765b5047c3c629ab97c0c49190a5da8 -stevedore @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/stevedore/stevedore-5.7.0-20260421084126-py3-none-any.whl#sha256=0cf2a7cb9c915eddc77a591df48e8ab78f93167e8ac77d0efb04eb375f91d8b2 -supervisor @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/supervisor/supervisor-4.3.0-20260421084140-py2.py3-none-any.whl#sha256=81d63e968a5133203a334102b8e6e72b1f5ecfc9673c1af7680f9f7e0db8d4fd -vertica-python @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/vertica-python/vertica_python-1.4.0-20260421084155-py3-none-any.whl#sha256=df8d667b7bd070532a72c25f37e7259d3673c1908ae726fdfb3087d777caa9da -websocket-client @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/websocket-client/websocket_client-1.9.0-20260421084209-py3-none-any.whl#sha256=b628876a9b1eed1d49f1a230bf4b1c21fa3cd9163594f9f9628c8a8b22f97e10 +stevedore @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/stevedore/stevedore-5.7.0-20260421133826-py3-none-any.whl#sha256=0cf2a7cb9c915eddc77a591df48e8ab78f93167e8ac77d0efb04eb375f91d8b2 +supervisor @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/supervisor/supervisor-4.3.0-20260421133841-py2.py3-none-any.whl#sha256=81d63e968a5133203a334102b8e6e72b1f5ecfc9673c1af7680f9f7e0db8d4fd +vertica-python @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/vertica-python/vertica_python-1.4.0-20260421133856-py3-none-any.whl#sha256=df8d667b7bd070532a72c25f37e7259d3673c1908ae726fdfb3087d777caa9da +websocket-client @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/websocket-client/websocket_client-1.9.0-20260421133911-py3-none-any.whl#sha256=b628876a9b1eed1d49f1a230bf4b1c21fa3cd9163594f9f9628c8a8b22f97e10 annotated-types @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/external/annotated-types/annotated_types-0.7.0-py3-none-any.whl#sha256=1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53 attrs @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/external/attrs/attrs-26.1.0-py3-none-any.whl#sha256=c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309 aws-msk-iam-sasl-signer-python @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/external/aws-msk-iam-sasl-signer-python/aws_msk_iam_sasl_signer_python-1.0.2-py2.py3-none-any.whl#sha256=310eb2db9ca0ff55ed06a24212739b87533e7f1cf6f34e43aabbd97a3b21290e diff --git a/.deps/resolved/macos-x86_64_3.13.txt b/.deps/resolved/macos-x86_64_3.13.txt index 602170b96af26..200b9e8777924 100644 --- a/.deps/resolved/macos-x86_64_3.13.txt +++ b/.deps/resolved/macos-x86_64_3.13.txt @@ -1,28 +1,28 @@ -botocore @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/botocore/botocore-1.42.72-20260421100323-py3-none-any.whl#sha256=f1933a8ca6c1108ed23f7b01f82577327fc254e330025887fdd4ba17db03e8e2 +botocore @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/botocore/botocore-1.42.72-20260421153126-py3-none-any.whl#sha256=f1933a8ca6c1108ed23f7b01f82577327fc254e330025887fdd4ba17db03e8e2 cm-client @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/cm-client/cm_client-45.0.4-20260326173218-py3-none-macosx_12_0_universal2.whl#sha256=0bbcf2766028850c26a917deef3704a096cc9ba0c25220d45ff424334d25dcd7 -confluent-kafka @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/confluent-kafka/confluent_kafka-2.13.2-20260419053856-cp313-cp313-macosx_12_0_x86_64.whl#sha256=e217d743a2d906dd4cbe16d711aad2bc0519772fc00891e8159f004fd33c5a5a +confluent-kafka @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/confluent-kafka/confluent_kafka-2.13.2-20260421153309-cp313-cp313-macosx_12_0_x86_64.whl#sha256=f8c08d2f08a641599ceb4661e740743df09da1e92fc318764a5c172b1f72ab7b ddtrace @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/ddtrace/ddtrace-3.19.5-20260417115332-cp313-cp313-macosx_12_0_x86_64.whl#sha256=813c9fae90bd65d60d97e183b21dff8f9d54591a9186cf163f606fb11b7a6575 foundationdb @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/foundationdb/foundationdb-6.3.25-20260326173219-py3-none-macosx_12_0_universal2.whl#sha256=d34180500220db4458e57505c774de0363456d4129f0e3fe98c9e99e8eef77c2 gssapi @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/gssapi/gssapi-1.11.1-20260326173219-cp311-abi3-macosx_10_9_x86_64.whl#sha256=91608d102056a7768b9e572ccbe2ccbe7da84688a84f05bb8c4ea56e9d0e979d -keystoneauth1 @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/keystoneauth1/keystoneauth1-5.13.1-20260421100330-py3-none-any.whl#sha256=a15092187950de965ff6096e203d31e461c61cfd47ec1f5249a0e2955187cba2 +keystoneauth1 @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/keystoneauth1/keystoneauth1-5.13.1-20260421153141-py3-none-any.whl#sha256=a15092187950de965ff6096e203d31e461c61cfd47ec1f5249a0e2955187cba2 krb5 @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/krb5/krb5-0.9.0-20260326173220-cp311-abi3-macosx_10_9_x86_64.whl#sha256=0fe3a687f4e9a8d305ba0183f9b8368e9ed13f4e32716ba3a14de77e12f1e978 -openstacksdk @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/openstacksdk/openstacksdk-4.10.0-20260421100335-py3-none-any.whl#sha256=88abe8f44e3b8c5c25b1093de735c700aa727a7ac408e273aa855d6db6ba38bf -os-service-types @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/os-service-types/os_service_types-1.8.2-20260421100341-py3-none-any.whl#sha256=758ccaa020eea0edd84bcf4123746ddd060d1dbaeef63d04d76bd2e0ae6f91d8 -pbr @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/pbr/pbr-7.0.3-20260421100347-py2.py3-none-any.whl#sha256=1544652b80307f0b4c491bd66f58f969cb0656994e632365f90e8e044c223b4e +openstacksdk @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/openstacksdk/openstacksdk-4.10.0-20260421153148-py3-none-any.whl#sha256=88abe8f44e3b8c5c25b1093de735c700aa727a7ac408e273aa855d6db6ba38bf +os-service-types @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/os-service-types/os_service_types-1.8.2-20260421153155-py3-none-any.whl#sha256=758ccaa020eea0edd84bcf4123746ddd060d1dbaeef63d04d76bd2e0ae6f91d8 +pbr @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/pbr/pbr-7.0.3-20260421153201-py2.py3-none-any.whl#sha256=1544652b80307f0b4c491bd66f58f969cb0656994e632365f90e8e044c223b4e psutil @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/psutil/psutil-6.0.0-20260326173222-cp36-abi3-macosx_10_9_x86_64.whl#sha256=81ae816033cb82995bc78424b02886430400b730698d6a7c492e3256b7854777 -psycopg-c @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/psycopg-c/psycopg_c-3.3.3-20260418125859-cp313-cp313-macosx_12_0_x86_64.whl#sha256=eb227dea25dadacf8cfe6a20fb7206f889723f0990b603ae388d9e5fb5087110 +psycopg-c @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/psycopg-c/psycopg_c-3.3.3-20260421153335-cp313-cp313-macosx_12_0_x86_64.whl#sha256=e8ab0dba4501610ffbddf96a2747ab5894650634498b6933c7646852f1933520 pymongo @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/pymongo/pymongo-4.8.0-20260326173223-cp313-cp313-macosx_12_0_x86_64.whl#sha256=8b8c0174d55284134d7373fa1116522a241804560b86f05b883d4964692caaaa pymqi @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/pymqi/pymqi-1.12.13-20260326173223-cp313-cp313-macosx_12_0_x86_64.whl#sha256=95ed07eebe53c2720cdaaf5d7de3364c80d373b9286b4a1b301f157592ee8ccb -pysnmp-mibs @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/pysnmp-mibs/pysnmp_mibs-0.1.6-20260421100353-py2.py3-none-any.whl#sha256=0cc4610711208cdc64361464a23d1f2dce88ec5990a12b4bdce4f13b6a169810 +pysnmp-mibs @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/pysnmp-mibs/pysnmp_mibs-0.1.6-20260421153209-py2.py3-none-any.whl#sha256=0cc4610711208cdc64361464a23d1f2dce88ec5990a12b4bdce4f13b6a169810 pyvmomi @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/pyvmomi/pyvmomi-8.0.3.0.1-20260326173224-py2.py3-none-macosx_12_0_universal2.whl#sha256=dd71476b7308286ed4219373ca9523e4f06bfed3f5932f60e5c67d8d5a673e1e -requests-unixsocket2 @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/requests-unixsocket2/requests_unixsocket2-1.0.1-20260421100359-py3-none-any.whl#sha256=aae3f1743ab60955ea91e9a095d54997ea56b956bab652bf194379ef4dc6fa7f -securesystemslib @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/securesystemslib/securesystemslib-0.28.0-20260421100405-py3-none-any.whl#sha256=861ab6f8c1930e0c05915f32a34f1c4ae1d76ee542ad2b424121e3e26a9fb1dd -setuptools @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/setuptools/setuptools-82.0.1-20260421100411-py3-none-any.whl#sha256=b020c62c9ea6c1c3e7a29a8e385967909ceb85a77398f7fbe3c63e2abab52e87 +requests-unixsocket2 @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/requests-unixsocket2/requests_unixsocket2-1.0.1-20260421153216-py3-none-any.whl#sha256=aae3f1743ab60955ea91e9a095d54997ea56b956bab652bf194379ef4dc6fa7f +securesystemslib @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/securesystemslib/securesystemslib-0.28.0-20260421153223-py3-none-any.whl#sha256=861ab6f8c1930e0c05915f32a34f1c4ae1d76ee542ad2b424121e3e26a9fb1dd +setuptools @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/setuptools/setuptools-82.0.1-20260421153230-py3-none-any.whl#sha256=b020c62c9ea6c1c3e7a29a8e385967909ceb85a77398f7fbe3c63e2abab52e87 simplejson @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/simplejson/simplejson-3.20.2-20260326173225-cp313-cp313-macosx_10_13_x86_64.whl#sha256=41b283f75ddb7e47b24fb57dc37d88078e51cd777438f368224e1282fc8ee465 -stevedore @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/stevedore/stevedore-5.7.0-20260421100416-py3-none-any.whl#sha256=0cf2a7cb9c915eddc77a591df48e8ab78f93167e8ac77d0efb04eb375f91d8b2 -supervisor @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/supervisor/supervisor-4.3.0-20260421100422-py2.py3-none-any.whl#sha256=81d63e968a5133203a334102b8e6e72b1f5ecfc9673c1af7680f9f7e0db8d4fd -vertica-python @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/vertica-python/vertica_python-1.4.0-20260421100428-py3-none-any.whl#sha256=df8d667b7bd070532a72c25f37e7259d3673c1908ae726fdfb3087d777caa9da -websocket-client @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/websocket-client/websocket_client-1.9.0-20260421100434-py3-none-any.whl#sha256=b628876a9b1eed1d49f1a230bf4b1c21fa3cd9163594f9f9628c8a8b22f97e10 +stevedore @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/stevedore/stevedore-5.7.0-20260421153237-py3-none-any.whl#sha256=0cf2a7cb9c915eddc77a591df48e8ab78f93167e8ac77d0efb04eb375f91d8b2 +supervisor @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/supervisor/supervisor-4.3.0-20260421153243-py2.py3-none-any.whl#sha256=81d63e968a5133203a334102b8e6e72b1f5ecfc9673c1af7680f9f7e0db8d4fd +vertica-python @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/vertica-python/vertica_python-1.4.0-20260421153250-py3-none-any.whl#sha256=df8d667b7bd070532a72c25f37e7259d3673c1908ae726fdfb3087d777caa9da +websocket-client @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/websocket-client/websocket_client-1.9.0-20260421153257-py3-none-any.whl#sha256=b628876a9b1eed1d49f1a230bf4b1c21fa3cd9163594f9f9628c8a8b22f97e10 annotated-types @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/external/annotated-types/annotated_types-0.7.0-py3-none-any.whl#sha256=1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53 attrs @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/external/attrs/attrs-26.1.0-py3-none-any.whl#sha256=c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309 aws-msk-iam-sasl-signer-python @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/external/aws-msk-iam-sasl-signer-python/aws_msk_iam_sasl_signer_python-1.0.2-py2.py3-none-any.whl#sha256=310eb2db9ca0ff55ed06a24212739b87533e7f1cf6f34e43aabbd97a3b21290e diff --git a/.deps/resolved/windows-x86_64_3.13.txt b/.deps/resolved/windows-x86_64_3.13.txt index aae4cea5f0b9c..ca37c76eedd57 100644 --- a/.deps/resolved/windows-x86_64_3.13.txt +++ b/.deps/resolved/windows-x86_64_3.13.txt @@ -1,28 +1,28 @@ -botocore @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/botocore/botocore-1.42.72-20260421100149-py3-none-any.whl#sha256=6f69d4818864f67ab304ac48497fefcc7f4fdd9bbcb9403cbc22dbe211177824 +botocore @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/botocore/botocore-1.42.72-20260421152939-py3-none-any.whl#sha256=6f69d4818864f67ab304ac48497fefcc7f4fdd9bbcb9403cbc22dbe211177824 cm-client @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/cm-client/cm_client-45.0.4-20260326173335-py3-none-win_amd64.whl#sha256=6a11ff78eeff20d6a20036e7320a2cb1fd4a5c318a2f1b81b1449efea34048eb colorama @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/colorama/colorama-0.4.6-20260417115313-py2.py3-none-any.whl#sha256=3eb3f5bc1022d96fbe8df6f419cfb07d028e24c055cc3c59517fa49a95ab067a -confluent-kafka @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/confluent-kafka/confluent_kafka-2.13.2-20260421100152-cp313-cp313-win_amd64.whl#sha256=a36f5a37b3471c7cadd85ff8c631db92240291be32c0fb76aa442c31b9f6e7eb +confluent-kafka @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/confluent-kafka/confluent_kafka-2.13.2-20260421152942-cp313-cp313-win_amd64.whl#sha256=d117d3bf84a201f672010af224fbf252fbe9041eaa961451516ec4f66e233a3d ddtrace @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/ddtrace/ddtrace-3.19.5-20260417115314-cp313-cp313-win_amd64.whl#sha256=4f3009589d1c2e0ca84fe8bdb20367de10f090e84cb401ab1d538055927ac0f7 foundationdb @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/foundationdb/foundationdb-6.3.25-20260326173337-py3-none-win_amd64.whl#sha256=828ed23b81a64a5495b1091dd8a66ea51e84c55d9d814c5b6baf7b80dbd9881b -keystoneauth1 @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/keystoneauth1/keystoneauth1-5.13.1-20260421100159-py3-none-any.whl#sha256=81b21cc6f3283215bb1a993f7c8240a0aeef36775d52ccca99c438075e054fba -openstacksdk @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/openstacksdk/openstacksdk-4.10.0-20260421100204-py3-none-any.whl#sha256=4ac88799ad5c355825b9567f5ca00fe9bcbd97cfe2649f60500fbe5f66610732 -os-service-types @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/os-service-types/os_service_types-1.8.2-20260421100210-py3-none-any.whl#sha256=668903c54b88cc4db5fd1dcbaf7cf7417220ef70592b70b49a76d202e8a7f4e8 -pbr @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/pbr/pbr-7.0.3-20260421100216-py2.py3-none-any.whl#sha256=dbc2e1e0dbf694097374a40b72c890c915302ae4dd7d37c73db9cff8bf520c4b +keystoneauth1 @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/keystoneauth1/keystoneauth1-5.13.1-20260421152949-py3-none-any.whl#sha256=81b21cc6f3283215bb1a993f7c8240a0aeef36775d52ccca99c438075e054fba +openstacksdk @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/openstacksdk/openstacksdk-4.10.0-20260421152955-py3-none-any.whl#sha256=4ac88799ad5c355825b9567f5ca00fe9bcbd97cfe2649f60500fbe5f66610732 +os-service-types @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/os-service-types/os_service_types-1.8.2-20260421153002-py3-none-any.whl#sha256=668903c54b88cc4db5fd1dcbaf7cf7417220ef70592b70b49a76d202e8a7f4e8 +pbr @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/pbr/pbr-7.0.3-20260421153008-py2.py3-none-any.whl#sha256=dbc2e1e0dbf694097374a40b72c890c915302ae4dd7d37c73db9cff8bf520c4b psutil @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/psutil/psutil-6.0.0-20260326173339-cp37-abi3-win_amd64.whl#sha256=484a4a6e0e16a9adf22b01dc2917426536c8bf63378e445816eee9833aad4f71 -psycopg-c @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/psycopg-c/psycopg_c-3.3.3-20260421100219-cp313-cp313-win_amd64.whl#sha256=7f90c425cf418f9cf66009096134f8279908392c16f468af3b96781704ef2de7 -pymongo @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/pymongo/pymongo-4.8.0-20260421100222-cp313-cp313-win_amd64.whl#sha256=3d30f69794ad794f74301f24ed49fcd1a2acb8eb981c19465263f68cab18fb8a -pymqi @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/pymqi/pymqi-1.12.13-20260421100226-cp313-cp313-win_amd64.whl#sha256=dcddff1b1dfcab879595da327f922a762e0380928632f387671e955e02c06bfd -pysnmp-mibs @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/pysnmp-mibs/pysnmp_mibs-0.1.6-20260421100231-py2.py3-none-any.whl#sha256=b3796e82ce920d942b3e2de5af4c8567738b72caffac49ec6d88684fd0365690 +psycopg-c @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/psycopg-c/psycopg_c-3.3.3-20260421153012-cp313-cp313-win_amd64.whl#sha256=96bdfed0be771bb7e311a30c196fc9cead6b46495471025abc2b3e2df5c9a06f +pymongo @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/pymongo/pymongo-4.8.0-20260421153016-cp313-cp313-win_amd64.whl#sha256=763de328e56a4b33ea9a1885a69ebe8e4dfa2d32317670b1be2bc088931f6b15 +pymqi @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/pymqi/pymqi-1.12.13-20260421153019-cp313-cp313-win_amd64.whl#sha256=e7a0dcbb13ac844510d5b6293c75f15fe4aab7d052be027195f70057eda3351b +pysnmp-mibs @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/pysnmp-mibs/pysnmp_mibs-0.1.6-20260421153026-py2.py3-none-any.whl#sha256=b3796e82ce920d942b3e2de5af4c8567738b72caffac49ec6d88684fd0365690 pyvmomi @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/pyvmomi/pyvmomi-8.0.3.0.1-20260326173340-py2.py3-none-win_amd64.whl#sha256=c8487fb88881dc6bfc3507b9c351929221c8e85aa5e74179b82cda9d21364218 pywin32 @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/pywin32/pywin32-311-20260326173341-cp313-cp313-win_amd64.whl#sha256=1e7784bf006cbfd7ffc4ce238eecc6ae43bfaf5d8132a6401d58a4ad0a36aea5 -requests-unixsocket2 @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/requests-unixsocket2/requests_unixsocket2-1.0.1-20260421100238-py3-none-any.whl#sha256=7f0bbfc823535680dd0e1ad2aedad8dc958130a180c421288244a33509ea2b0d -securesystemslib @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/securesystemslib/securesystemslib-0.28.0-20260421100244-py3-none-any.whl#sha256=4b33353c4d80e63f2417fff600939c30580c49721c76b0f7cf1ea4a18a131c4b -setuptools @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/setuptools/setuptools-82.0.1-20260421100250-py3-none-any.whl#sha256=3e5b8439ed8ba11221d6479f27a25a261cba045c357a912dc60e236710504ef6 +requests-unixsocket2 @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/requests-unixsocket2/requests_unixsocket2-1.0.1-20260421153033-py3-none-any.whl#sha256=7f0bbfc823535680dd0e1ad2aedad8dc958130a180c421288244a33509ea2b0d +securesystemslib @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/securesystemslib/securesystemslib-0.28.0-20260421153040-py3-none-any.whl#sha256=4b33353c4d80e63f2417fff600939c30580c49721c76b0f7cf1ea4a18a131c4b +setuptools @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/setuptools/setuptools-82.0.1-20260421153047-py3-none-any.whl#sha256=3e5b8439ed8ba11221d6479f27a25a261cba045c357a912dc60e236710504ef6 simplejson @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/simplejson/simplejson-3.20.2-20260326173342-cp313-cp313-win_amd64.whl#sha256=cd71398a228fa91cd9ee2bb88079ba6693c60a68c14e684d386181a8a5eb67bc -stevedore @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/stevedore/stevedore-5.7.0-20260421100256-py3-none-any.whl#sha256=b6ba40fc40b665f04276c98a21b7ddd029b6b5d80bc3c3e68dc58964f2ca0828 -supervisor @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/supervisor/supervisor-4.3.0-20260421100302-py2.py3-none-any.whl#sha256=01f0c6c7fbc4b9a0ccb659a6463319eb83742ba0d6c156e5256484aaedef2917 -vertica-python @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/vertica-python/vertica_python-1.4.0-20260421100308-py3-none-any.whl#sha256=3a094a32c4a892c32be2acb3e77452c8d7b907b6b6ebaa1e6b0a1f5bbecf4d38 -websocket-client @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/websocket-client/websocket_client-1.9.0-20260421100314-py3-none-any.whl#sha256=cb12e51596b0dbb085df6efdbd7d00cc315ea04e88f667513702899903ec39fc +stevedore @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/stevedore/stevedore-5.7.0-20260421153054-py3-none-any.whl#sha256=b6ba40fc40b665f04276c98a21b7ddd029b6b5d80bc3c3e68dc58964f2ca0828 +supervisor @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/supervisor/supervisor-4.3.0-20260421153101-py2.py3-none-any.whl#sha256=01f0c6c7fbc4b9a0ccb659a6463319eb83742ba0d6c156e5256484aaedef2917 +vertica-python @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/vertica-python/vertica_python-1.4.0-20260421153108-py3-none-any.whl#sha256=3a094a32c4a892c32be2acb3e77452c8d7b907b6b6ebaa1e6b0a1f5bbecf4d38 +websocket-client @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/built/websocket-client/websocket_client-1.9.0-20260421153115-py3-none-any.whl#sha256=cb12e51596b0dbb085df6efdbd7d00cc315ea04e88f667513702899903ec39fc annotated-types @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/external/annotated-types/annotated_types-0.7.0-py3-none-any.whl#sha256=1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53 attrs @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/external/attrs/attrs-26.1.0-py3-none-any.whl#sha256=c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309 aws-msk-iam-sasl-signer-python @ https://agent-int-packages.datadoghq.com/${INTEGRATIONS_WHEELS_STORAGE}/external/aws-msk-iam-sasl-signer-python/aws_msk_iam_sasl_signer_python-1.0.2-py2.py3-none-any.whl#sha256=310eb2db9ca0ff55ed06a24212739b87533e7f1cf6f34e43aabbd97a3b21290e