iris-security-sdk 0.2.16__tar.gz → 0.2.18__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.
- {iris_security_sdk-0.2.16 → iris_security_sdk-0.2.18}/PKG-INFO +7 -5
- {iris_security_sdk-0.2.16 → iris_security_sdk-0.2.18}/README.md +1 -1
- {iris_security_sdk-0.2.16 → iris_security_sdk-0.2.18}/iris/__init__.py +3 -3
- {iris_security_sdk-0.2.16 → iris_security_sdk-0.2.18}/iris/scan.py +47 -6
- {iris_security_sdk-0.2.16 → iris_security_sdk-0.2.18}/iris_security_sdk.egg-info/PKG-INFO +7 -5
- {iris_security_sdk-0.2.16 → iris_security_sdk-0.2.18}/iris_security_sdk.egg-info/requires.txt +1 -1
- {iris_security_sdk-0.2.16 → iris_security_sdk-0.2.18}/pyproject.toml +6 -4
- iris_security_sdk-0.2.18/tests/test_scan.py +125 -0
- iris_security_sdk-0.2.16/tests/test_scan.py +0 -51
- {iris_security_sdk-0.2.16 → iris_security_sdk-0.2.18}/iris/_telemetry.py +0 -0
- {iris_security_sdk-0.2.16 → iris_security_sdk-0.2.18}/iris/_telemetry_config.py +0 -0
- {iris_security_sdk-0.2.16 → iris_security_sdk-0.2.18}/iris/hitl.py +0 -0
- {iris_security_sdk-0.2.16 → iris_security_sdk-0.2.18}/iris_sdk/__init__.py +0 -0
- {iris_security_sdk-0.2.16 → iris_security_sdk-0.2.18}/iris_sdk/scan.py +0 -0
- {iris_security_sdk-0.2.16 → iris_security_sdk-0.2.18}/iris_security_sdk.egg-info/SOURCES.txt +0 -0
- {iris_security_sdk-0.2.16 → iris_security_sdk-0.2.18}/iris_security_sdk.egg-info/dependency_links.txt +0 -0
- {iris_security_sdk-0.2.16 → iris_security_sdk-0.2.18}/iris_security_sdk.egg-info/top_level.txt +0 -0
- {iris_security_sdk-0.2.16 → iris_security_sdk-0.2.18}/setup.cfg +0 -0
- {iris_security_sdk-0.2.16 → iris_security_sdk-0.2.18}/tests/test_telemetry.py +0 -0
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: iris-security-sdk
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.18
|
|
4
4
|
Summary: IRIS — AI Agent Governance SDK. Govern AI agents locally.
|
|
5
5
|
Author-email: Gilbert Martin <gilbert@iris-security.io>
|
|
6
6
|
License: Apache-2.0
|
|
7
|
-
Project-URL: Homepage, https://
|
|
8
|
-
Project-URL: Repository, https://github.com/
|
|
7
|
+
Project-URL: Homepage, https://iris-security.github.io/iris-sdk/
|
|
8
|
+
Project-URL: Repository, https://github.com/IRIS-Security/iris-sdk
|
|
9
|
+
Project-URL: Documentation, https://iris-security.github.io/iris-sdk/getting-started.html
|
|
10
|
+
Project-URL: Issues, https://github.com/IRIS-Security/iris-sdk/issues
|
|
9
11
|
Keywords: ai-governance,policy-as-code,cedar,compliance,llm,ai-agents,langchain,anthropic,openai,colorado-ai-act,eu-ai-act,hipaa,fedramp,mcp,claude,iris,guardrails,responsible-ai
|
|
10
12
|
Classifier: Development Status :: 3 - Alpha
|
|
11
13
|
Classifier: Intended Audience :: Developers
|
|
@@ -17,7 +19,7 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
17
19
|
Classifier: Programming Language :: Python :: 3.12
|
|
18
20
|
Requires-Python: >=3.10
|
|
19
21
|
Description-Content-Type: text/markdown
|
|
20
|
-
Requires-Dist: iris-security-core>=0.1.
|
|
22
|
+
Requires-Dist: iris-security-core>=0.1.18
|
|
21
23
|
Requires-Dist: pyyaml>=6.0
|
|
22
24
|
Requires-Dist: pydantic>=2.0
|
|
23
25
|
Requires-Dist: click>=8.1
|
|
@@ -62,7 +64,7 @@ IRIS — AI Agent Governance SDK. Govern AI agents locally.
|
|
|
62
64
|
Discover, register, and govern AI agents with Cedar policy evaluation,
|
|
63
65
|
compliance bundles, and local-first governance.
|
|
64
66
|
|
|
65
|
-
Part of the [IRIS SDK](https://github.com/
|
|
67
|
+
Part of the [IRIS SDK](https://github.com/IRIS-Security/iris-sdk).
|
|
66
68
|
|
|
67
69
|
## Install
|
|
68
70
|
|
|
@@ -5,7 +5,7 @@ IRIS — AI Agent Governance SDK. Govern AI agents locally.
|
|
|
5
5
|
Discover, register, and govern AI agents with Cedar policy evaluation,
|
|
6
6
|
compliance bundles, and local-first governance.
|
|
7
7
|
|
|
8
|
-
Part of the [IRIS SDK](https://github.com/
|
|
8
|
+
Part of the [IRIS SDK](https://github.com/IRIS-Security/iris-sdk).
|
|
9
9
|
|
|
10
10
|
## Install
|
|
11
11
|
|
|
@@ -47,9 +47,9 @@ from iris_core.evidence.vault import EvidenceVault
|
|
|
47
47
|
from iris_core.cost.tracker import CostSummary, CostTracker, CostEntry
|
|
48
48
|
from iris_core.cost.pricing import PricingRegistry
|
|
49
49
|
|
|
50
|
-
__version__ = "0.2.
|
|
50
|
+
__version__ = "0.2.18"
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
AARM_ALIGNMENT = "designed-toward" # AARM R1–R9 partial; not Core conformant
|
|
53
53
|
AARM_VERSION = "1.0"
|
|
54
54
|
AIUC1_ALIGNMENT = "Q1-2026"
|
|
55
55
|
__all__ = [
|
|
@@ -78,7 +78,7 @@ __all__ = [
|
|
|
78
78
|
"CostSummary",
|
|
79
79
|
"CostEntry",
|
|
80
80
|
"PricingRegistry",
|
|
81
|
-
"
|
|
81
|
+
"AARM_ALIGNMENT",
|
|
82
82
|
"AARM_VERSION",
|
|
83
83
|
"AIUC1_ALIGNMENT",
|
|
84
84
|
"__version__",
|
|
@@ -57,27 +57,43 @@ _MODEL_PROVIDER_PREFIXES: list[tuple[re.Pattern[str], str]] = [
|
|
|
57
57
|
]
|
|
58
58
|
|
|
59
59
|
_DATA_CATEGORY_PATTERNS = {
|
|
60
|
+
# Note: regulation/framework names (hipaa, pci, gdpr, ...) are deliberately
|
|
61
|
+
# excluded here. A compliance tool's own source legitimately talks *about*
|
|
62
|
+
# those frameworks (rule engines, questionnaire copy, requirement labels)
|
|
63
|
+
# without ever handling the regulated data itself, so a bare framework
|
|
64
|
+
# name is not evidence of a data category — only concrete data-field
|
|
65
|
+
# vocabulary is. Likewise "passport" alone is excluded: this codebase's
|
|
66
|
+
# own AgentPassport/passport.yaml artifact naming collides with the word
|
|
67
|
+
# far more often than it means travel-document PII.
|
|
60
68
|
"pii": re.compile(
|
|
61
|
-
r"\b(ssn|social_security|date_of_birth|dob|
|
|
62
|
-
r"first_name|last_name|address_line|national_id)\b",
|
|
69
|
+
r"\b(ssn|social_security|date_of_birth|dob|passport_number|passport_no|"
|
|
70
|
+
r"email_address|phone_number|first_name|last_name|address_line|national_id)\b",
|
|
63
71
|
re.I,
|
|
64
72
|
),
|
|
65
73
|
"phi": re.compile(
|
|
66
|
-
r"\b(patient_id|medical_record|diagnosis|icd_?10|
|
|
74
|
+
r"\b(patient_id|medical_record|diagnosis|icd_?10|health_record|"
|
|
67
75
|
r"prescription|mrn|protected_health)\b",
|
|
68
76
|
re.I,
|
|
69
77
|
),
|
|
70
78
|
"financial": re.compile(
|
|
71
|
-
r"\b(credit_card|card_number|bank_account|routing_number|iban|
|
|
79
|
+
r"\b(credit_card|card_number|bank_account|routing_number|iban|"
|
|
72
80
|
r"account_balance|transaction_amount)\b",
|
|
73
81
|
re.I,
|
|
74
82
|
),
|
|
75
83
|
"biometric": re.compile(
|
|
76
|
-
r"\b(fingerprint|face_id|retina_scan|voice_print
|
|
84
|
+
r"\b(fingerprint|face_id|retina_scan|voice_print)\b",
|
|
77
85
|
re.I,
|
|
78
86
|
),
|
|
79
87
|
}
|
|
80
88
|
|
|
89
|
+
# Adjacency required (after removing whitespace/quote noise) for a data-field
|
|
90
|
+
# term to count as source code actually *handling* that field, rather than
|
|
91
|
+
# just naming it in a docstring, questionnaire string, or keyword list — an
|
|
92
|
+
# assignment, a type annotation, or a dict/JSON key all qualify; a bare
|
|
93
|
+
# occurrence inside a comma-separated keyword list or prose sentence does
|
|
94
|
+
# not.
|
|
95
|
+
_CODE_ASSIGNMENT_CONTEXT = re.compile(r"\A\s{0,3}[\'\"]?\s{0,3}[:=]")
|
|
96
|
+
|
|
81
97
|
_REQUIREMENTS_FILES = (
|
|
82
98
|
"requirements.txt",
|
|
83
99
|
"requirements-dev.txt",
|
|
@@ -100,6 +116,16 @@ def _iter_source_files(root: Path) -> list[Path]:
|
|
|
100
116
|
return files
|
|
101
117
|
|
|
102
118
|
|
|
119
|
+
def _is_test_file(path: Path) -> bool:
|
|
120
|
+
"""Test suites routinely embed sample field names/fixtures (fake ssns,
|
|
121
|
+
demo passport.yaml content, etc.) to exercise detection logic itself —
|
|
122
|
+
that sample data isn't evidence the workload actually handles it."""
|
|
123
|
+
if any(part in {"tests", "test"} for part in path.parts):
|
|
124
|
+
return True
|
|
125
|
+
stem = path.stem
|
|
126
|
+
return stem.startswith("test_") or stem.endswith("_test")
|
|
127
|
+
|
|
128
|
+
|
|
103
129
|
def _scan_imports(text: str) -> tuple[set[str], set[str]]:
|
|
104
130
|
providers: set[str] = set()
|
|
105
131
|
frameworks: set[str] = set()
|
|
@@ -132,6 +158,20 @@ def _scan_data_categories(text: str) -> set[str]:
|
|
|
132
158
|
return categories
|
|
133
159
|
|
|
134
160
|
|
|
161
|
+
def _scan_data_categories_in_source(text: str) -> set[str]:
|
|
162
|
+
"""Like `_scan_data_categories`, but for source files: only count a term
|
|
163
|
+
that sits where a real field would (assignment, annotation, or dict/JSON
|
|
164
|
+
key), not one that merely appears in prose, a docstring, or a keyword
|
|
165
|
+
list describing the vocabulary."""
|
|
166
|
+
categories: set[str] = set()
|
|
167
|
+
for category, pattern in _DATA_CATEGORY_PATTERNS.items():
|
|
168
|
+
for match in pattern.finditer(text):
|
|
169
|
+
if _CODE_ASSIGNMENT_CONTEXT.match(text[match.end() : match.end() + 6]):
|
|
170
|
+
categories.add(category)
|
|
171
|
+
break
|
|
172
|
+
return categories
|
|
173
|
+
|
|
174
|
+
|
|
135
175
|
def infer_provider_from_model(model: str) -> str | None:
|
|
136
176
|
"""Infer provider slug from a model identifier (shared by observability adapters)."""
|
|
137
177
|
if not model:
|
|
@@ -196,7 +236,8 @@ def detect_workload(path: str = ".") -> dict[str, Any]:
|
|
|
196
236
|
providers |= p
|
|
197
237
|
frameworks |= f
|
|
198
238
|
models |= _scan_models(text)
|
|
199
|
-
|
|
239
|
+
if not _is_test_file(file_path):
|
|
240
|
+
data_categories |= _scan_data_categories_in_source(text)
|
|
200
241
|
|
|
201
242
|
agent_hints = sum(1 for _ in root.rglob("passport.yaml"))
|
|
202
243
|
autonomy = "assistive"
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: iris-security-sdk
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.18
|
|
4
4
|
Summary: IRIS — AI Agent Governance SDK. Govern AI agents locally.
|
|
5
5
|
Author-email: Gilbert Martin <gilbert@iris-security.io>
|
|
6
6
|
License: Apache-2.0
|
|
7
|
-
Project-URL: Homepage, https://
|
|
8
|
-
Project-URL: Repository, https://github.com/
|
|
7
|
+
Project-URL: Homepage, https://iris-security.github.io/iris-sdk/
|
|
8
|
+
Project-URL: Repository, https://github.com/IRIS-Security/iris-sdk
|
|
9
|
+
Project-URL: Documentation, https://iris-security.github.io/iris-sdk/getting-started.html
|
|
10
|
+
Project-URL: Issues, https://github.com/IRIS-Security/iris-sdk/issues
|
|
9
11
|
Keywords: ai-governance,policy-as-code,cedar,compliance,llm,ai-agents,langchain,anthropic,openai,colorado-ai-act,eu-ai-act,hipaa,fedramp,mcp,claude,iris,guardrails,responsible-ai
|
|
10
12
|
Classifier: Development Status :: 3 - Alpha
|
|
11
13
|
Classifier: Intended Audience :: Developers
|
|
@@ -17,7 +19,7 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
17
19
|
Classifier: Programming Language :: Python :: 3.12
|
|
18
20
|
Requires-Python: >=3.10
|
|
19
21
|
Description-Content-Type: text/markdown
|
|
20
|
-
Requires-Dist: iris-security-core>=0.1.
|
|
22
|
+
Requires-Dist: iris-security-core>=0.1.18
|
|
21
23
|
Requires-Dist: pyyaml>=6.0
|
|
22
24
|
Requires-Dist: pydantic>=2.0
|
|
23
25
|
Requires-Dist: click>=8.1
|
|
@@ -62,7 +64,7 @@ IRIS — AI Agent Governance SDK. Govern AI agents locally.
|
|
|
62
64
|
Discover, register, and govern AI agents with Cedar policy evaluation,
|
|
63
65
|
compliance bundles, and local-first governance.
|
|
64
66
|
|
|
65
|
-
Part of the [IRIS SDK](https://github.com/
|
|
67
|
+
Part of the [IRIS SDK](https://github.com/IRIS-Security/iris-sdk).
|
|
66
68
|
|
|
67
69
|
## Install
|
|
68
70
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "iris-security-sdk"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.18"
|
|
8
8
|
description = "IRIS — AI Agent Governance SDK. Govern AI agents locally."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
authors = [{ name = "Gilbert Martin", email = "gilbert@iris-security.io" }]
|
|
@@ -27,7 +27,7 @@ classifiers = [
|
|
|
27
27
|
"Programming Language :: Python :: 3.12",
|
|
28
28
|
]
|
|
29
29
|
dependencies = [
|
|
30
|
-
"iris-security-core>=0.1.
|
|
30
|
+
"iris-security-core>=0.1.18",
|
|
31
31
|
"pyyaml>=6.0",
|
|
32
32
|
"pydantic>=2.0",
|
|
33
33
|
"click>=8.1",
|
|
@@ -63,8 +63,10 @@ dev = [
|
|
|
63
63
|
]
|
|
64
64
|
|
|
65
65
|
[project.urls]
|
|
66
|
-
Homepage = "https://
|
|
67
|
-
Repository = "https://github.com/
|
|
66
|
+
Homepage = "https://iris-security.github.io/iris-sdk/"
|
|
67
|
+
Repository = "https://github.com/IRIS-Security/iris-sdk"
|
|
68
|
+
Documentation = "https://iris-security.github.io/iris-sdk/getting-started.html"
|
|
69
|
+
Issues = "https://github.com/IRIS-Security/iris-sdk/issues"
|
|
68
70
|
|
|
69
71
|
[tool.setuptools.packages.find]
|
|
70
72
|
where = ["."]
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# Copyright 2024-2025 Gilbert Martin / IRIS Security, Inc.
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from unittest.mock import patch
|
|
7
|
+
|
|
8
|
+
import pytest
|
|
9
|
+
|
|
10
|
+
from iris.scan import detect_workload
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@pytest.fixture
|
|
14
|
+
def sample_project(tmp_path: Path) -> Path:
|
|
15
|
+
(tmp_path / "requirements.txt").write_text(
|
|
16
|
+
"openai>=1.0\nlangchain>=0.2\n",
|
|
17
|
+
encoding="utf-8",
|
|
18
|
+
)
|
|
19
|
+
app = tmp_path / "app.py"
|
|
20
|
+
app.write_text(
|
|
21
|
+
"""
|
|
22
|
+
import openai
|
|
23
|
+
from langchain_openai import ChatOpenAI
|
|
24
|
+
|
|
25
|
+
model = ChatOpenAI(model="gpt-4o")
|
|
26
|
+
client = openai.OpenAI()
|
|
27
|
+
|
|
28
|
+
class UserSchema:
|
|
29
|
+
ssn = "social_security"
|
|
30
|
+
email_address = "test@example.com"
|
|
31
|
+
""",
|
|
32
|
+
encoding="utf-8",
|
|
33
|
+
)
|
|
34
|
+
return tmp_path
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def test_detect_workload_finds_openai_and_langchain(sample_project: Path):
|
|
38
|
+
profile = detect_workload(str(sample_project))
|
|
39
|
+
assert "openai" in profile["providers"]
|
|
40
|
+
assert "langchain" in profile["frameworks"]
|
|
41
|
+
assert any("gpt" in m for m in profile["models"])
|
|
42
|
+
assert "pii" in profile["data_categories"]
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def test_detect_workload_offline_no_network(sample_project: Path):
|
|
46
|
+
def fail_socket(*args, **kwargs):
|
|
47
|
+
raise AssertionError("Network call attempted during offline scan")
|
|
48
|
+
|
|
49
|
+
with patch("socket.socket", side_effect=fail_socket):
|
|
50
|
+
profile = detect_workload(str(sample_project))
|
|
51
|
+
assert profile["source"] == "sdk_scan"
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
# Regression coverage for the dogfood false positive: detect_workload() used
|
|
55
|
+
# to flag data_categories=[biometric, financial, phi, pii] when scanning a
|
|
56
|
+
# governance/compliance tool's own source, because that source legitimately
|
|
57
|
+
# talks *about* those categories (DataClassification enum members, framework
|
|
58
|
+
# names like HIPAA/PCI, questionnaire copy, AgentPassport/passport.yaml
|
|
59
|
+
# vocabulary) without ever handling real data of that kind. apps/iris-cli/ in
|
|
60
|
+
# this repo is exactly that kind of codebase, so scanning it is the natural
|
|
61
|
+
# regression fixture.
|
|
62
|
+
_REPO_ROOT = Path(__file__).resolve().parents[3]
|
|
63
|
+
_IRIS_CLI_ROOT = _REPO_ROOT / "apps" / "iris-cli"
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
@pytest.mark.skipif(not _IRIS_CLI_ROOT.is_dir(), reason="apps/iris-cli not present in this checkout")
|
|
67
|
+
def test_detect_workload_does_not_flag_own_compliance_vocabulary():
|
|
68
|
+
profile = detect_workload(str(_IRIS_CLI_ROOT))
|
|
69
|
+
assert profile["data_categories"] == []
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
@pytest.mark.skipif(not _IRIS_CLI_ROOT.is_dir(), reason="apps/iris-cli not present in this checkout")
|
|
73
|
+
def test_detect_workload_does_not_flag_iris_python_own_source():
|
|
74
|
+
iris_python_root = Path(__file__).resolve().parents[1]
|
|
75
|
+
profile = detect_workload(str(iris_python_root))
|
|
76
|
+
assert profile["data_categories"] == []
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def test_detect_workload_ignores_vocabulary_in_keyword_lists_and_prose(tmp_path: Path):
|
|
80
|
+
(tmp_path / "linter.py").write_text(
|
|
81
|
+
'''
|
|
82
|
+
"""Detects high-risk domains in someone else's code."""
|
|
83
|
+
|
|
84
|
+
high_risk_keywords = ["loan", "credit", "insurance", "medical", "diagnosis"]
|
|
85
|
+
|
|
86
|
+
QUESTIONS = [
|
|
87
|
+
"Yes -- biometric or sensitive data",
|
|
88
|
+
"HIPAA (healthcare)",
|
|
89
|
+
"PCI DSS (payment cards)",
|
|
90
|
+
]
|
|
91
|
+
|
|
92
|
+
def load_passport(agent):
|
|
93
|
+
passport = (agent / "passport.yaml").read_text()
|
|
94
|
+
return passport
|
|
95
|
+
''',
|
|
96
|
+
encoding="utf-8",
|
|
97
|
+
)
|
|
98
|
+
profile = detect_workload(str(tmp_path))
|
|
99
|
+
assert profile["data_categories"] == []
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def test_detect_workload_still_flags_real_field_assignment(tmp_path: Path):
|
|
103
|
+
(tmp_path / "models.py").write_text(
|
|
104
|
+
'''
|
|
105
|
+
class Patient:
|
|
106
|
+
patient_id: str
|
|
107
|
+
diagnosis = ""
|
|
108
|
+
|
|
109
|
+
record = {"credit_card": "4111111111111111", "fingerprint": template}
|
|
110
|
+
''',
|
|
111
|
+
encoding="utf-8",
|
|
112
|
+
)
|
|
113
|
+
profile = detect_workload(str(tmp_path))
|
|
114
|
+
assert set(profile["data_categories"]) == {"phi", "financial", "biometric"}
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def test_detect_workload_skips_data_category_matches_in_test_files(tmp_path: Path):
|
|
118
|
+
tests_dir = tmp_path / "tests"
|
|
119
|
+
tests_dir.mkdir()
|
|
120
|
+
(tests_dir / "test_fixture.py").write_text(
|
|
121
|
+
'ssn = "123-45-6789"\ncredit_card = "4111111111111111"\n',
|
|
122
|
+
encoding="utf-8",
|
|
123
|
+
)
|
|
124
|
+
profile = detect_workload(str(tmp_path))
|
|
125
|
+
assert profile["data_categories"] == []
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
# Copyright 2024-2025 Gilbert Martin / IRIS Security, Inc.
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
from pathlib import Path
|
|
6
|
-
from unittest.mock import patch
|
|
7
|
-
|
|
8
|
-
import pytest
|
|
9
|
-
|
|
10
|
-
from iris.scan import detect_workload
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
@pytest.fixture
|
|
14
|
-
def sample_project(tmp_path: Path) -> Path:
|
|
15
|
-
(tmp_path / "requirements.txt").write_text(
|
|
16
|
-
"openai>=1.0\nlangchain>=0.2\n",
|
|
17
|
-
encoding="utf-8",
|
|
18
|
-
)
|
|
19
|
-
app = tmp_path / "app.py"
|
|
20
|
-
app.write_text(
|
|
21
|
-
"""
|
|
22
|
-
import openai
|
|
23
|
-
from langchain_openai import ChatOpenAI
|
|
24
|
-
|
|
25
|
-
model = ChatOpenAI(model="gpt-4o")
|
|
26
|
-
client = openai.OpenAI()
|
|
27
|
-
|
|
28
|
-
class UserSchema:
|
|
29
|
-
ssn = "social_security"
|
|
30
|
-
email_address = "test@example.com"
|
|
31
|
-
""",
|
|
32
|
-
encoding="utf-8",
|
|
33
|
-
)
|
|
34
|
-
return tmp_path
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
def test_detect_workload_finds_openai_and_langchain(sample_project: Path):
|
|
38
|
-
profile = detect_workload(str(sample_project))
|
|
39
|
-
assert "openai" in profile["providers"]
|
|
40
|
-
assert "langchain" in profile["frameworks"]
|
|
41
|
-
assert any("gpt" in m for m in profile["models"])
|
|
42
|
-
assert "pii" in profile["data_categories"]
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
def test_detect_workload_offline_no_network(sample_project: Path):
|
|
46
|
-
def fail_socket(*args, **kwargs):
|
|
47
|
-
raise AssertionError("Network call attempted during offline scan")
|
|
48
|
-
|
|
49
|
-
with patch("socket.socket", side_effect=fail_socket):
|
|
50
|
-
profile = detect_workload(str(sample_project))
|
|
51
|
-
assert profile["source"] == "sdk_scan"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{iris_security_sdk-0.2.16 → iris_security_sdk-0.2.18}/iris_security_sdk.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{iris_security_sdk-0.2.16 → iris_security_sdk-0.2.18}/iris_security_sdk.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|