AkurAI Build
Menu

AkurAI-Build

public

Latest change 8ae29dbf818d2f3a15c678eba2b46f62300ab29f - Preserve non-root cache mount ownership by Ólafur Búi Ólafsson

use std::{fs, path::Path, process::Command};

use anyhow::{Context, Result, ensure};
use serde_json::Value;

#[test]
#[ignore = "run through ./deploy.sh docker-smoke on a Docker host"]
fn restricted_docker_job_produces_verified_artifact() -> Result<()> {
    let temporary = tempfile::tempdir()?;
    let repository = temporary.path().join("repository");
    let data = temporary.path().join("data");
    let key = temporary.path().join("database.key");
    fs::create_dir(&repository)?;
    git(&repository, &["init", "-b", "main"])?;
    git(&repository, &["config", "user.name", "AkurAI Test"])?;
    git(
        &repository,
        &["config", "user.email", "test@example.invalid"],
    )?;
    fs::write(
        repository.join(".akurai.yml"),
        "version: 1\njobs:\n  - name: build\n    image: alpine:3.22\n    cache: [cache]\n    run: mkdir -p out && printf hit > cache/state && printf container > out/artifact.txt\n    artifacts: [out/artifact.txt]\n",
    )?;
    git(&repository, &["add", ".akurai.yml"])?;
    git(&repository, &["commit", "-m", "docker pipeline"])?;

    cli(&data, &key, &["keygen", "--out", path(&key)?])?;
    cli(&data, &key, &["migrate"])?;
    cli(
        &data,
        &key,
        &[
            "repo",
            "add",
            "docker-fixture",
            path(&repository)?,
            "--branch",
            "main",
        ],
    )?;
    let run = cli(&data, &key, &["run", "docker-fixture", "--wait"])?;
    ensure!(
        run["data"]["status"] == "succeeded",
        "Docker run failed: {run}"
    );
    let artifact = &run["data"]["artifacts"][0];
    ensure!(
        artifact["sha256"].as_str().is_some(),
        "artifact digest missing"
    );
    Ok(())
}

fn cli(data: &Path, key: &Path, arguments: &[&str]) -> Result<Value> {
    let output = Command::new(env!("CARGO_BIN_EXE_akurai"))
        .args(["--data", path(data)?, "--key-file", path(key)?])
        .args(arguments)
        .output()?;
    let value: Value = serde_json::from_slice(&output.stdout).with_context(|| {
        format!(
            "invalid CLI JSON: {}",
            String::from_utf8_lossy(&output.stdout)
        )
    })?;
    ensure!(
        output.status.success(),
        "CLI failed: {value}\n{}",
        String::from_utf8_lossy(&output.stderr)
    );
    Ok(value)
}

fn git(directory: &Path, arguments: &[&str]) -> Result<()> {
    let output = Command::new("git")
        .current_dir(directory)
        .args(arguments)
        .output()?;
    ensure!(
        output.status.success(),
        "git failed: {}",
        String::from_utf8_lossy(&output.stderr)
    );
    Ok(())
}

fn path(path: &Path) -> Result<&str> {
    path.to_str().context("test path is not UTF-8")
}