From 04fea0e412ce6908e3650e9bd5d5d77a2b999362 Mon Sep 17 00:00:00 2001 From: chrischeng-c4 Date: Sat, 24 Oct 2026 00:05:51 +0800 Subject: [PATCH] test(operator): gate committed crd.yaml against generator and run in CI (#14) - Assert that committed k8s/operator/crd.yaml is byte-equal to keep::operator::crd_yaml() with trailing-newline normalization in crates/keep/tests/operator.rs - Name exact regeneration command in assertion failure message - Regenerate k8s/operator/crd.yaml with measured drift (evictionPolicy, maxDiskBytes, maxmemory, spillThresholdBytes) - Run cargo test -p keep --features operator --test operator in keep-ci.yml gates --- .github/workflows/keep-ci.yml | 1 + crates/keep/tests/operator.rs | 15 +++++++++++++++ k8s/operator/crd.yaml | 17 +++++++++++++++++ 3 files changed, 33 insertions(+) diff --git a/.github/workflows/keep-ci.yml b/.github/workflows/keep-ci.yml index e10b6a6..4a6e208 100644 --- a/.github/workflows/keep-ci.yml +++ b/.github/workflows/keep-ci.yml @@ -39,6 +39,7 @@ jobs: set -euo pipefail cargo fmt --all -- --check cargo clippy --locked --workspace --all-targets --all-features -- -D warnings + cargo test --locked -p keep --features operator --test operator cargo test --locked --workspace - name: Release contract shell: bash diff --git a/crates/keep/tests/operator.rs b/crates/keep/tests/operator.rs index aebdd17..92cf1d6 100644 --- a/crates/keep/tests/operator.rs +++ b/crates/keep/tests/operator.rs @@ -250,3 +250,18 @@ fn rustls_provider_install_is_idempotent() { install_default_crypto_provider(); install_default_crypto_provider(); } + +/// R6 (#14) — the committed `k8s/operator/crd.yaml` is byte-equal to the generator output. +#[test] +fn committed_crd_matches_generator() { + let _ = include_str!("../../../k8s/operator/crd.yaml"); + let crd_path = + std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("../../k8s/operator/crd.yaml"); + let committed = std::fs::read(&crd_path).expect("read committed k8s/operator/crd.yaml"); + let generated = cli_std::artifact::ensure_trailing_newline(&crd_yaml()); + assert_eq!( + committed.as_slice(), + generated.as_bytes(), + "k8s/operator/crd.yaml does not match generator output; regenerate with:\n cargo run -p keep --features operator -- k8s crd render --out k8s/operator/crd.yaml" + ); +} diff --git a/k8s/operator/crd.yaml b/k8s/operator/crd.yaml index 46f7562..aebf581 100644 --- a/k8s/operator/crd.yaml +++ b/k8s/operator/crd.yaml @@ -63,6 +63,10 @@ spec: description: Per-node engine shard count (`KEEP_SHARDS`) for multi-core scaling — distinct from `shardCount` (the cluster-routing fan-out). Defaults to 256. type: integer minimum: 0.0 + evictionPolicy: + description: Memory eviction policy (`KEEP_EVICTION_POLICY`, default `allkeys-lru`). + nullable: true + type: string graceSecs: default: 30 description: Graceful drain window on SIGTERM (seconds); tracks `terminationGracePeriodSeconds`. Defaults to 30. @@ -77,6 +81,14 @@ spec: description: Log level (`trace|debug|info|warn|error`). Defaults to `info`. nullable: true type: string + maxDiskBytes: + description: Optional maximum disk quota for `/data/blobs/` (`KEEP_MAX_DISK_BYTES`, e.g. `8Gi`). + nullable: true + type: string + maxmemory: + description: Optional explicit memory cap (`KEEP_MAXMEMORY`, e.g. `4Gi` or bytes). When unset, the pod auto-detects its cgroup memory limit and applies `KEEP_MAXMEMORY_RATIO` (default 0.80). + nullable: true + type: string replicasPerShard: default: 1 description: Starting/minimum members per shard. With startup-static raft-runtime membership this is also the fixed desired value; a future membership controller may plan whole replica layers above this floor. @@ -99,6 +111,11 @@ spec: default: 1 type: integer minimum: 0.0 + spillThresholdBytes: + description: Byte size threshold above which `Bytes` payloads spill to `/data/blobs/` (`KEEP_SPILL_THRESHOLD_BYTES`). + type: integer + minimum: 0.0 + nullable: true storage: default: 10Gi description: Per-pod durable disk-tier (WAL + snapshots) PVC size. Defaults to `10Gi`.