fix(appgate): classify ports from the catalog even for on-node-built apps
The port map deferred to DISK manifests for any app with a build source — which is exactly the four companion UIs (lnd-ui, bitcoin-ui, electrs-ui, fips-ui). Their disk manifests reach nodes only via the frontend runtime payload or a per-node repo checkout, and in the v1.7.125 rollout both proved stale or entirely absent: one node had no checkout at all, others restored an older payload over apps/ at every boot. Result: session_passthrough never reached the gate, so the node's own screens 401'd on every data call, and on nodes whose UI rebuilt from a stale context the app held its port UNGATED. Classification now uses a ports-only overlay that accepts build-source manifests (install/orchestration still defers to disk — unchanged). The signed catalog is the freshest, operator-signed source, and the gate's address binds fail safely against a container publishing differently (logged CANNOT PROTECT), so this can only tighten policy, never expose. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
83d7234824
commit
6c0fc366b3
@@ -147,11 +147,18 @@ pub fn build_port_map() -> PortMap {
|
||||
let mut seen_apps: std::collections::HashSet<String> = std::collections::HashSet::new();
|
||||
|
||||
for (app_id, value) in crate::container::app_catalog::catalog_manifest_values() {
|
||||
// Ports-only overlay: unlike the install path, classification also
|
||||
// accepts BUILD-SOURCE manifests. The on-node-built companion UIs
|
||||
// are exactly the apps whose gate policy (session_passthrough,
|
||||
// auth: gated) must arrive reliably, and their disk manifests
|
||||
// proved stale or absent fleet-wide in the v1.7.125 rollout. The
|
||||
// gate's binds fail safely on conflict with a differently-published
|
||||
// container, so a fresher catalog can only tighten, never expose.
|
||||
let Some(manifest) =
|
||||
crate::container::app_catalog::catalog_manifest_overlay(&app_id, value)
|
||||
crate::container::app_catalog::catalog_manifest_ports_overlay(&app_id, value)
|
||||
else {
|
||||
// Unparseable/invalid/build-source → the orchestrator falls back
|
||||
// to disk for this app, so classification must too.
|
||||
// Unparseable/invalid → the orchestrator falls back to disk for
|
||||
// this app, so classification must too.
|
||||
continue;
|
||||
};
|
||||
if seen_apps.insert(app_id) {
|
||||
|
||||
@@ -256,6 +256,33 @@ pub fn catalog_manifest_overlay(
|
||||
Some(m)
|
||||
}
|
||||
|
||||
/// Like [`catalog_manifest_overlay`] but WITHOUT the build-source refusal —
|
||||
/// for PORT CLASSIFICATION only, never for install/orchestration.
|
||||
///
|
||||
/// The on-node-built companion UIs (lnd-ui, bitcoin-ui, electrs-ui, fips-ui)
|
||||
/// are exactly the apps whose port policy (auth/bind/session_passthrough)
|
||||
/// must reach the gate reliably, yet their build sources made the overlay
|
||||
/// defer to DISK manifests — whose only delivery paths (frontend runtime
|
||||
/// payload, per-node repo copies) proved stale or absent across the fleet in
|
||||
/// the v1.7.125 rollout: nodes served ungated UIs or 401-dead panels until
|
||||
/// hand-fixed. The signed catalog is fresher and operator-signed; and the
|
||||
/// gate's address binds fail safely on conflict with a container that
|
||||
/// publishes differently (logged as CANNOT PROTECT), so classifying from the
|
||||
/// catalog cannot open anything the running container hasn't already opened.
|
||||
pub fn catalog_manifest_ports_overlay(
|
||||
app_id: &str,
|
||||
value: serde_json::Value,
|
||||
) -> Option<archipelago_container::manifest::AppManifest> {
|
||||
let m: archipelago_container::manifest::AppManifest = serde_json::from_value(value).ok()?;
|
||||
if m.app.id != app_id {
|
||||
return None;
|
||||
}
|
||||
if m.validate().is_err() {
|
||||
return None;
|
||||
}
|
||||
Some(m)
|
||||
}
|
||||
|
||||
/// The catalog's default/latest version string for an app (the top-level
|
||||
/// `version` field), if covered. Used to decide whether an install-time
|
||||
/// selection should pin (older) or track-latest (default).
|
||||
|
||||
Reference in New Issue
Block a user