#![allow(
clippy::todo,
clippy::unimplemented,
clippy::panic,
clippy::unwrap_used,
clippy::expect_used,
clippy::missing_errors_doc,
clippy::missing_panics_doc,
clippy::doc_markdown,
clippy::needless_pass_by_value,
clippy::too_many_arguments,
clippy::unused_async,
clippy::diverging_sub_expression,
clippy::no_effect_underscore_binding,
clippy::let_unit_value,
clippy::used_underscore_binding,
clippy::let_underscore_untyped,
clippy::struct_field_names,
clippy::manual_let_else,
clippy::map_unwrap_or,
clippy::redundant_pub_crate,
dead_code,
unreachable_code,
unused_assignments,
unused_mut,
unused_imports,
unused_variables
)]
use std::env;
use arcp::error::ARCPError;
use arcp::transport::MemoryTransport;
use arcp::ARCPClient;
use serde_json::json;
type Client = ARCPClient<MemoryTransport>;
async fn submit_fetcher(
_client: &Client,
_allowed_urls: &[&str],
) -> Result<(String, String), ARCPError> {
todo!()
}
async fn agent_fetch(_client: &Client, _job_id: &str, _url: &str) -> Result<String, ARCPError> {
todo!()
}
async fn await_revoked_event(_client: &Client, _lease_id: &str) -> Result<String, ARCPError> {
todo!()
}
async fn scenario_normal(client: &Client) -> Result<(), ARCPError> {
let allowed = &["https://example.com/**"];
let (job_id, lease_id) = submit_fetcher(client, allowed).await?;
println!("[normal] job={job_id} lease={lease_id}");
let body = agent_fetch(client, &job_id, "https://example.com/index.html").await?;
println!("[normal] fetch succeeded, len={}", body.len());
Ok(())
}
async fn scenario_over_reach(client: &Client) -> Result<(), ARCPError> {
let allowed = &["https://example.com/**"];
let (job_id, lease_id) = submit_fetcher(client, allowed).await?;
println!("[over-reach] job={job_id} lease={lease_id}");
let result = agent_fetch(client, &job_id, "https://evil.example.net/data").await;
match result {
Err(ARCPError::LeaseSubsetViolation { .. }) => {
let reason = await_revoked_event(client, &lease_id).await?;
println!("[over-reach] lease revoked with reason={reason} — expected");
}
other => {
return Err(ARCPError::Unknown {
detail: format!("expected LeaseSubsetViolation but got {other:?}"),
});
}
}
Ok(())
}
async fn scenario_expired_lease(client: &Client) -> Result<(), ARCPError> {
let allowed = &["https://example.com/**"];
let (job_id, lease_id) = submit_fetcher(client, allowed).await?;
tokio::time::sleep(std::time::Duration::from_secs(2)).await;
let result = agent_fetch(client, &job_id, "https://example.com/data").await;
match result {
Err(ARCPError::LeaseExpired { .. }) => {
println!("[expired] access after expiry rejected — expected");
}
other => eprintln!("[expired] unexpected outcome: {other:?}"),
}
Ok(())
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client: Client = todo!();
match env::args().nth(1).as_deref().unwrap_or("normal") {
"normal" => scenario_normal(&client).await?,
"over-reach" | "over_reach" => scenario_over_reach(&client).await?,
"expired" => scenario_expired_lease(&client).await?,
other => {
eprintln!("unknown scenario: {other} (normal|over-reach|expired)");
std::process::exit(2);
}
}
println!("done");
Ok(())
}