Commit e37e336
Mirror MCPExternalAuthConfig Valid=False onto consumer CR conditions (#5354)
* Mirror MCPExternalAuthConfig Valid=False onto consumer CR conditions
Closes the Status Condition Parity gap noted in #5347. Before this
change, an obo-typed MCPExternalAuthConfig surfaced
Valid=False/EnterpriseRequired only on the referenced resource. The
consumer CR (MCPServer, MCPRemoteProxy, VirtualMCPServer) showed only
the generic dispatch failure, leaving users to inspect the referenced
config to understand why their workload would not deploy.
Each consumer reconciler now inspects the referenced config's Valid
condition. When it is False, the reconciler mirrors the source's reason
and message onto its own ExternalAuthConfigValidated condition (or
per-backend DiscoveredAuthConfig/BackendAuthConfig condition for vMCP).
This must merge before #5329 lights up apiserver-level admission of
obo-typed configs so production users see the failure on the resource
they applied. The envtest integration test for this propagation is
deferred to #5329 to avoid adding a setup-envtest dependency here; once
#5329 admits "obo" at the CRD layer, the test no longer needs a
CRD-enum bypass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Address code review feedback on consumer-CR mirror
Two changes from the code review on the previous commit:
1. (correctness) MCPServer.handleExternalAuthConfig now clears any
stale ExternalAuthConfigValidated=False the mirror previously wrote
when the referenced source has healed (Valid=True or absent).
Without this, the False condition outlived its cause: the user fixed
their spec but the mirror stayed sticky because MCPServer has no
downstream True setter on this condition. Adds a regression-guard
test case.
2. (parity) The mirror probe, typed error, and reason-extraction
helper now live in a shared external_auth_mirror.go file instead
of being duplicated across the three consumer reconcilers. All
three reconcilers (MCPServer, MCPRemoteProxy, VirtualMCPServer)
call the same primitive and surface the same typed error so
downstream consumers like buildOutgoingAuthConfig can react
without string-matching.
MCPRemoteProxy already sets ExternalAuthConfigValidated=True
downstream and so does not need the heal-clearing branch — its
existing True writer overwrites any stale mirror. VirtualMCPServer
heals naturally because setAuthConfigConditions removes stale
per-backend conditions on each reconcile.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Tighten mirror probe API; trim duplicated error prefix
Two changes from the second round of code review feedback on the
consumer-CR mirror:
1. mirroredExternalAuthConfigInvalid now returns the typed
*mirroredInvalidExternalAuthConfigError directly (nil when the
source is healed) instead of a (reason, error) tuple. Callers no
longer need errors.As to recover the message field, and the
pointer-or-nil shape removes the awkward "discard the bool"
pattern at the MCPServer and MCPRemoteProxy call sites. The typed
value still satisfies the error interface so vMCP's
convertBackendAuthConfigToVMCP can keep passing it through opaque
error-returning APIs and recover the reason later via
mirroredReasonFromError.
2. MCPServer and MCPRemoteProxy's outer error wrap no longer repeats
the typed error's "referenced MCPExternalAuthConfig is invalid"
prefix, so messages render as a single sentence instead of a
doubled phrase. The namespaced name is preserved through %w.
Updates the mirror probe's unit test to the new return shape and
adds a round-trip assertion that the typed pointer flows through
mirroredReasonFromError.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Clear stale consumer-CR mirror across all heal paths
Addresses #5354 review comments:
- HIGH cmd/thv-operator/controllers/mcpserver_controller.go (F1):
the previous mirror added in this branch handled the
source-Valid-flips-True heal path, but the no-ref early-return
in handleExternalAuthConfig never reached the helper, so removing
the spec.externalAuthConfigRef left a stale Valid=False/EnterpriseRequired
on the consumer indefinitely. Clear the condition in the no-ref
branch and in both NotFound branches so the mirror does not
outlive its cause.
- MEDIUM cmd/thv-operator/controllers/mcpremoteproxy_controller.go (F2):
mirror helper now defensively clears its own condition on the
healed path, matching MCPServer. The downstream True-writer at
the end of handleExternalAuthConfig still sets the
ConditionReasonMCPRemoteProxyExternalAuthConfigValid reason on
success; the defensive clear closes the gap if a future control-flow
change adds an early return between this helper and that writer.
- LOW cmd/thv-operator/controllers/mcpserver_externalauth_test.go (F10):
two new regression-guard tests for the heal paths uncovered by F1
— spec.externalAuthConfigRef removed, referenced source NotFound.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Consolidate mirror helpers; tighten error+test contract
Addresses #5354 review comments:
- MEDIUM cmd/thv-operator/controllers/virtualmcpserver_externalauth_test.go (F3):
add a wrapped-error round-trip assertion so a future %w -> %v
regression in buildOutgoingAuthConfig can't silently break
per-backend reason propagation.
- MEDIUM cmd/thv-operator/controllers/mcpserver_controller.go (F4):
move both consumer mirror functions to free functions in
external_auth_mirror.go (mirrorInvalidOnMCPServer /
mirrorInvalidOnRemoteProxy) instead of one method with an unused
receiver and one suffixed free function. Single canonical home.
- LOW cmd/thv-operator/controllers/mcpserver_controller.go (F5):
drop the "referenced MCPExternalAuthConfig is invalid" prefix from
the typed error's Error(); the outer wrap on each consumer carries
the namespaced name. Rendered messages now read
"MCPExternalAuthConfig ns/name: invalid (Reason): Message".
- LOW cmd/thv-operator/controllers/external_auth_mirror.go (F6):
substitute a fallback reason when the source surfaces Valid=False
with an empty Reason so the apiserver patch cannot fail validation
on a corrupt/partial source status. Add a TestMirroredExternalAuthConfigInvalid
subtest for the empty-Reason input.
- LOW cmd/thv-operator/controllers/external_auth_mirror.go (F7):
trim the probe doc; package-level comment carries the #5347
motivation once, the per-function docs are now contract-only.
- LOW cmd/thv-operator/controllers/mcpremoteproxy_controller_test.go (F8):
add expectedCondMessage to the test table and assert it on the
OBO mirror row.
- LOW cmd/thv-operator/controllers/mcpserver_externalauth_test.go (F9):
set non-zero Generation on the test fixtures and assert
ObservedGeneration on the mirrored condition. Same gap covered on
the MCPRemoteProxy row.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>1 parent 686eb1b commit e37e336
8 files changed
Lines changed: 774 additions & 32 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
735 | 735 | | |
736 | 736 | | |
737 | 737 | | |
| 738 | + | |
| 739 | + | |
| 740 | + | |
| 741 | + | |
| 742 | + | |
| 743 | + | |
| 744 | + | |
| 745 | + | |
738 | 746 | | |
739 | 747 | | |
740 | 748 | | |
| |||
Lines changed: 65 additions & 9 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
499 | 499 | | |
500 | 500 | | |
501 | 501 | | |
502 | | - | |
503 | | - | |
504 | | - | |
505 | | - | |
506 | | - | |
507 | | - | |
508 | | - | |
509 | | - | |
510 | | - | |
| 502 | + | |
| 503 | + | |
| 504 | + | |
| 505 | + | |
| 506 | + | |
| 507 | + | |
| 508 | + | |
| 509 | + | |
| 510 | + | |
| 511 | + | |
511 | 512 | | |
512 | 513 | | |
513 | 514 | | |
| |||
671 | 672 | | |
672 | 673 | | |
673 | 674 | | |
| 675 | + | |
| 676 | + | |
| 677 | + | |
| 678 | + | |
| 679 | + | |
| 680 | + | |
| 681 | + | |
| 682 | + | |
| 683 | + | |
| 684 | + | |
| 685 | + | |
| 686 | + | |
| 687 | + | |
| 688 | + | |
| 689 | + | |
| 690 | + | |
| 691 | + | |
| 692 | + | |
| 693 | + | |
| 694 | + | |
| 695 | + | |
| 696 | + | |
| 697 | + | |
| 698 | + | |
| 699 | + | |
| 700 | + | |
| 701 | + | |
| 702 | + | |
| 703 | + | |
| 704 | + | |
| 705 | + | |
| 706 | + | |
| 707 | + | |
| 708 | + | |
| 709 | + | |
| 710 | + | |
| 711 | + | |
| 712 | + | |
| 713 | + | |
| 714 | + | |
| 715 | + | |
| 716 | + | |
| 717 | + | |
| 718 | + | |
| 719 | + | |
674 | 720 | | |
675 | 721 | | |
676 | 722 | | |
| |||
752 | 798 | | |
753 | 799 | | |
754 | 800 | | |
| 801 | + | |
| 802 | + | |
| 803 | + | |
| 804 | + | |
| 805 | + | |
| 806 | + | |
| 807 | + | |
| 808 | + | |
| 809 | + | |
| 810 | + | |
755 | 811 | | |
756 | 812 | | |
757 | 813 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2016 | 2016 | | |
2017 | 2017 | | |
2018 | 2018 | | |
2019 | | - | |
| 2019 | + | |
| 2020 | + | |
| 2021 | + | |
2020 | 2022 | | |
2021 | 2023 | | |
2022 | 2024 | | |
| |||
2029 | 2031 | | |
2030 | 2032 | | |
2031 | 2033 | | |
| 2034 | + | |
| 2035 | + | |
| 2036 | + | |
| 2037 | + | |
| 2038 | + | |
2032 | 2039 | | |
2033 | 2040 | | |
2034 | 2041 | | |
2035 | 2042 | | |
| 2043 | + | |
2036 | 2044 | | |
2037 | 2045 | | |
2038 | 2046 | | |
| 2047 | + | |
| 2048 | + | |
| 2049 | + | |
| 2050 | + | |
| 2051 | + | |
| 2052 | + | |
| 2053 | + | |
| 2054 | + | |
2039 | 2055 | | |
2040 | 2056 | | |
2041 | 2057 | | |
| |||
0 commit comments