Harness owns canonical operation semantics. ServiceRegistry normalizes registry records;
DRS, TRS, Beacon (pre-1.0, v1 and v2), and WES adapters map operations to native APIs; SafeHttpClient enforces
transport policy; and WorkflowRunLedger stores WES submission state in SQLite.
Endpoints do not have to appear in the public implementation registry. Pass trusted,
explicit ServiceDescriptor values through ServiceRegistry(..., static_services=[...]) for
private services, local services, or public services discovered out of band.
The default policy allows read-only operations. WES submission and cancellation require the
profile scopes ga4gh:workflow:submit and ga4gh:workflow:cancel respectively (or ga4gh:*):
uv run ga4gh-harness ga4gh.wes.run.cancel \
--scope ga4gh:workflow:cancel \
--input '{"service_id":"example-wes","run_id":"run-123"}'This only satisfies the local Harness policy. The target WES still makes the final authorization decision.
The default test suite is fully mocked and makes no network calls:
uv run pytest
uv run ruff check .
uv run mypy srcLive tests are disabled unless both the marker and environment flag are supplied:
uv run pytest -m live --run-liveLive tests are read-only. No live WES submission or cancellation is part of the suite.
Build and invoke the image without deploying it:
docker build -t ga4gh-agentic-harness:local .
docker run --rm ga4gh-agentic-harness:local ga4gh.harness.describe --prettyPersist a local WES ledger by mounting /data and setting
GA4GH_HARNESS_LEDGER_PATH=/data/runs.db. Do not bake tokens into the image. Pass local test
credentials as runtime environment variables and use a pinned CredentialProvider in Python.
- HTTPS is required.
- Private, loopback, link-local, reserved, and metadata destinations are blocked. The address is checked again when the connection is made, so a second DNS answer cannot redirect it.
- Credential headers are sent only over HTTPS to the exact origin of the resource they were acquired for, and credentialed redirects cannot cross origins.
- Operations whose policy decision requires approval fail with
APPROVAL_REQUIREDuntil thePolicyEvaluatorholds an approval for the request. - GET, HEAD, and OPTIONS receive bounded retries; mutations do not.
- Responses are size-limited and transport errors become structured envelopes.
Plain HTTP to this machine (localhost, 127.0.0.0/8, ::1) follows the private-host
setting: with private hosts allowed, a local service such as a WES on http://127.0.0.1:18090
needs no allow_http. Every other host still requires HTTPS unless allow_http is set, names
are never resolved to decide what counts as loopback, and credentials are never sent over plain
HTTP.
Private endpoints can be tested by explicitly setting
GA4GH_HARNESS_ALLOW_PRIVATE_HOSTS=true. Use this only in a controlled local network and
prefer GA4GH_HARNESS_ALLOWED_HOSTS to restrict the destinations.
For a local GA4GH Service Registry, the equivalent explicit CLI invocation is:
uv run ga4gh-harness ga4gh.service.search \
--registry service-registry=http://127.0.0.1:18080/ga4gh/registry \
--allow-private-hosts \
--input '{"product":"drs"}' --prettyThe HTTP and private-host flags are opt-in and should not be used for remote services.
ga4gh.beacon.variant.query reaches every Beacon version: pre-1.0, v1 and v2. It picks the
protocol from what the service's registry record declares, never by probing the service.
Callers always send v1/v2 field names (referenceName, start, referenceBases,
alternateBases, assemblyId) with 0-based positions, as a flat mapping or a v2 request entity.
-
queryShape, when the record has one, wins over the declared version. Pre-1.0 Beacons differ in path, parameter names, coordinate base, chromosome form and answer format, and two that both declare 0.2 count positions from different bases, so the version cannot say which. The record says instead:
"queryShape": { "method": "GET", "path": "/query", "parameters": {"dataset": "lovd", "chromosome": "{referenceName}", "position": "{start}", "alternateBases": "{alternateBases}"}, "positions": "1-based", "chromosome": "bare", "assemblies": {"GRCh37": "GRCh37", "hg19": "GRCh37"}, "answer": {"format": "json", "exists": "response.exists"}, "matchesOn": "allele" }
methodis GET or POST (a form-encoded body).pathextends the service URL and cannot leave it. Parameter values are literals or one of the five placeholders above.positions(0-basedor1-based) andchromosome(barefor 11,chrfor chr11) convert the caller's values.assemblieslists theassemblyIdvalues the Beacon holds and the token sent for each.answerreadsexistsfrom a JSON field path (""is the whole body; a list is true when non-empty; the stringstrue,falseandnullare read as such) or, with"format": "text", from literalfoundandnotFoundsubstrings.matchesOn: "position"adds aPOSITION_MATCH_ONLYwarning. The result is{exists, apiVersion, matchesOn, request, response}, with the exact request sent and the Beacon's own answer as evidence. The shape is checked before any request is sent. -
v1 (
1.x), and 0.3 / 0.4 without a shape (v1 kept their BeaconAlleleRequest):GET {url}/querywith BeaconAlleleRequest parameters.referenceName,referenceBasesandassemblyIdare required. A v2 request entity is accepted and mapped:query.requestParameterssupplies the parameters, a one-elementstart/endarray becomesstart/endand a two-element onestartMin/startMaxandendMin/endMax, andincludeResultsetResponsesbecomesincludeDatasetResponses. Onlyentry_typeg_variantsexists in v1. The native BeaconAlleleResponse (exists,datasetAlleleResponses) is returned as is. -
v2 (
2.x), or no declared version:{url}/{entry_type}. A flat query, and a request entity whose parts all have a GET spelling (request parameters,requestedGranularity,includeResultsetResponses,pagination), go as GET with list values comma-concatenated as the Beacon v2 documentation specifies. An entity with filters or other nested structure is POSTed as is. GET is the portable form: AfriGen-D rejects the array positions the v2 schema specifies in a POST body, and answers the same query over GET. -
0.1 / 0.2 without a shape, or any other major version, fail with
NOT_SUPPORTED.
Some pre-1.0 Beacons are served over plain HTTP only. Reaching them needs allow_http
(GA4GH_HARNESS_ALLOW_HTTP=true); credentials are never sent over HTTP, and such results carry a
PLAIN_HTTP warning.