Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions .github/workflows/test-compliance.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
name: Test Compliance

on:
pull_request:
paths:
- 'e2e-tests/tests/**'

permissions:
contents: read

jobs:
run-as-admin-compliance:
name: run-as-admin compliance
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
Comment thread
midays marked this conversation as resolved.

- name: Check for non-compliant test patterns
run: |
set +e
VIOLATIONS=()

for FILE in $(find e2e-tests/tests -name '*_test.go'); do
[ -f "$FILE" ] || continue

# Skip admin tests — only non-admin tests call SetupActiveKubectlRunners
if ! grep -q "SetupActiveKubectlRunners\|SetupNamespaceAdminUsersForScenario" "$FILE"; then
continue
fi

ISSUES=""

if grep -q "SetupNamespaceAdminUsersForScenario" "$FILE"; then
ISSUES="${ISSUES}\n - use SetupActiveKubectlRunners instead of SetupNamespaceAdminUsersForScenario"
fi

if grep -q 'NonAdmin\.Context == ""' "$FILE"; then
ISSUES="${ISSUES}\n - remove empty-context Skip guards (they block RUN_AS_ADMIN override)"
fi

if [ -n "$ISSUES" ]; then
VIOLATIONS+=("$FILE:$ISSUES")
fi
done

echo ""
if [ ${#VIOLATIONS[@]} -eq 0 ]; then
echo "PASS: all non-admin test files are compliant."
exit 0
fi

echo "FAIL: the following non-admin test files are not compliant with RUN_AS_ADMIN:"
echo ""
for V in "${VIOLATIONS[@]}"; do
FILE="${V%%:*}"
ISSUES="${V#*:}"
echo " $FILE"
echo -e "$ISSUES"
echo ""
done

exit 1
1 change: 1 addition & 0 deletions e2e-tests/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ var (
SourceNonAdminContext string
TargetNonAdminContext string
InsecureSkipTLSVerify bool
RunAs string
)
41 changes: 41 additions & 0 deletions e2e-tests/framework/rbac.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"log"
"strings"

"github.com/konveyor/crane/e2e-tests/config"
"github.com/konveyor/crane/e2e-tests/utils"
)

Expand Down Expand Up @@ -108,6 +109,46 @@ func SetupNamespaceAdminUser(adminKubectl KubectlRunner, nonAdminContext, namesp
return userKubectl, cleanup, nil
}

// SetupActiveNamespaceAdmin sets up namespace-scoped access on a single cluster.
// When config.RunAs == "admin", it creates the namespace with the admin runner and returns
// a no-op cleanup. Otherwise it delegates to SetupNamespaceAdminUser.
func SetupActiveNamespaceAdmin(adminKubectl KubectlRunner, nonAdminContext, namespace string) (KubectlRunner, func(), error) {
if config.RunAs == "admin" {
if err := adminKubectl.CreateNamespace(namespace); err != nil {
return KubectlRunner{}, nil, fmt.Errorf("failed to create namespace %q: %w", namespace, err)
}
return adminKubectl, func() {}, nil
}
return SetupNamespaceAdminUser(adminKubectl, nonAdminContext, namespace)
}

// SetupActiveKubectlRunners returns kubectl runners appropriate for the current RunAs mode.
// When config.RunAs == "admin", it creates the namespace with admin credentials and returns
// admin runners directly (bypassing RBAC setup). Otherwise it delegates to
// SetupNamespaceAdminUsersForScenario to grant namespace-scoped permissions to the non-admin user.
func SetupActiveKubectlRunners(scenario MigrationScenario, namespace string) (KubectlRunner, KubectlRunner, func(), error) {
if config.RunAs == "admin" {
if srcUser, err := ResolveUsernameForContext(scenario.KubectlSrc.Context); err != nil {
log.Printf("[run-as=admin] source context=%q: could not resolve username: %v", scenario.KubectlSrc.Context, err)
} else {
log.Printf("[run-as=admin] source context=%q running as user=%q", scenario.KubectlSrc.Context, srcUser)
}
if tgtUser, err := ResolveUsernameForContext(scenario.KubectlTgt.Context); err != nil {
log.Printf("[run-as=admin] target context=%q: could not resolve username: %v", scenario.KubectlTgt.Context, err)
} else {
log.Printf("[run-as=admin] target context=%q running as user=%q", scenario.KubectlTgt.Context, tgtUser)
}
if err := scenario.KubectlSrc.CreateNamespace(namespace); err != nil {
return KubectlRunner{}, KubectlRunner{}, nil, fmt.Errorf("failed to create namespace %q on source: %w", namespace, err)
}
if err := scenario.KubectlTgt.CreateNamespace(namespace); err != nil {
return KubectlRunner{}, KubectlRunner{}, nil, fmt.Errorf("failed to create namespace %q on target: %w", namespace, err)
Comment thread
midays marked this conversation as resolved.
}
return scenario.KubectlSrc, scenario.KubectlTgt, func() {}, nil
}
return SetupNamespaceAdminUsersForScenario(scenario, namespace)
}

// SetupNamespaceAdminUsersForScenario grants namespace-scoped admin permissions
// on both source and target clusters for the configured non-admin contexts.
// It returns kubectl runners bound to the non-admin contexts and a combined
Expand Down
19 changes: 14 additions & 5 deletions e2e-tests/framework/scenario.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,16 @@ type MigrationScenario struct {
}

// NewMigrationScenario builds shared runners and app objects for a migration test.
// When config.RunAs == "admin", the NonAdmin fields are populated with admin contexts
// so all test code using those fields automatically runs with cluster-admin credentials.
func NewMigrationScenario(appName, namespace, k8sDeployBin, craneBin, srcCtx, tgtCtx string) MigrationScenario {
srcNonAdminCtx := config.SourceNonAdminContext
tgtNonAdminCtx := config.TargetNonAdminContext
if config.RunAs == "admin" {
srcNonAdminCtx = srcCtx
tgtNonAdminCtx = tgtCtx
}
Comment thread
midays marked this conversation as resolved.

return MigrationScenario{
AppName: appName,
Namespace: namespace,
Expand All @@ -48,27 +57,27 @@ func NewMigrationScenario(appName, namespace, k8sDeployBin, craneBin, srcCtx, tg
Name: appName,
Namespace: namespace,
Bin: k8sDeployBin,
Context: config.SourceNonAdminContext,
Context: srcNonAdminCtx,
InsecureSkipTLS: config.InsecureSkipTLSVerify,
},
TgtAppNonAdmin: K8sDeployApp{
Name: appName,
Namespace: namespace,
Bin: k8sDeployBin,
Context: config.TargetNonAdminContext,
Context: tgtNonAdminCtx,
InsecureSkipTLS: config.InsecureSkipTLSVerify,
},
KubectlSrc: KubectlRunner{Bin: "kubectl", Context: srcCtx},
KubectlTgt: KubectlRunner{Bin: "kubectl", Context: tgtCtx},
KubectlSrcNonAdmin: KubectlRunner{Bin: "kubectl", Context: config.SourceNonAdminContext},
KubectlTgtNonAdmin: KubectlRunner{Bin: "kubectl", Context: config.TargetNonAdminContext},
KubectlSrcNonAdmin: KubectlRunner{Bin: "kubectl", Context: srcNonAdminCtx},
KubectlTgtNonAdmin: KubectlRunner{Bin: "kubectl", Context: tgtNonAdminCtx},
Crane: CraneRunner{
Bin: craneBin,
SourceContext: srcCtx,
},
CraneNonAdmin: CraneRunner{
Bin: craneBin,
SourceContext: config.SourceNonAdminContext,
SourceContext: srcNonAdminCtx,
},
}
}
Expand Down
1 change: 1 addition & 0 deletions e2e-tests/tests/tier0/e2e_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ func init() {
flag.StringVar(&config.SourceNonAdminContext, "source-nonadmin-context", "", "Source cluster non-admin context for RBAC scenarios")
flag.StringVar(&config.TargetNonAdminContext, "target-nonadmin-context", "", "Target cluster non-admin context for RBAC scenarios")
flag.BoolVar(&config.InsecureSkipTLSVerify, "insecure-skip-tls-verify", false, "Skip TLS certificate verification for k8sdeploy connections (use for OCP clusters with self-signed certs)")
flag.StringVar(&config.RunAs, "run-as", "", "Override user context: set to 'admin' to run all tests with cluster-admin credentials")
}

// TestE2E configures Ginkgo and executes the e2e test suite.
Expand Down
8 changes: 1 addition & 7 deletions e2e-tests/tests/tier0/mta_804_empty_pvc_migration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,6 @@ var _ = Describe("Empty PVC migration", func() {
config.SourceContext,
config.TargetContext,
)
if scenario.KubectlSrcNonAdmin.Context == "" {
Skip("source-nonadmin-context is required for non-admin test")
}
if scenario.KubectlTgtNonAdmin.Context == "" {
Skip("target-nonadmin-context is required for non-admin test")
}
srcApp := scenario.SrcAppNonAdmin
tgtApp := scenario.TgtAppNonAdmin

Expand All @@ -42,7 +36,7 @@ var _ = Describe("Empty PVC migration", func() {
}

By("Grant ns admin permissions to nonadmin user on source and target")
kubectlSrcNonAdmin, kubectlTgtNonAdmin, cleanup, err := SetupNamespaceAdminUsersForScenario(scenario, namespace)
kubectlSrcNonAdmin, kubectlTgtNonAdmin, cleanup, err := SetupActiveKubectlRunners(scenario, namespace)
Expect(err).NotTo(HaveOccurred())
DeferCleanup(cleanup)

Expand Down
8 changes: 1 addition & 7 deletions e2e-tests/tests/tier0/mta_805_sets_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,6 @@ var _ = Describe("Sets resources migration", func() {
config.SourceContext,
config.TargetContext,
)
if scenario.KubectlSrcNonAdmin.Context == "" {
Skip("source-nonadmin-context is required for non-admin stateless migration test")
}
if scenario.KubectlTgtNonAdmin.Context == "" {
Skip("target-nonadmin-context is required for non-admin stateless migration test")
}
srcApp := scenario.SrcAppNonAdmin
tgtApp := scenario.TgtAppNonAdmin
runner := scenario.CraneNonAdmin
Expand All @@ -53,7 +47,7 @@ var _ = Describe("Sets resources migration", func() {
tgtApp.ExtraVars = srcApp.ExtraVars

By("Grant ns admin permissions to nonadmin user on source and target")
kubectlSrcNonAdmin, kubectlTgtNonAdmin, cleanup, err := SetupNamespaceAdminUsersForScenario(scenario, namespace)
kubectlSrcNonAdmin, kubectlTgtNonAdmin, cleanup, err := SetupActiveKubectlRunners(scenario, namespace)
Comment thread
midays marked this conversation as resolved.
Expect(err).NotTo(HaveOccurred())
DeferCleanup(func() {
By("Delete test namespace on source and target (best effort)")
Expand Down
8 changes: 1 addition & 7 deletions e2e-tests/tests/tier0/mta_806_pvc_data_integrity_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,6 @@ var _ = Describe("PVC data integrity migration", func() {
config.SourceContext,
config.TargetContext,
)
if scenario.KubectlSrcNonAdmin.Context == "" {
Skip("source-nonadmin-context is required for non-admin test")
}
if scenario.KubectlTgtNonAdmin.Context == "" {
Skip("target-nonadmin-context is required for non-admin test")
}
srcApp := scenario.SrcAppNonAdmin
tgtApp := scenario.TgtAppNonAdmin

Expand All @@ -48,7 +42,7 @@ var _ = Describe("PVC data integrity migration", func() {
}

By("Grant ns admin permissions to nonadmin user on source and target")
kubectlSrcNonAdmin, kubectlTgtNonAdmin, cleanup, err := SetupNamespaceAdminUsersForScenario(scenario, namespace)
kubectlSrcNonAdmin, kubectlTgtNonAdmin, cleanup, err := SetupActiveKubectlRunners(scenario, namespace)
Expect(err).NotTo(HaveOccurred())
DeferCleanup(cleanup)

Expand Down
8 changes: 1 addition & 7 deletions e2e-tests/tests/tier0/mta_807_data_validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,12 +129,6 @@ var _ = Describe("Data validation with indirect migration of MySQL DB", func() {
config.SourceContext,
config.TargetContext,
)
if scenario.KubectlSrcNonAdmin.Context == "" {
Skip("source-nonadmin-context is required for non-admin stateful migration test")
}
if scenario.KubectlTgtNonAdmin.Context == "" {
Skip("target-nonadmin-context is required for non-admin stateful migration test")
}
srcApp := scenario.SrcAppNonAdmin
tgtApp := scenario.TgtAppNonAdmin
runner := scenario.CraneNonAdmin
Expand All @@ -150,7 +144,7 @@ var _ = Describe("Data validation with indirect migration of MySQL DB", func() {
}

By("Grant namespace admin permissions to nonadmin user on source and target")
kubectlSrcNonAdmin, kubectlTgtNonAdmin, cleanup, err := SetupNamespaceAdminUsersForScenario(scenario, namespace)
kubectlSrcNonAdmin, kubectlTgtNonAdmin, cleanup, err := SetupActiveKubectlRunners(scenario, namespace)
Expect(err).NotTo(HaveOccurred())

DeferCleanup(func() {
Expand Down
8 changes: 1 addition & 7 deletions e2e-tests/tests/tier0/mta_809_initcontainer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,6 @@ var _ = Describe("InitContainer Migration", func() {
config.SourceContext,
config.TargetContext,
)
if scenario.KubectlSrcNonAdmin.Context == "" {
Skip("source-nonadmin-context is required for non-admin stateless migration test")
}
if scenario.KubectlTgtNonAdmin.Context == "" {
Skip("target-nonadmin-context is required for non-admin stateless migration test")
}
srcApp := scenario.SrcAppNonAdmin
tgtApp := scenario.TgtAppNonAdmin
runner := scenario.CraneNonAdmin
Expand All @@ -43,7 +37,7 @@ var _ = Describe("InitContainer Migration", func() {
}

By("Grant ns admin permissions to nonadmin user on source and target")
kubectlSrcNonAdmin, kubectlTgtNonAdmin, cleanup, err := SetupNamespaceAdminUsersForScenario(scenario, namespace)
kubectlSrcNonAdmin, kubectlTgtNonAdmin, cleanup, err := SetupActiveKubectlRunners(scenario, namespace)
Expect(err).NotTo(HaveOccurred())
DeferCleanup(func() {
By("Delete test namespace on source and target (wait for completion)")
Expand Down
8 changes: 1 addition & 7 deletions e2e-tests/tests/tier0/mta_810_configmap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,6 @@ var _ = Describe("ConfigMap Migration", func() {
config.TargetContext,
)

if scenario.KubectlSrcNonAdmin.Context == "" {
Skip("source-nonadmin-context is required for non-admin stateless migration test")
}
if scenario.KubectlTgtNonAdmin.Context == "" {
Skip("target-nonadmin-context is required for non-admin stateless migration test")
}
srcApp := scenario.SrcAppNonAdmin
tgtApp := scenario.TgtAppNonAdmin
runner := scenario.CraneNonAdmin
Expand All @@ -43,7 +37,7 @@ var _ = Describe("ConfigMap Migration", func() {
}

By("Grant ns admin permissions to nonadmin user on source and target")
kubectlSrcNonAdmin, kubectlTgtNonAdmin, cleanup, err := SetupNamespaceAdminUsersForScenario(scenario, namespace)
kubectlSrcNonAdmin, kubectlTgtNonAdmin, cleanup, err := SetupActiveKubectlRunners(scenario, namespace)
Expect(err).NotTo(HaveOccurred())
DeferCleanup(func() {
By("Delete test namespace on source and target (wait for completion)")
Expand Down
8 changes: 1 addition & 7 deletions e2e-tests/tests/tier0/mta_811_mongodb_non_admin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,12 +108,6 @@ var _ = Describe("MongoDB Migration", func() {
config.TargetContext,
)

if scenario.KubectlSrcNonAdmin.Context == "" {
Skip("source-nonadmin-context is required for non-admin stateful migration test")
}
if scenario.KubectlTgtNonAdmin.Context == "" {
Skip("target-nonadmin-context is required for non-admin stateful migration test")
}
srcApp := scenario.SrcAppNonAdmin
tgtApp := scenario.TgtAppNonAdmin
runner := scenario.CraneNonAdmin
Expand All @@ -126,7 +120,7 @@ var _ = Describe("MongoDB Migration", func() {
}

By("Grant namespace admin permissions to nonadmin user on source and target")
kubectlSrcNonAdmin, kubectlTgtNonAdmin, cleanup, err := SetupNamespaceAdminUsersForScenario(scenario, namespace)
kubectlSrcNonAdmin, kubectlTgtNonAdmin, cleanup, err := SetupActiveKubectlRunners(scenario, namespace)
Expect(err).NotTo(HaveOccurred())
Comment thread
midays marked this conversation as resolved.

DeferCleanup(func() {
Expand Down
8 changes: 1 addition & 7 deletions e2e-tests/tests/tier0/mta_812_role_migration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,6 @@ var _ = Describe("Role and RoleBinding migration", func() {
config.TargetContext,
)

if scenario.KubectlSrcNonAdmin.Context == "" {
Skip("source-nonadmin-context is required for non-admin role migration test")
}
if scenario.KubectlTgtNonAdmin.Context == "" {
Skip("target-nonadmin-context is required for non-admin role migration test")
}

srcApp := scenario.SrcAppNonAdmin
tgtApp := scenario.TgtAppNonAdmin
Expand All @@ -43,7 +37,7 @@ var _ = Describe("Role and RoleBinding migration", func() {
}

By("Grant ns admin permissions to nonadmin user on source and target")
kubectlSrcNonAdmin, kubectlTgtNonAdmin, cleanup, err := SetupNamespaceAdminUsersForScenario(scenario, namespace)
kubectlSrcNonAdmin, kubectlTgtNonAdmin, cleanup, err := SetupActiveKubectlRunners(scenario, namespace)
Expect(err).NotTo(HaveOccurred())
DeferCleanup(func() {
By("Delete test namespace on source and target (wait for completion)")
Expand Down
8 changes: 1 addition & 7 deletions e2e-tests/tests/tier0/mta_813_cronJob_PVC_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,6 @@ var _ = Describe("CronJob with attached PVC migration as non-admin user", func()
config.TargetContext,
)

if scenario.KubectlSrcNonAdmin.Context == "" {
Skip("source-nonadmin-context is required for this test")
}
if scenario.KubectlTgtNonAdmin.Context == "" {
Skip("target-nonadmin-context is required for this test")
}

srcApp := scenario.SrcAppNonAdmin
tgtApp := scenario.TgtAppNonAdmin
Expand All @@ -51,7 +45,7 @@ var _ = Describe("CronJob with attached PVC migration as non-admin user", func()
}

By("Grant namespace-admin permissions to non-admin user on source and target")
kubectlSrcNonAdmin, _, cleanup, err := SetupNamespaceAdminUsersForScenario(scenario, namespace)
kubectlSrcNonAdmin, _, cleanup, err := SetupActiveKubectlRunners(scenario, namespace)
Expect(err).NotTo(HaveOccurred())
DeferCleanup(func() {
By("Delete test namespace on source and target (wait for completion)")
Expand Down
Loading
Loading