mirror of
https://github.com/openziti/ziti.git
synced 2026-10-23 20:26:05 +00:00
f18ce1b580
- collapses the edge service boltz child store into the unified service store:
EdgeService becomes a type alias for Service, and RoleAttributes, Configs, and
EncryptionRequired become top-level Service fields
- adds an IsFabricOnly discriminator separating pure-fabric ("management")
services from edge services
- adds a forward-only, irreversible migration that moves edge service data out of
the edge child bucket, classifies pre-existing services (fabric -> IsFabricOnly
with encryptionRequired=false; edge -> IsFabricOnly=false), deletes the old edge
bucket and its index, and rebuilds the role-attributes index via CheckIntegrity
- guards every edge-facing path on the unified store against fabric-only services
so they stay invisible to the edge API: by-id Read/ReadByName/Delete, list/query
and the detail lister, ReadForIdentity, identity service-config overrides,
service policy / SERP @id and #all/role denormalization, the association-list
routes (terminators, policies, configs), and the router data-model sync
- rejects edge-surface updates of fabric-only services, and preserves edge fields
on fabric-surface updates of edge services
- marks the fabric-only guards TEMPORARY(fabric-edge-collapse): they exist only to
keep seldom-used management services hidden, and are removed when the fabric/edge
distinction is erased
- adds in-CI migration tests (forward plus a round-trip asserting FK sub-bucket
relocation and forward/reverse refcount preservation), durable fabric-only
behavior tests, and store-level policy-exclusion tests
- adds one-time authentic-migration gate tooling under zititest/migration-test
(create-model.sh, query, verify) and its operator runbook
142 lines
4.3 KiB
Go
142 lines
4.3 KiB
Go
package model
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/openziti/ziti/v2/controller/storage/ast"
|
|
"github.com/openziti/ziti/v2/controller/storage/boltztest"
|
|
"github.com/openziti/ziti/v2/common/eid"
|
|
"github.com/openziti/ziti/v2/controller/change"
|
|
"github.com/openziti/ziti/v2/controller/db"
|
|
)
|
|
|
|
func TestIdentityManager(t *testing.T) {
|
|
ctx := NewTestContext(t)
|
|
defer ctx.Cleanup()
|
|
ctx.Init()
|
|
|
|
t.Run("test identity config overrides service delete", ctx.testIdentityConfigOverridesServiceDelete)
|
|
t.Run("test identity config overrides identity delete", ctx.testIdentityConfigOverridesIdentityDelete)
|
|
}
|
|
|
|
func (ctx *TestContext) testIdentityConfigOverridesServiceDelete(t *testing.T) {
|
|
ctx.requireNewEdgeRouter()
|
|
identity := ctx.requireNewIdentity(false)
|
|
|
|
cfg1 := ctx.requireNewConfig("host.v1", map[string]any{
|
|
"address": "localhost",
|
|
"port": 8080,
|
|
"protocol": "tcp",
|
|
})
|
|
|
|
service := ctx.requireNewService(cfg1.Id)
|
|
service.RoleAttributes = []string{eid.New()}
|
|
ctx.NoError(ctx.managers.EdgeService.Update(service, nil, change.New()))
|
|
|
|
ctx.requireNewServicePolicy(db.PolicyTypeDialName, ss("#all"), ss("#all"))
|
|
ctx.requireNewServicePolicy(db.PolicyTypeBindName, ss("#all"), ss("#all"))
|
|
ctx.requireNewEdgeRouterPolicy(ss("#all"), ss("#all"))
|
|
ctx.requireNewServiceNewEdgeRouterPolicy(ss("#all"), ss("#all"))
|
|
|
|
cfg2 := ctx.requireNewConfig("host.v1", map[string]any{
|
|
"address": "localhost",
|
|
"port": 8080,
|
|
"protocol": "tcp",
|
|
})
|
|
|
|
err := ctx.managers.Identity.AssignServiceConfigs(identity.Id, []ServiceConfig{
|
|
{
|
|
Service: service.Id,
|
|
Config: cfg2.Id,
|
|
},
|
|
}, change.New())
|
|
ctx.NoError(err)
|
|
|
|
query, err := ast.Parse(ctx.GetStores().Service, "true")
|
|
ctx.NoError(err)
|
|
|
|
result, err := ctx.managers.EdgeService.PublicQueryForIdentity(identity, map[string]struct{}{"all": {}}, query)
|
|
ctx.NoError(err)
|
|
ctx.Equal(1, len(result.Services))
|
|
|
|
err = ctx.managers.Config.Delete(cfg1.Id, change.New())
|
|
ctx.Nil(err)
|
|
|
|
err = ctx.managers.Config.Delete(cfg2.Id, change.New())
|
|
ctx.NotNil(err)
|
|
|
|
err = ctx.managers.EdgeService.Delete(service.Id, change.New())
|
|
ctx.NoError(err)
|
|
|
|
err = ctx.managers.Config.Delete(cfg2.Id, change.New())
|
|
ctx.NoError(err)
|
|
|
|
boltztest.ValidateDeleted(ctx, service.Id)
|
|
boltztest.ValidateDeleted(ctx, cfg1.Id)
|
|
boltztest.ValidateDeleted(ctx, cfg2.Id)
|
|
}
|
|
|
|
func (ctx *TestContext) testIdentityConfigOverridesIdentityDelete(t *testing.T) {
|
|
ctx.requireNewEdgeRouter()
|
|
identity := ctx.requireNewIdentity(false)
|
|
|
|
cfg1 := ctx.requireNewConfig("host.v1", map[string]any{
|
|
"address": "localhost",
|
|
"port": 8080,
|
|
"protocol": "tcp",
|
|
})
|
|
|
|
service := ctx.requireNewService(cfg1.Id)
|
|
service.RoleAttributes = []string{eid.New()}
|
|
ctx.NoError(ctx.managers.EdgeService.Update(service, nil, change.New()))
|
|
|
|
ctx.requireNewServicePolicy(db.PolicyTypeDialName, ss("#all"), ss("#all"))
|
|
ctx.requireNewServicePolicy(db.PolicyTypeBindName, ss("#all"), ss("#all"))
|
|
ctx.requireNewEdgeRouterPolicy(ss("#all"), ss("#all"))
|
|
ctx.requireNewServiceNewEdgeRouterPolicy(ss("#all"), ss("#all"))
|
|
|
|
cfg2 := ctx.requireNewConfig("host.v1", map[string]any{
|
|
"address": "localhost",
|
|
"port": 8080,
|
|
"protocol": "tcp",
|
|
})
|
|
|
|
err := ctx.managers.Identity.AssignServiceConfigs(identity.Id, []ServiceConfig{
|
|
{
|
|
Service: service.Id,
|
|
Config: cfg2.Id,
|
|
},
|
|
}, change.New())
|
|
ctx.NoError(err)
|
|
|
|
query, err := ast.Parse(ctx.GetStores().Service, "true")
|
|
ctx.NoError(err)
|
|
|
|
result, err := ctx.managers.EdgeService.PublicQueryForIdentity(identity, map[string]struct{}{"all": {}}, query)
|
|
ctx.NoError(err)
|
|
ctx.Equal(1, len(result.Services))
|
|
|
|
err = ctx.managers.Config.Delete(cfg1.Id, change.New())
|
|
ctx.Nil(err)
|
|
|
|
err = ctx.managers.Config.Delete(cfg2.Id, change.New())
|
|
ctx.NotNil(err)
|
|
|
|
err = ctx.managers.Identity.Delete(identity.Id, change.New())
|
|
ctx.NoError(err)
|
|
|
|
err = ctx.managers.Config.Delete(cfg2.Id, change.New())
|
|
ctx.NoError(err)
|
|
|
|
err = ctx.managers.EdgeService.Delete(service.Id, change.New())
|
|
ctx.NoError(err)
|
|
|
|
boltztest.ValidateDeleted(ctx, service.Id)
|
|
// Deleting an identity creates an identity-scoped revocation keyed by the
|
|
// identity id (to revoke its live OIDC sessions), which legitimately remains
|
|
// under the revocations bucket, so exclude that path from the scan.
|
|
boltztest.ValidateDeleted(ctx, identity.Id, "/"+db.RootBucket+"/"+db.EntityTypeRevocations)
|
|
boltztest.ValidateDeleted(ctx, cfg1.Id)
|
|
boltztest.ValidateDeleted(ctx, cfg2.Id)
|
|
}
|