Honua Server Protocol Integration Lane
The integration lane in test/integration/ exercises the public
HonuaClient and its sub-surfaces against a real seeded Honua Server.
It complements the mock-backed unit suites in test/ (which prove SDK
behavior in isolation) by catching drift between the SDK and live
server routes, response shapes, errors, and capability negotiation.
Lane shape
- Connect-only. The SDK does not own the server bootstrap. The
integration lane reads
HONUA_INTEGRATION_BASE_URLand skips the entire suite when that variable is unset, so a clean clone passesnpm run test:integrationeven with no server running. - Caller owns auth + seeding. The lane assumes the target server is
already running, seeded with the configured service / layer /
collection, and reachable.
getCompatibility()(the global setup health probe) hits/api/v1/admin/capabilities, which is gated by the server's admin auth — the harness passesHONUA_INTEGRATION_API_KEYas theX-API-Keyheader, and that value must match the server'sHONUA_ADMIN_PASSWORD. - Public API only. Tests call methods on
HonuaClient, its factory-returned helpers (featureLayer,mapService,imageService,geometryService,geoprocessing,ogcFeatures,ogcTiles,ogcMaps,ogcProcesses,stac,wfs,wms,wmts,odata), and standalone public clients such asHonuaGeocodingClient. Private HTTP helpers fromhonua-server/tests/are not used. - One file per protocol surface.
test/integration/surfaces/contains one*.integration.tsper surface; each file callsintegrationSuite("<friendly>", "<surface-tag>", () => …)so the metadata reporter can attach the surface to every CI run.
Running locally
The recommended local fixture is tests/python/shared/js_test_server.py
in honua-server, which spins up a seeded PostGIS, applies the test
catalog (service test_service_gw0, layer 1000 named "Test Layer", a
small set of point features), and runs Honua Server in dev-auth mode on
:5555:
# 1. Start the seeded JS test server (from the honua-server checkout).
cd /path/to/honua-server
python -m tests.python.shared.js_test_server # prints {"base_url": "http://127.0.0.1:5555", ...}
# 2. Run the integration lane against it. The js_test_server fixture
# runs the server in dev-auth mode, so HONUA_INTEGRATION_API_KEY can
# be any non-empty string (the value is still forwarded as
# X-API-Key but the server does not validate it in dev-auth mode).
cd /path/to/honua-sdk-js
HONUA_INTEGRATION_BASE_URL=http://localhost:5555 \
HONUA_INTEGRATION_API_KEY=local-dev \
npm run test:integration
If you point the lane at a Docker Compose-launched server (admin auth
on, default port :8080), pass the configured admin password as the
API key:
HONUA_INTEGRATION_BASE_URL=http://localhost:8080 \
HONUA_INTEGRATION_API_KEY="$HONUA_ADMIN_PASSWORD" \
HONUA_INTEGRATION_COLLECTION_ID=places \
npm run test:integration
Environment variables
| Variable | Default | Purpose |
|---|---|---|
HONUA_INTEGRATION_ALERTS_ENABLED |
(unset: positive draft validation) | Dedicated Pro alerts fixture selects false for the capability-off negative control and true for the enabled positive control. This selects assertions only; the workflow configures the server opt-in separately. |
HONUA_INTEGRATION_BASE_URL |
(required) | Server URL the lane connects to. Suite skips when absent. |
HONUA_INTEGRATION_SERVICE_ID |
test_service_gw0 |
GeoServices service ID (FeatureServer / MapServer / WMS / WMTS). |
HONUA_INTEGRATION_LAYER_ID |
1000 |
FeatureServer / MapServer layer ID. |
HONUA_INTEGRATION_COLLECTION_ID |
1000 (numeric layer ID) |
OGC API Features / Maps / Tiles collection ID. The default rides the server's layer-id-by-numeric resolution path so it works against the js_test_server.py seed; override with the layer name when the target seed exposes a friendlier collection identifier (places, roads, etc). |
HONUA_INTEGRATION_API_KEY |
(required) | X-API-Key header sent on every SDK call, including the getCompatibility() health probe against /api/v1/admin/capabilities. Must match the server's HONUA_ADMIN_PASSWORD. |
HONUA_INTEGRATION_TILE_MATRIX_SET |
WebMercatorQuad |
OGC Tiles tile-matrix-set ID. |
HONUA_INTEGRATION_SEED_PROFILE |
places-roads-v1 |
Free-form label for the seed configuration; recorded into the metadata file but not sent on the wire. |
HONUA_INTEGRATION_BEARER_TOKEN |
(unset) | Optional Authorization: Bearer … header (use only against bearer-secured deployments — admin endpoints expect X-API-Key). |
HONUA_INTEGRATION_TIMEOUT_MS |
30000 |
Per-request timeout used by the harness HonuaClient. |
HONUA_INTEGRATION_SERVER_IMAGE |
(unset) | Recorded into integration-meta.json (CI uses the resolved image digest). |
HONUA_INTEGRATION_SERVER_COMMIT |
(unset) | Honua Server commit SHA, recorded into integration-meta.json. CI reads it from the workflow server_commit input or vars.HONUA_INTEGRATION_SERVER_COMMIT; it is never derived from ${{ github.sha }} (which is the SDK repo commit). Leave blank when the server commit is unknown. |
HONUA_INTEGRATION_STAC_COLLECTION_ID |
HONUA_INTEGRATION_COLLECTION_ID |
STAC collection ID used for optional collection/item probes. |
HONUA_INTEGRATION_ODATA_BASE_PATH |
/odata |
OData service root path. |
HONUA_INTEGRATION_ODATA_ENTITY_SET |
Layers(<layerId>)/Features |
OData entity set or navigation path for the configured layer. |
HONUA_INTEGRATION_IMAGE_SERVICE_ID |
(unset) | Enables ImageServer live coverage against a seeded raster service. |
HONUA_INTEGRATION_GP_SERVICE_ID |
(unset) | Enables GPServer live coverage against a seeded job service. |
HONUA_INTEGRATION_GP_TASK_NAME |
(unset) | Optional GPServer task segment for task-scoped services. |
HONUA_INTEGRATION_GP_PARAMETERS_JSON |
{} |
JSON object submitted to the configured GPServer task. |
HONUA_INTEGRATION_WFS_ENDPOINT_URL |
(unset) | Enables WFS live coverage against a seeded WFS endpoint. |
HONUA_INTEGRATION_WFS_TYPE_NAME |
(unset) | WFS feature type used by the live WFS probe. |
HONUA_INTEGRATION_GEOCODING_LOCATOR |
(unset) | Enables GeocodeServer live coverage against a seeded locator. |
HONUA_INTEGRATION_GEOCODING_PROBE_TEXT |
Honolulu |
Forward-geocode text used when geocoding coverage is enabled. |
Surface coverage
The lane exercises the following surfaces against the seed profile.
| Surface | Status | Notes |
|---|---|---|
| FeatureServer | Exercised | metadata, queryFeatures, queryFeatureCount, queryObjectIds |
| MapServer | Exercised | metadata, mapLayer.queryFeatures, queryFeatureCount, exportMap |
| ImageServer | Configured | client.imageService().metadata when HONUA_INTEGRATION_IMAGE_SERVICE_ID is set; otherwise recorded skipped because the default seed is vector-only |
| GeometryServer | Exercised | client.geometryService().project, buffer |
| GPServer | Configured | submitJob and jobStatus when HONUA_INTEGRATION_GP_SERVICE_ID is set; otherwise recorded skipped because the default seed has no runnable GP task |
| OGC API Features | Exercised | landing, conformance, collections, items, item |
| OGC API Tiles | Exercised | landing, conformance, tileMatrixSets (list + by id), tilesets, tile |
| OGC API Maps | Exercised | landing, conformance, map render |
| OGC API Processes | Exercised | landing, conformance, list, describe (when registered) |
| STAC | Exercised | landing, collections, search, collection when advertised |
| WFS | Configured | capabilities and bounded GetFeature when WFS endpoint/type env vars are set; otherwise recorded skipped |
| WMS | Exercised | capabilities, GetMap |
| WMTS | Exercised | capabilities, GetTile |
| OData | Exercised | metadata, bounded entity query |
| Alert draft evaluation | Preview / experimental | Dedicated single-tenant Pro fixture only; explicit alerts.geofence off returns typed HTTP 404, on validates an unpersisted rule and zone. Both runs use the same resolved immutable candidate. |
| Geocoding | Configured | forwardGeocode when HONUA_INTEGRATION_GEOCODING_LOCATOR is set; otherwise recorded skipped |
Skipped surfaces are recorded in test-results/integration-meta.json
with a reason field so the gap is visible in CI artifacts; this keeps
unsupported surfaces from silently disappearing from coverage.
Failure diagnostics
Each SDK call is wrapped in runWithDiagnostics(...). When an
assertion or an SDK error fires, the test message is augmented with a
standard block:
[honua-integration]
SDK method : client.featureLayer().queryFeatures
Request path : /rest/services/test_service_gw0/FeatureServer/1000/query
HTTP method : GET
HTTP status : 500
Duration ms : 142.3
Body excerpt : { "error": { "code": 500, "message": "..." } }
The body excerpt is bounded to 500 characters; longer bodies are
truncated with a [truncated, original N chars] suffix.
CI integration
.github/workflows/integration.yml runs the lane on trunk /
release/** pushes, nightly, and on manual dispatch. By default it is
self-contained: the job runs the pinned Honua Server image plus
Postgres and Redis inside the workflow. An external base URL (dispatch
base_url input or the HONUA_INTEGRATION_BASE_URL repo variable)
switches it to connect-only against an already-seeded deployment.
The self-contained stack starts in this order (honua-sdk-js#1946):
- Start Postgres and Redis, then install
postgisandpostgis_raster. - Boot the server against the empty database. It applies every
migration itself, contract-phase ones such as
038_DropV1MetadataGraphTablesincluded, and journals them. - Wait for
/healthz/ready. - Apply
test/integration/seed/places-roads-v1.sqlto the migrated schema. It registerstest_service/ layer0and activates the Metadata v2 compat snapshot last. - Restart the server and wait for ready again.
Do not seed before the first boot. A seeded database counts as
"existing", and the migration safety gate then refuses the pending
contract migrations. CI never sets HONUA_APPROVE_CONTRACT_MIGRATIONS or
HONUA_SKIP_MIGRATIONS to get past that gate. Installing
postgis_raster after the first boot has the same effect: the raster
migrations stay pending and the restart is refused.
Production refuses the placeholder connection-encryption key/salt and needs an operation key-ring certificate. The step mints both per run; they never leave the runner.
Reviewed self-contained server pin
The workflow pins the reviewed candidate at workflow level for both the Community fixture and the dedicated single-tenant Pro alerts off/on fixture:
| Env | Default |
|---|---|
HONUA_INTEGRATION_SERVER_IMAGE |
ghcr.io/honua-io/honua-server@sha256:3ef3bd41a2f84d1f3a6194c11db496f741cc4d869b54bf57e9d7067dd9cf3d39 |
HONUA_INTEGRATION_SERVER_COMMIT |
ff5f5671903e96e13cffac7b73546c3ed0f853c5 |
HONUA_CANDIDATE_CUT_AT |
2026-10-04T08:09:54Z |
These literal values are authoritative for self-contained runs; repository variables cannot replace them. Advance the image, source, cut, and compatible seed together through a reviewed change. The current identity was selected in PR #1956 and published by successful server run 37188030565. It includes the Preview alerts opt-in gate that the former August repository variable image did not enforce. This selection is integration evidence, not a claim of complete release qualification. External mode still accepts the explicit target inputs and variables below.
External mode configuration
| Scope | Name | Purpose |
|---|---|---|
| Repository variable | HONUA_INTEGRATION_BASE_URL |
URL of an external Honua Server. Unset means self-contained mode. |
| Repository secret | HONUA_INTEGRATION_API_KEY |
X-API-Key (matches server HONUA_ADMIN_PASSWORD). Required in external mode. |
| Repository variable (optional) | HONUA_INTEGRATION_SERVICE_ID, HONUA_INTEGRATION_LAYER_ID, HONUA_INTEGRATION_COLLECTION_ID, HONUA_INTEGRATION_TILE_MATRIX_SET, HONUA_INTEGRATION_SEED_PROFILE, HONUA_INTEGRATION_SERVER_COMMIT, HONUA_INTEGRATION_EXTERNAL_SERVER_IMAGE |
Override the harness defaults to match the external seed and record its provenance. HONUA_INTEGRATION_SERVER_COMMIT records the Honua Server commit (not the SDK commit) in integration-meta.json. |
Metadata artifact
integration-meta.json records the run context:
{
"sdkPackage": "@honua/sdk-js",
"sdkVersion": "0.0.3-alpha.0",
"serverVersion": "1.x.y",
"serverReleaseChannel": "preview",
"serverImage": "ghcr.io/honua-io/honua-server@sha256:…",
"serverCommit": "<honua-server commit SHA, or null when unknown>",
"baseUrl": "http://localhost:5555",
"seedProfile": "places-roads-v1",
"serviceId": "test_service_gw0",
"layerId": 1000,
"collectionId": "1000",
"tileMatrixSetId": "WebMercatorQuad",
"startedAt": "2026-04-28T01:23:45Z",
"surfaces": [
{ "surface": "feature-server", "status": "exercised", "recordedAt": "…" },
{ "surface": "image-server", "status": "skipped", "reason": "…", "recordedAt": "…" }
]
}
This is the lane's only persistent observable signal — the workflow attaches it to every run so SDK / server drift is traceable from the GitHub Actions UI without re-running the suite.
Governed certification receipts
Ordinary push, schedule, and context-free dispatch runs still execute the live
integration and conformance suites and retain their raw reports. They do not
emit a protocol certification fragment. A certification dispatch supplies
requirements_context; both nightly_dispatch_id and
licensed_certification: true require it. Missing context fails the run.
The reviewed release dispatcher projects honua.protocol-producer-context/v1
from the canonical requirements catalog. The JSON input is limited to 60,000
UTF-8 bytes and binds its catalog requirements_revision, producer
honua-sdk-js, executing producer_source_sha, and candidate
source_sha, image_digest, and cut_at. Its requirements array contains the
complete 67-row SDK roster for community/nightly execution, or the two-row
licensed roster for an explicit licensed execution. Community runs retain the
two licensed rows as skips with no receipt, even if a report contains passing
realtime markers; only the separate live-entitlement path can certify them.
Each row carries
capability_key, surface, operation, canonical_client, client_version,
client_lane, deployment_target, fixture_revision, contract_revision,
auth_policy_revision, scenario_facets, maturity, and required_tier.
The producer refuses missing, duplicate, foreign, or mismatched rows. SDK
contracts currently govern facet markers rather than test_ids; adding
ungoverned test IDs is refused.
Every executed receipt uses honua.certification-evidence-receipt/v2 and includes
producer-owned maturity, required tier, requirements revision, and the candidate
cut in its hashed identity. There is no v1 or context-free receipt fallback.
Missing executable coverage remains a reported gap, even with valid context.
Licensed receipts still require the existing live entitlement proof.
For an offline normalization of retained reports, pass the reviewed context file
using node scripts/protocol-certification-fragment.mjs --requirements-context /path/to/context.json together with the existing execution identity inputs.
HONUA_REQUIREMENTS_CONTEXT supplies the same JSON in the hosted workflow.
Context must come from the reviewed catalog projection; do not manufacture it
from the observed test outcomes.