Skip to main content

Client

Struct Client 

Source
pub struct Client { /* private fields */ }
Expand description

Performs Agentknock operations using one local pairing.

A client stores only application identity and the location of its local state. It can be cloned and reused for concurrent operations; pairing-file updates are synchronized between clients and processes.

Implementations§

Source§

impl Client

Source

pub fn new(application_info: ApplicationInfo) -> Self

Creates a client that uses the user’s shared Agentknock state.

The state directory is $HOME/.agentknock. If HOME isn’t set, operations that need local state return ConfigurationError::HomeNotSet.

Source

pub fn new_in( application_info: ApplicationInfo, state_directory: impl Into<PathBuf>, ) -> Self

Creates a client that stores its state in state_directory.

Use this constructor only when an application needs a pairing isolated from the user’s default Agentknock pairing. Agentknock stores the pairing in pairing.json inside this directory.

Source

pub fn pairing_status(&self) -> Result<PairingStatus, ConfigurationError>

Returns the state of the pairing stored on this client.

This method reads only local state. It doesn’t contact the relay or device, so PairingStatus::Active doesn’t confirm that the device still accepts the pairing. A missing pairing file returns PairingStatus::NotPaired; an unreadable, insecure, or malformed file returns a ConfigurationError.

§Errors

Returns ConfigurationError if the state directory can’t be located or the pairing file can’t be read and validated safely.

§Examples
use agentknock::{ApplicationInfo, Client, PairingStatus};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = Client::new(ApplicationInfo::new("my-application", "1.0.0"));

    match client.pairing_status()? {
        PairingStatus::NotPaired => println!("not paired"),
        PairingStatus::Pending => println!("pairing is pending"),
        PairingStatus::Active => println!("pairing is active"),
        _ => println!("pairing has an unknown status"),
    }

    Ok(())
}
Source§

impl Client

Source

pub async fn request_git_signature<P>( &self, request: GitSignRequest<'_>, cancellation: impl Future<Output = ()>, progress: P, ) -> Result<String, RequestError>

Requests a Git signature from a secret selected for an invocation.

The device makes a separate decision for each signature. The request includes the exact bytes that Git asks the signing program to sign. SSH-backed secrets use the SSHSIG git namespace.

§Errors

Returns RequestError if local pairing state isn’t active, the relay exchange fails, the device denies the signature, the response is invalid, or the operation is canceled.

Source§

impl Client

Source

pub async fn start_pairing<P>( &self, address: &str, cancellation: impl Future<Output = ()>, progress: P, ) -> Result<PairingSas, RequestError>

Starts pairing with the device displaying address.

address must contain one or more lowercase ASCII words separated by single hyphens. The method creates a pending local pairing and returns the PairingSas after the initial exchange is complete. The pairing remains pending until Client::finish_pairing succeeds.

The progress callback receives lifecycle updates synchronously and should return promptly. If cancellation resolves before the method returns, Agentknock stops the exchange, removes any pending state it created, and returns RequestError::Interrupted. Pass std::future::pending() when the operation doesn’t need cancellation.

§Errors

Returns an error if the address is invalid, local pairing state already exists, the state can’t be read or written safely, the exchange fails, or the operation is canceled.

Source§

impl Client

Source

pub async fn finish_pairing<P>( &self, cancellation: impl Future<Output = ()>, progress: P, ) -> Result<(), RequestError>

Activates the pending pairing after the user verifies and accepts it.

Call this only after the user confirms the complete PairingSas on the device and accepts the pairing there. Agentknock requires an authenticated acceptance response before it marks the local pairing as active.

The progress callback receives lifecycle updates synchronously and should return promptly. Cancellation before authenticated acceptance leaves the pairing pending and returns RequestError::Interrupted. Once acceptance is authenticated and local activation is durable, the pairing remains active even if the completion handoff fails. Cancellation after activation only shortens that handoff and doesn’t undo or report failure. Pass std::future::pending() when the operation doesn’t need cancellation.

§Errors

Returns an error if there is no pending pairing, local state is invalid, the device rejects the pairing, the operation is canceled before activation, or the exchange fails. An exchange error during completion can be returned after the local pairing becomes active.

Source

pub fn abort_pairing(&self) -> Result<(), ConfigurationError>

Deletes a pending local pairing without contacting the device.

Use this after the user rejects or abandons an initial pairing. This method refuses to delete an active pairing.

§Errors

Returns ConfigurationError::NoPairing if no pairing exists, ConfigurationError::PairingNotPending if the pairing is active, or another configuration error if the pending state can’t be removed.

Source

pub fn force_remove_pairing(&self) -> Result<(), ConfigurationError>

Deletes the local pairing without contacting the device.

This is a recovery operation for state that can’t be removed through Client::remove_pairing. It can delete either a pending or an active pairing, and it leaves any corresponding device state unchanged.

§Errors

Returns a configuration error if no local pairing exists or the pairing file can’t be removed.

Source

pub async fn remove_pairing<P>( &self, cancellation: impl Future<Output = ()>, progress: P, ) -> Result<(), PairingRemoveError>

Removes an active pairing from both the device and this client.

Agentknock waits for an authenticated device response before deleting local state. It then hands off a best-effort completion to tell the device that local removal succeeded.

The progress callback receives lifecycle updates synchronously and should return promptly. Cancellation before the authenticated response leaves local state unchanged. Cancellation after local removal only shortens the best-effort completion attempt. Pass std::future::pending() when the operation doesn’t need cancellation.

§Errors

Returns PairingRemoveError if the pairing isn’t active, the exchange fails before authenticated removal, or local deletion fails.

Source§

impl Client

Source

pub async fn request_secret_use<P>( &self, request: SecretUseRequest<'_>, cancellation: impl Future<Output = ()>, progress: P, ) -> Result<SecretUseOutput, RequestError>

Requests selected secrets for an invocation.

The authenticated response must contain exactly the requested secret names. Environment values are returned directly. An SSH secret returns its public key and authorization for related operations. If multiple secrets provide the same environment variable, their values must be identical. The response can contain at most one SSH secret. Otherwise, the method sends an aborted completion and returns an error.

The progress callback receives lifecycle updates synchronously and should return promptly. If cancellation resolves before a response is returned, Agentknock sends a best-effort aborted completion when the request was sent and returns RequestError::Interrupted. Cancellation after a response prevents approved values from being returned. Pass std::future::pending() when the operation doesn’t need cancellation.

§Errors

Returns RequestError if local pairing state isn’t active, the relay exchange fails, the device denies the request, the response is invalid, or the operation is canceled.

§Examples
use std::{collections::BTreeSet, future};

use agentknock::{
    Client, ExecutableMode, RequestError, SecretUseOperation, SecretUseRequest,
    StreamKind,
};

let secrets = BTreeSet::from(["github".to_owned()]);
let arguments = ["issue".to_owned(), "list".to_owned()];
let launcher_chain = ["/usr/bin/bash".to_owned()];
let request = SecretUseRequest {
    secrets: &secrets,
    operation: SecretUseOperation::Exec {
        command: "gh",
        arguments: &arguments,
        working_directory: "/work/project",
        executable_path: "/usr/bin/gh",
        executable_hash: None,
        executable_mode: ExecutableMode::Binary,
        stdin: StreamKind::Terminal,
        stdout: StreamKind::Terminal,
        stderr: StreamKind::Terminal,
    },
    reason: Some("Review open issues"),
    launcher_chain: &launcher_chain,
};

let output = client
    .request_secret_use(request, future::pending(), |_| {})
    .await?;
let environment = output.into_environment();
Source§

impl Client

Source

pub async fn list_secrets<P>( &self, cancellation: impl Future<Output = ()>, progress: P, ) -> Result<Secrets, RequestError>

Lists metadata for secrets available from the paired device.

The returned Secrets includes names, types, descriptions, and the names of values each secret provides. It never includes secret values.

The progress callback receives lifecycle updates synchronously and should return promptly. Cancellation before an authenticated response returns RequestError::Interrupted. After a response is authenticated, cancellation only shortens the best-effort completion handoff and the method still returns the decoded list. Pass std::future::pending() when the operation doesn’t need cancellation.

§Errors

Returns RequestError if local pairing state isn’t active, the relay exchange fails, the response is invalid, or the operation is canceled before a response is authenticated.

Source

pub async fn upload_secret<P>( &self, secret: &SecretUpload, mode: SecretUploadMode, cancellation: impl Future<Output = ()>, progress: P, ) -> Result<(), SecretUploadError>

Uploads a secret for review on the device.

Success means that the device received and stored the upload proposal. It doesn’t mean that the user accepted the proposal or that the secret is available for use. Upload mode controls how a later acceptance would change device state.

The progress callback receives lifecycle updates synchronously and should return promptly. Cancellation before an authenticated response returns RequestError::Interrupted through SecretUploadError. After a response is authenticated, cancellation only shortens the best-effort completion handoff and the method still returns the device’s result. Pass std::future::pending() when the operation doesn’t need cancellation.

§Errors

Returns SecretUploadError if local pairing state isn’t active, the relay exchange fails, the device rejects the proposal, the response is invalid, or the operation is canceled before a response is authenticated.

Trait Implementations§

Source§

impl Clone for Client

Source§

fn clone(&self) -> Client

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Client

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.