iris-security-cli 0.2.0__py3-none-any.whl → 0.2.4__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.
iris_cli/certify.py CHANGED
@@ -10,6 +10,7 @@ import click
10
10
  from rich.console import Console
11
11
  from rich.panel import Panel
12
12
 
13
+ from iris_core.compliance.dynamic_loader import ComplianceRule, DynamicBundleLoader
13
14
  from iris_core.entitlements import Entitlements, Feature
14
15
  from iris_core.models.passport import AgentPassport
15
16
 
@@ -26,20 +27,60 @@ from iris_cli.framework_test import (
26
27
  console = Console()
27
28
 
28
29
 
30
+ def _evaluate_custom_rule(rule: ComplianceRule, passport: AgentPassport) -> str:
31
+ safe_globals = {"__builtins__": {}}
32
+ safe_locals = {
33
+ "passport": passport,
34
+ "hitl_config": getattr(passport, "hitl_config", None),
35
+ "cost_config": getattr(passport, "cost_config", None),
36
+ "bool": bool,
37
+ "len": len,
38
+ }
39
+ try:
40
+ value = eval(rule.check_expression, safe_globals, safe_locals)
41
+ except Exception:
42
+ return "FAIL"
43
+ return "PASS" if value else "FAIL"
44
+
45
+
46
+ def _rule_source_label(loader: DynamicBundleLoader) -> str:
47
+ info = loader.registry_info()
48
+ if info.source == "live":
49
+ return "Live registry"
50
+ if info.source == "cache":
51
+ hours = info.cache_age_hours
52
+ if hours is not None and hours < 1:
53
+ return "Live registry (updated recently)"
54
+ if hours is not None:
55
+ return f"Live registry (updated {int(hours)} hours ago)"
56
+ return "Cached registry"
57
+ return "Bundled fallback"
58
+
59
+
29
60
  def _render_certification_header(
30
61
  framework: str,
31
62
  agent_name: str,
32
63
  result,
64
+ *,
65
+ loader: DynamicBundleLoader,
66
+ custom_rule_count: int,
33
67
  ) -> None:
68
+ bundle = loader.load_bundle(framework)
69
+ info = loader.registry_info()
34
70
  framework_label = _framework_name(framework)
35
71
  if framework == "colorado-ai-act":
36
72
  framework_label = "Colorado AI Act (SB 26-189)"
37
73
 
74
+ version = bundle.metadata.get("current_version", info.registry_version)
75
+ law_name = bundle.metadata.get("law_name", framework_label)
76
+
38
77
  console.print(Panel(
39
- f"Agent: {agent_name}\n"
40
- f"Framework: {framework_label}\n"
41
- f"Generated: {datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ')}\n"
42
- f"Attested: IRIS · Commit: local",
78
+ f"Agent: {agent_name}\n"
79
+ f"Framework: {law_name} v{version}\n"
80
+ f"Rule source: {_rule_source_label(loader)}\n"
81
+ f"Custom rules: {custom_rule_count} organization rule{'s' if custom_rule_count != 1 else ''} evaluated\n"
82
+ f"Generated: {datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ')}\n"
83
+ f"Attested: IRIS · Commit: local",
43
84
  title=f"IRIS Certification — {framework}",
44
85
  style="blue",
45
86
  ))
@@ -63,25 +104,72 @@ def _render_certification_header(
63
104
  )
64
105
 
65
106
 
107
+ def _render_custom_rules_section(
108
+ custom_rules: list[ComplianceRule],
109
+ passport: AgentPassport,
110
+ ) -> None:
111
+ if not custom_rules:
112
+ return
113
+ console.print("\n[bold]ORGANIZATION POLICY[/bold]")
114
+ console.print("─" * 65)
115
+ for rule in custom_rules:
116
+ status = _evaluate_custom_rule(rule, passport)
117
+ icon = "[green]✓[/green]" if status == "PASS" else "[red]✗[/red]"
118
+ console.print(f"{icon} {rule.rule_id:<14} {rule.name}")
119
+ if status != "PASS" and rule.remediation_command:
120
+ console.print(f" Fix: {rule.remediation_command}")
121
+
122
+
66
123
  @click.command("certify")
67
124
  @click.option(
68
125
  "--framework",
69
126
  required=True,
70
- type=click.Choice(sorted(["colorado-ai-act", "nist-ai-rmf", "fedramp-moderate", "hipaa", "soc2", "gdpr"])),
127
+ type=click.Choice(sorted([
128
+ "colorado-ai-act", "nist-ai-rmf", "fedramp-moderate", "hipaa", "soc2", "gdpr",
129
+ "nyc-ll144", "illinois-ai-video", "eu-ai-act", "ccpa-admt", "china-pipl",
130
+ ])),
71
131
  )
72
132
  @click.option("--agent", "agent_name", required=True, help="Agent name under governance/agents")
73
133
  @click.option("--format", "output_format", default="table", type=click.Choice(["table", "json", "markdown"]))
74
- def certify_cmd(framework: str, agent_name: str, output_format: str) -> None:
134
+ @click.option(
135
+ "--registry-version",
136
+ default=None,
137
+ help="Pin to a specific registry version for reproducible certifications",
138
+ )
139
+ @click.option("--dir", "governance_dir", type=click.Path(path_type=Path), default=None)
140
+ @click.option("--offline", is_flag=True, help="Use bundled registry only (no network refresh)")
141
+ def certify_cmd(
142
+ framework: str,
143
+ agent_name: str,
144
+ output_format: str,
145
+ registry_version: Optional[str],
146
+ governance_dir: Optional[Path],
147
+ offline: bool,
148
+ ) -> None:
75
149
  """
76
150
  Certify compliance readiness against a regulatory framework.
77
151
 
78
152
  Alias: iris test
79
153
  """
80
- passport_path = Path.cwd() / "governance" / "agents" / agent_name / "passport.yaml"
154
+ gov_dir = governance_dir or Path.cwd() / "governance"
155
+ passport_path = gov_dir / "agents" / agent_name / "passport.yaml"
81
156
  if not passport_path.exists():
82
157
  raise click.ClickException(f"Passport not found: {passport_path}")
83
158
  passport = AgentPassport.from_yaml(passport_path.read_text())
84
159
 
160
+ loader = DynamicBundleLoader(pinned_version=registry_version)
161
+
162
+ if not offline and not registry_version:
163
+ if not loader.is_cache_fresh():
164
+ console.print("[dim]Checking for regulatory updates...[/dim]")
165
+ updated = loader.refresh_registry()
166
+ if updated:
167
+ console.print("[green]✓ Regulatory intelligence updated[/green]")
168
+ console.print("[dim] Run: iris regulatory check for change summary[/dim]")
169
+
170
+ custom_rules = loader.load_custom_rules(gov_dir)
171
+ loader.get_effective_rules(framework, gov_dir)
172
+
85
173
  ents = Entitlements()
86
174
  has_pro = ents.has(Feature.CLI_TEST_FULL_REPORT)
87
175
 
@@ -97,13 +185,22 @@ def certify_cmd(framework: str, agent_name: str, output_format: str) -> None:
97
185
  elif output_format == "markdown":
98
186
  click.echo(_render_markdown(result, has_pro))
99
187
  else:
100
- _render_certification_header(framework, agent_name, result)
188
+ _render_certification_header(
189
+ framework, agent_name, result,
190
+ loader=loader,
191
+ custom_rule_count=len(custom_rules),
192
+ )
101
193
  _render_table(result, has_pro)
102
- _render_response_configuration(framework, passport)
194
+ _render_custom_rules_section(custom_rules, passport)
195
+ _render_response_configuration(framework, passport, loader=loader)
103
196
 
104
197
 
105
- def _render_response_configuration(framework: str, passport: AgentPassport) -> None:
106
- from iris_core.compliance.framework_check import load_bundle_data
198
+ def _render_response_configuration(
199
+ framework: str,
200
+ passport: AgentPassport,
201
+ *,
202
+ loader: Optional[DynamicBundleLoader] = None,
203
+ ) -> None:
107
204
  from iris_core.compliance.violation_response import (
108
205
  get_effective_response,
109
206
  rule_response_label,
@@ -111,7 +208,11 @@ def _render_response_configuration(framework: str, passport: AgentPassport) -> N
111
208
  )
112
209
 
113
210
  try:
114
- bundle = load_bundle_data(framework)
211
+ if loader:
212
+ bundle = loader.load_bundle(framework).to_dict()
213
+ else:
214
+ from iris_core.compliance.framework_check import load_bundle_data
215
+ bundle = load_bundle_data(framework)
115
216
  except ValueError:
116
217
  return
117
218
  rules = bundle.get("rules", [])
@@ -131,7 +232,7 @@ def _render_response_configuration(framework: str, passport: AgentPassport) -> N
131
232
  if base == ViolationResponse.BLOCK:
132
233
  line += " (unconditional — cannot be overridden)"
133
234
  elif effective != default:
134
- line += f" (override active)"
235
+ line += " (override active)"
135
236
  else:
136
237
  line += " (default)"
137
238
  console.print(line)
@@ -44,6 +44,25 @@ CONVERSATIONAL_KEYWORDS = (
44
44
  "chat bot",
45
45
  )
46
46
 
47
+ EMPLOYMENT_KEYWORDS = (
48
+ "hiring",
49
+ "recruiting",
50
+ "recruitment",
51
+ "hr",
52
+ "ats",
53
+ "screening",
54
+ "employment",
55
+ "interview",
56
+ "resume",
57
+ "candidate",
58
+ )
59
+
60
+ VIDEO_KEYWORDS = (
61
+ "video",
62
+ "interview",
63
+ "biometric",
64
+ )
65
+
47
66
  Q1_CHOICES = [
48
67
  "Makes decisions that affect individual people (hiring, loans, medical, etc.)",
49
68
  "Automates business processes (summarization, classification, routing)",
@@ -267,6 +286,48 @@ def build_recommendations(answers: dict[str, Any]) -> list[Recommendation]:
267
286
  soc2 = q2 == Q2_CHOICES[5] or "SOC 2 (SaaS / enterprise)" in q7
268
287
  gdpr = "Outside the US" in q8 or "Other / multiple states" in q8
269
288
 
289
+ ccpa_admt = (
290
+ "California" in q8
291
+ and q5
292
+ and (
293
+ q1 == Q1_CHOICES[0]
294
+ or q2 in {Q2_CHOICES[2], Q2_CHOICES[3]}
295
+ )
296
+ )
297
+ china_pipl = (
298
+ "Outside the US" in q8
299
+ or "china" in agent_description
300
+ or "asia" in agent_description
301
+ or (q2 == Q2_CHOICES[4] and "Outside the US" in q8)
302
+ )
303
+
304
+ employment_domain = (
305
+ q1 == Q1_CHOICES[0]
306
+ or any(kw in q1.lower() for kw in EMPLOYMENT_KEYWORDS)
307
+ or any(kw in agent_description for kw in EMPLOYMENT_KEYWORDS)
308
+ or q2 in {Q2_CHOICES[4], Q2_CHOICES[6]}
309
+ )
310
+ illinois_video = (
311
+ employment_domain
312
+ and (
313
+ "Illinois" in q8
314
+ or "Other / multiple states" in q8
315
+ )
316
+ and (
317
+ any(kw in agent_description for kw in VIDEO_KEYWORDS)
318
+ or q4 == Q4_CHOICES[3]
319
+ or "video" in q1.lower()
320
+ or "interview" in q1.lower()
321
+ )
322
+ )
323
+ nyc_ll144 = (
324
+ employment_domain
325
+ and (
326
+ "New York" in q8
327
+ or "Other / multiple states" in q8
328
+ )
329
+ )
330
+
270
331
  colorado_reason = (
271
332
  "Your agent makes consequential decisions for Colorado users. "
272
333
  "SB 26-189 applies (replaces SB 24-205, effective Jan. 1, 2027). "
@@ -378,6 +439,62 @@ def build_recommendations(answers: dict[str, Any]) -> list[Recommendation]:
378
439
  ),
379
440
  command="iris test --framework gdpr" if gdpr else None,
380
441
  ),
442
+ Recommendation(
443
+ framework="ccpa-admt",
444
+ tier="PRO",
445
+ status="REQUIRED" if ccpa_admt else "NOT APPLICABLE",
446
+ reason=(
447
+ "California ADMT regulations (effective Jan. 1, 2026) apply to "
448
+ "automated decisions affecting California consumers in employment, "
449
+ "credit, healthcare, housing, or education."
450
+ if ccpa_admt
451
+ else "No California ADMT scope detected."
452
+ ),
453
+ command="iris compliance check --framework ccpa-admt" if ccpa_admt else None,
454
+ ),
455
+ Recommendation(
456
+ framework="china-pipl",
457
+ tier="PRO",
458
+ status="REQUIRED" if china_pipl else "NOT APPLICABLE",
459
+ reason=(
460
+ "China PIPL applies when processing personal information of "
461
+ "individuals located in China, including automated decision-making "
462
+ "and cross-border transfer restrictions."
463
+ if china_pipl
464
+ else "No China or Asia-Pacific user footprint detected."
465
+ ),
466
+ command="iris compliance check --framework china-pipl" if china_pipl else None,
467
+ ),
468
+ Recommendation(
469
+ framework="illinois-ai-video",
470
+ tier="PRO",
471
+ status="REQUIRED" if illinois_video else "NOT APPLICABLE",
472
+ reason=(
473
+ "Illinois AI Video Interview Act applies to AI analysis of video "
474
+ "interviews for Illinois-based positions. Consent must be logged "
475
+ "before any video analysis (820 ILCS 42)."
476
+ if illinois_video
477
+ else "No Illinois video interview AI scope detected."
478
+ ),
479
+ command=(
480
+ "iris compliance check --framework illinois-ai-video"
481
+ if illinois_video
482
+ else None
483
+ ),
484
+ ),
485
+ Recommendation(
486
+ framework="nyc-ll144",
487
+ tier="PRO",
488
+ status="REQUIRED" if nyc_ll144 else "NOT APPLICABLE",
489
+ reason=(
490
+ "NYC Local Law 144 requires annual independent bias audits, public "
491
+ "disclosure, and candidate notice before using Automated Employment "
492
+ "Decision Tools (AEDTs) for NYC hiring."
493
+ if nyc_ll144
494
+ else "No NYC AEDT hiring scope detected."
495
+ ),
496
+ command="iris compliance check --framework nyc-ll144" if nyc_ll144 else None,
497
+ ),
381
498
  ]
382
499
  return recommendations
383
500
 
iris_cli/main.py CHANGED
@@ -24,7 +24,7 @@ console = Console()
24
24
 
25
25
 
26
26
  @click.group()
27
- @click.version_option(version="0.2.0", prog_name="iris")
27
+ @click.version_option(version="0.2.4", prog_name="iris")
28
28
  def cli():
29
29
  """
30
30
  IRIS — Policy as Code for AI Agents
iris_cli/regulatory.py CHANGED
@@ -50,6 +50,41 @@ def _format_effective_date(iso_date: str) -> str:
50
50
  return iso_date
51
51
 
52
52
 
53
+ def _render_rule_changes(bundle_id: str, old_version: str, new_version: str) -> None:
54
+ """Show rule-level changes when registry versions differ."""
55
+ import json
56
+
57
+ from iris_core.compliance.dynamic_loader import DynamicBundleLoader, _bundled_registry_path
58
+
59
+ loader = DynamicBundleLoader()
60
+ cache_path = Path.home() / ".iris" / "registry-cache.json"
61
+ bundled = _bundled_registry_path()
62
+
63
+ old_registry: dict = {}
64
+ if cache_path.exists():
65
+ try:
66
+ old_registry = json.loads(cache_path.read_text())
67
+ except Exception:
68
+ pass
69
+ elif bundled.exists():
70
+ old_registry = json.loads(bundled.read_text())
71
+
72
+ if not bundled.exists():
73
+ return
74
+ new_registry = json.loads(bundled.read_text())
75
+ changes = loader.diff_rules(bundle_id, old_registry, new_registry)
76
+ if not changes:
77
+ return
78
+
79
+ console.print(f"\n [bold]REGULATORY UPDATE — {bundle_id} v{old_version} → v{new_version}[/bold]")
80
+ console.print(" [bold]RULE CHANGES:[/bold]")
81
+ for change in changes[:10]:
82
+ console.print(f" ● {change}")
83
+ console.print(
84
+ "\n Run: [bold]iris certify --agent <name>[/bold] to see updated status"
85
+ )
86
+
87
+
53
88
  def _render_check_output(
54
89
  tracker: RegulatoryTracker,
55
90
  updates: list,
@@ -101,6 +136,7 @@ def _render_check_output(
101
136
  console.print(
102
137
  f"Effective: {_format_effective_date(update.effective_date)}"
103
138
  )
139
+ _render_rule_changes(update.bundle_id, update.current_installed_version, update.available_version)
104
140
  console.print(" Action required:")
105
141
  console.print(
106
142
  " 1. Run: [bold]pip install --upgrade iris-security-sdk[/bold]"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: iris-security-cli
3
- Version: 0.2.0
3
+ Version: 0.2.4
4
4
  Summary: IRIS CLI — declare, compile, preview, enforce, witness, certify, sentinel
5
5
  License: Apache-2.0
6
6
  Project-URL: Homepage, https://github.com/gimartinb/iris-sdk
@@ -15,13 +15,13 @@ Classifier: Programming Language :: Python :: 3.11
15
15
  Classifier: Programming Language :: Python :: 3.12
16
16
  Requires-Python: >=3.10
17
17
  Description-Content-Type: text/markdown
18
- Requires-Dist: iris-security-core>=0.1.8
19
- Requires-Dist: iris-security-sdk>=0.2.0
18
+ Requires-Dist: iris-security-core>=0.1.11
19
+ Requires-Dist: iris-security-sdk>=0.2.4
20
20
  Requires-Dist: click>=8.1
21
21
  Requires-Dist: rich>=13.0
22
22
  Requires-Dist: pyyaml>=6.0
23
23
  Provides-Extra: scm
24
- Requires-Dist: iris-security-scm[all]>=0.1.1; extra == "scm"
24
+ Requires-Dist: iris-security-scm[all]>=0.2.0; extra == "scm"
25
25
 
26
26
  # iris-security-cli
27
27
 
@@ -2,7 +2,7 @@ iris_cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  iris_cli/action_plan.py,sha256=qSI9ZusJcfZKDXMeQhUJgTECwS4CP1dvXeuogWBpUlQ,11147
3
3
  iris_cli/assess.py,sha256=ZXcjRr7FT4vPLe_xC76c4WHQGbPzLDzeP0RAh3P9j20,19182
4
4
  iris_cli/cedar_parser.py,sha256=3V1t-L3cSBCAMDmCkzcoBDA6S4ulg5LKpWDN2fU_jbM,15161
5
- iris_cli/certify.py,sha256=lW49-UIBKp-uIcQchR7imWLPn-8iO88WfVql12xk76o,5433
5
+ iris_cli/certify.py,sha256=aVUXI_TkX-gTs0TaIp9EvhEOYxbDxNC0tiFtdzsYVv4,9069
6
6
  iris_cli/compiler_config.py,sha256=9SX2IkkWWc2R5vx_QBd7L4veKfLx2KSk2XzXm53tNS8,2083
7
7
  iris_cli/compliance_check_cmd.py,sha256=N8N-01X8eACmoxM7uEyi-whtXKPkDxAgJ75Podpco9A,6803
8
8
  iris_cli/compliance_fix.py,sha256=8zs_GR9R7U93KncDcTUBSsyeyk75ExSm-tocgRbCcC4,6545
@@ -15,11 +15,11 @@ iris_cli/enforce.py,sha256=GX0vKT5FQPi8HoBB6PMYiBiIeLHgYg5J8wh6EKZqJuY,5911
15
15
  iris_cli/entitlements_cmd.py,sha256=lgwFP-uv3JC6lAT9J9EK3xUd_5rYPp7kjcQfzCCjRDM,426
16
16
  iris_cli/evidence.py,sha256=H4uq_o0RAGHkmqLO20D9JNXKYGT6V9uLqvuxxeKm1Iw,29814
17
17
  iris_cli/explain.py,sha256=ShtQsTDFm8BntufsLLyleAHI1sjmI0lUFh23OwwYvx0,2708
18
- iris_cli/framework_suggest.py,sha256=Ez3I_a-SDr4O399WAocm1QV-Fx-0ttcxDPousYAgg5M,19199
18
+ iris_cli/framework_suggest.py,sha256=B9DObZXk10ccf2_KMLIuUN5raqSh7RWTngsBKvKADHk,23090
19
19
  iris_cli/framework_test.py,sha256=0WCzuJScXJHO2Gh58Gv0mB0kat2F0_vMMaVOQveyk-M,22200
20
20
  iris_cli/hitl.py,sha256=vN_aEsoi7qMTc7ZqgnZvnXm1amZZqxim5zrDHX_GJVQ,11672
21
21
  iris_cli/license_cmd.py,sha256=fq5lnxAuyU13VMRDNr-afQA7LoeBKKL9Wem_adOelaY,5649
22
- iris_cli/main.py,sha256=mxy3zub-oFzNqlAufSVB80Afb3G7qOwnxjm8xGWZlzs,18625
22
+ iris_cli/main.py,sha256=ExpdhEtgjDyjFpScZjU1jZZLBSoztk3CLW7m3Wg0FbA,18625
23
23
  iris_cli/mcp_server.py,sha256=Cpwtdy94NzTJqiCrM_4YUdyi-_-Dti_4d-2AXQCor7g,20815
24
24
  iris_cli/models_cmd.py,sha256=D44ajAzIg5TodKvWvpcbzegKEDKn-JGLeugeok_FuiU,4767
25
25
  iris_cli/policy_cache.py,sha256=cSqbbvSwFfQU3JnD8EWxQ0dW8sOcHYfTEXVpMkre87U,3456
@@ -27,7 +27,7 @@ iris_cli/policy_diff.py,sha256=CymsDBeWJ30WonIzhTtWcA03mcW6v9UA-6VFh1fpByc,15945
27
27
  iris_cli/preview.py,sha256=nIeHdK3pFMRe8ydCSS3Kh_Y-NN274td_-NbXQB0O5QU,4238
28
28
  iris_cli/quickstart.py,sha256=Vvz6pn78MvR29ykw1Dh5e4tdPjku9RVzhi_X2TOqMPM,13428
29
29
  iris_cli/redteam.py,sha256=Ao1V510_y0qYMJXS-xDN62jxldxZDc8Pg7yWopC4GFg,6087
30
- iris_cli/regulatory.py,sha256=iCN7WYiiumi1ARht96mGIaTv-LkLaCBSWGRz7uRK9DQ,12111
30
+ iris_cli/regulatory.py,sha256=uk5xyELgwFB8WMqn8hXGReRJbImGNsIGzZWbWMGcDT0,13431
31
31
  iris_cli/scan_govern.py,sha256=YPfWwcj0kgVFI4s9mMllKMYzSmjQjkkTOMbJB069BYQ,11466
32
32
  iris_cli/scan_report.py,sha256=myYuvF6rfUxJFDHWi-iErB17-QbHbfwzUleXt6MU0uo,5097
33
33
  iris_cli/scm.py,sha256=ubqaH7EKmVKDhSGxZDL0KOU_cMfrpObVXDyC9HuQGho,11960
@@ -46,8 +46,8 @@ tests/test_mcp_model_governance.py,sha256=_-WFjm9i4ZzVYuaKVb76dOHiLLgiBA1zkFxs81
46
46
  tests/test_policy_diff.py,sha256=338L3eb6BKiUAixan_TGSCSGFkUEw74F12RxH2rHxLo,8052
47
47
  tests/test_quickstart.py,sha256=2Iumgg4r2Hy-2K3RhvahrqycVDPaDv3REUDx0rnmQQ8,2969
48
48
  tests/test_vocabulary.py,sha256=qu5Wh1Y27hV-vCF8pdQ-41VQCOPr7PlK5YWERQquXXQ,13204
49
- iris_security_cli-0.2.0.dist-info/METADATA,sha256=j7JvrRY0tOFd5hcD0tznH_hPQ_w0k0ZlCagNDfS12rI,1492
50
- iris_security_cli-0.2.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
51
- iris_security_cli-0.2.0.dist-info/entry_points.txt,sha256=MGi5_jQ_DETbkKiZLmgKYNRt6vIXtMQvmwCSU0T7e64,43
52
- iris_security_cli-0.2.0.dist-info/top_level.txt,sha256=OanTp8Sdq_suSs9gfugtQibn3SJ71i-JCSsOfA9CSsg,15
53
- iris_security_cli-0.2.0.dist-info/RECORD,,
49
+ iris_security_cli-0.2.4.dist-info/METADATA,sha256=aUVQYs5hsNoWd3zUy4hQlr5nNgiDqDX8J9s-1yRNRqg,1493
50
+ iris_security_cli-0.2.4.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
51
+ iris_security_cli-0.2.4.dist-info/entry_points.txt,sha256=MGi5_jQ_DETbkKiZLmgKYNRt6vIXtMQvmwCSU0T7e64,43
52
+ iris_security_cli-0.2.4.dist-info/top_level.txt,sha256=OanTp8Sdq_suSs9gfugtQibn3SJ71i-JCSsOfA9CSsg,15
53
+ iris_security_cli-0.2.4.dist-info/RECORD,,