Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
3c7406c
feat(test-server): add the .NET ESDK test server
Aug 1, 2026
08d0632
feat(test-server): add the Dafny-Rust ESDK test server
Aug 1, 2026
ec6b0f6
feat(test-server): add the Go ESDK test server
Aug 1, 2026
f154649
ci(test-server): build + test the three servers
Aug 1, 2026
e3eee03
chore(test-server): format commons configurations with prettier
Aug 1, 2026
efd687b
fix(rust): pin aws-lc-sys 0.43 to match aws-lc-rs 1.17
Aug 1, 2026
fe3e183
fix(test-server): sign Go server AWS requests via the default credent…
Aug 1, 2026
9caa54d
ci(test-server): run the cross-language suite for each server on PR
lucasmcdonald3 Aug 4, 2026
9a0db91
ci(test-server): use the public KMS role ARN instead of a secret
lucasmcdonald3 Aug 5, 2026
4f3296e
ci(test-server): reference the COMMONS_REPO_PAT secret
lucasmcdonald3 Aug 5, 2026
5f01ae6
ci(test-server): stub the unpublished MPL test-vectors artifact for t…
lucasmcdonald3 Aug 5, 2026
d526931
ci(esdk): provision full cross-language toolchain matrix for the Test…
lucasmcdonald3 Aug 5, 2026
517bc78
ci(esdk): restore commons build caches + widen server-readiness windo…
lucasmcdonald3 Aug 5, 2026
9150f6a
ci(esdk): restore JDK 21 before the net orchestrated run
lucasmcdonald3 Aug 7, 2026
7287e62
ci(esdk): restore full matrix toolchain before the net orchestrated run
lucasmcdonald3 Aug 7, 2026
01af721
chore: re-trigger CI
lucasmcdonald3 Aug 12, 2026
9eade3c
chore: re-trigger test-server CI (watchdog)
lucasmcdonald3 Aug 12, 2026
8564790
chore: re-trigger test-server CI (watchdog)
lucasmcdonald3 Aug 12, 2026
b1b0e61
chore: re-trigger test-server CI (watchdog)
lucasmcdonald3 Aug 12, 2026
780bb07
chore: re-trigger test-server CI (watchdog)
lucasmcdonald3 Aug 12, 2026
eb96edf
fix(esdk): match direct aws-lc -sys versions to aws-lc-rs
Aug 14, 2026
ee8b254
ci(esdk): make the duplicate-aws-lc failure actionable
Aug 14, 2026
76520a9
ci(esdk): fix duplicate-aws-lc false failure on a clean tree
Aug 14, 2026
f164096
ci(esdk): restore a one-line 'why it matters' to the duplicate-aws-lc…
Aug 14, 2026
a1aa24e
ci(esdk): reframe the duplicate-aws-lc 'why' as customer build cost
Aug 14, 2026
a8663d2
ci(esdk): add version-ambiguity reason to duplicate-aws-lc 'why'
Aug 14, 2026
88b3f33
fix(esdk): match TestVectors direct aws-lc -sys versions to aws-lc-rs
Aug 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
634 changes: 634 additions & 0 deletions .github/workflows/esdk-test-servers.yml

Large diffs are not rendered by default.

93 changes: 32 additions & 61 deletions .github/workflows/rust_duplicate_deps.yml
Original file line number Diff line number Diff line change
@@ -1,25 +1,13 @@
# Fails CI if more than one version of the aws-lc native crates
# (aws-lc-sys / aws-lc-fips-sys) resolves into the Rust dependency tree.
#
# aws-lc-rs pulls in one of these -sys crates transitively. Declaring a
# DIRECT dependency on a different version forces a second copy of AWS-LC to
# compile, which has real costs:
# * ~2x native C build time, and a larger binary (two libcrypto copies are
# statically linked).
# * The SDK's raw FFI calls (aws_lc_sys_impl::*) run against the version
# declared directly here, while aws-lc-rs's safe APIs run against the
# version aws-lc-rs pulls in. The two paths can therefore use different
# AWS-LC builds, and the raw-FFI path can stay on a stale or vulnerable
# version independently of aws-lc-rs. Only byte buffers cross between the
# two copies, so it is memory-safe -- but wasteful and a security-skew risk.
#
# The fix is always to pin the direct -sys version to match aws-lc-rs.
# Fails CI if a direct aws-lc-sys / aws-lc-fips-sys version differs from the one
# aws-lc-rs pulls in transitively. Two versions compile two separate copies of
# AWS-LC -- roughly 2x the native build time and a larger binary for customers
# building our code -- and leave it unclear which version is actually in use, so
# behavior can diverge if the two differ. The fix is to match the direct -sys
# version to aws-lc-rs.
name: Rust Duplicate aws-lc Dependency Check

on:
# Invoked by pull.yml so this check is part of the required
# pr-ci-all-required gate (a failure must block merge). Also runs
# directly on push to the default branch.
# Invoked by pull.yml so a failure blocks the pr-ci-all-required gate.
workflow_call: {}
push:
branches:
Expand All @@ -41,10 +29,8 @@ jobs:
with:
cache: false

# The Rust sources under runtimes/rust are partially generated
# (gitignored), but `cargo tree` only needs a resolvable manifest.
# Stub any missing targets so dependency resolution succeeds without
# running codegen.
# runtimes/rust sources are partially generated (gitignored); cargo tree
# needs a resolvable manifest, not the sources, so stub missing targets.
- name: Stub generated targets
shell: bash
working-directory: ./AwsEncryptionSDK/runtimes/rust
Expand All @@ -60,50 +46,35 @@ jobs:
set -euo pipefail
status=0

# Print the duplicate aws-lc blocks for one feature profile, and if
# any exist, explain what to do. `cargo tree -d` lists each duplicated
# package followed by the reverse-dependency tree, so it shows exactly
# which package pulls in each version (e.g. the direct dep vs aws-lc-rs).
check_profile() {
label="$1"
args="$2"

# Liveness guard: a "no duplicates" result is only trustworthy if the
# tree actually resolved. This check intentionally ignores cargo
# errors below, so without this guard a resolution failure (broken
# stub, missing submodule, dropped feature, etc.) would pass silently.
# aws-lc-rs is a non-optional dependency, so it MUST appear; if it
# does not, fail loudly instead of reporting a false "all clear".
if ! cargo tree $args 2>/dev/null | grep -q 'aws-lc-rs v'; then
echo "::error::Duplicate check could not resolve the dependency tree ($label build) -- failing instead of passing silently. Run 'cargo tree $args' locally to debug."
status=1
return
fi
# aws-lc-rs is non-optional, so it must resolve; if it does not the
# tree is broken and a "no duplicates" result would be a false pass.
tree=$(cargo tree $args 2>/dev/null || true)
case "$tree" in
*"aws-lc-rs v"*) : ;;
*)
echo "::error::Duplicate check could not resolve the dependency tree ($label build). Run 'cargo tree $args' locally to debug."
status=1
return 0
;;
esac

dup=$(cargo tree -d $args 2>/dev/null || true)
awslc=$(printf '%s\n' "$dup" | awk 'BEGIN{RS="";ORS="\n\n"} /^aws-lc-(sys|fips-sys) v/' || true)
if [ -n "$(printf '%s' "$awslc" | tr -d '[:space:]')" ]; then
status=1
echo "::error::Duplicate aws-lc native crate detected ($label build). See log for how to fix."
echo "------------------------------------------------------------------------"
echo "Duplicate aws-lc native crate(s) in the $label dependency tree."
echo "Each version below compiles a separate copy of AWS-LC. The tree shows"
echo "which package pulls in each version:"
echo ""
printf '%s\n' "$awslc" | sed 's/^/ /'
echo "Declared directly in this crate's Cargo.toml:"
grep -nE '^aws-lc-(sys|fips-sys)[[:space:]]' Cargo.toml | sed 's/^/ /' || true
echo ""
echo "Why this matters: a different DIRECT -sys version forces a second copy"
echo "of AWS-LC to compile (~2x native C build time + larger binary), and the"
echo "SDK's raw FFI (aws_lc_sys_impl::*) then uses the version YOU declared"
echo "while aws-lc-rs uses the one it pulls in -- so the raw path can stay on a"
echo "stale/vulnerable AWS-LC independently of aws-lc-rs."
echo ""
echo "How to fix: set the direct version to the SAME version aws-lc-rs resolves"
echo "to (shown above), then confirm locally with: cargo tree -d"
echo "------------------------------------------------------------------------"
awslc=$(cargo tree -d $args 2>/dev/null | awk 'BEGIN{RS="";ORS="\n\n"} /^aws-lc-(sys|fips-sys) v/' || true)
if [ -z "$(printf '%s' "$awslc" | tr -d '[:space:]')" ]; then
return 0
fi

status=1
crate=$(printf '%s\n' "$awslc" | grep -oE '^aws-lc-(fips-)?sys' | head -1 || true)
have=$(grep -E "^${crate}[[:space:]]*=" Cargo.toml | grep -oE 'version = "[^"]+"' | head -1 | grep -oE '"[^"]+"' | tr -d '"' || true)
want=$(cargo tree $args -p aws-lc-rs 2>/dev/null | grep -oE "${crate} v[0-9]+(\.[0-9]+)+" | head -1 | sed 's/.* v//' || true)

echo "::error::Duplicate ${crate} in the ${label} build: Cargo.toml declares \"${have}\", aws-lc-rs pulls v${want}."
echo "Why it matters: two versions compile two separate copies of AWS-LC -- ~2x the native build time and a larger binary for customers building our code -- and it is unclear which version is actually in use, so our library's behavior can diverge if the two differ."
echo "Fix: open a PR changing ${crate} in AwsEncryptionSDK/runtimes/rust/Cargo.toml from \"${have}\" to \"${want}\", then verify with: cargo tree -d${args:+ $args}"
}

check_profile "default" ""
Expand Down
4 changes: 2 additions & 2 deletions AwsEncryptionSDK/runtimes/rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ readme = "README.md"
[dependencies]
aws-config = "1.8.12"
aws-lc-rs = {version = "1.17.0"}
aws-lc-sys = { version = "0.42", optional = true }
aws-lc-fips-sys = { version = "0.13.1", optional = true }
aws-lc-sys = { version = "0.44", optional = true }
aws-lc-fips-sys = { version = "0.14.1", optional = true }
aws-sdk-dynamodb = "1.103.0"
aws-sdk-kms = "1.98.0"
aws-smithy-runtime-api = {version = "1.10.0", features = ["client"] }
Expand Down
4 changes: 2 additions & 2 deletions TestVectors/runtimes/rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ readme = "README.md"
[dependencies]
aws-config = "1.8.12"
aws-lc-rs = {version = "1.15.4"}
aws-lc-sys = { version = "0.39", optional = true }
aws-lc-fips-sys = { version = "0.13", optional = true }
aws-lc-sys = { version = "0.44", optional = true }
aws-lc-fips-sys = { version = "0.14.1", optional = true }
aws-sdk-dynamodb = "1.103.0"
aws-sdk-kms = "1.98.0"
aws-smithy-runtime-api = {version = "1.10.0", features = ["client"] }
Expand Down
5 changes: 5 additions & 0 deletions esdk-test-servers/go/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
esdk-test-server
/go
.server.pid
.server.log
.commons-clone/
103 changes: 103 additions & 0 deletions esdk-test-servers/go/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# Target vocabulary (build-server / start-server / wait-for-server / stop-server)
# matches the commons TestServer orchestration. Recipes are single shell lines
# for the 3.81 Make that ships with macOS.

SHELL := bash

# Port for the server (override: make run-server PORT=9090).
PORT ?= 8099

BIN := esdk-test-server
PID_FILE := .server.pid
LOG_FILE := .server.log

# Bootstrap-then-delegate coordinates for `make test-server`. The commons
# repository coordinates live in commons-configuration.json next to this
# Makefile; COMMONS_BRANCH overrides the configured branch at invocation time.
MAKEFILE_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST))))
REPO_ROOT := $(abspath $(MAKEFILE_DIR)/../..)
COMMONS_CONFIGURATION := $(MAKEFILE_DIR)/commons-configuration.json
COMMONS_BRANCH ?=
CLONE_DIR ?= $(MAKEFILE_DIR)/.commons-clone
CLONE_ORCH_DIR := $(CLONE_DIR)/esdk/test-server/orchestrator

.PHONY: help build-server run-server start-server wait-for-server stop-server \
test test-server check-java fmt vet check clean

help: ## Show this help
@echo "ESDK TestServer (Go) — make targets"
@grep -E '^[a-zA-Z0-9_-]+:.*## ' "$(lastword $(MAKEFILE_LIST))" \
| sort | awk 'BEGIN{FS=":.*## "}{printf " %-18s %s\n", $$1, $$2}'
@echo ""
@echo " PORT=$(PORT)"

build-server: ## Build the server
go build -o $(BIN) .

run-server: build-server ## Run the server in the FOREGROUND on PORT (Ctrl-C to stop)
./$(BIN) $(PORT)

start-server: build-server ## Start the server in the BACKGROUND on PORT (writes .server.pid)
@./$(BIN) $(PORT) >"$(LOG_FILE)" 2>&1 & echo $$! >"$(PID_FILE)"; \
echo "started esdk-test-server (pid $$(cat $(PID_FILE))) on port $(PORT)"

wait-for-server: ## Block until the server accepts connections on PORT (120s timeout)
@for i in $$(seq 1 120); do \
if (exec 3<>"/dev/tcp/127.0.0.1/$(PORT)") 2>/dev/null; then echo "server ready on $(PORT)"; exit 0; fi; \
sleep 1; \
done; \
echo "timed out waiting for port $(PORT)"; [ -f "$(LOG_FILE)" ] && tail -n 40 "$(LOG_FILE)"; exit 1

stop-server: ## Stop the background server and free PORT
@if [ -f "$(PID_FILE)" ]; then kill "$$(cat $(PID_FILE))" 2>/dev/null || true; rm -f "$(PID_FILE)"; fi; \
pids=$$(lsof -ti tcp:$(PORT) 2>/dev/null || true); \
if [ -n "$$pids" ]; then kill $$pids 2>/dev/null || true; fi; \
echo "stopped server on port $(PORT)"

test: ## Run the server's tests
go test ./...

check-java: ## Verify JAVA_HOME points at a JDK 21+ (the commons orchestrator needs it)
@if [ -z "$$JAVA_HOME" ] || [ ! -x "$$JAVA_HOME/bin/java" ]; then \
echo "ERROR: JAVA_HOME must point at a JDK 21+ for the commons orchestrator." >&2; exit 1; \
fi; \
v=$$("$$JAVA_HOME/bin/java" -version 2>&1 | grep -i version | head -1 | sed -E 's/.*version .?([0-9]+).*/\1/'); \
if [ -z "$$v" ] || [ "$$v" -lt 21 ] 2>/dev/null; then \
echo "ERROR: JDK 21+ required, JAVA_HOME has major version '$$v'." >&2; exit 1; \
fi

# Bootstrap-then-delegate (the single orchestrated entry point): parse the
# commons coordinates, clone commons at the branch head, and run the
# orchestrator core in the clone with this working tree as the live Go
# library + server source. The core builds and launches every configured
# Language_Server, runs the full Tests matrix, and tears down; its exit code
# propagates. Needs AWS credentials and a JDK 21+.
test-server: check-java ## Run the complete cross-language TestServer via the commons orchestrator; COMMONS_BRANCH=<b> overrides
@set -eo pipefail; \
if ! coords=$$(python3 -c 'import json,sys; c=json.load(open(sys.argv[1]))["commonsRepository"]; print(c["url"]); print(c["branch"])' "$(COMMONS_CONFIGURATION)" 2>/dev/null); then \
echo "ERROR: missing or unparseable $(COMMONS_CONFIGURATION); halting before any clone." >&2; exit 1; \
fi; \
{ read -r url; read -r branch; } <<< "$$coords"; \
if [ -n "$(strip $(COMMONS_BRANCH))" ]; then branch="$(strip $(COMMONS_BRANCH))"; reason="invocation-override"; else reason="configuration-entry"; fi; \
echo "==> Cloning commons at '$$branch' ($$reason) into $(CLONE_DIR)"; \
rm -rf "$(CLONE_DIR)"; \
if ! git clone --depth 1 --single-branch --branch "$$branch" "$$url" "$(CLONE_DIR)"; then \
echo "ERROR: failed to clone $$url at branch $$branch; no Tests will run." >&2; exit 1; \
fi; \
if [ ! -d "$(CLONE_ORCH_DIR)" ]; then \
echo "ERROR: branch $$branch of $$url has no orchestrator at esdk/test-server/orchestrator." >&2; exit 1; \
fi; \
echo "==> Delegating: context=language:go languageRepoRoot=$(REPO_ROOT)"; \
cd "$(CLONE_ORCH_DIR)" && ./gradlew --console=plain run \
--args="context=language:go languageRepoRoot=$(REPO_ROOT) commonsOrigin.url=$$url commonsOrigin.branch=$$branch commonsOrigin.reason=$$reason"

fmt: ## Check formatting
@out=$$(gofmt -l .); if [ -n "$$out" ]; then echo "gofmt needed on:"; echo "$$out"; exit 1; fi

vet: ## Lint with go vet
go vet ./...

check: fmt vet build-server test ## fmt + vet + build + test (the CI gate)

clean: ## Remove build output, server scratch files, and the commons clone
rm -f "$(BIN)" "$(PID_FILE)" "$(LOG_FILE)"; rm -rf "$(CLONE_DIR)"
53 changes: 53 additions & 0 deletions esdk-test-servers/go/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# ESDK TestServer — Go Language_Server

A hand-rolled [rpcv2Cbor](https://smithy.io/2.0/additional-specs/protocols/smithy-rpc-v2.html)
HTTP server that implements the ESDK TestServer Smithy contract and delegates
each operation to the AWS Encryption SDK for Go
(`releases/go/encryption-sdk` in this repository).

## Embedded reference to the commons TestServer

The single source of truth for the wire contract — the Smithy model, the one
generated Test_Client, and the one Tests suite — lives in the commons repo:

- Repository: [`aws/aws-crypto-tools-commons`](https://github.com/aws/aws-crypto-tools-commons)
- Model: `esdk/test-server/model/esdk-test-server.smithy`
- Tests: `esdk/test-server/tests`

This directory hosts only the Go Language_Server; it consumes the commons
contract. The commons coordinates are pinned in `commons-configuration.json`.

## What it speaks

- `POST /service/ESDKTestServer/operation/{Operation}`
- Header `smithy-protocol: rpc-v2-cbor`, `Content-Type: application/cbor`
- CBOR map request/response bodies; errors as a CBOR map `{__type, message}`
- Operations: `CreateClient`, `Encrypt`, `Decrypt`. `EncryptStream` / `DecryptStream`
return `GenericServerError` (this server is non-streaming).

## Running

```bash
make run-server PORT=8099 # foreground
# or, orchestrated:
make start-server PORT=8099
make wait-for-server PORT=8099
make stop-server PORT=8099
make check # fmt + vet + build + test (the CI gate)
```

## Full cross-language matrix

```bash
make test-server # clone commons and delegate to its orchestrator
```

Clones the commons repository at the branch pinned in
`commons-configuration.json` (`COMMONS_BRANCH=<b>` overrides) and runs the
orchestrator's full Tests matrix against this server. Needs AWS credentials and
a JDK 21+.

## Layout

`model.go` (shapes + CBOR mapping), `wire.go` (protocol), `keyring.go`
(config→MPL mapping), `handlers.go` (delegation + client registry).
24 changes: 24 additions & 0 deletions esdk-test-servers/go/commons-configuration.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"commonsRepository": {
"name": "aws-crypto-tools-commons",
"url": "git@github.com:aws/aws-crypto-tools-commons.git",
"branch": "lucmcdon/esdk-test-server-all-languages"
},
"product": "esdk",
"supportedFeatures": [
"MPL",
"hierarchical",
"raw-aes",
"raw-rsa",
"multi",
"aws-kms",
"aws-kms-multi",
"aws-kms-discovery",
"aws-kms-mrk",
"aws-kms-mrk-multi",
"aws-kms-mrk-discovery",
"aws-kms-rsa",
"required-encryption-context"
],
"unsupportedFeatures": ["streaming", "raw-ecdh", "aws-kms-ecdh", "caching"]
}
36 changes: 36 additions & 0 deletions esdk-test-servers/go/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
module github.com/aws/aws-encryption-sdk/esdk-test-servers/go

go 1.24

require (
github.com/aws/aws-cryptographic-material-providers-library/releases/go/mpl v0.4.0
github.com/aws/aws-encryption-sdk/releases/go/encryption-sdk v0.0.0
github.com/aws/aws-sdk-go-v2 v1.41.7
github.com/aws/aws-sdk-go-v2/config v1.32.17
github.com/aws/aws-sdk-go-v2/service/dynamodb v1.57.3
github.com/aws/aws-sdk-go-v2/service/kms v1.51.1
github.com/aws/smithy-go v1.25.1
github.com/google/uuid v1.6.0
)

require (
github.com/aws/aws-cryptographic-material-providers-library/releases/go/dynamodb v0.4.0 // indirect
github.com/aws/aws-cryptographic-material-providers-library/releases/go/kms v0.4.0 // indirect
github.com/aws/aws-cryptographic-material-providers-library/releases/go/primitives v0.4.0 // indirect
github.com/aws/aws-cryptographic-material-providers-library/releases/go/smithy-dafny-standard-library v0.4.0 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.19.16 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.23 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.23 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.23 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.24 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.9 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.11.23 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.23 // indirect
github.com/aws/aws-sdk-go-v2/service/signin v1.0.11 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.30.17 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.21 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.42.1 // indirect
github.com/dafny-lang/DafnyRuntimeGo/v4 v4.11.3 // indirect
)

replace github.com/aws/aws-encryption-sdk/releases/go/encryption-sdk => ../../releases/go/encryption-sdk
Loading
Loading