Skip to content

Fix dead securityLevelGRPC settings.conf key - #1674

Open
icellan wants to merge 1 commit into
bsv-blockchain:mainfrom
icellan:fix/dead-security-level-grpc-config-key
Open

Fix dead securityLevelGRPC settings.conf key#1674
icellan wants to merge 1 commit into
bsv-blockchain:mainfrom
icellan:fix/dead-security-level-grpc-config-key

Conversation

@icellan

@icellan icellan commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Problem

settings.conf shipped securityLevelGRPC = 0. Nothing reads that key. The loader
reads security_level_grpc (settings/settings.go), and the struct tag is
key:"security_level_grpc" (settings/interface.go). The committed line is dead.

It is harmless at its current value because the real default is also 0 - but an
operator who edits it to 1 expecting to enable TLS on inter-service gRPC gets
silent plaintext instead: util/grpc_helper.go GetGRPCClient() never sees the
change and keeps picking insecure.NewCredentials().

The likely cause: the sibling setting genuinely is camelCase - SecurityLevelHTTP
carries key:"securityLevelHTTP" (settings/interface.go) - so securityLevelGRPC
looked correct by analogy. securityLevelHTTP itself is untouched by this PR; the
broader camelCase/snake_case inconsistency across the settings package is a
separate, larger question and remains a follow-up.

Fix

  • settings.conf: securityLevelGRPC -> security_level_grpc, value and comments
    unchanged.
  • Same wrong spelling also appeared in operator-facing recommendation text, which
    told operators to set the dead key - corrected in cmd/diagnose/config_checks.go,
    util/admin_api_key.go, docs/howto/diagnose.md, and
    docs/references/services/rpc_reference.md.
  • Searched deploy/, kubernetes/, compose/, and every .conf/.yml/.yaml/.env
    file in the repo for other occurrences of the wrong spelling (including
    context-suffixed variants like securityLevelGRPC.docker) - found none beyond the
    ones listed above.

Regression test

Added TestSettingsConfNoShadowedKeys (settings/settings_conf_dead_key_test.go),
which fails on any settings.conf key whose case/underscore-normalized form
collides with a real key: tag while the literal key does not match it exactly -
the precise failure mode that let securityLevelGRPC through silently, since
gocore's config lookup is exact-case and exact-string.

This is deliberately narrower than a full "every settings.conf key resolves to
something real" sweep. TestSettingsConfHasNoDeadKeys (added on main separately)
already covers a related but different case - asserting that two specific,
already-removed keys stay removed - and does not attempt the full sweep either,
since most unresolved base keys are legitimate (interpolation ${VAR} targets,
startXxx bootstrap flags, keys read outside the reflection-tagged struct). This
test targets only the mechanically-detectable signature of a copy-paste-by-analogy
typo.

Six existing normalized collisions are exempted in the test with individual
reasoning. Four are genuinely distinct ALL_CAPS interpolation constants
(P2P_PORT, P2P_PORT_COINBASE - confirmed referenced via ${...} elsewhere in
settings.conf; LOG_LEVEL, COINBASE_GRPC_ADDRESS - same naming block, no
confirmed Go reader). The other two look like the same bug class as
securityLevelGRPC but are left for the settings owner to triage rather than fixed
here, to keep this change scoped:

  • kafka_unitTest (settings.conf, builds a full Kafka URL) is never read by any Go
    code; the real setting is the ALL_CAPS KAFKA_UNITTEST, a bare topic-name string.
  • coinbase_Store.docker is a lone context-only override with no base assignment,
    so it cannot resolve to anything regardless; the real key is coinbase_store.

Verification

  • go build ./...
  • go vet ./settings/... ./util/...
  • go test ./settings/... -race
  • go test ./util/ -race (admin API key + gRPC TLS/security-level tests)
  • golangci-lint run / staticcheck on the touched packages - no new issues (three
    pre-existing prealloc warnings confirmed present on main before this change)
  • End-to-end contrast, run as a standalone binary against isolated settings.conf
    fixtures so gocore's config singleton can't carry state between runs:
    • security_level_grpc = 1 -> NewSettings().SecurityLevelGRPC == 1
    • securityLevelGRPC = 1 (old spelling) -> NewSettings().SecurityLevelGRPC == 0
  • Reintroduced the misspelling to confirm TestSettingsConfNoShadowedKeys fails and
    names the dead key, then reverted.

settings.conf shipped securityLevelGRPC, but the loader reads
security_level_grpc (settings/settings.go) and the struct tag is
key:"security_level_grpc" (settings/interface.go). The line was harmless
at its default of 0, since the real default is also 0, but an operator
who edited it to 1 to enable TLS on inter-service gRPC got silent
plaintext: util/grpc_helper.go GetGRPCClient() only ever saw the unread
default and picked insecure.NewCredentials().

The likely cause is that the sibling setting genuinely is camelCase -
SecurityLevelHTTP carries key:"securityLevelHTTP" - so securityLevelGRPC
looked correct by analogy. That broader camelCase/snake_case
inconsistency across the settings package is out of scope here and
remains a follow-up.

Also corrects the same wrong spelling in operator-facing recommendation
text (cmd/diagnose/config_checks.go, util/admin_api_key.go) and docs
(docs/howto/diagnose.md, docs/references/services/rpc_reference.md),
all of which told operators to set the dead key.

Adds TestSettingsConfNoShadowedKeys, a regression test that fails any
settings.conf key whose case/underscore-normalized form collides with a
real key tag while the literal key does not - the exact failure mode
that let this typo through silently. Six normalized collisions already
present in settings.conf are exempted with reasoning; two of them
(kafka_unitTest and coinbase_Store) look like the same bug class but are
left for the settings owner to triage separately, to keep this change
scoped to securityLevelGRPC.
Copilot AI lite review requested due to automatic review settings August 31, 2026 12:56
@icellan
icellan requested review from ctnguyen and ordishs August 31, 2026 12:56

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions

Copy link
Copy Markdown
Contributor

🤖 Claude Code Review

Status: Complete

Current Review:

No issues found. This is a clean, correct fix.

Verified the core claim against the code: the loader reads getInt("security_level_grpc", ...) (settings/settings.go:85) and the struct tag is key:"security_level_grpc" (settings/interface.go:59), so the old securityLevelGRPC line in settings.conf was indeed dead — normalizing to the right key but never matching gocore's exact-case lookup. The sibling securityLevelHTTP is genuinely camelCase (key:"securityLevelHTTP", read at settings/settings.go:50), so leaving it untouched is correct and internally consistent.

Confirmed no stray occurrences of the old spelling remain outside the intentional doc comments in the new test. The operator-facing text corrections (cmd/diagnose/config_checks.go, util/admin_api_key.go, docs/howto/diagnose.md, docs/references/services/rpc_reference.md) all now point at the real key, and the docs still correctly reference securityLevelHTTP where that (correct) key applies.

The regression test (TestSettingsConfNoShadowedKeys) is a sound, appropriately-scoped guard: it flags exactly the copy-paste-by-analogy signature via ExportMetadata() key tags and case/underscore normalization, with each of the six exemptions individually justified. The PR description is unusually thorough and its reasoning holds up.

@sonarqubecloud

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown
Contributor

Benchmark Comparison Report

Baseline: main (unknown)

Current: PR-1674 (52dec27)

Summary

  • Regressions: 0
  • Improvements: 0
  • Unchanged: 139
  • Significance level: p < 0.05
All benchmark results (sec/op)
Benchmark Baseline Current Change p-value
_NewBlockFromBytes-4 2.021µ 2.009µ ~ 1.000
Block_ValidOrderAndBlessed_DiskVsMemory/leaves=1024/memory-4 11.94m 12.14m ~ 0.100
Block_ValidOrderAndBlessed_DiskVsMemory/leaves=1024/disk_1-4 12.66m 12.82m ~ 0.200
Block_ValidOrderAndBlessed_DiskVsMemory/leaves=1024/disk_2-4 12.89m 12.94m ~ 0.100
Block_ValidOrderAndBlessed_DiskVsMemory/leaves=16384/memo... 28.75m 30.24m ~ 0.100
Block_ValidOrderAndBlessed_DiskVsMemory/leaves=16384/disk... 37.22m 39.32m ~ 0.100
Block_ValidOrderAndBlessed_DiskVsMemory/leaves=16384/disk... 38.03m 37.05m ~ 0.700
SplitSyncedParentMap_SetIfNotExists/256_buckets-4 64.11n 63.99n ~ 0.700
SplitSyncedParentMap_SetIfNotExists/16_buckets-4 64.02n 64.13n ~ 0.700
SplitSyncedParentMap_SetIfNotExists/1_bucket-4 64.16n 64.06n ~ 0.200
SplitSyncedParentMap_ConcurrentSetIfNotExists/256_buckets... 31.01n 29.95n ~ 0.200
SplitSyncedParentMap_ConcurrentSetIfNotExists/16_buckets_... 53.74n 52.68n ~ 0.700
SplitSyncedParentMap_ConcurrentSetIfNotExists/1_bucket_pa... 107.3n 110.0n ~ 0.700
MiningCandidate_Stringify_Short-4 223.9n 222.9n ~ 0.200
MiningCandidate_Stringify_Long-4 1.535µ 1.532µ ~ 0.400
MiningSolution_Stringify-4 771.1n 771.0n ~ 1.000
BlockInfo_MarshalJSON-4 1.570µ 1.555µ ~ 0.100
NewFromBytes-4 132.6n 156.3n ~ 1.000
AddTxBatchColumnar_Validation-4 1.913µ 1.876µ ~ 0.400
OffsetValidationLoop-4 723.0n 719.3n ~ 0.300
Mine_EasyDifficulty-4 60.68µ 61.66µ ~ 0.100
Mine_WithAddress-4 7.009µ 7.077µ ~ 0.100
DirectSubtreeAdd/4_per_subtree-4 58.20n 57.64n ~ 0.700
DirectSubtreeAdd/64_per_subtree-4 31.00n 30.23n ~ 0.400
DirectSubtreeAdd/256_per_subtree-4 29.48n 29.27n ~ 0.200
DirectSubtreeAdd/1024_per_subtree-4 28.47n 27.96n ~ 0.100
DirectSubtreeAdd/2048_per_subtree-4 27.58n 27.65n ~ 0.400
SubtreeProcessorAdd/4_per_subtree-4 236.6n 240.0n ~ 0.200
SubtreeProcessorAdd/64_per_subtree-4 234.1n 236.0n ~ 0.700
SubtreeProcessorAdd/256_per_subtree-4 238.9n 236.5n ~ 0.400
SubtreeProcessorAdd/1024_per_subtree-4 230.8n 229.1n ~ 0.100
SubtreeProcessorAdd/2048_per_subtree-4 231.3n 229.3n ~ 0.100
SubtreeProcessorRotate/4_per_subtree-4 234.1n 231.5n ~ 0.200
SubtreeProcessorRotate/64_per_subtree-4 231.8n 232.1n ~ 1.000
SubtreeProcessorRotate/256_per_subtree-4 231.8n 229.6n ~ 0.100
SubtreeProcessorRotate/1024_per_subtree-4 230.6n 230.7n ~ 1.000
SubtreeNodeAddOnly/4_per_subtree-4 54.10n 62.78n ~ 0.100
SubtreeNodeAddOnly/64_per_subtree-4 33.99n 35.14n ~ 0.100
SubtreeNodeAddOnly/256_per_subtree-4 33.06n 33.23n ~ 0.400
SubtreeNodeAddOnly/1024_per_subtree-4 32.51n 32.59n ~ 0.700
SubtreeCreationOnly/4_per_subtree-4 114.8n 134.3n ~ 0.100
SubtreeCreationOnly/64_per_subtree-4 401.2n 387.6n ~ 0.700
SubtreeCreationOnly/256_per_subtree-4 1.277µ 1.265µ ~ 0.700
SubtreeCreationOnly/1024_per_subtree-4 4.180µ 4.784µ ~ 0.100
SubtreeCreationOnly/2048_per_subtree-4 7.498µ 8.567µ ~ 0.100
SubtreeProcessorOverheadBreakdown/64_per_subtree-4 229.8n 229.6n ~ 0.800
SubtreeProcessorOverheadBreakdown/1024_per_subtree-4 229.7n 228.5n ~ 0.200
ParallelGetAndSetIfNotExists/1k_nodes-4 10.04m 12.51m ~ 0.100
ParallelGetAndSetIfNotExists/10k_nodes-4 13.32m 15.87m ~ 0.100
ParallelGetAndSetIfNotExists/50k_nodes-4 16.05m 19.13m ~ 0.100
ParallelGetAndSetIfNotExists/100k_nodes-4 18.60m 22.35m ~ 0.700
SequentialGetAndSetIfNotExists/1k_nodes-4 9.135m 12.724m ~ 0.100
SequentialGetAndSetIfNotExists/10k_nodes-4 13.41m 17.45m ~ 0.100
SequentialGetAndSetIfNotExists/50k_nodes-4 22.08m 23.10m ~ 0.100
SequentialGetAndSetIfNotExists/100k_nodes-4 31.06m 31.26m ~ 1.000
ProcessOwnBlockSubtreeNodesParallel/1k_nodes-4 11.88m 12.05m ~ 0.400
ProcessOwnBlockSubtreeNodesParallel/10k_nodes-4 14.00m 14.67m ~ 0.400
ProcessOwnBlockSubtreeNodesParallel/100k_nodes-4 19.68m 19.42m ~ 1.000
ProcessOwnBlockSubtreeNodesSequential/1k_nodes-4 11.93m 12.51m ~ 1.000
ProcessOwnBlockSubtreeNodesSequential/10k_nodes-4 15.74m 15.55m ~ 0.400
ProcessOwnBlockSubtreeNodesSequential/100k_nodes-4 59.39m 52.57m ~ 0.100
DiskTxMap_SetIfNotExists-4 3.360µ 3.394µ ~ 0.400
DiskTxMap_SetIfNotExists_Parallel-4 3.179µ 3.128µ ~ 0.700
DiskTxMap_ExistenceOnly-4 291.1n 289.6n ~ 0.400
Queue-4 187.7n 190.1n ~ 0.700
AtomicPointer-4 4.308n 4.314n ~ 1.000
TxMapSetIfNotExists-4 63.29n 63.03n ~ 1.000
TxMapSetIfNotExistsDuplicate-4 46.75n 47.36n ~ 0.200
ChannelSendReceive-4 578.5n 575.1n ~ 0.400
BlockAssembler_AddTx-4 0.02538n 0.02308n ~ 0.700
AddNode-4 10.55 10.85 ~ 0.100
AddNodeWithMap-4 11.10 11.15 ~ 0.700
CalcBlockWork-4 520.2n 518.1n ~ 0.700
CalculateWork-4 695.9n 718.9n ~ 0.100
CheckOldBlockIDs/on-chain-prefetch/1000-4 65.91µ 65.43µ ~ 1.000
CheckOldBlockIDs/in-memory-chain-check/1000-4 1.399m 1.448m ~ 0.100
CheckOldBlockIDs/on-chain-prefetch/10000-4 458.6µ 456.6µ ~ 1.000
CheckOldBlockIDs/in-memory-chain-check/10000-4 2.178m 2.134m ~ 0.200
BuildBlockLocatorString_Helpers/Size_10-4 1.349µ 1.352µ ~ 0.700
BuildBlockLocatorString_Helpers/Size_100-4 12.99µ 12.85µ ~ 0.100
BuildBlockLocatorString_Helpers/Size_1000-4 129.0µ 129.1µ ~ 1.000
CatchupWithHeaderCache-4 107.2m 107.1m ~ 0.700
_BufferPoolAllocation/16KB-4 2.764µ 2.780µ ~ 0.700
_BufferPoolAllocation/32KB-4 6.506µ 6.376µ ~ 0.400
_BufferPoolAllocation/64KB-4 12.85µ 13.83µ ~ 0.700
_BufferPoolAllocation/128KB-4 25.41µ 25.75µ ~ 0.400
_BufferPoolAllocation/512KB-4 81.81µ 88.70µ ~ 0.700
_BufferPoolConcurrent/32KB-4 16.74µ 14.34µ ~ 0.100
_BufferPoolConcurrent/64KB-4 26.57µ 22.36µ ~ 0.100
_BufferPoolConcurrent/512KB-4 123.4µ 121.1µ ~ 0.400
_SubtreeDeserializationWithBufferSizes/16KB-4 531.8µ 532.1µ ~ 1.000
_SubtreeDeserializationWithBufferSizes/32KB-4 468.1µ 490.0µ ~ 0.100
_SubtreeDeserializationWithBufferSizes/64KB-4 472.1µ 493.3µ ~ 0.100
_SubtreeDeserializationWithBufferSizes/128KB-4 470.2µ 490.0µ ~ 0.200
_SubtreeDeserializationWithBufferSizes/512KB-4 495.7µ 493.7µ ~ 0.100
_SubtreeDataDeserializationWithBufferSizes/16KB-4 28.24m 28.02m ~ 0.400
_SubtreeDataDeserializationWithBufferSizes/32KB-4 28.29m 28.11m ~ 0.400
_SubtreeDataDeserializationWithBufferSizes/64KB-4 28.16m 28.02m ~ 0.400
_SubtreeDataDeserializationWithBufferSizes/128KB-4 27.91m 27.67m ~ 0.200
_SubtreeDataDeserializationWithBufferSizes/512KB-4 27.64m 27.90m ~ 0.200
_PooledVsNonPooled/Pooled-4 652.3n 643.7n ~ 0.100
_PooledVsNonPooled/NonPooled-4 6.190µ 5.598µ ~ 0.100
_MemoryFootprint/Current_512KB_32concurrent-4 5.546µ 6.073µ ~ 0.200
_MemoryFootprint/Proposed_32KB_32concurrent-4 9.397µ 7.306µ ~ 0.100
_MemoryFootprint/Alternative_64KB_32concurrent-4 7.955µ 7.050µ ~ 0.100
_prepareTxsPerLevel-4 403.7m 449.1m ~ 0.100
_prepareTxsPerLevelOrdered-4 3.982m 4.312m ~ 0.700
_prepareTxsPerLevel_Comparison/Original-4 398.5m 458.5m ~ 0.100
_prepareTxsPerLevel_Comparison/Optimized-4 3.878m 4.246m ~ 0.100
SubtreeSizes/10k_tx_4_per_subtree-4 1.041m 1.009m ~ 0.400
SubtreeSizes/10k_tx_16_per_subtree-4 241.0µ 236.6µ ~ 0.700
SubtreeSizes/10k_tx_64_per_subtree-4 57.77µ 57.53µ ~ 0.400
SubtreeSizes/10k_tx_256_per_subtree-4 14.40µ 14.10µ ~ 0.200
SubtreeSizes/10k_tx_512_per_subtree-4 7.127µ 7.020µ ~ 0.100
SubtreeSizes/10k_tx_1024_per_subtree-4 3.474µ 3.493µ ~ 0.700
SubtreeSizes/10k_tx_2k_per_subtree-4 1.742µ 1.712µ ~ 0.100
BlockSizeScaling/10k_tx_64_per_subtree-4 55.47µ 54.88µ ~ 0.700
BlockSizeScaling/10k_tx_256_per_subtree-4 13.92µ 13.76µ ~ 0.200
BlockSizeScaling/10k_tx_1024_per_subtree-4 3.425µ 3.428µ ~ 1.000
BlockSizeScaling/50k_tx_64_per_subtree-4 292.6µ 288.8µ ~ 0.700
BlockSizeScaling/50k_tx_256_per_subtree-4 68.48µ 68.63µ ~ 0.400
BlockSizeScaling/50k_tx_1024_per_subtree-4 16.82µ 17.14µ ~ 0.700
SubtreeAllocations/small_subtrees_exists_check-4 116.3µ 117.1µ ~ 0.400
SubtreeAllocations/small_subtrees_data_fetch-4 123.5µ 122.8µ ~ 0.700
SubtreeAllocations/small_subtrees_full_validation-4 238.6µ 237.5µ ~ 0.100
SubtreeAllocations/medium_subtrees_exists_check-4 7.013µ 6.973µ ~ 0.700
SubtreeAllocations/medium_subtrees_data_fetch-4 7.315µ 7.288µ ~ 0.200
SubtreeAllocations/medium_subtrees_full_validation-4 13.89µ 13.78µ ~ 0.100
SubtreeAllocations/large_subtrees_exists_check-4 1.651µ 1.657µ ~ 0.700
SubtreeAllocations/large_subtrees_data_fetch-4 1.764µ 1.772µ ~ 0.700
SubtreeAllocations/large_subtrees_full_validation-4 3.444µ 3.425µ ~ 0.500
StoreBlock_Sequential/BelowCSVHeight-4 348.7µ 351.7µ ~ 1.000
StoreBlock_Sequential/AboveCSVHeight-4 349.7µ 346.9µ ~ 0.700
GetUtxoHashes-4 264.4n 260.2n ~ 0.100
GetUtxoHashes_ManyOutputs-4 48.85µ 44.51µ ~ 0.100
MetaBytes-4 88.98n 88.65n ~ 0.800
_NewMetaDataFromBytes-4 279.6n 279.2n ~ 0.800
_Bytes-4 403.1n 397.3n ~ 0.200
_MetaBytes-4 140.1n 146.4n ~ 0.200

Threshold: >10% with p < 0.05 | Generated: 2026-08-31 13:10 UTC

@ctnguyen ctnguyen left a comment

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.

Review at commit bd6376f

The core change is plainly right and unusually well evidenced. settings/interface.go:59 carries key:"security_level_grpc", settings/settings.go reads that string, and gocore's lookup is exact — os.LookupEnv(key) then a case-sensitive map probe in findValue — so the old settings.conf line really was inert, and the "typed by analogy to the genuinely-camelCase securityLevelHTTP" diagnosis is convincing. The blast radius is correctly identified too: git grep over tracked files shows the old spelling now survives only in the new test's own explanatory comments, and every operator-facing string that told people to set the dead key is caught. The regression test targets the right signature — normalized collision without exact match — rather than reaching for a blanket "every key resolves" sweep it would have had to exempt half of settings.conf to pass; the six exemptions are individually reasoned and the two that admit to being the same bug class are honestly labelled as deferred rather than quietly dropped. I traced the two COINBASE_GRPC_ADDRESS claims and both halves hold: nothing in Go reads that literal key, and since gocore looks up the requested key name, the docker-compose-3blasters.yml env var never reaches coinbase_grpcAddress. Adding a base assignment equal to the struct default also can't shadow anything — env still wins, and findValue walks context suffixes before falling back to base, so the only observable change is the reported source in the settings dump.

Nothing here should hold up the merge. Both notes below are about the neighbourhood the fix lands in: now that the key resolves and the diagnose output names it correctly, operators are much more likely to actually turn gRPC TLS on, and the two places that meet them when they do are a little out of step with the rest of the codebase.

Non-blocking issues

ChiR1 — Diagnose cert-file check gates only on HTTP, so a gRPC TLS misconfiguration passes

Problem: cmd/diagnose/config_checks.go:237 guards the cert-file check with s.SecurityLevelHTTP > 0 && (s.ServerCertFile == "" || s.ServerKeyFile == "")SecurityLevelGRPC is not consulted. But util/grpc.go:48-57 returns a ConfigurationError (server_certFile is required for security level %d) whenever SecurityLevelGRPC > 0 and the cert or key path is empty, so every gRPC service refuses to start. The docs table this commit touched describes the check generically — docs/howto/diagnose.md:180 reads TLS cert files | TLS enabled but server_certFile or server_keyFile empty | ERROR — which overstates what it covers. This path was always possible to reach, since gocore layers settings_local.conf and environment overrides ahead of the struct-tag default; what this commit changes is that the shipped base config now exposes the key and the diagnose recommendation names it correctly, so an operator is far more likely to walk into it.

Why it matters: An operator who acts on the gRPC TLS recommendation without cert paths configured gets a green gRPC TLS row from diagnose and then a node that will not come up. Catching exactly that before a restart is what the config checks are for.

Fix: Include the gRPC level in the condition:

if (s.SecurityLevelHTTP > 0 || s.SecurityLevelGRPC > 0) && (s.ServerCertFile == "" || s.ServerKeyFile == "") {

Both server paths read the same ServerCertFile / ServerKeyFile, so one combined check is sufficient.

ChiR2 — Diagnose reports level 1 as OK while the same commit warns about it elsewhere

Problem: cmd/diagnose/config_checks.go:213-219 reports any non-zero SecurityLevelGRPC as SeverityOK with the value level 1 and no caveat. On that same configuration, util/admin_api_key.go:76 — changed in this commit — warns that security_level_grpc=1 "does not provide verified transport security, so the admin key can be harvested in transit". So two parts of the node disagree about whether the operator is in good shape. The recommendation strings show the same split: config_checks.go:211 now says Set security_level_grpc >= 1 for production, while the two other strings this commit touched say >= 2 (util/admin_api_key.go:76 and docs/references/services/rpc_reference.md:435). Level 1 client-side is credentials.NewTLS(&tls.Config{InsecureSkipVerify: true}), which util/grpc_helper.go:389 and :426 describe as MITM-vulnerable by design.

Why it matters: Level 1 is a legitimate supported mode, so recommending it is not wrong in itself — but a green OK on it is, because it is the one signal that tells an operator to stop looking. Having the diagnostic bless a configuration the runtime warns about undercuts both messages, and since this commit is what makes all three strings take effect, it is the natural place to line them up.

Fix: Report level 1 at the same severity the runtime uses, and match the other two call sites on the recommended floor:

Recommended: "Set security_level_grpc >= 2 for production (level 1 does not verify certificates)",

with the non-zero branch treating level 1 as a warning rather than SeverityOK. The sample output at docs/howto/diagnose.md:242 needs the same edit.

Recap

ID Description Required Criticality
ChiR1 Cert check ignores gRPC level 40%
ChiR2 Level 1 reported as OK 30%

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants