Sync public tree to 4a860d7
This commit is contained in:
parent
1dad0df5c4
commit
4f5df7da20
4 changed files with 236 additions and 5 deletions
|
|
@ -1,4 +1,4 @@
|
|||
use std::collections::BTreeSet;
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
use std::io::{BufRead, BufReader, Write};
|
||||
use std::net::{TcpListener, TcpStream, ToSocketAddrs};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
|
@ -10,8 +10,9 @@ use base64::{engine::general_purpose::STANDARD as BASE64_STANDARD, Engine as _};
|
|||
use clap::{Args, Parser, Subcommand};
|
||||
use disasmer_core::{
|
||||
diagnose_environment_references, BrowserLoginFlow, BundleIdentityInputs, BundleMetadata,
|
||||
Capability, CliLoginFlow, Digest, EnvironmentReference, LimitKind, NodeCapabilities,
|
||||
ProjectModel, ResourceLimits, SelectedInput, SourceProviderKind, SourceProviderManifest,
|
||||
Capability, CliLoginFlow, Digest, EnvironmentBackend, EnvironmentReference, LimitKind,
|
||||
NodeCapabilities, ProjectModel, ResourceLimits, SelectedInput, SourceProviderKind,
|
||||
SourceProviderManifest,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::{json, Value};
|
||||
|
|
@ -678,6 +679,7 @@ struct NodeAttachPlan {
|
|||
node: String,
|
||||
coordinator: Option<String>,
|
||||
capabilities: NodeCapabilities,
|
||||
detection: NodeAttachDetectionEvidence,
|
||||
grant_disclosures: Vec<CapabilityGrantDisclosure>,
|
||||
enrollment: Option<NodeEnrollmentPlan>,
|
||||
}
|
||||
|
|
@ -711,6 +713,32 @@ struct CapabilityGrantDisclosure {
|
|||
coordinator_policy_limited: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
|
||||
struct NodeAttachDetectionEvidence {
|
||||
auto_detected: bool,
|
||||
os: disasmer_core::Os,
|
||||
arch: String,
|
||||
command_backend: String,
|
||||
command_backend_available: bool,
|
||||
container_backend: Option<String>,
|
||||
container_backend_reported: bool,
|
||||
container_backend_available: bool,
|
||||
source_provider_backends: Vec<SourceProviderBackendStatus>,
|
||||
manual_capability_overrides_allowed: bool,
|
||||
manual_capability_overrides: Vec<String>,
|
||||
recognized_capability_overrides: Vec<Capability>,
|
||||
unrecognized_capability_overrides: Vec<String>,
|
||||
os_arch_capabilities_require_manual_flags: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
|
||||
struct SourceProviderBackendStatus {
|
||||
provider: String,
|
||||
detected: bool,
|
||||
available: bool,
|
||||
reason: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
|
||||
struct NodeEnrollmentPlan {
|
||||
grant: String,
|
||||
|
|
@ -2794,6 +2822,12 @@ fn human_report(value: &Value) -> String {
|
|||
}
|
||||
}
|
||||
}
|
||||
if let Some(detection) = value
|
||||
.pointer("/plan/detection")
|
||||
.or_else(|| value.get("detection"))
|
||||
{
|
||||
push_node_attach_detection(&mut lines, detection);
|
||||
}
|
||||
if let Some(disclosures) = value
|
||||
.get("grant_disclosures")
|
||||
.and_then(Value::as_array)
|
||||
|
|
@ -2825,6 +2859,64 @@ fn human_report(value: &Value) -> String {
|
|||
lines.join("\n")
|
||||
}
|
||||
|
||||
fn push_node_attach_detection(lines: &mut Vec<String>, detection: &Value) {
|
||||
push_nested_string_field(lines, detection, "os", "node os");
|
||||
push_nested_string_field(lines, detection, "arch", "node arch");
|
||||
push_nested_string_field(lines, detection, "command_backend", "command backend");
|
||||
if let Some(backend) = detection.get("container_backend").and_then(Value::as_str) {
|
||||
let available = detection
|
||||
.get("container_backend_available")
|
||||
.and_then(Value::as_bool)
|
||||
.unwrap_or(false);
|
||||
lines.push(format!(
|
||||
"container backend: {backend} ({})",
|
||||
if available { "available" } else { "reported" }
|
||||
));
|
||||
} else if detection
|
||||
.get("container_backend_reported")
|
||||
.and_then(Value::as_bool)
|
||||
.unwrap_or(false)
|
||||
{
|
||||
lines.push("container backend: reported".to_owned());
|
||||
}
|
||||
if let Some(providers) = detection
|
||||
.get("source_provider_backends")
|
||||
.and_then(Value::as_array)
|
||||
{
|
||||
let entries = providers
|
||||
.iter()
|
||||
.filter_map(|provider| {
|
||||
let name = provider.get("provider").and_then(Value::as_str)?;
|
||||
let state = if provider
|
||||
.get("available")
|
||||
.and_then(Value::as_bool)
|
||||
.unwrap_or(false)
|
||||
{
|
||||
"available"
|
||||
} else {
|
||||
"detected"
|
||||
};
|
||||
Some(format!("{name}={state}"))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
if !entries.is_empty() {
|
||||
lines.push(format!("source providers: {}", entries.join(", ")));
|
||||
}
|
||||
}
|
||||
if let Some(overrides) = detection
|
||||
.get("manual_capability_overrides")
|
||||
.and_then(Value::as_array)
|
||||
{
|
||||
let overrides = overrides
|
||||
.iter()
|
||||
.filter_map(Value::as_str)
|
||||
.collect::<Vec<_>>();
|
||||
if !overrides.is_empty() {
|
||||
lines.push(format!("capability overrides: {}", overrides.join(", ")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn push_string_field(lines: &mut Vec<String>, value: &Value, key: &str, label: &str) {
|
||||
if let Some(text) = value.get(key).and_then(Value::as_str) {
|
||||
lines.push(format!("{label}: {text}"));
|
||||
|
|
@ -5748,11 +5840,18 @@ fn add_workflow_actor_fields(request: &mut Value, session: &CliSession, fallback
|
|||
|
||||
fn attach_plan(args: AttachArgs) -> NodeAttachPlan {
|
||||
let mut capabilities = NodeCapabilities::detect_current();
|
||||
let mut recognized_capability_overrides = Vec::new();
|
||||
let mut unrecognized_capability_overrides = Vec::new();
|
||||
for cap in &args.caps {
|
||||
if let Some(parsed) = parse_capability(&cap) {
|
||||
recognized_capability_overrides.push(parsed.clone());
|
||||
capabilities.capabilities.insert(parsed);
|
||||
} else {
|
||||
unrecognized_capability_overrides.push(cap.clone());
|
||||
}
|
||||
}
|
||||
recognized_capability_overrides.sort();
|
||||
recognized_capability_overrides.dedup();
|
||||
let node = args.node.unwrap_or_else(default_node_id);
|
||||
let public_key = args
|
||||
.public_key
|
||||
|
|
@ -5762,17 +5861,94 @@ fn attach_plan(args: AttachArgs) -> NodeAttachPlan {
|
|||
public_key_fingerprint: Digest::sha256(public_key),
|
||||
exchanges_short_lived_grant_for_long_lived_node_identity: true,
|
||||
});
|
||||
let detection = node_attach_detection_evidence(
|
||||
&capabilities,
|
||||
args.caps,
|
||||
recognized_capability_overrides,
|
||||
unrecognized_capability_overrides,
|
||||
);
|
||||
let grant_disclosures = capability_grant_disclosures(&capabilities);
|
||||
|
||||
NodeAttachPlan {
|
||||
node,
|
||||
coordinator: args.coordinator,
|
||||
capabilities,
|
||||
detection,
|
||||
grant_disclosures,
|
||||
enrollment,
|
||||
}
|
||||
}
|
||||
|
||||
fn node_attach_detection_evidence(
|
||||
capabilities: &NodeCapabilities,
|
||||
manual_capability_overrides: Vec<String>,
|
||||
recognized_capability_overrides: Vec<Capability>,
|
||||
unrecognized_capability_overrides: Vec<String>,
|
||||
) -> NodeAttachDetectionEvidence {
|
||||
let command_backend_available = capabilities.capabilities.contains(&Capability::Command);
|
||||
let container_backend_reported = capabilities
|
||||
.environment_backends
|
||||
.contains(&EnvironmentBackend::Container);
|
||||
let container_backend = container_backend_reported.then(|| "rootless-podman".to_owned());
|
||||
let container_backend_available = container_backend_reported
|
||||
&& capabilities
|
||||
.capabilities
|
||||
.contains(&Capability::RootlessPodman)
|
||||
&& command_available("podman");
|
||||
|
||||
NodeAttachDetectionEvidence {
|
||||
auto_detected: true,
|
||||
os: capabilities.os.clone(),
|
||||
arch: capabilities.arch.clone(),
|
||||
command_backend: if command_backend_available {
|
||||
"native-command".to_owned()
|
||||
} else {
|
||||
"unavailable".to_owned()
|
||||
},
|
||||
command_backend_available,
|
||||
container_backend,
|
||||
container_backend_reported,
|
||||
container_backend_available,
|
||||
source_provider_backends: source_provider_backend_statuses(capabilities),
|
||||
manual_capability_overrides_allowed: true,
|
||||
manual_capability_overrides,
|
||||
recognized_capability_overrides,
|
||||
unrecognized_capability_overrides,
|
||||
os_arch_capabilities_require_manual_flags: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn source_provider_backend_statuses(
|
||||
capabilities: &NodeCapabilities,
|
||||
) -> Vec<SourceProviderBackendStatus> {
|
||||
let mut statuses = BTreeMap::new();
|
||||
for provider in &capabilities.source_providers {
|
||||
let available = match provider.as_str() {
|
||||
"filesystem" => capabilities
|
||||
.capabilities
|
||||
.contains(&Capability::SourceFilesystem),
|
||||
"git" => command_available("git"),
|
||||
_ => true,
|
||||
};
|
||||
statuses.insert(
|
||||
provider.clone(),
|
||||
SourceProviderBackendStatus {
|
||||
provider: provider.clone(),
|
||||
detected: true,
|
||||
available,
|
||||
reason: if available {
|
||||
"detected by local node capability probe".to_owned()
|
||||
} else {
|
||||
format!(
|
||||
"source provider `{provider}` was detected but its local helper is missing"
|
||||
)
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
statuses.into_values().collect()
|
||||
}
|
||||
|
||||
fn capability_grant_disclosures(capabilities: &NodeCapabilities) -> Vec<CapabilityGrantDisclosure> {
|
||||
let mut disclosures = Vec::new();
|
||||
let mut push = |capability: Capability, grant: &str, description: &str, risk: &str| {
|
||||
|
|
@ -6225,6 +6401,27 @@ mod tests {
|
|||
.capabilities
|
||||
.contains(&Capability::QuicDirect));
|
||||
assert!(!plan.capabilities.arch.is_empty());
|
||||
assert!(plan.detection.auto_detected);
|
||||
assert_eq!(plan.detection.os, plan.capabilities.os);
|
||||
assert_eq!(plan.detection.arch, plan.capabilities.arch);
|
||||
assert_eq!(plan.detection.command_backend, "native-command");
|
||||
assert!(plan.detection.command_backend_available);
|
||||
assert!(plan.detection.manual_capability_overrides_allowed);
|
||||
assert_eq!(
|
||||
plan.detection.manual_capability_overrides,
|
||||
vec!["quic-direct".to_owned()]
|
||||
);
|
||||
assert!(plan
|
||||
.detection
|
||||
.recognized_capability_overrides
|
||||
.contains(&Capability::QuicDirect));
|
||||
assert!(plan.detection.unrecognized_capability_overrides.is_empty());
|
||||
assert!(!plan.detection.os_arch_capabilities_require_manual_flags);
|
||||
assert!(plan
|
||||
.detection
|
||||
.source_provider_backends
|
||||
.iter()
|
||||
.any(|provider| provider.provider == "filesystem" && provider.detected));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue