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
70 changes: 70 additions & 0 deletions tests/fleet_api/managed_integration_api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
"""
This module contains API calls related to the managed integrations API.
(/api/fleet/managed_integrations — replaces the deprecated agentless_policies endpoint)
"""

from fleet_api.base_call_api import APICallException, perform_api_call
from loguru import logger
from munch import Munch, munchify

_FIELDS_NOT_ACCEPTED = frozenset({"policy_id", "policy_ids", "supports_agentless", "output_id"})


def create_managed_integration(cfg: Munch, json_policy: dict) -> str:
"""Create a managed (agentless) integration via the unified managed_integrations endpoint.

Args:
cfg (Munch): Config object containing authentication data.
json_policy (dict): Simplified package policy body. Fields policy_id, policy_ids,
supports_agentless, and output_id are stripped automatically.

Returns:
str: The ID of the created managed integration.

Raises:
APICallException: If the API call fails or returns a non-200 status code.
"""
url = f"{cfg.kibana_url}/api/fleet/managed_integrations"
body = {k: v for k, v in json_policy.items() if k not in _FIELDS_NOT_ACCEPTED}

try:
response = perform_api_call(
method="POST",
url=url,
auth=cfg.auth,
params={"json": body},
)
managed_id = munchify(response).item.id
logger.info(f"Managed integration '{managed_id}' created successfully")
return managed_id
except APICallException as api_ex:
logger.error(
f"API call failed, status code {api_ex.status_code}. Response: {api_ex.response_text}",
)
raise api_ex


def delete_managed_integration(cfg: Munch, policy_id: str):
"""Delete a managed integration.

Args:
cfg (Munch): Config object containing authentication data.
policy_id (str): The ID of the managed integration to delete.

Raises:
APICallException: If the API call fails or returns a non-200 status code.
"""
url = f"{cfg.kibana_url}/api/fleet/managed_integrations/{policy_id}"

try:
perform_api_call(
method="DELETE",
url=url,
auth=cfg.auth,
)
logger.info(f"Managed integration '{policy_id}' deleted successfully")
except APICallException as api_ex:
logger.error(
f"API call failed, status code {api_ex.status_code}. Response: {api_ex.response_text}",
)
raise api_ex
30 changes: 7 additions & 23 deletions tests/integrations_setup/install_agentless_integrations.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,9 @@
"""

import json
import os

import configuration_fleet as cnfg
from fleet_api.agent_policy_api import create_agent_policy
from fleet_api.package_policy_api import create_cspm_integration
from fleet_api.managed_integration_api import create_managed_integration
from loguru import logger
from package_policy import generate_policy_template, generate_random_name, load_data
from state_file_manager import HostType, PolicyState, state_manager
Expand Down Expand Up @@ -82,43 +80,29 @@ def generate_gcp_integration_data():
generate_azure_integration_data(),
generate_gcp_integration_data(),
]
serverless_mode = os.getenv("SERVERLESS_MODE", "false").lower() == "true"

cspm_template = generate_policy_template(
cfg=cnfg.elk_config,
stream_prefix="cloud_security_posture",
)
for integration_data in integrations:
INTEGRATION_NAME = integration_data["name"]
AGENTLESS_INPUT = {
"name": f"Agentless policy for {INTEGRATION_NAME}",
"supports_agentless": True,
"fleet_server_host_id": "default-fleet-server" if serverless_mode else "fleet-default-fleet-server-host",
}

logger.info(f"Starting installation of agentless-agent {INTEGRATION_NAME} integration.")
agent_data, package_data = load_data(
_, package_data = load_data(
cfg=cnfg.elk_config,
agent_input=AGENTLESS_INPUT,
agent_input={"name": INTEGRATION_NAME},
package_input=integration_data,
stream_name="cloud_security_posture.findings",
)

logger.info("Create agentless-agent policy")
agent_policy_id = create_agent_policy(cfg=cnfg.elk_config, json_policy=agent_data)

logger.info(f"Create agentless-agent {INTEGRATION_NAME} integration")
package_policy_id = create_cspm_integration(
cfg=cnfg.elk_config,
pkg_policy=package_data,
agent_policy_id=agent_policy_id,
cspm_data={},
)
logger.info(f"Create managed integration for {INTEGRATION_NAME}")
managed_id = create_managed_integration(cfg=cnfg.elk_config, json_policy=package_data)

state_manager.add_policy(
PolicyState(
agent_policy_id,
package_policy_id,
managed_id,
managed_id,
1,
[],
HostType.KUBERNETES.value,
Expand Down
11 changes: 9 additions & 2 deletions tests/integrations_setup/purge_integrations.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
get_agents,
unenroll_agents_from_policy,
)
from fleet_api.managed_integration_api import delete_managed_integration
from fleet_api.package_policy_api import delete_package_policy
from loguru import logger
from state_file_manager import state_manager
Expand All @@ -29,12 +30,18 @@ def purge_integrations():
"""
Purge integrations and policies based on stored IDs in the state_data.json file.
"""
# Check if the state_data.json file exists

agents = get_agents(cfg=cnfg.elk_config)
# Delete policies based on the stored IDs
for policy in state_manager.get_policies():
logger.info("Deleting policy", policy.pkg_policy_id, policy.agnt_policy_id)

# When agnt_policy_id == pkg_policy_id the entry was created via the managed_integrations
# API (a single combined resource). Deleting the managed integration cleans up both the
# agent policy and package policy automatically.
if policy.agnt_policy_id == policy.pkg_policy_id:
delete_managed_integration(cfg=cnfg.elk_config, policy_id=policy.agnt_policy_id)
continue

delete_package_policy(cfg=cnfg.elk_config, policy_ids=[policy.pkg_policy_id])

agents_list = [item.agent.id for item in agents if item.policy_id == policy.agnt_policy_id]
Expand Down
Loading