Skip to content

chore: update passphrase to file rather than string in cli#146

Merged
chatton merged 2 commits into
mainfrom
cian/fix-evnode-flags
Oct 24, 2025
Merged

chore: update passphrase to file rather than string in cli#146
chatton merged 2 commits into
mainfrom
cian/fix-evnode-flags

Conversation

@chatton
Copy link
Copy Markdown
Collaborator

@chatton chatton commented Oct 24, 2025

Overview

The test will fail in this repo until evstack/ev-node#2764 is merged, however I ran locally and have passing tests in both repos with this fix.

=== RUN   TestDockerSuite
=== RUN   TestDockerSuite/TestBasicDockerE2E
    logger.go:146: 2025-10-24T15:54:31.953+0100	INFO	Exec	{"validator": true, "i": 0, "chain_id": "test", "test": "TestDockerSuite/TestBasicDockerE2E", "image": "ghcr.io/celestiaorg/celestia-app:v5.0.2", "test_name": "TestDockerSuite/TestBasicDockerE2E", "command": "celestia-appd init test-val-0-TestDockerSuite_TestBasicDockerE2E --chain-id test --home /var/cosmos-chain/celestia", "env,": [], "hostname": "TestDockerSuite_TestBasicDockerE2E-tabzlu", "container": "TestDockerSuite_TestBasicDockerE2E-tabzlu"}
    logger.go:146: 2025-10-24T15:54:35.482+0100	INFO	Exec	{"validator": true, "i": 0, "chain_id": "test", "test": "TestDockerSuite/TestBasicDockerE2E", "image": "ghcr.io/celestiaorg/celestia-app:v5.0.2", "test_name": "TestDockerSuite/TestBasicDockerE2E", "command": "celestia-appd keys add validator --coin-type 118 --keyring-backend test --home /var/cosmos-chain/celestia", "env,": [], "hostname": "TestDockerSuite_TestBasicDockerE2E-ppybtl", "container": "TestDockerSuite_TestBasicDockerE2E-ppybtl"}
    logger.go:146: 2025-10-24T15:54:36.606+0100	INFO	Exec	{"validator": true, "i": 0, "chain_id": "test", "test": "TestDockerSuite/TestBasicDockerE2E", "image": "ghcr.io/celestiaorg/celestia-app:v5.0.2", "test_name": "TestDockerSuite/TestBasicDockerE2E", "command": "celestia-appd keys show --address validator --home /var/cosmos-chain/celestia --keyring-backend test", "env,": [], "hostname": "TestDockerSuite_TestBasicDockerE2E-vzjpsc", "container": "TestDockerSuite_TestBasicDockerE2E-vzjpsc"}
    logger.go:146: 2025-10-24T15:54:37.678+0100	INFO	Exec	{"validator": true, "i": 0, "chain_id": "test", "test": "TestDockerSuite/TestBasicDockerE2E", "image": "ghcr.io/celestiaorg/celestia-app:v5.0.2", "test_name": "TestDockerSuite/TestBasicDockerE2E", "command": "celestia-appd genesis add-genesis-account celestia1h44ny8hqn5lkyesp69e4ekaseux5exwvjaftpl 10000000000000utia --home /var/cosmos-chain/celestia", "env,": [], "hostname": "TestDockerSuite_TestBasicDockerE2E-ahxruq", "container": "TestDockerSuite_TestBasicDockerE2E-ahxruq"}
    logger.go:146: 2025-10-24T15:54:38.752+0100	INFO	Exec	{"validator": true, "i": 0, "chain_id": "test", "test": "TestDockerSuite/TestBasicDockerE2E", "image": "ghcr.io/celestiaorg/celestia-app:v5.0.2", "test_name": "TestDockerSuite/TestBasicDockerE2E", "command": "celestia-appd genesis gentx validator 5000000utia --gas-prices 0.025utia --gas-adjustment 1.3 --keyring-backend test --chain-id test --home /var/cosmos-chain/celestia", "env,": [], "hostname": "TestDockerSuite_TestBasicDockerE2E-komnhs", "container": "TestDockerSuite_TestBasicDockerE2E-komnhs"}
    logger.go:146: 2025-10-24T15:54:39.865+0100	INFO	Exec	{"validator": true, "i": 0, "chain_id": "test", "test": "TestDockerSuite/TestBasicDockerE2E", "image": "ghcr.io/celestiaorg/celestia-app:v5.0.2", "test_name": "TestDockerSuite/TestBasicDockerE2E", "command": "celestia-appd keys add faucet --coin-type 118 --keyring-backend test --home /var/cosmos-chain/celestia", "env,": [], "hostname": "TestDockerSuite_TestBasicDockerE2E-iaqlly", "container": "TestDockerSuite_TestBasicDockerE2E-iaqlly"}
    logger.go:146: 2025-10-24T15:54:41.022+0100	INFO	Exec	{"validator": true, "i": 0, "chain_id": "test", "test": "TestDockerSuite/TestBasicDockerE2E", "image": "ghcr.io/celestiaorg/celestia-app:v5.0.2", "test_name": "TestDockerSuite/TestBasicDockerE2E", "command": "celestia-appd keys show --address faucet --home /var/cosmos-chain/celestia --keyring-backend test", "env,": [], "hostname": "TestDockerSuite_TestBasicDockerE2E-xzzhrd", "container": "TestDockerSuite_TestBasicDockerE2E-xzzhrd"}
    logger.go:146: 2025-10-24T15:54:42.162+0100	INFO	Exec	{"validator": true, "i": 0, "chain_id": "test", "test": "TestDockerSuite/TestBasicDockerE2E", "image": "ghcr.io/celestiaorg/celestia-app:v5.0.2", "test_name": "TestDockerSuite/TestBasicDockerE2E", "command": "celestia-appd genesis add-genesis-account celestia12t0cprqewsfq7lv7ngprzat36np0xwz33cslhw 10000000000000utia --home /var/cosmos-chain/celestia", "env,": [], "hostname": "TestDockerSuite_TestBasicDockerE2E-ydhscq", "container": "TestDockerSuite_TestBasicDockerE2E-ydhscq"}
    logger.go:146: 2025-10-24T15:54:43.290+0100	INFO	Exec	{"validator": true, "i": 0, "chain_id": "test", "test": "TestDockerSuite/TestBasicDockerE2E", "image": "ghcr.io/celestiaorg/celestia-app:v5.0.2", "test_name": "TestDockerSuite/TestBasicDockerE2E", "command": "celestia-appd genesis collect-gentxs --home /var/cosmos-chain/celestia", "env,": [], "hostname": "TestDockerSuite_TestBasicDockerE2E-tjkhnh", "container": "TestDockerSuite_TestBasicDockerE2E-tjkhnh"}
    logger.go:146: 2025-10-24T15:54:44.692+0100	DEBUG	successfully wrote genesis file contents	{"validator": true, "i": 0, "chain_id": "test", "test": "TestDockerSuite/TestBasicDockerE2E"}
    logger.go:146: 2025-10-24T15:54:44.692+0100	INFO	Will run command	{"image": "ghcr.io/celestiaorg/celestia-app:v5.0.2", "container": "test-val-0-TestDockerSuite_TestBasicDockerE2E", "command": "celestia-appd start --home /var/cosmos-chain/celestia --force-no-bbr --grpc.enable --grpc.address 0.0.0.0:9090 --rpc.grpc_laddr=tcp://0.0.0.0:9098 --timeout-commit 1s"}
    logger.go:146: 2025-10-24T15:54:44.812+0100	INFO	Starting container	{"container": "test-val-0-TestDockerSuite_TestBasicDockerE2E", "peers": "b605dad9c8efee6f7ee5c4faea1f54acdb1486ed@test-val-0-TestDockerSuite_TestBasicDockerE2E:26656"}
    logger.go:146: 2025-10-24T15:54:47.308+0100	INFO	Container started	{"container": "test-val-0-TestDockerSuite_TestBasicDockerE2E"}
=== RUN   TestDockerSuite/TestBasicDockerE2E/start_celestia_chain
--- PASS: TestDockerSuite/TestBasicDockerE2E/start_celestia_chain (23.41s)
    logger.go:146: 2025-10-24T15:54:55.380+0100	INFO	Exec	{"node_type": "bridge", "image": "ghcr.io/celestiaorg/celestia-node:v0.25.3", "test_name": "TestDockerSuite/TestBasicDockerE2E", "command": "cel-key add my-key --node.type bridge --keyring-dir /home/celestia/keys --output json --no-backup --keyring-backend test", "env,": [], "hostname": "TestDockerSuite_TestBasicDockerE2E-hzhdtn", "container": "TestDockerSuite_TestBasicDockerE2E-hzhdtn"}
    logger.go:146: 2025-10-24T15:54:55.753+0100	INFO	Exec	{"node_type": "bridge", "image": "ghcr.io/celestiaorg/celestia-node:v0.25.3", "test_name": "TestDockerSuite/TestBasicDockerE2E", "command": "celestia bridge init --p2p.network test --keyring.keyname my-key --node.store /home/celestia --keyring.backend test", "env,": ["CELESTIA_CUSTOM=test:E1EEBCE5067121FCC1C2DF154669EF26BB6347D17D3E28086F79597D157DC531", "P2P_NETWORK=test"], "hostname": "TestDockerSuite_TestBasicDockerE2E-gsrwjz", "container": "TestDockerSuite_TestBasicDockerE2E-gsrwjz"}
    logger.go:146: 2025-10-24T15:54:56.095+0100	INFO	Exec	{"node_type": "bridge", "image": "ghcr.io/celestiaorg/celestia-node:v0.25.3", "test_name": "TestDockerSuite/TestBasicDockerE2E", "command": "celestia bridge auth admin", "env,": [], "hostname": "TestDockerSuite_TestBasicDockerE2E-rzbgje", "container": "TestDockerSuite_TestBasicDockerE2E-rzbgje"}
    logger.go:146: 2025-10-24T15:54:56.344+0100	INFO	Will run command	{"image": "ghcr.io/celestiaorg/celestia-node:v0.25.3", "container": "da-bridge-0-TestDockerSuite_TestBasicDockerE2E", "command": "celestia bridge start --node.store /home/celestia --p2p.network test --core.ip test-val-0-TestDockerSuite_TestBasicDockerE2E --rpc.addr 0.0.0.0"}
    logger.go:146: 2025-10-24T15:54:58.869+0100	INFO	Container started	{"container": "da-bridge-0-TestDockerSuite_TestBasicDockerE2E"}
=== RUN   TestDockerSuite/TestBasicDockerE2E/start_bridge_node
--- PASS: TestDockerSuite/TestBasicDockerE2E/start_bridge_node (3.55s)
    base_test.go:43: da node celestia address: celestia1msk87k7k72qsr4td3yf7ff3teumqw257katra9
    logger.go:146: 2025-10-24T15:54:59.918+0100	INFO	broadcasted message	{"wallet_address": "celestia12t0cprqewsfq7lv7ngprzat36np0xwz33cslhw", "message_types": ["MsgSend"], "tx_hash": "FA2F382537EC3B5BCE0BB60BFEC49693F61EC5D794B3640B1741F4F81860DAE3"}
=== RUN   TestDockerSuite/TestBasicDockerE2E/fund_da_wallet
--- PASS: TestDockerSuite/TestBasicDockerE2E/fund_da_wallet (4.06s)
    logger.go:146: 2025-10-24T15:55:03.232+0100	INFO	Exec	{"i": 0, "aggregator": true, "image": "evstack:local-dev", "test_name": "TestDockerSuite/TestBasicDockerE2E", "command": "testapp --home /var/evstack --chain_id evchain-test init --evnode.node.aggregator --evnode.signer.passphrase_file=/var/evstack/config/passphrase.txt --evnode.signer.signer_path=/var/evstack/config", "env,": [], "hostname": "TestDockerSuite_TestBasicDockerE2E-wvtlsv", "container": "TestDockerSuite_TestBasicDockerE2E-wvtlsv"}
    logger.go:146: 2025-10-24T15:55:03.484+0100	INFO	Will run command	{"image": "evstack:local-dev", "container": "evchain-test-evstack-0-TestDockerSuite_TestBasicDockerE2E", "command": "testapp --home /var/evstack start --evnode.node.aggregator --evnode.signer.passphrase_file=/var/evstack/config/passphrase.txt --evnode.signer.signer_path=/var/evstack/config --evnode.da.address http://da-bridge-0-TestDockerSuite_TestBasicDockerE2E:26658 --evnode.da.gas_price 0.025 --evnode.da.auth_token eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJBbGxvdyI6WyJwdWJsaWMiLCJyZWFkIiwid3JpdGUiLCJhZG1pbiJdLCJOb25jZSI6InBiWGVBY1ZlMnFrQnE2eThydW5PNzhNMHZwTzhxUktkR3Z4SWhmQ3NjZnM9IiwiRXhwaXJlc0F0IjoiMDAwMS0wMS0wMVQwMDowMDowMFoifQ.E9MsFrI5U0_kTau0qoVws2zK7-26bcSteO9flXy5ffE --evnode.rpc.address 0.0.0.0:7331 --evnode.da.namespace ev-header --evnode.da.data_namespace ev-data --kv-endpoint 0.0.0.0:8080"}
    logger.go:146: 2025-10-24T15:55:05.675+0100	INFO	Container started	{"container": "evchain-test-evstack-0-TestDockerSuite_TestBasicDockerE2E"}
    logger.go:146: 2025-10-24T15:55:12.685+0100	INFO	evstack node is ready	{"chain_id": "evchain-test", "test": "TestDockerSuite/TestBasicDockerE2E"}
=== RUN   TestDockerSuite/TestBasicDockerE2E/start_evolve_chain_node
--- PASS: TestDockerSuite/TestBasicDockerE2E/start_evolve_chain_node (9.76s)
=== RUN   TestDockerSuite/TestBasicDockerE2E/submit_a_transaction_to_the_evolve_chain
    base_test.go:59: EV node RPC port: 0.0.0.0:50007
    base_test.go:60: EV node HTTP port: 0.0.0.0:50005
    base_test.go:64: EV node HTTP address: 0.0.0.0:50005
    base_test.go:82: Extracted host: localhost, port: 50005
    base_test.go:86: Created HTTP client with base URL: http://localhost:50005
    base_test.go:90: Attempting to POST key=key1, value=value1 to /tx
--- PASS: TestDockerSuite/TestBasicDockerE2E/submit_a_transaction_to_the_evolve_chain (1.01s)
--- PASS: TestDockerSuite/TestBasicDockerE2E (42.57s)
--- PASS: TestDockerSuite (42.57s)

Summary by CodeRabbit

  • Refactor
    • Passphrase handling moved from passing raw values to writing and using a local passphrase file.
    • Initialization now writes the node passphrase to disk before starting; startup commands use a passphrase-file option.
    • Improved error handling around passphrase file creation to avoid starting with missing credentials.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Oct 24, 2025

Walkthrough

Replaces direct CLI passphrase arguments with file-based passphrases across evstack and evmsingle nodes: adds passphraseFilePath() helpers, writes configured passphrases to config/passphrase.txt before init/start, and switches flags to --*-passphrase_file in Init and container start commands.

Changes

Cohort / File(s) Summary
evstack Node changes
framework/docker/evstack/node.go
Added passphraseFilePath() helper. Write AggregatorPassphrase to config/passphrase.txt before initialization. Replaced --evnode.signer.passphrase with --evnode.signer.passphrase_file in Init() and createEvstackContainer(); return error on file write failures.
evmsingle Node changes
framework/docker/evstack/evmsingle/node.go
Added passphraseFilePath() helper (imports filepath). Write EVMSignerPassphrase to config/passphrase.txt in initContainer when set. Replaced --rollkit.signer.passphrase and --evnode.signer.passphrase with --rollkit.signer.passphrase_file and --evnode.signer.passphrase_file respectively; propagate file-write errors.

Sequence Diagram(s)

sequenceDiagram
    participant Test as Test Harness
    participant Node as Node (evstack / evmsingle)
    participant FS as Filesystem
    participant Container as evnode Container

    Note over Node,FS: Init / initContainer flow (new)
    Test->>Node: call Init/initContainer(...)
    Node->>FS: write "config/passphrase.txt" with passphrase
    alt write succeeds
      Node->>Container: start with --*.signer.passphrase_file=/path/config/passphrase.txt
      Container-->>Node: started
      Node-->>Test: success
    else write fails
      FS-->>Node: error
      Node-->>Test: return error (formatted)
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • refactor: update to new evnode flag #112: Modifies evnode CLI flag handling in the same file (framework/docker/evstack/node.go) and renames signer flag — strongly related to the passphrase->file flag changes.

Suggested labels

enhancement

Suggested reviewers

  • mojtaba-esk
  • tty47

Poem

🐰 I wrote the passphrase to a little file so neat,
No more whispered secrets on the CLI street.
I hop, I patch, I change the flag with care,
Now containers read the secret stored in there.
Tiny paws, tidy code — secure and sweet. 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The PR title "chore: update passphrase to file rather than string in cli" accurately summarizes the main change across both modified files. The changes introduce file-based passphrase handling by replacing direct passphrase parameters (--evnode.signer.passphrase and --rollkit.signer.passphrase) with file-based flags (--evnode.signer.passphrase_file and --rollkit.signer.passphrase_file), along with new helper methods to manage passphrase file paths. The title is clear, specific, and concise without unnecessary noise or vague terminology, enabling reviewers to quickly understand the primary change.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch cian/fix-evnode-flags

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b070f0b and c9d6874.

📒 Files selected for processing (1)
  • framework/docker/evstack/evmsingle/node.go (4 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
framework/docker/evstack/evmsingle/node.go (1)
framework/docker/evstack/reth/node.go (1)
  • Node (23-31)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: test
  • GitHub Check: Analyze (go)
🔇 Additional comments (4)
framework/docker/evstack/evmsingle/node.go (4)

9-9: LGTM: Import addition is appropriate.

The filepath import is correctly added to support the new passphrase file path construction.


64-67: LGTM: Helper method is clean and reusable.

The helper correctly constructs the absolute path to the passphrase file within the container.


169-169: LGTM: Consistent passphrase file usage.

The flag correctly references the passphrase file path, consistent with the approach in initContainer.


124-126: No action required; passphrase file permissions already properly set.

Verification confirms that the WriteFile method already sets restrictive permissions (0o600) for all written files at line 85 of framework/docker/file/file_writer.go. This ensures the passphrase file is readable and writable only by the owner, meeting security best practices.


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 and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between be63c71 and b070f0b.

📒 Files selected for processing (1)
  • framework/docker/evstack/node.go (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
framework/docker/evstack/node.go (2)
framework/docker/evstack/reth/node.go (1)
  • Node (23-31)
framework/docker/container/node.go (1)
  • Node (20-31)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: test
  • GitHub Check: Analyze (go)
🔇 Additional comments (3)
framework/docker/evstack/node.go (3)

96-99: LGTM! Clean abstraction for passphrase file path.

The helper method provides a consistent, cross-platform path for the passphrase file across both initialization and startup commands.


115-115: LGTM! Correct flag usage with proper sequencing.

The passphrase file flag correctly references the file path, and the preceding error handling ensures the file exists before this command executes.


159-159: <!-- [scratchpad_start]
[task review_file_1/1 review_segment_4/4]
Checking Build() and Chain.Start() to see if Init() is called

[observations]

  • Build() method calls initializeNodes() -> newNode() but NO Init() call
  • Build() only creates nodes and sets up volumes (CreateAndSetupVolume)
  • Init() is NOT called during Build()
  • Need to check Chain.Start() to see if it calls node.Init()

[analysis]

  • Build() does not initialize nodes
  • The concern is getting stronger - need to verify if Chain.Start() calls node.Init()
  • If Chain.Start() does NOT call node.Init(), then the review comment is correct

[pending]

  • Find Chain.Start() method
  • Verify if it calls node.Init() before starting nodes

[actions]
Search for Chain.Start() method in evstack package

Comment on lines +108 to +110
if err := n.WriteFile(ctx, filepath.Join("config", "passphrase.txt"), []byte(n.cfg.AggregatorPassphrase)); err != nil {
return fmt.Errorf("failed to write passphrase file: %w", err)
}
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.

⚠️ Potential issue | 🟠 Major

Set restrictive file permissions when writing the passphrase.

The passphrase file should be created with restrictive permissions (e.g., 0600) to prevent unauthorized access, even in test environments. Currently, the file is written with default permissions which may allow other users or processes to read the sensitive passphrase.

Check if the WriteFile method supports setting permissions. If it does, apply this pattern:

-	if err := n.WriteFile(ctx, filepath.Join("config", "passphrase.txt"), []byte(n.cfg.AggregatorPassphrase)); err != nil {
+	if err := n.WriteFile(ctx, filepath.Join("config", "passphrase.txt"), []byte(n.cfg.AggregatorPassphrase), 0600); err != nil {
 		return fmt.Errorf("failed to write passphrase file: %w", err)
 	}

If WriteFile doesn't support permission parameters, consider using a different method or ensuring the container's umask is set appropriately.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In framework/docker/evstack/node.go around lines 108 to 110, the passphrase file
is written with default permissions which may be world-readable; change the
write to create the file with restrictive permissions (0600). First check if
n.WriteFile accepts a file mode argument and, if so, pass os.FileMode(0o600). If
n.WriteFile does not support permissions, replace the call with a write that
allows setting mode (e.g., os.WriteFile or creating the file with os.OpenFile
and os.FileMode(0o600)), or explicitly set the file mode right after writing
using os.Chmod(ctxPath, 0o600); ensure the final file is created with permission
0600 to protect the passphrase.

@chatton chatton merged commit 2bea587 into main Oct 24, 2025
5 of 6 checks passed
@chatton chatton deleted the cian/fix-evnode-flags branch October 24, 2025 15:10
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