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
13 changes: 13 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@
# - use environment variables to overwrite this value (e.g export VERSION=0.0.2)
VERSION ?= 1.13.0

# PREVIOUS_VERSION defines the version that this release replaces.
# Update this value when you bump VERSION to the next release.
# This is used to set spec.replaces in the OpenShift bundle CSV.
PREVIOUS_VERSION ?= 1.12.1

# CHANNELS define the bundle channels used in the bundle.
# Add a new line here if you would like to change its default config. (E.g CHANNELS = "candidate,fast,stable")
# To re-generate a bundle for other specific channels without changing the standard setup, you can:
Expand Down Expand Up @@ -346,3 +351,11 @@ catalog-push: ## Push a catalog image.
.PHONY: non-olm
non-olm: kustomize ## Generate non-olm deployment manifest
$(KUSTOMIZE) build config/non-olm -o deploy/falcon-operator.yaml

.PHONY: bundle-openshift
bundle-openshift: bundle ## Generate bundle and patch with OpenShift certification requirements
@hack/patch-openshift-bundle.sh

.PHONY: bundle-openshift-validate
bundle-openshift-validate: ## Validate OpenShift bundle patches were applied correctly
@hack/validate-openshift-bundle.sh
77 changes: 77 additions & 0 deletions hack/get-latest-rh-image.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#!/usr/bin/env bash

set -e

if [ "$#" -ne 1 ]; then
echo "Usage: $0 <component>" >&2
echo "Available components: falcon-sensor, falcon-container, falcon-kac, falcon-imageanalyzer, falcon-operator" >&2
exit 1
fi

COMPONENT="$1"

# Map component names to registry and repo paths
case "$COMPONENT" in
falcon-sensor)
REGISTRY="registry.crowdstrike.com"
REPO_PATH="falcon-sensor/release/falcon-sensor"
;;
falcon-container)
REGISTRY="registry.crowdstrike.com"
REPO_PATH="falcon-container/release/falcon-container"
;;
falcon-kac)
REGISTRY="registry.crowdstrike.com"
REPO_PATH="falcon-kac/release/falcon-kac"
;;
falcon-imageanalyzer)
REGISTRY="registry.crowdstrike.com"
REPO_PATH="falcon-imageanalyzer/release/falcon-imageanalyzer"
;;
falcon-operator)
REGISTRY="registry.connect.redhat.com"
REPO_PATH="crowdstrike/falcon-operator"
;;
*)
echo "Error: Unknown component '$COMPONENT'" >&2
echo "Available components: falcon-sensor, falcon-container, falcon-kac, falcon-imageanalyzer, falcon-operator" >&2
exit 1
;;
esac

API_PREFIX="https://catalog.redhat.com/api/containers/v1/repositories/registry/${REGISTRY}/repository"

# First, get pagination info to determine the last page
FIRST_PAGE=$(curl -s "${API_PREFIX}/${REPO_PATH}/images")
TOTAL=$(echo "$FIRST_PAGE" | jq -r '.total')
PAGE_SIZE=$(echo "$FIRST_PAGE" | jq -r '.page_size')

# Calculate the last page number (pages are 0-indexed)
LAST_PAGE=$(( (TOTAL - 1) / PAGE_SIZE ))

# Fetch the last page
RESPONSE=$(curl -s "${API_PREFIX}/${REPO_PATH}/images?page=${LAST_PAGE}")

# Extract all repositories with their tags and manifest digests
# Filter to only numeric version tags, sort by version, and get the latest
RESULT=$(echo "$RESPONSE" | jq -r '
.data[].repositories[] |
select(.tags[0].name | test("^[0-9]")) |
{
tag: .tags[0].name,
manifest_list_digest: .manifest_list_digest
} |
"\(.tag)|\(.manifest_list_digest)"
' | sort -V | tail -n1)

if [ -z "$RESULT" ]; then
echo "Error: Could not retrieve image information from Red Hat catalog" >&2
exit 1
fi

# Parse the result
TAG=$(echo "$RESULT" | cut -d'|' -f1)
DIGEST=$(echo "$RESULT" | cut -d'|' -f2)

echo "tag=${TAG}"
echo "manifest_list_digest=${DIGEST}"
188 changes: 188 additions & 0 deletions hack/patch-openshift-bundle.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
#!/usr/bin/env bash
#
# Patch OpenShift bundle with certification requirements
#
# This script applies all necessary patches to the operator bundle for OpenShift certification.
# It is run by 'make bundle-openshift' after 'make bundle' generates the base bundle.
#
# IMPORTANT: When adding new patches to this script, also add corresponding validation
# assertions to hack/validate-openshift-bundle.sh to ensure the patches are applied correctly.
#

set -e

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
CSV_FILE="bundle/manifests/falcon-operator.clusterserviceversion.yaml"
PATCH_SCC_FILE="${SCRIPT_DIR}/patch-openshift-scc.yaml"
SKIPS_FILE="${SCRIPT_DIR}/patch-openshift-skips.yaml"
GET_IMAGE_SCRIPT="${SCRIPT_DIR}/get-latest-rh-image.sh"
OPERATOR_SDK="${PROJECT_ROOT}/bin/operator-sdk"

if [ ! -f "$CSV_FILE" ]; then
echo "Error: $CSV_FILE not found" >&2
exit 1
fi

if [ ! -f "$PATCH_SCC_FILE" ]; then
echo "Error: $PATCH_SCC_FILE not found" >&2
exit 1
fi

if [ ! -f "$SKIPS_FILE" ]; then
echo "Error: $SKIPS_FILE not found" >&2
exit 1
fi

if [ ! -f "$GET_IMAGE_SCRIPT" ]; then
echo "Error: $GET_IMAGE_SCRIPT not found" >&2
exit 1
fi

echo "Patching $CSV_FILE with OpenShift certification requirements..."

# Step 1: Add SCC permissions
if grep -q "serviceAccountName: falcon-operator-node-sensor" "$CSV_FILE"; then
echo "✓ SCC permissions already present"
else
echo "Adding SCC permissions..."
yq -i ".spec.install.spec.clusterPermissions += load(\"$PATCH_SCC_FILE\")" "$CSV_FILE"
fi

# Step 2: Update repository and support fields
echo "Updating repository and support fields..."
yq -i '.metadata.annotations.repository = "registry.connect.redhat.com/crowdstrike/falcon-operator"' "$CSV_FILE"
yq -i '.metadata.annotations.support = "CrowdStrike"' "$CSV_FILE"
yq -i '.metadata.annotations."operators.openshift.io/valid-subscription" = "Not required to use this operator"' "$CSV_FILE"

# Step 3: Fetch and add relatedImages
echo "Fetching latest image digests for relatedImages..."

# Read VERSION and PREVIOUS_VERSION from Makefile
VERSION=$(grep -E '^VERSION\s*\?=' "${PROJECT_ROOT}/Makefile" | awk '{print $3}')
if [ -z "$VERSION" ]; then
echo "Error: VERSION not found in Makefile" >&2
exit 1
fi

PREVIOUS_VERSION=$(grep -E '^PREVIOUS_VERSION\s*\?=' "${PROJECT_ROOT}/Makefile" | awk '{print $3}')
if [ -z "$PREVIOUS_VERSION" ]; then
echo "Error: PREVIOUS_VERSION not found in Makefile" >&2
exit 1
fi

echo "Using VERSION=${VERSION} and PREVIOUS_VERSION=${PREVIOUS_VERSION} from Makefile"

echo " Fetching falcon-operator image..."
eval "$("$GET_IMAGE_SCRIPT" falcon-operator)"
OPERATOR_DIGEST="$manifest_list_digest"

# Update containerImage annotation with operator image and digest
echo "Updating containerImage annotation..."
yq -i ".metadata.annotations.containerImage = \"registry.connect.redhat.com/crowdstrike/falcon-operator@${OPERATOR_DIGEST}\"" "$CSV_FILE"

# Update spec.version with the VERSION from Makefile
echo "Updating spec.version to ${VERSION}..."
yq -i ".spec.version = \"${VERSION}\"" "$CSV_FILE"

# Update spec.replaces with the PREVIOUS_VERSION from Makefile
echo "Updating spec.replaces to falcon-operator.v${PREVIOUS_VERSION}..."
yq -i ".spec.replaces = \"falcon-operator.v${PREVIOUS_VERSION}\"" "$CSV_FILE"

echo " Fetching falcon-sensor image..."
eval "$("$GET_IMAGE_SCRIPT" falcon-sensor)"
SENSOR_DIGEST="$manifest_list_digest"

echo " Fetching falcon-container image..."
eval "$("$GET_IMAGE_SCRIPT" falcon-container)"
CONTAINER_DIGEST="$manifest_list_digest"

echo " Fetching falcon-kac image..."
eval "$("$GET_IMAGE_SCRIPT" falcon-kac)"
KAC_DIGEST="$manifest_list_digest"

echo " Fetching falcon-imageanalyzer image..."
eval "$("$GET_IMAGE_SCRIPT" falcon-imageanalyzer)"
IAR_DIGEST="$manifest_list_digest"

echo "Updating deployment container images and environment variables..."
# Update the controller manager container image
yq -i "(.spec.install.spec.deployments[] | select(.name == \"falcon-operator-controller-manager\") | .spec.template.spec.containers[] | select(.name == \"manager\") | .image) = \"registry.connect.redhat.com/crowdstrike/falcon-operator@${OPERATOR_DIGEST}\"" "$CSV_FILE"

# Add RELATED_IMAGE environment variables
yq -i "(.spec.install.spec.deployments[] | select(.name == \"falcon-operator-controller-manager\") | .spec.template.spec.containers[] | select(.name == \"manager\") | .env) += [
{\"name\": \"RELATED_IMAGE_NODE_SENSOR\", \"value\": \"registry.crowdstrike.com/falcon-sensor/release/falcon-sensor@${SENSOR_DIGEST}\"},
{\"name\": \"RELATED_IMAGE_SIDECAR_SENSOR\", \"value\": \"registry.crowdstrike.com/falcon-container/release/falcon-container@${CONTAINER_DIGEST}\"},
{\"name\": \"RELATED_IMAGE_ADMISSION_CONTROLLER\", \"value\": \"registry.crowdstrike.com/falcon-kac/release/falcon-kac@${KAC_DIGEST}\"},
{\"name\": \"RELATED_IMAGE_IMAGE_ANALYZER\", \"value\": \"registry.crowdstrike.com/falcon-imageanalyzer/release/falcon-imageanalyzer@${IAR_DIGEST}\"}
]" "$CSV_FILE"

echo "Adding relatedImages..."
yq -i ".spec.relatedImages = [
{
\"image\": \"registry.connect.redhat.com/crowdstrike/falcon-operator@${OPERATOR_DIGEST}\",
\"name\": \"operator\"
},
{
\"image\": \"registry.crowdstrike.com/falcon-sensor/release/falcon-sensor@${SENSOR_DIGEST}\",
\"name\": \"node-sensor\"
},
{
\"image\": \"registry.crowdstrike.com/falcon-container/release/falcon-container@${CONTAINER_DIGEST}\",
\"name\": \"sidecar-sensor\"
},
{
\"image\": \"registry.crowdstrike.com/falcon-kac/release/falcon-kac@${KAC_DIGEST}\",
\"name\": \"admission-controller\"
},
{
\"image\": \"registry.crowdstrike.com/falcon-imageanalyzer/release/falcon-imageanalyzer@${IAR_DIGEST}\",
\"name\": \"image-analyzer\"
}
]" "$CSV_FILE"

# Step 4: Sort specDescriptors alphabetically by path for deterministic ordering
echo "Sorting specDescriptors by path for deterministic ordering..."
yq -i '(.spec.customresourcedefinitions.owned[].specDescriptors) |= sort_by(.path)' "$CSV_FILE"

# Step 5: Add skips
if grep -q "skips:" "$CSV_FILE"; then
echo "✓ Skips already present"
else
echo "Adding skips..."
yq -i ".spec.skips = load(\"$SKIPS_FILE\")" "$CSV_FILE"
fi

# Step 6: Update bundle metadata annotations
ANNOTATIONS_FILE="bundle/metadata/annotations.yaml"
echo ""
echo "Updating bundle metadata annotations..."

# Change channel from alpha to certified-1.0
sed -i.bak 's/operators\.operatorframework\.io\.bundle\.channels\.v1: alpha/operators.operatorframework.io.bundle.channels.v1: certified-1.0/' "$ANNOTATIONS_FILE"

# Add the two new annotations if they don't already exist
if ! grep -q "operators.operatorframework.io.bundle.channel.default.v1" "$ANNOTATIONS_FILE"; then
echo "" >> "$ANNOTATIONS_FILE"
echo " operators.operatorframework.io.bundle.channel.default.v1: certified-1.0" >> "$ANNOTATIONS_FILE"
fi

if ! grep -q "com.redhat.openshift.versions" "$ANNOTATIONS_FILE"; then
echo " com.redhat.openshift.versions: \"v4.12\"" >> "$ANNOTATIONS_FILE"
fi

# Remove backup file
rm -f "${ANNOTATIONS_FILE}.bak"

# Step 7: Validate the bundle using operator-sdk
echo ""
echo "Validating bundle..."
if [ -f "$OPERATOR_SDK" ]; then
if ! "$OPERATOR_SDK" bundle validate ./bundle; then
echo "Error: Bundle validation failed!" >&2
exit 1
fi
echo "✓ Bundle validation: OK"
else
echo "Warning: operator-sdk not found, skipping validation (run 'make operator-sdk' to install)"
fi
10 changes: 10 additions & 0 deletions hack/patch-openshift-scc.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
- rules:
- apiGroups:
- security.openshift.io
resourceNames:
- privileged
resources:
- securitycontextconstraints
verbs:
- use
serviceAccountName: falcon-operator-node-sensor
2 changes: 2 additions & 0 deletions hack/patch-openshift-skips.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- falcon-operator.v1.3.0
- falcon-operator.v1.12.0
Loading