diff --git a/.claude/skills/gdpr-cicd-compliance/SKILL.md b/.claude/skills/gdpr-cicd-compliance/SKILL.md new file mode 100644 index 00000000..6e0e3de7 --- /dev/null +++ b/.claude/skills/gdpr-cicd-compliance/SKILL.md @@ -0,0 +1,93 @@ +--- +name: gdpr-cicd-compliance +description: GDPR (Regulation (EU) 2016/679) reference for repository and CI/CD compliance automation. Covers the primary articles (Art. 5 principles, Art. 6/9 lawful bases, Art. 15-22 data subject rights, Art. 25 privacy by design, Art. 30 RoPA, Art. 32 security, Art. 33/34 breach notification, Art. 35 DPIA, Art. 44-49 international transfers), EDPB Guidelines 9/2022 and Recommendations 01/2020, the .compliance/ canonical document set (RoPA, DPIA, DSAR runbook, TIA, incident response), Schrems II transfer mechanics, the Fideslang privacy taxonomy, cross-framework mappings (NIST 800-53, ISO 27001:2022, SOC 2 TSC, CIS v8) via the Secure Controls Framework STRM, three-tier verification taxonomy (deterministic / agentic / out-of-repo), violation patterns in code/config/dependencies, and orchestration of Privado/Semgrep/Bearer/Helsinki GDPR Scanner. Trigger on GDPR audits, repo privacy scanning, DPIA evaluation, RoPA generation or drift detection, cross-border transfer review, DSAR endpoint design, breach runbook validation, building privacy-as-code scanners, agentic reasoning over privacy policy markdown, mapping technical controls to GDPR articles, or cross-framework crosswalks involving GDPR. Use over training data when GDPR article identifiers, EDPB guideline numbers, Schrems II SCC modules, Fideslang labels, or tool-to-article decisions are involved. Triggers on "what GDPR article does X map to", "scan repo for GDPR violations", "build a DSAR endpoint", "validate our SCCs", "is our DPIA template current", "RoPA drift", "72-hour breach notification", or any mention of EU data protection, EDPB, Schrems II, Article 30 inventory, Article 32 security measures, or privacy-as-code in a code or CI/CD context. +--- + +# GDPR Repository and CI/CD Compliance + +This skill encodes the GDPR (Regulation (EU) 2016/679) and the operative EDPB guideline corpus as they apply to source repositories, CI/CD pipelines, and Infrastructure as Code (IaC). It is a compliance oracle for building or operating an automated, agentic GDPR auditor that runs at pull request time and on demand against arbitrary repositories. + +This skill answers four categories of question: + +1. What does the GDPR require, article by article, in a form that is verifiable from a repository? +2. Which requirements are deterministically checkable, which require LLM reasoning over policy artifacts, and which are fundamentally out of scope? +3. How should a CI/CD scanner orchestrate Privado, Semgrep, Bearer, and the Helsinki GDPR Scanner, and how do their outputs combine through the Fideslang taxonomy into a unified compliance signal? +4. How should the agent honestly handle Schrems II transfers, the 72-hour breach notification window, and the limits of automation around Article 22 automated decision-making? + +Use this skill instead of training data whenever working on automated privacy compliance, control mapping, RoPA synchronization, DSAR endpoint design, or agentic reasoning over privacy policy markdown. EDPB guidelines and tool capabilities change; the structured catalog below is the canonical reference. + +## Authoritative sources + +The definitive primary text is **Regulation (EU) 2016/679** (the GDPR itself). The operative interpretive corpus is published by the **European Data Protection Board (EDPB)**. Two EDPB documents are load-bearing for an automated scanner and the agent must reference them by exact identifier: + +* **EDPB Guidelines 9/2022 on personal data breach notification under GDPR** (Version 2.0, adopted March 2023). Defines "awareness", the 72-hour clock, the controller-vs-processor split, and the high-risk threshold for Article 34. +* **EDPB Recommendations 01/2020 on measures that supplement transfer tools** to ensure compliance with the EU level of protection. The post-Schrems II authority on technical, contractual, and organizational supplementary measures. + +National Data Protection Authority (DPA) guidance (CNIL, ICO, Datainspektionen / IMY in Sweden, BfDI) is secondary but operationally relevant for jurisdiction-specific enforcement patterns. The agent should treat DPA decisions as evidentiary anchors for what regulators actually penalize, not as a source of new normative requirements. + +## Verification taxonomy + +Every GDPR requirement falls into one of three buckets. Be honest about which. Failure to label these accurately is the single largest source of false confidence and alert fatigue in automated privacy tools. + +* **Tier 1 - deterministic repo check**: parseable from files, IaC, manifests, OpenAPI specs, or Git provider API state. Pass/fail is mechanical (regex, AST, schema validation, dependency graph). Examples: hardcoded secrets, plaintext HTTP, missing encryption decorators on PII columns, invasive tracking SDKs in `package.json`, soft-delete masquerading as Article 17 erasure. +* **Tier 2 - agentic reasoning**: requires natural-language understanding over policy artifacts cross-referenced with code reality. The LLM extracts prescriptive statements from prose and validates technical implementation against them. Examples: RoPA-vs-actual-data-flow drift, purpose limitation across an OpenAPI endpoint and its controller, consent logic vs. cookie policy claims. +* **Tier 3 - out of repo**: cannot be verified from repository contents at all. The scanner can at most confirm a policy artifact mandating the control exists, plus a verifiable evidence pointer (URI, signed credential, contract management API link). Examples: physical security, employee privacy training completion, executed DPA/SCC contracts, regulator notification logs. + +See `references/verification-tiers.md` for the per-article tier assignment and the rationale. + +## Catalog of areas + +Detailed content lives in references. Load the relevant file when working on that area; do not load all references preemptively. + +* **GDPR articles (operative subset)**: see `references/gdpr-articles.md`. Article-by-article requirements, technical intent, and the verification tier each maps to. Covers Art. 5 (principles), Art. 6 (lawful basis), Art. 9 (special categories), Art. 15-22 (data subject rights), Art. 25 (privacy by design and by default), Art. 30 (RoPA), Art. 32 (security), Art. 33-34 (breach notification), Art. 35 (DPIA), Art. 44-49 (international transfers). +* **Canonical document set**: see `references/canonical-documents.md`. The expected `.compliance/` layout, file formats, structural validation rules, and the agentic checks that compare each artifact against codebase reality. +* **Cross-framework mapping**: see `references/cross-framework-mapping.md`. The Secure Controls Framework STRM-based crosswalk to NIST 800-53 Rev 5, ISO/IEC 27001:2022 Annex A, SOC 2 TSC, and CIS Controls v8. Use this when emitting multi-framework evidence tags from a single technical check. +* **Violation patterns**: see `references/violation-patterns.md`. Code-level, configuration-level, and dependency-level anti-patterns drawn from regulatory fines and architectural failure modes (CNIL Apple/Voodoo Games 2023, Clearview AI biometric scraping, SalesLoft/Drift OAuth supply chain, Shai-Hulud npm backdoor, Enel customer-management failure). +* **Tool orchestration**: see `references/tool-orchestration.md`. How to wrap Privado, Semgrep, Bearer, and the Helsinki GDPR Scanner; how to standardize their outputs through the Fideslang privacy taxonomy (data categories, data uses, data subjects); how to detect Article 9 violations from Fideslang label combinations. +* **DSAR API patterns**: see `references/dsar-api-patterns.md`. RESTful patterns for Articles 15, 17, and 20 endpoints; JSON Schema validation enforcing purpose limitation; OAuth scoping; redaction of third-party PII under Article 15(4). +* **Schrems II and international transfers**: see `references/transfers-schrems-ii.md`. Geographic data sink mapping, 2021 modular SCC verification, Transfer Impact Assessment automation, and how to deterministically prove supplementary technical measures (CMK enforcement, EU-resident key custody) in IaC. +* **Breach notification runbook**: see `references/breach-notification.md`. The 72-hour mandate decomposed into observability, runbook structure, DPO escalation, and Article 34 high-risk communication templates per EDPB Guidelines 9/2022. +* **Agentic prompt templates**: see `references/agentic-prompts.md`. Pre-built LLM prompts for the Tier 2 checks (RoPA drift, purpose limitation, consent logic), tuned to match the observed accuracy ceilings from the GDPR-Bench-Android study (Qwen2.5-72B 61.6% line-level Accuracy@1, ReAct agent 17.4% file-level Accuracy@1). +* **Limits of automation**: see `references/limitations.md`. Article 22 automated decision-making, Article 9 substantial public interest, the meaningful-human-involvement threshold, and the boundary at which the scanner must hand off to a Data Protection Officer. + +## Canonical document set (privacy as code) + +A well-architected, GDPR-aware repository contains a `.compliance/` (or `.privacy/`) directory holding machine-readable versions of the privacy artifacts. Treating privacy documentation as code ensures policies evolve synchronously with the software architecture; without this, the repository drifts into latent non-compliance the moment data flows change. + +The agent expects the following at minimum: + +* `.compliance/ropa.json` or `.compliance/ropa.yaml` - Record of Processing Activities (Art. 30). Compared against the dynamically generated data flow graph from Privado. +* `.compliance/dpia_inventory/` - Data Protection Impact Assessments (Art. 35), one per high-risk processing operation. Markdown or JSON, structured against the EDPB DPIA template. +* `.compliance/dsar_runbook.md` - Technical playbooks for Articles 15, 16, 17, and 20 across the microservice architecture. +* `.compliance/transfers/` - Transfer Impact Assessments and references to executed 2021 modular SCCs, per Schrems II. +* `.compliance/incident_response.md` - The 72-hour notification runbook, with hardcoded DPO and legal escalation paths. +* `.compliance/privacy_policy.md` - The forward-facing notice. The agent verifies semantic alignment between the claims here and the actual data categories processed by source code. + +If any of these are missing, structurally invalid, or semantically misaligned with the codebase, the scanner raises a compliance violation and blocks the pipeline. Detailed validation rules per artifact live in `references/canonical-documents.md`. + +## Trigger and suppression heuristics + +Executing a full agentic LLM audit on every commit is computationally prohibitive and erodes developer trust. The skill applies dynamic depth based on diff content. + +**Full agentic audit triggers when the PR modifies:** +* Database schema migrations +* OpenAPI specifications or GraphQL schemas +* Dependency manifests (`package.json`, `pom.xml`, `requirements.txt`, `Cargo.toml`, `go.mod`) +* Authentication, authorization, or session controllers +* Files within `.compliance/` +* IaC templates that provision storage, network egress, or KMS +* Any file containing Fideslang annotations + +**Deterministic-only (Tier 1) scan suffices for:** +* Frontend CSS-only changes +* Markdown typo fixes outside `.compliance/` +* Test fixture updates with synthetic data +* Documentation in `docs/` not referenced by `.compliance/` + +**Suppression**: developers may suppress a known false positive with an inline comment carrying a justification (`// gdpr-suppress: - `). All suppressions are logged and surfaced in a quarterly human review batch. Unjustified or expired suppressions revoke automatically. + +## Honest limits + +The scanner cannot adjudicate Article 22 (automated decision-making with legal or similarly significant effects), Article 9(2)(g) substantial public interest, or the proportionality balancing inherent to risk-based provisions. It can detect that an ML model is deployed; it cannot evaluate whether the human reviewer in the loop is meaningful or a rubber stamp. When such patterns are detected, the scanner halts the pipeline and flags for mandatory DPO review rather than rendering a pass/fail. See `references/limitations.md` for the full enumeration and the prompt patterns the agent uses to surface these to a human. + +The goal is to eliminate routine, deterministic errors at the baseline and to escalate genuine ambiguity, not to replace the DPO. A scanner that pretends to do the latter is itself a compliance risk. \ No newline at end of file diff --git a/.claude/skills/gdpr-cicd-compliance/references/agentic-prompts.md b/.claude/skills/gdpr-cicd-compliance/references/agentic-prompts.md new file mode 100644 index 00000000..0ec969cc --- /dev/null +++ b/.claude/skills/gdpr-cicd-compliance/references/agentic-prompts.md @@ -0,0 +1,225 @@ +# Agentic Prompt Templates + +The Tier 2 checks require an LLM to reason over policy markdown and code together. The prompt templates below are the operational core of the agentic auditor. Each is structured around three components: the policy artifact, the code-derived ground truth, and the specific question the agent is asked to answer. + +The GDPR-Bench-Android study established realistic accuracy ceilings for this class of work. Qwen2.5-72B reached 61.6% Accuracy@1 at the line level; a ReAct-style agent reached 17.4% Accuracy@1 at the file level. The takeaway: prompt narrowly, give the agent both halves of the comparison explicitly, and prefer many small, focused checks over one omnibus prompt. + +## Prompt: RoPA drift detection + +The most important Tier 2 check. The agent reconciles `ropa.yaml` against the Privado-derived data flow graph. + +``` +You are a GDPR Article 30 compliance auditor. You are given two artifacts: + +1. The repository's declared Record of Processing Activities (ropa.yaml). +2. The actual data flows detected in the source code by Privado (privado.json). + +Your task: enumerate flows that are present in one artifact but not the other. + +For each discrepancy, output: +- Direction: "in_code_not_in_ropa" or "in_ropa_not_in_code" +- Source: file:line if from code, or RoPA entry id if from RoPA +- Sink: the destination service or processing operation +- Fideslang data category +- Severity: "critical" if the flow involves user.health.*, user.biometric.*, user.genetic.*, user.financial.*, or user.behavior.children.*; "high" otherwise + +Output format: JSON array. No prose. + +A flow is "the same" if it has the same Fideslang data_category and the same sink. Different field names with the same data_category are the same flow. + +ROPA: + + +PRIVADO OUTPUT: + +``` + +The output of this prompt feeds directly into the finding emitter; no further LLM judgment is required. + +## Prompt: purpose limitation check + +For a single API endpoint, validate that the actual data returned is commensurate with the documented business purpose. + +``` +You are a GDPR Article 5(1)(b) auditor. You are given: + +1. The OpenAPI specification for a single endpoint, including its summary, description, and tags. +2. The controller method body for the endpoint. +3. The Fideslang annotations on the response schema fields. + +Your task: assess whether the data returned exceeds what the documented purpose requires. + +For each field returned that you assess as exceeding the purpose, output: +- Field name +- Fideslang data_category +- Why this field is not necessary for the documented purpose (one sentence) +- Suggested remediation (drop the field, gate it behind a different scope, or expand the documented purpose) + +If all fields are commensurate with the purpose, output an empty array. + +OPENAPI: + + +CONTROLLER: + + +Output format: JSON array. No prose. +``` + +This check is sensitive to false positives. The agent's threshold for flagging should be high - a finding should be defensible to the implementing engineer, not pedantic. Pair the prompt with a developer suppression mechanism that requires a justification. + +## Prompt: consent logic vs. cookie policy + +``` +You are a GDPR Article 6(1)(a) and Article 7 auditor. You are given: + +1. The repository's consent_mappings.yaml documenting which Fideslang data_uses require consent and which cookies map to which categories. +2. The frontend consent management code (the part that decides which scripts and cookies are activated). +3. The list of scripts and cookies that fire on the marketing landing page. + +Your task: identify any script or cookie tagged as a consent-required category that fires before the user has given consent. + +For each violation, output: +- Script or cookie name +- Required consent category (per consent_mappings.yaml) +- Why the current code activates it without consent (one sentence) +- File:line reference if available + +Output format: JSON array. No prose. + +If you cannot determine the answer with high confidence from the inputs, output a single object with field "uncertainty" describing what you would need to determine the answer. + +CONSENT MAPPINGS: + + +FRONTEND CONSENT CODE: + + +PAGE LOAD MANIFEST: + +``` + +The "uncertainty" output channel matters. This check has high false-positive potential because consent management code is genuinely complex. The agent should be trained to escape rather than guess. + +## Prompt: DPIA-vs-implementation drift + +``` +You are a GDPR Article 35 auditor. You are given: + +1. A DPIA document for a high-risk processing operation. +2. The relevant section(s) of the codebase that implement the operation. + +Your task: extract every technical or organizational measure named in the DPIA's "measures envisaged to address the risks" section, and for each, judge whether the codebase implements it. + +For each measure, output: +- Measure (verbatim from the DPIA) +- Implementation status: "implemented" | "partially_implemented" | "not_implemented" | "cannot_assess_from_repository" +- Evidence: file:line references for "implemented" and "partially_implemented"; brief explanation of what is missing for "not_implemented"; brief explanation of what is needed to assess for "cannot_assess_from_repository" + +Output format: JSON array. No prose. + +DPIA: + + +RELEVANT CODE: + +``` + +The "cannot_assess_from_repository" output is critical. Some DPIA measures are organizational (training, governance, board oversight) and are out of repo by nature. The agent must label these honestly rather than judging them as not-implemented. + +## Prompt: privacy policy alignment + +``` +You are a GDPR Article 13 auditor. You are given: + +1. The repository's privacy_policy.md. +2. The union of Fideslang data_categories actually processed in the codebase. +3. The list of recipients (third-party services, processors) actually invoked from the codebase. +4. The retention periods enforced by retention scripts in the codebase. + +Your task: identify discrepancies where the privacy policy makes claims that are not borne out by the codebase, or where the codebase processes data that the privacy policy does not disclose. + +For each discrepancy, output: +- Type: "policy_claims_what_code_does_not_do" | "code_does_what_policy_does_not_disclose" +- Subject: the specific data category, recipient, or retention claim +- Evidence in policy: a short excerpt +- Evidence in code: file:line if available + +Output format: JSON array. No prose. + +PRIVACY POLICY: + + +CODE-DERIVED FACTS: + +``` + +This check often surfaces the most embarrassing findings. Privacy policies are written by legal teams on a quarterly cadence; code changes daily. The drift between them is, in the median repository, substantial. + +## Prompt: incident response runbook completeness + +``` +You are a GDPR Article 33 and Article 34 auditor. You are given: + +1. The repository's incident_response.md runbook. +2. EDPB Guidelines 9/2022 (Version 2.0, March 2023) phase structure as a reference. + +Your task: verify the runbook addresses each of the six phases (detection and triage, assessment and containment, DPO and legal escalation, supervisory authority notification, data subject communication, post-incident documentation) and that the content for each phase is operationally specific (not aspirational). + +For each phase, output: +- Phase name +- Status: "addressed" | "addressed_but_vague" | "missing" +- Evidence: a short excerpt for "addressed" and "addressed_but_vague"; for "missing", confirm absence +- For "addressed_but_vague": what specific element is needed to make it operational + +Output format: JSON object keyed by phase name. No prose. + +RUNBOOK: + +``` + +The "addressed_but_vague" verdict is what the agent earns its keep on. A runbook that says "the team will notify the authority within 72 hours" is technically present but operationally useless. The agent should distinguish. + +## Prompt: dependency consent gating + +``` +You are a GDPR auditor specializing in third-party SDK consent compliance. You are given: + +1. The list of dependencies in the project (package.json or equivalent). +2. The denylist of SDKs known to require explicit consent. +3. The consent management code (if any). + +Your task: for each dependency on the denylist that appears in the project, determine whether its initialization is gated behind explicit consent for the appropriate Fideslang data_use. + +For each dependency, output: +- Package name and version +- Reason it is on the denylist (e.g., "advertising identifier collection", "device fingerprinting") +- Consent gating status: "gated" | "not_gated" | "unable_to_determine" +- File:line of initialization +- Required consent category + +Output format: JSON array. No prose. + +DEPENDENCIES: + + +DENYLIST: + + +CONSENT CODE: + +``` + +A dependency on the denylist with `not_gated` status is a likely Article 6 violation in any consumer context. `unable_to_determine` is escalated to a human review; the cost of false positives in this category is reputational, so the agent should err toward escalation. + +## Prompt construction principles + +A few patterns repeat across these prompts and should be replicated when adding new ones: + +* **Show both halves**: the agent gets the policy artifact and the code-derived facts in the same prompt. Without one, the agent guesses. +* **Constrain output to JSON**: the findings flow into a downstream emitter. Prose responses cannot be parsed reliably. +* **Provide an "uncertainty" or "cannot_assess" escape**: the agent must be able to say "I don't know" rather than guess. The downstream system treats these as escalation triggers. +* **Anchor severity in objective criteria**: "critical" if special category data, "high" otherwise. The agent's tone-driven severity guesses are not useful; explicit rules are. +* **Reference the EDPB document by exact identifier when relevant**: this anchors the LLM in the correct interpretive corpus and reduces drift toward generic privacy advice. + +When iterating on these prompts based on observed false positive / negative rates, change one variable at a time and re-evaluate against a held-out set. The GDPR-Bench-Android study's accuracy numbers are a useful sanity check ceiling: if a custom prompt reports 95% accuracy on a real-world repository, it is overfitting or measuring something narrower than it claims. \ No newline at end of file diff --git a/.claude/skills/gdpr-cicd-compliance/references/breach-notification.md b/.claude/skills/gdpr-cicd-compliance/references/breach-notification.md new file mode 100644 index 00000000..9bb7e3b6 --- /dev/null +++ b/.claude/skills/gdpr-cicd-compliance/references/breach-notification.md @@ -0,0 +1,129 @@ +# Breach Notification (Articles 33 and 34) + +Article 33 imposes a 72-hour notification window from the moment the controller becomes "aware" of a personal data breach. Article 34 requires direct communication to data subjects when the breach is likely to result in a "high risk" to their rights and freedoms. EDPB Guidelines 9/2022 (Version 2.0, March 2023) define awareness, the high-risk threshold, and the controller-vs-processor split. + +Compliance with the 72-hour mandate is impossible without specific technical and organizational preparedness in advance. The scanner verifies that the preparedness exists in the repository. + +## "Awareness" - the operative trigger + +Per EDPB Guidelines 9/2022, awareness occurs when the controller has a reasonable degree of certainty that a security incident has occurred leading to the compromise of personal data. Awareness is not when the security team first sees an alert; it is when the technical and forensic facts establish, at a reasonable level of confidence, that personal data was affected. + +The 72-hour clock starts at awareness. A scanner that focuses only on the runbook misses the upstream technical question: does the observability stack actually let the team reach awareness in a timely manner? + +## Tier 1 checks: observability infrastructure + +The scanner parses monitoring and alerting configurations to verify that the necessary detection capacity exists. + +### Required signals + +The agent expects detection rules for at minimum: + +* **Mass exfiltration patterns**: outbound network volume anomalies, especially to unfamiliar destinations +* **Mass deletion**: bulk DELETE operations on PII tables outside of documented retention jobs +* **Unauthorized administrative access**: privilege escalation, root/sudo use outside documented break-glass procedures, IAM policy changes outside Terraform-driven workflows +* **Authentication anomalies**: credential stuffing, impossible-travel logins, account lockout spikes +* **Application-level anomalies**: query rate spikes against PII-bearing endpoints, unusual response sizes (a `GET /users/me` returning 50MB is not `users/me`) +* **Integrity violations**: unexpected modifications to audit logs, security configurations, or critical IAM resources + +### Configuration substrates + +The scanner reads: + +* `prometheus/alerts/*.yml` and Alertmanager routing +* Datadog monitor exports (`monitors-*.json`) +* AWS CloudWatch alarm definitions (in IaC) +* GuardDuty / Security Hub / Macie configurations +* SIEM rule definitions (Splunk, Elastic, Sentinel, Wazuh) +* Application-level audit log emitters + +For each required signal class above, the agent verifies at least one detection rule exists, and that the detection routes to a paging destination (PagerDuty, Opsgenie, on-call alias) rather than to a low-priority dashboard. + +### Logging completeness + +The detection only works if the underlying logs exist. The scanner verifies: + +* PII-bearing endpoints emit access logs to a centralized destination +* The destination is append-only or has tamper-evidence (S3 with object lock, immutable bucket, write-only IAM policies) +* Log retention covers a window long enough for forensic reconstruction (typically 12-24 months for PII access logs) +* Logs themselves do not contain PII payloads (an audit log that records "user X accessed user Y's medical record" is correct; one that records the medical record's content is itself a confidentiality breach) + +## Tier 2 checks: the runbook + +`.compliance/incident_response.md` is read by the agent and validated against EDPB Guidelines 9/2022's phase structure. + +### Phase 1: Detection and triage + +The runbook documents: +* Who is on the initial response rotation +* The classification framework (confidentiality breach, integrity breach, availability breach, or some combination) +* The threshold criteria for declaring an incident vs. a non-incident security event +* The handoff to phase 2 + +A breach can be one or more of: +* **Confidentiality breach**: unauthorized disclosure of, or access to, personal data +* **Integrity breach**: unauthorized alteration of personal data +* **Availability breach**: accidental or unlawful destruction or loss of access to personal data + +Loss of availability counts. A ransomware encryption that the controller cannot reverse is an availability breach even if no data is exfiltrated. The runbook should not treat ransomware as exclusively a security incident; it is also an Article 33 trigger. + +### Phase 2: Assessment and containment + +The runbook documents: +* The technical playbook for halting active data loss (revoke credentials, isolate hosts, block network egress) +* The forensic preservation requirements (snapshot affected systems before remediation, preserve volatile memory if relevant) +* The query playbook for answering: "Who was affected, and exactly what data?" + +The "who and what" question is the hardest one and the one most often unanswerable in practice. The scanner specifically looks for query playbooks against the audit log destinations that can answer it; absence is a major finding. + +### Phase 3: DPO and legal escalation + +The runbook documents: +* Hardcoded routing to the DPO and external legal counsel within the first hours +* The decision authority for whether the threshold for Article 33 notification is met +* The decision authority for whether Article 34 high-risk communication to data subjects is required + +### Phase 4: Supervisory authority notification + +The runbook references: +* The competent supervisory authority for the controller (typically the lead authority under the One-Stop-Shop mechanism for cross-border processing) +* The notification template and required content per Article 33(3) +* The submission portal or contact for the authority +* The escalation if the 72-hour window cannot be met (Article 33(1) permits delayed notification "where the notification to the supervisory authority is not made within 72 hours, it shall be accompanied by reasons for the delay") + +For Sweden, the competent authority is IMY (Integritetsskyddsmyndigheten). The runbook should reference the current IMY notification portal and the Swedish-language template. + +### Phase 5: Data subject communication (Article 34) + +When the breach is "likely to result in a high risk to the rights and freedoms of natural persons", communication directly to data subjects is required, in clear and plain language, "without undue delay". + +The runbook should contain: +* Pre-drafted templates for common breach scenarios (credential breach, PII exfiltration, ransomware) +* Multilingual versions for jurisdictions in scope +* The threshold logic for high-risk determination, anchored in EDPB Guidelines 9/2022 and any DPA-specific guidance +* The communication channel decision tree (email, in-app, postal, public notice) + +Article 34(3) lists exceptions: the data was encrypted to a level rendering it unintelligible, subsequent measures eliminated the high risk, or direct communication would involve disproportionate effort. The runbook should reference these exceptions explicitly so the decision is principled rather than ad hoc. + +### Phase 6: Post-incident documentation + +Article 33(5) requires the controller to document any personal data breach, regardless of whether it triggered notification, in a manner that enables the supervisory authority to verify compliance. The runbook documents the format and retention of the breach register. + +## Common runbook failures the scanner catches + +* Missing classification framework (the runbook treats all breaches as confidentiality breaches and ignores integrity / availability) +* DPO escalation path references a person who is no longer the DPO (drift; cross-reference against an HR/IDP source if available) +* Notification portal URL is deprecated or the regulator has updated the submission process +* Article 34 templates are present in only one language for a multi-jurisdiction service +* No defined query playbook for "who was affected and what data" - the runbook waves at "the security team will determine the scope" without specifying how +* No documented threshold logic for high-risk determination, leaving phase 5 to ad hoc judgment + +## Processor notification + +Article 33(2) requires processors to notify their controllers "without undue delay" upon becoming aware. The 72-hour clock for the controller starts when the controller is informed by the processor (subject to interpretation; the EDPB position is that the controller should be informed as quickly as possible to preserve the 72-hour window). + +If the repository operates as a processor for one or more controllers, the runbook documents: +* The notification SLA to controllers (typically 24 hours or sooner, set in the DPA) +* The communication channel per controller relationship +* Sample notification content + +The scanner verifies the existence of these elements when the codebase has indicators of processor operation (DPA templates in `.compliance/`, multi-tenant architecture, service-level agreements naming controller customers). \ No newline at end of file diff --git a/.claude/skills/gdpr-cicd-compliance/references/canonical-documents.md b/.claude/skills/gdpr-cicd-compliance/references/canonical-documents.md new file mode 100644 index 00000000..5e935120 --- /dev/null +++ b/.claude/skills/gdpr-cicd-compliance/references/canonical-documents.md @@ -0,0 +1,150 @@ +# Canonical Document Set + +A GDPR-aware repository contains a `.compliance/` directory holding machine-readable versions of the privacy artifacts. Treating privacy documentation as code is the precondition for every Tier 2 agentic check; without it, the auditor has no policy substrate against which to validate codebase reality. + +## Layout + +``` +.compliance/ +├── ropa.yaml # or ropa.json - Record of Processing Activities +├── dpia_inventory/ +│ ├── ml_credit_scoring.md # one DPIA per high-risk operation +│ ├── biometric_login.md +│ └── customer_segmentation.md +├── dsar_runbook.md # technical playbook for Articles 15/16/17/20 +├── transfers/ +│ ├── tia_aws_us_east_1.md # one TIA per restricted transfer +│ ├── scc_module_2_aws.pdf # executed SCCs, by module +│ └── transfers_inventory.yaml # machine-readable index +├── incident_response.md # 72-hour breach runbook +├── privacy_policy.md # forward-facing notice +└── consent_mappings.yaml # cookie/consent state to processing operation map +``` + +The structure is a convention, not a regulation. The agent should be tolerant of variants (`/.privacy/`, `/docs/compliance/`, etc.) but must locate and validate equivalents of all the artifacts above. + +## Per-artifact validation rules + +### `ropa.yaml` - Article 30 + +**Required schema**: +```yaml +processing_activities: + - id: "string" + name: "string" + purpose: "string" + lawful_basis: "consent | contract | legal_obligation | vital_interests | public_task | legitimate_interests" + data_categories: ["fideslang-label", ...] + data_subjects: ["fideslang-label", ...] + recipients: ["string", ...] # internal services + external processors + retention_period: "ISO-8601 duration" + international_transfers: + - destination: "country-code" + safeguard: "adequacy | scc_module_X | bcr | derogation_art_49" + tia_ref: "path/to/transfers/tia_*.md" + security_measures: ["string", ...] +``` + +**Tier 1 checks**: schema validity; every `data_categories` and `data_subjects` entry resolves to a Fideslang label; every `tia_ref` points to an existing file under `.compliance/transfers/`. + +**Tier 2 checks**: every flow in the Privado-generated data flow graph appears as a `processing_activities` entry, and vice versa. The agentic prompt for this is in `agentic-prompts.md`. + +**Common failure mode**: the RoPA is hand-maintained and drifts the moment a developer adds a new third-party SDK or a new database column. Drift is the rule, not the exception. The scanner exists primarily to catch this. + +### `dpia_inventory/` - Article 35 + +Each file is a DPIA for a single high-risk processing operation. Structure follows the EDPB DPIA template (April 2026 update): + +1. Systematic description of envisaged processing operations and purposes +2. Assessment of necessity and proportionality +3. Assessment of risks to data subjects' rights and freedoms +4. Measures envisaged to address the risks (including safeguards, security measures, mechanisms to ensure protection) +5. Date and signature of the DPO consultation +6. Where applicable, prior consultation with the supervisory authority (Art. 36) + +**Tier 1 checks**: file presence per high-risk trigger detected in code; section headers match the EDPB template. + +**Tier 2 checks**: the "measures envisaged" section names specific technical controls that the agent can then verify exist in code (encryption keys managed by service X, access logged to service Y, etc.). If the DPIA promises a control that the codebase does not implement, the scanner flags a DPIA-vs-implementation drift. + +### `dsar_runbook.md` - Articles 15-22 + +Documents the technical mechanism by which each data subject right is satisfied. For each right, expected content: + +* Endpoint(s) involved +* Authentication mechanism +* Identity verification procedure (proof-of-identity above the API auth layer) +* Microservices queried (with explicit join logic for distributed PII) +* SLA against the 30-day Article 12(3) window +* Escalation path for ambiguous requests (e.g., requests touching ongoing legal proceedings, conflicting data subjects) + +**Tier 2 check**: the agent reads the runbook, extracts the named endpoints, and verifies each exists in the API layer with the documented authentication and behavior. + +### `transfers/` - Articles 44-49 + +`transfers_inventory.yaml` is the machine-readable index: + +```yaml +transfers: + - destination_country: "US" + destination_service: "aws-us-east-1" + fideslang_data_categories: ["user.contact.email", "user.preferences"] + safeguard: "scc_module_2" + scc_executed_date: "2024-03-15" + scc_artifact: "transfers/scc_module_2_aws.pdf" + tia_artifact: "transfers/tia_aws_us_east_1.md" + supplementary_measures: + - "encryption in transit (TLS 1.3)" + - "encryption at rest with CMK held in EU" + - "pseudonymization of direct identifiers prior to transfer" +``` + +Detailed Schrems II evaluation logic is in `transfers-schrems-ii.md`. + +### `incident_response.md` - Articles 33 and 34 + +Detailed phase structure and EDPB Guidelines 9/2022 alignment in `breach-notification.md`. The high-level required phases: + +1. Detection and triage (confidentiality / integrity / availability classification) +2. Assessment and containment +3. DPO and legal escalation paths +4. Supervisory authority notification (within 72 hours of awareness) +5. Data subject communication (Article 34, when high risk) +6. Post-incident review and Article 33(5) documentation + +### `privacy_policy.md` - Articles 12, 13, 14 + +The user-facing notice. The agent verifies: + +* Every Fideslang `data_category` actually processed by the codebase appears in the policy +* Every `data_use` actually invoked appears in the policy as a stated purpose +* Every recipient (third-party SDK, processor) appears in the policy +* Retention periods named in the policy match the retention enforcement in code +* Lawful basis named in the policy matches the basis declared in `ropa.yaml` + +**Common failure mode**: the legal team updates the privacy policy on a quarterly cadence; the engineering team adds a new analytics SDK on a Tuesday afternoon. The policy is now lying to data subjects. The scanner catches this within the same PR. + +### `consent_mappings.yaml` + +Maps cookie / consent state to the processing operations they unlock. Used by the agent to validate frontend consent logic against backend behavior: + +```yaml +consent_categories: + strictly_necessary: + fideslang_data_uses: ["provide.service.operations"] + consent_required: false + analytics: + fideslang_data_uses: ["improve.system", "improve.system.analytics"] + consent_required: true + cookie_names: ["_ga", "_gid"] + marketing: + fideslang_data_uses: ["marketing.advertising.first_party.contextual"] + consent_required: true +``` + +The agent uses this to check, for example, that no script tagged as `marketing` initializes before the user has accepted the marketing consent category. + +## Drift as the primary failure mode + +In every category above, the dominant failure mode is not the absence of the artifact but its silent divergence from code reality. A scanner that only checks for file existence is performing security theater. Every Tier 2 check in this file is, fundamentally, a drift check. + +The agent's mental model: each artifact is a *contract* between legal and engineering, expressed in code-adjacent form. Drift is contract breach. \ No newline at end of file diff --git a/.claude/skills/gdpr-cicd-compliance/references/cross-framework-mapping.md b/.claude/skills/gdpr-cicd-compliance/references/cross-framework-mapping.md new file mode 100644 index 00000000..1f7bf037 --- /dev/null +++ b/.claude/skills/gdpr-cicd-compliance/references/cross-framework-mapping.md @@ -0,0 +1,59 @@ +# Cross-Framework Mapping + +The Secure Controls Framework (SCF) operates as a Living Control Set (LCS) and provides Set Theory Relationship Mapping (STRM) between regulatory regimes. The SCF translates the GDPR into 1,400+ discrete technical controls across 33 domains, and exports its mappings as NIST OSCAL JSON. The scanner ingests this OSCAL artifact to emit multi-framework evidence tags from a single technical check. + +When a GDPR violation is detected, the agent should output the GDPR article *and* the equivalent identifier in NIST 800-53 Rev 5, ISO/IEC 27001:2022 Annex A, SOC 2 TSC, and CIS Controls v8. This serves the typical compliance team that operates against multiple regimes simultaneously and reduces remediation duplication. + +## The crosswalk table + +The mapping below is the operational core. The agent should treat it as authoritative for the GDPR articles enumerated; for less common articles, fall back to the SCF OSCAL export. + +| GDPR | Verifiable technical objective | NIST 800-53 R5 | ISO/IEC 27001:2022 Annex A | SOC 2 TSC | CIS v8 | +|------|---------------------------------|----------------|----------------------------|-----------|--------| +| Art. 5(1)(f), Art. 32 | Encryption at rest (AES-256) and in transit (TLS 1.2+); key management | SC-8 (Transmission Confidentiality and Integrity), SC-28 (Protection of Information at Rest), SC-12 (Cryptographic Key Establishment) | A.8.24 (Use of cryptography) | CC6.1 (Logical Access), CC6.6 (Boundary Protection), CC6.7 (Data Transmission) | 3.10, 3.11 (Data protection) | +| Art. 5(1)(c) | Data minimization in API schemas and data collection | PT-2 (Authority to Process), PT-3 (PII Processing Purposes) | A.5.34 (Privacy and protection of PII) | P3.1, P3.2 (Privacy purpose) | 3.1 (Data management process) | +| Art. 5(1)(e), Art. 17 | Storage limitation, retention enforcement, irreversible erasure | SI-12 (Information Management and Retention), MP-6 (Media Sanitization) | A.5.10 (Acceptable use), A.8.10 (Information deletion) | P4.2 (Privacy retention), P4.3 (Privacy erasure) | 3.4 (Data retention), 3.5 (Disposal) | +| Art. 25 | Privacy by design and default; least privilege; secure defaults | AC-2 (Account Management), AC-3 (Access Enforcement), AC-6 (Least Privilege), CM-6 (Configuration Settings), CM-7 (Least Functionality) | A.5.15 (Access control), A.8.2 (Privileged access rights), A.8.9 (Configuration management) | CC6.1, CC6.3 (Logical and Physical Access) | 3.3 (Access control list), 4.1 (Secure configuration) | +| Art. 30 | Records of Processing Activities; data inventory; data flow mapping | PM-5 (System Inventory), PT-2, PT-3, CM-8 (System Component Inventory) | A.5.9 (Inventory of information and other associated assets), A.5.34 | CC6.1 (Information Asset Inventory), P3.1 | 1.1 (Asset inventory), 3.2 (Data inventory) | +| Art. 32, Art. 5(1)(f) | Continuous logging, integrity monitoring, secret scanning | AU-2 (Event Logging), AU-12 (Audit Generation), SI-7 (Software Integrity), IA-5 (Authenticator Management) | A.8.15 (Logging), A.8.16 (Monitoring activities), A.5.17 (Authentication information) | CC7.1, CC7.2 (System Operations) | 8.1, 8.2 (Audit log management) | +| Art. 33, Art. 34 | Incident detection, response, breach notification within 72 hours | IR-4 (Incident Handling), IR-6 (Incident Reporting), IR-8 (Incident Response Plan) | A.5.24 (Information security incident management planning), A.5.25 (Assessment and decision on information security events), A.5.26 (Response to information security incidents) | CC7.3 (Incident detection), CC7.4 (Incident response) | 17.1-17.9 (Incident response) | +| Art. 35 | DPIA for high-risk processing; risk assessment | RA-3 (Risk Assessment), RA-8 (Privacy Impact Assessments), PT-7 (Specific Categories of PII) | A.5.30 (ICT readiness), A.5.34 | P1.1 (Privacy notice), P6.1-P6.6 (Privacy disclosure and notification) | n/a (CIS does not address DPIA) | +| Art. 15-21 | Data subject rights endpoints; access, rectification, erasure, portability | PT-4 (Consent), PT-5 (Privacy Notice), PT-6 (System of Records Notice), PM-21 (Accounting of Disclosures) | A.5.34, A.8.10 (Information deletion), A.8.11 (Data masking) | P4.1 (Privacy access), P4.3 (Privacy erasure), P5.1 (Privacy disclosure) | n/a | +| Art. 44-49 | International transfers, SCCs, TIAs, supplementary measures | SR-3 (Supply Chain Controls and Processes), AC-21 (Information Sharing), CA-3 (Information Exchange) | A.5.20 (Addressing information security within supplier agreements), A.5.21 (Managing information security in the ICT supply chain), A.5.31 (Legal, statutory, regulatory and contractual requirements) | CC9.2 (Vendor Risk), C1.1 (Confidentiality) | 15.1-15.7 (Service provider management) | +| Art. 32 | Backup and recovery; ability to restore | CP-9 (System Backup), CP-10 (System Recovery and Reconstitution) | A.8.13 (Information backup), A.5.30 (ICT readiness for business continuity) | A1.2 (Availability backup), A1.3 (Recovery testing) | 11.1-11.5 (Data recovery) | + +## SCF OSCAL ingestion + +The full SCF OSCAL export is available from the SCF's GitHub. The scanner should: + +1. Pin a specific SCF release version in the build pipeline (the SCF is a Living Control Set; mappings change). +2. Parse the OSCAL JSON to build an in-memory map: `gdpr_article -> [scf_control_id, ...] -> [external_framework_control_id, ...]`. +3. When a check fails, the scanner traverses from the GDPR article through the SCF control to all linked external framework controls, and emits the full set in the output. + +## Output format + +A single technical violation should produce a finding shaped like: + +```json +{ + "rule_id": "gdpr-32-unencrypted-storage", + "severity": "high", + "file": "infrastructure/terraform/s3.tf", + "line": 42, + "evidence": "aws_s3_bucket.user_uploads has server_side_encryption_configuration absent", + "framework_mappings": { + "gdpr": ["Art. 32(1)(a)"], + "nist_800_53_r5": ["SC-28"], + "iso_27001_2022": ["A.8.24"], + "soc2_tsc": ["CC6.1", "CC6.6"], + "cis_v8": ["3.11"] + }, + "remediation": "Add server_side_encryption_configuration block with sse_algorithm = \"AES256\" and (for restricted-transfer destinations) a CMK ARN." +} +``` + +This structure satisfies a vendor risk team running ISO 27001, an enterprise customer demanding SOC 2 evidence, and a European DPA simultaneously, from a single repository scan. + +## DPMP reference + +The SCF also incorporates the Data Privacy Management Principles (DPMP), which organize 86 individual privacy principles into 11 domains and map them to 31 global privacy frameworks. When the customer organization operates outside the EU but processes EU data subject information, the DPMP layer is what extends GDPR-aligned controls to PIPEDA, LGPD, CCPA/CPRA, and other regimes. The mapping logic is identical: GDPR article -> SCF control -> DPMP principle -> destination-framework control identifier. \ No newline at end of file diff --git a/.claude/skills/gdpr-cicd-compliance/references/dsar-api-patterns.md b/.claude/skills/gdpr-cicd-compliance/references/dsar-api-patterns.md new file mode 100644 index 00000000..2ba0269d --- /dev/null +++ b/.claude/skills/gdpr-cicd-compliance/references/dsar-api-patterns.md @@ -0,0 +1,145 @@ +# DSAR API Patterns + +Articles 15-22 require the data controller to fulfill data subject requests within 30 days (Article 12(3), extendable by two months for complex cases). The scanner verifies that the repository implements specific endpoint patterns and that the OpenAPI contracts enforce purpose limitation. + +## Required endpoints + +The agent searches for endpoints satisfying the access (Art. 15), erasure (Art. 17), and portability (Art. 20) rights. Rectification (Art. 16) is typically satisfied through the existing user-profile-update endpoint and is verified differently. Restriction (Art. 18) and objection (Art. 21) usually correspond to flag-flip operations on processing consent. + +### Access (Art. 15) + +``` +GET /api/v1/privacy/user/data +Authorization: Bearer +Accept: application/json +``` + +**Behavior**: aggregates and returns a unified profile of all personal data the controller holds about the requesting subject across the entire microservice architecture. + +**Verification rules**: +* The endpoint exists and is registered in the OpenAPI spec. +* The controller method invokes a documented aggregation function (not a single-table query). +* Response schema includes every Fideslang `data_category` documented in `.compliance/ropa.yaml` for the subject's category. +* Identity verification beyond the API auth layer is documented in `.compliance/dsar_runbook.md` (proof-of-identity requirement, since a stolen access token must not enable a full data dump). + +### Erasure (Art. 17) + +``` +DELETE /api/v1/privacy/user/data +Authorization: Bearer +``` + +**Behavior**: triggers irreversible deletion or cryptographic shredding across all data stores. Returns a job identifier for asynchronous processing tracking. + +**Verification rules** (the highest-frequency violation site): +* The handler does NOT execute `UPDATE ... SET is_deleted = true` (or equivalent ORM soft-delete). The agent traces the controller statically. +* The handler invokes a documented hard-delete or cryptographic-shredding function on each data store enumerated in the RoPA. +* Legitimate retention overrides (tax law, AML) are documented in the DPIA or RoPA, with the specific fields and retention bases enumerated. The handler honors these overrides via specific conditional logic (not a general soft-delete fallback). +* The job state is auditable and the controller can demonstrate completion within 30 days. + +### Portability (Art. 20) + +``` +GET /api/v1/privacy/user/export +Authorization: Bearer +Accept: application/json | text/csv +``` + +**Behavior**: serializes the subject's data into a structured, commonly used, machine-readable format. JSON or CSV are the typical defaults; XML or other open formats are also acceptable. + +**Verification rules**: +* The response is structured (not a PDF or HTML rendering of profile data). +* The schema is the same shape as Article 15 for the data the subject provided to the controller (Article 20(1) is narrower in scope than Article 15; only data the subject has provided is portable). + +### Rectification (Art. 16) + +Typically the existing `PUT /api/v1/users/me` or equivalent. The verification check is that the same endpoint also exists for non-self-service modifications when the subject's request must be processed asynchronously. + +### Restriction and objection (Art. 18, Art. 21) + +``` +POST /api/v1/privacy/user/restrict +POST /api/v1/privacy/user/object +``` + +**Behavior**: flag-flip operations that alter downstream processing. The verification check is that the flag is *honored* by the relevant processing operations - the agent traces from the flag store to the processing operations registered against it in the RoPA. + +## OpenAPI Schema validation + +Purpose limitation (Article 5(1)(b)) is mechanically enforceable through schema validation. Two rules: + +### `additionalProperties: false` + +Every data-ingestion request schema must set `additionalProperties: false`. Without it, the schema admits unbounded extraneous fields that bypass the data minimization principle. + +```yaml +components: + schemas: + CreateUserRequest: + type: object + additionalProperties: false # required + required: [email, locale] + properties: + email: { type: string, format: email, x-fideslang: "user.contact.email" } + locale: { type: string, x-fideslang: "user.preferences" } +``` + +### Fideslang annotation alignment with declared scope + +The agent reads the OAuth scope required by the endpoint (e.g., `customer_support`) and validates against the response schema's Fideslang annotations. An endpoint scoped `customer_support` must not return fields annotated `user.payment.credit_card_number` or `user.behavior.browsing_history` - those scopes are not commensurate with customer support purposes. + +## RBAC and identity verification + +DSAR endpoints are high-value targets. An attacker with a stolen access token effectively has the keys to a complete data dump. Two layers of defense are required: + +### API-layer authentication + +OAuth 2.0 or OpenID Connect with strict scope. The token must carry a scope specific to DSAR operations (e.g., `dsar:self`); a general `user` scope is insufficient. + +### Identity proofing + +The DSAR runbook documents a proof-of-identity step beyond the access token. Common patterns: +* Email-link confirmation to the registered address with a short TTL +* Multi-factor reauthentication +* Knowledge-based verification questions (less preferred) +* For high-sensitivity contexts, a manual review step + +The agent verifies that the runbook documents this and that the endpoint's controller logic invokes the documented verification function. + +## Third-party PII redaction + +Article 15(4) limits the right of access to the extent that providing data would adversely affect the rights and freedoms of others. In practice: a chat log including messages from other users, a shared document with co-author identities, an organization context with peer information. + +The agent verifies that the response builder for `GET /api/v1/privacy/user/data` invokes a documented redaction function over fields that may contain third-party PII. The redaction function must: + +* Replace direct identifiers (other users' names, email addresses) with anonymous placeholders +* Strip metadata that could re-identify the third party (user IDs, session IDs) +* Preserve the structural relationship for the requesting subject's understanding (so a chat log remains coherent without naming the other party) + +The check is partly Tier 1 (the function exists and is invoked) and partly Tier 2 (the redaction is sufficient given the actual third-party data shapes in scope). + +## Asynchronous job tracking + +Erasure and large-scale exports cannot complete synchronously. The agent verifies the existence of: + +* A job creation endpoint that returns a job identifier +* A status endpoint to poll job completion +* A retention period for the job artifact (export downloads must expire; the export file itself is sensitive PII) +* An audit log of job initiation, progression, and completion, with each entry tied to the requesting subject + +## Idempotency and replay + +DSAR endpoints should be idempotent at the request level. A subject who issues an erasure request twice in error should not have the request re-queued or duplicated. The agent checks for an idempotency key pattern in the controller, typically a request ID or a content-derived hash. + +## Common failure modes by article + +| Article | Common DSAR endpoint failure | +|---------|------------------------------| +| Art. 15 | Endpoint returns only the primary user table; misses records in event store, analytics warehouse, message queues, third-party processors | +| Art. 17 | Soft-delete masquerading as erasure | +| Art. 17 | Backups not addressed; deleted data remains recoverable indefinitely | +| Art. 20 | Format is not machine-readable (PDF), or limited to data the controller derived rather than data the subject provided | +| Art. 18 | Flag flipped but downstream processors do not consult the flag | +| Art. 21 | Marketing systems not wired to the objection flag; opt-out is not honored | + +The scanner should emit specific findings against each of these patterns when detected. \ No newline at end of file diff --git a/.claude/skills/gdpr-cicd-compliance/references/gdpr-articles.md b/.claude/skills/gdpr-cicd-compliance/references/gdpr-articles.md new file mode 100644 index 00000000..8a59884d --- /dev/null +++ b/.claude/skills/gdpr-cicd-compliance/references/gdpr-articles.md @@ -0,0 +1,125 @@ +# GDPR Articles - Operative Subset + +The articles below form the verifiable core of an automated GDPR scanner. Each entry gives the legal scope, the technical intent for an automated auditor, the verification tier, and the concrete artifacts the scanner inspects. + +The agent must reference articles by exact identifier in its output. Multi-framework crosswalks for each article live in `cross-framework-mapping.md`. + +## Article 5 - Principles relating to processing of personal data + +**Scope**: Lawfulness, fairness, transparency, purpose limitation, data minimization, accuracy, storage limitation, integrity and confidentiality (the "security principle"), and accountability. + +**Technical intent**: Verify that data collection mechanisms are scoped strictly to stated purposes (no over-collection), that retention policies exist and are mechanically enforced, and that integrity/confidentiality is upheld through cryptographic primitives. + +**Tier**: Mixed. Tier 1 for retention scripts, schema minimality, and encryption. Tier 2 for purpose limitation against stated business purpose in OpenAPI documentation. + +**Artifacts inspected**: +* OpenAPI request and response schemas (over-collection detection) +* Cron jobs and lifecycle policies for storage (retention enforcement) +* ORM column definitions and IaC encryption flags (integrity/confidentiality) +* `.compliance/privacy_policy.md` claims vs. actual fields collected (transparency) + +## Article 6 - Lawfulness of processing + +**Scope**: Establishes the six lawful bases (consent, contract, legal obligation, vital interests, public task, legitimate interests). + +**Technical intent**: For each processing operation, verify that the declared lawful basis is structurally compatible with the operation. Consent-based operations require evidence of opt-in capture; legitimate-interest operations require a documented LIA (Legitimate Interests Assessment). + +**Tier**: Tier 2. The legal basis is declared in `.compliance/ropa.yaml` per processing activity; the agent reads the declaration and validates it against the code path. + +**Common violation**: invoking a sensitive API (camera, geolocation, contacts) without a preceding consent check. From the document, an Android example: `manager.openCamera(cameraId, stateCallback, null)` with no preceding conditional gating consent state. + +## Article 9 - Special categories of personal data + +**Scope**: Prohibits processing of racial/ethnic origin, political opinions, religious beliefs, trade union membership, genetic data, biometric data, health data, and data concerning sex life or sexual orientation. Lifted only by one of the Article 9(2) exceptions (explicit consent, vital interests, substantial public interest, etc.). + +**Technical intent**: Detect any code path or schema field annotated as a special category and require an explicit Article 9(2) basis declaration in the RoPA, plus matching consent capture infrastructure if the basis is 9(2)(a). + +**Tier**: Tier 1 detection of the field via Fideslang labels (`user.health.*`, `user.biometric.*`, `user.genetic.*`); Tier 2 validation of the declared 9(2) basis. + +**Hard rule**: an endpoint with Fideslang `data_use: marketing.advertising.third_party` and any data category under `user.health.*`, `user.biometric.*`, or `user.genetic.*` is an immediate, non-suppressible Article 9 violation. Marketing is never a valid 9(2) basis. + +## Articles 15-22 - Data subject rights + +**Scope**: Access (15), rectification (16), erasure / right to be forgotten (17), restriction (18), portability (20), objection (21), automated decision-making (22). + +**Technical intent**: Verify the existence of dedicated, RBAC-protected API endpoints satisfying each right within 30 days. Detailed REST patterns and JSON Schema rules are in `dsar-api-patterns.md`. + +**Tier**: Tier 1 for endpoint existence and method shape; Tier 2 for tracing the execution path of `DELETE /api/v1/privacy/user/data` to verify hard deletion (or cryptographic shredding) rather than a soft-delete boolean toggle. + +**Article 17 anti-pattern (highest-frequency violation)**: implementing erasure as `UPDATE users SET is_deleted = 1`. This is non-compliant. The right to erasure requires hard deletion or mathematically irreversible anonymization. The agent must trace the controller method statically and flag any soft-delete pattern. + +**Article 22**: see `limitations.md`. The scanner can detect ML model deployment; it cannot adjudicate whether human review is "meaningful". + +## Article 25 - Data protection by design and by default + +**Scope**: Embedding privacy-enhancing technologies (PETs) into system architecture from the earliest design stages. Default settings must be the most privacy-preserving available. + +**Technical intent**: Audit configuration files for secure defaults (minimum necessary permissions, tracking disabled by default, opt-in rather than opt-out flows). Verify IaC implements least-privilege architectures. + +**Tier**: Tier 1 across IaC (Terraform, CloudFormation, Pulumi) for IAM policy granularity, default-deny network rules, default-encrypted storage, and disabled telemetry. + +**Common violations**: +* `Access-Control-Allow-Origin: *` on endpoints serving authenticated PII +* AWS S3 buckets with `public-read` default ACL +* Mobile app `AndroidManifest.xml` requesting `ACCESS_FINE_LOCATION` or `READ_CONTACTS` without functional necessity tied to declared purpose +* Missing `Strict-Transport-Security`, `Content-Security-Policy`, `X-Content-Type-Options` headers + +## Article 30 - Records of processing activities (RoPA) + +**Scope**: Comprehensive documentation of personal data flows, categories of data subjects, processing purposes, recipients (including third parties), retention periods, and (for international transfers) the safeguards in place. + +**Technical intent**: Validate the existence and structural integrity of `.compliance/ropa.yaml`, then reconcile its declared flows against the data flow graph generated by Privado. Any flow appearing in code but not in the RoPA, or vice versa, is a synchronization violation. + +**Tier**: Tier 1 for schema validation; Tier 2 for the RoPA-vs-actual-flow reconciliation. + +**Drift detection prompt** (excerpt; full version in `agentic-prompts.md`): the agent receives the parsed RoPA and the Privado JSON, and is asked to enumerate flows present in one but not the other. Drift directly violates Art. 30(1) and is a precondition for almost every downstream GDPR violation. + +## Article 32 - Security of processing + +**Scope**: Appropriate technical and organizational measures, with explicit examples: pseudonymization, encryption, ability to ensure ongoing confidentiality / integrity / availability / resilience, ability to restore access in a timely manner after an incident, and a process for regularly testing those measures. + +**Technical intent**: The most deterministically scannable article. Hardcoded secrets, weak cryptography, plaintext transmission, unencrypted storage, missing backup configurations, and absent restore procedures are all Tier 1. + +**Tier**: Tier 1 for nearly everything. + +**Detection rules**: +* Secret scanning via GitLeaks or Semgrep against the full Git history (not just HEAD) +* TLS configuration parsing rejecting SSLv3, TLS 1.0, TLS 1.1, and weak cipher suites +* IaC parsing for `encrypted: true` on storage resources, with KMS key ARN validation +* ORM annotation scanning for sensitive entities (`SocialSecurityNumber`, `HealthRecord`, anything Fideslang-labeled `user.payment.*` or `user.health.*`) without encryption decorators +* Backup job verification (cron presence + retention period + restore drill schedule) + +## Articles 33 and 34 - Personal data breach notification + +**Scope**: Article 33 imposes a 72-hour notification window to the supervisory authority from the moment of "awareness". Article 34 requires direct communication to data subjects when the breach is likely to result in a "high risk" to their rights and freedoms. EDPB Guidelines 9/2022 (Version 2.0, March 2023) define the operative thresholds. + +**Technical intent**: Verify that the repository's monitoring, alerting, and runbook infrastructure can technically support the 72-hour window. The runbook itself is a Tier 2 artifact; the alerting infrastructure is Tier 1. + +**Tier**: Tier 1 for monitoring configurations (Prometheus alert rules, Datadog monitors, CloudWatch alarms, OpenSearch detectors); Tier 2 for `.compliance/incident_response.md` evaluation against EDPB Guidelines 9/2022 phases. + +Full decomposition in `breach-notification.md`. + +## Article 35 - Data protection impact assessment (DPIA) + +**Scope**: Required for any processing "likely to result in a high risk to the rights and freedoms of natural persons", with explicit triggers including systematic and extensive automated profiling, large-scale processing of special categories, and systematic monitoring of publicly accessible areas. + +**Technical intent**: Identify code patterns matching high-risk criteria (ML profiling, biometric processing, large-scale special-category handling, public-area monitoring) and require a corresponding DPIA in `.compliance/dpia_inventory/` structured against the EDPB DPIA template (April 2026 update). + +**Tier**: Tier 1 for the trigger detection (ML library imports, biometric API calls); Tier 2 for the DPIA artifact structural and content validation. + +**Trigger heuristics**: +* Imports of `tensorflow`, `pytorch`, `sklearn`, `xgboost`, `lightgbm` in production paths +* Calls to facial recognition, voice analysis, or fingerprinting APIs +* Cross-database joins producing comprehensive individual profiles + +When triggered without a corresponding DPIA, the scanner blocks the pipeline. + +## Articles 44-49 - Transfers to third countries + +**Scope**: Prohibits transfers of personal data outside the EEA absent an adequacy decision (Art. 45), appropriate safeguards (Art. 46, including the 2021 modular SCCs and Binding Corporate Rules), or a derogation (Art. 49). Schrems II (CJEU C-311/18) requires that even with SCCs, the controller must perform a Transfer Impact Assessment and apply supplementary measures where the destination's law undermines EU protection. + +**Technical intent**: Trace data flows to external sinks, resolve their geographic location, classify as restricted transfer if non-EEA, and validate corresponding SCC + TIA + supplementary measures in `.compliance/transfers/`. + +**Tier**: Tier 1 for IP/hostname geolocation and TIA-mandated technical measure verification (CMK enforcement, EU-resident key custody); Tier 2 for SCC module selection correctness (Module 1 controller-to-controller, Module 2 controller-to-processor, Module 3 processor-to-processor, Module 4 processor-to-controller). + +Full decomposition in `transfers-schrems-ii.md`. \ No newline at end of file diff --git a/.claude/skills/gdpr-cicd-compliance/references/limitations.md b/.claude/skills/gdpr-cicd-compliance/references/limitations.md new file mode 100644 index 00000000..4fdf27c4 --- /dev/null +++ b/.claude/skills/gdpr-cicd-compliance/references/limitations.md @@ -0,0 +1,118 @@ +# Limits of Automation + +The honest scope of what an automated GDPR scanner cannot do. A scanner that pretends otherwise is itself a compliance risk, because it produces a false sense of completeness while the actual high-stakes legal questions go unaddressed. + +This document enumerates the categories of GDPR question that fall outside automation's reach, and prescribes how the scanner should behave when it encounters them: surface, halt, escalate, never silently pass. + +## Article 22: automated decision-making with legal or similarly significant effects + +Article 22 protects individuals from decisions based "solely" on automated processing that produce "legal effects" or "similarly significantly affect" them. Hiring decisions, credit scoring, insurance underwriting, parole risk assessment, eligibility for state benefits - these are paradigm cases. Recommender systems and ad targeting are usually not, but can become so depending on context (e.g., serving high-stakes ads only to certain demographic clusters). + +What the scanner can do: +* Detect the presence of an ML model in a production code path +* Identify the model's role in a decision pipeline (advisory, gating, automated) +* Verify a DPIA exists for the operation if it is high-risk +* Extract from the DPIA the declared mitigation measures and check them against code + +What the scanner cannot do: +* Adjudicate whether the decision produces "legal effects" or "similarly significantly affects" the data subject. This is fact-specific legal interpretation. +* Adjudicate whether a human in the loop constitutes "meaningful human involvement" or is a rubber stamp. The CPPA's recent rules and the EDPB's guidance both emphasize this distinction, but it cannot be measured statically. A reviewer who clicks "approve" on 1,000 cases per day is rubber-stamping; a reviewer who reads each case takes 10 minutes per case. The scanner cannot tell from code which is happening. +* Adjudicate whether the operation falls within the Article 22(2) exceptions (necessary for contract, authorized by law, based on explicit consent). + +What the scanner does: +* When it detects a model in a pipeline that touches Fideslang categories `user.financial.*`, `user.employment.*`, `user.legal.*`, `user.health.*`, `user.behavior.children.*`, or `user.demographic.protected_class`, it halts the pipeline. +* It emits a structured escalation: "Article 22 review required. Detected model at . Decision pipeline shape: . DPIA present: yes/no. Human review step present in code: yes/no. The following questions cannot be answered automatically: [whether the decision produces legal effects, whether human involvement is meaningful, whether an Article 22(2) exception applies]. Resolution requires DPO sign-off." +* It does not emit a pass. + +## Article 9: special category processing under "substantial public interest" + +Article 9(2)(g) permits processing of special category data when "necessary for reasons of substantial public interest, on the basis of Union or Member State law". This is the basis under which research databases, public health systems, and certain national security operations process health, biometric, or other special category data. + +What the scanner cannot do: +* Adjudicate whether a stated public interest is "substantial". +* Verify the existence and current status of the Union or Member State legal basis claimed. +* Weigh the public interest against the data subjects' rights (the proportionality test). + +What the scanner does: +* When it detects special category processing with declared basis `art_9_2_g_substantial_public_interest`, it requires: + - A reference in the DPIA to the specific Union or Member State law providing the basis + - A reference to the proportionality assessment + - A reference to safeguards specific to special category processing +* It does not adjudicate the substance, but it does verify the artifacts that an audit would need to evaluate the substance exist. + +## Risk-based provisions: "appropriate measures", "high risk", "undue delay" + +The GDPR is replete with standards rather than rules. "Appropriate technical and organizational measures" (Art. 32). "High risk to the rights and freedoms of natural persons" (Art. 35, Art. 34). "Without undue delay" (Art. 12, Art. 33). "Likely to result in" (Art. 35, Art. 34). + +The scanner cannot adjudicate these standards directly. It can: +* Encode common heuristics as defaults (TLS 1.2+ is appropriate; TLS 1.0 is not; AES-256 is appropriate; DES is not) +* Verify that a DPIA explicitly addresses the risk question +* Verify that the runbook defines operational thresholds rather than leaving them to ad hoc judgment + +It cannot: +* Decide whether a specific implementation is "appropriate" in a contested case +* Decide whether a specific breach is "high risk" without DPO judgment +* Decide whether a specific delay was "undue" + +When the scanner cannot decide, it should not pretend to. A "needs DPO review" finding is a complete answer. + +## Cross-border legal landscape changes + +Adequacy decisions are issued, suspended, and revoked. The CJEU rules on standing concepts (Schrems II invalidated the Privacy Shield in a single decision). National DPA enforcement priorities shift. + +The scanner pins reference data (the adequacy decision list, the SCC module text, the EDPB guideline versions) at a specific date. It cannot self-update with currency. The scanner emits a soft warning when its reference data is older than 90 days and a hard requirement when it is older than 365 days, prompting the operator to update. + +The scanner does not pretend to know about cases or guidelines published after its reference date. + +## Out-of-repository organizational facts + +Several Tier 3 facts cannot be verified from code at all. The scanner expects evidence pointers but cannot validate the substance: + +* DPO competence and independence (Art. 38, 39) +* Effective implementation of training programs +* Real-world execution of contractual safeguards (a signed DPA does not guarantee the processor honors it) +* Physical security measures +* Governance independence between data controller and security functions + +For each of these, the scanner verifies that an evidence pointer exists pointing somewhere in principle accountable. It does not verify that the underlying claim is true. + +## The boundary the scanner enforces + +The scanner's contract with its operator is precise: + +| Category | Scanner verdict | +|----------|-----------------| +| Tier 1 violation present | Block the build, specific finding | +| Tier 2 violation present | Block the build, agentic explanation | +| Tier 3 evidence pointer missing | Block the build, request evidence URI | +| Article 22 / Article 9(2)(g) / risk-based provision implicated | Block the build, escalate to DPO | +| Reference data is stale | Soft warning to operator, hard block above threshold | +| Suppression with valid justification | Pass with logged exception | +| Everything checks out | Pass | + +There is no "pass with concerns" verdict. The scanner either passes or escalates; concerns become concrete blocks or concrete escalations. This is what makes the scanner useful. A scanner that emits ambient anxiety without actionable next steps becomes background noise that engineers route around. + +## Why the limits matter + +Two failure modes haunt automated compliance: + +**False confidence**: the scanner passes, the engineer ships, the regulator later finds a violation in territory the scanner never covered. The organization then claims good-faith reliance on tooling, which the regulator does not credit because the violation was in a category any competent privacy program would have addressed manually. + +**Alert fatigue**: the scanner emits dozens of low-confidence warnings on every PR. Engineers learn to ignore them or to suppress them en masse. The signal-to-noise ratio collapses, and a real violation passes unnoticed. + +The remedy for both is the same: be honest about what the scanner does and does not check. Tier 1 findings are mechanical and high-confidence; emit them with conviction. Tier 2 findings are agentic and require human review; mark them as such. Tier 3 facts are out of repo; collect pointers, do not pretend to verify substance. And for the genuinely subjective questions (Art. 22, substantial public interest, undue delay), do not emit a verdict at all - escalate. + +The scanner's value is in the boundary it draws between "this is mechanically wrong" and "this requires legal judgment". Both halves are necessary; both halves must be honestly named. + +## Reference: the human-in-the-loop pattern + +The deployment pattern this skill is built for is not "automated GDPR compliance". It is "automated elimination of routine compliance errors, with structured escalation of substantive questions to a Data Protection Officer". + +The DPO uses the scanner's outputs to: +* Spend zero time on Tier 1 findings (they are auto-blocked, the engineer fixes them, no DPO involvement) +* Spend modest time auditing Tier 2 findings (the agentic reasoning is a draft; the DPO reviews and accepts or rejects) +* Spend the bulk of their time on the substantive questions the scanner correctly refuses to answer (Article 22, Article 9 substantial public interest, proportionality) + +This division of labor is what justifies the engineering investment. The scanner makes the DPO more effective by removing routine work from their plate; it does not replace the DPO. + +A scanner sold as a DPO replacement is being mis-sold. A scanner sold as a DPO force multiplier is being sold honestly. \ No newline at end of file diff --git a/.claude/skills/gdpr-cicd-compliance/references/tool-orchestration.md b/.claude/skills/gdpr-cicd-compliance/references/tool-orchestration.md new file mode 100644 index 00000000..bf610338 --- /dev/null +++ b/.claude/skills/gdpr-cicd-compliance/references/tool-orchestration.md @@ -0,0 +1,133 @@ +# Tool Orchestration + +Build the scanner as an orchestrator over specialized open-source tools, not a bespoke static analysis engine. Each tool below has been refined to outperform a general scanner within its niche; the skill's contribution is the unified data model (Fideslang), the agentic reasoning over standardized outputs, and the multi-framework finding format. + +## The Fideslang taxonomy + +The Fideslang privacy taxonomy (developed by Ethyca, maintained with the IAB Tech Lab) is the standardization layer. Without it, each tool emits findings in its own ontology, and cross-tool reasoning is impossible. + +Three orthogonal label axes: + +* **Data categories**: what the data is. Hierarchical. `user.contact.email`, `user.health.genetic`, `user.financial.account_number`, `user.behavior.browsing_history`, `system.operations.logs`. +* **Data uses**: why it is processed. `provide.service.operations`, `improve.system.analytics`, `marketing.advertising.first_party.contextual`, `marketing.advertising.third_party.targeted`. +* **Data subjects**: who it concerns. `customer`, `employee`, `prospect`, `patient`, `child`. + +Developers annotate code, OpenAPI specs, and YAML configurations with Fideslang labels. The agent's reasoning then operates against these labels, which are tool-agnostic. + +### Hard rules over Fideslang label combinations + +Some label combinations are categorical violations regardless of consent state, because they violate Article 9 prohibition (no Article 9(2) basis is configurable for them). + +| Data category | Data use | Verdict | +|---------------|----------|---------| +| `user.health.*` | `marketing.advertising.*` | Article 9 violation, immediate | +| `user.biometric.*` | `marketing.advertising.*` | Article 9 violation, immediate | +| `user.genetic.*` | any except documented Art. 9(2) basis | Article 9 violation | +| `user.behavior.children.*` | `marketing.advertising.third_party.targeted` | Art. 8 (children's consent) + UK ICO Children's Code violation | +| `user.financial.account_number` (full PAN) | any logged or persisted state outside PCI scope | Art. 32 violation, plus PCI DSS scope violation | + +The agent should encode these as deterministic rules running against the union of Fideslang annotations across the codebase. + +## Privado - data flow mapping and RoPA automation + +**Function**: identifies 110+ specific personal data elements in source code and traces their trajectory to sinks (databases, third-party APIs, log destinations). + +**Why**: the only credible open-source tool for generating an actual data flow graph from source. The graph is the substrate against which RoPA drift is detected. + +**Integration**: +```bash +privado scan --skip-dependency-check +``` + +Output: `.privado/privado.json` containing a knowledge graph of sources, processors, and sinks, each annotated with Fideslang-compatible labels. + +**Privacy property**: Privado generates the graph natively, without sending source code to a cloud service. This is critical when the scanner itself is processing customer source code. + +**Skill consumption**: the agent loads `privado.json`, extracts the flow set, and reconciles against `.compliance/ropa.yaml`. The reconciliation is the Tier 2 RoPA drift check. + +## Semgrep - deterministic AST rule enforcement + +**Function**: AST pattern matching at the speed required for synchronous PR-time checks. + +**Why**: rules are expressed in a near-source-code DSL that engineers can read and write. Custom rules for organization-specific patterns (e.g., "no logging of `personnummer`") are cheap to author. + +**Integration**: maintain a `.semgrep/gdpr/` rule directory. Run via: +```bash +semgrep --config .semgrep/gdpr --json . +``` + +**Skill consumption**: parse the JSON output, map each rule ID through the cross-framework table, emit unified findings. + +**Privacy note**: Semgrep offers zero data retention for AI subprocessors and isolates customer data. This is relevant when the scanner is operated as a SaaS over customer code. + +## Bearer - privacy-as-code auditing and reporting + +**Function**: compiles privacy information required by legal teams; produces RoPA-shaped artifacts and risk reports. + +**Why**: where Privado focuses on flow graph generation, Bearer focuses on continuous evidence artifact generation aligned to Article 30. Useful for the legal-engineering interface. + +**Integration**: +```bash +bearer scan . --report privacy --format json +``` + +**Skill consumption**: Bearer's report becomes a secondary substrate for cross-validation against the Privado flow graph. Discrepancies between the two tools' findings are themselves signal (each tool has different blind spots). + +## Helsinki GDPR Scanner - frontend consent and cookie validation + +**Function**: scans rendered frontend pages against documented cookie banner site settings; detects scripts that fire before consent. + +**Why**: Tier 1 deterministic checks on backend code do not catch the most common consent violation, which is frontend tracking SDKs that initialize on page load regardless of consent state. + +**Integration** (Docker via Stonehenge): +```bash +docker run --rm -v $(pwd):/work helsinki-gdpr-scanner /work --output /work/json +``` + +**Skill consumption**: parses the JSON reports under `/json`, identifies tracking scripts that loaded prior to consent, and cross-references against `.compliance/consent_mappings.yaml` to determine whether each script's category required consent. + +## Combining outputs: the unified finding format + +Each tool emits in its own format. The agent normalizes to: + +```json +{ + "rule_id": "string", + "tool": "privado|semgrep|bearer|helsinki|builtin", + "severity": "critical|high|medium|low", + "tier": 1 | 2 | 3, + "file": "path", + "line": int, + "evidence": "string", + "fideslang": { + "data_categories": ["..."], + "data_uses": ["..."], + "data_subjects": ["..."] + }, + "framework_mappings": { + "gdpr": ["Art. ..."], + "nist_800_53_r5": ["..."], + "iso_27001_2022": ["..."], + "soc2_tsc": ["..."], + "cis_v8": ["..."] + }, + "remediation": "string", + "suppression_eligible": bool +} +``` + +A single semantic violation may surface in multiple tools' outputs. Deduplication key: `(file, line, fideslang.data_categories, framework_mappings.gdpr)`. When duplicates merge, retain the union of evidence statements and the highest severity. + +## Execution ordering + +For pull request gating, run in this order; later stages depend on earlier outputs: + +1. **Secret scanners** (GitLeaks, Trufflehog) - fast, fail fast. +2. **Semgrep** - AST rules, parallelizable, completes in seconds. +3. **SCA / dependency scan** (Trivy, Snyk, Dependabot data) - parallelizable with Semgrep. +4. **Privado** - slower, requires graph construction. Begin in parallel with stages 2-3. +5. **Bearer** - parallel with Privado. +6. **Helsinki GDPR Scanner** - requires built frontend assets; runs after build stage. +7. **Agentic Tier 2 reasoning** - runs only after all Tier 1 outputs are normalized. Has the longest latency budget; should be skipped on PRs that don't trigger it (see SKILL.md trigger heuristics). + +For nightly or scheduled deep scans, run all stages without parallelism budget concerns and run additional out-of-band checks (DAST, penetration smoke tests, transfer geolocation refresh). \ No newline at end of file diff --git a/.claude/skills/gdpr-cicd-compliance/references/transfers-schrems-ii.md b/.claude/skills/gdpr-cicd-compliance/references/transfers-schrems-ii.md new file mode 100644 index 00000000..9fc01b4c --- /dev/null +++ b/.claude/skills/gdpr-cicd-compliance/references/transfers-schrems-ii.md @@ -0,0 +1,108 @@ +# Schrems II and International Transfers + +CJEU C-311/18 (Schrems II, 2020) invalidated the EU-US Privacy Shield and held that transfers under Standard Contractual Clauses (SCCs) require a case-by-case assessment of the destination country's legal framework. EDPB Recommendations 01/2020 establish the operational methodology: identify the transfer, identify the transfer tool (SCC, BCR, derogation), assess the destination law, identify supplementary measures, and re-evaluate periodically. + +The 2021 modular SCCs (Commission Implementing Decision 2021/914) replaced the 2010 SCCs and structure the clauses by transfer scenario: +* Module 1: controller to controller +* Module 2: controller to processor +* Module 3: processor to processor +* Module 4: processor to controller + +The scanner's job is to verify that for every detected restricted transfer, a SCC of the correct module exists, a Transfer Impact Assessment (TIA) is on file, and the technical supplementary measures the TIA promises are actually enforced in code. + +## Detection: mapping data sinks to geography + +Privado identifies external sinks in the data flow graph, including their hostnames and IP addresses. The agent enriches each sink with geographic metadata via: + +* Reverse DNS to identify the hosting provider +* IP geolocation databases (MaxMind, IP2Location, RIPE) +* Provider-specific region tagging (AWS region, GCP region, Azure region encoded in the hostname or in the IaC resource) +* For SaaS endpoints, a maintained mapping of vendor data residency commitments (Stripe, Twilio, OpenAI, Anthropic, etc.) + +A sink resolving outside the EEA, and not in a country covered by a current adequacy decision (Andorra, Argentina, Canada commercial, Faroe Islands, Guernsey, Israel, Isle of Man, Japan, Jersey, New Zealand, South Korea, Switzerland, United Kingdom, Uruguay, and the EU-US Data Privacy Framework for participating organizations as of the framework's status), is classified as a restricted transfer subject to Chapter V. + +**Caveat**: adequacy decisions evolve. The scanner pins a dated reference table and emits a soft warning when the table is older than 90 days, prompting an update. + +## Verification: SCC presence and module correctness + +For each restricted transfer, the agent expects: + +* A reference in `.compliance/transfers/transfers_inventory.yaml` to an SCC artifact under `.compliance/transfers/scc_*`. +* The SCC module corresponds to the actual data flow direction: + * The controller's own service exporting to a vendor's processor → Module 2 + * Two of the controller's services in different jurisdictions both classifying as controllers (joint controllership scenarios) → Module 1 + * The controller's processor sub-engaging another processor → Module 3 +* The SCC artifact metadata names the parties, the categories of data subjects, the categories of personal data, the purposes of processing, and the retention period - and these match the corresponding RoPA entry. + +Module mismatch is a common drift mode: a vendor relationship begins as a vanilla SaaS (Module 2) and evolves into a joint controllership (Module 1) without the SCC being updated. + +## Verification: TIA presence and supplementary measures + +The TIA evaluates whether the destination country's legal framework offers protections "essentially equivalent" to GDPR. EDPB Recommendations 01/2020 note that for several major destinations (notably the United States in respect of Section 702 FISA and Executive Order 12333), the answer is no without supplementary measures. + +The TIA enumerates the supplementary measures the controller relies on. These are typically: + +* Encryption in transit (TLS 1.3 with verified ciphersuites) +* Encryption at rest with a Customer Managed Key held inside the EEA, where the foreign processor cannot access the plaintext key material +* Pseudonymization of direct identifiers prior to transfer +* Contractual measures (notification of access requests by foreign authorities, transparency reports) +* Organizational measures (legal challenge of access requests, data minimization at the export boundary) + +The scanner verifies that the technical measures are deterministically implemented: + +### CMK enforcement (Tier 1) + +For any storage resource (S3, RDS, GCS, Azure Blob, etc.) provisioned in a non-EEA region where the TIA promises CMK with EU-resident key material: + +* The IaC must reference a KMS key whose key store is in an EEA region +* For AWS, this typically means a multi-region key with the primary in eu-* regions, or an external key store +* For cross-account access, the key policy must explicitly grant the destination service `kms:Decrypt` only via a documented temporary mechanism, not blanket access + +### Pseudonymization at the boundary (Tier 1) + +If the TIA promises that direct identifiers are pseudonymized prior to transfer, the agent looks for a transformation function on the egress path. Common patterns: + +* A reverse-proxy or API gateway that hashes / tokenizes specific fields before forwarding +* A schema mapping in a streaming pipeline that drops or transforms identifier columns +* A dedicated tokenization service whose key material does not leave the EEA + +If none of these exists in the codebase but the TIA claims pseudonymization, the scanner flags TIA-vs-implementation drift. + +### Encryption in transit (Tier 1) + +TLS 1.2+ with strong ciphersuites for the transfer leg. AST scan of HTTP client configuration for the destination service. + +## Article 49 derogations + +Article 49 permits certain transfers without an Article 46 safeguard, but only in narrow circumstances: explicit consent, contract with the data subject, important reasons of public interest, legal claims, vital interests, public register data. Derogations are not a fallback for ordinary commercial transfers. + +The agent flags any RoPA entry where the international transfer safeguard is `derogation_art_49_X` and the processing is recurring, large-scale, or commercial. The EDPB has been explicit that derogations cannot be used systematically. + +## The agent's check sequence per detected transfer + +1. Locate the transfer in `.compliance/transfers/transfers_inventory.yaml`. If absent, emit a finding (Article 30 + Article 44 violation: undocumented restricted transfer). +2. Verify the SCC artifact exists at the referenced path. If absent, emit a finding. +3. Verify the SCC module matches the actual data flow direction. If mismatched, emit a finding. +4. Verify the TIA artifact exists. If absent, emit a finding. +5. Read the TIA's "supplementary measures" section. For each named technical measure, run the corresponding deterministic check against IaC and code. For each missing implementation, emit a finding. +6. For SaaS vendors: check the vendor's most recent Transparency Report against the TIA's vendor risk assumptions. (Tier 3 evidence pointer.) + +## A worked example + +A Swedish controller routes user contact data (`user.contact.email`) to AWS US-East-1 for processing by an analytics vendor. + +* Restricted transfer detected (US, no current Privacy Shield, vendor not on EU-US DPF). +* `transfers_inventory.yaml` shows safeguard `scc_module_2`, references `transfers/scc_aws_us_east_1.pdf`, references `transfers/tia_aws_us_east_1.md`. +* SCC artifact present, Module 2 correct (controller-to-processor). +* TIA promises: TLS 1.3, AES-256 at rest with CMK held in eu-north-1, no pseudonymization (direct identifiers are necessary for the analytics use case). +* IaC check: S3 bucket references KMS key whose primary is in eu-north-1 and replicated to us-east-1 with restrictive access policy. Pass. +* TLS check: HTTPS endpoint uses TLS 1.3. Pass. +* No findings. Transfer is documented and technically supported. + +A subsequent pull request adds a new field `user.health.conditions` to the analytics export. The agent now flags: + +* Article 9 violation (special category data being processed under SCC Module 2 with no explicit Article 9(2) basis declared) +* TIA-vs-implementation drift: the TIA's risk assessment did not contemplate health data; the supplementary measures are inadequate for special category data crossing into a jurisdiction with broad surveillance authorities +* Mandatory DPO escalation before merge. + +This is exactly the kind of case where the scanner adds asymmetric value: the change looks innocuous to the engineer (one extra column) but materially alters the legal posture. \ No newline at end of file diff --git a/.claude/skills/gdpr-cicd-compliance/references/verification-tiers.md b/.claude/skills/gdpr-cicd-compliance/references/verification-tiers.md new file mode 100644 index 00000000..4ee015de --- /dev/null +++ b/.claude/skills/gdpr-cicd-compliance/references/verification-tiers.md @@ -0,0 +1,113 @@ +# Verification Tiers + +The honest scope of automated GDPR detection. Every requirement maps to one of three tiers; misclassification is the primary cause of false confidence in privacy tooling. The ordering below is by tier, not by article number, because the operational decision (which engine handles this check?) is tier-driven. + +## Tier 1: deterministically verifiable from the repository + +Static analysis with high confidence. AST parsing, regex, schema validation, IaC parsing. The GDPR-Bench-Android study found that formal-AST baselines achieve high specificity but limited recall; LLMs improve line-level recall (Qwen2.5-72B at 61.6% Accuracy@1 line-level) at the cost of some specificity. For Tier 1 checks that are mechanical, prefer the deterministic engine. + +### Hardcoded secrets and credentials (Art. 32) + +API keys, OAuth tokens, database passwords, private keys committed to source. Direct, indisputable Article 32 violation. Run secret scanners across the full Git history, not just HEAD; secrets remain compromised after they are removed from the working tree. + +Tools: GitLeaks, Semgrep secret rules, Trufflehog. Wrap as a pre-commit hook *and* a CI gate; the hook fails fast for the developer, the CI gate is the audit-grade signal. + +### Insecure data transmission (Art. 32, Art. 5(1)(f)) + +Plain-HTTP API calls, deprecated TLS configurations (SSLv3, TLS 1.0, TLS 1.1), weak cipher suites, missing certificate validation (`verify=False` in requests, `rejectUnauthorized: false` in Node). AST-detectable. + +### Missing cryptographic primitives on PII (Art. 32) + +ORM column definitions storing entities matching known sensitive patterns (`SocialSecurityNumber`, `personnummer`, `HealthRecord`, anything Fideslang-labeled `user.payment.*`, `user.health.*`, `user.biometric.*`, `user.genetic.*`) without encryption decorators or hashing functions. AST-detectable when the ORM is annotation-driven (TypeORM, SQLAlchemy with declarative base, Hibernate JPA). + +### Unconstrained data collection (Art. 5(1)(c) data minimization) + +OpenAPI request payload schemas accepting fields not functionally required for the documented endpoint operation. The deterministic check is `additionalProperties: false`; without it, the schema admits unbounded extraneous PII. + +### Invasive third-party dependencies (Art. 6, Art. 25) + +Tracking SDKs, analytics libraries, advertising networks present in dependency manifests (`package.json`, `build.gradle`, `pom.xml`, `requirements.txt`, HTML script tags) without consent management orchestration. The skill maintains a denylist of known-invasive SDKs; presence triggers a Tier 2 follow-up to validate consent gating. + +### Soft-delete masquerading as Article 17 erasure + +AST pattern matching on controller methods registered as the erasure endpoint. If the body is `UPDATE ... SET is_deleted = ...` or equivalent ORM `update()` rather than `DELETE` (or a documented cryptographic shredding call), it is non-compliant. + +### IaC default-secure violations (Art. 25) + +Terraform / CloudFormation / Pulumi / Kubernetes manifest parsing for: +* Storage resources without encryption configuration +* Storage resources with public ACLs +* Network rules with `0.0.0.0/0` ingress on ports serving PII workloads +* IAM policies with wildcard actions on resources holding PII +* Missing mandatory security headers on API gateway / ingress configurations + +Tools: Checkov, Trivy IaC, OPA/Rego, tfsec, Kics. The agent should run multiple in parallel and deduplicate findings by `(file, line, semantic_rule)`. + +## Tier 2: agentic reasoning over policy artifacts + +Requires natural-language understanding cross-referenced with code reality. An LLM (or a ReAct-style agent; the GDPR-Bench-Android study reported the highest file-level Accuracy@1 of 17.4% from a ReAct configuration) extracts prescriptive statements from policy markdown, then validates implementation against them. The prompt templates for these checks are in `agentic-prompts.md`. + +### RoPA drift (Art. 30) + +The agent receives the parsed `.compliance/ropa.yaml` and the Privado data flow JSON. It enumerates flows present in the code but not in the RoPA (under-documentation, the Article 30 violation) and flows present in the RoPA but not in the code (stale documentation, a less severe but still flagged drift). + +### Purpose limitation (Art. 5(1)(b), Art. 6) + +The agent reads the OpenAPI spec for an endpoint, extracts the documented business purpose, then reads the controller method to enumerate which data objects are queried and returned. If the data objects exceed what the documented purpose justifies, the agent flags purpose creep. + +### Consent logic vs. cookie policy (Art. 6, Art. 7) + +The agent reads `.compliance/consent_mappings.yaml` and the frontend consent management code. It validates that scripts categorized as analytics or marketing only initialize after the corresponding consent state is recorded. The check requires understanding both the policy intent and the runtime control flow. + +### DPIA-vs-implementation drift (Art. 35) + +The agent reads each DPIA in `.compliance/dpia_inventory/`, extracts the "measures envisaged" section, and verifies each named control exists in code. A DPIA promising "all access logged to immutable storage" must have a corresponding logging configuration in IaC. + +### Privacy policy semantic alignment (Art. 12, Art. 13) + +The agent compares `.compliance/privacy_policy.md` claims about data categories collected, processing purposes, recipients, and retention against the union of all detected processing in code. Mismatches are misrepresentations to data subjects, an Article 12/13 violation. + +### Incident response runbook completeness (Art. 33, Art. 34) + +The agent reads `.compliance/incident_response.md` and validates it against the EDPB Guidelines 9/2022 phase structure (detection, assessment, containment, escalation, notification, communication). Missing phases or deprecated communication channels block the build. + +## Tier 3: fundamentally out of repo + +The repository cannot prove these. The scanner can at most check for an *evidence pointer*: a URI, signed credential, or external API reference that points to where the proof lives. + +### Physical security (related to Art. 32 organizational measures) + +A data center server room being locked is unprovable from code. The scanner expects `.compliance/evidence_pointers.yaml` to contain a URI to the latest physical facility audit (SOC 2 report covering the colocation provider, ISO 27001 certificate scope, etc.). + +### Employee privacy training (Art. 39 DPO support, organizational measures) + +The scanner expects an evidence pointer to an HR / LMS API endpoint confirming all currently active contributors (matched by email against the Git committer set) have completed annual privacy training within a documented validity window. + +### Executed DPA / SCC contracts (Art. 28, Art. 46) + +The repository may contain Markdown templates of Data Processing Agreements and SCCs. The scanner cannot verify that a specific vendor *signed* a specific instance. The evidence pointer is an URI to the contract management system (DocuSign API, Ironclad, etc.) returning the signed instance keyed by vendor + module + execution date. + +### Regulator notification logs (Art. 33) + +Whether a notification was actually sent to the supervisory authority within 72 hours of awareness is a runtime, organizational fact. The scanner expects an evidence pointer to a notification log API. + +### Board independence and governance (organizational measures) + +Governance structure, role separation between DPO and CISO, board oversight of the privacy program. Out of repo entirely. The scanner verifies that the *policy* documents these structures exist, not that they actually do. + +## The Honest Output Pattern + +When the scanner emits a finding, it should annotate the tier explicitly: + +``` +[GDPR Art. 32 / SC-28 / A.8.24] +Tier 1 (deterministic): server_side_encryption_configuration missing on aws_s3_bucket.user_uploads. + +[GDPR Art. 30] +Tier 2 (agentic): ropa.yaml does not document the data flow from /api/v1/orders to Stripe (detected by Privado at services/checkout.ts:142). + +[GDPR Art. 39 / Organizational] +Tier 3 (out of repo): no evidence pointer found for employee privacy training. Add an entry to .compliance/evidence_pointers.yaml referencing the LMS API. +``` + +The user knows immediately which findings can be fixed by editing code, which require updating policy markdown, and which require organizational action outside engineering's scope. This honesty is what makes the scanner trustworthy. \ No newline at end of file diff --git a/.claude/skills/gdpr-cicd-compliance/references/violation-patterns.md b/.claude/skills/gdpr-cicd-compliance/references/violation-patterns.md new file mode 100644 index 00000000..18129c38 --- /dev/null +++ b/.claude/skills/gdpr-cicd-compliance/references/violation-patterns.md @@ -0,0 +1,126 @@ +# Violation Patterns + +Real-world heuristics for the scanner. Each pattern below is drawn either from a regulatory enforcement action, an architectural failure mode documented in the GDPR-Bench-Android study, or a publicly disclosed supply chain incident. The agent should treat these as concrete detection targets rather than abstract guidelines. + +## Code-level anti-patterns + +### Sensitive API access without consent gate (Art. 6) + +**Pattern**: invocation of camera, microphone, geolocation, contacts, or biometric APIs without a preceding conditional checking the documented consent state. + +**Android example** (from the source document): +```java +manager.openCamera(cameraId, stateCallback, null); // no consent check +``` + +**Detection**: AST scan for the sensitive API surface (per platform: `android.hardware.camera2`, `CoreLocation`, `navigator.geolocation`, `MediaDevices.getUserMedia`), then walk up the control flow graph looking for a guard against a consent provider. Absence of the guard is the finding. + +**Why it lands as Article 6**: any processing operation needs a lawful basis. For sensor APIs in a consumer context, the basis is almost always consent (Art. 6(1)(a)). Capturing without checking the consent state means processing without lawful basis. + +### Unsafe logging of PII (Art. 32, Art. 5(1)(f)) + +**Pattern**: stack traces, request bodies, or full user objects written to standard output, log files, or third-party log aggregators. + +**Examples**: +```javascript +console.log(userObject); // Node.js +logger.info("Failed login for " + email); // Java/Python +fmt.Printf("%+v\n", request) // Go, with PII in request +``` + +**Detection**: Semgrep rules for `console.log`, `logger.*`, `print` calls whose arguments resolve to variables flagged by Privado as containing PII. + +**Operational nuance**: distinguishing safe logging (log a request ID, not a request body) from unsafe logging is exactly the kind of check where deterministic AST analysis underperforms LLM analysis. The skill should run a Semgrep first pass for the obviously bad patterns, then escalate ambiguous cases to the agentic auditor. + +### Inadequate Article 17 erasure + +**Pattern**: the endpoint registered to satisfy the right to erasure performs a soft-delete (boolean flag, status enum change, timestamp on a `deleted_at` column) rather than hard deletion or cryptographic shredding. + +**Detection**: identify the erasure endpoint via: +* OpenAPI tag `dsar` or `privacy` +* Convention paths (`/api/.*privacy.*delete`, `/api/.*forget`) +* DSAR runbook reference + +Then trace the controller method statically. Any path that reaches a SQL `UPDATE` (or ORM `update()`) instead of `DELETE` (or a documented anonymization function) is the finding. + +**Edge case**: legitimate retention obligations (tax law, anti-money-laundering) may legally override the right to erasure for specific fields. The DPIA or RoPA should document this; the scanner should escalate to the agentic auditor when it detects soft-delete patterns to check for a documented retention basis rather than auto-flagging. + +### Plaintext PII in error responses (Art. 32) + +**Pattern**: API error handlers reflecting PII back to the caller in error messages or stack traces. + +```python +@app.errorhandler(500) +def handle_500(e): + return {"error": str(e), "context": request.json}, 500 # leaks PII +``` + +**Detection**: Semgrep on error handler bodies that reference request bodies, query parameters, or session objects. + +## Configuration-level anti-patterns + +### Overly permissive CORS (Art. 25, Art. 32) + +**Pattern**: `Access-Control-Allow-Origin: *` on endpoints serving authenticated PII; `Access-Control-Allow-Credentials: true` paired with permissive origins. + +**Detection**: parse middleware configuration (Express, FastAPI, Spring), API gateway resource policies, and CDN configurations. Cross-reference with the endpoint inventory; permissive CORS on a public marketing endpoint is fine, on `/api/v1/users/me` it is not. + +### Mobile permission overreach (Art. 5(1)(c)) + +**Pattern**: `AndroidManifest.xml` requesting `ACCESS_FINE_LOCATION`, `READ_CONTACTS`, `READ_SMS`, `RECORD_AUDIO`, `CAMERA` when the app's documented purposes do not require them. iOS equivalent: `Info.plist` `NS*UsageDescription` keys. + +**Detection**: enumerate requested permissions, cross-reference each against the Fideslang `data_categories` documented in `.compliance/ropa.yaml`. An app that lists no `user.location` data category in the RoPA but requests `ACCESS_FINE_LOCATION` is flagged. + +### Disabled or missing security headers (Art. 32) + +**Pattern**: web server configurations missing `Strict-Transport-Security`, `Content-Security-Policy`, `X-Content-Type-Options: nosniff`, `X-Frame-Options`, or `Referrer-Policy`. + +**Detection**: parse Nginx, Apache, Caddy, Cloudflare, AWS CloudFront, or framework-level header configurations. Check for the canonical set; emit findings per missing header. + +## Dependency and supply chain risks + +### Invasive third-party SDKs + +**Pattern**: presence of advertising or analytics SDKs known for covert tracking or device fingerprinting without valid consent. + +**Regulatory anchors**: +* CNIL fined Apple and Voodoo Games in 2023 over advertising identifier use without adequate consent +* CNIL fined Clearview AI repeatedly for non-compliant biometric scraping +* IMY (Sweden) has issued multiple decisions on Google Analytics post-Schrems II + +**Detection**: maintain a denylist of SDK package coordinates (e.g., `com.facebook.android:facebook-android-sdk` for advertising-grade fingerprinting, specific MMP SDKs, ad-tech identifiers). Match against `package.json`, `build.gradle`, `Podfile`, etc. Presence requires Tier 2 escalation to verify consent gating. + +### Compromised OAuth integrations + +**Pattern**: outdated authentication libraries or OAuth client implementations vulnerable to known account takeover patterns. + +**Reference incident**: the SalesLoft / Drift supply chain compromise demonstrated that OAuth tokens leaked through an integrated tool propagated to dozens of downstream Salesforce instances, each constituting an Article 32 confidentiality breach. + +**Detection**: SCA tools (Snyk, Dependabot, Trivy, Grype) cross-referenced with NVD CVE data for OAuth, SAML, and session-management libraries. Combine with secret scanning for committed OAuth refresh tokens and client secrets. + +### Transitive dependency backdoors + +**Pattern**: deeply nested dependencies containing data-harvesting code that exfiltrates environment variables, secrets, or PII to external servers. + +**Reference incident**: the Shai-Hulud npm backdoor pattern, where compromised packages walked the environment looking for credentials and posted them to attacker-controlled hosts. + +**Detection**: SCA combined with malware scanners (Phylum, Socket, Snyk Malicious Packages). The scanner should inspect not just direct dependencies but the full transitive closure, with particular attention to recently published versions of long-lived packages and to packages with low download counts being added near production paths. + +### Customer management system exposure + +**Pattern**: customer-facing applications with exposed administrative interfaces, weak authentication on internal CRMs, or insecure data export endpoints. + +**Reference incident**: the Italian Garante fined Enel substantially for failing to secure a customer management system that enabled unauthorized data acquisition by third parties. + +**Detection**: out-of-band, requires DAST (dynamic application security testing). The static scanner can verify that admin routes have RBAC middleware applied; it cannot verify that the RBAC is correctly enforced at runtime without DAST. + +## Combining patterns into severity + +A single low-severity finding rarely justifies blocking a deployment. Combinations do: + +* **Critical (block)**: hardcoded production credentials + plaintext PII transmission. The combined exposure is multiplicative. +* **Critical (block)**: special category data (Art. 9) + missing encryption at rest + non-EEA data sink. Three-way violation: Art. 9(2) basis missing, Art. 32 inadequate, Art. 44 transfer inadequate. +* **High (warn)**: invasive SDK present + no consent gating + frontend tracker initializes pre-consent. Defer to agentic Tier 2 to confirm before blocking. +* **Medium (warn)**: missing security header + cookie tagged as analytics without consent flow. + +The agent should compute these combinations rather than emitting each finding in isolation. The blast radius of compounded violations is what regulators actually fine on. \ No newline at end of file diff --git a/.claude/skills/iso-27001-2022-compliance/SKILL.md b/.claude/skills/iso-27001-2022-compliance/SKILL.md new file mode 100644 index 00000000..c3596712 --- /dev/null +++ b/.claude/skills/iso-27001-2022-compliance/SKILL.md @@ -0,0 +1,165 @@ +--- +name: iso-27001-2022-compliance +description: Authoritative reference for verifying ISO/IEC 27001:2022 compliance from a code repository. Use whenever a task involves auditing, automating, or generating evidence for ISO 27001 controls, the ISMS document set (Clauses 4-10), the Statement of Applicability (SoA), or Annex A controls (A.5 Organizational, A.6 People, A.7 Physical, A.8 Technological). Trigger on mentions of ISO 27001, ISO/IEC 27001, 27001:2022, ISMS, SoA, Annex A, "Statement of Applicability", a specific control identifier (A.5.x, A.6.x, A.7.x, A.8.x), Checkov/Trivy/Steampipe ISO compliance specs, the 2013-to-2022 control transition, NIST 800-53 / CIS Controls / SOC 2 crosswalks, agentic auditing of policy documents, or building CI/CD pipeline gates for security compliance. Trigger even when phrasing is indirect — "is our Terraform compliant", "scan our policies for audit readiness", "what does the standard require for cryptography", "map our controls to SOC 2", "build a compliance scanner" — these all qualify. +--- + +# ISO/IEC 27001:2022 Compliance Verification Skill + +## Purpose + +This skill provides authoritative, repository-grounded reference data for two distinct verification modes against ISO/IEC 27001:2022: + +1. **Deterministic CI/CD scanning** — Pull-Request-time evaluation of code, IaC, and dependency manifests against Annex A.8 (Technological Controls). +2. **Agentic auditing** — On-demand semantic review of ISMS policy documents (Clauses 4-10) and organizational controls (Annex A.5). + +The skill is designed for engineers building compliance automation, not for end-user training. It is a compliance oracle: when in doubt about what the standard actually requires, consult this skill rather than relying on memory. + +## Why two modes exist + +ISO 27001:2022 is structurally bifurcated. Clauses 4-10 govern the management system (governance, scope, leadership, planning, operation, performance, improvement) and are expressed in natural-language documents. Annex A enumerates 93 security controls, the majority of which (the 34 in A.8) map directly to repository artifacts. Deterministic parsers handle A.8; LLM-based agentic auditors handle Clauses 4-10 and A.5. A.7 (Physical) and most of A.6 (People) sit out-of-repo and require evidence pointers, not direct verification. + +## Routing — read this first + +Before consulting any reference file, identify which mode the task requires: + +- Task touches Terraform, CloudFormation, Kubernetes manifests, Dockerfiles, application source code, package manifests, CI/CD definitions, or branch protection → **deterministic mode**. Read `references/annex-a-controls.md` and `references/violation-patterns.md`. +- Task touches Markdown policies, the Information Security Policy, Risk Register, SoA, Management Review minutes, internal audit logs → **agentic mode**. Read `references/isms-clauses.md` and `references/agentic-prompts.md`. +- Task asks about new controls introduced in the 2022 revision → read `references/new-controls-2022.md`. +- Task references a 2013-era control identifier (e.g., A.14.2.1, A.12.1.2) → read `references/legacy-mapping.md` to translate before responding. +- Task involves NIST 800-53, CIS Controls v8.1, or SOC 2 → read `references/cross-framework-mapping.md`. +- Task involves wrapping Checkov, Trivy, or Steampipe → read `references/tool-orchestration.md`. + +## The Statement of Applicability is the routing table + +Never apply all 93 Annex A controls blindly. Compliance is governed by the organization's SoA (Clause 6.1.3d), which declares which controls are included, which are excluded, and the justification for each. A machine-readable SoA (`soa.json` or `soa.csv`, conventionally located at `.security/` or `ISMS/`) is the primary input to any compliance scan. If the SoA is missing, the first finding is always: "Cannot determine control applicability — Clause 6.1.3 violation." + +A valid SoA contains four core elements per control: +1. The control identifier and title. +2. A statement of inclusion or exclusion. +3. Justification (operational reasoning for inclusion, risk-based reasoning for exclusion). +4. Implementation status (Implemented, Planned, Not Applicable). + +Suppression logic for the scanner: +- Excluded controls → suppress all checks. Do not generate findings. +- Included + Implemented → run all checks. Failures are blocking. +- Included + Planned → run all checks. Failures are warnings, not blocking. +- Included + Not Applicable → structural contradiction. Flag as SoA inconsistency. + +## Three verification typologies + +Every Annex A control falls into one of three categories. Be explicit about which one applies before claiming a control has been verified. + +### Deterministic in-repo +Structured parsing produces a binary outcome. Examples: A.8.24 (encryption flags in IaC), A.8.4 (branch protection rules), A.8.8 (CVEs in dependency manifests), A.8.28 (SAST presence in pipelines). These are the highest-leverage targets for automation. + +### Agentic over policy artifacts +Constrained LLM evaluation of natural-language documents. Examples: Clause 5.2 (Information Security Policy adequacy), Clause 9.3 (Management Review completeness), A.5.1 (Policies for information security), A.5.7 (Threat Intelligence — does the documented threat-intel process actually address the control intent?). The LLM produces "Observations" and "Potential Non-Conformities" for human validation. Never autonomous decisions. + +### Out-of-repo / evidence pointer +Cannot be verified from the repository alone. Examples: A.7.x (all Physical Controls), A.6.1 (Screening), A.6.4 (Disciplinary process). The skill's job is to confirm that the policy exists AND that the policy contains a pointer (URL, API reference, named system of record) to the external evidence source. If both the policy and the pointer are absent, flag a documentation gap. Never claim the underlying control is "verified." + +## Trigger mechanics for CI/CD integration + +The scanner must select sub-modules based on the Git diff to avoid running the full audit on trivial commits: + +| Files changed | Modules to run | +|---|---| +| `*.tf`, `*.yml`, `*.yaml`, `*.json`, `Dockerfile`, K8s manifests | Checkov (IaC) → A.8.9, A.8.20, A.8.22, A.8.24, A.8.27 | +| `package-lock.json`, `requirements.txt`, `go.sum`, `Cargo.lock`, `pom.xml` | Trivy (SCA) → A.8.8, A.8.30 | +| Application source code | SAST + secret scanning → A.8.24, A.8.28 | +| `.github/workflows/*`, `.gitlab-ci.yml` | Pipeline integrity → A.8.25, A.8.29, A.8.31, A.8.32 | +| `ISMS/**/*.md`, `ISMS/**/*.docx`, `*.md` policies | Agentic LLM auditor → Clauses 4-10, A.5.x | +| `soa.json`, `soa.csv` | SoA structural validation → Clause 6.1.3 | + +## Suppression and risk acceptance — the critical coupling + +Inline suppressions in scanner output (e.g., `# checkov:skip=CKV_AWS_19`) are legitimate only when paired with a documented, executive-approved Risk Register entry. The scanner must enforce this coupling: + +1. Parse suppression comments for a Risk ID reference. +2. Cross-reference the Risk ID against the canonical Risk Register (Clause 8.2 artifact, typically `Risk_Register.xlsx` or equivalent). +3. Verify the entry exists, has a Risk Owner, has a residual risk score, and is referenced in the Risk Treatment Plan (Clause 8.3). +4. If any of these are missing, the suppression is invalid. Generate a Clause 6.1.3 finding regardless of the technical check passing. + +This mechanism is the binding contract between developer behavior and GRC oversight. Without it, suppressions become a compliance laundering mechanism. + +## Honest limitations — surface these proactively + +Automated scanners cannot prove physical reality, behavioral compliance, or runtime state. When generating reports, label every finding with its verification scope: + +- "Documentation Verified — Physical Validation Required" for A.7.x policies. +- "Policy Verified — Behavioral Compliance Out of Scope" for A.6.3 (training), A.7.7 (clear desk). +- "Point-in-Time" for any deterministic check. Continuous runtime monitoring (A.8.16) is required to detect drift after merge. + +For agentic AI workflows in the audited system itself, reference the OWASP Top 10 for Agentic Applications and demand heightened governance controls. Standard SOC 2 / ISO 27001 controls assume deterministic systems and are insufficient for autonomous agents. + +Read `references/limitations.md` for the full catalog of what automation cannot verify and how to communicate this to auditors. + +## Required ISMS directory structure + +Expect (and enforce) this canonical layout: + +``` +ISMS/ +├── Governance/ +│ ├── ISMS_Scope.md (Clause 4.3) +│ ├── InfoSec_Policy.md (Clause 5.2) +│ └── Security_Objectives.md (Clause 6.2) +├── Risk/ +│ ├── Risk_Methodology.md (Clause 6.1.2) +│ ├── Risk_Register.xlsx (Clause 8.2) +│ └── Risk_Treatment.md (Clause 8.3) +├── SoA/ +│ └── SoA.json (Clause 6.1.3) +├── Competence/ +│ └── Competency_Matrix.csv (Clause 7.2) +└── Audits/ + ├── Internal_Audit_Log.md (Clause 9.2) + └── Mgmt_Review_Minutes.md (Clause 9.3) +``` + +For each document, beyond existence, verify: classification mark-up (Confidential / Internal Use Only), version control table, executive sign-off, review timestamp within the declared annual interval. Missing metadata is a Clause 7.5 (Documented Information) violation. + +## Output report structure + +Every compliance scan output should follow this template so findings are auditor-defensible: + +``` +# ISO/IEC 27001:2022 Compliance Report +## Repository: | Commit: | SoA Version: | Date: + +## Summary +- Controls in scope (per SoA): +- Findings: critical, high, medium, low +- Documentation gaps: +- Suppression integrity: + +## Findings by Annex A theme +### Organizational Controls (A.5) +### People Controls (A.6) +### Physical Controls (A.7) +### Technological Controls (A.8) + +## ISMS Clause Findings (4-10) + +## Cross-framework mapping (if requested) +- NIST SP 800-53 Rev. 5 +- CIS Controls v8.1 +- SOC 2 TSC + +## Verification scope disclaimer +- Point-in-time scan of commit +- Out-of-repo controls verified by evidence pointer only +- Behavioral compliance not in scope +``` + +## Reference files + +- `references/annex-a-controls.md` — Full catalog of Annex A.5, A.6, A.7, A.8 with verification logic per control. +- `references/new-controls-2022.md` — The 11 net-new controls in the 2022 revision and their automation implications. +- `references/legacy-mapping.md` — 2013 → 2022 control identifier translation matrix. +- `references/isms-clauses.md` — Clauses 4-10 mandatory documents and content expectations. +- `references/violation-patterns.md` — Real-world code, configuration, and dependency violation patterns with detection logic. +- `references/cross-framework-mapping.md` — NIST 800-53 Rev. 5, CIS Controls v8.1, SOC 2 TSC crosswalks. +- `references/tool-orchestration.md` — Checkov / Trivy / Steampipe wrapping patterns, including custom YAML policies. +- `references/agentic-prompts.md` — Constrained LLM prompts for policy and management review evaluation. +- `references/limitations.md` — Catalog of what automation cannot verify and required disclaimers. diff --git a/.claude/skills/iso-27001-2022-compliance/references/agentic-prompts.md b/.claude/skills/iso-27001-2022-compliance/references/agentic-prompts.md new file mode 100644 index 00000000..2a0a5cd9 --- /dev/null +++ b/.claude/skills/iso-27001-2022-compliance/references/agentic-prompts.md @@ -0,0 +1,286 @@ +# Agentic Prompts — Constrained LLM Evaluation of Policy Artifacts + +The deterministic scanner cannot evaluate the semantic adequacy of a policy document. For Clauses 4-10 and most A.5 controls, the skill must use a constrained LLM auditor. + +These prompts are designed to: +- Force the LLM into auditor role with explicit normative criteria. +- Suppress hallucination by demanding citation of clause identifiers. +- Output structured findings (Non-Conformity, Observation, Pass) that can be aggregated into reports. +- Refuse autonomous certification — every output is "for human validation". + +The LLM operates in advisory mode only. It never closes findings, never approves documents, never overrides human reviewers. + +--- + +## System prompt — base auditor persona + +Use this as the system message for every agentic auditor invocation: + +``` +You are a certified ISO/IEC 27001:2022 Lead Auditor performing a documentation review. + +Your role: +- Evaluate documents strictly against the normative requirements of ISO/IEC 27001:2022. +- Cite the specific Clause or Annex A control identifier for every finding. +- Output findings in three categories: Non-Conformity (NC), Observation (OBS), Pass. +- A Non-Conformity is a clear deviation from a normative requirement. An Observation is a weakness or improvement opportunity that does not (yet) breach a requirement. +- Never make assumptions about content not present in the document. If a requirement is not addressed, the finding is "Requirement not addressed" — do not infer intent. +- Flag generic, AI-generated, or boilerplate language as an Observation. +- Output is advisory only. Human auditors make all final determinations. + +Output format (JSON): +{ + "document_evaluated": "", + "clauses_in_scope": ["", ...], + "findings": [ + { + "type": "NC" | "OBS" | "Pass", + "clause_or_control": "", + "requirement": "", + "evidence": "", + "rationale": "" + } + ], + "boilerplate_risk": "low" | "medium" | "high", + "human_review_required": true +} +``` + +--- + +## Information Security Policy review (Clause 5.2 + A.5.1) + +User prompt: + +``` +Document under review: +Document content: +<<< +{document_text} +>>> + +Evaluate this Information Security Policy against ISO/IEC 27001:2022 Clause 5.2 and Annex A control A.5.1. + +Required elements: +1. Establishes information security objectives or provides a framework for setting them (Clause 5.2.b). +2. Includes a commitment to satisfy applicable requirements related to information security (Clause 5.2.c). +3. Includes a commitment to continual improvement of the ISMS (Clause 5.2.d). +4. Is approved by top management (evidence of executive sign-off). +5. Is communicated within the organization (reference to distribution mechanism). +6. Is available to interested parties as appropriate (reference to availability). +7. Is reviewed at planned intervals (reference to review cadence). + +For each required element, output a finding (Pass / OBS / NC) with the exact quoted evidence or "absent". +``` + +--- + +## Statement of Applicability review (Clause 6.1.3) + +``` +Document under review: +Format: JSON / CSV +Content: +<<< +{soa_content} +>>> + +Evaluate against ISO/IEC 27001:2022 Clause 6.1.3(d). + +Structural requirements: +1. Lists all 93 controls of Annex A:2022 (or equivalent justification for omitted controls). +2. For each control, declares status: Included or Excluded. +3. For Included controls, provides operational justification. +4. For Excluded controls, provides risk-based justification. +5. For Included controls, declares implementation status: Implemented, Planned, or Not Applicable (with rationale). + +Cross-checks: +- Are any of the 11 net-new 2022 controls missing entirely? (A.5.7, A.5.23, A.5.30, A.7.4, A.8.9, A.8.10, A.8.11, A.8.12, A.8.16, A.8.23, A.8.28) +- Are exclusion justifications generic ("not applicable") or specific (referencing organizational context)? +- Do "Implemented" claims have plausible scope given the organization size and industry? + +Output structural findings AND a list of any 2013-era control identifiers detected (these indicate incomplete transition). +``` + +--- + +## Risk Register review (Clause 8.2) + +``` +Document under review: +Format: spreadsheet / structured data +Content: +<<< +{risk_register_content} +>>> + +Evaluate against ISO/IEC 27001:2022 Clause 8.2 and Clause 6.1.2. + +Per-entry requirements: +1. Unique Risk ID. +2. Risk description (threat × vulnerability × asset). +3. Risk owner (named individual or role). +4. Inherent risk score (using documented methodology). +5. Treatment decision (Mitigate, Transfer, Accept, Avoid). +6. If Mitigate: linked control(s) from SoA. +7. Residual risk score after treatment. +8. Acceptance criteria reference (for Accept decisions, must reference Clause 8.3 risk acceptance authority). + +Cross-cutting requirements: +- All accepted risks above threshold have executive sign-off. +- Linked controls in SoA are marked as Included. +- No orphan controls (controls in SoA marked Implemented but no Risk Register entry references them — possible compliance theater). + +For each finding, output the Risk ID and the missing field. +``` + +--- + +## Management Review minutes (Clause 9.3) + +``` +Document under review: +Content: +<<< +{minutes_text} +>>> + +Evaluate against ISO/IEC 27001:2022 Clause 9.3.2 (Management review inputs). + +The minutes MUST cover all seven mandatory inputs: +a) Status of actions from previous management reviews. +b) Changes in external and internal issues relevant to the ISMS. +c) Changes in needs and expectations of interested parties. +d) Feedback on information security performance, including: + - Nonconformities and corrective actions + - Monitoring and measurement results + - Audit results + - Fulfilment of information security objectives +e) Feedback from interested parties. +f) Results of risk assessment and status of risk treatment plan. +g) Opportunities for continual improvement. + +The minutes MUST also cover (Clause 9.3.3): +- Decisions related to continual improvement opportunities. +- Decisions for any need for changes to the ISMS. + +Per-input output: +{ + "input_id": "9.3.2.a", + "label": "Status of previous actions", + "covered": true | false, + "evidence": "", + "depth": "substantive" | "perfunctory" | "absent" +} + +Also evaluate: Is there evidence of executive participation (named C-suite attendees)? Are decisions documented with action owners and timelines? +``` + +--- + +## Risk Treatment Plan review (Clause 8.3) + +``` +Document under review: +Content: +<<< +{rtp_text} +>>> + +Evaluate against ISO/IEC 27001:2022 Clause 6.1.3 and Clause 8.3. + +Required content: +1. Treatment options chosen for each risk in the Risk Register. +2. Controls determined to implement each chosen treatment. +3. Comparison of determined controls with Annex A (gap analysis). +4. Justification for any controls outside of Annex A. +5. Approval of the plan by risk owners. +6. Approval of acceptance of residual risks by risk owners. + +Cross-references: +- Every Risk Register risk has a corresponding entry in the RTP. +- Every linked control is also in the SoA as Included. +- No "Implemented" controls in SoA without a corresponding RTP entry justifying their inclusion. + +Output gaps where the RTP, Risk Register, and SoA are inconsistent. +``` + +--- + +## Internal Audit review (Clause 9.2) + +``` +Documents under review: +Content: +<<< +{audit_log_text} +{audit_findings_text} +>>> + +Evaluate against ISO/IEC 27001:2022 Clause 9.2. + +Required elements: +1. Audit programme covering all parts of the ISMS at planned intervals (typically annually). +2. Audit criteria, scope, frequency, and methods defined. +3. Auditor independence (auditor is not auditing their own work). +4. Reported findings to relevant management. +5. Evidence of corrective actions for non-conformities. + +For each audit cycle, output: +- Date(s) of audit. +- Auditor identity and independence statement. +- Scope (which clauses / which Annex A controls / which business units). +- Findings count by severity. +- Status of corrective actions (open / closed / overdue). + +Flag if any audit was conducted by the same person who owns the audited area. +``` + +--- + +## Generic policy adequacy review + +For organizational policies (A.5.x) where there is no specific clause prompt, use: + +``` +Document under review: +Mapped controls: +Content: +<<< +{policy_text} +>>> + +For each mapped control, evaluate: +1. Does the policy text address the control's purpose as defined in ISO/IEC 27002:2022 implementation guidance? +2. Are responsibilities assigned (named roles, not just "the team")? +3. Are review and update mechanisms defined? +4. Is the policy specific to this organization (vs generic boilerplate)? +5. Are there enforcement mechanisms (consequences for violation)? + +Boilerplate detection: Search for phrases that suggest the document is a generic template: +- "the company" / "the organization" with no actual company name. +- Generic threat lists with no organizational risk context. +- Identical phrasing to common policy templates on GitHub. + +Output one finding per mapped control plus a boilerplate_risk score. +``` + +--- + +## Constraints and safety + +The agentic auditor must never: + +1. Approve a document. Approval is a human management responsibility. +2. Mark a control as "Implemented" based solely on policy review. Implementation requires technical evidence beyond the policy itself. +3. Generate certification decisions. Certification is performed by accredited certification bodies. +4. Apply checks to controls excluded by the SoA, unless asked to evaluate the exclusion justification itself. +5. Hallucinate references. Every clause citation must be a real ISO 27001:2022 clause. If unsure, say "uncertain — human review". + +Every agentic finding must carry `human_review_required: true`. The skill's report generator must surface this field prominently so that no automated CI/CD step interprets agentic findings as final. + +## Token / cost considerations + +For large policy bundles, batch by document type rather than concatenating everything. Each document gets its own auditor invocation with the prompt template above. This keeps prompts within reasonable token budgets and produces auditable per-document outputs. + +For very large repositories, run agentic checks only on changed documents (Git diff filter on `*.md` in `ISMS/` directory). Full agentic re-scan should run on a scheduled cadence (weekly / monthly) outside of PR-time CI/CD. diff --git a/.claude/skills/iso-27001-2022-compliance/references/annex-a-controls.md b/.claude/skills/iso-27001-2022-compliance/references/annex-a-controls.md new file mode 100644 index 00000000..71525729 --- /dev/null +++ b/.claude/skills/iso-27001-2022-compliance/references/annex-a-controls.md @@ -0,0 +1,161 @@ +# Annex A Controls — Full Catalog with Verification Logic + +ISO/IEC 27001:2022 Annex A contains 93 controls across four themes. This file is the authoritative per-control reference. Use it to look up exact control intent and the deterministic / agentic / out-of-repo verification logic for each. + +## Theme structure + +| Theme | Range | Count | Primary mode | +|---|---|---|---| +| A.5 Organizational | A.5.1 – A.5.37 | 37 | Agentic | +| A.6 People | A.6.1 – A.6.8 | 8 | Out-of-repo (evidence pointers) | +| A.7 Physical | A.7.1 – A.7.14 | 14 | Out-of-repo (evidence pointers) | +| A.8 Technological | A.8.1 – A.8.34 | 34 | Deterministic | + +## Control attributes (2022 addition) + +Every control carries five attribute dimensions. Surface these in dashboards: + +1. **Control type**: preventive, detective, corrective. +2. **Information security property**: confidentiality, integrity, availability. +3. **Cybersecurity concept**: identify, protect, detect, respond, recover. +4. **Operational capability**: governance, asset management, identity and access management, etc. +5. **Security domain**: governance and ecosystem, protection, defense, resilience. + +--- + +## A.5 Organizational Controls (37 controls) + +Primary verification mode: agentic. Most A.5 controls are evaluated by LLM review of policy artifacts. A subset has deterministic anchors (e.g., A.5.7 Threat Intelligence is deterministically anchored by the presence of an SCA tool subscription). + +| ID | Title | Verification logic | +|---|---|---| +| A.5.1 | Policies for information security | Agentic — verify InfoSec_Policy.md exists, includes commitment to applicable requirements + continual improvement, signed by top management. | +| A.5.2 | Information security roles and responsibilities | Agentic — RACI matrix or equivalent in policy documents. | +| A.5.3 | Segregation of duties | Agentic + deterministic — policy text plus IAM role separation in IaC. | +| A.5.4 | Management responsibilities | Agentic — leadership commitment language in policy. | +| A.5.5 | Contact with authorities | Agentic — incident response plan references regulators (e.g., IMY for Sweden, Datainspektionen). | +| A.5.6 | Contact with special interest groups | Agentic — documented memberships (CERT, ISAC, etc.). | +| A.5.7 | Threat Intelligence (NEW 2022) | Deterministic-anchored — presence of SCA tooling (Trivy, Snyk, Dependabot) actively pulling vuln databases. | +| A.5.8 | Information security in project management | Agentic — project lifecycle docs reference security gates. | +| A.5.9 | Inventory of information and other associated assets | Deterministic — asset inventory file, CMDB reference, or IaC as the inventory source. | +| A.5.10 | Acceptable use of information and other associated assets | Agentic — AUP exists and is acknowledged. | +| A.5.11 | Return of assets | Out-of-repo — pointer to HR offboarding workflow. | +| A.5.12 | Classification of information | Agentic — classification scheme documented; deterministic spot-checks for classification mark-up in files. | +| A.5.13 | Labelling of information | Deterministic — regex check for classification labels in document headers. | +| A.5.14 | Information transfer | Agentic — transfer policy; deterministic — TLS enforcement in IaC. | +| A.5.15 | Access control | Agentic + deterministic — policy + IAM IaC + Steampipe runtime queries. | +| A.5.16 | Identity management | Deterministic — IdP integration verified via Steampipe. | +| A.5.17 | Authentication information | Deterministic — secret manager references in IaC; no hardcoded credentials. | +| A.5.18 | Access rights | Deterministic — least-privilege IAM policies; periodic access review evidence. | +| A.5.19 | Information security in supplier relationships | Agentic — supplier policy and contracts with security clauses. | +| A.5.20 | Addressing information security within supplier agreements | Agentic — DPA/security addendum templates. | +| A.5.21 | Managing information security in the ICT supply chain | Agentic + deterministic — SBOM generation in CI/CD. | +| A.5.22 | Monitoring, review and change management of supplier services | Agentic — supplier review cadence documented. | +| A.5.23 | Information security for use of cloud services (NEW 2022) | Deterministic — IaC alignment with cloud provider security baselines (CIS AWS, CIS Azure). | +| A.5.24 | Information security incident management planning and preparation | Agentic — incident response plan exists. | +| A.5.25 | Assessment and decision on information security events | Agentic — triage criteria documented. | +| A.5.26 | Response to information security incidents | Agentic — runbooks exist. | +| A.5.27 | Learning from information security incidents | Agentic — post-mortem template / blameless review process. | +| A.5.28 | Collection of evidence | Agentic — forensic procedures documented. | +| A.5.29 | Information security during disruption | Agentic — BCP exists. | +| A.5.30 | ICT readiness for business continuity (NEW 2022) | Deterministic — multi-region/multi-AZ in IaC, backup automation. | +| A.5.31 | Legal, statutory, regulatory and contractual requirements | Agentic — compliance register exists and lists applicable laws. | +| A.5.32 | Intellectual property rights | Agentic — IP policy; deterministic — license scanner output. | +| A.5.33 | Protection of records | Agentic — records retention schedule. | +| A.5.34 | Privacy and protection of PII | Agentic — privacy policy; deterministic — data masking in code (links to A.8.11). | +| A.5.35 | Independent review of information security | Agentic — internal audit log shows independent reviewers. | +| A.5.36 | Compliance with policies, rules and standards for information security | Agentic — compliance assessment reports. | +| A.5.37 | Documented operating procedures | Agentic — runbook directory exists. | + +--- + +## A.6 People Controls (8 controls) + +Primary verification mode: out-of-repo. Verify policy + evidence pointer to HRIS / LMS / ticketing system. + +| ID | Title | Verification logic | +|---|---|---| +| A.6.1 | Screening | Out-of-repo — policy + pointer to HR vetting workflow. | +| A.6.2 | Terms and conditions of employment | Out-of-repo — policy + pointer to contract templates with confidentiality clauses. | +| A.6.3 | Information security awareness, education and training | Out-of-repo — policy + pointer to LMS API showing completion records. | +| A.6.4 | Disciplinary process | Out-of-repo — policy + pointer to HR escalation procedure. | +| A.6.5 | Responsibilities after termination or change of employment | Out-of-repo — policy + pointer to offboarding checklist. | +| A.6.6 | Confidentiality or non-disclosure agreements | Out-of-repo — NDA template exists in repo or pointer. | +| A.6.7 | Remote working | Agentic — remote work policy; deterministic — VPN/zero-trust enforcement in network config. | +| A.6.8 | Information security event reporting | Agentic — reporting channel documented. | + +--- + +## A.7 Physical Controls (14 controls) + +Primary verification mode: out-of-repo. Cannot be verified from repository alone. The skill verifies that the policy exists and references the system of record (facility management, badge system, environmental monitoring). + +| ID | Title | Verification logic | +|---|---|---| +| A.7.1 | Physical security perimeters | Out-of-repo — policy + facility diagram pointer. | +| A.7.2 | Physical entry | Out-of-repo — policy + badge system reference. | +| A.7.3 | Securing offices, rooms and facilities | Out-of-repo — policy. | +| A.7.4 | Physical security monitoring (NEW 2022) | Out-of-repo — policy + CCTV/access log pointer. | +| A.7.5 | Protecting against physical and environmental threats | Out-of-repo — policy + insurance + environmental monitoring. | +| A.7.6 | Working in secure areas | Out-of-repo — policy. | +| A.7.7 | Clear desk and clear screen | Out-of-repo — policy + screen lock GPO/MDM enforcement. | +| A.7.8 | Equipment siting and protection | Out-of-repo — policy. | +| A.7.9 | Security of assets off-premises | Out-of-repo — laptop/mobile policy + MDM pointer. | +| A.7.10 | Storage media | Out-of-repo — media handling policy. | +| A.7.11 | Supporting utilities | Out-of-repo — UPS/HVAC documentation. | +| A.7.12 | Cabling security | Out-of-repo — facility documentation. | +| A.7.13 | Equipment maintenance | Out-of-repo — maintenance log pointer. | +| A.7.14 | Secure disposal or re-use of equipment | Out-of-repo — disposal policy + certificates of destruction pointer. | + +--- + +## A.8 Technological Controls (34 controls) + +Primary verification mode: deterministic. This is where CI/CD scanner ROI is highest. + +| ID | Title | Verification logic | +|---|---|---| +| A.8.1 | User endpoint devices | Deterministic — MDM integration scripts; agentic — endpoint policy. | +| A.8.2 | Privileged access rights | Deterministic — IAM IaC scanned for wildcard `Action: "*"` / `Resource: "*"`; Steampipe runtime check for over-privileged roles. | +| A.8.3 | Information access restriction | Deterministic — RBAC middleware / route-level access control in app code. | +| A.8.4 | Access to source code | Deterministic — branch protection rules in `.github/settings.yml`, mandatory code review, no direct push to main. | +| A.8.5 | Secure authentication | Deterministic — MFA enforced in IdP config; HTTP basic auth deprecated; cookie/session security flags set. | +| A.8.6 | Capacity management | Deterministic — autoscaling group definitions, resource limits in K8s manifests. | +| A.8.7 | Protection against malware | Deterministic — endpoint protection deployment; container image vuln scanning (Trivy). | +| A.8.8 | Management of technical vulnerabilities | Deterministic — SCA executes on every PR; CVE threshold enforced. | +| A.8.9 | Configuration management (NEW 2022) | Deterministic — all infrastructure defined as code; drift detection. | +| A.8.10 | Information deletion (NEW 2022) | Deterministic — lifecycle/retention policies in storage IaC. | +| A.8.11 | Data masking (NEW 2022) | Deterministic — static analysis confirming hashing/tokenization on PII handlers. | +| A.8.12 | Data leakage prevention (NEW 2022) | Deterministic — egress filtering rules, restrictive CORS, no public buckets. | +| A.8.13 | Information backup | Deterministic — automated snapshot schedules, backup vault config. | +| A.8.14 | Redundancy of information processing facilities | Deterministic — multi-AZ / multi-region in IaC. | +| A.8.15 | Logging | Deterministic — log aggregation deployed; native cloud audit logs (CloudTrail) enabled. | +| A.8.16 | Monitoring activities (NEW 2022) | Deterministic — alerting rules + webhooks defined. | +| A.8.17 | Clock synchronization | Deterministic — NTP service uniformly configured. | +| A.8.18 | Use of privileged utility programs | Deterministic — no `--privileged` containers; agentic — utility access policy. | +| A.8.19 | Installation of software on operational systems | Deterministic — immutable infrastructure pattern enforced; CI/CD is the only path to production. | +| A.8.20 | Network security | Deterministic — TLS 1.2+ minimums, WAF deployment in load balancers. | +| A.8.21 | Security of network services | Deterministic — service definitions declare security profiles. | +| A.8.22 | Segregation of networks | Deterministic — VPC subnets, route tables, K8s NetworkPolicy enforce isolation. | +| A.8.23 | Web filtering (NEW 2022) | Deterministic — proxy / DNS firewall allow-deny lists. | +| A.8.24 | Use of cryptography | Deterministic — encryption-at-rest flags, encryption-in-transit, no MD5/SHA-1, no hardcoded keys. | +| A.8.25 | Secure development life cycle | Deterministic — Dev/Test/Prod environment isolation; security gates in pipeline. | +| A.8.26 | Application security requirements | Agentic — review of ADRs / design docs for security constraints. | +| A.8.27 | Secure system architecture and engineering principles | Agentic — review of architecture docs for zero-trust / defense-in-depth. | +| A.8.28 | Secure coding (NEW 2022) | Deterministic — SAST in CI/CD scanning OWASP Top 10. | +| A.8.29 | Security testing in development and acceptance | Deterministic — DAST + SAST mandatory pipeline steps. | +| A.8.30 | Outsourced development | Deterministic — SCA on third-party libs; agentic — vendor management policy. | +| A.8.31 | Separation of development, test and production environments | Deterministic — IaC variable files / account separation. | +| A.8.32 | Change management | Deterministic — Git PR approval requirements; CODEOWNERS enforcement. | +| A.8.33 | Test information | Deterministic — test directories scanned for unsanitized production data. | +| A.8.34 | Protection of information systems during audit testing | Deterministic — read-only roles for scanners; no destructive test executions. | + +--- + +## How to use this catalog + +1. The SoA tells you which subset applies. Filter this catalog by the SoA before scanning. +2. For each in-scope control, route to the verification mode column. +3. Deterministic controls map to specific Checkov / Trivy / Steampipe checks — see `tool-orchestration.md`. +4. Agentic controls map to LLM prompts — see `agentic-prompts.md`. +5. Out-of-repo controls require evidence pointer verification only. diff --git a/.claude/skills/iso-27001-2022-compliance/references/cross-framework-mapping.md b/.claude/skills/iso-27001-2022-compliance/references/cross-framework-mapping.md new file mode 100644 index 00000000..7174b404 --- /dev/null +++ b/.claude/skills/iso-27001-2022-compliance/references/cross-framework-mapping.md @@ -0,0 +1,150 @@ +# Cross-Framework Mapping — NIST 800-53, CIS Controls, SOC 2 + +A single ISO 27001 finding can be projected onto NIST SP 800-53 Rev. 5, CIS Controls v8.1, and SOC 2 Trust Services Criteria. Embedding these mappings into the scanner's data model lets a single scan produce dual- or quad-compliance reports. + +## Why these three + +| Framework | Purpose | Audit type | Best paired with ISO 27001 when | +|---|---|---|---| +| NIST SP 800-53 Rev. 5 | U.S. federal control catalog (highly prescriptive, granular) | Self-assessment / FedRAMP | Selling to U.S. government / FedRAMP authorization. | +| CIS Controls v8.1 | Prioritized, technical implementation roadmap | Operational benchmark | Used as the technical companion to ISO's governance focus. | +| SOC 2 Trust Services Criteria | Operational effectiveness attestation | Type I (point-in-time) or Type II (period) | Selling SaaS to U.S. enterprise customers. | + +ISO 27001 is governance-first; CIS is technique-first; NIST is exhaustive-first; SOC 2 is operational-effectiveness-first. They overlap heavily but are not interchangeable. + +## ISO 27001:2022 → NIST SP 800-53 Rev. 5 + +The official NIST mapping uses an asterisk convention: an unmarked mapping means full equivalence; an asterisk means the ISO control does not fully satisfy the NIST control's intent. + +| ISO 2022 ID | NIST Control(s) | Equivalence | +|---|---|---| +| A.5.1 (Policies) | PL-1, PM-1 | Full | +| A.5.2 (Roles) | PS-2, AC-1 | Full | +| A.5.7 (Threat Intelligence) | PM-15, PM-16, RA-3, SI-5 | Partial — NIST is more prescriptive on TI sources | +| A.5.9 (Inventory) | CM-8, PM-5 | Partial — NIST CM-8 demands more frequent reconciliation | +| A.5.15 (Access control) | AC-1, AC-2, AC-3, AC-5, AC-6 | Full | +| A.5.23 (Cloud security) | SA-9 (External system services), CA-3 | Partial | +| A.5.30 (BC readiness) | CP-2, CP-7, CP-10 | Full | +| A.5.34 (Privacy / PII) | PT-1 through PT-8 (Privacy family) | **Significant gap — see below** | +| A.6.1 (Screening) | PS-3 | Full | +| A.6.3 (Awareness) | AT-1, AT-2 | Full | +| A.7.1 (Physical perimeter) | PE-3 | Full | +| A.7.4 (Physical monitoring) | PE-6 | Full | +| A.8.2 (Privileged access) | AC-6 (Least privilege) | Full | +| A.8.3 (Information access restriction) | AC-3 | Full | +| A.8.4 (Source code access) | CM-5, AC-3 | Full | +| A.8.8 (Vulnerability management) | RA-5, SI-2 | Full | +| A.8.9 (Configuration management) | CM-2, CM-3, CM-6 | Full | +| A.8.10 (Information deletion) | MP-6, SI-12 | Full | +| A.8.11 (Data masking) | SC-28, SI-19 | Partial | +| A.8.12 (DLP) | SC-7 (Boundary protection), SC-8 | Partial | +| A.8.15 (Logging) | AU-2, AU-3, AU-12 | Full | +| A.8.16 (Monitoring) | AU-6, SI-4 | Full | +| A.8.20 (Network security) | SC-7, SC-8 | Full | +| A.8.22 (Network segregation) | SC-7(13), SC-32 | Full | +| A.8.24 (Cryptography) | SC-13, SC-28, IA-7 | Full | +| A.8.25 (Secure SDLC) | SA-3, SA-15 | Full | +| A.8.28 (Secure coding) | SA-11, SI-10 | Full | +| A.8.32 (Change management) | CM-3, CM-4 | Full | + +### Critical NIST gap — privacy + +NIST SP 800-53 Rev. 5 integrates a full Privacy (PT) control family directly into the catalog. ISO 27001 addresses privacy primarily through A.5.34 and points to ISO 27701 for full privacy management. Organizations claiming dual ISO 27001 + NIST 800-53 compliance must either: +1. Adopt ISO 27701 in addition, OR +2. Implement the NIST PT family separately and document this as a SoA inclusion above and beyond Annex A. + +The scanner should explicitly flag NIST PT family as a documentation gap when generating dual-compliance reports based solely on ISO 27001. + +--- + +## ISO 27001:2022 → CIS Controls v8.1 + +CIS Controls are organized into 18 numbered controls (formerly "Critical Security Controls"). They are the most operationally prescriptive of the four frameworks. + +| ISO 2022 | CIS Control | Notes | +|---|---|---| +| A.5.9 (Inventory of assets) | CIS 1 (Enterprise Assets), CIS 2 (Software Assets) | CIS provides the technical methodology. | +| A.8.10, A.8.11, A.8.12 (Data lifecycle) | CIS 3 (Data Protection) | Direct alignment. | +| A.8.9 (Configuration management) | CIS 4 (Secure Configuration) | Direct alignment. | +| A.5.15, A.8.2 (Access control) | CIS 5 (Account Management), CIS 6 (Access Control Management) | Split across two CIS controls. | +| A.8.8 (Vulnerability management) | CIS 7 (Continuous Vulnerability Management) | Direct alignment. | +| A.8.15 (Logging) | CIS 8 (Audit Log Management) | Direct alignment. | +| A.8.7 (Malware protection) | CIS 10 (Malware Defenses) | Direct alignment. | +| A.8.13 (Backup) | CIS 11 (Data Recovery) | Direct alignment. | +| A.8.20, A.8.22 (Network security) | CIS 12 (Network Infrastructure Management), CIS 13 (Network Monitoring) | Split. | +| A.6.3 (Awareness training) | CIS 14 (Security Awareness and Skills Training) | Direct alignment. | +| A.5.21, A.8.30 (Supply chain) | CIS 15 (Service Provider Management) | Direct alignment. | +| A.8.25, A.8.28 (SDLC, secure coding) | CIS 16 (Application Software Security) | Direct alignment. | +| A.5.24-28 (Incident management) | CIS 17 (Incident Response Management) | Direct alignment. | +| A.8.29 (Security testing) | CIS 18 (Penetration Testing) | Direct alignment. | + +CIS Controls have three Implementation Groups (IG1, IG2, IG3) of increasing rigor. The scanner should report which IG level each in-scope CIS control reaches based on detected configurations. + +--- + +## ISO 27001:2022 → SOC 2 Trust Services Criteria + +SOC 2 has five categories. Security (Common Criteria, CC) is mandatory for every SOC 2 report; the others are optional based on the service's commitments. + +| TSC Category | When to include | +|---|---| +| Security (CC1-CC9) | Always. | +| Availability | If uptime is part of customer commitments. | +| Processing Integrity | If accuracy/completeness of processing matters (e.g., financial systems). | +| Confidentiality | If protecting non-personal confidential data (trade secrets, customer business data). | +| Privacy | If processing personal information. | + +### ISO → SOC 2 Common Criteria mapping + +| ISO 2022 | SOC 2 CC | Notes | +|---|---|---| +| A.5.1 (Policies) | CC1.1, CC2.2 | Control environment foundation. | +| Clause 5 (Leadership) | CC1.1, CC1.2, CC1.3 | Tone at the top. | +| A.5.2 (Roles) | CC1.4, CC1.5 | Accountability. | +| A.5.4 (Management responsibilities) | CC2.1, CC2.2 | Communication. | +| Clause 6.1 (Risk) | CC3.1, CC3.2, CC3.3, CC3.4 | Risk assessment. | +| Clause 9 (Performance evaluation) | CC4.1, CC4.2 | Monitoring. | +| A.5.1, Clause 5.2 | CC5.1, CC5.2, CC5.3 | Control activities. | +| A.5.15, A.5.16, A.8.2, A.8.3, A.8.5 | CC6.1, CC6.2, CC6.3 | Logical access. | +| A.7.1-A.7.14 | CC6.4, CC6.5 | Physical access. | +| A.8.10 | CC6.5 | Information disposal. | +| A.8.24 | CC6.6, CC6.7, CC6.8 | Data protection in transit and at rest. | +| A.8.15, A.8.16 | CC7.1, CC7.2 | System operations. | +| A.5.24-A.5.28 | CC7.3, CC7.4, CC7.5 | Incident response. | +| A.8.32 | CC8.1 | Change management. | +| Clause 10 (Improvement), A.5.21 | CC9.1, CC9.2 | Risk mitigation, vendor management. | + +### Dual-report generation + +When generating a SOC 2 + ISO 27001 dual report, the scanner should: + +1. Run the ISO 27001 scan as primary. +2. Project each finding onto the corresponding SOC 2 CC. +3. Highlight ISO controls that have **no SOC 2 equivalent** (rare, but exists for some governance-heavy A.5 controls). +4. Highlight SOC 2 CCs that are **only partially covered** by ISO controls (e.g., processing integrity and privacy categories require additional evidence). + +--- + +## Implementation in scanner data model + +Each finding object should carry a `framework_mappings` field: + +```json +{ + "finding_id": "F-001", + "iso_27001_2022": ["A.8.24"], + "nist_800_53_r5": ["SC-13", "SC-28"], + "cis_v8_1": ["3.11"], + "soc_2_tsc": ["CC6.6", "CC6.7"], + "severity": "high", + "title": "EBS volume not encrypted at rest" +} +``` + +This allows the same finding to appear in four different report views without re-running the scan. + +## Caveats + +- Mappings are bidirectional but lossy. ISO is governance-heavy; NIST is technical-heavy; CIS is implementation-heavy; SOC 2 is operational-effectiveness-heavy. Different frameworks emphasize different aspects of the same underlying risk. +- An organization passing one framework does not automatically pass another. Each framework has unique requirements (NIST privacy family, SOC 2 processing integrity, etc.). +- Mappings change between framework versions. Verify the version (ISO 27001:2022, NIST 800-53 Rev. 5, CIS v8.1, SOC 2 2017 TSC) every time. The skill should refuse to map without explicit version assertions. diff --git a/.claude/skills/iso-27001-2022-compliance/references/isms-clauses.md b/.claude/skills/iso-27001-2022-compliance/references/isms-clauses.md new file mode 100644 index 00000000..c3763cac --- /dev/null +++ b/.claude/skills/iso-27001-2022-compliance/references/isms-clauses.md @@ -0,0 +1,94 @@ +# ISMS Clauses 4-10 — Mandatory Documents and Verification Logic + +ISO/IEC 27001:2022 is structurally bifurcated. Annex A enumerates security controls; Clauses 4-10 define the management system that must wrap them. Certification fails without a complete and operating Management System, regardless of how well Annex A controls are implemented technically. + +The clauses are: Context (4), Leadership (5), Planning (6), Support (7), Operation (8), Performance Evaluation (9), Improvement (10). Each produces required documented information that the agentic auditor must locate and evaluate. + +## Mandatory documents per clause + +| Clause | Document | Filename convention | Verification logic | +|---|---|---|---| +| 4.3 | Scope of the ISMS | `ISMS_Scope.md` | Must define exact boundaries — included departments, locations, systems, exclusions with justification. | +| 5.2 | Information Security Policy | `InfoSec_Policy.md` | Must include framework for objectives, commitment to satisfy applicable requirements, commitment to continual improvement, top management approval. | +| 6.1.2 | Risk Assessment Process | `Risk_Methodology.md` | Must define scoring matrix (impact × likelihood), risk acceptance thresholds, owner assignment criteria. | +| 6.1.3 | Statement of Applicability | `SoA.json` / `SoA.csv` | Must contain four core elements per control: identifier, inclusion/exclusion statement, justification, implementation status. | +| 6.2 | Information Security Objectives | `Security_Objectives.md` | Must contain measurable, time-bound goals with assigned owners. | +| 7.2 | Evidence of Competence | `Competency_Matrix.csv` | Records of training, qualifications, certifications. Cross-reference with HRIS where possible. | +| 7.5 | Documented Information control | (cross-cutting) | Every document must have classification mark-up, version table, sign-off, review date within annual interval. | +| 8.2 | Risk Assessment Results | `Risk_Register.xlsx` | Active ledger. Every entry must have risk owner, residual risk score, treatment decision. | +| 8.3 | Risk Treatment Plan | `Risk_Treatment.md` | Must align with Risk Register and SoA. Every accepted risk must be referenced. | +| 9.1 | Performance evaluation results | `KPI_Dashboard.md` or equivalent | Metrics on ISMS effectiveness. | +| 9.2 | Internal Audit Programme + Results | `Internal_Audit_Log.md` | Dates, auditors (independent from auditee), findings, non-conformities, corrective actions. | +| 9.3 | Management Review minutes | `Mgmt_Review_Minutes.md` | Must show executive participation and cover the mandatory inputs (see below). | +| 10.1 | Continual improvement | (cross-cutting) | Evidence of corrective actions closing previous findings. | +| 10.2 | Nonconformity and corrective action records | `NC_Log.md` or `NC_Register.xlsx` | Each NC must have root cause analysis, corrective action, effectiveness verification. | + +## Clause 9.3 — Mandatory Management Review inputs + +This is the most commonly under-documented requirement. Management Review minutes must explicitly cover **all** of the following: + +1. Status of actions from previous management reviews. +2. Changes in external and internal issues relevant to the ISMS. +3. Changes in needs and expectations of interested parties. +4. Feedback on information security performance, including: + a. Nonconformities and corrective actions. + b. Monitoring and measurement results. + c. Audit results. + d. Fulfilment of information security objectives. +5. Feedback from interested parties. +6. Results of risk assessment and status of risk treatment plan. +7. Opportunities for continual improvement. + +The agentic auditor must verify each of these is textually present. Output a per-input checklist showing pass/fail for each agenda item. + +## Clause 7.5 — Documented Information requirements + +Every controlled document must satisfy: + +| Requirement | Verification logic | +|---|---| +| Title and identifier | Regex check for unique document ID. | +| Date of issue / last revision | Regex check + freshness check (within annual interval). | +| Version number | Regex check for semantic versioning or sequential numbering. | +| Classification mark-up | Regex search for "Confidential", "Internal Use Only", "Public" tokens. | +| Author / approver | Regex check for sign-off section. | +| Approval evidence | Cross-reference with version control history (Git blame for last approver). | + +Documents missing any of these elements are deterministic violations of Clause 7.5, separate from any content-quality issues. + +## Document quality vs document existence + +The agentic auditor must distinguish two failure modes: + +1. **Existence failure**: Document is missing entirely. Deterministic. +2. **Adequacy failure**: Document exists but content does not meet the clause requirements. Probabilistic, requires LLM evaluation. + +Adequacy failures are more common than existence failures in mature organizations. A `Mgmt_Review_Minutes.md` may exist as a file but fail to mention 5 of the 7 mandatory Clause 9.3 inputs. The deterministic check passes; the agentic check fails. + +Always run both checks and report them separately. + +## Boilerplate detection + +Be especially alert to AI-generated boilerplate. Common red flags: + +- Generic language with no organizational specificity (no team names, no system names, no actual numbers). +- Missing contextual references to the organization's actual systems, products, or geography. +- Inconsistent voice or tense across sections. +- Identical phrasing to template repositories on GitHub. + +Boilerplate documents technically satisfy existence checks but fail adequacy. Flag as Observation, not Non-Conformity, since they can be remediated by genuine documentation work. + +## Cross-clause consistency checks + +The auditor must run cross-references: + +| Check | Source A | Source B | Failure mode | +|---|---|---|---| +| Risk Register entries → SoA controls | Risk_Register | SoA | Risk references control X but SoA excludes X without justification linking to compensating controls. | +| Risk Treatment Plan → Risk Register | Risk_Treatment | Risk_Register | Treatment references risk ID not in register. | +| SoA inclusions → InfoSec_Policy | SoA | InfoSec_Policy | Policy claims commitments not reflected in SoA inclusions. | +| Internal Audit findings → NC Log | Internal_Audit_Log | NC_Log | Audit identified NC but no entry in NC log. | +| Competency Matrix → InfoSec roles | Competency_Matrix | Roles defined in policies | Role exists in policy but no competency requirement defined. | +| Suppression Risk IDs → Risk Register | Inline scanner suppressions | Risk_Register | Suppression references Risk ID that does not exist. | + +These cross-checks are the highest-value agentic operations because they detect compliance theater — where every individual document looks fine but the documents are internally inconsistent. diff --git a/.claude/skills/iso-27001-2022-compliance/references/legacy-mapping.md b/.claude/skills/iso-27001-2022-compliance/references/legacy-mapping.md new file mode 100644 index 00000000..9ebe5f85 --- /dev/null +++ b/.claude/skills/iso-27001-2022-compliance/references/legacy-mapping.md @@ -0,0 +1,82 @@ +# 2013 → 2022 Control Mapping + +When scanning legacy repositories or evaluating SoAs that still reference 2013-era control identifiers, translate using this matrix before generating findings. Failing to translate produces false-positive non-conformities. + +## Structural change + +| Aspect | 2013 | 2022 | +|---|---|---| +| Control count | 114 | 93 | +| Domains/themes | 14 domains (A.5–A.18) | 4 themes (A.5–A.8) | +| Attribute system | None | 5 attribute dimensions per control | +| Merged controls | — | 57 → 24 | +| New controls | — | 11 net-new | +| Retained (renamed/renumbered) | — | 58 | + +## Common translation patterns + +The 2013 controls A.5–A.18 do not map cleanly to A.5–A.8. The new themes are reorganized around governance level, not topical similarity to the old domains. + +| 2013 ID | 2013 Title | 2022 ID | 2022 Title | Notes | +|---|---|---|---|---| +| A.5.1.1 | Policies for information security | A.5.1 | Policies for information security | Direct rename. | +| A.6.1.1 | Information security roles and responsibilities | A.5.2 | Information security roles and responsibilities | Direct rename. | +| A.6.1.2 | Segregation of duties | A.5.3 | Segregation of duties | Direct rename. | +| A.6.1.3 | Contact with authorities | A.5.5 | Contact with authorities | Direct rename. | +| A.6.1.4 | Contact with special interest groups | A.5.6 | Contact with special interest groups | Direct rename. | +| A.6.2 | Mobile devices and teleworking | A.6.7, A.8.1 | Remote working / User endpoint devices | Split. | +| A.7 | Human resource security (entire domain) | A.6 | People (entire theme) | Restructured. | +| A.8.1.1 | Inventory of assets | A.5.9 | Inventory of information and other associated assets | Renamed, broader. | +| A.8.2 | Information classification | A.5.12, A.5.13 | Classification of information / Labelling | Split into two. | +| A.9 | Access control (entire domain) | A.5.15–A.5.18, A.8.2–A.8.5 | Distributed across themes | Major restructure. | +| A.9.1.1 | Access control policy | A.5.15 | Access control | Merged. | +| A.9.2.1 | User registration and de-registration | A.5.16 | Identity management | Renamed. | +| A.9.2.3 | Management of privileged access rights | A.8.2 | Privileged access rights | Renamed. | +| A.9.4.5 | Access control to program source code | A.8.4 | Access to source code | Renamed. | +| A.10 | Cryptography | A.8.24 | Use of cryptography | Compressed. | +| A.10.1.1 | Policy on the use of cryptographic controls | A.8.24 | Use of cryptography | Merged. | +| A.10.1.2 | Key management | A.8.24 | Use of cryptography | Merged. | +| A.11 | Physical and environmental security | A.7 | Physical (entire theme) | Restructured. | +| A.12.1.1 | Documented operating procedures | A.5.37 | Documented operating procedures | Moved to Organizational. | +| A.12.1.2 | Change management | A.8.32 | Change management | Renumbered. | +| A.12.1.3 | Capacity management | A.8.6 | Capacity management | Renumbered. | +| A.12.1.4 | Separation of development, testing and operational environments | A.8.31 | Separation of development, test and production environments | Renumbered. | +| A.12.2.1 | Controls against malware | A.8.7 | Protection against malware | Renamed. | +| A.12.3.1 | Information backup | A.8.13 | Information backup | Direct rename. | +| A.12.4.1 | Event logging | A.8.15 | Logging | Compressed (4 controls into 1). | +| A.12.4.2 | Protection of log information | A.8.15 | Logging | Merged. | +| A.12.4.3 | Administrator and operator logs | A.8.15 | Logging | Merged. | +| A.12.4.4 | Clock synchronisation | A.8.17 | Clock synchronization | Renumbered. | +| A.12.5.1 | Installation of software on operational systems | A.8.19 | Installation of software on operational systems | Renumbered. | +| A.12.6.1 | Management of technical vulnerabilities | A.8.8 | Management of technical vulnerabilities | Renumbered. | +| A.12.6.2 | Restrictions on software installation | A.8.19 | Installation of software on operational systems | Merged. | +| A.13.1.1 | Network controls | A.8.20 | Network security | Renamed. | +| A.13.1.2 | Security of network services | A.8.21 | Security of network services | Renumbered. | +| A.13.1.3 | Segregation in networks | A.8.22 | Segregation of networks | Renumbered. | +| A.13.2 | Information transfer | A.5.14 | Information transfer | Moved to Organizational. | +| A.14.1 | Security requirements of information systems | A.8.26 | Application security requirements | Compressed. | +| A.14.2.1 | Secure development policy | A.8.25 | Secure development life cycle | **Frequently referenced legacy ID.** | +| A.14.2.2 | System change control procedures | A.8.32 | Change management | Merged. | +| A.14.2.5 | Secure system engineering principles | A.8.27 | Secure system architecture and engineering principles | Renamed. | +| A.14.2.7 | Outsourced development | A.8.30 | Outsourced development | Renumbered. | +| A.14.2.8 | System security testing | A.8.29 | Security testing in development and acceptance | Renamed. | +| A.14.3.1 | Protection of test data | A.8.33 | Test information | Renamed. | +| A.15 | Supplier relationships | A.5.19–A.5.22 | Supplier-related controls | Restructured into Organizational. | +| A.16 | Information security incident management | A.5.24–A.5.28 | Incident-related controls | Restructured. | +| A.17 | Information security aspects of business continuity | A.5.29, A.5.30, A.8.13, A.8.14 | Distributed | Restructured. | +| A.18.1 | Compliance with legal and contractual requirements | A.5.31 | Legal, statutory, regulatory and contractual requirements | Compressed. | +| A.18.1.3 | Protection of records | A.5.33 | Protection of records | Renumbered. | +| A.18.1.4 | Privacy and protection of PII | A.5.34 | Privacy and protection of PII | Renumbered. | +| A.18.2.1 | Independent review of information security | A.5.35 | Independent review of information security | Renumbered. | + +## Implementation note for the scanner + +When parsing a SoA that uses 2013 identifiers: + +1. Detect the format (heuristic: presence of identifiers like A.9.x, A.12.x, A.14.x indicates 2013). +2. Apply the translation table above. +3. Generate a warning: "SoA references 2013-era identifiers. Translation applied. Recommend updating SoA to 2022 identifiers." +4. Run all checks against translated 2022 controls. +5. Verify the 11 net-new controls (see `new-controls-2022.md`) are now addressed in the SoA — they will not have legacy equivalents. + +The translation is one-way and lossy. Several 2013 controls map to multiple 2022 controls (splits) and several 2022 controls absorb multiple 2013 controls (merges). When in doubt, apply the most restrictive interpretation. diff --git a/.claude/skills/iso-27001-2022-compliance/references/limitations.md b/.claude/skills/iso-27001-2022-compliance/references/limitations.md new file mode 100644 index 00000000..8080068b --- /dev/null +++ b/.claude/skills/iso-27001-2022-compliance/references/limitations.md @@ -0,0 +1,114 @@ +# Honest Limitations of Automated ISO 27001:2022 Compliance Verification + +The skill is an aid to certification, not a substitute. A scanner that overpromises destroys audit credibility. Surface these limitations in every report. + +## Limitation 1 — Physical reality + +No code execution can verify physical reality. The scanner can confirm a policy says "server room doors must be locked" (A.7.2) or "premises shall be monitored" (A.7.4). It cannot confirm that any physical door is actually locked or that any actual camera is recording. + +**Required disclaimer in reports**: +> "Physical Controls (A.7.x) verified by documentation only. Physical validation requires on-site inspection and is out of scope for repository-based scanning." + +## Limitation 2 — Behavioral compliance + +Human behavior is opaque to scanners. Several controls require people to actually do things, not just for the documentation to require it. + +| Control | What scanner can verify | What scanner cannot verify | +|---|---|---| +| A.6.3 Awareness training | LMS API shows completion | Whether the employee understood the material | +| A.7.7 Clear desk and clear screen | Policy exists, screen lock GPO/MDM enforced | Whether actual desks are clear, whether passwords are written on post-its | +| A.6.6 NDAs | Template exists | Whether all employees have signed | +| A.5.10 Acceptable use | Policy exists | Whether employees follow it | + +**Required disclaimer**: +> "Behavioral compliance is out of scope. Verification requires walkthroughs, interviews, and observation by human auditors." + +## Limitation 3 — Point-in-time scans vs continuous compliance + +A repository can pass all checks at PR-merge time and immediately drift out of compliance through: +- Manual changes via cloud console (clickops). +- Resources created outside IaC (e.g., emergency hotfixes). +- Configuration changes by SaaS vendors (e.g., default settings changing in a managed service). +- Credentials rotated outside the documented process. + +This violates A.8.9 (Configuration management) and A.8.16 (Monitoring) by definition. Mitigation requires continuous runtime monitoring (Steampipe queries on a schedule, AWS Config rules, Azure Policy, GCP Organization Policy) — not just CI/CD-time scans. + +**Required disclaimer**: +> "This is a point-in-time assessment of commit . Production state may have drifted from this commit. Continuous runtime monitoring (A.8.16) is required to detect post-merge drift." + +## Limitation 4 — Document existence vs adequacy + +The scanner can prove a file exists. It can apply LLM evaluation to assess whether the file's content meets normative requirements. It cannot prove that the document is current, that the listed approvers actually approved it, or that the procedures described are actually followed. + +The agentic auditor produces "Observations" that require human validation. Adequacy claims are not certifications. + +**Required disclaimer**: +> "Agentic policy review is advisory. Findings labeled 'Observation' or 'Potential Non-Conformity' require validation by a qualified human auditor." + +## Limitation 5 — Agentic AI in the audited system itself + +If the audited system uses AI agents in production (e.g., LLM-based workflows, autonomous decision-making, MCP-server-driven automation), traditional ISO 27001 controls are insufficient. + +Issues: +- A.8.28 (Secure coding) was written for deterministic code. LLM behavior is probabilistic. +- A.8.32 (Change management) assumes changes are deployable artifacts. Prompt or retrieval changes may bypass this. +- A.5.7 (Threat intelligence) does not cover prompt injection or jailbreaking. +- A.8.29 (Security testing) does not specify adversarial robustness testing. + +Reference: OWASP Top 10 for Agentic Applications, Agentic Trust Framework. The scanner should: +1. Detect presence of agentic AI components (LLM API calls, MCP servers, autonomous agents). +2. Demand additional documented governance for autonomy boundaries. +3. Flag standard SOC 2 / ISO 27001 audit reports as insufficient for autonomous systems. + +**Required disclaimer when agentic AI detected**: +> "This system uses agentic AI components. Standard ISO 27001:2022 controls do not adequately address probabilistic and autonomous system behavior. Reference OWASP Top 10 for Agentic Applications and supplement with agent-specific governance controls." + +## Limitation 6 — Out-of-repo systems + +Many controls depend on systems outside the repository: HRIS, IdP, MDM, ticketing, badge access. The scanner can verify policy + evidence pointers, but not the state of external systems unless explicit API integration is configured (e.g., Steampipe with appropriate plugins). + +When external API integration is unavailable, mark the control as "Documentation Verified — System of Record Not Queried" rather than "Verified". + +## Limitation 7 — SoA dependency + +The scanner is only as accurate as the SoA. A SoA that excludes critical controls without justification will cause the scanner to skip checks that should be running. The agentic auditor must evaluate the SoA's exclusion justifications, but ultimately the SoA reflects organizational decisions that the scanner cannot override. + +If the SoA is missing, malformed, or includes obviously inappropriate exclusions, generate a Clause 6.1.3 finding and refuse to issue a "compliant" verdict regardless of technical scan results. + +## Limitation 8 — Certification body discretion + +ISO 27001 certification is issued by accredited certification bodies, not by automated tools. A clean scanner output is not a certificate. Certification bodies apply professional judgment, conduct interviews, perform sampling, and examine evidence in ways that cannot be fully automated. + +The skill produces audit-defensible evidence and identifies probable findings. It does not certify. + +**Required language**: +> "This report is internal evidence to support the organization's information security management system. It is not an ISO 27001 certificate. Certification requires audit by an accredited certification body." + +## Limitation 9 — Accuracy of cross-framework mappings + +NIST 800-53 Rev. 5, CIS Controls v8.1, and SOC 2 TSC are independent frameworks. ISO 27001 mappings are approximations. A control passing in ISO does not automatically pass in another framework. Privacy is the largest gap (see `cross-framework-mapping.md`). + +**Required disclaimer when generating dual-framework reports**: +> "Cross-framework mappings are approximations. Each framework has unique requirements that may not be covered by ISO 27001 alone. Specifically, NIST 800-53 Rev. 5 Privacy (PT) family and SOC 2 Privacy criteria require supplementary controls beyond ISO 27001." + +## Limitation 10 — False negatives in static analysis + +SAST tools have known false-negative rates. Custom detection patterns, novel vulnerabilities, business-logic flaws, and authorization bypasses often escape pattern matching. Achieving high pass rates on the scanner does not prove the absence of vulnerabilities — it proves the absence of detected vulnerabilities. + +A.8.29 (Security testing) requires testing methods beyond SAST: DAST, IAST, manual penetration testing, threat modeling. The scanner can verify these are scheduled and that reports exist; it cannot replace them. + +--- + +## Summary table for report generators + +| Verification claim | Strength | Required disclaimer | +|---|---|---| +| "EBS volume encrypted (A.8.24)" | Strong | None for the IaC fact; add point-in-time disclaimer for the runtime state. | +| "Branch protection enabled (A.8.4)" | Strong | None. | +| "Information Security Policy adequate (Clause 5.2)" | Moderate | Agentic / human review required. | +| "Physical perimeter secured (A.7.1)" | Weak | Documentation only. Physical validation required. | +| "Awareness training completed (A.6.3)" | Weak | LMS records verify completion, not comprehension. | +| "Configuration drift detected" | Strong | Requires Steampipe runtime querying. | +| "ISO 27001:2022 compliant" | **Never claim this** | Certification is the certification body's determination. | + +The skill can claim "evidence of conformance with ". It cannot claim "compliant". diff --git a/.claude/skills/iso-27001-2022-compliance/references/new-controls-2022.md b/.claude/skills/iso-27001-2022-compliance/references/new-controls-2022.md new file mode 100644 index 00000000..fa193440 --- /dev/null +++ b/.claude/skills/iso-27001-2022-compliance/references/new-controls-2022.md @@ -0,0 +1,85 @@ +# 11 New Controls Introduced in ISO/IEC 27001:2022 + +The 2022 revision condensed 114 controls (in 14 domains) down to 93 controls (in 4 themes). 57 legacy controls were merged into 24 modern equivalents, 58 were retained with minor updates, and 11 were introduced net-new. The 11 net-new controls are the most likely automation gaps when transitioning from a 2013-era compliance program. + +The October 31, 2025 transition deadline has now passed, so any active certification must be against the 2022 standard. Treat absence of these 11 controls in a SoA as a presumptive transition failure. + +## The 11 new controls + +### A.5.7 Threat Intelligence +**Intent**: Collect and analyze information about threats to inform risk treatment. +**Repository signal**: Active SCA tooling (Trivy, Snyk, Dependabot, Mend) with continuously updated vulnerability databases. Threat-intel feed subscriptions documented. +**Common gap**: Organizations have a vuln scanner but no documented threat-intel ingestion process. The control requires both. + +### A.5.23 Information security for use of cloud services +**Intent**: Specify, manage, and review security requirements for acquiring and using cloud services. +**Repository signal**: IaC templates aligned with cloud provider security baselines (CIS AWS Foundations Benchmark, CIS Azure Benchmark, CIS GCP Benchmark). Cloud account governance documented (landing zones, organizational policies). +**Common gap**: Multi-account / multi-cloud deployments without a documented cloud security strategy. SoA inclusion is mandatory for any organization using IaaS/PaaS. + +### A.5.30 ICT readiness for business continuity +**Intent**: Plan, implement, maintain, and test ICT readiness based on business continuity objectives. +**Repository signal**: Multi-AZ / multi-region deployment in IaC. Backup automation. Documented RTO/RPO. Disaster recovery runbooks. DR test evidence. +**Common gap**: Backups exist but restore procedures are never tested. The control requires evidence of testing. + +### A.7.4 Physical security monitoring +**Intent**: Monitor premises continuously for unauthorized physical access. +**Repository signal**: Out-of-repo. Verify policy + pointer to CCTV / access log system. For fully remote organizations, document the exclusion in the SoA with justification. +**Common gap**: Organization claims "we are remote-first" but employees still have home offices with company equipment. Document the boundary. + +### A.8.9 Configuration management +**Intent**: Establish, document, implement, monitor, and review configurations of hardware, software, services, and networks. +**Repository signal**: All infrastructure defined as code in version control. Drift detection in pipelines (terraform plan against deployed state). Configuration baselines for OS images / container base images. +**Common gap**: Production resources created via console clickops alongside Terraform-managed resources. The scanner must detect this divergence. + +### A.8.10 Information deletion +**Intent**: Ensure information is deleted when no longer required to prevent unauthorized exposure and to meet legal, regulatory, and contractual requirements. +**Repository signal**: S3 lifecycle rules, database TTLs, log retention policies, GDPR right-to-erasure handlers in application code. +**Common gap**: Test/staging environments with stale production-derived data sitting indefinitely. + +### A.8.11 Data masking +**Intent**: Use data masking, pseudonymization, or anonymization to protect sensitive information. +**Repository signal**: PII handlers in application code use hashing, tokenization, or format-preserving encryption. Test fixtures use synthetic data. Logging frameworks redact sensitive fields before output. +**Common gap**: Logs include full payloads of API requests with PII intact. + +### A.8.12 Data leakage prevention +**Intent**: Apply DLP measures to systems, networks, and devices that process, store, or transmit sensitive information. +**Repository signal**: Egress filtering in security groups / network policies. Restrictive CORS configurations. No public S3/GCS/Azure Blob buckets. Email DLP integration where applicable. +**Common gap**: Unrestricted egress to the internet from production VPCs. + +### A.8.16 Monitoring activities +**Intent**: Monitor networks, systems, and applications for anomalous behavior to detect potential information security incidents. +**Repository signal**: Alerting rules deployed via IaC. SIEM integration. Webhook integrations to incident response tooling (PagerDuty, Opsgenie). Anomaly detection on key metrics. +**Common gap**: Logging exists (A.8.15) but nobody is alerted on anomalies. A.8.15 and A.8.16 are distinct — implement both. + +### A.8.23 Web filtering +**Intent**: Manage access to external websites to reduce exposure to malicious content. +**Repository signal**: DNS firewall configuration (Cloudflare Gateway, Cisco Umbrella, AWS Route 53 Resolver DNS Firewall). Proxy allow/deny lists. Outbound HTTP egress restricted. +**Common gap**: Endpoint-level web filtering exists but server-side egress is unrestricted. + +### A.8.28 Secure coding +**Intent**: Apply secure coding principles to reduce vulnerabilities introduced during development. +**Repository signal**: SAST tooling (Semgrep, SonarQube, CodeQL) in CI/CD. Linter rules for security patterns. Pre-commit hooks. Documented secure coding standards. +**Common gap**: SAST runs but findings are never blocking. The control requires that findings actually gate merges. + +## SoA implications + +If transitioning from 2013, every SoA must explicitly address these 11 controls. The reasonable defaults for inclusion / exclusion: + +| Control | Default | Notes | +|---|---|---| +| A.5.7 | Include | Almost no organization can credibly exclude threat intelligence. | +| A.5.23 | Include if any cloud usage | Exclude only for strictly on-prem orgs. | +| A.5.30 | Include | Business continuity is universal. | +| A.7.4 | Conditional exclusion if remote-only | Document boundary clearly. | +| A.8.9 | Include | If you have any IT infrastructure, this applies. | +| A.8.10 | Include | Data lifecycle is universal. | +| A.8.11 | Conditional | Exclude only if processing zero PII (rare). | +| A.8.12 | Include | Universal. | +| A.8.16 | Include | Universal. | +| A.8.23 | Conditional | Exclude only if all egress is fundamentally restricted by architecture. | +| A.8.28 | Include | Mandatory for any organization developing software. | + +Suspicious patterns the auditor should flag: +- More than 2 of these excluded → likely incomplete transition. +- All included as "Planned" → SoA is aspirational rather than reflective of actual state. +- Any included as "Implemented" without corresponding repository evidence → false claim. diff --git a/.claude/skills/iso-27001-2022-compliance/references/tool-orchestration.md b/.claude/skills/iso-27001-2022-compliance/references/tool-orchestration.md new file mode 100644 index 00000000..a254725a --- /dev/null +++ b/.claude/skills/iso-27001-2022-compliance/references/tool-orchestration.md @@ -0,0 +1,289 @@ +# Tool Orchestration — Checkov, Trivy, Steampipe + +The skill must not reimplement what mature open-source security tools already do. Wrap them. The three primary engines together cover the full repository-and-runtime surface for ISO 27001:2022. + +| Tool | Domain | Typical input | Output | +|---|---|---|---| +| Checkov | IaC static analysis | Terraform, CloudFormation, Kubernetes, ARM, Helm, Dockerfile | JSON / SARIF / JUnit | +| Trivy | SCA, container, secret scanning | Filesystem, container images, dependency manifests | JSON / SARIF / table | +| Steampipe | Live runtime querying | Cloud APIs, IdP APIs, GitHub API | SQL result sets | + +Checkov and Trivy answer "what does the code say?" Steampipe answers "what is actually deployed?" Both questions matter — IaC drift means the code may be compliant while production isn't. + +--- + +## Checkov + +### Why +Checkov has the deepest IaC coverage of any open-source scanner: ~1,000 built-in policies across AWS, Azure, GCP, Kubernetes, Docker, Helm, and more. It uses a graph-based engine that can evaluate cross-resource relationships (e.g., "this RDS is in a subnet whose route table allows 0.0.0.0/0"). + +### Mapping built-in policies to ISO 27001 + +Checkov's built-in policies are CIS-aligned. To wrap them for ISO 27001:2022 the skill needs a translation layer: + +```yaml +# .checkov.yaml or via custom config +iso_27001_mapping: + CKV_AWS_3: # EBS volume encryption + iso_controls: ["A.8.24"] + CKV_AWS_16: # RDS encryption + iso_controls: ["A.8.24"] + CKV_AWS_19: # S3 server-side encryption + iso_controls: ["A.8.24", "A.8.10"] + CKV_AWS_24: # SSH from 0.0.0.0/0 + iso_controls: ["A.8.20", "A.8.22"] + CKV_AWS_46: # IAM hardcoded AWS access keys + iso_controls: ["A.8.24", "A.5.17"] + CKV_AWS_53: # S3 block public ACLs + iso_controls: ["A.8.12", "A.8.3"] + # ... and so on +``` + +The wrapper script: +1. Runs `checkov -d ./repo --output json --quiet`. +2. Parses the JSON output. +3. Joins each `check_id` against the mapping table. +4. Re-emits findings tagged with ISO 27001 control identifiers. +5. Filters out findings for controls excluded by the SoA. + +### Custom policies for ISO-specific patterns + +Checkov supports custom policies in YAML for simple attribute checks and Python for graph-based checks. Example custom policy for A.8.24 — ensuring all EBS volumes are encrypted: + +```yaml +metadata: + name: "Ensure EBS volumes are encrypted (ISO 27001 A.8.24)" + id: "CUSTOM_ISO_A824_EBS_ENCRYPTION" + category: "ENCRYPTION" +definition: + cond_type: "attribute" + resource_types: + - "aws_ebs_volume" + attribute: "encrypted" + operator: "equals" + value: true +``` + +Place custom policies in `.checkov/custom_policies/` and run with `--external-checks-dir`. + +### Suppression integration + +Checkov inline suppressions (`# checkov:skip=: `) must be parsed by the wrapper to extract Risk Register IDs. Recommended convention: + +```hcl +# checkov:skip=CKV_AWS_19: Risk accepted by CISO 2026-05-01 (Risk-ID: SEC-102) +resource "aws_s3_bucket" "legacy_export" { + # ... +} +``` + +The wrapper extracts `Risk-ID: SEC-102` and verifies SEC-102 exists in the canonical Risk Register before honoring the suppression. + +--- + +## Trivy + +### Why +Trivy is the de-facto standard for container and dependency scanning. It supports filesystem scans, container images, Git repos, Kubernetes clusters, AWS environments, and SBOM generation. Its `--compliance` flag enables custom compliance specs. + +### Custom ISO 27001 compliance spec + +Create `trivy-iso27001-2022.yaml`: + +```yaml +spec: + id: iso-27001-2022 + title: ISO/IEC 27001:2022 + description: Custom compliance spec mapping Trivy checks to ISO 27001:2022 Annex A + relatedResources: [] + version: "1.0" + controls: + - id: A.8.8 + name: Management of technical vulnerabilities + description: Information about technical vulnerabilities of information systems in use shall be obtained, the organization's exposure to such vulnerabilities shall be evaluated and appropriate measures shall be taken. + checks: + - id: AVD-DS-0001 # Trivy container vulnerability check + - id: CVE-* # All CVE detection + severity: HIGH + + - id: A.8.24 + name: Use of cryptography + description: Rules for the effective use of cryptography, including cryptographic key management, shall be defined and implemented. + checks: + - id: secret-* # All secret detection rules + severity: CRITICAL + + - id: A.5.17 + name: Authentication information + description: Allocation and management of authentication information shall be controlled. + checks: + - id: secret-* + severity: CRITICAL + + - id: A.8.30 + name: Outsourced development + description: The organization shall direct, monitor and review the activities related to outsourced system development. + checks: + - id: AVD-DS-* # Dependency CVEs + severity: HIGH +``` + +Run: +```bash +trivy fs ./repo --compliance @trivy-iso27001-2022.yaml --format json +``` + +### What Trivy covers for ISO + +| ISO Control | Trivy capability | +|---|---| +| A.8.8 (Vuln management) | OS package CVEs, language-specific CVEs (npm, pip, gem, etc.) | +| A.8.24 (Cryptography) | Secret detection (AWS keys, GitHub tokens, generic high-entropy strings) | +| A.5.17 (Authentication info) | Secret detection in source code | +| A.8.30 (Outsourced dev) | Third-party library CVEs | +| A.8.7 (Anti-malware) | Container image scanning for known malicious packages | +| A.8.21 (Network service security) | Misconfigurations in K8s services and Dockerfile exposed ports | + +### SBOM generation for A.5.21 + +Trivy can generate CycloneDX or SPDX SBOMs: +```bash +trivy fs --format cyclonedx --output sbom.json ./repo +``` +SBOM generation directly evidences A.5.21 (Managing information security in the ICT supply chain) and A.8.30. + +--- + +## Steampipe + +### Why +Checkov and Trivy operate on what's in the repo. Steampipe queries what's actually deployed. Drift between IaC and runtime is itself a Clause 8.1 (Operational planning) finding — and runtime queries are the only way to detect it. + +Steampipe uses a Postgres-compatible SQL interface over plugins for AWS, Azure, GCP, GitHub, Microsoft Entra ID, Google Workspace, Okta, Slack, and dozens more. + +### Key queries for ISO 27001 evidence + +#### A.8.2 — Privileged access rights +```sql +-- Find IAM users with admin policies attached +SELECT u.name, p.policy_name +FROM aws_iam_user u +JOIN aws_iam_user_policy_attachment a ON a.user_arn = u.arn +JOIN aws_iam_policy p ON p.arn = a.policy_arn +WHERE p.policy_name = 'AdministratorAccess'; +``` + +#### A.5.18 — Access rights review +```sql +-- Find IAM users who haven't logged in for 90+ days +SELECT name, password_last_used +FROM aws_iam_user +WHERE password_last_used < now() - interval '90 days' + OR password_last_used IS NULL; +``` + +#### A.8.5 — Secure authentication +```sql +-- Find IAM users without MFA +SELECT name, mfa_enabled +FROM aws_iam_user +WHERE mfa_enabled = false + AND password_enabled = true; +``` + +#### A.5.15 — Access control (Microsoft Entra ID) +```sql +-- Find guest users with privileged role assignments +SELECT u.display_name, r.role_definition_name +FROM azuread_user u +JOIN azuread_directory_role_assignment a ON a.principal_id = u.id +JOIN azuread_directory_role r ON r.id = a.role_definition_id +WHERE u.user_type = 'Guest'; +``` + +#### A.8.4 — Source code access +```sql +-- Find GitHub repos without branch protection on main +SELECT full_name, default_branch +FROM github_my_repository r +LEFT JOIN github_branch_protection b ON b.repository_full_name = r.full_name + AND b.name = r.default_branch +WHERE b.repository_full_name IS NULL; +``` + +#### A.8.15 — Logging +```sql +-- Find AWS regions where CloudTrail is not enabled +SELECT region +FROM aws_region +WHERE region NOT IN ( + SELECT home_region FROM aws_cloudtrail_trail WHERE is_multi_region_trail = true +); +``` + +### Continuous evidence generation + +Steampipe queries can be wrapped in [Powerpipe](https://powerpipe.io/) dashboards/benchmarks for continuous compliance evidence. Schedule them daily or hourly to maintain "operational effectiveness" evidence required for SOC 2 Type II — which goes beyond ISO 27001's point-in-time stance but is often required in dual-audit scenarios. + +--- + +## Unified output schema + +The wrapper around all three tools should normalize findings into: + +```json +{ + "scan_id": "uuid", + "repository": "org/repo", + "commit_sha": "abc123", + "soa_version": "1.4", + "scanned_at": "2026-05-07T10:00:00Z", + "tools_used": ["checkov", "trivy", "steampipe"], + "findings": [ + { + "finding_id": "F-001", + "tool": "checkov", + "tool_check_id": "CKV_AWS_19", + "severity": "high", + "title": "S3 bucket without server-side encryption", + "resource": "aws_s3_bucket.data", + "file": "infrastructure/storage.tf", + "line": 42, + "iso_27001_2022_controls": ["A.8.24", "A.8.10"], + "nist_800_53_r5_controls": ["SC-28"], + "cis_v8_1_controls": ["3.11"], + "soc_2_tsc": ["CC6.6"], + "soa_status": "included_implemented", + "suppression": null + } + ], + "documentation_findings": [], + "verification_scope": { + "deterministic_in_repo": true, + "agentic_policy_review": true, + "out_of_repo_evidence_pointers": true, + "runtime_state_via_steampipe": true, + "behavioral_compliance": false, + "physical_validation": false + } +} +``` + +This is the artifact that gets attached to the PR for human review and that becomes audit evidence. + +--- + +## Container packaging + +Distribute the wrapper as a single container image with all three tools pre-installed. Example Dockerfile sketch: + +```dockerfile +FROM python:3.12-slim +RUN pip install checkov +COPY --from=aquasec/trivy:latest /usr/local/bin/trivy /usr/local/bin/trivy +COPY --from=turbot/steampipe:latest /usr/local/bin/steampipe /usr/local/bin/steampipe +COPY wrapper/ /opt/iso27001-scanner/ +ENTRYPOINT ["python", "/opt/iso27001-scanner/scan.py"] +``` + +The wrapper script orchestrates the three engines, normalizes outputs, applies SoA filtering, and produces the unified JSON report. diff --git a/.claude/skills/iso-27001-2022-compliance/references/violation-patterns.md b/.claude/skills/iso-27001-2022-compliance/references/violation-patterns.md new file mode 100644 index 00000000..9aaad14a --- /dev/null +++ b/.claude/skills/iso-27001-2022-compliance/references/violation-patterns.md @@ -0,0 +1,247 @@ +# Violation Patterns — Code, Configuration, Dependency + +This file catalogs concrete violation patterns the scanner must detect. Patterns are organized by where they live in the repository: source code, infrastructure-as-code, or dependency manifests. + +For each pattern: the violation, the controls violated, and the detection logic. + +--- + +## Code-level violations + +### SQL injection via string concatenation +**Controls violated**: A.8.28 (Secure coding), A.8.3 (Information access restriction). +**Pattern**: +```python +query = "SELECT * FROM users WHERE id = " + user_input +cursor.execute(query) +``` +**Detection**: SAST rule (Semgrep, CodeQL) flagging string concatenation into SQL execution functions. Compare to parameterized form `cursor.execute("SELECT * FROM users WHERE id = %s", (user_input,))`. + +### Command injection via shell concatenation +**Controls violated**: A.8.28. +**Pattern**: +```python +os.system("ping " + user_input) +subprocess.call(f"git clone {repo_url}", shell=True) +``` +**Detection**: SAST rule for `os.system`, `subprocess.*` with `shell=True` and unsanitized inputs. + +### Hardcoded secrets +**Controls violated**: A.8.24 (Use of cryptography), A.5.17 (Authentication information). +**Pattern**: +```python +AWS_SECRET_KEY = "AKIAIOSFODNN7EXAMPLE" +db_password = "p@ssw0rd123" +``` +**Detection**: Entropy analysis + regex (Trivy secret scanner, gitleaks, truffleHog). Scan full Git history, not just current HEAD — secrets in old commits are still exposed. + +### Weak cryptography +**Controls violated**: A.8.24. +**Patterns**: +```python +import hashlib +hashlib.md5(password.encode()) # Broken +hashlib.sha1(password.encode()) # Broken +``` +```javascript +crypto.createHash('md5') // Broken +``` +**Detection**: SAST rule for MD5, SHA-1, DES, RC4, ECB mode, or hashing without salt for password storage. Required alternatives: SHA-256+ for hashing, bcrypt/argon2/scrypt for passwords. + +### Missing input validation on PII handlers +**Controls violated**: A.8.11 (Data masking), A.5.34 (Privacy and protection of PII). +**Pattern**: Functions that accept PII parameters and write them to logs, return them in error messages, or store them unencrypted. +**Detection**: Tag-based SAST — annotate PII-handling functions and verify masking/redaction is applied before output sinks (logs, errors, storage). + +### Insecure deserialization +**Controls violated**: A.8.28. +**Patterns**: +```python +pickle.loads(user_input) +yaml.load(user_input) # Without SafeLoader +``` +**Detection**: SAST rule for known-unsafe deserializers with untrusted input. + +### Path traversal +**Controls violated**: A.8.3, A.8.28. +**Pattern**: +```python +open(os.path.join(base_dir, user_provided_filename)) +``` +**Detection**: SAST rule for filesystem operations using unsanitized user input. Required guard: realpath check that resolved path is within base_dir. + +--- + +## Configuration-level violations (IaC) + +### Public storage buckets +**Controls violated**: A.8.12 (DLP), A.8.3 (Access restriction), A.5.34. +**Patterns**: +```hcl +resource "aws_s3_bucket" "data" { + acl = "public-read" +} +``` +```hcl +resource "aws_s3_bucket_public_access_block" "data" { + block_public_acls = false + block_public_policy = false +} +``` +**Detection**: Checkov CKV_AWS_53, CKV_AWS_54, CKV_AWS_55, CKV_AWS_56. + +### Wildcard IAM permissions +**Controls violated**: A.8.2 (Privileged access rights). +**Pattern**: +```json +{ + "Effect": "Allow", + "Action": "*", + "Resource": "*" +} +``` +**Detection**: Checkov CKV_AWS_1, CKV_AWS_46, CKV_AWS_49. JSON path query for any policy statement with `Action: *` AND `Resource: *`. Some narrow exceptions exist (e.g., `iam:GetUser` on self) but `*:*` is never justifiable. + +### Unencrypted storage +**Controls violated**: A.8.24. +**Patterns**: +```hcl +resource "aws_ebs_volume" "data" { + encrypted = false # Or omitted (default false in older provider versions) +} + +resource "aws_db_instance" "main" { + storage_encrypted = false +} +``` +**Detection**: Checkov CKV_AWS_3 (EBS), CKV_AWS_16 (RDS), CKV_AWS_17 (RDS publicly accessible), CKV_AWS_19 (S3 server-side encryption). + +### Database in public subnet +**Controls violated**: A.8.20 (Network security), A.8.22 (Segregation of networks). +**Pattern**: RDS / managed database resource attached to a subnet whose route table has a route to an Internet Gateway, plus a security group allowing 0.0.0.0/0 ingress on the database port. +**Detection**: Graph-based check (Checkov supports this via cross-resource attribute queries). + +### Unrestricted security group ingress +**Controls violated**: A.8.20, A.8.22. +**Pattern**: +```hcl +resource "aws_security_group" "open" { + ingress { + from_port = 0 + to_port = 65535 + cidr_blocks = ["0.0.0.0/0"] + } +} +``` +**Detection**: Checkov CKV_AWS_24 (port 22 / SSH from 0.0.0.0/0), CKV_AWS_25 (port 3389 / RDP), generic checks for all-port ingress from 0.0.0.0/0. + +### Missing TLS enforcement +**Controls violated**: A.8.20, A.8.24. +**Patterns**: +```hcl +resource "aws_lb_listener" "http" { + protocol = "HTTP" # Should be HTTPS + port = 80 +} +``` +S3 buckets without bucket policy denying non-HTTPS requests. +**Detection**: Checkov CKV_AWS_2 (ALB listener HTTPS), CKV_AWS_103 (TLS 1.2+ for ALB), CKV_AWS_91 (ALB access logging). + +### Privileged containers +**Controls violated**: A.8.18 (Use of privileged utility programs). +**Pattern**: +```yaml +spec: + containers: + - name: app + securityContext: + privileged: true + runAsUser: 0 + capabilities: + add: ["SYS_ADMIN"] +``` +**Detection**: Checkov CKV_K8S_16, CKV_K8S_20, CKV_K8S_22. + +### Missing resource limits +**Controls violated**: A.8.6 (Capacity management). +**Pattern**: Kubernetes containers without `resources.limits.cpu` and `resources.limits.memory`. +**Detection**: Checkov CKV_K8S_10, CKV_K8S_11, CKV_K8S_12, CKV_K8S_13. + +### Missing logging +**Controls violated**: A.8.15 (Logging). +**Pattern**: AWS resources without CloudTrail enabled, S3 buckets without access logging, VPCs without flow logs. +**Detection**: Checkov CKV_AWS_67 (CloudTrail multi-region), CKV_AWS_18 (S3 access logging), CKV_AWS_11 (VPC flow logs). + +### Unprotected branch +**Controls violated**: A.8.4 (Access to source code), A.8.32 (Change management). +**Pattern**: GitHub `main` / `master` branch without protection rules requiring PR review, status checks, and signed commits. +**Detection**: Steampipe query against GitHub API, or scan of `.github/settings.yml` if probot/settings is used. + +--- + +## Dependency-level violations + +### Known CVEs in production dependencies +**Controls violated**: A.8.8 (Management of technical vulnerabilities), A.8.30 (Outsourced development). +**Detection**: Trivy / Snyk / Dependabot scanning `package-lock.json`, `requirements.txt`, `go.sum`, `Cargo.lock`, `pom.xml`, `Gemfile.lock`, `composer.lock`. Threshold: any CVSS ≥ 7.0 with available patch is blocking. + +### Unpinned dependencies +**Controls violated**: A.8.8, A.8.32. +**Patterns**: +``` +# requirements.txt +requests +django>=3.0 +``` +```json +// package.json +"lodash": "^4.0.0" +``` +**Detection**: Manifest parsing for version specifiers using `>=`, `^`, `~`, or no version. Floating versions break reproducibility and audit trail. + +### Missing lockfile +**Controls violated**: A.8.32 (Change management). +**Pattern**: `package.json` without `package-lock.json`, `requirements.txt` without `requirements.lock` or `Pipfile.lock`. +**Detection**: Filesystem check. + +### Abandoned / unmaintained dependencies +**Controls violated**: A.8.8, A.8.30. +**Detection**: Cross-reference dependency list with deps.dev / libraries.io / OSV to detect packages with no commits in >24 months. + +### License risk +**Controls violated**: A.5.32 (Intellectual property rights). +**Detection**: License scanner (FOSSA, Black Duck, license-checker) flagging GPL-3.0, AGPL-3.0, SSPL where they conflict with the repository's own licensing strategy. + +### Typosquatting / dependency confusion +**Controls violated**: A.8.30, A.5.21 (ICT supply chain). +**Detection**: Known-bad-package lists, registry mirror verification, internal package namespace enforcement. + +--- + +## Pipeline-level violations + +### SAST not in pipeline +**Controls violated**: A.8.28, A.8.29. +**Detection**: Parse `.github/workflows/*.yml` and `.gitlab-ci.yml`. Verify a SAST step (Semgrep, CodeQL, SonarQube, Snyk Code) runs on every PR targeting protected branches. + +### SCA not in pipeline +**Controls violated**: A.8.8. +**Detection**: As above, for SCA steps (Trivy, Snyk, Dependabot, OWASP Dependency-Check). + +### IaC scanner not in pipeline +**Controls violated**: A.8.9, A.8.27. +**Detection**: As above, for IaC scanning (Checkov, tfsec, Terrascan). + +### Secret scanning not in pipeline +**Controls violated**: A.8.24, A.5.17. +**Detection**: As above, for secret scanning (gitleaks, truffleHog, GitHub native secret scanning). + +### No environment separation +**Controls violated**: A.8.31 (Separation of dev/test/prod). +**Pattern**: Single Terraform state file or single AWS account hosting both staging and production resources. +**Detection**: Workspace / state file inspection. Account ID checks across environment-specific variable files. + +### Auto-merge bypassing review +**Controls violated**: A.8.4, A.8.32. +**Pattern**: GitHub auto-merge enabled on PRs without required reviewers, or CODEOWNERS not enforced. +**Detection**: Repository settings via Steampipe or GitHub API. diff --git a/.claude/skills/oss-license-compliance/SKILL.md b/.claude/skills/oss-license-compliance/SKILL.md new file mode 100644 index 00000000..679a4379 --- /dev/null +++ b/.claude/skills/oss-license-compliance/SKILL.md @@ -0,0 +1,140 @@ +--- +name: oss-license-compliance +description: Open source license compliance reference for repo scanning, SBOM generation, copyleft contamination, and CI/CD enforcement. Covers SPDX License List (JSON ingestion, expressions, matching), REUSE, Apache 2.0 NOTICE, OSADL Compatibility Matrix, FSF GPL/LGPL logic, AGPL §13 network-use, SSPL §13 service source code, BSL 1.1 competitive offering, license-change events (MongoDB, Elastic, Redis, HashiCorp), wrapping ScanCode and ORT (.ort.yml, rules.kts), SCANOSS/FossID snippet detection, agentic reasoning for ambiguous triggers, and mappings to NIST 800-53, CIS v8.1, ISO 27001:2022 Annex A, SOC 2 TSC, OpenChain ISO 5230. Trigger on OSS license scanning, SBOM, copyleft risk, AGPL/SSPL/BSL detection, license compatibility, dependency audits, M&A OSS diligence, REUSE/SPDX headers, NOTICE validation, ScanCode/ORT orchestration, "can we ship this with proprietary code", "what does AGPL mean for SaaS", "scan deps for copyleft", or mention of SPDX identifiers or open source license risk. +--- + +# Open Source License Compliance + +This skill encodes the open source license compliance domain as it applies to source repositories, dependency trees, CI/CD pipelines, and the agentic auditing layer that sits on top of them. It is a compliance oracle for building or operating an automated OSS compliance scanner that runs at pull request time and on demand. + +This skill answers four categories of question: + +1. What does the license actually require, license by license, and which framework (SPDX, REUSE, OSADL, FSF) is the canonical source? +2. Which findings are deterministically verifiable from the repository alone, which require LLM reasoning over policy artifacts, and which are fundamentally out of repo? +3. How should a CI/CD scanner be architected, triggered, and scoped to honestly serve a license compliance program? +4. How do raw scan findings map into NIST 800-53, CIS v8.1, ISO 27001:2022, SOC 2 TSC, and OpenChain ISO/IEC 5230:2020 audit vernacular? + +Use this skill instead of training data whenever working on OSS license scanning, SBOM enrichment, copyleft contamination evaluation, license-change event tracking, or framework-control mapping. Upstream catalogs (SPDX list, OSADL matrix, vendor license terms) update frequently; the structured guidance below tells you where to fetch the live data, not what the live data currently is. + +## Authoritative sources + +The skill draws from four upstream truth sources. Always pin against a version, never trust a mirror. + +* **SPDX License List** — `spdx/license-list-XML` (governance, source XML) and `spdx/license-list-data` (machine-readable JSON, RDFa, HTML, plaintext distributions). Ingest `licenses.json` and `exceptions.json` from `license-list-data` releases (semantic versioning, `vX.Y` or `vX.Y.Z`). Pin to a specific release for auditability. +* **OSADL FOSS License Compatibility Matrix** — `matrix.json` (associative), `matrixseq.json` (indexed), `matrixseqexpl.json` (indexed with textual legal explanations). Ingest at scanner sync time, not at scan time. +* **FSF compatibility logic** — encoded in this skill (see `references/compatibility-and-copyleft.md`). Cross-reference against the FSF's published compatibility tables for GPL-family transitions. +* **REUSE Specification** — FSFE-maintained. The `reuse` linter is the canonical conformance tool; do not roll your own. + +## When to consult which reference + +Read the relevant reference file when the task touches that domain. Do not preload all of them. + +| Task | Reference | +|------|-----------| +| SPDX identifiers, matching guidelines, license expressions, REUSE conformance, NOTICE file structure, attribution preservation | `references/spdx-and-detection.md` | +| License compatibility checks, copyleft contamination logic, AGPL Section 13, SSPL Section 13, BSL 1.1 competitive-offering evaluation, license-change events (MongoDB, Elastic, Redis, HashiCorp) | `references/compatibility-and-copyleft.md` | +| Wrapping ScanCode Toolkit, OSS Review Toolkit (ORT) `.ort.yml` and `rules.kts`, SCANOSS / FossID snippet detection, false-positive triage, honest limits of automation | `references/scanners-and-tooling.md` | +| Real-world violation patterns, hidden Gist licenses, transitive copyleft, Stack Overflow CC-SA viral effect, legal precedents (Orange/Entr'ouvert, Copilot class action) | `references/violation-patterns.md` | +| Mapping findings to NIST 800-53 Rev. 5, CIS v8.1, ISO/IEC 27001:2022 Annex A, SOC 2 TSC, OpenChain ISO/IEC 5230:2020 | `references/cross-framework-mapping.md` | +| Agentic prompts for ambiguous evaluations (BSL competitive-offering, AGPL network-use, dual-licensed choice resolution) | `references/agentic-prompts.md` | + +## Verification taxonomy + +Every license compliance check falls into one of three buckets. Be honest about which. + +### 1. Deterministic from repository contents + +Pure script logic. No reasoning required. + +* Presence and exact path of `LICENSE`, `NOTICE`, `LICENSES/` directory, `.reuse/dep5`. +* SPDX identifier headers in source files (REUSE conformance via the `reuse` linter). +* Manifest parsing (`pom.xml`, `build.gradle`, `package.json`, `package-lock.json`, `go.mod`, `Cargo.toml`, `requirements.txt`, `Pipfile.lock`) cross-referenced against the local `licenses.json` snapshot. +* Version-to-license mapping for components that have changed license over time (e.g., MongoDB ≥ 4.0.3 → SSPL, Elasticsearch 7.11–7.16 → SSPL/Elastic, Redis ≥ 7.4 → RSALv2/SSPL, Terraform > 1.5.5 → BSL 1.1). +* OSADL matrix lookup for declared license pairs. +* `isOsiApproved` / `isFsfLibre` boolean gates from the SPDX JSON. +* SBOM generation in SPDX or CycloneDX format. +* Compiled rule evaluation via ORT `rules.kts`. + +If a check can be expressed as "does file X contain string Y" or "does pair (A, B) appear in the matrix", it belongs here. Use ScanCode + ORT + the `reuse` linter and stop reasoning. + +### 2. Agentic reasoning over policy artifacts + +Required when the legal trigger depends on facts about the host application that no manifest exposes. + +* **AGPL Section 13** — does the host expose modified AGPL code "remotely through a computer network"? Reading `Dockerfile`, `docker-compose.yml`, `kubernetes/`, deployment manifests, and `README.md` to determine whether the application is internal-only, air-gapped, or user-facing. +* **SSPL Section 13** — does the host offer the SSPL component "as a service to third parties"? The Service Source Code definition is sweeping (management, UI, APIs, automation, monitoring, backup, storage, hosting). Requires reading architecture docs. +* **BSL 1.1 competitive offering** — does the host constitute a product that "competes with HashiCorp's commercial offerings"? Pure business-logic question. +* **Dual-license selection** — when a dependency offers a choice (e.g., MPL-2.0 OR Apache-2.0), the project's outbound license and intended distribution must be reconciled with the choice. Encode the choice in `.ort.yml` once resolved so it does not require reasoning on every scan. +* **REUSE-style license choice** for files whose origin or intent is genuinely ambiguous. + +The agent's reasoning must be logged to a tamper-evident audit trail (commit-pinned input, prompt, model, output). The decision becomes the verifiable artifact. + +See `references/agentic-prompts.md` for prompt templates that produce structured JSON output suitable for ORT consumption. + +### 3. Fundamentally out of repository + +No script, no agent, no commit-bound artifact can resolve these. Generate evidence pointers (URLs, ticket references, document hashes) that link to external systems. + +* **Commercial supplier indemnification** — vendor contracts representing OSS-clean deliverables and indemnifying OSS-related IP claims. +* **M&A and cyber insurance OSS warranties** — the SBOM and triaged conflict log are the input; the warranty document is the artifact. +* **Shadow SaaS / SaaS-to-SaaS OAuth** — IdP logs, SaaS Management Platform (Zylo, BetterCloud) data; not in the repo. +* **End-user-facing attribution UIs** — the LICENSE file is in the repo, but whether the deployed product surfaces it to users (Apache 2.0 §4(d), MIT attribution preservation) requires UI inspection. + +Document the pointer, not the content. The compliance program is evidenced by the chain of pointers, not by duplicating external systems into the repo. + +## Trigger and suppression signals + +The scanner must run on the right diffs and stay quiet on the rest. + +### Trigger on any of: + +* Manifest changes — `pom.xml`, `build.gradle`, `package.json`, `package-lock.json`, `go.mod`, `go.sum`, `Cargo.toml`, `Cargo.lock`, `requirements.txt`, `Pipfile.lock`, `pyproject.toml`, `composer.json`, `Gemfile.lock`. +* Policy changes — `.ort.yml`, `.reuse/dep5`, `LICENSES/*`, `rules.kts`, `.whitesource`, scanner configuration. Forces a full repository re-baseline. +* Large uncommented code blocks introduced without a corresponding manifest change. Signals copy-paste; trigger snippet scanning. +* Dependency lockfile bumps even with no manifest change (transitive shifts). +* New `LICENSE`, `NOTICE`, or top-level legal file changes. + +### Suppress / downgrade severity for: + +* `/test`, `/tests`, `/__tests__`, `/spec`, `/mocks` — typically not distributed; copyleft distribution triggers do not apply. AGPL and SSPL network-use triggers may still apply if the test harness itself becomes a service. +* `.github/workflows/`, `.gitlab-ci.yml`, internal build tooling — not distributed to end users. +* Generated code directories explicitly listed in `.ort.yml` `excludes` (with a reasoned justification). +* Vendored documentation and example assets clearly marked as illustrative. + +Suppression is configuration, not silence. Encode every suppression in `.ort.yml` with a path glob and a reason, so the audit trail explains why the scanner ignored it. + +## Architecture pattern + +The recommended architecture is a three-layer pipeline: + +1. **Sync layer (scheduled, cached)** — Fetch SPDX `licenses.json`, OSADL matrix JSON, and any vendor advisory feeds. Pin versions in `.compliance/sources.lock`. +2. **PR-time scanner (deterministic)** — ScanCode (via Docker) for source-level detection; ORT analyzer + scanner + evaluator for dependency-tree evaluation; the `reuse` linter for header conformance; SCANOSS for snippet detection if license budget allows. Output structured JSON, fail the build on hard violations, post a PR comment summarizing soft findings. +3. **On-demand agentic auditor** — Invoked manually or on flagged dependencies. Reads the committed scan output plus repository policy artifacts (`README.md`, `architecture.md`, deployment manifests). Produces structured JSON with reasoning chain. Persists to an audit log keyed by commit SHA + prompt hash. + +This separation is important: the deterministic layer must be fast and binary, the agentic layer must be slow and reasoned. Mixing them produces a scanner that is both flaky and slow. + +## Output artifacts + +Every scanner run produces, at minimum: + +* **SBOM** in SPDX 2.3 or CycloneDX 1.5 (preferably both). The SBOM is the lingua franca for downstream consumers (M&A diligence, cyber insurance, OpenChain conformance). +* **Violations report** in JSON with a stable schema (eval ID, severity, license identifier, package coordinate, path, rule that fired, suppression status, evidence pointer). +* **Attribution bundle** — concatenated `LICENSE` and `NOTICE` content for every distributed dependency, suitable for shipping in product about-screens or `THIRD_PARTY_NOTICES.md`. +* **Audit trail entry** for every agentic decision, with commit SHA, scanned input hash, prompt, model identifier, and structured output. + +The SBOM and the audit trail together are the evidence packet. Everything else is derived. + +## Honest limits + +State these limits explicitly to consumers of the skill, in PR comments and in audit-package documentation. + +* **Dynamic linking and obfuscation** — SCA cannot see what is dynamically linked into a binary at runtime, nor can it identify obfuscated Java (ProGuard, R8) or stripped native binaries. +* **Reachability ≠ obligation** — A copyleft dependency reached only on a dead code path is still distributed and still triggers obligations. Do not let runtime SCA reachability filters quietly suppress legal risk. +* **Snippet false positives** — Boilerplate, autogenerated stubs, and standard algorithms produce constant noise. Confidence thresholds and persisted triage decisions in `.ort.yml` are the only way to keep alert fatigue manageable. +* **License-change events** — A dependency licensed permissively today may relicense tomorrow (Redis 2024, HashiCorp 2023, Elastic 2021/2024). Continuous monitoring of upstream license metadata is required; a one-time scan ages out fast. +* **Stack Overflow CC-SA** — Up to 33% of identified license conflicts in enterprise audits trace to Stack Overflow snippet pasting. Snippet scanning is the only line of defense. +* **The agent is non-deterministic** — Two runs of the same agentic prompt against the same input may differ. Pin model versions, log prompts, and treat the audit log as the artifact rather than the model output itself. + +## Skill scope boundaries + +This skill is a compliance oracle. It does not replace external legal counsel. When a finding has commercial consequences (M&A, large-scale copyleft contamination, willful violation exposure), the artifact this skill produces is the evidence packet for counsel; the legal judgment is theirs. diff --git a/.claude/skills/oss-license-compliance/references/agentic-prompts.md b/.claude/skills/oss-license-compliance/references/agentic-prompts.md new file mode 100644 index 00000000..ab125a8e --- /dev/null +++ b/.claude/skills/oss-license-compliance/references/agentic-prompts.md @@ -0,0 +1,200 @@ +# Agentic Prompts for Ambiguous License Evaluation + +The deterministic scanner identifies the presence of a high-risk license. It cannot determine whether the legal trigger of that license actually fires, because the trigger depends on facts about the host application that no manifest exposes. This reference provides prompt templates for the agentic auditor that resolves these cases. + +## Operating principles + +1. **The agent does not replace the scanner.** The scanner produces the deterministic finding ("MongoDB 6.0 is SSPL"); the agent answers the qualitative question ("does our deployment trigger §13"). +2. **Output is structured.** Every prompt requires a JSON response so downstream tooling (ORT, the violations report, the audit log) can consume it. +3. **Reasoning is logged.** The prompt, model identifier, input file hashes, and full output are persisted to a tamper-evident audit trail keyed by commit SHA. The agent's reasoning becomes the verifiable artifact, not the model output alone. +4. **Conservatism is the default.** When evidence is ambiguous, the agent returns `is_compliant: false` with `confidence: low` and a request for human review. Optimistic defaults compound legal risk silently. +5. **Scope is bounded.** The agent reads only the files explicitly provided in the prompt. It does not browse the web, query external APIs, or infer facts not present in the inputs. + +## Prompt template: AGPL §13 network-use evaluation + +**When to invoke**: scanner has identified a direct or transitive AGPLv3 dependency in a repository that may deploy a network-facing service. + +**Inputs to provide**: +* The dependency tree path showing how the AGPL component arrived. +* The repository's `Dockerfile`, `docker-compose.yml`, `kubernetes/` manifests, ingress configuration, deployment manifests. +* The repository's `README.md` and any `architecture.md` / `ARCHITECTURE.md`. +* The license text of the AGPL component. + +**Prompt**: + +> You are evaluating whether the AGPLv3 §13 ("Remote Network Interaction") trigger applies to a specific deployment of an AGPL-licensed component within the host repository whose files are attached. +> +> AGPLv3 §13 states that if the program is modified and the modified version is "interacted with remotely through a computer network", the operator must offer all interacting users the opportunity to receive the corresponding source code of the modified version. +> +> Evaluate three factual questions, in order: +> +> 1. **Modification**: Is the AGPL component modified by the host repository? Inspect any patches, monkey-patches, forks, configuration that overrides component behavior, or build steps that alter the component's source. Report yes / no / uncertain with evidence (file paths and excerpts). +> 2. **Network interaction**: Does the deployed application allow users to interact with the AGPL component remotely through a computer network? Inspect ingress configuration, exposed ports, public DNS records, deployment topology. Internal-only deployments behind a corporate VPN with no external user access do **not** trigger §13. SaaS deployments with external users **do** trigger §13. Air-gapped batch jobs **do not** trigger §13. Report yes / no / uncertain with evidence. +> 3. **User interaction with modified version**: Does the user's network interaction reach the modified portion of the AGPL component, or only unmodified portions? This is a narrower question than §13's literal text and conservative analysis treats any reachable modified code as triggering. Report yes / no / uncertain with evidence. +> +> Output a JSON object exactly matching this schema: +> +> ```json +> { +> "modification": {"answer": "yes|no|uncertain", "evidence": "..."}, +> "network_interaction": {"answer": "yes|no|uncertain", "evidence": "..."}, +> "modified_code_reachable": {"answer": "yes|no|uncertain", "evidence": "..."}, +> "section_13_triggers": true|false, +> "confidence": "high|medium|low", +> "recommended_action": "...", +> "human_review_required": true|false +> } +> ``` +> +> If any of the three sub-questions is `uncertain`, set `human_review_required` to `true` and `confidence` to `low`. The cost of false negatives in this domain (failing to detect a triggered §13) far exceeds the cost of false positives (escalating an untriggered case). Bias accordingly. + +## Prompt template: SSPL §13 service-source-code evaluation + +**When to invoke**: scanner has identified an SSPL-licensed component (MongoDB ≥ 4.0.3, Elasticsearch 7.11–7.16 / 7.16+ partial, Redis ≥ 7.4 dual SSPL, etc.) in a repository that may offer the component's functionality as a service. + +**Inputs to provide**: same as AGPL template, plus the Service Source Code definition language from SSPL §13. + +**Prompt**: + +> You are evaluating whether the SSPL v1.0 §13 ("Offering the Program as a Service") trigger applies to a specific deployment of an SSPL-licensed component within the host repository whose files are attached. +> +> SSPL §13 states that if the functionality of the SSPL-licensed program is "made available to third parties as a service", the operator must release the **Service Source Code** under SSPL. The SSPL definition of Service Source Code is sweeping and includes the program plus management software, user interfaces, application program interfaces, automation software, monitoring software, backup software, storage software, and hosting software used to make the service available. +> +> Evaluate three factual questions, in order: +> +> 1. **Service offering to third parties**: Does the host repository deploy the SSPL component such that third parties (customers, partners, end users) can use the component's functionality? "Third parties" excludes employees of the operator and contractors working on the operator's behalf. Report yes / no / uncertain with evidence. +> 2. **Functionality offered**: What functionality of the SSPL component is exposed? Inspect API endpoints, exposed ports, application logic. Internal use of the component for the operator's own data processing, where the third-party-facing service does not surface the component's functionality, may not trigger §13. Direct exposure (e.g., offering a managed Redis API) does trigger §13. Report functionality details with evidence. +> 3. **Service Source Code scope**: If §13 triggers, identify which surrounding components fall within the Service Source Code definition (management, UI, APIs, automation, monitoring, backup, storage, hosting). This is the scope of source-disclosure obligation if compliance is the chosen path. Report the list with evidence. +> +> Output a JSON object exactly matching this schema: +> +> ```json +> { +> "service_to_third_parties": {"answer": "yes|no|uncertain", "evidence": "..."}, +> "functionality_exposed": {"answer": "...", "evidence": "..."}, +> "service_source_code_scope": ["..."], +> "section_13_triggers": true|false, +> "confidence": "high|medium|low", +> "recommended_action": "...", +> "human_review_required": true|false +> } +> ``` +> +> SSPL §13 is broader and harder to comply with than AGPL §13. Where AGPL compliance generally requires only releasing the modified component's source, SSPL compliance can require releasing substantial proprietary infrastructure code. The recommended action in nearly all SaaS contexts is to remove the SSPL component or migrate to a permissively-licensed fork (Valkey for Redis, OpenSearch for Elasticsearch). + +## Prompt template: BSL 1.1 competitive-offering evaluation + +**When to invoke**: scanner has identified an HashiCorp BSL 1.1 component (Terraform > 1.5.5, Vault, Consul, Boundary, Waypoint, Nomad post-license-change) in the dependency tree. + +**Inputs to provide**: +* Dependency tree path. +* The repository's `README.md`, `architecture.md`, product description / pitch deck if available. +* HashiCorp's current commercial-product list (provided as a static input, refreshed periodically). +* The BSL 1.1 license text. + +**Prompt**: + +> You are evaluating whether the host repository constitutes a "Competitive Offering" under HashiCorp's BSL 1.1 license, which would prohibit use of the BSL-licensed component in the host's commercial offering. +> +> BSL 1.1 defines a Competitive Offering as a product or service that is sold to third parties and: +> 1. Provides similar functionality to HashiCorp's commercial offerings, **or** +> 2. Embeds the BSL-licensed work such that the offering requires the BSL-licensed work to operate. +> +> Evaluate four factual questions, in order: +> +> 1. **Sold to third parties**: Is the host repository's product or service sold to third parties? Internal tools used only within the operating organization are not Competitive Offerings. Report yes / no / uncertain with evidence. +> 2. **Functional overlap with HashiCorp commercial offerings**: List HashiCorp's current commercial products (Terraform Cloud, HCP Vault, HCP Consul, etc., as supplied in the prompt input). Compare the host repository's functionality against each. Identify any meaningful overlap. Report findings with evidence. +> 3. **Embedded vs internal use**: Does the host repository embed the BSL-licensed component such that the host's offering requires the component to operate? "Embedded" means the host's customers receive or interact with the BSL component as part of the offering. "Internal use" means the host operator uses the BSL component to build or operate the offering, but customers do not interact with it. Report with evidence. +> 4. **Migration to fork available**: Is there a viable permissively-licensed fork (OpenTofu for Terraform, OpenBao for Vault) that the host could migrate to? Report with evidence. +> +> Output a JSON object exactly matching this schema: +> +> ```json +> { +> "sold_to_third_parties": {"answer": "yes|no|uncertain", "evidence": "..."}, +> "functional_overlap": [{"hashicorp_product": "...", "overlap_description": "...", "evidence": "..."}], +> "embedded_use": {"answer": "yes|no|uncertain", "evidence": "..."}, +> "fork_available": {"answer": "...", "evidence": "..."}, +> "is_competitive_offering": true|false, +> "confidence": "high|medium|low", +> "recommended_action": "...", +> "human_review_required": true|false +> } +> ``` +> +> Competitive Offering is a contested term; HashiCorp's enforcement posture is evolving. When the determination is non-obvious, set `human_review_required` to `true` and surface for legal review. Migration to a fork is the safest resolution for any host that is or might become a Competitive Offering. + +## Prompt template: dual-license selection + +**When to invoke**: scanner finds a dependency declared under an `OR` SPDX expression (e.g., `MIT OR Apache-2.0`, `MPL-2.0 OR Apache-2.0`, `GPL-2.0-or-later WITH Classpath-exception-2.0 OR EPL-2.0`), and `.ort.yml` does not yet contain a `license_choices` entry for it. + +**Inputs to provide**: +* The dependency identifier and version. +* The full SPDX expression. +* The host repository's outbound license declaration. +* The host repository's distribution model (proprietary SaaS, distributed binary, source-available, etc.). + +**Prompt**: + +> You are selecting the optimal license choice for a dual-licensed (or multi-licensed) dependency that the host repository consumes. The chosen license becomes the license under which the host repository is using the dependency. +> +> Evaluate the following: +> +> 1. **Outbound compatibility**: For each license option in the SPDX expression, evaluate whether it is compatible with the host repository's outbound license. Use the OSADL FOSS License Compatibility Matrix logic and FSF compatibility rules. +> 2. **Distribution-model fit**: For each compatible option, evaluate whether the license terms are appropriate for the host's distribution model. SaaS hosts should prefer options that do not have network-use triggers (avoid AGPL where it is one of the choices). Distributed-binary hosts should prefer options that minimize attribution and source-disclosure burden. +> 3. **Recommendation**: Select the single best license. Provide reasoning. +> +> Output: +> +> ```json +> { +> "compatibility_evaluation": [ +> {"license": "...", "compatible_with_outbound": true|false, "reason": "..."} +> ], +> "distribution_fit_evaluation": [ +> {"license": "...", "fit_score": "high|medium|low", "reason": "..."} +> ], +> "selected_license": "...", +> "reasoning": "...", +> "confidence": "high|medium|low" +> } +> ``` +> +> Once selected, the choice should be persisted in `.ort.yml` under `license_choices`, removing the need for re-evaluation on subsequent scans. + +## Audit-trail schema + +Every agentic invocation persists an audit-trail entry. Recommended schema: + +```json +{ + "decision_id": "uuid", + "timestamp": "ISO 8601", + "commit_sha": "...", + "trigger": "scanner-finding-id or manual", + "prompt_template": "agpl-section-13 | sspl-section-13 | bsl-competitive-offering | dual-license", + "input_file_hashes": {"path": "sha256", "...": "..."}, + "scanner_finding": { /* the deterministic finding that triggered the agent */ }, + "model_identifier": "claude-X.Y-YYYYMMDD", + "prompt": "the full prompt sent to the model", + "response": { /* the structured JSON response */ }, + "human_review": { + "required": true|false, + "reviewer": "...", + "decision": "...", + "decision_timestamp": "ISO 8601" + } +} +``` + +The audit trail must be append-only and content-addressed (commit SHA + prompt-template hash + input-file-hash composite key). Replay against the same inputs produces a new entry, not a mutation of the old one. This preserves the historical record even if the model or prompt template is updated. + +## When agentic review is overkill + +Not every license finding deserves an agentic pass. Skip the agent when: + +* The scanner finding is unambiguous (e.g., GPLv3 dependency in a clearly-internal CLI tool, AGPL dependency that has been allowlisted with documented exception). +* The repository has a standing `license_choices` curation covering the case. +* The deterministic policy in `rules.kts` produces a definitive verdict. + +Reserve the agent for cases where the legal trigger genuinely depends on facts about the host application that the scanner cannot read. Overuse of the agent introduces latency, cost, and audit-log noise without compliance gain. diff --git a/.claude/skills/oss-license-compliance/references/compatibility-and-copyleft.md b/.claude/skills/oss-license-compliance/references/compatibility-and-copyleft.md new file mode 100644 index 00000000..08d51bd9 --- /dev/null +++ b/.claude/skills/oss-license-compliance/references/compatibility-and-copyleft.md @@ -0,0 +1,190 @@ +# License Compatibility, Copyleft, and High-Risk Triggers + +This reference encodes the legal logic the scanner must apply when evaluating multi-license combinations and identifying high-risk licenses (AGPL, SSPL, BSL) that trigger consequences far beyond the standard copyleft model. + +## OSADL FOSS License Compatibility Matrix + +License compatibility is the framework that determines whether two licensed components can be combined and distributed together without contradiction. The Open Source Automation Development Lab (OSADL) maintains a machine-readable matrix that encodes pairwise compatibility for the major OSS licenses. + +### Endpoints + +Three JSON shapes from OSADL, choose by use case: + +| Endpoint | Shape | Use | +|----------|-------|-----| +| `matrix.json` | Associative array `{outbound: {inbound: result}}` | Direct programmatic lookup by license pair. | +| `matrixseq.json` | Indexed array | Streaming or table generation. | +| `matrixseqexpl.json` | Indexed array with textual legal explanations | Human-readable PR comments and audit reports. | + +Sync the matrix on a scheduled cadence (daily is sufficient) and pin the snapshot version in `.compliance/sources.lock`. Do not query OSADL on every PR scan. + +### Result encoding + +A pairwise lookup returns one of: + +* **Compatible** — combination is permitted. +* **Incompatible** — combination violates one or both licenses; the matrix gives the contradiction reason in `matrixseqexpl.json`. +* **Conditional** — combination is permitted only if specific conditions are met (e.g., dynamic linking, system library exception). Requires reading the explanation field. + +### Tooling + +`flict` (FOSS License Compatibility Tool, Python) consumes the OSADL matrix directly and exposes: + +* Compatibility verification across an entire dependency tree (input: SPDX SBOM). +* Candidate outbound license suggestion given a set of inbound licenses. +* Policy file evaluation — supply your organization's outbound license and a list of disallowed licenses; `flict` returns a verdict. + +Wrap `flict` as a CI step rather than reimplementing matrix lookup logic in scanner code. + +## FSF compatibility logic + +The Free Software Foundation publishes the canonical compatibility tables for the GPL family. The scanner must encode the following: + +### Permissive licenses + +MIT, BSD-2-Clause, BSD-3-Clause, ISC, Apache 2.0 (with the patent-clause caveat below) are broadly compatible. Code under permissive licenses can be incorporated into copyleft-licensed projects, proprietary projects, and other permissively-licensed projects. + +### GPL family + +| Combination | Compatible? | Notes | +|-------------|-------------|-------| +| GPLv2-only + GPLv3 | **No** | Patent termination and indemnification differ. | +| GPLv2-or-later + GPLv3 | Yes | The "-or-later" allows promotion to GPLv3. | +| GPLv2-only + Apache 2.0 | **No** | Same patent-clause incompatibility. | +| GPLv3 + Apache 2.0 | Yes | GPLv3 was drafted to absorb Apache 2.0's patent clause. | +| GPLv3 + LGPLv2.1 | Yes | LGPLv2.1 is upgradable to GPLv3 via its `or-later` provision (when present). | +| GPLv3 + LGPLv3 | Yes | Designed to interoperate. | +| AGPLv3 + GPLv3 | Yes | AGPLv3 §13 explicitly allows linking with GPLv3. | + +### LGPL nuance: linking model + +The Lesser GPL is the only mainstream copyleft that allows proprietary code to use the LGPL component without the proprietary code becoming LGPL-licensed. The mechanism depends on linking: + +* **Dynamic linking** (proprietary code calls LGPL library at runtime) — proprietary code remains proprietary; user must be able to relink against a modified LGPL library. +* **Static linking** (LGPL library compiled into proprietary binary) — proprietary code must allow the user to substitute a modified library, typically by shipping object files or statically linkable artifacts. + +The scanner cannot determine link model from manifests alone. Surface the LGPL finding with a flag for human review of the build configuration, or use agentic reasoning over the `Makefile` / `CMakeLists.txt` / `Cargo.toml` link configuration. + +### System library exception + +GPLv2 and GPLv3 both contain a "system library" exception: a GPL-incompatible library that qualifies as a standard system component (libc, OS-shipped runtime libraries) can be linked with a GPL program without forcing source disclosure of that library. The scanner must not flag system-library combinations as violations; the dependency analyzer should classify these via known system-library lists. + +## Copyleft contamination policy + +If the scanner detects a strong copyleft license (GPL, AGPL, EUPL, OSL, CDDL with linking restrictions) in any dependency — direct or transitive — within a repository flagged for proprietary commercial distribution, the pipeline should: + +1. Fail the build on the PR with a clear, specific error message naming the dependency, the license, and the contamination path. +2. Block the merge. +3. Generate a high-severity supply chain alert in the audit log. +4. Provide a remediation checklist: replace dependency, isolate as a separate process (microservice boundary), comply with the license, or seek a commercial alternative. + +The contamination path is essential. A developer who imported a permissive package needs to see that the GPL dependency arrived via three transitive hops, not just that "something is GPL". + +## AGPL Section 13: the network-use trigger + +AGPL closes the "ASP loophole" left by traditional GPL. Standard GPL distribution triggers fire only on physical / binary distribution; SaaS providers historically argued that providing functionality over the network was not distribution. AGPL §13 contradicts this directly. + +> "...if you modify the Program, your modified version must prominently offer all users interacting with it remotely through a computer network... an opportunity to receive the Corresponding Source of your version..." + +Consequences if triggered: + +* The full corresponding source of the modified AGPL component must be made available to every user who interacts with the running service over a network. +* "Corresponding source" includes scripts to control installation and modifications, per GPLv3 definition incorporated by reference. +* Internal proprietary backend code that has been combined with the AGPL component is potentially within the scope of "Corresponding Source" — this is the contamination risk. + +### Detection + +* Static: any AGPL-licensed dependency in a repository deploying a network-facing service. Trigger an immediate critical finding. +* Agentic (see `agentic-prompts.md`): determine whether the deployment topology actually exposes the AGPL component over a network. Air-gapped, internal-only, or batch-processing deployments may not trigger §13. The agent reads `Dockerfile`, deployment manifests, ingress configuration, and architecture documentation to make the call. + +### Resolution paths + +* Replace the AGPL dependency with a permissively-licensed equivalent. +* Comply: publish the corresponding source. +* Air-gap: isolate the AGPL component in a process / service that has no network exposure to external users (often impractical). +* Negotiate a commercial dual-license with the upstream rightsholder (where offered). + +## SSPL Section 13: service source code + +The Server Side Public License v1.0 (MongoDB, October 2018) is AGPL-Section-13-on-steroids. SSPL §13 mandates that if the program's functionality is "made available to third parties as a service", the deployer must release the **Service Source Code**. + +### Service Source Code definition + +The SSPL definition is sweeping. It includes not only the licensed program but also: + +* Management software +* User interfaces +* Application program interfaces (APIs) +* Automation software +* Monitoring software +* Backup software +* Storage software +* Hosting software + +In practice this can pull the entire orchestration and operations stack of a SaaS deployment into scope. + +### OSI status + +The OSI did not approve SSPL as an open source license. Debian and Red Hat declined to package SSPL-licensed software as free software. Treat SSPL as **source-available**, not open source, in all internal documentation. + +### Scanner behavior + +* Flag SSPL components as highly restricted. +* Block introduction into any SaaS-facing build pipeline pending legal review. +* Do not auto-suggest SSPL replacements without confirming the consumer's distribution model. + +## Business Source License (BSL) 1.1 + +The Business Source License is a source-available license designed to permit broad use while reserving "competitive offering" exclusions for the licensor. HashiCorp adopted BSL 1.1 in August 2023 (Terraform > 1.5.5, Vault, Consul, etc.). + +### Mechanics + +* Source is publicly readable and auditable. +* Use in production is permitted **except** as a "Competitive Offering". +* After a "Change Date" (typically four years), the work converts to a designated "Change License" (typically MPL 2.0 or Apache 2.0) and the BSL restrictions lift. + +### Competitive Offering definition + +A product or service sold to third parties that: + +1. Provides similar functionality to the licensor's commercial offerings, **or** +2. Embeds the BSL-licensed work such that the offering requires it to operate. + +### Why this is a hard call + +Determining "competitive offering" requires evaluating: + +* What the licensor sells commercially today. +* Whether the host application's functionality overlaps. +* Whether the BSL component is embedded vs. used as an internal tool. +* Whether the host application is sold to third parties at all. + +This is not deterministic. The scanner detects the BSL component (deterministic); an agent evaluates the competitive-offering question (see `agentic-prompts.md` for the prompt template). + +### Forks + +Significant license-change events have spawned forks designed to preserve permissive licensing: + +* **OpenTofu** — fork of Terraform, MPL 2.0, hosted under the Linux Foundation. +* **OpenBao** — fork of Vault, MPL 2.0. + +Where a fork is viable and feature-complete, the cleanest resolution to a BSL finding is migration to the fork. + +## License-change event registry + +The scanner must encode the following historical license-change events. A dependency upgrade across one of these boundaries is automatically a high-severity finding. + +| Project | Original | New | Change Date | Driver | +|---------|----------|-----|-------------|--------| +| MongoDB | AGPL | SSPL 1.0 | October 2018 | Block managed-service competitors. | +| Elasticsearch / Kibana | Apache 2.0 | Dual SSPL / Elastic License 2.0 | January 2021 | Block AWS Elasticsearch Service. | +| Elastic | SSPL/ELv2 | Added AGPLv3 (triple license) | August 2024 | Partial reversal; community pressure. | +| HashiCorp (Terraform, Vault, Consul, etc.) | MPL 2.0 | BSL 1.1 | August 2023 | Block competitive offerings; spawned OpenTofu, OpenBao. | +| Redis | BSD 3-Clause | Dual RSALv2 / SSPL 1.0 | March 2024 | Block managed Redis competitors; spawned Valkey (Linux Foundation). | +| Redis | RSALv2/SSPL | Added AGPLv3 | May 2025 | Partial reversal; ongoing fork dynamics. | + +This registry ages. Always cross-check against the project's current license file at the version the scanner observes. A version-specific lookup is mandatory: MongoDB 3.6 is AGPL; MongoDB 4.0.3+ is SSPL. Treating MongoDB as a single license-bearing entity is wrong. + +## Stack Overflow and CC-SA viral effect + +Public Stack Overflow contributions are licensed CC BY-SA. Code copied from Stack Overflow into a proprietary codebase carries the share-alike obligation, which acts as a copyleft contamination vector. Up to a third of identified license conflicts in enterprise audits originate from Stack Overflow snippets. Snippet-level scanning (see `scanners-and-tooling.md`) is the only practical defense; relying on developer self-reporting is insufficient. diff --git a/.claude/skills/oss-license-compliance/references/cross-framework-mapping.md b/.claude/skills/oss-license-compliance/references/cross-framework-mapping.md new file mode 100644 index 00000000..57e71245 --- /dev/null +++ b/.claude/skills/oss-license-compliance/references/cross-framework-mapping.md @@ -0,0 +1,102 @@ +# Cross-Framework Mapping + +OSS license compliance findings are inputs to multiple security and compliance frameworks. The scanner output (SBOM, violations report, audit trail) must speak the vernacular of each framework's auditors. This reference enumerates the mappings. + +## NIST 800-53 Rev. 5 + +National Institute of Standards and Technology Special Publication 800-53 Revision 5 — security and privacy controls for federal information systems and supporting commercial infrastructure (FedRAMP, CMMC). + +| Control | Name | OSS compliance mapping | Evidence artifact | +|---------|------|------------------------|-------------------| +| **CM-8** | System Component Inventory | The SBOM is the inventory of OSS components. Every build emits a versioned SPDX or CycloneDX SBOM, archived. | `sbom.spdx.json`, `sbom.cdx.json`, retained per release. | +| **CM-8(2)** | Automated Maintenance | The CI/CD-integrated scanner regenerates the SBOM on every merge to main, eliminating drift between deployed components and declared inventory. | CI pipeline logs showing SBOM generation step succeeded for every merged PR. | +| **CM-8(3)** | Automated Unauthorized Component Detection | The deny-list policy in `rules.kts` blocks unauthorized licenses (typically AGPL, SSPL in proprietary contexts). | Policy file + CI pipeline failure logs for blocked PRs. | +| **SA-8** | Security Engineering Principles | The compliance program is itself an engineering principle: deterministic checks at PR time, agentic review of ambiguous cases, audit trail for non-deterministic decisions. | Compliance program documentation. | +| **SA-15** | Development Process, Standards, and Tools | The CI/CD scanner enforces approved licenses and toolchain configuration as a deterministic gate. | Pipeline configuration showing the scanner is mandatory and not bypassable. | +| **SA-15(8)** | Reuse of Threat / Vulnerability Information | Scanner integrates with vulnerability advisories (Dependabot, OSV, GitHub Advisory) so license findings and CVE findings share the same dependency-tree resolver. | Combined SCA + license report. | +| **SI-12** | Information Management and Retention | License audit trails, NOTICE attribution files, and agentic decision logs are retained per organizational retention policy. | Retention policy documenting compliance artifact lifecycle. | +| **SI-12(1)** | Limit Personally Identifiable Information Elements | When telemetry is sent to external SCA or LLM services, scrub PII and proprietary logic. Document what leaves the boundary. | Data-flow diagram for scanner telemetry. | +| **SR-3** | Supply Chain Controls and Processes | The scanner is the implementation of supply chain controls for OSS components. | Supply chain risk management plan referencing the scanner. | +| **SR-4** | Provenance | SBOM with package coordinates, version pins, and source URLs documents OSS provenance. | SBOM. | +| **SR-11** | Component Authenticity | Verify package integrity (checksums, signatures) at scanner ingestion. | Lockfile + checksum verification step in CI. | + +## CIS Critical Security Controls v8.1 + +Center for Internet Security Critical Security Controls v8.1 — prioritized, actionable safeguards. + +| Safeguard | Name | OSS compliance mapping | Evidence artifact | +|-----------|------|------------------------|-------------------| +| **2.1** | Establish and Maintain a Software Inventory | SBOM covers every OSS component, including transitive dependencies and snippet-detected fragments. | SBOM, periodic snippet-scan results. | +| **2.2** | Ensure Authorized Software is Currently Supported | Scanner flags OSS components that are deprecated, unmaintained, or running unsupported versions. | SCA report with end-of-life flags. | +| **2.3** | Address Unauthorized Software | Deny-list licenses in `rules.kts`; block PRs that introduce them. | Pipeline failure log + denied license catalog. | +| **2.5** | Allowlist Authorized Software | Curated `licenseClassifications.yml` defining acceptable licenses per distribution model. | License-classification configuration. | +| **2.6** | Allowlist Authorized Libraries | The combined ORT analyzer + curation file allowlists specific package coordinates per repository. | `.ort.yml` curations + per-repo policy. | +| **3.1** | Establish and Maintain a Data Management Process | Audit-trail retention covers OSS compliance artifacts. | Retention policy. | +| **16.4** | Establish and Manage an Inventory of Third-Party Software Components | Same as CM-8 / 2.1: the SBOM. | SBOM. | +| **16.5** | Use Up-to-Date and Trusted Third-Party Software Components | Scanner integrates with vulnerability feeds; license-and-CVE findings share dependency resolution. | Combined report. | + +## ISO/IEC 27001:2022 Annex A + +The 2022 revision of ISO/IEC 27001 restructured Annex A around four control themes: Organizational (5), People (6), Physical (7), Technological (8). The relevant controls for OSS license compliance: + +| Control | Name | OSS compliance mapping | Evidence artifact | +|---------|------|------------------------|-------------------| +| **5.19** | Information Security in Supplier Relationships | OSS upstreams are suppliers; the policy treats them as such. | Supplier policy referencing OSS upstreams; SBOM. | +| **5.20** | Addressing Information Security Within Supplier Agreements | Outsourced development contracts require flow-down of OSS scanning to subcontracted code. | Contract template + flow-down clause. | +| **5.21** | Managing Information Security in the ICT Supply Chain | SBOM, scanner audit trail, license-change event monitoring. | SBOM + monitoring procedure. | +| **5.22** | Monitoring, Review and Change Management of Supplier Services | Scanner reruns on dependency updates; license-change events trigger review. | Continuous monitoring procedure. | +| **5.31** | Legal, Statutory, Regulatory and Contractual Requirements | License obligations are contractual requirements; the program documents how they are met. | Statement of Applicability covering OSS license obligations. | +| **5.33** | Protection of Records | OSS audit-trail records (scan outputs, agentic decisions) are retained as evidence. | Retention procedure. | +| **8.4** | Access to Source Code | Where OSS license obligations require source disclosure (GPL, AGPL, MPL), the controls allow it without compromising proprietary boundaries. | Source-disclosure procedure. | +| **8.25** | Secure Development Lifecycle | The PR-time scanner is part of the SDLC. | SDLC documentation. | +| **8.28** | Secure Coding | Scanner blocks introduction of unapproved licenses and snippets. | Pipeline configuration. | +| **8.30** | Outsourced Development | Code from agencies and contractors must be scanned before acceptance. The scanner is the acceptance gate. | Acceptance procedure + scan logs from contractor deliverables. | +| **8.32** | Change Management | Every PR is scanned; the scan is part of the change-control evidence chain. | PR-scan logs. | + +## SOC 2 Trust Services Criteria + +AICPA TSP Section 100 (2017, revised 2022). Relevant Common Criteria for OSS license compliance: + +| Criterion | Name | OSS compliance mapping | Evidence artifact | +|-----------|------|------------------------|-------------------| +| **CC2.1** | Information Quality | The SBOM is high-quality information about software composition. | SBOM with version pins and source provenance. | +| **CC3.2** | Risk Assessment | License risk (copyleft contamination, license-change events) is part of the risk assessment. | Risk register entries for OSS license risk. | +| **CC3.4** | Risk Management Process Updates | The scanner is updated for license-change events (Redis 2024, Elastic 2024, etc.). | Change log of `licenses.json` snapshot updates. | +| **CC4.1** | Continuous Monitoring | Scanner runs on every PR + on a nightly cadence + on release. | CI pipeline configuration + scheduled-job logs. | +| **CC7.1** | Change Identification | Lockfile changes trigger scans; license-change events are detected. | Trigger configuration + alert log. | +| **CC8.1** | Change Management | Every PR is reviewed against deterministic and (where applicable) agentic license policy before merge. | PR scan results stored per merge commit. | +| **CC9.1** | Risk Mitigation Plans | Detection of high-risk licenses (SSPL, AGPL in SaaS contexts) triggers documented mitigation. | Mitigation playbook. | +| **CC9.2** | Vendor and Business Partner Management | OSS upstreams are managed as the third-party-risk-managed entities they are. License changes are vendor change events. | Vendor-management register including OSS upstreams. | + +## OpenChain ISO/IEC 5230:2020 + +ISO/IEC 5230 is the international standard for OSS license compliance program quality. The standard is short and program-focused; the scanner is the operational arm of conformance. + +Conformance requires: + +| Requirement | Mapping | +|-------------|---------| +| **3.1** Written program documentation | Compliance program document referencing this skill, the scanner, and the agentic auditor. | +| **3.2** Program scope | Defined: every repository in scope, every PR scanned, every release SBOM-published. | +| **3.3** Identified personnel and roles | Designated compliance owner, legal escalation path, scanner-tooling owner. | +| **3.4** Compliance training | Onboarding includes the scanner, `.ort.yml` curation, and high-risk license recognition. | +| **3.5** Bill of Materials | SBOM in SPDX or CycloneDX, generated per release, archived. | +| **3.6** Compliance artifact procedure | Documented: SBOM generation, NOTICE bundle assembly, attribution distribution. | +| **3.7** External open source request handling | Procedure for receiving and responding to source-disclosure requests (GPL, AGPL, MPL recipients). | +| **3.8** External community contribution policy | Outbound-contribution policy (this is adjacent to but distinct from inbound license compliance). | +| **3.9** Internal compliance program review | Periodic internal audit of program effectiveness. | + +OpenChain conformance is an attestation, not a certification, but it is the de facto contract-level standard for OSS compliance maturity. Major customers and acquirers increasingly request OpenChain conformance attestation in supplier qualification. + +## Cross-mapping at a glance + +For a single OSS compliance finding, the mapping into framework vernacular: + +* **Detected unapproved AGPL dependency in proprietary SaaS repository, blocked at PR time, audit trail retained.** + * NIST 800-53: CM-8(3) (automated unauthorized component detection), SA-15 (development process tools), SR-3 (supply chain controls). + * CIS v8.1: 2.3 (address unauthorized software), 2.6 (allowlist authorized libraries). + * ISO 27001:2022 Annex A: 5.21 (ICT supply chain), 8.28 (secure coding), 8.32 (change management). + * SOC 2 TSC: CC8.1 (change management), CC9.1 (risk mitigation), CC9.2 (vendor management). + * OpenChain ISO/IEC 5230: 3.5 (BOM), 3.6 (compliance artifact procedure). + +This is the kind of multi-framework crosswalk that a single PR-time scan can produce, given the right reporting layer. Build the reporter to emit the framework annotations alongside the raw violation, and a single scanner run feeds every audit downstream. diff --git a/.claude/skills/oss-license-compliance/references/scanners-and-tooling.md b/.claude/skills/oss-license-compliance/references/scanners-and-tooling.md new file mode 100644 index 00000000..6b943108 --- /dev/null +++ b/.claude/skills/oss-license-compliance/references/scanners-and-tooling.md @@ -0,0 +1,155 @@ +# Scanners and Tooling: ScanCode, ORT, SCANOSS, FossID + +Building a scanner from scratch is the wrong default. Mature OSS scanners have invested years in license matching corpora, regression test suites, and ecosystem-specific package manager integration. The skill author's job is orchestration, policy, and reporting — not reimplementing matching. + +## ScanCode Toolkit + +Reference implementation for license, copyright, and dependency metadata extraction. Maintained by AboutCode (Nexus B) under Apache 2.0. + +### Why it is the baseline + +* Full license-text diff matching, not approximate string matching. Detects licenses even when copyright placeholders, formatting, or whitespace differ. +* Tested with 30,000+ regression cases against the real-world distribution of license-text variants. +* Wide ecosystem coverage: Maven, npm, PyPI, Go modules, RubyGems, Cargo, Composer, NuGet, package-lock files, OS package metadata, archive contents. +* Outputs structured JSON suitable for downstream programmatic policy evaluation. + +### Container-based CI integration + +The official Docker image (`ghcr.io/aboutcode-org/scancode.io:latest`) is the most reliable invocation path; it pins the matcher version and avoids host Python environment drift. + +```bash +docker run --rm \ + -v "$(pwd)":/codedrop \ + ghcr.io/aboutcode-org/scancode.io:latest \ + run scan_codebase /codedrop \ + > scancode_results.json +``` + +Cache the Docker layer in CI (`actions/cache`, GitLab `cache:`, etc.) — the image is large and uncached pulls add minutes per run. + +### Output structure + +ScanCode JSON contains `files[]` with per-file `licenses[]`, `copyrights[]`, and `package_data[]`. The downstream scanner consumes this as input — it should not re-derive license findings from raw source. + +For SBOM generation, prefer `scancode-toolkit`'s `--spdx-tv` or `--spdx-rdf` outputs for SPDX, or chain through `cyclonedx-cli` for CycloneDX. + +## OSS Review Toolkit (ORT) + +ORT is the orchestration layer the skill should build on. It composes multiple scanners (ScanCode, Fossology, others) and adds policy evaluation, reporting, and SBOM generation. + +### Pipeline architecture + +ORT decomposes the workflow into discrete tools, each consuming the previous tool's JSON output: + +1. **Analyzer** — resolves dependency trees from package manifests. Ecosystem-aware (Maven, npm, Cargo, etc.). Produces an `analyzer-result.json`. +2. **Scanner** — fetches sources and runs configured per-package scanners (ScanCode, Fossology). Produces `scan-result.yml`. +3. **Advisor** (optional) — queries security advisory databases for known vulnerabilities. +4. **Evaluator** — applies user-defined policy rules in Kotlin script (`rules.kts`) against the combined analyzer + scanner data. +5. **Reporter** — produces SBOMs (SPDX, CycloneDX), notice files, HTML reports, and developer-friendly summaries. + +This decomposition lets the CI pipeline cache intermediate outputs, rerun only the policy layer when `rules.kts` changes, and ship the same reports to multiple downstream audiences. + +### `.ort.yml` repository configuration + +Per-repository configuration sits in `.ort.yml` at the repository root. Key sections: + +* **`excludes.paths`** — path globs to exclude from analysis (vendored examples, generated code). Each exclude has a `reason` field; never silently exclude. +* **`excludes.scopes`** — exclude scopes like `test`, `devDependencies`. Use carefully; license obligations may apply to artifacts produced from devDependency tooling. +* **`curations`** — corrections to upstream metadata (a known-bad declared license overridden with the actual license). +* **`license_choices`** — for dual-licensed dependencies, record the choice made (e.g., for `MIT OR Apache-2.0`, the project chose `Apache-2.0`). +* **`resolutions`** — triaged decisions on findings the scanner produced; mark a snippet match as "false positive, boilerplate" with reason. + +`.ort.yml` is the durable artifact of compliance triage. Treat it as code: review changes, require justification, never delete entries silently. + +### `rules.kts` policy + +ORT evaluates compliance via Kotlin script. Skill authors should ship a baseline `rules.kts` covering: + +* Banned licenses (deny list, e.g., AGPL in proprietary distribution context). +* Required license choices (every dual-licensed dep must have a `license_choices` entry). +* Required attribution (every Apache 2.0 dep must have a NOTICE entry). +* Allowed license combinations against outbound license. +* Severity grading: `ERROR` blocks merge, `WARNING` produces PR comment. + +Kotlin script is more powerful than YAML rules for this purpose — it can compose conditions, traverse the dependency graph, and emit structured violation objects. Resist the urge to reinvent it in a less expressive language. + +### CLI invocation + +```bash +ort analyze -i . -o ort/analyzer +ort scan -i ort/analyzer/analyzer-result.yml -o ort/scanner +ort evaluate \ + -i ort/scanner/scan-result.yml \ + --rules-file rules.kts \ + --license-classifications-file license-classifications.yml \ + --package-curations-file curations.yml \ + -o ort/evaluator +ort report \ + -i ort/evaluator/evaluation-result.yml \ + -f WebApp,SpdxDocument,CycloneDx,NoticeTemplate \ + -o ort/reporter +``` + +Pipeline steps cache cleanly: re-evaluating policy on a stable scan result is seconds; re-scanning is minutes. + +## Snippet detection: SCANOSS, FossID + +Manifest scanning misses copy-pasted code. Snippet detection compares source fingerprints against a corpus of known OSS files. + +### SCANOSS + +Open-source SCA engine with snippet matching. Fingerprint database covers hundreds of millions of files. + +* Detection threshold: configurable, typically 6-line minimum match window. +* Resilient to reformatting, variable renaming, comment changes; sensitive to logic alteration. +* Correlates fingerprints to licenses, copyright holders, and (for vulnerable code) specific CVEs. +* Persists triage decisions via ORT integration: `.ort.yml` `snippet_choices` entries record "snippet match X is boilerplate, ignore" with audit-trail reason. + +SCANOSS can be run as a self-hosted service or against the public API. Self-hosting eliminates source-code-leaving-premises concerns for proprietary repositories. + +### FossID + +Commercial SCA with snippet matching, broader corpus, and enterprise workflow integration. Use when: + +* Snippet-detection corpus needs to exceed SCANOSS coverage. +* Compliance program requires a vendor SLA on detection accuracy. +* Integration with enterprise GRC platforms is required. + +The skill remains the same; only the scanner selection changes. The orchestration / policy / reporting layers built on ORT can consume SCANOSS or FossID output equivalently if the integration layer normalizes findings. + +## False positives and alert fatigue + +Snippet scanners flag boilerplate, autogenerated stubs, and standard algorithms as matches. Without management, developer trust in the scanner collapses within weeks. + +### Mitigation patterns + +1. **Confidence thresholds** — most scanners expose a confidence score; require ≥ 80% match before raising a finding to a blocking severity. +2. **Persisted triage** — `.ort.yml` `snippet_choices` (or equivalent) records every triaged decision. The scanner respects the decision on subsequent runs. +3. **Boilerplate corpus** — maintain an internal allow list of known-boilerplate snippet hashes (autogenerated API stubs, common algorithm implementations, vendor SDKs). +4. **PR-comment severity tiering** — block on hard violations only; surface soft findings as informational PR comments without failing the build. +5. **Periodic full audits** — rerun the scanner with low thresholds quarterly, off the critical path. Triage findings into `.ort.yml` rather than at PR time. + +The goal is not zero alerts. The goal is that every alert that reaches a developer represents a decision worth making. + +## Honest limits of automated detection + +State these in PR comments and audit-package documentation: + +* **Dynamic linking** — runtime-linked libraries (system libraries, OS-provided runtimes) are invisible to source-level scanning. If the deployment payload includes an OS image, the OS layer must be scanned separately. +* **Obfuscation** — Java code processed by ProGuard or R8 strips function signatures, dead code, and class names. Snippet matching against obfuscated artifacts is unreliable. Scan pre-obfuscation source. +* **Reachability ≠ legal obligation** — runtime SCA tools can suppress findings on unreachable code paths. From a legal perspective, distribution of the code triggers obligations regardless of reachability. Do not allow a security-oriented reachability filter to suppress license findings. +* **Native binaries without symbols** — stripped C/C++/Rust binaries are largely opaque. Scan source, not stripped artifacts. +* **Licensed-by-reference** — a `README.md` "this is MIT" with no license text is detectable but not actionable; the scanner should flag for human resolution. +* **License changes mid-version-range** — a dependency that flipped licenses across versions requires lockfile-pinned version-aware scanning. Bare manifest scans can miss this. + +## When to run which scanner + +| Stage | Scanner | Cost | Catches | +|-------|---------|------|---------| +| Pre-commit / IDE | `reuse` linter | Negligible | Missing SPDX headers in new files. | +| PR-time fast | ORT analyzer + curated `rules.kts` | Seconds–low minutes | Manifest-level new dependencies, banned licenses. | +| PR-time deep | ORT analyzer + ScanCode scanner + evaluator | Minutes | License findings in actual fetched source, NOTICE compliance, attribution gaps. | +| Periodic / nightly | ORT + SCANOSS snippet | Tens of minutes | Copy-pasted snippets, transitive shifts. | +| Pre-release | Full ORT + SCANOSS + manual triage | Hours | Final SBOM, attribution bundle, audit packet. | + +Tier the scanner so PR-time stays fast; reserve expensive analysis for nightly and release gates. The PR-time scanner that takes 20 minutes will be turned off; the one that takes 90 seconds becomes infrastructure. diff --git a/.claude/skills/oss-license-compliance/references/spdx-and-detection.md b/.claude/skills/oss-license-compliance/references/spdx-and-detection.md new file mode 100644 index 00000000..87d3c73a --- /dev/null +++ b/.claude/skills/oss-license-compliance/references/spdx-and-detection.md @@ -0,0 +1,123 @@ +# SPDX, REUSE, NOTICE: Detection and Attribution Reference + +The deterministic detection layer of any OSS compliance scanner rests on the SPDX License List and adjacent attribution conventions. This reference defines the canonical inputs, the matching rules, and the structural checks that scripts must perform. + +## SPDX License List framework + +### Repository topology + +Two repositories under the SPDX organization, with distinct roles: + +* **`spdx/license-list-XML`** — the governance and authoring repository. Contains the source XML schema for every license and exception. Maintained by the SPDX Legal Team. Do **not** parse this directly from a scanner; the XML is structured for human curation, not machine evaluation. +* **`spdx/license-list-data`** — the downstream distribution repository. Compiled from `license-list-XML` into stable machine-readable formats: JSON, RDFa, HTML, plaintext. This is what the scanner ingests. + +Both repositories release under semantic versioning tags (`vX.Y` or `vX.Y.Z`). Pin to a specific release in `.compliance/sources.lock` so two runs of the scanner against the same commit always evaluate against the same license catalog. + +### JSON ingestion + +Pull two arrays from `license-list-data`: + +* `licenses.json` — every active and deprecated license entry. +* `exceptions.json` — every license exception (e.g., `Classpath-exception-2.0`, `LLVM-exception`, `Autoconf-exception-2.0`). + +Per-entry fields the scanner must consume: + +| Field | Purpose | +|-------|---------| +| `licenseId` | Standardized short identifier. ASCII, letters / digits / `.` / `-` only. The matching key. | +| `name` | Formal legal title, normalized (version abbreviations stripped from sort name). | +| `licenseText` / `standardLicenseTemplate` | Full prose; the diff target for full-text matching. | +| `seeAlso` | Canonical permanent URLs. | +| `isOsiApproved` | Boolean. OSI-approved → safe baseline for "open source" declarations. | +| `isFsfLibre` | Boolean. FSF-recognized free software license. | +| `isDeprecatedLicenseId` | Boolean. Deprecated identifiers still resolve but should be flagged for migration. | + +Boolean gates compose into deterministic policy: e.g., fail the PR if any newly introduced direct dependency has `isOsiApproved == false` and is not on an explicit allow list. + +## SPDX matching guidelines + +License texts in the wild differ from canonical text by typography, formatting, copyright placeholders, and trivial wording variants. The SPDX Matching Guidelines define what differences are tolerable. + +### Markup attributes + +The XML schema marks regions of license text with attributes that the matcher must respect: + +* **Omittable text** — visually styled blue in HTML; tagged via `altParagraphType` in the XML. Can be absent from a candidate without disqualifying the match. Common for optional preambles or address blocks. +* **Replaceable text** — visually styled red in HTML; represents fields like copyright holder name, year, project title. The matcher must capture these via wildcard / placeholder logic, not literal matching. + +### Equivalent words + +`equivalentwords.txt` in the SPDX repository catalogs spelling variants of legally significant terms (British vs American English: `licence`/`license`, `merchantability` variants, etc.). The matcher must treat listed variants as equivalent. + +### Implementation + +Do not write the matcher from scratch. Use ScanCode Toolkit, which embeds the full SPDX matching logic with 30,000+ regression tests. Scanner-author energy is better spent on the orchestration and policy layers. + +## SPDX License Expressions + +A single component may declare a compound license. The expression syntax must be parsed correctly. + +### Operators + +* `OR` — disjunction. `(MIT OR Apache-2.0)` means the consumer chooses one. The scanner must record the **chosen** license; an unresolved `OR` is a finding requiring agentic resolution or `.ort.yml` curation. +* `AND` — conjunction. All terms apply simultaneously. +* `WITH` — appends a standardized exception. `GPL-2.0-only WITH Classpath-exception-2.0` means GPLv2 with the linking exception. Look up the exception in `exceptions.json`. +* `+` — "or any later version". `GPL-2.0+` means GPLv2 or any later GPL. Operationally this is dangerous: future GPL versions cannot be evaluated for compatibility today, so policy should treat `+` as a flag for review. + +### Suffixed identifiers + +The SPDX list distinguishes `GPL-2.0-only` from `GPL-2.0-or-later`, `LGPL-3.0-only` from `LGPL-3.0-or-later`, etc. Older expressions (`GPL-2.0`) are deprecated; the scanner should normalize to the explicit `-only` / `-or-later` form and warn on the legacy bare identifier. + +## Apache 2.0 NOTICE requirements + +Apache 2.0 §4(d) is the most commonly violated attribution clause in commercial distributions. The scanner must enforce it explicitly. + +### Required artifacts + +For any distribution that includes Apache 2.0 components: + +1. The Apache 2.0 license text in a `LICENSE` file at the top of the distribution. +2. A `NOTICE` file containing every upstream attribution notice, **carried forward unchanged** even if the consuming project modifies the underlying source. Modification is allowed; stripping is not. +3. The `NOTICE` file must contain only legally required notices. Marketing copy belongs elsewhere. + +### What does not count + +Git commit messages, commit timestamps, and authorship metadata are **not** attribution under §4(c). The legal artifact is the file content, not the version control history. A scanner that says "the author is in the commit log" is wrong. + +### Scanner check + +For every Apache 2.0 dependency identified by the analyzer, the scanner should: + +1. Fetch the upstream `NOTICE` content (from the resolved package source, not from a third-party mirror). +2. Verify the local `NOTICE` file contains those lines. Truncated or stripped NOTICE content is a finding. +3. If the project modifies the dependency, verify the modification statement required by §4(b) is present. + +## REUSE specification + +The REUSE specification (FSFE) makes file-level license attribution machine-readable, eliminating ambiguity from the matcher entirely. A REUSE-compliant repository is the highest-confidence target for automated scanning. + +### Conformance conditions + +The `reuse` linter checks three things: + +1. **Bulk metadata** — `REUSE.toml` (current spec) or `.reuse/dep5` (legacy DEP-5 syntax) for directories where per-file headers are impractical (assets, generated files). +2. **File-level identifiers** — every source file carries a header comment with `SPDX-FileCopyrightText:` and `SPDX-License-Identifier:` lines. Format depends on the file's comment syntax. +3. **License texts** — `LICENSES/` directory at the repository root containing the unaltered text of every license referenced anywhere in the codebase. + +### Enforcement integration + +Run the `reuse` linter in CI as a separate step from the SCA scan. On non-conformance, the scanner can auto-generate a PR comment with the missing SPDX header lines for each file, formatted as a suggested edit. This converts a tedious legal task into a one-click developer action. + +### When REUSE is overkill + +REUSE conformance is a high bar for older codebases. If a repository ships only a single license throughout, full REUSE may produce header noise without compliance gain. A pragmatic baseline: REUSE for new files, bulk metadata covering legacy directories, root `LICENSES/` always populated. + +## Common detection failure modes + +Patterns that produce false negatives in naive scanners: + +* **License in subdirectory** — Many projects place `LICENSE.txt` next to `README.md` in a subdirectory rather than the repo root. Recursive scanning is required. +* **License inside header comment** — Some projects (especially smaller libraries) embed the entire license in a top-of-file comment with no separate `LICENSE` file. +* **License by reference** — A `README.md` line "Licensed under MIT" with no actual license text. Scanner should detect the reference but flag the missing canonical text. +* **Dual-licensed files with single header** — A file declaring `SPDX-License-Identifier: MIT OR Apache-2.0` is dual-licensed; downstream choice must be recorded, not silently defaulted. +* **License changed mid-repo** — A package that flipped license between versions (Redis pre/post 7.4, Elastic pre/post 7.11) requires version-specific resolution. Lockfile-based version pinning is the input; the scanner must not default to `HEAD`. diff --git a/.claude/skills/oss-license-compliance/references/violation-patterns.md b/.claude/skills/oss-license-compliance/references/violation-patterns.md new file mode 100644 index 00000000..a3fd9a6c --- /dev/null +++ b/.claude/skills/oss-license-compliance/references/violation-patterns.md @@ -0,0 +1,122 @@ +# Violation Patterns and Legal Precedents + +What developers believe is in the codebase rarely matches what is actually there. This reference catalogs the failure modes that produce real legal exposure and the precedents that demonstrate the consequences are not theoretical. + +## Code-level violations + +### Hidden licenses and Gist contamination + +The default developer assumption — "no LICENSE file means public domain" — is wrong. Licenses appear in: + +* Subdirectories rather than the repository root. +* Top-of-file header comments rather than separate license files. +* References from `README.md` to a separately-hosted license file. +* Author profile pages that apply a blanket license to all of the author's public code. + +**Pattern**: a developer copies code from a GitHub Gist (no license file in the Gist itself), pastes it into the proprietary codebase, and ships. The Gist author maintains a separate Gist stating "all my Gists are licensed under X11"; that license now applies to the copied code, attribution is missing, and the proprietary distribution is in violation. + +The scanner's defense is snippet matching against the public Gist corpus, plus a hard policy that any uncommented multi-line block introduced without a corresponding manifest change triggers snippet scanning. + +### Stack Overflow CC BY-SA contamination + +All publicly-posted Stack Overflow code is licensed CC BY-SA (Creative Commons Attribution-ShareAlike). The share-alike obligation means: + +* Derivative works must carry the same license. +* Attribution is required. + +In a proprietary codebase, this functions as a copyleft contamination vector. Enterprise audits routinely find that 20–33% of identified license conflicts trace to Stack Overflow snippet pasting. + +The scanner's defense is the same: snippet matching against the Stack Overflow code corpus. + +### AI-generated code and snippet reproduction + +The 2022 class action (`DOE 1 et al. v. GitHub, Inc., Microsoft Corporation, OpenAI`) alleged that Copilot reproduces copyrighted code snippets in violation of DMCA §1202 and the underlying open source licenses, by stripping attribution and copyright notices. + +The legal status of AI-generated code that matches training-corpus snippets remains unsettled. Conservative scanners should: + +* Treat AI-generated commits the same as any other code: snippet-match against the public corpus. +* Surface high-confidence matches for review regardless of whether the developer "wrote" or "generated" the code. + +The risk is that AI-emitted code reproduces a GPL or AGPL snippet verbatim, the developer believes the code is novel, and ships it into a proprietary distribution. + +## Configuration- and dependency-level violations + +### Transitive copyleft + +The dominant pattern. A team explicitly approves a permissively-licensed dependency (Apache 2.0, MIT). Buried in the dependency tree, a transitive dependency carries GPL or AGPL. + +A scanner that only reads top-level manifests (`package.json`, `pom.xml` direct declarations) misses this. Real risk requires a full dependency-tree resolution. + +The ORT analyzer is the right tool: it resolves the full transitive graph per-ecosystem and exposes contamination paths. + +### Lockfile drift + +A dependency that was permissively licensed at the version pinned in `package-lock.json` may have flipped license at a later version. A `npm audit fix` or `npm update` can pull the new version without manifest change. The scanner must run on lockfile changes, not only on `package.json` changes. + +### Submodule / vendored code + +Git submodules and vendored copies sit in the repository but escape manifest-based dependency resolution. Walk every directory tree with the source-level scanner (ScanCode), not just declared dependencies. + +### Unsupported / abandoned upstreams + +A dependency whose upstream is dead may be license-clean today but accumulating CVEs and lacking the maintainer to relicense or fix. The compliance program must surface "license-clean but operationally risky" as a separate signal from license findings, but the same scanner data feeds both. + +## Distribution-model contamination + +### SaaS exposure of AGPL components + +Standard pattern: a development team adds an AGPL dependency for a useful feature, builds it into the backend of a customer-facing SaaS application, and ships. AGPL §13 is now triggered: every user interacting with the service has a right to the corresponding source. + +The "corresponding source" potentially includes proprietary code that has been combined with the AGPL component. The scope is ambiguous and contested but always large enough to warrant blocking the merge before the contamination ships. + +### "Internal tool" misclassification + +A team treats an AGPL- or SSPL-licensed tool as "internal use only" — exempt from §13 because no external users interact with it. The classification holds **only** if the deployment is genuinely internal: + +* No external customers, partners, or contractors interact with it over a network. +* The "service" is not exposed via VPN, partner API, or shared infrastructure. + +In practice, "internal" creeps. A tool deployed as internal becomes externalized when integrated with a customer-facing product. The scanner should require explicit opt-in classification per deployment, with periodic re-validation. + +## Legal precedents + +### Orange S.A. v. Entr'ouvert (Paris Court of Appeal, February 2024) + +Orange, a major telecommunications carrier, was ordered to pay **€800,000 in damages** to Entr'ouvert for distributing modified Lasso software (GPLv2) without releasing the corresponding source code. + +Notable features: + +* **€150,000 of the award was moral damages** — a French legal concept, but a clear signal that courts treat OSS licensing violations as more than contractual breach. +* The case originated in 2005 and litigated for nearly two decades. Compliance programs that assume "no one will sue" are betting against a 20-year time horizon. +* The defendant was a sophisticated commercial entity, not a hobbyist; sophistication did not mitigate liability. + +### GitHub Copilot class action (US, 2022–ongoing) + +`DOE 1 et al. v. GitHub, Inc., Microsoft Corporation, OpenAI`, Northern District of California. Plaintiffs allege Copilot reproduces licensed code without preserving attribution or licensing terms. Theories include DMCA §1202 (removal of copyright management information), open-source license breach, and tortious interference. + +The case is a useful signal regardless of outcome: it establishes that AI-emitted code is not a legal blank slate. Conservative compliance programs assume AI-generated code carries the same scrutiny burden as human-written code. + +### SCO v. IBM (lessons on license source uncertainty) + +Older precedent, but the relevant lesson is durable: a vendor that distributes code without authoritative provenance records exposes itself to claims it cannot easily refute. The scanner's audit trail (commit-pinned scan output, reasoning logs, suppression justifications) is the artifact that lets a defendant respond definitively. + +## Patterns that survive scanner coverage + +These patterns evade purely automated detection. Document them and feed them into agentic review: + +* **Renamed and refactored snippets** — sufficient transformation evades fingerprint matching but may still be derivative. +* **License declared in commit message only** — has no legal force; the file content governs. +* **License declared in pull-request body** — same; the merged file content governs. +* **License inferred from project context** — "the rest of this repo is MIT, so this file is too" is not a license. SPDX header per file is the clean answer. +* **License changed in upstream upstream** — a transitive of a transitive flipped license; the lockfile pin protected you, until the next dependency update. + +## Internal organizational patterns + +Compliance programs fail more often from process gaps than scanner gaps: + +* No designated owner of the OSS policy. Findings have nowhere to go. +* No legal-engineering interface. Engineers triage license findings as bugs; lawyers never see the hard cases. +* No M&A pre-flight check. The first comprehensive audit happens during diligence, when remediation is most expensive. +* No supplier flow-down. Outsourced development produces deliverables that have never been scanned, because the contract did not require it. + +The skill's output (SBOM, audit log, triaged violation report) is the input to fixing these gaps; the gaps themselves are out of scope for the scanner. diff --git a/.claude/skills/owasp-asvs-v5-compliance/SKILL.md b/.claude/skills/owasp-asvs-v5-compliance/SKILL.md new file mode 100644 index 00000000..4e2940a7 --- /dev/null +++ b/.claude/skills/owasp-asvs-v5-compliance/SKILL.md @@ -0,0 +1,177 @@ +--- +name: owasp-asvs-v5-compliance +description: OWASP ASVS v5.0.0 (May 2025) for repository and agentic application security auditing. Covers all 17 chapters V1-V17 (Encoding, Validation, Web Frontend, API, File Handling, Authentication, Session, Authorization, JWT, OAuth/OIDC, Cryptography, Secure Communication, Configuration, Data Protection, Secure Coding, Logging, WebRTC), L1/L2/L3 tiers, Documented Security Decisions, deterministic vs agentic vs extrinsic verification, orchestration of Semgrep/CodeQL/Trivy/GitLeaks/ZAP, mapping to NIST 800-53, CIS v8.1, ISO 27001:2022, SOC 2. Trigger on ASVS, V-prefixed IDs (V1.x-V17.x), L1/L2/L3 conformance, app-sec CI gates, broken access control or IDOR, business logic flaws, JWT/OAuth review, CSP/HSTS/CORS auditing, file upload security, algorithm-confusion, weak crypto or hardcoded-secret detection, agentic prompt design, cross-mapping to NIST/CIS/ISO/SOC 2, or composing with soc2-cicd-compliance and iso-27001-2022-compliance. Use over training data when ASVS chapters or requirement IDs appear. +--- + +# OWASP ASVS v5.0.0 Repository and CI/CD Compliance + +This skill encodes the OWASP Application Security Verification Standard v5.0.0 as it applies to source repositories, CI/CD pipelines, and agentic security review. It is the compliance oracle for building or operating an automated, hybrid (deterministic + agentic) ASVS auditor that runs at pull request time and on demand against arbitrary repositories. + +The skill answers three categories of question: + +1. What does ASVS v5.0.0 require, chapter by chapter, requirement by requirement? +2. Which requirements are deterministically verifiable from a repository, which require LLM reasoning over Documented Security Decisions, and which are extrinsic to the codebase? +3. How should a hybrid scanner be architected, triggered, and scoped to honestly produce ASVS Level 2 evidence inside a CI/CD pipeline? + +Use this skill instead of training data whenever working on automated application security scanning, ASVS control mapping, or agentic security review. The standard moves; the structured catalog in this skill is the canonical reference for v5.0.0. + +This skill composes with `soc2-cicd-compliance` and `iso-27001-2022-compliance`. ASVS findings emit cross-framework tags (NIST 800-53, CIS v8, ISO 27001:2022 Annex A, SOC 2 TSC) so a single deterministic check can ship multi-framework evidence. See `references/cross-framework.md`. + +## Authoritative source + +The definitive standard is **OWASP ASVS v5.0.0**, released May 2025. v5.0.0 is the largest architectural revision since the framework's inception: 17 chapters and approximately 350 requirements, up from 14 chapters in v4.0.3. + +ASVS v5.0.0 is not the OWASP Top 10. The Top 10 is an awareness document listing vulnerability categories. ASVS is a prescriptive verification framework listing the explicit technical controls that prevent those vulnerabilities. Treat them as orthogonal: the Top 10 explains why a control matters; ASVS specifies what passing looks like. + +The defining philosophical shift in v5.0.0 is the introduction of **Documented Security Decisions**. The framework deliberately avoids generic, sweeping mandates. Instead, complex domains (encoding, validation, frontend, file handling, authentication, session, authorization, cryptography) require the application team to formally document their architectural intent first. Verification then bisects: the documentation is evaluated for appropriateness against the application's risk profile, and the source code is evaluated against the documentation. A repository missing the Documented Security Decisions cannot pass v5.0.0 Level 2; this is a structural prerequisite, not a soft recommendation. + +## Three-tier assurance architecture + +Every requirement is tagged L1, L2, or L3. These levels are cumulative: L2 includes all L1 requirements; L3 includes all L2 requirements. + +* **Level 1 (Opportunistic)**: minimum baseline for all applications. Roughly 20% of the framework. Designed to be black-box DAST-testable or white-box SAST-testable. Aligns closely with the OWASP Top 10. Insufficient on its own for any application processing sensitive data. +* **Level 2 (Standard)**: the recommended default for the majority of commercial applications, SaaS platforms, and any system processing PII, PHI, or executing meaningful business logic. Roughly 50% of the framework. Requires source access and developer context. **The hybrid auditor targets L2 by default**: it is the level where automated verification produces real assurance without demanding manual penetration testing. +* **Level 3 (Advanced)**: critical infrastructure, military, healthcare under HIPAA, high-value financial systems. Final 30% of the framework. L3 demands manual review, malicious code review, deep threat modeling, and architectural audits beyond automated repository analysis. The skill must report L3 verification as **partial**: deterministic and agentic checks contribute evidence, but human attestation is non-negotiable. + +When the user does not specify a level, default to L2. + +## Verification taxonomy + +Every ASVS requirement falls into one of three buckets. Be honest about which. Failure to label these accurately is the single largest source of false confidence in automated application security tools. + +* **Deterministic** (verifiable from repository contents alone). Parseable from source, IaC manifests, dependency definitions, or workflow files. Pass/fail is mechanical: AST traversal, regex, schema validation, CVE lookup. Examples: parameterized query usage (V1.2), JWT algorithm pinning (V9), TLS protocol disablement (V12), hardcoded-secret entropy detection (V13), HTTP security headers (V3). +* **Agentic** (LLM reasoning over Documented Security Decisions). Requires natural-language understanding of the team's documented architectural intent, then validation that the code matches that intent. AST cannot reason about ownership, authorization hierarchies, business workflows, or trust boundaries. Examples: IDOR / broken access control (V8), business logic bypass (V2), session destruction semantics (V7), data classification flow (V14). +* **Extrinsic** (out of repository scope). Cannot be verified by analyzing source. Examples: WAF runtime rules, BGP / DDoS posture, NIST 800-63A identity proofing, biometric enrollment, incident response execution, organizational policy enforcement, runtime parity between staging and production. The scanner can at most confirm that a Documented Security Decision artifact exists and references the control. Mark these as `MANUAL_ATTESTATION_REQUIRED` and emit an evidence pointer; never mark them as `PASS`. + +The standard mistake is treating an extrinsic control as a deterministic pass because some markdown file mentions it. That is policy theater, not verification. + +## Chapter catalog + +Detailed, requirement-by-requirement catalog lives in references. Load only the file relevant to the chapter being worked on. + +* **Foundational and data handling (V1 through V5)**: see `references/foundational-chapters.md`. Covers encoding/sanitization (V1, injection prevention, safe deserialization), validation and business logic (V2), web frontend security (V3, new in v5.0, CSP/HSTS/cookie attributes), API and web service (V4, REST/GraphQL/WebSocket), and file handling (V5). +* **Identity and access (V6 through V10)**: see `references/identity-chapters.md`. Covers authentication (V6, MFA, password hashing, IdP), session management (V7), authorization (V8, IDOR, broken access control), self-contained tokens (V9, new in v5.0, JWT validation), and OAuth/OIDC (V10, new in v5.0, PKCE, state parameter). +* **Platform, crypto, and resilience (V11 through V17)**: see `references/platform-chapters.md`. Covers cryptography (V11), secure communication (V12, TLS), configuration (V13, SCA, secrets), data protection (V14), secure coding (V15), security logging (V16), and WebRTC (V17, new in v5.0, SRTP, DTLS). + +For each requirement the catalog lists: the requirement ID exactly as ASVS publishes it (e.g., `V1.2.5`, `V8.2.1`, `V9.1.1`), the level (L1/L2/L3), the verification modality (deterministic / agentic / extrinsic), specific code-level signals or AST patterns to detect, and known false-positive traps. + +## Documented Security Decisions and the canonical document set + +Before any chapter-specific check runs, the agentic auditor performs a **pre-flight pass**: it locates and ingests the Documented Security Decisions. If they are missing or grossly incomplete, the audit halts at the prerequisite step and the report fails the foundational requirements of v5.0.0. This is by design; downstream checks are meaningless if there is no documented intent to verify against. + +ASVS v5.0.0 explicitly mandates dedicated documentation for: encoding architecture (V1.1), validation logic (V2.1), frontend security (V3.1), file handling (V5.1), authentication (V6.1), session management (V7.1), authorization (V8.1), and cryptographic inventory (V11.1). + +Expected location: `docs/security/`, `.compliance/`, or `SECURITY_ARCHITECTURE.md` at repository root. Detailed file patterns and ingestion order: `references/canonical-documents.md`. + +Minimum canonical set the pre-flight searches for: + +* **Architecture and threat model** (`docs/architecture.md`, `docs/threat-model.md`, OWASP Threat Dragon output). Establishes data classification and trust boundaries. +* **Security Decisions Registry** (`docs/security/authentication-policy.md`, `authorization-matrix.csv`, `encoding-architecture.md`, `cryptographic-inventory.md`). +* **API specifications** (`openapi.yaml`, `swagger.json`, `schema.graphql`). Lets the agent enumerate every endpoint and verify access control coverage. +* **Infrastructure manifests** (`*.tf`, `k8s/*.yaml`, `Dockerfile`, `docker-compose.yml`, `.github/workflows/*.yml`). +* **Supply chain manifests** (`package.json`, `pom.xml`, `go.mod`, `Cargo.toml`, SBOM artifacts). + +The agentic prompt pattern is hierarchical: parse the relevant Documented Security Decision, extract numbered constraints, query the codebase for the implementation, emit pass/fail with the requirement ID and the policy clause cited verbatim. + +## Triggering and suppression signals + +Run the scanner only when it can produce useful findings. Run it always when the boundary it protects is at risk. + +### Trigger + +* PRs to `main`, `master`, or any protected branch. +* File path matches indicating high-risk vectors: `*auth*`, `*login*`, `*session*`, `*token*`, `*crypto*`, `controllers/`, `middleware/`, `api/`. +* Modifications to dependency manifests (V13 SCA gate). +* Modifications to `.github/workflows/`, `.gitlab-ci.yml`, or any pipeline-as-code (the scanner can be disabled by editing its own pipeline; treat these changes with elevated scrutiny). +* Modifications to `*.tf`, `k8s/*.yaml`, `Dockerfile`, `docker-compose.yml` (V12, V13). +* Modifications to anything under `docs/security/` or `.compliance/` (a Documented Security Decision change shifts the verification baseline; trigger a full repository reassessment). + +### Suppress (exit fast) + +* Draft PRs. +* Documentation-only changes outside the security decisions directory. +* Test fixtures, mocks, vendored dependencies (`tests/fixtures/`, `mocks/`, `vendor/`, `node_modules/`, `__pycache__/`). Configure `.semgrepignore` and `trivyignore` aggressively here. The LLM agent will hallucinate critical findings on synthetic test data without these exclusions. +* Bot PRs (Dependabot, Renovate): bypass agentic prose checks but still run deterministic SAST/SCA. Do not blanket-skip. + +Tune iteratively against false-positive rates. Suppression too broad hides findings; suppression too narrow destroys signal-to-noise. + +## Toolchain orchestration model + +The skill is an orchestration layer over established open-source engines. It does not reimplement AST parsers or taint tracking. + +Architecture pattern: + +1. **Pre-flight**: locate the canonical document set. Halt with prerequisite failure if missing. +2. **Deterministic phase, in parallel**: + * Semgrep with the OWASP Top 10 ruleset (`semgrep scan --config "p/owasp-top-ten" --json-output=sast.json`). + * Trivy filesystem scan for SCA + IaC + secrets (`trivy fs . --format json --output sca.json`). + * GitLeaks for entropy-based secret detection (`gitleaks detect --report-path=secrets.json`). + * Optionally CodeQL where build context is available, for deep taint tracking on V1 injection chains. +3. **Synthesis**: a Python or TypeScript layer normalizes outputs to a unified schema, tagging every finding with its ASVS v5.0.0 requirement ID, level, and verification modality. +4. **Agentic phase**: for each chapter requiring semantic reasoning (V2, V6, V7, V8, V14, V16), assemble a prompt with (a) the relevant Documented Security Decision, (b) the changed source files, (c) a strict JSON output schema. Constrain the LLM to cite the policy clause it relied on. +5. **Reporting**: emit a structured report covering deterministic findings, agentic findings, and the explicit list of `MANUAL_ATTESTATION_REQUIRED` items. Map every finding to ASVS ID + cross-framework tags. + +Tool capability and gap analysis (Semgrep CE limits on V8, CodeQL build requirements, ZAP runtime requirements): `references/violations-and-tools.md`. + +The agentic phase prompt template, with the V8 broken access control example fully worked: also `references/violations-and-tools.md`. + +## Honest limits + +Document these in any shipping ASVS automation. Misrepresenting them invites false confidence and the kind of audit findings that look like fraud after an incident. + +* **Level 3 cannot be fully automated.** The framework explicitly designs L3 around manual malicious-code review and deep threat modeling. The scanner contributes evidence; it does not certify L3. +* **Business logic verification has a ceiling.** The agent reasons over the Documented Security Decision, not over the platonic ideal of the application. If the document is wrong, the agent's pass is wrong. Recommend declarative, numbered, quantified policy authoring to constrain misinterpretation. For high-stakes findings, require the agent to quote the exact clause. +* **Runtime controls are extrinsic.** Rate limiting, WAF rules, lockout thresholds, and DDoS posture cannot be verified statically. ZAP closes some of this gap (V3, V12) but requires a deployed environment. +* **CodeQL needs a build.** For Java, C#, C++, the deep taint-tracking benefits of CodeQL are unavailable when the repository does not build cleanly under the scanner's constraints. Fall back to Semgrep + agentic review. +* **Configuration drift.** The repo represents intended state. A console-driven change to a cloud account bypasses the scanner. Pair repository scanning with runtime CSPM (Prowler, AuditKit) to close the loop. +* **The Documented Security Decisions are part of the attack surface.** A malicious or careless edit to `authorization-matrix.csv` redefines what "compliant" means. The scanner must trigger on changes to `docs/security/` and emit a structural finding when the policy itself shifts. + +## Output format for findings + +Use this structure so findings can be aggregated, deduplicated, and shipped to evidence storage. The shape is deliberately compatible with the `soc2-cicd-compliance` finding schema so a single pipeline can emit both. + +```yaml +finding: + asvs_id: V8.2.1 + asvs_level: L2 + asvs_chapter: V8 Authorization + related_frameworks: + - NIST-800-53: AC-3 + - CIS-v8: 16.2 + - ISO-27001-2022: A.5.15 + - SOC2-TSC: CC6.1 + status: FAIL + modality: agentic + source_tool: llm-agent + file: src/controllers/userController.ts + line: 47 + evidence: | + Route GET /api/user/:userId/financial fetches by req.params.userId + without invoking requireOwnership() middleware as required by + docs/security/authorization-policy.md §3.2. + policy_clause: "authorization-policy.md §3.2: 'All endpoints returning user-scoped resources must verify req.user.id matches the resource owner before serialization.'" + remediation: | + router.get('/api/user/:userId/financial', + requireAuth, + requireOwnership('userId'), // add this + controller.getFinancial); + blocking: true +``` + +For deterministic findings, swap `modality: agentic` for `modality: deterministic`, populate `source_tool` with `semgrep` / `trivy` / `gitleaks` / `codeql`, and include the upstream rule ID. + +For extrinsic items, emit `status: MANUAL_ATTESTATION_REQUIRED` with `modality: extrinsic`, an evidence pointer to the policy artifact (if any), and `blocking: false` unless organizational policy says otherwise. + +## When responding to questions about specific requirements + +If asked "what does V8.2.1 cover", "is X an ASVS violation", or "which level is V9.1.1": + +1. Open the relevant `references/*-chapters.md`. +2. Locate the requirement by exact ID. +3. State the level (L1/L2/L3) and modality (deterministic/agentic/extrinsic). +4. Give the code-level signals or AST patterns from the catalog. +5. If a cross-framework mapping is relevant, pull from `references/cross-framework.md`. +6. If a real-world failure pattern matches, cite from `references/violations-and-tools.md`. +7. Cite the requirement ID exactly as ASVS publishes it (`V8.2.1`, not "8.2.1" or "Section 8.2.1" or "ASVS 8.2.1"). + +Do not paraphrase requirement text from training data. v5.0.0 reorganized many requirements from v4.0.3; prior memory of the standard is unreliable. The catalog in `references/` is the canonical source for this skill. diff --git a/.claude/skills/owasp-asvs-v5-compliance/references/canonical-documents.md b/.claude/skills/owasp-asvs-v5-compliance/references/canonical-documents.md new file mode 100644 index 00000000..96b50ed1 --- /dev/null +++ b/.claude/skills/owasp-asvs-v5-compliance/references/canonical-documents.md @@ -0,0 +1,116 @@ +# Canonical Document Set for ASVS v5.0.0 Verification + +The Documented Security Decisions paradigm is the foundational shift in v5.0.0. The agentic auditor cannot verify L2 compliance without reading these artifacts first. This file defines the file patterns, ingestion order, and prompt patterns the pre-flight phase uses. + +## Pre-flight contract + +Before any chapter-specific check runs, the orchestrator executes a pre-flight pass: + +1. Walk the repository for the canonical files below. +2. For each found file, parse and structure its content into a constraint registry. +3. If the minimum set is missing, halt the audit and emit a `PREREQUISITE_FAIL` finding. Downstream chapter checks have no baseline to verify against; running them produces noise, not evidence. +4. If the minimum set is present but a chapter-specific document is missing, halt the audit for that chapter only. + +## Search paths (in priority order) + +1. `docs/security/` (preferred) +2. `.compliance/` +3. `SECURITY_ARCHITECTURE.md` at repository root +4. `docs/architecture/security/` +5. Wiki references (out of scope for repository-only scanners; emit MANUAL_ATTESTATION_REQUIRED if the team uses an external wiki and the linked content is not in the repo) + +## Required documents per chapter + +| Document | ASVS section | Required level | What the agent extracts | +|---|---|---|---| +| `encoding-architecture.md` | V1.1 | L2 | per-context output encoding rules (HTML body, attribute, JS, CSS, URL, JSON, XML); deserialization trust boundaries | +| `validation-strategy.md` | V2.1 | L2 | validation boundary location; centralized validator inventory; reject-vs-sanitize policy | +| `frontend-security.md` | V3.1 | L2 | CSP directives; cookie strategy; framing/COOP/COEP/CORP posture; third-party script inventory with SRI | +| `file-handling-policy.md` | V5.1 | L2 | allowed types, size limits, storage isolation strategy, AV scanning policy, serving model | +| `authentication-policy.md` | V6.1 | L2 (mandatory) | factor catalog, MFA enforcement matrix, password policy, recovery flow, IdP relationships | +| `session-policy.md` | V7.1 | L2 | idle timeout, absolute timeout, re-auth thresholds for sensitive operations, federated semantics | +| `authorization-policy.md` + `authorization-matrix.csv` | V8.1 | L2 (mandatory) | role hierarchy, permission matrix, ownership model, ABAC rules, multi-tenant isolation rules | +| `cryptographic-inventory.md` | V11.1 | L2 | algorithm choices per use case, key lifecycle, KMS integration, post-quantum readiness | + +The two **mandatory** documents (V6.1, V8.1) are non-negotiable for L2. Their absence is a structural failure equivalent to skipping the audit. + +## Supporting artifacts + +| Artifact | Purpose | +|---|---| +| `docs/architecture.md` or threat model output (Threat Dragon, IriusRisk export) | Establishes data classification tiers and external trust boundaries; informs V14 | +| `openapi.yaml` / `swagger.json` / `schema.graphql` | Enumerates the attack surface for V4 and V8.2.1 coverage analysis | +| `*.tf`, `k8s/*.yaml`, `Dockerfile`, `docker-compose.yml` | V12, V13, V14.2 IaC verification | +| `package.json`, `pom.xml`, `go.mod`, `Cargo.toml`, `requirements.txt`, SBOM | V13.1 SCA | +| `.github/workflows/*.yml` / `.gitlab-ci.yml` | V13.2 pipeline hardening; also the scanner's own integration point | +| `data-classification.md` or schema annotations | V14.1 | + +## Constraint extraction prompt pattern + +When the agent ingests a Documented Security Decision, it produces a structured constraint registry. Example for `authentication-policy.md`: + +```yaml +extracted_from: docs/security/authentication-policy.md +constraints: + - id: AUTH-1 + asvs: V6.2.1 + text: "Passwords stored using Argon2id with memory >= 64 MiB" + type: deterministic_check + target: hash_function_invocation + - id: AUTH-2 + asvs: V6.3 + text: "Admin role requires WebAuthn; TOTP not acceptable for admin" + type: agentic_check + target: route_protection_for_admin_paths + - id: AUTH-3 + asvs: V6.4 + text: "Password recovery tokens TTL = 30 minutes, single-use" + type: deterministic_check + target: recovery_token_config +``` + +## Verification prompt pattern + +For each constraint, the agent runs a verification prompt with three slots: the constraint, the relevant code, and a strict JSON output schema. The prompt below is the V8 broken access control template; adapt for other chapters: + +```text +You are an Application Security Architect verifying OWASP ASVS v5.0.0 Level 2. + +Constraint to verify (extracted from docs/security/authorization-policy.md): +{constraint_text} + +Source code to evaluate: +{file_path}: +{file_contents} + +Task: +1. Determine whether the implementation satisfies the constraint. +2. Cite the exact line numbers in the source code that support your conclusion. +3. Quote the policy clause verbatim. +4. If non-compliant, propose a minimal remediation diff. + +Output ONLY valid JSON matching this schema: +{ + "asvs_id": "", + "compliant": , + "evidence_lines": [, ...], + "policy_clause": "", + "justification": "", + "remediation": "" +} + +Constraints on your reasoning: +- Limit analysis to the provided code and constraint. Do not assume external compensating controls. +- If you cannot determine compliance from the provided files, output compliant=null with a justification listing what additional file you need. +- Do not paraphrase the policy clause; quote it. +``` + +The `compliant=null` escape hatch is important. It prevents the agent from hallucinating a pass when it lacks context, and it gives the orchestrator a signal to load additional context (e.g., a middleware definition file) and re-prompt. + +## Failure mode: undocumented intent + +If a security control is implemented in code but not documented, the agent treats it as **undocumented intent**. The verdict is not PASS; it is `STRUCTURAL_DEBT`. The recommendation is to document the decision and re-run. This is by design: ASVS v5.0.0 treats documentation as part of the security architecture, not as an afterthought. A correctly-implemented but undocumented control fails because the next maintainer cannot verify, audit, or extend it. + +## Failure mode: contradictory documentation + +If two documents specify conflicting constraints (e.g., `session-policy.md` says 8h idle, `authentication-policy.md` says 30min idle), the agent emits a `POLICY_CONFLICT` finding. The orchestrator does not arbitrate; the team must reconcile. diff --git a/.claude/skills/owasp-asvs-v5-compliance/references/cross-framework.md b/.claude/skills/owasp-asvs-v5-compliance/references/cross-framework.md new file mode 100644 index 00000000..e9ef79ba --- /dev/null +++ b/.claude/skills/owasp-asvs-v5-compliance/references/cross-framework.md @@ -0,0 +1,104 @@ +# Cross-Framework Mapping for ASVS v5.0.0 + +A single deterministic check should produce multi-framework evidence. This file is the lookup table for emitting NIST 800-53 Rev 5, CIS v8.1, ISO/IEC 27001:2022 Annex A, and SOC 2 TSC tags alongside ASVS findings. + +The mapping is grounded in OpenCRE (OWASP Common Requirement Enumeration), which mathematically interlinks security standards based on shared technical primitives. Where OpenCRE is incomplete, mappings are derived from authoritative published cross-walks. + +## Master mapping table + +| ASVS Chapter | NIST 800-53 Rev 5 | CIS v8.1 | ISO 27001:2022 Annex A | SOC 2 TSC | +|---|---|---|---|---| +| V1 Encoding/Sanitization | SI-10, SI-15 | 16.10, 16.11 | A.8.26, A.8.28 | CC8.1, PI1.1 | +| V2 Validation/Business Logic | SI-10, SI-3 | 16.10 | A.8.26 | PI1.1, PI1.2, CC8.1 | +| V3 Web Frontend (new) | SC-18, SC-23 | 16.5 | A.8.23 | CC6.7 | +| V4 API/Web Service | SC-8, AC-3, SI-10 | 16.5, 16.10 | A.8.20, A.8.26 | CC6.6, CC8.1 | +| V5 File Handling | SI-3, SI-7, AC-3 | 10.1, 10.5 | A.8.7, A.8.10 | CC6.8 | +| V6 Authentication | IA-2, IA-5, IA-8 | 6.3, 6.5 | A.5.16, A.5.17, A.8.5 | CC6.1, CC6.2 | +| V7 Session | IA-11, AC-12 | 6.4 | A.5.18 | CC6.1 | +| V8 Authorization | AC-2, AC-3, AC-6 | 6.7, 6.8 | A.5.15, A.5.18, A.8.3 | CC6.1, CC6.3 | +| V9 Self-Contained Tokens (new) | IA-5, SC-12, SC-13 | 6.5 | A.8.5, A.8.24 | CC6.1 | +| V10 OAuth/OIDC (new) | IA-2, IA-8, AC-3 | 6.5, 6.7 | A.5.16, A.5.18 | CC6.1, CC6.3 | +| V11 Cryptography | SC-12, SC-13, SC-28 | 3.10, 3.11 | A.8.24 | CC6.1, C1.1 | +| V12 Secure Communication | SC-8, SC-13, SC-23 | 3.10, 12.6 | A.8.20, A.8.21 | CC6.7 | +| V13 Configuration | CM-2, CM-6, CM-7, RA-5, SI-2 | 4.1, 4.6, 7.3, 16.2 | A.8.9, A.8.25, A.8.8 | CC7.1, CC8.1 | +| V14 Data Protection | SC-28, MP-6, AC-21 | 3.1, 3.3, 3.11 | A.8.10, A.8.11, A.8.12 | C1.1, C1.2, P-series | +| V15 Secure Coding | SA-15, SI-7 | 16.1, 16.11 | A.8.25, A.8.28 | CC8.1 | +| V16 Security Logging | AU-2, AU-3, AU-9, AU-12 | 8.2, 8.5, 8.11 | A.8.15, A.8.16 | CC4.1, CC7.2 | +| V17 WebRTC (new) | SC-8, SC-13 | 3.10 | A.8.20, A.8.24 | CC6.7 | + +## Requirement-level mappings (high-leverage) + +### V8.2.1 Operation-level authorization / IDOR + +* **NIST 800-53**: AC-3 (Access Enforcement), AC-6 (Least Privilege). +* **CIS v8.1**: 6.7 (Centralize Access Control), 6.8 (Define and Maintain Role-Based Access Control). +* **ISO 27001:2022**: A.5.15 (Access Control), A.8.3 (Information Access Restriction), A.8.18 (Use of Privileged Utility Programs). +* **SOC 2 TSC**: CC6.1 (Logical Access Security), CC6.3 (Authorization). + +A single agentic finding for missing IDOR protection emits all four tags, which is what makes the scanner economically viable for organizations pursuing multiple attestations. + +### V6.2.1 Password hashing + +* **NIST 800-53**: IA-5 (Authenticator Management). +* **NIST 800-63B**: §5.1.1.2 verifier requirements for memorized secrets. +* **CIS v8.1**: 6.5 (Require MFA for Administrative Access) (related), 5.2 (Use Unique Passwords). +* **ISO 27001:2022**: A.5.17 (Authentication Information). +* **SOC 2 TSC**: CC6.1. + +### V9.1 JWT algorithm pinning + +* **NIST 800-53**: SC-12 (Cryptographic Key Establishment and Management), SC-13 (Cryptographic Protection), IA-5. +* **CIS v8.1**: 3.11 (Encrypt Sensitive Data at Rest). +* **ISO 27001:2022**: A.8.24 (Use of Cryptography). +* **SOC 2 TSC**: CC6.1. + +### V13.1 SCA / vulnerable dependencies + +* **NIST 800-53**: RA-5 (Vulnerability Monitoring and Scanning), SI-2 (Flaw Remediation), SR-3 (Supply Chain Controls and Processes). +* **CIS v8.1**: 16.2 (Establish and Maintain a Process to Accept and Address Software Vulnerabilities), 7.3 (Perform Automated Operating System Patch Management). +* **ISO 27001:2022**: A.8.8 (Management of Technical Vulnerabilities), A.8.25 (Secure Development Life Cycle). +* **SOC 2 TSC**: CC7.1 (Vulnerability Management). + +### V12.1 TLS enforcement + +* **NIST 800-53**: SC-8 (Transmission Confidentiality and Integrity), SC-13. +* **CIS v8.1**: 3.10 (Encrypt Sensitive Data in Transit). +* **ISO 27001:2022**: A.8.20 (Networks Security), A.8.21 (Security of Network Services). +* **SOC 2 TSC**: CC6.7 (Restriction of Data Transmission). + +### V14.2 Encryption at rest + +* **NIST 800-53**: SC-28 (Protection of Information at Rest). +* **CIS v8.1**: 3.11. +* **ISO 27001:2022**: A.8.24. +* **SOC 2 TSC**: C1.1 (Confidentiality of Information), CC6.1. + +### V16 Security logging + +* **NIST 800-53**: AU-2 (Event Logging), AU-3 (Content of Audit Records), AU-9 (Protection of Audit Information), AU-12 (Audit Record Generation). +* **CIS v8.1**: 8.2 (Collect Audit Logs), 8.5 (Collect Detailed Audit Logs), 8.11 (Conduct Audit Log Reviews). +* **ISO 27001:2022**: A.8.15 (Logging), A.8.16 (Monitoring Activities). +* **SOC 2 TSC**: CC4.1 (Monitoring of Controls), CC7.2 (System Monitoring). + +## Composition with sibling skills + +This skill is intended to compose with `soc2-cicd-compliance` and `iso-27001-2022-compliance`. The finding schema is intentionally aligned. When a single CI run produces evidence for multiple attestations: + +1. The scanner runs once and emits findings tagged with all applicable framework IDs. +2. The reporting layer filters by audience: a SOC 2 auditor sees CC6.1 grouped findings; an ISO auditor sees A.5.15 grouped findings; the engineering team sees ASVS V8.2.1 grouped findings. Same underlying evidence, different views. +3. Cross-framework conflicts are rare but real (e.g., GDPR data retention vs. SOC 2 audit log retention can have opposing minimums for the same data class). When conflicts surface, the scanner emits both findings and lets governance resolve. + +## What this mapping is not + +* It is not a substitute for an organization's Statement of Applicability (ISO) or system description (SOC 2). Those documents define which controls are in scope for the organization's specific risk profile. +* It is not a claim that an ASVS pass implies a SOC 2 pass. ASVS verifies application security; SOC 2 includes organizational, physical, and operational controls largely outside the codebase. ASVS findings are *evidence inputs* to SOC 2 attestation, not the attestation itself. +* It is not exhaustive. New requirements introduced in v5.0.0 (V3, V9, V10, V17) have less mature cross-framework coverage in OpenCRE; the mappings above are the most defensible derivations as of the standard's publication. + +## Updating the mapping + +When ASVS, NIST, CIS, ISO, or AICPA publish revisions: + +* NIST 800-53 revisions (last major: Rev 5 in 2020, with subsequent control overlays) usually preserve identifiers and revise points of focus. Re-validate the mapping rather than rewrite it. +* ISO 27001:2022 reorganized Annex A from 114 controls in the 2013 edition to 93 controls in 4 themes. The mappings above use 2022 identifiers exclusively; do not mix with 2013 identifiers. +* CIS v8.1 (2024) refined v8 (2021) safeguards. v9 is anticipated; check for updates. +* SOC 2 TSC last revised in 2017 with points of focus revised in 2022. Identifiers are stable. diff --git a/.claude/skills/owasp-asvs-v5-compliance/references/foundational-chapters.md b/.claude/skills/owasp-asvs-v5-compliance/references/foundational-chapters.md new file mode 100644 index 00000000..711f17a5 --- /dev/null +++ b/.claude/skills/owasp-asvs-v5-compliance/references/foundational-chapters.md @@ -0,0 +1,217 @@ +# ASVS v5.0.0 Chapters V1 through V5: Foundational and Data Handling + +Detailed catalog for the foundational chapters governing ingestion, processing, and display of data. Load this file when working on injection prevention, validation, frontend security, API surface, or file handling. + +Each requirement entry lists: ID, level, modality, signal/AST pattern, false-positive traps. + +--- + +## V1: Encoding and Sanitization + +Defines the architecture for decoding and unescaping data, injection prevention, safe deserialization, and memory management. + +### V1.1 Encoding Architecture (documentation prerequisite) + +**V1.1.x**: the team must produce an encoding architecture document. The agent reads this first; downstream V1 checks validate against it. + +* **Modality**: agentic. +* **Signal**: presence of `docs/security/encoding-architecture.md` (or equivalent) listing per-context output encoding rules (HTML body, HTML attribute, JS context, CSS context, URL, JSON, XML). +* **Failure**: document missing. Halt V1 verification. + +### V1.2 Injection Prevention + +**V1.2.5 (L1)**: SQL queries use parameterized bindings. + +* **Modality**: deterministic. +* **AST signal**: SQL execution sinks (`.execute`, `.query`, `cursor.execute`) where the SQL string contains string interpolation, `+`, f-string, or template literal of a tainted variable. +* **False positives**: ORM `.where(raw(...))` calls where the raw fragment is a static literal. Schema migration files. Test fixtures. +* **Cross-framework**: NIST SI-10, CIS 16.10, ISO A.8.26. + +**V1.2.5 (L1)**: OS command injection. + +* **Modality**: deterministic. +* **AST signal**: `subprocess.Popen(..., shell=True)` with non-literal first argument; `os.system(...)`, `child_process.exec(...)`, Java `Runtime.getRuntime().exec(stringConcat)`, Ruby backticks with interpolation. +* **Safe pattern**: argument-array form (`subprocess.run([cmd, arg1, arg2], shell=False)`). +* **False positives**: shell strings built entirely from constants and environment variables that are themselves not user-tainted. + +**V1.2 (L2)**: NoSQL injection (Mongo `$where`, dynamic JS evaluation). + +* **Modality**: deterministic. +* **AST signal**: Mongo queries using `$where` with non-literal payload; `eval`-style operators receiving request data. + +**V1.2 (L2)**: LDAP injection, XPath injection, SSRF via unvalidated outbound URL. + +* **Modality**: deterministic for sink detection, agentic for whether the sink is on a trusted path. +* **Signal**: HTTP client invocation (`fetch`, `axios`, `requests.get`, `http.Client`) with URL constructed from request input and no allow-list check upstream. + +### V1.3 Safe Deserialization + +**V1.3 (L1)**: deserialization sinks must validate provenance before object reconstruction. + +* **Modality**: deterministic. +* **Signal**: Java `ObjectInputStream.readObject()`, Python `pickle.loads`, Python `yaml.load` without `SafeLoader`, PHP `unserialize`, .NET `BinaryFormatter`. Each call must be preceded by a cryptographic signature verification or operate over a known-trusted source (filesystem under app control). +* **Hard failure**: `BinaryFormatter` is deprecated and unsafe under any circumstance; flag unconditionally. + +### V1.4 Memory Safety (C/C++ scope) + +**V1.4 (L2)**: bounds-checked memory operations. + +* **Modality**: deterministic. +* **Signal**: `strcpy`, `strcat`, `sprintf`, `gets` in C/C++. Recommend `strncpy_s`, `snprintf`, fmtlib. + +--- + +## V2: Validation and Business Logic + +Robust input validation, anti-automation, and protection of logical workflows against circumvention. + +### V2.1 Validation Architecture (documentation prerequisite) + +* **Modality**: agentic. +* **Signal**: documented validation strategy: where validation runs (edge, controller, domain), what the trust boundary is, whether server-side validation is mandatory after any client-side check. +* **Failure**: document missing. + +### V2.2 Centralized Validation + +**V2.2 (L2)**: validation lives in declarative middleware, not scattered ad-hoc checks. + +* **Modality**: hybrid. SAST detects schema validators (Joi, Zod, Pydantic, Bean Validation, FluentValidation). Agent verifies every controller is covered. +* **Signal (deterministic)**: presence of validation middleware on routes; absence of `req.body` direct access bypassing validation. + +### V2.3 Business Logic Integrity + +**V2.3 (L2)**: state machines cannot be bypassed by skipping steps. + +* **Modality**: agentic. +* **Signal**: the agent reads the documented business workflow, then traces controllers to verify state transitions check prior state. Common failure: `POST /checkout/finalize` does not verify `cart.state === 'PAYMENT_VERIFIED'`. +* **False positives**: legitimate admin override paths. The agent must read the policy to distinguish. + +### V2.4 Anti-Automation + +**V2.4 (L2)**: anti-automation controls on credential, registration, and high-value endpoints. + +* **Modality**: hybrid. Deterministic detection of rate-limit middleware, CAPTCHA invocation, lockout configuration. Runtime effectiveness is extrinsic (DAST or production telemetry). +* **Signal**: rate-limit annotations or middleware on `/login`, `/register`, `/forgot-password`, payment endpoints. + +--- + +## V3: Web Frontend Security (new in v5.0.0) + +Browser-side protections, CSP, secure cookies, origin separation, external resource integrity. + +### V3.1 Frontend Security Decisions (documentation prerequisite) + +Required: CSP policy, cookie strategy, framing strategy, COOP/COEP/CORP posture, third-party script inventory. + +### V3.2 HTTP Security Headers + +**V3.2 (L1)**: security headers present. + +* **Modality**: deterministic. +* **Signal**: configuration parsing of Nginx/Apache/middleware (Helmet for Express, Spring Security headers, ASP.NET headers middleware). Required: `Strict-Transport-Security` (with `max-age >= 31536000`, `includeSubDomains`), `X-Content-Type-Options: nosniff`, `Referrer-Policy`, `Content-Security-Policy`. +* **False positives**: dev-only configs not deployed; check the production config path. + +### V3.3 Content Security Policy + +**V3.3 (L2)**: CSP without `unsafe-inline` or `unsafe-eval` in script-src. + +* **Modality**: deterministic with caveats. +* **Signal**: parse the `Content-Security-Policy` header. Flag `unsafe-inline`, `unsafe-eval`, wildcard `*` in `script-src` or `default-src`. Hashes and nonces are acceptable. + +### V3.4 Cookie Attributes + +**V3.4 (L1)**: session cookies have `HttpOnly`, `Secure`, `SameSite=Lax` or stricter. + +* **Modality**: deterministic. +* **Signal**: cookie configuration in session middleware, framework session config, or `Set-Cookie` literal strings. Flag missing `HttpOnly`, missing `Secure`, `SameSite=None` without `Secure`. + +### V3.5 CORS + +**V3.5 (L2)**: CORS does not combine `Access-Control-Allow-Origin: *` with `Access-Control-Allow-Credentials: true`. Origin allow-lists are explicit, not wildcarded for authenticated endpoints. + +* **Modality**: deterministic. +* **Signal**: CORS middleware config. The `*` + `credentials: true` combination is browser-blocked but indicates a fundamental misunderstanding; flag aggressively. + +--- + +## V4: API and Web Service + +REST, GraphQL, WebSocket message structure validation; generic web service security. + +### V4.1 API Surface Documentation (prerequisite) + +* **Signal**: `openapi.yaml` / `swagger.json` / `schema.graphql` present. Agent uses these to enumerate the attack surface. + +### V4.2 Schema Validation + +**V4.2 (L1)**: requests validate against the published schema. + +* **Modality**: deterministic. +* **Signal**: schema-validating middleware (`express-openapi-validator`, `connexion`, Spring `@Valid`, FastAPI Pydantic models). + +### V4.3 GraphQL Specifics + +**V4.3 (L2)**: query depth and complexity limits; introspection disabled in production. + +* **Modality**: deterministic. +* **Signal**: presence of depth-limit / complexity-limit plugins (`graphql-depth-limit`, `graphql-cost-analysis`). Production config sets `introspection: false`. + +### V4.4 WebSocket + +**V4.4 (L2)**: WebSocket message handlers validate state and authorization on every message, not only at handshake. + +* **Modality**: agentic. +* **Signal**: agent reads handler functions, checks for per-message auth or state validation. Common failure: handshake-only auth allows a hijacked connection to issue privileged messages indefinitely. + +### V4.5 Mass Assignment + +**V4.5 (L2)**: object updates use allow-list field binding, not whole-object hydration from request body. + +* **Modality**: hybrid. +* **Signal**: `User.update(req.body)` patterns; absence of `pick`/`omit`/DTO mapping. Especially dangerous on user/role objects where a client-supplied `role: 'admin'` in body bypasses authorization. + +--- + +## V5: File Handling + +Upload processing, content inspection, storage isolation, safe download delivery. + +### V5.1 File Handling Decisions (prerequisite) + +Required: allowed types, size limits, storage location, virus scan policy, serving strategy (direct / proxied / signed URL). + +### V5.2 Upload Validation + +**V5.2 (L1)**: file uploads validate content type by inspection, not extension or `Content-Type` header alone. + +* **Modality**: deterministic. +* **Signal**: presence of magic-number check (`file-type` / `python-magic` / Apache Tika). Flag uploads accepted on `req.file.mimetype` alone. + +### V5.3 Path Traversal + +**V5.3 (L1)**: filesystem paths constructed from upload metadata are sandboxed. + +* **Modality**: deterministic. +* **Signal**: `path.join(uploadDir, req.body.filename)` or equivalent without normalization. Required: canonicalize and verify resulting path remains within `uploadDir`. Flag `../` permitted in resolved path. + +### V5.4 Storage Isolation + +**V5.4 (L2)**: uploaded files served from a domain or path that does not execute server-side code. + +* **Modality**: hybrid. +* **Signal (deterministic)**: cloud storage IaC. Bucket has `block_public_acls = true`, `block_public_policy = true`, encryption at rest, no public list permission. Bucket policy denies execution of uploaded content (no Lambda triggers on user uploads without signature). +* **Common failure**: uploads served from `/uploads/` under the application origin, allowing stored XSS or HTML smuggling. + +### V5.5 Antivirus / Content Scan + +**V5.5 (L2)**: malware scanning on accepted uploads. + +* **Modality**: agentic for whether scan occurs before user-visible storage; deterministic for the presence of a scanner integration (ClamAV, S3 + GuardDuty Malware Protection, third-party API). + +--- + +## Cross-references + +* For agentic prompt templates against V2 (business logic) and V8 (authorization): `violations-and-tools.md`. +* For NIST/CIS/ISO/SOC 2 mappings of these requirements: `cross-framework.md`. +* For canonical document file paths the pre-flight searches: `canonical-documents.md`. diff --git a/.claude/skills/owasp-asvs-v5-compliance/references/identity-chapters.md b/.claude/skills/owasp-asvs-v5-compliance/references/identity-chapters.md new file mode 100644 index 00000000..7eb27132 --- /dev/null +++ b/.claude/skills/owasp-asvs-v5-compliance/references/identity-chapters.md @@ -0,0 +1,228 @@ +# ASVS v5.0.0 Chapters V6 through V10: Identity and Access + +Detailed catalog for the chapters governing the entire identity lifecycle: authentication, session, authorization, self-contained tokens, OAuth/OIDC. V8 (Authorization) is the highest-leverage chapter for agentic verification; broken access control is the #1 OWASP Top 10 entry and is largely invisible to deterministic SAST. + +--- + +## V6: Authentication + +Identity proofing, password security, MFA, identity provider integration. + +### V6.1 Authentication Decisions (documentation prerequisite) + +Required: authentication factors per assurance level, IdP relationships, password policy, MFA enrollment flow, account recovery flow, session establishment semantics. + +* **Modality**: agentic. +* **Failure**: document missing. Halt V6 verification. + +### V6.2 Password Security + +**V6.2.1 (L1)**: passwords stored using a memory-hard or work-factor-tunable hash with salt. + +* **Modality**: deterministic. +* **Signal**: hash function invocation. Acceptable: Argon2id (preferred), bcrypt with cost >= 12, scrypt with appropriate parameters, PBKDF2-HMAC-SHA256 with iterations >= 600,000 (OWASP 2023 baseline). +* **Failure patterns**: `MD5(password)`, `SHA1(password)`, `SHA256(password)` without HMAC + salt, `crypt()` without specifier, custom-rolled hashing, plaintext storage. +* **Cross-framework**: NIST IA-5, ISO A.5.17, SOC 2 CC6.1. + +**V6.2.2 (L1)**: password length minimum 8 (L1) / 12 (L2); no composition rules (no forced character classes); breach-list check on creation. + +* **Modality**: deterministic. +* **Signal**: validation rules in registration / password-change handlers. Flag patterns enforcing uppercase + digit + symbol counts; recommend HaveIBeenPwned k-anonymity check. + +### V6.3 Multi-Factor Authentication + +**V6.3 (L2)**: MFA available for all users; required for privileged accounts and sensitive operations. + +* **Modality**: hybrid. +* **Signal (deterministic)**: presence of TOTP / WebAuthn / push library; route protection middleware that enforces MFA for admin paths. +* **Signal (agentic)**: agent reads `authentication-policy.md` to determine which roles MUST have MFA and verifies enforcement matches. +* **Failure pattern**: MFA enabled at the user level but not enforced at sensitive endpoints (e.g., `/admin/*` does not require an active MFA assertion). + +### V6.4 Account Recovery + +**V6.4 (L2)**: recovery does not weaken the authentication factor. Recovery tokens are single-use, time-limited (<= 60 minutes), bound to the requesting context. + +* **Modality**: deterministic. +* **Signal**: token TTL configuration; single-use semantics (token is invalidated on first redemption, before the password mutation occurs). + +### V6.5 Credential Storage + +**V6.5 (L2)**: credentials at rest are encrypted; transport is TLS-only. + +* **Modality**: hybrid; cross-references V12. + +--- + +## V7: Session Management + +Session lifecycle, timeouts, secure termination, federated re-authentication, defense against hijacking. + +### V7.1 Session Decisions (documentation prerequisite) + +Required: idle timeout, absolute timeout, re-authentication thresholds for sensitive operations, federated session relationship to IdP. + +### V7.2 Session Identifier Generation + +**V7.2 (L1)**: session identifiers are cryptographically random, at least 64 bits of entropy. + +* **Modality**: deterministic. +* **Signal**: framework session middleware uses CSPRNG. Flag custom session IDs built from `Math.random()`, timestamps, or user attributes. + +### V7.3 Timeout + +**V7.3 (L2)**: idle timeout enforced server-side; absolute timeout independent of activity. + +* **Modality**: hybrid. +* **Signal (deterministic)**: session config values (e.g., `cookie.maxAge`, framework session timeout). Compare against the documented value in `session-policy.md`. +* **Signal (agentic)**: agent verifies the timeout value matches policy. Flag JWTs with `expiresIn` exceeding the documented session lifetime, e.g., `jwt.sign(payload, secret, { expiresIn: '10y' })` against a policy of 8h. + +### V7.4 Session Termination + +**V7.4.1 (L2)**: logout invalidates the session server-side. + +* **Modality**: agentic. +* **Signal**: agent reads the logout controller. Required: server-side session destruction or token revocation list update. Failure: client-side cookie deletion only, with server-side session record still valid. +* **For JWTs**: short access token TTL + revocation list for refresh tokens; or rotate signing keys; or accept the architectural tradeoff and document it. + +### V7.5 Re-Authentication + +**V7.5 (L2)**: sensitive operations (password change, MFA enrollment, payment authorization) require recent authentication, not merely an active session. + +* **Modality**: agentic. +* **Signal**: agent verifies sensitive endpoints check a `last_auth_time` claim or trigger a step-up flow. + +--- + +## V8: Authorization + +The most important chapter for agentic verification. Broken access control and IDOR cannot be detected by syntax alone. + +### V8.1 Authorization Documentation (documentation prerequisite, MANDATORY) + +Required: role hierarchy, permission matrix, data ownership model, resource-to-owner relationships, attribute-based access control (ABAC) rules if applicable. + +* **Modality**: agentic. +* **Failure**: document missing. Halt V8 verification entirely. Without an ownership model the agent cannot reason about IDOR. + +### V8.2 Operation-Level Authorization + +**V8.2.1 (L2)**: every state-changing endpoint enforces server-side authorization. + +* **Modality**: agentic. +* **Signal**: agent enumerates routes from OpenAPI/router config, identifies state-changing methods (POST, PUT, PATCH, DELETE), and verifies each route invokes an authorization middleware or explicit check before the mutation. +* **Failure pattern**: `app.post('/api/updateRole', (req, res) => { db.users.update(req.body.userId, { role: req.body.role }) })` with no `requireAdmin` middleware. The developer relied on the frontend hiding the UI button. Frontend-only access control is the canonical broken access control failure. + +**V8.2.2 (L2)**: IDOR / direct object reference protection. + +* **Modality**: agentic. +* **Signal**: routes accepting an object identifier (`/api/user/:userId/financial`, `/api/order/:orderId`, `/api/document/:docId`) verify the requesting user's relationship to the resource. Required: explicit ownership check or scoped query (`SELECT * FROM orders WHERE id = ? AND user_id = ?`). +* **Failure pattern**: scoped query absent; ownership check absent; reliance on the identifier being unguessable (UUIDs help but do not satisfy the requirement). + +### V8.3 Privilege Escalation + +**V8.3 (L2)**: vertical privilege escalation prevented; role assignments cannot be modified by the holder. + +* **Modality**: agentic. +* **Signal**: agent reviews role-mutation endpoints. Required: role changes are audit-logged; the modifying user has higher privilege than both the source and target role; users cannot self-elevate. + +### V8.4 Multi-Tenant Isolation + +**V8.4 (L2)**: tenant boundary enforced at the data layer. + +* **Modality**: agentic. +* **Signal**: every query against tenant-scoped tables includes a `WHERE tenant_id = ?` clause matching the authenticated tenant. Row-Level Security (Postgres RLS, Supabase RLS) policies present and tested. +* **Failure pattern**: tenant ID derived from request body or query parameter rather than from the authenticated session. + +--- + +## V9: Self-Contained Tokens (new in v5.0.0) + +Validation of source, cryptographic integrity, and content payload of stateless tokens, predominantly JWTs. + +### V9.1 JWT Algorithm Pinning + +**V9.1.1 (L1)**: token verification pins the algorithm. + +* **Modality**: deterministic. +* **Signal**: JWT verification calls explicitly specify `algorithms: ['RS256']` or `['ES256']` or `['EdDSA']`. Flag `jwt.verify(token, key)` without the algorithms parameter (library defaults vary; some accept the algorithm declared in the token header, enabling the algorithm-confusion attack). +* **Hard failure**: any code path accepting `alg: none`. Flag unconditionally. + +### V9.1.2 (L1): no key confusion between asymmetric and symmetric. + +* **Signal**: when using RS256 / ES256, the verification key is loaded as a public key (PEM, JWK), never reused as an HMAC secret. Flag patterns where a public key is also passed to HS256 verification, enabling the classic algorithm-confusion attack. + +### V9.2 JWT Claims Validation + +**V9.2 (L2)**: tokens verify `iss`, `aud`, `exp`, `nbf`, `iat`. The audience claim matches the validating service. + +* **Modality**: deterministic. +* **Signal**: verification config sets `issuer`, `audience` (or library equivalent). Flag verification that ignores audience. + +### V9.3 Key Management + +**V9.3 (L1)**: signing keys are not hardcoded. + +* **Modality**: deterministic. +* **Signal**: GitLeaks entropy-based detection of high-entropy strings near `jwt.sign` calls. Required: keys loaded from environment variables, secret manager, or KMS. +* **Failure pattern**: `const SECRET = "supersecretkey123"`. Also flag committed `.env` files containing JWT secrets. + +### V9.4 Token Lifetime + +**V9.4 (L2)**: access tokens are short-lived (typically <= 15 minutes). Refresh tokens are stored server-side and rotated. + +* **Modality**: hybrid. +* **Signal (deterministic)**: `expiresIn` value at signing time. Compare against `session-policy.md`. + +--- + +## V10: OAuth and OIDC (new in v5.0.0) + +Authorization flow security, OAuth client configuration, resource server policies, consent management. + +### V10.1 OAuth Decisions (prerequisite) + +Required: client type per integration (public / confidential), grant types in use, scope catalog, consent semantics, IdP relationships. + +### V10.2 PKCE + +**V10.2.1 (L1)**: public clients use PKCE (Proof Key for Code Exchange). + +* **Modality**: deterministic. +* **Signal**: OAuth client library configuration. Required for any non-confidential client (SPA, mobile, native): `code_verifier` and `code_challenge` (with `code_challenge_method=S256`) participate in the flow. +* **L2**: PKCE for confidential clients as defense-in-depth. + +### V10.3 State Parameter + +**V10.3.1 (L1)**: the `state` parameter is generated, sent on authorization request, and verified on callback. + +* **Modality**: deterministic. +* **Signal**: state generation uses CSPRNG; callback handler compares received state to the bound session value before exchanging the code. +* **Failure pattern**: state generated but not validated; state set but never compared on callback. This enables CSRF against the OAuth flow. + +### V10.4 Redirect URI Validation + +**V10.4 (L1)**: the IdP-side redirect URI allow-list is exact-match, no wildcards in path or origin. + +* **Modality**: extrinsic for the IdP config (cannot read from repo if IdP is external); deterministic for self-hosted IdP config files. +* **Signal**: client registration / IdP config artifacts. + +### V10.5 Token Storage + +**V10.5 (L2)**: tokens are not stored in `localStorage` (XSS-readable). Acceptable storage: HttpOnly Secure cookies, in-memory for SPAs paired with refresh-token rotation. + +* **Modality**: deterministic. +* **Signal**: `localStorage.setItem('access_token', ...)` or equivalent. Flag. + +### V10.6 Resource Server Validation + +**V10.6 (L2)**: resource servers validate tokens (V9 applies), check scope claims against the operation, and validate the token's audience matches the resource server. + +* **Modality**: hybrid. + +--- + +## Cross-references + +* The V8 broken access control prompt template, fully worked: `violations-and-tools.md`. +* JWT algorithm-confusion AST pattern in detail: `violations-and-tools.md`. +* Mappings to NIST IA-2, IA-5, AC-3, IA-11; ISO A.5.15 to A.5.18; SOC 2 CC6.1: `cross-framework.md`. diff --git a/.claude/skills/owasp-asvs-v5-compliance/references/platform-chapters.md b/.claude/skills/owasp-asvs-v5-compliance/references/platform-chapters.md new file mode 100644 index 00000000..6fa1d722 --- /dev/null +++ b/.claude/skills/owasp-asvs-v5-compliance/references/platform-chapters.md @@ -0,0 +1,278 @@ +# ASVS v5.0.0 Chapters V11 through V17: Platform, Crypto, Resilience + +Detailed catalog for the chapters governing cryptographic primitives, infrastructure configuration, data privacy, secure coding paradigms, security logging, and WebRTC. + +--- + +## V11: Cryptography + +Encryption algorithms, hashing, RNG, public key infrastructure. + +### V11.1 Cryptographic Inventory (documentation prerequisite) + +Required: full inventory of cryptographic operations in the application, algorithm choices, key lifecycle (generation, rotation, destruction), key storage location, post-quantum readiness assessment. + +* **Modality**: agentic. +* **Failure**: document missing. Halt V11 verification. + +### V11.2 Algorithm Selection + +**V11.2.1 (L1)**: only approved algorithms in use. + +* **Modality**: deterministic. +* **Signal**: algorithm string literals in cipher / hash invocations. +* **Approved (2025 baseline)**: + * Symmetric: AES-256-GCM, AES-256-CBC with HMAC, ChaCha20-Poly1305. + * Asymmetric: RSA >= 2048 (>= 3072 preferred), ECDSA P-256/P-384, Ed25519. + * Hash: SHA-256, SHA-384, SHA-512, SHA-3. + * Password: Argon2id, bcrypt (cost >= 12), scrypt, PBKDF2 (iterations >= 600,000). +* **Hard failures (flag unconditionally)**: DES, 3DES, RC4, MD5 (except for non-security checksums; agent verifies context), SHA-1 for signatures, ECB mode for any cipher. +* **Patterns**: + * Java: `Cipher.getInstance("DES/...")`, `Cipher.getInstance("AES/ECB/...")`, `MessageDigest.getInstance("MD5")` in security context. + * Python: `Crypto.Cipher.DES`, `algorithms.ARC4()`, `hashlib.md5()` in security context. + * Node: `crypto.createCipheriv('des-...', ...)`, `crypto.createHash('md5')` in security context. + * Go: `crypto/des`, `crypto/rc4`. + +### V11.3 Random Number Generation + +**V11.3.1 (L1)**: security-relevant randomness uses CSPRNG. + +* **Modality**: deterministic. +* **Signal**: token / nonce / salt generation. Flag `Math.random()`, `java.util.Random`, Python `random` module, Go `math/rand` in security contexts. +* **Approved**: `crypto.randomBytes` (Node), `secrets` module (Python), `java.security.SecureRandom`, `crypto/rand` (Go). +* **False positives**: `Math.random()` for non-security UI animation, A/B test bucketing where collision is acceptable. Agent disambiguates by context. + +### V11.4 IV / Nonce Reuse + +**V11.4 (L2)**: IVs and nonces are not reused under the same key. + +* **Modality**: deterministic with limits. +* **Signal**: hardcoded IV literal passed to AES-GCM, AES-CTR, ChaCha20. Flag `Buffer.alloc(12, 0)` or similar zero-filled IV passed to authenticated encryption. + +### V11.5 Key Storage + +**V11.5 (L1)**: keys are not in source. + +* **Modality**: deterministic. +* **Signal**: GitLeaks + Trivy secrets scanning. Cross-reference V13. + +--- + +## V12: Secure Communication + +TLS, certificate validation, secure communication channel configuration. + +### V12.1 Transport Layer Security + +**V12.1.1 (L1)**: HTTPS enforced; HTTP redirects to HTTPS. + +* **Modality**: deterministic. +* **Signal**: IaC parsing. + * Kubernetes Ingress: `nginx.ingress.kubernetes.io/force-ssl-redirect: "true"` or `ssl-redirect: "true"`. + * AWS ALB: listener on 80 with redirect action to 443. + * Cloudflare: `always_use_https = true`. + * Application middleware: HSTS-aware redirect. +* **Failure pattern**: HTTP listener serving content directly; missing redirect rule. + +**V12.1.2 (L2)**: TLS 1.2 minimum, TLS 1.3 preferred. TLS 1.0 / 1.1 / SSLv3 disabled. + +* **Modality**: deterministic. +* **Signal**: TLS protocol configuration in load balancer policy, web server config, application config. + +### V12.2 Certificate Validation + +**V12.2 (L1)**: outbound HTTPS clients validate certificates. + +* **Modality**: deterministic. +* **Signal**: HTTP client configuration. Flag `rejectUnauthorized: false` (Node), `verify=False` (Python requests), `InsecureSkipVerify: true` (Go), `-k` / `--insecure` in shell scripts. Production code should never disable verification; flag aggressively. +* **False positives**: test fixtures, local-dev configs guarded by environment checks. Agent verifies guard. + +### V12.3 Internal Service Communication + +**V12.3 (L2)**: internal service-to-service traffic is encrypted (mTLS or service mesh). + +* **Modality**: hybrid. +* **Signal**: service mesh config (Istio PeerAuthentication, Linkerd policy), or explicit TLS in client config for internal endpoints. + +--- + +## V13: Configuration + +Application frameworks, third-party libraries, environment variables, build pipelines. + +### V13.1 Dependency Management (SCA) + +**V13.1.1 (L1)**: no known-vulnerable dependencies at high or critical severity. + +* **Modality**: deterministic. +* **Signal**: Trivy / Snyk / OSV-Scanner output cross-referenced against NVD CVE feed. +* **Manifest scope**: `package-lock.json`, `pom.xml`, `go.sum`, `Cargo.lock`, `Gemfile.lock`, `requirements.txt` with pinned versions, `pyproject.toml`. +* **Canonical examples**: `log4j-core` < 2.17.1 (Log4Shell), `lodash` versions vulnerable to prototype pollution, `xz-utils` 5.6.0/5.6.1 (CVE-2024-3094 backdoor). + +### V13.2 Pipeline Hardening + +**V13.2 (L2)**: CI/CD pipelines pin actions/images by SHA, not floating tags. + +* **Modality**: deterministic. +* **Signal**: `.github/workflows/*.yml` references using `@v3` (mutable) versus `@` (immutable). Recommend SHA pinning for third-party actions, especially those with secrets access. + +### V13.3 Secret Storage + +**V13.3.1 (L1)**: no hardcoded secrets. + +* **Modality**: deterministic. +* **Signal**: GitLeaks (entropy + regex), Trivy secrets, custom Semgrep rules for known secret formats (AWS keys, GCP service account JSONs, Stripe keys, Slack webhooks). +* **False positives**: example values, test fixtures, public keys. Configure `.gitleaksignore` for known-safe paths. + +**V13.3.2 (L2)**: secrets are scoped, rotated, and revocable. + +* **Modality**: agentic. +* **Signal**: agent reads secret-management policy and verifies the application loads from a manager (AWS Secrets Manager, Vault, GCP Secret Manager, Doppler) rather than long-lived environment variables. + +### V13.4 Configuration Defaults + +**V13.4 (L1)**: production configuration disables debug, verbose error pages, default credentials. + +* **Modality**: deterministic. +* **Signal**: framework debug flags. `DEBUG = True` in Django production config, `app.debug = True` in Flask, `NODE_ENV !== 'production'` paths reachable in production. Default admin credentials in seed data files. + +--- + +## V14: Data Protection + +Sensitive data at rest, in transit, on the client; data retention; privacy. + +### V14.1 Data Classification (prerequisite) + +Required: data inventory, sensitivity tiers (Public, Internal, Confidential, Restricted), retention policy, deletion procedure. + +### V14.2 Encryption at Rest + +**V14.2 (L2)**: data classified Confidential or Restricted is encrypted at rest. + +* **Modality**: hybrid. +* **Signal (deterministic)**: storage IaC. Cloud bucket encryption flags (`server_side_encryption_configuration`), database encryption settings (`storage_encrypted = true` for RDS, transparent data encryption for SQL Server), volume encryption. +* **Signal (agentic)**: agent reads data classification, identifies fields tagged Confidential or Restricted in the schema, verifies the encryption pathway for those fields. + +### V14.3 Data Minimization + +**V14.3 (L2)**: only necessary data is collected and retained. + +* **Modality**: agentic. +* **Signal**: agent reviews API responses and database schema against the data inventory. Flags fields collected but not used or retained beyond the documented retention window. + +### V14.4 Sensitive Data in Logs + +**V14.4 (L1)**: sensitive data is not written to logs. + +* **Modality**: hybrid. +* **Signal (deterministic)**: log statements containing variables named `password`, `token`, `ssn`, `cardNumber`, `api_key`. Custom Semgrep rules per data classification tags. +* **Signal (agentic)**: agent reads logging middleware to verify PII redaction is centralized. + +### V14.5 Client-Side Storage + +**V14.5 (L2)**: sensitive data is not persisted in `localStorage`, `sessionStorage`, or IndexedDB unless encrypted with a per-session key not stored alongside. + +* **Modality**: deterministic. +* **Signal**: `localStorage.setItem` calls with sensitive payloads (cross-references V10.5). + +--- + +## V15: Secure Coding + +Defensive coding patterns, memory safety, resilient architecture. + +### V15.1 Dynamic Code Execution + +**V15.1 (L1)**: no dynamic evaluation of user input. + +* **Modality**: deterministic. +* **Signal**: `eval()`, `Function()` constructor with concatenated input, `setTimeout(string, ...)` / `setInterval(string, ...)` (string form), Python `exec()` / `eval()`, Ruby `eval` / `instance_eval`, PHP `eval`. + +### V15.2 Type Safety + +**V15.2 (L2)**: language type guarantees are not subverted. + +* **Modality**: deterministic. +* **Signal**: TypeScript `any` / `as any` in security-sensitive paths, `unsafe` blocks in Rust without justification comment, JNI / FFI calls without bounds documentation. + +### V15.3 Memory Safety (C/C++ scope) + +**V15.3 (L2)**: pointer arithmetic is bounds-checked; manual memory management uses RAII or smart pointers. + +* **Modality**: deterministic. +* **Signal**: raw `new` / `delete`, raw `malloc` / `free`, manual buffer arithmetic. Recommend `std::unique_ptr`, `std::span`, `std::string`. + +--- + +## V16: Security Logging + +Auditable security events, safe error handling, prevention of sensitive data leakage. + +### V16.1 Security Event Logging + +**V16.1 (L2)**: authentication, authorization, and high-impact operations are logged with timestamp, actor, action, target, outcome. + +* **Modality**: agentic. +* **Signal**: agent reviews authentication and authorization paths for explicit logging calls. Verifies log schema includes the required fields. Flags critical-event paths missing log emission. + +### V16.2 Error Handling + +**V16.2 (L1)**: errors do not leak sensitive details to clients. + +* **Modality**: deterministic. +* **Signal**: catch blocks that pass `error.stack`, `error.message` raw to HTTP response. Flag `res.status(500).send(err)` patterns, `res.json({ error: err.toString() })`. Production must return generic error identifiers; full detail goes to server-side logs only. + +### V16.3 Log Integrity + +**V16.3 (L2)**: logs are protected against tampering and unauthorized access. + +* **Modality**: hybrid. +* **Signal**: external log shipping configuration (Datadog, Splunk, CloudWatch). Append-only retention. Application service account does not have log-deletion permission on the log store. + +### V16.4 PII in Logs + +**V16.4 (L1)**: PII is masked or omitted in log output. + +* **Modality**: hybrid; cross-references V14.4. + +--- + +## V17: WebRTC (new in v5.0.0) + +Media streams, signaling protocols, TURN/STUN server controls. + +### V17.1 Transport Security + +**V17.1 (L1)**: SRTP for media; DTLS for the SCTP / data channel handshake. + +* **Modality**: deterministic. +* **Signal**: WebRTC peer-connection configuration. RTCConfiguration includes ICE servers over TURNS (TURN over TLS) or STUN over secured channel. SDP negotiation enforces SRTP profiles (`RTP/SAVPF`), not unencrypted `RTP/AVPF`. + +### V17.2 Signaling Channel + +**V17.2 (L1)**: signaling occurs over WSS (WebSocket Secure) or HTTPS. + +* **Modality**: deterministic. +* **Signal**: signaling client uses `wss://` / `https://`, never `ws://` / `http://`. + +### V17.3 TURN Authentication + +**V17.3 (L2)**: TURN credentials are short-lived (ephemeral, e.g., HMAC-based time-limited credentials), not long-lived shared secrets. + +* **Modality**: deterministic. +* **Signal**: TURN credential generation logic. Flag long-lived static TURN passwords in config. + +### V17.4 Media Permission Lifecycle + +**V17.4 (L2)**: camera/microphone permission is requested per session, with explicit user gesture, and released on disconnect. + +* **Modality**: agentic. +* **Signal**: `getUserMedia` invocations and corresponding `stop()` calls on tracks during teardown. + +--- + +## Cross-references + +* For NIST/CIS/ISO/SOC 2 mappings: `cross-framework.md`. +* For tool orchestration patterns covering V11 (Semgrep crypto rules), V13 (Trivy + GitLeaks), V12 (IaC parsing): `violations-and-tools.md`. diff --git a/.claude/skills/owasp-asvs-v5-compliance/references/violations-and-tools.md b/.claude/skills/owasp-asvs-v5-compliance/references/violations-and-tools.md new file mode 100644 index 00000000..da2e074b --- /dev/null +++ b/.claude/skills/owasp-asvs-v5-compliance/references/violations-and-tools.md @@ -0,0 +1,492 @@ +# Violation Patterns and Toolchain Orchestration + +This file is the operational manual: real-world failure patterns mapped to ASVS requirements, tool capabilities and gaps, and the agentic prompt templates that bridge the deterministic / semantic boundary. + +## Table of contents + +1. Tool capability and gap matrix +2. Code-level violation patterns by ASVS chapter +3. Configuration-level violation patterns +4. Dependency-level violation patterns +5. Agentic prompt templates (worked examples) +6. Orchestration recipes (CI/CD wiring) + +--- + +## 1. Tool capability and gap matrix + +### Semgrep (Community Edition) + +* **Strengths**: 35+ languages; 4,000+ community rules tagged to OWASP Top 10 2025; semantic pattern matching beyond regex; SARIF + JSON output; fast enough for synchronous PR-time gating. +* **Coverage**: V1 (injection sinks), V11 (algorithm strings), V13 (secret patterns), V15 (eval / dangerous APIs), some V3 (header middleware presence), some V9 (JWT library misuse). +* **Gaps**: no deep inter-procedural taint tracking in CE; no policy-document reasoning; no business logic understanding (V2); no IDOR detection (V8). The gap on V2 and V8 is structural, not a bug. +* **When to use**: deterministic phase, primary engine for AST-based checks. Run with `--config "p/owasp-top-ten" --config "p/security-audit"`. + +### CodeQL + +* **Strengths**: superior taint-tracking accuracy via relational queries over the compiled code-as-database; official curated query suites for high-severity issues; deep cross-procedural analysis where Semgrep CE cannot reach. +* **Coverage**: V1 (deep injection chains), V5 (path traversal across functions), some V8 (where authorization decorators are decorator-pattern enforceable). +* **Gaps**: requires a build for compiled languages (Java, C#, C++, Go); analysis can be slow on large codebases (multi-minute), making synchronous PR gating problematic; cannot read policy documents. +* **When to use**: scheduled deep-scan rather than PR gate, or PR gate only when the diff touches files Semgrep flagged at lower confidence. + +### Trivy + +* **Strengths**: unified scanner for filesystem, container images, IaC, secrets; high-quality CVE feed; SBOM generation; fast. +* **Coverage**: V13 (SCA, secrets, IaC misconfigurations including TLS settings, encryption flags), V12 (IaC TLS), V14.2 (encryption-at-rest IaC checks), V5.4 (storage bucket public-access flags). +* **Gaps**: no application code analysis; no policy reasoning. +* **When to use**: deterministic phase, IaC + dependencies + secrets in one pass. + +### GitLeaks + +* **Strengths**: entropy-based + regex-based secret detection across full Git history; `gitleaks protect` for pre-commit; `gitleaks detect` for CI. +* **Coverage**: V13.3, V11.5 (key storage), V9.3 (JWT secret hardcoding). +* **Gaps**: high false-positive rate on test fixtures and example values without disciplined `.gitleaksignore`. +* **When to use**: deterministic phase, run alongside Trivy; differential coverage (Trivy and GitLeaks find slightly different secret patterns). + +### OWASP ZAP + +* **Strengths**: industry-standard DAST; active scan rules tagged to ASVS; custom scripts in JS/Python/ZEST. +* **Coverage**: runtime aspects of V3 (response headers as observed), V12 (TLS as negotiated), some V4 (API endpoints), some V13 (information disclosure). +* **Gaps**: requires a deployed environment; ZAP's own documentation acknowledges most L2 requirements are not amenable to black-box testing alone; not a repository-only tool. +* **When to use**: post-deploy stage gate, not PR gate. Out of scope for the repository-only scanner this skill primarily describes; mention as the runtime counterpart. + +### Custom Semgrep rules + +For ASVS requirements with no community rule, write custom rules. Pattern: + +```yaml +rules: + - id: asvs-v9-1-1-jwt-no-algorithm-pin + languages: [javascript, typescript] + severity: ERROR + metadata: + asvs: V9.1.1 + asvs_level: L1 + cwe: CWE-345 + message: "JWT verification without explicit algorithm pinning. ASVS V9.1.1 requires algorithm pinning to prevent algorithm-confusion attacks." + pattern-either: + - pattern: jwt.verify($TOKEN, $KEY) + - pattern: jwt.verify($TOKEN, $KEY, $OPTS) + pattern-not: | + jwt.verify($TOKEN, $KEY, { ..., algorithms: [...], ... }) +``` + +Custom rules should always include `metadata.asvs` so the orchestrator can tag findings without re-mapping. + +--- + +## 2. Code-level violation patterns by ASVS chapter + +### V1.2.5 SQL injection + +```python +# FAIL +cursor.execute(f"SELECT * FROM users WHERE id = {user_id}") +cursor.execute("SELECT * FROM users WHERE id = " + user_id) +cursor.execute("SELECT * FROM users WHERE name = '%s'" % name) + +# PASS +cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,)) +``` + +### V1.2.5 OS command injection + +```python +# FAIL +subprocess.Popen(f"convert {filename} output.png", shell=True) +os.system("ping " + host) + +# PASS +subprocess.run(["convert", filename, "output.png"], check=True) +``` + +### V1.3 Unsafe deserialization + +```python +# FAIL +data = pickle.loads(request.body) +config = yaml.load(uploaded_file) # default Loader is unsafe + +# PASS (signature verification) +verify_hmac(request.body, request.headers["x-signature"]) +data = pickle.loads(request.body) + +# PASS (safe loader) +config = yaml.safe_load(uploaded_file) +``` + +### V8.2.1 Broken access control (frontend-only protection) + +```javascript +// FAIL: no server-side check +app.post('/api/users/:id/role', (req, res) => { + db.users.update({ id: req.params.id }, { role: req.body.role }); + res.json({ ok: true }); +}); + +// PASS +app.post('/api/users/:id/role', + requireAuth, + requireRole('admin'), + validateRoleTransition, + async (req, res) => { + await db.users.update({ id: req.params.id }, { role: req.body.role }); + audit.log('role_change', { actor: req.user.id, target: req.params.id, role: req.body.role }); + res.json({ ok: true }); + } +); +``` + +### V8.2.2 IDOR + +```javascript +// FAIL: any authenticated user can read any document +app.get('/api/documents/:id', requireAuth, async (req, res) => { + const doc = await db.documents.findOne({ id: req.params.id }); + res.json(doc); +}); + +// PASS: scoped query +app.get('/api/documents/:id', requireAuth, async (req, res) => { + const doc = await db.documents.findOne({ + id: req.params.id, + ownerId: req.user.id + }); + if (!doc) return res.status(404).end(); + res.json(doc); +}); +``` + +### V9.1 JWT algorithm-confusion + +```javascript +// FAIL: algorithm not pinned +jwt.verify(token, publicKey); // library may accept HS256 with publicKey as the secret + +// FAIL: alg=none accepted +jwt.verify(token, publicKey, { algorithms: ['none'] }); + +// PASS +jwt.verify(token, publicKey, { algorithms: ['RS256'] }); +``` + +### V11.2 Weak cryptography + +```java +// FAIL +Cipher c = Cipher.getInstance("DES/ECB/PKCS5Padding"); +Cipher c = Cipher.getInstance("AES/ECB/PKCS5Padding"); +MessageDigest md = MessageDigest.getInstance("MD5"); + +// PASS +Cipher c = Cipher.getInstance("AES/GCM/NoPadding"); +MessageDigest md = MessageDigest.getInstance("SHA-256"); +``` + +### V11.3 Insecure RNG in security context + +```javascript +// FAIL +const token = Math.random().toString(36).substring(2); + +// PASS +const token = crypto.randomBytes(32).toString('hex'); +``` + +### V15.1 Dynamic code execution + +```javascript +// FAIL +setTimeout("doStuff(" + userInput + ")", 100); +new Function('x', userInput)(); + +// PASS +setTimeout(() => doStuff(safeArg), 100); +``` + +### V16.2 Sensitive error leakage + +```javascript +// FAIL +app.use((err, req, res, next) => { + res.status(500).json({ error: err.stack }); +}); + +// PASS +app.use((err, req, res, next) => { + const id = uuid.v4(); + logger.error({ id, err }); + res.status(500).json({ error: 'Internal error', incident_id: id }); +}); +``` + +--- + +## 3. Configuration-level violation patterns + +### V3.2 Missing security headers (Express + Helmet) + +```javascript +// FAIL +const app = express(); +app.use(express.json()); +// no helmet, no manual headers + +// PASS +const app = express(); +app.use(helmet({ + contentSecurityPolicy: { directives: { /* explicit */ } }, + hsts: { maxAge: 31536000, includeSubDomains: true, preload: true } +})); +``` + +### V3.4 Cookie attributes + +```javascript +// FAIL +res.cookie('session', sessionId); +res.cookie('session', sessionId, { secure: false, httpOnly: false }); + +// PASS +res.cookie('session', sessionId, { + httpOnly: true, + secure: true, + sameSite: 'lax', + maxAge: 8 * 60 * 60 * 1000 +}); +``` + +### V3.5 CORS misconfiguration + +```javascript +// FAIL +app.use(cors({ origin: '*', credentials: true })); // browser-blocked but indicates misunderstanding + +// PASS +app.use(cors({ + origin: ['https://app.example.com', 'https://admin.example.com'], + credentials: true +})); +``` + +### V12.1 Kubernetes Ingress without HTTPS redirect + +```yaml +# FAIL: no force-ssl-redirect annotation +metadata: + name: app-ingress + +# PASS +metadata: + name: app-ingress + annotations: + nginx.ingress.kubernetes.io/force-ssl-redirect: "true" + nginx.ingress.kubernetes.io/ssl-protocols: "TLSv1.2 TLSv1.3" +``` + +### V13.4 Production debug enabled + +```python +# FAIL: Django settings.py +DEBUG = True +ALLOWED_HOSTS = ['*'] + +# PASS +DEBUG = os.environ.get('DJANGO_DEBUG', 'False').lower() == 'true' +ALLOWED_HOSTS = os.environ.get('DJANGO_ALLOWED_HOSTS', '').split(',') +``` + +### V14.2 Unencrypted storage (Terraform) + +```hcl +# FAIL +resource "aws_db_instance" "primary" { + storage_encrypted = false + # or absent (default depends on instance class) +} + +# PASS +resource "aws_db_instance" "primary" { + storage_encrypted = true + kms_key_id = aws_kms_key.rds.arn +} +``` + +--- + +## 4. Dependency-level violation patterns + +* `log4j-core` < 2.17.1 (Log4Shell, CVE-2021-44228 and follow-ons): V13.1 critical. +* `lodash` < 4.17.21 (prototype pollution): V13.1. +* `xz-utils` 5.6.0 / 5.6.1 (CVE-2024-3094 supply-chain backdoor): V13.1. +* `spring-core` versions vulnerable to Spring4Shell (CVE-2022-22965): V13.1. +* `jackson-databind` versions with deserialization gadgets: V1.3 and V13.1. +* `colors.js` and `faker.js` 2022 sabotage: V13.1 (illustrates supply-chain pinning value, V13.2). + +Trivy + the OSV database cover these. For organizations on long-term support branches, validate that backports actually patched the issue rather than the version string lying about it. + +--- + +## 5. Agentic prompt templates (worked examples) + +### V8.2.1 Broken access control (full template) + +```text +SYSTEM: +You are an Application Security Architect verifying OWASP ASVS v5.0.0 Level 2 compliance against an application's Documented Security Decisions. + +You will receive: +1. A constraint extracted from docs/security/authorization-policy.md +2. A list of route handlers from src/controllers/ +3. A reference to the authorization middleware in src/middleware/ + +Your task is to determine whether each route enforces the constraint. Output ONLY a JSON array. + +Schema: +[ + { + "route": "", + "asvs_id": "V8.2.1", + "compliant": true | false | null, + "evidence_lines": [, ...], + "policy_clause": "", + "justification": "", + "remediation": "" + } +] + +Rules: +- compliant=null means you cannot determine from the provided files. Specify what file you need. +- Frontend hiding of UI elements is NOT compliance. Server-side enforcement is required. +- A scoped database query that filters by ownership IS compliance, even without an explicit middleware. +- Policy must be quoted verbatim, not paraphrased. + +USER: +Constraint: +"All endpoints returning user-scoped resources must verify the requesting user's ownership of the resource before serialization. Ownership is established by req.user.id matching the resource.owner_id field, or by a scoped query that filters on owner_id." +Source: docs/security/authorization-policy.md §3.2 + +Routes: +{enumerated_route_list} + +Middleware definitions: +{middleware_file_contents} + +Authorization matrix: +{authorization_matrix_csv} +``` + +### V2 Business logic bypass (template) + +```text +SYSTEM: +You are verifying OWASP ASVS v5.0.0 V2.3 (Business Logic Integrity). + +You will receive a documented workflow and the controller code that implements it. Determine whether any state-skipping or replay attack is possible. + +Output JSON: +{ + "asvs_id": "V2.3", + "compliant": , + "attack_paths": [ + {"description": "", "evidence_lines": [, ...]} + ], + "remediation": "" +} + +Rules: +- A state machine bypass exists if any controller can be invoked in an order other than the documented sequence without a server-side check rejecting the out-of-order call. +- A replay attack exists if a successful operation can be repeated using captured request data with the same effect. + +USER: +Documented workflow (from docs/business-logic/checkout.md): +{workflow_text} + +Controllers implementing the workflow: +{controller_files} +``` + +--- + +## 6. Orchestration recipes + +### Minimal CI invocation (GitHub Actions) + +```yaml +name: ASVS L2 Audit +on: + pull_request: + push: + branches: [main] + +jobs: + audit: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@ # pin per V13.2 + with: { fetch-depth: 0 } + + - name: Pre-flight (canonical document set) + run: python scripts/preflight.py + + - name: Semgrep + run: | + pip install semgrep + semgrep scan --config "p/owasp-top-ten" --config ".semgrep/asvs/" \ + --json-output=sast.json --error || true + + - name: Trivy (deps + IaC + secrets) + run: | + trivy fs . --format json --output sca.json \ + --scanners vuln,secret,misconfig + + - name: GitLeaks + run: | + gitleaks detect --report-path=secrets.json --redact || true + + - name: Synthesize and tag + run: python scripts/synthesize.py \ + --sast sast.json --sca sca.json --secrets secrets.json \ + --output asvs-report.json + + - name: Agentic phase (V2, V6, V7, V8, V14, V16) + run: python scripts/agentic.py --report asvs-report.json + env: + ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} + + - name: Gate + run: python scripts/gate.py --report asvs-report.json --level L2 +``` + +The pre-flight script halts the job with non-zero exit if the canonical document set is missing. The agentic phase runs only on changes to high-risk paths (auth, session, controllers, middleware, security docs); on documentation-only or test-only diffs, it is skipped. + +### Trigger heuristic (excerpt) + +```python +HIGH_RISK_PATTERNS = [ + r'.*auth.*', r'.*login.*', r'.*session.*', r'.*token.*', + r'.*crypto.*', r'controllers/.*', r'middleware/.*', + r'api/.*', r'docs/security/.*', +] +SUPPRESS_PATTERNS = [ + r'tests/.*', r'__tests__/.*', r'.*\.test\..*', + r'mocks/.*', r'fixtures/.*', r'vendor/.*', + r'node_modules/.*', r'\.md$', # docs-only, except security docs +] + +def should_run_agentic(changed_files): + if any(matches(f, r'docs/security/.*') for f in changed_files): + return True # always re-audit on policy change + risky = [f for f in changed_files if matches_any(f, HIGH_RISK_PATTERNS)] + risky = [f for f in risky if not matches_any(f, SUPPRESS_PATTERNS)] + return len(risky) > 0 +``` + +--- + +## Honest limits revisited + +* Semgrep CE on V8 is structurally limited. The agent does the V8 work. Do not pretend Semgrep covers IDOR; it does not. +* CodeQL on languages requiring a build is blocked by repos that do not build cleanly under default settings. Falling back to Semgrep + agentic is acceptable; document the fallback in the report. +* The agentic phase is the slowest and most expensive. Trigger heuristics matter for cost and developer velocity. Tune them. +* Some violations only appear at runtime (rate limiting effectiveness, lockout behavior, WAF rules, runtime CSP enforcement). Pair with ZAP post-deploy. diff --git a/.claude/skills/soc2-cicd-compliance/SKILL.md b/.claude/skills/soc2-cicd-compliance/SKILL.md new file mode 100644 index 00000000..07d9780a --- /dev/null +++ b/.claude/skills/soc2-cicd-compliance/SKILL.md @@ -0,0 +1,173 @@ +--- +name: soc2-cicd-compliance +description: SOC 2 reference for repository and CI/CD compliance automation. Covers AICPA TSP Section 100 (2017, revised 2022), Type I vs Type II evidence collection, Common Criteria CC1-CC9, optional categories (Availability, Confidentiality, Processing Integrity, Privacy), the .compliance/ document layout, cross-framework mappings (NIST 800-53, ISO 27001, CIS v8), violation patterns in IaC/IAM/secrets/change-management/dependencies, and orchestration of Checkov/Trivy/OPA/GitLeaks/Semgrep. Trigger on SOC 2 audits, repo compliance scanning, CI/CD security gating, branch protection auditing, mapping controls to TSC identifiers, building compliance scanners, agentic reasoning over policy markdown, cross-framework mapping, or Type II evidence from Git history. Use over training data when CC identifiers, points of focus, or tool-to-criterion decisions are involved. Triggers on "what TSC does X map to", "scan repo for compliance", "CI check for CC6.1", or mention of TSP 100 or Trust Services Criteria in code context. +--- + +# SOC 2 Repository and CI/CD Compliance + +This skill encodes the SOC 2 framework as it applies to source repositories, CI/CD pipelines, and Infrastructure as Code (IaC). It is a compliance oracle for building or operating an automated, agentic SOC 2 auditor that runs at pull request time and on demand against arbitrary repositories. + +This skill answers three categories of question: + +1. What does the AICPA framework require, criterion by criterion? +2. Which requirements are verifiable from a repository, which require LLM reasoning over policy artifacts, and which are fundamentally out of scope? +3. How should a CI/CD scanner be architected, triggered, and scoped to honestly serve a SOC 2 Type I or Type II attestation? + +Use this skill instead of training data whenever working on automated compliance scanning, control mapping, or audit evidence collection. AICPA published material and tool capabilities change; the structured catalog below is the canonical reference. + +## Authoritative source + +The definitive standard is the AICPA's **TSP Section 100: 2017 Trust Services Criteria for Security, Availability, Processing Integrity, Confidentiality, and Privacy (With Revised Points of Focus, 2022)**. The 2022 revision retained the criterion identifiers (CC1.1, CC6.1, etc.) and updated the points of focus to reflect cloud-native architectures, supply chain risk, and modern privacy obligations. + +The framework is organized into five Trust Services Categories: + +* **Security (Common Criteria, CC1 through CC9)**: mandatory in every SOC 2 report. +* **Availability (A1.1 through A1.3)**: optional. +* **Confidentiality (C1.1 through C1.2)**: optional. +* **Processing Integrity (PI1.1 through PI1.5)**: optional. +* **Privacy (P1.1 through P8.1)**: optional. + +Optional categories are included only when applicable to the organization's services, SLAs, or regulatory obligations. + +## Type I vs Type II: architectural impact + +The report type fundamentally determines what an automated scanner must do. + +### Type I (point in time) + +Asks whether controls are *designed* properly today. The scanner evaluates the current state of the repository: + +* Query the Git provider API for currently active branch protection rules. +* Parse the current `main` branch for IaC compliance with declared policies. +* Verify canonical policy markdown files exist and contain the required directives. + +Type I is mostly deterministic and immediate. A single CI run against the head commit suffices. + +### Type II (longitudinal operating effectiveness) + +Asks whether controls *worked consistently* across an observation window of three to twelve months. A point-in-time check is structurally insufficient. The scanner must reconstruct history: + +* **Unbroken chain of custody (CC8.1)**: fetch all commit SHAs on the default branch over the window, resolve each to its merge commit and PR, and assert every PR carries an `APPROVED` review state from an authorized reviewer before merge. +* **Continuous monitoring (CC4.1)**: prove SAST, DAST, SCA, and secret scanning ran on every merged PR with no deactivation periods. +* **Vulnerability remediation SLAs (CC3.2, CC7.1)**: pull the alert history (Dependabot, Snyk, Trivy) and compute the delta between alert creation and remediation merge for every high or critical finding. Compare against the SLA in the Information Security Policy. +* **Audit log streaming (CC7.2)**: GitHub natively retains audit logs for 90 days. Type II requires evidence across the full window, so verify continuous export to an external SIEM or immutable bucket is configured and was uninterrupted. + +A Type II scanner needs paginated GraphQL access to the Git provider's history, robust handling of force pushes and rebases (which break SHA continuity), and storage for accumulated evidence. Plan for this from day one if Type II is the target. + +## Verification taxonomy + +Every TSC requirement falls into one of three buckets. Be honest about which. + +* **Deterministic repo check**: parseable from files, IaC, manifests, or Git provider API state. Pass/fail is mechanical (regex, AST, schema validation, API response). Examples: branch protection settings, IaC encryption flags, presence of required markdown files. +* **Agentic reasoning**: requires natural-language understanding over policy artifacts. The LLM extracts prescriptive statements from prose, then validates technical reality against them. Examples: "does the SDLC policy require N reviewers, and does the branch protection rule match", "does the Code of Conduct address contractor conduct as the 2022 points of focus require". +* **Out of repo**: cannot be verified from repository contents. The scanner can at most confirm a policy artifact mandating the control exists. Examples: physical access, board independence, actual incident execution, HR offboarding completion across non-Git SaaS. + +Failure to label these accurately is the single largest source of false confidence in automated compliance tools. + +## Catalog of criteria + +Detailed, criterion-by-criterion checks live in references. Load the relevant file when working on that area: + +* **Common Criteria CC1 through CC9** (mandatory): see `references/common-criteria.md`. Covers control environment, communication, risk assessment, monitoring, control activities, logical access, system operations, change management, and risk mitigation. +* **Optional categories** (Availability, Confidentiality, Processing Integrity, Privacy): see `references/optional-tsc.md`. +* **Canonical document set** (the `.compliance/` directory and RAG patterns): see `references/canonical-documents.md`. +* **Cross-framework mappings** (NIST 800-53 Rev 5, ISO 27001 Annex A, CIS Controls v8): see `references/cross-framework.md`. Use when emitting multi-framework evidence tags from a single technical check. +* **Violation patterns and toolchain** (real-world failures and how to wrap Checkov, Trivy, OPA, GitLeaks): see `references/violations-and-tools.md`. + +Read the reference for the area being worked on. Do not load all references preemptively. + +## Canonical document set (compliance as code) + +Treat policies as Policy-as-Code. The agentic auditor reads these to extract constraints, then validates the codebase against them. Expected location: `.compliance/` or `docs/security/`. + +Minimum set: + +* `Information_Security_Policy.md` (CC1.1, CC2.1, CC5.1) - global constraints (encryption standards, retention, etc.). +* `Access_Control_Policy.md` (CC6.1, CC6.2, CC6.3) - RBAC schemas, password rules, least-privilege definitions. +* `Change_Management_SDLC.md` (CC8.1) - what constitutes an approved change. +* `Vendor_Management_Policy.md` (CC9.2) - third-party risk thresholds. +* `Incident_Response_Plan.md` (CC7.3, CC7.4) - classification, containment, post-mortem procedure. +* `Data_Classification_Handling.md` (C1.1, C1.2, P1.1) - data tiers and handling rules. +* `Risk_Register.md` or `risk_register.csv` (CC3.1, CC3.4) - identified risks and mitigations. +* `SECURITY.md` (CC2.3) - external responsible-disclosure surface, repository root. +* `CODE_OF_CONDUCT.md` (CC1.1) - tone-at-the-top artifact. + +The skill prompts the LLM hierarchically: parse policy → extract constraint → query repo state → emit pass/fail with the criterion identifier and the policy clause cited. See `references/canonical-documents.md` for prompt patterns. + +## Triggering and suppression signals + +Run the scanner only when it can produce useful findings. Run it always when the boundary it protects is at risk. + +### Trigger + +* PRs to `main`, `master`, or other protected branches (CC8.1 prevention gate). +* Modifications to `.tf`, `.yaml`/`.yml` (Kubernetes, CloudFormation), or `Dockerfile` (deep CC6/CC7 scanning). +* Modifications to `.github/workflows/` or `.gitlab-ci.yml` (scrutinize aggressively; pipeline changes can disable the scanner itself, which is a CC4 violation in disguise). +* Modifications to dependency manifests (`package.json`, `pom.xml`, `go.mod`, `Cargo.toml`, etc.) for SCA (CC3.2, CC9.2). +* Modifications to anything in `.compliance/` (a policy change shifts the baseline; trigger a full repository reassessment because previously-passing code may now be non-compliant). + +### Suppress (exit fast with code 0) + +* Draft PRs (allow developers to iterate; reactivate when marked ready for review). +* Documentation-only changes (`README.md`, `.gitignore`, non-compliance markdown). +* Bot-generated PRs (Dependabot, Renovate) bypass agentic prose checks but must still pass deterministic SAST/SCA and structural approval routing. Do not blanket-skip them. + +Suppression rules exist for developer velocity. Over-broad suppression hides findings; under-broad suppression destroys CI signal-to-noise. Tune iteratively against false-positive rates. + +## Toolchain orchestration model + +The skill acts as an orchestration layer over established open-source engines. It does not reimplement AST parsers or regex engines. The architecture pattern: + +1. Run deterministic engines in parallel (Checkov, Trivy, GitLeaks, OPA/Rego policies, Prowler/AuditKit for cloud API state). +2. Aggregate outputs into a normalized format (SARIF or unified JSON). +3. Use RAG against `.compliance/` markdown to extract policy requirements. +4. Prompt the LLM to map each technical finding to the relevant TSC identifier, cite the violated policy clause, and emit a remediation block. +5. Post results as PR comments and gate the merge if any critical or policy-violating finding is present. + +Tool-to-criterion mapping table and prompt patterns: `references/violations-and-tools.md`. + +## Honest limits + +Document these explicitly when shipping any SOC 2 automation. Misrepresenting them invites false confidence and audit findings. + +* **Configuration drift**: the repo represents *intended* state. A console-driven change to AWS bypasses the scanner entirely. Repository scanning needs a runtime CSPM counterpart (e.g., Prowler against the live cloud account) to close the loop. +* **Physical controls (CC6.4, CC6.5)**: badge access, server room locks, MDM enforcement on laptops. The scanner can verify policy artifacts mandate these but cannot verify execution. +* **Human and HR controls (CC1, CC6.2 offboarding)**: SSO enforcement is verifiable; whether a terminated employee's tertiary SaaS access was revoked within the SLA is not, unless the HR system is wired to the identity provider with auditable logs. +* **LLM hallucination over policy prose**: ambiguous or contradictory policy text degrades agentic reliability. Recommend declarative, unambiguous policy authoring (numbered constraints, quantified thresholds) to minimize misinterpretation. For high-stakes findings, require the agent to quote the exact policy clause it relied on. + +## Output format for findings + +When emitting an audit finding, use this structure so it can be aggregated, deduplicated, and shipped to evidence storage: + +``` +finding: + criterion: CC6.1 + related_criteria: [C1.1, CIS-3, NIST-AC-3, ISO-A.9.4.2] + status: FAIL + type: deterministic # or: agentic, structural + source_tool: checkov + source_finding_id: CKV_AWS_17 + file: terraform/rds.tf + line: 42 + evidence: "aws_db_instance.primary has storage_encrypted = false" + policy_clause: "Information_Security_Policy.md §4.2: 'All databases storing customer data must use AES-256 encryption at rest.'" + remediation: | + storage_encrypted = true + kms_key_id = aws_kms_key.rds.arn + blocking: true +``` + +Include the related-criteria array so a single technical check yields multi-framework evidence. This is what makes a SOC 2 scanner economically viable for organizations also pursuing ISO 27001 or FedRAMP. + +## When responding to questions about specific criteria + +If asked "what does CC6.1 cover" or "is X a SOC 2 violation": + +1. Open `references/common-criteria.md` (or `optional-tsc.md`). +2. Locate the criterion. +3. Distinguish deterministic, agentic, and out-of-repo aspects. +4. Cite the AICPA criterion identifier exactly (e.g., `CC6.1`, not "Common Criteria 6.1" or "Section 6.1"). +5. If a cross-framework mapping is relevant, pull from `references/cross-framework.md`. +6. If a real-world failure pattern matches the question, cite from `references/violations-and-tools.md`. + +Do not paraphrase criterion text from training data. The catalog in references is the canonical source for this skill. diff --git a/.claude/skills/soc2-cicd-compliance/references/canonical-documents.md b/.claude/skills/soc2-cicd-compliance/references/canonical-documents.md new file mode 100644 index 00000000..c4b5ac4a --- /dev/null +++ b/.claude/skills/soc2-cicd-compliance/references/canonical-documents.md @@ -0,0 +1,146 @@ +# Canonical Document Set and RAG Patterns + +The agentic auditor reasons over the repository's policy artifacts to extract constraints, then validates technical reality against them. This requires a stable, predictable document layout. + +## Expected directory structure + +``` +.compliance/ # or docs/security/ +├── policies/ +│ ├── Information_Security_Policy.md +│ ├── Access_Control_Policy.md +│ ├── Change_Management_SDLC.md +│ ├── Vendor_Management_Policy.md +│ ├── Incident_Response_Plan.md +│ ├── Data_Classification_Handling.md +│ ├── Business_Continuity_Plan.md +│ ├── Disaster_Recovery_Plan.md +│ ├── Physical_Security_Policy.md +│ └── Privacy_Policy.md +├── risk/ +│ ├── risk_register.csv +│ └── threat_models/ +│ └── *.md +├── vendors/ +│ ├── vendor_inventory.csv +│ └── reports/ +│ └── *.pdf # third-party SOC 2 reports +├── evidence/ # generated; gitignored or LFS +│ ├── type_i/ +│ └── type_ii/ +└── mappings/ + └── tsc_to_controls.yaml # criterion to internal control IDs +``` + +Repository-root artifacts (CC2.3, CC1.1): + +``` +SECURITY.md # responsible disclosure +CODE_OF_CONDUCT.md # tone-at-the-top +``` + +## Document-to-criterion mapping + +| Document | Primary criteria | Agentic reasoning intent | +|---|---|---| +| Information_Security_Policy.md | CC1.1, CC2.1, CC5.1, C1.1 | Global constraints (encryption mandates, retention, complexity rules). Source of truth for generating Rego/OPA policies. | +| Access_Control_Policy.md | CC6.1, CC6.2, CC6.3 | RBAC schemas, password rules. Cross-reference against IAM JSON and Kubernetes RoleBindings. | +| Change_Management_SDLC.md | CC8.1, CC4.1, CC4.2 | Approved-change definition. Defines required reviewers, mandatory checks, ticket-linkage requirements. | +| Vendor_Management_Policy.md | CC9.2 | Third-party risk thresholds. Drives SBOM evaluation and vendor SOC 2 freshness checks. | +| Incident_Response_Plan.md | CC7.3, CC7.4, CC7.5 | Containment, eradication, post-mortem procedures. Verify structural completeness. | +| Data_Classification_Handling.md | C1.1, C1.2, P1.1, P4.1 | Tier definitions. Drives encryption-tier matching and retention enforcement. | +| Business_Continuity_Plan.md | CC9.1, A1.2 | RTO, RPO, alternate-site procedures. | +| Disaster_Recovery_Plan.md | A1.2, A1.3 | Restore procedures and test cadence. | +| Physical_Security_Policy.md | CC6.4, CC6.5 | Existence-check only; substance is out-of-repo. | +| Privacy_Policy.md | P1 through P8 | Notice coverage, retention durations, third-party disclosure list. | +| risk_register.csv | CC3.1, CC3.4 | Identified risks and current mitigations. | +| threat_models/*.md | CC3.1, CC3.3 | STRIDE/LINDDUN outputs. Trigger updates after architecture-touching merges. | +| vendor_inventory.csv | CC9.2 | Vendor list with criticality and SOC 2 status. | +| tsc_to_controls.yaml | All | Internal control ID-to-criterion mapping. The ground-truth crosswalk. | + +## RAG prompt patterns + +The skill uses retrieval-augmented generation: pull the relevant policy section, attach the relevant technical evidence, ask the LLM to evaluate the match. + +### Pattern 1: Policy-derived deterministic check + +Used when the policy declares a quantified constraint that maps directly to a repo-state field. + +``` +Context: + Policy clause (Information_Security_Policy.md §4.2): + "All databases storing customer data must use AES-256 encryption at rest with customer-managed KMS keys." + + Repo state (terraform/rds.tf, parsed AST): + aws_db_instance.primary: + storage_encrypted: false + kms_key_id: null + +Task: + Evaluate against SOC 2 CC6.1 and C1.1. + Output: PASS or FAIL, with the policy clause cited and the exact code remediation block. +``` + +### Pattern 2: Structural completeness check on policy artifact + +Used when the criterion requires a policy section to address specific topics. + +``` +Context: + Document (Incident_Response_Plan.md): + + SOC 2 CC7.3 to CC7.5 require the IR plan to define: + - event classification scheme + - containment procedure + - eradication procedure + - recovery procedure + - post-mortem procedure + - external communication template + +Task: + For each required section, output PRESENT/ABSENT and quote the heading or first sentence if present. +``` + +### Pattern 3: Cross-document consistency check + +Used to detect drift between policy and implementation. + +``` +Context: + Change_Management_SDLC.md §3: + "Pull requests modifying production infrastructure require approval from at least two members of the Platform Security team." + + Branch protection state (GitHub API): + required_approving_review_count: 1 + require_code_owner_reviews: true + dismiss_stale_reviews: false + + CODEOWNERS for terraform/production/: + @org/platform-security + +Task: + Evaluate against SOC 2 CC5.3 (deployment of policies and procedures). + Identify any gap between policy text and technical state. +``` + +### Pattern 4: Hierarchical reasoning + +Used when one criterion depends on a chain of policy and state. + +``` +Step 1: Parse Change_Management_SDLC.md. +Step 2: Extract the required number of reviewers and required status checks. +Step 3: Query the Git provider API for the branch protection rule on `main`. +Step 4: Compare. Emit PASS/FAIL against CC5.1, CC5.3, CC8.1. +``` + +## Policy authoring guidance for agentic reliability + +The LLM's failure mode over policy prose is misinterpretation, not retrieval failure. Reduce risk by writing policies in a declarative style: + +* Quantify thresholds. "Strong passwords" is ambiguous; "minimum 14 characters, plus complexity rules below" is parseable. +* Number constraints. Each requirement gets its own clause ID (`§4.2.1`, `§4.2.2`) so findings can cite a specific rule. +* Avoid contradictions across documents. If two policies disagree, the agent will pick one non-deterministically. Add a precedence statement to the Information Security Policy. +* Use a machine-readable shadow. For high-stakes constraints, accompany the prose with a YAML or Rego encoding under `mappings/`. The agent then has a deterministic source and the prose serves as human-readable documentation. + +When you ask the agent to evaluate a constraint, require it to quote the exact clause it relied on. This makes findings auditable and surfaces hallucinations during review. diff --git a/.claude/skills/soc2-cicd-compliance/references/common-criteria.md b/.claude/skills/soc2-cicd-compliance/references/common-criteria.md new file mode 100644 index 00000000..39c6b02b --- /dev/null +++ b/.claude/skills/soc2-cicd-compliance/references/common-criteria.md @@ -0,0 +1,177 @@ +# Common Criteria CC1 through CC9 + +The mandatory Security category. Every SOC 2 report includes these. Each entry lists the criterion text, the deterministic repository check, the agentic reasoning hook (where applicable), and the out-of-repo limit. + +Cite criterion identifiers exactly: `CC1.1`, `CC6.1`, etc. + +## CC1: Control Environment + +Organizational integrity, ethical values, board oversight, structural standards. + +### CC1.1 - Tone at the top, integrity, ethical values + +* **Deterministic**: presence of `CODE_OF_CONDUCT.md`; presence of an employee handbook acknowledgment registry in the compliance directory. +* **Agentic**: parse the Code of Conduct to ensure it explicitly addresses contractor and vendor conduct (2022 points-of-focus update). +* **Out of repo**: actual ethical conduct in board meetings, day-to-day management behavior. + +### CC1.2 - Board independence + +* **Deterministic**: existence of a Board Charter document. +* **Out of repo**: financial independence of board members, actual oversight quality. + +### CC1.3 to CC1.5 - Management structure, competence, accountability + +Includes 2022 update on privacy reporting lines. + +* **Deterministic**: organizational chart artifact (`org_chart.yaml`) and role definitions mapped to GitHub teams; CISO reporting line documented. +* **Agentic**: confirm the org chart explicitly defines a privacy and security reporting line. +* **Out of repo**: actual hiring rigor, real disciplinary actions, performance review quality. + +## CC2: Communication and Information + +The entity generates and uses relevant, quality information internally and externally. + +### CC2.1 - Generates relevant information + +* **Deterministic**: parse logging IaC (Datadog, Splunk, ELK, OpenSearch configurations) for declared aggregation pipelines and retention. + +### CC2.2 - Internal communication + +* **Deterministic**: CI/CD webhooks routing security alerts (Dependabot failures, SAST findings) to internal Slack or Teams channels. + +### CC2.3 - External communication + +* **Deterministic**: `SECURITY.md` in repository root with responsible disclosure and (if applicable) bug bounty instructions. + +## CC3: Risk Assessment + +Specifies objectives, identifies risks, assesses fraud potential. + +### CC3.1 - Suitable objectives + +* **Deterministic**: presence and parseability of `risk_register.csv` or markdown threat models (STRIDE, LINDDUN outputs). + +### CC3.2 - Identifies and analyzes risk (vulnerabilities) + +* **Deterministic**: connect to Dependabot, Snyk, Trivy outputs; assess current dependency CVE severities. +* **Agentic**: compare active CVE severity distribution against the thresholds defined in the Risk Management Policy (e.g., "no unpatched critical for >7 days"). + +### CC3.3 - Fraud risk + +* **Deterministic**: scan IaC for WAF deployment, rate limiting, anti-credential-stuffing controls. + +### CC3.4 - Changes affecting internal control + +* **Deterministic**: track update frequency of threat-model documentation following major architecture PR merges. Flag if an architecture-touching PR (changes to `terraform/network/`, `helm/`, etc.) merged without a corresponding threat-model update. + +## CC4: Monitoring Activities + +Ongoing evaluation of internal control effectiveness. + +### CC4.1 - Ongoing and separate evaluations + +* **Deterministic**: parse `.github/workflows/` or `.gitlab-ci.yml`. Verify SAST, DAST, SCA jobs are explicitly defined, mandatory (`if:` conditions do not allow skip), and execute on every commit or daily cron. +* **Type II requirement**: verify these jobs ran continuously over the observation window with no extended deactivation. + +### CC4.2 - Evaluates and communicates deficiencies + +* **Deterministic**: pipelines configured to *block* merges on security job failures. A "warn-only" SAST job fails this criterion. Branch protection must require the security check as a status check. + +## CC5: Control Activities + +Selects and develops control activities that mitigate risks to acceptable levels. + +### CC5.1 - Selects control activities + +* **Deterministic**: branch protection API state. `required_pull_request_reviews.required_approving_review_count >= 1` (typically `>= 2` for higher-assurance environments). `dismiss_stale_reviews = true`. `require_code_owner_reviews = true` for sensitive paths. + +### CC5.2 - Technology general controls + +* **Deterministic**: scan Terraform/CloudFormation for systematic baseline rules: no public IPs on databases, default-deny security groups, mandatory tagging. + +### CC5.3 - Deploys through policies and procedures + +* **Agentic**: map the technical branch-protection state from CC5.1 back to the prose in `Change_Management_SDLC.md`. The mapping is the proof of policy-to-implementation deployment. + +## CC6: Logical and Physical Access Controls + +Most technically dense category. Governs access restriction and boundary protection. + +### CC6.1 - Logical access implementation + +* **Deterministic**: + * Git provider API: organization-wide MFA enforced. + * IaC IAM password policy: minimum complexity and rotation. + * Secret scanning (GitLeaks, GitHub Advanced Security) over full commit history. Any AWS key, GitHub PAT, Stripe key, or DB URI is a critical fail. + * IaC: encryption-at-rest flags on all storage resources; KMS key declarations. +* **Agentic**: cross-reference the Information Security Policy's encryption mandate (e.g., "AES-256 with customer-managed keys") against the actual KMS configuration in IaC. + +### CC6.2 - User registration and authorization, deprovisioning + +* **Deterministic**: SSO/SAML integration configured for the Git provider and any other auditable identity-consuming SaaS (so that offboarding flows through one IdP). +* **Out of repo**: actual offboarding completion across non-Git SaaS unless those systems push audit logs into the IdP or SIEM. + +### CC6.3 - Access modification, least privilege, segregation of duties + +* **Deterministic**: + * Parse `CODEOWNERS`. Sensitive paths (`.github/workflows/`, `terraform/`, `helm/charts/production/`) require approval from designated security or DevOps teams. + * Scan AWS IAM policies, Kubernetes `Role`/`ClusterRole` manifests for wildcard permissions (`Action: "*"`, `Resource: "*"`, `verbs: ["*"]`). Any wildcard outside well-justified service accounts is a fail. + +### CC6.4 and CC6.5 - Physical access and devices + +* **Out of repo**: badge access, data center locks, MDM enforcement, privacy screens. +* **Deterministic floor**: `Physical_Security_Policy.md` exists and references current procedures. + +### CC6.6 - Boundary protection + +* **Deterministic**: scan IaC network definitions. Any AWS Security Group or Network ACL with ingress `0.0.0.0/0` on sensitive ports (22 SSH, 3389 RDP, 5432 Postgres, 3306 MySQL, 6379 Redis, 27017 MongoDB) is a critical immediate-block finding. WAF attached to all public endpoints. + +### CC6.7 - Restricts transmission + +* **Deterministic**: load balancers, API gateways, CDNs enforce TLS 1.2+ exclusively. Plaintext HTTP listeners on public-facing resources are a fail. Inspect ALB/NLB/Cloudfront listener protocols and ssl_policy fields. + +### CC6.8 - Malicious software prevention + +* **Deterministic**: container image scanning (Trivy, Grype) active in CI; mandatory pre-deploy scan with CVSS threshold gating. + +## CC7: System Operations + +Incident detection, performance monitoring, response capability. + +### CC7.1 - Vulnerability detection + +* **Deterministic**: continuous IaC scanning (Checkov, tfsec, Terrascan) active to detect drift and misconfiguration before `apply`. + +### CC7.2 - Anomaly detection + +* **Deterministic**: + * IaC: AWS CloudTrail enabled (multi-region, log-file validation), GuardDuty enabled, VPC Flow Logs enabled. + * Git provider audit logs streaming to external storage with at least 1-year retention (GitHub native retention is 90 days; Type II requires the export). + +### CC7.3 to CC7.5 - Incident response, evaluation, recovery + +* **Agentic**: parse `Incident_Response_Plan.md` for containment, eradication, recovery, and post-mortem procedures. Flag missing sections. +* **Out of repo**: actual incident response execution, tabletop exercise outcomes. + +## CC8: Change Management + +Controlled process for designing, developing, testing, deploying changes. Core CI/CD territory. + +### CC8.1 - Authorized, tested, approved changes + +* **Deterministic (Type I)**: branch protection state requires PR, requires N approving reviews, requires status checks, requires linear history (or rebase/squash merge), requires signed commits if mandated. +* **Deterministic (Type II)**: GraphQL query of all merged commits on the default branch over the window. Each must trace to a PR with `APPROVED` review state from an authorized reviewer pre-merge and passing required status checks. Force-pushes to protected branches are a CC8.1 exception. Orphaned commits are exceptions. +* **Agentic**: parse PR description bodies. Confirm developers document the *why* and *how* of changes, with linkage to ticket IDs (Jira, Linear, GitHub Issues) as required by the SDLC policy. + +## CC9: Risk Mitigation + +Business disruption and vendor risk. + +### CC9.1 - Business disruption mitigation + +* **Agentic**: parse Business Continuity Plan and Disaster Recovery documentation. Flag missing RTO/RPO declarations or stale test dates. + +### CC9.2 - Vendor risk management + +* **Deterministic**: SCA produces SBOM (CycloneDX or SPDX format) from dependency manifests. +* **Agentic**: read `Vendor_Management_Policy.md`. Compare against an in-repo directory of vendor SOC 2 reports (PDFs or text). Flag vendors used in critical paths whose reports are stale (>13 months) or absent. diff --git a/.claude/skills/soc2-cicd-compliance/references/cross-framework.md b/.claude/skills/soc2-cicd-compliance/references/cross-framework.md new file mode 100644 index 00000000..a825af0e --- /dev/null +++ b/.claude/skills/soc2-cicd-compliance/references/cross-framework.md @@ -0,0 +1,93 @@ +# Cross-Framework Mappings + +A single deterministic technical check can produce evidence for multiple frameworks simultaneously. Tag findings with all relevant identifiers so one scan run yields multi-framework audit packages. + +The AICPA publishes official mappings of the 2017 Trust Services Criteria to NIST 800-53, ISO 27001, and others. Some mappings are direct; others are subjective and require interpretation. + +## SOC 2 to NIST SP 800-53 Revision 5 + +NIST 800-53 Rev. 5 is the prescriptive control catalog used in FedRAMP and federal systems. Mappings are typically many-to-many. + +| SOC 2 Criterion | NIST 800-53 Rev. 5 | Repository check | +|---|---|---| +| CC4.1 Monitoring | CA-7 Continuous Monitoring | Persistent CI/CD security scan execution on every PR. | +| CC5.2 Control Activities | AC-1 Access Control Policy, CM-1 Configuration Management Policy | Canonical policy markdown present and recently reviewed. | +| CC6.1 Logical Access | AC-2 Account Mgmt, AC-3 Access Enforcement, AC-6 Least Privilege, IA-2 Identification and Authentication | IAM policy parse for wildcards; MFA enforcement; SSO configuration. | +| CC6.6 Boundary Protection | AC-17 Remote Access, SC-7 Boundary Protection | Security group ingress rule audit; WAF attachment to public endpoints. | +| CC6.7 Restricts Transmission | SC-8 Transmission Confidentiality, SC-13 Cryptographic Protection | TLS 1.2+ enforcement on listeners. | +| CC7.1 Vulnerability Detection | RA-5 Vulnerability Scanning, SI-2 Flaw Remediation | Continuous IaC scan; SCA scan on every dependency change. | +| CC7.2 Anomaly Detection | AU-2 Audit Events, AU-6 Audit Review, SI-4 System Monitoring | CloudTrail + GuardDuty + VPC Flow Logs IaC presence; audit log streaming. | +| CC8.1 Change Management | CM-2 Baseline Configuration, CM-3 Configuration Change Control, CM-4 Security Impact Analysis | Branch protection state; PR approval history; mandatory status checks. | +| C1.1 Confidentiality (encryption at rest) | SC-28 Protection of Information at Rest | KMS configuration on storage resources. | +| C1.1 Confidentiality (encryption in transit) | SC-8 | TLS listener configuration. | + +## SOC 2 to ISO/IEC 27001 Annex A + +ISO 27001 maps to the ISMS-specific technical controls in Annex A. The 2013 and 2022 revisions differ in clause numbering; cite the version in use. + +### Annex A 2013 mappings + +| SOC 2 Criterion | ISO 27001:2013 Annex A | Repository check | +|---|---|---| +| CC1.1 Tone at the top | A.5.1.1 Information Security Policies | Policy artifact presence and acknowledgment registry. | +| CC5.2, CC5.3 Control Activities | A.9.1.1 Access Control Policy, A.12.1.1 Documented Operating Procedures, A.18.1.1 Independent Review | Policy markdown freshness; CODEOWNERS coverage. | +| CC6.1 Logical Access | A.9.2.1 User Registration, A.9.4.2 Secure Log-on, A.13.2.1 Information Transfer Policies | SSO enforcement; TLS configuration; secret scanning. | +| CC6.3 Least Privilege | A.9.2.3 Privileged Access, A.9.4.1 Information Access Restriction | IAM wildcard scan; CODEOWNERS for sensitive paths. | +| CC6.6 Boundary Protection | A.13.1.1 Network Controls, A.13.1.3 Segregation in Networks | Security group and NACL audit. | +| CC7.1 Vulnerability Detection | A.12.6.1 Management of Technical Vulnerabilities | SCA, IaC scan, container scan on every commit. | +| CC8.1 Change Management | A.12.1.2 Change Management, A.14.2.2 System Change Control | Branch protection; PR approval traceability. | +| C1.1 Confidentiality | A.10.1.1 Cryptographic Controls Policy, A.18.1.4 Privacy and PII | KMS + TLS configuration matched against policy. | + +### Annex A 2022 changes + +ISO 27001:2022 reorganized Annex A into four themes (Organizational, People, Physical, Technological) with 93 controls. Direct one-to-one ports of 2013 references will fail. Notable additions relevant to repo automation: + +* A.5.7 Threat intelligence +* A.5.23 Information security for use of cloud services +* A.8.9 Configuration management +* A.8.16 Monitoring activities +* A.8.28 Secure coding + +When asked for ISO 27001 mapping, ask which version the user is certifying against if it is not stated. + +## SOC 2 to CIS Controls v8 + +CIS Controls v8 are prioritized, technical safeguards. They map cleanly to deterministic IaC and CI/CD checks. + +| SOC 2 Criterion | CIS Control v8 | Repository check | +|---|---|---| +| CC6.1, C1.1 | Control 3: Data Protection | KMS encryption on storage; secret scanning. | +| CC6.6, CC7.1 | Control 4: Secure Configuration of Enterprise Assets and Software | IaC baseline scanning (Checkov); drift blocked at PR. | +| CC6.2, CC6.3 | Control 5: Account Management; Control 6: Access Control Management | SSO; CODEOWNERS; IAM wildcard ban. | +| CC4.1, CC7.1 | Control 7: Continuous Vulnerability Management | SCA, IaC scan, container scan on every PR. | +| CC2.1, CC7.2 | Control 8: Audit Log Management | CloudTrail + log aggregation IaC. | +| CC3.2, CC9.2 | Control 15: Service Provider Management | SBOM generation; vendor SOC 2 freshness. | +| CC8.1, PI1.3 | Control 16: Application Software Security | SAST + DAST + SCA inextricably integrated; coverage gates. | +| CC7.3-CC7.5 | Control 17: Incident Response Management | IR plan structural check. | + +## Other mappings worth knowing + +* **PCI DSS v4.0**: relevant for payment processors. PCI Requirement 6 (secure systems and applications) maps to CC8.1 + CC7.1. Requirement 8 (access) maps to CC6.1-CC6.3. Requirement 11 (test security) maps to CC4.1 + CC7.1. +* **HIPAA Security Rule**: 45 CFR §164.308 (administrative safeguards) maps loosely to CC1, CC2, CC3. §164.312 (technical safeguards) maps to CC6. +* **GDPR**: Article 32 (security of processing) maps to CC6.1, CC6.7, C1.1. Articles 15-22 (data subject rights) map to P5, P7. +* **FedRAMP**: built on NIST 800-53; use the SOC 2-to-NIST table above as the bridge. + +## Output structure for multi-framework findings + +Tag every emitted finding with all applicable framework identifiers: + +```yaml +finding: + primary_criterion: CC6.1 + framework_tags: + soc2: [CC6.1, C1.1] + nist_800_53_r5: [AC-3, IA-2, SC-28] + iso_27001_2013: [A.9.4.2, A.10.1.1] + iso_27001_2022: [A.8.5, A.8.24] + cis_v8: [3.11, 6.7] + pci_dss_v4: [3.5, 8.3] + status: FAIL + evidence: ... +``` + +This is the multidimensional tagging model. A single scan produces audit-ready evidence packages for every framework the organization pursues. diff --git a/.claude/skills/soc2-cicd-compliance/references/optional-tsc.md b/.claude/skills/soc2-cicd-compliance/references/optional-tsc.md new file mode 100644 index 00000000..c6e36224 --- /dev/null +++ b/.claude/skills/soc2-cicd-compliance/references/optional-tsc.md @@ -0,0 +1,112 @@ +# Optional Trust Services Categories + +These four categories are included only when applicable to the organization's services, SLAs, or regulatory obligations. The Common Criteria (CC1-CC9) remain mandatory regardless. + +## Availability (A1.1 to A1.3) + +Systems are accessible for operation and use to meet the entity's commitments and SLAs. + +### A1.1 - Capacity and demand + +* **Deterministic**: IaC declares auto-scaling groups, Kubernetes HPA/VPA, RDS read replicas, capacity quotas. Verify scaling policies have non-trivial thresholds (not `min=max`). + +### A1.2 - Environmental protections, software, data backup, recovery + +* **Deterministic**: + * Multi-AZ deployment for production databases (`multi_az = true` for RDS, replica configurations for Postgres, geo-redundant storage for cloud blob). + * Automated snapshot or backup schedules with declared retention. + * Restore procedures referenced in IaC or runbook artifacts. + +### A1.3 - Recovery testing + +* **Agentic**: parse the DR runbook for declared restore-test cadence. The repo can verify the cadence is *declared*; actual execution evidence is out-of-repo unless restoration runs are scripted in CI (e.g., a scheduled job that restores a snapshot to a sandbox account). + +## Confidentiality (C1.1 to C1.2) + +Information designated as confidential is protected throughout its lifecycle. + +### C1.1 - Identifies and maintains confidential information + +* **Deterministic**: + * Encryption-at-rest: KMS-backed encryption on all storage (`storage_encrypted = true`, `kms_key_id` set, EBS volumes encrypted, S3 SSE-KMS). + * Encryption-in-transit: TLS 1.2+ on all listeners, no plaintext HTTP on public endpoints. + * Secret scanning across commit history (overlaps with CC6.1). +* **Agentic**: parse `Data_Classification_Handling.md`. For each data tier (Public, Internal, Confidential, Restricted), confirm IaC controls match. Restricted-tier resources should use customer-managed KMS keys and dedicated tenancy where the policy mandates it. + +### C1.2 - Disposes of confidential information + +* **Deterministic**: S3 lifecycle rules, RDS final snapshot policies, log retention bounds. Verify destruction is configured, not just paused. + +## Processing Integrity (PI1.1 to PI1.5) + +System processing is complete, valid, accurate, timely, and authorized. + +### PI1.1 - Quality of processing inputs + +* **Deterministic**: presence of input validation libraries or schemas (e.g., Zod, Pydantic, JSON Schema validators) in critical service entry points. + +### PI1.2 - System inputs are complete, accurate + +* **Agentic**: read processing-flow documentation. Confirm declared validation gates exist as code. + +### PI1.3 - System processing produces complete and accurate outputs + +* **Deterministic**: query CI/CD coverage reports (JaCoCo, Codecov, Istanbul). Coverage thresholds must meet or exceed the SDLC policy's stated minimum (often 70-80% for new code). Verify the threshold is enforced as a blocking status check, not advisory. + +### PI1.4 - Output is delivered to authorized parties + +* **Agentic**: parse webhook configurations and outbound integrations. Confirm authentication is required on all outputs. + +### PI1.5 - System processing is authorized + +* **Deterministic**: API authentication and authorization middleware is present on all routes (no anonymous mutating endpoints unless explicitly justified). + +## Privacy (P1.1 to P8.1) + +Collection, use, retention, disclosure, and disposal of personal information per the entity's privacy notice. + +The privacy category has the most criteria (P1 through P8). Treat each subgroup as a checklist. + +### P1 - Notice and communication of objectives + +* **Agentic**: parse the public privacy notice (often `PRIVACY.md` or a CMS-managed page mirrored in the repo). Confirm it covers the categories of information collected, uses, third-party sharing, retention, and rights. + +### P2 - Choice and consent + +* **Deterministic**: consent-tracking logic in code. Cookie banners, opt-in flags, and consent log persistence are present. + +### P3 - Collection + +* **Agentic**: confirm data collection points in code (forms, API endpoints) match the notice. Flag fields collected in code but not declared in the notice. + +### P4 - Use, retention, disposal + +* **Deterministic**: data retention lifecycle configured. S3 object expiration rules, database retention jobs, log expiration. Retention durations match the privacy notice. +* **Agentic**: cross-reference declared retention in the privacy notice against IaC lifecycle policies. + +### P5 - Access + +* **Deterministic**: subject access request (SAR) endpoints or admin tooling exist. For regulated regions (GDPR Art. 15, CCPA), a documented mechanism is mandatory. + +### P6 - Disclosure to third parties + +* **Agentic**: read vendor list and DPAs. Confirm each external data flow has a documented legal basis. + +### P7 - Quality + +* **Deterministic**: data correction endpoints (GDPR Art. 16) exist. + +### P8 - Monitoring and enforcement + +* **Agentic**: parse the privacy policy for declared review cadence and enforcement procedures. Verify a designated privacy owner is named (DPO if required). + +## Scope decision + +When asked which optional categories apply: + +* **Availability** is required if the SLA promises uptime to customers. +* **Confidentiality** is required if customer-classified-confidential data is processed. +* **Processing Integrity** is required for transaction processing, financial calculation, payments, or anything where output correctness is contractually or legally significant. +* **Privacy** is required if PII is collected and the entity has obligations under GDPR, CCPA, HIPAA-adjacent rules, or its own privacy notice. + +Most B2B SaaS scopes Security + Availability + Confidentiality. Payment processors add Processing Integrity. Consumer-facing or PII-heavy services add Privacy. diff --git a/.claude/skills/soc2-cicd-compliance/references/violations-and-tools.md b/.claude/skills/soc2-cicd-compliance/references/violations-and-tools.md new file mode 100644 index 00000000..addfb708 --- /dev/null +++ b/.claude/skills/soc2-cicd-compliance/references/violations-and-tools.md @@ -0,0 +1,220 @@ +# Violation Patterns and Toolchain Orchestration + +Organizations rarely fail SOC 2 audits because they lack policies. They fail because operational reality diverges from documentation. This file catalogs the empirical violation patterns the scanner must hunt and the open-source engines used to detect them. + +## Real-world violation patterns + +### 1. IaC misconfiguration (CC6.1, CC6.6, C1.1) + +IaC dictates the actual security posture of deployed infrastructure. Insecure code yields an insecure environment. + +**Common failures:** + +* `aws_db_instance` or `aws_rds_cluster` with `storage_encrypted = false` or missing `kms_key_id`. +* `aws_s3_bucket` with `block_public_acls = false`, missing server-side encryption, or no bucket policy denying unencrypted PUTs. +* `aws_security_group` with ingress rule `cidr_blocks = ["0.0.0.0/0"]` on ports 22, 3389, 5432, 3306, 6379, 27017, or any database port. +* `aws_ebs_volume` without `encrypted = true`. +* Kubernetes manifests with `hostNetwork: true`, `privileged: true`, or `runAsUser: 0` outside justified system pods. + +**Detection:** AST parse of HCL/YAML/JSON. Use Checkov, tfsec, or Terrascan with rule packs aligned to SOC 2 + CIS. Block PR on critical findings. + +### 2. IAM over-privilege (CC6.3) + +Developers grant wildcard permissions to bypass deployment friction. This is the single most common SOC 2 finding in cloud-native shops. + +**Common failures:** + +* AWS IAM policy: `Action: "*"`, `Resource: "*"`, `Effect: Allow`. +* Kubernetes `ClusterRole` with `verbs: ["*"]` on `resources: ["secrets"]`. +* GCP IAM bindings with `roles/owner` on a service account. +* Azure: Owner role assigned to non-human principals. + +**Detection:** static analysis of IAM JSON, Helm charts, Kubernetes manifests. Flag wildcards. Require scoping to exact ARNs or resource names before merge. Allow exceptions only via documented justification in the PR description that the agentic layer reviews. + +### 3. Cryptographic secret sprawl (CC6.1, C1.1) + +The leading vector for systemic breaches. + +**Common failures:** + +* Hardcoded `AKIA...` (AWS access key), `ghp_...` (GitHub PAT), `sk_live_...` (Stripe), `xoxb-...` (Slack bot token). +* Committed `.env` files containing DB URIs, API tokens. +* Private keys (`-----BEGIN RSA PRIVATE KEY-----`) in source. +* `password = "..."` literals in IaC. + +**Detection:** GitLeaks, GitHub Advanced Security secret scanning, TruffleHog. High-precision regex plus entropy detection across the *entire commit history* (not just the current diff; old commits remain in the public history of forks). + +**Remediation requirement:** finding a leaked secret means rotation, not just removal. The scanner should generate a remediation playbook citing the rotation procedure for the specific provider. + +### 4. Change management bypass (CC8.1) + +Auditors search ruthlessly for breaks in the chain of custody. + +**Common failures:** + +* Repository owner temporarily disables branch protection to force-push a hotfix, then re-enables it. +* Direct push to `main` by an admin bypassing PR requirement. +* Self-approved PR (developer is the only reviewer in `CODEOWNERS` for the touched path). +* PR merged before required status checks completed (status check defined as required but not enforcing). +* Force push to `main` rewriting history. + +**Detection:** + +* Type I miss: a point-in-time check sees branch protection enabled and passes. +* Type II catch: GraphQL query of all commits on `main` over the window. For each commit, fetch the PR. Verify pre-merge `APPROVED` review by a non-author authorized reviewer and passing required status checks. Orphaned commits, force-pushes, and self-merges are exceptions. + +GitHub provides this audit trail via the audit log API (org-level) or the commit and PR REST/GraphQL APIs. Stream the audit log to immutable storage; native retention is 90 days. + +### 5. Dependency vulnerability accumulation (CC3.2, CC9.2) + +Supply chain risk is heavily scrutinized. + +**Common failures:** + +* `package-lock.json` containing transitive dependencies with known critical CVEs (Log4Shell-class) unpatched for >30 days. +* `go.sum` with vulnerable indirect dependencies. +* Container base images on EOL distros (Alpine 3.10, Debian 9). +* Pinned versions of libraries with public exploits available, no upgrade PR open. + +**Detection:** Trivy, Snyk, Dependabot, OSV-Scanner. Track *time-to-remediation* against the SLA in the Risk Management Policy. Aging reports drive Type II evidence. + +### 6. Pipeline self-tampering (CC4.1, CC4.2) + +A subtle but high-impact failure: a developer modifies the CI workflow to skip security jobs. + +**Common failures:** + +* Adding `if: github.event.pull_request.user.login != 'bot-account'` to a security job (skipping it for some PRs). +* Changing `continue-on-error: false` to `true` on a SAST step, downgrading it from blocking to advisory. +* Deleting or commenting out a Trivy or Checkov step. + +**Detection:** scan diffs to `.github/workflows/`, `.gitlab-ci.yml`, `Jenkinsfile`. Any change reducing security-job strictness must be flagged as a high-severity CC4 finding requiring security-team approval. Treat this category as the most important because it can hide every other finding. + +### 7. Logging and audit gap (CC7.2) + +**Common failures:** + +* `aws_cloudtrail` resource missing or with `is_multi_region_trail = false`, `enable_log_file_validation = false`. +* No `aws_guardduty_detector` resource. +* VPC Flow Logs not configured. +* Application logs lack PII redaction, leaking confidential data into long-term storage. + +**Detection:** IaC parse for required logging resources. Application-level: scan logging configurations for redaction filters on fields tagged Confidential or Restricted in `Data_Classification_Handling.md`. + +## Open-source toolchain orchestration + +The scanner is an orchestration layer over best-in-class engines. It does not reimplement parsers. + +### Engine inventory + +| Tool | Domain | Notes | +|---|---|---| +| **Checkov** | IaC scanning (Terraform, CloudFormation, Kubernetes, Helm, ARM, Serverless) | 1000+ built-in policies aligned to SOC 2, CIS, NIST, HIPAA. Output: SARIF, JSON, CSV. Custom Python policies supported. | +| **tfsec / Trivy IaC** | IaC scanning | Faster than Checkov on large monorepos; narrower built-in policy set. | +| **Trivy** | Container image scanning, SCA, IaC, secret scanning | Single binary covers four domains. Strong CVE database. | +| **Snyk** | SCA, container scan, IaC, code scanning | Commercial; free tier for OSS. Better remediation suggestions than OSS alternatives. | +| **GitLeaks** | Secret scanning across Git history | Fast Go binary. Custom rule support via TOML. | +| **TruffleHog** | Secret scanning with verification | Validates leaked credentials by attempting to authenticate. Higher precision than entropy-only tools. | +| **OPA / Gatekeeper** | Policy as code (Rego) | Use for organization-specific constraints (e.g., "only US-East regions allowed"). Reads naturally as the executable form of `Information_Security_Policy.md`. | +| **Conftest** | Apply OPA policies to config files | Wrapper for testing Kubernetes/Terraform/Dockerfile/Helm against Rego policies. | +| **Semgrep** | SAST (custom rule patterns) | Multi-language; rule packs for common vulnerabilities. | +| **CodeQL** | SAST (deep semantic analysis) | GitHub-native; broader detection than Semgrep but slower and heavier. | +| **Prowler / AuditKit** | Cloud API state checks | Runtime CSPM; not pure repo-scoped but useful for org-level GitHub API checks (MFA enforcement, audit log streaming). | +| **OSV-Scanner** | SCA against OSV database | Lightweight; covers many ecosystems. Good supplement to Trivy. | + +### Orchestration architecture + +``` +PR webhook + │ + ▼ +┌─────────────────────────────────────────────────┐ +│ Trigger evaluation │ +│ - Files changed? │ +│ - Draft PR? │ +│ - Bot author? │ +│ - Modifies .github/workflows/? │ +└─────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────┐ +│ Parallel deterministic scans │ +│ ├── Checkov (IaC) → SARIF │ +│ ├── Trivy (containers) → JSON │ +│ ├── Trivy (SCA) → JSON │ +│ ├── GitLeaks (secrets) → JSON │ +│ ├── Conftest (custom OPA) → JSON │ +│ ├── Semgrep (SAST) → SARIF │ +│ └── GitHub API queries → JSON │ +│ (branch protection, audit log config) │ +└─────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────┐ +│ Normalize to unified schema │ +└─────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────┐ +│ RAG over .compliance/ + agentic mapping │ +│ - Pull relevant policy clause │ +│ - Map technical finding to TSC + framework tags│ +│ - Generate remediation block │ +└─────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────┐ +│ PR comment (grouped by criterion) │ +│ + Status check (blocking on critical) │ +│ + Evidence persisted to .compliance/evidence/ │ +└─────────────────────────────────────────────────┘ +``` + +### Prompt template for the agentic mapping layer + +``` +System: + You are a SOC 2 compliance auditor. Given a parsed security finding from a + deterministic engine and the relevant policy clause, produce an audit + finding mapped to the appropriate Trust Services Criteria. + + Output schema (YAML): + primary_criterion: + related_criteria: [list] + framework_tags: {soc2: [...], nist_800_53_r5: [...], iso_27001_2013: [...], cis_v8: [...]} + status: PASS | FAIL + severity: critical | high | medium | low + type: deterministic | agentic + source_tool: + file: + line: + evidence: + policy_clause: + remediation: | + + blocking: + +User: + Finding from Checkov: + rule_id: CKV_AWS_17 + file: terraform/rds.tf + line: 42 + description: Ensure RDS instances have storage encrypted + + Policy clause from Information_Security_Policy.md §4.2: + "All databases storing customer data must use AES-256 encryption at rest + with customer-managed KMS keys." + + Produce the audit finding. +``` + +### Cost and latency considerations + +* Run deterministic engines in parallel; total wall-clock is bounded by the slowest (typically Checkov on a large IaC tree, 30-90 seconds). +* Cache scan results by content hash. Re-running the scanner on a no-op rebase should be near-free. +* Agentic mapping is the expensive step in dollar terms. Batch findings: send 10-20 findings per LLM call, not one at a time. +* For Type II evidence collection (history-walk), schedule as nightly batch, not per-PR. The PR-time scanner produces Type I evidence; the nightly walker accumulates Type II. + +### Failure mode: tool drift + +Open-source engines update rule packs frequently. A passing scan today may fail tomorrow because Checkov shipped a new rule. Pin the engine version in CI. Promote upgrades through a PR like any other dependency. Treat rule-pack diffs as risk-assessment input (CC3.4: changes affecting internal control). diff --git a/app/(dashboard)/expenses/[id]/page.tsx b/app/(dashboard)/expenses/[id]/page.tsx index 1f894a6c..c6ba6838 100644 --- a/app/(dashboard)/expenses/[id]/page.tsx +++ b/app/(dashboard)/expenses/[id]/page.tsx @@ -1,515 +1,10 @@ -'use client' +import { redirect } from 'next/navigation' -import { useState, useEffect } from 'react' -import { useParams, useRouter } from 'next/navigation' -import { Button } from '@/components/ui/button' -import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' -import { Badge } from '@/components/ui/badge' -import { Input } from '@/components/ui/input' -import { Label } from '@/components/ui/label' -import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog' -import { useToast } from '@/components/ui/use-toast' -import { getErrorMessage } from '@/lib/errors/get-error-message' -import { ArrowLeft, CheckCircle, CreditCard, FileText, Trash2 } from 'lucide-react' -import Link from 'next/link' -import { AccountNumber } from '@/components/ui/account-number' -import { DestructiveConfirmDialog, useDestructiveConfirm } from '@/components/ui/destructive-confirm-dialog' -import type { SupplierInvoice, SupplierInvoiceItem, SupplierInvoicePayment, EntityType } from '@/types' - -const statusConfig: Record = { - registered: { label: 'Obetald', color: 'bg-blue-100 text-blue-800' }, - approved: { label: 'Obetald', color: 'bg-yellow-100 text-yellow-800' }, - paid: { label: 'Betald', color: 'bg-success/10 text-success' }, - partially_paid: { label: 'Delbetald', color: 'bg-orange-100 text-orange-800' }, - overdue: { label: 'Förfallen', color: 'bg-destructive/10 text-destructive' }, - disputed: { label: 'Tvist', color: 'bg-purple-100 text-purple-800' }, - credited: { label: 'Krediterad', color: 'bg-gray-100 text-gray-800' }, -} - -function formatAmount(amount: number): string { - return amount.toLocaleString('sv-SE', { minimumFractionDigits: 2, maximumFractionDigits: 2 }) -} - -export default function ExpenseDetailPage() { - const params = useParams() - const router = useRouter() - const { toast } = useToast() - const [invoice, setInvoice] = useState(null) - const [, setEntityType] = useState('enskild_firma') - const [isLoading, setIsLoading] = useState(true) - const [isPayDialogOpen, setIsPayDialogOpen] = useState(false) - const [payAmount, setPayAmount] = useState('') - const [paymentDate, setPaymentDate] = useState(() => new Date().toISOString().split('T')[0]) - const [isProcessing, setIsProcessing] = useState(false) - const { dialogProps: confirmDialogProps, confirm: confirmAction } = useDestructiveConfirm() - - async function fetchInvoice() { - setIsLoading(true) - const res = await fetch(`/api/supplier-invoices/${params.id}`) - const { data, error } = await res.json() - if (error) { - toast({ title: 'Kunde inte ladda utgift', description: error, variant: 'destructive' }) - } else { - setInvoice(data) - setPayAmount(String(data.remaining_amount)) - setPaymentDate(new Date().toISOString().split('T')[0]) - } - setIsLoading(false) - } - - async function fetchEntityType() { - try { - const res = await fetch('/api/settings') - const { data } = await res.json() - if (data?.entity_type) { - setEntityType(data.entity_type) - } - } catch { - // Default to enskild_firma - } - } - - useEffect(() => { - fetchInvoice() - fetchEntityType() - }, [params.id]) - - async function handleApprove() { - setIsProcessing(true) - const res = await fetch(`/api/supplier-invoices/${params.id}/approve`, { method: 'POST' }) - const result = await res.json() - if (!res.ok) { - toast({ title: 'Kunde inte godkänna', description: getErrorMessage(result, { context: 'supplier_invoice' }), variant: 'destructive' }) - } else { - toast({ title: 'Godkänd', description: 'Utgiften har godkänts' }) - fetchInvoice() - } - setIsProcessing(false) - } - - async function handleMarkPaid() { - setIsProcessing(true) - const res = await fetch(`/api/supplier-invoices/${params.id}/mark-paid`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ amount: parseFloat(payAmount), payment_date: paymentDate }), - }) - const result = await res.json() - if (!res.ok) { - toast({ title: 'Betalning misslyckades', description: getErrorMessage(result, { context: 'supplier_invoice' }), variant: 'destructive' }) - } else { - toast({ - title: result.status === 'paid' ? 'Betald' : 'Delbetalning registrerad', - description: `${formatAmount(parseFloat(payAmount))} kr registrerat`, - }) - setIsPayDialogOpen(false) - fetchInvoice() - } - setIsProcessing(false) - } - - async function handleCredit() { - const ok = await confirmAction({ - title: 'Registrera kreditfaktura', - description: 'En kreditfaktura skapas som reverserar den ursprungliga fakturan. Denna åtgärd kan inte ångras.', - confirmLabel: 'Registrera kreditfaktura', - variant: 'warning', - }) - if (!ok) return - setIsProcessing(true) - const res = await fetch(`/api/supplier-invoices/${params.id}/credit`, { method: 'POST' }) - const result = await res.json() - if (!res.ok) { - toast({ title: 'Kunde inte kreditera', description: getErrorMessage(result, { context: 'supplier_invoice' }), variant: 'destructive' }) - } else { - toast({ title: 'Kreditfaktura registrerad' }) - fetchInvoice() - } - setIsProcessing(false) - } - - async function handleDelete() { - const ok = await confirmAction({ - title: 'Ta bort utgift', - description: 'Utgiften och tillhörande data tas bort permanent. Denna åtgärd kan inte ångras.', - confirmLabel: 'Ta bort', - variant: 'destructive', - }) - if (!ok) return - const res = await fetch(`/api/supplier-invoices/${params.id}`, { method: 'DELETE' }) - const result = await res.json() - if (!res.ok) { - toast({ title: 'Kunde inte ta bort', description: getErrorMessage(result, { context: 'supplier_invoice' }), variant: 'destructive' }) - } else { - toast({ title: 'Borttagen' }) - router.push('/expenses') - } - } - - if (isLoading) { - return ( -
-
- -
- ) - } - - if (!invoice) { - return ( -
-

Utgiften hittades inte

- -
- ) - } - - const items = (invoice.items || []) as SupplierInvoiceItem[] - const payments = (invoice.payments || []) as SupplierInvoicePayment[] - const status = statusConfig[invoice.status] || { label: invoice.status, color: '' } - - return ( -
- {/* Header */} -
-
- -
-
-

- Utgift #{invoice.arrival_number} -

- - {status.label} - -
-

- {invoice.supplier?.name} · Faktura {invoice.supplier_invoice_number} -

-
-
- - {/* Context-aware actions */} -
- {invoice.status === 'registered' && ( - <> - - - - )} - {['approved', 'overdue'].includes(invoice.status) && ( - <> - - - - )} - {invoice.status === 'partially_paid' && ( - - )} -
-
- - {/* Card 1: Fakturadetaljer */} - - - Fakturadetaljer - - - {/* Info grid */} -
-
- Leverantör -

- {invoice.supplier ? ( - - {invoice.supplier.name} - - ) : '-'} -

- {invoice.supplier?.org_number && ( -

Org.nr: {invoice.supplier.org_number}

- )} -
-
- Fakturanummer -

{invoice.supplier_invoice_number}

-
-
- Ankomstnummer -

{invoice.arrival_number}

-
-
- Fakturadatum -

{invoice.invoice_date}

-
-
- Förfallodatum -

{invoice.due_date}

-
- {invoice.delivery_date && ( -
- Leveransdatum -

{invoice.delivery_date}

-
- )} - {invoice.payment_reference && ( -
- OCR/referens -

{invoice.payment_reference}

-
- )} -
- - {invoice.reverse_charge && ( - Omvänd skattskyldighet - )} - - {/* Line items */} - {items.length > 0 && ( -
- {/* Desktop: table */} -
- - - - - - - - - - - - {items.map((item) => ( - - - - - - - - ))} - -
BeskrivningKontoMoms%BeloppMoms
{item.description}{Math.round(item.vat_rate * 100)}%{formatAmount(item.line_total)}{formatAmount(item.vat_amount)}
-
- - {/* Mobile: stacked cards */} -
- {items.map((item) => ( -
-
- {item.description || 'Ingen beskrivning'} - -
-
- Belopp - {formatAmount(item.line_total)} -
-
- Moms ({Math.round(item.vat_rate * 100)}%) - {formatAmount(item.vat_amount)} -
-
- ))} -
- - {/* Amounts summary */} -
-
- Netto (exkl. moms) - {formatAmount(invoice.subtotal)} {invoice.currency} -
-
- Moms - {formatAmount(invoice.vat_amount)} {invoice.currency} -
-
- Totalt - {formatAmount(invoice.total)} {invoice.currency} -
-
- Betalt - {formatAmount(invoice.paid_amount)} {invoice.currency} -
-
- Kvar att betala - {formatAmount(invoice.remaining_amount)} {invoice.currency} -
-
-
- )} - - {/* Notes inline */} - {invoice.notes && ( -
-

{invoice.notes}

-
- )} -
-
- - {/* Card 2: Betalningar & bokföring (only if data exists) */} - {(payments.length > 0 || invoice.registration_journal_entry_id) && ( - - - Betalningar & bokföring - - - {/* Payment history */} - {payments.length > 0 && ( -
-

Betalningshistorik

- - {/* Desktop: table */} -
- - - - - - - - - - - {payments.map((p) => ( - - - - - - - ))} - -
DatumBeloppVerifikationAnteckning
{p.payment_date}{formatAmount(p.amount)} {p.currency} - {p.journal_entry_id ? ( - - {p.journal_entry_id.substring(0, 8)}... - - ) : '-'} - {p.notes || '-'}
-
- - {/* Mobile: stacked cards */} -
- {payments.map((p) => ( -
-
- {p.payment_date} - {formatAmount(p.amount)} {p.currency} -
- {p.journal_entry_id && ( -
- Verifikation - - {p.journal_entry_id.substring(0, 8)}... - -
- )} - {p.notes && ( -

{p.notes}

- )} -
- ))} -
-
- )} - - {/* Journal entry links */} -
-

Verifikationer

- {invoice.registration_journal_entry_id ? ( -
- Registreringsverifikation - - {invoice.registration_journal_entry_id.substring(0, 8)}... - -
- ) : ( -

Ingen registreringsverifikation

- )} - {invoice.payment_journal_entry_id && ( -
- Betalningsverifikation - - {invoice.payment_journal_entry_id.substring(0, 8)}... - -
- )} -
-
-
- )} - - - - {/* Pay Dialog */} - - - - Markera som betald - -
-
- - setPaymentDate(e.target.value)} - className="w-full sm:w-48" - /> -
-
- - setPayAmount(e.target.value)} - /> -

- Kvar att betala: {formatAmount(invoice.remaining_amount)} {invoice.currency} -

-
-
- - -
-
-
-
-
- ) +export default async function ExpenseDetailRedirectPage({ + params, +}: { + params: Promise<{ id: string }> +}) { + const { id } = await params + redirect(`/supplier-invoices/${id}`) } diff --git a/app/(dashboard)/expenses/new/page.tsx b/app/(dashboard)/expenses/new/page.tsx index 4772462f..f06b7521 100644 --- a/app/(dashboard)/expenses/new/page.tsx +++ b/app/(dashboard)/expenses/new/page.tsx @@ -1,884 +1,22 @@ -'use client' +import { redirect } from 'next/navigation' -import { useState, useEffect } from 'react' -import { useRouter } from 'next/navigation' -import { useForm, Controller, useFieldArray } from 'react-hook-form' -import { Button } from '@/components/ui/button' -import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' -import { Input } from '@/components/ui/input' -import { Label } from '@/components/ui/label' -import { Textarea } from '@/components/ui/textarea' -import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select' -import { Checkbox } from '@/components/ui/checkbox' -import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from '@/components/ui/dialog' -import { useToast } from '@/components/ui/use-toast' -import { ConfirmationDialog } from '@/components/ui/confirmation-dialog' -import { SupplierInvoiceReviewContent } from '@/components/suppliers/SupplierInvoiceReviewContent' -import AccountCombobox from '@/components/bookkeeping/AccountCombobox' -import { getAccountDescription } from '@/lib/bookkeeping/account-descriptions' -import { getErrorMessage } from '@/lib/errors/get-error-message' -import { useUnsavedChanges } from '@/lib/hooks/use-unsaved-changes' -import { ArrowLeft, Plus, Trash2, ChevronDown, Loader2, Lock } from 'lucide-react' -import { useCanWrite } from '@/lib/hooks/use-can-write' -import type { Supplier, BASAccount, VatTreatment, EntityType } from '@/types' +type SearchParams = Record -interface LineItem { - description: string - amount: number - account_number: string - vat_rate: number -} - -interface FormData { - supplier_id: string - supplier_invoice_number: string - invoice_date: string - due_date: string - delivery_date: string - currency: string - exchange_rate: string - reverse_charge: boolean - payment_reference: string - notes: string - items: LineItem[] -} - -interface NewSupplierForm { - name: string - supplier_type: string - org_number: string - bankgiro: string - plusgiro: string - default_expense_account: string -} - -function formatAmount(amount: number): string { - return amount.toLocaleString('sv-SE', { minimumFractionDigits: 2, maximumFractionDigits: 2 }) -} - -function inferVatTreatment(items: LineItem[], reverseCharge: boolean): VatTreatment { - if (reverseCharge) return 'reverse_charge' - - const rates = new Set(items.map((i) => i.vat_rate)) - if (rates.size === 1) { - const rate = rates.values().next().value! - if (rate === 0.25) return 'standard_25' - if (rate === 0.12) return 'reduced_12' - if (rate === 0.06) return 'reduced_6' - if (rate === 0) return 'exempt' - } - - return 'standard_25' -} - -export default function NewExpensePage() { - const router = useRouter() - const { canWrite } = useCanWrite() - const { toast } = useToast() - const [suppliers, setSuppliers] = useState([]) - const [accounts, setAccounts] = useState([]) - const [entityType, setEntityType] = useState('enskild_firma') - const [isSubmitting, setIsSubmitting] = useState(false) - const [showReview, setShowReview] = useState(false) - const [pendingData, setPendingData] = useState(null) - const [showNewSupplier, setShowNewSupplier] = useState(false) - const [isCreatingSupplier, setIsCreatingSupplier] = useState(false) - const [pendingSupplierSelect, setPendingSupplierSelect] = useState(null) - const [advancedOpen, setAdvancedOpen] = useState(false) - const [newSupplier, setNewSupplier] = useState({ - name: '', - supplier_type: 'swedish_business', - org_number: '', - bankgiro: '', - plusgiro: '', - default_expense_account: '', - }) - - const { register, control, handleSubmit, watch, setValue, formState: { isDirty } } = useForm({ - defaultValues: { - supplier_id: '', - supplier_invoice_number: '', - invoice_date: new Date().toISOString().split('T')[0], - due_date: '', - delivery_date: '', - currency: 'SEK', - exchange_rate: '', - reverse_charge: false, - payment_reference: '', - notes: '', - items: [{ description: '', amount: 0, account_number: '5010', vat_rate: 0.25 }], - }, - }) - - useUnsavedChanges(isDirty) - - const { fields, append, remove } = useFieldArray({ control, name: 'items' }) - const watchedItems = watch('items') - const watchedSupplierId = watch('supplier_id') - const watchedCurrency = watch('currency') - - const isEF = entityType === 'enskild_firma' - - useEffect(() => { - fetchSuppliers() - fetchAccounts() - fetchEntityType() - }, []) - - // Auto-fill due date and defaults when supplier is selected - useEffect(() => { - if (watchedSupplierId) { - const supplier = suppliers.find((s) => s.id === watchedSupplierId) - if (supplier) { - const invoiceDate = watch('invoice_date') - if (invoiceDate) { - const due = new Date(invoiceDate) - due.setDate(due.getDate() + supplier.default_payment_terms) - setValue('due_date', due.toISOString().split('T')[0]) - } - if (supplier.default_expense_account && fields.length > 0) { - setValue('items.0.account_number', supplier.default_expense_account) - } - if (supplier.default_currency) { - setValue('currency', supplier.default_currency) - } - if (supplier.supplier_type === 'eu_business') { - setValue('reverse_charge', true) - } - } - } - }, [watchedSupplierId, suppliers]) - - // Auto-select newly created supplier once it's in the list - useEffect(() => { - if (pendingSupplierSelect && suppliers.find((s) => s.id === pendingSupplierSelect)) { - setValue('supplier_id', pendingSupplierSelect, { shouldDirty: true, shouldValidate: true }) - setPendingSupplierSelect(null) - } - }, [suppliers, pendingSupplierSelect, setValue]) - - async function fetchSuppliers() { - const res = await fetch('/api/suppliers') - const { data } = await res.json() - setSuppliers(data || []) - } - - async function fetchAccounts() { - const res = await fetch('/api/bookkeeping/accounts') - const { data } = await res.json() - setAccounts(data || []) - } - - async function fetchEntityType() { - try { - const res = await fetch('/api/settings') - const { data } = await res.json() - if (data?.entity_type) { - setEntityType(data.entity_type) - } - } catch { - // Default to enskild_firma - } - } - - function handleAccountChange(index: number, accountNumber: string) { - setValue(`items.${index}.account_number`, accountNumber) - const currentDesc = watch(`items.${index}.description`) - if (!currentDesc && accountNumber.length === 4) { - const desc = getAccountDescription(accountNumber) - if (desc) { - setValue(`items.${index}.description`, desc.name) - } - } - } - - // Calculate totals - const itemTotals = (watchedItems || []).map((item) => { - const lineTotal = Math.round((item.amount || 0) * 100) / 100 - const vatAmount = Math.round(lineTotal * (item.vat_rate || 0) * 100) / 100 - return { lineTotal, vatAmount } - }) - - const subtotal = itemTotals.reduce((sum, t) => sum + t.lineTotal, 0) - const totalVat = itemTotals.reduce((sum, t) => sum + t.vatAmount, 0) - const total = Math.round((subtotal + totalVat) * 100) / 100 - - async function handleCreateSupplier() { - if (!newSupplier.name.trim()) { - toast({ title: 'Namn saknas', description: 'Ange ett namn för leverantören.', variant: 'destructive' }) - return - } - setIsCreatingSupplier(true) - - const payload: Record = { - name: newSupplier.name, - supplier_type: newSupplier.supplier_type, - } - if (newSupplier.org_number) payload.org_number = newSupplier.org_number - if (newSupplier.bankgiro) payload.bankgiro = newSupplier.bankgiro - if (newSupplier.plusgiro) payload.plusgiro = newSupplier.plusgiro - if (newSupplier.default_expense_account) payload.default_expense_account = newSupplier.default_expense_account - - const res = await fetch('/api/suppliers', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(payload), - }) - const result = await res.json() - - if (!res.ok) { - toast({ title: 'Kunde inte skapa leverantör', description: getErrorMessage(result, { context: 'supplier' }), variant: 'destructive' }) +export default async function NewExpenseRedirectPage({ + searchParams, +}: { + searchParams: Promise +}) { + const params = await searchParams + const qs = new URLSearchParams() + for (const [key, value] of Object.entries(params)) { + if (value == null) continue + if (Array.isArray(value)) { + for (const v of value) qs.append(key, v) } else { - const created = result.data as Supplier - setSuppliers((prev) => [...prev, created].sort((a, b) => a.name.localeCompare(b.name))) - setPendingSupplierSelect(created.id) - setShowNewSupplier(false) - setNewSupplier({ name: '', supplier_type: 'swedish_business', org_number: '', bankgiro: '', plusgiro: '', default_expense_account: '' }) - toast({ title: 'Leverantör skapad', description: created.name }) - } - - setIsCreatingSupplier(false) - } - - function onSubmit(data: FormData) { - if (!data.supplier_id) { - toast({ title: 'Leverantör saknas', description: 'Välj eller skapa en leverantör.', variant: 'destructive' }) - return - } - if (!data.supplier_invoice_number) { - toast({ title: 'Fakturanummer saknas', description: 'Ange leverantörens fakturanummer.', variant: 'destructive' }) - return - } - - if (isEF) { - // EF: submit directly (auto-approve after create) - setPendingData(data) - handleDirectSubmit(data) - } else { - // AB: show review dialog first - setPendingData(data) - setShowReview(true) + qs.set(key, value) } } - - function buildPayload(data: FormData) { - const vatTreatment = inferVatTreatment(data.items, data.reverse_charge) - return { - supplier_id: data.supplier_id, - supplier_invoice_number: data.supplier_invoice_number, - invoice_date: data.invoice_date, - due_date: data.due_date, - delivery_date: data.delivery_date || undefined, - currency: data.currency, - exchange_rate: data.exchange_rate ? parseFloat(data.exchange_rate) : undefined, - vat_treatment: vatTreatment, - reverse_charge: data.reverse_charge, - payment_reference: data.payment_reference || undefined, - notes: data.notes || undefined, - items: data.items.map((item) => ({ - description: item.description, - amount: item.amount, - account_number: item.account_number, - vat_rate: item.vat_rate, - })), - } - } - - // EF flow: create + auto-approve - async function handleDirectSubmit(data: FormData) { - setIsSubmitting(true) - - const res = await fetch('/api/supplier-invoices', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(buildPayload(data)), - }) - const result = await res.json() - - if (!res.ok) { - toast({ title: 'Kunde inte registrera utgift', description: getErrorMessage(result, { context: 'supplier_invoice', statusCode: res.status }), variant: 'destructive' }) - setIsSubmitting(false) - return - } - - // Auto-approve for EF - const approveRes = await fetch(`/api/supplier-invoices/${result.data.id}/approve`, { method: 'POST' }) - if (!approveRes.ok) { - toast({ - title: 'Varning', - description: 'Utgiften skapades men kunde inte godkännas automatiskt', - variant: 'destructive', - }) - router.push(`/expenses/${result.data.id}`) - } else { - toast({ title: 'Utgift registrerad', description: `Ankomstnummer: ${result.data.arrival_number}` }) - router.push('/expenses') - } - - setIsSubmitting(false) - } - - // AB flow: create after review dialog confirmation - async function handleConfirm() { - if (!pendingData) return - setIsSubmitting(true) - - const res = await fetch('/api/supplier-invoices', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(buildPayload(pendingData)), - }) - const result = await res.json() - - if (!res.ok) { - toast({ title: 'Kunde inte registrera utgift', description: getErrorMessage(result, { context: 'supplier_invoice', statusCode: res.status }), variant: 'destructive' }) - } else { - toast({ title: 'Utgift registrerad', description: `Ankomstnummer: ${result.data.arrival_number}` }) - setShowReview(false) - router.push(`/expenses/${result.data.id}`) - } - - setIsSubmitting(false) - } - - return ( -
-
- -
-

Ny utgift

-

- Registrera en inkommande faktura -

-
-
- -
- {/* Section 1: Faktura */} - - - Faktura - - -
-
- - ( - - )} - /> -
-
- - -
-
-
-
- - -
-
- - -
-
- - -
-
-
-
- - {/* Section 2: Kontering */} - - - Kontering - - - - {/* Desktop: table layout */} -
- - - - - - - - - - - - - {fields.map((field, index) => ( - - - - - - - - - ))} - -
KontoBeskrivningBelopp (exkl.)MomssatsMoms
- ( - handleAccountChange(index, val)} - /> - )} - /> - - ( - - )} - /> - - ( - { - const parsed = parseFloat(e.target.value) - field.onChange(e.target.value === '' || isNaN(parsed) ? 0 : parsed) - }} - /> - )} - /> - - ( - - )} - /> - - {formatAmount(itemTotals[index]?.vatAmount || 0)} - - {fields.length > 1 && ( - - )} -
-
- - {/* Mobile: stacked card layout */} -
- {fields.map((field, index) => ( -
-
- Rad {index + 1} - {fields.length > 1 && ( - - )} -
-
- - ( - handleAccountChange(index, val)} - /> - )} - /> -
-
- - ( - - )} - /> -
-
-
- - ( - field.onChange(e.target.value === '' ? 0 : parseFloat(e.target.value) || 0)} - /> - )} - /> -
-
- - ( - - )} - /> -
-
-
- Moms - {formatAmount(itemTotals[index]?.vatAmount || 0)} kr -
-
- ))} -
- - {/* Totals */} -
-
- Netto (exkl. moms) - {formatAmount(subtotal)} kr -
-
- Moms - {formatAmount(totalVat)} kr -
-
- Totalt - {formatAmount(total)} kr -
-
-
-
- - {/* Section 3: Övrigt (collapsible) */} - - setAdvancedOpen(!advancedOpen)} - > -
- Övrigt - -
-
- {advancedOpen && ( - -
-
- - ( - - )} - /> -
- {watchedCurrency !== 'SEK' && ( -
- - -
- )} -
-
- - -
-
- ( - - )} - /> - -
-
- -