Skip to content
Merged
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
2 changes: 1 addition & 1 deletion pkg/features/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ var (
QuayRobotAccounts = registerFeature("Enable Robot accounts in Quay Image Integration", "ROX_QUAY_ROBOT_ACCOUNTS", true)

// RoxctlNetpolGenerate enables 'roxctl netpol generate' command which integrates with NP-Guard
RoxctlNetpolGenerate = registerFeature("Enable 'roxctl netpol generate' command", "ROX_ROXCTL_NETPOL_GENERATE", false)
RoxctlNetpolGenerate = registerFeature("Enable 'roxctl generate netpol' command", "ROX_ROXCTL_NETPOL_GENERATE", true)

// ObjectCollections enables 'collection' entity APIs and Frontend collection pages
ObjectCollections = registerFeature("Enable object collection entities", "ROX_OBJECT_COLLECTIONS", false)
Expand Down
30 changes: 0 additions & 30 deletions roxctl/generate/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,36 +12,6 @@ The static network policy generator is a tool that analyzes k8s manifests and ge

## Usage

### Compiling

The feature `roxctl generate netpol` is currently not available in the officially released images of `roxctl` and must be compiled locally after fetching the stackrox repository.

Refer to [the build tooling section in the Readme](https://github.com/stackrox/stackrox#build-tooling) for details about build prerequisites.

```shell
git clone https://github.com/stackrox/stackrox.git && cd stackrox
# Compile roxctl for a given OS with empty GOTAGS
make cli-{darwin,linux} GOTAGS=''
# Set feature-flag
export ROX_ROXCTL_NETPOL_GENERATE="true"
# Confirm feature availability

$ bin/darwin_amd64/roxctl generate netpol -h
Based on a given folder containing deployment YAMLs, will generate a list of recommended Network Policies. Will write to stdout if no output flags are provided.

Usage:
bin/darwin_amd64/roxctl generate netpol <folder-path> [flags]

Flags:
--fail fail on the first encountered error (default false)
-h, --help help for netpol
-d, --output-dir string save generated policies into target folder - one file per policy
-f, --output-file string save and merge generated policies into a single yaml file
--remove remove the output path if it already exists (default false)
--strict treat warnings as errors (default false)
(...)
```

### Generating Network Policies from yaml manifests

To generate network policies, `roxctl generate netpol` requires a folder containing K8s manifests.
Expand Down
1 change: 1 addition & 0 deletions roxctl/generate/netpol/netpol.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ func Command(cliEnvironment environment.Environment) *cobra.Command {
Use: "netpol <folder-path>",
Args: cobra.ExactArgs(1),
RunE: func(c *cobra.Command, args []string) error {
generateNetpolCmd.env.Logger().WarnfLn("This is a Technology Preview feature. Red Hat does not recommend using Technology Preview features in production.")
synth, err := generateNetpolCmd.construct(args, c)
if err != nil {
return err
Expand Down
9 changes: 5 additions & 4 deletions roxctl/help/help.properties
Original file line number Diff line number Diff line change
Expand Up @@ -172,11 +172,12 @@ helm.output.long =
helm.derive-local-values.short = Derive local Helm values from cluster configuration.
helm.derive-local-values.long =

generate.short = Commands related to generating different resources.
generate.long =
generate.short = (Technology Preview) Commands related to generating different resources.
generate.long = Commands related to generating different resources.\n\n** This is a Technology Preview feature **\nTechnology Preview features are not supported with Red Hat production service level agreements (SLAs) and might not be functionally complete. Red Hat does not recommend using them in production. These features provide early access to upcoming product features, enabling customers to test functionality and provide feedback during the development process. For more information about the support scope of Red Hat Technology Preview features, see https://access.redhat.com/support/offerings/techpreview/

generate.netpol.short = (Technology Preview) Recommend Network Policies based on deployment information.
generate.netpol.long = Based on a given folder containing deployment YAMLs, will generate a list of recommended Network Policies. Will write to stdout if no output flags are provided.\n\n** This is a Technology Preview feature **\nTechnology Preview features are not supported with Red Hat production service level agreements (SLAs) and might not be functionally complete. Red Hat does not recommend using them in production. These features provide early access to upcoming product features, enabling customers to test functionality and provide feedback during the development process. For more information about the support scope of Red Hat Technology Preview features, see https://access.redhat.com/support/offerings/techpreview/

generate.netpol.short = Recommend Network Policies based on deployment information.
generate.netpol.long = Based on a given folder containing deployment YAMLs, will generate a list of recommended Network Policies. Will write to stdout if no output flags are provided.

version.short = Display the current roxctl version.
version.long = Display the current roxctl version.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,13 @@ setup_file() {
setup() {
out_dir="$(mktemp -d -u)"
ofile="$(mktemp)"
export ROX_ROXCTL_NETPOL_GENERATE='true'
}

teardown() {
rm -rf "$out_dir"
rm -f "$ofile"
}

@test "roxctl-development generate netpol should respect ROX_ROXCTL_NETPOL_GENERATE feature-flag at runtime" {
export ROX_ROXCTL_NETPOL_GENERATE=false
run roxctl-development generate netpol "$out_dir"
assert_failure
assert_line --partial 'unknown command "generate"'
}


@test "roxctl-development generate netpol should return error on empty or non-existing directory" {
run roxctl-development generate netpol "$out_dir"
assert_failure
Expand Down
142 changes: 139 additions & 3 deletions tests/roxctl/bats-tests/local/roxctl-netpol-generate-release.bats
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
load "../helpers.bash"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[not blocking the merge]
Is this file a copy-paste of roxctl-netpol-generate-development.bats with the only difference that roxctl-development is changed for roxctl-release? I don't think that massively copy-pasting anything is healthy practice that we can sustainably do. If there's no way to parameterize tests that they run development and release builds, I would vote to keep only the test that checks roxctl-release.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, there is no way for this - we have been exploring this some time ago. The only way to avoid copy-paste is to write a code generator and generate tests dynamically.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it work to parameterize the specific parts with env vars and source generic_test.sh from two bats tests files? (didn't test)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, unfortunately sourcing would not work. There was a thread about this somewhere in the Bats GH/Wiki. Maybe I will give it a look if they got any new feats regarding this.


out_dir=""
templated_fragment='"{{ printf "%s" ._thing.image }}"'

setup_file() {
command -v yq >/dev/null || skip "Tests in this file require yq"
Expand All @@ -23,11 +24,146 @@ teardown() {
rm -f "$ofile"
}

@test "roxctl-release generate netpol should not respect ROX_ROXCTL_NETPOL_GENERATE feature-flag at runtime" {
export ROX_ROXCTL_NETPOL_GENERATE='true'
@test "roxctl-release generate netpol should return error on empty or non-existing directory" {
run roxctl-release generate netpol "$out_dir"
assert_failure
assert_line --partial 'unknown command "generate"'
assert_line --partial "error generating network policies"
assert_line --partial "no such file or directory"

run roxctl-release generate netpol
assert_failure
assert_line --partial "accepts 1 arg(s), received 0"
}

@test "roxctl-release generate netpol generates network policies" {
assert_file_exist "${test_data}/np-guard/scenario-minimal-service/frontend.yaml"
assert_file_exist "${test_data}/np-guard/scenario-minimal-service/backend.yaml"
echo "Writing network policies to ${ofile}" >&3
run roxctl-release generate netpol "${test_data}/np-guard/scenario-minimal-service"
assert_success

echo "$output" > "$ofile"
assert_file_exist "$ofile"
yaml_valid "$ofile"

# There must be at least 2 yaml documents in the output
# yq version 4.16.2 has problems with handling 'document_index', thus we use 'di'
run yq e 'di' "${ofile}"
assert_line '0'
assert_line '1'

# Ensure that both yaml docs are of kind 'NetworkPolicy'
run yq e '.kind | ({"match": ., "doc": di})' "${ofile}"
assert_line --index 0 'match: NetworkPolicy'
assert_line --index 1 'doc: 0'
assert_line --index 2 'match: NetworkPolicy'
assert_line --index 3 'doc: 1'
}

@test "roxctl-release generate netpol produces no output when all yamls are templated" {
mkdir -p "$out_dir"
write_yaml_to_file "$templated_fragment" "$(mktemp "$out_dir/templated-XXXXXX.yaml")"

echo "Analyzing a corrupted yaml file '$templatedYaml'" >&3
run roxctl-release generate netpol "$out_dir/"
assert_failure
assert_output --partial 'YAML document is malformed'
assert_output --partial 'no relevant Kubernetes resources found'
}

@test "roxctl-release generate netpol produces errors when some yamls are templated" {
mkdir -p "$out_dir"
write_yaml_to_file "$templated_fragment" "$(mktemp "$out_dir/templated-XXXXXX.yaml")"

assert_file_exist "${test_data}/np-guard/scenario-minimal-service/frontend.yaml"
assert_file_exist "${test_data}/np-guard/scenario-minimal-service/backend.yaml"
cp "${test_data}/np-guard/scenario-minimal-service/frontend.yaml" "$out_dir/frontend.yaml"
cp "${test_data}/np-guard/scenario-minimal-service/backend.yaml" "$out_dir/backend.yaml"

echo "Analyzing a directory where 1/3 of yaml files are templated '$out_dir/'" >&3
run roxctl-release generate netpol "$out_dir/" --remove --output-file=/dev/null
assert_failure
assert_output --partial 'YAML document is malformed'
refute_output --partial 'no relevant Kubernetes resources found'
}

@test "roxctl-release generate netpol produces warnings (or errors for --strict) when yamls are not K8s resources" {
mkdir -p "$out_dir"
assert_file_exist "${test_data}/np-guard/empty-yamls/empty.yaml"
assert_file_exist "${test_data}/np-guard/empty-yamls/empty2.yaml"
cp "${test_data}/np-guard/empty-yamls/empty.yaml" "$out_dir/empty.yaml"
cp "${test_data}/np-guard/empty-yamls/empty2.yaml" "$out_dir/empty2.yaml"

run roxctl-release generate netpol "$out_dir/" --remove --output-file=/dev/null
assert_success
assert_output --partial 'Yaml document is not a K8s resource'
assert_output --partial 'no relevant Kubernetes resources found'

run roxctl-release generate netpol "$out_dir/" --remove --output-file=/dev/null --strict
assert_failure
assert_output --partial 'Yaml document is not a K8s resource'
assert_output --partial 'no relevant Kubernetes resources found'
assert_output --partial 'ERROR:'
assert_output --partial 'there were warnings during execution'
}

@test "roxctl-release generate netpol stops on first error when run with --fail" {
mkdir -p "$out_dir"
write_yaml_to_file "$templated_fragment" "$(mktemp "$out_dir/templated-01-XXXXXX-file1.yaml")"
write_yaml_to_file "$templated_fragment" "$(mktemp "$out_dir/templated-02-XXXXXX-file2.yaml")"

run roxctl-release generate netpol "$out_dir/" --remove --output-file=/dev/null --fail
assert_failure
assert_output --partial 'YAML document is malformed'
assert_output --partial 'file1.yaml'
refute_output --partial 'file2.yaml'
}

write_yaml_to_file() {
image="${1}"
templatedYaml="${2:-/dev/null}"
cat >"$templatedYaml" <<-EOF
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
spec:
selector:
matchLabels:
app: frontend
template:
metadata:
labels:
app: frontend
spec:
containers:
- name: server
image: $image
ports:
- containerPort: 8080
env:
- name: PORT
value: "8080"
resources:
requests:
cpu: 100m
memory: 64Mi
limits:
cpu: 200m
memory: 128Mi
---
apiVersion: v1
kind: Service
metadata:
name: frontend
spec:
type: ClusterIP
selector:
app: frontend
ports:
- name: http
port: 80
targetPort: 8080
EOF
}