Skip to content

Commit ce298d0

Browse files
fix: make config files & evm/tron chain load optional
Fixes issue where users needed dummy config files with deployer keys to analyze MCMS proposals locally. Context: https://chainlink-core.slack.com/archives/C08QF1BEW4T/p1761128244593229 Changes: - Config files now optional, falls back to environment variables - EVM and Tron chains only load when credentials provided (key or KMS) - Added tests for optional config and credential scenarios Users can now analyze proposals without credentials by using: environment.WithoutJD() + environment.OnlyLoadChainsFor([]uint64{}) No breaking changes.
1 parent 2cc6462 commit ce298d0

File tree

5 files changed

+132
-8
lines changed

5 files changed

+132
-8
lines changed

.changeset/some-plants-doubt.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"chainlink-deployments-framework": patch
3+
---
4+
5+
fix: make config files and chain credentials optional

engine/cld/chains/chains.go

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -167,10 +167,20 @@ func LoadChains(
167167
func newChainLoaders(
168168
lggr logger.Logger, networks *cfgnet.Config, cfg cfgenv.OnchainConfig,
169169
) map[string]ChainLoader {
170-
// EVM chains are always loaded.
171-
loaders := map[string]ChainLoader{
172-
chainsel.FamilyEVM: newChainLoaderEVM(networks, cfg, lggr),
173-
chainsel.FamilyTron: newChainLoaderTron(networks, cfg),
170+
loaders := map[string]ChainLoader{}
171+
172+
// EVM chains are loaded if either KMS or deployer key is configured.
173+
if useKMS(cfg.KMS) || cfg.EVM.DeployerKey != "" {
174+
loaders[chainsel.FamilyEVM] = newChainLoaderEVM(networks, cfg, lggr)
175+
} else {
176+
lggr.Warn("Skipping EVM chains, no private key or KMS config found in secrets")
177+
}
178+
179+
// Tron chains are loaded if either KMS or deployer key is configured.
180+
if useKMS(cfg.KMS) || cfg.Tron.DeployerKey != "" {
181+
loaders[chainsel.FamilyTron] = newChainLoaderTron(networks, cfg)
182+
} else {
183+
lggr.Warn("Skipping Tron chains, no private key or KMS config found in secrets")
174184
}
175185

176186
if cfg.Solana.ProgramsDirPath != "" && cfg.Solana.WalletKey != "" {

engine/cld/chains/chains_test.go

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,114 @@ import (
2020
cfgnet "github.com/smartcontractkit/chainlink-deployments-framework/engine/cld/config/network"
2121
)
2222

23+
func Test_newChainLoaders(t *testing.T) {
24+
t.Parallel()
25+
26+
lggr := logger.Test(t)
27+
networks := &cfgnet.Config{}
28+
29+
tests := []struct {
30+
name string
31+
onchainConfig cfgenv.OnchainConfig
32+
wantLoaders []string // Expected chain families with loaders
33+
}{
34+
{
35+
name: "All credentials provided",
36+
onchainConfig: cfgenv.OnchainConfig{
37+
EVM: cfgenv.EVMConfig{
38+
DeployerKey: "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
39+
},
40+
Tron: cfgenv.TronConfig{
41+
DeployerKey: "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
42+
},
43+
Solana: cfgenv.SolanaConfig{
44+
WalletKey: "test-key",
45+
ProgramsDirPath: "/tmp/programs",
46+
},
47+
Aptos: cfgenv.AptosConfig{
48+
DeployerKey: "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
49+
},
50+
Sui: cfgenv.SuiConfig{
51+
DeployerKey: "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
52+
},
53+
Ton: cfgenv.TonConfig{
54+
DeployerKey: "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
55+
},
56+
},
57+
wantLoaders: []string{
58+
chainsel.FamilyEVM,
59+
chainsel.FamilyTron,
60+
chainsel.FamilySolana,
61+
chainsel.FamilyAptos,
62+
chainsel.FamilySui,
63+
chainsel.FamilyTon,
64+
},
65+
},
66+
{
67+
name: "No EVM credentials - EVM skipped",
68+
onchainConfig: cfgenv.OnchainConfig{
69+
Tron: cfgenv.TronConfig{
70+
DeployerKey: "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
71+
},
72+
},
73+
wantLoaders: []string{
74+
chainsel.FamilyTron,
75+
},
76+
},
77+
{
78+
name: "KMS configured - EVM and Tron loaded",
79+
onchainConfig: cfgenv.OnchainConfig{
80+
KMS: cfgenv.KMSConfig{
81+
KeyID: "test-key-id",
82+
KeyRegion: "us-west-2",
83+
},
84+
},
85+
wantLoaders: []string{
86+
chainsel.FamilyEVM,
87+
chainsel.FamilyTron,
88+
},
89+
},
90+
{
91+
name: "No credentials - all chains skipped",
92+
onchainConfig: cfgenv.OnchainConfig{},
93+
wantLoaders: []string{},
94+
},
95+
{
96+
name: "Only EVM deployer key",
97+
onchainConfig: cfgenv.OnchainConfig{
98+
EVM: cfgenv.EVMConfig{
99+
DeployerKey: "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
100+
},
101+
},
102+
wantLoaders: []string{
103+
chainsel.FamilyEVM,
104+
},
105+
},
106+
}
107+
108+
for _, tt := range tests {
109+
t.Run(tt.name, func(t *testing.T) {
110+
t.Parallel()
111+
112+
loaders := newChainLoaders(lggr, networks, tt.onchainConfig)
113+
114+
// Check that we got the expected number of loaders
115+
assert.Len(t, loaders, len(tt.wantLoaders),
116+
"Expected %d loaders but got %d", len(tt.wantLoaders), len(loaders))
117+
118+
// Check that each expected family has a loader
119+
for _, family := range tt.wantLoaders {
120+
assert.Contains(t, loaders, family, "Expected loader for family %s", family)
121+
}
122+
123+
// Check that we don't have unexpected loaders
124+
for family := range loaders {
125+
assert.Contains(t, tt.wantLoaders, family, "Unexpected loader for family %s", family)
126+
}
127+
})
128+
}
129+
}
130+
23131
func Test_LoadChains(t *testing.T) {
24132
t.Parallel()
25133

engine/cld/config/config_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,14 @@ func Test_Load(t *testing.T) {
3737
wantErr: "failed to load networks",
3838
},
3939
{
40-
name: "fails to load env config",
40+
name: "loads config without local config file (falls back to env vars)",
4141
beforeFunc: func(t *testing.T, dom fdomain.Domain, envKey string) {
4242
t.Helper()
4343

4444
writeConfigNetworksFile(t, dom, "networks.yaml", "networks-testnet.yaml")
4545
writeConfigDomainFile(t, dom, "domain.yaml")
46+
// Note: not creating a local config file - it should fall back to env vars
4647
},
47-
wantErr: "failed to load env config",
4848
},
4949
}
5050

engine/cld/config/env.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ import (
1212
//
1313
// Loading strategy:
1414
// - In CI environments: Loads configuration exclusively from environment variables set by the CI pipeline.
15-
// - In local development: Loads configuration from a local config file specific to the domain and environment.
15+
// - In local development: Loads configuration from a local config file if it exists, otherwise falls back
16+
// to environment variables. Environment variables can override file values when both are present.
1617
func LoadEnvConfig(dom fdomain.Domain, env string) (*cfgenv.Config, error) {
1718
if isCI() {
1819
cfg, err := cfgenv.LoadEnv()
@@ -25,5 +26,5 @@ func LoadEnvConfig(dom fdomain.Domain, env string) (*cfgenv.Config, error) {
2526

2627
fp := filepath.Join(dom.ConfigLocalFilePath(env))
2728

28-
return cfgenv.LoadFile(fp)
29+
return cfgenv.Load(fp)
2930
}

0 commit comments

Comments
 (0)