A correction, first
An older architecture document in this repository assumedExecutionGateway lives at
packages/api/src/execution-gateway/ExecutionGateway.ts. That path does not exist. The real,
current location is packages/execution-gateway/src/ExecutionGateway.ts, a separate,
top-level package, not something nested inside packages/api. This chapter is written
directly from that real file.
What it is
ExecutionGateway implements @parmana/execution-system’s ExecutionSystem interface, the
same seam RuntimeFactory.create() (Chapter 8) accepts any implementation of. Its own class
doc comment calls it “the sole release boundary” for whichever Connector it’s constructed
with: no execution reaches a connector without passing through this gateway’s full
verification sequence first.
Why it was built
A signedExecutionAuthorizationPayload (Chapter 9) proves a decision was made, but
something still has to actually check that proof before letting a connector run, and that
something needs to independently re-verify, not just trust, every claim the envelope makes,
including claims about the world having stayed the same since the envelope was signed
(the policy hasn’t changed, the underlying signals haven’t drifted). ExecutionGateway
composes @parmana/envelope-verifier’s EnvelopeVerifier (signature/expiry/TTL/nonce) and
adds two further checks of its own: a content-hash recompute-and-compare, and, when wired,
policy-freshness and signal-freshness checks against the current state of the world, not
just the state at authorization time.
How it works
Construction (ExecutionGatewayOptions) requires a publicKey (or a keyProvider for
keyId-aware, rotation-safe lookup) and a nonceStore, and exactly one of a connector or an
executionControl (constructing with both, or neither, throws immediately). Optional
policyRepository and signalStateVerifier enable the two additive checks below; omitting
either skips that specific check rather than failing closed on it.
verify(request, now) runs the checks in this exact order, quoted directly from the class
doc comment, “Session 3’s ordering rule: side-effect-free checks first, nonce consumed last
and only on success”:
version -> signature -> expiry -> TTL policy(all insideEnvelopeVerifier.verifyChecks()).businessTransactionHashrecompute-and-compare, only attempted if step 1 passed.policyStillCurrentrecompute-and-compare (when aPolicyRepositoryis wired and the authorization carries apolicyContentHash), recomputes the current content hash of the named policy and compares it to what the authorization was signed under. If the policy no longer exists at all (e.g. replaced in place by a governed change), this is treated identically to a content mismatch, not a separate error case.signalsStillCurrentrecompute-and-verify (when aSignalStateVerifieris wired and both the request and authorization carry signals/signalsHash), first a hash comparison (catching a request whose signals were altered after authorization), then an independent re-verification of those signals against real-world state via the verifier.- Nonce consumption, last, only if every prior check passed. This is the only side-effecting check in the sequence, “a mismatched or forged request must not burn a nonce.”
execute(request) calls verify(), and on any failure throws, specifically,
NonceAlreadyConsumedError when nonce replay is the sole failing check (every other check
passed), or a generic Error naming every failing check and both hash values on a content
mismatch otherwise. isSoleFailureNonceReplay() is the precise logic for that distinction:
strip out nonceUnseen, and check every remaining value is true or undefined (an
undefined check means “skipped,” which still counts as passing for this purpose). On success,
the verified executableContent is deep-frozen and handed to either the legacy Connector
interface (this.connector.execute(...)) or the newer executionControl path (a
service.execute(...) call with a freshly minted or static gatewayAuthentication value, or
an ExecutionChannel.release(...) call for the deprecated channel-based path).
How it enables things, with examples
examples/tutorials/34-execution-gateway, the gateway directly.examples/tutorials/33-execution-boundary, the boundary concept: what does and doesn’t cross it.examples/tutorials/32-execution-pipeline, the gateway inside the larger pipeline.examples/tutorials/81-connector-execution-gateway, a real connector behind the gateway.examples/tutorials/86-gateway-attestation, attestation semantics at this boundary.
How to validate this yourself
packages/execution-gateway/src/ExecutionGateway.ts, the full verification sequence; every ordering and failure-handling claim above is a direct comment or method in this file.packages/execution-gateway/src/GatewayVerificationResult.ts, the structured result shape (checks,hashMismatch,policyContentMismatch,signalsHashMismatch,signalDivergence).packages/execution-gateway/tests/unit/execution-gateway.test.ts, the primary unit coverage.packages/execution-gateway/tests/unit/execution-gateway.dilithium3.test.ts, the same gateway logic under a post-quantum signature algorithm (see Chapter 3).packages/execution-gateway/tests/unit/credential-non-exposure.test.ts, a separate but closely related guarantee this package also carries, covered in full in Chapter 11 (Credential Isolation).
Integration requirements
- A public key (or
KeyProvider) matching whatever signed the authorizations this gateway will verify. - A
NonceStoreimplementation,MemoryNonceStorefor tests/tutorials,SupabaseNonceStore(via the storage layer, Chapter 13) for a real deployment, so replay protection survives a process restart. - To enable policy-freshness checking: a
PolicyRepository(Chapter 4/13) pointed at the same policy content the signing side used. - To enable signal-freshness checking: a
SignalStateVerifier(Chapter 5) capable of re-deriving the relevant real-world facts. - Exactly one of a
Connectorimplementation or anexecutionControlconfiguration , Chapter 12 covers what a realConnectorlooks like.