syntax = "proto3";

package image.v1;

option go_package = "github.com/sailresearchco/sail/backend/internal/sailbox/image/pb;pb";

message ImageSpec {
  oneof source {
    BaseImage base = 1;
  }
  repeated ImageBuildStep build_steps = 2;
  map<string, string> env = 3;
  ImageArchitecture architecture = 4;
  // Exact Python version that imagebuilder should install as python3 for
  // Python-dependent build steps and function execution.
  string python_version = 5;
  // ssh is not an image property: openssh-server ships in every base image.
  reserved 6;
  reserved "enable_ssh";
}

enum ImageArchitecture {
  IMAGE_ARCHITECTURE_UNSPECIFIED = 0;
  IMAGE_ARCHITECTURE_AMD64 = 1;
  IMAGE_ARCHITECTURE_ARM64 = 2;
}

enum BaseImage {
  BASE_IMAGE_UNSPECIFIED = 0;
  BASE_IMAGE_DEBIAN = 1;
  // The debian base plus a baked dev layer: node LTS, build-essential, and
  // editor remote-server OS prerequisites. Prebuilt builtin only: it supports
  // no python_version, build steps, or env (use the debian base for custom
  // builds).
  BASE_IMAGE_DEVBOX = 2;
}

enum ImageBuildStatus {
  IMAGE_BUILD_STATUS_UNSPECIFIED = 0;
  IMAGE_BUILD_STATUS_QUEUED = 1;
  IMAGE_BUILD_STATUS_BUILDING = 2;
  IMAGE_BUILD_STATUS_READY = 3;
  IMAGE_BUILD_STATUS_FAILED = 4;
}

message ImageBuildStep {
  oneof step {
    PackageInstall apt_install = 1;
    PackageInstall pip_install = 2;
    RunCommand run_command = 3;
    AddLocalFile add_local_file = 4;
    AddLocalDir add_local_dir = 5;
  }
}

message PackageInstall {
  repeated string packages = 1;
}

message RunCommand {
  string command = 1;
}

// AddLocalFile copies one local file's bytes into the image at remote_path.
// The bytes themselves do not travel through ImageSpec; the SDK uploads them
// to the imagebuilder's content-addressed asset store before BuildImage and
// the worker pulls by sha256 at build time.
message AddLocalFile {
  // Lowercase 64-char hex sha256 of the file contents. Folded into the
  // canonical image spec so a one-byte change to the local file changes
  // the resulting image_id.
  string content_sha256 = 1;
  // Absolute POSIX path inside the rootfs.
  string remote_path = 2;
  // File mode permission bits (low 9 bits, i.e. rwx for owner/group/other).
  // Zero is treated as "unset" because proto3 cannot distinguish absent from
  // 0; the worker substitutes its default (0644) in that case. Setuid /
  // setgid / sticky bits are intentionally not supported.
  uint32 mode = 3;
}

// AddLocalDir copies a tree of local files into the image rooted at
// remote_path. Each file is content-addressed individually (same as
// add_local_file), so per-file dedupe across both step types is automatic.
message AddLocalDir {
  // Absolute POSIX path inside the rootfs where files land.
  // remote_path/relative_path is the final location of each file.
  string remote_path = 1;
  repeated AddLocalDirFile files = 2;
}

message AddLocalDirFile {
  // POSIX-relative path under AddLocalDir.remote_path. No leading "/", no
  // ".." segments, no NUL bytes.
  string relative_path = 1;
  // Lowercase 64-char hex sha256 of the file contents.
  string content_sha256 = 2;
  // File mode permission bits; same convention as AddLocalFile.mode (zero
  // is "unset", worker defaults to 0644).
  uint32 mode = 3;
}
