gloves 0.5.11

seamless secret manager and handoff
Documentation
#[cfg(unix)]
mod unix_tests {
    use assert_cmd::Command;
    use serde_json::Value;
    use std::{
        fs,
        os::unix::fs::PermissionsExt,
        path::{Path, PathBuf},
    };

    fn write_executable(path: &Path, contents: &str) {
        fs::write(path, contents).unwrap();
        let mut permissions = fs::metadata(path).unwrap().permissions();
        permissions.set_mode(0o755);
        fs::set_permissions(path, permissions).unwrap();
    }

    fn write_bridge_config(root: &Path, runtime_root: &Path, docker_bin: &Path) -> PathBuf {
        fs::create_dir_all(runtime_root).unwrap();
        let config_path = runtime_root.join("bridge.toml");
        fs::write(
            &config_path,
            format!(
                r#"
version = 1
gloves_root = "{root}"
runtime_root = "{runtime_root}"
docker_bin = "{docker_bin}"
audit_agent = "openclaw"
secret_mount_root = "/run/secrets"
tmpfs_spec = "/run/secrets:size=2M,mode=0700,noexec,nosuid,nodev"

[[targets]]
secret_ref = "gloves://agents/devy/api-keys/anthropic"
container_path = "/run/secrets/anthropic"

[targets.selector.labels]
"openclaw.agent" = "devy"
"#,
                root = root.display(),
                runtime_root = runtime_root.display(),
                docker_bin = docker_bin.display(),
            ),
        )
        .unwrap();
        config_path
    }

    fn install_fake_docker(fake_docker: &Path, fake_root: &Path) {
        write_executable(
            fake_docker,
            &format!(
                r#"#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'
FAKE_ROOT="{fake_root}"
mkdir -p "${{FAKE_ROOT}}"
printf '%s\n' "$*" >> "${{FAKE_ROOT}}/docker.log"

extract_name() {{
  local previous=""
  for token in "$@"; do
    if [[ "${{previous}}" == "--name" ]]; then
      printf '%s' "${{token}}"
      return 0
    fi
    case "${{token}}" in
      --name=*)
        printf '%s' "${{token#--name=}}"
        return 0
        ;;
    esac
    previous="${{token}}"
  done
  printf 'container-unknown'
}}

subcommand="${{1:-}}"
shift || true
case "${{subcommand}}" in
  create|run)
    name="$(extract_name "$@")"
    mkdir -p "${{FAKE_ROOT}}/containerfs/${{name}}"
    printf 'container-123456\n'
    ;;
  start|stop|rm)
    exit 0
    ;;
  exec)
    if [[ "${{1:-}}" == "-i" ]]; then
      shift
    fi
    container="${{1:?missing container}}"
    shift
    path="${{@: -1}}"
    mkdir -p "${{FAKE_ROOT}}/containerfs/${{container}}$(dirname "${{path}}")"
    cat > "${{FAKE_ROOT}}/containerfs/${{container}}${{path}}"
    chmod 0400 "${{FAKE_ROOT}}/containerfs/${{container}}${{path}}"
    ;;
  *)
    exit 0
    ;;
esac
"#,
                fake_root = fake_root.display(),
            ),
        );
    }

    fn setup_secret_runtime(root: &Path) {
        let root_string = root.to_str().unwrap();
        let gloves_bin = assert_cmd::cargo::cargo_bin!("gloves");
        Command::new(gloves_bin)
            .args(["--root", root_string, "set-identity", "--agent", "devy"])
            .assert()
            .success();
        fs::create_dir_all(root.join("store")).unwrap();
        fs::write(
            root.join("store/.gloves.yaml"),
            "version: 1\ncreation_rules:\n  - path_regex: ^agents/devy/.*$\n    age: []\n",
        )
        .unwrap();
        Command::new(gloves_bin)
            .args([
                "--root",
                root_string,
                "--agent",
                "devy",
                "set",
                "agents/devy/api-keys/anthropic",
                "--value",
                "sk-ant-api03-bridge-test",
            ])
            .assert()
            .success();
    }

    fn bridge_state_path(runtime_root: &Path) -> PathBuf {
        runtime_root.join("docker-bridge/state.json")
    }

    #[test]
    fn docker_bridge_injects_tmpfs_files_on_start_without_leaking_plaintext() {
        let temp = tempfile::tempdir().unwrap();
        let root = temp.path().join("root");
        let runtime_root = temp.path().join("runtime");
        let fake_root = temp.path().join("fake-docker");
        let fake_docker = temp.path().join("docker-real");
        setup_secret_runtime(&root);
        install_fake_docker(&fake_docker, &fake_root);
        let config_path = write_bridge_config(&root, &runtime_root, &fake_docker);

        Command::new(assert_cmd::cargo::cargo_bin!("gloves-docker-bridge"))
            .env("GLOVES_DOCKER_BRIDGE_CONFIG", &config_path)
            .args([
                "create",
                "--name",
                "openclaw-agent-devy",
                "--label",
                "openclaw.agent=devy",
                "ghcr.io/openclaw/agent:latest",
                "sleep",
                "60",
            ])
            .assert()
            .success()
            .stdout(predicates::str::contains("container-123456"));

        Command::new(assert_cmd::cargo::cargo_bin!("gloves-docker-bridge"))
            .env("GLOVES_DOCKER_BRIDGE_CONFIG", &config_path)
            .args(["start", "openclaw-agent-devy"])
            .assert()
            .success();

        let injected_path = fake_root.join("containerfs/openclaw-agent-devy/run/secrets/anthropic");
        let injected_value = fs::read_to_string(&injected_path).unwrap();
        let injected_mode = fs::metadata(&injected_path).unwrap().permissions().mode() & 0o777;
        let docker_log = fs::read_to_string(fake_root.join("docker.log")).unwrap();
        let audit_log = fs::read_to_string(root.join("audit.jsonl")).unwrap();

        assert_eq!(injected_value, "sk-ant-api03-bridge-test");
        assert_eq!(injected_mode, 0o400);
        assert!(docker_log.contains("--tmpfs"));
        assert!(docker_log.contains("/run/secrets:size=2M,mode=0700,noexec,nosuid,nodev"));
        assert!(audit_log.contains("inject_ref"));
        assert!(!audit_log.contains("sk-ant-api03-bridge-test"));
    }

    #[test]
    fn docker_bridge_supports_exec_rechecks_and_cleanup_state() {
        let temp = tempfile::tempdir().unwrap();
        let root = temp.path().join("root");
        let runtime_root = temp.path().join("runtime");
        let fake_root = temp.path().join("fake-docker");
        let fake_docker = temp.path().join("docker-real");
        setup_secret_runtime(&root);
        install_fake_docker(&fake_docker, &fake_root);
        let config_path = write_bridge_config(&root, &runtime_root, &fake_docker);

        Command::new(assert_cmd::cargo::cargo_bin!("gloves-docker-bridge"))
            .env("GLOVES_DOCKER_BRIDGE_CONFIG", &config_path)
            .args([
                "create",
                "--name",
                "openclaw-agent-devy",
                "--label=openclaw.agent=devy",
                "ghcr.io/openclaw/agent:latest",
                "sleep",
                "60",
            ])
            .assert()
            .success();

        Command::new(assert_cmd::cargo::cargo_bin!("gloves-docker-bridge"))
            .env("GLOVES_DOCKER_BRIDGE_CONFIG", &config_path)
            .args([
                "exec",
                "-i",
                "openclaw-agent-devy",
                "/bin/sh",
                "-lc",
                "true",
            ])
            .assert()
            .success();

        let state_before_stop: Value =
            serde_json::from_slice(&fs::read(bridge_state_path(&runtime_root)).unwrap()).unwrap();
        assert_eq!(state_before_stop[0]["injected"], true);

        Command::new(assert_cmd::cargo::cargo_bin!("gloves-docker-bridge"))
            .env("GLOVES_DOCKER_BRIDGE_CONFIG", &config_path)
            .args(["stop", "openclaw-agent-devy"])
            .assert()
            .success();

        let state_after_stop: Value =
            serde_json::from_slice(&fs::read(bridge_state_path(&runtime_root)).unwrap()).unwrap();
        assert_eq!(state_after_stop[0]["injected"], false);

        Command::new(assert_cmd::cargo::cargo_bin!("gloves-docker-bridge"))
            .env("GLOVES_DOCKER_BRIDGE_CONFIG", &config_path)
            .args(["rm", "openclaw-agent-devy"])
            .assert()
            .success();

        let state_after_rm: Value =
            serde_json::from_slice(&fs::read(bridge_state_path(&runtime_root)).unwrap()).unwrap();
        assert_eq!(state_after_rm, Value::Array(vec![]));
    }
}