cycode 3.25.2.dev2__py3-none-any.whl → 3.25.2.dev4__py3-none-any.whl

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.
cycode/__init__.py CHANGED
@@ -5,4 +5,4 @@ import time as _time
5
5
  # end-to-end scan duration from the moment the user actually triggered it.
6
6
  _BOOT_WALL: float = _time.time()
7
7
 
8
- __version__ = '3.25.2.dev2' # DON'T TOUCH. Placeholder. Will be filled automatically on poetry build from Git Tag
8
+ __version__ = '3.25.2.dev4' # DON'T TOUCH. Placeholder. Will be filled automatically on poetry build from Git Tag
@@ -327,10 +327,14 @@ def _check_mcp_server_authorization(payload: AIHookPayload, policy: dict) -> _Pr
327
327
  return None
328
328
 
329
329
  status = statuses.status_of(server_name)
330
- if not is_enforced(status):
330
+ treat_unreviewed = statuses.treat_unreviewed_as_unauthorized
331
+ if not is_enforced(status, treat_unreviewed):
331
332
  return None
332
333
 
333
- logger.debug('MCP server is not authorized, %s', {'mcp_server_name': server_name, 'status': status})
334
+ logger.debug(
335
+ 'MCP server is not authorized, %s',
336
+ {'mcp_server_name': server_name, 'status': status, 'treat_unreviewed': treat_unreviewed},
337
+ )
334
338
  return _PreScanFinding(
335
339
  block_reason=BlockReason.UNAUTHORIZED_MCP_SERVER,
336
340
  mode=get_effective_mode(mcp_config, action_key='server_action'),
@@ -14,7 +14,12 @@ from marshmallow import EXCLUDE, Schema, fields, post_load
14
14
  from cycode.cli.apps.ai_guardrails.scan.guardrail_config import DEFAULT_TTL_SECONDS
15
15
  from cycode.cli.consts import CYCODE_CONFIGURATION_DIRECTORY
16
16
  from cycode.cli.utils.path_utils import atomic_write_text, quarantine_corrupt_file
17
- from cycode.cyclient.models import McpServerAuthorizationStatus, McpServerStatus, McpServerStatusSchema
17
+ from cycode.cyclient.models import (
18
+ McpServerAuthorizationStatus,
19
+ McpServerStatus,
20
+ McpServerStatusSchema,
21
+ TrueOnlyBoolean,
22
+ )
18
23
  from cycode.logger import get_logger
19
24
 
20
25
  logger = get_logger('AI Guardrails')
@@ -34,8 +39,10 @@ def get_mcp_server_statuses_cache_path() -> Path:
34
39
  return Path.home() / CYCODE_CONFIGURATION_DIRECTORY / MCP_SERVER_STATUSES_FILE_NAME
35
40
 
36
41
 
37
- def is_enforced(status: McpServerAuthorizationStatus | None) -> bool:
42
+ def is_enforced(status: McpServerAuthorizationStatus | None, treat_unreviewed: bool) -> bool:
38
43
  """``status`` is None when the platform never saw the server."""
44
+ if treat_unreviewed:
45
+ return status != McpServerAuthorizationStatus.AUTHORIZED
39
46
  return status == McpServerAuthorizationStatus.UNAUTHORIZED
40
47
 
41
48
 
@@ -45,6 +52,7 @@ class McpServerStatuses:
45
52
  fetched_at: float
46
53
  tenant_id: str | None = None
47
54
  ttl_seconds: float = DEFAULT_TTL_SECONDS
55
+ treat_unreviewed_as_unauthorized: bool = False
48
56
  _by_alias: dict = field(init=False, repr=False)
49
57
 
50
58
  def __post_init__(self) -> None:
@@ -70,6 +78,7 @@ class McpServerStatusesSchema(Schema):
70
78
  fetched_at = fields.Float(required=True)
71
79
  tenant_id = fields.String(allow_none=True, load_default=None)
72
80
  ttl_seconds = fields.Float(allow_none=True, load_default=None)
81
+ treat_unreviewed_as_unauthorized = TrueOnlyBoolean(data_key='should_treat_unreviewed_as_unauthorized')
73
82
 
74
83
  @post_load
75
84
  def build_dto(self, data: dict[str, Any], **_) -> McpServerStatuses:
@@ -78,10 +87,19 @@ class McpServerStatusesSchema(Schema):
78
87
 
79
88
 
80
89
  def save_mcp_server_statuses(
81
- servers: list[McpServerStatus], tenant_id: str | None, ttl_seconds: float = DEFAULT_TTL_SECONDS
90
+ servers: list[McpServerStatus],
91
+ tenant_id: str | None,
92
+ ttl_seconds: float = DEFAULT_TTL_SECONDS,
93
+ treat_unreviewed_as_unauthorized: bool = False,
82
94
  ) -> None:
83
95
  path = get_mcp_server_statuses_cache_path()
84
- statuses = McpServerStatuses(servers=servers, fetched_at=time.time(), tenant_id=tenant_id, ttl_seconds=ttl_seconds)
96
+ statuses = McpServerStatuses(
97
+ servers=servers,
98
+ fetched_at=time.time(),
99
+ tenant_id=tenant_id,
100
+ ttl_seconds=ttl_seconds,
101
+ treat_unreviewed_as_unauthorized=treat_unreviewed_as_unauthorized,
102
+ )
85
103
  try:
86
104
  path.parent.mkdir(parents=True, exist_ok=True)
87
105
  atomic_write_text(str(path), json.dumps(McpServerStatusesSchema().dump(statuses)))
@@ -129,7 +129,9 @@ def _report_session_context(
129
129
  _save_report_cache(digest, tenant_id)
130
130
  if response.mcp_servers is not None:
131
131
  ttl_seconds = config.ttl_seconds if config is not None else DEFAULT_TTL_SECONDS
132
- save_mcp_server_statuses(response.mcp_servers, tenant_id, ttl_seconds)
132
+ save_mcp_server_statuses(
133
+ response.mcp_servers, tenant_id, ttl_seconds, response.should_treat_unreviewed_as_unauthorized
134
+ )
133
135
  logger.debug('MCP server statuses cache updated')
134
136
  except Exception as e:
135
137
  logger.debug('Failed to report session context', exc_info=e)
cycode/cli/consts.py CHANGED
@@ -124,6 +124,7 @@ SCA_CONFIGURATION_SCAN_SUPPORTED_FILES = ( # keep in lowercase
124
124
  'deno.lock',
125
125
  'deno.json',
126
126
  'pnpm-lock.yaml',
127
+ 'pnpm-workspace.yaml',
127
128
  'bun.lock',
128
129
  'npm-shrinkwrap.json',
129
130
  'packages.config',
@@ -189,6 +190,7 @@ PROJECT_FILES_BY_ECOSYSTEM_MAP = {
189
190
  'npm-shrinkwrap.json',
190
191
  '.npmrc',
191
192
  'pnpm-lock.yaml',
193
+ 'pnpm-workspace.yaml',
192
194
  'bun.lock',
193
195
  'deno.lock',
194
196
  'deno.json',
cycode/cyclient/models.py CHANGED
@@ -601,6 +601,13 @@ class McpServerAuthorizationStatusField(fields.Field):
601
601
  return McpServerAuthorizationStatus.parse(None if value is missing else value)
602
602
 
603
603
 
604
+ class TrueOnlyBoolean(fields.Boolean):
605
+ """Anything but a literal true reads as False, so a malformed flag never tightens enforcement."""
606
+
607
+ def deserialize(self, value: object, *_, **__) -> bool:
608
+ return value is True
609
+
610
+
604
611
  @dataclass
605
612
  class McpServerStatus:
606
613
  alias: str | None = None
@@ -625,6 +632,8 @@ class McpServerStatusSchema(Schema):
625
632
  class SessionContextResponse:
626
633
  # None when the response carries no (or malformed) MCP server statuses.
627
634
  mcp_servers: list[McpServerStatus] | None = None
635
+ # Strict mode: Unreviewed servers count as Unauthorized.
636
+ should_treat_unreviewed_as_unauthorized: bool = False
628
637
 
629
638
 
630
639
  class SessionContextResponseSchema(Schema):
@@ -632,6 +641,7 @@ class SessionContextResponseSchema(Schema):
632
641
  unknown = EXCLUDE
633
642
 
634
643
  mcp_servers = fields.List(fields.Nested(McpServerStatusSchema), allow_none=True, load_default=None)
644
+ should_treat_unreviewed_as_unauthorized = TrueOnlyBoolean()
635
645
 
636
646
  @post_load
637
647
  def build_dto(self, data: dict[str, Any], **_) -> SessionContextResponse:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cycode
3
- Version: 3.25.2.dev2
3
+ Version: 3.25.2.dev4
4
4
  Summary: Boost security in your dev lifecycle via SAST, SCA, Secrets & IaC scanning.
5
5
  License-Expression: MIT
6
6
  License-File: LICENCE
@@ -1,4 +1,4 @@
1
- cycode/__init__.py,sha256=wJ8aEY50gYDz0qyJPREJI85aAXCUaQxHqdslewq6rd4,396
1
+ cycode/__init__.py,sha256=WFOG1meth_l-N9dkT3YvvkSOCUuMykZZ8eCvWSDBFCk,396
2
2
  cycode/__main__.py,sha256=Z3bD5yrA7yPvAChcADQrqCaZd0ChGI1gdiwALwbWJ6U,104
3
3
  cycode/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  cycode/cli/app.py,sha256=sI6wBHmfo7RchO9rnOXaQyUHRG9fm4r9aIduV4ZOD5c,10167
@@ -21,14 +21,14 @@ cycode/cli/apps/ai_guardrails/scan/__init__.py,sha256=qJc82XiQGiAuc1sYY8Ij_A-qXp
21
21
  cycode/cli/apps/ai_guardrails/scan/consts.py,sha256=8H8JXlgm65sYkgTXqsBInHhHe80UPjqY4vumZXB4GGM,1060
22
22
  cycode/cli/apps/ai_guardrails/scan/detach.py,sha256=8BRgBq9Qi8nXEx6NKlE8scSRPkO30XCfsiI5PLvq6Gk,2700
23
23
  cycode/cli/apps/ai_guardrails/scan/guardrail_config.py,sha256=cU5DqsPvt_dejkiDhbN7ve--1LlT-VuQvLv70kWUtJs,7911
24
- cycode/cli/apps/ai_guardrails/scan/handlers.py,sha256=u8MRB9krA9MgrBdnnC2zxgy2CfhdHAfdemEs0Mt3hoo,20505
25
- cycode/cli/apps/ai_guardrails/scan/mcp_server_status.py,sha256=DLC-L-euqclpQw-fH8cOk1-zcIptz0M0wJgOK_pEiTI,3870
24
+ cycode/cli/apps/ai_guardrails/scan/handlers.py,sha256=qGghjMm82NlB5rnDVQ-5i79JDuZKvu-VU3MNABcrV8A,20649
25
+ cycode/cli/apps/ai_guardrails/scan/mcp_server_status.py,sha256=44wij2VtjsB7cffxEnEBqQ5RInmzLROwOC0VwtDRl4s,4355
26
26
  cycode/cli/apps/ai_guardrails/scan/payload.py,sha256=dyxhrTdSiVuODlzRR3RJFAeiP3zTL6Lt_5Wteng9f7k,1467
27
27
  cycode/cli/apps/ai_guardrails/scan/policy.py,sha256=nqLjWqNty-p4pk4mSCyy7EfqavUNCdP3nUSkKC7QRMY,4984
28
28
  cycode/cli/apps/ai_guardrails/scan/scan_command.py,sha256=WKRlg6ubwUPkyAnJDu6q9JWMtmN4ZuBM8-y9P7fGi6c,8286
29
29
  cycode/cli/apps/ai_guardrails/scan/types.py,sha256=6nh_40KSTuWabsaVqkZEl712m6lAI8k9OuhPo8KhJdw,1553
30
30
  cycode/cli/apps/ai_guardrails/scan/utils.py,sha256=4CIZAILS9m5-JsFbUderwBVzFAjqAVVVRhWgE9oLPhM,5292
31
- cycode/cli/apps/ai_guardrails/session_start_command.py,sha256=lEKE5InZv1DgG_27SFw55_UVvgKnIUII_xHRfWkbnDU,8233
31
+ cycode/cli/apps/ai_guardrails/session_start_command.py,sha256=1TsTK_SY6dp-iILCIqzxVFV0oHFtyyrg6fDIOV96stQ,8313
32
32
  cycode/cli/apps/ai_guardrails/status_command.py,sha256=OXWnGhFwt4zILbtGHWnB6Bh-Z3OhcgKDGQW6e-7QyHU,3190
33
33
  cycode/cli/apps/ai_guardrails/uninstall_command.py,sha256=po-Uh-U5itNOPPAG7wAfBLEB85DvZX1VMUVS-pgHX64,2685
34
34
  cycode/cli/apps/ai_remediation/__init__.py,sha256=8vYthY9RQeJqEni3AIF5sryz8n-XJQ6VNqG4aEFBAdY,553
@@ -99,7 +99,7 @@ cycode/cli/apps/status/version_command.py,sha256=c6Iko_rmZo9T_kQSd3HUloBi40Qv7cj
99
99
  cycode/cli/cli_types.py,sha256=Xqf2eSx3yUvFoQG29ObUZ3QLVBhtZ4mkqxf_cJXpntU,3406
100
100
  cycode/cli/config.py,sha256=Op-lX_neanJtvPvoOEx4ByBdveh5ygElIga1FdSHhOI,299
101
101
  cycode/cli/console.py,sha256=fsKqkOQCkvVn34Vf0XYBjXwKbK51J_Ic7mLBFUtsjzI,1901
102
- cycode/cli/consts.py,sha256=jI1M2PolPIIodJMphQYrTbzCOrjO3umjb6R92h1Ntww,11163
102
+ cycode/cli/consts.py,sha256=gYldShCpOT1m6_wi2LVgdPbl9sMxOs7o7KMYFj_QqHo,11221
103
103
  cycode/cli/exceptions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
104
104
  cycode/cli/exceptions/custom_exceptions.py,sha256=Mvjfkww2mmMBBCD4OWAkSfl_9iOvi4bLTLGLBL7OdOk,5423
105
105
  cycode/cli/exceptions/handle_ai_remediation_errors.py,sha256=mA70upSYXK3rL_fmanzKYeUzLENhpXdkW8k3aIHrKzU,785
@@ -219,13 +219,13 @@ cycode/cyclient/cycode_token_based_client.py,sha256=frbrv1jzF388SXqHNNkZ95Hbx7Vj
219
219
  cycode/cyclient/headers.py,sha256=Ktmn7cPsFXcPYdQMmkURmcHZBmjwWMRY1TZ_x1f7JBQ,1306
220
220
  cycode/cyclient/import_sbom_client.py,sha256=AvEa6APERHGT-1v3LtENuekrse7tGgLr18Dma5WHTA0,2731
221
221
  cycode/cyclient/logger.py,sha256=oTkay7QzoOIVQ71cGOy4ukkijYGA3IKJlHkL24Px5ds,70
222
- cycode/cyclient/models.py,sha256=s7nR_Ih_Q0OKCgLood_MZLuxjreI5ydCbLNgjrNCFz8,17526
222
+ cycode/cyclient/models.py,sha256=4JjBL7kxkoztXvbFy9fy67JZ0U8z6bMDabp4HN9uQD0,17942
223
223
  cycode/cyclient/report_client.py,sha256=PaKEo6Q0GFVdpNC18vvR4uBoUX1MnllVmKkS72eAPmk,4368
224
224
  cycode/cyclient/scan_client.py,sha256=AZ-3G9eC8Y_-jjivllP7ESPpdLds0Dkl4-KIxe5jNyE,16944
225
225
  cycode/cyclient/scan_config_base.py,sha256=mXsPZGYCtp85rv5GIige40yQZXuRcEKUW-VQJ0vgFzk,1201
226
226
  cycode/logger.py,sha256=OHmfkf4dnyZgfixGqkWf3js3uysrOXU_4cS8TChtAzc,2079
227
- cycode-3.25.2.dev2.dist-info/METADATA,sha256=QAcKCvKqyWmRco-Ra32SRZ28vrmWxPbOorYqBj-e7Yk,96119
228
- cycode-3.25.2.dev2.dist-info/WHEEL,sha256=L-WvLdSBvJWHXv5zrQxDvNRnIgoBzLUpcbuiw19KCuQ,88
229
- cycode-3.25.2.dev2.dist-info/entry_points.txt,sha256=iDcVJM8ByLElVgvBgtYxDjw1kT7O8Mo0LcWZIT5L3Ig,45
230
- cycode-3.25.2.dev2.dist-info/licenses/LICENCE,sha256=2Wx4N6mD_4xB7-E3hPkZ3MPhpJy__k_I8MaCSO-PDRo,1068
231
- cycode-3.25.2.dev2.dist-info/RECORD,,
227
+ cycode-3.25.2.dev4.dist-info/METADATA,sha256=jKryL6ABnTfBmYrFv2Pt5Pbv1AMlsVUCXU0voRQOQ-Y,96119
228
+ cycode-3.25.2.dev4.dist-info/WHEEL,sha256=L-WvLdSBvJWHXv5zrQxDvNRnIgoBzLUpcbuiw19KCuQ,88
229
+ cycode-3.25.2.dev4.dist-info/entry_points.txt,sha256=iDcVJM8ByLElVgvBgtYxDjw1kT7O8Mo0LcWZIT5L3Ig,45
230
+ cycode-3.25.2.dev4.dist-info/licenses/LICENCE,sha256=2Wx4N6mD_4xB7-E3hPkZ3MPhpJy__k_I8MaCSO-PDRo,1068
231
+ cycode-3.25.2.dev4.dist-info/RECORD,,