Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,14 @@ queryable committed Ledger lineage. Browser success additionally requires the
exact production Console build to pass its Playwright suite against that same
assembly.

Backend runtime registration uses an ephemeral private PKI generated by the
acceptance process. Runtime A publishes through an authenticated TLS Nacos
endpoint; Runtime B and its replacement publish through an mTLS endpoint. The
Router observes those leases before managed invocation. Negative containers
with a wrong CA, wrong server name, or missing mTLS client identity must fail
before publication and leave no routable instance. Test keys exist only in the
caller-owned runtime directory and are never committed or recorded in Ledger.

The `Core integration` reusable workflow accepts a full Core commit SHA,
renders a temporary immutable manifest, and runs both backend and browser
acceptance. Core calls it after every merge to `main`; the tracked Stack
Expand Down
6 changes: 3 additions & 3 deletions components.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"schemaVersion": "1",
"contractIdentity": "NeKiro/contracts@a737184be63533a578355f98d1b8b94648e05910",
"contractIdentity": "NeKiro/contracts@8c385babc9da4c383a0aaa9efe1daeb0b72dd812",
"components": {
"core": {
"repository": "NeKiro-project/NeKiro",
"commitSha": "a737184be63533a578355f98d1b8b94648e05910"
"commitSha": "8c385babc9da4c383a0aaa9efe1daeb0b72dd812"
},
"console": {
"repository": "NeKiro-project/NeKiro-Console",
Expand All @@ -16,7 +16,7 @@
},
"samples": {
"repository": "NeKiro-project/NeKiro-Samples",
"commitSha": "9f26d5e674a79b2d89685b05ca4ed02a2c5ba37d"
"commitSha": "1dcfae990564febdb545c4d02408f3f2991aa5a0"
},
"transportGo": {
"repository": "NeKiro-project/nekiro-a2a-transport-go",
Expand Down
31 changes: 28 additions & 3 deletions compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ services:
RUNTIME_B_CARD_DIGEST: "${RUNTIME_B_CARD_DIGEST:-}"
RUNTIME_B_CANONICAL_ENDPOINT: "${RUNTIME_B_CANONICAL_ENDPOINT:-}"
RUNTIME_B_AUDIENCE: "${RUNTIME_B_AUDIENCE:-}"
RUNTIME_B_NACOS_API_ORIGIN: "http://nacos:8848/nacos"
RUNTIME_B_NACOS_API_ORIGIN: "https://host.docker.internal:${NEKIRO_E2E_NACOS_MTLS_PORT:?NEKIRO_E2E_NACOS_MTLS_PORT must be set and non-empty}/nacos"
RUNTIME_B_NACOS_NAMESPACE_ID: "nekiro"
RUNTIME_B_NACOS_GROUP_NAME: "NEKIRO"
RUNTIME_B_NACOS_SERVICE_NAME: "runtime-b"
Expand All @@ -242,6 +242,10 @@ services:
RUNTIME_B_NACOS_IP_DELETE_TIMEOUT_MS: "10000"
RUNTIME_B_NACOS_REQUEST_TIMEOUT_MS: "3000"
RUNTIME_B_NACOS_AUTH_MODE: "none"
RUNTIME_B_NACOS_TLS_CA_FILE: "/var/run/nekiro-nacos-tls/ca.pem"
RUNTIME_B_NACOS_TLS_SERVER_NAME: "nacos.internal"
RUNTIME_B_NACOS_TLS_CLIENT_CERT_FILE: "/var/run/nekiro-nacos-tls/client.pem"
RUNTIME_B_NACOS_TLS_CLIENT_KEY_FILE: "/var/run/nekiro-nacos-tls/client-key.pem"
RUNTIME_B_ROUTER_URL: "http://a2a-router:8081"
RUNTIME_B_ROUTER_TOKEN: "${RUNTIME_B_ROUTER_TOKEN:?RUNTIME_B_ROUTER_TOKEN must be set and non-empty}"
RUNTIME_B_TARGET_AGENT_ID: "runtime-a"
Expand All @@ -256,9 +260,14 @@ services:
depends_on:
a2a-router:
condition: service_healthy
extra_hosts:
- "host.docker.internal:host-gateway"
volumes:
- "${NEKIRO_E2E_TLS_ROOT:?NEKIRO_E2E_TLS_ROOT must be set and non-empty}:/var/run/nekiro-nacos-tls:ro"
networks:
platform-internal:
ipv4_address: 172.28.0.12
local-access:
healthcheck:
test: ["CMD", "wget", "-q", "-O", "/dev/null", "http://127.0.0.1:8092/readyz"]
interval: 5s
Expand All @@ -279,7 +288,7 @@ services:
RUNTIME_B_CARD_DIGEST: "${RUNTIME_B_CARD_DIGEST:-}"
RUNTIME_B_CANONICAL_ENDPOINT: "${RUNTIME_B_CANONICAL_ENDPOINT:-}"
RUNTIME_B_AUDIENCE: "${RUNTIME_B_AUDIENCE:-}"
RUNTIME_B_NACOS_API_ORIGIN: "http://nacos:8848/nacos"
RUNTIME_B_NACOS_API_ORIGIN: "https://host.docker.internal:${NEKIRO_E2E_NACOS_MTLS_PORT:?NEKIRO_E2E_NACOS_MTLS_PORT must be set and non-empty}/nacos"
RUNTIME_B_NACOS_NAMESPACE_ID: "nekiro"
RUNTIME_B_NACOS_GROUP_NAME: "NEKIRO"
RUNTIME_B_NACOS_SERVICE_NAME: "runtime-b"
Expand All @@ -293,6 +302,10 @@ services:
RUNTIME_B_NACOS_IP_DELETE_TIMEOUT_MS: "10000"
RUNTIME_B_NACOS_REQUEST_TIMEOUT_MS: "3000"
RUNTIME_B_NACOS_AUTH_MODE: "none"
RUNTIME_B_NACOS_TLS_CA_FILE: "/var/run/nekiro-nacos-tls/ca.pem"
RUNTIME_B_NACOS_TLS_SERVER_NAME: "nacos.internal"
RUNTIME_B_NACOS_TLS_CLIENT_CERT_FILE: "/var/run/nekiro-nacos-tls/client.pem"
RUNTIME_B_NACOS_TLS_CLIENT_KEY_FILE: "/var/run/nekiro-nacos-tls/client-key.pem"
RUNTIME_B_ROUTER_URL: "http://a2a-router:8081"
RUNTIME_B_ROUTER_TOKEN: "${RUNTIME_B_ROUTER_TOKEN:?RUNTIME_B_ROUTER_TOKEN must be set and non-empty}"
RUNTIME_B_TARGET_AGENT_ID: "runtime-a"
Expand All @@ -307,9 +320,14 @@ services:
depends_on:
a2a-router:
condition: service_healthy
extra_hosts:
- "host.docker.internal:host-gateway"
volumes:
- "${NEKIRO_E2E_TLS_ROOT:?NEKIRO_E2E_TLS_ROOT must be set and non-empty}:/var/run/nekiro-nacos-tls:ro"
networks:
platform-internal:
ipv4_address: 172.28.0.13
local-access:
healthcheck:
test: ["CMD", "wget", "-q", "-O", "/dev/null", "http://127.0.0.1:8092/readyz"]
interval: 5s
Expand Down Expand Up @@ -363,7 +381,7 @@ services:
RUNTIME_A_CARD_DIGEST: "${RUNTIME_A_CARD_DIGEST:-}"
RUNTIME_A_CANONICAL_ENDPOINT: "${RUNTIME_A_CANONICAL_ENDPOINT:-}"
RUNTIME_A_AUDIENCE: "${RUNTIME_A_AUDIENCE:-}"
RUNTIME_A_NACOS_API_ORIGIN: "http://nacos:8848/nacos"
RUNTIME_A_NACOS_API_ORIGIN: "https://host.docker.internal:${NEKIRO_E2E_NACOS_TLS_PORT:?NEKIRO_E2E_NACOS_TLS_PORT must be set and non-empty}/nacos"
RUNTIME_A_NACOS_NAMESPACE_ID: "nekiro"
RUNTIME_A_NACOS_GROUP_NAME: "NEKIRO"
RUNTIME_A_NACOS_SERVICE_NAME: "runtime-a"
Expand All @@ -377,6 +395,8 @@ services:
RUNTIME_A_NACOS_IP_DELETE_TIMEOUT_MS: "10000"
RUNTIME_A_NACOS_REQUEST_TIMEOUT_MS: "3000"
RUNTIME_A_NACOS_AUTH_MODE: "none"
RUNTIME_A_NACOS_TLS_CA_FILE: "/var/run/nekiro-nacos-tls/ca.pem"
RUNTIME_A_NACOS_TLS_SERVER_NAME: "nacos.internal"
RUNTIME_A_ROUTER_URL: "http://a2a-router:8081"
RUNTIME_A_ROUTER_TOKEN: "${RUNTIME_A_ROUTER_TOKEN:?RUNTIME_A_ROUTER_TOKEN must be set and non-empty}"
RUNTIME_A_TARGET_AGENT_ID: "runtime-b"
Expand All @@ -393,9 +413,14 @@ services:
condition: service_healthy
runtime-b:
condition: service_healthy
extra_hosts:
- "host.docker.internal:host-gateway"
volumes:
- "${NEKIRO_E2E_TLS_ROOT:?NEKIRO_E2E_TLS_ROOT must be set and non-empty}:/var/run/nekiro-nacos-tls:ro"
networks:
platform-internal:
ipv4_address: 172.28.0.14
local-access:
healthcheck:
test: ["CMD", "wget", "-q", "-O", "/dev/null", "http://127.0.0.1:8091/readyz"]
interval: 5s
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module github.com/NeKiro-project/NeKiro-Stack
go 1.26.0

require (
github.com/NeKiro-project/NeKiro v0.0.0-20260810073448-a737184be635
github.com/NeKiro-project/NeKiro v0.0.0-20260810110658-8c385babc9da
github.com/jackc/pgx/v5 v5.10.0
)

Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
github.com/Masterminds/semver/v3 v3.5.0 h1:kQceYJfbupGfZOKZQg0kou0DgAKhzDg2NZPAwZ/2OOE=
github.com/Masterminds/semver/v3 v3.5.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
github.com/NeKiro-project/NeKiro v0.0.0-20260810073448-a737184be635 h1:lNVDKPv040qm4EGN26vet3feeSyvfDmTS51ZUWJnjdI=
github.com/NeKiro-project/NeKiro v0.0.0-20260810073448-a737184be635/go.mod h1:JCIEeiLu52WC/Q5QlcAKmWKRtW7CNLkZ3lV3BAn92Oo=
github.com/NeKiro-project/NeKiro v0.0.0-20260810110658-8c385babc9da h1:jZSoKwcJe8m7dHg5OlJ06R4zf6Rm+OeYWuF2DHpZ5Yc=
github.com/NeKiro-project/NeKiro v0.0.0-20260810110658-8c385babc9da/go.mod h1:JCIEeiLu52WC/Q5QlcAKmWKRtW7CNLkZ3lV3BAn92Oo=
github.com/a2aproject/a2a-go v0.3.15 h1:h5YpCiPq3jxQ5rIns7oDjPag3ivP8u817AzdA4F+NiI=
github.com/a2aproject/a2a-go v0.3.15/go.mod h1:I7Cm+a1oL+UT6zMoP+roaRE5vdfUa1iQGVN8aSOuZ0I=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
Expand Down
5 changes: 5 additions & 0 deletions scripts/write-ci-env.sh
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ fi

write_common() {
config_root="$stack_root/.runtime-config/$compose_project"
tls_root="$stack_root/.runtime-tls/$compose_project"
mkdir -p "$config_root"
mkdir -p "$tls_root"
printf '%s\n' '{"schemaVersion":"1","revision":"stack-bootstrap-1","targets":[]}' >"$config_root/cfg-v1-cm91dGVyL2luc3RhbmNlLWRpcmVjdG9yeQ.value"
cat >>"$output" <<'EOF'
POSTGRES_PORT=55432
Expand Down Expand Up @@ -56,8 +58,11 @@ NEKIRO_ROUTER_NACOS_REQUEST_TIMEOUT_MS=3000
NEKIRO_ROUTER_NACOS_GRPC_REQUEST_TIMEOUT_MS=3000
NEKIRO_ROUTER_NACOS_PENDING_CHANGES=64
NEKIRO_ROUTER_NACOS_MAX_OBSERVATIONS=1024
NEKIRO_E2E_NACOS_TLS_PORT=19443
NEKIRO_E2E_NACOS_MTLS_PORT=19444
EOF
printf 'NEKIRO_ROUTER_CONFIG_CENTER_ROOT=%s\n' "$config_root" >>"$output"
printf 'NEKIRO_E2E_TLS_ROOT=%s\n' "$tls_root" >>"$output"
printf 'NEKIRO_E2E_COMPOSE_FILE=%s/compose.yaml\n' "$stack_root" >>"$output"
printf 'NEKIRO_E2E_COMPOSE_PROJECT=%s\n' "$compose_project" >>"$output"
}
Expand Down
9 changes: 9 additions & 0 deletions tests/backend/invoke_record_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ type acceptanceEnv struct {
publicAgentIDs map[string]string
credentialForbidden []string
forbidden []string
tlsRoot string
tlsPort string
mtlsPort string
secureNacos *secureNacosFixture
}

func (env *acceptanceEnv) forbid(values ...string) {
Expand Down Expand Up @@ -86,6 +90,7 @@ type httpResult struct {

func TestInvokeToRecordAcceptance(t *testing.T) {
env := loadAcceptanceEnv(t)
startSecureNacosFixture(t, &env)
env.credentialForbidden = []string{
"acceptance-owner-token", "acceptance-user-token", "acceptance-other-token",
"router-internal-token", "control-plane-internal-token", "runtime-a-router-token",
Expand Down Expand Up @@ -278,6 +283,9 @@ func loadAcceptanceEnv(t *testing.T) acceptanceEnv {
userToken: requiredEnv(t, "NEKIRO_E2E_USER_TOKEN"),
otherToken: requiredEnv(t, "NEKIRO_E2E_OTHER_TOKEN"),
databaseURL: requiredEnv(t, "NEKIRO_E2E_DATABASE_URL"),
tlsRoot: requiredEnv(t, "NEKIRO_E2E_TLS_ROOT"),
tlsPort: requiredEnv(t, "NEKIRO_E2E_NACOS_TLS_PORT"),
mtlsPort: requiredEnv(t, "NEKIRO_E2E_NACOS_MTLS_PORT"),
composeFile: composeFile,
composeProject: requiredEnv(t, "NEKIRO_E2E_COMPOSE_PROJECT"),
challengeTTL: time.Duration(ttlSeconds) * time.Second,
Expand Down Expand Up @@ -312,6 +320,7 @@ func assertNacosRegistrations(t *testing.T, client *http.Client, env acceptanceE

func startRegisteredRuntimes(t *testing.T, env acceptanceEnv) {
t.Helper()
assertSecureRegistrationFailureMatrix(t, env)
command := composeCommand(
t.Context(), env,
"--profile", "runtime-registration", "up", "--detach", "--no-deps", "--force-recreate",
Expand Down
Loading
Loading