Repository navigation
Queued DM overwrite, storage bucket ownership #142
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
61cd483
1f9d101
e690a58
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -123,9 +123,18 @@ where | |
| { | ||
| let (agent_id, filename) = agent_and_filename(&req)?; | ||
|
|
||
| if !registry.agents.lock()?.contains_key(&agent_id) { | ||
| let agents = registry.agents.lock()?; | ||
| let Some(record) = agents.get(&agent_id) else { | ||
| return Err(StorageError::AgentNotFound); | ||
| }; | ||
| // An id's existence is not ownership: the listener is reachable from every | ||
| // interface, so a PUT is accepted only from the address the agent | ||
| // registered from, or from loopback where the server's own runners and | ||
| // modules write on an agent's behalf. | ||
| if !requester_owns_bucket(record.last_known_ip.as_deref(), req.peer_addr()) { | ||
| return Err(StorageError::RequesterNotBucketOwner); | ||
| } | ||
| drop(agents); | ||
|
|
||
| // The body is buffered rather than streamed to the store. | ||
| // `ObjectStore::put` takes a whole payload, and the alternative (`put_multipart`) buys streaming at the | ||
|
|
@@ -149,6 +158,22 @@ where | |
| Ok(response.finish()) | ||
| } | ||
|
|
||
| /// Whether the request peer may write to the bucket of the agent whose registered address is `registered_ip`. | ||
| /// | ||
| /// The registered address is the identity: `connect_agent` records the IP the agent's WebSocket arrived from, | ||
| /// and a module or runner writing on an agent's behalf does so from this machine. Loopback is therefore | ||
| /// accepted as well. Anything else -- including an agent that never registered a usable address (recorded as | ||
| /// "unknown") or a request with no peer at all -- is a stranger and is refused. | ||
| fn requester_owns_bucket(registered_ip: Option<&str>, peer: Option<std::net::SocketAddr>) -> bool { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Avoid using The And we need to dig a bit more into why
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agent IP are now mandatory per #89 |
||
| let Some(peer) = peer else { | ||
| return false; | ||
| }; | ||
| if peer.ip().is_loopback() { | ||
| return true; | ||
| } | ||
| registered_ip.is_some_and(|registered| registered.parse::<std::net::IpAddr>().is_ok_and(|ip| ip == peer.ip())) | ||
| } | ||
|
|
||
| /// Log a stored image, and show it on the terminal when the `tty-image` feature is on. | ||
| /// | ||
| /// `put_file` is the only path a file reaches storage through, so it is where every stored file can be watched | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The intent is to have only one message pending for an agent to another. This is to ensure that the size of the pending messages is kept predicable so that the amount of memory can be constrained and known. It is the responsibility of the agents to use this wisely. I am sorry this hasnt been clearly documented.
If you want a all messages kept, I would accept a Config to allow different modes of message retention.