Repository navigation
fix: BCE-11514 - tell an empty keystore table apart from an empty cluster filter - #40
Merged
Merged
Conversation
The zero-row guard in 0.4.2 was unconditional, with --allow-no-keys as the way
out. That put the burden on an operator to declare which kind of empty a signer
is, and the flag has to be toggled in lockstep with the signer's lifecycle:
left on it permanently disables the guard for that namespace, and removed at the
wrong moment the pod will not start. Either way the protection is unreliable,
which makes the flag close to useless as a safety mechanism.
The two cases are distinguishable from the data instead. count_all_keys()
counts the table ignoring any cluster predicate:
table empty -> nothing provisioned yet. Start with an empty
keystore, which is what web3signer already
does and what 0.4.1 did.
rows present, none for my -> this database holds keys, just not for the
cluster cluster asked for. Almost always a wrong
cluster id or a keystore URL pointing at
another namespace, so refuse.
The keystore directory cannot answer this, because it is a tmpfs emptyDir and
is therefore empty on every pod start either way.
Consequences: QA's euw1/hoodi-2 needs no flag at all, and neither does a fresh
KOS database before keys are copied into it. The dangerous case now fails
whether or not anyone remembered a flag. --allow-no-keys stays only as a narrow
escape hatch for a signer that genuinely serves none of a populated table's
clusters, such as one of two co-located clusters being empty.
Verified: the new unit tests and the two new real-PostgreSQL tests all fail
against 0.4.2 and pass here; 79 tests pass with a live server; and run against
the real QA euw1/hoodi-2 database with no flags at all it prints "starting with
an empty keystore" and exits 0, writing nothing.
Under one KOS database per namespace the filtered read returns the same set an unfiltered read would, so the refusal below it is unreachable for a correctly configured signer. It can only fire when the cluster id or the keystore URL is wrong, and those are not conditions to wave through -- the flag could only ever mask a real misconfiguration while silently disabling the guard for that namespace from then on. Empty tables are already tolerated without it, which is the case that actually occurs: QA's euw1/hoodi-2 has zero rows with web3signer running 3/3 ready, and a fresh KOS database before the key copy is the same shape. Verified: 79 tests pass against live PostgreSQL 16; the refusal is now proven unoverridable by a test asserting the option is rejected; and re-run against the real euw1/hoodi-2 database with no flags it prints "starting with an empty keystore" and exits 0, writing nothing.
rhaquegalaxy
approved these changes
Sep 7, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #38. Releases as 0.4.3.
0.4.2 refuses a zero-row read unconditionally, with
--allow-no-keysas the opt-out. That flag has to track a signer's lifecycle: left on it disables the guard permanently, removed at the wrong moment the pod won't start.Instead
count_all_keys()counts the table ignoring any cluster predicate, which separates the two cases:--allow-no-keysis removed. A table with noclient_cluster_idcolumn behaves exactly as 0.4.1, since filtered and unfiltered are then the same read.Verified: the new unit tests and two new real-PostgreSQL tests fail against 0.4.2 and pass here; 79 tests pass against a live PostgreSQL 16; mypy,
ruff checkandruff formatclean.Chart users: skip 0.4.2. It stops a signer that legitimately serves no validators from starting.