mirror of
https://github.com/wshobson/agents.git
synced 2026-03-18 09:37:15 +00:00
Add domain expert agents with comprehensive skill sets: - service-mesh-expert (cloud-infrastructure): Istio/Linkerd patterns, mTLS, observability - event-sourcing-architect (backend-development): CQRS, event stores, projections, sagas - vector-database-engineer (llm-application-dev): embeddings, similarity search, hybrid search - monorepo-architect (developer-essentials): Nx, Turborepo, Bazel, pnpm workspaces - threat-modeling-expert (security-scanning): STRIDE, attack trees, security requirements Update all documentation to reflect correct counts: - 67 plugins, 99 agents, 107 skills, 71 commands
678 lines
24 KiB
Markdown
678 lines
24 KiB
Markdown
---
|
|
name: security-requirement-extraction
|
|
description: Derive security requirements from threat models and business context. Use when translating threats into actionable requirements, creating security user stories, or building security test cases.
|
|
---
|
|
|
|
# Security Requirement Extraction
|
|
|
|
Transform threat analysis into actionable security requirements.
|
|
|
|
## When to Use This Skill
|
|
|
|
- Converting threat models to requirements
|
|
- Writing security user stories
|
|
- Creating security test cases
|
|
- Building security acceptance criteria
|
|
- Compliance requirement mapping
|
|
- Security architecture documentation
|
|
|
|
## Core Concepts
|
|
|
|
### 1. Requirement Categories
|
|
|
|
```
|
|
Business Requirements → Security Requirements → Technical Controls
|
|
↓ ↓ ↓
|
|
"Protect customer "Encrypt PII at rest" "AES-256 encryption
|
|
data" with KMS key rotation"
|
|
```
|
|
|
|
### 2. Security Requirement Types
|
|
|
|
| Type | Focus | Example |
|
|
|------|-------|---------|
|
|
| **Functional** | What system must do | "System must authenticate users" |
|
|
| **Non-functional** | How system must perform | "Authentication must complete in <2s" |
|
|
| **Constraint** | Limitations imposed | "Must use approved crypto libraries" |
|
|
|
|
### 3. Requirement Attributes
|
|
|
|
| Attribute | Description |
|
|
|-----------|-------------|
|
|
| **Traceability** | Links to threats/compliance |
|
|
| **Testability** | Can be verified |
|
|
| **Priority** | Business importance |
|
|
| **Risk Level** | Impact if not met |
|
|
|
|
## Templates
|
|
|
|
### Template 1: Security Requirement Model
|
|
|
|
```python
|
|
from dataclasses import dataclass, field
|
|
from enum import Enum
|
|
from typing import List, Dict, Optional, Set
|
|
from datetime import datetime
|
|
|
|
class RequirementType(Enum):
|
|
FUNCTIONAL = "functional"
|
|
NON_FUNCTIONAL = "non_functional"
|
|
CONSTRAINT = "constraint"
|
|
|
|
|
|
class Priority(Enum):
|
|
CRITICAL = 1
|
|
HIGH = 2
|
|
MEDIUM = 3
|
|
LOW = 4
|
|
|
|
|
|
class SecurityDomain(Enum):
|
|
AUTHENTICATION = "authentication"
|
|
AUTHORIZATION = "authorization"
|
|
DATA_PROTECTION = "data_protection"
|
|
AUDIT_LOGGING = "audit_logging"
|
|
INPUT_VALIDATION = "input_validation"
|
|
ERROR_HANDLING = "error_handling"
|
|
SESSION_MANAGEMENT = "session_management"
|
|
CRYPTOGRAPHY = "cryptography"
|
|
NETWORK_SECURITY = "network_security"
|
|
AVAILABILITY = "availability"
|
|
|
|
|
|
class ComplianceFramework(Enum):
|
|
PCI_DSS = "pci_dss"
|
|
HIPAA = "hipaa"
|
|
GDPR = "gdpr"
|
|
SOC2 = "soc2"
|
|
NIST_CSF = "nist_csf"
|
|
ISO_27001 = "iso_27001"
|
|
OWASP = "owasp"
|
|
|
|
|
|
@dataclass
|
|
class SecurityRequirement:
|
|
id: str
|
|
title: str
|
|
description: str
|
|
req_type: RequirementType
|
|
domain: SecurityDomain
|
|
priority: Priority
|
|
rationale: str = ""
|
|
acceptance_criteria: List[str] = field(default_factory=list)
|
|
test_cases: List[str] = field(default_factory=list)
|
|
threat_refs: List[str] = field(default_factory=list)
|
|
compliance_refs: List[str] = field(default_factory=list)
|
|
dependencies: List[str] = field(default_factory=list)
|
|
status: str = "draft"
|
|
owner: str = ""
|
|
created_date: datetime = field(default_factory=datetime.now)
|
|
|
|
def to_user_story(self) -> str:
|
|
"""Convert to user story format."""
|
|
return f"""
|
|
**{self.id}: {self.title}**
|
|
|
|
As a security-conscious system,
|
|
I need to {self.description.lower()},
|
|
So that {self.rationale.lower()}.
|
|
|
|
**Acceptance Criteria:**
|
|
{chr(10).join(f'- [ ] {ac}' for ac in self.acceptance_criteria)}
|
|
|
|
**Priority:** {self.priority.name}
|
|
**Domain:** {self.domain.value}
|
|
**Threat References:** {', '.join(self.threat_refs)}
|
|
"""
|
|
|
|
def to_test_spec(self) -> str:
|
|
"""Convert to test specification."""
|
|
return f"""
|
|
## Test Specification: {self.id}
|
|
|
|
### Requirement
|
|
{self.description}
|
|
|
|
### Test Cases
|
|
{chr(10).join(f'{i+1}. {tc}' for i, tc in enumerate(self.test_cases))}
|
|
|
|
### Acceptance Criteria Verification
|
|
{chr(10).join(f'- {ac}' for ac in self.acceptance_criteria)}
|
|
"""
|
|
|
|
|
|
@dataclass
|
|
class RequirementSet:
|
|
name: str
|
|
version: str
|
|
requirements: List[SecurityRequirement] = field(default_factory=list)
|
|
|
|
def add(self, req: SecurityRequirement) -> None:
|
|
self.requirements.append(req)
|
|
|
|
def get_by_domain(self, domain: SecurityDomain) -> List[SecurityRequirement]:
|
|
return [r for r in self.requirements if r.domain == domain]
|
|
|
|
def get_by_priority(self, priority: Priority) -> List[SecurityRequirement]:
|
|
return [r for r in self.requirements if r.priority == priority]
|
|
|
|
def get_by_threat(self, threat_id: str) -> List[SecurityRequirement]:
|
|
return [r for r in self.requirements if threat_id in r.threat_refs]
|
|
|
|
def get_critical_requirements(self) -> List[SecurityRequirement]:
|
|
return [r for r in self.requirements if r.priority == Priority.CRITICAL]
|
|
|
|
def export_markdown(self) -> str:
|
|
"""Export all requirements as markdown."""
|
|
lines = [f"# Security Requirements: {self.name}\n"]
|
|
lines.append(f"Version: {self.version}\n")
|
|
|
|
for domain in SecurityDomain:
|
|
domain_reqs = self.get_by_domain(domain)
|
|
if domain_reqs:
|
|
lines.append(f"\n## {domain.value.replace('_', ' ').title()}\n")
|
|
for req in domain_reqs:
|
|
lines.append(req.to_user_story())
|
|
|
|
return "\n".join(lines)
|
|
|
|
def traceability_matrix(self) -> Dict[str, List[str]]:
|
|
"""Generate threat-to-requirement traceability."""
|
|
matrix = {}
|
|
for req in self.requirements:
|
|
for threat_id in req.threat_refs:
|
|
if threat_id not in matrix:
|
|
matrix[threat_id] = []
|
|
matrix[threat_id].append(req.id)
|
|
return matrix
|
|
```
|
|
|
|
### Template 2: Threat-to-Requirement Extractor
|
|
|
|
```python
|
|
from dataclasses import dataclass
|
|
from typing import List, Dict, Tuple
|
|
|
|
@dataclass
|
|
class ThreatInput:
|
|
id: str
|
|
category: str # STRIDE category
|
|
title: str
|
|
description: str
|
|
target: str
|
|
impact: str
|
|
likelihood: str
|
|
|
|
|
|
class RequirementExtractor:
|
|
"""Extract security requirements from threats."""
|
|
|
|
# Mapping of STRIDE categories to security domains and requirement patterns
|
|
STRIDE_MAPPINGS = {
|
|
"SPOOFING": {
|
|
"domains": [SecurityDomain.AUTHENTICATION, SecurityDomain.SESSION_MANAGEMENT],
|
|
"patterns": [
|
|
("Implement strong authentication for {target}",
|
|
"Ensure {target} authenticates all users before granting access"),
|
|
("Validate identity tokens for {target}",
|
|
"All authentication tokens must be cryptographically verified"),
|
|
("Implement session management for {target}",
|
|
"Sessions must be securely managed with proper expiration"),
|
|
]
|
|
},
|
|
"TAMPERING": {
|
|
"domains": [SecurityDomain.INPUT_VALIDATION, SecurityDomain.DATA_PROTECTION],
|
|
"patterns": [
|
|
("Validate all input to {target}",
|
|
"All input must be validated against expected formats"),
|
|
("Implement integrity checks for {target}",
|
|
"Data integrity must be verified using cryptographic signatures"),
|
|
("Protect {target} from modification",
|
|
"Implement controls to prevent unauthorized data modification"),
|
|
]
|
|
},
|
|
"REPUDIATION": {
|
|
"domains": [SecurityDomain.AUDIT_LOGGING],
|
|
"patterns": [
|
|
("Log all security events for {target}",
|
|
"Security-relevant events must be logged for audit purposes"),
|
|
("Implement non-repudiation for {target}",
|
|
"Critical actions must have cryptographic proof of origin"),
|
|
("Protect audit logs for {target}",
|
|
"Audit logs must be tamper-evident and protected"),
|
|
]
|
|
},
|
|
"INFORMATION_DISCLOSURE": {
|
|
"domains": [SecurityDomain.DATA_PROTECTION, SecurityDomain.CRYPTOGRAPHY],
|
|
"patterns": [
|
|
("Encrypt sensitive data in {target}",
|
|
"Sensitive data must be encrypted at rest and in transit"),
|
|
("Implement access controls for {target}",
|
|
"Data access must be restricted based on need-to-know"),
|
|
("Prevent information leakage from {target}",
|
|
"Error messages and logs must not expose sensitive information"),
|
|
]
|
|
},
|
|
"DENIAL_OF_SERVICE": {
|
|
"domains": [SecurityDomain.AVAILABILITY, SecurityDomain.INPUT_VALIDATION],
|
|
"patterns": [
|
|
("Implement rate limiting for {target}",
|
|
"Requests must be rate-limited to prevent resource exhaustion"),
|
|
("Ensure availability of {target}",
|
|
"System must remain available under high load conditions"),
|
|
("Implement resource quotas for {target}",
|
|
"Resource consumption must be bounded and monitored"),
|
|
]
|
|
},
|
|
"ELEVATION_OF_PRIVILEGE": {
|
|
"domains": [SecurityDomain.AUTHORIZATION],
|
|
"patterns": [
|
|
("Enforce authorization for {target}",
|
|
"All actions must be authorized based on user permissions"),
|
|
("Implement least privilege for {target}",
|
|
"Users must only have minimum necessary permissions"),
|
|
("Validate permissions for {target}",
|
|
"Permission checks must be performed server-side"),
|
|
]
|
|
},
|
|
}
|
|
|
|
def extract_requirements(
|
|
self,
|
|
threats: List[ThreatInput],
|
|
project_name: str
|
|
) -> RequirementSet:
|
|
"""Extract security requirements from threats."""
|
|
req_set = RequirementSet(
|
|
name=f"{project_name} Security Requirements",
|
|
version="1.0"
|
|
)
|
|
|
|
req_counter = 1
|
|
for threat in threats:
|
|
reqs = self._threat_to_requirements(threat, req_counter)
|
|
for req in reqs:
|
|
req_set.add(req)
|
|
req_counter += len(reqs)
|
|
|
|
return req_set
|
|
|
|
def _threat_to_requirements(
|
|
self,
|
|
threat: ThreatInput,
|
|
start_id: int
|
|
) -> List[SecurityRequirement]:
|
|
"""Convert a single threat to requirements."""
|
|
requirements = []
|
|
mapping = self.STRIDE_MAPPINGS.get(threat.category, {})
|
|
domains = mapping.get("domains", [])
|
|
patterns = mapping.get("patterns", [])
|
|
|
|
priority = self._calculate_priority(threat.impact, threat.likelihood)
|
|
|
|
for i, (title_pattern, desc_pattern) in enumerate(patterns):
|
|
req = SecurityRequirement(
|
|
id=f"SR-{start_id + i:03d}",
|
|
title=title_pattern.format(target=threat.target),
|
|
description=desc_pattern.format(target=threat.target),
|
|
req_type=RequirementType.FUNCTIONAL,
|
|
domain=domains[i % len(domains)] if domains else SecurityDomain.DATA_PROTECTION,
|
|
priority=priority,
|
|
rationale=f"Mitigates threat: {threat.title}",
|
|
threat_refs=[threat.id],
|
|
acceptance_criteria=self._generate_acceptance_criteria(
|
|
threat.category, threat.target
|
|
),
|
|
test_cases=self._generate_test_cases(
|
|
threat.category, threat.target
|
|
)
|
|
)
|
|
requirements.append(req)
|
|
|
|
return requirements
|
|
|
|
def _calculate_priority(self, impact: str, likelihood: str) -> Priority:
|
|
"""Calculate requirement priority from threat attributes."""
|
|
score_map = {"LOW": 1, "MEDIUM": 2, "HIGH": 3, "CRITICAL": 4}
|
|
impact_score = score_map.get(impact.upper(), 2)
|
|
likelihood_score = score_map.get(likelihood.upper(), 2)
|
|
|
|
combined = impact_score * likelihood_score
|
|
|
|
if combined >= 12:
|
|
return Priority.CRITICAL
|
|
elif combined >= 6:
|
|
return Priority.HIGH
|
|
elif combined >= 3:
|
|
return Priority.MEDIUM
|
|
return Priority.LOW
|
|
|
|
def _generate_acceptance_criteria(
|
|
self,
|
|
category: str,
|
|
target: str
|
|
) -> List[str]:
|
|
"""Generate acceptance criteria for requirement."""
|
|
criteria_templates = {
|
|
"SPOOFING": [
|
|
f"Users must authenticate before accessing {target}",
|
|
"Authentication failures are logged and monitored",
|
|
"Multi-factor authentication is available for sensitive operations",
|
|
],
|
|
"TAMPERING": [
|
|
f"All input to {target} is validated",
|
|
"Data integrity is verified before processing",
|
|
"Modification attempts trigger alerts",
|
|
],
|
|
"REPUDIATION": [
|
|
f"All actions on {target} are logged with user identity",
|
|
"Logs cannot be modified by regular users",
|
|
"Log retention meets compliance requirements",
|
|
],
|
|
"INFORMATION_DISCLOSURE": [
|
|
f"Sensitive data in {target} is encrypted",
|
|
"Access to sensitive data is logged",
|
|
"Error messages do not reveal sensitive information",
|
|
],
|
|
"DENIAL_OF_SERVICE": [
|
|
f"Rate limiting is enforced on {target}",
|
|
"System degrades gracefully under load",
|
|
"Resource exhaustion triggers alerts",
|
|
],
|
|
"ELEVATION_OF_PRIVILEGE": [
|
|
f"Authorization is checked for all {target} operations",
|
|
"Users cannot access resources beyond their permissions",
|
|
"Privilege changes are logged and monitored",
|
|
],
|
|
}
|
|
return criteria_templates.get(category, [])
|
|
|
|
def _generate_test_cases(
|
|
self,
|
|
category: str,
|
|
target: str
|
|
) -> List[str]:
|
|
"""Generate test cases for requirement."""
|
|
test_templates = {
|
|
"SPOOFING": [
|
|
f"Test: Unauthenticated access to {target} is denied",
|
|
"Test: Invalid credentials are rejected",
|
|
"Test: Session tokens cannot be forged",
|
|
],
|
|
"TAMPERING": [
|
|
f"Test: Invalid input to {target} is rejected",
|
|
"Test: Tampered data is detected and rejected",
|
|
"Test: SQL injection attempts are blocked",
|
|
],
|
|
"REPUDIATION": [
|
|
"Test: Security events are logged",
|
|
"Test: Logs include sufficient detail for forensics",
|
|
"Test: Log integrity is protected",
|
|
],
|
|
"INFORMATION_DISCLOSURE": [
|
|
f"Test: {target} data is encrypted in transit",
|
|
f"Test: {target} data is encrypted at rest",
|
|
"Test: Error messages are sanitized",
|
|
],
|
|
"DENIAL_OF_SERVICE": [
|
|
f"Test: Rate limiting on {target} works correctly",
|
|
"Test: System handles burst traffic gracefully",
|
|
"Test: Resource limits are enforced",
|
|
],
|
|
"ELEVATION_OF_PRIVILEGE": [
|
|
f"Test: Unauthorized access to {target} is denied",
|
|
"Test: Privilege escalation attempts are blocked",
|
|
"Test: IDOR vulnerabilities are not present",
|
|
],
|
|
}
|
|
return test_templates.get(category, [])
|
|
```
|
|
|
|
### Template 3: Compliance Mapping
|
|
|
|
```python
|
|
from typing import Dict, List, Set
|
|
|
|
class ComplianceMapper:
|
|
"""Map security requirements to compliance frameworks."""
|
|
|
|
FRAMEWORK_CONTROLS = {
|
|
ComplianceFramework.PCI_DSS: {
|
|
SecurityDomain.AUTHENTICATION: ["8.1", "8.2", "8.3"],
|
|
SecurityDomain.AUTHORIZATION: ["7.1", "7.2"],
|
|
SecurityDomain.DATA_PROTECTION: ["3.4", "3.5", "4.1"],
|
|
SecurityDomain.AUDIT_LOGGING: ["10.1", "10.2", "10.3"],
|
|
SecurityDomain.NETWORK_SECURITY: ["1.1", "1.2", "1.3"],
|
|
SecurityDomain.CRYPTOGRAPHY: ["3.5", "3.6", "4.1"],
|
|
},
|
|
ComplianceFramework.HIPAA: {
|
|
SecurityDomain.AUTHENTICATION: ["164.312(d)"],
|
|
SecurityDomain.AUTHORIZATION: ["164.312(a)(1)"],
|
|
SecurityDomain.DATA_PROTECTION: ["164.312(a)(2)(iv)", "164.312(e)(2)(ii)"],
|
|
SecurityDomain.AUDIT_LOGGING: ["164.312(b)"],
|
|
},
|
|
ComplianceFramework.GDPR: {
|
|
SecurityDomain.DATA_PROTECTION: ["Art. 32", "Art. 25"],
|
|
SecurityDomain.AUDIT_LOGGING: ["Art. 30"],
|
|
SecurityDomain.AUTHORIZATION: ["Art. 25"],
|
|
},
|
|
ComplianceFramework.OWASP: {
|
|
SecurityDomain.AUTHENTICATION: ["V2.1", "V2.2", "V2.3"],
|
|
SecurityDomain.SESSION_MANAGEMENT: ["V3.1", "V3.2", "V3.3"],
|
|
SecurityDomain.INPUT_VALIDATION: ["V5.1", "V5.2", "V5.3"],
|
|
SecurityDomain.CRYPTOGRAPHY: ["V6.1", "V6.2"],
|
|
SecurityDomain.ERROR_HANDLING: ["V7.1", "V7.2"],
|
|
SecurityDomain.DATA_PROTECTION: ["V8.1", "V8.2", "V8.3"],
|
|
SecurityDomain.AUDIT_LOGGING: ["V7.1", "V7.2"],
|
|
},
|
|
}
|
|
|
|
def map_requirement_to_compliance(
|
|
self,
|
|
requirement: SecurityRequirement,
|
|
frameworks: List[ComplianceFramework]
|
|
) -> Dict[str, List[str]]:
|
|
"""Map a requirement to compliance controls."""
|
|
mapping = {}
|
|
for framework in frameworks:
|
|
controls = self.FRAMEWORK_CONTROLS.get(framework, {})
|
|
domain_controls = controls.get(requirement.domain, [])
|
|
if domain_controls:
|
|
mapping[framework.value] = domain_controls
|
|
return mapping
|
|
|
|
def get_requirements_for_control(
|
|
self,
|
|
requirement_set: RequirementSet,
|
|
framework: ComplianceFramework,
|
|
control_id: str
|
|
) -> List[SecurityRequirement]:
|
|
"""Find requirements that satisfy a compliance control."""
|
|
matching = []
|
|
framework_controls = self.FRAMEWORK_CONTROLS.get(framework, {})
|
|
|
|
for domain, controls in framework_controls.items():
|
|
if control_id in controls:
|
|
matching.extend(requirement_set.get_by_domain(domain))
|
|
|
|
return matching
|
|
|
|
def generate_compliance_matrix(
|
|
self,
|
|
requirement_set: RequirementSet,
|
|
frameworks: List[ComplianceFramework]
|
|
) -> Dict[str, Dict[str, List[str]]]:
|
|
"""Generate compliance traceability matrix."""
|
|
matrix = {}
|
|
|
|
for framework in frameworks:
|
|
matrix[framework.value] = {}
|
|
framework_controls = self.FRAMEWORK_CONTROLS.get(framework, {})
|
|
|
|
for domain, controls in framework_controls.items():
|
|
for control in controls:
|
|
reqs = self.get_requirements_for_control(
|
|
requirement_set, framework, control
|
|
)
|
|
if reqs:
|
|
matrix[framework.value][control] = [r.id for r in reqs]
|
|
|
|
return matrix
|
|
|
|
def gap_analysis(
|
|
self,
|
|
requirement_set: RequirementSet,
|
|
framework: ComplianceFramework
|
|
) -> Dict[str, List[str]]:
|
|
"""Identify compliance gaps."""
|
|
gaps = {"missing_controls": [], "weak_coverage": []}
|
|
framework_controls = self.FRAMEWORK_CONTROLS.get(framework, {})
|
|
|
|
for domain, controls in framework_controls.items():
|
|
domain_reqs = requirement_set.get_by_domain(domain)
|
|
for control in controls:
|
|
matching = self.get_requirements_for_control(
|
|
requirement_set, framework, control
|
|
)
|
|
if not matching:
|
|
gaps["missing_controls"].append(f"{framework.value}:{control}")
|
|
elif len(matching) < 2:
|
|
gaps["weak_coverage"].append(f"{framework.value}:{control}")
|
|
|
|
return gaps
|
|
```
|
|
|
|
### Template 4: Security User Story Generator
|
|
|
|
```python
|
|
class SecurityUserStoryGenerator:
|
|
"""Generate security-focused user stories."""
|
|
|
|
STORY_TEMPLATES = {
|
|
SecurityDomain.AUTHENTICATION: {
|
|
"as_a": "security-conscious user",
|
|
"so_that": "my identity is protected from impersonation",
|
|
},
|
|
SecurityDomain.AUTHORIZATION: {
|
|
"as_a": "system administrator",
|
|
"so_that": "users can only access resources appropriate to their role",
|
|
},
|
|
SecurityDomain.DATA_PROTECTION: {
|
|
"as_a": "data owner",
|
|
"so_that": "my sensitive information remains confidential",
|
|
},
|
|
SecurityDomain.AUDIT_LOGGING: {
|
|
"as_a": "security analyst",
|
|
"so_that": "I can investigate security incidents",
|
|
},
|
|
SecurityDomain.INPUT_VALIDATION: {
|
|
"as_a": "application developer",
|
|
"so_that": "the system is protected from malicious input",
|
|
},
|
|
}
|
|
|
|
def generate_story(self, requirement: SecurityRequirement) -> str:
|
|
"""Generate a user story from requirement."""
|
|
template = self.STORY_TEMPLATES.get(
|
|
requirement.domain,
|
|
{"as_a": "user", "so_that": "the system is secure"}
|
|
)
|
|
|
|
story = f"""
|
|
## {requirement.id}: {requirement.title}
|
|
|
|
**User Story:**
|
|
As a {template['as_a']},
|
|
I want the system to {requirement.description.lower()},
|
|
So that {template['so_that']}.
|
|
|
|
**Priority:** {requirement.priority.name}
|
|
**Type:** {requirement.req_type.value}
|
|
**Domain:** {requirement.domain.value}
|
|
|
|
**Acceptance Criteria:**
|
|
{self._format_acceptance_criteria(requirement.acceptance_criteria)}
|
|
|
|
**Definition of Done:**
|
|
- [ ] Implementation complete
|
|
- [ ] Security tests pass
|
|
- [ ] Code review complete
|
|
- [ ] Security review approved
|
|
- [ ] Documentation updated
|
|
|
|
**Security Test Cases:**
|
|
{self._format_test_cases(requirement.test_cases)}
|
|
|
|
**Traceability:**
|
|
- Threats: {', '.join(requirement.threat_refs) or 'N/A'}
|
|
- Compliance: {', '.join(requirement.compliance_refs) or 'N/A'}
|
|
"""
|
|
return story
|
|
|
|
def _format_acceptance_criteria(self, criteria: List[str]) -> str:
|
|
return "\n".join(f"- [ ] {c}" for c in criteria) if criteria else "- [ ] TBD"
|
|
|
|
def _format_test_cases(self, tests: List[str]) -> str:
|
|
return "\n".join(f"- {t}" for t in tests) if tests else "- TBD"
|
|
|
|
def generate_epic(
|
|
self,
|
|
requirement_set: RequirementSet,
|
|
domain: SecurityDomain
|
|
) -> str:
|
|
"""Generate an epic for a security domain."""
|
|
reqs = requirement_set.get_by_domain(domain)
|
|
|
|
epic = f"""
|
|
# Security Epic: {domain.value.replace('_', ' ').title()}
|
|
|
|
## Overview
|
|
This epic covers all security requirements related to {domain.value.replace('_', ' ')}.
|
|
|
|
## Business Value
|
|
- Protect against {domain.value.replace('_', ' ')} related threats
|
|
- Meet compliance requirements
|
|
- Reduce security risk
|
|
|
|
## Stories in this Epic
|
|
{chr(10).join(f'- [{r.id}] {r.title}' for r in reqs)}
|
|
|
|
## Acceptance Criteria
|
|
- All stories complete
|
|
- Security tests passing
|
|
- Security review approved
|
|
- Compliance requirements met
|
|
|
|
## Risk if Not Implemented
|
|
- Vulnerability to {domain.value.replace('_', ' ')} attacks
|
|
- Compliance violations
|
|
- Potential data breach
|
|
|
|
## Dependencies
|
|
{chr(10).join(f'- {d}' for r in reqs for d in r.dependencies) or '- None identified'}
|
|
"""
|
|
return epic
|
|
```
|
|
|
|
## Best Practices
|
|
|
|
### Do's
|
|
- **Trace to threats** - Every requirement should map to threats
|
|
- **Be specific** - Vague requirements can't be tested
|
|
- **Include acceptance criteria** - Define "done"
|
|
- **Consider compliance** - Map to frameworks early
|
|
- **Review regularly** - Requirements evolve with threats
|
|
|
|
### Don'ts
|
|
- **Don't be generic** - "Be secure" is not a requirement
|
|
- **Don't skip rationale** - Explain why it matters
|
|
- **Don't ignore priorities** - Not all requirements are equal
|
|
- **Don't forget testability** - If you can't test it, you can't verify it
|
|
- **Don't work in isolation** - Involve stakeholders
|
|
|
|
## Resources
|
|
|
|
- [OWASP ASVS](https://owasp.org/www-project-application-security-verification-standard/)
|
|
- [NIST SP 800-53](https://csrc.nist.gov/publications/detail/sp/800-53/rev-5/final)
|
|
- [Security User Stories](https://www.oreilly.com/library/view/agile-application-security/9781491938836/)
|