diff --git a/.forgejo/workflows/gate.yml b/.forgejo/workflows/gate.yml index 1c43ee17d7..15e6ca218e 100644 --- a/.forgejo/workflows/gate.yml +++ b/.forgejo/workflows/gate.yml @@ -12,10 +12,11 @@ jobs: steps: - uses: actions/checkout@v4 with: { fetch-depth: 0 } - - name: forkd microVM CI (zen-gates gate_run) + - name: forkd microVM CI (gate_run) env: - ZEN_GATES_URL: ${{ secrets.ZEN_GATES_URL }} - ZEN_GATES_TOKEN: ${{ secrets.ZEN_GATES_TOKEN }} + FORKD_URL: ${{ secrets.FORKD_URL }} + FORKD_TOKEN: ${{ secrets.FORKD_TOKEN }} + FORKD_SNAPSHOT_TAG: ${{ vars.FORKD_SNAPSHOT_TAG }} run: | if [ -x ./.forgejo/gates/forkd-ci.sh ]; then ./.forgejo/gates/forkd-ci.sh else echo "forkd-ci not yet wired (cal/forkd plane)"; exit 1; fi diff --git a/lib/components/fabro-referee/src/gate.rs b/lib/components/fabro-referee/src/gate.rs index 79f87b9168..3bbaaa517f 100644 --- a/lib/components/fabro-referee/src/gate.rs +++ b/lib/components/fabro-referee/src/gate.rs @@ -71,7 +71,7 @@ pub enum BackendKind { impl BackendKind { pub fn from_str_loose(s: &str) -> Option { match s.to_ascii_lowercase().as_str() { - "forkd" | "controller" | "zen-gates" => Some(Self::Forkd), + "forkd" | "controller" => Some(Self::Forkd), "hermetic" | "local" | "fallback" => Some(Self::Hermetic), "fake" | "test" | "mock" => Some(Self::Fake), _ => None, diff --git a/lib/components/fabro-referee/src/gate/backend.rs b/lib/components/fabro-referee/src/gate/backend.rs index 1688d69080..fab9ef704b 100644 --- a/lib/components/fabro-referee/src/gate/backend.rs +++ b/lib/components/fabro-referee/src/gate/backend.rs @@ -21,7 +21,42 @@ use tracing::{info, warn}; use super::{GateBackend, GateOutput}; use crate::types::{Acceptance, TaskSpec, Verdict}; -const FORKD_TOKEN_FILE: &str = "/home/vvladescu/fabro-run/.forkd-token"; +/// Default forkd token file path. Used only when the `FORKD_TOKEN_FILE` +/// env var is unset or empty. Keep this a generic, non-host-specific +/// example; operators must override it for their deployment. +const FORKD_TOKEN_FILE_DEFAULT: &str = "/etc/forkd/token"; + +/// Default forkd snapshot tag. Used only when the `FORKD_SNAPSHOT_TAG` +/// env var is unset or empty. Keep this a generic, non-host-specific +/// example; the value here is the example the public spec uses. +const FORKD_SNAPSHOT_TAG_DEFAULT: &str = "forkd-base"; + +/// Resolve the path to the forkd bearer-token file. The operator can +/// override the default with the `FORKD_TOKEN_FILE` env var. The +/// returned path is the one [`forkd_token`] will read. +#[expect( + clippy::disallowed_methods, + reason = "sync scorer binary: one-shot environment lookup for the token-file path" +)] +pub fn forkd_token_file() -> std::path::PathBuf { + match std::env::var("FORKD_TOKEN_FILE") { + Ok(value) if !value.trim().is_empty() => std::path::PathBuf::from(value.trim()), + _ => std::path::PathBuf::from(FORKD_TOKEN_FILE_DEFAULT), + } +} + +/// Resolve the default forkd snapshot tag. The operator can override +/// the default with the `FORKD_SNAPSHOT_TAG` env var. +#[expect( + clippy::disallowed_methods, + reason = "sync scorer binary: one-shot environment lookup for the default snapshot tag" +)] +pub fn forkd_snapshot_tag() -> String { + match std::env::var("FORKD_SNAPSHOT_TAG") { + Ok(value) if !value.trim().is_empty() => value.trim().to_string(), + _ => FORKD_SNAPSHOT_TAG_DEFAULT.to_string(), + } +} /// Resolve the forkd bearer token without exposing its value in errors/logs. #[expect( @@ -36,7 +71,8 @@ pub fn forkd_token() -> Result { } } - match std::fs::read_to_string(FORKD_TOKEN_FILE) { + let token_path = forkd_token_file(); + match std::fs::read_to_string(&token_path) { Ok(contents) => { let token = contents.trim().to_string(); if !token.is_empty() { @@ -45,18 +81,19 @@ pub fn forkd_token() -> Result { } Err(error) if error.kind() == std::io::ErrorKind::NotFound => {} Err(error) => { - return Err(error).with_context(|| format!("read forkd token file {FORKD_TOKEN_FILE}")); + return Err(error).with_context(|| format!("read forkd token file {}", token_path.display())); } } - bail!("forkd token unavailable: set FORKD_TOKEN or provide {FORKD_TOKEN_FILE}") + bail!("forkd token unavailable: set FORKD_TOKEN or provide {}", token_path.display()) } /// The real forkd controller at `forkd.internal.example:8891`. The scorer only uses the -/// existing score/read path: it creates a `zen-gate-base` sandbox, executes -/// the apply-and-acceptance pipeline, and deletes that sandbox. It never -/// activates, reconfigures, restarts, or re-baselines the controller or its -/// golden rootfs. +/// existing score/read path: it creates a snapshot from the configured +/// tag (env `FORKD_SNAPSHOT_TAG`, default "forkd-base"), executes the +/// apply-and-acceptance pipeline, and deletes that sandbox. It never +/// activates, reconfigures, restarts, or re-baselines the controller or +/// its golden rootfs. pub struct ForkdController { /// The controller endpoint, e.g. `http://forkd.internal.example:8891`. endpoint: String, @@ -101,7 +138,7 @@ impl GateBackend for ForkdController { // 1. create a sandbox from the golden snapshot. let create = auth(self.client.post(format!("{base}/v1/sandboxes"))) - .json(&serde_json::json!({ "snapshot_tag": "zen-gate-base" })) + .json(&serde_json::json!({ "snapshot_tag": forkd_snapshot_tag() })) .send() .with_context(|| format!("forkd create sandbox @ {base}"))?; let cstatus = create.status(); diff --git a/lib/components/fabro-sandbox/src/config.rs b/lib/components/fabro-sandbox/src/config.rs index 864d2a8ff1..c44980d03a 100644 --- a/lib/components/fabro-sandbox/src/config.rs +++ b/lib/components/fabro-sandbox/src/config.rs @@ -161,8 +161,9 @@ pub enum ForkdNetwork { #[cfg(feature = "forkd")] #[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] pub struct ForkdSettings { - /// forkd snapshot tag to boot from (e.g. `"zen-gate-base"`). - /// Resolved from `FORKD_SNAPSHOT_TAG` env var; default `"zen-gate-base"`. + /// forkd snapshot tag to boot from (e.g. `"forkd-base"`). + /// Resolved from `FORKD_SNAPSHOT_TAG` env var; default + /// `"forkd-base"` (see [`crate::forkd::DEFAULT_SNAPSHOT_TAG`]). #[serde(default = "ForkdSettings::default_snapshot_tag")] pub snapshot_tag: String, /// Legacy VM image/kernel/memory settings — retained for deserialization diff --git a/lib/components/fabro-sandbox/src/forkd/mod.rs b/lib/components/fabro-sandbox/src/forkd/mod.rs index 26944cb82e..3fc3db4d8b 100644 --- a/lib/components/fabro-sandbox/src/forkd/mod.rs +++ b/lib/components/fabro-sandbox/src/forkd/mod.rs @@ -37,7 +37,9 @@ pub(crate) const REPOS_ROOT: &str = "/home/fabro/repos"; const PROVIDER: &str = "forkd"; /// Default snapshot tag used when `FORKD_SNAPSHOT_TAG` is not set. -pub const DEFAULT_SNAPSHOT_TAG: &str = "zen-gate-base"; +/// Generic, non-host-specific example value; operators override via +/// the `FORKD_SNAPSHOT_TAG` env var or per-sandbox `ForkdSettings`. +pub const DEFAULT_SNAPSHOT_TAG: &str = "forkd-base"; /// Maximum number of retry attempts for transient HTTP failures (5xx / /// connect). diff --git a/specs/forkd-e2e/behavior.feature b/specs/forkd-e2e/behavior.feature index 9cdf7609d6..d2c5565516 100644 --- a/specs/forkd-e2e/behavior.feature +++ b/specs/forkd-e2e/behavior.feature @@ -7,8 +7,8 @@ Feature: forkd end-to-end capability @task-create-sandbox Scenario: creating a sandbox from a snapshot tag returns a server-assigned id Given the forkd service is reachable - And a snapshot tag "zen-gate-base" exists in the snapshot registry - When I send a create-sandbox request with snapshot_tag "zen-gate-base" + And a snapshot tag "forkd-base" exists in the snapshot registry + When I send a create-sandbox request with snapshot_tag "forkd-base" Then the response status is 201 And the response body contains a non-empty "id" field And the returned id matches the pattern "[a-f0-9-]{36}" @@ -54,8 +54,8 @@ Feature: forkd end-to-end capability @task-real-workflow Scenario: a real workflow executing git clone and running a command completes inside the microVM Given the forkd service is reachable - And a snapshot tag "zen-gate-base" exists in the snapshot registry - When I create a sandbox from snapshot_tag "zen-gate-base" and store its id as "wf_sandbox_id" + And a snapshot tag "forkd-base" exists in the snapshot registry + When I create a sandbox from snapshot_tag "forkd-base" and store its id as "wf_sandbox_id" And I exec in sandbox "wf_sandbox_id" with argv ["git", "clone", "--depth", "1", "https://github.com/nicowillis/hello-world.git", "/tmp/repo"] Then the exec response exit_code is 0 And the sandbox filesystem path "/tmp/repo" exists