Files
ziti/controller/handler_edge_ctrl/errors_test.go
Paul Lorenz d7076430c9 Make ER/T terminator create failures diagnosable. Fixes #4193
- reports edge router policy denials with an access-denied error naming the missing policy,
  replacing the session error reused on the sessionless ER/T and create-circuit-v3 paths
- adds EdgeRouterManager.GetEdgeRouterAccess, which reports which of the two required policy
  links (identity-to-edge-router, service-to-edge-router) is absent, and removes the boolean
  IsAccessToEdgeRouterAllowed it replaces
- logs the controller's rejection on the router at warn level, since it is recoverable and
  retried by the periodic scan; the router previously discarded the error code and message
- delays a new terminator's first create attempt by a fixed 2s so config applied in quick
  succession settles before the router asks, avoiding a 2-3 minute wait for the retry scan; the
  delay is a deliberate stopgap until edge router policy visibility lands in the router data model
- propagates the controller's error code and retry hint to SDK clients on the dial paths, which
  dropped the code and left every refusal classified as unknown
- adds the retry hint header to controller error replies, grouped with the other error-reply
  headers rather than the create-circuit-v3 request headers
- notes that the sync strategy headers alias the edge namespace's 1013-1015 ids and stay
  disjoint only by message content type
- tests the per-policy denial reporting, the error code carried with and without a retry hint,
  the controller-to-SDK error code mapping at both dial relay sites, and the terminator settle
  gate
- waits for terminator establishment in the tunneler dataflow tests instead of a fixed sleep, so
  they no longer race the settle delay
- restores the tproxy multiple-lanIf and multiple-resolver changelog entries with keep markers,
  which regeneration drops because their commits reference pull requests rather than issues
2026-08-03 15:43:30 -04:00

77 lines
2.5 KiB
Go

/*
Copyright NetFoundry Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package handler_edge_ctrl
import (
"testing"
"github.com/openziti/sdk-golang/v2/ziti/edge"
"github.com/openziti/ziti/v2/controller/model"
"github.com/pkg/errors"
"github.com/stretchr/testify/require"
)
func Test_ErrorsIs(t *testing.T) {
err := error(InvalidSessionError{})
req := require.New(t)
req.True(errors.Is(err, InvalidSessionError{}))
}
// TestNewEdgeRouterAccessDeniedError checks that the denial names the specific policy that is
// missing for each way access can be denied, and that all three are reported as access denied.
func TestNewEdgeRouterAccessDeniedError(t *testing.T) {
ctx := &baseSessionRequestContext{
sourceRouter: &model.Router{Name: "er1"},
service: &model.EdgeService{Name: "svc1"},
}
tests := []struct {
name string
access model.EdgeRouterAccess
expectedReason string
}{
{
name: "neither policy links",
access: model.EdgeRouterAccess{IdentityAllowed: false, ServiceAllowed: false},
expectedReason: "no edge router policy links the identity to the edge router and no service edge router policy links the service to the edge router",
},
{
name: "only service linked",
access: model.EdgeRouterAccess{IdentityAllowed: false, ServiceAllowed: true},
expectedReason: "no edge router policy links the identity to the edge router",
},
{
name: "only identity linked",
access: model.EdgeRouterAccess{IdentityAllowed: true, ServiceAllowed: false},
expectedReason: "no service edge router policy links the service to the edge router",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
req := require.New(t)
err := ctx.newEdgeRouterAccessDeniedError("identity1", test.access)
req.Equal(edge.ErrorCodeAccessDenied, err.ErrorCode())
req.Contains(err.Error(), test.expectedReason)
req.Contains(err.Error(), "er1")
req.Contains(err.Error(), "svc1")
req.Contains(err.Error(), "identity1")
})
}
}