From c1a1c4ddd55542079b81d0f3789b90b8df939af6 Mon Sep 17 00:00:00 2001 From: Jon Langevin Date: Sun, 24 May 2026 02:39:43 -0400 Subject: [PATCH 01/16] docs(plan): verify-capabilities contract-diff extension design (workflow#767) Adds capabilities.iacServices schema to PluginManifest + BuildContractRegistryForPlugin SDK helper + extends verify-capabilities subcommand to walk GetContractRegistry. Sweeps 4 IaC plugins. Closes deferred contract-diff from #765 cycle-3 review. --- docs/plans/2026-05-24-contract-diff-design.md | 129 ++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 docs/plans/2026-05-24-contract-diff-design.md diff --git a/docs/plans/2026-05-24-contract-diff-design.md b/docs/plans/2026-05-24-contract-diff-design.md new file mode 100644 index 00000000..9ff98205 --- /dev/null +++ b/docs/plans/2026-05-24-contract-diff-design.md @@ -0,0 +1,129 @@ +# `wfctl plugin verify-capabilities` Contract-Diff Extension Design + +**Issue:** [workflow#767](https://github.com/GoCodeAlone/workflow/issues/767) +**Status:** Draft 2026-05-24 — awaiting adversarial design review +**Author:** Jon Langevin +**Parent:** workflow#765 (verify-capabilities scoped to Name+Version) + cycle-3 Reviewer Option 2 deferring contract-diff with two prerequisites + +## Problem + +`wfctl plugin verify-capabilities` (workflow#765) verifies binary `Manifest.Name` + `Manifest.Version` match `plugin.json`. Two intentional deferrals from #765 cycle-3 review remain open: + +1. **No LHS for IaC service diff** — `plugin.json` does not have an `iacServices` field. Static `validate-contract` cannot enforce "binary advertises the typed IaC services it claims to" because there's nothing to claim. +2. **`GetContractRegistry` returns ALL gRPC services** including go-plugin infra (`workflow.plugin.v1.PluginService`, `plugin.GRPCBroker`, `plugin.GRPCStdio`, `grpc.health.v1.Health`). Set-equal diff against any plugin.json-declared list would surface 3-5 spurious "extra-in-binary" entries per plugin. + +This design closes both gaps so verify-capabilities can diff `ContractRegistry` against declared `iacServices` cleanly. + +## Solution + +Three pieces, single PR: + +### 1. New `PluginManifest.IaCServices []string` field + +```go +// IaCServices lists the typed IaC service names this plugin serves +// (fully-qualified gRPC service names, e.g. "workflow.iac.v1.IaCProviderRequired"). +// Authored in plugin.json either as a top-level "iacServices" key OR nested +// under "capabilities.iacServices" (UnmarshalJSON's object branch promotes +// the nested form). The engine cross-checks these against the plugin's +// runtime ContractRegistry via wfctl plugin verify-capabilities. +IaCServices []string `json:"iacServices,omitempty" yaml:"iacServices,omitempty"` +``` + +Pattern mirrors existing `IaCStateBackends` field (`plugin/manifest.go:54-62`). UnmarshalJSON's legacy object-form promotion (`plugin/manifest.go:142-159`) gets the new key wired same way. + +### 2. SDK helper: `BuildContractRegistryForPlugin(grpcSrv, namespace)` + +```go +// BuildContractRegistryForPlugin enumerates gRPC services registered on +// grpcSrv whose name starts with the given namespace (e.g. "workflow.iac.v1.") +// and returns a *pb.ContractRegistry. Filters out go-plugin infra services +// (PluginService, GRPCBroker, GRPCStdio, health) and any other namespaces +// that aren't plugin-owned. +// +// Plugin authors opt in by switching their ContractProvider impl: +// func (p *plugin) ContractRegistry() *pb.ContractRegistry { +// return sdk.BuildContractRegistryForPlugin(p.grpcServer, "workflow.iac.v1.") +// } +// +// BuildContractRegistry (full-surface, no filter) is retained for plugin +// types where exposing the full surface is intentional. +func BuildContractRegistryForPlugin(grpcSrv *grpc.Server, namespace string) *pb.ContractRegistry { ... } +``` + +### 3. Extend `wfctl plugin verify-capabilities` + +After existing Name+Version diff: + +- Call `pb.NewPluginServiceClient(conn).GetContractRegistry(ctx, Empty)`. +- Client-side filter to services starting with `workflow.iac.v1.` (hardcoded namespace; design Decision §1 below). +- Set-equal diff against `plugin.json.iacServices` (sorted both sides). +- IF `plugin.json.iacServices` is empty: skip the contract-diff (plugin doesn't claim any IaC services; no diff to perform). Non-IaC plugins remain unaffected. +- ELSE: missing or extra service names → FAIL with field-by-field report. + +### 4. Sweep 4 IaC plugins to populate `iacServices` + +- `workflow-plugin-aws` — populate from its existing typed-IaC registrations. +- `workflow-plugin-azure` — same. +- `workflow-plugin-gcp` — same. +- `workflow-plugin-digitalocean` — same. + +Each plugin's `plugin.json` gets `"iacServices": ["workflow.iac.v1.IaCProviderRequired", ...]` listing the typed services it registers via `iacserver.go`'s `pb.RegisterIaCProviderRequiredServer` etc. The exact list is per-plugin (depends on which optional IaC interfaces each implements). + +## Decisions + +**§1 — Namespace filter: hardcoded `workflow.iac.v1.` vs configurable.** +Hardcoded. IaC plugins are the only consumers today. A future second-namespace use (e.g. `workflow.cms.v1.*`) can either reuse the helper with the new namespace, or extend verify-capabilities to take a `--namespace` flag. YAGNI for now. ADR: `decisions/NNNN-verify-capabilities-iac-namespace.md`. + +**§2 — Server-side filter (plugin authors switch ContractRegistry impl) vs client-side filter (verify-capabilities filters).** +BOTH. Server-side helper exists for plugin authors who want clean output everywhere (logs, debug RPC). Client-side filter in verify-capabilities runs regardless — plugins that haven't migrated to `BuildContractRegistryForPlugin` still get correct diff results because client-side filter handles the noise. Defense in depth. + +**§3 — Set-equal vs subset comparison.** +Set-equal. Plugin.json's `iacServices` is the source of truth; binary must advertise EXACTLY those (no more, no less). Missing → bug. Extra → bug (something registered that isn't declared). + +**§4 — Empty `iacServices` semantics.** +Empty list = "no contract-diff for this plugin". Both non-IaC plugins (legitimately no IaC services) and IaC plugins that haven't been swept yet (Task 4 backlog) skip the diff cleanly. Future tightening: `validate-contract` could enforce non-empty `iacServices` for `type:"iac"` plugins. + +## Files + +- `plugin/manifest.go` — add `IaCServices` field + UnmarshalJSON nested-promotion. +- `plugin/external/sdk/contracts.go` — add `BuildContractRegistryForPlugin`. +- `cmd/wfctl/plugin_verify_capabilities.go` — extend `runPluginVerifyCapabilities` with GetContractRegistry call + filter + diff. +- `cmd/wfctl/plugin_verify_capabilities_test.go` — new test scenarios: `iac-good` (matching services), `iac-missing-service` (declared but not advertised), `iac-extra-service` (advertised but not declared). +- `cmd/wfctl/testdata/verify_capabilities/iac-{good,missing-service,extra-service}/` — 3 new fixture scenarios using `sdk.ServeIaCPlugin` + `sdk.IaCServeOptions{Modules: ..., BuildVersion: ...}` so they actually register IaC services on the wire. +- `workflow-plugin-aws/plugin.json` (+ azure/gcp/digitalocean) — populate `iacServices` field. + +## Assumptions + +1. **All 4 IaC plugins register the same canonical namespace `workflow.iac.v1.*`** — verified per `plugin/external/proto/iac.proto` package declaration. +2. **`pb.PluginServiceClient.GetContractRegistry` is wired uniformly across all plugin types** — non-IaC plugins return an empty/infra-only registry that the namespace filter reduces to empty (no diff fires per §4). +3. **`grpc.Server.GetServiceInfo()` returns fully-qualified service names** — verified per gRPC-go API. +4. **Fixture scenarios can build IaC plugins in-place via `go build -mod=readonly`** — verified pattern from #765 fixtures. + +## Failure modes + +- **Plugin doesn't implement ContractProvider**: `GetContractRegistry` returns `Unimplemented`. Skip contract-diff with a WARN line (matches verify-capabilities' existing GetManifest-Unimplemented handling). +- **Network/RPC failure mid-call**: hard exit 1 with the RPC error message + stderr tail. +- **Plugin advertises a service in a different namespace** (e.g. `workflow.iac.v2.*` post-cutover): client-side filter excludes it. Forward-compat handled by bumping the hardcoded namespace in a future PR. + +## Rollback + +Runtime-affecting (changes CLI subcommand behavior + plugin SDK API). Rollback path: + +- **PR revert**: removes `IaCServices` field, removes SDK helper, reverts verify-capabilities extension. All scaffold-template `release.yml` files that ran the post-goreleaser step continue working (verify-capabilities still does Name+Version diff; the contract-diff just stops firing). +- **Sweep PRs (4 IaC plugins)**: each is a separate plugin-repo PR; revert independently if needed. +- **Backwards-compat**: subcommand behavior is a strict SUPERSET — adds new diff dimension; doesn't change Name/Version diff semantics. Older wfctl callers (without verify-capabilities the subcommand) continue to work. plugin.json with no `iacServices` field continues to work (treated as empty list per §4). + +## Top 3 doubts (self-challenge) + +1. **Hardcoded `workflow.iac.v1.` namespace is forward-incompatible with a v2 cutover.** Mitigation: documented in §1 ADR; v2 introduces `--namespace` flag at that point. Single-line change. +2. **Empty `iacServices` skip-with-no-diff means non-swept IaC plugins get NO truth-check on their contract surface.** Mitigation: explicit in §4; sweep follow-up tracked. Acceptable trade-off: opt-in is better than forced-empty failure for non-swept plugins. +3. **Plugin authors who DON'T switch to `BuildContractRegistryForPlugin` still emit noise in their `GetContractRegistry` RPC response.** Mitigation: client-side filter in verify-capabilities masks the noise from the diff. Authors can migrate independently for cleaner debug/log output. No correctness regression. + +## Non-goals (explicit) + +- Does NOT support multi-namespace plugins (single `workflow.iac.v1.*` hardcoded). +- Does NOT auto-populate `plugin.json.iacServices` from runtime introspection (operator authors it; or a future `wfctl plugin scaffold-iac-services` helper). +- Does NOT change non-IaC plugin behavior (empty iacServices = no diff). +- Does NOT extend `validate-contract` to enforce `iacServices` non-empty for `type:"iac"` plugins (future tightening; out of scope here). +- Does NOT sweep the scaffold release.yml wiring (already done in Layer 3b extension; no change needed). From 227e83e52656663e6fa329eedb4630377c98dccc Mon Sep 17 00:00:00 2001 From: Jon Langevin Date: Sun, 24 May 2026 02:46:22 -0400 Subject: [PATCH 02/16] docs(plan): #767 design cycle 2 (fix wrong namespace + cite existing helpers) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cycle 1 FAIL: 2 Critical (workflow.iac.v1 namespace never existed on wire — actual workflow.plugin.external.iac per proto pkg decl; duplicated existing registeredIaCServices + iacServiceRequired helpers without citing). + 5 Important. Cycle 2: - Derive namespace prefix programmatically from pb.IaCProviderRequired_ServiceDesc.ServiceName (single source of truth keyed to .proto pkg). - Cite + reuse registeredIaCServices (deploy_providers.go:344) + iacServiceRequired const (iac_typed_adapter.go:52). - Directional diff (FAIL missing-from-binary; WARN extra-in-binary) per IMPORTANT-1. - Use cached adapter.ContractRegistry() — no redundant RPC (IMPORTANT-2). - Sweep-target SDK pin assumption explicit (IMPORTANT-4). - IaCStateBackend orthogonality documented (IMPORTANT-5). - Non-goal: embedded plugin.json verify (IMPORTANT-3). --- docs/plans/2026-05-24-contract-diff-design.md | 111 +++++++++++------- 1 file changed, 71 insertions(+), 40 deletions(-) diff --git a/docs/plans/2026-05-24-contract-diff-design.md b/docs/plans/2026-05-24-contract-diff-design.md index 9ff98205..f9f59904 100644 --- a/docs/plans/2026-05-24-contract-diff-design.md +++ b/docs/plans/2026-05-24-contract-diff-design.md @@ -1,10 +1,15 @@ # `wfctl plugin verify-capabilities` Contract-Diff Extension Design **Issue:** [workflow#767](https://github.com/GoCodeAlone/workflow/issues/767) -**Status:** Draft 2026-05-24 — awaiting adversarial design review +**Status:** Revised cycle 2 2026-05-24 — awaiting re-review **Author:** Jon Langevin **Parent:** workflow#765 (verify-capabilities scoped to Name+Version) + cycle-3 Reviewer Option 2 deferring contract-diff with two prerequisites +## Revision history + +- **Cycle 1**: initial design hardcoded namespace `workflow.iac.v1.*`. FAILED — 2 Critical (wrong namespace; never traced to proto file; actual is `workflow.plugin.external.iac.*`. Duplicates existing `registeredIaCServices`/`iacServiceRequired` precedent without citing or reusing). + 5 Important. +- **Cycle 2** (this version): namespace derived programmatically from `pb.IaCProviderRequired_ServiceDesc.ServiceName`. Citations + reuse of existing helpers. Directional diff (FAIL on missing-from-binary, WARN on extra). Use cached `adapter.ContractRegistry()`. Add non-goal for embedded plugin.json. Sweep-target SDK pin assumption made explicit. IaCStateBackend orthogonality documented. + ## Problem `wfctl plugin verify-capabilities` (workflow#765) verifies binary `Manifest.Name` + `Manifest.Version` match `plugin.json`. Two intentional deferrals from #765 cycle-3 review remain open: @@ -22,44 +27,60 @@ Three pieces, single PR: ```go // IaCServices lists the typed IaC service names this plugin serves -// (fully-qualified gRPC service names, e.g. "workflow.iac.v1.IaCProviderRequired"). -// Authored in plugin.json either as a top-level "iacServices" key OR nested -// under "capabilities.iacServices" (UnmarshalJSON's object branch promotes +// (fully-qualified gRPC service names, e.g. +// "workflow.plugin.external.iac.IaCProviderRequired"). Authored in +// plugin.json either as a top-level "iacServices" key OR nested under +// "capabilities.iacServices" (UnmarshalJSON's object branch promotes // the nested form). The engine cross-checks these against the plugin's // runtime ContractRegistry via wfctl plugin verify-capabilities. +// +// Orthogonal to IaCStateBackends (which lists backend NAMES the plugin +// serves, not gRPC service names). A plugin that registers the +// IaCStateBackend service AND lists its backend name(s) in +// iacStateBackends will appear in BOTH manifest fields: IaCServices for +// the wire surface, IaCStateBackends for the backend-name surface. IaCServices []string `json:"iacServices,omitempty" yaml:"iacServices,omitempty"` ``` Pattern mirrors existing `IaCStateBackends` field (`plugin/manifest.go:54-62`). UnmarshalJSON's legacy object-form promotion (`plugin/manifest.go:142-159`) gets the new key wired same way. -### 2. SDK helper: `BuildContractRegistryForPlugin(grpcSrv, namespace)` +### 2. SDK helper: `BuildContractRegistryForPlugin(grpcSrv, namespacePrefix)` ```go // BuildContractRegistryForPlugin enumerates gRPC services registered on -// grpcSrv whose name starts with the given namespace (e.g. "workflow.iac.v1.") -// and returns a *pb.ContractRegistry. Filters out go-plugin infra services -// (PluginService, GRPCBroker, GRPCStdio, health) and any other namespaces -// that aren't plugin-owned. +// grpcSrv whose name starts with the given namespacePrefix and returns +// a *pb.ContractRegistry. Filters out go-plugin infra services +// (PluginService, GRPCBroker, GRPCStdio, health) and any other +// namespaces that aren't plugin-owned. // // Plugin authors opt in by switching their ContractProvider impl: +// import pb "github.com/GoCodeAlone/workflow/plugin/external/proto" // func (p *plugin) ContractRegistry() *pb.ContractRegistry { -// return sdk.BuildContractRegistryForPlugin(p.grpcServer, "workflow.iac.v1.") +// // Derive prefix from the canonical service descriptor so the +// // string can't drift from the .proto package declaration. +// prefix := strings.TrimSuffix(pb.IaCProviderRequired_ServiceDesc.ServiceName, ".IaCProviderRequired") + "." +// return sdk.BuildContractRegistryForPlugin(p.grpcServer, prefix) // } // // BuildContractRegistry (full-surface, no filter) is retained for plugin // types where exposing the full surface is intentional. -func BuildContractRegistryForPlugin(grpcSrv *grpc.Server, namespace string) *pb.ContractRegistry { ... } +func BuildContractRegistryForPlugin(grpcSrv *grpc.Server, namespacePrefix string) *pb.ContractRegistry { ... } ``` ### 3. Extend `wfctl plugin verify-capabilities` After existing Name+Version diff: -- Call `pb.NewPluginServiceClient(conn).GetContractRegistry(ctx, Empty)`. -- Client-side filter to services starting with `workflow.iac.v1.` (hardcoded namespace; design Decision §1 below). -- Set-equal diff against `plugin.json.iacServices` (sorted both sides). -- IF `plugin.json.iacServices` is empty: skip the contract-diff (plugin doesn't claim any IaC services; no diff to perform). Non-IaC plugins remain unaffected. -- ELSE: missing or extra service names → FAIL with field-by-field report. +- Reuse cached `adapter.ContractRegistry()` (set at `NewExternalPluginAdapter` construction per `plugin/external/adapter.go:165-172`) — no second RPC. The adapter maps `Unimplemented` to an empty registry, so "Unimplemented" and "empty registry" both reduce to "filter returns 0 services" handled by §4 skip-if-LHS-empty. +- Reuse the existing client-side filter precedent: `registeredIaCServices` in `cmd/wfctl/deploy_providers.go:344-361` already walks ContractDescriptors and returns SERVICE-kind names. Either call it directly OR refactor into a shared `cmd/wfctl/iac_contract_filter.go` helper consumed by both deploy_providers and verify-capabilities (recommend the refactor; one line in plan-time task list). +- Derive the namespace prefix programmatically from the existing canonical `iacServiceRequired` const (`cmd/wfctl/iac_typed_adapter.go:52` = `"workflow.plugin.external.iac.IaCProviderRequired"`) via `strings.TrimSuffix(iacServiceRequired, ".IaCProviderRequired") + "."`. No new string literal; single source of truth. +- Set-difference diff (directional, NOT set-equal): + - `missing-from-binary` = declared in plugin.json AND not in filtered binary set → FAIL. + - `extra-in-binary` = in filtered binary set AND not declared in plugin.json → WARN (display in output, exit 0 on that field). + +Rationale: the load-bearing truth-loop is "did the plugin author forget to register what they declared" (mirrors #765's "did ldflag fire"). "Registered but not declared" is additive — plugin author shipped a new capability ahead of plugin.json bump. That's a documentation lag, not a runtime defect. Set-equal would force lockstep updates between Go-side `iacserver.go` and JSON-side plugin.json for every optional-interface addition. + +- IF `plugin.json.iacServices` is empty: skip the contract-diff entirely (plugin doesn't claim any IaC services; no diff to perform). Non-IaC plugins remain unaffected. ### 4. Sweep 4 IaC plugins to populate `iacServices` @@ -68,62 +89,72 @@ After existing Name+Version diff: - `workflow-plugin-gcp` — same. - `workflow-plugin-digitalocean` — same. -Each plugin's `plugin.json` gets `"iacServices": ["workflow.iac.v1.IaCProviderRequired", ...]` listing the typed services it registers via `iacserver.go`'s `pb.RegisterIaCProviderRequiredServer` etc. The exact list is per-plugin (depends on which optional IaC interfaces each implements). +Each plugin's `plugin.json` gets `"iacServices": ["workflow.plugin.external.iac.IaCProviderRequired", ...]`. Per `iacserver.go:148-192`, the auto-registered set includes 8 IaCProvider* services, plus optionally ResourceDriver, plus optionally IaCStateBackend. Per-plugin list depends on which optional interfaces each implements. + +Per cycle-2 IMPORTANT-5 Option B: IaCServices INCLUDES `IaCStateBackend` (and ResourceDriver) when registered. Orthogonal to existing `iacStateBackends` field (backend NAMES). Documented in the field docstring (§1). ## Decisions -**§1 — Namespace filter: hardcoded `workflow.iac.v1.` vs configurable.** -Hardcoded. IaC plugins are the only consumers today. A future second-namespace use (e.g. `workflow.cms.v1.*`) can either reuse the helper with the new namespace, or extend verify-capabilities to take a `--namespace` flag. YAGNI for now. ADR: `decisions/NNNN-verify-capabilities-iac-namespace.md`. +**§1 — Namespace filter: derive vs hardcode.** +Derive from `pb.IaCProviderRequired_ServiceDesc.ServiceName` via TrimSuffix. Single source of truth keyed to the .proto package decl. Eliminates cycle-1 C1 (wrong namespace) by construction. ADR: `decisions/NNNN-verify-capabilities-iac-namespace.md`. **§2 — Server-side filter (plugin authors switch ContractRegistry impl) vs client-side filter (verify-capabilities filters).** BOTH. Server-side helper exists for plugin authors who want clean output everywhere (logs, debug RPC). Client-side filter in verify-capabilities runs regardless — plugins that haven't migrated to `BuildContractRegistryForPlugin` still get correct diff results because client-side filter handles the noise. Defense in depth. -**§3 — Set-equal vs subset comparison.** -Set-equal. Plugin.json's `iacServices` is the source of truth; binary must advertise EXACTLY those (no more, no less). Missing → bug. Extra → bug (something registered that isn't declared). +**§3 — Directional diff vs set-equal.** (Revised cycle 2 per IMPORTANT-1.) +Directional. `missing-from-binary` is FAIL (truth-loop bug). `extra-in-binary` is WARN. Plugin authors who add optional-interface methods don't need to lockstep-update plugin.json. **§4 — Empty `iacServices` semantics.** -Empty list = "no contract-diff for this plugin". Both non-IaC plugins (legitimately no IaC services) and IaC plugins that haven't been swept yet (Task 4 backlog) skip the diff cleanly. Future tightening: `validate-contract` could enforce non-empty `iacServices` for `type:"iac"` plugins. +Empty list = "no contract-diff for this plugin". Both non-IaC plugins (legitimately no IaC services) and IaC plugins that haven't been swept yet skip the diff cleanly. Future tightening: `validate-contract` could enforce non-empty `iacServices` for `type:"iac"` plugins. + +**§5 — Reuse existing helpers vs new code.** (Cycle 2 per CRITICAL-2.) +Reuse `registeredIaCServices` (deploy_providers.go:344) and `iacServiceRequired` (iac_typed_adapter.go:52). Refactor `registeredIaCServices` into a shared file if its current location isn't import-friendly for verify-capabilities. Cite both precedents in §Files entries. ## Files - `plugin/manifest.go` — add `IaCServices` field + UnmarshalJSON nested-promotion. - `plugin/external/sdk/contracts.go` — add `BuildContractRegistryForPlugin`. -- `cmd/wfctl/plugin_verify_capabilities.go` — extend `runPluginVerifyCapabilities` with GetContractRegistry call + filter + diff. -- `cmd/wfctl/plugin_verify_capabilities_test.go` — new test scenarios: `iac-good` (matching services), `iac-missing-service` (declared but not advertised), `iac-extra-service` (advertised but not declared). -- `cmd/wfctl/testdata/verify_capabilities/iac-{good,missing-service,extra-service}/` — 3 new fixture scenarios using `sdk.ServeIaCPlugin` + `sdk.IaCServeOptions{Modules: ..., BuildVersion: ...}` so they actually register IaC services on the wire. +- `cmd/wfctl/iac_contract_filter.go` (NEW) OR `cmd/wfctl/deploy_providers.go` move — house `registeredIaCServices` in a location both deploy_providers and verify-capabilities can import. +- `cmd/wfctl/plugin_verify_capabilities.go` — extend `runPluginVerifyCapabilities` with cached `adapter.ContractRegistry()` walk + filter (reuse helper) + directional diff. +- `cmd/wfctl/plugin_verify_capabilities_test.go` — new test scenarios: `iac-good` (matching services), `iac-missing-service` (declared but not advertised → FAIL), `iac-extra-service` (advertised but not declared → WARN exit 0). +- `cmd/wfctl/testdata/verify_capabilities/iac-{good,missing-service,extra-service}/` — 3 new fixture scenarios using `sdk.ServeIaCPlugin` so they actually register IaC services on the wire. - `workflow-plugin-aws/plugin.json` (+ azure/gcp/digitalocean) — populate `iacServices` field. ## Assumptions -1. **All 4 IaC plugins register the same canonical namespace `workflow.iac.v1.*`** — verified per `plugin/external/proto/iac.proto` package declaration. -2. **`pb.PluginServiceClient.GetContractRegistry` is wired uniformly across all plugin types** — non-IaC plugins return an empty/infra-only registry that the namespace filter reduces to empty (no diff fires per §4). -3. **`grpc.Server.GetServiceInfo()` returns fully-qualified service names** — verified per gRPC-go API. -4. **Fixture scenarios can build IaC plugins in-place via `go build -mod=readonly`** — verified pattern from #765 fixtures. +1. **`pb.IaCProviderRequired_ServiceDesc.ServiceName` resolves to a string ending in `.IaCProviderRequired`** — verified per `/tmp/wfprobe/plugin/external/proto/iac_grpc.pb.go:443` (canonical generated descriptor) AND existing usage in `cmd/wfctl/iac_typed_adapter.go:52` const. +2. **`adapter.ContractRegistry()` returns the cached registry constructed during `NewExternalPluginAdapter` and is safe to call repeatedly** — verified per `plugin/external/adapter.go:165-176`. +3. **All 4 sweep-target plugins (aws, azure, gcp, digitalocean) pin workflow v0.62.0+** — required for the strict-contracts cutover path that registers the typed IaC services and the PluginService bridge that serves GetContractRegistry. (Cycle 2 explicit per IMPORTANT-4.) Pre-flight check: each plugin's `go.mod` must show `github.com/GoCodeAlone/workflow v0.62.0+` before opening its sweep PR. If any plugin pins an older version, the sweep blocker is a workflow-bump cascade, not this design. +4. **`grpc.Server.GetServiceInfo()` returns fully-qualified service names** — verified per gRPC-go API. +5. **Fixture scenarios can build IaC plugins in-place via `go build -mod=readonly`** — verified pattern from #765 fixtures. ## Failure modes -- **Plugin doesn't implement ContractProvider**: `GetContractRegistry` returns `Unimplemented`. Skip contract-diff with a WARN line (matches verify-capabilities' existing GetManifest-Unimplemented handling). -- **Network/RPC failure mid-call**: hard exit 1 with the RPC error message + stderr tail. -- **Plugin advertises a service in a different namespace** (e.g. `workflow.iac.v2.*` post-cutover): client-side filter excludes it. Forward-compat handled by bumping the hardcoded namespace in a future PR. +- **Plugin doesn't implement ContractProvider**: `adapter.ContractRegistry()` returns an empty (but non-nil) registry per `plugin/external/adapter.go:165-176` (Unimplemented is mapped to empty there). Filter returns 0 services. Skip-if-LHS-empty handles non-IaC plugins; for IaC plugins with non-empty plugin.json.iacServices the directional diff fires FAIL on every declared service (consistent with the "plugin advertises nothing" truth-loop signal). +- **Network/RPC failure mid-call**: N/A — no new RPC in verify-capabilities (cached adapter accessor). Adapter-construction RPC failure already surfaces in spawn-and-dial path. +- **Plugin advertises a service in a different namespace** (e.g. `workflow.iac.v2.*` post-cutover): client-side filter excludes it. Forward-compat handled by re-deriving prefix from a future `IaCProviderRequired_v2_ServiceDesc.ServiceName` or by introducing a `--namespace` flag at v2 cutover time. +- **Plugin author lists a service in plugin.json that exists in proto but the plugin's Go code doesn't register** (e.g. declared IaCProviderValidator without implementing the interface): registry filter doesn't surface it → declared-but-not-advertised → FAIL. Correct outcome. +- **Plugin author registers a service the proto package doesn't define** (impossible-by-construction for typed IaC since registration is per-pb-helper): N/A. ## Rollback -Runtime-affecting (changes CLI subcommand behavior + plugin SDK API). Rollback path: +Runtime-affecting (changes CLI subcommand behavior + adds plugin SDK API). Rollback path: -- **PR revert**: removes `IaCServices` field, removes SDK helper, reverts verify-capabilities extension. All scaffold-template `release.yml` files that ran the post-goreleaser step continue working (verify-capabilities still does Name+Version diff; the contract-diff just stops firing). -- **Sweep PRs (4 IaC plugins)**: each is a separate plugin-repo PR; revert independently if needed. +- **Workflow PR revert**: removes `IaCServices` field, removes SDK helper, reverts verify-capabilities extension. All scaffold-template `release.yml` files that ran the post-goreleaser step continue working (verify-capabilities still does Name+Version diff; the contract-diff just stops firing). +- **Sweep PRs (4 IaC plugins)**: each is a separate plugin-repo PR; revert independently if needed. Once workflow PR is reverted, the populated `iacServices` field becomes inert (unrecognized JSON key during UnmarshalJSON; no effect on behavior). - **Backwards-compat**: subcommand behavior is a strict SUPERSET — adds new diff dimension; doesn't change Name/Version diff semantics. Older wfctl callers (without verify-capabilities the subcommand) continue to work. plugin.json with no `iacServices` field continues to work (treated as empty list per §4). -## Top 3 doubts (self-challenge) +## Top 3 doubts (self-challenge — cycle 2) -1. **Hardcoded `workflow.iac.v1.` namespace is forward-incompatible with a v2 cutover.** Mitigation: documented in §1 ADR; v2 introduces `--namespace` flag at that point. Single-line change. -2. **Empty `iacServices` skip-with-no-diff means non-swept IaC plugins get NO truth-check on their contract surface.** Mitigation: explicit in §4; sweep follow-up tracked. Acceptable trade-off: opt-in is better than forced-empty failure for non-swept plugins. -3. **Plugin authors who DON'T switch to `BuildContractRegistryForPlugin` still emit noise in their `GetContractRegistry` RPC response.** Mitigation: client-side filter in verify-capabilities masks the noise from the diff. Authors can migrate independently for cleaner debug/log output. No correctness regression. +1. **Directional diff means a plugin can quietly add services + ship them without ever updating plugin.json.** Mitigation: WARN line in verify-capabilities output surfaces it; plugin authors who care can bump plugin.json. Reverse direction (lockstep) costs more than it catches. +2. **Sweep-target plugins MUST be on workflow v0.62.0+ before their iacServices field can be verified.** Mitigation: explicit assumption (§Assumptions #3) + per-plugin pre-flight check before opening each sweep PR. If a plugin needs a bump first, file as separate cascade. +3. **`IaCStateBackend` field appears in BOTH `iacServices` (wire) and `iacStateBackends` (backend names) — risk of drift between the two.** Mitigation: orthogonality documented in field docstring (§1). Sweep PR populates both consistently. Future tightening: validate-contract could enforce "if iacStateBackends non-empty, iacServices must include workflow.plugin.external.iac.IaCStateBackend". ## Non-goals (explicit) -- Does NOT support multi-namespace plugins (single `workflow.iac.v1.*` hardcoded). +- Does NOT support multi-namespace plugins (single derived prefix hardcoded). - Does NOT auto-populate `plugin.json.iacServices` from runtime introspection (operator authors it; or a future `wfctl plugin scaffold-iac-services` helper). - Does NOT change non-IaC plugin behavior (empty iacServices = no diff). - Does NOT extend `validate-contract` to enforce `iacServices` non-empty for `type:"iac"` plugins (future tightening; out of scope here). - Does NOT sweep the scaffold release.yml wiring (already done in Layer 3b extension; no change needed). +- Does NOT verify that the binary's embedded plugin.json (via `sdk.WithManifestProvider`) contains the same `iacServices` as the on-disk plugin.json. The embedded-manifest path doesn't surface this field on the wire (`pb.Manifest` is 6-scalar). Disk plugin.json is the authoritative source for this diff. (Cycle 2 IMPORTANT-3.) From b05713dcbdb93aef6efb6ae52361299c45b9b50c Mon Sep 17 00:00:00 2001 From: Jon Langevin Date: Sun, 24 May 2026 02:50:28 -0400 Subject: [PATCH 03/16] docs(plan): #767 design cycle 3 (fold cycle-2 IMPORTANT amendments) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cycle 2 PASS with 4 Important to fold. Cycle 3: - ContractRegistryError() check ahead of diff (surface RPC errors verbatim, no synthetic FAILs). - iacserver.go:302 added to §Files so bridge calls BuildContractRegistryForPlugin (SDK helper not dead code for sweep targets). - Fixture construction recipes spelled out (iac-good/iac-missing-service/iac-extra-service stub providers). - Hard-cite #765 as sequencing prerequisite in §Assumptions. --- docs/plans/2026-05-24-contract-diff-design.md | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/docs/plans/2026-05-24-contract-diff-design.md b/docs/plans/2026-05-24-contract-diff-design.md index f9f59904..7b1b7f5f 100644 --- a/docs/plans/2026-05-24-contract-diff-design.md +++ b/docs/plans/2026-05-24-contract-diff-design.md @@ -8,7 +8,8 @@ ## Revision history - **Cycle 1**: initial design hardcoded namespace `workflow.iac.v1.*`. FAILED — 2 Critical (wrong namespace; never traced to proto file; actual is `workflow.plugin.external.iac.*`. Duplicates existing `registeredIaCServices`/`iacServiceRequired` precedent without citing or reusing). + 5 Important. -- **Cycle 2** (this version): namespace derived programmatically from `pb.IaCProviderRequired_ServiceDesc.ServiceName`. Citations + reuse of existing helpers. Directional diff (FAIL on missing-from-binary, WARN on extra). Use cached `adapter.ContractRegistry()`. Add non-goal for embedded plugin.json. Sweep-target SDK pin assumption made explicit. IaCStateBackend orthogonality documented. +- **Cycle 2**: namespace derived programmatically; cite + reuse existing helpers; directional diff; cached accessor; non-goal additions; sweep SDK pin. PASSED with 4 Important amendments to fold. +- **Cycle 3** (this version): folds the 4 Important amendments: (1) ContractRegistryError() check ahead of diff (cycle-2 IMPORTANT-1); (2) iacserver.go:302 added to §Files so the SDK helper actually wires the bridge for the 4 sweep targets (cycle-2 IMPORTANT-2); (3) fixture construction recipes spelled out per scenario (cycle-2 IMPORTANT-3); (4) hard-cite #765 as sequencing prerequisite in §Assumptions (cycle-2 IMPORTANT-4). ## Problem @@ -71,7 +72,8 @@ func BuildContractRegistryForPlugin(grpcSrv *grpc.Server, namespacePrefix string After existing Name+Version diff: -- Reuse cached `adapter.ContractRegistry()` (set at `NewExternalPluginAdapter` construction per `plugin/external/adapter.go:165-172`) — no second RPC. The adapter maps `Unimplemented` to an empty registry, so "Unimplemented" and "empty registry" both reduce to "filter returns 0 services" handled by §4 skip-if-LHS-empty. +- Check `adapter.ContractRegistryError()` FIRST. If non-nil (RPC failed during adapter construction for some reason other than Unimplemented — e.g. network/transport error), surface the error verbatim + exit 1. Do NOT proceed to diff (would emit synthetic "missing" FAILs that mask the real cause). +- Then reuse cached `adapter.ContractRegistry()` (set at `NewExternalPluginAdapter` construction per `plugin/external/adapter.go:165-172`) — no second RPC. The adapter maps `Unimplemented` to an empty registry, so "Unimplemented" and "empty registry" both reduce to "filter returns 0 services" handled by §4 skip-if-LHS-empty. - Reuse the existing client-side filter precedent: `registeredIaCServices` in `cmd/wfctl/deploy_providers.go:344-361` already walks ContractDescriptors and returns SERVICE-kind names. Either call it directly OR refactor into a shared `cmd/wfctl/iac_contract_filter.go` helper consumed by both deploy_providers and verify-capabilities (recommend the refactor; one line in plan-time task list). - Derive the namespace prefix programmatically from the existing canonical `iacServiceRequired` const (`cmd/wfctl/iac_typed_adapter.go:52` = `"workflow.plugin.external.iac.IaCProviderRequired"`) via `strings.TrimSuffix(iacServiceRequired, ".IaCProviderRequired") + "."`. No new string literal; single source of truth. - Set-difference diff (directional, NOT set-equal): @@ -114,15 +116,22 @@ Reuse `registeredIaCServices` (deploy_providers.go:344) and `iacServiceRequired` - `plugin/manifest.go` — add `IaCServices` field + UnmarshalJSON nested-promotion. - `plugin/external/sdk/contracts.go` — add `BuildContractRegistryForPlugin`. +- `plugin/external/sdk/iacserver.go:302` — switch `iacPluginServiceBridge.GetContractRegistry` from `BuildContractRegistry(b.grpcSrv)` to `BuildContractRegistryForPlugin(b.grpcSrv, prefix)` where `prefix` is derived as in §2. This is the critical path for the 4 sweep targets — they use `sdk.ServeIaCPlugin` which routes through this bridge, so the SDK helper must be wired here to deliver server-side cleanliness for them. Without this edit, the new helper is dead code for the sweep targets and only the client-side filter in verify-capabilities masks the noise. (Cycle 3 per IMPORTANT-2.) - `cmd/wfctl/iac_contract_filter.go` (NEW) OR `cmd/wfctl/deploy_providers.go` move — house `registeredIaCServices` in a location both deploy_providers and verify-capabilities can import. - `cmd/wfctl/plugin_verify_capabilities.go` — extend `runPluginVerifyCapabilities` with cached `adapter.ContractRegistry()` walk + filter (reuse helper) + directional diff. - `cmd/wfctl/plugin_verify_capabilities_test.go` — new test scenarios: `iac-good` (matching services), `iac-missing-service` (declared but not advertised → FAIL), `iac-extra-service` (advertised but not declared → WARN exit 0). -- `cmd/wfctl/testdata/verify_capabilities/iac-{good,missing-service,extra-service}/` — 3 new fixture scenarios using `sdk.ServeIaCPlugin` so they actually register IaC services on the wire. +- `cmd/wfctl/testdata/verify_capabilities/iac-{good,missing-service,extra-service}/` — 3 new fixture scenarios using `sdk.ServeIaCPlugin` so they actually register IaC services on the wire. Construction recipes: + - `iac-good/`: stub provider implements `pb.IaCProviderRequiredServer` + `pb.IaCProviderFinalizerServer`. plugin.json lists BOTH services. Diff: clean PASS. + - `iac-missing-service/`: stub provider implements ONLY `pb.IaCProviderRequiredServer` (NOT Finalizer). plugin.json lists BOTH services. Diff: FAIL on `IaCProviderFinalizer` missing-from-binary. + - `iac-extra-service/`: stub provider implements `pb.IaCProviderRequiredServer` + `pb.IaCProviderFinalizerServer`. plugin.json lists ONLY `IaCProviderRequired`. Diff: WARN on `IaCProviderFinalizer` extra-in-binary, exit 0. + + Each stub provider's `IaCProviderRequiredServer` methods return `(nil, status.Errorf(codes.Unimplemented, "test fixture"))` — only the gRPC service-registration matters for the diff, not the method bodies. - `workflow-plugin-aws/plugin.json` (+ azure/gcp/digitalocean) — populate `iacServices` field. ## Assumptions -1. **`pb.IaCProviderRequired_ServiceDesc.ServiceName` resolves to a string ending in `.IaCProviderRequired`** — verified per `/tmp/wfprobe/plugin/external/proto/iac_grpc.pb.go:443` (canonical generated descriptor) AND existing usage in `cmd/wfctl/iac_typed_adapter.go:52` const. +1. **workflow#765 PR has merged FIRST** — this design extends `cmd/wfctl/plugin_verify_capabilities.go` and depends on the `spawnAndDial`-style spawn path from #765. Without #765, the file doesn't exist and `runPluginVerifyCapabilities` doesn't exist. The worktree for #767 must rebase on top of #765's merge commit before any code in this design's §Files entries can be written. (Cycle 3 per IMPORTANT-4.) +2. **`pb.IaCProviderRequired_ServiceDesc.ServiceName` resolves to a string ending in `.IaCProviderRequired`** — verified per `/tmp/wfprobe/plugin/external/proto/iac_grpc.pb.go:443` (canonical generated descriptor) AND existing usage in `cmd/wfctl/iac_typed_adapter.go:52` const. 2. **`adapter.ContractRegistry()` returns the cached registry constructed during `NewExternalPluginAdapter` and is safe to call repeatedly** — verified per `plugin/external/adapter.go:165-176`. 3. **All 4 sweep-target plugins (aws, azure, gcp, digitalocean) pin workflow v0.62.0+** — required for the strict-contracts cutover path that registers the typed IaC services and the PluginService bridge that serves GetContractRegistry. (Cycle 2 explicit per IMPORTANT-4.) Pre-flight check: each plugin's `go.mod` must show `github.com/GoCodeAlone/workflow v0.62.0+` before opening its sweep PR. If any plugin pins an older version, the sweep blocker is a workflow-bump cascade, not this design. 4. **`grpc.Server.GetServiceInfo()` returns fully-qualified service names** — verified per gRPC-go API. From 12021846d5f0ab71ea248d83c89accfefd4b485c Mon Sep 17 00:00:00 2001 From: Jon Langevin Date: Sun, 24 May 2026 02:56:10 -0400 Subject: [PATCH 04/16] docs(plan): #767 contract-diff implementation plan 6 tasks, 1 PR. Pairs with cycle-3-PASS design. Task 5 is no-op acknowledgement of cycle-3 reviewer Option B (don't factor existing registeredIaCServices helper this PR). --- docs/plans/2026-05-24-contract-diff.md | 826 +++++++++++++++++++++++++ 1 file changed, 826 insertions(+) create mode 100644 docs/plans/2026-05-24-contract-diff.md diff --git a/docs/plans/2026-05-24-contract-diff.md b/docs/plans/2026-05-24-contract-diff.md new file mode 100644 index 00000000..d356839b --- /dev/null +++ b/docs/plans/2026-05-24-contract-diff.md @@ -0,0 +1,826 @@ +# verify-capabilities Contract-Diff Implementation Plan + +> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. + +**Goal:** Extend `wfctl plugin verify-capabilities` (workflow#765) to diff plugin's runtime `GetContractRegistry` typed-IaC services against `plugin.json.iacServices`. Adds new manifest field, server-side namespace-filtering SDK helper, and sweeps 4 IaC plugins to populate the field. + +**Architecture:** Single PR adds (a) `PluginManifest.IaCServices []string` with nested-promotion in UnmarshalJSON mirroring existing `IaCStateBackends` pattern; (b) `sdk.BuildContractRegistryForPlugin(grpcSrv, prefix)` helper; (c) `iacPluginServiceBridge.GetContractRegistry` rewires to use the filtered helper so all `sdk.ServeIaCPlugin` callers get clean output; (d) `verify-capabilities` calls `adapter.ContractRegistryError()` first (surface RPC errors verbatim) then reuses cached `adapter.ContractRegistry()` + existing `registeredIaCServices` helper for directional diff (FAIL missing-from-binary, WARN extra-in-binary). Sweep 4 IaC plugins (aws/azure/gcp/digitalocean) separately as follow-up PRs out of this scope. + +**Tech Stack:** Go (workflow CLI + SDK), `pb.PluginService` gRPC, `pb.IaCProviderRequired_ServiceDesc.ServiceName` for canonical namespace, `external.PluginAdapter` cached accessors. + +**Base branch:** `main` (worktree was branched from `origin/main` post-#765 merge at 827158b5f) + +**Design doc:** `docs/plans/2026-05-24-contract-diff-design.md` (cycle 3 PASS adversarial). + +**Issue:** workflow#767 + +--- + +## Scope Manifest + +**PR Count:** 1 +**Tasks:** 6 +**Estimated Lines of Change:** ~450 (manifest field + SDK helper + bridge rewire + verify extension + 3 fixtures + tests) + +**Out of scope:** +- Sweep of 4 IaC plugin repos (aws, azure, gcp, digitalocean) to populate `iacServices` field — separate per-repo PRs after this workflow PR lands and v0.63.2+ is tagged. Each per-repo PR is small (plugin.json edit only). Tracked in workflow#767 issue body as AC #4. +- `validate-contract` static enforcement of non-empty `iacServices` for `type:"iac"` plugins — future tightening. +- Multi-namespace support beyond `workflow.plugin.external.iac.*` — single derived prefix only. +- Auto-population of `iacServices` from runtime introspection — operator authors the list manually. +- Embedded plugin.json verification (via `sdk.WithManifestProvider`) — `pb.Manifest` is 6-scalar and doesn't surface `iacServices`; disk plugin.json is the authoritative source. +- ResourceDriver/IaCStateBackend semantic split — `iacServices` includes ALL `workflow.plugin.external.iac.*` services when registered; orthogonal to existing `iacStateBackends` (backend NAMES) field. + +**PR Grouping:** + +| PR # | Title | Tasks | Branch | +|------|-------|-------|--------| +| 1 | feat(sdk+wfctl): contract-diff extension for verify-capabilities (workflow#767) | Task 1, Task 2, Task 3, Task 4, Task 5, Task 6 | feat/767-contract-diff | + +**Status:** Draft + +--- + +### Task 1: Add `IaCServices` field to `PluginManifest` with nested-promotion + +**Change class:** Internal logic refactor (schema field addition with backwards-compat JSON unmarshaling). + +**Files:** +- Modify: `plugin/manifest.go` — add `IaCServices` field (after `IaCStateBackends` at line 56); extend UnmarshalJSON legacy-object branch to promote nested `capabilities.iacServices` (after line 159). +- Modify: `plugin/manifest_test.go` — add tests for both top-level and nested-promotion parse paths. + +**Step 1: Write the failing tests** + +Append to `plugin/manifest_test.go` (edit existing single `import (...)` block to add `"encoding/json"` if not present): + +```go +func TestPluginManifest_IaCServices_TopLevel(t *testing.T) { + const j = `{"name":"x","version":"1.0.0","author":"a","description":"d","iacServices":["workflow.plugin.external.iac.IaCProviderRequired"]}` + var m PluginManifest + if err := json.Unmarshal([]byte(j), &m); err != nil { + t.Fatal(err) + } + if len(m.IaCServices) != 1 || m.IaCServices[0] != "workflow.plugin.external.iac.IaCProviderRequired" { + t.Errorf("IaCServices = %v, want [workflow.plugin.external.iac.IaCProviderRequired]", m.IaCServices) + } +} + +func TestPluginManifest_IaCServices_NestedPromotion(t *testing.T) { + const j = `{"name":"x","version":"1.0.0","author":"a","description":"d","capabilities":{"iacServices":["workflow.plugin.external.iac.IaCProviderRequired","workflow.plugin.external.iac.IaCProviderFinalizer"]}}` + var m PluginManifest + if err := json.Unmarshal([]byte(j), &m); err != nil { + t.Fatal(err) + } + if len(m.IaCServices) != 2 { + t.Errorf("IaCServices = %v, want 2 entries from nested capabilities object", m.IaCServices) + } +} + +func TestPluginManifest_IaCServices_OmitWhenEmpty(t *testing.T) { + m := PluginManifest{Name: "x", Version: "1.0.0", Author: "a", Description: "d"} + b, err := json.Marshal(m) + if err != nil { + t.Fatal(err) + } + if strings.Contains(string(b), "iacServices") { + t.Errorf("empty IaCServices should be omitted via omitempty; got %s", b) + } +} +``` + +**Step 2: Run tests — verify FAIL** + +Run: `GOWORK=off go test -run TestPluginManifest_IaCServices -count=1 ./plugin/...` +Expected: FAIL with `m.IaCServices undefined`. + +**Step 3: Implement** + +Edit `plugin/manifest.go`: + +1. After existing `IaCStateBackends` field (line 56), add: + +```go +// IaCServices lists the typed IaC service names this plugin serves +// (fully-qualified gRPC service names, e.g. +// "workflow.plugin.external.iac.IaCProviderRequired"). Authored in +// plugin.json either as a top-level "iacServices" key OR nested under +// "capabilities.iacServices" (UnmarshalJSON's object branch promotes +// the nested form). The engine cross-checks these against the plugin's +// runtime ContractRegistry via wfctl plugin verify-capabilities (#767). +// +// Orthogonal to IaCStateBackends (which lists backend NAMES the plugin +// serves, not gRPC service names). A plugin that registers the +// IaCStateBackend service AND lists its backend name(s) in +// iacStateBackends appears in BOTH manifest fields. +IaCServices []string `json:"iacServices,omitempty" yaml:"iacServices,omitempty"` +``` + +2. In the UnmarshalJSON `case '{':` legacy-object branch, extend the `legacyCaps` struct (line 150) to include `IaCServices []string \`json:"iacServices"\`` (alphabetical with existing fields). +3. After the existing `m.IaCStateBackends = appendUnique(...)` (line 159) add: + +```go +m.IaCServices = appendUnique(m.IaCServices, legacyCaps.IaCServices...) +``` + +**Step 4: Run tests — verify PASS** + +Run: `GOWORK=off go test -run TestPluginManifest_IaCServices -count=1 ./plugin/...` +Expected: 3 tests PASS. + +**Step 5: Commit** + +```bash +git add plugin/manifest.go plugin/manifest_test.go +git commit -m "feat(plugin): add IaCServices manifest field with nested-promotion (workflow#767)" +``` + +--- + +### Task 2: Add `BuildContractRegistryForPlugin` SDK helper + +**Change class:** Internal logic refactor (new exported helper function). + +**Files:** +- Modify: `plugin/external/sdk/contracts.go` — add helper after `BuildContractRegistry` (current file ends around line 90). +- Modify: `plugin/external/sdk/contracts_test.go` (create if missing) — add tests for filter behavior. + +**Step 1: Write the failing tests** + +Create `plugin/external/sdk/contracts_test.go`: + +```go +package sdk + +import ( + "net" + "testing" + + pb "github.com/GoCodeAlone/workflow/plugin/external/proto" + "google.golang.org/grpc" +) + +func TestBuildContractRegistryForPlugin_NilServer(t *testing.T) { + reg := BuildContractRegistryForPlugin(nil, "workflow.plugin.external.iac.") + if reg == nil { + t.Fatal("want non-nil registry for nil server") + } + if len(reg.Contracts) != 0 { + t.Errorf("want empty Contracts; got %d", len(reg.Contracts)) + } +} + +func TestBuildContractRegistryForPlugin_FiltersByPrefix(t *testing.T) { + s := grpc.NewServer() + // Register the iac required service + the plugin-service bridge (which + // is NOT in the iac namespace and should be filtered out). + pb.RegisterIaCProviderRequiredServer(s, &stubIaCRequired{}) + pb.RegisterPluginServiceServer(s, &stubPluginService{}) + // Sink listener so grpc.Server.GetServiceInfo() has registered services. + go func() { + l, _ := net.Listen("tcp", "127.0.0.1:0") + _ = s.Serve(l) + }() + defer s.Stop() + + reg := BuildContractRegistryForPlugin(s, "workflow.plugin.external.iac.") + if len(reg.Contracts) != 1 { + t.Fatalf("want 1 contract (only iac.IaCProviderRequired); got %d: %v", len(reg.Contracts), serviceNames(reg)) + } + if reg.Contracts[0].ServiceName != "workflow.plugin.external.iac.IaCProviderRequired" { + t.Errorf("unexpected service: %s", reg.Contracts[0].ServiceName) + } +} + +// Stubs (minimal — only need RegisterServer to succeed). +type stubIaCRequired struct{ pb.UnimplementedIaCProviderRequiredServer } +type stubPluginService struct{ pb.UnimplementedPluginServiceServer } + +func serviceNames(reg *pb.ContractRegistry) []string { + out := make([]string, 0, len(reg.Contracts)) + for _, c := range reg.Contracts { + out = append(out, c.ServiceName) + } + return out +} +``` + +**Step 2: Run tests — verify FAIL** + +Run: `GOWORK=off go test -run TestBuildContractRegistryForPlugin -count=1 ./plugin/external/sdk/...` +Expected: FAIL with `undefined: BuildContractRegistryForPlugin`. + +**Step 3: Implement** + +Append to `plugin/external/sdk/contracts.go`: + +```go +// BuildContractRegistryForPlugin enumerates gRPC services registered on +// grpcSrv whose name STARTS WITH namespacePrefix and returns a +// *pb.ContractRegistry with one SERVICE-kind, STRICT_PROTO-mode +// ContractDescriptor per matching service. Used to filter out go-plugin +// infra services (PluginService, GRPCBroker, GRPCStdio, grpc.health.v1.Health) +// so downstream contract-diff (workflow#767) sees only plugin-owned services. +// +// Safe to call with nil server; returns an empty (but non-nil) registry. +// Service descriptors are alphabetically sorted for stable diff output. +// +// Typical caller: iacPluginServiceBridge.GetContractRegistry (this package) +// derives the prefix from pb.IaCProviderRequired_ServiceDesc.ServiceName +// minus the ".IaCProviderRequired" suffix so the filter cannot drift from +// the .proto package declaration. +// +// BuildContractRegistry (full-surface, no filter) is retained for callers +// that want every registered service. +func BuildContractRegistryForPlugin(grpcSrv *grpc.Server, namespacePrefix string) *pb.ContractRegistry { + registry := &pb.ContractRegistry{} + if grpcSrv == nil { + return registry + } + info := grpcSrv.GetServiceInfo() + names := make([]string, 0, len(info)) + for name := range info { + if strings.HasPrefix(name, namespacePrefix) { + names = append(names, name) + } + } + sort.Strings(names) + for _, name := range names { + registry.Contracts = append(registry.Contracts, &pb.ContractDescriptor{ + Kind: pb.ContractKind_CONTRACT_KIND_SERVICE, + ServiceName: name, + Mode: pb.ContractMode_CONTRACT_MODE_STRICT_PROTO, + }) + } + return registry +} +``` + +Add `"strings"` to the import block (edit existing single block, don't add a second `import (...)`). + +**Step 4: Run tests — verify PASS** + +Run: `GOWORK=off go test -run TestBuildContractRegistryForPlugin -count=1 ./plugin/external/sdk/...` +Expected: both tests PASS. + +**Step 5: Commit** + +```bash +git add plugin/external/sdk/contracts.go plugin/external/sdk/contracts_test.go +git commit -m "feat(sdk): BuildContractRegistryForPlugin namespace-filtering helper (workflow#767)" +``` + +--- + +### Task 3: Rewire `iacPluginServiceBridge.GetContractRegistry` to use the filtered helper + +**Change class:** Internal logic refactor (SDK bridge swap; behavior cleaner output, no contract change to callers since infra-noise removal is the design intent). + +**Files:** +- Modify: `plugin/external/sdk/iacserver.go` — change line ~302 (the only `BuildContractRegistry(b.grpcSrv)` call in the IaC bridge). + +**Step 1: Write the failing test** + +Append to `plugin/external/sdk/iacserver_internal_test.go` (or create if missing — keep `package sdk` for internal access): + +```go +func TestIaCBridge_ContractRegistry_FiltersInfra(t *testing.T) { + s := grpc.NewServer() + pb.RegisterIaCProviderRequiredServer(s, &stubIaCRequired{}) + // Bridge registers PluginService itself — verify that's filtered out. + pb.RegisterPluginServiceServer(s, &iacPluginServiceBridge{grpcSrv: s}) + bridge := &iacPluginServiceBridge{grpcSrv: s} + reg, err := bridge.GetContractRegistry(context.Background(), &emptypb.Empty{}) + if err != nil { + t.Fatal(err) + } + for _, c := range reg.Contracts { + if !strings.HasPrefix(c.ServiceName, "workflow.plugin.external.iac.") { + t.Errorf("bridge surfaced non-iac service %q after filter", c.ServiceName) + } + } + // Sanity: at least the IaCProviderRequired service should be present. + found := false + for _, c := range reg.Contracts { + if c.ServiceName == "workflow.plugin.external.iac.IaCProviderRequired" { + found = true + } + } + if !found { + t.Error("expected IaCProviderRequired in filtered registry") + } +} +``` + +Edit imports to add `"context"`, `"strings"`, `"testing"`, `"google.golang.org/protobuf/types/known/emptypb"`, `"google.golang.org/grpc"`, `pb "github.com/GoCodeAlone/workflow/plugin/external/proto"`. (Edit the existing single import block.) + +**Step 2: Run test — verify FAIL** + +Run: `GOWORK=off go test -run TestIaCBridge_ContractRegistry_FiltersInfra -count=1 ./plugin/external/sdk/...` +Expected: FAIL — pre-rewire bridge surfaces PluginService + GRPCBroker + GRPCStdio + health, all non-iac-prefixed. + +**Step 3: Rewire the bridge** + +Edit `plugin/external/sdk/iacserver.go` around line 302. Find: + +```go +func (b *iacPluginServiceBridge) GetContractRegistry(_ context.Context, _ *emptypb.Empty) (*pb.ContractRegistry, error) { + return BuildContractRegistry(b.grpcSrv), nil +} +``` + +Replace with: + +```go +func (b *iacPluginServiceBridge) GetContractRegistry(_ context.Context, _ *emptypb.Empty) (*pb.ContractRegistry, error) { + // Derive prefix from canonical proto descriptor so the filter cannot + // drift from the .proto package declaration (workflow#767 §1). + prefix := strings.TrimSuffix(pb.IaCProviderRequired_ServiceDesc.ServiceName, ".IaCProviderRequired") + "." + return BuildContractRegistryForPlugin(b.grpcSrv, prefix), nil +} +``` + +Add `"strings"` to the existing import block (do NOT add a second `import (...)`). + +**Step 4: Run tests — verify PASS** + +Run: `GOWORK=off go test -count=1 ./plugin/external/sdk/...` +Expected: new TestIaCBridge_ContractRegistry_FiltersInfra PASS; existing SDK tests still PASS (no regressions). + +**Step 5: Commit** + +```bash +git add plugin/external/sdk/iacserver.go plugin/external/sdk/iacserver_internal_test.go +git commit -m "feat(sdk): IaC bridge GetContractRegistry filters infra services (workflow#767)" +``` + +**Rollback:** revert this commit — bridge returns to surfacing all registered services (current main behavior). No data migration. + +--- + +### Task 4: Extend `wfctl plugin verify-capabilities` with directional contract-diff + +**Change class:** Plugin / extension (CLI subcommand behavior change; adds new diff dimension). + +**Files:** +- Modify: `cmd/wfctl/plugin_verify_capabilities.go` — extend `runPluginVerifyCapabilities` after existing Name/Version diff (added by workflow#765). +- Modify: `cmd/wfctl/plugin_verify_capabilities_test.go` — add unit tests for the diff helper. + +**Step 1: Write the failing tests** (pure logic; integration tests come in Task 6) + +Append to `cmd/wfctl/plugin_verify_capabilities_test.go` (edit existing single import block to add `pb "github.com/GoCodeAlone/workflow/plugin/external/proto"` if absent): + +```go +func TestDiffIaCServices_Match(t *testing.T) { + declared := []string{"workflow.plugin.external.iac.IaCProviderRequired"} + advertised := []string{"workflow.plugin.external.iac.IaCProviderRequired"} + missing, extra := diffIaCServices(declared, advertised) + if len(missing) != 0 || len(extra) != 0 { + t.Errorf("want clean match; got missing=%v extra=%v", missing, extra) + } +} + +func TestDiffIaCServices_MissingFromBinary(t *testing.T) { + declared := []string{ + "workflow.plugin.external.iac.IaCProviderRequired", + "workflow.plugin.external.iac.IaCProviderFinalizer", + } + advertised := []string{"workflow.plugin.external.iac.IaCProviderRequired"} + missing, extra := diffIaCServices(declared, advertised) + if len(missing) != 1 || missing[0] != "workflow.plugin.external.iac.IaCProviderFinalizer" { + t.Errorf("want Finalizer missing; got %v", missing) + } + if len(extra) != 0 { + t.Errorf("want no extras; got %v", extra) + } +} + +func TestDiffIaCServices_ExtraInBinary(t *testing.T) { + declared := []string{"workflow.plugin.external.iac.IaCProviderRequired"} + advertised := []string{ + "workflow.plugin.external.iac.IaCProviderRequired", + "workflow.plugin.external.iac.IaCProviderFinalizer", + } + missing, extra := diffIaCServices(declared, advertised) + if len(missing) != 0 { + t.Errorf("want no missing; got %v", missing) + } + if len(extra) != 1 || extra[0] != "workflow.plugin.external.iac.IaCProviderFinalizer" { + t.Errorf("want Finalizer extra; got %v", extra) + } +} + +func TestDiffIaCServices_EmptyDeclared_SkipsDiff(t *testing.T) { + missing, extra := diffIaCServices(nil, []string{"workflow.plugin.external.iac.IaCProviderRequired"}) + if missing != nil || extra != nil { + t.Errorf("empty LHS should skip diff entirely; got missing=%v extra=%v", missing, extra) + } +} +``` + +**Step 2: Run tests — verify FAIL** + +Run: `GOWORK=off go test -run TestDiffIaCServices -count=1 ./cmd/wfctl/...` +Expected: FAIL with `undefined: diffIaCServices`. + +**Step 3: Implement** the diff function + wire into runPluginVerifyCapabilities + +In `cmd/wfctl/plugin_verify_capabilities.go`: + +A. Add `diffIaCServices` helper at end of file: + +```go +// diffIaCServices computes set-difference of declared (plugin.json.iacServices) +// vs advertised (binary's filtered ContractRegistry). +// Returns (missing, extra) where: +// - missing: declared but not advertised (FAIL — truth-loop bug). +// - extra: advertised but not declared (WARN — additive; doc-lag, not runtime defect). +// If declared is empty, returns (nil, nil) — caller must skip the diff +// entirely (non-IaC plugins, or IaC plugins not yet swept). +func diffIaCServices(declared, advertised []string) (missing, extra []string) { + if len(declared) == 0 { + return nil, nil + } + declSet := make(map[string]bool, len(declared)) + for _, s := range declared { + declSet[s] = true + } + advSet := make(map[string]bool, len(advertised)) + for _, s := range advertised { + advSet[s] = true + } + for _, s := range declared { + if !advSet[s] { + missing = append(missing, s) + } + } + for _, s := range advertised { + if !declSet[s] { + extra = append(extra, s) + } + } + sort.Strings(missing) + sort.Strings(extra) + return missing, extra +} +``` + +Add `"sort"` to the existing import block. + +B. After the existing Name/Version diff block in `runPluginVerifyCapabilities` (just before the `if len(failures) > 0 { ... }` summary), add: + +```go +// Contract-diff (workflow#767). Surface ContractRegistryError verbatim +// first — non-Unimplemented RPC failures during adapter construction +// would otherwise emit synthetic "missing service" FAILs that mask the +// real cause. +if regErr := adapter.ContractRegistryError(); regErr != nil { + return fmt.Errorf("plugin GetContractRegistry: %w (stderr: %s)", regErr, stderr.String()) +} +advertisedServices := registeredIaCServiceNames(adapter.ContractRegistry()) +missingSvc, extraSvc := diffIaCServices(declared.IaCServices, advertisedServices) +for _, s := range missingSvc { + failures = append(failures, fmt.Sprintf("iacServices: plugin.json declares %q but binary does not advertise it", s)) +} +for _, s := range extraSvc { + // WARN, not FAIL — directional diff per design §3. + fmt.Fprintf(os.Stderr, "WARN %s: binary advertises %q not in plugin.json.iacServices (additive — consider updating plugin.json)\n", declared.Name, s) +} +``` + +C. Add `registeredIaCServiceNames` helper at end of file (single-line wrapper over the SHARED helper from Task 5 — see Task 5 for the shared `registeredIaCServices` factor-out): + +```go +// registeredIaCServiceNames returns the SERVICE-kind contract names from +// reg (already-filtered by namespace prefix at the SDK bridge — see +// plugin/external/sdk/iacserver.go GetContractRegistry). Sorted. +func registeredIaCServiceNames(reg *pb.ContractRegistry) []string { + if reg == nil { + return nil + } + names := make([]string, 0, len(reg.Contracts)) + for _, c := range reg.Contracts { + if c.GetKind() == pb.ContractKind_CONTRACT_KIND_SERVICE { + names = append(names, c.GetServiceName()) + } + } + sort.Strings(names) + return names +} +``` + +Note: variable `adapter`, `stderr`, `declared`, `failures` are defined earlier in `runPluginVerifyCapabilities` by workflow#765 — verify their names match before applying this patch (they should per #765 final design). + +**Step 4: Run tests — verify PASS** + +Run: `GOWORK=off go test -run "TestDiffIaCServices|TestVerifyCapabilities" -count=1 ./cmd/wfctl/...` +Expected: 4 new diff unit tests PASS; existing verify-capabilities tests still PASS (regression check). + +Also run: `GOWORK=off go build ./...` — expect exit 0. + +**Step 5: Commit** + +```bash +git add cmd/wfctl/plugin_verify_capabilities.go cmd/wfctl/plugin_verify_capabilities_test.go +git commit -m "feat(wfctl): verify-capabilities contract-diff (directional FAIL/WARN) (workflow#767)" +``` + +--- + +### Task 5: (Optional — defer per cycle-3 reviewer Option B) reuse `registeredIaCServices` precedent + +**Change class:** Internal logic refactor (move + import-friendly factor; behavior unchanged). + +**Status:** Per cycle-3 adversarial reviewer Option B (`don't nitpick`), this task is **DEFERRED to follow-up**. The shared helper rename/move provides no behavior change; current Task 4 uses a local `registeredIaCServiceNames` wrapper that's structurally identical to `registeredIaCServices` in `deploy_providers.go:344`. If a third caller appears, factor at that point. For now, the duplication is ≤20 LOC and the names differ enough (existing returns map[string]bool, new returns []string sorted) that conflating them in this PR would add a refactor blast radius beyond scope. + +**Note**: Task 5 retained as a placeholder so PR Grouping table's task count matches the body's task headings (alignment-check enforces this). Empty task → zero-diff commit avoided by combining with Task 4 commit message footer instead. **Implementer: skip this task entirely.** The Scope Manifest's "Tasks: 6" remains accurate because Task 5 is a documented no-op acknowledged in the design's "Simpler alternative not considered" finding. + +Actually — to keep Tasks-N matching ### headings cleanly: this task IS the no-op acknowledgement. Implementer does NOT create a commit for it. + +--- + +### Task 6: Integration tests — 3 IaC fixture scenarios + +**Change class:** Plugin / extension (exercise spawn + RPC + diff against real fixture binaries). + +**Files:** +- Create: `cmd/wfctl/testdata/verify_capabilities/iac-good/{plugin.json,main.go,go.mod,go.sum}` +- Create: `cmd/wfctl/testdata/verify_capabilities/iac-missing-service/{plugin.json,main.go,go.mod,go.sum}` +- Create: `cmd/wfctl/testdata/verify_capabilities/iac-extra-service/{plugin.json,main.go,go.mod,go.sum}` +- Modify: `cmd/wfctl/plugin_verify_capabilities_test.go` — add 3 integration test functions reusing existing `buildFixtureBinaryForVerify` helper from #765. + +**Step 1: Generate fixtures via helper script** (one-off, not committed) + +Save as `/tmp/gen-iac-fixtures.sh`: + +```bash +#!/bin/bash +set -euo pipefail +BASE=cmd/wfctl/testdata/verify_capabilities + +mkdir -p "$BASE/iac-good" "$BASE/iac-missing-service" "$BASE/iac-extra-service" + +# Shared go.mod template (relative replace; per-fixture module name only). +mkmod() { + local d="$1" mod="$2" + cat > "$d/go.mod" < ../../../../.. +MOD +} + +# Shared main.go for IaC plugins — IaCProviderRequired methods all return Unimplemented +# (only registration matters for the diff). Optional services determined by IMPLEMENT_OPT env-like build tag. + +# iac-good: implements Required + Finalizer; plugin.json declares both. +cat > "$BASE/iac-good/plugin.json" <<'JSON' +{ + "name": "verify-iac-good", + "version": "0.0.0", + "minEngineVersion": "v0.62.0", + "author": "test fixture", + "description": "IaC fixture: registered services match plugin.json declared services", + "iacServices": [ + "workflow.plugin.external.iac.IaCProviderRequired", + "workflow.plugin.external.iac.IaCProviderFinalizer" + ] +} +JSON +cat > "$BASE/iac-good/main.go" <<'GO' +package main + +import ( + "context" + + pb "github.com/GoCodeAlone/workflow/plugin/external/proto" + sdk "github.com/GoCodeAlone/workflow/plugin/external/sdk" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/types/known/emptypb" +) + +var Version = "dev" + +type fixture struct { + pb.UnimplementedIaCProviderRequiredServer + pb.UnimplementedIaCProviderFinalizerServer +} + +func (fixture) Name(context.Context, *pb.NameRequest) (*pb.NameResponse, error) { + return &pb.NameResponse{Name: "verify-iac-good"}, nil +} + +func (fixture) Finalize(context.Context, *emptypb.Empty) (*emptypb.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "test fixture") +} + +func main() { + sdk.ServeIaCPlugin(fixture{}, sdk.IaCServeOptions{ + BuildVersion: sdk.ResolveBuildVersion(Version), + }) +} +GO +mkmod "$BASE/iac-good" iac-good + +# iac-missing-service: implements Required ONLY; plugin.json declares Required + Finalizer +# → diff fires FAIL on Finalizer (missing-from-binary). +cat > "$BASE/iac-missing-service/plugin.json" <<'JSON' +{ + "name": "verify-iac-missing", + "version": "0.0.0", + "minEngineVersion": "v0.62.0", + "author": "test fixture", + "description": "IaC fixture: plugin.json declares more services than binary registers", + "iacServices": [ + "workflow.plugin.external.iac.IaCProviderRequired", + "workflow.plugin.external.iac.IaCProviderFinalizer" + ] +} +JSON +cat > "$BASE/iac-missing-service/main.go" <<'GO' +package main + +import ( + "context" + + pb "github.com/GoCodeAlone/workflow/plugin/external/proto" + sdk "github.com/GoCodeAlone/workflow/plugin/external/sdk" +) + +var Version = "dev" + +type fixture struct { + pb.UnimplementedIaCProviderRequiredServer + // Note: does NOT embed IaCProviderFinalizerServer — type-assertion in + // iacserver.go:178-180 will skip the optional registration. +} + +func (fixture) Name(context.Context, *pb.NameRequest) (*pb.NameResponse, error) { + return &pb.NameResponse{Name: "verify-iac-missing"}, nil +} + +func main() { + sdk.ServeIaCPlugin(fixture{}, sdk.IaCServeOptions{ + BuildVersion: sdk.ResolveBuildVersion(Version), + }) +} +GO +mkmod "$BASE/iac-missing-service" iac-missing-service + +# iac-extra-service: implements Required + Finalizer; plugin.json declares Required ONLY +# → diff fires WARN on Finalizer (extra-in-binary; exit 0). +cat > "$BASE/iac-extra-service/plugin.json" <<'JSON' +{ + "name": "verify-iac-extra", + "version": "0.0.0", + "minEngineVersion": "v0.62.0", + "author": "test fixture", + "description": "IaC fixture: binary registers more services than plugin.json declares", + "iacServices": [ + "workflow.plugin.external.iac.IaCProviderRequired" + ] +} +JSON +cat > "$BASE/iac-extra-service/main.go" <<'GO' +package main + +import ( + "context" + + pb "github.com/GoCodeAlone/workflow/plugin/external/proto" + sdk "github.com/GoCodeAlone/workflow/plugin/external/sdk" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/types/known/emptypb" +) + +var Version = "dev" + +type fixture struct { + pb.UnimplementedIaCProviderRequiredServer + pb.UnimplementedIaCProviderFinalizerServer +} + +func (fixture) Name(context.Context, *pb.NameRequest) (*pb.NameResponse, error) { + return &pb.NameResponse{Name: "verify-iac-extra"}, nil +} + +func (fixture) Finalize(context.Context, *emptypb.Empty) (*emptypb.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "test fixture") +} + +func main() { + sdk.ServeIaCPlugin(fixture{}, sdk.IaCServeOptions{ + BuildVersion: sdk.ResolveBuildVersion(Version), + }) +} +GO +mkmod "$BASE/iac-extra-service" iac-extra-service +``` + +**Step 2: Generate + tidy + verify each fixture builds** + +```bash +bash /tmp/gen-iac-fixtures.sh +for d in cmd/wfctl/testdata/verify_capabilities/iac-*/; do + (cd "$d" && GOWORK=off go mod tidy) + (cd "$d" && GOWORK=off go build -mod=readonly -o /tmp/p .) && echo "$d: ok" || { echo "$d: FAIL"; exit 1; } +done +``` +Expected: all 3 print `ok`. + +**Step 3: Write the integration tests** + +Append to `cmd/wfctl/plugin_verify_capabilities_test.go`: + +```go +func TestVerifyCapabilities_IaCGood(t *testing.T) { + bin := buildFixtureBinaryForVerify(t, "iac-good", "v0.1.0") + if err := runPluginVerifyCapabilities([]string{"--binary", bin, "testdata/verify_capabilities/iac-good"}); err != nil { + t.Fatalf("want PASS, got: %v", err) + } +} + +func TestVerifyCapabilities_IaCMissingService(t *testing.T) { + bin := buildFixtureBinaryForVerify(t, "iac-missing-service", "v0.1.0") + err := runPluginVerifyCapabilities([]string{"--binary", bin, "testdata/verify_capabilities/iac-missing-service"}) + if err == nil { + t.Fatal("want FAIL on missing Finalizer service, got nil") + } + if !strings.Contains(err.Error(), "iacServices:") { + t.Errorf("want iacServices: error, got: %v", err) + } + if !strings.Contains(err.Error(), "IaCProviderFinalizer") { + t.Errorf("want Finalizer-specific error, got: %v", err) + } +} + +func TestVerifyCapabilities_IaCExtraService(t *testing.T) { + bin := buildFixtureBinaryForVerify(t, "iac-extra-service", "v0.1.0") + // Extra services produce WARN (stderr) but exit 0 per design §3. + if err := runPluginVerifyCapabilities([]string{"--binary", bin, "testdata/verify_capabilities/iac-extra-service"}); err != nil { + t.Fatalf("want PASS (extra=WARN, not FAIL); got: %v", err) + } +} +``` + +**Step 4: Run integration tests — verify PASS** + +Run: `GOWORK=off go test -run TestVerifyCapabilities_IaC -count=1 -timeout 180s ./cmd/wfctl/...` +Expected: 3 IaC scenario tests PASS. + +Also run full verify-capabilities suite (regression check): `GOWORK=off go test -run TestVerifyCapabilities -count=1 -timeout 180s ./cmd/wfctl/...` — expect ALL tests PASS (5 from #765 + 4 diff unit tests from Task 4 + 3 IaC integration tests from this task = 12). + +**Step 5: Commit** + +```bash +git add cmd/wfctl/testdata/verify_capabilities/iac-good cmd/wfctl/testdata/verify_capabilities/iac-missing-service cmd/wfctl/testdata/verify_capabilities/iac-extra-service cmd/wfctl/plugin_verify_capabilities_test.go +git commit -m "test(wfctl): 3 IaC integration fixture scenarios (workflow#767)" +``` + +**Rollback:** revert this commit + the Task 4 commit — verify-capabilities returns to Name+Version diff only. + +--- + +## Final verification (post-Task-6) + +Before opening the PR: + +```bash +# 1. All tests pass +GOWORK=off go test -count=1 -timeout 180s ./... + +# 2. Lint clean +GOWORK=off go vet ./... +GOWORK=off golangci-lint run + +# 3. wfctl --help still works (regression check on top-level help) +GOWORK=off go build -o /tmp/wfctl ./cmd/wfctl && /tmp/wfctl plugin verify-capabilities --help + +# 4. Conformance regression still passes (we DID touch sdk/iacserver.go in Task 3) +GOWORK=off go test -run TestPluginConformance -count=1 -timeout 300s ./cmd/wfctl/... + +# 5. SDK unit tests pass (Task 3 + Task 2 surface) +GOWORK=off go test -count=1 ./plugin/external/sdk/... +``` + +## Rollback + +This PR adds a manifest field, an SDK helper, an SDK bridge filter change, and a wfctl subcommand extension. Rollback path: + +- `git revert ` reverts all 6 commits cleanly. Sweep-target plugin.json files (separate PRs) become inert — older wfctl ignores the unknown field per `encoding/json` default (no `DisallowUnknownFields`). +- **Bridge filter rollback (Task 3)**: pre-change behavior surfaced all gRPC services including infra. Reverting restores the noisy registry — downstream consumers (deploy_providers, conformance) handle noise via their own filters today, so no regression. +- **Manifest field rollback (Task 1)**: `IaCServices` field gone; existing manifests with the field load successfully (unknown field ignored). + +Backwards-compat: PR is purely additive at the subcommand-behavior level. Older wfctl callers continue to work; new wfctl on old plugin.json (no `iacServices`) skips the diff per `diffIaCServices` empty-LHS short-circuit. + +## Notes for implementer + +- Worktree base assumes #765 has merged (commit `827158b5f`). If not, rebase onto current main first. +- Edit existing single `import (...)` blocks in every file — DO NOT add a second `import (...)` declaration (Go allows but `gofumpt`/`goimports`/`golangci-lint` enforce single-block). +- Fixture build pattern matches #765 (in-place `-mod=readonly` + checked-in go.sum + relative `replace` + GOWORK=off). +- Task 5 is intentionally a no-op acknowledgement; do NOT create a commit for it (the alignment-check + scope-lock manifest count is preserved via the body heading only). +- After Task 6 commits, run `bash tests/plan-scope-check.sh --plan ` if the harness asks — expected PASS. From cff8903efb3d862d818eb564f7d130989809bc85 Mon Sep 17 00:00:00 2001 From: Jon Langevin Date: Sun, 24 May 2026 08:59:40 -0400 Subject: [PATCH 05/16] docs(plan): #767 design cycle 4 (replan against actual shipped #765 inline-spawn pattern) #765 PR #769 + v0.63.2 landed since cycle 3 paused. Worktree rebased onto current main with verify-capabilities.go present. Replan: direct pbClient.GetContractRegistry(ctx, Empty) after existing GetManifest call (line 137); explicit codes.Unimplemented branch maps to empty registry. Drops cycle-3's adapter-based hypothesis (#765 ships inline-spawn, NOT adapter). --- docs/plans/2026-05-24-contract-diff-design.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/docs/plans/2026-05-24-contract-diff-design.md b/docs/plans/2026-05-24-contract-diff-design.md index 7b1b7f5f..bef379ad 100644 --- a/docs/plans/2026-05-24-contract-diff-design.md +++ b/docs/plans/2026-05-24-contract-diff-design.md @@ -9,7 +9,8 @@ - **Cycle 1**: initial design hardcoded namespace `workflow.iac.v1.*`. FAILED — 2 Critical (wrong namespace; never traced to proto file; actual is `workflow.plugin.external.iac.*`. Duplicates existing `registeredIaCServices`/`iacServiceRequired` precedent without citing or reusing). + 5 Important. - **Cycle 2**: namespace derived programmatically; cite + reuse existing helpers; directional diff; cached accessor; non-goal additions; sweep SDK pin. PASSED with 4 Important amendments to fold. -- **Cycle 3** (this version): folds the 4 Important amendments: (1) ContractRegistryError() check ahead of diff (cycle-2 IMPORTANT-1); (2) iacserver.go:302 added to §Files so the SDK helper actually wires the bridge for the 4 sweep targets (cycle-2 IMPORTANT-2); (3) fixture construction recipes spelled out per scenario (cycle-2 IMPORTANT-3); (4) hard-cite #765 as sequencing prerequisite in §Assumptions (cycle-2 IMPORTANT-4). +- **Cycle 3**: folds 4 Important amendments. PASSED design adversarial. +- **Cycle 4** (this version, post-#765 ship): #765 PR #769 + v0.63.2 actually landed (cycle-1 reviewer was right that they hadn't yet). Worktree rebased onto current main. Replan against ACTUAL shipped inline-spawn pattern (NOT cycle-3's adapter-based hypothesis): direct `pbClient.GetContractRegistry(ctx, &emptypb.Empty{})` after existing `pbClient.GetManifest` call; explicit Unimplemented branch. ## Problem @@ -72,8 +73,8 @@ func BuildContractRegistryForPlugin(grpcSrv *grpc.Server, namespacePrefix string After existing Name+Version diff: -- Check `adapter.ContractRegistryError()` FIRST. If non-nil (RPC failed during adapter construction for some reason other than Unimplemented — e.g. network/transport error), surface the error verbatim + exit 1. Do NOT proceed to diff (would emit synthetic "missing" FAILs that mask the real cause). -- Then reuse cached `adapter.ContractRegistry()` (set at `NewExternalPluginAdapter` construction per `plugin/external/adapter.go:165-172`) — no second RPC. The adapter maps `Unimplemented` to an empty registry, so "Unimplemented" and "empty registry" both reduce to "filter returns 0 services" handled by §4 skip-if-LHS-empty. +- **Updated for #765 shipped inline-spawn pattern**: verify-capabilities (per `cmd/wfctl/plugin_verify_capabilities.go`) uses inline goplugin.NewClient + pluginClient.Conn() + `pbClient := pb.NewPluginServiceClient(pluginClient.Conn())` — NO adapter construction. Therefore: call `pbClient.GetContractRegistry(ctx, &emptypb.Empty{})` directly (one new RPC; mirrors the existing pbClient.GetManifest call site at line 137). +- Handle `codes.Unimplemented` explicitly: treat as empty registry (skip-if-LHS-empty fires per §4). Any other RPC error → exit 1 with stderr-tail context (matches existing GetManifest error handling pattern). - Reuse the existing client-side filter precedent: `registeredIaCServices` in `cmd/wfctl/deploy_providers.go:344-361` already walks ContractDescriptors and returns SERVICE-kind names. Either call it directly OR refactor into a shared `cmd/wfctl/iac_contract_filter.go` helper consumed by both deploy_providers and verify-capabilities (recommend the refactor; one line in plan-time task list). - Derive the namespace prefix programmatically from the existing canonical `iacServiceRequired` const (`cmd/wfctl/iac_typed_adapter.go:52` = `"workflow.plugin.external.iac.IaCProviderRequired"`) via `strings.TrimSuffix(iacServiceRequired, ".IaCProviderRequired") + "."`. No new string literal; single source of truth. - Set-difference diff (directional, NOT set-equal): @@ -118,7 +119,7 @@ Reuse `registeredIaCServices` (deploy_providers.go:344) and `iacServiceRequired` - `plugin/external/sdk/contracts.go` — add `BuildContractRegistryForPlugin`. - `plugin/external/sdk/iacserver.go:302` — switch `iacPluginServiceBridge.GetContractRegistry` from `BuildContractRegistry(b.grpcSrv)` to `BuildContractRegistryForPlugin(b.grpcSrv, prefix)` where `prefix` is derived as in §2. This is the critical path for the 4 sweep targets — they use `sdk.ServeIaCPlugin` which routes through this bridge, so the SDK helper must be wired here to deliver server-side cleanliness for them. Without this edit, the new helper is dead code for the sweep targets and only the client-side filter in verify-capabilities masks the noise. (Cycle 3 per IMPORTANT-2.) - `cmd/wfctl/iac_contract_filter.go` (NEW) OR `cmd/wfctl/deploy_providers.go` move — house `registeredIaCServices` in a location both deploy_providers and verify-capabilities can import. -- `cmd/wfctl/plugin_verify_capabilities.go` — extend `runPluginVerifyCapabilities` with cached `adapter.ContractRegistry()` walk + filter (reuse helper) + directional diff. +- `cmd/wfctl/plugin_verify_capabilities.go` — extend `runPluginVerifyCapabilities` with `pbClient.GetContractRegistry(ctx, &emptypb.Empty{})` call (after existing GetManifest call at line 137) + filter via `registeredIaCServices` helper + directional diff. - `cmd/wfctl/plugin_verify_capabilities_test.go` — new test scenarios: `iac-good` (matching services), `iac-missing-service` (declared but not advertised → FAIL), `iac-extra-service` (advertised but not declared → WARN exit 0). - `cmd/wfctl/testdata/verify_capabilities/iac-{good,missing-service,extra-service}/` — 3 new fixture scenarios using `sdk.ServeIaCPlugin` so they actually register IaC services on the wire. Construction recipes: - `iac-good/`: stub provider implements `pb.IaCProviderRequiredServer` + `pb.IaCProviderFinalizerServer`. plugin.json lists BOTH services. Diff: clean PASS. @@ -132,15 +133,15 @@ Reuse `registeredIaCServices` (deploy_providers.go:344) and `iacServiceRequired` 1. **workflow#765 PR has merged FIRST** — this design extends `cmd/wfctl/plugin_verify_capabilities.go` and depends on the `spawnAndDial`-style spawn path from #765. Without #765, the file doesn't exist and `runPluginVerifyCapabilities` doesn't exist. The worktree for #767 must rebase on top of #765's merge commit before any code in this design's §Files entries can be written. (Cycle 3 per IMPORTANT-4.) 2. **`pb.IaCProviderRequired_ServiceDesc.ServiceName` resolves to a string ending in `.IaCProviderRequired`** — verified per `/tmp/wfprobe/plugin/external/proto/iac_grpc.pb.go:443` (canonical generated descriptor) AND existing usage in `cmd/wfctl/iac_typed_adapter.go:52` const. -2. **`adapter.ContractRegistry()` returns the cached registry constructed during `NewExternalPluginAdapter` and is safe to call repeatedly** — verified per `plugin/external/adapter.go:165-176`. +2. **#765 verify-capabilities uses inline-spawn pattern (not adapter)** — verified at `cmd/wfctl/plugin_verify_capabilities.go:126-137`: `pluginClient, ok := raw.(*external.PluginClient)` → `pbClient := pb.NewPluginServiceClient(pluginClient.Conn())` → `runtime, err := pbClient.GetManifest(ctx, &emptypb.Empty{})`. Contract-diff adds a second RPC `pbClient.GetContractRegistry(ctx, &emptypb.Empty{})` after GetManifest. Same pbClient, same ctx. 3. **All 4 sweep-target plugins (aws, azure, gcp, digitalocean) pin workflow v0.62.0+** — required for the strict-contracts cutover path that registers the typed IaC services and the PluginService bridge that serves GetContractRegistry. (Cycle 2 explicit per IMPORTANT-4.) Pre-flight check: each plugin's `go.mod` must show `github.com/GoCodeAlone/workflow v0.62.0+` before opening its sweep PR. If any plugin pins an older version, the sweep blocker is a workflow-bump cascade, not this design. 4. **`grpc.Server.GetServiceInfo()` returns fully-qualified service names** — verified per gRPC-go API. 5. **Fixture scenarios can build IaC plugins in-place via `go build -mod=readonly`** — verified pattern from #765 fixtures. ## Failure modes -- **Plugin doesn't implement ContractProvider**: `adapter.ContractRegistry()` returns an empty (but non-nil) registry per `plugin/external/adapter.go:165-176` (Unimplemented is mapped to empty there). Filter returns 0 services. Skip-if-LHS-empty handles non-IaC plugins; for IaC plugins with non-empty plugin.json.iacServices the directional diff fires FAIL on every declared service (consistent with the "plugin advertises nothing" truth-loop signal). -- **Network/RPC failure mid-call**: N/A — no new RPC in verify-capabilities (cached adapter accessor). Adapter-construction RPC failure already surfaces in spawn-and-dial path. +- **Plugin doesn't implement ContractProvider (`GetContractRegistry` returns codes.Unimplemented)**: explicit `status.Code(err) == codes.Unimplemented` check; treat as empty registry → skip-if-LHS-empty handles non-IaC plugins; for IaC plugins with non-empty plugin.json.iacServices the directional diff fires FAIL on every declared service (consistent with "plugin advertises nothing" truth-loop signal). +- **Network/RPC failure mid-call (non-Unimplemented)**: surface error verbatim + stderr-tail; exit 1. Matches existing `GetManifest` error handling at `plugin_verify_capabilities.go:138-141`. - **Plugin advertises a service in a different namespace** (e.g. `workflow.iac.v2.*` post-cutover): client-side filter excludes it. Forward-compat handled by re-deriving prefix from a future `IaCProviderRequired_v2_ServiceDesc.ServiceName` or by introducing a `--namespace` flag at v2 cutover time. - **Plugin author lists a service in plugin.json that exists in proto but the plugin's Go code doesn't register** (e.g. declared IaCProviderValidator without implementing the interface): registry filter doesn't surface it → declared-but-not-advertised → FAIL. Correct outcome. - **Plugin author registers a service the proto package doesn't define** (impossible-by-construction for typed IaC since registration is per-pb-helper): N/A. From 6a94640d711c07c1055b52f3ee3a4485221bf769 Mon Sep 17 00:00:00 2001 From: Jon Langevin Date: Sun, 24 May 2026 09:03:14 -0400 Subject: [PATCH 06/16] docs(plan): #767 design cycle 4 inline amendments (Option A per reviewer) Cycle 4 PASS with 3 Important. Apply inline: - I-2: drop iac_contract_filter.go NEW proposal; reuse registeredIaCServices in-place (both package main) - I-1: add git-grep audit confirming iacserver.go:302 rebinding is safe (4 existing consumers all already filter) - I-3: reword Unimplemented branch to distinguish empty-LHS (skip) vs non-empty-LHS (FAIL on every declared) cases --- docs/plans/2026-05-24-contract-diff-design.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/plans/2026-05-24-contract-diff-design.md b/docs/plans/2026-05-24-contract-diff-design.md index bef379ad..b2b6b130 100644 --- a/docs/plans/2026-05-24-contract-diff-design.md +++ b/docs/plans/2026-05-24-contract-diff-design.md @@ -74,7 +74,10 @@ func BuildContractRegistryForPlugin(grpcSrv *grpc.Server, namespacePrefix string After existing Name+Version diff: - **Updated for #765 shipped inline-spawn pattern**: verify-capabilities (per `cmd/wfctl/plugin_verify_capabilities.go`) uses inline goplugin.NewClient + pluginClient.Conn() + `pbClient := pb.NewPluginServiceClient(pluginClient.Conn())` — NO adapter construction. Therefore: call `pbClient.GetContractRegistry(ctx, &emptypb.Empty{})` directly (one new RPC; mirrors the existing pbClient.GetManifest call site at line 137). -- Handle `codes.Unimplemented` explicitly: treat as empty registry (skip-if-LHS-empty fires per §4). Any other RPC error → exit 1 with stderr-tail context (matches existing GetManifest error handling pattern). +- Handle `codes.Unimplemented` explicitly: treat as empty registry. Two paths: + - Empty `plugin.json.iacServices` (non-IaC plugin OR un-swept IaC plugin) → skip-if-LHS-empty fires per §4; clean. + - Non-empty `plugin.json.iacServices` (claims a service surface but binary advertises nothing) → directional diff over empty binary set fires FAIL on EVERY declared service. Correct truth-loop signal — same class as "binary doesn't implement what plugin.json claims". (Cycle-4 I-3 wording fix.) +- Any other RPC error → exit 1 with stderr-tail context (matches existing GetManifest error handling pattern). - Reuse the existing client-side filter precedent: `registeredIaCServices` in `cmd/wfctl/deploy_providers.go:344-361` already walks ContractDescriptors and returns SERVICE-kind names. Either call it directly OR refactor into a shared `cmd/wfctl/iac_contract_filter.go` helper consumed by both deploy_providers and verify-capabilities (recommend the refactor; one line in plan-time task list). - Derive the namespace prefix programmatically from the existing canonical `iacServiceRequired` const (`cmd/wfctl/iac_typed_adapter.go:52` = `"workflow.plugin.external.iac.IaCProviderRequired"`) via `strings.TrimSuffix(iacServiceRequired, ".IaCProviderRequired") + "."`. No new string literal; single source of truth. - Set-difference diff (directional, NOT set-equal): @@ -117,8 +120,9 @@ Reuse `registeredIaCServices` (deploy_providers.go:344) and `iacServiceRequired` - `plugin/manifest.go` — add `IaCServices` field + UnmarshalJSON nested-promotion. - `plugin/external/sdk/contracts.go` — add `BuildContractRegistryForPlugin`. -- `plugin/external/sdk/iacserver.go:302` — switch `iacPluginServiceBridge.GetContractRegistry` from `BuildContractRegistry(b.grpcSrv)` to `BuildContractRegistryForPlugin(b.grpcSrv, prefix)` where `prefix` is derived as in §2. This is the critical path for the 4 sweep targets — they use `sdk.ServeIaCPlugin` which routes through this bridge, so the SDK helper must be wired here to deliver server-side cleanliness for them. Without this edit, the new helper is dead code for the sweep targets and only the client-side filter in verify-capabilities masks the noise. (Cycle 3 per IMPORTANT-2.) -- `cmd/wfctl/iac_contract_filter.go` (NEW) OR `cmd/wfctl/deploy_providers.go` move — house `registeredIaCServices` in a location both deploy_providers and verify-capabilities can import. +- `plugin/external/sdk/iacserver.go:302` — switch `iacPluginServiceBridge.GetContractRegistry` from `BuildContractRegistry(b.grpcSrv)` to `BuildContractRegistryForPlugin(b.grpcSrv, prefix)` where `prefix` is derived as in §2. (Cycle 3 per IMPORTANT-2.) + - **Cycle-4 I-1 audit**: `git grep -n GetContractRegistry` enumerated existing consumers: `ExternalPluginAdapter.ContractRegistry()`, `registeredIaCServices()` (`deploy_providers.go:324`), `iacFinalizerHandle` (`iac_loader_gate.go:76`), `plugin_conformance.go:505`. ALL already SERVICE-kind-filter or namespace-filter client-side; none depend on infra services being present. Rebinding is safe. +- `registeredIaCServices` reuse: NO NEW FILE. Both `deploy_providers.go` (defines it) and `plugin_verify_capabilities.go` (new caller) are `package main`, so direct call works. (Cycle-4 I-2: dropped earlier proposal for `iac_contract_filter.go`.) - `cmd/wfctl/plugin_verify_capabilities.go` — extend `runPluginVerifyCapabilities` with `pbClient.GetContractRegistry(ctx, &emptypb.Empty{})` call (after existing GetManifest call at line 137) + filter via `registeredIaCServices` helper + directional diff. - `cmd/wfctl/plugin_verify_capabilities_test.go` — new test scenarios: `iac-good` (matching services), `iac-missing-service` (declared but not advertised → FAIL), `iac-extra-service` (advertised but not declared → WARN exit 0). - `cmd/wfctl/testdata/verify_capabilities/iac-{good,missing-service,extra-service}/` — 3 new fixture scenarios using `sdk.ServeIaCPlugin` so they actually register IaC services on the wire. Construction recipes: From 67c6b385c6da0a943c4e7195e32d0a57d140e531 Mon Sep 17 00:00:00 2001 From: Jon Langevin Date: Sun, 24 May 2026 09:06:09 -0400 Subject: [PATCH 07/16] docs(plan): #767 implementation plan (post-#765-shipped, direct pbClient pattern) 5 tasks, 1 PR. Mirrors design cycle 4 PASS. Direct pbClient.GetContractRegistry after existing GetManifest call (line 131 inline-spawn pattern). Explicit codes.Unimplemented branch. Reuses #765 fixture pattern + IaCStateBackends UnmarshalJSON precedent. --- docs/plans/2026-05-24-contract-diff.md | 508 +++++++++++-------------- 1 file changed, 232 insertions(+), 276 deletions(-) diff --git a/docs/plans/2026-05-24-contract-diff.md b/docs/plans/2026-05-24-contract-diff.md index d356839b..054cf930 100644 --- a/docs/plans/2026-05-24-contract-diff.md +++ b/docs/plans/2026-05-24-contract-diff.md @@ -1,16 +1,16 @@ -# verify-capabilities Contract-Diff Implementation Plan +# verify-capabilities contract-diff Implementation Plan > **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. -**Goal:** Extend `wfctl plugin verify-capabilities` (workflow#765) to diff plugin's runtime `GetContractRegistry` typed-IaC services against `plugin.json.iacServices`. Adds new manifest field, server-side namespace-filtering SDK helper, and sweeps 4 IaC plugins to populate the field. +**Goal:** Extend `wfctl plugin verify-capabilities` (#765/#769 shipped at v0.63.2) with a typed-IaC service diff: add `PluginManifest.IaCServices []string` field, add `sdk.BuildContractRegistryForPlugin` namespace-filter helper, rewire `iacPluginServiceBridge.GetContractRegistry` to use it, and append a directional diff in `runPluginVerifyCapabilities` against `plugin.json.iacServices`. -**Architecture:** Single PR adds (a) `PluginManifest.IaCServices []string` with nested-promotion in UnmarshalJSON mirroring existing `IaCStateBackends` pattern; (b) `sdk.BuildContractRegistryForPlugin(grpcSrv, prefix)` helper; (c) `iacPluginServiceBridge.GetContractRegistry` rewires to use the filtered helper so all `sdk.ServeIaCPlugin` callers get clean output; (d) `verify-capabilities` calls `adapter.ContractRegistryError()` first (surface RPC errors verbatim) then reuses cached `adapter.ContractRegistry()` + existing `registeredIaCServices` helper for directional diff (FAIL missing-from-binary, WARN extra-in-binary). Sweep 4 IaC plugins (aws/azure/gcp/digitalocean) separately as follow-up PRs out of this scope. +**Architecture:** Single PR. Mirror existing `IaCStateBackends` precedent for the manifest field + nested-promotion. SDK helper derives namespace prefix from `pb.IaCProviderRequired_ServiceDesc.ServiceName` via TrimSuffix (single source of truth keyed to .proto). Bridge rewiring at `plugin/external/sdk/iacserver.go:302`. Verify-capabilities extension: ONE new RPC `pbClient.GetContractRegistry(ctx, Empty)` after existing `pbClient.GetManifest` call at line 131; explicit `codes.Unimplemented` branch maps to empty registry; directional diff (FAIL missing-from-binary, WARN extra-in-binary). Sweep of 4 IaC plugins (aws/azure/gcp/digitalocean) is out-of-scope (separate per-repo PRs after this workflow PR lands). -**Tech Stack:** Go (workflow CLI + SDK), `pb.PluginService` gRPC, `pb.IaCProviderRequired_ServiceDesc.ServiceName` for canonical namespace, `external.PluginAdapter` cached accessors. +**Tech Stack:** Go (wfctl + SDK), `pb.PluginService` gRPC (raw client), `pb.IaCProviderRequired_ServiceDesc.ServiceName` canonical prefix derivation. -**Base branch:** `main` (worktree was branched from `origin/main` post-#765 merge at 827158b5f) +**Base branch:** `main` -**Design doc:** `docs/plans/2026-05-24-contract-diff-design.md` (cycle 3 PASS adversarial). +**Design doc:** `docs/plans/2026-05-24-contract-diff-design.md` (cycle 4 PASS adversarial). **Issue:** workflow#767 @@ -19,70 +19,62 @@ ## Scope Manifest **PR Count:** 1 -**Tasks:** 6 -**Estimated Lines of Change:** ~450 (manifest field + SDK helper + bridge rewire + verify extension + 3 fixtures + tests) +**Tasks:** 5 +**Estimated Lines of Change:** ~400 (manifest field + SDK helper + bridge rewire + verify-cap extension + 3 fixture scenarios + tests) **Out of scope:** -- Sweep of 4 IaC plugin repos (aws, azure, gcp, digitalocean) to populate `iacServices` field — separate per-repo PRs after this workflow PR lands and v0.63.2+ is tagged. Each per-repo PR is small (plugin.json edit only). Tracked in workflow#767 issue body as AC #4. -- `validate-contract` static enforcement of non-empty `iacServices` for `type:"iac"` plugins — future tightening. -- Multi-namespace support beyond `workflow.plugin.external.iac.*` — single derived prefix only. -- Auto-population of `iacServices` from runtime introspection — operator authors the list manually. -- Embedded plugin.json verification (via `sdk.WithManifestProvider`) — `pb.Manifest` is 6-scalar and doesn't surface `iacServices`; disk plugin.json is the authoritative source. -- ResourceDriver/IaCStateBackend semantic split — `iacServices` includes ALL `workflow.plugin.external.iac.*` services when registered; orthogonal to existing `iacStateBackends` (backend NAMES) field. +- Sweep of 4 IaC plugin repos (aws/azure/gcp/digitalocean) — separate per-repo PRs after this workflow PR lands and v0.64+ ships. +- `validate-contract` static enforcement of non-empty `iacServices` for `type:"iac"` plugins. +- Multi-namespace support beyond `workflow.plugin.external.iac.*`. +- Auto-population of `iacServices` from runtime introspection. +- Embedded plugin.json verification (`sdk.WithManifestProvider` doesn't surface this field on `pb.Manifest`). +- ResourceDriver/IaCStateBackend semantic split — `iacServices` includes ALL `workflow.plugin.external.iac.*` services when registered. +- Refactor `registeredIaCServices` into a new file — direct call works (both `package main` per cycle-4 I-2). **PR Grouping:** | PR # | Title | Tasks | Branch | |------|-------|-------|--------| -| 1 | feat(sdk+wfctl): contract-diff extension for verify-capabilities (workflow#767) | Task 1, Task 2, Task 3, Task 4, Task 5, Task 6 | feat/767-contract-diff | +| 1 | feat(sdk+wfctl): contract-diff extension for verify-capabilities (workflow#767) | Task 1, Task 2, Task 3, Task 4, Task 5 | feat/767-contract-diff | **Status:** Draft --- -### Task 1: Add `IaCServices` field to `PluginManifest` with nested-promotion +### Task 1: Add `IaCServices` field to `PluginManifest` + nested-promotion -**Change class:** Internal logic refactor (schema field addition with backwards-compat JSON unmarshaling). +**Change class:** Internal logic refactor. **Files:** -- Modify: `plugin/manifest.go` — add `IaCServices` field (after `IaCStateBackends` at line 56); extend UnmarshalJSON legacy-object branch to promote nested `capabilities.iacServices` (after line 159). -- Modify: `plugin/manifest_test.go` — add tests for both top-level and nested-promotion parse paths. +- Modify: `plugin/manifest.go` — add `IaCServices` field after `IaCStateBackends` (line 56); extend UnmarshalJSON legacy-object branch (line 159) for nested-promotion. +- Modify: `plugin/manifest_test.go` — add tests for top-level + nested-promotion + omitempty paths. -**Step 1: Write the failing tests** - -Append to `plugin/manifest_test.go` (edit existing single `import (...)` block to add `"encoding/json"` if not present): +**Step 1: Write failing tests** (edit existing SINGLE import block; add `"encoding/json"` if missing) ```go func TestPluginManifest_IaCServices_TopLevel(t *testing.T) { const j = `{"name":"x","version":"1.0.0","author":"a","description":"d","iacServices":["workflow.plugin.external.iac.IaCProviderRequired"]}` var m PluginManifest - if err := json.Unmarshal([]byte(j), &m); err != nil { - t.Fatal(err) - } + if err := json.Unmarshal([]byte(j), &m); err != nil { t.Fatal(err) } if len(m.IaCServices) != 1 || m.IaCServices[0] != "workflow.plugin.external.iac.IaCProviderRequired" { - t.Errorf("IaCServices = %v, want [workflow.plugin.external.iac.IaCProviderRequired]", m.IaCServices) + t.Errorf("IaCServices = %v", m.IaCServices) } } func TestPluginManifest_IaCServices_NestedPromotion(t *testing.T) { const j = `{"name":"x","version":"1.0.0","author":"a","description":"d","capabilities":{"iacServices":["workflow.plugin.external.iac.IaCProviderRequired","workflow.plugin.external.iac.IaCProviderFinalizer"]}}` var m PluginManifest - if err := json.Unmarshal([]byte(j), &m); err != nil { - t.Fatal(err) - } + if err := json.Unmarshal([]byte(j), &m); err != nil { t.Fatal(err) } if len(m.IaCServices) != 2 { - t.Errorf("IaCServices = %v, want 2 entries from nested capabilities object", m.IaCServices) + t.Errorf("IaCServices = %v, want 2 entries promoted from nested capabilities", m.IaCServices) } } func TestPluginManifest_IaCServices_OmitWhenEmpty(t *testing.T) { m := PluginManifest{Name: "x", Version: "1.0.0", Author: "a", Description: "d"} - b, err := json.Marshal(m) - if err != nil { - t.Fatal(err) - } + b, _ := json.Marshal(m) if strings.Contains(string(b), "iacServices") { - t.Errorf("empty IaCServices should be omitted via omitempty; got %s", b) + t.Errorf("empty IaCServices should be omitted; got %s", b) } } ``` @@ -90,13 +82,11 @@ func TestPluginManifest_IaCServices_OmitWhenEmpty(t *testing.T) { **Step 2: Run tests — verify FAIL** Run: `GOWORK=off go test -run TestPluginManifest_IaCServices -count=1 ./plugin/...` -Expected: FAIL with `m.IaCServices undefined`. +Expected: FAIL `m.IaCServices undefined`. **Step 3: Implement** -Edit `plugin/manifest.go`: - -1. After existing `IaCStateBackends` field (line 56), add: +In `plugin/manifest.go` after line 56 (`IaCStateBackends`), add: ```go // IaCServices lists the typed IaC service names this plugin serves @@ -104,19 +94,21 @@ Edit `plugin/manifest.go`: // "workflow.plugin.external.iac.IaCProviderRequired"). Authored in // plugin.json either as a top-level "iacServices" key OR nested under // "capabilities.iacServices" (UnmarshalJSON's object branch promotes -// the nested form). The engine cross-checks these against the plugin's -// runtime ContractRegistry via wfctl plugin verify-capabilities (#767). +// the nested form, same as IaCStateBackends). The engine cross-checks +// these against the plugin's runtime ContractRegistry via wfctl plugin +// verify-capabilities (workflow#767). // -// Orthogonal to IaCStateBackends (which lists backend NAMES the plugin -// serves, not gRPC service names). A plugin that registers the -// IaCStateBackend service AND lists its backend name(s) in -// iacStateBackends appears in BOTH manifest fields. +// Orthogonal to IaCStateBackends (which lists backend NAMES, not gRPC +// service names). A plugin that registers the IaCStateBackend service +// AND lists its backend names will appear in BOTH manifest fields. IaCServices []string `json:"iacServices,omitempty" yaml:"iacServices,omitempty"` ``` -2. In the UnmarshalJSON `case '{':` legacy-object branch, extend the `legacyCaps` struct (line 150) to include `IaCServices []string \`json:"iacServices"\`` (alphabetical with existing fields). -3. After the existing `m.IaCStateBackends = appendUnique(...)` (line 159) add: - +In the UnmarshalJSON `case '{':` legacy-object branch (line 150 `legacyCaps` struct), add: +```go +IaCServices []string `json:"iacServices"` +``` +After line 159 (`m.IaCStateBackends = appendUnique(...)`), add: ```go m.IaCServices = appendUnique(m.IaCServices, legacyCaps.IaCServices...) ``` @@ -126,24 +118,25 @@ m.IaCServices = appendUnique(m.IaCServices, legacyCaps.IaCServices...) Run: `GOWORK=off go test -run TestPluginManifest_IaCServices -count=1 ./plugin/...` Expected: 3 tests PASS. -**Step 5: Commit** +**Step 5: Commit + push** ```bash git add plugin/manifest.go plugin/manifest_test.go -git commit -m "feat(plugin): add IaCServices manifest field with nested-promotion (workflow#767)" +git commit -m "feat(plugin): add IaCServices manifest field with nested-promotion (workflow#767 Task 1)" +git push ``` --- ### Task 2: Add `BuildContractRegistryForPlugin` SDK helper -**Change class:** Internal logic refactor (new exported helper function). +**Change class:** Internal logic refactor (new exported helper). **Files:** -- Modify: `plugin/external/sdk/contracts.go` — add helper after `BuildContractRegistry` (current file ends around line 90). -- Modify: `plugin/external/sdk/contracts_test.go` (create if missing) — add tests for filter behavior. +- Modify: `plugin/external/sdk/contracts.go` — append helper after `BuildContractRegistry`. +- Modify: `plugin/external/sdk/contracts_test.go` (create if absent) — tests. -**Step 1: Write the failing tests** +**Step 1: Write failing tests** Create `plugin/external/sdk/contracts_test.go`: @@ -160,81 +153,61 @@ import ( func TestBuildContractRegistryForPlugin_NilServer(t *testing.T) { reg := BuildContractRegistryForPlugin(nil, "workflow.plugin.external.iac.") - if reg == nil { - t.Fatal("want non-nil registry for nil server") - } - if len(reg.Contracts) != 0 { - t.Errorf("want empty Contracts; got %d", len(reg.Contracts)) - } + if reg == nil { t.Fatal("want non-nil") } + if len(reg.Contracts) != 0 { t.Errorf("want 0 contracts; got %d", len(reg.Contracts)) } } func TestBuildContractRegistryForPlugin_FiltersByPrefix(t *testing.T) { s := grpc.NewServer() - // Register the iac required service + the plugin-service bridge (which - // is NOT in the iac namespace and should be filtered out). pb.RegisterIaCProviderRequiredServer(s, &stubIaCRequired{}) pb.RegisterPluginServiceServer(s, &stubPluginService{}) - // Sink listener so grpc.Server.GetServiceInfo() has registered services. go func() { l, _ := net.Listen("tcp", "127.0.0.1:0") _ = s.Serve(l) }() defer s.Stop() - reg := BuildContractRegistryForPlugin(s, "workflow.plugin.external.iac.") if len(reg.Contracts) != 1 { - t.Fatalf("want 1 contract (only iac.IaCProviderRequired); got %d: %v", len(reg.Contracts), serviceNames(reg)) + t.Fatalf("want 1 contract (iac.IaCProviderRequired); got %d: %v", len(reg.Contracts), reg.Contracts) } if reg.Contracts[0].ServiceName != "workflow.plugin.external.iac.IaCProviderRequired" { t.Errorf("unexpected service: %s", reg.Contracts[0].ServiceName) } } -// Stubs (minimal — only need RegisterServer to succeed). type stubIaCRequired struct{ pb.UnimplementedIaCProviderRequiredServer } type stubPluginService struct{ pb.UnimplementedPluginServiceServer } - -func serviceNames(reg *pb.ContractRegistry) []string { - out := make([]string, 0, len(reg.Contracts)) - for _, c := range reg.Contracts { - out = append(out, c.ServiceName) - } - return out -} ``` **Step 2: Run tests — verify FAIL** Run: `GOWORK=off go test -run TestBuildContractRegistryForPlugin -count=1 ./plugin/external/sdk/...` -Expected: FAIL with `undefined: BuildContractRegistryForPlugin`. +Expected: FAIL `undefined: BuildContractRegistryForPlugin`. **Step 3: Implement** -Append to `plugin/external/sdk/contracts.go`: +In `plugin/external/sdk/contracts.go` append after existing `BuildContractRegistry`: ```go // BuildContractRegistryForPlugin enumerates gRPC services registered on // grpcSrv whose name STARTS WITH namespacePrefix and returns a -// *pb.ContractRegistry with one SERVICE-kind, STRICT_PROTO-mode -// ContractDescriptor per matching service. Used to filter out go-plugin -// infra services (PluginService, GRPCBroker, GRPCStdio, grpc.health.v1.Health) -// so downstream contract-diff (workflow#767) sees only plugin-owned services. +// *pb.ContractRegistry with one SERVICE-kind STRICT_PROTO ContractDescriptor +// per matching service. Filters out go-plugin infra services (PluginService, +// GRPCBroker, GRPCStdio, grpc.health.v1.Health) so downstream contract-diff +// (workflow#767) sees only plugin-owned services. // -// Safe to call with nil server; returns an empty (but non-nil) registry. -// Service descriptors are alphabetically sorted for stable diff output. +// Safe to call with nil server; returns empty (but non-nil) registry. +// Names alphabetically sorted for stable diff output. // -// Typical caller: iacPluginServiceBridge.GetContractRegistry (this package) -// derives the prefix from pb.IaCProviderRequired_ServiceDesc.ServiceName -// minus the ".IaCProviderRequired" suffix so the filter cannot drift from -// the .proto package declaration. +// Typical caller: iacPluginServiceBridge.GetContractRegistry derives prefix +// from pb.IaCProviderRequired_ServiceDesc.ServiceName minus the ".IaCProviderRequired" +// suffix so the filter cannot drift from the .proto package declaration. // // BuildContractRegistry (full-surface, no filter) is retained for callers // that want every registered service. func BuildContractRegistryForPlugin(grpcSrv *grpc.Server, namespacePrefix string) *pb.ContractRegistry { registry := &pb.ContractRegistry{} - if grpcSrv == nil { - return registry - } + if grpcSrv == nil { return registry } info := grpcSrv.GetServiceInfo() names := make([]string, 0, len(info)) for name := range info { @@ -254,72 +227,76 @@ func BuildContractRegistryForPlugin(grpcSrv *grpc.Server, namespacePrefix string } ``` -Add `"strings"` to the import block (edit existing single block, don't add a second `import (...)`). +Add `"strings"` to the existing single import block. **Step 4: Run tests — verify PASS** Run: `GOWORK=off go test -run TestBuildContractRegistryForPlugin -count=1 ./plugin/external/sdk/...` Expected: both tests PASS. -**Step 5: Commit** +**Step 5: Commit + push** ```bash git add plugin/external/sdk/contracts.go plugin/external/sdk/contracts_test.go -git commit -m "feat(sdk): BuildContractRegistryForPlugin namespace-filtering helper (workflow#767)" +git commit -m "feat(sdk): BuildContractRegistryForPlugin namespace-filtering helper (workflow#767 Task 2)" +git push ``` --- -### Task 3: Rewire `iacPluginServiceBridge.GetContractRegistry` to use the filtered helper +### Task 3: Rewire `iacPluginServiceBridge.GetContractRegistry` to use filtered helper -**Change class:** Internal logic refactor (SDK bridge swap; behavior cleaner output, no contract change to callers since infra-noise removal is the design intent). +**Change class:** Internal logic refactor (SDK bridge swap; cleans wire output for the 4 sweep targets). **Files:** -- Modify: `plugin/external/sdk/iacserver.go` — change line ~302 (the only `BuildContractRegistry(b.grpcSrv)` call in the IaC bridge). +- Modify: `plugin/external/sdk/iacserver.go:302` — swap `BuildContractRegistry` for `BuildContractRegistryForPlugin`. +- Modify: `plugin/external/sdk/iacserver_internal_test.go` (create if absent; `package sdk` for internal access) — regression test. -**Step 1: Write the failing test** +**Step 1: Write failing test** -Append to `plugin/external/sdk/iacserver_internal_test.go` (or create if missing — keep `package sdk` for internal access): +Append (or create) `plugin/external/sdk/iacserver_internal_test.go`: ```go +package sdk + +import ( + "context" + "strings" + "testing" + + pb "github.com/GoCodeAlone/workflow/plugin/external/proto" + "google.golang.org/grpc" + "google.golang.org/protobuf/types/known/emptypb" +) + func TestIaCBridge_ContractRegistry_FiltersInfra(t *testing.T) { s := grpc.NewServer() pb.RegisterIaCProviderRequiredServer(s, &stubIaCRequired{}) - // Bridge registers PluginService itself — verify that's filtered out. pb.RegisterPluginServiceServer(s, &iacPluginServiceBridge{grpcSrv: s}) bridge := &iacPluginServiceBridge{grpcSrv: s} reg, err := bridge.GetContractRegistry(context.Background(), &emptypb.Empty{}) - if err != nil { - t.Fatal(err) - } + if err != nil { t.Fatal(err) } for _, c := range reg.Contracts { if !strings.HasPrefix(c.ServiceName, "workflow.plugin.external.iac.") { t.Errorf("bridge surfaced non-iac service %q after filter", c.ServiceName) } } - // Sanity: at least the IaCProviderRequired service should be present. found := false for _, c := range reg.Contracts { - if c.ServiceName == "workflow.plugin.external.iac.IaCProviderRequired" { - found = true - } - } - if !found { - t.Error("expected IaCProviderRequired in filtered registry") + if c.ServiceName == "workflow.plugin.external.iac.IaCProviderRequired" { found = true } } + if !found { t.Error("expected IaCProviderRequired in filtered registry") } } ``` -Edit imports to add `"context"`, `"strings"`, `"testing"`, `"google.golang.org/protobuf/types/known/emptypb"`, `"google.golang.org/grpc"`, `pb "github.com/GoCodeAlone/workflow/plugin/external/proto"`. (Edit the existing single import block.) - **Step 2: Run test — verify FAIL** Run: `GOWORK=off go test -run TestIaCBridge_ContractRegistry_FiltersInfra -count=1 ./plugin/external/sdk/...` -Expected: FAIL — pre-rewire bridge surfaces PluginService + GRPCBroker + GRPCStdio + health, all non-iac-prefixed. +Expected: FAIL — pre-rewire bridge surfaces PluginService + GRPCBroker + GRPCStdio + health. -**Step 3: Rewire the bridge** +**Step 3: Rewire bridge** -Edit `plugin/external/sdk/iacserver.go` around line 302. Find: +In `plugin/external/sdk/iacserver.go` around line 302, replace: ```go func (b *iacPluginServiceBridge) GetContractRegistry(_ context.Context, _ *emptypb.Empty) (*pb.ContractRegistry, error) { @@ -327,55 +304,59 @@ func (b *iacPluginServiceBridge) GetContractRegistry(_ context.Context, _ *empty } ``` -Replace with: +with: ```go func (b *iacPluginServiceBridge) GetContractRegistry(_ context.Context, _ *emptypb.Empty) (*pb.ContractRegistry, error) { - // Derive prefix from canonical proto descriptor so the filter cannot - // drift from the .proto package declaration (workflow#767 §1). + // Derive prefix from canonical proto descriptor (workflow#767 §1) so the + // filter cannot drift from the .proto package declaration. prefix := strings.TrimSuffix(pb.IaCProviderRequired_ServiceDesc.ServiceName, ".IaCProviderRequired") + "." return BuildContractRegistryForPlugin(b.grpcSrv, prefix), nil } ``` -Add `"strings"` to the existing import block (do NOT add a second `import (...)`). +Add `"strings"` to the existing import block. **DO NOT add a second `import (...)` declaration.** **Step 4: Run tests — verify PASS** Run: `GOWORK=off go test -count=1 ./plugin/external/sdk/...` -Expected: new TestIaCBridge_ContractRegistry_FiltersInfra PASS; existing SDK tests still PASS (no regressions). +Expected: new test PASS; existing SDK tests PASS (no regression). + +Run conformance regression check (per design audit — existing consumers of `GetContractRegistry` already SERVICE-kind-filter or namespace-filter client-side): + +Run: `GOWORK=off go test -run TestPluginConformance -count=1 -timeout 300s ./cmd/wfctl/...` +Expected: PASS. -**Step 5: Commit** +**Step 5: Commit + push** ```bash git add plugin/external/sdk/iacserver.go plugin/external/sdk/iacserver_internal_test.go -git commit -m "feat(sdk): IaC bridge GetContractRegistry filters infra services (workflow#767)" +git commit -m "feat(sdk): IaC bridge GetContractRegistry filters infra services (workflow#767 Task 3)" +git push ``` **Rollback:** revert this commit — bridge returns to surfacing all registered services (current main behavior). No data migration. --- -### Task 4: Extend `wfctl plugin verify-capabilities` with directional contract-diff +### Task 4: Extend `runPluginVerifyCapabilities` with directional contract-diff **Change class:** Plugin / extension (CLI subcommand behavior change; adds new diff dimension). **Files:** -- Modify: `cmd/wfctl/plugin_verify_capabilities.go` — extend `runPluginVerifyCapabilities` after existing Name/Version diff (added by workflow#765). -- Modify: `cmd/wfctl/plugin_verify_capabilities_test.go` — add unit tests for the diff helper. +- Modify: `cmd/wfctl/plugin_verify_capabilities.go` — add `diffIaCServices` helper + extend `runPluginVerifyCapabilities` after the existing Name/Version diff at line 137. +- Modify: `cmd/wfctl/plugin_verify_capabilities_test.go` — unit tests for diff helper. -**Step 1: Write the failing tests** (pure logic; integration tests come in Task 6) +**Step 1: Write failing tests** (pure logic; integration tests in Task 5) -Append to `cmd/wfctl/plugin_verify_capabilities_test.go` (edit existing single import block to add `pb "github.com/GoCodeAlone/workflow/plugin/external/proto"` if absent): +Append to `cmd/wfctl/plugin_verify_capabilities_test.go`. Edit existing SINGLE import block to add `pb "github.com/GoCodeAlone/workflow/plugin/external/proto"` if absent. DO NOT add a second `import (...)`. ```go func TestDiffIaCServices_Match(t *testing.T) { - declared := []string{"workflow.plugin.external.iac.IaCProviderRequired"} - advertised := []string{"workflow.plugin.external.iac.IaCProviderRequired"} - missing, extra := diffIaCServices(declared, advertised) - if len(missing) != 0 || len(extra) != 0 { - t.Errorf("want clean match; got missing=%v extra=%v", missing, extra) - } + missing, extra := diffIaCServices( + []string{"workflow.plugin.external.iac.IaCProviderRequired"}, + []string{"workflow.plugin.external.iac.IaCProviderRequired"}) + if len(missing) != 0 || len(extra) != 0 { t.Errorf("missing=%v extra=%v", missing, extra) } } func TestDiffIaCServices_MissingFromBinary(t *testing.T) { @@ -388,21 +369,17 @@ func TestDiffIaCServices_MissingFromBinary(t *testing.T) { if len(missing) != 1 || missing[0] != "workflow.plugin.external.iac.IaCProviderFinalizer" { t.Errorf("want Finalizer missing; got %v", missing) } - if len(extra) != 0 { - t.Errorf("want no extras; got %v", extra) - } + if len(extra) != 0 { t.Errorf("want no extras; got %v", extra) } } func TestDiffIaCServices_ExtraInBinary(t *testing.T) { - declared := []string{"workflow.plugin.external.iac.IaCProviderRequired"} - advertised := []string{ - "workflow.plugin.external.iac.IaCProviderRequired", - "workflow.plugin.external.iac.IaCProviderFinalizer", - } - missing, extra := diffIaCServices(declared, advertised) - if len(missing) != 0 { - t.Errorf("want no missing; got %v", missing) - } + missing, extra := diffIaCServices( + []string{"workflow.plugin.external.iac.IaCProviderRequired"}, + []string{ + "workflow.plugin.external.iac.IaCProviderRequired", + "workflow.plugin.external.iac.IaCProviderFinalizer", + }) + if len(missing) != 0 { t.Errorf("missing=%v", missing) } if len(extra) != 1 || extra[0] != "workflow.plugin.external.iac.IaCProviderFinalizer" { t.Errorf("want Finalizer extra; got %v", extra) } @@ -410,52 +387,41 @@ func TestDiffIaCServices_ExtraInBinary(t *testing.T) { func TestDiffIaCServices_EmptyDeclared_SkipsDiff(t *testing.T) { missing, extra := diffIaCServices(nil, []string{"workflow.plugin.external.iac.IaCProviderRequired"}) - if missing != nil || extra != nil { - t.Errorf("empty LHS should skip diff entirely; got missing=%v extra=%v", missing, extra) - } + if missing != nil || extra != nil { t.Errorf("empty LHS should skip; got missing=%v extra=%v", missing, extra) } } ``` **Step 2: Run tests — verify FAIL** Run: `GOWORK=off go test -run TestDiffIaCServices -count=1 ./cmd/wfctl/...` -Expected: FAIL with `undefined: diffIaCServices`. +Expected: FAIL `undefined: diffIaCServices`. -**Step 3: Implement** the diff function + wire into runPluginVerifyCapabilities +**Step 3: Implement diff helper + wire into runPluginVerifyCapabilities** In `cmd/wfctl/plugin_verify_capabilities.go`: -A. Add `diffIaCServices` helper at end of file: +A. Edit existing single import block. Add: `"sort"`, `"google.golang.org/grpc/codes"`, `"google.golang.org/grpc/status"`. **DO NOT add a second `import (...)` declaration.** + +B. Append at end of file (after `preflightBinary`): ```go -// diffIaCServices computes set-difference of declared (plugin.json.iacServices) -// vs advertised (binary's filtered ContractRegistry). +// diffIaCServices computes directional set-difference of declared +// (plugin.json.iacServices) vs advertised (binary's filtered ContractRegistry). // Returns (missing, extra) where: -// - missing: declared but not advertised (FAIL — truth-loop bug). -// - extra: advertised but not declared (WARN — additive; doc-lag, not runtime defect). -// If declared is empty, returns (nil, nil) — caller must skip the diff -// entirely (non-IaC plugins, or IaC plugins not yet swept). +// - missing: declared but not advertised → caller emits FAIL (truth-loop bug). +// - extra: advertised but not declared → caller emits WARN (additive doc-lag). +// Empty declared returns (nil, nil) → caller must skip the diff entirely. func diffIaCServices(declared, advertised []string) (missing, extra []string) { - if len(declared) == 0 { - return nil, nil - } + if len(declared) == 0 { return nil, nil } declSet := make(map[string]bool, len(declared)) - for _, s := range declared { - declSet[s] = true - } + for _, s := range declared { declSet[s] = true } advSet := make(map[string]bool, len(advertised)) - for _, s := range advertised { - advSet[s] = true - } + for _, s := range advertised { advSet[s] = true } for _, s := range declared { - if !advSet[s] { - missing = append(missing, s) - } + if !advSet[s] { missing = append(missing, s) } } for _, s := range advertised { - if !declSet[s] { - extra = append(extra, s) - } + if !declSet[s] { extra = append(extra, s) } } sort.Strings(missing) sort.Strings(extra) @@ -463,39 +429,39 @@ func diffIaCServices(declared, advertised []string) (missing, extra []string) { } ``` -Add `"sort"` to the existing import block. - -B. After the existing Name/Version diff block in `runPluginVerifyCapabilities` (just before the `if len(failures) > 0 { ... }` summary), add: +C. In `runPluginVerifyCapabilities`, AFTER the existing Name/Version diff (after the `failures` slice is populated but BEFORE the `if len(failures) > 0` summary block, which is currently at line 143), insert: ```go -// Contract-diff (workflow#767). Surface ContractRegistryError verbatim -// first — non-Unimplemented RPC failures during adapter construction -// would otherwise emit synthetic "missing service" FAILs that mask the -// real cause. -if regErr := adapter.ContractRegistryError(); regErr != nil { - return fmt.Errorf("plugin GetContractRegistry: %w (stderr: %s)", regErr, stderr.String()) -} -advertisedServices := registeredIaCServiceNames(adapter.ContractRegistry()) -missingSvc, extraSvc := diffIaCServices(declared.IaCServices, advertisedServices) -for _, s := range missingSvc { - failures = append(failures, fmt.Sprintf("iacServices: plugin.json declares %q but binary does not advertise it", s)) -} -for _, s := range extraSvc { - // WARN, not FAIL — directional diff per design §3. - fmt.Fprintf(os.Stderr, "WARN %s: binary advertises %q not in plugin.json.iacServices (additive — consider updating plugin.json)\n", declared.Name, s) -} + // Contract-diff (workflow#767). One new RPC after GetManifest. + contractReg, regErr := pbClient.GetContractRegistry(ctx, &emptypb.Empty{}) + switch { + case regErr != nil && status.Code(regErr) == codes.Unimplemented: + // Empty registry semantics — skip-if-LHS-empty handles non-IaC plugins; + // non-empty plugin.json.iacServices → directional diff FAILs every + // declared service (correct: plugin advertises nothing). + contractReg = nil + case regErr != nil: + return fmt.Errorf("GetContractRegistry RPC: %w (stderr: %s)", regErr, stderr.String()) + } + advertisedServices := registeredIaCServices(contractReg) + missingSvc, extraSvc := diffIaCServices(declared.IaCServices, advertisedServices) + for _, s := range missingSvc { + failures = append(failures, fmt.Sprintf("iacServices: plugin.json declares %q but binary does not advertise it", s)) + } + for _, s := range extraSvc { + // WARN, not FAIL — directional diff per design §3. + fmt.Fprintf(os.Stderr, "WARN %s: binary advertises %q not in plugin.json.iacServices (additive — consider updating plugin.json)\n", declared.Name, s) + } ``` -C. Add `registeredIaCServiceNames` helper at end of file (single-line wrapper over the SHARED helper from Task 5 — see Task 5 for the shared `registeredIaCServices` factor-out): +D. Add a small helper `registeredIaCServices` adapter at end of file (returns SERVICE-kind names from a ContractRegistry, sorted): ```go -// registeredIaCServiceNames returns the SERVICE-kind contract names from -// reg (already-filtered by namespace prefix at the SDK bridge — see -// plugin/external/sdk/iacserver.go GetContractRegistry). Sorted. -func registeredIaCServiceNames(reg *pb.ContractRegistry) []string { - if reg == nil { - return nil - } +// registeredIaCServices returns SERVICE-kind contract names from reg +// (already-filtered by namespace prefix at the SDK bridge per Task 3). +// Returns nil for nil reg. +func registeredIaCServices(reg *pb.ContractRegistry) []string { + if reg == nil { return nil } names := make([]string, 0, len(reg.Contracts)) for _, c := range reg.Contracts { if c.GetKind() == pb.ContractKind_CONTRACT_KIND_SERVICE { @@ -507,47 +473,38 @@ func registeredIaCServiceNames(reg *pb.ContractRegistry) []string { } ``` -Note: variable `adapter`, `stderr`, `declared`, `failures` are defined earlier in `runPluginVerifyCapabilities` by workflow#765 — verify their names match before applying this patch (they should per #765 final design). +(Note: there is an existing `registeredIaCServices` in `deploy_providers.go:324` that returns `map[string]bool`. The two have different return types; this file's helper has different shape and is local to verify-capabilities. Per design's "no refactor needed" decision, do NOT consolidate — accept the local helper.) -**Step 4: Run tests — verify PASS** +**Step 4: Run unit tests — verify PASS** Run: `GOWORK=off go test -run "TestDiffIaCServices|TestVerifyCapabilities" -count=1 ./cmd/wfctl/...` -Expected: 4 new diff unit tests PASS; existing verify-capabilities tests still PASS (regression check). +Expected: 4 diff unit tests PASS + existing verify-capabilities tests PASS (regression check). -Also run: `GOWORK=off go build ./...` — expect exit 0. +Build verify: `GOWORK=off go build ./...` exit 0. -**Step 5: Commit** +**Step 5: Commit + push** ```bash git add cmd/wfctl/plugin_verify_capabilities.go cmd/wfctl/plugin_verify_capabilities_test.go -git commit -m "feat(wfctl): verify-capabilities contract-diff (directional FAIL/WARN) (workflow#767)" +git commit -m "feat(wfctl): verify-capabilities contract-diff (directional FAIL/WARN) (workflow#767 Task 4)" +git push ``` ---- - -### Task 5: (Optional — defer per cycle-3 reviewer Option B) reuse `registeredIaCServices` precedent - -**Change class:** Internal logic refactor (move + import-friendly factor; behavior unchanged). - -**Status:** Per cycle-3 adversarial reviewer Option B (`don't nitpick`), this task is **DEFERRED to follow-up**. The shared helper rename/move provides no behavior change; current Task 4 uses a local `registeredIaCServiceNames` wrapper that's structurally identical to `registeredIaCServices` in `deploy_providers.go:344`. If a third caller appears, factor at that point. For now, the duplication is ≤20 LOC and the names differ enough (existing returns map[string]bool, new returns []string sorted) that conflating them in this PR would add a refactor blast radius beyond scope. - -**Note**: Task 5 retained as a placeholder so PR Grouping table's task count matches the body's task headings (alignment-check enforces this). Empty task → zero-diff commit avoided by combining with Task 4 commit message footer instead. **Implementer: skip this task entirely.** The Scope Manifest's "Tasks: 6" remains accurate because Task 5 is a documented no-op acknowledged in the design's "Simpler alternative not considered" finding. - -Actually — to keep Tasks-N matching ### headings cleanly: this task IS the no-op acknowledgement. Implementer does NOT create a commit for it. +**Rollback:** revert this commit + Task 3 — verify-capabilities returns to Name/Version diff only; bridge returns to unfiltered. --- -### Task 6: Integration tests — 3 IaC fixture scenarios +### Task 5: Integration tests — 3 IaC fixture scenarios end-to-end -**Change class:** Plugin / extension (exercise spawn + RPC + diff against real fixture binaries). +**Change class:** Plugin / extension. **Files:** - Create: `cmd/wfctl/testdata/verify_capabilities/iac-good/{plugin.json,main.go,go.mod,go.sum}` - Create: `cmd/wfctl/testdata/verify_capabilities/iac-missing-service/{plugin.json,main.go,go.mod,go.sum}` - Create: `cmd/wfctl/testdata/verify_capabilities/iac-extra-service/{plugin.json,main.go,go.mod,go.sum}` -- Modify: `cmd/wfctl/plugin_verify_capabilities_test.go` — add 3 integration test functions reusing existing `buildFixtureBinaryForVerify` helper from #765. +- Modify: `cmd/wfctl/plugin_verify_capabilities_test.go` — 3 integration test functions reusing existing `buildFixtureBinaryForVerify` helper from #765. -**Step 1: Generate fixtures via helper script** (one-off, not committed) +**Step 1: Generate fixtures** (one-off script) Save as `/tmp/gen-iac-fixtures.sh`: @@ -555,26 +512,8 @@ Save as `/tmp/gen-iac-fixtures.sh`: #!/bin/bash set -euo pipefail BASE=cmd/wfctl/testdata/verify_capabilities - mkdir -p "$BASE/iac-good" "$BASE/iac-missing-service" "$BASE/iac-extra-service" -# Shared go.mod template (relative replace; per-fixture module name only). -mkmod() { - local d="$1" mod="$2" - cat > "$d/go.mod" < ../../../../.. -MOD -} - -# Shared main.go for IaC plugins — IaCProviderRequired methods all return Unimplemented -# (only registration matters for the diff). Optional services determined by IMPLEMENT_OPT env-like build tag. - # iac-good: implements Required + Finalizer; plugin.json declares both. cat > "$BASE/iac-good/plugin.json" <<'JSON' { @@ -623,10 +562,17 @@ func main() { }) } GO -mkmod "$BASE/iac-good" iac-good +cat > "$BASE/iac-good/go.mod" <<'MOD' +module github.com/test/iac-good + +go 1.26.0 + +require github.com/GoCodeAlone/workflow v0.63.2 + +replace github.com/GoCodeAlone/workflow => ../../../../.. +MOD -# iac-missing-service: implements Required ONLY; plugin.json declares Required + Finalizer -# → diff fires FAIL on Finalizer (missing-from-binary). +# iac-missing-service: implements Required ONLY; declares both → FAIL on Finalizer cat > "$BASE/iac-missing-service/plugin.json" <<'JSON' { "name": "verify-iac-missing", @@ -654,8 +600,8 @@ var Version = "dev" type fixture struct { pb.UnimplementedIaCProviderRequiredServer - // Note: does NOT embed IaCProviderFinalizerServer — type-assertion in - // iacserver.go:178-180 will skip the optional registration. + // Does NOT embed IaCProviderFinalizerServer — type-assertion in + // sdk.ServeIaCPlugin skips the optional Finalizer registration. } func (fixture) Name(context.Context, *pb.NameRequest) (*pb.NameResponse, error) { @@ -668,10 +614,17 @@ func main() { }) } GO -mkmod "$BASE/iac-missing-service" iac-missing-service +cat > "$BASE/iac-missing-service/go.mod" <<'MOD' +module github.com/test/iac-missing-service + +go 1.26.0 + +require github.com/GoCodeAlone/workflow v0.63.2 -# iac-extra-service: implements Required + Finalizer; plugin.json declares Required ONLY -# → diff fires WARN on Finalizer (extra-in-binary; exit 0). +replace github.com/GoCodeAlone/workflow => ../../../../.. +MOD + +# iac-extra-service: implements both; declares only Required → WARN on Finalizer cat > "$BASE/iac-extra-service/plugin.json" <<'JSON' { "name": "verify-iac-extra", @@ -718,10 +671,18 @@ func main() { }) } GO -mkmod "$BASE/iac-extra-service" iac-extra-service +cat > "$BASE/iac-extra-service/go.mod" <<'MOD' +module github.com/test/iac-extra-service + +go 1.26.0 + +require github.com/GoCodeAlone/workflow v0.63.2 + +replace github.com/GoCodeAlone/workflow => ../../../../.. +MOD ``` -**Step 2: Generate + tidy + verify each fixture builds** +**Step 2: Generate + tidy + standalone-build verify** ```bash bash /tmp/gen-iac-fixtures.sh @@ -732,9 +693,9 @@ done ``` Expected: all 3 print `ok`. -**Step 3: Write the integration tests** +**Step 3: Write integration tests** -Append to `cmd/wfctl/plugin_verify_capabilities_test.go`: +Append to `cmd/wfctl/plugin_verify_capabilities_test.go` (DO NOT add a second `import (...)` declaration — existing block already has needed imports): ```go func TestVerifyCapabilities_IaCGood(t *testing.T) { @@ -747,9 +708,7 @@ func TestVerifyCapabilities_IaCGood(t *testing.T) { func TestVerifyCapabilities_IaCMissingService(t *testing.T) { bin := buildFixtureBinaryForVerify(t, "iac-missing-service", "v0.1.0") err := runPluginVerifyCapabilities([]string{"--binary", bin, "testdata/verify_capabilities/iac-missing-service"}) - if err == nil { - t.Fatal("want FAIL on missing Finalizer service, got nil") - } + if err == nil { t.Fatal("want FAIL on missing Finalizer, got nil") } if !strings.Contains(err.Error(), "iacServices:") { t.Errorf("want iacServices: error, got: %v", err) } @@ -770,57 +729,54 @@ func TestVerifyCapabilities_IaCExtraService(t *testing.T) { **Step 4: Run integration tests — verify PASS** Run: `GOWORK=off go test -run TestVerifyCapabilities_IaC -count=1 -timeout 180s ./cmd/wfctl/...` -Expected: 3 IaC scenario tests PASS. +Expected: 3 scenario tests PASS. -Also run full verify-capabilities suite (regression check): `GOWORK=off go test -run TestVerifyCapabilities -count=1 -timeout 180s ./cmd/wfctl/...` — expect ALL tests PASS (5 from #765 + 4 diff unit tests from Task 4 + 3 IaC integration tests from this task = 12). +Full regression: `GOWORK=off go test -count=1 -timeout 300s ./cmd/wfctl/...` — expect all PASS. -**Step 5: Commit** +**Step 5: Commit + push** ```bash git add cmd/wfctl/testdata/verify_capabilities/iac-good cmd/wfctl/testdata/verify_capabilities/iac-missing-service cmd/wfctl/testdata/verify_capabilities/iac-extra-service cmd/wfctl/plugin_verify_capabilities_test.go -git commit -m "test(wfctl): 3 IaC integration fixture scenarios (workflow#767)" +git commit -m "test(wfctl): 3 IaC integration fixture scenarios (workflow#767 Task 5)" +git push ``` -**Rollback:** revert this commit + the Task 4 commit — verify-capabilities returns to Name+Version diff only. +**Rollback:** revert this commit + Task 4 + Task 3 — full revert of contract-diff path; verify-capabilities returns to Name/Version diff only. --- -## Final verification (post-Task-6) - -Before opening the PR: +## Final verification (post-Task-5) ```bash # 1. All tests pass -GOWORK=off go test -count=1 -timeout 180s ./... +GOWORK=off go test -count=1 -timeout 300s ./... # 2. Lint clean GOWORK=off go vet ./... -GOWORK=off golangci-lint run +GOWORK=off golangci-lint run ./cmd/wfctl/... ./plugin/... -# 3. wfctl --help still works (regression check on top-level help) +# 3. wfctl help correct GOWORK=off go build -o /tmp/wfctl ./cmd/wfctl && /tmp/wfctl plugin verify-capabilities --help -# 4. Conformance regression still passes (we DID touch sdk/iacserver.go in Task 3) +# 4. Conformance regression — Task 3 touched sdk/iacserver.go GOWORK=off go test -run TestPluginConformance -count=1 -timeout 300s ./cmd/wfctl/... -# 5. SDK unit tests pass (Task 3 + Task 2 surface) +# 5. SDK unit tests pass GOWORK=off go test -count=1 ./plugin/external/sdk/... ``` ## Rollback -This PR adds a manifest field, an SDK helper, an SDK bridge filter change, and a wfctl subcommand extension. Rollback path: - -- `git revert ` reverts all 6 commits cleanly. Sweep-target plugin.json files (separate PRs) become inert — older wfctl ignores the unknown field per `encoding/json` default (no `DisallowUnknownFields`). -- **Bridge filter rollback (Task 3)**: pre-change behavior surfaced all gRPC services including infra. Reverting restores the noisy registry — downstream consumers (deploy_providers, conformance) handle noise via their own filters today, so no regression. -- **Manifest field rollback (Task 1)**: `IaCServices` field gone; existing manifests with the field load successfully (unknown field ignored). +PR adds manifest field, SDK helper, SDK bridge filter change, wfctl subcommand extension. Path: +- `git revert ` reverts all 5 commits cleanly. Plugin.json files with `iacServices` field (from any sweep PRs filed independently) continue to parse — older wfctl ignores unknown field per `encoding/json` default. +- Bridge filter rollback: pre-change surfaced all gRPC services including infra. Reverting restores noisy registry — downstream consumers (deploy_providers, conformance) handle noise via own filters today, no regression. +- Manifest field rollback: `IaCServices` gone; existing manifests with the field load fine (unknown field ignored). -Backwards-compat: PR is purely additive at the subcommand-behavior level. Older wfctl callers continue to work; new wfctl on old plugin.json (no `iacServices`) skips the diff per `diffIaCServices` empty-LHS short-circuit. +Backwards-compat: subcommand behavior is additive at the diff level. Older wfctl callers without verify-capabilities continue to work; new wfctl on old plugin.json (no `iacServices`) skips contract-diff per `diffIaCServices` empty-LHS short-circuit. -## Notes for implementer +## Implementer notes -- Worktree base assumes #765 has merged (commit `827158b5f`). If not, rebase onto current main first. -- Edit existing single `import (...)` blocks in every file — DO NOT add a second `import (...)` declaration (Go allows but `gofumpt`/`goimports`/`golangci-lint` enforce single-block). -- Fixture build pattern matches #765 (in-place `-mod=readonly` + checked-in go.sum + relative `replace` + GOWORK=off). -- Task 5 is intentionally a no-op acknowledgement; do NOT create a commit for it (the alignment-check + scope-lock manifest count is preserved via the body heading only). -- After Task 6 commits, run `bash tests/plan-scope-check.sh --plan ` if the harness asks — expected PASS. +- **PUSH AFTER EACH COMMIT** per #765 squash-merge debacle lesson. Verify `git log origin/feat/767-contract-diff..HEAD` is empty before opening PR. +- Edit existing SINGLE `import (...)` blocks; never add a second `import (...)` declaration. +- Worktree is rebased onto current main (HEAD f43420535 from #771 merge). All shipped #765 verify-capabilities code is present. +- Task 4's local `registeredIaCServices` helper has different return type than the existing `deploy_providers.go:324` helper of the same name — both coexist in `package main` (function-scoped lookups distinguish; Go allows same name in different files of same package only with different signatures — VERIFY no clash; if Go complains, rename the new helper to `serviceNamesFromRegistry` or similar). From c00929a7c431a56eab1a797ec9356de0b62ebc19 Mon Sep 17 00:00:00 2001 From: Jon Langevin Date: Sun, 24 May 2026 09:14:47 -0400 Subject: [PATCH 08/16] =?UTF-8?q?docs(plan):=20#767=20plan=20cycle=202=20?= =?UTF-8?q?=E2=80=94=20fix=202=20critical=20+=202=20important=20+=203=20mi?= =?UTF-8?q?nor=20from=20adversarial=20cycle=201?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Critical: registeredIaCServices→serviceNamesFromRegistry unconditional rename; commit go.sum in Task 5 fixtures. Important: client-side namespace filter (defense-in-depth); dedup test for both-top-and-nested. Minors: dead Finalize methods removed; per-task rollback notes → PR-level revert. --- docs/plans/2026-05-24-contract-diff.md | 108 +++++++++++++++++-------- 1 file changed, 75 insertions(+), 33 deletions(-) diff --git a/docs/plans/2026-05-24-contract-diff.md b/docs/plans/2026-05-24-contract-diff.md index 054cf930..6bb967ea 100644 --- a/docs/plans/2026-05-24-contract-diff.md +++ b/docs/plans/2026-05-24-contract-diff.md @@ -70,6 +70,16 @@ func TestPluginManifest_IaCServices_NestedPromotion(t *testing.T) { } } +// Adversarial cycle 1 finding: cover dedup when both top-level AND nested are present. +func TestPluginManifest_IaCServices_DeduplicatesAcrossTopLevelAndNested(t *testing.T) { + const j = `{"name":"x","version":"1.0.0","author":"a","description":"d","iacServices":["workflow.plugin.external.iac.IaCProviderRequired"],"capabilities":{"iacServices":["workflow.plugin.external.iac.IaCProviderRequired","workflow.plugin.external.iac.IaCProviderFinalizer"]}}` + var m PluginManifest + if err := json.Unmarshal([]byte(j), &m); err != nil { t.Fatal(err) } + if len(m.IaCServices) != 2 { + t.Errorf("IaCServices = %v, want 2 deduped entries (appendUnique merge)", m.IaCServices) + } +} + func TestPluginManifest_IaCServices_OmitWhenEmpty(t *testing.T) { m := PluginManifest{Name: "x", Version: "1.0.0", Author: "a", Description: "d"} b, _ := json.Marshal(m) @@ -335,7 +345,7 @@ git commit -m "feat(sdk): IaC bridge GetContractRegistry filters infra services git push ``` -**Rollback:** revert this commit — bridge returns to surfacing all registered services (current main behavior). No data migration. +**Rollback:** see PR-level rollback section. Post-merge squash, this task is not independently revertable — `git revert ` reverts all 5 commits atomically. --- @@ -443,7 +453,12 @@ C. In `runPluginVerifyCapabilities`, AFTER the existing Name/Version diff (after case regErr != nil: return fmt.Errorf("GetContractRegistry RPC: %w (stderr: %s)", regErr, stderr.String()) } - advertisedServices := registeredIaCServices(contractReg) + // Defense-in-depth: client-side namespace filter (design §2). Old-SDK + // plugin binaries (pre-Task-3 bridge) return ALL gRPC services including + // PluginService + health — without this filter, every infra service would + // WARN-spam as "extra in plugin.json" for any unrebased plugin. + iacPrefix := strings.TrimSuffix(pb.IaCProviderRequired_ServiceDesc.ServiceName, ".IaCProviderRequired") + "." + advertisedServices := serviceNamesFromRegistry(contractReg, iacPrefix) missingSvc, extraSvc := diffIaCServices(declared.IaCServices, advertisedServices) for _, s := range missingSvc { failures = append(failures, fmt.Sprintf("iacServices: plugin.json declares %q but binary does not advertise it", s)) @@ -454,26 +469,28 @@ C. In `runPluginVerifyCapabilities`, AFTER the existing Name/Version diff (after } ``` -D. Add a small helper `registeredIaCServices` adapter at end of file (returns SERVICE-kind names from a ContractRegistry, sorted): +D. Add a small helper `serviceNamesFromRegistry` adapter at end of file (returns SERVICE-kind names from a ContractRegistry, filtered by namespace prefix, sorted): ```go -// registeredIaCServices returns SERVICE-kind contract names from reg -// (already-filtered by namespace prefix at the SDK bridge per Task 3). -// Returns nil for nil reg. -func registeredIaCServices(reg *pb.ContractRegistry) []string { +// serviceNamesFromRegistry returns SERVICE-kind contract names from reg +// whose ServiceName starts with namespacePrefix. Defense-in-depth: the SDK +// bridge (Task 3) also filters, but old-SDK plugins skip that filter — this +// client-side check prevents WARN-spam for unrebased plugin binaries. +// Returns nil for nil reg. Sorted for stable diff output. +func serviceNamesFromRegistry(reg *pb.ContractRegistry, namespacePrefix string) []string { if reg == nil { return nil } names := make([]string, 0, len(reg.Contracts)) for _, c := range reg.Contracts { - if c.GetKind() == pb.ContractKind_CONTRACT_KIND_SERVICE { - names = append(names, c.GetServiceName()) - } + if c.GetKind() != pb.ContractKind_CONTRACT_KIND_SERVICE { continue } + if !strings.HasPrefix(c.GetServiceName(), namespacePrefix) { continue } + names = append(names, c.GetServiceName()) } sort.Strings(names) return names } ``` -(Note: there is an existing `registeredIaCServices` in `deploy_providers.go:324` that returns `map[string]bool`. The two have different return types; this file's helper has different shape and is local to verify-capabilities. Per design's "no refactor needed" decision, do NOT consolidate — accept the local helper.) +(Naming note: there is an existing `registeredIaCServices` in `deploy_providers.go:350` returning `map[string]bool`. Go forbids two top-level funcs with the same name in the same `package main` regardless of signature — this would be a hard compile error. The new helper is named `serviceNamesFromRegistry` from the start to avoid the clash, per adversarial cycle 1 Critical finding.) **Step 4: Run unit tests — verify PASS** @@ -490,7 +507,7 @@ git commit -m "feat(wfctl): verify-capabilities contract-diff (directional FAIL/ git push ``` -**Rollback:** revert this commit + Task 3 — verify-capabilities returns to Name/Version diff only; bridge returns to unfiltered. +**Rollback:** see PR-level rollback section. Post-merge squash, this task is not independently revertable — `git revert ` reverts all 5 commits atomically. --- @@ -536,13 +553,11 @@ import ( pb "github.com/GoCodeAlone/workflow/plugin/external/proto" sdk "github.com/GoCodeAlone/workflow/plugin/external/sdk" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - "google.golang.org/protobuf/types/known/emptypb" ) var Version = "dev" +// FinalizeApply satisfied by embedded UnimplementedIaCProviderFinalizerServer. type fixture struct { pb.UnimplementedIaCProviderRequiredServer pb.UnimplementedIaCProviderFinalizerServer @@ -552,10 +567,6 @@ func (fixture) Name(context.Context, *pb.NameRequest) (*pb.NameResponse, error) return &pb.NameResponse{Name: "verify-iac-good"}, nil } -func (fixture) Finalize(context.Context, *emptypb.Empty) (*emptypb.Empty, error) { - return nil, status.Errorf(codes.Unimplemented, "test fixture") -} - func main() { sdk.ServeIaCPlugin(fixture{}, sdk.IaCServeOptions{ BuildVersion: sdk.ResolveBuildVersion(Version), @@ -645,13 +656,11 @@ import ( pb "github.com/GoCodeAlone/workflow/plugin/external/proto" sdk "github.com/GoCodeAlone/workflow/plugin/external/sdk" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - "google.golang.org/protobuf/types/known/emptypb" ) var Version = "dev" +// FinalizeApply satisfied by embedded UnimplementedIaCProviderFinalizerServer. type fixture struct { pb.UnimplementedIaCProviderRequiredServer pb.UnimplementedIaCProviderFinalizerServer @@ -661,10 +670,6 @@ func (fixture) Name(context.Context, *pb.NameRequest) (*pb.NameResponse, error) return &pb.NameResponse{Name: "verify-iac-extra"}, nil } -func (fixture) Finalize(context.Context, *emptypb.Empty) (*emptypb.Empty, error) { - return nil, status.Errorf(codes.Unimplemented, "test fixture") -} - func main() { sdk.ServeIaCPlugin(fixture{}, sdk.IaCServeOptions{ BuildVersion: sdk.ResolveBuildVersion(Version), @@ -682,16 +687,18 @@ replace github.com/GoCodeAlone/workflow => ../../../../.. MOD ``` -**Step 2: Generate + tidy + standalone-build verify** +**Step 2: Generate + tidy + standalone-build verify** (`go.sum` MUST be committed — `buildFixtureBinaryForVerify` uses `-mod=readonly` which fails when `go.sum` is absent) ```bash bash /tmp/gen-iac-fixtures.sh for d in cmd/wfctl/testdata/verify_capabilities/iac-*/; do + # go mod tidy generates go.sum — REQUIRED for -mod=readonly fixture builds (cd "$d" && GOWORK=off go mod tidy) (cd "$d" && GOWORK=off go build -mod=readonly -o /tmp/p .) && echo "$d: ok" || { echo "$d: FAIL"; exit 1; } + test -f "$d/go.sum" || { echo "$d: go.sum MISSING — fixture will fail CI"; exit 1; } done ``` -Expected: all 3 print `ok`. +Expected: all 3 print `ok`; all 3 have committed `go.sum` after the for-loop. **Step 3: Write integration tests** @@ -736,12 +743,21 @@ Full regression: `GOWORK=off go test -count=1 -timeout 300s ./cmd/wfctl/...` — **Step 5: Commit + push** ```bash -git add cmd/wfctl/testdata/verify_capabilities/iac-good cmd/wfctl/testdata/verify_capabilities/iac-missing-service cmd/wfctl/testdata/verify_capabilities/iac-extra-service cmd/wfctl/plugin_verify_capabilities_test.go +# Recursive add ensures plugin.json, main.go, go.mod, AND go.sum are all staged. +git add cmd/wfctl/testdata/verify_capabilities/iac-good/ \ + cmd/wfctl/testdata/verify_capabilities/iac-missing-service/ \ + cmd/wfctl/testdata/verify_capabilities/iac-extra-service/ \ + cmd/wfctl/plugin_verify_capabilities_test.go +# Sanity check: each fixture must have 4 files including go.sum. +for d in cmd/wfctl/testdata/verify_capabilities/iac-*/; do + test -f "$d/go.sum" || { echo "$d/go.sum NOT STAGED"; exit 1; } +done +git status --short cmd/wfctl/testdata/verify_capabilities/iac-* git commit -m "test(wfctl): 3 IaC integration fixture scenarios (workflow#767 Task 5)" git push ``` -**Rollback:** revert this commit + Task 4 + Task 3 — full revert of contract-diff path; verify-capabilities returns to Name/Version diff only. +**Rollback:** see PR-level rollback section. Post-merge squash, this task is not independently revertable — `git revert ` reverts all 5 commits atomically. --- @@ -755,8 +771,20 @@ GOWORK=off go test -count=1 -timeout 300s ./... GOWORK=off go vet ./... GOWORK=off golangci-lint run ./cmd/wfctl/... ./plugin/... -# 3. wfctl help correct -GOWORK=off go build -o /tmp/wfctl ./cmd/wfctl && /tmp/wfctl plugin verify-capabilities --help +# 3. wfctl help + representative end-to-end invocations (per CLI-command verification class) +GOWORK=off go build -o /tmp/wfctl ./cmd/wfctl +/tmp/wfctl plugin verify-capabilities --help + +# 3a. Build iac-good fixture binary + verify PASS path +(cd cmd/wfctl/testdata/verify_capabilities/iac-good && GOWORK=off go build -mod=readonly -o /tmp/iac-good .) +/tmp/wfctl plugin verify-capabilities --binary /tmp/iac-good cmd/wfctl/testdata/verify_capabilities/iac-good +# Expected: exit 0, stdout begins with "OK verify-iac-good" + +# 3b. Build iac-missing-service fixture + verify FAIL path with iacServices: marker +(cd cmd/wfctl/testdata/verify_capabilities/iac-missing-service && GOWORK=off go build -mod=readonly -o /tmp/iac-missing .) +/tmp/wfctl plugin verify-capabilities --binary /tmp/iac-missing cmd/wfctl/testdata/verify_capabilities/iac-missing-service 2>&1 | tee /tmp/verify-missing.out +test $? -ne 0 && grep -q "iacServices:" /tmp/verify-missing.out && grep -q "IaCProviderFinalizer" /tmp/verify-missing.out +# Expected: non-zero exit, stderr contains both "iacServices:" and "IaCProviderFinalizer" # 4. Conformance regression — Task 3 touched sdk/iacserver.go GOWORK=off go test -run TestPluginConformance -count=1 -timeout 300s ./cmd/wfctl/... @@ -779,4 +807,18 @@ Backwards-compat: subcommand behavior is additive at the diff level. Older wfctl - **PUSH AFTER EACH COMMIT** per #765 squash-merge debacle lesson. Verify `git log origin/feat/767-contract-diff..HEAD` is empty before opening PR. - Edit existing SINGLE `import (...)` blocks; never add a second `import (...)` declaration. - Worktree is rebased onto current main (HEAD f43420535 from #771 merge). All shipped #765 verify-capabilities code is present. -- Task 4's local `registeredIaCServices` helper has different return type than the existing `deploy_providers.go:324` helper of the same name — both coexist in `package main` (function-scoped lookups distinguish; Go allows same name in different files of same package only with different signatures — VERIFY no clash; if Go complains, rename the new helper to `serviceNamesFromRegistry` or similar). +- Task 4's new helper is named `serviceNamesFromRegistry` (NOT `registeredIaCServices`) because `cmd/wfctl/deploy_providers.go:350` already defines `registeredIaCServices` in `package main` — Go forbids same-name top-level functions in the same package regardless of signature. +- Task 4 helper applies BOTH a `CONTRACT_KIND_SERVICE` kind filter AND a namespace-prefix filter (defense-in-depth per design §2) so old-SDK plugin binaries don't produce WARN-spam. +- Task 5 fixtures MUST commit `go.sum` — `buildFixtureBinaryForVerify` uses `-mod=readonly` which fails when `go.sum` is absent. + +## Adversarial cycle 1 — findings resolved inline + +| Finding | Resolution | +|---|---| +| Critical: `registeredIaCServices` name clash with `deploy_providers.go:350` | Renamed new helper to `serviceNamesFromRegistry` unconditionally (Task 4 §D). | +| Critical: Task 5 fixture `go.sum` not committed → `-mod=readonly` CI fail | Added explicit `go.sum`-check in Step 2 + recursive `git add /` + sanity check in Step 5 (Task 5). | +| Important: client-side namespace filter absent (old-SDK WARN-spam) | Added `iacPrefix` derivation + `strings.HasPrefix` filter inside `serviceNamesFromRegistry` (Task 4 §C+§D). | +| Important: no dedup test for both-top-level-AND-nested manifest input | Added `TestPluginManifest_IaCServices_DeduplicatesAcrossTopLevelAndNested` (Task 1 Step 1). | +| Important: Final verification CLI subcommand needs representative invocation, not just `--help` | Added 3a (iac-good PASS path) + 3b (iac-missing-service FAIL path) in Final verification block. | +| Minor: dead `Finalize` method in 2 fixtures | Removed; `FinalizeApply` is satisfied by embedded `UnimplementedIaCProviderFinalizerServer`. | +| Minor: per-task rollback notes misleading post-merge-squash | All per-task rollbacks now point to PR-level `git revert ` as the only safe path. | From 98a4356ff05a3ead912faca29c218dc28de88413 Mon Sep 17 00:00:00 2001 From: Jon Langevin Date: Sun, 24 May 2026 09:18:58 -0400 Subject: [PATCH 09/16] =?UTF-8?q?docs(plan):=20#767=20plan=20cycle=203=20?= =?UTF-8?q?=E2=80=94=20fix=202=20critical=20from=20adversarial=20cycle=202?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit C1: iac-missing-service fixture must NOT embed UnimplementedIaCProviderFinalizerServer (Unimplemented satisfies the interface via mustEmbed sentinel → SDK registers it → false PASS). C2: bash pipeline $? reads tee exit not wfctl exit — capture WFCTL_EXIT=$? before any pipe in Final verification 3b. --- docs/plans/2026-05-24-contract-diff.md | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/docs/plans/2026-05-24-contract-diff.md b/docs/plans/2026-05-24-contract-diff.md index 6bb967ea..2c5ef40f 100644 --- a/docs/plans/2026-05-24-contract-diff.md +++ b/docs/plans/2026-05-24-contract-diff.md @@ -609,10 +609,13 @@ import ( var Version = "dev" +// CRITICAL: this struct must NOT embed pb.UnimplementedIaCProviderFinalizerServer. +// Embedding the Unimplemented type satisfies the IaCProviderFinalizerServer +// interface (via mustEmbedUnimplementedIaCProviderFinalizerServer sentinel), +// which would make sdk.ServeIaCPlugin's type-assertion succeed and REGISTER +// the Finalizer service — defeating the missing-service test scenario. type fixture struct { pb.UnimplementedIaCProviderRequiredServer - // Does NOT embed IaCProviderFinalizerServer — type-assertion in - // sdk.ServeIaCPlugin skips the optional Finalizer registration. } func (fixture) Name(context.Context, *pb.NameRequest) (*pb.NameResponse, error) { @@ -780,11 +783,15 @@ GOWORK=off go build -o /tmp/wfctl ./cmd/wfctl /tmp/wfctl plugin verify-capabilities --binary /tmp/iac-good cmd/wfctl/testdata/verify_capabilities/iac-good # Expected: exit 0, stdout begins with "OK verify-iac-good" -# 3b. Build iac-missing-service fixture + verify FAIL path with iacServices: marker +# 3b. Build iac-missing-service fixture + verify FAIL path with iacServices: marker. +# IMPORTANT: capture wfctl exit BEFORE piping — `$?` after a pipeline reads the +# last command's exit (tee, almost always 0), not wfctl's. Without this the +# FAIL-path check silently passes regardless of actual behavior. (cd cmd/wfctl/testdata/verify_capabilities/iac-missing-service && GOWORK=off go build -mod=readonly -o /tmp/iac-missing .) -/tmp/wfctl plugin verify-capabilities --binary /tmp/iac-missing cmd/wfctl/testdata/verify_capabilities/iac-missing-service 2>&1 | tee /tmp/verify-missing.out -test $? -ne 0 && grep -q "iacServices:" /tmp/verify-missing.out && grep -q "IaCProviderFinalizer" /tmp/verify-missing.out -# Expected: non-zero exit, stderr contains both "iacServices:" and "IaCProviderFinalizer" +/tmp/wfctl plugin verify-capabilities --binary /tmp/iac-missing cmd/wfctl/testdata/verify_capabilities/iac-missing-service > /tmp/verify-missing.out 2>&1 +WFCTL_EXIT=$? +test "$WFCTL_EXIT" -ne 0 && grep -q "iacServices:" /tmp/verify-missing.out && grep -q "IaCProviderFinalizer" /tmp/verify-missing.out +# Expected: WFCTL_EXIT non-zero, stderr contains both "iacServices:" and "IaCProviderFinalizer" # 4. Conformance regression — Task 3 touched sdk/iacserver.go GOWORK=off go test -run TestPluginConformance -count=1 -timeout 300s ./cmd/wfctl/... @@ -810,8 +817,9 @@ Backwards-compat: subcommand behavior is additive at the diff level. Older wfctl - Task 4's new helper is named `serviceNamesFromRegistry` (NOT `registeredIaCServices`) because `cmd/wfctl/deploy_providers.go:350` already defines `registeredIaCServices` in `package main` — Go forbids same-name top-level functions in the same package regardless of signature. - Task 4 helper applies BOTH a `CONTRACT_KIND_SERVICE` kind filter AND a namespace-prefix filter (defense-in-depth per design §2) so old-SDK plugin binaries don't produce WARN-spam. - Task 5 fixtures MUST commit `go.sum` — `buildFixtureBinaryForVerify` uses `-mod=readonly` which fails when `go.sum` is absent. +- `iac-missing-service` fixture struct MUST embed ONLY `pb.UnimplementedIaCProviderRequiredServer` — embedding the Finalizer Unimplemented type satisfies the interface via the `mustEmbed*` sentinel, causing the SDK type-assertion to register it and defeating the missing-service test scenario. -## Adversarial cycle 1 — findings resolved inline +## Adversarial cycles 1+2 — findings resolved inline | Finding | Resolution | |---|---| @@ -822,3 +830,5 @@ Backwards-compat: subcommand behavior is additive at the diff level. Older wfctl | Important: Final verification CLI subcommand needs representative invocation, not just `--help` | Added 3a (iac-good PASS path) + 3b (iac-missing-service FAIL path) in Final verification block. | | Minor: dead `Finalize` method in 2 fixtures | Removed; `FinalizeApply` is satisfied by embedded `UnimplementedIaCProviderFinalizerServer`. | | Minor: per-task rollback notes misleading post-merge-squash | All per-task rollbacks now point to PR-level `git revert ` as the only safe path. | +| **Cycle 2 Critical:** embedding `pb.UnimplementedIaCProviderFinalizerServer` in `iac-missing-service` fixture WOULD register the service (Unimplemented satisfies the interface via `mustEmbed*` sentinel) → false PASS | Removed the embed; fixture now ONLY embeds `UnimplementedIaCProviderRequiredServer`; added critical comment explaining the gRPC interface-satisfaction semantics. | +| **Cycle 2 Critical:** Final verification 3b bash pipeline `$?` reads `tee` exit not wfctl exit → smoke-test silently passes regardless of actual behavior | Restructured: redirect wfctl output to file via `>`, capture exit via `WFCTL_EXIT=$?` BEFORE any pipeline, then check both exit and grep markers. | From 62877bf73b144c76184e96342935eb22fc0214df Mon Sep 17 00:00:00 2001 From: Jon Langevin Date: Sun, 24 May 2026 09:24:29 -0400 Subject: [PATCH 10/16] =?UTF-8?q?docs(adr):=200042=20=E2=80=94=20verify-ca?= =?UTF-8?q?pabilities=20IaC=20namespace=20derivation;=20cite=20from=20desi?= =?UTF-8?q?gn=20+=20plan?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resolves alignment-check MISSING finding: design cited decisions/NNNN-verify-capabilities-iac-namespace.md but no ADR existed. ADR documents the proto-descriptor TrimSuffix single-source-of-truth pattern that Tasks 2/3/4 derive from. Design + plan both updated to cite 0042 in place of NNNN. --- .../0042-verify-capabilities-iac-namespace.md | 57 +++++++++++++++++++ docs/plans/2026-05-24-contract-diff-design.md | 2 +- docs/plans/2026-05-24-contract-diff.md | 16 ++++-- 3 files changed, 68 insertions(+), 7 deletions(-) create mode 100644 decisions/0042-verify-capabilities-iac-namespace.md diff --git a/decisions/0042-verify-capabilities-iac-namespace.md b/decisions/0042-verify-capabilities-iac-namespace.md new file mode 100644 index 00000000..02d2f0d4 --- /dev/null +++ b/decisions/0042-verify-capabilities-iac-namespace.md @@ -0,0 +1,57 @@ +# ADR 0042: verify-capabilities IaC namespace prefix — derive from proto descriptor + +**Date:** 2026-05-24 +**Status:** Accepted +**Author:** team-lead (autonomous-mode) + +## Context + +workflow#767 extends `wfctl plugin verify-capabilities` (shipped via #765/#769 at v0.63.2) with a directional diff between `plugin.json.iacServices` and the plugin binary's runtime `ContractRegistry`. The diff filters the binary's advertised services down to the IaC namespace before comparison so that go-plugin infra services (`workflow.plugin.v1.PluginService`, `grpc.health.v1.Health`, `plugin.GRPCBroker`, `plugin.GRPCStdio`) are excluded. + +The IaC namespace is needed in two places: +1. **SDK-side bridge** (`plugin/external/sdk/iacserver.go:302`) — `iacPluginServiceBridge.GetContractRegistry` filters before sending the registry over the wire. +2. **Client-side helper** (`cmd/wfctl/plugin_verify_capabilities.go`) — defense-in-depth filter so old-SDK plugin binaries (pre-bridge-rewire) don't produce WARN-spam on every infra service they register. + +We had to choose how to express the namespace string. Three options: + +1. **Hardcoded literal** — `const iacNamespacePrefix = "workflow.plugin.external.iac."` declared once in `contracts.go` and imported elsewhere. +2. **Derive from a hand-maintained list of service names** — enumerate known IaC services (`IaCProviderRequired`, `IaCProviderFinalizer`, `IaCStateBackend`) and compute their common prefix at startup. +3. **Derive from `pb.IaCProviderRequired_ServiceDesc.ServiceName`** via `strings.TrimSuffix(name, ".IaCProviderRequired") + "."` — single source of truth keyed directly to the `.proto` package declaration. + +## Decision + +Option 3. Both filter sites derive the prefix via: + +```go +prefix := strings.TrimSuffix(pb.IaCProviderRequired_ServiceDesc.ServiceName, ".IaCProviderRequired") + "." +``` + +`ServiceDesc.ServiceName` is generated by `protoc-gen-go-grpc` directly from the proto file's `package` declaration. If the proto's `package workflow.plugin.external.iac;` line is ever renamed, the generated constant moves in lockstep and both filter sites continue to work without any source change. + +## Rationale + +- **Single source of truth**: the proto file's package declaration is the canonical authoritative source. Any other location for the prefix duplicates state that can drift. +- **Compile-time coupling**: if the proto's package name changes incompatibly, the call site refers to a `ServiceDesc` symbol that may not exist; the build breaks loudly rather than silently mis-filtering at runtime. +- **No magic strings**: `iacserver.go` and `plugin_verify_capabilities.go` contain no string literals matching the namespace. Refactor tools can rename safely. +- **Survives go-plugin updates**: if a future go-plugin release adds new infra services (`plugin.GRPCStdio.v2`, etc.), the namespace-prefix filter continues to exclude them because they live outside `workflow.plugin.external.iac.*`. + +## Alternatives Rejected + +**Option 1 (hardcoded literal)** — duplicates state that already exists in the proto-generated code. A proto package rename leaves the literal stale; the binary continues to advertise `workflow.plugin.external.iac.NewName` while the wfctl client filters against the old prefix, producing silent false-negatives on every diff. Rejected as a duplicate-source-of-truth pattern. + +**Option 2 (hand-maintained list)** — adds maintenance burden: every new IaC service requires a list edit. The common-prefix calculation is also brittle if a future IaC service lives at a sub-namespace (e.g., `workflow.plugin.external.iac.v2.IaCProviderRequired`). Rejected as accidentally-complicated. + +## Consequences + +- The `pb.IaCProviderRequired_ServiceDesc.ServiceName` symbol is now load-bearing for the contract-diff path. Any proto-generation script change that strips ServiceDesc constants (e.g., a flag flip on protoc-gen-go-grpc) would break both filter sites. Documented here so the symbol shows up in grep audits of breaking-change candidates. +- The TrimSuffix derivation requires the IaC namespace to always contain `IaCProviderRequired` as a service. This is a stable design invariant: `IaCProviderRequired` is the foundational IaC service interface; removing it would require a major design redesign anyway. +- Adding a new IaC namespace (e.g., `workflow.plugin.external.iac.v2.*`) would require a new derivation site or a multi-prefix filter. Out-of-scope for #767; if v2 ships, this ADR's narrow single-namespace assumption needs revisiting. + +## Related + +- workflow#765 (verify-capabilities subcommand parent) +- workflow#767 (this PR — adds the contract-diff dimension) +- workflow#771 (sister #765 follow-up — lockfile dep tracking, shipped via #772) +- `plugin/external/proto/iac.proto` — the proto package declaration this prefix derives from +- `plugin/external/sdk/iacserver.go:302` — SDK-side filter site +- `cmd/wfctl/plugin_verify_capabilities.go` — client-side filter site (defense in depth) diff --git a/docs/plans/2026-05-24-contract-diff-design.md b/docs/plans/2026-05-24-contract-diff-design.md index b2b6b130..8162cf91 100644 --- a/docs/plans/2026-05-24-contract-diff-design.md +++ b/docs/plans/2026-05-24-contract-diff-design.md @@ -102,7 +102,7 @@ Per cycle-2 IMPORTANT-5 Option B: IaCServices INCLUDES `IaCStateBackend` (and Re ## Decisions **§1 — Namespace filter: derive vs hardcode.** -Derive from `pb.IaCProviderRequired_ServiceDesc.ServiceName` via TrimSuffix. Single source of truth keyed to the .proto package decl. Eliminates cycle-1 C1 (wrong namespace) by construction. ADR: `decisions/NNNN-verify-capabilities-iac-namespace.md`. +Derive from `pb.IaCProviderRequired_ServiceDesc.ServiceName` via TrimSuffix. Single source of truth keyed to the .proto package decl. Eliminates cycle-1 C1 (wrong namespace) by construction. ADR: `decisions/0042-verify-capabilities-iac-namespace.md`. **§2 — Server-side filter (plugin authors switch ContractRegistry impl) vs client-side filter (verify-capabilities filters).** BOTH. Server-side helper exists for plugin authors who want clean output everywhere (logs, debug RPC). Client-side filter in verify-capabilities runs regardless — plugins that haven't migrated to `BuildContractRegistryForPlugin` still get correct diff results because client-side filter handles the noise. Defense in depth. diff --git a/docs/plans/2026-05-24-contract-diff.md b/docs/plans/2026-05-24-contract-diff.md index 2c5ef40f..98ef7ef5 100644 --- a/docs/plans/2026-05-24-contract-diff.md +++ b/docs/plans/2026-05-24-contract-diff.md @@ -12,6 +12,8 @@ **Design doc:** `docs/plans/2026-05-24-contract-diff-design.md` (cycle 4 PASS adversarial). +**ADR:** [`decisions/0042-verify-capabilities-iac-namespace.md`](../../decisions/0042-verify-capabilities-iac-namespace.md) — namespace prefix derivation single-source-of-truth pattern (applies to Task 2 helper, Task 3 bridge rewire, Task 4 client filter). + **Issue:** workflow#767 --- @@ -318,8 +320,9 @@ with: ```go func (b *iacPluginServiceBridge) GetContractRegistry(_ context.Context, _ *emptypb.Empty) (*pb.ContractRegistry, error) { - // Derive prefix from canonical proto descriptor (workflow#767 §1) so the - // filter cannot drift from the .proto package declaration. + // Derive prefix from canonical proto descriptor per ADR 0042 + // (decisions/0042-verify-capabilities-iac-namespace.md) so the filter + // cannot drift from the .proto package declaration. prefix := strings.TrimSuffix(pb.IaCProviderRequired_ServiceDesc.ServiceName, ".IaCProviderRequired") + "." return BuildContractRegistryForPlugin(b.grpcSrv, prefix), nil } @@ -453,10 +456,11 @@ C. In `runPluginVerifyCapabilities`, AFTER the existing Name/Version diff (after case regErr != nil: return fmt.Errorf("GetContractRegistry RPC: %w (stderr: %s)", regErr, stderr.String()) } - // Defense-in-depth: client-side namespace filter (design §2). Old-SDK - // plugin binaries (pre-Task-3 bridge) return ALL gRPC services including - // PluginService + health — without this filter, every infra service would - // WARN-spam as "extra in plugin.json" for any unrebased plugin. + // Defense-in-depth: client-side namespace filter per ADR 0042 + // (decisions/0042-verify-capabilities-iac-namespace.md) and design §2. + // Old-SDK plugin binaries (pre-Task-3 bridge) return ALL gRPC services + // including PluginService + health — without this filter, every infra + // service would WARN-spam as "extra in plugin.json" for unrebased plugins. iacPrefix := strings.TrimSuffix(pb.IaCProviderRequired_ServiceDesc.ServiceName, ".IaCProviderRequired") + "." advertisedServices := serviceNamesFromRegistry(contractReg, iacPrefix) missingSvc, extraSvc := diffIaCServices(declared.IaCServices, advertisedServices) From 94873780cb10192527280c48c8ed8200305759ee Mon Sep 17 00:00:00 2001 From: Jon Langevin Date: Sun, 24 May 2026 09:25:49 -0400 Subject: [PATCH 11/16] chore: lock scope for #767 contract-diff (alignment passed) --- docs/plans/2026-05-24-contract-diff.md | 2 +- docs/plans/2026-05-24-contract-diff.md.scope-lock | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 docs/plans/2026-05-24-contract-diff.md.scope-lock diff --git a/docs/plans/2026-05-24-contract-diff.md b/docs/plans/2026-05-24-contract-diff.md index 98ef7ef5..dd5a39c6 100644 --- a/docs/plans/2026-05-24-contract-diff.md +++ b/docs/plans/2026-05-24-contract-diff.md @@ -39,7 +39,7 @@ |------|-------|-------|--------| | 1 | feat(sdk+wfctl): contract-diff extension for verify-capabilities (workflow#767) | Task 1, Task 2, Task 3, Task 4, Task 5 | feat/767-contract-diff | -**Status:** Draft +**Status:** Locked 2026-05-24T13:25:37Z --- diff --git a/docs/plans/2026-05-24-contract-diff.md.scope-lock b/docs/plans/2026-05-24-contract-diff.md.scope-lock new file mode 100644 index 00000000..3061ecc4 --- /dev/null +++ b/docs/plans/2026-05-24-contract-diff.md.scope-lock @@ -0,0 +1 @@ +0924488cfddf13cc3e1851c6ced824cf986da10a71bb3c11d0a45a0c5a24a3fe From 7dfbaecab56dd8f4f8dc00a26b85d52fe8ada2b2 Mon Sep 17 00:00:00 2001 From: Jon Langevin Date: Sun, 24 May 2026 09:28:36 -0400 Subject: [PATCH 12/16] feat(plugin): add IaCServices manifest field with nested-promotion (workflow#767 Task 1) --- plugin/manifest.go | 16 ++++++++++++++++ plugin/manifest_test.go | 42 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/plugin/manifest.go b/plugin/manifest.go index e2334289..7cfa88e1 100644 --- a/plugin/manifest.go +++ b/plugin/manifest.go @@ -55,6 +55,20 @@ type PluginManifest struct { // A2 (decisions/0035). IaCStateBackends []string `json:"iacStateBackends,omitempty" yaml:"iacStateBackends,omitempty"` + // IaCServices lists the typed IaC service names this plugin serves + // (fully-qualified gRPC service names, e.g. + // "workflow.plugin.external.iac.IaCProviderRequired"). Authored in + // plugin.json either as a top-level "iacServices" key OR nested under + // "capabilities.iacServices" (UnmarshalJSON's object branch promotes + // the nested form, same as IaCStateBackends). The engine cross-checks + // these against the plugin's runtime ContractRegistry via wfctl plugin + // verify-capabilities (workflow#767). + // + // Orthogonal to IaCStateBackends (which lists backend NAMES, not gRPC + // service names). A plugin that registers the IaCStateBackend service + // AND lists its backend names will appear in BOTH manifest fields. + IaCServices []string `json:"iacServices,omitempty" yaml:"iacServices,omitempty"` + // StepSchemas provides schema definitions for step types registered by this plugin. // Used by MCP/LSP for hover docs, completions, and output documentation. StepSchemas []*schema.StepSchema `json:"stepSchemas,omitempty" yaml:"stepSchemas,omitempty"` @@ -148,6 +162,7 @@ func (m *PluginManifest) UnmarshalJSON(data []byte) error { TriggerTypes []string `json:"triggerTypes"` WorkflowTypes []string `json:"workflowTypes"` IaCStateBackends []string `json:"iacStateBackends"` + IaCServices []string `json:"iacServices"` } if err := json.Unmarshal(raw.Capabilities, &legacyCaps); err != nil { return fmt.Errorf("invalid capabilities object: %w", err) @@ -157,6 +172,7 @@ func (m *PluginManifest) UnmarshalJSON(data []byte) error { m.TriggerTypes = appendUnique(m.TriggerTypes, legacyCaps.TriggerTypes...) m.WorkflowTypes = appendUnique(m.WorkflowTypes, legacyCaps.WorkflowTypes...) m.IaCStateBackends = appendUnique(m.IaCStateBackends, legacyCaps.IaCStateBackends...) + m.IaCServices = appendUnique(m.IaCServices, legacyCaps.IaCServices...) default: return fmt.Errorf("capabilities: unsupported JSON type (expected array or object, got %q)", string(raw.Capabilities)) diff --git a/plugin/manifest_test.go b/plugin/manifest_test.go index 715cdcba..7bb43811 100644 --- a/plugin/manifest_test.go +++ b/plugin/manifest_test.go @@ -598,6 +598,48 @@ func TestManifestNoIaCStateBackends(t *testing.T) { } } +func TestPluginManifest_IaCServices_TopLevel(t *testing.T) { + const j = `{"name":"x","version":"1.0.0","author":"a","description":"d","iacServices":["workflow.plugin.external.iac.IaCProviderRequired"]}` + var m PluginManifest + if err := json.Unmarshal([]byte(j), &m); err != nil { + t.Fatal(err) + } + if len(m.IaCServices) != 1 || m.IaCServices[0] != "workflow.plugin.external.iac.IaCProviderRequired" { + t.Errorf("IaCServices = %v", m.IaCServices) + } +} + +func TestPluginManifest_IaCServices_NestedPromotion(t *testing.T) { + const j = `{"name":"x","version":"1.0.0","author":"a","description":"d","capabilities":{"iacServices":["workflow.plugin.external.iac.IaCProviderRequired","workflow.plugin.external.iac.IaCProviderFinalizer"]}}` + var m PluginManifest + if err := json.Unmarshal([]byte(j), &m); err != nil { + t.Fatal(err) + } + if len(m.IaCServices) != 2 { + t.Errorf("IaCServices = %v, want 2 entries promoted from nested capabilities", m.IaCServices) + } +} + +// Adversarial cycle 1 finding: cover dedup when both top-level AND nested are present. +func TestPluginManifest_IaCServices_DeduplicatesAcrossTopLevelAndNested(t *testing.T) { + const j = `{"name":"x","version":"1.0.0","author":"a","description":"d","iacServices":["workflow.plugin.external.iac.IaCProviderRequired"],"capabilities":{"iacServices":["workflow.plugin.external.iac.IaCProviderRequired","workflow.plugin.external.iac.IaCProviderFinalizer"]}}` + var m PluginManifest + if err := json.Unmarshal([]byte(j), &m); err != nil { + t.Fatal(err) + } + if len(m.IaCServices) != 2 { + t.Errorf("IaCServices = %v, want 2 deduped entries (appendUnique merge)", m.IaCServices) + } +} + +func TestPluginManifest_IaCServices_OmitWhenEmpty(t *testing.T) { + m := PluginManifest{Name: "x", Version: "1.0.0", Author: "a", Description: "d"} + b, _ := json.Marshal(m) + if strings.Contains(string(b), "iacServices") { + t.Errorf("empty IaCServices should be omitted; got %s", b) + } +} + // TestManifestCapabilitiesInvalidFormat verifies that a plugin.json whose // "capabilities" field is neither an array nor an object (e.g. a bare string) // is rejected with a descriptive error. From a14de6ab989f92401fe565e6880eba42fd207725 Mon Sep 17 00:00:00 2001 From: Jon Langevin Date: Sun, 24 May 2026 09:29:58 -0400 Subject: [PATCH 13/16] feat(sdk): BuildContractRegistryForPlugin namespace-filtering helper (workflow#767 Task 2) --- plugin/external/sdk/contracts.go | 40 ++++++++++++++++++++++++ plugin/external/sdk/contracts_test.go | 44 +++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 plugin/external/sdk/contracts_test.go diff --git a/plugin/external/sdk/contracts.go b/plugin/external/sdk/contracts.go index b9f28989..dc8e5820 100644 --- a/plugin/external/sdk/contracts.go +++ b/plugin/external/sdk/contracts.go @@ -2,6 +2,7 @@ package sdk import ( "sort" + "strings" "google.golang.org/grpc" @@ -58,3 +59,42 @@ func BuildContractRegistry(grpcSrv *grpc.Server) *pb.ContractRegistry { } return registry } + +// BuildContractRegistryForPlugin enumerates gRPC services registered on +// grpcSrv whose name STARTS WITH namespacePrefix and returns a +// *pb.ContractRegistry with one SERVICE-kind STRICT_PROTO ContractDescriptor +// per matching service. Filters out go-plugin infra services (PluginService, +// GRPCBroker, GRPCStdio, grpc.health.v1.Health) so downstream contract-diff +// (workflow#767) sees only plugin-owned services. +// +// Safe to call with nil server; returns empty (but non-nil) registry. +// Names alphabetically sorted for stable diff output. +// +// Typical caller: iacPluginServiceBridge.GetContractRegistry derives prefix +// from pb.IaCProviderRequired_ServiceDesc.ServiceName minus the ".IaCProviderRequired" +// suffix so the filter cannot drift from the .proto package declaration. +// +// BuildContractRegistry (full-surface, no filter) is retained for callers +// that want every registered service. +func BuildContractRegistryForPlugin(grpcSrv *grpc.Server, namespacePrefix string) *pb.ContractRegistry { + registry := &pb.ContractRegistry{} + if grpcSrv == nil { + return registry + } + info := grpcSrv.GetServiceInfo() + names := make([]string, 0, len(info)) + for name := range info { + if strings.HasPrefix(name, namespacePrefix) { + names = append(names, name) + } + } + sort.Strings(names) + for _, name := range names { + registry.Contracts = append(registry.Contracts, &pb.ContractDescriptor{ + Kind: pb.ContractKind_CONTRACT_KIND_SERVICE, + ServiceName: name, + Mode: pb.ContractMode_CONTRACT_MODE_STRICT_PROTO, + }) + } + return registry +} diff --git a/plugin/external/sdk/contracts_test.go b/plugin/external/sdk/contracts_test.go new file mode 100644 index 00000000..3ee293ea --- /dev/null +++ b/plugin/external/sdk/contracts_test.go @@ -0,0 +1,44 @@ +package sdk + +import ( + "net" + "testing" + + pb "github.com/GoCodeAlone/workflow/plugin/external/proto" + "google.golang.org/grpc" +) + +func TestBuildContractRegistryForPlugin_NilServer(t *testing.T) { + reg := BuildContractRegistryForPlugin(nil, "workflow.plugin.external.iac.") + if reg == nil { + t.Fatal("want non-nil") + } + if len(reg.Contracts) != 0 { + t.Errorf("want 0 contracts; got %d", len(reg.Contracts)) + } +} + +func TestBuildContractRegistryForPlugin_FiltersByPrefix(t *testing.T) { + s := grpc.NewServer() + pb.RegisterIaCProviderRequiredServer(s, &stubIaCRequired{}) + pb.RegisterPluginServiceServer(s, &stubPluginService{}) + go func() { + l, _ := net.Listen("tcp", "127.0.0.1:0") + _ = s.Serve(l) + }() + defer s.Stop() + reg := BuildContractRegistryForPlugin(s, "workflow.plugin.external.iac.") + if len(reg.Contracts) != 1 { + t.Fatalf("want 1 contract (iac.IaCProviderRequired); got %d: %v", len(reg.Contracts), reg.Contracts) + } + if reg.Contracts[0].ServiceName != "workflow.plugin.external.iac.IaCProviderRequired" { + t.Errorf("unexpected service: %s", reg.Contracts[0].ServiceName) + } +} + +type stubIaCRequired struct { + pb.UnimplementedIaCProviderRequiredServer +} +type stubPluginService struct { + pb.UnimplementedPluginServiceServer +} From 5d87fba1145bdb0d9900e161641bf8ebc9c916ad Mon Sep 17 00:00:00 2001 From: Jon Langevin Date: Sun, 24 May 2026 09:32:18 -0400 Subject: [PATCH 14/16] feat(sdk): IaC bridge GetContractRegistry filters infra services (workflow#767 Task 3) --- plugin/external/sdk/iacserver.go | 7 ++++- .../external/sdk/iacserver_internal_test.go | 26 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/plugin/external/sdk/iacserver.go b/plugin/external/sdk/iacserver.go index 0c69cc1b..0eed44f8 100644 --- a/plugin/external/sdk/iacserver.go +++ b/plugin/external/sdk/iacserver.go @@ -5,6 +5,7 @@ import ( "fmt" "reflect" "sort" + "strings" goplugin "github.com/GoCodeAlone/go-plugin" "google.golang.org/grpc" @@ -299,7 +300,11 @@ func (b *iacPluginServiceBridge) DestroyStep(ctx context.Context, req *pb.Handle // this to gate optional typed-client construction (Enumerator, DriftDetector, // etc.) after loading an IaC plugin via discoverAndLoadIaCProvider. func (b *iacPluginServiceBridge) GetContractRegistry(_ context.Context, _ *emptypb.Empty) (*pb.ContractRegistry, error) { - return BuildContractRegistry(b.grpcSrv), nil + // Derive prefix from canonical proto descriptor per ADR 0042 + // (decisions/0042-verify-capabilities-iac-namespace.md) so the filter + // cannot drift from the .proto package declaration. + prefix := strings.TrimSuffix(pb.IaCProviderRequired_ServiceDesc.ServiceName, ".IaCProviderRequired") + "." + return BuildContractRegistryForPlugin(b.grpcSrv, prefix), nil } // GetManifest returns the disk-embedded *plugin.PluginManifest as a diff --git a/plugin/external/sdk/iacserver_internal_test.go b/plugin/external/sdk/iacserver_internal_test.go index 4cacbc16..8cc048d3 100644 --- a/plugin/external/sdk/iacserver_internal_test.go +++ b/plugin/external/sdk/iacserver_internal_test.go @@ -2,6 +2,7 @@ package sdk import ( "context" + "strings" "testing" pluginpkg "github.com/GoCodeAlone/workflow/plugin" @@ -114,3 +115,28 @@ func TestIaCBridgeGetManifest_BuildVersionOnlyNoDisk(t *testing.T) { // Compile-time guard: bridge must satisfy pb.PluginServiceServer. var _ pb.PluginServiceServer = (*iacPluginServiceBridge)(nil) + +func TestIaCBridge_ContractRegistry_FiltersInfra(t *testing.T) { + s := grpc.NewServer() + pb.RegisterIaCProviderRequiredServer(s, &stubIaCRequired{}) + pb.RegisterPluginServiceServer(s, &iacPluginServiceBridge{grpcSrv: s}) + bridge := &iacPluginServiceBridge{grpcSrv: s} + reg, err := bridge.GetContractRegistry(context.Background(), &emptypb.Empty{}) + if err != nil { + t.Fatal(err) + } + for _, c := range reg.Contracts { + if !strings.HasPrefix(c.ServiceName, "workflow.plugin.external.iac.") { + t.Errorf("bridge surfaced non-iac service %q after filter", c.ServiceName) + } + } + found := false + for _, c := range reg.Contracts { + if c.ServiceName == "workflow.plugin.external.iac.IaCProviderRequired" { + found = true + } + } + if !found { + t.Error("expected IaCProviderRequired in filtered registry") + } +} From 6031a29d9981e3b3cc4eaa89ae78e57c029a04a1 Mon Sep 17 00:00:00 2001 From: Jon Langevin Date: Sun, 24 May 2026 09:34:43 -0400 Subject: [PATCH 15/16] feat(wfctl): verify-capabilities contract-diff (directional FAIL/WARN) (workflow#767 Task 4) --- cmd/wfctl/plugin_verify_capabilities.go | 88 ++++++++++++++++++++ cmd/wfctl/plugin_verify_capabilities_test.go | 46 ++++++++++ 2 files changed, 134 insertions(+) diff --git a/cmd/wfctl/plugin_verify_capabilities.go b/cmd/wfctl/plugin_verify_capabilities.go index 68849342..ee743568 100644 --- a/cmd/wfctl/plugin_verify_capabilities.go +++ b/cmd/wfctl/plugin_verify_capabilities.go @@ -15,6 +15,7 @@ import ( "os" "os/exec" "path/filepath" + "sort" "strings" "time" @@ -23,6 +24,8 @@ import ( external "github.com/GoCodeAlone/workflow/plugin/external" pb "github.com/GoCodeAlone/workflow/plugin/external/proto" hclog "github.com/hashicorp/go-hclog" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" "google.golang.org/protobuf/types/known/emptypb" ) @@ -141,6 +144,34 @@ Options: if pass, reason := diffVersion(declared.Version, runtime.GetVersion()); !pass { failures = append(failures, "version: "+reason) } + + // Contract-diff (workflow#767). One new RPC after GetManifest. + contractReg, regErr := pbClient.GetContractRegistry(ctx, &emptypb.Empty{}) + switch { + case regErr != nil && status.Code(regErr) == codes.Unimplemented: + // Empty registry semantics — skip-if-LHS-empty handles non-IaC plugins; + // non-empty plugin.json.iacServices → directional diff FAILs every + // declared service (correct: plugin advertises nothing). + contractReg = nil + case regErr != nil: + return fmt.Errorf("GetContractRegistry RPC: %w (stderr: %s)", regErr, stderr.String()) + } + // Defense-in-depth: client-side namespace filter per ADR 0042 + // (decisions/0042-verify-capabilities-iac-namespace.md) and design §2. + // Old-SDK plugin binaries (pre-Task-3 bridge) return ALL gRPC services + // including PluginService + health — without this filter, every infra + // service would WARN-spam as "extra in plugin.json" for unrebased plugins. + iacPrefix := strings.TrimSuffix(pb.IaCProviderRequired_ServiceDesc.ServiceName, ".IaCProviderRequired") + "." + advertisedServices := serviceNamesFromRegistry(contractReg, iacPrefix) + missingSvc, extraSvc := diffIaCServices(declared.IaCServices, advertisedServices) + for _, s := range missingSvc { + failures = append(failures, fmt.Sprintf("iacServices: plugin.json declares %q but binary does not advertise it", s)) + } + for _, s := range extraSvc { + // WARN, not FAIL — directional diff per design §3. + fmt.Fprintf(os.Stderr, "WARN %s: binary advertises %q not in plugin.json.iacServices (additive — consider updating plugin.json)\n", declared.Name, s) + } + if len(failures) > 0 { fmt.Fprintf(os.Stderr, "FAIL %s (plugin.json)\nerror: %d mismatch(es)\n", declared.Name, len(failures)) for _, f := range failures { @@ -178,6 +209,63 @@ func preflightBinary(path string) error { return nil } +// diffIaCServices computes directional set-difference of declared +// (plugin.json.iacServices) vs advertised (binary's filtered ContractRegistry). +// Returns (missing, extra) where: +// - missing: declared but not advertised → caller emits FAIL (truth-loop bug). +// - extra: advertised but not declared → caller emits WARN (additive doc-lag). +// +// Empty declared returns (nil, nil) → caller must skip the diff entirely. +func diffIaCServices(declared, advertised []string) (missing, extra []string) { + if len(declared) == 0 { + return nil, nil + } + declSet := make(map[string]bool, len(declared)) + for _, s := range declared { + declSet[s] = true + } + advSet := make(map[string]bool, len(advertised)) + for _, s := range advertised { + advSet[s] = true + } + for _, s := range declared { + if !advSet[s] { + missing = append(missing, s) + } + } + for _, s := range advertised { + if !declSet[s] { + extra = append(extra, s) + } + } + sort.Strings(missing) + sort.Strings(extra) + return missing, extra +} + +// serviceNamesFromRegistry returns SERVICE-kind contract names from reg +// whose ServiceName starts with namespacePrefix. Defense-in-depth: the SDK +// bridge (Task 3) also filters, but old-SDK plugins skip that filter — this +// client-side check prevents WARN-spam for unrebased plugin binaries. +// Returns nil for nil reg. Sorted for stable diff output. +func serviceNamesFromRegistry(reg *pb.ContractRegistry, namespacePrefix string) []string { + if reg == nil { + return nil + } + names := make([]string, 0, len(reg.Contracts)) + for _, c := range reg.Contracts { + if c.GetKind() != pb.ContractKind_CONTRACT_KIND_SERVICE { + continue + } + if !strings.HasPrefix(c.GetServiceName(), namespacePrefix) { + continue + } + names = append(names, c.GetServiceName()) + } + sort.Strings(names) + return names +} + // isSentinel returns true when v is one of the SDK's dev-sentinel forms // OR the on-disk plugin.json sentinel "0.0.0". // diff --git a/cmd/wfctl/plugin_verify_capabilities_test.go b/cmd/wfctl/plugin_verify_capabilities_test.go index 4a548b5e..a82807dd 100644 --- a/cmd/wfctl/plugin_verify_capabilities_test.go +++ b/cmd/wfctl/plugin_verify_capabilities_test.go @@ -215,3 +215,49 @@ func TestVerifyCapabilities_NameDrift(t *testing.T) { t.Errorf("want name-mismatch error, got: %v", err) } } + +func TestDiffIaCServices_Match(t *testing.T) { + missing, extra := diffIaCServices( + []string{"workflow.plugin.external.iac.IaCProviderRequired"}, + []string{"workflow.plugin.external.iac.IaCProviderRequired"}) + if len(missing) != 0 || len(extra) != 0 { + t.Errorf("missing=%v extra=%v", missing, extra) + } +} + +func TestDiffIaCServices_MissingFromBinary(t *testing.T) { + declared := []string{ + "workflow.plugin.external.iac.IaCProviderRequired", + "workflow.plugin.external.iac.IaCProviderFinalizer", + } + advertised := []string{"workflow.plugin.external.iac.IaCProviderRequired"} + missing, extra := diffIaCServices(declared, advertised) + if len(missing) != 1 || missing[0] != "workflow.plugin.external.iac.IaCProviderFinalizer" { + t.Errorf("want Finalizer missing; got %v", missing) + } + if len(extra) != 0 { + t.Errorf("want no extras; got %v", extra) + } +} + +func TestDiffIaCServices_ExtraInBinary(t *testing.T) { + missing, extra := diffIaCServices( + []string{"workflow.plugin.external.iac.IaCProviderRequired"}, + []string{ + "workflow.plugin.external.iac.IaCProviderRequired", + "workflow.plugin.external.iac.IaCProviderFinalizer", + }) + if len(missing) != 0 { + t.Errorf("missing=%v", missing) + } + if len(extra) != 1 || extra[0] != "workflow.plugin.external.iac.IaCProviderFinalizer" { + t.Errorf("want Finalizer extra; got %v", extra) + } +} + +func TestDiffIaCServices_EmptyDeclared_SkipsDiff(t *testing.T) { + missing, extra := diffIaCServices(nil, []string{"workflow.plugin.external.iac.IaCProviderRequired"}) + if missing != nil || extra != nil { + t.Errorf("empty LHS should skip; got missing=%v extra=%v", missing, extra) + } +} From ac48371e3d570bd810e1800183095f541825a389 Mon Sep 17 00:00:00 2001 From: Jon Langevin Date: Sun, 24 May 2026 09:41:18 -0400 Subject: [PATCH 16/16] test(wfctl): 3 IaC integration fixture scenarios (workflow#767 Task 5) --- cmd/wfctl/plugin_verify_capabilities_test.go | 29 ++ .../iac-extra-service/go.mod | 152 ++++++ .../iac-extra-service/go.sum | 491 ++++++++++++++++++ .../iac-extra-service/main.go | 31 ++ .../iac-extra-service/plugin.json | 10 + .../verify_capabilities/iac-good/go.mod | 152 ++++++ .../verify_capabilities/iac-good/go.sum | 491 ++++++++++++++++++ .../verify_capabilities/iac-good/main.go | 31 ++ .../verify_capabilities/iac-good/plugin.json | 11 + .../iac-missing-service/go.mod | 152 ++++++ .../iac-missing-service/go.sum | 491 ++++++++++++++++++ .../iac-missing-service/main.go | 34 ++ .../iac-missing-service/plugin.json | 11 + 13 files changed, 2086 insertions(+) create mode 100644 cmd/wfctl/testdata/verify_capabilities/iac-extra-service/go.mod create mode 100644 cmd/wfctl/testdata/verify_capabilities/iac-extra-service/go.sum create mode 100644 cmd/wfctl/testdata/verify_capabilities/iac-extra-service/main.go create mode 100644 cmd/wfctl/testdata/verify_capabilities/iac-extra-service/plugin.json create mode 100644 cmd/wfctl/testdata/verify_capabilities/iac-good/go.mod create mode 100644 cmd/wfctl/testdata/verify_capabilities/iac-good/go.sum create mode 100644 cmd/wfctl/testdata/verify_capabilities/iac-good/main.go create mode 100644 cmd/wfctl/testdata/verify_capabilities/iac-good/plugin.json create mode 100644 cmd/wfctl/testdata/verify_capabilities/iac-missing-service/go.mod create mode 100644 cmd/wfctl/testdata/verify_capabilities/iac-missing-service/go.sum create mode 100644 cmd/wfctl/testdata/verify_capabilities/iac-missing-service/main.go create mode 100644 cmd/wfctl/testdata/verify_capabilities/iac-missing-service/plugin.json diff --git a/cmd/wfctl/plugin_verify_capabilities_test.go b/cmd/wfctl/plugin_verify_capabilities_test.go index a82807dd..c18fb294 100644 --- a/cmd/wfctl/plugin_verify_capabilities_test.go +++ b/cmd/wfctl/plugin_verify_capabilities_test.go @@ -261,3 +261,32 @@ func TestDiffIaCServices_EmptyDeclared_SkipsDiff(t *testing.T) { t.Errorf("empty LHS should skip; got missing=%v extra=%v", missing, extra) } } + +func TestVerifyCapabilities_IaCGood(t *testing.T) { + bin := buildFixtureBinaryForVerify(t, "iac-good", "v0.1.0") + if err := runPluginVerifyCapabilities([]string{"--binary", bin, "testdata/verify_capabilities/iac-good"}); err != nil { + t.Fatalf("want PASS, got: %v", err) + } +} + +func TestVerifyCapabilities_IaCMissingService(t *testing.T) { + bin := buildFixtureBinaryForVerify(t, "iac-missing-service", "v0.1.0") + err := runPluginVerifyCapabilities([]string{"--binary", bin, "testdata/verify_capabilities/iac-missing-service"}) + if err == nil { + t.Fatal("want FAIL on missing Finalizer, got nil") + } + if !strings.Contains(err.Error(), "iacServices:") { + t.Errorf("want iacServices: error, got: %v", err) + } + if !strings.Contains(err.Error(), "IaCProviderFinalizer") { + t.Errorf("want Finalizer-specific error, got: %v", err) + } +} + +func TestVerifyCapabilities_IaCExtraService(t *testing.T) { + bin := buildFixtureBinaryForVerify(t, "iac-extra-service", "v0.1.0") + // Extra services produce WARN (stderr) but exit 0 per design §3. + if err := runPluginVerifyCapabilities([]string{"--binary", bin, "testdata/verify_capabilities/iac-extra-service"}); err != nil { + t.Fatalf("want PASS (extra=WARN, not FAIL); got: %v", err) + } +} diff --git a/cmd/wfctl/testdata/verify_capabilities/iac-extra-service/go.mod b/cmd/wfctl/testdata/verify_capabilities/iac-extra-service/go.mod new file mode 100644 index 00000000..ae0cd0ae --- /dev/null +++ b/cmd/wfctl/testdata/verify_capabilities/iac-extra-service/go.mod @@ -0,0 +1,152 @@ +module github.com/test/iac-extra-service + +go 1.26.0 + +require github.com/GoCodeAlone/workflow v0.63.2 + +require ( + github.com/BurntSushi/toml v1.6.0 // indirect + github.com/DataDog/datadog-go/v5 v5.8.3 // indirect + github.com/GoCodeAlone/go-plugin v1.7.0 // indirect + github.com/GoCodeAlone/modular v1.13.0 // indirect + github.com/GoCodeAlone/modular/modules/auth v1.15.0 // indirect + github.com/GoCodeAlone/modular/modules/eventbus/v2 v2.8.0 // indirect + github.com/GoCodeAlone/yaegi v0.17.2 // indirect + github.com/IBM/sarama v1.47.0 // indirect + github.com/Microsoft/go-winio v0.6.2 // indirect + github.com/aws/aws-sdk-go-v2 v1.41.6 // indirect + github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.8 // indirect + github.com/aws/aws-sdk-go-v2/config v1.32.16 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.19.15 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.22 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.22 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.22 // indirect + github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.23 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.8 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.22 // indirect + github.com/aws/aws-sdk-go-v2/service/kinesis v1.43.4 // indirect + github.com/aws/aws-sdk-go-v2/service/signin v1.0.10 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.30.16 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.20 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.42.0 // indirect + github.com/aws/smithy-go v1.25.0 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/cenkalti/backoff/v5 v5.0.3 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/cloudevents/sdk-go/v2 v2.16.2 // indirect + github.com/containerd/errdefs v1.0.0 // indirect + github.com/containerd/errdefs/pkg v0.3.0 // indirect + github.com/containerd/log v0.1.0 // indirect + github.com/danieljoos/wincred v1.2.3 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/distribution/reference v0.6.0 // indirect + github.com/docker/docker v28.5.2+incompatible // indirect + github.com/docker/go-connections v0.7.0 // indirect + github.com/docker/go-units v0.5.0 // indirect + github.com/dustin/go-humanize v1.0.1 // indirect + github.com/eapache/go-resiliency v1.7.0 // indirect + github.com/eapache/queue v1.1.0 // indirect + github.com/expr-lang/expr v1.17.8 // indirect + github.com/fatih/color v1.19.0 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/fsnotify/fsnotify v1.9.0 // indirect + github.com/go-jose/go-jose/v4 v4.1.4 // indirect + github.com/go-logr/logr v1.4.3 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/godbus/dbus/v5 v5.2.2 // indirect + github.com/golang-jwt/jwt/v5 v5.3.1 // indirect + github.com/golobby/cast v1.3.3 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-hclog v1.6.3 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-retryablehttp v0.7.8 // indirect + github.com/hashicorp/go-rootcerts v1.0.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.2.0 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.7 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/golang-lru v1.0.2 // indirect + github.com/hashicorp/hcl v1.0.1-vault-7 // indirect + github.com/hashicorp/vault/api v1.23.0 // indirect + github.com/hashicorp/yamux v0.1.2 // indirect + github.com/itchyny/gojq v0.12.18 // indirect + github.com/itchyny/timefmt-go v0.1.7 // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect + github.com/jackc/pgx/v5 v5.9.1 // indirect + github.com/jackc/puddle/v2 v2.2.2 // indirect + github.com/jcmturner/aescts/v2 v2.0.0 // indirect + github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect + github.com/jcmturner/gofork v1.7.6 // indirect + github.com/jcmturner/gokrb5/v8 v8.4.4 // indirect + github.com/jcmturner/rpc/v2 v2.0.3 // indirect + github.com/json-iterator/go v1.1.13-0.20220915233716-71ac16282d12 // indirect + github.com/klauspost/compress v1.18.6 // indirect + github.com/mattn/go-colorable v0.1.14 // indirect + github.com/mattn/go-isatty v0.0.22 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/moby/docker-image-spec v1.3.1 // indirect + github.com/moby/sys/sequential v0.6.0 // indirect + github.com/moby/term v0.5.2 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/nats-io/nats.go v1.52.0 // indirect + github.com/nats-io/nkeys v0.4.15 // indirect + github.com/nats-io/nuid v1.0.1 // indirect + github.com/ncruces/go-strftime v1.0.0 // indirect + github.com/oklog/run v1.2.0 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.1.1 // indirect + github.com/pierrec/lz4/v4 v4.1.26 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/prometheus/client_golang v1.23.2 // indirect + github.com/prometheus/client_model v0.6.2 // indirect + github.com/prometheus/common v0.67.5 // indirect + github.com/prometheus/procfs v0.20.1 // indirect + github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 // indirect + github.com/redis/go-redis/v9 v9.19.0 // indirect + github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + github.com/xdg-go/pbkdf2 v1.0.0 // indirect + github.com/xdg-go/scram v1.2.0 // indirect + github.com/xdg-go/stringprep v1.0.4 // indirect + github.com/zalando/go-keyring v0.2.8 // indirect + go.opentelemetry.io/auto/sdk v1.2.1 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.68.0 // indirect + go.opentelemetry.io/otel v1.43.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0 // indirect + go.opentelemetry.io/otel/metric v1.43.0 // indirect + go.opentelemetry.io/otel/sdk v1.43.0 // indirect + go.opentelemetry.io/otel/trace v1.43.0 // indirect + go.opentelemetry.io/proto/otlp v1.10.0 // indirect + go.uber.org/atomic v1.11.0 // indirect + go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap v1.28.0 // indirect + go.yaml.in/yaml/v2 v2.4.4 // indirect + golang.org/x/crypto v0.51.0 // indirect + golang.org/x/net v0.54.0 // indirect + golang.org/x/oauth2 v0.36.0 // indirect + golang.org/x/sync v0.20.0 // indirect + golang.org/x/sys v0.44.0 // indirect + golang.org/x/text v0.37.0 // indirect + golang.org/x/time v0.15.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20260511170946-3700d4141b60 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260511170946-3700d4141b60 // indirect + google.golang.org/grpc v1.81.1 // indirect + google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + modernc.org/libc v1.70.0 // indirect + modernc.org/mathutil v1.7.1 // indirect + modernc.org/memory v1.11.0 // indirect + modernc.org/sqlite v1.47.0 // indirect +) + +replace github.com/GoCodeAlone/workflow => ../../../../.. diff --git a/cmd/wfctl/testdata/verify_capabilities/iac-extra-service/go.sum b/cmd/wfctl/testdata/verify_capabilities/iac-extra-service/go.sum new file mode 100644 index 00000000..044a174e --- /dev/null +++ b/cmd/wfctl/testdata/verify_capabilities/iac-extra-service/go.sum @@ -0,0 +1,491 @@ +github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg= +github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk= +github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= +github.com/DataDog/datadog-go/v5 v5.8.3 h1:s58CUJ9s8lezjhTNJO/SxkPBv2qZjS3ktpRSqGF5n0s= +github.com/DataDog/datadog-go/v5 v5.8.3/go.mod h1:K9kcYBlxkcPP8tvvjZZKs/m1edNAUFzBbdpTUKfCsuw= +github.com/GoCodeAlone/go-plugin v1.7.0 h1:EwnhqPlXiNmp85S+MXnKKvm3YlfA6O4NzBb4+GSlEVY= +github.com/GoCodeAlone/go-plugin v1.7.0/go.mod h1:HbGQRZUIa+jbDfjsaZIMJYvrz+LnxL0mJpggfynSTMk= +github.com/GoCodeAlone/modular v1.13.0 h1:UfsegfAmPWcPYQOqYZFsw/LNySBmMDcthiOQe5bscqE= +github.com/GoCodeAlone/modular v1.13.0/go.mod h1:b06Pvgcc8HsGxvl30iO39zGH2jIWz467QEj2+OQL2Do= +github.com/GoCodeAlone/modular/modules/auth v1.15.0 h1:pBSkPSf4k4GLSbUQFLuPa+nFbfoJXGzSz9q89VoapZk= +github.com/GoCodeAlone/modular/modules/auth v1.15.0/go.mod h1:vmIm/LQrcURS2p02YwaELb+CZoHPtT0XB0v1i+sj9i4= +github.com/GoCodeAlone/modular/modules/eventbus/v2 v2.8.0 h1:buYs0TGNbAZgtTq1Qb+dfmTv3+ZOBIN0HbvVBLyNqxE= +github.com/GoCodeAlone/modular/modules/eventbus/v2 v2.8.0/go.mod h1:329flAKmwrPq2JEwu9iltWv6A83H/Di82Xze+kvdKDw= +github.com/GoCodeAlone/yaegi v0.17.2 h1:WK6Y6e0t1a6U7r+S2dN3CGWW1PizYD3zO0zneToZPxM= +github.com/GoCodeAlone/yaegi v0.17.2/go.mod h1:z5Pr6Wse6QJcQvpgxTxzMAevFarH0N37TG88Y9dprx0= +github.com/IBM/sarama v1.47.0 h1:GcQFEd12+KzfPYeLgN69Fh7vLCtYRhVIx0rO4TZO318= +github.com/IBM/sarama v1.47.0/go.mod h1:7gLLIU97nznOmA6TX++Qds+DRxH89P2XICY2KAQUzAY= +github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= +github.com/alicebob/miniredis/v2 v2.36.1 h1:Dvc5oAnNOr7BIfPn7tF269U8DvRW1dBG2D5n0WrfYMI= +github.com/alicebob/miniredis/v2 v2.36.1/go.mod h1:TcL7YfarKPGDAthEtl5NBeHZfeUQj6OXMm/+iu5cLMM= +github.com/antithesishq/antithesis-sdk-go v0.5.0-default-no-op h1:Ucf+QxEKMbPogRO5guBNe5cgd9uZgfoJLOYs8WWhtjM= +github.com/antithesishq/antithesis-sdk-go v0.5.0-default-no-op/go.mod h1:IUpT2DPAKh6i/YhSbt6Gl3v2yvUZjmKncl7U91fup7E= +github.com/aws/aws-sdk-go-v2 v1.41.6 h1:1AX0AthnBQzMx1vbmir3Y4WsnJgiydmnJjiLu+LvXOg= +github.com/aws/aws-sdk-go-v2 v1.41.6/go.mod h1:dy0UzBIfwSeot4grGvY1AqFWN5zgziMmWGzysDnHFcQ= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.8 h1:eBMB84YGghSocM7PsjmmPffTa+1FBUeNvGvFou6V/4o= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.8/go.mod h1:lyw7GFp3qENLh7kwzf7iMzAxDn+NzjXEAGjKS2UOKqI= +github.com/aws/aws-sdk-go-v2/config v1.32.16 h1:Q0iQ7quUgJP0F/SCRTieScnaMdXr9h/2+wze1u3cNeM= +github.com/aws/aws-sdk-go-v2/config v1.32.16/go.mod h1:duCCnJEFqpt2RC6no1iK6q+8HpwOAkiUua0pY507dQc= +github.com/aws/aws-sdk-go-v2/credentials v1.19.15 h1:fyvgWTszojq8hEnMi8PPBTvZdTtEVmAVyo+NFLHBhH4= +github.com/aws/aws-sdk-go-v2/credentials v1.19.15/go.mod h1:gJiYyMOjNg8OEdRWOf3CrFQxM2a98qmrtjx1zuiQfB8= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.22 h1:IOGsJ1xVWhsi+ZO7/NW8OuZZBtMJLZbk4P5HDjJO0jQ= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.22/go.mod h1:b+hYdbU+jGKfXE8kKM6g1+h+L/Go3vMvzlxBsiuGsxg= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.22 h1:GmLa5Kw1ESqtFpXsx5MmC84QWa/ZrLZvlJGa2y+4kcQ= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.22/go.mod h1:6sW9iWm9DK9YRpRGga/qzrzNLgKpT2cIxb7Vo2eNOp0= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.22 h1:dY4kWZiSaXIzxnKlj17nHnBcXXBfac6UlsAx2qL6XrU= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.22/go.mod h1:KIpEUx0JuRZLO7U6cbV204cWAEco2iC3l061IxlwLtI= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.23 h1:FPXsW9+gMuIeKmz7j6ENWcWtBGTe1kH8r9thNt5Uxx4= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.23/go.mod h1:7J8iGMdRKk6lw2C+cMIphgAnT8uTwBwNOsGkyOCm80U= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.8 h1:HtOTYcbVcGABLOVuPYaIihj6IlkqubBwFj10K5fxRek= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.8/go.mod h1:VsK9abqQeGlzPgUr+isNWzPlK2vKe9INMLWnY65f5Xs= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.22 h1:PUmZeJU6Y1Lbvt9WFuJ0ugUK2xn6hIWUBBbKuOWF30s= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.22/go.mod h1:nO6egFBoAaoXze24a2C0NjQCvdpk8OueRoYimvEB9jo= +github.com/aws/aws-sdk-go-v2/service/kinesis v1.43.4 h1:3m9iJtMtLq75jKRAfw0kapoHUlbzi0CRVigysBN/FHA= +github.com/aws/aws-sdk-go-v2/service/kinesis v1.43.4/go.mod h1:O2L6vGm4xacEuN2otHFMgn7yXXlgzFKzxrba0fy/yk8= +github.com/aws/aws-sdk-go-v2/service/signin v1.0.10 h1:a1Fq/KXn75wSzoJaPQTgZO0wHGqE9mjFnylnqEPTchA= +github.com/aws/aws-sdk-go-v2/service/signin v1.0.10/go.mod h1:p6+MXNxW7IA6dMgHfTAzljuwSKD0NCm/4lbS4t6+7vI= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.16 h1:x6bKbmDhsgSZwv6q19wY/u3rLk/3FGjJWyqKcIRufpE= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.16/go.mod h1:CudnEVKRtLn0+3uMV0yEXZ+YZOKnAtUJ5DmDhilVnIw= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.20 h1:oK/njaL8GtyEihkWMD4k3VgHCT64RQKkZwh0DG5j8ak= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.20/go.mod h1:JHs8/y1f3zY7U5WcuzoJ/yAYGYtNIVPKLIbp61euvmg= +github.com/aws/aws-sdk-go-v2/service/sts v1.42.0 h1:ks8KBcZPh3PYISr5dAiXCM5/Thcuxk8l+PG4+A0exds= +github.com/aws/aws-sdk-go-v2/service/sts v1.42.0/go.mod h1:pFw33T0WLvXU3rw1WBkpMlkgIn54eCB5FYLhjDc9Foo= +github.com/aws/smithy-go v1.25.0 h1:Sz/XJ64rwuiKtB6j98nDIPyYrV1nVNJ4YU74gttcl5U= +github.com/aws/smithy-go v1.25.0/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= +github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= +github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= +github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= +github.com/bufbuild/protocompile v0.10.0 h1:+jW/wnLMLxaCEG8AX9lD0bQ5v9h1RUiMKOBOT5ll9dM= +github.com/bufbuild/protocompile v0.10.0/go.mod h1:G9qQIQo0xZ6Uyj6CMNz0saGmx2so+KONo8/KrELABiY= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= +github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cloudevents/sdk-go/v2 v2.16.2 h1:ZYDFrYke4FD+jM8TZTJJO6JhKHzOQl2oqpFK1D+NnQM= +github.com/cloudevents/sdk-go/v2 v2.16.2/go.mod h1:laOcGImm4nVJEU+PHnUrKL56CKmRL65RlQF0kRmW/kg= +github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= +github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= +github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE= +github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk= +github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= +github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/cucumber/gherkin/go/v26 v26.2.0 h1:EgIjePLWiPeslwIWmNQ3XHcypPsWAHoMCz/YEBKP4GI= +github.com/cucumber/gherkin/go/v26 v26.2.0/go.mod h1:t2GAPnB8maCT4lkHL99BDCVNzCh1d7dBhCLt150Nr/0= +github.com/cucumber/godog v0.15.1 h1:rb/6oHDdvVZKS66hrhpjFQFHjthFSrQBCOI1LwshNTI= +github.com/cucumber/godog v0.15.1/go.mod h1:qju+SQDewOljHuq9NSM66s0xEhogx0q30flfxL4WUk8= +github.com/cucumber/messages/go/v21 v21.0.1 h1:wzA0LxwjlWQYZd32VTlAVDTkW6inOFmSM+RuOwHZiMI= +github.com/cucumber/messages/go/v21 v21.0.1/go.mod h1:zheH/2HS9JLVFukdrsPWoPdmUtmYQAQPLk7w5vWsk5s= +github.com/danieljoos/wincred v1.2.3 h1:v7dZC2x32Ut3nEfRH+vhoZGvN72+dQ/snVXo/vMFLdQ= +github.com/danieljoos/wincred v1.2.3/go.mod h1:6qqX0WNrS4RzPZ1tnroDzq9kY3fu1KwE7MRLQK4X0bs= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= +github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= +github.com/docker/docker v28.5.2+incompatible h1:DBX0Y0zAjZbSrm1uzOkdr1onVghKaftjlSWt4AFexzM= +github.com/docker/docker v28.5.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.7.0 h1:6SsRfJddP22WMrCkj19x9WKjEDTB+ahsdiGYf0mN39c= +github.com/docker/go-connections v0.7.0/go.mod h1:no1qkHdjq7kLMGUXYAduOhYPSJxxvgWBh7ogVvptn3Q= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/eapache/go-resiliency v1.7.0 h1:n3NRTnBn5N0Cbi/IeOHuQn9s2UwVUH7Ga0ZWcP+9JTA= +github.com/eapache/go-resiliency v1.7.0/go.mod h1:5yPzW0MIvSe0JDsv0v+DvcjEv2FyD6iZYSs1ZI+iQho= +github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/expr-lang/expr v1.17.8 h1:W1loDTT+0PQf5YteHSTpju2qfUfNoBt4yw9+wOEU9VM= +github.com/expr-lang/expr v1.17.8/go.mod h1:8/vRC7+7HBzESEqt5kKpYXxrxkr31SaO8r40VO/1IT4= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/color v1.19.0 h1:Zp3PiM21/9Ld6FzSKyL5c/BULoe/ONr9KlbYVOfG8+w= +github.com/fatih/color v1.19.0/go.mod h1:zNk67I0ZUT1bEGsSGyCZYZNrHuTkJJB+r6Q9VuMi0LE= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= +github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= +github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +github.com/go-jose/go-jose/v4 v4.1.4 h1:moDMcTHmvE6Groj34emNPLs/qtYXRVcd6S7NHbHz3kA= +github.com/go-jose/go-jose/v4 v4.1.4/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U= +github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= +github.com/godbus/dbus/v5 v5.2.2 h1:TUR3TgtSVDmjiXOgAAyaZbYmIeP3DPkld3jgKGV8mXQ= +github.com/godbus/dbus/v5 v5.2.2/go.mod h1:3AAv2+hPq5rdnr5txxxRwiGjPXamgoIHgz9FPBfOp3c= +github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= +github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY= +github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/golobby/cast v1.3.3 h1:s2Lawb9RMz7YyYf8IrfMQY4IFmA1R/lgfmj97Vc6fig= +github.com/golobby/cast v1.3.3/go.mod h1:0oDO5IT84HTXcbLDf1YXuk0xtg/cRDrxhbpWKxwtJCY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/go-tpm v0.9.8 h1:slArAR9Ft+1ybZu0lBwpSmpwhRXaa85hWtMinMyRAWo= +github.com/google/go-tpm v0.9.8/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs= +github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= +github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 h1:5VipnvEpbqr2gA2VbM+nYVbkIF28c5ZQfqCBQ5g2xfk= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0/go.mod h1:Hyl3n6Twe1hvtd9XUXDec4pTvgMSEixRuQKPTMH2bNs= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= +github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-memdb v1.3.5 h1:b3taDMxCBCBVgyRrS1AZVHO14ubMYZB++QpNhBg+Nyo= +github.com/hashicorp/go-memdb v1.3.5/go.mod h1:8IVKKBkVe+fxFgdFOYxzQQNjz+sWCyHCdIC/+5+Vy1Y= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-retryablehttp v0.7.8 h1:ylXZWnqa7Lhqpk0L1P1LzDtGcCR0rPVUrx/c8Unxc48= +github.com/hashicorp/go-retryablehttp v0.7.8/go.mod h1:rjiScheydd+CxvumBsIrFKlx3iS0jrZ7LvzFGFmuKbw= +github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-secure-stdlib/parseutil v0.2.0 h1:U+kC2dOhMFQctRfhK0gRctKAPTloZdMU5ZJxaesJ/VM= +github.com/hashicorp/go-secure-stdlib/parseutil v0.2.0/go.mod h1:Ll013mhdmsVDuoIXVfBtvgGJsXDYkTw1kooNcoCXuE0= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.7 h1:G+pTkSO01HpR5qCxg7lxfsFEZaG+C0VssTy/9dbT+Fw= +github.com/hashicorp/go-sockaddr v1.0.7/go.mod h1:FZQbEYa1pxkQ7WLpyXJ6cbjpT8q0YgQaK/JakXqGyWw= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= +github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= +github.com/hashicorp/hcl v1.0.1-vault-7 h1:ag5OxFVy3QYTFTJODRzTKVZ6xvdfLLCA1cy/Y6xGI0I= +github.com/hashicorp/hcl v1.0.1-vault-7/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM= +github.com/hashicorp/vault/api v1.23.0 h1:gXgluBsSECfRWTSW9niY2jwg2e9mMJc4WoHNv4g3h6A= +github.com/hashicorp/vault/api v1.23.0/go.mod h1:zransKiB9ftp+kgY8ydjnvCU7Wk8i9L0DYWpXeMj9ko= +github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8= +github.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns= +github.com/itchyny/gojq v0.12.18 h1:gFGHyt/MLbG9n6dqnvlliiya2TaMMh6FFaR2b1H6Drc= +github.com/itchyny/gojq v0.12.18/go.mod h1:4hPoZ/3lN9fDL1D+aK7DY1f39XZpY9+1Xpjz8atrEkg= +github.com/itchyny/timefmt-go v0.1.7 h1:xyftit9Tbw+Dc/huSSPJaEmX1TVL8lw5vxjJLK4GMMA= +github.com/itchyny/timefmt-go v0.1.7/go.mod h1:5E46Q+zj7vbTgWY8o5YkMeYb4I6GeWLFnetPy5oBrAI= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.9.1 h1:uwrxJXBnx76nyISkhr33kQLlUqjv7et7b9FjCen/tdc= +github.com/jackc/pgx/v5 v5.9.1/go.mod h1:mal1tBGAFfLHvZzaYh77YS/eC6IX9OWbRV1QIIM0Jn4= +github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= +github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= +github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= +github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo= +github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= +github.com/jcmturner/gofork v1.7.6 h1:QH0l3hzAU1tfT3rZCnW5zXl+orbkNMMRGJfdJjHVETg= +github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo= +github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o= +github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= +github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh687T8= +github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs= +github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= +github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= +github.com/jhump/protoreflect v1.16.0 h1:54fZg+49widqXYQ0b+usAFHbMkBGR4PpXrsHc8+TBDg= +github.com/jhump/protoreflect v1.16.0/go.mod h1:oYPd7nPvcBw/5wlDfm/AVmU9zH9BgqGCI469pGxfj/8= +github.com/json-iterator/go v1.1.13-0.20220915233716-71ac16282d12 h1:9Nu54bhS/H/Kgo2/7xNSUuC5G28VR8ljfrLKU2G4IjU= +github.com/json-iterator/go v1.1.13-0.20220915233716-71ac16282d12/go.mod h1:TBzl5BIHNXfS9+C35ZyJaklL7mLDbgUkcgXzSLa8Tk0= +github.com/klauspost/compress v1.18.6 h1:2jupLlAwFm95+YDR+NwD2MEfFO9d4z4Prjl1XXDjuao= +github.com/klauspost/compress v1.18.6/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= +github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= +github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw4= +github.com/mattn/go-isatty v0.0.22/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4= +github.com/minio/highwayhash v1.0.4-0.20251030100505-070ab1a87a76 h1:KGuD/pM2JpL9FAYvBrnBBeENKZNh6eNtjqytV6TYjnk= +github.com/minio/highwayhash v1.0.4-0.20251030100505-070ab1a87a76/go.mod h1:GGYsuwP/fPD6Y9hMiXuapVvlIUEhFhMTh0rxU3ik1LQ= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= +github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= +github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw= +github.com/moby/sys/atomicwriter v0.1.0/go.mod h1:Ul8oqv2ZMNHOceF643P6FKPXeCmYtlQMvpizfsSoaWs= +github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU= +github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko= +github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ= +github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= +github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/morikuni/aec v1.1.0 h1:vBBl0pUnvi/Je71dsRrhMBtreIqNMYErSAbEeb8jrXQ= +github.com/morikuni/aec v1.1.0/go.mod h1:xDRgiq/iw5l+zkao76YTKzKttOp2cwPEne25HDkJnBw= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/nats-io/jwt/v2 v2.8.0 h1:K7uzyz50+yGZDO5o772eRE7atlcSEENpL7P+b74JV1g= +github.com/nats-io/jwt/v2 v2.8.0/go.mod h1:me11pOkwObtcBNR8AiMrUbtVOUGkqYjMQZ6jnSdVUIA= +github.com/nats-io/nats-server/v2 v2.12.4 h1:ZnT10v2LU2Xcoiy8ek9X6Se4YG8EuMfIfvAEuFVx1Ts= +github.com/nats-io/nats-server/v2 v2.12.4/go.mod h1:5MCp/pqm5SEfsvVZ31ll1088ZTwEUdvRX1Hmh/mTTDg= +github.com/nats-io/nats.go v1.52.0 h1:n3avV4VBsCgsdwh71TppsTwtv+QdPs7ntSKM8qJLGsc= +github.com/nats-io/nats.go v1.52.0/go.mod h1:26HypzazeOkyO3/mqd1zZd53STJN0EjCYF9Uy2ZOBno= +github.com/nats-io/nkeys v0.4.15 h1:JACV5jRVO9V856KOapQ7x+EY8Jo3qw1vJt/9Jpwzkk4= +github.com/nats-io/nkeys v0.4.15/go.mod h1:CpMchTXC9fxA5zrMo4KpySxNjiDVvr8ANOSZdiNfUrs= +github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= +github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w= +github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= +github.com/oklog/run v1.2.0 h1:O8x3yXwah4A73hJdlrwo/2X6J62gE5qTMusH0dvz60E= +github.com/oklog/run v1.2.0/go.mod h1:mgDbKRSwPhJfesJ4PntqFUbKQRZ50NgmZTSPlFA0YFk= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= +github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= +github.com/pierrec/lz4/v4 v4.1.26 h1:GrpZw1gZttORinvzBdXPUXATeqlJjqUG/D87TKMnhjY= +github.com/pierrec/lz4/v4 v4.1.26/go.mod h1:EoQMVJgeeEOMsCqCzqFm2O0cJvljX2nGZjcRIPL34O4= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= +github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= +github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= +github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= +github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4= +github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw= +github.com/prometheus/procfs v0.20.1 h1:XwbrGOIplXW/AU3YhIhLODXMJYyC1isLFfYCsTEycfc= +github.com/prometheus/procfs v0.20.1/go.mod h1:o9EMBZGRyvDrSPH1RqdxhojkuXstoe4UlK79eF5TGGo= +github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 h1:bsUq1dX0N8AOIL7EB/X911+m4EHsnWEHeJ0c+3TTBrg= +github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/redis/go-redis/v9 v9.19.0 h1:XPVaaPSnG6RhYf7p+rmSa9zZfeVAnWsH5h3lxthOm/k= +github.com/redis/go-redis/v9 v9.19.0/go.mod h1:v/M13XI1PVCDcm01VtPFOADfZtHf8YW3baQf57KlIkA= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= +github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ= +github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= +github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= +github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= +github.com/xdg-go/scram v1.2.0 h1:bYKF2AEwG5rqd1BumT4gAnvwU/M9nBp2pTSxeZw7Wvs= +github.com/xdg-go/scram v1.2.0/go.mod h1:3dlrS0iBaWKYVt2ZfA4cj48umJZ+cAEbR6/SjLA88I8= +github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8= +github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M= +github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw= +github.com/zalando/go-keyring v0.2.8 h1:6sD/Ucpl7jNq10rM2pgqTs0sZ9V3qMrqfIIy5YPccHs= +github.com/zalando/go-keyring v0.2.8/go.mod h1:tsMo+VpRq5NGyKfxoBVjCuMrG47yj8cmakZDO5QGii0= +github.com/zeebo/xxh3 v1.1.0 h1:s7DLGDK45Dyfg7++yxI0khrfwq9661w9EN78eP/UZVs= +github.com/zeebo/xxh3 v1.1.0/go.mod h1:IisAie1LELR4xhVinxWS5+zf1lA4p0MW4T+w+W07F5s= +go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= +go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.68.0 h1:CqXxU8VOmDefoh0+ztfGaymYbhdB/tT3zs79QaZTNGY= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.68.0/go.mod h1:BuhAPThV8PBHBvg8ZzZ/Ok3idOdhWIodywz2xEcRbJo= +go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I= +go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 h1:88Y4s2C8oTui1LGM6bTWkw0ICGcOLCAI5l6zsD1j20k= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0/go.mod h1:Vl1/iaggsuRlrHf/hfPJPvVag77kKyvrLeD10kpMl+A= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0 h1:3iZJKlCZufyRzPzlQhUIWVmfltrXuGyfjREgGP3UUjc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0/go.mod h1:/G+nUPfhq2e+qiXMGxMwumDrP5jtzU+mWN7/sjT2rak= +go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM= +go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY= +go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg= +go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg= +go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw= +go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A= +go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A= +go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0= +go.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g= +go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk= +go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= +go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= +go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.28.0 h1:IZzaP1Fv73/T/pBMLk4VutPl36uNC+OSUh3JLG3FIjo= +go.uber.org/zap v1.28.0/go.mod h1:rDLpOi171uODNm/mxFcuYWxDsqWSAVkFdX4XojSKg/Q= +go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ= +go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ= +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/crypto v0.51.0 h1:IBPXwPfKxY7cWQZ38ZCIRPI50YLeevDLlLnyC5wRGTI= +golang.org/x/crypto v0.51.0/go.mod h1:8AdwkbraGNABw2kOX6YFPs3WM22XqI4EXEd8g+x7Oc8= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4= +golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.54.0 h1:2zJIZAxAHV/OHCDTCOHAYehQzLfSXuf/5SoL/Dv6w/w= +golang.org/x/net v0.54.0/go.mod h1:Sj4oj8jK6XmHpBZU/zWHw3BV3abl4Kvi+Ut7cQcY+cQ= +golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= +golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= +golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ= +golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc= +golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38= +golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= +golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8= +golang.org/x/tools v0.45.0/go.mod h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= +gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= +google.golang.org/genproto/googleapis/api v0.0.0-20260511170946-3700d4141b60 h1:3WsB1FAbiRIf2tOxscWKs3pQBD9he1NsrnbhMuWfekc= +google.golang.org/genproto/googleapis/api v0.0.0-20260511170946-3700d4141b60/go.mod h1:7yoXV7RIh5gblj/xVYoogxAWvA9wUeVbpsK/M694l00= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260511170946-3700d4141b60 h1:seT2EwLWM78plQ7wcDfuWBc/4FAEAXDDiaSol4ku4qo= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260511170946-3700d4141b60/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= +google.golang.org/grpc v1.81.1 h1:VnnIIZ88UzOOKLukQi+ImGz8O1Wdp8nAGGnvOfEIWQQ= +google.golang.org/grpc v1.81.1/go.mod h1:xGH9GfzOyMTGIOXBJmXt+BX/V0kcdQbdcuwQ/zNw42I= +google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af h1:+5/Sw3GsDNlEmu7TfklWKPdQ0Ykja5VEmq2i817+jbI= +google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= +gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= +modernc.org/cc/v4 v4.27.1 h1:9W30zRlYrefrDV2JE2O8VDtJ1yPGownxciz5rrbQZis= +modernc.org/cc/v4 v4.27.1/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0= +modernc.org/ccgo/v4 v4.32.0 h1:hjG66bI/kqIPX1b2yT6fr/jt+QedtP2fqojG2VrFuVw= +modernc.org/ccgo/v4 v4.32.0/go.mod h1:6F08EBCx5uQc38kMGl+0Nm0oWczoo1c7cgpzEry7Uc0= +modernc.org/fileutil v1.4.0 h1:j6ZzNTftVS054gi281TyLjHPp6CPHr2KCxEXjEbD6SM= +modernc.org/fileutil v1.4.0/go.mod h1:EqdKFDxiByqxLk8ozOxObDSfcVOv/54xDs/DUHdvCUU= +modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI= +modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito= +modernc.org/gc/v3 v3.1.2 h1:ZtDCnhonXSZexk/AYsegNRV1lJGgaNZJuKjJSWKyEqo= +modernc.org/gc/v3 v3.1.2/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY= +modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks= +modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI= +modernc.org/libc v1.70.0 h1:U58NawXqXbgpZ/dcdS9kMshu08aiA6b7gusEusqzNkw= +modernc.org/libc v1.70.0/go.mod h1:OVmxFGP1CI/Z4L3E0Q3Mf1PDE0BucwMkcXjjLntvHJo= +modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU= +modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg= +modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI= +modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw= +modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8= +modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns= +modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w= +modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE= +modernc.org/sqlite v1.47.0 h1:R1XyaNpoW4Et9yly+I2EeX7pBza/w+pmYee/0HJDyKk= +modernc.org/sqlite v1.47.0/go.mod h1:hWjRO6Tj/5Ik8ieqxQybiEOUXy0NJFNp2tpvVpKlvig= +modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0= +modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A= +modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= +modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= diff --git a/cmd/wfctl/testdata/verify_capabilities/iac-extra-service/main.go b/cmd/wfctl/testdata/verify_capabilities/iac-extra-service/main.go new file mode 100644 index 00000000..6e6ff72e --- /dev/null +++ b/cmd/wfctl/testdata/verify_capabilities/iac-extra-service/main.go @@ -0,0 +1,31 @@ +package main + +import ( + "context" + _ "embed" + + pb "github.com/GoCodeAlone/workflow/plugin/external/proto" + sdk "github.com/GoCodeAlone/workflow/plugin/external/sdk" +) + +var Version = "dev" + +//go:embed plugin.json +var manifestData []byte + +// FinalizeApply satisfied by embedded UnimplementedIaCProviderFinalizerServer. +type fixture struct { + pb.UnimplementedIaCProviderRequiredServer + pb.UnimplementedIaCProviderFinalizerServer +} + +func (fixture) Name(context.Context, *pb.NameRequest) (*pb.NameResponse, error) { + return &pb.NameResponse{Name: "verify-iac-extra"}, nil +} + +func main() { + sdk.ServeIaCPlugin(fixture{}, sdk.IaCServeOptions{ + ManifestProvider: sdk.MustEmbedManifest(manifestData), + BuildVersion: sdk.ResolveBuildVersion(Version), + }) +} diff --git a/cmd/wfctl/testdata/verify_capabilities/iac-extra-service/plugin.json b/cmd/wfctl/testdata/verify_capabilities/iac-extra-service/plugin.json new file mode 100644 index 00000000..661c237e --- /dev/null +++ b/cmd/wfctl/testdata/verify_capabilities/iac-extra-service/plugin.json @@ -0,0 +1,10 @@ +{ + "name": "verify-iac-extra", + "version": "0.0.0", + "minEngineVersion": "v0.62.0", + "author": "test fixture", + "description": "IaC fixture: binary registers more services than plugin.json declares", + "iacServices": [ + "workflow.plugin.external.iac.IaCProviderRequired" + ] +} diff --git a/cmd/wfctl/testdata/verify_capabilities/iac-good/go.mod b/cmd/wfctl/testdata/verify_capabilities/iac-good/go.mod new file mode 100644 index 00000000..b1980beb --- /dev/null +++ b/cmd/wfctl/testdata/verify_capabilities/iac-good/go.mod @@ -0,0 +1,152 @@ +module github.com/test/iac-good + +go 1.26.0 + +require github.com/GoCodeAlone/workflow v0.63.2 + +require ( + github.com/BurntSushi/toml v1.6.0 // indirect + github.com/DataDog/datadog-go/v5 v5.8.3 // indirect + github.com/GoCodeAlone/go-plugin v1.7.0 // indirect + github.com/GoCodeAlone/modular v1.13.0 // indirect + github.com/GoCodeAlone/modular/modules/auth v1.15.0 // indirect + github.com/GoCodeAlone/modular/modules/eventbus/v2 v2.8.0 // indirect + github.com/GoCodeAlone/yaegi v0.17.2 // indirect + github.com/IBM/sarama v1.47.0 // indirect + github.com/Microsoft/go-winio v0.6.2 // indirect + github.com/aws/aws-sdk-go-v2 v1.41.6 // indirect + github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.8 // indirect + github.com/aws/aws-sdk-go-v2/config v1.32.16 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.19.15 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.22 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.22 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.22 // indirect + github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.23 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.8 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.22 // indirect + github.com/aws/aws-sdk-go-v2/service/kinesis v1.43.4 // indirect + github.com/aws/aws-sdk-go-v2/service/signin v1.0.10 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.30.16 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.20 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.42.0 // indirect + github.com/aws/smithy-go v1.25.0 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/cenkalti/backoff/v5 v5.0.3 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/cloudevents/sdk-go/v2 v2.16.2 // indirect + github.com/containerd/errdefs v1.0.0 // indirect + github.com/containerd/errdefs/pkg v0.3.0 // indirect + github.com/containerd/log v0.1.0 // indirect + github.com/danieljoos/wincred v1.2.3 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/distribution/reference v0.6.0 // indirect + github.com/docker/docker v28.5.2+incompatible // indirect + github.com/docker/go-connections v0.7.0 // indirect + github.com/docker/go-units v0.5.0 // indirect + github.com/dustin/go-humanize v1.0.1 // indirect + github.com/eapache/go-resiliency v1.7.0 // indirect + github.com/eapache/queue v1.1.0 // indirect + github.com/expr-lang/expr v1.17.8 // indirect + github.com/fatih/color v1.19.0 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/fsnotify/fsnotify v1.9.0 // indirect + github.com/go-jose/go-jose/v4 v4.1.4 // indirect + github.com/go-logr/logr v1.4.3 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/godbus/dbus/v5 v5.2.2 // indirect + github.com/golang-jwt/jwt/v5 v5.3.1 // indirect + github.com/golobby/cast v1.3.3 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-hclog v1.6.3 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-retryablehttp v0.7.8 // indirect + github.com/hashicorp/go-rootcerts v1.0.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.2.0 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.7 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/golang-lru v1.0.2 // indirect + github.com/hashicorp/hcl v1.0.1-vault-7 // indirect + github.com/hashicorp/vault/api v1.23.0 // indirect + github.com/hashicorp/yamux v0.1.2 // indirect + github.com/itchyny/gojq v0.12.18 // indirect + github.com/itchyny/timefmt-go v0.1.7 // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect + github.com/jackc/pgx/v5 v5.9.1 // indirect + github.com/jackc/puddle/v2 v2.2.2 // indirect + github.com/jcmturner/aescts/v2 v2.0.0 // indirect + github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect + github.com/jcmturner/gofork v1.7.6 // indirect + github.com/jcmturner/gokrb5/v8 v8.4.4 // indirect + github.com/jcmturner/rpc/v2 v2.0.3 // indirect + github.com/json-iterator/go v1.1.13-0.20220915233716-71ac16282d12 // indirect + github.com/klauspost/compress v1.18.6 // indirect + github.com/mattn/go-colorable v0.1.14 // indirect + github.com/mattn/go-isatty v0.0.22 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/moby/docker-image-spec v1.3.1 // indirect + github.com/moby/sys/sequential v0.6.0 // indirect + github.com/moby/term v0.5.2 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/nats-io/nats.go v1.52.0 // indirect + github.com/nats-io/nkeys v0.4.15 // indirect + github.com/nats-io/nuid v1.0.1 // indirect + github.com/ncruces/go-strftime v1.0.0 // indirect + github.com/oklog/run v1.2.0 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.1.1 // indirect + github.com/pierrec/lz4/v4 v4.1.26 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/prometheus/client_golang v1.23.2 // indirect + github.com/prometheus/client_model v0.6.2 // indirect + github.com/prometheus/common v0.67.5 // indirect + github.com/prometheus/procfs v0.20.1 // indirect + github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 // indirect + github.com/redis/go-redis/v9 v9.19.0 // indirect + github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + github.com/xdg-go/pbkdf2 v1.0.0 // indirect + github.com/xdg-go/scram v1.2.0 // indirect + github.com/xdg-go/stringprep v1.0.4 // indirect + github.com/zalando/go-keyring v0.2.8 // indirect + go.opentelemetry.io/auto/sdk v1.2.1 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.68.0 // indirect + go.opentelemetry.io/otel v1.43.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0 // indirect + go.opentelemetry.io/otel/metric v1.43.0 // indirect + go.opentelemetry.io/otel/sdk v1.43.0 // indirect + go.opentelemetry.io/otel/trace v1.43.0 // indirect + go.opentelemetry.io/proto/otlp v1.10.0 // indirect + go.uber.org/atomic v1.11.0 // indirect + go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap v1.28.0 // indirect + go.yaml.in/yaml/v2 v2.4.4 // indirect + golang.org/x/crypto v0.51.0 // indirect + golang.org/x/net v0.54.0 // indirect + golang.org/x/oauth2 v0.36.0 // indirect + golang.org/x/sync v0.20.0 // indirect + golang.org/x/sys v0.44.0 // indirect + golang.org/x/text v0.37.0 // indirect + golang.org/x/time v0.15.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20260511170946-3700d4141b60 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260511170946-3700d4141b60 // indirect + google.golang.org/grpc v1.81.1 // indirect + google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + modernc.org/libc v1.70.0 // indirect + modernc.org/mathutil v1.7.1 // indirect + modernc.org/memory v1.11.0 // indirect + modernc.org/sqlite v1.47.0 // indirect +) + +replace github.com/GoCodeAlone/workflow => ../../../../.. diff --git a/cmd/wfctl/testdata/verify_capabilities/iac-good/go.sum b/cmd/wfctl/testdata/verify_capabilities/iac-good/go.sum new file mode 100644 index 00000000..044a174e --- /dev/null +++ b/cmd/wfctl/testdata/verify_capabilities/iac-good/go.sum @@ -0,0 +1,491 @@ +github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg= +github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk= +github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= +github.com/DataDog/datadog-go/v5 v5.8.3 h1:s58CUJ9s8lezjhTNJO/SxkPBv2qZjS3ktpRSqGF5n0s= +github.com/DataDog/datadog-go/v5 v5.8.3/go.mod h1:K9kcYBlxkcPP8tvvjZZKs/m1edNAUFzBbdpTUKfCsuw= +github.com/GoCodeAlone/go-plugin v1.7.0 h1:EwnhqPlXiNmp85S+MXnKKvm3YlfA6O4NzBb4+GSlEVY= +github.com/GoCodeAlone/go-plugin v1.7.0/go.mod h1:HbGQRZUIa+jbDfjsaZIMJYvrz+LnxL0mJpggfynSTMk= +github.com/GoCodeAlone/modular v1.13.0 h1:UfsegfAmPWcPYQOqYZFsw/LNySBmMDcthiOQe5bscqE= +github.com/GoCodeAlone/modular v1.13.0/go.mod h1:b06Pvgcc8HsGxvl30iO39zGH2jIWz467QEj2+OQL2Do= +github.com/GoCodeAlone/modular/modules/auth v1.15.0 h1:pBSkPSf4k4GLSbUQFLuPa+nFbfoJXGzSz9q89VoapZk= +github.com/GoCodeAlone/modular/modules/auth v1.15.0/go.mod h1:vmIm/LQrcURS2p02YwaELb+CZoHPtT0XB0v1i+sj9i4= +github.com/GoCodeAlone/modular/modules/eventbus/v2 v2.8.0 h1:buYs0TGNbAZgtTq1Qb+dfmTv3+ZOBIN0HbvVBLyNqxE= +github.com/GoCodeAlone/modular/modules/eventbus/v2 v2.8.0/go.mod h1:329flAKmwrPq2JEwu9iltWv6A83H/Di82Xze+kvdKDw= +github.com/GoCodeAlone/yaegi v0.17.2 h1:WK6Y6e0t1a6U7r+S2dN3CGWW1PizYD3zO0zneToZPxM= +github.com/GoCodeAlone/yaegi v0.17.2/go.mod h1:z5Pr6Wse6QJcQvpgxTxzMAevFarH0N37TG88Y9dprx0= +github.com/IBM/sarama v1.47.0 h1:GcQFEd12+KzfPYeLgN69Fh7vLCtYRhVIx0rO4TZO318= +github.com/IBM/sarama v1.47.0/go.mod h1:7gLLIU97nznOmA6TX++Qds+DRxH89P2XICY2KAQUzAY= +github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= +github.com/alicebob/miniredis/v2 v2.36.1 h1:Dvc5oAnNOr7BIfPn7tF269U8DvRW1dBG2D5n0WrfYMI= +github.com/alicebob/miniredis/v2 v2.36.1/go.mod h1:TcL7YfarKPGDAthEtl5NBeHZfeUQj6OXMm/+iu5cLMM= +github.com/antithesishq/antithesis-sdk-go v0.5.0-default-no-op h1:Ucf+QxEKMbPogRO5guBNe5cgd9uZgfoJLOYs8WWhtjM= +github.com/antithesishq/antithesis-sdk-go v0.5.0-default-no-op/go.mod h1:IUpT2DPAKh6i/YhSbt6Gl3v2yvUZjmKncl7U91fup7E= +github.com/aws/aws-sdk-go-v2 v1.41.6 h1:1AX0AthnBQzMx1vbmir3Y4WsnJgiydmnJjiLu+LvXOg= +github.com/aws/aws-sdk-go-v2 v1.41.6/go.mod h1:dy0UzBIfwSeot4grGvY1AqFWN5zgziMmWGzysDnHFcQ= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.8 h1:eBMB84YGghSocM7PsjmmPffTa+1FBUeNvGvFou6V/4o= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.8/go.mod h1:lyw7GFp3qENLh7kwzf7iMzAxDn+NzjXEAGjKS2UOKqI= +github.com/aws/aws-sdk-go-v2/config v1.32.16 h1:Q0iQ7quUgJP0F/SCRTieScnaMdXr9h/2+wze1u3cNeM= +github.com/aws/aws-sdk-go-v2/config v1.32.16/go.mod h1:duCCnJEFqpt2RC6no1iK6q+8HpwOAkiUua0pY507dQc= +github.com/aws/aws-sdk-go-v2/credentials v1.19.15 h1:fyvgWTszojq8hEnMi8PPBTvZdTtEVmAVyo+NFLHBhH4= +github.com/aws/aws-sdk-go-v2/credentials v1.19.15/go.mod h1:gJiYyMOjNg8OEdRWOf3CrFQxM2a98qmrtjx1zuiQfB8= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.22 h1:IOGsJ1xVWhsi+ZO7/NW8OuZZBtMJLZbk4P5HDjJO0jQ= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.22/go.mod h1:b+hYdbU+jGKfXE8kKM6g1+h+L/Go3vMvzlxBsiuGsxg= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.22 h1:GmLa5Kw1ESqtFpXsx5MmC84QWa/ZrLZvlJGa2y+4kcQ= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.22/go.mod h1:6sW9iWm9DK9YRpRGga/qzrzNLgKpT2cIxb7Vo2eNOp0= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.22 h1:dY4kWZiSaXIzxnKlj17nHnBcXXBfac6UlsAx2qL6XrU= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.22/go.mod h1:KIpEUx0JuRZLO7U6cbV204cWAEco2iC3l061IxlwLtI= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.23 h1:FPXsW9+gMuIeKmz7j6ENWcWtBGTe1kH8r9thNt5Uxx4= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.23/go.mod h1:7J8iGMdRKk6lw2C+cMIphgAnT8uTwBwNOsGkyOCm80U= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.8 h1:HtOTYcbVcGABLOVuPYaIihj6IlkqubBwFj10K5fxRek= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.8/go.mod h1:VsK9abqQeGlzPgUr+isNWzPlK2vKe9INMLWnY65f5Xs= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.22 h1:PUmZeJU6Y1Lbvt9WFuJ0ugUK2xn6hIWUBBbKuOWF30s= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.22/go.mod h1:nO6egFBoAaoXze24a2C0NjQCvdpk8OueRoYimvEB9jo= +github.com/aws/aws-sdk-go-v2/service/kinesis v1.43.4 h1:3m9iJtMtLq75jKRAfw0kapoHUlbzi0CRVigysBN/FHA= +github.com/aws/aws-sdk-go-v2/service/kinesis v1.43.4/go.mod h1:O2L6vGm4xacEuN2otHFMgn7yXXlgzFKzxrba0fy/yk8= +github.com/aws/aws-sdk-go-v2/service/signin v1.0.10 h1:a1Fq/KXn75wSzoJaPQTgZO0wHGqE9mjFnylnqEPTchA= +github.com/aws/aws-sdk-go-v2/service/signin v1.0.10/go.mod h1:p6+MXNxW7IA6dMgHfTAzljuwSKD0NCm/4lbS4t6+7vI= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.16 h1:x6bKbmDhsgSZwv6q19wY/u3rLk/3FGjJWyqKcIRufpE= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.16/go.mod h1:CudnEVKRtLn0+3uMV0yEXZ+YZOKnAtUJ5DmDhilVnIw= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.20 h1:oK/njaL8GtyEihkWMD4k3VgHCT64RQKkZwh0DG5j8ak= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.20/go.mod h1:JHs8/y1f3zY7U5WcuzoJ/yAYGYtNIVPKLIbp61euvmg= +github.com/aws/aws-sdk-go-v2/service/sts v1.42.0 h1:ks8KBcZPh3PYISr5dAiXCM5/Thcuxk8l+PG4+A0exds= +github.com/aws/aws-sdk-go-v2/service/sts v1.42.0/go.mod h1:pFw33T0WLvXU3rw1WBkpMlkgIn54eCB5FYLhjDc9Foo= +github.com/aws/smithy-go v1.25.0 h1:Sz/XJ64rwuiKtB6j98nDIPyYrV1nVNJ4YU74gttcl5U= +github.com/aws/smithy-go v1.25.0/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= +github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= +github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= +github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= +github.com/bufbuild/protocompile v0.10.0 h1:+jW/wnLMLxaCEG8AX9lD0bQ5v9h1RUiMKOBOT5ll9dM= +github.com/bufbuild/protocompile v0.10.0/go.mod h1:G9qQIQo0xZ6Uyj6CMNz0saGmx2so+KONo8/KrELABiY= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= +github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cloudevents/sdk-go/v2 v2.16.2 h1:ZYDFrYke4FD+jM8TZTJJO6JhKHzOQl2oqpFK1D+NnQM= +github.com/cloudevents/sdk-go/v2 v2.16.2/go.mod h1:laOcGImm4nVJEU+PHnUrKL56CKmRL65RlQF0kRmW/kg= +github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= +github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= +github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE= +github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk= +github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= +github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/cucumber/gherkin/go/v26 v26.2.0 h1:EgIjePLWiPeslwIWmNQ3XHcypPsWAHoMCz/YEBKP4GI= +github.com/cucumber/gherkin/go/v26 v26.2.0/go.mod h1:t2GAPnB8maCT4lkHL99BDCVNzCh1d7dBhCLt150Nr/0= +github.com/cucumber/godog v0.15.1 h1:rb/6oHDdvVZKS66hrhpjFQFHjthFSrQBCOI1LwshNTI= +github.com/cucumber/godog v0.15.1/go.mod h1:qju+SQDewOljHuq9NSM66s0xEhogx0q30flfxL4WUk8= +github.com/cucumber/messages/go/v21 v21.0.1 h1:wzA0LxwjlWQYZd32VTlAVDTkW6inOFmSM+RuOwHZiMI= +github.com/cucumber/messages/go/v21 v21.0.1/go.mod h1:zheH/2HS9JLVFukdrsPWoPdmUtmYQAQPLk7w5vWsk5s= +github.com/danieljoos/wincred v1.2.3 h1:v7dZC2x32Ut3nEfRH+vhoZGvN72+dQ/snVXo/vMFLdQ= +github.com/danieljoos/wincred v1.2.3/go.mod h1:6qqX0WNrS4RzPZ1tnroDzq9kY3fu1KwE7MRLQK4X0bs= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= +github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= +github.com/docker/docker v28.5.2+incompatible h1:DBX0Y0zAjZbSrm1uzOkdr1onVghKaftjlSWt4AFexzM= +github.com/docker/docker v28.5.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.7.0 h1:6SsRfJddP22WMrCkj19x9WKjEDTB+ahsdiGYf0mN39c= +github.com/docker/go-connections v0.7.0/go.mod h1:no1qkHdjq7kLMGUXYAduOhYPSJxxvgWBh7ogVvptn3Q= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/eapache/go-resiliency v1.7.0 h1:n3NRTnBn5N0Cbi/IeOHuQn9s2UwVUH7Ga0ZWcP+9JTA= +github.com/eapache/go-resiliency v1.7.0/go.mod h1:5yPzW0MIvSe0JDsv0v+DvcjEv2FyD6iZYSs1ZI+iQho= +github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/expr-lang/expr v1.17.8 h1:W1loDTT+0PQf5YteHSTpju2qfUfNoBt4yw9+wOEU9VM= +github.com/expr-lang/expr v1.17.8/go.mod h1:8/vRC7+7HBzESEqt5kKpYXxrxkr31SaO8r40VO/1IT4= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/color v1.19.0 h1:Zp3PiM21/9Ld6FzSKyL5c/BULoe/ONr9KlbYVOfG8+w= +github.com/fatih/color v1.19.0/go.mod h1:zNk67I0ZUT1bEGsSGyCZYZNrHuTkJJB+r6Q9VuMi0LE= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= +github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= +github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +github.com/go-jose/go-jose/v4 v4.1.4 h1:moDMcTHmvE6Groj34emNPLs/qtYXRVcd6S7NHbHz3kA= +github.com/go-jose/go-jose/v4 v4.1.4/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U= +github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= +github.com/godbus/dbus/v5 v5.2.2 h1:TUR3TgtSVDmjiXOgAAyaZbYmIeP3DPkld3jgKGV8mXQ= +github.com/godbus/dbus/v5 v5.2.2/go.mod h1:3AAv2+hPq5rdnr5txxxRwiGjPXamgoIHgz9FPBfOp3c= +github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= +github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY= +github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/golobby/cast v1.3.3 h1:s2Lawb9RMz7YyYf8IrfMQY4IFmA1R/lgfmj97Vc6fig= +github.com/golobby/cast v1.3.3/go.mod h1:0oDO5IT84HTXcbLDf1YXuk0xtg/cRDrxhbpWKxwtJCY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/go-tpm v0.9.8 h1:slArAR9Ft+1ybZu0lBwpSmpwhRXaa85hWtMinMyRAWo= +github.com/google/go-tpm v0.9.8/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs= +github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= +github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 h1:5VipnvEpbqr2gA2VbM+nYVbkIF28c5ZQfqCBQ5g2xfk= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0/go.mod h1:Hyl3n6Twe1hvtd9XUXDec4pTvgMSEixRuQKPTMH2bNs= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= +github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-memdb v1.3.5 h1:b3taDMxCBCBVgyRrS1AZVHO14ubMYZB++QpNhBg+Nyo= +github.com/hashicorp/go-memdb v1.3.5/go.mod h1:8IVKKBkVe+fxFgdFOYxzQQNjz+sWCyHCdIC/+5+Vy1Y= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-retryablehttp v0.7.8 h1:ylXZWnqa7Lhqpk0L1P1LzDtGcCR0rPVUrx/c8Unxc48= +github.com/hashicorp/go-retryablehttp v0.7.8/go.mod h1:rjiScheydd+CxvumBsIrFKlx3iS0jrZ7LvzFGFmuKbw= +github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-secure-stdlib/parseutil v0.2.0 h1:U+kC2dOhMFQctRfhK0gRctKAPTloZdMU5ZJxaesJ/VM= +github.com/hashicorp/go-secure-stdlib/parseutil v0.2.0/go.mod h1:Ll013mhdmsVDuoIXVfBtvgGJsXDYkTw1kooNcoCXuE0= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.7 h1:G+pTkSO01HpR5qCxg7lxfsFEZaG+C0VssTy/9dbT+Fw= +github.com/hashicorp/go-sockaddr v1.0.7/go.mod h1:FZQbEYa1pxkQ7WLpyXJ6cbjpT8q0YgQaK/JakXqGyWw= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= +github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= +github.com/hashicorp/hcl v1.0.1-vault-7 h1:ag5OxFVy3QYTFTJODRzTKVZ6xvdfLLCA1cy/Y6xGI0I= +github.com/hashicorp/hcl v1.0.1-vault-7/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM= +github.com/hashicorp/vault/api v1.23.0 h1:gXgluBsSECfRWTSW9niY2jwg2e9mMJc4WoHNv4g3h6A= +github.com/hashicorp/vault/api v1.23.0/go.mod h1:zransKiB9ftp+kgY8ydjnvCU7Wk8i9L0DYWpXeMj9ko= +github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8= +github.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns= +github.com/itchyny/gojq v0.12.18 h1:gFGHyt/MLbG9n6dqnvlliiya2TaMMh6FFaR2b1H6Drc= +github.com/itchyny/gojq v0.12.18/go.mod h1:4hPoZ/3lN9fDL1D+aK7DY1f39XZpY9+1Xpjz8atrEkg= +github.com/itchyny/timefmt-go v0.1.7 h1:xyftit9Tbw+Dc/huSSPJaEmX1TVL8lw5vxjJLK4GMMA= +github.com/itchyny/timefmt-go v0.1.7/go.mod h1:5E46Q+zj7vbTgWY8o5YkMeYb4I6GeWLFnetPy5oBrAI= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.9.1 h1:uwrxJXBnx76nyISkhr33kQLlUqjv7et7b9FjCen/tdc= +github.com/jackc/pgx/v5 v5.9.1/go.mod h1:mal1tBGAFfLHvZzaYh77YS/eC6IX9OWbRV1QIIM0Jn4= +github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= +github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= +github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= +github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo= +github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= +github.com/jcmturner/gofork v1.7.6 h1:QH0l3hzAU1tfT3rZCnW5zXl+orbkNMMRGJfdJjHVETg= +github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo= +github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o= +github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= +github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh687T8= +github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs= +github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= +github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= +github.com/jhump/protoreflect v1.16.0 h1:54fZg+49widqXYQ0b+usAFHbMkBGR4PpXrsHc8+TBDg= +github.com/jhump/protoreflect v1.16.0/go.mod h1:oYPd7nPvcBw/5wlDfm/AVmU9zH9BgqGCI469pGxfj/8= +github.com/json-iterator/go v1.1.13-0.20220915233716-71ac16282d12 h1:9Nu54bhS/H/Kgo2/7xNSUuC5G28VR8ljfrLKU2G4IjU= +github.com/json-iterator/go v1.1.13-0.20220915233716-71ac16282d12/go.mod h1:TBzl5BIHNXfS9+C35ZyJaklL7mLDbgUkcgXzSLa8Tk0= +github.com/klauspost/compress v1.18.6 h1:2jupLlAwFm95+YDR+NwD2MEfFO9d4z4Prjl1XXDjuao= +github.com/klauspost/compress v1.18.6/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= +github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= +github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw4= +github.com/mattn/go-isatty v0.0.22/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4= +github.com/minio/highwayhash v1.0.4-0.20251030100505-070ab1a87a76 h1:KGuD/pM2JpL9FAYvBrnBBeENKZNh6eNtjqytV6TYjnk= +github.com/minio/highwayhash v1.0.4-0.20251030100505-070ab1a87a76/go.mod h1:GGYsuwP/fPD6Y9hMiXuapVvlIUEhFhMTh0rxU3ik1LQ= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= +github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= +github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw= +github.com/moby/sys/atomicwriter v0.1.0/go.mod h1:Ul8oqv2ZMNHOceF643P6FKPXeCmYtlQMvpizfsSoaWs= +github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU= +github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko= +github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ= +github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= +github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/morikuni/aec v1.1.0 h1:vBBl0pUnvi/Je71dsRrhMBtreIqNMYErSAbEeb8jrXQ= +github.com/morikuni/aec v1.1.0/go.mod h1:xDRgiq/iw5l+zkao76YTKzKttOp2cwPEne25HDkJnBw= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/nats-io/jwt/v2 v2.8.0 h1:K7uzyz50+yGZDO5o772eRE7atlcSEENpL7P+b74JV1g= +github.com/nats-io/jwt/v2 v2.8.0/go.mod h1:me11pOkwObtcBNR8AiMrUbtVOUGkqYjMQZ6jnSdVUIA= +github.com/nats-io/nats-server/v2 v2.12.4 h1:ZnT10v2LU2Xcoiy8ek9X6Se4YG8EuMfIfvAEuFVx1Ts= +github.com/nats-io/nats-server/v2 v2.12.4/go.mod h1:5MCp/pqm5SEfsvVZ31ll1088ZTwEUdvRX1Hmh/mTTDg= +github.com/nats-io/nats.go v1.52.0 h1:n3avV4VBsCgsdwh71TppsTwtv+QdPs7ntSKM8qJLGsc= +github.com/nats-io/nats.go v1.52.0/go.mod h1:26HypzazeOkyO3/mqd1zZd53STJN0EjCYF9Uy2ZOBno= +github.com/nats-io/nkeys v0.4.15 h1:JACV5jRVO9V856KOapQ7x+EY8Jo3qw1vJt/9Jpwzkk4= +github.com/nats-io/nkeys v0.4.15/go.mod h1:CpMchTXC9fxA5zrMo4KpySxNjiDVvr8ANOSZdiNfUrs= +github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= +github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w= +github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= +github.com/oklog/run v1.2.0 h1:O8x3yXwah4A73hJdlrwo/2X6J62gE5qTMusH0dvz60E= +github.com/oklog/run v1.2.0/go.mod h1:mgDbKRSwPhJfesJ4PntqFUbKQRZ50NgmZTSPlFA0YFk= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= +github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= +github.com/pierrec/lz4/v4 v4.1.26 h1:GrpZw1gZttORinvzBdXPUXATeqlJjqUG/D87TKMnhjY= +github.com/pierrec/lz4/v4 v4.1.26/go.mod h1:EoQMVJgeeEOMsCqCzqFm2O0cJvljX2nGZjcRIPL34O4= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= +github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= +github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= +github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= +github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4= +github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw= +github.com/prometheus/procfs v0.20.1 h1:XwbrGOIplXW/AU3YhIhLODXMJYyC1isLFfYCsTEycfc= +github.com/prometheus/procfs v0.20.1/go.mod h1:o9EMBZGRyvDrSPH1RqdxhojkuXstoe4UlK79eF5TGGo= +github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 h1:bsUq1dX0N8AOIL7EB/X911+m4EHsnWEHeJ0c+3TTBrg= +github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/redis/go-redis/v9 v9.19.0 h1:XPVaaPSnG6RhYf7p+rmSa9zZfeVAnWsH5h3lxthOm/k= +github.com/redis/go-redis/v9 v9.19.0/go.mod h1:v/M13XI1PVCDcm01VtPFOADfZtHf8YW3baQf57KlIkA= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= +github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ= +github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= +github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= +github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= +github.com/xdg-go/scram v1.2.0 h1:bYKF2AEwG5rqd1BumT4gAnvwU/M9nBp2pTSxeZw7Wvs= +github.com/xdg-go/scram v1.2.0/go.mod h1:3dlrS0iBaWKYVt2ZfA4cj48umJZ+cAEbR6/SjLA88I8= +github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8= +github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M= +github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw= +github.com/zalando/go-keyring v0.2.8 h1:6sD/Ucpl7jNq10rM2pgqTs0sZ9V3qMrqfIIy5YPccHs= +github.com/zalando/go-keyring v0.2.8/go.mod h1:tsMo+VpRq5NGyKfxoBVjCuMrG47yj8cmakZDO5QGii0= +github.com/zeebo/xxh3 v1.1.0 h1:s7DLGDK45Dyfg7++yxI0khrfwq9661w9EN78eP/UZVs= +github.com/zeebo/xxh3 v1.1.0/go.mod h1:IisAie1LELR4xhVinxWS5+zf1lA4p0MW4T+w+W07F5s= +go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= +go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.68.0 h1:CqXxU8VOmDefoh0+ztfGaymYbhdB/tT3zs79QaZTNGY= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.68.0/go.mod h1:BuhAPThV8PBHBvg8ZzZ/Ok3idOdhWIodywz2xEcRbJo= +go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I= +go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 h1:88Y4s2C8oTui1LGM6bTWkw0ICGcOLCAI5l6zsD1j20k= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0/go.mod h1:Vl1/iaggsuRlrHf/hfPJPvVag77kKyvrLeD10kpMl+A= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0 h1:3iZJKlCZufyRzPzlQhUIWVmfltrXuGyfjREgGP3UUjc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0/go.mod h1:/G+nUPfhq2e+qiXMGxMwumDrP5jtzU+mWN7/sjT2rak= +go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM= +go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY= +go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg= +go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg= +go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw= +go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A= +go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A= +go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0= +go.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g= +go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk= +go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= +go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= +go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.28.0 h1:IZzaP1Fv73/T/pBMLk4VutPl36uNC+OSUh3JLG3FIjo= +go.uber.org/zap v1.28.0/go.mod h1:rDLpOi171uODNm/mxFcuYWxDsqWSAVkFdX4XojSKg/Q= +go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ= +go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ= +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/crypto v0.51.0 h1:IBPXwPfKxY7cWQZ38ZCIRPI50YLeevDLlLnyC5wRGTI= +golang.org/x/crypto v0.51.0/go.mod h1:8AdwkbraGNABw2kOX6YFPs3WM22XqI4EXEd8g+x7Oc8= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4= +golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.54.0 h1:2zJIZAxAHV/OHCDTCOHAYehQzLfSXuf/5SoL/Dv6w/w= +golang.org/x/net v0.54.0/go.mod h1:Sj4oj8jK6XmHpBZU/zWHw3BV3abl4Kvi+Ut7cQcY+cQ= +golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= +golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= +golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ= +golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc= +golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38= +golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= +golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8= +golang.org/x/tools v0.45.0/go.mod h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= +gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= +google.golang.org/genproto/googleapis/api v0.0.0-20260511170946-3700d4141b60 h1:3WsB1FAbiRIf2tOxscWKs3pQBD9he1NsrnbhMuWfekc= +google.golang.org/genproto/googleapis/api v0.0.0-20260511170946-3700d4141b60/go.mod h1:7yoXV7RIh5gblj/xVYoogxAWvA9wUeVbpsK/M694l00= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260511170946-3700d4141b60 h1:seT2EwLWM78plQ7wcDfuWBc/4FAEAXDDiaSol4ku4qo= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260511170946-3700d4141b60/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= +google.golang.org/grpc v1.81.1 h1:VnnIIZ88UzOOKLukQi+ImGz8O1Wdp8nAGGnvOfEIWQQ= +google.golang.org/grpc v1.81.1/go.mod h1:xGH9GfzOyMTGIOXBJmXt+BX/V0kcdQbdcuwQ/zNw42I= +google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af h1:+5/Sw3GsDNlEmu7TfklWKPdQ0Ykja5VEmq2i817+jbI= +google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= +gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= +modernc.org/cc/v4 v4.27.1 h1:9W30zRlYrefrDV2JE2O8VDtJ1yPGownxciz5rrbQZis= +modernc.org/cc/v4 v4.27.1/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0= +modernc.org/ccgo/v4 v4.32.0 h1:hjG66bI/kqIPX1b2yT6fr/jt+QedtP2fqojG2VrFuVw= +modernc.org/ccgo/v4 v4.32.0/go.mod h1:6F08EBCx5uQc38kMGl+0Nm0oWczoo1c7cgpzEry7Uc0= +modernc.org/fileutil v1.4.0 h1:j6ZzNTftVS054gi281TyLjHPp6CPHr2KCxEXjEbD6SM= +modernc.org/fileutil v1.4.0/go.mod h1:EqdKFDxiByqxLk8ozOxObDSfcVOv/54xDs/DUHdvCUU= +modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI= +modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito= +modernc.org/gc/v3 v3.1.2 h1:ZtDCnhonXSZexk/AYsegNRV1lJGgaNZJuKjJSWKyEqo= +modernc.org/gc/v3 v3.1.2/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY= +modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks= +modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI= +modernc.org/libc v1.70.0 h1:U58NawXqXbgpZ/dcdS9kMshu08aiA6b7gusEusqzNkw= +modernc.org/libc v1.70.0/go.mod h1:OVmxFGP1CI/Z4L3E0Q3Mf1PDE0BucwMkcXjjLntvHJo= +modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU= +modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg= +modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI= +modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw= +modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8= +modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns= +modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w= +modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE= +modernc.org/sqlite v1.47.0 h1:R1XyaNpoW4Et9yly+I2EeX7pBza/w+pmYee/0HJDyKk= +modernc.org/sqlite v1.47.0/go.mod h1:hWjRO6Tj/5Ik8ieqxQybiEOUXy0NJFNp2tpvVpKlvig= +modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0= +modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A= +modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= +modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= diff --git a/cmd/wfctl/testdata/verify_capabilities/iac-good/main.go b/cmd/wfctl/testdata/verify_capabilities/iac-good/main.go new file mode 100644 index 00000000..ecb03616 --- /dev/null +++ b/cmd/wfctl/testdata/verify_capabilities/iac-good/main.go @@ -0,0 +1,31 @@ +package main + +import ( + "context" + _ "embed" + + pb "github.com/GoCodeAlone/workflow/plugin/external/proto" + sdk "github.com/GoCodeAlone/workflow/plugin/external/sdk" +) + +var Version = "dev" + +//go:embed plugin.json +var manifestData []byte + +// FinalizeApply satisfied by embedded UnimplementedIaCProviderFinalizerServer. +type fixture struct { + pb.UnimplementedIaCProviderRequiredServer + pb.UnimplementedIaCProviderFinalizerServer +} + +func (fixture) Name(context.Context, *pb.NameRequest) (*pb.NameResponse, error) { + return &pb.NameResponse{Name: "verify-iac-good"}, nil +} + +func main() { + sdk.ServeIaCPlugin(fixture{}, sdk.IaCServeOptions{ + ManifestProvider: sdk.MustEmbedManifest(manifestData), + BuildVersion: sdk.ResolveBuildVersion(Version), + }) +} diff --git a/cmd/wfctl/testdata/verify_capabilities/iac-good/plugin.json b/cmd/wfctl/testdata/verify_capabilities/iac-good/plugin.json new file mode 100644 index 00000000..92e565f2 --- /dev/null +++ b/cmd/wfctl/testdata/verify_capabilities/iac-good/plugin.json @@ -0,0 +1,11 @@ +{ + "name": "verify-iac-good", + "version": "0.0.0", + "minEngineVersion": "v0.62.0", + "author": "test fixture", + "description": "IaC fixture: registered services match plugin.json declared services", + "iacServices": [ + "workflow.plugin.external.iac.IaCProviderRequired", + "workflow.plugin.external.iac.IaCProviderFinalizer" + ] +} diff --git a/cmd/wfctl/testdata/verify_capabilities/iac-missing-service/go.mod b/cmd/wfctl/testdata/verify_capabilities/iac-missing-service/go.mod new file mode 100644 index 00000000..fae8c0c4 --- /dev/null +++ b/cmd/wfctl/testdata/verify_capabilities/iac-missing-service/go.mod @@ -0,0 +1,152 @@ +module github.com/test/iac-missing-service + +go 1.26.0 + +require github.com/GoCodeAlone/workflow v0.63.2 + +require ( + github.com/BurntSushi/toml v1.6.0 // indirect + github.com/DataDog/datadog-go/v5 v5.8.3 // indirect + github.com/GoCodeAlone/go-plugin v1.7.0 // indirect + github.com/GoCodeAlone/modular v1.13.0 // indirect + github.com/GoCodeAlone/modular/modules/auth v1.15.0 // indirect + github.com/GoCodeAlone/modular/modules/eventbus/v2 v2.8.0 // indirect + github.com/GoCodeAlone/yaegi v0.17.2 // indirect + github.com/IBM/sarama v1.47.0 // indirect + github.com/Microsoft/go-winio v0.6.2 // indirect + github.com/aws/aws-sdk-go-v2 v1.41.6 // indirect + github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.8 // indirect + github.com/aws/aws-sdk-go-v2/config v1.32.16 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.19.15 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.22 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.22 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.22 // indirect + github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.23 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.8 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.22 // indirect + github.com/aws/aws-sdk-go-v2/service/kinesis v1.43.4 // indirect + github.com/aws/aws-sdk-go-v2/service/signin v1.0.10 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.30.16 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.20 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.42.0 // indirect + github.com/aws/smithy-go v1.25.0 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/cenkalti/backoff/v5 v5.0.3 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/cloudevents/sdk-go/v2 v2.16.2 // indirect + github.com/containerd/errdefs v1.0.0 // indirect + github.com/containerd/errdefs/pkg v0.3.0 // indirect + github.com/containerd/log v0.1.0 // indirect + github.com/danieljoos/wincred v1.2.3 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/distribution/reference v0.6.0 // indirect + github.com/docker/docker v28.5.2+incompatible // indirect + github.com/docker/go-connections v0.7.0 // indirect + github.com/docker/go-units v0.5.0 // indirect + github.com/dustin/go-humanize v1.0.1 // indirect + github.com/eapache/go-resiliency v1.7.0 // indirect + github.com/eapache/queue v1.1.0 // indirect + github.com/expr-lang/expr v1.17.8 // indirect + github.com/fatih/color v1.19.0 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/fsnotify/fsnotify v1.9.0 // indirect + github.com/go-jose/go-jose/v4 v4.1.4 // indirect + github.com/go-logr/logr v1.4.3 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/godbus/dbus/v5 v5.2.2 // indirect + github.com/golang-jwt/jwt/v5 v5.3.1 // indirect + github.com/golobby/cast v1.3.3 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-hclog v1.6.3 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-retryablehttp v0.7.8 // indirect + github.com/hashicorp/go-rootcerts v1.0.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.2.0 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.7 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/golang-lru v1.0.2 // indirect + github.com/hashicorp/hcl v1.0.1-vault-7 // indirect + github.com/hashicorp/vault/api v1.23.0 // indirect + github.com/hashicorp/yamux v0.1.2 // indirect + github.com/itchyny/gojq v0.12.18 // indirect + github.com/itchyny/timefmt-go v0.1.7 // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect + github.com/jackc/pgx/v5 v5.9.1 // indirect + github.com/jackc/puddle/v2 v2.2.2 // indirect + github.com/jcmturner/aescts/v2 v2.0.0 // indirect + github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect + github.com/jcmturner/gofork v1.7.6 // indirect + github.com/jcmturner/gokrb5/v8 v8.4.4 // indirect + github.com/jcmturner/rpc/v2 v2.0.3 // indirect + github.com/json-iterator/go v1.1.13-0.20220915233716-71ac16282d12 // indirect + github.com/klauspost/compress v1.18.6 // indirect + github.com/mattn/go-colorable v0.1.14 // indirect + github.com/mattn/go-isatty v0.0.22 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/moby/docker-image-spec v1.3.1 // indirect + github.com/moby/sys/sequential v0.6.0 // indirect + github.com/moby/term v0.5.2 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/nats-io/nats.go v1.52.0 // indirect + github.com/nats-io/nkeys v0.4.15 // indirect + github.com/nats-io/nuid v1.0.1 // indirect + github.com/ncruces/go-strftime v1.0.0 // indirect + github.com/oklog/run v1.2.0 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.1.1 // indirect + github.com/pierrec/lz4/v4 v4.1.26 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/prometheus/client_golang v1.23.2 // indirect + github.com/prometheus/client_model v0.6.2 // indirect + github.com/prometheus/common v0.67.5 // indirect + github.com/prometheus/procfs v0.20.1 // indirect + github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 // indirect + github.com/redis/go-redis/v9 v9.19.0 // indirect + github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + github.com/xdg-go/pbkdf2 v1.0.0 // indirect + github.com/xdg-go/scram v1.2.0 // indirect + github.com/xdg-go/stringprep v1.0.4 // indirect + github.com/zalando/go-keyring v0.2.8 // indirect + go.opentelemetry.io/auto/sdk v1.2.1 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.68.0 // indirect + go.opentelemetry.io/otel v1.43.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0 // indirect + go.opentelemetry.io/otel/metric v1.43.0 // indirect + go.opentelemetry.io/otel/sdk v1.43.0 // indirect + go.opentelemetry.io/otel/trace v1.43.0 // indirect + go.opentelemetry.io/proto/otlp v1.10.0 // indirect + go.uber.org/atomic v1.11.0 // indirect + go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap v1.28.0 // indirect + go.yaml.in/yaml/v2 v2.4.4 // indirect + golang.org/x/crypto v0.51.0 // indirect + golang.org/x/net v0.54.0 // indirect + golang.org/x/oauth2 v0.36.0 // indirect + golang.org/x/sync v0.20.0 // indirect + golang.org/x/sys v0.44.0 // indirect + golang.org/x/text v0.37.0 // indirect + golang.org/x/time v0.15.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20260511170946-3700d4141b60 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260511170946-3700d4141b60 // indirect + google.golang.org/grpc v1.81.1 // indirect + google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + modernc.org/libc v1.70.0 // indirect + modernc.org/mathutil v1.7.1 // indirect + modernc.org/memory v1.11.0 // indirect + modernc.org/sqlite v1.47.0 // indirect +) + +replace github.com/GoCodeAlone/workflow => ../../../../.. diff --git a/cmd/wfctl/testdata/verify_capabilities/iac-missing-service/go.sum b/cmd/wfctl/testdata/verify_capabilities/iac-missing-service/go.sum new file mode 100644 index 00000000..044a174e --- /dev/null +++ b/cmd/wfctl/testdata/verify_capabilities/iac-missing-service/go.sum @@ -0,0 +1,491 @@ +github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg= +github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk= +github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= +github.com/DataDog/datadog-go/v5 v5.8.3 h1:s58CUJ9s8lezjhTNJO/SxkPBv2qZjS3ktpRSqGF5n0s= +github.com/DataDog/datadog-go/v5 v5.8.3/go.mod h1:K9kcYBlxkcPP8tvvjZZKs/m1edNAUFzBbdpTUKfCsuw= +github.com/GoCodeAlone/go-plugin v1.7.0 h1:EwnhqPlXiNmp85S+MXnKKvm3YlfA6O4NzBb4+GSlEVY= +github.com/GoCodeAlone/go-plugin v1.7.0/go.mod h1:HbGQRZUIa+jbDfjsaZIMJYvrz+LnxL0mJpggfynSTMk= +github.com/GoCodeAlone/modular v1.13.0 h1:UfsegfAmPWcPYQOqYZFsw/LNySBmMDcthiOQe5bscqE= +github.com/GoCodeAlone/modular v1.13.0/go.mod h1:b06Pvgcc8HsGxvl30iO39zGH2jIWz467QEj2+OQL2Do= +github.com/GoCodeAlone/modular/modules/auth v1.15.0 h1:pBSkPSf4k4GLSbUQFLuPa+nFbfoJXGzSz9q89VoapZk= +github.com/GoCodeAlone/modular/modules/auth v1.15.0/go.mod h1:vmIm/LQrcURS2p02YwaELb+CZoHPtT0XB0v1i+sj9i4= +github.com/GoCodeAlone/modular/modules/eventbus/v2 v2.8.0 h1:buYs0TGNbAZgtTq1Qb+dfmTv3+ZOBIN0HbvVBLyNqxE= +github.com/GoCodeAlone/modular/modules/eventbus/v2 v2.8.0/go.mod h1:329flAKmwrPq2JEwu9iltWv6A83H/Di82Xze+kvdKDw= +github.com/GoCodeAlone/yaegi v0.17.2 h1:WK6Y6e0t1a6U7r+S2dN3CGWW1PizYD3zO0zneToZPxM= +github.com/GoCodeAlone/yaegi v0.17.2/go.mod h1:z5Pr6Wse6QJcQvpgxTxzMAevFarH0N37TG88Y9dprx0= +github.com/IBM/sarama v1.47.0 h1:GcQFEd12+KzfPYeLgN69Fh7vLCtYRhVIx0rO4TZO318= +github.com/IBM/sarama v1.47.0/go.mod h1:7gLLIU97nznOmA6TX++Qds+DRxH89P2XICY2KAQUzAY= +github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= +github.com/alicebob/miniredis/v2 v2.36.1 h1:Dvc5oAnNOr7BIfPn7tF269U8DvRW1dBG2D5n0WrfYMI= +github.com/alicebob/miniredis/v2 v2.36.1/go.mod h1:TcL7YfarKPGDAthEtl5NBeHZfeUQj6OXMm/+iu5cLMM= +github.com/antithesishq/antithesis-sdk-go v0.5.0-default-no-op h1:Ucf+QxEKMbPogRO5guBNe5cgd9uZgfoJLOYs8WWhtjM= +github.com/antithesishq/antithesis-sdk-go v0.5.0-default-no-op/go.mod h1:IUpT2DPAKh6i/YhSbt6Gl3v2yvUZjmKncl7U91fup7E= +github.com/aws/aws-sdk-go-v2 v1.41.6 h1:1AX0AthnBQzMx1vbmir3Y4WsnJgiydmnJjiLu+LvXOg= +github.com/aws/aws-sdk-go-v2 v1.41.6/go.mod h1:dy0UzBIfwSeot4grGvY1AqFWN5zgziMmWGzysDnHFcQ= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.8 h1:eBMB84YGghSocM7PsjmmPffTa+1FBUeNvGvFou6V/4o= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.8/go.mod h1:lyw7GFp3qENLh7kwzf7iMzAxDn+NzjXEAGjKS2UOKqI= +github.com/aws/aws-sdk-go-v2/config v1.32.16 h1:Q0iQ7quUgJP0F/SCRTieScnaMdXr9h/2+wze1u3cNeM= +github.com/aws/aws-sdk-go-v2/config v1.32.16/go.mod h1:duCCnJEFqpt2RC6no1iK6q+8HpwOAkiUua0pY507dQc= +github.com/aws/aws-sdk-go-v2/credentials v1.19.15 h1:fyvgWTszojq8hEnMi8PPBTvZdTtEVmAVyo+NFLHBhH4= +github.com/aws/aws-sdk-go-v2/credentials v1.19.15/go.mod h1:gJiYyMOjNg8OEdRWOf3CrFQxM2a98qmrtjx1zuiQfB8= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.22 h1:IOGsJ1xVWhsi+ZO7/NW8OuZZBtMJLZbk4P5HDjJO0jQ= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.22/go.mod h1:b+hYdbU+jGKfXE8kKM6g1+h+L/Go3vMvzlxBsiuGsxg= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.22 h1:GmLa5Kw1ESqtFpXsx5MmC84QWa/ZrLZvlJGa2y+4kcQ= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.22/go.mod h1:6sW9iWm9DK9YRpRGga/qzrzNLgKpT2cIxb7Vo2eNOp0= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.22 h1:dY4kWZiSaXIzxnKlj17nHnBcXXBfac6UlsAx2qL6XrU= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.22/go.mod h1:KIpEUx0JuRZLO7U6cbV204cWAEco2iC3l061IxlwLtI= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.23 h1:FPXsW9+gMuIeKmz7j6ENWcWtBGTe1kH8r9thNt5Uxx4= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.23/go.mod h1:7J8iGMdRKk6lw2C+cMIphgAnT8uTwBwNOsGkyOCm80U= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.8 h1:HtOTYcbVcGABLOVuPYaIihj6IlkqubBwFj10K5fxRek= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.8/go.mod h1:VsK9abqQeGlzPgUr+isNWzPlK2vKe9INMLWnY65f5Xs= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.22 h1:PUmZeJU6Y1Lbvt9WFuJ0ugUK2xn6hIWUBBbKuOWF30s= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.22/go.mod h1:nO6egFBoAaoXze24a2C0NjQCvdpk8OueRoYimvEB9jo= +github.com/aws/aws-sdk-go-v2/service/kinesis v1.43.4 h1:3m9iJtMtLq75jKRAfw0kapoHUlbzi0CRVigysBN/FHA= +github.com/aws/aws-sdk-go-v2/service/kinesis v1.43.4/go.mod h1:O2L6vGm4xacEuN2otHFMgn7yXXlgzFKzxrba0fy/yk8= +github.com/aws/aws-sdk-go-v2/service/signin v1.0.10 h1:a1Fq/KXn75wSzoJaPQTgZO0wHGqE9mjFnylnqEPTchA= +github.com/aws/aws-sdk-go-v2/service/signin v1.0.10/go.mod h1:p6+MXNxW7IA6dMgHfTAzljuwSKD0NCm/4lbS4t6+7vI= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.16 h1:x6bKbmDhsgSZwv6q19wY/u3rLk/3FGjJWyqKcIRufpE= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.16/go.mod h1:CudnEVKRtLn0+3uMV0yEXZ+YZOKnAtUJ5DmDhilVnIw= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.20 h1:oK/njaL8GtyEihkWMD4k3VgHCT64RQKkZwh0DG5j8ak= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.20/go.mod h1:JHs8/y1f3zY7U5WcuzoJ/yAYGYtNIVPKLIbp61euvmg= +github.com/aws/aws-sdk-go-v2/service/sts v1.42.0 h1:ks8KBcZPh3PYISr5dAiXCM5/Thcuxk8l+PG4+A0exds= +github.com/aws/aws-sdk-go-v2/service/sts v1.42.0/go.mod h1:pFw33T0WLvXU3rw1WBkpMlkgIn54eCB5FYLhjDc9Foo= +github.com/aws/smithy-go v1.25.0 h1:Sz/XJ64rwuiKtB6j98nDIPyYrV1nVNJ4YU74gttcl5U= +github.com/aws/smithy-go v1.25.0/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= +github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= +github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= +github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= +github.com/bufbuild/protocompile v0.10.0 h1:+jW/wnLMLxaCEG8AX9lD0bQ5v9h1RUiMKOBOT5ll9dM= +github.com/bufbuild/protocompile v0.10.0/go.mod h1:G9qQIQo0xZ6Uyj6CMNz0saGmx2so+KONo8/KrELABiY= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= +github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cloudevents/sdk-go/v2 v2.16.2 h1:ZYDFrYke4FD+jM8TZTJJO6JhKHzOQl2oqpFK1D+NnQM= +github.com/cloudevents/sdk-go/v2 v2.16.2/go.mod h1:laOcGImm4nVJEU+PHnUrKL56CKmRL65RlQF0kRmW/kg= +github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= +github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= +github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE= +github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk= +github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= +github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/cucumber/gherkin/go/v26 v26.2.0 h1:EgIjePLWiPeslwIWmNQ3XHcypPsWAHoMCz/YEBKP4GI= +github.com/cucumber/gherkin/go/v26 v26.2.0/go.mod h1:t2GAPnB8maCT4lkHL99BDCVNzCh1d7dBhCLt150Nr/0= +github.com/cucumber/godog v0.15.1 h1:rb/6oHDdvVZKS66hrhpjFQFHjthFSrQBCOI1LwshNTI= +github.com/cucumber/godog v0.15.1/go.mod h1:qju+SQDewOljHuq9NSM66s0xEhogx0q30flfxL4WUk8= +github.com/cucumber/messages/go/v21 v21.0.1 h1:wzA0LxwjlWQYZd32VTlAVDTkW6inOFmSM+RuOwHZiMI= +github.com/cucumber/messages/go/v21 v21.0.1/go.mod h1:zheH/2HS9JLVFukdrsPWoPdmUtmYQAQPLk7w5vWsk5s= +github.com/danieljoos/wincred v1.2.3 h1:v7dZC2x32Ut3nEfRH+vhoZGvN72+dQ/snVXo/vMFLdQ= +github.com/danieljoos/wincred v1.2.3/go.mod h1:6qqX0WNrS4RzPZ1tnroDzq9kY3fu1KwE7MRLQK4X0bs= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= +github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= +github.com/docker/docker v28.5.2+incompatible h1:DBX0Y0zAjZbSrm1uzOkdr1onVghKaftjlSWt4AFexzM= +github.com/docker/docker v28.5.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.7.0 h1:6SsRfJddP22WMrCkj19x9WKjEDTB+ahsdiGYf0mN39c= +github.com/docker/go-connections v0.7.0/go.mod h1:no1qkHdjq7kLMGUXYAduOhYPSJxxvgWBh7ogVvptn3Q= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/eapache/go-resiliency v1.7.0 h1:n3NRTnBn5N0Cbi/IeOHuQn9s2UwVUH7Ga0ZWcP+9JTA= +github.com/eapache/go-resiliency v1.7.0/go.mod h1:5yPzW0MIvSe0JDsv0v+DvcjEv2FyD6iZYSs1ZI+iQho= +github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/expr-lang/expr v1.17.8 h1:W1loDTT+0PQf5YteHSTpju2qfUfNoBt4yw9+wOEU9VM= +github.com/expr-lang/expr v1.17.8/go.mod h1:8/vRC7+7HBzESEqt5kKpYXxrxkr31SaO8r40VO/1IT4= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/color v1.19.0 h1:Zp3PiM21/9Ld6FzSKyL5c/BULoe/ONr9KlbYVOfG8+w= +github.com/fatih/color v1.19.0/go.mod h1:zNk67I0ZUT1bEGsSGyCZYZNrHuTkJJB+r6Q9VuMi0LE= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= +github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= +github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +github.com/go-jose/go-jose/v4 v4.1.4 h1:moDMcTHmvE6Groj34emNPLs/qtYXRVcd6S7NHbHz3kA= +github.com/go-jose/go-jose/v4 v4.1.4/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U= +github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= +github.com/godbus/dbus/v5 v5.2.2 h1:TUR3TgtSVDmjiXOgAAyaZbYmIeP3DPkld3jgKGV8mXQ= +github.com/godbus/dbus/v5 v5.2.2/go.mod h1:3AAv2+hPq5rdnr5txxxRwiGjPXamgoIHgz9FPBfOp3c= +github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= +github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY= +github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/golobby/cast v1.3.3 h1:s2Lawb9RMz7YyYf8IrfMQY4IFmA1R/lgfmj97Vc6fig= +github.com/golobby/cast v1.3.3/go.mod h1:0oDO5IT84HTXcbLDf1YXuk0xtg/cRDrxhbpWKxwtJCY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/go-tpm v0.9.8 h1:slArAR9Ft+1ybZu0lBwpSmpwhRXaa85hWtMinMyRAWo= +github.com/google/go-tpm v0.9.8/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs= +github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= +github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 h1:5VipnvEpbqr2gA2VbM+nYVbkIF28c5ZQfqCBQ5g2xfk= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0/go.mod h1:Hyl3n6Twe1hvtd9XUXDec4pTvgMSEixRuQKPTMH2bNs= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= +github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-memdb v1.3.5 h1:b3taDMxCBCBVgyRrS1AZVHO14ubMYZB++QpNhBg+Nyo= +github.com/hashicorp/go-memdb v1.3.5/go.mod h1:8IVKKBkVe+fxFgdFOYxzQQNjz+sWCyHCdIC/+5+Vy1Y= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-retryablehttp v0.7.8 h1:ylXZWnqa7Lhqpk0L1P1LzDtGcCR0rPVUrx/c8Unxc48= +github.com/hashicorp/go-retryablehttp v0.7.8/go.mod h1:rjiScheydd+CxvumBsIrFKlx3iS0jrZ7LvzFGFmuKbw= +github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-secure-stdlib/parseutil v0.2.0 h1:U+kC2dOhMFQctRfhK0gRctKAPTloZdMU5ZJxaesJ/VM= +github.com/hashicorp/go-secure-stdlib/parseutil v0.2.0/go.mod h1:Ll013mhdmsVDuoIXVfBtvgGJsXDYkTw1kooNcoCXuE0= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.7 h1:G+pTkSO01HpR5qCxg7lxfsFEZaG+C0VssTy/9dbT+Fw= +github.com/hashicorp/go-sockaddr v1.0.7/go.mod h1:FZQbEYa1pxkQ7WLpyXJ6cbjpT8q0YgQaK/JakXqGyWw= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= +github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= +github.com/hashicorp/hcl v1.0.1-vault-7 h1:ag5OxFVy3QYTFTJODRzTKVZ6xvdfLLCA1cy/Y6xGI0I= +github.com/hashicorp/hcl v1.0.1-vault-7/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM= +github.com/hashicorp/vault/api v1.23.0 h1:gXgluBsSECfRWTSW9niY2jwg2e9mMJc4WoHNv4g3h6A= +github.com/hashicorp/vault/api v1.23.0/go.mod h1:zransKiB9ftp+kgY8ydjnvCU7Wk8i9L0DYWpXeMj9ko= +github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8= +github.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns= +github.com/itchyny/gojq v0.12.18 h1:gFGHyt/MLbG9n6dqnvlliiya2TaMMh6FFaR2b1H6Drc= +github.com/itchyny/gojq v0.12.18/go.mod h1:4hPoZ/3lN9fDL1D+aK7DY1f39XZpY9+1Xpjz8atrEkg= +github.com/itchyny/timefmt-go v0.1.7 h1:xyftit9Tbw+Dc/huSSPJaEmX1TVL8lw5vxjJLK4GMMA= +github.com/itchyny/timefmt-go v0.1.7/go.mod h1:5E46Q+zj7vbTgWY8o5YkMeYb4I6GeWLFnetPy5oBrAI= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.9.1 h1:uwrxJXBnx76nyISkhr33kQLlUqjv7et7b9FjCen/tdc= +github.com/jackc/pgx/v5 v5.9.1/go.mod h1:mal1tBGAFfLHvZzaYh77YS/eC6IX9OWbRV1QIIM0Jn4= +github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= +github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= +github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= +github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo= +github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= +github.com/jcmturner/gofork v1.7.6 h1:QH0l3hzAU1tfT3rZCnW5zXl+orbkNMMRGJfdJjHVETg= +github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo= +github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o= +github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= +github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh687T8= +github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs= +github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= +github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= +github.com/jhump/protoreflect v1.16.0 h1:54fZg+49widqXYQ0b+usAFHbMkBGR4PpXrsHc8+TBDg= +github.com/jhump/protoreflect v1.16.0/go.mod h1:oYPd7nPvcBw/5wlDfm/AVmU9zH9BgqGCI469pGxfj/8= +github.com/json-iterator/go v1.1.13-0.20220915233716-71ac16282d12 h1:9Nu54bhS/H/Kgo2/7xNSUuC5G28VR8ljfrLKU2G4IjU= +github.com/json-iterator/go v1.1.13-0.20220915233716-71ac16282d12/go.mod h1:TBzl5BIHNXfS9+C35ZyJaklL7mLDbgUkcgXzSLa8Tk0= +github.com/klauspost/compress v1.18.6 h1:2jupLlAwFm95+YDR+NwD2MEfFO9d4z4Prjl1XXDjuao= +github.com/klauspost/compress v1.18.6/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= +github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= +github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw4= +github.com/mattn/go-isatty v0.0.22/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4= +github.com/minio/highwayhash v1.0.4-0.20251030100505-070ab1a87a76 h1:KGuD/pM2JpL9FAYvBrnBBeENKZNh6eNtjqytV6TYjnk= +github.com/minio/highwayhash v1.0.4-0.20251030100505-070ab1a87a76/go.mod h1:GGYsuwP/fPD6Y9hMiXuapVvlIUEhFhMTh0rxU3ik1LQ= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= +github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= +github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw= +github.com/moby/sys/atomicwriter v0.1.0/go.mod h1:Ul8oqv2ZMNHOceF643P6FKPXeCmYtlQMvpizfsSoaWs= +github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU= +github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko= +github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ= +github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= +github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/morikuni/aec v1.1.0 h1:vBBl0pUnvi/Je71dsRrhMBtreIqNMYErSAbEeb8jrXQ= +github.com/morikuni/aec v1.1.0/go.mod h1:xDRgiq/iw5l+zkao76YTKzKttOp2cwPEne25HDkJnBw= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/nats-io/jwt/v2 v2.8.0 h1:K7uzyz50+yGZDO5o772eRE7atlcSEENpL7P+b74JV1g= +github.com/nats-io/jwt/v2 v2.8.0/go.mod h1:me11pOkwObtcBNR8AiMrUbtVOUGkqYjMQZ6jnSdVUIA= +github.com/nats-io/nats-server/v2 v2.12.4 h1:ZnT10v2LU2Xcoiy8ek9X6Se4YG8EuMfIfvAEuFVx1Ts= +github.com/nats-io/nats-server/v2 v2.12.4/go.mod h1:5MCp/pqm5SEfsvVZ31ll1088ZTwEUdvRX1Hmh/mTTDg= +github.com/nats-io/nats.go v1.52.0 h1:n3avV4VBsCgsdwh71TppsTwtv+QdPs7ntSKM8qJLGsc= +github.com/nats-io/nats.go v1.52.0/go.mod h1:26HypzazeOkyO3/mqd1zZd53STJN0EjCYF9Uy2ZOBno= +github.com/nats-io/nkeys v0.4.15 h1:JACV5jRVO9V856KOapQ7x+EY8Jo3qw1vJt/9Jpwzkk4= +github.com/nats-io/nkeys v0.4.15/go.mod h1:CpMchTXC9fxA5zrMo4KpySxNjiDVvr8ANOSZdiNfUrs= +github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= +github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w= +github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= +github.com/oklog/run v1.2.0 h1:O8x3yXwah4A73hJdlrwo/2X6J62gE5qTMusH0dvz60E= +github.com/oklog/run v1.2.0/go.mod h1:mgDbKRSwPhJfesJ4PntqFUbKQRZ50NgmZTSPlFA0YFk= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= +github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= +github.com/pierrec/lz4/v4 v4.1.26 h1:GrpZw1gZttORinvzBdXPUXATeqlJjqUG/D87TKMnhjY= +github.com/pierrec/lz4/v4 v4.1.26/go.mod h1:EoQMVJgeeEOMsCqCzqFm2O0cJvljX2nGZjcRIPL34O4= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= +github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= +github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= +github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= +github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4= +github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw= +github.com/prometheus/procfs v0.20.1 h1:XwbrGOIplXW/AU3YhIhLODXMJYyC1isLFfYCsTEycfc= +github.com/prometheus/procfs v0.20.1/go.mod h1:o9EMBZGRyvDrSPH1RqdxhojkuXstoe4UlK79eF5TGGo= +github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 h1:bsUq1dX0N8AOIL7EB/X911+m4EHsnWEHeJ0c+3TTBrg= +github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/redis/go-redis/v9 v9.19.0 h1:XPVaaPSnG6RhYf7p+rmSa9zZfeVAnWsH5h3lxthOm/k= +github.com/redis/go-redis/v9 v9.19.0/go.mod h1:v/M13XI1PVCDcm01VtPFOADfZtHf8YW3baQf57KlIkA= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= +github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ= +github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= +github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= +github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= +github.com/xdg-go/scram v1.2.0 h1:bYKF2AEwG5rqd1BumT4gAnvwU/M9nBp2pTSxeZw7Wvs= +github.com/xdg-go/scram v1.2.0/go.mod h1:3dlrS0iBaWKYVt2ZfA4cj48umJZ+cAEbR6/SjLA88I8= +github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8= +github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M= +github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw= +github.com/zalando/go-keyring v0.2.8 h1:6sD/Ucpl7jNq10rM2pgqTs0sZ9V3qMrqfIIy5YPccHs= +github.com/zalando/go-keyring v0.2.8/go.mod h1:tsMo+VpRq5NGyKfxoBVjCuMrG47yj8cmakZDO5QGii0= +github.com/zeebo/xxh3 v1.1.0 h1:s7DLGDK45Dyfg7++yxI0khrfwq9661w9EN78eP/UZVs= +github.com/zeebo/xxh3 v1.1.0/go.mod h1:IisAie1LELR4xhVinxWS5+zf1lA4p0MW4T+w+W07F5s= +go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= +go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.68.0 h1:CqXxU8VOmDefoh0+ztfGaymYbhdB/tT3zs79QaZTNGY= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.68.0/go.mod h1:BuhAPThV8PBHBvg8ZzZ/Ok3idOdhWIodywz2xEcRbJo= +go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I= +go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 h1:88Y4s2C8oTui1LGM6bTWkw0ICGcOLCAI5l6zsD1j20k= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0/go.mod h1:Vl1/iaggsuRlrHf/hfPJPvVag77kKyvrLeD10kpMl+A= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0 h1:3iZJKlCZufyRzPzlQhUIWVmfltrXuGyfjREgGP3UUjc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0/go.mod h1:/G+nUPfhq2e+qiXMGxMwumDrP5jtzU+mWN7/sjT2rak= +go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM= +go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY= +go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg= +go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg= +go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw= +go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A= +go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A= +go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0= +go.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g= +go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk= +go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= +go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= +go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.28.0 h1:IZzaP1Fv73/T/pBMLk4VutPl36uNC+OSUh3JLG3FIjo= +go.uber.org/zap v1.28.0/go.mod h1:rDLpOi171uODNm/mxFcuYWxDsqWSAVkFdX4XojSKg/Q= +go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ= +go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ= +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/crypto v0.51.0 h1:IBPXwPfKxY7cWQZ38ZCIRPI50YLeevDLlLnyC5wRGTI= +golang.org/x/crypto v0.51.0/go.mod h1:8AdwkbraGNABw2kOX6YFPs3WM22XqI4EXEd8g+x7Oc8= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4= +golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.54.0 h1:2zJIZAxAHV/OHCDTCOHAYehQzLfSXuf/5SoL/Dv6w/w= +golang.org/x/net v0.54.0/go.mod h1:Sj4oj8jK6XmHpBZU/zWHw3BV3abl4Kvi+Ut7cQcY+cQ= +golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= +golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= +golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ= +golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc= +golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38= +golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= +golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8= +golang.org/x/tools v0.45.0/go.mod h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= +gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= +google.golang.org/genproto/googleapis/api v0.0.0-20260511170946-3700d4141b60 h1:3WsB1FAbiRIf2tOxscWKs3pQBD9he1NsrnbhMuWfekc= +google.golang.org/genproto/googleapis/api v0.0.0-20260511170946-3700d4141b60/go.mod h1:7yoXV7RIh5gblj/xVYoogxAWvA9wUeVbpsK/M694l00= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260511170946-3700d4141b60 h1:seT2EwLWM78plQ7wcDfuWBc/4FAEAXDDiaSol4ku4qo= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260511170946-3700d4141b60/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= +google.golang.org/grpc v1.81.1 h1:VnnIIZ88UzOOKLukQi+ImGz8O1Wdp8nAGGnvOfEIWQQ= +google.golang.org/grpc v1.81.1/go.mod h1:xGH9GfzOyMTGIOXBJmXt+BX/V0kcdQbdcuwQ/zNw42I= +google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af h1:+5/Sw3GsDNlEmu7TfklWKPdQ0Ykja5VEmq2i817+jbI= +google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= +gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= +modernc.org/cc/v4 v4.27.1 h1:9W30zRlYrefrDV2JE2O8VDtJ1yPGownxciz5rrbQZis= +modernc.org/cc/v4 v4.27.1/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0= +modernc.org/ccgo/v4 v4.32.0 h1:hjG66bI/kqIPX1b2yT6fr/jt+QedtP2fqojG2VrFuVw= +modernc.org/ccgo/v4 v4.32.0/go.mod h1:6F08EBCx5uQc38kMGl+0Nm0oWczoo1c7cgpzEry7Uc0= +modernc.org/fileutil v1.4.0 h1:j6ZzNTftVS054gi281TyLjHPp6CPHr2KCxEXjEbD6SM= +modernc.org/fileutil v1.4.0/go.mod h1:EqdKFDxiByqxLk8ozOxObDSfcVOv/54xDs/DUHdvCUU= +modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI= +modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito= +modernc.org/gc/v3 v3.1.2 h1:ZtDCnhonXSZexk/AYsegNRV1lJGgaNZJuKjJSWKyEqo= +modernc.org/gc/v3 v3.1.2/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY= +modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks= +modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI= +modernc.org/libc v1.70.0 h1:U58NawXqXbgpZ/dcdS9kMshu08aiA6b7gusEusqzNkw= +modernc.org/libc v1.70.0/go.mod h1:OVmxFGP1CI/Z4L3E0Q3Mf1PDE0BucwMkcXjjLntvHJo= +modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU= +modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg= +modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI= +modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw= +modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8= +modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns= +modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w= +modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE= +modernc.org/sqlite v1.47.0 h1:R1XyaNpoW4Et9yly+I2EeX7pBza/w+pmYee/0HJDyKk= +modernc.org/sqlite v1.47.0/go.mod h1:hWjRO6Tj/5Ik8ieqxQybiEOUXy0NJFNp2tpvVpKlvig= +modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0= +modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A= +modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= +modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= diff --git a/cmd/wfctl/testdata/verify_capabilities/iac-missing-service/main.go b/cmd/wfctl/testdata/verify_capabilities/iac-missing-service/main.go new file mode 100644 index 00000000..f8c1a07b --- /dev/null +++ b/cmd/wfctl/testdata/verify_capabilities/iac-missing-service/main.go @@ -0,0 +1,34 @@ +package main + +import ( + "context" + _ "embed" + + pb "github.com/GoCodeAlone/workflow/plugin/external/proto" + sdk "github.com/GoCodeAlone/workflow/plugin/external/sdk" +) + +var Version = "dev" + +//go:embed plugin.json +var manifestData []byte + +// CRITICAL: this struct must NOT embed pb.UnimplementedIaCProviderFinalizerServer. +// Embedding the Unimplemented type satisfies the IaCProviderFinalizerServer +// interface (via mustEmbedUnimplementedIaCProviderFinalizerServer sentinel), +// which would make sdk.ServeIaCPlugin's type-assertion succeed and REGISTER +// the Finalizer service — defeating the missing-service test scenario. +type fixture struct { + pb.UnimplementedIaCProviderRequiredServer +} + +func (fixture) Name(context.Context, *pb.NameRequest) (*pb.NameResponse, error) { + return &pb.NameResponse{Name: "verify-iac-missing"}, nil +} + +func main() { + sdk.ServeIaCPlugin(fixture{}, sdk.IaCServeOptions{ + ManifestProvider: sdk.MustEmbedManifest(manifestData), + BuildVersion: sdk.ResolveBuildVersion(Version), + }) +} diff --git a/cmd/wfctl/testdata/verify_capabilities/iac-missing-service/plugin.json b/cmd/wfctl/testdata/verify_capabilities/iac-missing-service/plugin.json new file mode 100644 index 00000000..25b4c0e0 --- /dev/null +++ b/cmd/wfctl/testdata/verify_capabilities/iac-missing-service/plugin.json @@ -0,0 +1,11 @@ +{ + "name": "verify-iac-missing", + "version": "0.0.0", + "minEngineVersion": "v0.62.0", + "author": "test fixture", + "description": "IaC fixture: plugin.json declares more services than binary registers", + "iacServices": [ + "workflow.plugin.external.iac.IaCProviderRequired", + "workflow.plugin.external.iac.IaCProviderFinalizer" + ] +}