Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Expand Down
129 changes: 52 additions & 77 deletions SECURITY.md
Original file line number Diff line number Diff line change
@@ -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.
105 changes: 105 additions & 0 deletions tests/test_dna_circuits.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,17 @@

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,
get_available_dna_sequences,
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,
)
Expand Down Expand Up @@ -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")
Expand All @@ -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")
Expand Down Expand Up @@ -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"
Expand All @@ -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")
Expand All @@ -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"
Expand All @@ -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
Loading