Skip to content

feat: deliver enclave credential with IRSA#1013

Merged
tomatoishealthy merged 7 commits into
mainfrom
feat/enclave-credential-refactor
Jul 3, 2026
Merged

feat: deliver enclave credential with IRSA#1013
tomatoishealthy merged 7 commits into
mainfrom
feat/enclave-credential-refactor

Conversation

@tomatoishealthy

@tomatoishealthy tomatoishealthy commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

  • New Features
    • Added startup support for securely loading temporary AWS credentials into the enclave when IRSA is configured.
    • Added one-shot enclave protocol support for credential delivery with explicit acknowledgement.
  • Bug Fixes
    • Improved credential handoff reliability with exchange timeouts, response size limits, and OK status checks.
    • If the enclave reports the key is not initialized, the signer now re-injects credentials between retries so signing can continue without a full restart.
    • Startup now fails fast when configured credentials can’t be delivered.
  • Chores
    • Updated the bundled Ethereum (go-ethereum) dependency version.

@tomatoishealthy tomatoishealthy requested a review from a team as a code owner July 1, 2026 12:32
@tomatoishealthy tomatoishealthy requested review from SecurityLife and removed request for a team July 1, 2026 12:32
@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 905e5f98-8840-4f42-aa07-d670d51b5a21

📥 Commits

Reviewing files that changed from the base of the PR and between 76f2bb3 and 371409f.

⛔ Files ignored due to path filters (9)
  • bindings/go.sum is excluded by !**/*.sum
  • common/go.sum is excluded by !**/*.sum
  • contracts/go.sum is excluded by !**/*.sum
  • go.work.sum is excluded by !**/*.sum
  • node/go.sum is excluded by !**/*.sum
  • ops/l2-genesis/go.sum is excluded by !**/*.sum
  • ops/tools/go.sum is excluded by !**/*.sum
  • token-price-oracle/go.sum is excluded by !**/*.sum
  • tx-submitter/go.sum is excluded by !**/*.sum
📒 Files selected for processing (10)
  • Makefile
  • bindings/go.mod
  • common/go.mod
  • contracts/go.mod
  • node/go.mod
  • node/l1sequencer/enclave_signer.go
  • ops/l2-genesis/go.mod
  • ops/tools/go.mod
  • token-price-oracle/go.mod
  • tx-submitter/go.mod
💤 Files with no reviewable changes (1)
  • node/l1sequencer/enclave_signer.go
✅ Files skipped from review due to trivial changes (1)
  • ops/l2-genesis/go.mod

📝 Walkthrough

Walkthrough

Adds AWS/IRSA credential injection for the enclave signer, including startup initialization, STS credential exchange, wire encoding, and retrying injection when the enclave reports an uninitialized key.

Changes

Enclave Credential Injection

Layer / File(s) Summary
Protocol constants and startup wiring
node/l1sequencer/enclave_signer.go
Adds opProvideCredentials and credLoadTimeout, and calls injectCredentials() during signer startup before probing, failing initialization on error.
Credential injection entry point
node/l1sequencer/enclave_creds.go
Adds injectCredentials() to conditionally resolve IRSA credentials, connect to the enclave, and send them with startup-time error handling.
IRSA resolution and STS exchange
node/l1sequencer/enclave_creds.go
Adds irsaCreds() and assumeRoleWithWebIdentity() to load the projected OIDC token, call STS, validate the returned fields, and parse optional expiration.
Wire message serialization
node/l1sequencer/enclave_creds.go
Adds writeProvideCredentials(), protocol length caps, and appendLPString() to serialize the credential payload and await OK acknowledgment.
Status parsing and retry
node/l1sequencer/enclave_signer.go
Returns typed enclave errors, detects KeyNotInitialized with errors.As, and reinjects credentials before retrying signing.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

  • morph-l2/morph#748: Both PRs update github.com/morph-l2/go-ethereum version pins and related build/version constants.
  • morph-l2/morph#756: Both PRs touch Makefile Ethereum version pins and node/go.mod dependency updates.
  • morph-l2/morph#839: Both PRs bump github.com/morph-l2/go-ethereum pins across the build and module files.

Suggested reviewers: SecurityLife, FletcherMan

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: delivering enclave credentials via IRSA.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/enclave-credential-refactor

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@node/l1sequencer/enclave_creds.go`:
- Around line 114-117: The STS failure path in enclave_creds.go currently
returns the full response body from resp.Body, which can leak sensitive token
data when injectCredentials() logs the error. Update the error handling in the
STS response check to return a bounded/redacted message instead of
strings.TrimSpace(string(raw)), keeping the status code but sanitizing or
omitting the external body content. Use the existing sts fetch/error-return
logic in the credential-loading flow to locate the fix.
- Around line 132-143: The STS credential parsing in awsCreds creation only
checks AccessKeyID and SecretAccessKey, so update the enclave_creds.go flow to
also validate SessionToken and Expiration before returning usable temporary
credentials. In the logic around parsed.Result.Credentials and awsCreds{}, treat
empty sessionToken or missing/invalid c.Expiration as an error, and keep the
existing time.Parse validation path in the same Get/parse credentials handling
so AssumeRoleWithWebIdentity never returns ambiguous creds.
- Around line 70-72: The IRSA environment check currently treats a partially
configured setup as if credentials are simply absent. Update the
`roleARN`/`tokenFile` guard in the enclave credentials path so that
`AWS_ROLE_ARN` or `AWS_WEB_IDENTITY_TOKEN_FILE` being set alone is considered a
misconfiguration, not a silent skip. In the `awsCreds` handling logic, return an
explicit error for partial IRSA env instead of `awsCreds{}, false, nil`, while
keeping the existing no-op path only when both values are empty.
- Around line 154-173: Guard the LP-string encoding in appendLPString used by
writeProvideCredentials so oversized credential fields cannot be silently
narrowed to uint16 and wrapped into a malformed frame. Update appendLPString (or
its callers in writeProvideCredentials) to check len(s) before encoding, return
an error when a field exceeds uint16 max, and propagate that error back from
writeProvideCredentials instead of building the buffer with invalid lengths.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e615bf1a-18e1-4fb4-a0e1-3920e3ed7d1a

📥 Commits

Reviewing files that changed from the base of the PR and between 4654bd3 and 6eaa2a8.

📒 Files selected for processing (2)
  • node/l1sequencer/enclave_creds.go
  • node/l1sequencer/enclave_signer.go

Comment on lines +70 to +72
if roleARN == "" || tokenFile == "" {
return awsCreds{}, false, nil
}

@coderabbitai coderabbitai Bot Jul 1, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Treat partial IRSA env as misconfiguration.

Line 70 skips injection when either AWS_ROLE_ARN or AWS_WEB_IDENTITY_TOKEN_FILE is missing, which hides broken IRSA setup until a later enclave probe fails with less context.

Proposed fix
-	if roleARN == "" || tokenFile == "" {
+	if roleARN == "" && tokenFile == "" {
 		return awsCreds{}, false, nil
 	}
+	if roleARN == "" || tokenFile == "" {
+		return awsCreds{}, true, fmt.Errorf("incomplete IRSA env: AWS_ROLE_ARN and AWS_WEB_IDENTITY_TOKEN_FILE are both required")
+	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if roleARN == "" || tokenFile == "" {
return awsCreds{}, false, nil
}
if roleARN == "" && tokenFile == "" {
return awsCreds{}, false, nil
}
if roleARN == "" || tokenFile == "" {
return awsCreds{}, true, fmt.Errorf("incomplete IRSA env: AWS_ROLE_ARN and AWS_WEB_IDENTITY_TOKEN_FILE are both required")
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@node/l1sequencer/enclave_creds.go` around lines 70 - 72, The IRSA environment
check currently treats a partially configured setup as if credentials are simply
absent. Update the `roleARN`/`tokenFile` guard in the enclave credentials path
so that `AWS_ROLE_ARN` or `AWS_WEB_IDENTITY_TOKEN_FILE` being set alone is
considered a misconfiguration, not a silent skip. In the `awsCreds` handling
logic, return an explicit error for partial IRSA env instead of `awsCreds{},
false, nil`, while keeping the existing no-op path only when both values are
empty.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Ignore, should check with logs

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@tomatoishealthy, understood — makes sense to confirm actual behavior via logs before deciding whether to enforce a hard error for partial IRSA env. Let me know if you'd like to revisit this afterward.

(=^・ω・^=)

Comment thread node/l1sequencer/enclave_creds.go
Comment thread node/l1sequencer/enclave_creds.go
Comment thread node/l1sequencer/enclave_creds.go
allen.wu and others added 2 commits July 1, 2026 20:44
Validate accessKeyID/secretAccessKey/sessionToken lengths against the
protocol caps in writeProvideCredentials before encoding, so an oversized
field is rejected instead of wrapping the u16 length prefix into a
malformed frame. Also require SessionToken in the
AssumeRoleWithWebIdentity response. Caps mirror crates/protocol and
ops-cli in morph-enclave-signer.

Co-authored-by: Cursor <cursoragent@cursor.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@node/l1sequencer/enclave_signer.go`:
- Around line 163-166: In enclave_signer.go, the error path in the sign/retry
flow is still returning the original sign failure even when
s.injectCredentials() fails, so the caller never sees the real recovery error.
Update the logic around isKeyNotInitialized(err) in the signer method to
preserve the injection failure as the returned cause, and make sure the final
wrapped/returned error uses ierr when injectCredentials() fails instead of the
prior sign error.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5e9a32f4-e95c-4b18-9242-39e58459b3ad

📥 Commits

Reviewing files that changed from the base of the PR and between 0addacb and 76f2bb3.

📒 Files selected for processing (1)
  • node/l1sequencer/enclave_signer.go

Comment on lines +163 to +166
if isKeyNotInitialized(err) {
if ierr := s.injectCredentials(); ierr != nil {
s.logger.Error("re-inject credentials after key-not-loaded failed", "err", ierr)
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Preserve failed re-injection as the returned cause.

When injectCredentials() fails, the final error still wraps the prior sign error, hiding the actual recovery failure from the caller.

Suggested fix
 		if isKeyNotInitialized(err) {
 			if ierr := s.injectCredentials(); ierr != nil {
+				lastErr = fmt.Errorf("re-inject credentials after key-not-loaded: %w", ierr)
 				s.logger.Error("re-inject credentials after key-not-loaded failed", "err", ierr)
 			}
 		}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if isKeyNotInitialized(err) {
if ierr := s.injectCredentials(); ierr != nil {
s.logger.Error("re-inject credentials after key-not-loaded failed", "err", ierr)
}
if isKeyNotInitialized(err) {
if ierr := s.injectCredentials(); ierr != nil {
lastErr = fmt.Errorf("re-inject credentials after key-not-loaded: %w", ierr)
s.logger.Error("re-inject credentials after key-not-loaded failed", "err", ierr)
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@node/l1sequencer/enclave_signer.go` around lines 163 - 166, In
enclave_signer.go, the error path in the sign/retry flow is still returning the
original sign failure even when s.injectCredentials() fails, so the caller never
sees the real recovery error. Update the logic around isKeyNotInitialized(err)
in the signer method to preserve the injection failure as the returned cause,
and make sure the final wrapped/returned error uses ierr when
injectCredentials() fails instead of the prior sign error.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Makefile`:
- Line 252: The SUBMITTERS extraction in the Makefile is using a grep pattern
that wrongly requires a non-colon character after the submitter number, so
tx-submitter-<n>: entries are missed and the helper targets end up empty. Update
the pattern used in the SUBMITTERS assignment so it matches the compose service
names directly without depending on a trailing non-colon character, and keep the
logic consistent with the existing sort/uniq pipeline.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 905e5f98-8840-4f42-aa07-d670d51b5a21

📥 Commits

Reviewing files that changed from the base of the PR and between 76f2bb3 and 371409f.

⛔ Files ignored due to path filters (9)
  • bindings/go.sum is excluded by !**/*.sum
  • common/go.sum is excluded by !**/*.sum
  • contracts/go.sum is excluded by !**/*.sum
  • go.work.sum is excluded by !**/*.sum
  • node/go.sum is excluded by !**/*.sum
  • ops/l2-genesis/go.sum is excluded by !**/*.sum
  • ops/tools/go.sum is excluded by !**/*.sum
  • token-price-oracle/go.sum is excluded by !**/*.sum
  • tx-submitter/go.sum is excluded by !**/*.sum
📒 Files selected for processing (10)
  • Makefile
  • bindings/go.mod
  • common/go.mod
  • contracts/go.mod
  • node/go.mod
  • node/l1sequencer/enclave_signer.go
  • ops/l2-genesis/go.mod
  • ops/tools/go.mod
  • token-price-oracle/go.mod
  • tx-submitter/go.mod
💤 Files with no reviewable changes (1)
  • node/l1sequencer/enclave_signer.go
✅ Files skipped from review due to trivial changes (1)
  • ops/l2-genesis/go.mod

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Makefile`:
- Line 252: The SUBMITTERS extraction in the Makefile is using a grep pattern
that wrongly requires a non-colon character after the submitter number, so
tx-submitter-<n>: entries are missed and the helper targets end up empty. Update
the pattern used in the SUBMITTERS assignment so it matches the compose service
names directly without depending on a trailing non-colon character, and keep the
logic consistent with the existing sort/uniq pipeline.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 905e5f98-8840-4f42-aa07-d670d51b5a21

📥 Commits

Reviewing files that changed from the base of the PR and between 76f2bb3 and 371409f.

⛔ Files ignored due to path filters (9)
  • bindings/go.sum is excluded by !**/*.sum
  • common/go.sum is excluded by !**/*.sum
  • contracts/go.sum is excluded by !**/*.sum
  • go.work.sum is excluded by !**/*.sum
  • node/go.sum is excluded by !**/*.sum
  • ops/l2-genesis/go.sum is excluded by !**/*.sum
  • ops/tools/go.sum is excluded by !**/*.sum
  • token-price-oracle/go.sum is excluded by !**/*.sum
  • tx-submitter/go.sum is excluded by !**/*.sum
📒 Files selected for processing (10)
  • Makefile
  • bindings/go.mod
  • common/go.mod
  • contracts/go.mod
  • node/go.mod
  • node/l1sequencer/enclave_signer.go
  • ops/l2-genesis/go.mod
  • ops/tools/go.mod
  • token-price-oracle/go.mod
  • tx-submitter/go.mod
💤 Files with no reviewable changes (1)
  • node/l1sequencer/enclave_signer.go
✅ Files skipped from review due to trivial changes (1)
  • ops/l2-genesis/go.mod
🛑 Comments failed to post (1)
Makefile (1)

252-252: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Fix the SUBMITTERS extraction pattern.

[^:] requires a non-colon character after the digits, so tx-submitter-<n>: entries in the compose file will not match and these helper targets will get an empty list.

Proposed fix
-SUBMITTERS := $(shell grep -o 'tx-submitter-[0-9]*[^:]' ops/docker/docker-compose-devnet.yml | sort | uniq)
+SUBMITTERS := $(shell grep -oE 'tx-submitter-[0-9]+' ops/docker/docker-compose-devnet.yml | sort -u)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

SUBMITTERS := $(shell grep -oE 'tx-submitter-[0-9]+' ops/docker/docker-compose-devnet.yml | sort -u)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Makefile` at line 252, The SUBMITTERS extraction in the Makefile is using a
grep pattern that wrongly requires a non-colon character after the submitter
number, so tx-submitter-<n>: entries are missed and the helper targets end up
empty. Update the pattern used in the SUBMITTERS assignment so it matches the
compose service names directly without depending on a trailing non-colon
character, and keep the logic consistent with the existing sort/uniq pipeline.

@tomatoishealthy tomatoishealthy merged commit 92cbecf into main Jul 3, 2026
15 checks passed
@tomatoishealthy tomatoishealthy deleted the feat/enclave-credential-refactor branch July 3, 2026 07:02
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.

3 participants