Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 46 additions & 7 deletions .github/workflows/ci_rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,28 @@ jobs:
cache-bin: false
save-if: false

- uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8
with:
version: ${{ steps.ci-config.outputs.uv_version }}

- uses: taiki-e/install-action@c070f87102a1c75b3183910f391c1cb887fe13c8 # v2.77.6
with:
tool: just@${{ steps.ci-config.outputs.just_version }}

- name: Set CLI binary version
working-directory: ${{ env.NEMO_RELAY_CI_WORKSPACE }}
env:
REF_NAME: ${{ github.ref_name }}
REF_TYPE: ${{ github.ref_type }}
run: |
set -euo pipefail
version="$REF_NAME"
if [[ "$REF_TYPE" != "tag" ]]; then
version="$(sed -n 's/^version = "\(.*\)"$/\1/p' Cargo.toml | head -n1)+${GIT_COMMIT::8}"
fi
just set-cargo-version "$version"
printf 'NEMO_RELAY_CLI_PACKAGE_VERSION=%s\n' "$version" >> "$GITHUB_ENV"

- name: Install musl tools
if: ${{ startsWith(matrix.target, 'x86_64-unknown-linux-musl') || startsWith(matrix.target, 'aarch64-unknown-linux-musl') }}
run: |
Expand Down Expand Up @@ -300,8 +322,17 @@ jobs:
docker run --rm \
--volume "${{ env.NEMO_RELAY_CI_WORKSPACE }}:${{ env.NEMO_RELAY_CI_WORKSPACE }}" \
--workdir "${{ env.NEMO_RELAY_CI_WORKSPACE }}" \
--env NEMO_RELAY_CI_WORKSPACE \
--env NEMO_RELAY_CLI_PACKAGE_VERSION \
"${{ matrix.runtime_image }}" \
"${{ env.NEMO_RELAY_CI_WORKSPACE }}/target/${{ matrix.target }}/release/nemo-relay" --version
/bin/sh -ec '
actual="$("$NEMO_RELAY_CI_WORKSPACE/target/${{ matrix.target }}/release/nemo-relay" --version)"
Comment thread
willkill07 marked this conversation as resolved.
expected="nemo-relay $NEMO_RELAY_CLI_PACKAGE_VERSION"
if [ "$actual" != "$expected" ]; then
echo "Error: expected CLI version \"$expected\", got \"$actual\"" >&2
exit 1
fi
'

- name: Stage CLI binary artifact
working-directory: ${{ env.NEMO_RELAY_CI_WORKSPACE }}
Expand Down Expand Up @@ -337,10 +368,7 @@ jobs:
binary="${binary}.exe"
fi
source="${NEMO_RELAY_CI_WORKSPACE}/target/${target}/release/${binary}"
version="${{ github.ref_name }}"
if [ "${{ github.ref_type }}" != "tag" ]; then
version="$(sed -n 's/^version = "\(.*\)"$/\1/p' Cargo.toml | head -n1)+${GIT_COMMIT::8}"
fi
version="$NEMO_RELAY_CLI_PACKAGE_VERSION"
rm -rf "${NEMO_RELAY_CI_WORKSPACE_TMP}/cli-packages"
mkdir -p "${NEMO_RELAY_CI_WORKSPACE_TMP}/cli-packages"
args=(
Expand Down Expand Up @@ -369,7 +397,12 @@ jobs:
venv_cli="${NEMO_RELAY_CI_WORKSPACE_TMP}/cli-wheel-venv/bin/nemo-relay"
fi
"$venv_python" -m pip install --force-reinstall --no-deps "${wheels[0]}"
"$venv_cli" --version
actual="$("$venv_cli" --version)"
expected="nemo-relay $NEMO_RELAY_CLI_PACKAGE_VERSION"
if [[ "$actual" != "$expected" ]]; then
echo "Error: expected CLI version '$expected', got '$actual'" >&2
exit 1
fi

- name: Install and run CLI wheel on musllinux
if: ${{ endsWith(matrix.target, '-musl') }}
Expand All @@ -380,13 +413,19 @@ jobs:
--volume "${{ env.NEMO_RELAY_CI_WORKSPACE }}:${{ env.NEMO_RELAY_CI_WORKSPACE }}" \
--workdir "${{ env.NEMO_RELAY_CI_WORKSPACE }}" \
--env NEMO_RELAY_CI_WORKSPACE_TMP \
--env NEMO_RELAY_CLI_PACKAGE_VERSION \
"${{ matrix.runtime_image }}" \
/bin/sh -ec '
wheel="$(find "$NEMO_RELAY_CI_WORKSPACE_TMP/cli-packages" -maxdepth 1 -name "*.whl" -print -quit)"
test -n "$wheel"
/opt/python/cp311-cp311/bin/python -m venv /tmp/nemo-relay-cli-wheel-venv
/tmp/nemo-relay-cli-wheel-venv/bin/python -m pip install --force-reinstall --no-deps "$wheel"
/tmp/nemo-relay-cli-wheel-venv/bin/nemo-relay --version
actual="$(/tmp/nemo-relay-cli-wheel-venv/bin/nemo-relay --version)"
expected="nemo-relay $NEMO_RELAY_CLI_PACKAGE_VERSION"
if [ "$actual" != "$expected" ]; then
echo "Error: expected CLI version \"$expected\", got \"$actual\"" >&2
exit 1
fi
'

- name: Upload CLI binary artifact
Expand Down
2 changes: 1 addition & 1 deletion crates/cli/src/bootstrap/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ use state::{BOOTSTRAP_STATE_DIR_ENV, state_dir as bootstrap_state_dir};
pub(crate) const DEFAULT_BIND: &str = "127.0.0.1:47632";
pub(crate) const DEFAULT_URL: &str = "http://127.0.0.1:47632";
pub(crate) const HEALTHZ_TIMEOUT: Duration = Duration::from_millis(500);
pub(crate) const BOOTSTRAP_PROTOCOL_VERSION: u64 = 2;
pub(crate) const BOOTSTRAP_PROTOCOL_VERSION: u64 = 3;

pub(super) const BOOTSTRAP_LOCK_TIMEOUT: Duration = Duration::from_secs(20);
const BOOTSTRAP_START_TIMEOUT: Duration = Duration::from_secs(10);
Expand Down
23 changes: 14 additions & 9 deletions crates/cli/tests/cli_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ fn gateway_bin() -> &'static str {
}

const ACTIVE_GENERATION_TOKEN: &str = "active-generation";
const BOOTSTRAP_PROTOCOL_VERSION: u64 = 3;
const SIDECAR_PUBLICATION_TIMEOUT: Duration = Duration::from_secs(30);

fn write_active_generation(temp: &std::path::Path) -> std::path::PathBuf {
Expand Down Expand Up @@ -639,8 +640,9 @@ fn cli_mcp_starts_gateway_even_when_stdio_closes_before_request() {
fn cli_mcp_rejects_an_unauthenticated_transparent_gateway() {
let temp = tempfile::tempdir().unwrap();
let body = format!(
r#"{{"status":"ok","service":"nemo-relay","version":"{}","bootstrap_protocol":2,"instance_id":"transparent"}}"#,
env!("CARGO_PKG_VERSION")
r#"{{"status":"ok","service":"nemo-relay","version":"{}","bootstrap_protocol":{},"instance_id":"transparent"}}"#,
env!("CARGO_PKG_VERSION"),
BOOTSTRAP_PROTOCOL_VERSION,
);
let (gateway_url, received) = spawn_single_request_server(200, &body);
let mut child = Command::new(gateway_bin())
Expand Down Expand Up @@ -1127,8 +1129,9 @@ fn write_fake_bootstrap_health(
let nonce = bootstrap_request_header(request, "x-nemo-relay-bootstrap-nonce").unwrap();
let proof_header = fake_bootstrap_proof_header(proof, key_path, fingerprint, nonce);
let body = format!(
r#"{{"status":"ok","service":"nemo-relay","version":"{}","bootstrap_protocol":2,"instance_id":"test-instance"}}"#,
env!("CARGO_PKG_VERSION")
r#"{{"status":"ok","service":"nemo-relay","version":"{}","bootstrap_protocol":{},"instance_id":"test-instance"}}"#,
env!("CARGO_PKG_VERSION"),
BOOTSTRAP_PROTOCOL_VERSION,
);
stream
.write_all(
Expand Down Expand Up @@ -1171,8 +1174,9 @@ fn handle_fake_bootstrap_tunnel(
let health = read_http_request(&mut stream);
requests.lock().unwrap().push(health);
let body = format!(
r#"{{"status":"ok","service":"nemo-relay","version":"{}","bootstrap_protocol":2,"instance_id":"test-instance"}}"#,
env!("CARGO_PKG_VERSION")
r#"{{"status":"ok","service":"nemo-relay","version":"{}","bootstrap_protocol":{},"instance_id":"test-instance"}}"#,
env!("CARGO_PKG_VERSION"),
BOOTSTRAP_PROTOCOL_VERSION,
);
stream
.write_all(
Expand Down Expand Up @@ -1635,7 +1639,7 @@ fn cli_mcp_clients_share_gateway_until_final_idle_shutdown() {
let health = relay_health(address);
assert_eq!(health["service"], "nemo-relay");
assert_eq!(health["version"], env!("CARGO_PKG_VERSION"));
assert_eq!(health["bootstrap_protocol"], 2);
assert_eq!(health["bootstrap_protocol"], BOOTSTRAP_PROTOCOL_VERSION);
assert!(
health["instance_id"]
.as_str()
Expand Down Expand Up @@ -4500,8 +4504,9 @@ fn write_phase_health_response(
.ok_or_else(|| "health probe omitted its nonce".to_string())?;
let proof = fake_bootstrap_proof(key, fingerprint, nonce);
let body = format!(
r#"{{"status":"ok","service":"nemo-relay","version":"{}","bootstrap_protocol":2,"instance_id":"phase-health"}}"#,
env!("CARGO_PKG_VERSION")
r#"{{"status":"ok","service":"nemo-relay","version":"{}","bootstrap_protocol":{},"instance_id":"phase-health"}}"#,
env!("CARGO_PKG_VERSION"),
BOOTSTRAP_PROTOCOL_VERSION,
);
stream
.write_all(
Expand Down
18 changes: 11 additions & 7 deletions crates/cli/tests/coverage/shared/bootstrap_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,17 +88,21 @@ fn compatible_gateway_is_reused_without_starting_another_process() {
#[test]
fn foreign_and_incompatible_listeners_are_never_adopted() {
crate::test_support::enable_operational_logs();
let incompatible = format!(
"{{\"status\":\"incompatible\",\"service\":\"nemo-relay\",\"version\":\"other\",\"bootstrap_protocol\":{BOOTSTRAP_PROTOCOL_VERSION},\"instance_id\":\"other\"}}"
);
let previous_protocol = format!(
"{{\"status\":\"ok\",\"service\":\"nemo-relay\",\"version\":\"{}\",\"bootstrap_protocol\":{},\"instance_id\":\"previous\"}}",
env!("CARGO_PKG_VERSION"),
BOOTSTRAP_PROTOCOL_VERSION - 1,
);
for (status, body, expected) in [
("200 OK", "{}", "not a compatible"),
(
"409 Conflict",
"{\"status\":\"incompatible\",\"service\":\"nemo-relay\",\"version\":\"other\",\"bootstrap_protocol\":2,\"instance_id\":\"other\"}",
"different version",
),
("200 OK", "{}".to_string(), "not a compatible"),
("409 Conflict", incompatible, "different version"),
("200 OK", previous_protocol, "not a compatible"),
] {
let listener = TcpListener::bind("127.0.0.1:0").unwrap();
let address = listener.local_addr().unwrap();
let body = body.to_string();
listener.set_nonblocking(true).unwrap();
let (stop_tx, stop_rx) = std::sync::mpsc::channel();
let server = std::thread::spawn(move || {
Expand Down
29 changes: 27 additions & 2 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -453,8 +453,17 @@ import sys
version = sys.argv[1]
if version.startswith("v"):
raise SystemExit("Release tags must not start with 'v'; use raw SemVer such as 0.1.0")
if not re.fullmatch(r"\d+\.\d+\.\d+(?:-(?:alpha|beta|rc)\.\d+)?", version):
raise SystemExit(f"Unsupported release tag '{version}'; use 0.1.0 or prereleases like 0.1.0-rc.1")
numeric_identifier = r"(?:0|[1-9][0-9]*)"
if not re.fullmatch(
rf"{numeric_identifier}\.{numeric_identifier}\.{numeric_identifier}"
rf"(?:-(?:alpha|beta|rc)\.{numeric_identifier})?"
r"(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?",
version,
):
raise SystemExit(
f"Unsupported Cargo version '{version}'; use 0.1.0, prereleases like "
"0.1.0-rc.1, or build metadata like 0.1.0+deadbeef"
)
Comment thread
willkill07 marked this conversation as resolved.

path = Path("Cargo.toml")
text = path.read_text()
Expand Down Expand Up @@ -1485,6 +1494,22 @@ set-version version="":
cd "$NEMO_RELAY_REPO_ROOT"
set_project_version "$version"

# Set only the Cargo workspace version for release artifact builds.
# [version] or --set ref_name=<version>
set-cargo-version version="":
#!/usr/bin/env bash
{{ bash_helpers }}
version="{{ version }}"
if [[ -z "$version" ]]; then
version="{{ ref_name }}"
fi
if [[ -z "$version" ]]; then
echo "Error: version is required for set-cargo-version" >&2
exit 1
fi
cd "$NEMO_RELAY_REPO_ROOT"
set_cargo_workspace_version "$version"

# --set [output_dir=<path>] [ref_name=<name>]
package-rust:
#!/usr/bin/env bash
Expand Down
Loading