Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using stackrox/storage/ResourceCollection #1622

Closed
wants to merge 11 commits into from
Closed
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
133 changes: 133 additions & 0 deletions collector/lib/ResourceSelector.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
//
// Created by Robby Cochran on 3/28/24.
//

#include "ResourceSelector.h"

#include <regex>

#include "Hash.h"

namespace collector {

UnorderedMap<std::string, std::regex> ResourceSelector::regexMap_;

std::regex ResourceSelector::GetOrCompileRegex(const std::string& str) {
auto pair = regexMap_.find(str);
if (pair != regexMap_.end()) {
return pair->second;
} else {
std::regex pattern(str);
regexMap_[str] = pattern;
return pattern;
}
}

bool ResourceSelector::IsRuleValueFollowed(const storage::RuleValue& value, const std::string& resource_name) {
if (value.match_type() == storage::REGEX) {
std::regex pattern = GetOrCompileRegex(value.value());
return std::regex_match(resource_name, pattern);
} else {
return (resource_name == value.value());
}
}

bool ResourceSelector::IsRuleFollowed(const storage::SelectorRule& rule, const std::string& resource_name) {
const auto& values = rule.values();

if (values.size() == 0) {
return true;
}

auto op = [resource_name](const auto& value) -> bool {
return IsRuleValueFollowed(value, resource_name);
};

if (rule.operator_() == storage::BooleanOperator::OR) {
return std::any_of(values.begin(), values.end(), op);
} else if (rule.operator_() == storage::BooleanOperator::AND) {
return std::all_of(values.begin(), values.end(), op);
}

return false;
}

bool ResourceSelector::IsResourceInResourceSelector(const storage::ResourceSelector& rs, const std::string& resource_type, const std::string& resource_name) {
const auto& rules = rs.rules();

if (rules.size() == 0) {
return true;
}

return std::all_of(rules.begin(), rules.end(), [resource_type, resource_name](const auto& rule) -> bool {
return rule.field_name() != resource_type || IsRuleFollowed(rule, resource_name);
});
}

bool ResourceSelector::IsNamespaceInResourceSelector(const storage::ResourceSelector& rs, const std::string& ns) {
return IsResourceInResourceSelector(rs, "Namespace", ns);
}

bool ResourceSelector::IsClusterInResourceSelector(const storage::ResourceSelector& rs, const std::string& cluster) {
return IsResourceInResourceSelector(rs, "Cluster", cluster);
}

bool ResourceSelector::IsNamespaceSelected(const storage::ResourceCollection& rc, const std::string& ns) {
const auto& resource_selectors = rc.resource_selectors();

if (resource_selectors.size() == 0) {
return true;
}

return std::any_of(resource_selectors.begin(), resource_selectors.end(), [ns](const auto& rs) -> bool {
return IsNamespaceInResourceSelector(rs, ns);
});
}

bool ResourceSelector::AreClusterAndNamespaceSelected(const storage::ResourceCollection& rc, const std::string& cluster, const std::string& ns) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

One alternative could be to have a function that strips out all of the ResourceSelectors where the cluster does not match collector's cluster.

const auto& resource_selectors = rc.resource_selectors();

if (resource_selectors.size() == 0) {
return true;
}

return std::any_of(resource_selectors.begin(), resource_selectors.end(), [cluster, ns](const auto& rs) -> bool {
return IsClusterInResourceSelector(rs, cluster) && IsNamespaceInResourceSelector(rs, ns);
});
}

bool ResourceSelector::AreClusterAndNamespaceSelected(const storage::ResourceCollection& rc, const UnorderedMap<std::string, storage::ResourceCollection> rcMap, const std::string& cluster, const std::string& ns) {
if (AreClusterAndNamespaceSelected(rc, cluster, ns)) {
return true;
}

for (const auto& embeddedCollection : rc.embedded_collections()) {
auto embeddedRc = rcMap.find(embeddedCollection.id());
if (embeddedRc != rcMap.end()) {
bool inEmbeddedRc = AreClusterAndNamespaceSelected(embeddedRc->second, rcMap, cluster, ns);
if (inEmbeddedRc) {
Comment on lines +107 to +108
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
bool inEmbeddedRc = AreClusterAndNamespaceSelected(embeddedRc->second, rcMap, cluster, ns);
if (inEmbeddedRc) {
if (AreClusterAndNamespaceSelected(embeddedRc->second, rcMap, cluster, ns)) {

return true;
}
}
}
return false;
Comment on lines +104 to +113
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can this be std::any_of as well?

}
Copy link
Contributor Author

@JoukoVirtanen JoukoVirtanen Mar 30, 2024

Choose a reason for hiding this comment

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

Possible improvements to this function include checks for cycles and stopping at a maximum depth.


// Applies multiple rules for ResourceCollections. Starts with a default status and applies the rules one by one.
// If a cluster/namespace is in a collection the status becomes the status for that collection.
bool ResourceSelector::IsFeatureEnabledForClusterAndNamespace(const std::vector<FilteringRule>& filteringRules, const UnorderedMap<std::string, storage::ResourceCollection> rcMap, bool defaultStatus, const std::string& cluster, const std::string& ns) {
bool status = defaultStatus;

for (auto filteringRule : filteringRules) {
auto rc = rcMap.find(filteringRule.collectionId());
if (rc != rcMap.end()) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Need to decide what to do if the key is not in the map.

if (AreClusterAndNamespaceSelected(rc->second, rcMap, cluster, ns)) {
status = filteringRule.status();
}
}
}

return status;
}

} // namespace collector
56 changes: 56 additions & 0 deletions collector/lib/ResourceSelector.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//
// Created by Robby Cochran on 3/28/24.
//

#ifndef RESOURCESELECTOR_H
#define RESOURCESELECTOR_H
#include <regex>
#include <string>

#include "storage/resource_collection.pb.h"

#include "Hash.h"

namespace collector {

class FilteringRule {
public:
FilteringRule(std::string collectionId, bool status) {
collectionId_ = collectionId;
status_ = status;
}

std::string collectionId() {
return collectionId_;
}

bool status() {
return status_;
}

private:
std::string collectionId_;
bool status_;
};

class ResourceSelector {
Copy link
Collaborator

Choose a reason for hiding this comment

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

The use of a class here feels a little redundant since everything is static anyway. A namespace might be a better fit

public:
static bool IsNamespaceSelected(const storage::ResourceCollection& rc, const std::string& ns);
static bool AreClusterAndNamespaceSelected(const storage::ResourceCollection& rc, const std::string& cluster, const std::string& ns);
static bool AreClusterAndNamespaceSelected(const storage::ResourceCollection& rc, const UnorderedMap<std::string, storage::ResourceCollection> rcMap, const std::string& cluster, const std::string& ns);
static bool IsFeatureEnabledForClusterAndNamespace(const std::vector<FilteringRule>& filteringRules, const UnorderedMap<std::string, storage::ResourceCollection> rcMap, bool defaultStatus, const std::string& cluster, const std::string& ns);

private:
static bool IsRuleFollowed(const storage::SelectorRule& rule, const std::string& ns);
static bool IsRuleValueFollowed(const storage::RuleValue& value, const std::string& ns);
Comment on lines +44 to +45
Copy link
Collaborator

Choose a reason for hiding this comment

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

Could also use overloading here and call both functions IsRuleFollowed (or IsFollowed to be type-agnostic)

static bool IsResourceInResourceSelector(const storage::ResourceSelector& rs, const std::string& resource_type, const std::string& resource_name);
Molter73 marked this conversation as resolved.
Show resolved Hide resolved
static bool IsNamespaceInResourceSelector(const storage::ResourceSelector& rs, const std::string& ns);
static bool IsClusterInResourceSelector(const storage::ResourceSelector& rs, const std::string& cluster);
Comment on lines +46 to +48
Copy link
Collaborator

Choose a reason for hiding this comment

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

[nit] these are pretty verbose and the type name suffix is unnecessary - perhaps ContainsResource ContainsNamespace ContainsCluster?

static std::regex GetOrCompileRegex(const std::string& str);

static UnorderedMap<std::string, std::regex> regexMap_;
};

} // namespace collector

#endif // RESOURCESELECTOR_H
14 changes: 14 additions & 0 deletions collector/proto/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,22 @@ set(ROX_PROTO_FILES
internalapi/sensor/network_connection_iservice.proto
internalapi/sensor/network_enums.proto
internalapi/sensor/signal_iservice.proto
storage/container_runtime.proto
storage/cve.proto
storage/deployment.proto
storage/image.proto
storage/labels.proto
storage/network_flow.proto
storage/policy.proto
storage/process_indicator.proto
storage/rbac.proto
storage/resource_collection.proto
storage/role.proto
storage/scope.proto
storage/taints.proto
storage/traits.proto
storage/user.proto
storage/vulnerability.proto
)

add_library(rox-proto ${ROX_PROTO_FILES})
Expand Down
2 changes: 1 addition & 1 deletion collector/proto/third_party/stackrox
Submodule stackrox updated 9410 files
Loading
Loading