Skip to content

feat(migration): node key export shared between CLI and devenv - #1318

Open
tt-cll wants to merge 2 commits into
split/1-key-importfrom
split/3-migration-export
Open

feat(migration): node key export shared between CLI and devenv#1318
tt-cll wants to merge 2 commits into
split/1-key-importfrom
split/3-migration-export

Conversation

@tt-cll

@tt-cll tt-cll commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Description

Shared library for the node-facing half of the CL-to-standalone migration: exporting the OCR2 EVM bundle and funded EVM account from a running Chainlink node. Single implementation behind both ccv migrate export (next PR in the stack) and the devenv cutover (following PR), so the path an operator runs by hand and the path the e2e test exercises cannot drift apart.

  • Minimal four-endpoint REST client (login, key listings, job list, exports) — stdlib only, so the verifier/executor binaries don't link the Chainlink node dependency graph.
  • Preflight enforces the migratable shape (exactly one ccvcommitteeverifier and one ccvexecutor job); ambiguous bundles/accounts are errors with override options, not guesses.
  • Exports are taken under a generated password, decoded immediately, and the transmitter is cross-checked against the account the node registered — failures surface while the node is still up.

Testing

Unit tests against an httptest fake node that encrypts fixtures with the requested password the way the real node does: bundle/account resolution, job counting, login/cookie flow, export cross-checks, overrides, snippet generation.

Checklist

  • Breaking changes documented in changelog (see changelog directory)
  • Cross link related PRs (in this or other repositories)

Stack created with GitHub Stacks CLIGive Feedback 💬

@tt-cll
tt-cll requested a review from a team as a code owner July 31, 2026 10:52
@tt-cll tt-cll mentioned this pull request Jul 31, 2026
2 tasks
Comment thread migration/export.go
Comment on lines +124 to +136
passwordPath := filepath.Join(cfg.OutDir, PasswordFileName)
if err := os.WriteFile(passwordPath, []byte(exportPassword), 0o600); err != nil {
return nil, fmt.Errorf("failed to write the export password file: %w", err)
}

ocr2Path := filepath.Join(cfg.OutDir, OCR2ExportFileName)
if err := exportToFile(ctx, client.ExportOCR2Bundle, bundleID, exportPassword, ocr2Path); err != nil {
return nil, fmt.Errorf("failed to export the OCR2 bundle %s: %w", bundleID, err)
}
ethPath := filepath.Join(cfg.OutDir, ETHExportFileName)
if err := exportToFile(ctx, client.ExportETHKey, account, exportPassword, ethPath); err != nil {
return nil, fmt.Errorf("failed to export the EVM account %s: %w", account, err)
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

In practice, do these files end up being written to the chainlink container? My guess is the paths should point to a volume, so that the operator can get them out?

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.

It writes to a dir which we mount from the host. The runbook should specify the command to run and where the file gets written on disk

Comment thread migration/export.go Outdated
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