Skip to content

control-plane-api: add a root effectiveAlertConfig(catalogPrefixOrName:) query - #3227

Merged
GregorShear merged 1 commit into
masterfrom
greg/effective-config
Jul 28, 2026
Merged

control-plane-api: add a root effectiveAlertConfig(catalogPrefixOrName:) query#3227
GregorShear merged 1 commit into
masterfrom
greg/effective-config

Conversation

@GregorShear

@GregorShear GregorShear commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds a top-level effectiveAlertConfig(catalogPrefixOrName:) GraphQL query that resolves the effective alert config at a single prefix or catalog name — merging all ancestor prefix layers and controller defaults, with per-field provenance.

Why a root query

Master already exposes effective config as fields (AlertConfigEntry.effective, LiveSpec.effectiveAlertConfig), which only answer for scopes that have an entry or a live spec. This root query takes an arbitrary catalogPrefixOrName and does not require an alert_configs row to exist there, so it answers for prefixes and names that carry no explicit config and are therefore absent from the alertConfigs listing.

It reuses the existing resolve_effective_alert_config helper and its provenance output; auth requires CatalogRead on the scope, matching the field-level accessors.

Input validation

validate_prefix_or_name now rejects a slash-less token like aliceCo. Such a token is neither a prefix (no trailing /) nor a real catalog name (names are always hierarchical), so it previously validated as a bare Name and then failed authorization with a confusing PermissionDenied — a grant at aliceCo/ never covers the bare string aliceCo. It now returns a validation error pointing at the trailing-slash prefix form, matching the slash requirement the mutation path already enforces via governing_prefix.

Testing

test_effective_alert_config_query covers:

  • defaults-only resolution (no row present; provenance source: null)
  • an inherited prefix override with provenance attribution
  • the exact-catalog-name layer (aliceCo/in/capture-foo)
  • the slash-less validation rejection
  • read-denied

SDL regenerated.

pub struct PrefixFilter {
/// Match rows whose value is prefixed by this string.
pub starts_with: Option<String>,
/// Match the single row whose value equals this string exactly.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

i'm not sure why this has to be a single row - could be multiple rows that have the same prefix, right?

@GregorShear
GregorShear force-pushed the greg/effective-config branch from b7bcd02 to 2a516b7 Compare July 23, 2026 02:00
@GregorShear
GregorShear force-pushed the greg/effective-config branch from 2a516b7 to e2fcce7 Compare July 23, 2026 20:38
@GregorShear GregorShear changed the title Add effectiveAlertConfig GraphQL query control-plane-api: add a root effectiveAlertConfig(catalogPrefixOrName:) query Jul 23, 2026
@GregorShear
GregorShear changed the base branch from master to greg/gql-storage-mappings-filter July 23, 2026 20:38
let policy_result = crate::server::evaluate_names_authorization(
env.snapshot(),
claims,
models::Capability::Read,

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

could we use the capability_bit instead of legacy capability?

@GregorShear
GregorShear force-pushed the greg/effective-config branch from e2fcce7 to fe12453 Compare July 23, 2026 20:51
@GregorShear
GregorShear force-pushed the greg/gql-storage-mappings-filter branch 3 times, most recently from 572cb9c to 95c7343 Compare July 24, 2026 20:38
jshearer
jshearer previously approved these changes Jul 27, 2026

@jshearer jshearer left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM, left a couple nits -- need to rebase ontop of master once the base branch is merged, regenerate graphql schema etc. Plus a test coverage nit and an error message nit

Let me know once you rebase/regen gql and I'll re-approve

Comment thread crates/flow-client/control-plane-api.graphql Outdated
Comment thread crates/control-plane-api/src/server/public/graphql/alert_configs.rs
Comment thread crates/control-plane-api/src/server/public/graphql/alert_configs.rs
@GregorShear
GregorShear force-pushed the greg/effective-config branch from fe12453 to 7685414 Compare July 27, 2026 19:29
@GregorShear
GregorShear changed the base branch from greg/gql-storage-mappings-filter to master July 27, 2026 19:30
@GregorShear
GregorShear dismissed jshearer’s stale review July 27, 2026 19:30

The base branch was changed.

…me:)` query

Adds a top-level query that resolves the effective alert config at a single
prefix or catalog name, merging all ancestor prefix layers and controller
defaults, with per-field provenance.

Unlike the existing field-level accessors (`AlertConfigEntry.effective`,
`LiveSpec.effectiveAlertConfig`), this takes an arbitrary `catalogPrefixOrName`
and does not require an `alert_configs` row to exist at that scope — so it
answers for prefixes and names that carry no explicit config and are therefore
absent from the `alertConfigs` listing. The caller must have `CatalogRead`
capability on the scope; ancestor layers merged into the result are visible to
anyone who can read the scope, matching the field-level accessors.

Reuses the existing `resolve_effective_alert_config` helper and its provenance
output.

`validate_prefix_or_name` now rejects a slash-less token (e.g. `aliceCo`): it is
neither a prefix nor a real catalog name, so it previously validated as a bare
`Name` and then failed authorization with a confusing `PermissionDenied`. It now
returns a clear validation error suggesting the trailing-slash prefix form,
matching the slash requirement the mutation path already enforces via
`governing_prefix`.

Test coverage exercises defaults-only resolution, an inherited prefix override
with provenance attribution, the exact-catalog-name layer, the slash-less
validation rejection, and read-denied.
@GregorShear
GregorShear force-pushed the greg/effective-config branch from 7685414 to d958300 Compare July 27, 2026 20:23
@GregorShear
GregorShear requested a review from jshearer July 27, 2026 20:44
@GregorShear
GregorShear merged commit c8fbf5c into master Jul 28, 2026
11 of 14 checks passed
@GregorShear
GregorShear deleted the greg/effective-config branch July 28, 2026 14:21
williamhbaker pushed a commit to estuary/homebrew-flowctl that referenced this pull request Aug 12, 2026
## What's Changed
* control-plane-api: fix storage-mapping suffix strip to respect path-segment boundaries by @GregorShear in estuary/flow#3239
* materialize: remove deprecated `constraints` from materialize protocol by @mdibaiee in estuary/flow#3104
* control-plane: verify delete permission for user storage mappings by @williamhbaker in estuary/flow#3197
* Gate invite-link private-DP grants on an existing private data plane by @GregorShear in estuary/flow#3234
* local: fix dashboard origin to the external UI (http://localhost:3000) by @jgraettinger in estuary/flow#3230
* data-plane-controller: add GitHub App git auth to replace SSH machine user by @skord in estuary/flow#3243
* data-plane-controller: fix broken deploy (comments in env/secrets block scalars) by @skord in estuary/flow#3250
* notifications: remove stale alert_notifications snapshot files by @jwhartley in estuary/flow#3079
* Docs: Link fixes, remove example pages by @aeluce in estuary/flow#3231
* data-plane-controller: cut git auth over to the GitHub App by @skord in estuary/flow#3249
* Docs: reference page for OpenSearch materialization by @aeluce in estuary/flow#3113
* vm: fix Lima development VMs on Linux hosts by @skord in estuary/flow#3267
* publisher: discard unauthorized recovered ACK intents by @jgraettinger in estuary/flow#3268
* docs: source-sqs by @Alex-Bair in estuary/flow#3201
* runtime-next: remove hardcoded materialization ser_policy fallback by @dgreer-dev in estuary/flow#3140
* runtime-v2: bind task terms to ShardSpec bytes and restart gracefully from Join-wait by @jgraettinger in estuary/flow#3264
* Extend `PrefixFilter` with `in` and add storage mapping query as a consumer by @GregorShear in estuary/flow#3242
* docs: add initial materialize-hubspot docs by @danielnelson in estuary/flow#3042
* shuffle: fix open-phase deadlock via EOF-cascade teardown by @jgraettinger in estuary/flow#3261
* docs: add dataMovementStalled threshold example and format by @jwhartley in estuary/flow#3251
* control-plane-api: add a root effectiveAlertConfig(catalogPrefixOrName:) query by @GregorShear in estuary/flow#3227
* runtime-next: stop constructing per-iteration timers in actor loops by @jgraettinger in estuary/flow#3273
* tests: update to projection constraints in ledger connector by @danielnelson in estuary/flow#3274
* docs: document _meta field selection and depth behavior by @jwhartley in estuary/flow#3209
* control-plane: refresh notification emails by @aeluce in estuary/flow#3179
* docs: source-braintree-native resources have configurable concurrency by @Alex-Bair in estuary/flow#3270
* docs: materialize-iceberg table_identifier_case and field_name_case options by @jacobmarble in estuary/flow#3262
* runtime-v2: fix shuffle recovery deadlock under split read cohorts by @jgraettinger in estuary/flow#3278
* 2781: Preemptively deploying states for Discovery and Publish by @bbartman in estuary/flow#3279
* Docs: Add Snowflake user type by @aeluce in estuary/flow#3280
* docs: rediscovery interval config setting for SQL capture connectors by @Alex-Bair in estuary/flow#3285
* docs: source-mailchimp-native by @nicolaslazo in estuary/flow#3288
* config-encryption: fix broken image and deploy from CI by @mdibaiee in estuary/flow#3308
* config-encryption: fix Cloud Run startup probe port by @mdibaiee in estuary/flow#3315
* Docs: Webhook capture organization and fixes by @aeluce in estuary/flow#3313
* Sync Schedule moved to runtime v2 by @dgreer-dev in estuary/flow#3269
* dekaf: fix avro schema when property type is invalid by @danielnelson in estuary/flow#3301
* docs: source-brevo rewrite by @Alex-Bair in estuary/flow#3316
* docs: AWS IAM auth cross-account guidance, correct Identity Provider ARN wording by @jwhartley in estuary/flow#3298
* Local-stack QA quality of life: arm64 connector containers, child-process cleanup, readiness by @jgraettinger in estuary/flow#3276
* control-plane-api: remove dead evolutions module by @jshearer in estuary/flow#3302
* Introduce an indirect form of built specifications by @jgraettinger in estuary/flow#3303
* docs: clarify BYOK KMS is decrypt-only and identity may not be in dashboard by @jwhartley in estuary/flow#3065
* shuffle: gate the causal-hint stall timeout on a requested checkpoint by @williamhbaker in estuary/flow#3323
* docs: source-shopify-native add markets stream by @Alex-Bair in estuary/flow#3331
* docs: source-commercetools by @Alex-Bair in estuary/flow#3332

**Full Changelog**: estuary/flow@v0.6.12...v0.6.13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants