Skip to content

g8e v1.6.0

Choose a tag to compare

@Badoot Badoot released this 20 Jul 18:19
Immutable release. Only release title and notes can be modified.
7a2190f

[1.6.0] - 2026-07-20

Overview

Cross-language governance hash parity, enrollment token TOCTOU fix, SSE resilience improvements, and governance model schema alignment. This release ensures Go and Python produce identical transaction hash digests by aligning canonicalization logic, hardens enrollment token consumption against race conditions with atomic conditional updates, makes the SSE heartbeat interval configurable, fixes multi-line SSE data parsing per spec, improves pubsub reconnect backoff reset logic, updates Python governance models to match proto definitions, adds a canonical governance JSON schema, and expands test coverage by approximately 1,665 lines across 15 new test files.

Added

  • Governance JSON schemaprotocol/models/governance.json (263 lines) defines canonical governance wire shapes matching protocol/proto/g8e/common/v1/common.proto. Covers l1_metadata, l2_vote, l2_metadata, l3_proof, l3_metadata, governance_metadata, and governance_envelope.
  • GovernanceL3Proof Python modelprotocol/python/g8e/models/governance.py adds GovernanceL3Proof model representing the L3 notary proof union (WebAuthn or CLI/mTLS). Fields: client_data_json, authenticator_data, signature, credential_id (WebAuthn), mtls_cert_fingerprint, cli_signature (CLI/mTLS). Exported from protocol/python/g8e/models/__init__.py.
  • Cross-language hash parity conformance testsprotocol/conformance/test_hash_parity.py (127 lines) verifies Python compute_transaction_hash matches Go GenerateMessageID using shared test vectors in protocol/conformance/hash_vectors.json (109 lines). Covers standard, nested intent, unicode, empty payload, empty intent, optional omitted, and timestamp normalization cases.
  • DocConditionalUpdate methodinternal/services/gateway/document_store_service.go adds DocConditionalUpdate(collection, id, setFields, conditionField, conditionValue) for atomic conditional SQL updates. Uses json_extract in a WHERE clause to check a condition and json_set chain to apply updates in a single statement, preventing TOCTOU races.
  • Configurable SSE heartbeat intervalHTTPHandlerDependencies and HTTPHandler gain SSEHeartbeatInterval field (internal/services/gateway/gateway_http.go). Defaults to 30 seconds when zero. handleInternalSSEStream uses h.sseHeartbeatInterval instead of a hardcoded 30s constant.
  • ErrPasskeySSEStreamClosed errorinternal/constants/errors.go adds error for unexpected SSE stream disconnection during passkey enrollment, enabling distinct handling of timeout vs. stream-closed scenarios.
  • programSender interfaceinternal/cli/auth/passkey_bootstrap.go adds programSender interface (implemented by *tea.Program) to decouple SSE monitoring from the terminal program, enabling unit testing of monitorPasskeyRegistration with a channel-based mock.
  • SetSubscribeError mock methodinternal/services/pubsub/pubsubtest/mock_client.go adds SetSubscribeError(err) to inject subscribe failures in tests.
  • Static linking verification.github/workflows/build-and-test.yml adds a CI step that verifies the Linux binary is statically linked using file and ldd checks.
  • Governance model conformance testsprotocol/conformance/test_models.py adds TestGovernanceL1Conformance, TestGovernanceL2Conformance, TestGovernanceL3Conformance, TestGovernanceMetadataConformance, and TestGovernanceEnvelopeConformance classes with round-trip serialization, default value, and schema field parity tests for the updated governance models.

Changed

  • Go canonicalizeMap / canonicalizeValue error propagationinternal/governance/envelope.go: Both functions now return (string, error) instead of string. Unknown types produce an error instead of silently falling back to json.Marshal, ensuring cross-language hash parity. GenerateMessageID propagates canonicalization errors. Removed encoding/json import.
  • Python compute_transaction_hash rewriteprotocol/python/g8e/models/governance.py: Rewritten to match Go's GenerateMessageID exactly. Empty/None fields are omitted entirely (no value, no separator). A trailing | follows each present field. Timestamps normalized to fixed 6-digit microsecond UTC via _normalize_timestamp(). Intent data canonicalized as key=value,key=value via _canonicalize_map() / _canonicalize_value() instead of JSON. Unsupported types raise TypeError.
  • Python governance model field updatesprotocol/python/g8e/models/governance.py:
    • GovernanceL1.violations changed from list[dict[str, Any]] to list[str]
    • GovernanceL2Vote fields changed from (voter_id, decision, timestamp, signature) to (signer_key_id, consensus_signature, decision)
    • GovernanceL2 fields changed from (votes, consensus_reached, threshold) to (tribunal_id, votes)
    • GovernanceL3 fields changed from (notary_id, signature, timestamp, certificate_chain) to (proof)
  • Enrollment token atomic consumptioninternal/services/gateway/enrollment_token_service.go: ValidateAndConsumeToken now uses DocConditionalUpdate with consumed = 0 condition instead of read-then-write. The atomic conditional UPDATE prevents TOCTOU races where concurrent callers could both read consumed=false before either writes consumed=true. Returns ErrEnrollmentTokenConsumed if another caller consumed it between read and update.
  • Passkey bootstrap SSE monitoring extractioninternal/cli/auth/passkey_bootstrap.go: SSE monitoring logic extracted into monitorPasskeyRegistration(ctx, sseClient, sender) function. On clean SSE disconnect without a registration event, sends enrollErrMsg with ErrPasskeySSEStreamClosed (previously only handled context cancellation/timeout).
  • SSE multi-line data parsinginternal/cli/sse/client.go: parseSSEStream now concatenates multiple data: lines with \n between them per the SSE specification, instead of overwriting the previous data line.
  • Pubsub reconnect backoff resetinternal/services/pubsub/pubsub_commands.go: Reconnect attempt counter (attempts) is now reset to 0 on successful connection. Previously, attempts accumulated across disconnect cycles, causing premature give-up after transient failures. Backoff delay calculation extracted into nextReconnectDelay(current, max) and give-up check into shouldGiveUp(attempts, maxAttempts).
  • actions/setup-go v6 to v7 — Bumped across .github/workflows/build-and-test.yml and .github/workflows/release-binary.yml.
  • Governance architecture docdocs/architecture/governance.md updated: intent data canonicalization now rejects unsupported types with an error (no silent fallback), ensuring cross-language hash parity between Go and Python.
  • Tests documentationdocs/devs/tests.md updated: conformance suite count updated from 330 to 420 tests across 3 files, with test_hash_parity.py description added.

Fixed

  • Enrollment token TOCTOU race — Concurrent calls to ValidateAndConsumeToken could both read consumed=false and proceed to consume the same token. Fixed with atomic conditional SQL update that only sets consumed=true if the current value is 0 (false).
  • SSE multi-line data lossparseSSEStream overwrote data on each data: line instead of concatenating, causing multi-line SSE data payloads to be truncated. Fixed to join lines with \n per spec.
  • Pubsub premature reconnect give-up — The attempts counter was never reset on successful reconnection, so a sequence of transient disconnects across multiple connection lifetimes could exhaust maxReconnectAttempts even though each individual disconnect was recoverable. Fixed by resetting attempts to 0 when a connection is established.

Tests

  • internal/cli/auth/passkey_bootstrap_sse_test.go — 159 lines: monitorPasskeyRegistration behavior with mock programSender, covering registration event, timeout, and stream-closed scenarios
  • internal/cli/sse/sse_parser_test.go — 98 lines: SSE parser edge cases including multi-line data, event/data ordering, and blank line dispatch
  • internal/governance/envelope_hash_parity_test.go — 175 lines: Go hash canonicalization with nested maps, arrays, unicode, empty fields, and unsupported type error cases
  • internal/services/gateway/enrollment_token_concurrent_test.go — 114 lines: Concurrent token consumption race condition verification
  • internal/services/gateway/enrollment_token_service_test.go — 16 lines: Additional enrollment token service edge cases
  • internal/services/gateway/sse_backpressure_test.go — 111 lines: SSE backpressure and slow consumer handling
  • internal/services/gateway/sse_event_cleanup_test.go — 117 lines: SSE event cleanup and subscriber removal
  • internal/services/governance/l4_warden_dependency_failure_test.go — 128 lines: L4 Warden behavior when dependencies fail
  • internal/services/governance/l4_warden_tribunal_edge_test.go — 278 lines: L4 Warden tribunal edge cases
  • internal/services/governance/signer_store_test.go — Renamed from warden_edge_test.go: signer store test coverage
  • internal/services/pubsub/reconnect_backoff_test.go — 219 lines: Reconnect backoff progression, cap, and reset behavior
  • internal/services/pubsub/reconnect_reset_test.go — 162 lines: Reconnect attempt counter reset on successful connection
  • internal/services/tribunal/factory_error_test.go — Renamed from factory_edge_test.go: tribunal factory error cases
  • internal/services/tribunal/service_concurrent_test.go — 81 lines: Tribunal service concurrent operation safety
  • protocol/conformance/test_hash_parity.py — 127 lines: Cross-language hash parity with shared test vectors
  • protocol/conformance/test_models.py — Governance model conformance tests for updated L1, L2, L3, L3Proof, Metadata, and Envelope models
  • protocol/python/tests/test_models.py — Updated governance model tests to match new field names and structures