Skip to content

Commit d4a027d

Browse files
committed
Add namespace selector changes to conformance tests
1 parent 72895f2 commit d4a027d

7 files changed

Lines changed: 240 additions & 0 deletions

conformance/tests/admin-network-policy-standard-egress-sctp-rules.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,43 @@ var CNPAdminTierEgressSCTP = suite.ConformanceTest{
5252
serverPod.Status.PodIP, int32(9005), s.TimeoutConfig, true)
5353
})
5454

55+
t.Run("Should support a 'deny-egress' policy for SCTP protocol on a namespace selector when namespace labels are changed to no longer match", func(t *testing.T) {
56+
// This test uses `egress-sctp` admin CNP
57+
// harry-potter-0 is our server pod in gryffindor namespace
58+
serverPod := kubernetes.GetPod(t, s.Client, "network-policy-conformance-gryffindor", "harry-potter-0", s.TimeoutConfig.GetTimeout)
59+
// luna-lovegood-0 is our client pod in ravenclaw namespace
60+
// ensure egress is ALLOWED to gryffindor from ravenclaw
61+
// egressRule at index0 will take precedence over egressRule at index1; thus ALLOW takes precedence over DENY since rules are ordered
62+
kubernetes.PokeServer(t, s.ClientSet, &s.KubeConfig, "network-policy-conformance-ravenclaw", "luna-lovegood-0", "sctp",
63+
serverPod.Status.PodIP, int32(9003), s.TimeoutConfig, true)
64+
// luna-lovegood-1 is our client pod in ravenclaw namespace
65+
kubernetes.PokeServer(t, s.ClientSet, &s.KubeConfig, "network-policy-conformance-ravenclaw", "luna-lovegood-1", "sctp",
66+
serverPod.Status.PodIP, int32(9005), s.TimeoutConfig, true)
67+
68+
cnp := kubernetes.GetClusterNetworkPolicy(t, s.Client, "egress-sctp", s.TimeoutConfig.GetTimeout)
69+
mutate := cnp.DeepCopy()
70+
// update namespace selector in egressRule at index0 to match "conformance-house: gryffindor" label
71+
mutate.Spec.Egress[0].To[0].Namespaces.MatchLabels = map[string]string{"conformance-house": "gryffindor"}
72+
kubernetes.PatchClusterNetworkPolicy(t, s.Client, cnp, mutate, s.TimeoutConfig.GetTimeout)
73+
74+
// ensure egress is ALLOWED to gryffindor from ravenclaw since namespace label still matches
75+
kubernetes.PokeServer(t, s.ClientSet, &s.KubeConfig, "network-policy-conformance-ravenclaw", "luna-lovegood-0", "sctp",
76+
serverPod.Status.PodIP, int32(9003), s.TimeoutConfig, true)
77+
78+
// update namespace label for gryffindor to "conformance-house": "denied-namespace-label" to no longer match egressRule at index0
79+
allowedNamespace := kubernetes.GetNamespace(t, s.Client, "network-policy-conformance-gryffindor", s.TimeoutConfig.GetTimeout)
80+
mutateNamespace := allowedNamespace.DeepCopy()
81+
mutateNamespace.SetLabels(map[string]string{"conformance-house": "denied-namespace-label"})
82+
kubernetes.PatchNamespace(t, s.Client, allowedNamespace, mutateNamespace, s.TimeoutConfig.GetTimeout)
83+
84+
// ensure egress is DENIED to gryffindor from ravenclaw since namespace label no longer matches
85+
kubernetes.PokeServer(t, s.ClientSet, &s.KubeConfig, "network-policy-conformance-ravenclaw", "luna-lovegood-0", "sctp",
86+
serverPod.Status.PodIP, int32(9003), s.TimeoutConfig, false)
87+
// luna-lovegood-1 is our client pod in ravenclaw namespace
88+
kubernetes.PokeServer(t, s.ClientSet, &s.KubeConfig, "network-policy-conformance-ravenclaw", "luna-lovegood-1", "sctp",
89+
serverPod.Status.PodIP, int32(9005), s.TimeoutConfig, false)
90+
})
91+
5592
t.Run("Should support an 'allow-egress' policy for SCTP protocol at the specified port", func(t *testing.T) {
5693
// This test uses `egress-sctp` admin CNP
5794
// cedric-diggory-1 is our server pod in hufflepuff namespace

conformance/tests/admin-network-policy-standard-egress-tcp-rules.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,43 @@ var CNPAdminTierEgressTCP = suite.ConformanceTest{
5151
serverPod.Status.PodIP, int32(8080), s.TimeoutConfig, true)
5252
})
5353

54+
t.Run("Should support a 'deny-egress' policy for TCP protocol on a namespace selector when namespace labels are changed to no longer match", func(t *testing.T) {
55+
// This test uses `egress-tcp` admin CNP
56+
// harry-potter-0 is our server pod in gryffindor namespace
57+
serverPod := kubernetes.GetPod(t, s.Client, "network-policy-conformance-gryffindor", "harry-potter-0", s.TimeoutConfig.GetTimeout)
58+
// luna-lovegood-0 is our client pod in ravenclaw namespace
59+
// ensure egress is ALLOWED to gryffindor from ravenclaw
60+
// egressRule at index0 will take precedence over egressRule at index1; thus ALLOW takes precedence over DENY since rules are ordered
61+
kubernetes.PokeServer(t, s.ClientSet, &s.KubeConfig, "network-policy-conformance-ravenclaw", "luna-lovegood-0", "tcp",
62+
serverPod.Status.PodIP, int32(80), s.TimeoutConfig, true)
63+
// luna-lovegood-1 is our client pod in ravenclaw namespace
64+
kubernetes.PokeServer(t, s.ClientSet, &s.KubeConfig, "network-policy-conformance-ravenclaw", "luna-lovegood-1", "tcp",
65+
serverPod.Status.PodIP, int32(8080), s.TimeoutConfig, true)
66+
67+
cnp := kubernetes.GetClusterNetworkPolicy(t, s.Client, "egress-tcp", s.TimeoutConfig.GetTimeout)
68+
mutate := cnp.DeepCopy()
69+
// update namespace selector in egressRule at index0 to match "conformance-house: gryffindor" label
70+
mutate.Spec.Egress[0].To[0].Namespaces.MatchLabels = map[string]string{"conformance-house": "gryffindor"}
71+
kubernetes.PatchClusterNetworkPolicy(t, s.Client, cnp, mutate, s.TimeoutConfig.GetTimeout)
72+
73+
// ensure egress is ALLOWED to gryffindor from ravenclaw since namespace label still matches
74+
kubernetes.PokeServer(t, s.ClientSet, &s.KubeConfig, "network-policy-conformance-ravenclaw", "luna-lovegood-0", "tcp",
75+
serverPod.Status.PodIP, int32(80), s.TimeoutConfig, true)
76+
77+
// update namespace label for gryffindor to "conformance-house": "denied-namespace-label" to no longer match egressRule at index0
78+
allowedNamespace := kubernetes.GetNamespace(t, s.Client, "network-policy-conformance-gryffindor", s.TimeoutConfig.GetTimeout)
79+
mutateNamespace := allowedNamespace.DeepCopy()
80+
mutateNamespace.SetLabels(map[string]string{"conformance-house": "denied-namespace-label"})
81+
kubernetes.PatchNamespace(t, s.Client, allowedNamespace, mutateNamespace, s.TimeoutConfig.GetTimeout)
82+
83+
// ensure egress is DENIED to gryffindor from ravenclaw since namespace label no longer matches
84+
kubernetes.PokeServer(t, s.ClientSet, &s.KubeConfig, "network-policy-conformance-ravenclaw", "luna-lovegood-0", "tcp",
85+
serverPod.Status.PodIP, int32(80), s.TimeoutConfig, false)
86+
// luna-lovegood-1 is our client pod in ravenclaw namespace
87+
kubernetes.PokeServer(t, s.ClientSet, &s.KubeConfig, "network-policy-conformance-ravenclaw", "luna-lovegood-1", "tcp",
88+
serverPod.Status.PodIP, int32(8080), s.TimeoutConfig, false)
89+
})
90+
5491
t.Run("Should support an 'allow-egress' policy for TCP protocol at the specified port", func(t *testing.T) {
5592
// This test uses `egress-tcp` admin CNP
5693
// cedric-diggory-1 is our server pod in hufflepuff namespace

conformance/tests/admin-network-policy-standard-egress-udp-rules.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,43 @@ var CNPAdminTierEgressUDP = suite.ConformanceTest{
5252
serverPod.Status.PodIP, int32(5353), s.TimeoutConfig, true)
5353
})
5454

55+
t.Run("Should support a 'deny-egress' policy for UDP protocol on a namespace selector when namespace labels are changed to no longer match", func(t *testing.T) {
56+
// This test uses `egress-udp` admin CNP
57+
// harry-potter-0 is our server pod in gryffindor namespace
58+
serverPod := kubernetes.GetPod(t, s.Client, "network-policy-conformance-gryffindor", "harry-potter-0", s.TimeoutConfig.GetTimeout)
59+
// luna-lovegood-0 is our client pod in ravenclaw namespace
60+
// ensure egress is ALLOWED to gryffindor from ravenclaw
61+
// egressRule at index0 will take precedence over egressRule at index1; thus ALLOW takes precedence over DENY since rules are ordered
62+
kubernetes.PokeServer(t, s.ClientSet, &s.KubeConfig, "network-policy-conformance-ravenclaw", "luna-lovegood-0", "udp",
63+
serverPod.Status.PodIP, int32(53), s.TimeoutConfig, true)
64+
// luna-lovegood-1 is our client pod in ravenclaw namespace
65+
kubernetes.PokeServer(t, s.ClientSet, &s.KubeConfig, "network-policy-conformance-ravenclaw", "luna-lovegood-1", "udp",
66+
serverPod.Status.PodIP, int32(5353), s.TimeoutConfig, true)
67+
68+
cnp := kubernetes.GetClusterNetworkPolicy(t, s.Client, "egress-udp", s.TimeoutConfig.GetTimeout)
69+
mutate := cnp.DeepCopy()
70+
// update namespace selector in egressRule at index0 to match "conformance-house: gryffindor" label
71+
mutate.Spec.Egress[0].To[0].Namespaces.MatchLabels = map[string]string{"conformance-house": "gryffindor"}
72+
kubernetes.PatchClusterNetworkPolicy(t, s.Client, cnp, mutate, s.TimeoutConfig.GetTimeout)
73+
74+
// ensure egress is ALLOWED to gryffindor from ravenclaw since namespace label still matches
75+
kubernetes.PokeServer(t, s.ClientSet, &s.KubeConfig, "network-policy-conformance-ravenclaw", "luna-lovegood-0", "udp",
76+
serverPod.Status.PodIP, int32(53), s.TimeoutConfig, true)
77+
78+
// update namespace label for gryffindor to "conformance-house": "denied-namespace-label" to no longer match egressRule at index0
79+
allowedNamespace := kubernetes.GetNamespace(t, s.Client, "network-policy-conformance-gryffindor", s.TimeoutConfig.GetTimeout)
80+
mutateNamespace := allowedNamespace.DeepCopy()
81+
mutateNamespace.SetLabels(map[string]string{"conformance-house": "denied-namespace-label"})
82+
kubernetes.PatchNamespace(t, s.Client, allowedNamespace, mutateNamespace, s.TimeoutConfig.GetTimeout)
83+
84+
// ensure egress is DENIED to gryffindor from ravenclaw since namespace label no longer matches
85+
kubernetes.PokeServer(t, s.ClientSet, &s.KubeConfig, "network-policy-conformance-ravenclaw", "luna-lovegood-0", "udp",
86+
serverPod.Status.PodIP, int32(53), s.TimeoutConfig, false)
87+
// luna-lovegood-1 is our client pod in ravenclaw namespace
88+
kubernetes.PokeServer(t, s.ClientSet, &s.KubeConfig, "network-policy-conformance-ravenclaw", "luna-lovegood-1", "udp",
89+
serverPod.Status.PodIP, int32(5353), s.TimeoutConfig, false)
90+
})
91+
5592
t.Run("Should support an 'allow-egress' policy for UDP protocol at the specified port", func(t *testing.T) {
5693
// This test uses `egress-udp` admin CNP
5794
// harry-potter-1 is our server pod in gryffindor namespace

conformance/tests/admin-network-policy-standard-ingress-sctp-rules.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,43 @@ var CNPAdminTierIngressSCTP = suite.ConformanceTest{
5151
serverPod.Status.PodIP, int32(9005), s.TimeoutConfig, true)
5252
})
5353

54+
t.Run("Should support a 'deny-ingress' policy for SCTP protocol on a namespace selector when namespace labels are changed to no longer match", func(t *testing.T) {
55+
// This test uses `ingress-sctp` admin CNP
56+
// harry-potter-0 is our server pod in gryffindor namespace
57+
serverPod := kubernetes.GetPod(t, s.Client, "network-policy-conformance-gryffindor", "harry-potter-0", s.TimeoutConfig.GetTimeout)
58+
// luna-lovegood-0 is our client pod in ravenclaw namespace
59+
// ensure ingress is ALLOWED from gryffindor to ravenclaw
60+
// ingressRule at index0 will take precedence over ingressRule at index1; thus ALLOW takes precedence over DENY since rules are ordered
61+
kubernetes.PokeServer(t, s.ClientSet, &s.KubeConfig, "network-policy-conformance-gryffindor", "harry-potter-0", "sctp",
62+
serverPod.Status.PodIP, int32(9003), s.TimeoutConfig, true)
63+
// luna-lovegood-1 is our client pod in ravenclaw namespace
64+
kubernetes.PokeServer(t, s.ClientSet, &s.KubeConfig, "network-policy-conformance-gryffindor", "harry-potter-1", "sctp",
65+
serverPod.Status.PodIP, int32(9005), s.TimeoutConfig, true)
66+
67+
cnp := kubernetes.GetClusterNetworkPolicy(t, s.Client, "ingress-sctp", s.TimeoutConfig.GetTimeout)
68+
mutate := cnp.DeepCopy()
69+
// update namespace selector in ingressRule at index0 to match "conformance-house: gryffindor" label
70+
mutate.Spec.Ingress[0].From[0].Namespaces.MatchLabels = map[string]string{"conformance-house": "gryffindor"}
71+
kubernetes.PatchClusterNetworkPolicy(t, s.Client, cnp, mutate, s.TimeoutConfig.GetTimeout)
72+
73+
// ensure ingress is ALLOWED from gryffindor to ravenclaw since namespace label still matches
74+
kubernetes.PokeServer(t, s.ClientSet, &s.KubeConfig, "network-policy-conformance-gryffindor", "harry-potter-0", "sctp",
75+
serverPod.Status.PodIP, int32(9003), s.TimeoutConfig, true)
76+
77+
// update namespace label for gryffindor to "conformance-house": "denied-namespace-label" to no longer match ingressRule at index0
78+
allowedNamespace := kubernetes.GetNamespace(t, s.Client, "network-policy-conformance-gryffindor", s.TimeoutConfig.GetTimeout)
79+
mutateNamespace := allowedNamespace.DeepCopy()
80+
mutateNamespace.SetLabels(map[string]string{"conformance-house": "denied-namespace-label"})
81+
kubernetes.PatchNamespace(t, s.Client, allowedNamespace, mutateNamespace, s.TimeoutConfig.GetTimeout)
82+
83+
// ensure ingress is DENIED from gryffindor to ravenclaw since namespace label no longer matches
84+
kubernetes.PokeServer(t, s.ClientSet, &s.KubeConfig, "network-policy-conformance-ravenclaw", "luna-lovegood-0", "sctp",
85+
serverPod.Status.PodIP, int32(9003), s.TimeoutConfig, false)
86+
// luna-lovegood-1 is our client pod in ravenclaw namespace
87+
kubernetes.PokeServer(t, s.ClientSet, &s.KubeConfig, "network-policy-conformance-ravenclaw", "luna-lovegood-1", "sctp",
88+
serverPod.Status.PodIP, int32(9005), s.TimeoutConfig, false)
89+
})
90+
5491
t.Run("Should support an 'allow-ingress' policy for SCTP protocol at the specified port", func(t *testing.T) {
5592
// This test uses `ingress-sctp` admin CNP
5693
// luna-lovegood-1 is our server pod in ravenclaw namespace

conformance/tests/admin-network-policy-standard-ingress-tcp-rules.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,43 @@ var CNPAdminTierIngressTCP = suite.ConformanceTest{
5151
serverPod.Status.PodIP, int32(8080), s.TimeoutConfig, true)
5252
})
5353

54+
t.Run("Should support a 'deny-ingress' policy for TCP protocol on a namespace selector when namespace labels are changed to no longer match", func(t *testing.T) {
55+
// This test uses `ingress-tcp` admin CNP
56+
// harry-potter-0 is our server pod in gryffindor namespace
57+
serverPod := kubernetes.GetPod(t, s.Client, "network-policy-conformance-gryffindor", "harry-potter-0", s.TimeoutConfig.GetTimeout)
58+
// luna-lovegood-0 is our client pod in ravenclaw namespace
59+
// ensure ingress is ALLOWED from gryffindor to ravenclaw
60+
// ingressRule at index0 will take precedence over ingressRule at index1; thus ALLOW takes precedence over DENY since rules are ordered
61+
kubernetes.PokeServer(t, s.ClientSet, &s.KubeConfig, "network-policy-conformance-gryffindor", "harry-potter-0", "tcp",
62+
serverPod.Status.PodIP, int32(80), s.TimeoutConfig, true)
63+
// luna-lovegood-1 is our client pod in ravenclaw namespace
64+
kubernetes.PokeServer(t, s.ClientSet, &s.KubeConfig, "network-policy-conformance-gryffindor", "harry-potter-1", "tcp",
65+
serverPod.Status.PodIP, int32(8080), s.TimeoutConfig, true)
66+
67+
cnp := kubernetes.GetClusterNetworkPolicy(t, s.Client, "ingress-tcp", s.TimeoutConfig.GetTimeout)
68+
mutate := cnp.DeepCopy()
69+
// update namespace selector in ingressRule at index0 to match "conformance-house: gryffindor" label
70+
mutate.Spec.Ingress[0].From[0].Namespaces.MatchLabels = map[string]string{"conformance-house": "gryffindor"}
71+
kubernetes.PatchClusterNetworkPolicy(t, s.Client, cnp, mutate, s.TimeoutConfig.GetTimeout)
72+
73+
// ensure ingress is ALLOWED from gryffindor to ravenclaw since namespace label still matches
74+
kubernetes.PokeServer(t, s.ClientSet, &s.KubeConfig, "network-policy-conformance-gryffindor", "harry-potter-0", "tcp",
75+
serverPod.Status.PodIP, int32(80), s.TimeoutConfig, true)
76+
77+
// update namespace label for gryffindor to "conformance-house": "denied-namespace-label" to no longer match ingressRule at index0
78+
allowedNamespace := kubernetes.GetNamespace(t, s.Client, "network-policy-conformance-gryffindor", s.TimeoutConfig.GetTimeout)
79+
mutateNamespace := allowedNamespace.DeepCopy()
80+
mutateNamespace.SetLabels(map[string]string{"conformance-house": "denied-namespace-label"})
81+
kubernetes.PatchNamespace(t, s.Client, allowedNamespace, mutateNamespace, s.TimeoutConfig.GetTimeout)
82+
83+
// ensure ingress is DENIED from gryffindor to ravenclaw since namespace label no longer matches
84+
kubernetes.PokeServer(t, s.ClientSet, &s.KubeConfig, "network-policy-conformance-ravenclaw", "luna-lovegood-0", "tcp",
85+
serverPod.Status.PodIP, int32(80), s.TimeoutConfig, false)
86+
// luna-lovegood-1 is our client pod in ravenclaw namespace
87+
kubernetes.PokeServer(t, s.ClientSet, &s.KubeConfig, "network-policy-conformance-ravenclaw", "luna-lovegood-1", "tcp",
88+
serverPod.Status.PodIP, int32(8080), s.TimeoutConfig, false)
89+
})
90+
5491
t.Run("Should support an 'allow-ingress' policy for TCP protocol at the specified port", func(t *testing.T) {
5592
// This test uses `ingress-tcp` admin CNP
5693
// harry-potter-1 is our server pod in gryffindor namespace

conformance/tests/admin-network-policy-standard-ingress-udp-rules.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,43 @@ var CNPAdminTierIngressUDP = suite.ConformanceTest{
5252
serverPod.Status.PodIP, int32(5353), s.TimeoutConfig, true)
5353
})
5454

55+
t.Run("Should support a 'deny-ingress' policy for UDP protocol on a namespace selector when namespace labels are changed to no longer match", func(t *testing.T) {
56+
// This test uses `ingress-udp` admin CNP
57+
// cedric-diggory-0 is our server pod in hufflepuff namespace
58+
serverPod := kubernetes.GetPod(t, s.Client, "network-policy-conformance-hufflepuff", "cedric-diggory-0", s.TimeoutConfig.GetTimeout)
59+
// luna-lovegood-0 is our client pod in ravenclaw namespace
60+
// ensure ingress is ALLOWED from ravenclaw to hufflepuff
61+
// ingressRule at index0 will take precedence over ingressRule at index1; thus ALLOW takes precedence over DENY since rules are ordered
62+
kubernetes.PokeServer(t, s.ClientSet, &s.KubeConfig, "network-policy-conformance-ravenclaw", "luna-lovegood-0", "udp",
63+
serverPod.Status.PodIP, int32(53), s.TimeoutConfig, true)
64+
// luna-lovegood-1 is our client pod in ravenclaw namespace
65+
kubernetes.PokeServer(t, s.ClientSet, &s.KubeConfig, "network-policy-conformance-ravenclaw", "luna-lovegood-1", "udp",
66+
serverPod.Status.PodIP, int32(5353), s.TimeoutConfig, true)
67+
68+
cnp := kubernetes.GetClusterNetworkPolicy(t, s.Client, "ingress-udp", s.TimeoutConfig.GetTimeout)
69+
mutate := cnp.DeepCopy()
70+
// update namespace selector in ingressRule at index0 to match "conformance-house: gryffindor" label
71+
mutate.Spec.Ingress[0].From[0].Namespaces.MatchLabels = map[string]string{"conformance-house": "gryffindor"}
72+
kubernetes.PatchClusterNetworkPolicy(t, s.Client, cnp, mutate, s.TimeoutConfig.GetTimeout)
73+
74+
// ensure ingress is ALLOWED from gryffindor to ravenclaw since namespace label still matches
75+
kubernetes.PokeServer(t, s.ClientSet, &s.KubeConfig, "network-policy-conformance-gryffindor", "harry-potter-0", "udp",
76+
serverPod.Status.PodIP, int32(53), s.TimeoutConfig, true)
77+
78+
// update namespace label for gryffindor to "conformance-house": "denied-namespace-label" to no longer match ingressRule at index0
79+
allowedNamespace := kubernetes.GetNamespace(t, s.Client, "network-policy-conformance-gryffindor", s.TimeoutConfig.GetTimeout)
80+
mutateNamespace := allowedNamespace.DeepCopy()
81+
mutateNamespace.SetLabels(map[string]string{"conformance-house": "denied-namespace-label"})
82+
kubernetes.PatchNamespace(t, s.Client, allowedNamespace, mutateNamespace, s.TimeoutConfig.GetTimeout)
83+
84+
// ensure ingress is DENIED from gryffindor to ravenclaw since namespace label no longer matches
85+
kubernetes.PokeServer(t, s.ClientSet, &s.KubeConfig, "network-policy-conformance-ravenclaw", "luna-lovegood-0", "udp",
86+
serverPod.Status.PodIP, int32(53), s.TimeoutConfig, false)
87+
// luna-lovegood-1 is our client pod in ravenclaw namespace
88+
kubernetes.PokeServer(t, s.ClientSet, &s.KubeConfig, "network-policy-conformance-ravenclaw", "luna-lovegood-1", "udp",
89+
serverPod.Status.PodIP, int32(5353), s.TimeoutConfig, false)
90+
})
91+
5592
t.Run("Should support an 'allow-ingress' policy for UDP protocol at the specified port", func(t *testing.T) {
5693
// This test uses `ingress-udp` admin CNP
5794
// cedric-diggory-1 is our server pod in hufflepuff namespace

0 commit comments

Comments
 (0)