Skip to content

feat(ssl-certs): add --ssl-certs flag to bundle CA certificates into images#81

Open
feloy wants to merge 3 commits into
openkaiden:mainfrom
feloy:certs
Open

feat(ssl-certs): add --ssl-certs flag to bundle CA certificates into images#81
feloy wants to merge 3 commits into
openkaiden:mainfrom
feloy:certs

Conversation

@feloy

@feloy feloy commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Enterprise environments that intercept HTTPS traffic with corporate proxies need a custom CA certificate trusted both during the build (so dnf/apt can reach repos) and at runtime (so the agent API calls work).

CA certificates from the host are now bundled into every image by default: the tool auto-discovers across 7 common Linux CA bundle paths and uses the first one it finds. Use --ssl-certs <FILE> to point to a specific bundle instead, or --disable-ssl-certs to opt out entirely.

Certs are installed in the final image via update-ca-trust (DNF) or update-ca-certificates (Ubuntu), and persist into the final sandbox image via the FROM system AS final inheritance.

To test default auto-discover mode (uses the host's CA bundle if present):

openshell-image-builder myimage:latest

To test explicit file mode:

openshell-image-builder \
  --ssl-certs /etc/ssl/certs/ca-certificates.crt \
  myimage:latest

To build without any certificates:

openshell-image-builder --disable-ssl-certs myimage:latest

To verify the cert landed in the final image — Ubuntu base (default):

podman run --rm myimage:latest -c \
  'test -f /usr/local/share/ca-certificates/system-ca.crt && echo found'

To test with other base images, create a config.toml first. DNF-based images (Fedora, UBI, Hummingbird) store the cert under the pki trust path instead. Example configs and the verification command:

# Fedora
echo '[openshell_image_builder.base_image]
image = "fedora"
tag = "latest"' > /tmp/myconfig/config.toml

# UBI
echo '[openshell_image_builder.base_image]
image = "ubi"
tag = "latest"' > /tmp/myconfig/config.toml

# Hummingbird
echo '[openshell_image_builder.base_image]
image = "hummingbird"
tag = "latest-builder"' > /tmp/myconfig/config.toml

Then build and verify:

openshell-image-builder \
  --config /tmp/myconfig \
  --ssl-certs /etc/ssl/certs/ca-certificates.crt \
  myimage:latest
podman run --rm myimage:latest -c \
  'test -f /etc/pki/ca-trust/source/anchors/system-ca.crt && echo found'

To verify error on a missing file:

openshell-image-builder --ssl-certs /nonexistent/bundle.crt myimage:latest
# exits non-zero with an OS error

Closes #62

@coderabbitai

coderabbitai Bot commented Jun 8, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 409dfdbf-7a28-4f12-9be5-4d99d48c94d0

📥 Commits

Reviewing files that changed from the base of the PR and between 7a3a075 and f6b27d1.

📒 Files selected for processing (7)
  • .agents/skills/add-cli-flag/SKILL.md
  • README.md
  • src/certs.rs
  • src/containerfile.rs
  • src/main.rs
  • tests/fixtures/test-ca.crt
  • tests/integration_test.rs
✅ Files skipped from review due to trivial changes (2)
  • tests/fixtures/test-ca.crt
  • .agents/skills/add-cli-flag/SKILL.md
🚧 Files skipped from review as they are similar to previous changes (4)
  • tests/integration_test.rs
  • src/certs.rs
  • src/main.rs
  • src/containerfile.rs

📝 Walkthrough

Walkthrough

This PR adds a new --ssl-certs CLI option to support CA certificate bundling for corporate proxy environments. It implements certificate discovery from common system paths, conditional staging into the build context, and optional injection of trust-store configuration into generated Containerfiles for Ubuntu and DNF-based images. Unit tests, integration tests with image building, PEM fixtures, and user documentation are included.

Changes

Add system CA certificates support

Layer / File(s) Summary
CLI option structure for CA certificate control
src/main.rs
Extends Cli struct with --ssl-certs (optional FILE path) and --disable-ssl-certs (boolean) flags to enable user selection of disabled, auto-discovery, or explicit certificate modes.
Certificate discovery and staging utilities
src/certs.rs
Defines SYSTEM_CA_CERT_PATHS and implements find_system_ca_certificates, copy_from_paths, and copy_from_file to discover system CA files, write them to context_dir/certs/system-ca.crt, with comprehensive unit tests covering selection, skipping, and error paths.
Conditional CA injection in generated Containerfiles
src/containerfile.rs
generate() gains with_ca_certs: bool parameter; ubuntu_system_stage and dnf_system_stage conditionally emit COPY certs/system-ca.crt and distro-specific trust-store update commands in correct sequence; test helpers and suites verify omission/inclusion and ordering relative to package installation.
CLI to build pipeline wiring
src/main.rs
Main entrypoint converts CLI flags to Option<Option<PathBuf>>, run() signature updated to accept ssl_certs parameter, conditionally stages certificates during context setup via certs module, forwards ca_certs_copied result into containerfile::generate(), and includes ContainerfileCapture test helper and SSL-cert behavior tests.
Integration tests and fixtures
tests/integration_test.rs, tests/fixtures/test-ca.crt
Adds Ubuntu/Fedora image builders with --ssl-certs and --disable-ssl-certs variants, PEM certificate fixture, ignored integration tests verifying CA bundle presence in ssl-certs images and absence in no-certs images, and cleanup list updates.
User and developer documentation
README.md, .agents/skills/add-cli-flag/SKILL.md
Adds "Enterprise environments" section documenting corporate proxy support, CA bundle auto-discovery, explicit path usage, per-distro trust-store installation; updates Full option reference table; updates skill guidance for CLI flag definition, run() signature wiring, and test patterns.

Sequence Diagram(s)

sequenceDiagram
  participant user as User
  participant cli as Cli Parser
  participant main as main()
  participant run as run()
  participant certs as certs module
  participant gen as containerfile::generate()
  participant docker as Docker Build
  user->>cli: --ssl-certs=/path/to/certs
  cli->>main: ssl_certs = Some(Some(path))
  main->>run: ssl_certs parameter
  run->>certs: copy_from_file(context_dir, path)
  certs-->>run: Ok(()) or IO error
  run->>gen: with_ca_certs = true
  gen-->>run: Containerfile with COPY + trust-update
  run->>docker: Containerfile with CA bundle
  docker-->>run: Built image with trusted CA
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • openkaiden/openshell-image-builder#101: Both PRs modify src/containerfile.rs::generate to thread a boolean flag and conditionally inject a COPY block into the final Containerfile, so the changes intersect at the shared containerfile-generation wiring.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: adding an SSL certificates bundling feature via a new --ssl-certs flag for enterprise environments.
Description check ✅ Passed The description is comprehensive and directly related to the changeset, explaining the feature's purpose, three operational modes, implementation details, and multiple usage examples.
Linked Issues check ✅ Passed The implementation fully addresses issue #62 by delivering auto-discovered CA certificate bundling (across 7 common paths), explicit file specification via --ssl-certs, disable option, and platform-specific installation for DNF and Ubuntu systems.
Out of Scope Changes check ✅ Passed All changes are directly scoped to implementing SSL certificate bundling: new certs.rs module, containerfile.rs integration, CLI flag support in main.rs, documentation, tests, and fixtures—all contributing to the stated feature objective.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/containerfile.rs (1)

190-220: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Move Ubuntu CA trust setup before the first apt-get network call.

The Ubuntu path currently installs the custom CA only after apt-get update && apt-get install, so it cannot help the package manager trust a corporate MITM/proxy during the build. That misses the core --ssl-certs objective for Ubuntu images, and the test at Lines 1005-1014 now hard-codes that wrong order.

Also applies to: 1005-1014

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/containerfile.rs` around lines 190 - 220, The CA install block is placed
after the apt-get install so custom CA can't be used by the package manager
during build; in the function ubuntu_system_stage move the ca_cert_section (the
COPY certs/... and update-ca-certificates) to appear before the RUN apt-get
update && apt-get install... line in the formatted Dockerfile string so the CA
is installed prior to any network package operations (also update the
corresponding test that asserts order around the same block referenced at lines
~1005-1014 to reflect the new order).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/certs.rs`:
- Around line 67-69: copy_from_file currently treats a zero-byte file as success
and calls write_cert_to_context, which makes callers (e.g., src/main.rs) think
CA certs were staged; change copy_from_file to read the file into content, check
if content.is_empty(), and if so return an Err (e.g.,
io::Error::new(io::ErrorKind::InvalidData, "empty certificate bundle")) instead
of calling write_cert_to_context; keep the existing success path unchanged so
non-empty files still call write_cert_to_context.

---

Outside diff comments:
In `@src/containerfile.rs`:
- Around line 190-220: The CA install block is placed after the apt-get install
so custom CA can't be used by the package manager during build; in the function
ubuntu_system_stage move the ca_cert_section (the COPY certs/... and
update-ca-certificates) to appear before the RUN apt-get update && apt-get
install... line in the formatted Dockerfile string so the CA is installed prior
to any network package operations (also update the corresponding test that
asserts order around the same block referenced at lines ~1005-1014 to reflect
the new order).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9ba0a052-9564-4889-b4d5-08095327b9a5

📥 Commits

Reviewing files that changed from the base of the PR and between 36d30a2 and 0d33b32.

📒 Files selected for processing (7)
  • .agents/skills/add-cli-flag/SKILL.md
  • README.md
  • src/certs.rs
  • src/containerfile.rs
  • src/main.rs
  • tests/fixtures/test-ca.crt
  • tests/integration_test.rs

Comment thread src/certs.rs
@codecov

codecov Bot commented Jun 8, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.94737% with 3 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/main.rs 96.70% 3 Missing ⚠️

📢 Thoughts on this report? Let us know!

@feloy

feloy commented Jun 8, 2026

Copy link
Copy Markdown
Contributor Author

@wherka-ama this is a port of the PR openkaiden/kdn#556 , this repo being the new way to build images for kaiden

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@README.md`:
- Line 25: The heading "### workspace.json fields" jumps from H1 to H3; change
that heading to H2 (replace "### workspace.json fields" with "## workspace.json
fields") or alternatively insert the missing parent H2 above it so the document
follows a proper H1→H2→H3 hierarchy; update any adjacent table-of-contents or
anchors if present to reflect the new heading level.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c0e74af7-7097-4b95-8def-ecbd29fbcc23

📥 Commits

Reviewing files that changed from the base of the PR and between 0d33b32 and f5b235f.

📒 Files selected for processing (7)
  • .agents/skills/add-cli-flag/SKILL.md
  • README.md
  • src/certs.rs
  • src/containerfile.rs
  • src/main.rs
  • tests/fixtures/test-ca.crt
  • tests/integration_test.rs
✅ Files skipped from review due to trivial changes (2)
  • tests/fixtures/test-ca.crt
  • .agents/skills/add-cli-flag/SKILL.md
🚧 Files skipped from review as they are similar to previous changes (4)
  • tests/integration_test.rs
  • src/certs.rs
  • src/containerfile.rs
  • src/main.rs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@README.md`:
- Line 25: The heading "### workspace.json fields" jumps from H1 to H3; change
that heading to H2 (replace "### workspace.json fields" with "## workspace.json
fields") or alternatively insert the missing parent H2 above it so the document
follows a proper H1→H2→H3 hierarchy; update any adjacent table-of-contents or
anchors if present to reflect the new heading level.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c0e74af7-7097-4b95-8def-ecbd29fbcc23

📥 Commits

Reviewing files that changed from the base of the PR and between 0d33b32 and f5b235f.

📒 Files selected for processing (7)
  • .agents/skills/add-cli-flag/SKILL.md
  • README.md
  • src/certs.rs
  • src/containerfile.rs
  • src/main.rs
  • tests/fixtures/test-ca.crt
  • tests/integration_test.rs
✅ Files skipped from review due to trivial changes (2)
  • tests/fixtures/test-ca.crt
  • .agents/skills/add-cli-flag/SKILL.md
🚧 Files skipped from review as they are similar to previous changes (4)
  • tests/integration_test.rs
  • src/certs.rs
  • src/containerfile.rs
  • src/main.rs
🛑 Comments failed to post (1)
README.md (1)

25-25: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix heading level jump at Line 25.

### workspace.json fields skips from H1 to H3, which violates MD001 and can break doc structure/navigation in some renderers. Use ## here (or insert the missing parent H2).

🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 25-25: Heading levels should only increment by one level at a time
Expected: h2; Actual: h3

(MD001, heading-increment)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@README.md` at line 25, The heading "### workspace.json fields" jumps from H1
to H3; change that heading to H2 (replace "### workspace.json fields" with "##
workspace.json fields") or alternatively insert the missing parent H2 above it
so the document follows a proper H1→H2→H3 hierarchy; update any adjacent
table-of-contents or anchors if present to reflect the new heading level.

Source: Linters/SAST tools

@jeffmaury jeffmaury left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about Windows ?

@feloy

feloy commented Jun 10, 2026

Copy link
Copy Markdown
Contributor Author

What about Windows ?

I would prefer to keep this PR focus on Linux, and create follow-up PRs for other systems

@feloy feloy requested a review from jeffmaury June 10, 2026 15:58

@benoitf benoitf left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a question

should it use the ssl cert automatically (without the empty --ssl-certs=)

I would assume that by default it reads them, that I can specify one or that I can disable it with another flag like --disable-ssl-certs but IMHO I'm finding the pattern --ssl-certs= not a classic pattern ?

@feloy

feloy commented Jun 18, 2026

Copy link
Copy Markdown
Contributor Author

I have a question

should it use the ssl cert automatically (without the empty --ssl-certs=)

I would assume that by default it reads them, that I can specify one or that I can disable it with another flag like --disable-ssl-certs but IMHO I'm finding the pattern --ssl-certs= not a classic pattern ?

I've updated to include auto-detected certs by default. --ssl-certs /path/to/specific/certs can be used to include specific ones, and --disable-ssl-certs to disable the inclusion

@feloy feloy requested a review from benoitf June 18, 2026 10:00

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/main.rs`:
- Around line 411-423: In the ContainerfileCapture struct's run method, the file
read operation using std::fs::read_to_string(path).unwrap_or_default() silently
falls back to an empty string when reading fails, which masks errors and allows
tests to pass incorrectly. Replace the unwrap_or_default() call with proper
error handling that propagates the error up the call chain using the ? operator,
so that file read failures are caught and fail the operation immediately instead
of continuing with empty content.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c1da17f3-731e-4d94-acdf-cfdd99f50929

📥 Commits

Reviewing files that changed from the base of the PR and between f5b235f and 6bb4d93.

📒 Files selected for processing (7)
  • .agents/skills/add-cli-flag/SKILL.md
  • README.md
  • src/certs.rs
  • src/containerfile.rs
  • src/main.rs
  • tests/fixtures/test-ca.crt
  • tests/integration_test.rs
✅ Files skipped from review due to trivial changes (2)
  • .agents/skills/add-cli-flag/SKILL.md
  • tests/fixtures/test-ca.crt
🚧 Files skipped from review as they are similar to previous changes (3)
  • tests/integration_test.rs
  • src/certs.rs
  • src/containerfile.rs

Comment thread src/main.rs
feloy and others added 3 commits June 19, 2026 10:24
…images

Enterprise environments that intercept HTTPS traffic with corporate
proxies need a custom CA certificate trusted both during the build
(so dnf/apt can reach repos) and at runtime (so the agent API calls
work). The flag accepts an optional FILE; omitting the value triggers
auto-discovery across 7 common Linux CA bundle paths. Certs are
installed in the final image via update-ca-trust (DNF) or
update-ca-certificates (Ubuntu), and persist into the final sandbox
image via the FROM system AS final inheritance.

To test auto-discover mode (uses the host's CA bundle if present):
  openshell-image-builder --ssl-certs= myimage:latest

To test explicit file mode:
  openshell-image-builder \
    --ssl-certs /etc/ssl/certs/ca-certificates.crt \
    myimage:latest

To verify the cert landed in the final image — Ubuntu base (default):
  podman run --rm myimage:latest -c \
    'test -f /usr/local/share/ca-certificates/system-ca.crt && echo found'

To test with other base images, create a config.toml first. DNF-based
images (Fedora, UBI, Hummingbird) store the cert under the pki trust
path instead. Example configs and the verification command:

  # Fedora
  echo '[openshell_image_builder.base_image]
  image = "fedora"
  tag = "latest"' > /tmp/myconfig/config.toml

  # UBI
  echo '[openshell_image_builder.base_image]
  image = "ubi"
  tag = "latest"' > /tmp/myconfig/config.toml

  # Hummingbird
  echo '[openshell_image_builder.base_image]
  image = "hummingbird"
  tag = "latest-builder"' > /tmp/myconfig/config.toml

Then build and verify:
  openshell-image-builder \
    --config /tmp/myconfig \
    --ssl-certs /etc/ssl/certs/ca-certificates.crt \
    myimage:latest
  podman run --rm myimage:latest -c \
    'test -f /etc/pki/ca-trust/source/anchors/system-ca.crt && echo found'

To verify error on a missing file:
  openshell-image-builder --ssl-certs /nonexistent/bundle.crt myimage:latest
  # exits non-zero with an OS error

Closes openkaiden#62

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Philippe Martin <phmartin@redhat.com>
…ssl-certs

CA certificates from the host are now bundled into every image by
default. Use --ssl-certs <FILE> to specify an explicit bundle instead,
or --disable-ssl-certs to opt out entirely. The bare --ssl-certs (no
value) is removed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Philippe Martin <phmartin@redhat.com>
…lencing it

unwrap_or_default() swallowed file-read failures in the test helper,
letting tests pass with empty content when the Containerfile was
unreadable. Replaced with ? so the error surfaces immediately.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Philippe Martin <phmartin@redhat.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add system CA certificates

3 participants