Conversation
There was a problem hiding this comment.
Pull request overview
This PR introduces per-network “control flags” for remote FDB connections, with the immediate goal of disabling wipe operations for selected client networks.
Changes:
- Add parsing of control flags into
ControlIdentifiersfrom configuration objects. - Wire network-derived
ControlIdentifiersinto the remote catalogue server and gate wipe-related control messages. - Refactor
FDBBaseinitialisation to constructcontrolIdentifiers_directly from config.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
src/fdb5/remote/server/CatalogueHandler.h |
Adds ControlIdentifiers state and a helper to check whether wipe is allowed. |
src/fdb5/remote/server/CatalogueHandler.cc |
Applies wipe gating to wipe-related messages and initialises control flags from matched network config. |
src/fdb5/api/helpers/ControlIterator.h |
Adds a ControlIdentifiers(LocalConfiguration) constructor declaration (and new include). |
src/fdb5/api/helpers/ControlIterator.cc |
Implements config-based control-flag parsing into the internal bitmask. |
src/fdb5/api/FDBFactory.cc |
Refactors FDBBase ctor to initialise controlIdentifiers_ via the new constructor. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| case Message::Wipe: // Initial wipe request | ||
| wipe(clientID, requestID, std::move(payload)); | ||
| return Handled::Yes; | ||
| if (isWipeEnabled(clientID, requestID)) { | ||
| wipe(clientID, requestID, std::move(payload)); | ||
| return Handled::Yes; | ||
| } | ||
| return Handled::Replied; | ||
|
|
||
| case Message::DoMaskIndexEntries: | ||
| // doit! We expect DoMaskIndexEntries, doWipeURIs, DoWipeUnknowns and doWipeEmptyDatabase in succession | ||
| doMaskIndexEntries(clientID, requestID, std::move(payload)); | ||
| return Handled::Yes; | ||
| if (isWipeEnabled(clientID, requestID)) { | ||
| // doit! We expect DoMaskIndexEntries, doWipeURIs, DoWipeUnknowns and doWipeEmptyDatabase in | ||
| // succession | ||
| doMaskIndexEntries(clientID, requestID, std::move(payload)); | ||
| return Handled::Yes; | ||
| } | ||
| return Handled::Replied; | ||
|
|
||
| case Message::DoWipeURIs: // Do the wipe on our currentWipeState | ||
| doWipeURIs(clientID, requestID, std::move(payload)); | ||
| return Handled::Yes; | ||
| if (isWipeEnabled(clientID, requestID)) { | ||
| doWipeURIs(clientID, requestID, std::move(payload)); | ||
| return Handled::Yes; | ||
| } | ||
| return Handled::Replied; | ||
|
|
||
| case Message::DoWipeFinish: // Finish wipe by deleting empty DBs | ||
| doWipeEmptyDatabase(clientID, requestID, std::move(payload)); | ||
| return Handled::Yes; | ||
| if (isWipeEnabled(clientID, requestID)) { | ||
| doWipeEmptyDatabase(clientID, requestID, std::move(payload)); | ||
| return Handled::Yes; | ||
| } | ||
| return Handled::Replied; | ||
|
|
||
| case Message::DoWipeUnknowns: // Wipe a set of unknown URIs | ||
| doWipeUnknowns(clientID, requestID, std::move(payload)); | ||
| return Handled::Yes; | ||
| if (isWipeEnabled(clientID, requestID)) { | ||
| doWipeUnknowns(clientID, requestID, std::move(payload)); | ||
| return Handled::Yes; | ||
| } |
There was a problem hiding this comment.
This new wipe-gating behaviour (based on per-network control flags) isn’t covered by the existing remote protocol tests. It would be good to add a remote test configuration that defines a networks entry matching the test client (e.g., localhost netmask) with wipe: false, and assert that FDB{}.wipe(...) fails with the expected error.
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## develop #267 +/- ##
===========================================
- Coverage 71.17% 71.05% -0.12%
===========================================
Files 376 376
Lines 23786 23834 +48
Branches 2480 2483 +3
===========================================
+ Hits 16930 16936 +6
- Misses 6856 6898 +42 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
5cd054d to
c194460
Compare
ChrisspyB
left a comment
There was a problem hiding this comment.
Pending test.
I am still worried about negligent / AI wipe commands from within a "trusted" network.
| if (!config.getBool("archive", writable)) { | ||
| value_ |= static_cast<value_type>(ControlIdentifier::Archive); | ||
| } | ||
| if (!config.getBool("wipe", writable)) { |
There was a problem hiding this comment.
So, to be clear, we set this bit to 1 if:
- Wipe is set to false in the config.
- Wipe is not specified, but writable is explicitly false in config.
So, I assume value_ is going to store the set of actions we cannot do.
And we set to 0 if:
- Wipe is set to true.
- Wipe unspecified but writable is true
- If both wipe and writable not specified in config (i.e. by default)
And 0 means it is allowed i.e. wiping is by default enabled. Is this correct?
Worth adding a comment to this ctor that variables marked true in the config correspond to 0 in the ControlIdentifers, which is an aspect of the ControlIdentifiers I dislike.
There was a problem hiding this comment.
After looking at the enabled function in the ControlIdentifiers class, I think Chris is right and we should at least leave a comment describing that behavior.
If this isn't true, we should definitely leave a comment, describing the behavior.
I would default to non-wipeable, too.
| eckit::net::IPAddress clientIPaddress{controlSocket_.remoteAddr()}; | ||
|
|
||
| clientNetwork_ = ""; | ||
| if (config_.has("networks")) { |
There was a problem hiding this comment.
If I have a typo in my serverside config, e.g. I write network instead of networks, none of this logic is called, and (I think) everyone can wipe my data.
I'm inclined to say that for remote wipe it should default to being disabled.
tbkr
left a comment
There was a problem hiding this comment.
Would be good to documentation the behavior of the ControlIdentifiers and the mapping to configuration.
simondsmart
left a comment
There was a problem hiding this comment.
In addition to the above, I want the ability to (fully) disable the wipe function on certain interfaces of the Store.
| s >> value_; | ||
| } | ||
|
|
||
| ControlIdentifiers::ControlIdentifiers(const eckit::LocalConfiguration& config) : value_(0) { |
There was a problem hiding this comment.
I don't like this at all.
This ControlIdentifiers class is used in a number of places. It is used in the lock/unlock control functionality. And it is used here in the enable/disable logic. But those should both be logic which uses ControlIdentifiers rather than logic that is in ControlIdentifiers.
So, I'm really not at all convinced that the logic to extract enable/disable from config belongs inside this class. This is visible in the PR in that only some of the logic is here - the rest is in the CatalogueHandler.cc file. Yuck.
I also note Chris' comment below, such that the boolean logic is the inverse of what one would naively expect. We should probably fix that.
|
|
||
| void CatalogueHandler::checkIsEnabled(ControlIdentifier identifier) { | ||
| if (!controlIdentifiers_.enabled(identifier)) { | ||
| throw UnhandledOperationException(identifier); |
There was a problem hiding this comment.
This is not an unhandled operation (which draws to mind not-implemented, or similar). It is a disabled operation. A relative of PermissionDenied (the exception might derive from that)
| inspect(clientID, requestID, std::move(payload)); | ||
| return Handled::Yes; | ||
|
|
||
| case Message::Stats: // inspect request. Location are sent aynchronously over the data connection |
There was a problem hiding this comment.
Stats/Exist/Axes/List should also be considered for permissions.
| } | ||
|
|
||
| void CatalogueHandler::wipe(uint32_t clientID, uint32_t requestID, eckit::Buffer&& payload) { | ||
| checkIsEnabled(ControlIdentifier::Wipe); |
There was a problem hiding this comment.
Is checkIsEnabled not called in handleControl()?
| eckit::net::NetMask netmask{net.getString("netmask")}; | ||
| if (netmask.contains(clientIPaddress)) { | ||
| clientNetwork_ = net.getString("name"); | ||
| controlIdentifiers_ = ControlIdentifiers(net); |
There was a problem hiding this comment.
These apply in addition (?) to the logic in the contained FDB object?
Description
add ControlIdentifier to the remote FDB networs (to prevent specific operations from selected networks)
Contributor Declaration
By opening this pull request, I affirm the following:
🌈🌦️📖🚧 Documentation FDB 🚧📖🌦️🌈
https://sites.ecmwf.int/docs/fdb/pull-requests/PR-267