From 01f1a156b79dd0999e8333e9faacce0a8e86476a Mon Sep 17 00:00:00 2001 From: overtrue Date: Mon, 9 Mar 2026 19:12:39 +0800 Subject: [PATCH 1/2] fix(docker): add jq and yq-go to runtime image --- Dockerfile | 6 ++++-- crates/cli/tests/dockerfile_contract.rs | 9 +++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 crates/cli/tests/dockerfile_contract.rs diff --git a/Dockerfile b/Dockerfile index 1927b0b..06e4b91 100644 --- a/Dockerfile +++ b/Dockerfile @@ -13,8 +13,10 @@ RUN cargo build --release FROM alpine:3.23 -# Install CA certificates for HTTPS -RUN apk add --no-cache ca-certificates +# Install runtime tools: +# - ca-certificates for HTTPS +# - jq/yq-go for Kubernetes-oriented config processing workflows +RUN apk add --no-cache ca-certificates jq yq-go COPY --from=builder /app/target/release/rc /usr/bin/rc COPY --from=builder /app/LICENSE-* /licenses/ diff --git a/crates/cli/tests/dockerfile_contract.rs b/crates/cli/tests/dockerfile_contract.rs new file mode 100644 index 0000000..d56ee3e --- /dev/null +++ b/crates/cli/tests/dockerfile_contract.rs @@ -0,0 +1,9 @@ +#[test] +fn runtime_image_contains_jq_and_yq() { + let dockerfile = include_str!("../../../Dockerfile"); + + assert!( + dockerfile.contains("apk add --no-cache ca-certificates jq yq-go"), + "runtime image must install jq and yq-go" + ); +} From 3d548cf067e24dd77dcf68d1c9c8fb7c30f54d0e Mon Sep 17 00:00:00 2001 From: overtrue Date: Mon, 9 Mar 2026 19:19:16 +0800 Subject: [PATCH 2/2] test(cli): harden dockerfile jq/yq contract check --- crates/cli/tests/dockerfile_contract.rs | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/crates/cli/tests/dockerfile_contract.rs b/crates/cli/tests/dockerfile_contract.rs index d56ee3e..220184b 100644 --- a/crates/cli/tests/dockerfile_contract.rs +++ b/crates/cli/tests/dockerfile_contract.rs @@ -1,9 +1,30 @@ +//! Contract tests for Dockerfile runtime image tooling guarantees. + #[test] fn runtime_image_contains_jq_and_yq() { let dockerfile = include_str!("../../../Dockerfile"); + let runtime_section = dockerfile + .split("FROM alpine:3.23") + .nth(1) + .expect("Dockerfile must contain runtime stage based on alpine:3.23"); + let runtime_apk_line = runtime_section + .lines() + .find(|line| line.contains("apk add --no-cache")) + .expect("runtime stage must install packages via `apk add --no-cache`"); + + let mut has_jq = false; + let mut has_yq_go = false; + + for token in runtime_apk_line.split_whitespace() { + if token == "jq" { + has_jq = true; + } else if token == "yq-go" { + has_yq_go = true; + } + } assert!( - dockerfile.contains("apk add --no-cache ca-certificates jq yq-go"), + has_jq && has_yq_go, "runtime image must install jq and yq-go" ); }