-
Notifications
You must be signed in to change notification settings - Fork 1
feat(htsget): c4gh-encrypted streams #214
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 24 commits
Commits
Show all changes
30 commits
Select commit
Hold shift + click to select a range
07b6bd0
docs: design spec for encrypted htsget streams
cmdoret bfa155d
docs: implementation plan for encrypted htsget streams
cmdoret 8155882
feat(c4gh): derive public key from secret key
cmdoret eb5ce1c
feat(htsget): negotiate C4GH encryption scheme in url
cmdoret 7f139fa
docs(htsget): add doctest for encrypted url
cmdoret f7195c4
feat(htsget): send Client-Public-Key header for encrypted streams
cmdoret 55669fd
style(htsget): tidy imports and docstrings
cmdoret 45fa858
feat(htsget): decrypt encrypted streams at open() boundary
cmdoret 6ddc01f
refactor(htsget): close consumed stream and tidy test imports
cmdoret 905438b
feat(api): pass secret key through stream_genomics
cmdoret a4a1e64
feat(cli): add --secret-key to stream command
cmdoret 05231da
test(cli): assert passphrase forwarding in stream
cmdoret 2f3fd21
docs: document encrypted htsget streaming
cmdoret 80e56c3
docs: normalize tab-set fence depth
cmdoret b5b5035
fix(htsget): ensure temp files and stream close on decrypt failure
cmdoret 233e26a
refactor(htsget): inline pubkey header and tidy passphrase read
cmdoret 2f0be74
docs(htsget): streamline encrypted stream spec
cmdoret 7efa789
docs(htsget): include flow in spec
cmdoret 5364761
Merge branch 'main' into feat/htsget-c4gh-streams
cmdoret e838d9e
chore: update gitignore
cmdoret 94ce8fb
refactor: clearer var name for secret key file
cmdoret d51307f
test(c4gh): drop redundant tests
cmdoret 5f96e86
refactor(c4gh): encryption x htsget impl
cmdoret 5e20a81
doc(htsget): note on decrypt+stream
cmdoret 602becb
fix(cli,remote): optional type hints to pipe
cmdoret ae4f11d
fix(cli,remote): optional type hints to pipe
cmdoret d1be398
chore: drop unused import
cmdoret cb24ba6
feat(c4gh): always include sender's public key in recipients
cmdoret c6d1ac7
fix(c4gh): indentation
cmdoret e8329fa
chore: drop obsolete type hints patterns
cmdoret File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,9 @@ | ||
| # agents | ||
| .agents | ||
| AGENTS.md | ||
| .claude | ||
| CLAUDE.md | ||
|
|
||
| # zarr | ||
| .zmetadata | ||
| # Byte-compiled / optimized / DLL files | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| # Client-side support for encrypted htsget streams | ||
|
|
||
| Date: 2026-06-12 | ||
|
|
||
| ## Problem | ||
|
|
||
| The htsget client in `modos.genomics.htsget` streams genomic regions by | ||
| fetching a ticket of byte ranges and concatenating them into a single stream. | ||
| The [htsget-rs](https://github.com/umccr/htsget-rs) server can serve | ||
| crypt4gh-encrypted streams, but the client cannot yet decrypt them (we only | ||
| do crypt4gh on *local* files, in `modos.genomics.c4gh`). | ||
|
|
||
| ## Server protocol (htsget-rs, experimental) | ||
|
|
||
| The client sends a `Client-Public-Key: <base64 crypt4gh public key>` header and | ||
| an `encryptionScheme=C4GH` query parameter. The server returns byte ranges that | ||
| concatenate into a valid crypt4gh file (header re-encrypted to that public key, | ||
| plus edit lists). The client decrypts the assembled stream with the matching | ||
| private key. | ||
|
|
||
| The `encryptionScheme=C4GH` parameter is experimental and subject to change. | ||
|
|
||
| ## Decisions | ||
|
|
||
| - User inputs: A `--secret-key` path (plus optional passphrase). The | ||
| public key is derived from it if possible. | ||
| - **Surface:** both the CLI `modos stream` and the Python API | ||
| (`HtsgetConnection` / `MODO.stream_genomics`). | ||
| - **Output:** decrypt transparently; the user gets the plaintext region. | ||
|
|
||
| ## Approach | ||
|
|
||
| Decrypt at the `HtsgetConnection.open()` boundary: when a secret key is set, | ||
| `open()` returns a decrypted readable and every consumer (CLI, `to_pysam`, | ||
| `to_file`) is unchanged. The encrypted stream is buffered to a temp file before | ||
| decryption (consistent with `to_pysam`, which already spools). | ||
|
|
||
| Rejected: decrypting in each consumer (duplication, leaks encryption awareness); | ||
| a lazy streaming-decrypt wrapper (crypt4gh has no clean incremental reader). | ||
|
|
||
| ## Flow | ||
|
|
||
| ```mermaid | ||
| sequenceDiagram | ||
| participant C as client | ||
| participant H as htsget-rs | ||
| participant S as store | ||
| C->>H: ticket (public key, C4GH) | ||
| H-->>C: byte ranges | ||
| C->>S: fetch ranges | ||
| S-->>C: crypt4gh blocks | ||
| Note over C: open(): assemble + decrypt | ||
| C->>C: plaintext region | ||
| ``` | ||
|
|
||
| ## Out of scope | ||
|
|
||
| - Server-side / deployment configuration of htsget-rs C4GH. | ||
| - Encrypting or decrypting remote objects at rest (client-side only). |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| """Tests for crypt4gh helpers.""" | ||
|
|
||
| from crypt4gh.keys import get_private_key, get_public_key | ||
|
|
||
| from modos.genomics.c4gh import derive_public_key | ||
|
|
||
|
|
||
| def test_derive_public_key_matches_keypair(c4gh_keypair): | ||
| """The derived public key equals the keypair's own public key.""" | ||
| seckey = get_private_key(str(c4gh_keypair["private_key"]), lambda: None) | ||
| expected = get_public_key(str(c4gh_keypair["public_key"])) | ||
|
|
||
| assert derive_public_key(seckey) == expected |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.