Skip to content

[CRE] Wire confidential relay handler#21375

Open
nadahalli wants to merge 7 commits intodevelopfrom
tejaswi/confidential-relay-wiring
Open

[CRE] Wire confidential relay handler#21375
nadahalli wants to merge 7 commits intodevelopfrom
tejaswi/confidential-relay-wiring

Conversation

@nadahalli
Copy link
Contributor

@nadahalli nadahalli commented Mar 3, 2026

Confidential CRE Workflows (implementation plan | relay DON design)

Summary

Wire the confidential-compute relay handler (confidential-compute#265) into chainlink as a CRE subservice. The relay handler validates Nitro attestation and dispatches confidential.secrets.get / confidential.capability.execute messages from the enclave to VaultDON and capability DONs via the gateway connector.

The handler code lives in confidential-compute/capabilities/relay as a standalone Go module. This PR imports it and wires it into the node's lifecycle.

Changes

  • core/capabilities/confidentialrelay/service.go (new): Thin lifecycle wrapper around the relay handler. The relay handler needs the gateway connector at construction time, but the connector isn't available until ServiceWrapper.Start(). This wrapper defers handler creation to its own Start(), bridging the gap.
  • core/services/cre/cre.go: Instantiate the relay service inside the gateway connector block, gated by CL_CONFIDENTIAL_RELAY_TRUSTED_PCRS env var.
  • go.mod: Bump chainlink-common to 3e3f9545d607 (adds confidentialrelay types), add confidential-compute/capabilities/relay and transitive dep confidential-compute/attestation.

Config: env var for now

Trusted PCR measurements are passed via CL_CONFIDENTIAL_RELAY_TRUSTED_PCRS as a JSON string:

{"pcr0":"<hex>","pcr1":"<hex>","pcr2":"<hex>"}

When unset, no relay service is started (zero impact on nodes that don't use confidential workflows). Proper TOML config (Capabilities.ConfidentialRelay section) can be added in a follow-up; PCR values change rarely (only when the enclave binary is rebuilt), so an env var is sufficient for now and avoids config interface boilerplate.

Dependency chain

chainlink-common (3e3f9545d607, confidentialrelay types)
  ^
  |
confidential-compute/capabilities/relay (bb7be43)
  |
  v
confidential-compute/attestation (bb7be43)

Related PRs

Instantiate the confidential-compute relay handler as a CRE subservice.
The handler validates Nitro attestation and dispatches secrets.get /
capability.execute messages to VaultDON and capability DONs via the
gateway connector.

Gated by CL_CONFIDENTIAL_RELAY_TRUSTED_PCRS env var (JSON with PCR0-2
hex values). When unset, no relay service is started.
Copilot AI review requested due to automatic review settings March 3, 2026 15:50
@nadahalli nadahalli requested review from a team as code owners March 3, 2026 15:50
@github-actions
Copy link
Contributor

github-actions bot commented Mar 3, 2026

👋 nadahalli, thanks for creating this pull request!

To help reviewers, please consider creating future PRs as drafts first. This allows you to self-review and make any final changes before notifying the team.

Once you're ready, you can mark it as "Ready for review" to request feedback. Thanks!

@github-actions
Copy link
Contributor

github-actions bot commented Mar 3, 2026

✅ No conflicts with other open PRs targeting develop

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Wires the confidential-compute relay handler into the CRE service graph as an optional subservice, gated by CL_CONFIDENTIAL_RELAY_TRUSTED_PCRS, and updates dependencies to pull in required relay/confidentialrelay types.

Changes:

  • Add a new core/capabilities/confidentialrelay lifecycle wrapper that defers handler construction to Start().
  • Wire the confidential relay service into core/services/cre when CL_CONFIDENTIAL_RELAY_TRUSTED_PCRS is set.
  • Bump chainlink-common and add confidential-compute relay/attestation dependencies.

Reviewed changes

Copilot reviewed 3 out of 4 changed files in this pull request and generated 4 comments.

File Description
go.mod Adds confidential-compute relay dependency and bumps chainlink-common.
go.sum Updates module sums for new/bumped dependencies.
core/services/cre/cre.go Conditionally registers the confidential relay service behind an env var gate.
core/capabilities/confidentialrelay/service.go Introduces a thin service wrapper around the confidential relay handler lifecycle.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +175 to +183
if trustedPCRs := os.Getenv("CL_CONFIDENTIAL_RELAY_TRUSTED_PCRS"); trustedPCRs != "" {
relayService := confidentialrelay.NewService(
gatewayConnectorWrapper,
opts.CapabilitiesRegistry,
[]byte(trustedPCRs),
lggr,
)
srvs = append(srvs, relayService)
}
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The relay service is conditionally enabled via CL_CONFIDENTIAL_RELAY_TRUSTED_PCRS, but there’s no log signal when it is enabled/disabled. This makes it hard to diagnose why the relay handler isn’t running (especially since other conditional subservices here log when they are skipped/created). Consider adding a Debug/Info log when the env var is set (service enabled) and when it’s unset (service disabled).

Copilot uses AI. Check for mistakes.
lggr,
)
srvs = append(srvs, relayService)
}
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If CL_CONFIDENTIAL_RELAY_TRUSTED_PCRS is set but capCfg.GatewayConnector().DonID() is empty, the relay will silently not start because the gateway connector wrapper isn’t created. Consider logging a warning in that case (env var set but gateway connector not configured), since it’s a misconfiguration that’s otherwise non-obvious.

Suggested change
}
}
} else {
if trustedPCRs := os.Getenv("CL_CONFIDENTIAL_RELAY_TRUSTED_PCRS"); trustedPCRs != "" {
lggr.Warn("CL_CONFIDENTIAL_RELAY_TRUSTED_PCRS is set but GatewayConnector DonID is empty; confidential relay will not start")
}

Copilot uses AI. Check for mistakes.
Comment on lines +56 to +61
h, err := relay.NewHandler(s.capRegistry, conn, s.trustedPCRs, s.lggr)
if err != nil {
return err
}
s.handler = h
return h.Start(ctx)
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

start returns raw errors from relay.NewHandler/h.Start without adding context. To make startup failures actionable in logs, wrap these errors with service-specific context (e.g., include that this is the confidential relay handler startup and whether it was due to handler construction vs start).

Copilot uses AI. Check for mistakes.
Comment on lines +51 to +69
func (s *Service) start(ctx context.Context) error {
conn := s.wrapper.GetGatewayConnector()
if conn == nil {
return errors.New("gateway connector not available")
}
h, err := relay.NewHandler(s.capRegistry, conn, s.trustedPCRs, s.lggr)
if err != nil {
return err
}
s.handler = h
return h.Start(ctx)
}

func (s *Service) close() error {
if s.handler != nil {
return s.handler.Close()
}
return nil
}
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are no unit tests covering the new lifecycle wrapper behavior (e.g., that it errors when the gateway connector isn’t available, and that it closes the underlying handler when started). Since the repo has extensive Go service tests elsewhere, consider adding a small test for Service.start/close using a fake ServiceWrapper/connector to prevent regressions.

Copilot uses AI. Check for mistakes.
@cl-sonarqube-production
Copy link

Quality Gate failed Quality Gate failed

Failed conditions
C Reliability Rating on New Code (required ≥ A)

See analysis details on SonarQube

Catch issues before they fail your Quality Gate with our IDE extension SonarQube IDE SonarQube IDE

Gateway-side handler that receives JSON-RPC requests from the enclave,
fans them out to relay DON nodes, and aggregates 2F+1 quorum responses.
Follows the vault handler pattern but simplified: no authorization, no
caching, no OCR3 signatures, no owner-prefixed request IDs.
Add gateway handler type, capability flag, and Feature implementation
so the CRE test framework can spin up a relay DON for remote-mode E2E
tests.
Pass CL_CONFIDENTIAL_RELAY_CA_ROOTS_PEM env var to relay handler
for custom attestation certificate validation. Update go.mod to
use remote confidential-compute module commits.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants