Files
tasks/components/nexusoperations/build_callback_url_test.go
93cc503639 Support Internal Nexus Callback Routing (#8308)
## What changed?
This PR introduces two key features to enable out-of-the-box Nexus
functionality with zero configuration:

1. **Always allow `temporal://system` callback URLs**: The
`component.callbacks.allowedAddresses` configuration now automatically
allows `temporal://system` URLs regardless of configured address rules.
This special scheme+host combination bypasses normal URL validation and
is always permitted.

2. **New UseSystemCallbackURL toggle**: Added
`component.nexusoperations.useSystemCallbackURL` dynamic config that
controls callback URL generation for worker targets:
- When `false` (default): Uses the existing callback URL template
approach
   - When `true`: Worker targets automatically get `temporal://system`
- External targets continue to use template-generated URLs regardless of
this setting
- NOTE: if this toggle is `true` HTTPCallerProvider must be able to
route internal requests based on theSource and Token headers. It should
also override the path to `/nexus/callback`. See the HTTPCallerProvider
code changes here.

3. **Callback URL Validation** has been refactored. The
`AddressMatchRules` struct now includes a `Validate` method that handles
the special `temporal://system` case and applies configured rules for
other URLs.
4. **Callback Source Header**: will no longer be populated for external
Targets.

## Why?
Once `component.nexusoperations.useSystemCallbackURL` is enabled by
default in a future release, these changes will allow Self-Hosted
Temporal Servers to support Nexus with zero dynamic configuration
See this issue: https://github.com/temporalio/temporal/issues/8298

## How did you test it?
- [x] built
- [x] run locally and tested manually
- [x] covered by existing tests
- [x] added new unit test(s)
- [x] added new functional test(s)

---------

Co-authored-by: alex stanfield <[email protected]>
Co-authored-by: Roey Berman <[email protected]>
2025-09-29 21:15:16 +00:00

62 lines
2.0 KiB
Go

package nexusoperations
import (
"testing"
"github.com/stretchr/testify/require"
persistencespb "go.temporal.io/server/api/persistence/v1"
"go.temporal.io/server/common/namespace"
)
func TestBuildCallbackURL(t *testing.T) {
ns := namespace.NewLocalNamespaceForTest(
&persistencespb.NamespaceInfo{Name: "ns-name", Id: "ns-id"},
&persistencespb.NamespaceConfig{},
"active-cluster",
)
workerEndpoint := &persistencespb.NexusEndpointEntry{
Endpoint: &persistencespb.NexusEndpoint{
Spec: &persistencespb.NexusEndpointSpec{
Name: "endpoint",
Target: &persistencespb.NexusEndpointTarget{
Variant: &persistencespb.NexusEndpointTarget_Worker_{
Worker: &persistencespb.NexusEndpointTarget_Worker{
NamespaceId: "ns-id",
TaskQueue: "nexus-tq",
},
},
},
},
},
}
externalEndpoint := &persistencespb.NexusEndpointEntry{
Endpoint: &persistencespb.NexusEndpoint{
Spec: &persistencespb.NexusEndpointSpec{
Name: "endpoint",
Target: &persistencespb.NexusEndpointTarget{
Variant: &persistencespb.NexusEndpointTarget_External_{
External: &persistencespb.NexusEndpointTarget_External{Url: "https://api.example.com"},
},
},
},
},
}
// When UseSystemCallbackURL is true and target is worker, return the system URL
got, err := buildCallbackURL(true, "http://example/callback/{{.NamespaceName}}", ns, workerEndpoint)
require.NoError(t, err)
require.Equal(t, "temporal://system", got)
// When UseSystemCallbackURL is true but target is external, use the template
got, err = buildCallbackURL(true, "http://example/callback/{{.NamespaceName}}-{{.NamespaceID}}", ns, externalEndpoint)
require.NoError(t, err)
require.Equal(t, "http://example/callback/ns-name-ns-id", got)
// When UseSystemCallbackURL is false, always use the template
got, err = buildCallbackURL(false, "https://cb/{{.NamespaceID}}/{{.NamespaceName}}", ns, workerEndpoint)
require.NoError(t, err)
require.Equal(t, "https://cb/ns-id/ns-name", got)
}