# -------------------------------------------------------------------------------------
#  Copyright (c) DevSecCode. All rights reserved.
#  Licensed under the MIT License. See LICENSE.txt in the project root for license
#  information.
# -------------------------------------------------------------------------------------

"""Canonical scope disclaimer text for the compliance engine.

Phase 6 of the compliance evolution plan. Single source of truth for every
surface that displays a compliance score: the IDE posture editor banner, the
first-use modal, OSCAL AR `metadata.props`, API response envelopes, the CLI
footer, the evidence-package `DISCLAIMER.md`, and per-framework hover
tooltips.

Why this exists. Deva evaluates code-level technical controls. A customer
reading "HIPAA 85%" without context could conclude they are 85 percent
HIPAA compliant overall -- which is false. HIPAA requires Business
Associate Agreements, workforce training, physical safeguards, and a great
deal of administrative process that no static analyzer can verify. This
module provides the legally reviewed text that disambiguates "code-level
posture" from "regulatory compliance."

All text is plain ASCII (no smart quotes, no em-dashes) so it round-trips
through every renderer without escaping surprises.
"""

from __future__ import annotations

from dataclasses import dataclass


# Schema namespace for the scope prop in OSCAL output. Reused by the
# emitter and any downstream tool that wants to read Deva-specific fields.
DEVA_OSCAL_NS = "https://devseccode.com/oscal/ns/v1"

# Scope value embedded in the OSCAL prop and the API response envelope.
# Stable identifier; do not change without updating downstream consumers.
SCOPE_VALUE = "code-level-technical-controls-only"

# Short label for tight UI surfaces (badges, status bars).
SCOPE_LABEL_SHORT = "Code-level controls only"


# ---------------------------------------------------------------------------
# Canonical disclaimer text
# ---------------------------------------------------------------------------

# Banner text. Shown persistently above any framework score in the IDE
# posture editor and at the top of every signed evidence package's
# DISCLAIMER.md. Two short sentences; longer text goes in the modal.
BANNER_TEXT = (
	"Deva evaluates code-level technical controls only. "
	"Compliance scores reflect what static analysis can verify and do not "
	"constitute regulatory compliance, certification, or audit attestation."
)

# Modal text. Shown on first use; the user must acknowledge before the
# compliance posture editor becomes interactive. Stored in workspace
# settings under devsecScanner.complianceDisclaimerAcknowledged so the
# acknowledgment doesn't repeat.
MODAL_TITLE = "About Deva compliance scores"

MODAL_BODY = (
	"Deva is a code-level static analyzer. Its compliance scoring maps "
	"detected vulnerabilities and code patterns to control identifiers in "
	"the named framework. This is one input to compliance, not a "
	"compliance verdict.\n"
	"\n"
	"What Deva covers:\n"
	"  - Code-detectable technical controls (e.g., SQL injection, "
	"hardcoded secrets, missing TLS, weak crypto, access-control errors).\n"
	"  - Sensitive-data type detection (PHI, PAN, PII, CUI) where present "
	"in source.\n"
	"  - Software bill of materials and known-vulnerable dependency "
	"detection.\n"
	"  - Attestation tracking for controls that are not code-detectable.\n"
	"\n"
	"What Deva does NOT cover:\n"
	"  - Administrative, physical, or organizational safeguards.\n"
	"  - Workforce training, governance, or policy review.\n"
	"  - Vendor risk, BAAs, contracts, or third-party assessments.\n"
	"  - Runtime monitoring, network security, or production "
	"infrastructure scanning.\n"
	"  - Auditor judgment, legal interpretation, or formal certification.\n"
	"\n"
	"Each framework has additional scope warnings shown when you hover "
	"its percentage. Evidence packages include this disclaimer at the top "
	"level and are signed for tamper detection. They are intended to "
	"feed into a broader compliance program, not to replace one."
)

# CLI footer. Appended to the bottom of any `dsc` output that displays
# compliance scores (one line so it doesn't bury structured output).
CLI_FOOTER = (
	"NOTE: Deva evaluates code-level technical controls only. "
	"Scores are not regulatory compliance, certification, or audit "
	"attestation. See https://docs.devseccode.com/compliance/scope."
)

# Evidence-package cover. Top-level DISCLAIMER.md inside the signed
# tarball. Long form -- this is what an auditor or procurement reviewer
# reads when they unpack the evidence.
EVIDENCE_DISCLAIMER_MD = """\
# Scope Disclaimer

Deva is a code-level static analyzer. Its compliance scoring maps
detected vulnerabilities and code patterns to control identifiers in the
named framework. **This is one input to compliance, not a compliance
verdict.**

## What this evidence package contains

- SARIF findings for code-detectable technical issues.
- An OSCAL Assessment Results (AR) document mapping findings to controls.
- A JSON compliance report with per-framework scoring.
- Attestations for controls that are not code-detectable.
- Software bill of materials artifacts where applicable.
- A signed manifest with SHA-256 hashes over every artifact and an
  Ed25519 signature over the manifest itself.

## What this evidence package is NOT

- Not a finding of regulatory compliance for any named framework.
- Not a certification or accreditation.
- Not an audit opinion.
- Not a substitute for the administrative, physical, organizational,
  governance, vendor, training, and policy controls that make up the
  bulk of any real compliance program.

## How to use this package

Treat it as one technical input to a broader compliance effort:

1. Provide it to your security team or auditor alongside other
   evidence (policies, training records, BAAs, etc.).
2. Verify the signature with `dsc evidence-verify` to confirm the
   package has not been tampered with.
3. Resolve all CRITICAL and HIGH findings; review attested controls
   for accuracy.

Each framework has additional scope notes -- see the per-framework
warnings emitted with each score in the source IDE or via the
`/api/compliance/evaluate` endpoint.
"""


# ---------------------------------------------------------------------------
# Per-framework warnings
# ---------------------------------------------------------------------------


@dataclass(frozen=True, slots=True)
class FrameworkScopeWarning:
	"""Per-framework caveat shown next to a framework's score.

	Two strings: a short tooltip line shown on hover, and a longer
	explanation rendered in the posture editor's expanded view and the
	evidence package per-framework section.
	"""

	framework_id: str
	short: str  # Single line for hover tooltips.
	long: str  # Multi-line rendered text.


# Keyed by canonical framework id (lowercased, hyphenless where the seed
# uses a hyphen — see the seed _meta blocks). Aliases for common variants
# are provided via :func:`for_framework`.
_PER_FRAMEWORK: dict[str, FrameworkScopeWarning] = {
	"hipaa": FrameworkScopeWarning(
		framework_id="HIPAA",
		short=(
			"Excludes BAAs, workforce training, physical safeguards, "
			"and 164.308 administrative requirements not visible in code."
		),
		long=(
			"HIPAA Security Rule compliance requires a Risk Analysis, "
			"workforce training, sanction policies, Business Associate "
			"Agreements with every vendor handling ePHI, and physical "
			"facility safeguards. Deva can verify code-detectable "
			"technical safeguards under 45 CFR 164.312 (access control, "
			"audit controls, integrity, transmission security) and a "
			"subset of administrative safeguards via attestation. "
			"It cannot perform Risk Analysis, replace BAAs, or attest "
			"workforce competence."
		),
	),
	"pci-dss": FrameworkScopeWarning(
		framework_id="PCI-DSS",
		short=(
			"Excludes QSA assessment, network segmentation testing, "
			"and SAQ self-assessment workflow."
		),
		long=(
			"PCI DSS v4.0 compliance requires either a Qualified Security "
			"Assessor (QSA) report or a completed Self-Assessment "
			"Questionnaire (SAQ) appropriate to the merchant level. "
			"Deva covers code-detectable controls in Reqs 3, 4, 6, 7, 8, "
			"10, and 11 (PAN protection, secure transmission, secure "
			"development, access control, authentication, audit logs, "
			"vulnerability scanning) but cannot perform network "
			"segmentation testing, validate cardholder-data-environment "
			"boundary controls in production, or substitute for QSA "
			"sign-off on Report on Compliance."
		),
	),
	"soc2": FrameworkScopeWarning(
		framework_id="SOC 2",
		short=(
			"Excludes auditor assessment of CC1-CC5 control environment "
			"and CC7-CC9 monitoring/incident-response activities."
		),
		long=(
			"SOC 2 reports require a licensed CPA firm to attest to the "
			"design and operating effectiveness of controls under the "
			"AICPA Trust Services Criteria. Deva can surface evidence "
			"for code-detectable controls under CC6 (logical access), "
			"CC7 (system operations), and CC5 (technology general "
			"controls) but cannot substitute for auditor judgment on "
			"control environment (CC1), risk assessment (CC3), or "
			"monitoring activities (CC4)."
		),
	),
	"nist-800-53": FrameworkScopeWarning(
		framework_id="NIST 800-53",
		short=(
			"Excludes program management, personnel security, "
			"contingency planning, and most PE/PS/PM family controls."
		),
		long=(
			"NIST SP 800-53 Rev 5 covers the full security and privacy "
			"control catalog used in federal authorization. Deva "
			"implements the code-relevant subset across AC, AU, CM, IA, "
			"SC, SI, and IR families. The catalog also includes PE "
			"(physical/environmental), PS (personnel security), PM "
			"(program management), AT (awareness/training), and CP "
			"(contingency planning) families that are out of scope for "
			"static analysis. Use Deva alongside an SSP, POA&M, and "
			"3PAO assessment for an authorization package."
		),
	),
	"gdpr": FrameworkScopeWarning(
		framework_id="GDPR",
		short=(
			"Excludes lawful basis determination, DPIA, DPO appointment, "
			"and DSAR fulfillment workflow."
		),
		long=(
			"GDPR compliance requires a documented lawful basis under "
			"Article 6, a Data Protection Impact Assessment for "
			"high-risk processing (Article 35), data subject access "
			"request (DSAR) workflow, breach notification within 72 "
			"hours, and (for many controllers) a designated Data "
			"Protection Officer. Deva detects PII in code paths and "
			"flags right-to-erasure and cross-border transfer signals, "
			"but cannot determine lawful basis, fulfill DSARs, or "
			"replace a DPIA. Engage data protection counsel before "
			"relying on Deva output for GDPR posture."
		),
	),
	"iso27001": FrameworkScopeWarning(
		framework_id="ISO 27001",
		short=(
			"Excludes ISMS scope definition, risk treatment plan, "
			"management review, and certification body audit."
		),
		long=(
			"ISO/IEC 27001 certification requires a documented "
			"Information Security Management System (ISMS), risk "
			"assessment and treatment plan, statement of applicability, "
			"management review cadence, and a stage 1/stage 2 audit by "
			"an accredited certification body. Deva covers code-relevant "
			"Annex A controls under A.5, A.8, and A.12 themes, but "
			"cannot perform certification-body audits or substitute for "
			"the ISMS documentation expected by a certification body."
		),
	),
	"fedramp": FrameworkScopeWarning(
		framework_id="FedRAMP",
		short=(
			"Excludes 3PAO assessment, SSP authoring, POA&M tracking, "
			"and continuous monitoring program."
		),
		long=(
			"FedRAMP authorization at any baseline (Low/Moderate/High) "
			"requires a Third Party Assessment Organization (3PAO) "
			"assessment, a System Security Plan, a Plan of Action and "
			"Milestones, and continuous-monitoring deliverables on a "
			"defined cadence. Deva supplies code-level evidence in the "
			"OSCAL AR format expected by RFC-0024 (mandatory September "
			"2026) but does not produce the SSP/POA&M, perform the "
			"3PAO role, or run the continuous-monitoring program."
		),
	),
	"cmmc": FrameworkScopeWarning(
		framework_id="CMMC",
		short=(
			"Excludes C3PAO assessment, SPRS submission, "
			"and contracting officer scope determination."
		),
		long=(
			"CMMC Level 2 and Level 3 require a Certified Third Party "
			"Assessment Organization (C3PAO) assessment and SPRS score "
			"submission. Level 1 allows annual self-assessment. Deva "
			"covers the NIST 800-171 / 800-172 code-detectable practices "
			"and emits SPRS-aware evidence, but cannot perform the C3PAO "
			"role or replace contracting-officer scope determinations."
		),
	),
	"owasp-top10": FrameworkScopeWarning(
		framework_id="OWASP Top 10",
		short=(
			"Awareness framework, not a certification or audit standard."
		),
		long=(
			"The OWASP Top 10 is an awareness document, not an audit "
			"standard. Deva uses it as a categorization layer over its "
			"finding output. There is no certification body for OWASP "
			"Top 10 compliance. Use OWASP ASVS or a framework-specific "
			"audit standard (PCI, HIPAA, SOC 2) for assurance contexts."
		),
	),
}


# Aliases that show up in seeds, rule metadata, and API requests. The
# canonical id (key in :data:`_PER_FRAMEWORK`) is what gets returned.
_FRAMEWORK_ALIASES: dict[str, str] = {
	"hipaa": "hipaa",
	"hipaa-security-rule": "hipaa",
	"pci": "pci-dss",
	"pci-dss": "pci-dss",
	"pci_dss": "pci-dss",
	"pcidss": "pci-dss",
	"soc2": "soc2",
	"soc-2": "soc2",
	"soc_2": "soc2",
	"nist": "nist-800-53",
	"nist-800-53": "nist-800-53",
	"nist_800_53": "nist-800-53",
	"nist80053": "nist-800-53",
	"gdpr": "gdpr",
	"iso27001": "iso27001",
	"iso-27001": "iso27001",
	"iso_27001": "iso27001",
	"fedramp": "fedramp",
	"cmmc": "cmmc",
	"cmmc2": "cmmc",
	"owasp": "owasp-top10",
	"owasp-top10": "owasp-top10",
	"owasp-top-10": "owasp-top10",
	"owasp_top10": "owasp-top10",
	"owasp_top_10": "owasp-top10",
	"owasptop10": "owasp-top10",
}


def for_framework(framework_id: str) -> FrameworkScopeWarning | None:
	"""Return the per-framework warning for *framework_id*, or ``None``.

	Aliases (``"PCI"``, ``"PCI_DSS"``, ``"NIST"``) resolve to the canonical
	id. Returns ``None`` for frameworks without a curated warning so the
	caller can fall back to the generic banner text.
	"""
	if not framework_id:
		return None
	canonical = _FRAMEWORK_ALIASES.get(framework_id.lower().replace(" ", "-"))
	if canonical is None:
		return None
	return _PER_FRAMEWORK.get(canonical)


def all_warnings() -> list[FrameworkScopeWarning]:
	"""Return every per-framework warning, sorted by framework id."""
	return sorted(_PER_FRAMEWORK.values(), key=lambda w: w.framework_id)


# ---------------------------------------------------------------------------
# Helpers for callers
# ---------------------------------------------------------------------------


def evidence_disclaimer_bytes() -> bytes:
	"""Return the DISCLAIMER.md body as UTF-8 bytes for tarball insertion."""
	return EVIDENCE_DISCLAIMER_MD.encode("utf-8")


def api_scope_envelope(framework_ids: list[str] | None = None) -> dict:
	"""Build the ``scope`` envelope returned by every compliance API endpoint.

	Includes the canonical scope value, the short banner, and per-framework
	warnings for the frameworks the response covers (so a single API call
	tells the consumer everything they need to render correctly).
	"""
	per_framework: list[dict] = []
	if framework_ids:
		for fid in framework_ids:
			w = for_framework(fid)
			if w is None:
				continue
			per_framework.append({
				"frameworkId": w.framework_id,
				"short": w.short,
				"long": w.long,
			})
	return {
		"value": SCOPE_VALUE,
		"label": SCOPE_LABEL_SHORT,
		"banner": BANNER_TEXT,
		"perFramework": per_framework,
	}


def oscal_scope_prop() -> dict:
	"""Return the Deva-namespaced OSCAL prop describing scope.

	OSCAL ``props`` entries take ``{ns, name, value, ...}``. The emitter
	attaches this to ``metadata.props`` so any downstream OSCAL consumer
	can read the scope without parsing free-text fields.
	"""
	return {
		"ns": DEVA_OSCAL_NS,
		"name": "scope",
		"value": SCOPE_VALUE,
		"remarks": BANNER_TEXT,
	}
