aigis-cli 1.0.0__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.
Files changed (58) hide show
  1. aigis_cli-1.0.0/LICENSE +21 -0
  2. aigis_cli-1.0.0/PKG-INFO +59 -0
  3. aigis_cli-1.0.0/README.md +32 -0
  4. aigis_cli-1.0.0/aigis_cli/SKILL.md +74 -0
  5. aigis_cli-1.0.0/aigis_cli/__init__.py +3 -0
  6. aigis_cli-1.0.0/aigis_cli/annotate.py +45 -0
  7. aigis_cli-1.0.0/aigis_cli/classify.py +192 -0
  8. aigis_cli-1.0.0/aigis_cli/cli.py +280 -0
  9. aigis_cli-1.0.0/aigis_cli/content/implement/audit-logging.md +171 -0
  10. aigis_cli-1.0.0/aigis_cli/content/implement/bias-monitoring.md +172 -0
  11. aigis_cli-1.0.0/aigis_cli/content/implement/confidence-scoring.md +180 -0
  12. aigis_cli-1.0.0/aigis_cli/content/implement/data-integrity.md +257 -0
  13. aigis_cli-1.0.0/aigis_cli/content/implement/explainability.md +174 -0
  14. aigis_cli-1.0.0/aigis_cli/content/implement/fallback-patterns.md +190 -0
  15. aigis_cli-1.0.0/aigis_cli/content/implement/human-oversight.md +220 -0
  16. aigis_cli-1.0.0/aigis_cli/content/implement/input-validation.md +212 -0
  17. aigis_cli-1.0.0/aigis_cli/content/implement/monitoring.md +207 -0
  18. aigis_cli-1.0.0/aigis_cli/content/implement/output-sanitization.md +183 -0
  19. aigis_cli-1.0.0/aigis_cli/content/implement/pii-handling.md +207 -0
  20. aigis_cli-1.0.0/aigis_cli/content/implement/prompt-security.md +153 -0
  21. aigis_cli-1.0.0/aigis_cli/content/implement/rag-security.md +230 -0
  22. aigis_cli-1.0.0/aigis_cli/content/implement/rate-limiting.md +217 -0
  23. aigis_cli-1.0.0/aigis_cli/content/implement/supply-chain.md +193 -0
  24. aigis_cli-1.0.0/aigis_cli/content/index/audit-scan.md +403 -0
  25. aigis_cli-1.0.0/aigis_cli/content/index/frameworks.md +82 -0
  26. aigis_cli-1.0.0/aigis_cli/content/index/guardrails.json +23 -0
  27. aigis_cli-1.0.0/aigis_cli/content/index/taxonomy.md +81 -0
  28. aigis_cli-1.0.0/aigis_cli/content/templates/ai-impact-assessment.md +54 -0
  29. aigis_cli-1.0.0/aigis_cli/content/templates/intended-purpose-doc.md +39 -0
  30. aigis_cli-1.0.0/aigis_cli/content/templates/risk-characterization.md +34 -0
  31. aigis_cli-1.0.0/aigis_cli/content/templates/third-party-assessment.md +41 -0
  32. aigis_cli-1.0.0/aigis_cli/content/verify/checklist-audit-logging.md +13 -0
  33. aigis_cli-1.0.0/aigis_cli/content/verify/checklist-bias-monitoring.md +13 -0
  34. aigis_cli-1.0.0/aigis_cli/content/verify/checklist-confidence-scoring.md +13 -0
  35. aigis_cli-1.0.0/aigis_cli/content/verify/checklist-data-integrity.md +12 -0
  36. aigis_cli-1.0.0/aigis_cli/content/verify/checklist-explainability.md +13 -0
  37. aigis_cli-1.0.0/aigis_cli/content/verify/checklist-fallback-patterns.md +13 -0
  38. aigis_cli-1.0.0/aigis_cli/content/verify/checklist-human-oversight.md +14 -0
  39. aigis_cli-1.0.0/aigis_cli/content/verify/checklist-input-validation.md +16 -0
  40. aigis_cli-1.0.0/aigis_cli/content/verify/checklist-monitoring.md +13 -0
  41. aigis_cli-1.0.0/aigis_cli/content/verify/checklist-output-sanitization.md +14 -0
  42. aigis_cli-1.0.0/aigis_cli/content/verify/checklist-pii-handling.md +14 -0
  43. aigis_cli-1.0.0/aigis_cli/content/verify/checklist-prompt-security.md +13 -0
  44. aigis_cli-1.0.0/aigis_cli/content/verify/checklist-rag-security.md +12 -0
  45. aigis_cli-1.0.0/aigis_cli/content/verify/checklist-rate-limiting.md +13 -0
  46. aigis_cli-1.0.0/aigis_cli/content/verify/checklist-supply-chain.md +13 -0
  47. aigis_cli-1.0.0/aigis_cli/fetch.py +99 -0
  48. aigis_cli-1.0.0/aigis_cli/init_ide.py +107 -0
  49. aigis_cli-1.0.0/aigis_cli/keywords.py +136 -0
  50. aigis_cli-1.0.0/aigis_cli/search.py +69 -0
  51. aigis_cli-1.0.0/aigis_cli.egg-info/PKG-INFO +59 -0
  52. aigis_cli-1.0.0/aigis_cli.egg-info/SOURCES.txt +56 -0
  53. aigis_cli-1.0.0/aigis_cli.egg-info/dependency_links.txt +1 -0
  54. aigis_cli-1.0.0/aigis_cli.egg-info/entry_points.txt +2 -0
  55. aigis_cli-1.0.0/aigis_cli.egg-info/requires.txt +6 -0
  56. aigis_cli-1.0.0/aigis_cli.egg-info/top_level.txt +1 -0
  57. aigis_cli-1.0.0/pyproject.toml +49 -0
  58. aigis_cli-1.0.0/setup.cfg +4 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Nayan Kanaparthi
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,59 @@
1
+ Metadata-Version: 2.4
2
+ Name: aigis-cli
3
+ Version: 1.0.0
4
+ Summary: AI governance guardrails for coding agents. Framework-aligned security and compliance patterns from NIST AI RMF, OWASP Top 10 for LLMs, and ISO/IEC 42001.
5
+ License-Expression: MIT
6
+ Project-URL: Homepage, https://github.com/NayanKanaparthi/aigis
7
+ Project-URL: Repository, https://github.com/NayanKanaparthi/aigis
8
+ Keywords: ai,governance,security,compliance,llm,owasp,nist,iso42001,guardrails,coding-agent
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.9
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Topic :: Security
17
+ Classifier: Topic :: Software Development :: Quality Assurance
18
+ Requires-Python: >=3.9
19
+ Description-Content-Type: text/markdown
20
+ License-File: LICENSE
21
+ Requires-Dist: click>=8.0
22
+ Requires-Dist: rich>=13.0
23
+ Requires-Dist: python-frontmatter>=1.0
24
+ Provides-Extra: dev
25
+ Requires-Dist: build>=1.0; extra == "dev"
26
+ Dynamic: license-file
27
+
28
+ # aigis-cli (Python)
29
+
30
+ AI governance guardrails for coding agents. Python port of the [@aigis-ai/cli](https://www.npmjs.com/package/@aigis-ai/cli) npm package.
31
+
32
+ Curated, agent-consumable security and compliance patterns from NIST AI RMF, OWASP Top 10 for LLMs, and ISO/IEC 42001.
33
+
34
+ ## Install
35
+
36
+ ```bash
37
+ pip install aigis-cli
38
+ ```
39
+
40
+ ## Quick start
41
+
42
+ ```bash
43
+ aigis classify --traits uses-llm,processes-pii,accepts-user-input
44
+ aigis get input-validation pii-handling
45
+ aigis verify input-validation pii-handling
46
+ aigis template ai-impact-assessment
47
+ aigis audit --scan
48
+ aigis search pii
49
+ aigis traits
50
+ aigis init cursor
51
+ ```
52
+
53
+ ## Documentation
54
+
55
+ See the full documentation at [github.com/NayanKanaparthi/aigis](https://github.com/NayanKanaparthi/aigis).
56
+
57
+ ## License
58
+
59
+ [MIT](LICENSE)
@@ -0,0 +1,32 @@
1
+ # aigis-cli (Python)
2
+
3
+ AI governance guardrails for coding agents. Python port of the [@aigis-ai/cli](https://www.npmjs.com/package/@aigis-ai/cli) npm package.
4
+
5
+ Curated, agent-consumable security and compliance patterns from NIST AI RMF, OWASP Top 10 for LLMs, and ISO/IEC 42001.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ pip install aigis-cli
11
+ ```
12
+
13
+ ## Quick start
14
+
15
+ ```bash
16
+ aigis classify --traits uses-llm,processes-pii,accepts-user-input
17
+ aigis get input-validation pii-handling
18
+ aigis verify input-validation pii-handling
19
+ aigis template ai-impact-assessment
20
+ aigis audit --scan
21
+ aigis search pii
22
+ aigis traits
23
+ aigis init cursor
24
+ ```
25
+
26
+ ## Documentation
27
+
28
+ See the full documentation at [github.com/NayanKanaparthi/aigis](https://github.com/NayanKanaparthi/aigis).
29
+
30
+ ## License
31
+
32
+ [MIT](LICENSE)
@@ -0,0 +1,74 @@
1
+ ---
2
+ name: aigis
3
+ description: AI governance skill for coding agents. Provides framework-aligned security and compliance patterns from NIST AI RMF, OWASP Top 10 for LLMs, and ISO/IEC 42001. Use before building any AI/LLM feature or when auditing existing AI systems.
4
+ ---
5
+
6
+ # Aigis — AI Governance Skill
7
+
8
+ Use the aigis CLI for governance patterns when building or auditing AI/LLM features.
9
+
10
+ ## Quick start — new feature
11
+ \`\`\`bash
12
+ # 1. Classify your system to get relevant controls
13
+ aigis classify --traits uses-llm,accepts-user-input,processes-pii,is-external --json
14
+
15
+ # 2. Fetch implementation patterns for each recommended file
16
+ aigis get input-validation pii-handling prompt-security audit-logging
17
+
18
+ # 3. Write code applying the patterns from the fetched files
19
+
20
+ # 4. After writing code, run verification
21
+ aigis verify input-validation pii-handling prompt-security audit-logging
22
+
23
+ # 5. If risk tier is HIGH or MEDIUM, generate compliance docs
24
+ aigis template ai-impact-assessment intended-purpose-doc
25
+ \`\`\`
26
+
27
+ ## Quick start — audit existing project
28
+ \`\`\`bash
29
+ # 1. Get the structured audit scan prompt
30
+ aigis audit --scan
31
+
32
+ # 2. Follow the scan instructions: inventory the project, detect traits, classify
33
+
34
+ # 3. Run the full audit with detected traits
35
+ aigis audit --traits uses-llm,processes-pii,is-external
36
+
37
+ # 4. Evaluate existing code against each check, produce gap report
38
+ \`\`\`
39
+
40
+ ## When to use
41
+ - Before writing any LLM API call or AI feature (new code)
42
+ - When auditing an existing AI system for governance gaps (existing code)
43
+ - Before processing any sensitive data through an AI system
44
+ - Before deploying any AI feature to production
45
+ - When onboarding to a new AI project to understand what controls exist
46
+
47
+ ## Commands
48
+ - \`aigis classify --traits <comma-separated>\` — get risk tier and relevant files
49
+ - \`aigis classify "<description>"\` — same, using natural language (keyword matching)
50
+ - \`aigis get <file-id> [file-id...]\` — fetch implementation patterns (one or more)
51
+ - \`aigis get <file-id> --lang py|js\` — fetch filtered to one language
52
+ - \`aigis verify <file-id> [file-id...]\` — fetch verification checklists
53
+ - \`aigis template <template-id> [template-id...]\` — fetch compliance documentation templates
54
+ - \`aigis audit --scan\` — get structured audit prompt for scanning existing codebases
55
+ - \`aigis audit --traits <comma-separated>\` — get bundled classification + all checklists for audit
56
+ - \`aigis search <query>\` — search across all content by keyword or control ID
57
+ - \`aigis search --list\` — list all available files
58
+ - \`aigis annotate <file-id> "<note>"\` — attach a local note for future sessions
59
+ - \`aigis annotate --list\` — list all annotations
60
+ - \`aigis init cursor|claude-code|windsurf|copilot\` — set up aigis for your IDE
61
+
62
+ ## Available traits (22)
63
+ AI architecture: uses-llm, uses-rag, uses-finetuned, uses-thirdparty-api, is-agentic, is-multimodal
64
+ Data sensitivity: processes-pii, handles-financial, handles-health, handles-proprietary, handles-minors
65
+ Impact scope: influences-decisions, accepts-user-input, is-external, is-internal, is-high-volume
66
+ Output type: generates-code, generates-content, multi-model-pipeline
67
+ Jurisdiction: jurisdiction-eu, jurisdiction-us-regulated, jurisdiction-global
68
+
69
+ ## Integration
70
+ - Claude Code: place this file in ~/.claude/skills/aigis/SKILL.md
71
+ - Cursor: run \`aigis init cursor\` in your project root
72
+ - Windsurf: run \`aigis init windsurf\` in your project root
73
+ - GitHub Copilot: run \`aigis init copilot\` in your project root
74
+ - Any agent: include aigis usage instructions in system prompt
@@ -0,0 +1,3 @@
1
+ """aigis-cli: AI governance guardrails for coding agents."""
2
+
3
+ __version__ = "1.0.0"
@@ -0,0 +1,45 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ from datetime import date
5
+ from pathlib import Path
6
+
7
+ AIGIS_DIR = Path.home() / ".aigis"
8
+ ANNOTATIONS_FILE = AIGIS_DIR / "annotations.json"
9
+
10
+
11
+ def _load_annotations() -> dict:
12
+ if not ANNOTATIONS_FILE.exists():
13
+ return {}
14
+ try:
15
+ return json.loads(ANNOTATIONS_FILE.read_text(encoding="utf-8"))
16
+ except (json.JSONDecodeError, OSError):
17
+ return {}
18
+
19
+
20
+ def _save_annotations(data: dict) -> None:
21
+ AIGIS_DIR.mkdir(parents=True, exist_ok=True)
22
+ ANNOTATIONS_FILE.write_text(json.dumps(data, indent=2), encoding="utf-8")
23
+
24
+
25
+ def annotate(file_id: str, note: str) -> None:
26
+ data = _load_annotations()
27
+ data.setdefault(file_id, []).append({
28
+ "note": note,
29
+ "date": date.today().isoformat(),
30
+ })
31
+ _save_annotations(data)
32
+
33
+
34
+ def get_annotations(file_id: str) -> list[dict]:
35
+ return _load_annotations().get(file_id, [])
36
+
37
+
38
+ def list_annotations() -> dict:
39
+ return _load_annotations()
40
+
41
+
42
+ def clear_annotation(file_id: str) -> None:
43
+ data = _load_annotations()
44
+ data.pop(file_id, None)
45
+ _save_annotations(data)
@@ -0,0 +1,192 @@
1
+ from __future__ import annotations
2
+
3
+ ALL_TRAITS = [
4
+ "uses-llm", "uses-rag", "uses-finetuned", "uses-thirdparty-api", "is-agentic", "is-multimodal",
5
+ "processes-pii", "handles-financial", "handles-health", "handles-proprietary", "handles-minors",
6
+ "influences-decisions", "accepts-user-input", "is-external", "is-internal", "is-high-volume",
7
+ "generates-code", "generates-content", "multi-model-pipeline",
8
+ "jurisdiction-eu", "jurisdiction-us-regulated", "jurisdiction-global",
9
+ ]
10
+
11
+ TRAIT_FILES: dict[str, list[str]] = {
12
+ "uses-llm": ["input-validation", "output-sanitization", "prompt-security", "audit-logging", "monitoring"],
13
+ "uses-rag": ["rag-security", "data-integrity"],
14
+ "uses-finetuned": ["data-integrity", "supply-chain"],
15
+ "uses-thirdparty-api": ["supply-chain"],
16
+ "is-agentic": ["human-oversight", "rate-limiting", "fallback-patterns", "audit-logging"],
17
+ "is-multimodal": ["input-validation", "output-sanitization", "pii-handling"],
18
+ "processes-pii": ["pii-handling", "audit-logging"],
19
+ "handles-financial": ["pii-handling", "audit-logging", "bias-monitoring"],
20
+ "handles-health": ["pii-handling", "audit-logging", "bias-monitoring", "explainability"],
21
+ "handles-proprietary": ["pii-handling", "prompt-security"],
22
+ "handles-minors": ["pii-handling", "bias-monitoring", "human-oversight"],
23
+ "influences-decisions": ["bias-monitoring", "confidence-scoring", "human-oversight", "explainability"],
24
+ "accepts-user-input": ["input-validation", "output-sanitization"],
25
+ "is-external": ["rate-limiting", "confidence-scoring"],
26
+ "is-internal": [],
27
+ "is-high-volume": ["rate-limiting", "monitoring", "fallback-patterns"],
28
+ "generates-code": ["output-sanitization", "human-oversight", "fallback-patterns"],
29
+ "generates-content": ["confidence-scoring", "bias-monitoring", "audit-logging"],
30
+ "multi-model-pipeline": ["audit-logging", "monitoring", "fallback-patterns", "data-integrity"],
31
+ "jurisdiction-eu": [],
32
+ "jurisdiction-us-regulated": [],
33
+ "jurisdiction-global": [],
34
+ }
35
+
36
+ FILE_CONTROLS: dict[str, dict[str, list[str]]] = {
37
+ "input-validation": {"owasp": ["LLM01"], "nist": ["MEASURE-2.7", "MANAGE-1.3"], "iso": ["Clause-8.2", "Annex-A.6"]},
38
+ "output-sanitization": {"owasp": ["LLM05"], "nist": ["MEASURE-2.6", "MEASURE-2.7"], "iso": ["Clause-8.2"]},
39
+ "pii-handling": {"owasp": ["LLM02"], "nist": ["MAP-2.1", "MEASURE-2.10"], "iso": ["Annex-A.7", "Annex-A.4"]},
40
+ "prompt-security": {"owasp": ["LLM07"], "nist": ["MEASURE-2.7", "MEASURE-2.8"], "iso": ["Clause-8.2"]},
41
+ "human-oversight": {"owasp": ["LLM06"], "nist": ["MAP-3.5", "MANAGE-1.3", "MANAGE-4.1"], "iso": ["Annex-A.9", "Clause-8.4"]},
42
+ "supply-chain": {"owasp": ["LLM03"], "nist": ["GOVERN-6.1", "GOVERN-6.2", "MANAGE-3.1", "MANAGE-3.2"], "iso": ["Annex-A.10"]},
43
+ "data-integrity": {"owasp": ["LLM04"], "nist": ["MAP-2.3", "MEASURE-2.6"], "iso": ["Annex-A.7"]},
44
+ "rag-security": {"owasp": ["LLM08"], "nist": ["MEASURE-2.7"], "iso": ["Clause-8.2", "Annex-A.7"]},
45
+ "confidence-scoring": {"owasp": ["LLM09"], "nist": ["MAP-2.2", "MEASURE-2.5", "MEASURE-2.9"], "iso": ["Annex-A.8"]},
46
+ "rate-limiting": {"owasp": ["LLM10"], "nist": ["MEASURE-2.6", "MANAGE-2.4"], "iso": ["Clause-8.2"]},
47
+ "audit-logging": {"owasp": [], "nist": ["MEASURE-2.8", "MANAGE-4.1", "MANAGE-4.3"], "iso": ["Clause-9.1", "Annex-A.6"]},
48
+ "bias-monitoring": {"owasp": [], "nist": ["MAP-2.3", "MEASURE-2.11", "MEASURE-3.1"], "iso": ["Clause-6.1", "Annex-C"]},
49
+ "fallback-patterns": {"owasp": [], "nist": ["MEASURE-2.6", "MANAGE-2.3", "MANAGE-2.4"], "iso": ["Clause-8.2"]},
50
+ "monitoring": {"owasp": [], "nist": ["MEASURE-2.4", "MEASURE-3.1", "MANAGE-4.1", "MANAGE-4.2"], "iso": ["Clause-9.1", "Clause-10"]},
51
+ "explainability": {"owasp": [], "nist": ["MEASURE-2.8", "MEASURE-2.9"], "iso": ["Annex-A.8", "Clause-7.4"]},
52
+ }
53
+
54
+
55
+ def classify(trait_list: list[str]) -> dict:
56
+ ts = set(trait_list)
57
+ warnings: list[str] = []
58
+
59
+ invalid = [t for t in trait_list if t not in ALL_TRAITS]
60
+ if invalid:
61
+ raise ValueError(
62
+ f'Unknown traits: {", ".join(invalid)}. Run "aigis traits" to see available traits.'
63
+ )
64
+
65
+ # Constraint C1: is-internal + is-external
66
+ if "is-internal" in ts and "is-external" in ts:
67
+ warnings.append("Both is-internal and is-external selected. Treating as is-external (stricter).")
68
+ ts.discard("is-internal")
69
+
70
+ # Step 1: trait-based file selection
71
+ files: set[str] = set()
72
+ for t in ts:
73
+ for f in TRAIT_FILES.get(t, []):
74
+ files.add(f)
75
+
76
+ # Step 2: risk tier
77
+ sens_data = bool(
78
+ ts & {"processes-pii", "handles-financial", "handles-health", "handles-proprietary", "handles-minors"}
79
+ )
80
+
81
+ tier = "LOW"
82
+ reason = "no high/medium triggers"
83
+
84
+ if "influences-decisions" in ts:
85
+ tier, reason = "HIGH", "influences-decisions"
86
+ elif "handles-health" in ts:
87
+ tier, reason = "HIGH", "handles-health"
88
+ elif "handles-financial" in ts and "accepts-user-input" in ts:
89
+ tier, reason = "HIGH", "handles-financial + accepts-user-input"
90
+ elif "handles-minors" in ts:
91
+ tier, reason = "HIGH", "handles-minors"
92
+ elif ("jurisdiction-eu" in ts or "jurisdiction-global" in ts) and sens_data:
93
+ tier, reason = "HIGH", "jurisdiction-eu + sensitive data"
94
+ elif "generates-code" in ts and "is-external" in ts:
95
+ tier, reason = "HIGH", "generates-code + is-external"
96
+ elif "generates-code" in ts and "is-agentic" in ts:
97
+ tier, reason = "HIGH", "generates-code + is-agentic"
98
+ elif "processes-pii" in ts:
99
+ tier, reason = "MEDIUM", "processes-pii"
100
+ elif "is-external" in ts:
101
+ tier, reason = "MEDIUM", "is-external"
102
+ elif "is-agentic" in ts:
103
+ tier, reason = "MEDIUM", "is-agentic"
104
+ elif "handles-proprietary" in ts:
105
+ tier, reason = "MEDIUM", "handles-proprietary"
106
+ elif "generates-content" in ts:
107
+ tier, reason = "MEDIUM", "generates-content"
108
+ elif "multi-model-pipeline" in ts:
109
+ tier, reason = "MEDIUM", "multi-model-pipeline"
110
+ elif "jurisdiction-us-regulated" in ts:
111
+ tier, reason = "MEDIUM", "jurisdiction-us-regulated"
112
+ elif "generates-code" in ts:
113
+ tier, reason = "MEDIUM", "generates-code"
114
+
115
+ # Jurisdiction modifier
116
+ if ("jurisdiction-eu" in ts or "jurisdiction-global" in ts) and tier != "HIGH":
117
+ old_tier = tier
118
+ tier = "MEDIUM" if tier == "LOW" else "HIGH"
119
+ reason += f" (elevated from {old_tier} by EU/global jurisdiction)"
120
+
121
+ # Step 3: guardrails
122
+ guardrails_fired: list[dict] = []
123
+
124
+ # G12 removal guardrail fires first
125
+ if "uses-llm" in ts and "uses-thirdparty-api" not in ts and "supply-chain" in files:
126
+ files.discard("supply-chain")
127
+ guardrails_fired.append({
128
+ "id": "G12",
129
+ "action": "REMOVE supply-chain",
130
+ "rationale": "Self-hosted models skip third-party controls",
131
+ })
132
+
133
+ guardrails = [
134
+ ("G1", lambda: sens_data and "audit-logging" not in files, "audit-logging", "Sensitive data requires traceability"),
135
+ ("G2", lambda: "handles-health" in ts and "bias-monitoring" not in files, "bias-monitoring", "Health data has demographic bias risks"),
136
+ ("G3", lambda: "handles-financial" in ts and "influences-decisions" in ts and "fallback-patterns" not in files, "fallback-patterns", "Financial decisions need safe failure"),
137
+ ("G4", lambda: "is-agentic" in ts and "human-oversight" not in files, "human-oversight", "Autonomous systems need oversight"),
138
+ ("G5", lambda: "generates-code" in ts and "output-sanitization" not in files, "output-sanitization", "Generated code is execution risk"),
139
+ ("G6", lambda: "jurisdiction-eu" in ts and "explainability" not in files, "explainability", "EU AI Act requires explainability"),
140
+ ("G7", lambda: "jurisdiction-eu" in ts and "bias-monitoring" not in files, "bias-monitoring", "EU AI Act mandates non-discrimination"),
141
+ ("G8", lambda: "handles-minors" in ts and "human-oversight" not in files, "human-oversight", "Systems affecting children require review"),
142
+ ("G9", lambda: "multi-model-pipeline" in ts and "monitoring" not in files, "monitoring", "Multi-model compounding failures"),
143
+ ("G10", lambda: tier == "HIGH" and "monitoring" not in files, "monitoring", "High-risk systems need monitoring"),
144
+ ("G11", lambda: tier == "HIGH" and "fallback-patterns" not in files, "fallback-patterns", "High-risk systems must fail safely"),
145
+ ("G13", lambda: "jurisdiction-us-regulated" in ts and "audit-logging" not in files, "audit-logging", "US regulated industries need audit trails"),
146
+ ("G14", lambda: "jurisdiction-us-regulated" in ts and "human-oversight" not in files, "human-oversight", "US regulated industries need human review"),
147
+ ("G15", lambda: "generates-code" in ts and "human-oversight" not in files, "human-oversight", "Code generation needs human review"),
148
+ ]
149
+
150
+ for gid, cond, file, rationale in guardrails:
151
+ if cond():
152
+ files.add(file)
153
+ guardrails_fired.append({"id": gid, "action": f"ADD {file}", "rationale": rationale})
154
+
155
+ # Step 4: templates
156
+ templates: list[str] = []
157
+ if tier == "HIGH" or "jurisdiction-eu" in ts or "jurisdiction-global" in ts or "influences-decisions" in ts:
158
+ templates.extend(["ai-impact-assessment", "intended-purpose-doc", "risk-characterization"])
159
+ elif tier == "MEDIUM" or "jurisdiction-us-regulated" in ts:
160
+ templates.append("intended-purpose-doc")
161
+
162
+ if "uses-thirdparty-api" in ts and tier != "LOW":
163
+ templates.append("third-party-assessment")
164
+
165
+ if "jurisdiction-us-regulated" in ts and "ai-impact-assessment" not in templates:
166
+ templates.insert(0, "ai-impact-assessment")
167
+
168
+ # Step 5: collect control IDs
169
+ all_owasp: set[str] = set()
170
+ all_nist: set[str] = set()
171
+ all_iso: set[str] = set()
172
+ for f in files:
173
+ c = FILE_CONTROLS.get(f)
174
+ if c:
175
+ all_owasp.update(c["owasp"])
176
+ all_nist.update(c["nist"])
177
+ all_iso.update(c["iso"])
178
+
179
+ return {
180
+ "risk_tier": tier,
181
+ "reason": reason,
182
+ "traits": list(ts),
183
+ "implement_files": sorted(files),
184
+ "templates": list(dict.fromkeys(templates)),
185
+ "guardrails_fired": guardrails_fired,
186
+ "warnings": warnings,
187
+ "controls": {
188
+ "owasp": sorted(all_owasp),
189
+ "nist": sorted(all_nist),
190
+ "iso": sorted(all_iso),
191
+ },
192
+ }