awslabs.eks-mcp-server 0.1.1__tar.gz → 0.1.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {awslabs_eks_mcp_server-0.1.1 → awslabs_eks_mcp_server-0.1.2}/Dockerfile +2 -2
- {awslabs_eks_mcp_server-0.1.1 → awslabs_eks_mcp_server-0.1.2}/PKG-INFO +29 -24
- {awslabs_eks_mcp_server-0.1.1 → awslabs_eks_mcp_server-0.1.2}/README.md +28 -23
- {awslabs_eks_mcp_server-0.1.1 → awslabs_eks_mcp_server-0.1.2}/awslabs/eks_mcp_server/aws_helper.py +3 -2
- {awslabs_eks_mcp_server-0.1.1 → awslabs_eks_mcp_server-0.1.2}/awslabs/eks_mcp_server/eks_stack_handler.py +21 -1
- {awslabs_eks_mcp_server-0.1.1 → awslabs_eks_mcp_server-0.1.2}/awslabs/eks_mcp_server/k8s_apis.py +12 -8
- {awslabs_eks_mcp_server-0.1.1 → awslabs_eks_mcp_server-0.1.2}/awslabs/eks_mcp_server/k8s_handler.py +35 -0
- {awslabs_eks_mcp_server-0.1.1 → awslabs_eks_mcp_server-0.1.2}/pyproject.toml +1 -1
- {awslabs_eks_mcp_server-0.1.1 → awslabs_eks_mcp_server-0.1.2}/tests/test_aws_helper.py +5 -3
- {awslabs_eks_mcp_server-0.1.1 → awslabs_eks_mcp_server-0.1.2}/tests/test_eks_stack_handler.py +80 -0
- {awslabs_eks_mcp_server-0.1.1 → awslabs_eks_mcp_server-0.1.2}/tests/test_k8s_apis.py +60 -60
- {awslabs_eks_mcp_server-0.1.1 → awslabs_eks_mcp_server-0.1.2}/tests/test_k8s_handler.py +179 -65
- {awslabs_eks_mcp_server-0.1.1 → awslabs_eks_mcp_server-0.1.2}/.gitignore +0 -0
- {awslabs_eks_mcp_server-0.1.1 → awslabs_eks_mcp_server-0.1.2}/.pre-commit-config.yaml +0 -0
- {awslabs_eks_mcp_server-0.1.1 → awslabs_eks_mcp_server-0.1.2}/.python-version +0 -0
- {awslabs_eks_mcp_server-0.1.1 → awslabs_eks_mcp_server-0.1.2}/CHANGELOG.md +0 -0
- {awslabs_eks_mcp_server-0.1.1 → awslabs_eks_mcp_server-0.1.2}/LICENSE +0 -0
- {awslabs_eks_mcp_server-0.1.1 → awslabs_eks_mcp_server-0.1.2}/NOTICE +0 -0
- {awslabs_eks_mcp_server-0.1.1 → awslabs_eks_mcp_server-0.1.2}/awslabs/__init__.py +0 -0
- {awslabs_eks_mcp_server-0.1.1 → awslabs_eks_mcp_server-0.1.2}/awslabs/eks_mcp_server/__init__.py +0 -0
- {awslabs_eks_mcp_server-0.1.1 → awslabs_eks_mcp_server-0.1.2}/awslabs/eks_mcp_server/cloudwatch_handler.py +0 -0
- {awslabs_eks_mcp_server-0.1.1 → awslabs_eks_mcp_server-0.1.2}/awslabs/eks_mcp_server/consts.py +0 -0
- {awslabs_eks_mcp_server-0.1.1 → awslabs_eks_mcp_server-0.1.2}/awslabs/eks_mcp_server/eks_kb_handler.py +0 -0
- {awslabs_eks_mcp_server-0.1.1 → awslabs_eks_mcp_server-0.1.2}/awslabs/eks_mcp_server/iam_handler.py +0 -0
- {awslabs_eks_mcp_server-0.1.1 → awslabs_eks_mcp_server-0.1.2}/awslabs/eks_mcp_server/k8s_client_cache.py +0 -0
- {awslabs_eks_mcp_server-0.1.1 → awslabs_eks_mcp_server-0.1.2}/awslabs/eks_mcp_server/logging_helper.py +0 -0
- {awslabs_eks_mcp_server-0.1.1 → awslabs_eks_mcp_server-0.1.2}/awslabs/eks_mcp_server/models.py +0 -0
- {awslabs_eks_mcp_server-0.1.1 → awslabs_eks_mcp_server-0.1.2}/awslabs/eks_mcp_server/server.py +0 -0
- {awslabs_eks_mcp_server-0.1.1 → awslabs_eks_mcp_server-0.1.2}/awslabs/eks_mcp_server/templates/eks-templates/eks-with-vpc.yaml +0 -0
- {awslabs_eks_mcp_server-0.1.1 → awslabs_eks_mcp_server-0.1.2}/awslabs/eks_mcp_server/templates/k8s-templates/deployment.yaml +0 -0
- {awslabs_eks_mcp_server-0.1.1 → awslabs_eks_mcp_server-0.1.2}/awslabs/eks_mcp_server/templates/k8s-templates/service.yaml +0 -0
- {awslabs_eks_mcp_server-0.1.1 → awslabs_eks_mcp_server-0.1.2}/docker-healthcheck.sh +0 -0
- {awslabs_eks_mcp_server-0.1.1 → awslabs_eks_mcp_server-0.1.2}/tests/test_cloudwatch_handler.py +0 -0
- {awslabs_eks_mcp_server-0.1.1 → awslabs_eks_mcp_server-0.1.2}/tests/test_eks_kb_handler.py +0 -0
- {awslabs_eks_mcp_server-0.1.1 → awslabs_eks_mcp_server-0.1.2}/tests/test_iam_handler.py +0 -0
- {awslabs_eks_mcp_server-0.1.1 → awslabs_eks_mcp_server-0.1.2}/tests/test_init.py +0 -0
- {awslabs_eks_mcp_server-0.1.1 → awslabs_eks_mcp_server-0.1.2}/tests/test_k8s_client_cache.py +0 -0
- {awslabs_eks_mcp_server-0.1.1 → awslabs_eks_mcp_server-0.1.2}/tests/test_logging_helper.py +0 -0
- {awslabs_eks_mcp_server-0.1.1 → awslabs_eks_mcp_server-0.1.2}/tests/test_main.py +0 -0
- {awslabs_eks_mcp_server-0.1.1 → awslabs_eks_mcp_server-0.1.2}/tests/test_models.py +0 -0
- {awslabs_eks_mcp_server-0.1.1 → awslabs_eks_mcp_server-0.1.2}/tests/test_server.py +0 -0
- {awslabs_eks_mcp_server-0.1.1 → awslabs_eks_mcp_server-0.1.2}/uv.lock +0 -0
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
# OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions
|
|
10
10
|
# and limitations under the License.
|
|
11
11
|
|
|
12
|
-
FROM public.ecr.aws/sam/build-python3.10@sha256:
|
|
12
|
+
FROM public.ecr.aws/sam/build-python3.10@sha256:e78695db10ca8cb129e59e30f7dc9789b0dbd0181dba195d68419c72bac51ac1 AS uv
|
|
13
13
|
|
|
14
14
|
# Install the project into `/app`
|
|
15
15
|
WORKDIR /app
|
|
@@ -43,7 +43,7 @@ RUN --mount=type=cache,target=/root/.cache/uv \
|
|
|
43
43
|
# Make the directory just in case it doesn't exist
|
|
44
44
|
RUN mkdir -p /root/.local
|
|
45
45
|
|
|
46
|
-
FROM public.ecr.aws/sam/build-python3.10@sha256:
|
|
46
|
+
FROM public.ecr.aws/sam/build-python3.10@sha256:e78695db10ca8cb129e59e30f7dc9789b0dbd0181dba195d68419c72bac51ac1
|
|
47
47
|
|
|
48
48
|
# Place executables in the environment at the front of the path and include other binaries
|
|
49
49
|
ENV PATH="/app/.venv/bin:$PATH:/usr/sbin"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: awslabs.eks-mcp-server
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Summary: An AWS Labs Model Context Protocol (MCP) server for EKS
|
|
5
5
|
Project-URL: homepage, https://awslabs.github.io/mcp/
|
|
6
6
|
Project-URL: docs, https://awslabs.github.io/mcp/servers/eks-mcp-server/
|
|
@@ -89,30 +89,35 @@ For read operations, the following permissions are required:
|
|
|
89
89
|
|
|
90
90
|
### Write Operations Policy
|
|
91
91
|
|
|
92
|
-
For write operations, the following
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
"
|
|
103
|
-
"
|
|
104
|
-
"
|
|
105
|
-
],
|
|
106
|
-
"Resource": "*",
|
|
107
|
-
"Condition": {
|
|
108
|
-
"StringEquals": {
|
|
109
|
-
"aws:RequestTag/CreatedBy": "EksMcpServer"
|
|
110
|
-
}
|
|
92
|
+
For write operations, we recommend the following IAM policies to ensure successful deployment of EKS clusters using the CloudFormation template in `/awslabs/eks_mcp_server/templates/eks-templates/eks-with-vpc.yaml`:
|
|
93
|
+
- [**IAMFullAccess**](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/IAMFullAccess.html): Enables creation and management of IAM roles and policies required for cluster operation
|
|
94
|
+
- [**AmazonVPCFullAccess**](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AmazonVPCFullAccess.html): Allows creation and configuration of VPC resources including subnets, route tables, internet gateways, and NAT gateways
|
|
95
|
+
- [**AWSCloudFormationFullAccess**](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AWSCloudFormationFullAccess.html): Provides permissions to create, update, and delete CloudFormation stacks that orchestrate the deployment
|
|
96
|
+
- **EKS Full Access (provided below)**: Required for creating and managing EKS clusters, including control plane configuration, node groups, and add-ons
|
|
97
|
+
```
|
|
98
|
+
{
|
|
99
|
+
"Version": "2012-10-17",
|
|
100
|
+
"Statement": [
|
|
101
|
+
{
|
|
102
|
+
"Effect": "Allow",
|
|
103
|
+
"Action": "eks:*",
|
|
104
|
+
"Resource": "*"
|
|
111
105
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
106
|
+
]
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
**Important Security Note**: Users should exercise caution when `--allow-write` and `--allow-sensitive-data-access` modes are enabled with these broad permissions, as this combination grants significant privileges to the MCP server. Only enable these flags when necessary and in trusted environments. For production use, consider creating more restrictive custom policies.
|
|
112
|
+
|
|
113
|
+
### Kubernetes API Access Requirements
|
|
114
|
+
|
|
115
|
+
All Kubernetes API operations will only work when one of the following conditions is met:
|
|
116
|
+
|
|
117
|
+
1. The user's principal (IAM role/user) actually created the EKS cluster being accessed
|
|
118
|
+
2. An EKS Access Entry has been configured for the user's principal
|
|
119
|
+
|
|
120
|
+
If you encounter authorization errors when using Kubernetes API operations, verify that an access entry has been properly configured for your principal.
|
|
116
121
|
|
|
117
122
|
## Quickstart
|
|
118
123
|
|
|
@@ -55,30 +55,35 @@ For read operations, the following permissions are required:
|
|
|
55
55
|
|
|
56
56
|
### Write Operations Policy
|
|
57
57
|
|
|
58
|
-
For write operations, the following
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
"
|
|
69
|
-
"
|
|
70
|
-
"
|
|
71
|
-
],
|
|
72
|
-
"Resource": "*",
|
|
73
|
-
"Condition": {
|
|
74
|
-
"StringEquals": {
|
|
75
|
-
"aws:RequestTag/CreatedBy": "EksMcpServer"
|
|
76
|
-
}
|
|
58
|
+
For write operations, we recommend the following IAM policies to ensure successful deployment of EKS clusters using the CloudFormation template in `/awslabs/eks_mcp_server/templates/eks-templates/eks-with-vpc.yaml`:
|
|
59
|
+
- [**IAMFullAccess**](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/IAMFullAccess.html): Enables creation and management of IAM roles and policies required for cluster operation
|
|
60
|
+
- [**AmazonVPCFullAccess**](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AmazonVPCFullAccess.html): Allows creation and configuration of VPC resources including subnets, route tables, internet gateways, and NAT gateways
|
|
61
|
+
- [**AWSCloudFormationFullAccess**](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AWSCloudFormationFullAccess.html): Provides permissions to create, update, and delete CloudFormation stacks that orchestrate the deployment
|
|
62
|
+
- **EKS Full Access (provided below)**: Required for creating and managing EKS clusters, including control plane configuration, node groups, and add-ons
|
|
63
|
+
```
|
|
64
|
+
{
|
|
65
|
+
"Version": "2012-10-17",
|
|
66
|
+
"Statement": [
|
|
67
|
+
{
|
|
68
|
+
"Effect": "Allow",
|
|
69
|
+
"Action": "eks:*",
|
|
70
|
+
"Resource": "*"
|
|
77
71
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
72
|
+
]
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
**Important Security Note**: Users should exercise caution when `--allow-write` and `--allow-sensitive-data-access` modes are enabled with these broad permissions, as this combination grants significant privileges to the MCP server. Only enable these flags when necessary and in trusted environments. For production use, consider creating more restrictive custom policies.
|
|
78
|
+
|
|
79
|
+
### Kubernetes API Access Requirements
|
|
80
|
+
|
|
81
|
+
All Kubernetes API operations will only work when one of the following conditions is met:
|
|
82
|
+
|
|
83
|
+
1. The user's principal (IAM role/user) actually created the EKS cluster being accessed
|
|
84
|
+
2. An EKS Access Entry has been configured for the user's principal
|
|
85
|
+
|
|
86
|
+
If you encounter authorization errors when using Kubernetes API operations, verify that an access entry has been properly configured for your principal.
|
|
82
87
|
|
|
83
88
|
## Quickstart
|
|
84
89
|
|
{awslabs_eks_mcp_server-0.1.1 → awslabs_eks_mcp_server-0.1.2}/awslabs/eks_mcp_server/aws_helper.py
RENAMED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
import boto3
|
|
15
15
|
import os
|
|
16
|
+
from awslabs.eks_mcp_server import __version__
|
|
16
17
|
from botocore.config import Config
|
|
17
18
|
from typing import Any, Optional
|
|
18
19
|
|
|
@@ -38,7 +39,7 @@ class AwsHelper:
|
|
|
38
39
|
def create_boto3_client(cls, service_name: str, region_name: Optional[str] = None) -> Any:
|
|
39
40
|
"""Create a boto3 client with the appropriate profile and region.
|
|
40
41
|
|
|
41
|
-
The client is configured with a custom user agent suffix 'awslabs/mcp/eks-mcp-server/
|
|
42
|
+
The client is configured with a custom user agent suffix 'awslabs/mcp/eks-mcp-server/{version}'
|
|
42
43
|
to identify API calls made by the EKS MCP Server.
|
|
43
44
|
|
|
44
45
|
Args:
|
|
@@ -55,7 +56,7 @@ class AwsHelper:
|
|
|
55
56
|
profile = cls.get_aws_profile()
|
|
56
57
|
|
|
57
58
|
# Create config with user agent suffix
|
|
58
|
-
config = Config(user_agent_extra='awslabs/mcp/eks-mcp-server/
|
|
59
|
+
config = Config(user_agent_extra=f'awslabs/mcp/eks-mcp-server/{__version__}')
|
|
59
60
|
|
|
60
61
|
# Create session with profile if specified
|
|
61
62
|
if profile:
|
|
@@ -36,7 +36,7 @@ from awslabs.eks_mcp_server.models import (
|
|
|
36
36
|
from mcp.server.fastmcp import Context
|
|
37
37
|
from mcp.types import EmbeddedResource, ImageContent, TextContent
|
|
38
38
|
from pydantic import Field
|
|
39
|
-
from typing import Dict, List, Optional, Tuple, Union, cast
|
|
39
|
+
from typing import Any, Dict, List, Optional, Tuple, Union, cast
|
|
40
40
|
|
|
41
41
|
|
|
42
42
|
class EksStackHandler:
|
|
@@ -345,6 +345,10 @@ class EksStackHandler:
|
|
|
345
345
|
if 'Parameters' in template_yaml and 'ClusterName' in template_yaml['Parameters']:
|
|
346
346
|
template_yaml['Parameters']['ClusterName']['Default'] = cluster_name
|
|
347
347
|
|
|
348
|
+
# Remove checkov metadata from the EKS cluster resource
|
|
349
|
+
if 'Resources' in template_yaml and 'EksCluster' in template_yaml['Resources']:
|
|
350
|
+
self._remove_checkov_metadata(template_yaml['Resources']['EksCluster'])
|
|
351
|
+
|
|
348
352
|
# Convert back to YAML
|
|
349
353
|
modified_template = yaml.dump(template_yaml, default_flow_style=False)
|
|
350
354
|
|
|
@@ -589,6 +593,22 @@ class EksStackHandler:
|
|
|
589
593
|
outputs={},
|
|
590
594
|
)
|
|
591
595
|
|
|
596
|
+
def _remove_checkov_metadata(self, resource: Dict[str, Any]) -> None:
|
|
597
|
+
"""Remove checkov metadata from a resource and clean up empty Metadata sections.
|
|
598
|
+
|
|
599
|
+
Args:
|
|
600
|
+
resource: The resource dictionary to process
|
|
601
|
+
"""
|
|
602
|
+
if 'Metadata' in resource:
|
|
603
|
+
# Check if there's checkov metadata
|
|
604
|
+
if 'checkov' in resource['Metadata']:
|
|
605
|
+
# Remove only the checkov metadata
|
|
606
|
+
del resource['Metadata']['checkov']
|
|
607
|
+
|
|
608
|
+
# If Metadata is now empty, remove it entirely
|
|
609
|
+
if not resource['Metadata']:
|
|
610
|
+
del resource['Metadata']
|
|
611
|
+
|
|
592
612
|
async def _delete_stack(
|
|
593
613
|
self, ctx: Context, stack_name: str, cluster_name: str
|
|
594
614
|
) -> DeleteStackResponse:
|
{awslabs_eks_mcp_server-0.1.1 → awslabs_eks_mcp_server-0.1.2}/awslabs/eks_mcp_server/k8s_apis.py
RENAMED
|
@@ -407,22 +407,26 @@ class K8sApis:
|
|
|
407
407
|
Pod logs as a string
|
|
408
408
|
"""
|
|
409
409
|
try:
|
|
410
|
-
|
|
411
|
-
|
|
410
|
+
from kubernetes import client
|
|
411
|
+
|
|
412
|
+
# Create CoreV1Api client
|
|
413
|
+
core_v1_api = client.CoreV1Api(self.api_client)
|
|
412
414
|
|
|
413
|
-
# Prepare parameters for the
|
|
415
|
+
# Prepare parameters for the read_namespaced_pod_log method
|
|
414
416
|
params = {}
|
|
415
417
|
if container_name:
|
|
416
418
|
params['container'] = container_name
|
|
417
419
|
if since_seconds:
|
|
418
|
-
params['
|
|
420
|
+
params['since_seconds'] = since_seconds
|
|
419
421
|
if tail_lines:
|
|
420
|
-
params['
|
|
422
|
+
params['tail_lines'] = tail_lines
|
|
421
423
|
if limit_bytes:
|
|
422
|
-
params['
|
|
424
|
+
params['limit_bytes'] = limit_bytes
|
|
423
425
|
|
|
424
|
-
# Call the
|
|
425
|
-
logs_response =
|
|
426
|
+
# Call the read_namespaced_pod_log method
|
|
427
|
+
logs_response = core_v1_api.read_namespaced_pod_log(
|
|
428
|
+
name=pod_name, namespace=namespace, **params
|
|
429
|
+
)
|
|
426
430
|
|
|
427
431
|
return logs_response
|
|
428
432
|
|
{awslabs_eks_mcp_server-0.1.1 → awslabs_eks_mcp_server-0.1.2}/awslabs/eks_mcp_server/k8s_handler.py
RENAMED
|
@@ -780,6 +780,37 @@ class K8sHandler:
|
|
|
780
780
|
output_file_path='',
|
|
781
781
|
)
|
|
782
782
|
|
|
783
|
+
def _remove_checkov_skip_annotations(self, content: str) -> str:
|
|
784
|
+
"""Remove checkov skip annotations from YAML content.
|
|
785
|
+
|
|
786
|
+
Args:
|
|
787
|
+
content: YAML content as string
|
|
788
|
+
|
|
789
|
+
Returns:
|
|
790
|
+
YAML content with checkov skip annotations removed
|
|
791
|
+
"""
|
|
792
|
+
# Use yaml to parse and modify the content
|
|
793
|
+
yaml_content = yaml.safe_load(content)
|
|
794
|
+
if (
|
|
795
|
+
yaml_content
|
|
796
|
+
and 'metadata' in yaml_content
|
|
797
|
+
and 'annotations' in yaml_content['metadata']
|
|
798
|
+
):
|
|
799
|
+
# Remove all checkov skip annotations
|
|
800
|
+
annotations = yaml_content['metadata']['annotations']
|
|
801
|
+
checkov_keys = [key for key in annotations.keys() if key.startswith('checkov.io/skip')]
|
|
802
|
+
for key in checkov_keys:
|
|
803
|
+
del annotations[key]
|
|
804
|
+
|
|
805
|
+
# If annotations is now empty, remove it
|
|
806
|
+
if not annotations:
|
|
807
|
+
del yaml_content['metadata']['annotations']
|
|
808
|
+
|
|
809
|
+
# Convert back to YAML string
|
|
810
|
+
content = yaml.dump(yaml_content, default_flow_style=False)
|
|
811
|
+
|
|
812
|
+
return content
|
|
813
|
+
|
|
783
814
|
def _load_yaml_template(self, template_files: list, values: Dict[str, Any]) -> str:
|
|
784
815
|
"""Load and process Kubernetes template files.
|
|
785
816
|
|
|
@@ -804,6 +835,10 @@ class K8sHandler:
|
|
|
804
835
|
for key, value in values.items():
|
|
805
836
|
content = content.replace(key, value)
|
|
806
837
|
|
|
838
|
+
# Remove checkov skip annotations if present
|
|
839
|
+
if template_file == 'deployment.yaml':
|
|
840
|
+
content = self._remove_checkov_skip_annotations(content)
|
|
841
|
+
|
|
807
842
|
template_contents.append(content)
|
|
808
843
|
|
|
809
844
|
# Combine templates into a single YAML document with separator
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
"""Tests for the AWS Helper."""
|
|
13
13
|
|
|
14
14
|
import os
|
|
15
|
+
from awslabs.eks_mcp_server import __version__
|
|
15
16
|
from awslabs.eks_mcp_server.aws_helper import AwsHelper
|
|
16
17
|
from unittest.mock import ANY, MagicMock, patch
|
|
17
18
|
|
|
@@ -131,7 +132,7 @@ class TestAwsHelper:
|
|
|
131
132
|
)
|
|
132
133
|
|
|
133
134
|
def test_create_boto3_client_user_agent(self):
|
|
134
|
-
"""Test that create_boto3_client sets the user agent suffix correctly."""
|
|
135
|
+
"""Test that create_boto3_client sets the user agent suffix correctly using the package version."""
|
|
135
136
|
# Create a real Config object to inspect
|
|
136
137
|
with patch.object(AwsHelper, 'get_aws_profile', return_value=None):
|
|
137
138
|
with patch.object(AwsHelper, 'get_aws_region', return_value=None):
|
|
@@ -143,6 +144,7 @@ class TestAwsHelper:
|
|
|
143
144
|
_, kwargs = mock_client.call_args
|
|
144
145
|
config = kwargs.get('config')
|
|
145
146
|
|
|
146
|
-
# Verify the user agent suffix
|
|
147
|
+
# Verify the user agent suffix uses the version from __init__.py
|
|
147
148
|
assert config is not None
|
|
148
|
-
|
|
149
|
+
expected_user_agent = f'awslabs/mcp/eks-mcp-server/{__version__}'
|
|
150
|
+
assert config.user_agent_extra == expected_user_agent
|
{awslabs_eks_mcp_server-0.1.1 → awslabs_eks_mcp_server-0.1.2}/tests/test_eks_stack_handler.py
RENAMED
|
@@ -505,6 +505,16 @@ class TestEksStackHandler:
|
|
|
505
505
|
ClusterName:
|
|
506
506
|
Type: String
|
|
507
507
|
Default: my-cluster
|
|
508
|
+
Resources:
|
|
509
|
+
EksCluster:
|
|
510
|
+
Type: AWS::EKS::Cluster
|
|
511
|
+
Metadata:
|
|
512
|
+
checkov:
|
|
513
|
+
skip:
|
|
514
|
+
- id: CKV_AWS_58
|
|
515
|
+
- comment: "Secrets encryption is enabled by default in EKS 1.27+"
|
|
516
|
+
Properties:
|
|
517
|
+
Name: my-cluster
|
|
508
518
|
"""
|
|
509
519
|
mock_yaml_content = yaml.safe_load(mock_template_content)
|
|
510
520
|
|
|
@@ -531,6 +541,76 @@ class TestEksStackHandler:
|
|
|
531
541
|
assert result.content[0].type == 'text'
|
|
532
542
|
assert 'template generated' in result.content[0].text
|
|
533
543
|
|
|
544
|
+
# Verify that the Metadata section was removed from the EksCluster resource
|
|
545
|
+
# because it only contained checkov metadata which was removed
|
|
546
|
+
assert 'Resources' in mock_yaml_content
|
|
547
|
+
assert 'EksCluster' in mock_yaml_content['Resources']
|
|
548
|
+
assert 'Metadata' not in mock_yaml_content['Resources']['EksCluster']
|
|
549
|
+
|
|
550
|
+
@pytest.mark.asyncio
|
|
551
|
+
async def test_generate_template_with_other_metadata(self):
|
|
552
|
+
"""Test that _generate_template only removes checkov metadata and keeps other metadata."""
|
|
553
|
+
# Create a mock MCP server
|
|
554
|
+
mock_mcp = MagicMock()
|
|
555
|
+
|
|
556
|
+
# Initialize the EKS handler with the mock MCP server
|
|
557
|
+
handler = EksStackHandler(mock_mcp)
|
|
558
|
+
|
|
559
|
+
# Create a mock context
|
|
560
|
+
mock_ctx = MagicMock(spec=Context)
|
|
561
|
+
|
|
562
|
+
# Mock the open function to return a mock file with both checkov and other metadata
|
|
563
|
+
mock_template_content = """
|
|
564
|
+
Parameters:
|
|
565
|
+
ClusterName:
|
|
566
|
+
Type: String
|
|
567
|
+
Default: my-cluster
|
|
568
|
+
Resources:
|
|
569
|
+
EksCluster:
|
|
570
|
+
Type: AWS::EKS::Cluster
|
|
571
|
+
Metadata:
|
|
572
|
+
checkov:
|
|
573
|
+
skip:
|
|
574
|
+
- id: CKV_AWS_58
|
|
575
|
+
- comment: "Secrets encryption is enabled by default in EKS 1.27+"
|
|
576
|
+
other_metadata:
|
|
577
|
+
key: value
|
|
578
|
+
Properties:
|
|
579
|
+
Name: my-cluster
|
|
580
|
+
"""
|
|
581
|
+
# Create a deep copy of the YAML content that we can modify
|
|
582
|
+
mock_yaml_content = yaml.safe_load(mock_template_content)
|
|
583
|
+
|
|
584
|
+
# Mock the necessary functions
|
|
585
|
+
with (
|
|
586
|
+
patch('builtins.open', mock_open(read_data=mock_template_content)),
|
|
587
|
+
patch('os.path.dirname', return_value='/mock/path'),
|
|
588
|
+
patch('os.path.join', return_value='/mock/path/template.yaml'),
|
|
589
|
+
patch('os.makedirs', return_value=None),
|
|
590
|
+
patch('yaml.safe_load', return_value=mock_yaml_content),
|
|
591
|
+
patch('yaml.dump', return_value=mock_template_content),
|
|
592
|
+
):
|
|
593
|
+
# Call the _generate_template method
|
|
594
|
+
result = await handler._generate_template(
|
|
595
|
+
ctx=mock_ctx,
|
|
596
|
+
template_path='/path/to/output/template.yaml',
|
|
597
|
+
cluster_name='test-cluster',
|
|
598
|
+
)
|
|
599
|
+
|
|
600
|
+
# Verify the result
|
|
601
|
+
assert not result.isError
|
|
602
|
+
assert result.template_path == '/path/to/output/template.yaml'
|
|
603
|
+
|
|
604
|
+
# Verify that only the checkov metadata was removed
|
|
605
|
+
assert 'Resources' in mock_yaml_content
|
|
606
|
+
assert 'EksCluster' in mock_yaml_content['Resources']
|
|
607
|
+
assert 'Metadata' in mock_yaml_content['Resources']['EksCluster']
|
|
608
|
+
assert 'checkov' not in mock_yaml_content['Resources']['EksCluster']['Metadata']
|
|
609
|
+
assert 'other_metadata' in mock_yaml_content['Resources']['EksCluster']['Metadata']
|
|
610
|
+
assert mock_yaml_content['Resources']['EksCluster']['Metadata']['other_metadata'] == {
|
|
611
|
+
'key': 'value'
|
|
612
|
+
}
|
|
613
|
+
|
|
534
614
|
@pytest.mark.asyncio
|
|
535
615
|
async def test_manage_eks_stacks_generate(self):
|
|
536
616
|
"""Test that manage_eks_stacks handles the generate operation correctly."""
|
|
@@ -419,69 +419,69 @@ class TestK8sApisOperations:
|
|
|
419
419
|
|
|
420
420
|
def test_get_pod_logs(self, k8s_apis):
|
|
421
421
|
"""Test get_pod_logs method."""
|
|
422
|
-
# Mock the
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
422
|
+
# Mock the CoreV1Api client
|
|
423
|
+
with patch('kubernetes.client') as mock_client:
|
|
424
|
+
# Create mock CoreV1Api
|
|
425
|
+
mock_core_v1_api = MagicMock()
|
|
426
|
+
mock_client.CoreV1Api.return_value = mock_core_v1_api
|
|
427
|
+
|
|
428
|
+
# Mock read_namespaced_pod_log to return logs
|
|
429
|
+
mock_core_v1_api.read_namespaced_pod_log.return_value = 'log line 1\nlog line 2\n'
|
|
430
|
+
|
|
431
|
+
# Get pod logs with all parameters
|
|
432
|
+
logs = k8s_apis.get_pod_logs(
|
|
433
|
+
pod_name='test-pod',
|
|
434
|
+
namespace='test-namespace',
|
|
435
|
+
container_name='test-container',
|
|
436
|
+
since_seconds=60,
|
|
437
|
+
tail_lines=100,
|
|
438
|
+
limit_bytes=1024,
|
|
439
|
+
)
|
|
440
|
+
|
|
441
|
+
# Verify the result
|
|
442
|
+
assert logs == 'log line 1\nlog line 2\n'
|
|
443
|
+
|
|
444
|
+
# Verify CoreV1Api was created with the correct API client
|
|
445
|
+
mock_client.CoreV1Api.assert_called_once_with(k8s_apis.api_client)
|
|
446
|
+
|
|
447
|
+
# Verify read_namespaced_pod_log was called with the correct parameters
|
|
448
|
+
mock_core_v1_api.read_namespaced_pod_log.assert_called_once_with(
|
|
449
|
+
name='test-pod',
|
|
450
|
+
namespace='test-namespace',
|
|
451
|
+
container='test-container',
|
|
452
|
+
since_seconds=60,
|
|
453
|
+
tail_lines=100,
|
|
454
|
+
limit_bytes=1024,
|
|
455
|
+
)
|
|
456
456
|
|
|
457
457
|
def test_get_pod_logs_minimal(self, k8s_apis):
|
|
458
458
|
"""Test get_pod_logs method with minimal parameters."""
|
|
459
|
-
# Mock the
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
459
|
+
# Mock the CoreV1Api client
|
|
460
|
+
with patch('kubernetes.client') as mock_client:
|
|
461
|
+
# Create mock CoreV1Api
|
|
462
|
+
mock_core_v1_api = MagicMock()
|
|
463
|
+
mock_client.CoreV1Api.return_value = mock_core_v1_api
|
|
464
|
+
|
|
465
|
+
# Mock read_namespaced_pod_log to return logs
|
|
466
|
+
mock_core_v1_api.read_namespaced_pod_log.return_value = 'log line 1\nlog line 2\n'
|
|
467
|
+
|
|
468
|
+
# Get pod logs with minimal parameters
|
|
469
|
+
logs = k8s_apis.get_pod_logs(
|
|
470
|
+
pod_name='test-pod',
|
|
471
|
+
namespace='test-namespace',
|
|
472
|
+
)
|
|
473
|
+
|
|
474
|
+
# Verify the result
|
|
475
|
+
assert logs == 'log line 1\nlog line 2\n'
|
|
476
|
+
|
|
477
|
+
# Verify CoreV1Api was created with the correct API client
|
|
478
|
+
mock_client.CoreV1Api.assert_called_once_with(k8s_apis.api_client)
|
|
479
|
+
|
|
480
|
+
# Verify read_namespaced_pod_log was called with the correct parameters
|
|
481
|
+
mock_core_v1_api.read_namespaced_pod_log.assert_called_once_with(
|
|
482
|
+
name='test-pod',
|
|
483
|
+
namespace='test-namespace',
|
|
484
|
+
)
|
|
485
485
|
|
|
486
486
|
def _create_mock_event(self):
|
|
487
487
|
"""Create a mock event for testing."""
|
|
@@ -132,6 +132,72 @@ class TestK8sHandler:
|
|
|
132
132
|
# Verify that the client was returned
|
|
133
133
|
assert client == mock_client_cache.get_client.return_value
|
|
134
134
|
|
|
135
|
+
def test_load_yaml_template_removes_checkov_annotations(self, mock_mcp, mock_client_cache):
|
|
136
|
+
"""Test _load_yaml_template method removes checkov skip annotations from deployment template."""
|
|
137
|
+
# Initialize the K8s handler
|
|
138
|
+
with patch(
|
|
139
|
+
'awslabs.eks_mcp_server.k8s_handler.K8sClientCache', return_value=mock_client_cache
|
|
140
|
+
):
|
|
141
|
+
handler = K8sHandler(mock_mcp)
|
|
142
|
+
|
|
143
|
+
# Create mock file content for templates with checkov skip annotations
|
|
144
|
+
deployment_template = """apiVersion: apps/v1
|
|
145
|
+
kind: Deployment
|
|
146
|
+
metadata:
|
|
147
|
+
name: APP_NAME
|
|
148
|
+
namespace: NAMESPACE
|
|
149
|
+
annotations:
|
|
150
|
+
checkov.io/skip1: "CKV_K8S_14=We're using a specific image version"
|
|
151
|
+
checkov.io/skip2: "CKV_K8S_43=Resource limits are set appropriately"
|
|
152
|
+
other-annotation: "This should be preserved"
|
|
153
|
+
spec:
|
|
154
|
+
replicas: REPLICAS"""
|
|
155
|
+
|
|
156
|
+
service_template = """apiVersion: v1
|
|
157
|
+
kind: Service
|
|
158
|
+
metadata:
|
|
159
|
+
name: APP_NAME
|
|
160
|
+
namespace: NAMESPACE
|
|
161
|
+
annotations:
|
|
162
|
+
service.beta.kubernetes.io/aws-load-balancer-scheme: LOAD_BALANCER_SCHEME"""
|
|
163
|
+
|
|
164
|
+
# Mock open to return our test templates
|
|
165
|
+
mock_open_func = mock_open()
|
|
166
|
+
mock_file = MagicMock()
|
|
167
|
+
mock_file.__enter__.return_value.read.side_effect = [deployment_template, service_template]
|
|
168
|
+
mock_open_func.return_value = mock_file
|
|
169
|
+
|
|
170
|
+
# Mock yaml.safe_load and yaml.dump to use real functions
|
|
171
|
+
with patch('builtins.open', mock_open_func):
|
|
172
|
+
# Test loading and processing templates
|
|
173
|
+
template_files = ['deployment.yaml', 'service.yaml']
|
|
174
|
+
values = {
|
|
175
|
+
'APP_NAME': 'test-app',
|
|
176
|
+
'NAMESPACE': 'test-namespace',
|
|
177
|
+
'REPLICAS': '3',
|
|
178
|
+
'LOAD_BALANCER_SCHEME': 'internal',
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
result = handler._load_yaml_template(template_files, values)
|
|
182
|
+
|
|
183
|
+
# Verify open was called for each template
|
|
184
|
+
assert mock_open_func.call_count == 2
|
|
185
|
+
|
|
186
|
+
# Verify template content was properly processed
|
|
187
|
+
assert 'kind: Deployment' in result
|
|
188
|
+
assert 'kind: Service' in result
|
|
189
|
+
assert 'name: test-app' in result
|
|
190
|
+
assert 'namespace: test-namespace' in result
|
|
191
|
+
assert 'replicas: 3' in result
|
|
192
|
+
assert 'service.beta.kubernetes.io/aws-load-balancer-scheme: internal' in result
|
|
193
|
+
|
|
194
|
+
# Verify checkov annotations were removed
|
|
195
|
+
assert 'checkov.io/skip1' not in result
|
|
196
|
+
assert 'checkov.io/skip2' not in result
|
|
197
|
+
|
|
198
|
+
# Verify other annotations were preserved
|
|
199
|
+
assert 'other-annotation: This should be preserved' in result
|
|
200
|
+
|
|
135
201
|
@pytest.mark.asyncio
|
|
136
202
|
async def test_apply_yaml_relative_path(self, mock_context, mock_mcp, mock_client_cache):
|
|
137
203
|
"""Test apply_yaml method with a relative path."""
|
|
@@ -886,74 +952,61 @@ metadata:
|
|
|
886
952
|
):
|
|
887
953
|
handler = K8sHandler(mock_mcp, allow_write=True)
|
|
888
954
|
|
|
889
|
-
#
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
955
|
+
# Mock the _load_yaml_template method to avoid template loading issues
|
|
956
|
+
with patch.object(handler, '_load_yaml_template', return_value='combined yaml content'):
|
|
957
|
+
# Mock os.path.isabs to return True for absolute paths
|
|
958
|
+
with patch('os.path.isabs', return_value=True):
|
|
959
|
+
# Mock os.makedirs to avoid creating directories
|
|
960
|
+
with patch('os.makedirs') as mock_makedirs:
|
|
961
|
+
# Mock open for writing output
|
|
962
|
+
with patch('builtins.open', mock_open()) as mocked_open:
|
|
963
|
+
# Mock os.path.abspath to return a predictable absolute path
|
|
964
|
+
with patch(
|
|
965
|
+
'os.path.abspath',
|
|
966
|
+
return_value='/absolute/path/test-output/test-app-manifest.yaml',
|
|
967
|
+
):
|
|
968
|
+
# Generate the manifest
|
|
969
|
+
result = await handler.generate_app_manifest(
|
|
970
|
+
mock_context,
|
|
971
|
+
app_name='test-app',
|
|
972
|
+
image_uri='123456789012.dkr.ecr.region.amazonaws.com/repo:tag',
|
|
973
|
+
port=8080,
|
|
974
|
+
replicas=3,
|
|
975
|
+
cpu='250m',
|
|
976
|
+
memory='256Mi',
|
|
977
|
+
namespace='test-namespace',
|
|
978
|
+
load_balancer_scheme='internet-facing',
|
|
979
|
+
output_dir='/absolute/path/test-output',
|
|
980
|
+
)
|
|
895
981
|
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
namespace: NAMESPACE
|
|
901
|
-
annotations:
|
|
902
|
-
service.beta.kubernetes.io/aws-load-balancer-scheme: LOAD_BALANCER_SCHEME"""
|
|
982
|
+
# Verify that os.makedirs was called with exist_ok=True
|
|
983
|
+
mock_makedirs.assert_called_once_with(
|
|
984
|
+
'/absolute/path/test-output', exist_ok=True
|
|
985
|
+
)
|
|
903
986
|
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
mock_open.return_value = mock_file
|
|
987
|
+
# Verify that open was called for writing output
|
|
988
|
+
mocked_open.assert_called_once_with(
|
|
989
|
+
'/absolute/path/test-output/test-app-manifest.yaml', 'w'
|
|
990
|
+
)
|
|
909
991
|
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
memory='256Mi',
|
|
929
|
-
namespace='test-namespace',
|
|
930
|
-
load_balancer_scheme='internet-facing',
|
|
931
|
-
output_dir='/absolute/path/test-output',
|
|
932
|
-
)
|
|
933
|
-
|
|
934
|
-
# Verify that os.makedirs was called with exist_ok=True
|
|
935
|
-
mock_makedirs.assert_called_once_with(
|
|
936
|
-
'/absolute/path/test-output', exist_ok=True
|
|
937
|
-
)
|
|
938
|
-
|
|
939
|
-
# Verify that open was called for reading templates and writing output
|
|
940
|
-
assert mock_open.call_count == 3 # 2 reads + 1 write
|
|
941
|
-
|
|
942
|
-
# Verify the result
|
|
943
|
-
assert not result.isError
|
|
944
|
-
assert isinstance(result.content[0], TextContent)
|
|
945
|
-
assert 'Successfully generated YAML for test-app' in result.content[0].text
|
|
946
|
-
assert (
|
|
947
|
-
'with image 123456789012.dkr.ecr.region.amazonaws.com/repo:tag'
|
|
948
|
-
in result.content[0].text
|
|
949
|
-
)
|
|
950
|
-
|
|
951
|
-
# Verify that the output path is absolute
|
|
952
|
-
assert os.path.isabs(result.output_file_path)
|
|
953
|
-
assert (
|
|
954
|
-
result.output_file_path
|
|
955
|
-
== '/absolute/path/test-output/test-app-manifest.yaml'
|
|
956
|
-
)
|
|
992
|
+
# Verify the result
|
|
993
|
+
assert not result.isError
|
|
994
|
+
assert isinstance(result.content[0], TextContent)
|
|
995
|
+
assert (
|
|
996
|
+
'Successfully generated YAML for test-app'
|
|
997
|
+
in result.content[0].text
|
|
998
|
+
)
|
|
999
|
+
assert (
|
|
1000
|
+
'with image 123456789012.dkr.ecr.region.amazonaws.com/repo:tag'
|
|
1001
|
+
in result.content[0].text
|
|
1002
|
+
)
|
|
1003
|
+
|
|
1004
|
+
# Verify that the output path is absolute
|
|
1005
|
+
assert os.path.isabs(result.output_file_path)
|
|
1006
|
+
assert (
|
|
1007
|
+
result.output_file_path
|
|
1008
|
+
== '/absolute/path/test-output/test-app-manifest.yaml'
|
|
1009
|
+
)
|
|
957
1010
|
|
|
958
1011
|
@pytest.mark.asyncio
|
|
959
1012
|
async def test_generate_app_manifest_error(self, mock_context, mock_mcp, mock_client_cache):
|
|
@@ -1705,6 +1758,67 @@ metadata:
|
|
|
1705
1758
|
result = handler.cleanup_resource_response(simple_input)
|
|
1706
1759
|
assert result == simple_input
|
|
1707
1760
|
|
|
1761
|
+
def test_remove_checkov_skip_annotations(self, mock_mcp, mock_client_cache):
|
|
1762
|
+
"""Test _remove_checkov_skip_annotations method directly to ensure line 807 is covered."""
|
|
1763
|
+
# Initialize the K8s handler
|
|
1764
|
+
with patch(
|
|
1765
|
+
'awslabs.eks_mcp_server.k8s_handler.K8sClientCache', return_value=mock_client_cache
|
|
1766
|
+
):
|
|
1767
|
+
handler = K8sHandler(mock_mcp)
|
|
1768
|
+
|
|
1769
|
+
# Test case 1: YAML with only checkov skip annotations (should remove annotations completely)
|
|
1770
|
+
yaml_content = """apiVersion: apps/v1
|
|
1771
|
+
kind: Deployment
|
|
1772
|
+
metadata:
|
|
1773
|
+
name: test-app
|
|
1774
|
+
namespace: default
|
|
1775
|
+
annotations:
|
|
1776
|
+
checkov.io/skip1: "CKV_K8S_14=We're using a specific image version"
|
|
1777
|
+
checkov.io/skip2: "CKV_K8S_43=Resource limits are set appropriately"
|
|
1778
|
+
spec:
|
|
1779
|
+
replicas: 3"""
|
|
1780
|
+
|
|
1781
|
+
expected_result = """apiVersion: apps/v1
|
|
1782
|
+
kind: Deployment
|
|
1783
|
+
metadata:
|
|
1784
|
+
name: test-app
|
|
1785
|
+
namespace: default
|
|
1786
|
+
spec:
|
|
1787
|
+
replicas: 3
|
|
1788
|
+
"""
|
|
1789
|
+
|
|
1790
|
+
result = handler._remove_checkov_skip_annotations(yaml_content)
|
|
1791
|
+
# Normalize whitespace for comparison
|
|
1792
|
+
result = result.replace(' ', '').replace('\n', '')
|
|
1793
|
+
expected_result = expected_result.replace(' ', '').replace('\n', '')
|
|
1794
|
+
assert result == expected_result
|
|
1795
|
+
|
|
1796
|
+
# Test case 2: YAML with mixed annotations (should keep non-checkov annotations)
|
|
1797
|
+
yaml_content = """apiVersion: apps/v1
|
|
1798
|
+
kind: Deployment
|
|
1799
|
+
metadata:
|
|
1800
|
+
name: test-app
|
|
1801
|
+
namespace: default
|
|
1802
|
+
annotations:
|
|
1803
|
+
checkov.io/skip1: "CKV_K8S_14=We're using a specific image version"
|
|
1804
|
+
other-annotation: "This should be preserved"
|
|
1805
|
+
spec:
|
|
1806
|
+
replicas: 3"""
|
|
1807
|
+
|
|
1808
|
+
expected_result = """apiVersion: apps/v1
|
|
1809
|
+
kind: Deployment
|
|
1810
|
+
metadata:
|
|
1811
|
+
name: test-app
|
|
1812
|
+
namespace: default
|
|
1813
|
+
annotations:
|
|
1814
|
+
other-annotation: This should be preserved
|
|
1815
|
+
spec:
|
|
1816
|
+
replicas: 3
|
|
1817
|
+
"""
|
|
1818
|
+
|
|
1819
|
+
result = handler._remove_checkov_skip_annotations(yaml_content)
|
|
1820
|
+
assert 'other-annotation: This should be preserved' in result
|
|
1821
|
+
|
|
1708
1822
|
def test_filter_null_values(self, mock_mcp, mock_client_cache):
|
|
1709
1823
|
"""Test filter_null_values method for removing null values from data structures."""
|
|
1710
1824
|
# Initialize the K8s handler
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{awslabs_eks_mcp_server-0.1.1 → awslabs_eks_mcp_server-0.1.2}/awslabs/eks_mcp_server/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{awslabs_eks_mcp_server-0.1.1 → awslabs_eks_mcp_server-0.1.2}/awslabs/eks_mcp_server/consts.py
RENAMED
|
File without changes
|
|
File without changes
|
{awslabs_eks_mcp_server-0.1.1 → awslabs_eks_mcp_server-0.1.2}/awslabs/eks_mcp_server/iam_handler.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{awslabs_eks_mcp_server-0.1.1 → awslabs_eks_mcp_server-0.1.2}/awslabs/eks_mcp_server/models.py
RENAMED
|
File without changes
|
{awslabs_eks_mcp_server-0.1.1 → awslabs_eks_mcp_server-0.1.2}/awslabs/eks_mcp_server/server.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{awslabs_eks_mcp_server-0.1.1 → awslabs_eks_mcp_server-0.1.2}/tests/test_cloudwatch_handler.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{awslabs_eks_mcp_server-0.1.1 → awslabs_eks_mcp_server-0.1.2}/tests/test_k8s_client_cache.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|