Skip to content

[pull] master from DataDog:master#565

Merged
pull[bot] merged 4 commits into
ConnectionMaster:masterfrom
DataDog:master
May 27, 2026
Merged

[pull] master from DataDog:master#565
pull[bot] merged 4 commits into
ConnectionMaster:masterfrom
DataDog:master

Conversation

@pull

@pull pull Bot commented May 27, 2026

Copy link
Copy Markdown

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

AAraKKe and others added 4 commits May 27, 2026 08:34
* Show exact run URL and add lifecycle comment to wheel promotion

- Extend dispatch_workflow with return_run_details so callers can get back the
  new run's html_url instead of a generic recent-runs link.
- ddev dep promote now prints the exact workflow run URL and suppresses noisy
  httpx request logs around the API calls.
- Replace the single success comment in dependency-wheel-promotion.yaml with a
  lifecycle comment that updates on start, success, and failure, scoped per
  (PR, head SHA) via a hidden marker so re-dispatches edit the same comment.

* Harden lifecycle comment chaining and github-script inputs

- Started-comment step now references find_comment.outputs.comment-id (the
  previous version pointed at its own step output, so re-dispatches for the
  same SHA would not have updated the existing comment).
- Pass inputs.head_sha into actions/github-script via env: HEAD_SHA and read
  process.env.HEAD_SHA in the script body, so a hostile workflow_dispatch
  input cannot break out of the JS string literal and execute arbitrary code.

* Type-narrow dispatch_workflow and bail out cleanly on missing run details

- Add Literal[True]/Literal[False] overloads to GitHubManager.dispatch_workflow
  so callers asking for run details get a non-nullable dict back at the type
  level.
- Replace the bare assert in ddev dep promote with an explicit app.abort, run
  the validity check before printing the success message, and keep the success
  output inside the httpx-suppression scope.
- Add ddev/changelog.d/23828.added so the PR-changelog check passes for the
  ddev source changes.
- Lift the github credentials setup into ddev/tests/cli/dep/conftest.py as an
  autouse fixture, hoist the test-side logging import, and add coverage for the
  no-run-details abort path and the failure-path httpx level restoration.
- Match the cleaner api_post.call_args.kwargs form already used in the
  companion test in tests/utils/test_github.py.

* Trim runtime imports and share httpx-debug fixture across promote tests

- Move Any and Literal under TYPE_CHECKING in github.py; they are only used
  inside annotations that PEP 563 keeps as strings, so they have no runtime
  cost. The overload decorator stays at module scope because it runs at class
  definition time.
- Add an httpx_at_debug fixture in tests/cli/dep/conftest.py and use it from
  both httpx-suppression tests so the get-logger/set-DEBUG/restore boilerplate
  lives in one place.

* Type-annotate the new ddev/tests/cli/dep fixtures
…#23144)

* feat(downloader): add TUFPointerDownloader for v2 pointer-file format

The new agent-integrations-tuf pipeline produces TUF targets as JSON
pointer files (targets/<project>/<version>.json) rather than the old
HTML simple index + in-toto approach. This commit adds:

- TUFPointerDownloader in download_v2.py: TUF-verifies the pointer
  file, then fetches and sha256-verifies the wheel from S3.
- DigestMismatch exception for sha256/length failures.
- --format v2 CLI flag: routes through TUFPointerDownloader.
  --unsafe-disable-verification carries forward; --type and
  --ignore-python-version are no-ops in v2 with a warning.
- 8 offline unit tests covering happy path, missing target, digest
  mismatch, length mismatch, and disable_verification mode.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(downloader): use --repository URL for wheel fetch, not pointer's baked value

The pointer file always contains the prod S3 repository URL. When
validating staging, the caller passes --repository <staging-url> to
point at the staging bucket; that URL should be used for both the TUF
metadata fetch AND the wheel download, not just the metadata.

Adds a test that asserts the wheel is fetched from the caller-supplied
URL even when the pointer contains a different (prod) repository value.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* refactor(downloader): resolve latest via S3 listing, drop latest.json reliance

Replace the ``latest.json`` rolling pointer fetch with an S3
``ListObjectsV2`` walk over ``targets/<project>/``: filter keys to PEP 440
stable versions and pick the maximum.  The chosen version is then fetched
through TUF as before, so the pointer file the client trusts is still
cryptographically verified.

Why list S3 instead of parsing the signed targets metadata: once
``path_hash_prefixes`` delegations are in use, a client cannot tell from
metadata alone which delegation signs the latest version of a given
project.  Listing the bucket sidesteps that — TUF still authoritatively
verifies the chosen version's pointer.

The publisher counterpart in agent-integrations-tuf drops ``latest.json``
entirely; see DataDog/agent-integrations-tuf PR #9.

- ``_resolve_latest_version`` lists ``targets/<project>/`` via the S3
  REST API (no boto3 dep), parses the XML response, follows the
  continuation-token pagination, and applies a PEP 440 stable filter
- ``get_pointer(project, version=None)`` resolves ``version`` itself
  before delegating to the TUF Updater
- 6 new offline tests cover max-version selection, pre-release/dev
  filtering, post-release support, the no-stable error, paginated
  listings, and non-pointer key skipping

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Revert "refactor(downloader): resolve latest via S3 listing, drop latest.json reliance"

This reverts commit 70688d8.

* feat(downloader): bundle 1.root.json; rename --format to --index; drop --root-json

- Bundle metadata/root_history/1.root.json from agent-integrations-tuf
  as a package resource; TUFPointerDownloader loads it via
  importlib.resources — no TOFU, no --root-json flag needed
- Rename --format v2 to --index (boolean flag); v1 remains the default
  when --index is absent
- Remove trust_anchor parameter from TUFPointerDownloader.__init__
- Drop --format and --root-json from instantiate_downloader (v1 path)
- Register 1.root.json as a wheel artifact in pyproject.toml
- Update tests to match new interface

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>

* fix(downloader): rename --index to --v2

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>

* feat(downloader): default to v2 with v1 fallback; add prod URL constant

Without any flag the downloader now attempts v2 (against the prod S3
bucket) and falls back to v1 on any failure, so callers get the new
format automatically without code changes. Passing --v2 explicitly keeps
the strict v2 path with no fallback (used by the pipeline's validate-
staging step).

V2_REPOSITORY_URL is the prod bucket constant used for the default
repository value in _download_v2(); callers can still override it with
--repository.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>

* feat(downloader): resolve hash-prefixed targets via N.targets.json

The v2 TUF repository uses consistent-snapshot format: pointer files are
stored as {sha256}.{version}.json on S3. Two changes to support this:

1. _make_updater now sets UpdaterConfig(prefix_targets_with_hash=True) so
   the TUF Updater resolves hash-prefixed paths automatically when calling
   download_target().

2. get_pointer() now parses N.targets.json (after Updater.refresh()) to
   enumerate available versions for the project. This replaces the removed
   latest.json: when version=None, _resolve_version() scans all
   <project>/<ver>.json entries in targets metadata and returns the highest
   stable PEP 440 version.

The disable_verification path fetches the metadata chain (timestamp →
snapshot → targets) without verifying signatures to find the hash-prefixed
URL, then fetches the pointer directly.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>

* feat(downloader): resolve latest via latest pointer target

* Move v2 TUF root metadata

* Simplify v2 downloader implementation

* feat(downloader): add MissingVersion and MalformedPointerError exceptions

Dedicated types replace the prior reuse of TargetNotFoundError for argument
validation (which mislabeled the failure category) and the unchecked KeyError
raised on a malformed pointer JSON.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(downloader): harden v2 wheel fetch and pointer handling

- Add explicit 60s timeout to urllib.request.urlopen so a stalled wheel
  fetch does not hang the Agent installer indefinitely.
- Validate required pointer JSON keys (digest, length, wheel_path) and
  raise the new MalformedPointerError instead of an opaque KeyError.
- Raise MissingVersion (a CLIError subclass) when
  --unsafe-disable-verification is set without --version, so the v1
  fallback log reports the actual cause instead of "target not found".
- Extract _verify_content to drop the pointer-is-None sentinel and make
  the verified and direct-download branches structurally parallel.
- Add `from __future__ import annotations` so the PEP 604 unions stay
  compatible with the declared requires-python = ">=3.8".
- Move logging.basicConfig out of the constructor and into the CLI entry
  point (separate commit); the class no longer mutates the root logger.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(downloader): make v2/v1 fallback handle validation errors and --force

- Split _download_v2() into instantiate_v2_downloader() and
  run_v2_downloader() to mirror the v1 instantiate/run split and let the
  warning/validation branches be tested without patching sys.argv.
- Re-raise user-input errors (CLIError, MissingVersion) before the broad
  except so they propagate as-is instead of triggering a spurious v1
  retry and a misleading "v2 download failed" log line.
- Add --force as a no-op compat stub on the v2 parser so v1-only callers
  do not trip parse_args -> SystemExit and silently skip the fallback.
- Hoist `import logging` to module top (was lazy-imported in the except
  block) and own the verbose-to-level + logging.basicConfig setup that
  used to live inside TUFPointerDownloader.__init__.
- Drop the meaningless `--v2 default=True` re-declaration; rename
  underscore-prefixed argparse dests to plain names.
- Note in the fallback block that v1 offline tests now traverse v2 first
  on every invocation.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* test(downloader): broaden v2 coverage and parametrize failure categories

- Parametrize _v2_failure_category across all five (exc, category) cases
  and add DownloadError / TimeoutError coverage that the categorizer
  already handles but previous tests never asserted.
- Replace direct calls to TUFPointerDownloader._target_path with a
  parametrized test that drives get_pointer and asserts on
  Updater.get_targetinfo so the behavior, not the private helper, is
  what's pinned.
- Add failure-mode tests for malformed pointer JSON (one per required
  key), urllib HTTPError/URLError mid-download, and wheel_path without
  a leading slash so the URL-composition contract is visible.
- Update test_direct_download_requires_explicit_version to expect
  MissingVersion now that argument-validation no longer reuses
  TargetNotFoundError.
- Move @pytest.mark.offline from each class to a module-level
  pytestmark; drop the leading-underscore prefix on module constants
  to match AGENTS.md style.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* style(downloader): sort test imports per project ruff config

Ruff in CI uses the root ../pyproject.toml which treats datadog_checks as
first-party. Reorder the test imports to match.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* refactor(downloader): address PR #23144 review feedback

- exceptions.py: type-hint MalformedPointerError/DigestMismatch __init__;
  add LengthMismatch (split from the overloaded DigestMismatch).
- download_v2.py: drop underscore from WHEEL_FETCH_TIMEOUT_SECONDS and
  REQUIRED_POINTER_KEYS per AGENTS.md; validate wheel_path leading slash
  via MalformedPointerError; verify length first (cheap early-out)
  before the sha256 digest check.
- cli.py: add type hints on download(), _v2_parser(),
  instantiate_v2_downloader(), run_v2_downloader(); drop the unused
  _args parameter from run_v2_downloader; collapse the redundant
  (CLIError, MissingVersion) except clause to just CLIError.
- test_v2_downloader.py: assert MalformedPointerError when wheel_path
  lacks a leading slash; split TestLengthMismatch from TestDigestMismatch;
  cover instantiate_v2_downloader validation/warning branches and the
  cli.download() v2-then-v1 fallback orchestration; drop the inline
  Updater patch in TestDisableVerification in favour of the fixture.

* Fix v2 downloader blockers: narrow fallback, future import

Narrow the v1 fallback in download() to a tuple of network/lookup
errors. Previously every non-CLIError exception triggered v1 retry,
including DigestMismatch / LengthMismatch / MalformedPointerError —
i.e. integrity failures the v2 path is meant to surface were silently
masked. Now those propagate; only TargetNotFoundError, DownloadError,
TimeoutError, and urllib.error.URLError fall back.

Add `from __future__ import annotations` to cli.py: the new module
uses PEP 604 unions and PEP 585 subscripted generics at definition
time, which crash on Python 3.8/3.9 (pyproject.toml declares
requires-python = ">=3.8"). download_v2.py already had the import.

Add parametrized test pinning the new behavior — DigestMismatch,
LengthMismatch, and MalformedPointerError propagate without invoking
the v1 downloader.

Other review feedback (refactor download(), gate compat warnings on
--v2, validate pointer field types, split download() into verified /
direct, etc.) is deferred to a follow-up to keep this PR focused.

* Preserve v1 downloader fallback behavior

* Format v2 downloader tests

* Add v2 downloader reviewer test coverage

* Reuse v2 downloader test wheel name

* Restore unsafe v1 fallback regression test

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* [MOPU-288] Add related links to kubernetes monitor templates

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* [MOPU-288] Add related links to nginx monitor templates

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* [MOPU-288] Add related links to postgres and redis monitor templates

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Fix broken Infrastructure links in monitor templates

The /infrastructure?filters=... links pointed to a non-existent path
with an unsupported query param, and used template variables not in
each monitor's group-by.

- nginx (4xx, 5xx, upstream_peer_fails): remove (upstream is not a
  host/pod/container resource)
- k8s deployments_replicas, statefulset_replicas, pods_failed_state:
  remove (no host/pod template var in group-by)
- k8s node_unavailable: replace with Hosts page scoped to
  kube_cluster_name
- k8s pod_crashloopbackoff, pod_imagepullbackoff, pod_oomkilled,
  pods_restarting: replace with Pod Explorer scoped to pod_name

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
@pull pull Bot locked and limited conversation to collaborators May 27, 2026
@pull pull Bot added the ⤵️ pull label May 27, 2026
@pull pull Bot merged commit 01c70a3 into ConnectionMaster:master May 27, 2026
1 check passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants