diff --git a/README.md b/README.md index bd6b60b..b8a5b3e 100644 --- a/README.md +++ b/README.md @@ -247,6 +247,22 @@ print([record.record_id for record in get_available_dna_sequences()]) This feature imports curated OpenQASM assets and exposes them as circuit-exploration data. It does not claim biological simulation fidelity. OpenQASM 3 assets require the optional dependency `qiskit_qasm3_import`. +#### Responsible Use Notice + +The DNA-related features in QPyth are provided for educational, computational, and circuit-exploration purposes only. + +- They do not constitute biological modeling, clinical analysis, or validated genetic interpretation. +- They do not provide medical, diagnostic, therapeutic, or laboratory guidance. +- They are not intended for pathogen design, wet-lab experimentation, synthesis planning, or any harmful biological application. +- They should not be relied upon as evidence of biological function, safety, or real-world DNA behavior. + +Any DNA-inspired or sequence-related assets in this repository are presented as computational abstractions or curated examples unless explicitly documented otherwise. + +#### Data Provenance + +Where bundled DNA or sequence-like assets are included, the repository should identify whether they are synthetic/demo-only, derived from public reference material, or transformed for educational use. +Unless explicitly stated otherwise, treat such assets as illustrative and non-authoritative. + **Available Hardware Profiles:** | Backend | Qubits | Avg T1 (Ξs) | Avg T2 (Ξs) | Avg Readout Error | diff --git a/SECURITY.md b/SECURITY.md index 497977a..0c85cf4 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,112 +1,87 @@ # 🔒 Security Policy -## Supported Versions - -| Version | Supported | -|---------|--------------------| -| 0.2.x | ✅ Active support | -| 0.1.x | ❌ End of life | - -Security updates are provided for the **latest stable release** on the `main` branch only. -Users are encouraged to upgrade to the latest version to receive all security fixes. - ---- +## Scope -## ðŸ›Ąïļ Security Best Practices +QPyth is an open-source quantum software toolkit. Some repository features use DNA-inspired or sequence-themed representations for computational exploration. These features are not biological simulation tools and are not intended for laboratory, medical, diagnostic, therapeutic, or bioengineering use. -### What We Do - -- **Dependency scanning**: Automated checks for vulnerable dependencies -- **Code review**: All PRs reviewed for security issues -- **Input validation**: Sanitization of user-provided values -- **Secure defaults**: Safe configurations out of the box +## Supported Versions -### Security Testing +Security updates are provided for the latest stable release and the `main` branch. -```bash -# Check for known vulnerabilities -pip-audit -r <(pip freeze) +| Version | Supported | +|---------|-----------| +| Latest stable release | ✅ | +| `main` branch | ✅ | +| Older releases | ❌ | -# Type checking for type-related issues -mypy quantumpytho/ - -# Static analysis -ruff check . -``` +Users should upgrade to the latest release to receive security fixes and dependency updates. --- -## 📎 Reporting a Vulnerability +## Security Boundaries -### Responsible Disclosure +QPyth should be treated as developer and research software, not as a safety-certified system. In particular: -We take security seriously and appreciate your help in keeping QPyth safe. +- outputs are not guaranteed to be biologically valid, clinically meaningful, or safe for real-world use +- DNA-related features must not be used for synthesis, pathogen engineering, wet-lab experimentation, or operational biological decision-making +- optional integrations and external services may introduce network, API, credential, or third-party dependency risk -**If you find a security issue:** +--- -1. **Do not** create a public GitHub issue -2. Use GitHub Security Advisories: - - Go to the repository **Security** tab - - Click **Report a vulnerability** -3. Alternatively, open a private issue with "SECURITY" in the title +## What We Review -### What to Include +We aim to reduce risk through: -- Description of the vulnerability -- Steps to reproduce -- Potential impact -- Suggested fix (if any) +- dependency monitoring +- static analysis and linting +- code review +- input validation for user-facing interfaces +- secure handling of optional integrations where applicable -### Response Timeline +Repository CI currently runs: -| Stage | Expected Time | -|-------|---------------| -| Acknowledgment | 48 hours | -| Triage | 7 days | -| Fix | Priority-based | -| Public disclosure | Coordinated | +```bash +ruff check . +ruff format --check . +pytest -v --tb=short +pytest --cov=quantumpytho --cov-report=xml +``` --- -## 🔐 Security Features +## Reporting a Vulnerability -### Dependency Security +Please do not open a public issue for suspected vulnerabilities. -```toml -# pyproject.toml -dependencies = [ - "qiskit>=1.1.0", # Version-pinned major releases - "qiskit-aer>=0.15.0", # Latest stable with security fixes - "numpy>=2.0.0", # Modern, maintained version -] -``` - -### Input Validation +Instead: -All user inputs are validated: +1. Use GitHub Security Advisories or private vulnerability reporting if it is enabled for the repository. +2. If private reporting is unavailable, contact the maintainers privately and include `SECURITY` in the subject line. -```python -def read_float(prompt: str, min_val: float, max_val: float) -> float: - """Validates user input against bounds.""" - # Raises ValueError if out of range -``` +Please include: -### Secure Defaults +- affected component +- reproduction steps +- impact assessment +- suggested mitigation, if available -- QuantumSimulator (Aer) as default - no external connections -- Local execution only - no remote API calls -- Minimal permissions - no filesystem/network access +We ask reporters to avoid public disclosure until the issue has been reviewed and a fix or mitigation is available. --- -## 📚 Security Resources +## Domain-Specific Responsible Use + +If you identify a risk involving: + +- misuse of DNA-related functionality +- unsafe interpretation of sequence-like assets +- misleading biological claims +- dual-use or biosecurity concerns -- [Qiskit Security](https://qiskit.org/security) -- [PyPI Security](https://pypi.org/security/) -- [OWASP Quantum Computing](https://owasp.org/www-project-quantum-computing/) +please report it as a security concern even if it is not a traditional software exploit. --- -## 🙏 Thank You +## Disclaimer -Your security reporting helps protect the entire quantum computing community. +QPyth is provided for research, education, and software experimentation. It is not intended for clinical, medical, diagnostic, therapeutic, biosurveillance, synthesis, or wet-lab decision support. diff --git a/tests/test_dna_circuits.py b/tests/test_dna_circuits.py index 310b540..e72de11 100644 --- a/tests/test_dna_circuits.py +++ b/tests/test_dna_circuits.py @@ -5,6 +5,7 @@ import pytest +import quantumpytho.modules.dna_circuits as dna_circuits from quantumpytho.modules.dna_circuits import ( get_available_dna_circuit_ids, get_available_dna_circuits, @@ -12,7 +13,9 @@ get_dna_circuit_preview, get_dna_sequence, load_dna_circuit, + load_dna_circuit_metadata, load_qasm_circuit_file, + run_dna_circuit_explorer, summarize_dna_circuit, validate_qasm_file, ) @@ -43,6 +46,14 @@ def test_load_dna_circuit_parses_qasm(): assert circuit.num_clbits == 21 +def test_load_dna_circuit_metadata_reads_bundled_json(): + """Bundled metadata should be readable without summary normalization.""" + metadata = load_dna_circuit_metadata("dna_helix_10bp") + + assert metadata["qubits"] == 21 + assert metadata["config"]["base_pairs"] == 10 + + def test_load_stealth_dna_circuit_parses_qasm(): """Bundled 34bp stealth QASM should parse into a large Qiskit circuit.""" circuit = load_dna_circuit("stealth_dna_34bp") @@ -64,6 +75,16 @@ def test_summarize_dna_circuit_normalizes_metadata(): assert summary.sequences["strand1"] == "GTAGGTAAGC" +def test_dna_summary_to_dict_is_json_safe(): + """Normalized summaries should serialize into simple Python data.""" + summary = summarize_dna_circuit("dna_helix_10bp") + payload = summary.to_dict() + + assert payload["circuit_id"] == "dna_helix_10bp" + assert payload["sequences"] == summary.sequences + assert payload["geometry"] == summary.geometry + + def test_summarize_stealth_dna_circuit_preserves_large_asset_metadata(): """Large stealth asset should preserve curated metadata and parsed metrics.""" summary = summarize_dna_circuit("stealth_dna_34bp") @@ -95,6 +116,21 @@ def test_stealth_circuit_preview_contains_named_registers(): assert "qreg bridge[34];" in preview +def test_validate_qasm_file_rejects_missing_file(tmp_path: Path): + """Missing QASM files should raise a helpful error.""" + with pytest.raises(FileNotFoundError, match="not found"): + validate_qasm_file(tmp_path / "missing.qasm") + + +def test_validate_qasm_file_rejects_invalid_header(tmp_path: Path): + """Non-OpenQASM files should be rejected before parsing.""" + invalid_qasm = tmp_path / "invalid.qasm" + invalid_qasm.write_text("qreg q[1];", encoding="utf-8") + + with pytest.raises(ValueError, match="not valid OpenQASM"): + validate_qasm_file(invalid_qasm) + + def test_validate_qasm_file_rejects_empty_file(tmp_path: Path): """Empty QASM placeholders should be rejected clearly.""" empty_qasm = tmp_path / "empty.qasm" @@ -113,6 +149,12 @@ def test_available_dna_sequences_contains_blueprint_and_library_entries(): assert "lib_acgt" in record_ids +def test_get_dna_sequence_unknown_record_raises_keyerror(): + """Sequence lookup should fail clearly for unknown ids.""" + with pytest.raises(KeyError, match="Unknown DNA sequence record"): + get_dna_sequence("missing-record") + + def test_get_dna_sequence_blueprint_is_normalized(): """Blueprint sequence should be normalized by stripping separators.""" record = get_dna_sequence("seq_3") @@ -122,6 +164,41 @@ def test_get_dna_sequence_blueprint_is_normalized(): assert record.phi_scaling == pytest.approx(0.7232610426788172) +def test_dna_sequence_to_dict_is_json_safe(): + """Sequence records should serialize into simple Python data.""" + record = get_dna_sequence("seq_3") + payload = record.to_dict() + + assert payload["record_id"] == "seq_3" + assert payload["sequence"] == record.sequence + assert payload["metadata"] == record.metadata + + +def test_load_dna_circuit_metadata_raises_for_missing_bundled_file( + monkeypatch: pytest.MonkeyPatch, tmp_path: Path +): + """Missing bundled metadata files should raise a clear error.""" + monkeypatch.setattr(dna_circuits, "_data_dir", lambda: tmp_path) + + with pytest.raises(FileNotFoundError, match="DNA metadata file not found"): + load_dna_circuit_metadata("dna_helix_10bp") + + +def test_load_dna_circuit_rejects_unknown_asset(): + """Unknown bundled circuit ids should fail clearly.""" + with pytest.raises(KeyError, match="Unknown DNA circuit asset"): + load_dna_circuit("missing-circuit") + + +def test_load_qasm_circuit_file_rejects_unsupported_openqasm_version(tmp_path: Path): + """Unknown OpenQASM versions should fail before import.""" + qasm_path = tmp_path / "sample.qasm" + qasm_path.write_text("OPENQASM 4.0;\nqubit q;\n", encoding="utf-8") + + with pytest.raises(ValueError, match="Unsupported OpenQASM version"): + load_qasm_circuit_file(qasm_path) + + def test_load_qasm_circuit_file_handles_openqasm3_optional_dependency(tmp_path: Path): """OpenQASM 3 loading should either parse or fail with an install hint.""" qasm3_path = tmp_path / "sample.qasm" @@ -136,3 +213,31 @@ def test_load_qasm_circuit_file_handles_openqasm3_optional_dependency(tmp_path: else: circuit = load_qasm_circuit_file(qasm3_path) assert circuit.num_qubits == 1 + + +def test_run_dna_circuit_explorer_allows_quit( + monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str] +): + """CLI explorer should return cleanly when the user quits.""" + monkeypatch.setattr("builtins.input", lambda _: "q") + + run_dna_circuit_explorer() + + output = capsys.readouterr().out + assert "[DNA-Inspired Circuit Explorer]" in output + assert "Returning to main menu..." in output + + +def test_run_dna_circuit_explorer_uses_default_selection( + monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str] +): + """Blank input should select the first bundled DNA circuit.""" + monkeypatch.setattr("builtins.input", lambda _: "") + monkeypatch.setattr(dna_circuits.importlib.util, "find_spec", lambda _: None) + + run_dna_circuit_explorer() + + output = capsys.readouterr().out + assert "OpenQASM 3 import support: install qiskit_qasm3_import" in output + assert "Name: DNA Helix 10bp" in output + assert "QASM preview:" in output