huskies: merge 1169 story Gateway pulls signed artifacts from a release channel into its local store

This commit is contained in:
Huskies Agent
2026-07-16 14:03:31 +00:00
parent 1e0e581bd7
commit 77e0394195
23 changed files with 1643 additions and 7 deletions
@@ -94,6 +94,14 @@ pub struct BotContext {
/// The `new project` command writes here so HTTP handlers see the new entry
/// immediately without requiring a gateway restart. `None` in standalone mode.
pub gateway_projects_store: Option<Arc<RwLock<BTreeMap<String, ProjectEntry>>>>,
/// In gateway mode: shared configured release channels (story 1169).
///
/// Read by the `pull <channel>` command to resolve a channel's
/// `base_url`, pinned `pubkey`, and optional `bearer_token`. `None` in
/// standalone mode.
pub gateway_channels_store: Option<
Arc<RwLock<BTreeMap<String, crate::service::gateway::config::ReleaseChannelConfig>>>,
>,
/// Bounded FIFO set of already-handled incoming event IDs.
///
/// The Matrix sync loop can replay events on reconnect. This set ensures
@@ -315,6 +323,7 @@ mod tests {
)),
gateway_active_project,
gateway_projects_store,
gateway_channels_store: None,
handled_incoming_event_ids: Arc::new(TokioMutex::new(SeenEventIds::new(
SEEN_EVENT_IDS_CAP,
))),
@@ -548,6 +548,33 @@ pub(in crate::chat::transport::matrix::bot) async fn on_room_message(
return;
}
// In gateway mode, handle the `pull <channel>` command: fetch, verify, and
// install a signed release-channel artifact into the artifact store.
if ctx.is_gateway()
&& let Some(channel) = super::super::super::pull::extract_pull_command(
&user_message,
&ctx.services.bot_name,
ctx.matrix_user_id.as_str(),
)
{
slog!("[matrix-bot] Handling 'pull {channel}' from {sender}");
let response = if let Some(ref store) = ctx.gateway_channels_store {
super::super::super::pull::handle_pull(&channel, store).await
} else {
"Gateway release channels unavailable — cannot pull.".to_string()
};
let html = markdown_to_html(&response);
if let Ok(msg_id) = ctx
.transport
.send_message(&room_id_str, &response, &html)
.await
&& let Ok(event_id) = msg_id.parse()
{
ctx.bot_sent_event_ids.lock().await.insert(event_id);
}
return;
}
// In gateway mode, handle the `upgrade [<project>]` command to upgrade a
// sled's binary in-container, streaming phase markers to the room.
if ctx.is_gateway()
@@ -40,6 +40,16 @@ pub async fn run_bot(
tokio::sync::broadcast::Receiver<crate::service::gateway::GatewayStatusEvent>,
>,
gateway_port: Option<u16>,
gateway_channels_store: Option<
Arc<
RwLock<
std::collections::BTreeMap<
String,
crate::service::gateway::config::ReleaseChannelConfig,
>,
>,
>,
>,
) -> Result<(), String> {
let project_root = &services.project_root;
let store_path = project_root.join(".huskies").join("matrix_store");
@@ -332,6 +342,7 @@ pub async fn run_bot(
timer_store,
gateway_active_project,
gateway_projects_store,
gateway_channels_store,
handled_incoming_event_ids: Arc::new(TokioMutex::new(super::context::SeenEventIds::new(
super::context::SEEN_EVENT_IDS_CAP,
))),