Skip to content

feat: --drop-unresolvable-principals flag + drop-aware connection scaffolding (1/4)#629

Merged
michael-richey merged 5 commits into
mainfrom
drop-unresolvable-principals-scaffolding
Jul 15, 2026
Merged

feat: --drop-unresolvable-principals flag + drop-aware connection scaffolding (1/4)#629
michael-richey merged 5 commits into
mainfrom
drop-unresolvable-principals-scaffolding

Conversation

@michael-richey

@michael-richey michael-richey commented Jul 14, 2026

Copy link
Copy Markdown
Collaborator

Context

Stacked PR 1 of 4. Base: main.

Exported resources can reference roles/principals that were deleted from the source before their state was captured, leaving references that can never resolve. Today one such dead reference makes connect_resources() raise ResourceConnectionError and skip the entire resource's access-control sync.

This series adds an opt-in --drop-unresolvable-principals flag: drop a principal absent from both destination and source (permanently gone), keep syncing the rest, and treat an emptied binding/list as a normal resource-connection failure. Default-off = byte-for-byte unchanged behavior.

Interaction with --skip-failed-resource-connections

Restriction policies are resource connections, so the existing flag remains authoritative:

  • Without --skip-failed-resource-connections, an emptied binding/list raises ResourceConnectionError and the resource is skipped.
  • With --skip-failed-resource-connections=true, that connection failure is intentionally suppressed and the resource continues syncing, even though the destination resource may become unrestricted.
  • The permitted escalation is explicit: an immediate ERROR says DESTINATION RESOURCE MAY BE UNRESTRICTED, the successful action metric carries risk:empty_restriction_policy, and the end-of-run ERROR summary lists resources that actually synced through this override.

This PR (scaffolding — inert when the flag is off)

  • --drop-unresolvable-principals CLI option (in _diffs_options → sync/diffs/migrate), threaded through Configuration.
  • BaseResource._resolve_or_drop: three-way resolver (destination-present / source-present "not yet synced" → hard-fail as today / absent-from-both → droppable only under the flag). For --minimize-reads, it rechecks destination after ensure_resource_loaded() before classifying the reference as pending or stale, because lazy loading can populate the destination mapping.
  • Shared _filter_stale_binding_principals, _filter_stale_flat_roles, _raise_connection_error_if_any helpers. Lists are rebuilt (never index-mutated) to avoid the enumerate/index-shift skip bug.
  • ResourceConnectionResult gives the base method and model overrides a named, type-safe result contract; successful suppressed-risk syncs set empty_binding_escalation explicitly rather than relying on truthiness.
  • ResourceConnectionError.empty_binding_risk; separate Counter buckets for skipped risks and successful suppressed-risk syncs; config.counter back-reference; truthful end-of-run summaries.
  • _apply_resource_cb tags both skipped and successful suppressed-risk metrics with risk:empty_restriction_policy.

No model opts into the drop-aware helpers yet — runtime behavior remains unchanged until PRs 2–4.

Testing

New unit tests cover the named connection-result contract, resolver branches—including lazy loads that populate destination-only and both source/destination—filtering, counters/reset, exception metadata, both empty-binding connection modes, truthful ERROR logs, skipped/success metrics, end-of-run summaries, and CLI flag round-trip. Focused tests and ruff are green locally; CI is pending the updated branch.

…on scaffolding

Adds the opt-in `--drop-unresolvable-principals` flag plus the shared, inert-when-off
machinery that later PRs wire into individual resource models. No behavior changes when
the flag is absent (the default).

- New `--drop-unresolvable-principals` CLI option (in `_diffs_options`, so it applies to
  sync/diffs/migrate) threaded through the `Configuration` dataclass.
- `BaseResource._resolve_or_drop`: three-way resolver distinguishing destination-present,
  source-present ("not yet synced", hard-fail as today), and permanently-gone
  (absent from both — droppable only under the flag).
- Shared `_filter_stale_binding_principals` / `_filter_stale_flat_roles` /
  `_raise_connection_error_if_any` helpers (rebuild lists rather than mutating in place,
  avoiding the enumerate/index-shift bug).
- `ResourceConnectionError.empty_binding_risk` flag for the access-elevation case.
- New `Counter` buckets (stale drops, empty-binding risks) + reset, surfaced by
  `_emit_apply_summary`; `config.counter` back-reference so models can record drops.
- `_apply_resource_cb` adds a `risk:empty_restriction_policy` metric tag when a binding
  emptied out.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@michael-richey
michael-richey force-pushed the drop-unresolvable-principals-scaffolding branch from 7db6366 to a7514ad Compare July 14, 2026 21:32
@michael-richey
michael-richey marked this pull request as ready for review July 15, 2026 13:39
@michael-richey
michael-richey requested a review from a team as a code owner July 15, 2026 13:39
@michael-richey
michael-richey requested a review from Copilot July 15, 2026 13:46

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds opt-in scaffolding for handling unresolvable principals/roles during resource connection, including new counters/summary output and metric tagging for the “empty restriction policy” risk path, while keeping default behavior unchanged when the flag is off.

Changes:

  • Introduces --drop-unresolvable-principals CLI option and threads it through Configuration.
  • Adds drop-aware connection helpers to BaseResource plus new Counter buckets and apply-summary reporting for dropped principals and empty-binding risk/escalation.
  • Extends ResourceConnectionError with empty_binding_risk metadata and tags both skipped and successful suppressed-risk metrics.

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
tests/unit/test_workers.py Adds unit coverage for new Counter buckets and reset behavior.
tests/unit/test_resource_utils.py Tests new ResourceConnectionError.empty_binding_risk behavior.
tests/unit/test_drop_unresolvable_principals_cli.py Verifies CLI option is accepted by sync/diffs/migrate and rejected by import.
tests/unit/test_base_resource.py Adds tests for _resolve_or_drop and empty-binding risk behavior.
tests/unit/test_apply_summary_handler.py Adds coverage for new apply-summary warning/error lines.
tests/unit/test_apply_resource_connection_error.py Validates risk tagging and counter recording for skipped and successful escalation paths.
datadog_sync/utils/workers.py Adds new Counter buckets + sets config.counter back-reference.
datadog_sync/utils/resources_handler.py Tags metrics and records counters for empty-binding risk/escalation; updates summary emission.
datadog_sync/utils/resource_utils.py Adds empty_binding_risk to ResourceConnectionError.
datadog_sync/utils/configuration.py Threads drop_unresolvable_principals through config + adds optional counter reference.
datadog_sync/utils/base_resource.py Adds shared resolver/filter helpers and shared empty-binding risk raising behavior.
datadog_sync/commands/shared/options.py Adds the --drop-unresolvable-principals click option to _diffs_options.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread datadog_sync/utils/resources_handler.py Outdated
Comment thread datadog_sync/utils/configuration.py
@michael-richey
michael-richey marked this pull request as draft July 15, 2026 14:28
@michael-richey
michael-richey marked this pull request as ready for review July 15, 2026 14:29
heyronhay
heyronhay previously approved these changes Jul 15, 2026
…the whole policy (2/4) (#630)

* fix(restriction_policies): drop stale principals instead of skipping the whole policy

Overrides `connect_resources` so that, under `--drop-unresolvable-principals`, a principal
absent from both destination and source state (permanently gone — e.g. a role deleted
before the org's first-ever import) is dropped from its binding and the policy still syncs,
instead of the entire restriction policy being skipped on a single dead reference.

- Principals present in source but not destination keep today's hard-fail/retry behavior.
- If dropping empties a binding whose source list was non-empty, the resource is still
  skipped and flagged as an access-elevation risk (ERROR + metric), governed by
  `--skip-failed-resource-connections` like any other connection failure.
- The "id" (dashboard/slo/notebook) connections keep the generic path unchanged.
- `extract_source_ids` is intentionally left unaffected (documented) so minimize-reads
  lazy-loading can still resolve which principals to check.

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

* fix(monitors,synthetics_tests): drop stale restricted_roles/principals under new flag (3/4) (#631)

* fix(monitors,synthetics_tests): drop stale restricted_roles/principals under new flag

Applies the same drop-aware pattern (PR1 helpers) to the two resource types that carry
both a flat `restricted_roles` list and a `restriction_policy.bindings.principals` composite:

- monitors: `restricted_roles` + `restriction_policy.bindings.principals`
- synthetics_tests: `options.restricted_roles` + `restriction_policy.bindings.principals`

Each `connect_resources` override keeps all non-access-control connections on the generic
path, filters access-control references through the shared helpers, and preserves the
empty-binding/empty-list access-elevation hard-fail. `extract_source_ids` left unaffected
(documented). Behavior is unchanged when `--drop-unresolvable-principals` is off.

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

* fix(dashboards,synthetics_private_locations): drop stale restricted_roles under new flag (#632)

Completes the rollout by applying the flat-list drop-aware filter to the two remaining
resource types with a `restricted_roles` list:

- dashboards: `restricted_roles`
- synthetics_private_locations: `metadata.restricted_roles`

Both previously had trivial pass-through `connect_id` overrides; they now get a
`connect_resources` override that filters stale roles under `--drop-unresolvable-principals`
while keeping widget/other connections on the generic path and preserving the empty-list
access-elevation hard-fail. Adds a new unit test module for synthetics_private_locations.

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
@michael-richey
michael-richey merged commit 7916f12 into main Jul 15, 2026
11 checks passed
@michael-richey
michael-richey deleted the drop-unresolvable-principals-scaffolding branch July 15, 2026 18:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants