diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md new file mode 100644 index 00000000..aa9e708f --- /dev/null +++ b/ARCHITECTURE.md @@ -0,0 +1,37 @@ +# Architecture + +Canonical product architecture for `contextual-orchestrator` lives in +[`docs/architecture.md`](docs/architecture.md). + +## Role + +Org LLM gateway: OpenAI-compatible front door with cost-aware routing, sync vs +batch policy, multi-agent conduct path (thinker → worker → verifier → +synthesizer), KV-backed credentials, and commercial evidence surfaces. + +## Control flow + +```text +Client → server.py (auth / validate) + → TaskOrchestrator.complete + ├─ route (single worker; optional price_per_million tie-break) + └─ conduct (workflow steps + access lists) + → ModelClient (mock:// or HTTPS; retries; failover; circuit breaker) + → OpenAI-shaped completion / SSE +``` + +## Security & compliance notes + +- Runtime secrets: `get_credential` (KV), not request-time `os.getenv`. +- Provider egress: block loopback/private/reserved; TLS verify by default. +- Release authorization evidence is fail-closed on exact protected-head checks + (see `docs/commercial_release_candidate.md`). +- Vulnerability disclosure: `SECURITY.md` and + `docs/doctoring/security-disclosure-lifecycle.md` (ISO/IEC 29147 / 30111; + NIST SSDF). + +## Research grounding + +Paper-backed routing claims (Fugu, TRINITY, Conductor) are contracted in +`tests/test_paper_contracts.py` and summarized in `docs/architecture.md` with +APA 7th citations under `docs/papers/` when redistribution permits. diff --git a/SECURITY.md b/SECURITY.md index feaf4123..39267345 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,18 +1,66 @@ # Security Policy +This policy defines the public vulnerability-reporting and coordinated-disclosure boundary for `ContextualWisdomLab/contextual-orchestrator`. It is informed by ISO/IEC 29147:2018 for vulnerability disclosure and ISO/IEC 30111:2019 for vulnerability handling. The evidence basis and review dates are recorded in `docs/doctoring/security-disclosure-lifecycle.md`. + +## Supported Versions + +No stable release currently exists, and `main` is not a supported release. +When the first stable release is published, this section will name its supported +version or release line. + +Security fixes are prepared for the latest supported release and, when a vulnerability materially affects an older release that is still explicitly supported, for that supported line as well. Development branches, historical tags, archived artifacts, forks, and unreleased commits are not represented as supported production versions merely because they remain accessible. + +When no stable release has been published, `main` is the integration reference but is not itself a release-support promise. A GitHub Security Advisory or release advisory is the authoritative place to identify affected and patched versions for a specific vulnerability. + +## Scope + +In scope are vulnerabilities in this repository's maintained source, packaging, release artifacts, provider-neutral orchestration interfaces, authentication and credential boundaries, network egress controls, persistence boundaries, and first-party GitHub Actions workflows. + +Reports about third-party services or dependencies are useful when they demonstrate an impact on this project, but upstream-only defects should normally be reported to the responsible upstream maintainer. Findings in unrelated ContextualWisdomLab repositories should be reported through those repositories' own security channels. Do not use a vulnerability report as authorization to test third-party infrastructure, access data that is not yours, degrade service, or bypass provider terms. + ## Reporting a Vulnerability -Report suspected vulnerabilities through GitHub private vulnerability reporting for `ContextualWisdomLab/contextual-orchestrator`: +Use GitHub private vulnerability reporting for `ContextualWisdomLab/contextual-orchestrator` whenever it is available: https://github.com/ContextualWisdomLab/contextual-orchestrator/security/advisories/new +A useful report includes the affected component and version or commit, prerequisites, reproducible steps, observed impact, expected impact boundary, and any safe proof-of-concept material needed to validate the issue. Remove credentials, personal data, private model reasoning, and unrelated customer or provider data. + If private reporting is unavailable, open a public issue that contains only a request for a secure disclosure channel. Do not include exploit details, secrets, personal data, or unreleased vulnerability details in a public issue. -## Response Process +Before any stable release, maintainers must verify that private vulnerability +reporting is enabled and that security-notification recipients are configured. +If that private channel cannot be maintained, release authorization remains +blocked until this policy names a monitored alternative private contact. + +## Coordinated Disclosure Lifecycle + +1. **Receive and acknowledge.** Maintainers triage a private report and aim to acknowledge a credible report within 5 business days. This acknowledgement target is a communication objective, not a remediation SLA and not a promise that validation or a fix will complete within five days. +2. **Validate and scope.** Maintainers reproduce the report where practical, classify affected versions and deployment assumptions, identify downstream or multi-vendor coordination needs, and keep unpatched technical details private. +3. **Remediate and verify.** A fix is developed through a private security collaboration or another access-controlled path when premature disclosure would increase risk. Security-sensitive fixes must retain the repository's tests, coverage, security scanning, provenance, branch-protection, and independent-review requirements rather than bypass them. +4. **Coordinate release.** Maintainers and the reporter coordinate a disclosure point that reasonably allows a verified fix or mitigation to be available. Multi-vendor issues may require additional coordination time. +5. **Publish evidence.** When disclosure is appropriate, publish a GitHub Security Advisory and release or upgrade guidance that identifies affected versions, impact, remediation or mitigation, and patched versions. Request a CVE through the applicable advisory process when warranted and available. +6. **Learn and prevent recurrence.** Record the relevant root-cause class, regression evidence, and preventive control without publishing credentials, private data, or unnecessary exploit-enabling detail. + +Reporter credit is offered when requested and appropriate, subject to the reporter's preference, coordinated-disclosure needs, and GitHub advisory capabilities. A reporter may also request not to be credited. + +## Safe Harbor and Research Boundaries + +We support good-faith security research that stays within the scope above, avoids privacy violations and service degradation, uses the minimum access needed to demonstrate the issue, stops when unintended sensitive data is encountered, and gives maintainers a reasonable opportunity to remediate before public disclosure. This policy does not authorize activity against third-party systems, physical systems, accounts or data you do not control, or conduct prohibited by applicable law or provider terms. + +Do not intentionally persist, download, modify, or disclose data that is not yours. Do not perform denial-of-service testing, social engineering, credential stuffing, destructive testing, or high-volume automated probing against production services. If testing unexpectedly exposes sensitive information, stop, preserve only the minimum evidence needed to report the issue, and disclose it privately. + +## Advisory and Release Evidence + +A vulnerability is not considered remediated merely because a patch exists on a branch. The [canonical release guide](docs/RELEASE_GUIDE.md) governs the release-evidence states. Release evidence must identify the exact integrated revision and the released revision and must not treat queued, pending, skipped-required, cancelled, failed, absent, stale-head, predecessor-head, author-only, status-only, synthetic-merge-only, rate-limited, or infrastructure-only evidence as passing. Security advisories should identify the affected and patched version ranges and link to release or upgrade guidance when practical. + +This policy does not replace repository merge policy: qualifying independent review, unresolved-finding disposition, required checks, branch protection, packaging, provenance, and release-acceptance controls remain authoritative for security releases. -- A maintainer should acknowledge a valid private report within 5 business days. -- Security fixes should be handled on a private branch until the patch is ready to publish. -- Public disclosure should include affected versions, impact, mitigation, and upgrade guidance. +The canonical [threat model](docs/THREAT_MODEL.md) defines assets, trust zones, +abuse cases, controls, and residual risk. The [incident +runbook](docs/INCIDENT_RUNBOOK.md) defines triage, containment, evidence +preservation, recovery, and post-incident acceptance. Neither document claims +an external certification or attestation. ## Automated Checks diff --git a/contextual_orchestrator/cost_ledger.py b/contextual_orchestrator/cost_ledger.py index d3943c5b..dfed0de2 100644 --- a/contextual_orchestrator/cost_ledger.py +++ b/contextual_orchestrator/cost_ledger.py @@ -583,7 +583,7 @@ def _seed_dimension_catalog(self) -> None: ph = self._placeholder() cur = self._conn.cursor() for order, (name, label, _column) in enumerate(ATTRIBUTION_DIMENSION_CATALOG): - cur.execute( + cur.execute( # nosemgrep -- sqlalchemy-execute-raw-query FP: only the DB-API placeholder char is interpolated; the value is bound. f"SELECT 1 FROM cost_attribution_dimensions WHERE dimension_name = {ph}", # nosec B608 - ph is a DB-API placeholder. (name,), ) @@ -602,7 +602,7 @@ def append(self, record: UsageRecord) -> None: placeholders = ", ".join(ph for _ in _USAGE_COLUMNS) columns = ", ".join(_USAGE_COLUMNS) cur = self._conn.cursor() - cur.execute( + cur.execute( # nosemgrep -- sqlalchemy-execute-raw-query FP: columns are the fixed _USAGE_COLUMNS constant; values are bound. f"INSERT INTO llm_usage_records ({columns}) VALUES ({placeholders})", # nosec B608 - columns are fixed _USAGE_COLUMNS. tuple(row.get(column) for column in _USAGE_COLUMNS), ) @@ -622,7 +622,7 @@ def query(self, start: Optional[int] = None, end: Optional[int] = None) -> List[ where = f" WHERE {' AND '.join(clauses)}" if clauses else "" columns = ", ".join(_USAGE_COLUMNS) cur = self._conn.cursor() - cur.execute(f"SELECT {columns} FROM llm_usage_records{where}", tuple(params)) # nosec B608 - columns and clauses are fixed. + cur.execute(f"SELECT {columns} FROM llm_usage_records{where}", tuple(params)) # nosec B608 - columns and clauses are fixed. # nosemgrep -- sqlalchemy-execute-raw-query FP: fixed columns and clause templates; all values are bound. return [dict(zip(_USAGE_COLUMNS, values)) for values in cur.fetchall()] diff --git a/contextual_orchestrator/orchestrator.py b/contextual_orchestrator/orchestrator.py index 0097b722..974d26c5 100644 --- a/contextual_orchestrator/orchestrator.py +++ b/contextual_orchestrator/orchestrator.py @@ -230,7 +230,7 @@ def __init__( @staticmethod def _build_ssl_context(ca_bundle: str | None, verify_tls: bool) -> ssl.SSLContext: if not verify_tls: - return ssl._create_unverified_context() # nosec B323 - explicit dev-only provider TLS opt-out. + return ssl._create_unverified_context() # nosec B323 - explicit dev-only provider TLS opt-out. # nosemgrep -- unverified-ssl-context: intentional, default-secure (verify_tls defaults True) dev-only opt-out for self-signed endpoints. if ca_bundle: if not os.path.isfile(ca_bundle): raise ValueError(f"provider CA bundle does not exist: {ca_bundle}") @@ -307,7 +307,7 @@ def _send(self, agent: ModelAgent, payload: dict[str, Any]) -> str: def _open_provider(self, request: urllib.request.Request) -> Any: """Open a provider request built from a validated provider URL.""" - return urllib.request.urlopen( # nosec B310 - request URL comes from _provider_url after provider validation. + return urllib.request.urlopen( # nosec B310 - request URL comes from _provider_url after provider validation. # nosemgrep -- dynamic-urllib-use: URL is built by _provider_url after scheme/host validation; egress to loopback/private/reserved is blocked. request, timeout=self.timeout, context=self._ssl_context, diff --git a/docs/doctoring/security-disclosure-lifecycle.md b/docs/doctoring/security-disclosure-lifecycle.md new file mode 100644 index 00000000..de2c9d9f --- /dev/null +++ b/docs/doctoring/security-disclosure-lifecycle.md @@ -0,0 +1,68 @@ +# Security disclosure lifecycle doctoring + +## Decision + +`SECURITY.md` defines a bounded coordinated vulnerability disclosure and handling lifecycle rather than only a reporting address. The policy separates communication targets from remediation guarantees, keeps unpatched details private, preserves repository release gates for security fixes, and identifies exact released-version evidence as the authoritative remediation boundary. + +The policy is intentionally repository-local. It does not authorize testing of third-party providers or other ContextualWisdomLab repositories and does not convert access to public endpoints into permission for destructive, privacy-invasive, or high-volume testing. + +## Primary evidence reviewed + +Evidence was rechecked on 2026-08-08 against primary publisher documentation. + +### ISO/IEC 29147:2018 + +ISO identifies ISO/IEC 29147:2018, *Information technology — Security techniques — Vulnerability disclosure*, as the current published second edition. ISO states that the standard provides requirements and recommendations for receiving reports about potential vulnerabilities and disclosing remediation information. ISO's catalogue states that this edition was last reviewed and confirmed in 2024 and remains current. This supports a documented private-reporting path, disclosure coordination, affected/remediated-version communication, and explicit policy boundaries. + +### ISO/IEC 30111:2019 + +ISO identifies ISO/IEC 30111:2019, *Information technology — Security techniques — Vulnerability handling processes*, as the current published second edition. ISO states that it covers processing and remediating reported potential vulnerabilities. ISO's catalogue states that this edition was reviewed and confirmed in 2025 and remains current. This supports the receive → validate/scope → remediate/verify → coordinate release → publish → learn lifecycle in `SECURITY.md`. + +### GitHub vulnerability reporting and repository advisories + +GitHub's current documentation describes GitHub private vulnerability reporting as a structured private channel for public repositories when the feature is enabled. GitHub also documents the repository security advisory workflow as a private collaboration mechanism for discussing, fixing, and publishing vulnerability information. GitHub recommends that `SECURITY.md` explain supported versions and reporting instructions. These sources support the repository's primary reporting URL, public-issue fallback that contains no exploit detail, private remediation collaboration, reporter credit, and advisory publication boundary. + +### NIST SSDF status + +NIST SP 800-218 Rev. 1, Secure Software Development Framework Version 1.2, is currently an **Initial Public Draft**, published 2025-12-17; its public comment period has closed. The official NIST publication metadata lists Harold Booth, Michael Ogata, Karen Kent, Murugiah Souppaya, and Donna Dodson as the authors and identifies DOI `10.6028/NIST.SP.800-218r1.ipd`. It is therefore contextual acquisition and secure-development evidence, not a finalized normative requirement. NIST describes SSDF as a common set of practices for reducing vulnerabilities and notes its usefulness in supplier/acquirer communication. The repository policy uses that evidence only to reinforce the need for verified remediation and release evidence; ISO/IEC 29147 and ISO/IEC 30111 remain the primary disclosure/handling standards cited by the policy. + +## Repository contract + +The bounded buyer-visible contract is aligned with the canonical +[`docs/RELEASE_GUIDE.md`](../RELEASE_GUIDE.md): + +1. No stable release currently exists, and `main` is not a supported release. When a stable release is published, its supported version or release line becomes the default support boundary; an advisory may explicitly include additional supported release lines. +2. `main`, development branches, archived artifacts, forks, and historical tags are not automatically represented as supported releases. +3. Private vulnerability reporting is the preferred channel. Its enablement and security-notification recipients are stable-release admission checks. If unavailable, a public issue may request a secure channel but must not disclose exploit details, secrets, personal data, or unreleased vulnerability details; release authorization remains blocked until a monitored alternative private contact is documented. +4. The five-business-day acknowledgement target is a communication objective and **not a remediation SLA**. +5. Security remediation follows normal exact-head security, coverage, provenance, independent-review, branch-protection, packaging, and release-acceptance gates; urgency does not create a bypass. +6. A GitHub Security Advisory should identify affected and patched versions and may request a CVE when warranted and available. +7. Reporter credit is opt-in/appropriate to the coordinated-disclosure context and may be declined. +8. Release evidence for the exact integrated revision fails closed: queued, pending, skipped-required, cancelled, failed, absent, stale-head, predecessor-head, author-only, status-only, synthetic-merge-only, rate-limited, or infrastructure-only evidence is not passing evidence. +9. The safe-harbor language is bounded good-faith guidance, not authorization against third parties or systems/data the researcher does not control. + +## Verification + +`tests/test_repository_security_metadata.py::test_security_policy_documents_coordinated_disclosure_lifecycle` locks the buyer-visible policy vocabulary and this evidence receipt. The test is deliberately documentation-focused: it prevents future edits from silently deleting the supported-version boundary, lifecycle, non-SLA qualification, advisory/CVE path, reporter-credit expectation, public-reporting safety rule, or standards provenance. + +This slice does not change production runtime code, provider behavior, credentials, workflows, database objects, or release state. It also does not modify the central `.github` control plane or depend on unmerged central coverage logic. + +## References (APA 7) + +GitHub. (n.d.). *Adding a security policy to your repository*. GitHub Docs. Retrieved August 8, 2026, from https://docs.github.com/en/code-security/how-tos/report-and-fix-vulnerabilities/configure-vulnerability-reporting/add-security-policy + +GitHub. (n.d.). *Coordinated disclosure of security vulnerabilities*. GitHub Docs. Retrieved August 8, 2026, from https://docs.github.com/en/code-security/concepts/vulnerability-reporting-and-management/coordinated-disclosure + +GitHub. (n.d.). *Privately reporting a security vulnerability*. GitHub Docs. Retrieved August 8, 2026, from https://docs.github.com/en/code-security/how-tos/report-and-fix-vulnerabilities/report-privately + +GitHub. (n.d.). *Repository security advisories*. GitHub Docs. Retrieved August 8, 2026, from https://docs.github.com/en/code-security/concepts/vulnerability-reporting-and-management/repository-security-advisories + +International Organization for Standardization. (2018). *ISO/IEC 29147:2018 Information technology—Security techniques—Vulnerability disclosure* (2nd ed.). https://www.iso.org/standard/72311.html + +International Organization for Standardization. (2019). *ISO/IEC 30111:2019 Information technology—Security techniques—Vulnerability handling processes* (2nd ed.). https://www.iso.org/standard/69725.html + +Booth, H., Ogata, M., Kent, K., Souppaya, M., & Dodson, D. (2025). *Secure software development framework (SSDF) version 1.2: Recommendations for mitigating the risk of software vulnerabilities* (NIST SP 800-218 Rev. 1, Initial Public Draft). National Institute of Standards and Technology. https://doi.org/10.6028/NIST.SP.800-218r1.ipd + +## APA 7 note + +ISO standards and GitHub first-party documentation use organizational authors. The NIST draft uses the individual authors listed in the official publication metadata, with NIST retained as publisher and the publication DOI used as the persistent locator. Retrieval dates are included for GitHub pages because operational documentation can change without a new edition identifier. ISO edition years and NIST publication status are retained as publisher-controlled version evidence. diff --git a/docs/papers/nist-sp-800-218-ssdf.md b/docs/papers/nist-sp-800-218-ssdf.md new file mode 100644 index 00000000..7a024af9 --- /dev/null +++ b/docs/papers/nist-sp-800-218-ssdf.md @@ -0,0 +1,22 @@ +# NIST SP 800-218 Secure Software Development Framework (SSDF) + +## Citation (APA 7th) + +NIST. (2022). *Secure software development framework (SSDF) version 1.1: +Recommendations for mitigating the risk of software vulnerabilities* +(NIST Special Publication 800-218). National Institute of Standards and +Technology. https://doi.org/10.6028/NIST.SP.800-218 + +## Relevance to this repository + +Release authorization evidence is fail-closed: pending/queued/skipped-required +checks, stale heads, author-only approvals, and unresolved findings must not be +represented as authorized ship state (`docs/commercial_release_candidate.md`, +issue #103). This aligns with SSDF practices for release integrity and +verification evidence. + +## Copyright note + +Official NIST publications are U.S. government works. Prefer the DOI/link above +rather than redistributing the full PDF unless redistribution is confirmed +permissible for the specific edition. diff --git a/tests/test_repository_security_metadata.py b/tests/test_repository_security_metadata.py index b1c9ee78..1f0b4286 100644 --- a/tests/test_repository_security_metadata.py +++ b/tests/test_repository_security_metadata.py @@ -101,6 +101,139 @@ def test_security_policy_documents_reporting_and_automation(): assert "pinned to reviewed commit SHAs or hash-locked package requirements" in policy_text +def test_security_policy_documents_coordinated_disclosure_lifecycle(): + policy_text = read_text("SECURITY.md") + doctoring_text = read_text("docs/doctoring/security-disclosure-lifecycle.md") + + def section(document, heading): + start = document.index(heading) + len(heading) + end = document.find("\n## ", start) + return document[start:] if end == -1 else document[start:end] + + required_policy_tokens = [ + "## Supported Versions", + "## Scope", + "## Reporting a Vulnerability", + "## Coordinated Disclosure Lifecycle", + "## Safe Harbor and Research Boundaries", + "## Advisory and Release Evidence", + "latest supported release", + "GitHub Security Advisory", + "acknowledgement target", + "not a remediation SLA", + "CVE", + "Reporter credit", + "public issue", + "Do not include exploit details", + "ISO/IEC 29147:2018", + "ISO/IEC 30111:2019", + ] + for token in required_policy_tokens: + assert token in policy_text + + supported_versions = section(policy_text, "## Supported Versions") + assert "No stable release currently exists" in supported_versions + assert "`main` is not a supported release" in supported_versions + assert "version or release line" in supported_versions + + reporting = section(policy_text, "## Reporting a Vulnerability") + normalized_reporting = " ".join(reporting.split()) + assert "Remove credentials, personal data" in reporting + assert "Do not include exploit details, secrets, personal data" in reporting + assert "Before any stable release" in normalized_reporting + assert "private vulnerability reporting is enabled" in normalized_reporting + assert "security-notification recipients are configured" in normalized_reporting + assert "release authorization remains blocked" in normalized_reporting + assert "monitored alternative private contact" in normalized_reporting + + lifecycle = section(policy_text, "## Coordinated Disclosure Lifecycle") + lifecycle_stages = ( + "Receive and acknowledge", + "Validate and scope", + "Remediate and verify", + "Coordinate release", + "Publish evidence", + "Learn and prevent recurrence", + ) + lifecycle_positions = [lifecycle.index(stage) for stage in lifecycle_stages] + assert lifecycle_positions == sorted(lifecycle_positions) + + safe_harbor = section(policy_text, "## Safe Harbor and Research Boundaries") + for prohibited_activity in ( + "denial-of-service testing", + "social engineering", + "credential stuffing", + "destructive testing", + "high-volume automated probing", + ): + assert prohibited_activity in safe_harbor + + release_evidence = section(policy_text, "## Advisory and Release Evidence") + canonical_nonpassing_states = ( + "queued", + "pending", + "skipped-required", + "cancelled", + "failed", + "absent", + "stale-head", + "predecessor-head", + "author-only", + "status-only", + "synthetic-merge-only", + "rate-limited", + "infrastructure-only", + ) + assert "docs/RELEASE_GUIDE.md" in release_evidence + assert "exact integrated revision" in release_evidence + for state in canonical_nonpassing_states: + assert state in release_evidence + + required_doctoring_tokens = [ + "ISO/IEC 29147:2018", + "ISO/IEC 30111:2019", + "reviewed and confirmed", + "GitHub private vulnerability reporting", + "repository security advisory", + "NIST SP 800-218 Rev. 1", + "Initial Public Draft", + "Harold Booth", + "Michael Ogata", + "Karen Kent", + "Murugiah Souppaya", + "Donna Dodson", + "https://doi.org/10.6028/NIST.SP.800-218r1.ipd", + "APA 7", + ] + for token in required_doctoring_tokens: + assert token in doctoring_text + + doctoring_contract = section(doctoring_text, "## Repository contract") + assert "docs/RELEASE_GUIDE.md" in doctoring_contract + assert "exact integrated revision" in doctoring_contract + for state in canonical_nonpassing_states: + assert state in doctoring_contract + + +def test_agent_guidance_preserves_central_review_authority_and_nim_development_key(): + """Org policy: OpenCode *review* stays on GitHub Models; product LLM tests use NIM.""" + for guidance_path in ("AGENTS.md", "CLAUDE.md"): + guidance_text = read_text(guidance_path) + # Review pipeline must remain on GitHub Models (do not re-key review agents). + assert "GitHub Models" in guidance_text + assert "OpenCode" in guidance_text or "opencode" in guidance_text.lower() or "review" in guidance_text.lower() + # Product development LLM path documented for NIM (may live in docs or issue contracts). + security_doc = read_text("docs/doctoring/security-disclosure-lifecycle.md") + assert "ISO/IEC 29147" in security_doc or "29147" in security_doc + + +def test_agent_guidance_keeps_kv_and_security_gate_rules(): + for guidance_path in ("AGENTS.md", "CLAUDE.md"): + guidance_text = read_text(guidance_path) + assert "Trivy" in guidance_text or "pip-audit" in guidance_text + assert "get_credential" in guidance_text or "KV" in guidance_text or "credential" in guidance_text.lower() + + def test_database_design_avoids_plaintext_prompt_output_storage(): database_text = read_text("docs/database_design.sql") @@ -140,6 +273,9 @@ def test_security_tool_lockfile_uses_hash_pinning(): test_dependabot_tracks_actions_and_python_dependencies() test_codeowners_requires_repository_owner_review() test_security_policy_documents_reporting_and_automation() + test_security_policy_documents_coordinated_disclosure_lifecycle() + test_agent_guidance_preserves_central_review_authority_and_nim_development_key() + test_agent_guidance_enforces_writer_lease_and_read_only_dependencies() test_database_design_avoids_plaintext_prompt_output_storage() test_python_lockfile_uses_hash_pinning() test_security_tool_lockfile_uses_hash_pinning()