Skip to content

Conversation

@mangelajo
Copy link
Member

@mangelajo mangelajo commented Dec 13, 2025

Summary by CodeRabbit

  • New Features

    • Web-based configuration UI (auth, forced password change, kubeconfig download, live stats, CR/application APIs, readiness) served on port 8880
    • End-to-end boot image workflow: build/push multi-arch images, QCOW2/ISO generation, and container lifecycle/run helpers
  • Documentation

    • Added comprehensive deployment README with quick start, build/run, customization, and troubleshooting
  • Chores

    • Default boot config updated (locale, keyboard, LVM disk layout); default root password set to "jumpstarter"

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 13, 2025

Walkthrough

Adds a Bootc-based MicroShift deployment under deploy/microshift-bootc: container image and Containerfile, a Makefile and run script for building and running images, a Flask-based configuration service with systemd units, kustomize manifests, image builder config, and README documentation.

Changes

Cohort / File(s) Summary
Container image & build
deploy/microshift-bootc/Containerfile, deploy/microshift-bootc/Makefile
New Containerfile layering MicroShift release, packages, manifests, systemd units and scripts; large Makefile providing build/push/multi-arch/image/ISO/QCOW2 targets and container lifecycle targets (bootc-*) with default BOOTC_IMG.
Runtime orchestration
deploy/microshift-bootc/run-microshift.sh
New run script to pull/run the bootc container, prepare or reuse an LVM disk image, set up LVM inside the container, run privileged Podman container, and wait for kubeconfig.
Config service & units
deploy/microshift-bootc/config-svc/app.py, deploy/microshift-bootc/config-svc/config-svc.service, deploy/microshift-bootc/config-svc/update-banner.service, deploy/microshift-bootc/config-svc/update-banner.sh
New Flask-based config-svc (PAM/basic auth, forced password-change path, hostname management, Jumpstarter CR generation/apply, kubeconfig/pod/route endpoints) plus systemd units and banner-update launcher. update-banner.sh now robustly loads the service module.
Image builder config
deploy/microshift-bootc/config.toml
New boot-image-builder configuration: locale, sample SSH block, LVM layout with VG/LV and root LV, and notes about network/DHCP and pull-secret.
Kustomize & manifests
deploy/microshift-bootc/kustomization.yaml, .../install-operator.yaml
New kustomization.yaml referencing operator install manifest and applying common labels for jumpstarter-controller.
Docs
deploy/microshift-bootc/README.md
New README covering quickstart, build/image/QCOW2/ISO workflow, architecture, customization, Makefile targets, troubleshooting, and development/production notes.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant Browser as Browser
    participant Config as config-svc (Flask)
    participant Host as Host OS (systemd)
    participant Boot as Boot Container
    participant Kube as Kubernetes API

    Browser->>Config: POST /configure (baseDomain, image)
    Config->>Config: validate, build Jumpstarter CR YAML
    Config->>Host: set hostname / set root password / update banner
    Host-->>Config: ack
    Config->>Boot: kubectl apply (using mounted kubeconfig)
    Boot->>Kube: API apply CR
    Kube-->>Boot: apply result
    Boot-->>Config: result
    Config-->>Browser: success / error

    Browser->>Config: GET /kubeconfig
    Config->>Boot: read kubeconfig
    Boot-->>Config: kubeconfig
    Config-->>Browser: kubeconfig (rewritten)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Focus review on deploy/microshift-bootc/config-svc/app.py (authentication, subprocess/kubectl use, file writes, CR/YAML generation).
  • Inspect deploy/microshift-bootc/run-microshift.sh and deploy/microshift-bootc/Makefile for privileged Podman/LVM/image operations, mounts, and error handling.
  • Verify deploy/microshift-bootc/Containerfile for correct placement of systemd units, scripts, and credential handling (root password).
  • Confirm kustomize references and labels in kustomization.yaml and presence/contents of install-operator.yaml.

Poem

🐇 I nudge the bootc box with twitchy paws,
Flask hums, banners glow, and hostname laws,
LVM roots settle, images spin and gleam,
Containers wake and clusters chase a dream,
Hop—new nodes sprout where rabbit winks and beams.

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Title check ❓ Inconclusive The title mentions 'bootc microshift' but contains a typo ('booc' instead of 'bootc') and only partially describes the main changes, which include a comprehensive deployment setup with Containerfile, Makefile, Flask app, config files, and scripts. Consider clarifying the title to better reflect the scope of changes. Suggested: 'Add bootc-based MicroShift deployment infrastructure with configuration service' or 'Create bootc MicroShift image with config service and build tooling'.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 84.21% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch microshift-image

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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Nitpick comments (2)
deploy/microshift-bootc/Makefile (1)

1-1: Incomplete .PHONY declaration.

The clean, build-all, and push-all targets are missing from the .PHONY declaration. This can cause issues if files with these names exist.

-.PHONY: help build build-config-svc build-bootc push push-config-svc push-bootc
+.PHONY: help build build-config-svc build-bootc push push-config-svc push-bootc build-all push-all clean
deploy/microshift-bootc/config-svc/app.py (1)

440-475: Consider using PyYAML instead of custom implementation.

The custom json_to_yaml implementation works for simple cases but has edge cases (multiline strings, special YAML characters beyond :/#/-). Since this is a container environment, adding python3-pyyaml to the Containerfile would be straightforward.

However, for the limited CR structure being generated, this implementation is functional.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a049e90 and 2cd20b3.

📒 Files selected for processing (7)
  • deploy/microshift-bootc/Containerfile (1 hunks)
  • deploy/microshift-bootc/Makefile (1 hunks)
  • deploy/microshift-bootc/config-svc/Containerfile (1 hunks)
  • deploy/microshift-bootc/config-svc/app.py (1 hunks)
  • deploy/microshift-bootc/config-svc/manifest.yaml (1 hunks)
  • deploy/microshift-bootc/config.toml (1 hunks)
  • deploy/microshift-bootc/kustomization.yaml (1 hunks)
🧰 Additional context used
🧠 Learnings (4)
📚 Learning: 2025-10-24T11:57:23.796Z
Learnt from: mangelajo
Repo: jumpstarter-dev/jumpstarter-controller PR: 170
File: deploy/operator/internal/controller/jumpstarter/jumpstarter_controller.go:328-333
Timestamp: 2025-10-24T11:57:23.796Z
Learning: In the jumpstarter-controller operator (deploy/operator/), the design allows only one Jumpstarter CR per namespace, which will be enforced by a validation webhook. This constraint eliminates concerns about resource name collisions within a namespace.

Applied to files:

  • deploy/microshift-bootc/kustomization.yaml
  • deploy/microshift-bootc/config-svc/manifest.yaml
📚 Learning: 2025-05-13T19:57:56.811Z
Learnt from: NickCao
Repo: jumpstarter-dev/jumpstarter-controller PR: 137
File: hack/deploy_with_helm.sh:26-34
Timestamp: 2025-05-13T19:57:56.811Z
Learning: The jumpstarter-dev repository uses a custom kind cluster configuration that allows NodePort services to use non-standard ports 5080 and 5443, outside the default Kubernetes NodePort range (30000-32767).

Applied to files:

  • deploy/microshift-bootc/kustomization.yaml
  • deploy/microshift-bootc/config-svc/manifest.yaml
📚 Learning: 2025-05-13T19:57:56.811Z
Learnt from: NickCao
Repo: jumpstarter-dev/jumpstarter-controller PR: 137
File: hack/deploy_with_helm.sh:26-34
Timestamp: 2025-05-13T19:57:56.811Z
Learning: The jumpstarter project uses a custom kind cluster configuration with an expanded NodePort range (3000-32767) and explicit port mappings for ingress (5080/5443) and gRPC services (30010/30011 mapped to 8082/8083).

Applied to files:

  • deploy/microshift-bootc/config-svc/manifest.yaml
📚 Learning: 2025-05-13T19:56:27.924Z
Learnt from: NickCao
Repo: jumpstarter-dev/jumpstarter-controller PR: 137
File: deploy/helm/jumpstarter/charts/jumpstarter-controller/templates/router-deployment.yaml:23-26
Timestamp: 2025-05-13T19:56:27.924Z
Learning: In the jumpstarter-controller project, the router service uses the same ConfigMap as the controller service (controller-cm.yaml) even though it has been moved to its own separate deployment.

Applied to files:

  • deploy/microshift-bootc/config-svc/manifest.yaml
🪛 checkmake (0.2.2)
deploy/microshift-bootc/Makefile

[warning] 1-1: Missing required phony target "all"

(minphony)


[warning] 1-1: Missing required phony target "clean"

(minphony)


[warning] 1-1: Missing required phony target "test"

(minphony)

🪛 Checkov (3.2.334)
deploy/microshift-bootc/config-svc/manifest.yaml

[medium] 68-117: Containers should not run with allowPrivilegeEscalation

(CKV_K8S_20)


[high] 68-117: Container should not be privileged

(CKV_K8S_16)


[medium] 68-117: Minimize the admission of root containers

(CKV_K8S_23)


[medium] 68-117: Containers should not share the host network namespace

(CKV_K8S_19)

🪛 Ruff (0.14.8)
deploy/microshift-bootc/config-svc/app.py

305-305: Do not catch blind exception: Exception

(BLE001)


306-306: Use explicit conversion flag

Replace with conversion flag

(RUF010)


318-318: Starting a process with a partial executable path

(S607)


341-341: subprocess call: check for execution of untrusted input

(S603)


342-342: Starting a process with a partial executable path

(S607)


356-356: Consider moving this statement to an else block

(TRY300)


357-357: Do not catch blind exception: Exception

(BLE001)


366-366: Do not catch blind exception: Exception

(BLE001)


374-374: subprocess call: check for execution of untrusted input

(S603)


375-375: Starting a process with a partial executable path

(S607)


380-380: Consider moving this statement to an else block

(TRY300)


385-385: Do not catch blind exception: Exception

(BLE001)


417-417: subprocess call: check for execution of untrusted input

(S603)


418-418: Starting a process with a partial executable path

(S607)


428-429: try-except-pass detected, consider logging the exception

(S110)


428-428: Do not catch blind exception: Exception

(BLE001)


435-435: Do not catch blind exception: Exception

(BLE001)


485-485: Possible binding to all interfaces

(S104)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: e2e-tests (ubuntu-24.04)
  • GitHub Check: e2e-tests-release-0-7
  • GitHub Check: e2e-tests (ubuntu-24.04-arm)
  • GitHub Check: lint-go
  • GitHub Check: tests
  • GitHub Check: e2e-test-operator
  • GitHub Check: deploy-kind
🔇 Additional comments (5)
deploy/microshift-bootc/config-svc/Containerfile (1)

1-24: LGTM - Clean Containerfile structure.

The Containerfile follows good practices: uses a specific base image version, consolidates RUN commands to reduce layers, and cleans up the dnf cache.

Minor nit: Line 18's chmod +x is unnecessary since the script is invoked explicitly with python3 on Line 24.

deploy/microshift-bootc/kustomization.yaml (1)

1-11: LGTM - Kustomization configuration is well-structured.

The resource references align correctly with the files copied in the main Containerfile, and the common labels appropriately identify the deployment context.

deploy/microshift-bootc/Containerfile (1)

1-6: LGTM - Manifest packaging is correct.

The Containerfile properly packages the Jumpstarter resources for MicroShift's manifest auto-loading. The numeric prefix 002-jumpstarter ensures proper ordering, and file renames align with the kustomization resource references.

deploy/microshift-bootc/config-svc/manifest.yaml (1)

68-116: Acknowledged: Privileged security context is intentional.

The static analysis correctly flags the privileged container, hostNetwork, and root container. However, these are necessary for this service's purpose:

  • hostNetwork: true - Required to set the system hostname via hostnamectl
  • privileged: true - Required for host-level operations
  • hostPath volume - Needed to read the MicroShift kubeconfig

Consider adding a comment in the manifest documenting why these elevated privileges are required.

deploy/microshift-bootc/config-svc/app.py (1)

313-359: LGTM - Network detection logic is well-implemented.

The function properly parses ip route and ip addr output to determine the default route IP. The dash-separated IP format for nip.io is correct.

Comment on lines 91 to 104
ports:
- containerPort: 8880
hostPort: 8880
name: http
protocol: TCP
securityContext:
privileged: true
volumeMounts:
- name: microshift-data
mountPath: /var/lib/microshift
readOnly: true
env:
- name: PORT
value: "8080"
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Critical: Port mismatch will cause connectivity failure.

The container declares containerPort: 8880 and hostPort: 8880 (lines 92-93), but the PORT environment variable is set to 8080 (line 104). The application reads PORT to determine the listening port, so it will listen on 8080 while the container expects 8880.

Additionally, the Service (lines 128-129) targets port 8080, which won't match the hostPort declaration.

           ports:
-            - containerPort: 8880
-              hostPort: 8880
+            - containerPort: 8080
+              hostPort: 8080
               name: http
               protocol: TCP
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
ports:
- containerPort: 8880
hostPort: 8880
name: http
protocol: TCP
securityContext:
privileged: true
volumeMounts:
- name: microshift-data
mountPath: /var/lib/microshift
readOnly: true
env:
- name: PORT
value: "8080"
ports:
- containerPort: 8080
hostPort: 8080
name: http
protocol: TCP
securityContext:
privileged: true
volumeMounts:
- name: microshift-data
mountPath: /var/lib/microshift
readOnly: true
env:
- name: PORT
value: "8080"
🤖 Prompt for AI Agents
In deploy/microshift-bootc/config-svc/manifest.yaml around lines 91 to 104 (and
note related Service at lines ~128-129), there is a port mismatch: containerPort
and hostPort are 8880 but the PORT env is 8080 and the Service targets 8080;
make them consistent by choosing one port and applying it everywhere—either
change the env PORT (and Service targetPort) to "8880" to match
containerPort/hostPort, or change containerPort/hostPort to 8080 to match the
env and Service; update the Service targetPort as well so containerPort,
hostPort, env PORT, and Service targetPort all use the same numeric port.

Comment on lines 7 to 10
# Root user password
[[customizations.user]]
name = "root"
password = "changeme123"
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Security concern: Hardcoded default password.

The root password changeme123 is committed to the repository. Even as a default/example, this creates risk if users deploy without changing it. Consider:

  1. Using an environment variable or build-time argument
  2. Adding a prominent warning comment
  3. Requiring password configuration at first boot

At minimum, add a clear warning that this must be changed before production use.

 # Root user password
+# WARNING: Change this password before any production or public deployment!
 [[customizations.user]]
 name = "root"
-password = "changeme123"
+password = "CHANGE_ME_BEFORE_DEPLOY"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Root user password
[[customizations.user]]
name = "root"
password = "changeme123"
# Root user password
# WARNING: Change this password before any production or public deployment!
[[customizations.user]]
name = "root"
password = "CHANGE_ME_BEFORE_DEPLOY"
🤖 Prompt for AI Agents
In deploy/microshift-bootc/config.toml around lines 7 to 10 the root password is
hardcoded ("changeme123"); remove the literal password and instead reference a
configurable value (e.g. an environment variable or build-time
variable/placeholders) so the password is injected at deploy time, add a
prominent warning comment above the user block stating this value must be
changed before production, and, if supported, implement or call out a mechanism
to require password configuration on first boot (or fail startup) so deployments
cannot proceed with a default password.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (3)
deploy/microshift-bootc/config-svc/app.py (2)

217-234: Security: Verify Jinja2 auto-escaping is enabled.

User-controlled values (current_hostname, suggested_hostname, message text) are rendered in the HTML template. While Flask's Jinja2 enables auto-escaping by default for render_template_string, it's best practice to explicitly escape user input for defense in depth.

Add explicit HTML escaping:

+import html

And in the rendering code, consider explicitly escaping values or verify that auto-escaping is functioning correctly for your Flask version.


485-496: Fix apiVersion for Jumpstarter CR.

The CR uses apiVersion: 'jumpstarter.dev/v1alpha1', but based on the CRD group structure, it should use operator.jumpstarter.dev/v1alpha1.

         cr = {
-            'apiVersion': 'jumpstarter.dev/v1alpha1',
+            'apiVersion': 'operator.jumpstarter.dev/v1alpha1',
             'kind': 'Jumpstarter',
deploy/microshift-bootc/Makefile (1)

14-16: Typo: "buinding" should be "building".

 build-bootc: ## Build the bootc image with MicroShift
-	@echo "Building bootc image: $(BOOTC_IMG): buinding as root to be on the container storage from root"
+	@echo "Building bootc image: $(BOOTC_IMG): building as root to use container storage from root"
 	sudo podman build -t $(BOOTC_IMG) -f Containerfile ../..
🧹 Nitpick comments (4)
deploy/microshift-bootc/config-svc/config-svc.service (1)

7-17: Consider adding systemd hardening directives.

The service performs privileged operations (hostname changes, password management, kubectl operations) and must run as root. Consider adding hardening directives to limit the attack surface:

 [Service]
 Type=simple
 ExecStart=/usr/bin/python3 /usr/local/bin/config-svc
 Restart=on-failure
 RestartSec=5
 Environment="PORT=8880"
 
 # Security and resource limits
+PrivateTmp=yes
+ProtectSystem=strict
+ReadWritePaths=/etc/hostname /var/lib/microshift
+NoNewPrivileges=yes
+ProtectHome=yes
 StandardOutput=journal
 StandardError=journal
 SyslogIdentifier=config-svc

Note: ProtectSystem=strict with ReadWritePaths allows write access only to necessary paths while protecting the rest of the filesystem.

deploy/microshift-bootc/config-svc/app.py (3)

358-364: Document the insecure-skip-tls-verify configuration.

The kubeconfig is modified to add insecure-skip-tls-verify: true, which disables TLS certificate validation. This is likely intentional for development/testing with self-signed certificates, but it reduces security.

Consider adding a comment in the code explaining this choice:

         # Add insecure-skip-tls-verify: true to the cluster section
-        # We'll add it after the server line in the cluster section
+        # Add after the server line to allow self-signed certificates in dev/test environments
+        # WARNING: This reduces security by skipping TLS certificate verification
         kubeconfig_content = re.sub(

457-478: Prefix unused variable with underscore.

The stdout variable is never used after being unpacked.

-        stdout, stderr = process.communicate(input=f'root:{password}\n')
+        _stdout, stderr = process.communicate(input=f'root:{password}\n')

529-564: Consider using PyYAML library instead of custom implementation.

The custom YAML serialization reinvents functionality available in the well-tested pyyaml library. Using a standard library reduces maintenance burden and potential edge-case bugs.

+import yaml
+
 def apply_jumpstarter_cr(base_domain, image):
     """Apply Jumpstarter Custom Resource using kubectl."""
     try:
         # Build the CR YAML
         cr = {
             ...
         }
         
         # Write CR to temporary file
         with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:
-            yaml_content = json_to_yaml(cr)
+            yaml_content = yaml.dump(cr, default_flow_style=False)
             f.write(yaml_content)
             temp_file = f.name

Then remove the json_to_yaml and yaml_value functions.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2cd20b3 and c0353a6.

📒 Files selected for processing (5)
  • deploy/microshift-bootc/Containerfile (1 hunks)
  • deploy/microshift-bootc/Makefile (1 hunks)
  • deploy/microshift-bootc/config-svc/app.py (1 hunks)
  • deploy/microshift-bootc/config-svc/config-svc.service (1 hunks)
  • deploy/microshift-bootc/kustomization.yaml (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • deploy/microshift-bootc/Containerfile
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-10-24T11:57:23.796Z
Learnt from: mangelajo
Repo: jumpstarter-dev/jumpstarter-controller PR: 170
File: deploy/operator/internal/controller/jumpstarter/jumpstarter_controller.go:328-333
Timestamp: 2025-10-24T11:57:23.796Z
Learning: In the jumpstarter-controller operator (deploy/operator/), the design allows only one Jumpstarter CR per namespace, which will be enforced by a validation webhook. This constraint eliminates concerns about resource name collisions within a namespace.

Applied to files:

  • deploy/microshift-bootc/kustomization.yaml
  • deploy/microshift-bootc/config-svc/app.py
🪛 checkmake (0.2.2)
deploy/microshift-bootc/Makefile

[warning] 1-1: Missing required phony target "all"

(minphony)


[warning] 1-1: Missing required phony target "clean"

(minphony)


[warning] 1-1: Missing required phony target "test"

(minphony)

🪛 Ruff (0.14.8)
deploy/microshift-bootc/config-svc/app.py

39-39: subprocess call: check for execution of untrusted input

(S603)


40-40: Starting a process with a partial executable path

(S607)


45-45: Consider moving this statement to an else block

(TRY300)


46-46: Do not catch blind exception: Exception

(BLE001)


376-376: Do not catch blind exception: Exception

(BLE001)


377-377: Use explicit conversion flag

Replace with conversion flag

(RUF010)


385-385: Starting a process with a partial executable path

(S607)


408-408: subprocess call: check for execution of untrusted input

(S603)


409-409: Starting a process with a partial executable path

(S607)


423-423: Consider moving this statement to an else block

(TRY300)


424-424: Do not catch blind exception: Exception

(BLE001)


433-433: Do not catch blind exception: Exception

(BLE001)


441-441: subprocess call: check for execution of untrusted input

(S603)


442-442: Starting a process with a partial executable path

(S607)


447-447: Consider moving this statement to an else block

(TRY300)


452-452: Do not catch blind exception: Exception

(BLE001)


462-462: Starting a process with a partial executable path

(S607)


468-468: Unpacked variable stdout is never used

Prefix it with an underscore or any other dummy variable pattern

(RUF059)


475-475: Consider moving this statement to an else block

(TRY300)


476-476: Do not catch blind exception: Exception

(BLE001)


506-506: subprocess call: check for execution of untrusted input

(S603)


507-507: Starting a process with a partial executable path

(S607)


517-518: try-except-pass detected, consider logging the exception

(S110)


517-517: Do not catch blind exception: Exception

(BLE001)


524-524: Do not catch blind exception: Exception

(BLE001)


574-574: Possible binding to all interfaces

(S104)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: e2e-tests-release-0-7
  • GitHub Check: e2e-tests (ubuntu-24.04-arm)
  • GitHub Check: e2e-tests (ubuntu-24.04)
  • GitHub Check: lint-go
  • GitHub Check: deploy-kind
  • GitHub Check: e2e-test-operator
  • GitHub Check: tests
🔇 Additional comments (10)
deploy/microshift-bootc/kustomization.yaml (1)

1-10: LGTM!

The Kustomization configuration is well-structured and follows Kubernetes labeling conventions. The resource reference and common labels are appropriate for this deployment.

deploy/microshift-bootc/Makefile (2)

18-35: LGTM!

The QCOW2 image generation target is well-configured with appropriate volume mounts, security options, and the latest bootc-image-builder. The privileged mode and security options are necessary for the bootc image building process.


45-49: LGTM!

The push target correctly uses non-sudo podman to leverage the user's registry credentials.

deploy/microshift-bootc/config-svc/app.py (7)

26-48: LGTM!

The authentication implementation correctly restricts access to the root user and uses PAM as the primary method with a reasonable fallback to su. The password is safely passed via stdin rather than command-line arguments.


51-68: LGTM!

The HTTP Basic Authentication decorator is correctly implemented with proper 401 response and WWW-Authenticate header.


262-275: LGTM!

The index route correctly retrieves system information and provides sensible defaults using nip.io for hostname suggestions.


278-331: LGTM!

The configuration handler correctly validates inputs, executes all three operations (password, hostname, CR), and provides appropriate feedback. The error aggregation ensures users see all failures rather than stopping at the first error.


380-426: LGTM!

The function correctly parses the default route and associated IP address, with appropriate error handling and nip.io formatting.


438-454: LGTM!

The hostname configuration correctly uses hostnamectl with proper error handling and informative return values.


567-574: LGTM - Network binding is intentional.

The service correctly binds to all interfaces (0.0.0.0) to allow remote access for configuration. This is appropriate given the service is protected by HTTP Basic Authentication and is intended for system administration.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 9

♻️ Duplicate comments (2)
deploy/microshift-bootc/config-svc/app.py (1)

1129-1175: Fix Jumpstarter CR apiVersion + apply against MicroShift explicitly.

  1. This still uses apiVersion: jumpstarter.dev/v1alpha1, but the CRD group is operator.jumpstarter.dev/v1alpha1 (per prior review).
  2. kubectl apply has no explicit --kubeconfig, so it can silently apply to the wrong cluster/context (or fail).
 def apply_jumpstarter_cr(base_domain, image):
     """Apply Jumpstarter Custom Resource using kubectl."""
     try:
+        kubeconfig_path = '/var/lib/microshift/resources/kubeadmin/kubeconfig'
         # Build the CR YAML
         cr = {
-            'apiVersion': 'jumpstarter.dev/v1alpha1',
+            'apiVersion': 'operator.jumpstarter.dev/v1alpha1',
             'kind': 'Jumpstarter',
             'metadata': {
                 'name': 'jumpstarter',
                 'namespace': 'default'
             },
...
             result = subprocess.run(
-                ['kubectl', 'apply', '-f', temp_file],
+                ['kubectl', '--kubeconfig', kubeconfig_path, 'apply', '-f', temp_file],
                 capture_output=True,
                 text=True,
                 check=True
             )
deploy/microshift-bootc/Makefile (1)

15-16: Fix typo in log message (“buinding” → “building”).

-	@echo "Building bootc image: $(BOOTC_IMG): buinding as root to be on the container storage from root"
+	@echo "Building bootc image: $(BOOTC_IMG): building as root to be on the container storage from root"
🧹 Nitpick comments (2)
deploy/microshift-bootc/config-svc/app.py (2)

1177-1213: Homegrown YAML emitter is too fragile for user-controlled strings; use a real YAML library.
json_to_yaml() / yaml_value() won’t correctly escape quotes/newlines/etc., and can generate invalid YAML (or surprise keys) for certain inputs. Prefer yaml.safe_dump() (PyYAML or ruamel.yaml) and keep quoting/escaping correct by construction.

+import yaml
...
-            yaml_content = json_to_yaml(cr)
+            yaml_content = yaml.safe_dump(cr, sort_keys=False)

1215-1229: Consider making bind host configurable (and avoid accidental LAN exposure).
Binding 0.0.0.0 is fine for container use, but it’s easy to expose the root-auth UI unintentionally. Consider BIND_HOST env defaulting to 127.0.0.1 for dev.

 def main():
     """Main entry point."""
     port = int(os.environ.get('PORT', 8080))
+    bind_host = os.environ.get('BIND_HOST', '0.0.0.0')
 ...
-    app.run(host='0.0.0.0', port=port, debug=False)
+    app.run(host=bind_host, port=port, debug=False)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c0353a6 and 7bb3024.

📒 Files selected for processing (8)
  • deploy/microshift-bootc/Containerfile (1 hunks)
  • deploy/microshift-bootc/Makefile (1 hunks)
  • deploy/microshift-bootc/README.md (1 hunks)
  • deploy/microshift-bootc/config-svc/app.py (1 hunks)
  • deploy/microshift-bootc/config-svc/config-svc.service (1 hunks)
  • deploy/microshift-bootc/config.toml (1 hunks)
  • deploy/microshift-bootc/kustomization.yaml (1 hunks)
  • deploy/microshift-bootc/run-microshift.sh (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • deploy/microshift-bootc/kustomization.yaml
  • deploy/microshift-bootc/config-svc/config-svc.service
  • deploy/microshift-bootc/Containerfile
  • deploy/microshift-bootc/config.toml
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-10-24T11:57:23.796Z
Learnt from: mangelajo
Repo: jumpstarter-dev/jumpstarter-controller PR: 170
File: deploy/operator/internal/controller/jumpstarter/jumpstarter_controller.go:328-333
Timestamp: 2025-10-24T11:57:23.796Z
Learning: In the jumpstarter-controller operator (deploy/operator/), the design allows only one Jumpstarter CR per namespace, which will be enforced by a validation webhook. This constraint eliminates concerns about resource name collisions within a namespace.

Applied to files:

  • deploy/microshift-bootc/config-svc/app.py
🪛 checkmake (0.2.2)
deploy/microshift-bootc/Makefile

[warning] 86-86: Target body for "clean" exceeds allowed length of 5 (6).

(maxbodylength)


[warning] 1-1: Missing required phony target "all"

(minphony)


[warning] 1-1: Missing required phony target "clean"

(minphony)


[warning] 1-1: Missing required phony target "test"

(minphony)

🪛 LanguageTool
deploy/microshift-bootc/README.md

[grammar] ~1-~1: Ensure spelling is correct
Context: # MicroShift Bootc Deployment This directory contains the...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)


[grammar] ~35-~35: Ensure spelling is correct
Context: ...ended ## Quick Start ### 1. Build the Bootc Image bash make bootc-build Th...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

🪛 markdownlint-cli2 (0.18.1)
deploy/microshift-bootc/README.md

56-56: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


184-184: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🪛 Ruff (0.14.8)
deploy/microshift-bootc/config-svc/app.py

40-40: subprocess call: check for execution of untrusted input

(S603)


41-41: Starting a process with a partial executable path

(S607)


46-46: Consider moving this statement to an else block

(TRY300)


47-47: Do not catch blind exception: Exception

(BLE001)


78-127: Possible hardcoded password assigned to: "PASSWORD_REQUIRED_TEMPLATE"

(S105)


841-841: subprocess call: check for execution of untrusted input

(S603)


842-842: Starting a process with a partial executable path

(S607)


898-898: Do not catch blind exception: Exception

(BLE001)


899-899: Use explicit conversion flag

Replace with conversion flag

(RUF010)


949-949: Do not catch blind exception: Exception

(BLE001)


950-950: Use explicit conversion flag

Replace with conversion flag

(RUF010)


980-980: Do not catch blind exception: Exception

(BLE001)


990-990: Starting a process with a partial executable path

(S607)


1013-1013: subprocess call: check for execution of untrusted input

(S603)


1014-1014: Starting a process with a partial executable path

(S607)


1028-1028: Consider moving this statement to an else block

(TRY300)


1029-1029: Do not catch blind exception: Exception

(BLE001)


1038-1038: Do not catch blind exception: Exception

(BLE001)


1046-1046: subprocess call: check for execution of untrusted input

(S603)


1047-1047: Starting a process with a partial executable path

(S607)


1052-1052: Consider moving this statement to an else block

(TRY300)


1057-1057: Do not catch blind exception: Exception

(BLE001)


1067-1067: Starting a process with a partial executable path

(S607)


1073-1073: Unpacked variable stdout is never used

Prefix it with an underscore or any other dummy variable pattern

(RUF059)


1080-1080: Consider moving this statement to an else block

(TRY300)


1081-1081: Do not catch blind exception: Exception

(BLE001)


1124-1124: Do not catch blind exception: Exception

(BLE001)


1154-1154: subprocess call: check for execution of untrusted input

(S603)


1155-1155: Starting a process with a partial executable path

(S607)


1165-1166: try-except-pass detected, consider logging the exception

(S110)


1165-1165: Do not catch blind exception: Exception

(BLE001)


1172-1172: Do not catch blind exception: Exception

(BLE001)


1229-1229: Possible binding to all interfaces

(S104)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: e2e-test-operator
  • GitHub Check: deploy-kind
  • GitHub Check: tests
  • GitHub Check: e2e-tests (ubuntu-24.04-arm)
  • GitHub Check: lint-go
  • GitHub Check: e2e-tests (ubuntu-24.04)
  • GitHub Check: e2e-tests-release-0-7

Comment on lines 130 to 250
PODS_TEMPLATE = """<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Pod Status - Jumpstarter</title>
<link href="https://jumpstarter.dev/_static/favicon.png" rel="shortcut icon">
<link rel="stylesheet" href="/static/styles.css">
<style>
/* Pods page specific overrides */
.container {
max-width: 1400px;
}
</style>
</head>
<body>
<div class="container">
<div class="banner">
<div class="banner-text">Jumpstarter Controller Community Edition • Powered by MicroShift</div>
<div class="logos">
<a href="https://jumpstarter.dev/" target="_blank" rel="noopener noreferrer" class="logo-link" title="Jumpstarter - Remote device management and testing">
<img src="https://jumpstarter.dev/main/_static/logo-light-theme.svg" alt="Jumpstarter" class="jumpstarter-logo" />
</a>
<a href="https://microshift.io/" target="_blank" rel="noopener noreferrer" class="logo-link" title="MicroShift - Optimized OpenShift for the device edge">
<img src="https://microshift.io/images/microshift_logo_white.png" alt="MicroShift" class="microshift-logo" />
</a>
</div>
</div>
<div class="header">
<div>
<h1>Pod Status Monitor</h1>
<div class="refresh-info">Auto-refreshing every 5 seconds</div>
</div>
<a href="/" class="back-btn">← Back to Configuration</a>
</div>

<div id="error-container"></div>
<div id="pod-count" class="pod-count"></div>

<div class="table-wrapper">
<table id="pods-table">
<thead>
<tr>
<th>Namespace</th>
<th>Name</th>
<th>Ready</th>
<th>Status</th>
<th>Restarts</th>
<th>Age</th>
<th>Node</th>
</tr>
</thead>
<tbody id="pods-body">
<tr>
<td colspan="7" class="loading">Loading pods...</td>
</tr>
</tbody>
</table>
</div>
</div>

<script>
function getStatusClass(status) {
const statusLower = status.toLowerCase();
if (statusLower === 'running') return 'status-running';
if (statusLower === 'pending') return 'status-pending';
if (statusLower === 'failed' || statusLower === 'error') return 'status-failed';
if (statusLower === 'succeeded' || statusLower === 'completed') return 'status-succeeded';
if (statusLower.includes('crashloop')) return 'status-crashloopbackoff';
return 'status-unknown';
}

function updatePods() {
fetch('/api/pods')
.then(response => response.json())
.then(data => {
const errorContainer = document.getElementById('error-container');
const podCount = document.getElementById('pod-count');
const tbody = document.getElementById('pods-body');

if (data.error) {
errorContainer.innerHTML = '<div class="error">' + data.error + '</div>';
tbody.innerHTML = '<tr><td colspan="7" class="loading">Failed to load pods</td></tr>';
return;
}

errorContainer.innerHTML = '';
podCount.textContent = 'Total pods: ' + data.pods.length;

if (data.pods.length === 0) {
tbody.innerHTML = '<tr><td colspan="7" class="loading">No pods found</td></tr>';
return;
}

tbody.innerHTML = data.pods.map(pod => `
<tr>
<td>${pod.namespace}</td>
<td>${pod.name}</td>
<td>${pod.ready}</td>
<td><span class="status-badge ${getStatusClass(pod.status)}">${pod.status}</span></td>
<td>${pod.restarts}</td>
<td>${pod.age}</td>
<td>${pod.node}</td>
</tr>
`).join('');
})
.catch(error => {
console.error('Error fetching pods:', error);
document.getElementById('error-container').innerHTML =
'<div class="error">Failed to fetch pod data: ' + error.message + '</div>';
});
}

// Initial load
updatePods();

// Refresh every 5 seconds
setInterval(updatePods, 5000);
</script>
</body>
</html>"""
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

DOM XSS on /pods: untrusted pod fields and data.error are injected via innerHTML / template literals.
Pod names/namespaces/status can be attacker-controlled by any workload author in-cluster; rendering them via HTML strings is an XSS vector. Build DOM nodes and set textContent (and avoid innerHTML for errors).

- errorContainer.innerHTML = '<div class="error">' + data.error + '</div>';
+ const err = document.createElement('div');
+ err.className = 'error';
+ err.textContent = data.error;
+ errorContainer.replaceChildren(err);
...
- tbody.innerHTML = data.pods.map(pod => `...`).join('');
+ tbody.replaceChildren(...data.pods.map(pod => {
+   const tr = document.createElement('tr');
+   const tdNs = document.createElement('td'); tdNs.textContent = pod.namespace;
+   const tdName = document.createElement('td'); tdName.textContent = pod.name;
+   const tdReady = document.createElement('td'); tdReady.textContent = pod.ready;
+   const tdStatus = document.createElement('td');
+   const badge = document.createElement('span');
+   badge.className = `status-badge ${getStatusClass(pod.status)}`;
+   badge.textContent = pod.status;
+   tdStatus.appendChild(badge);
+   const tdRestarts = document.createElement('td'); tdRestarts.textContent = String(pod.restarts);
+   const tdAge = document.createElement('td'); tdAge.textContent = pod.age;
+   const tdNode = document.createElement('td'); tdNode.textContent = pod.node;
+   tr.append(tdNs, tdName, tdReady, tdStatus, tdRestarts, tdAge, tdNode);
+   return tr;
+ }));
🤖 Prompt for AI Agents
In deploy/microshift-bootc/config-svc/app.py around lines 130 to 250, the client
HTML currently injects untrusted pod fields and data.error via
innerHTML/template literals causing DOM XSS; replace all innerHTML-based
rendering for errors and table rows with DOM node creation and textContent
assignments. Specifically: when data.error is present, set
errorContainer.textContent (or create a div element and set its textContent)
instead of injecting HTML; when rendering pods, clear tbody and for each pod
create a tr with td elements, assigning
pod.namespace/name/ready/status/restarts/age/node via textContent, create the
status badge span and add classes with classList.add rather than injecting HTML;
for loading/no-pods messages create a tr>td and set td.textContent; remove all
uses of innerHTML for untrusted content and only use innerHTML for static/safe
templates if needed.

Comment on lines +55 to +64
**Output example:**
```
MicroShift is running in a bootc container
Hostname: jumpstarter.10.0.2.2.nip.io
Container: jumpstarter-microshift-okd
LVM disk: /var/lib/microshift-okd/lvmdisk.image
VG name: myvg1
Ports: HTTP:80, HTTPS:443, Config Service:8880
```

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Add languages to fenced code blocks to satisfy markdownlint (MD040).
At least the “Output example” and the architecture diagram blocks should specify a language (text is fine).

-```
+```text
 MicroShift is running in a bootc container
 ...

...
- +text
┌─────────────────────────────────────────────┐
...

Also applies to: 184-195

🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

56-56: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
In deploy/microshift-bootc/README.md around lines 55 to 64 and also around lines
184 to 195, the fenced code blocks currently lack a language identifier which
triggers markdownlint MD040; update each triple-backtick fence for the “Output
example” block and the architecture diagram block to include a language (use
"text") so the opening fences become ```text, leaving the block contents
unchanged.

@mangelajo mangelajo force-pushed the microshift-image branch 3 times, most recently from 121a1f3 to 87c6824 Compare December 14, 2025 15:53
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (15)
deploy/microshift-bootc/README.md (2)

55-64: Add language specifier to fenced code blocks.

This was flagged in a previous review. The output example block should specify text as the language.


184-195: Add language specifier to the architecture diagram code block.

This was flagged in a previous review. The diagram block should specify text as the language.

deploy/microshift-bootc/run-microshift.sh (4)

86-86: Hostname is hardcoded instead of using the host's default route IP.

This was flagged in a previous review. The README implies the hostname should use the host's IP address, but 127-0-0-1 is hardcoded.


66-78: Missing pvcreate before vgcreate on raw disk image.

As noted in a previous review, vgcreate typically requires the device to be initialized as a physical volume first. On a fresh truncated disk, this will likely fail.

         # Find available loop device
         LOOP_DEV=\$(losetup --find --show --nooverlap '${container_lvm_disk}')
         echo \"Created loop device: \${LOOP_DEV}\"
         
+        # Initialize physical volume
+        pvcreate -ff -y \"\${LOOP_DEV}\"
+        
         # Create volume group
         vgcreate -f -y '${vg_name}' \"\${LOOP_DEV}\"

116-124: Add timeout to kubeconfig wait loop to prevent indefinite hangs.

This was flagged in a previous review. If MicroShift fails to start, this loop will hang forever.

     echo "Waiting for MicroShift to start"
     local -r kubeconfig="/var/lib/microshift/resources/kubeadmin/kubeconfig"
+    local -r deadline=$((SECONDS + 180))
     while true ; do
         if podman exec "${container_name}" /bin/test -f "${kubeconfig}" &>/dev/null ; then
             break
         fi
+        if (( SECONDS > deadline )); then
+            echo "ERROR: Timed out waiting for kubeconfig" >&2
+            return 1
+        fi
         sleep 1
     done

157-157: Config Service URL will not resolve.

${HOSTNAME%%.*} strips the domain, resulting in http://jumpstarter:8880 which won't resolve externally. Consider using http://localhost:${CONFIG_SVC_PORT} only, or use the full hostname.

-echo " - Config Service: http://${HOSTNAME%%.*}:${CONFIG_SVC_PORT} or http://localhost:${CONFIG_SVC_PORT}"
+echo " - Config Service: http://localhost:${CONFIG_SVC_PORT}"
deploy/microshift-bootc/Makefile (4)

15-15: Typo: "buinding" should be "building".

This was flagged in a previous review.


50-53: podman push will fail because image is in root's storage.

Since bootc-build uses sudo podman build, the push command should also use sudo podman push. This was flagged in a previous review.


86-89: podman rmi will fail because image is in root's storage.

Consistent with the build target, this should use sudo podman rmi. This was flagged in a previous review.


68-68: Missing space before ## breaks prerequisite.

bootc-stop## becomes a literal target name. This was flagged in a previous review.

-bootc-rm: bootc-stop## Remove the MicroShift container
+bootc-rm: bootc-stop ## Remove the MicroShift container
deploy/microshift-bootc/config-svc/app.py (5)

27-50: su fallback authentication is unreliable without a TTY.

The su command typically requires a TTY for password input. Providing password via stdin often won't authenticate correctly, potentially locking users out if PAM isn't available. This was flagged in a previous review.


1154-1170: Validate hostname/baseDomain input.

Arbitrary input to hostnamectl set-hostname could cause issues. Consider validating against a hostname pattern. This was flagged in a previous review for the configure endpoint.

+import re
+HOSTNAME_RE = re.compile(r'^(?=.{1,253}$)(?!-)([a-zA-Z0-9-]{1,63}(?<!-)\.)*[a-zA-Z0-9-]{1,63}(?<!-)$')
+
 def set_hostname(hostname):
     """Set the system hostname using hostnamectl."""
+    if not HOSTNAME_RE.match(hostname):
+        return False, "Invalid hostname format"
     try:

1247-1258: Fix apiVersion for Jumpstarter CR.

The CR uses apiVersion: 'jumpstarter.dev/v1alpha1', but the Jumpstarter CRD is defined in the operator.jumpstarter.dev group. This will cause the CR to fail when applied. This was flagged in a previous review.

         cr = {
-            'apiVersion': 'jumpstarter.dev/v1alpha1',
+            'apiVersion': 'operator.jumpstarter.dev/v1alpha1',
             'kind': 'Jumpstarter',

210-234: DOM XSS vulnerability via innerHTML with pod data.

Pod names, namespaces, and status values from the cluster are inserted via template literals into innerHTML. Any workload author in the cluster could inject malicious scripts. This was flagged in a previous review.

Use DOM APIs with textContent instead of innerHTML:

// Replace template literal injection with safe DOM construction
tbody.replaceChildren(...data.pods.map(pod => {
    const tr = document.createElement('tr');
    [pod.namespace, pod.name, pod.ready].forEach(val => {
        const td = document.createElement('td');
        td.textContent = val;
        tr.appendChild(td);
    });
    // ... status badge with textContent, restarts, age, node
    return tr;
}));

1173-1194: Validate password to prevent chpasswd injection.

If the password contains : or newline characters, it could break the chpasswd input format or inject additional entries. This was flagged in a previous review.

 def set_root_password(password):
     """Set the root user password using chpasswd."""
+    # Validate password to prevent chpasswd format injection
+    if any(c in password for c in (':', '\n', '\r')):
+        return False, "Password contains invalid characters (: or newlines not allowed)"
+    
     try:
         # Use chpasswd to set password (more reliable than passwd for scripting)
🧹 Nitpick comments (1)
deploy/microshift-bootc/Makefile (1)

1-1: Add clean to .PHONY declaration.

The clean target at line 86 should be declared as phony to ensure it always runs.

-.PHONY: help build bootc-build push bootc-push bootc-run bootc-stop bootc-sh bootc-rm
+.PHONY: help build bootc-build push bootc-push bootc-run bootc-stop bootc-sh bootc-rm clean build-image bootc-reload-app
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7bb3024 and 87c6824.

📒 Files selected for processing (10)
  • deploy/microshift-bootc/Containerfile (1 hunks)
  • deploy/microshift-bootc/Makefile (1 hunks)
  • deploy/microshift-bootc/README.md (1 hunks)
  • deploy/microshift-bootc/config-svc/app.py (1 hunks)
  • deploy/microshift-bootc/config-svc/config-svc.service (1 hunks)
  • deploy/microshift-bootc/config-svc/update-banner.service (1 hunks)
  • deploy/microshift-bootc/config-svc/update-banner.sh (1 hunks)
  • deploy/microshift-bootc/config.toml (1 hunks)
  • deploy/microshift-bootc/kustomization.yaml (1 hunks)
  • deploy/microshift-bootc/run-microshift.sh (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • deploy/microshift-bootc/Containerfile
  • deploy/microshift-bootc/config-svc/config-svc.service
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-05-13T19:56:27.924Z
Learnt from: NickCao
Repo: jumpstarter-dev/jumpstarter-controller PR: 137
File: deploy/helm/jumpstarter/charts/jumpstarter-controller/templates/router-deployment.yaml:23-26
Timestamp: 2025-05-13T19:56:27.924Z
Learning: In the jumpstarter-controller project, the router service uses the same ConfigMap as the controller service (controller-cm.yaml) even though it has been moved to its own separate deployment.

Applied to files:

  • deploy/microshift-bootc/run-microshift.sh
📚 Learning: 2025-10-24T11:57:23.796Z
Learnt from: mangelajo
Repo: jumpstarter-dev/jumpstarter-controller PR: 170
File: deploy/operator/internal/controller/jumpstarter/jumpstarter_controller.go:328-333
Timestamp: 2025-10-24T11:57:23.796Z
Learning: In the jumpstarter-controller operator (deploy/operator/), the design allows only one Jumpstarter CR per namespace, which will be enforced by a validation webhook. This constraint eliminates concerns about resource name collisions within a namespace.

Applied to files:

  • deploy/microshift-bootc/kustomization.yaml
  • deploy/microshift-bootc/config-svc/app.py
🪛 checkmake (0.2.2)
deploy/microshift-bootc/Makefile

[warning] 86-86: Target body for "clean" exceeds allowed length of 5 (6).

(maxbodylength)


[warning] 1-1: Missing required phony target "all"

(minphony)


[warning] 1-1: Missing required phony target "clean"

(minphony)


[warning] 1-1: Missing required phony target "test"

(minphony)

🪛 LanguageTool
deploy/microshift-bootc/README.md

[grammar] ~1-~1: Ensure spelling is correct
Context: # MicroShift Bootc Deployment This directory contains the...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)


[grammar] ~35-~35: Ensure spelling is correct
Context: ...ended ## Quick Start ### 1. Build the Bootc Image bash make bootc-build Th...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

🪛 markdownlint-cli2 (0.18.1)
deploy/microshift-bootc/README.md

56-56: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


184-184: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🪛 Ruff (0.14.8)
deploy/microshift-bootc/config-svc/app.py

40-40: subprocess call: check for execution of untrusted input

(S603)


41-41: Starting a process with a partial executable path

(S607)


46-46: Consider moving this statement to an else block

(TRY300)


47-47: Do not catch blind exception: Exception

(BLE001)


78-127: Possible hardcoded password assigned to: "PASSWORD_REQUIRED_TEMPLATE"

(S105)


899-899: subprocess call: check for execution of untrusted input

(S603)


900-900: Starting a process with a partial executable path

(S607)


930-930: Local variable e is assigned to but never used

Remove assignment to unused variable e

(F841)


935-935: Do not catch blind exception: Exception

(BLE001)


935-935: Local variable e is assigned to but never used

Remove assignment to unused variable e

(F841)


952-952: subprocess call: check for execution of untrusted input

(S603)


953-953: Starting a process with a partial executable path

(S607)


1009-1009: Do not catch blind exception: Exception

(BLE001)


1010-1010: Use explicit conversion flag

Replace with conversion flag

(RUF010)


1060-1060: Do not catch blind exception: Exception

(BLE001)


1061-1061: Use explicit conversion flag

Replace with conversion flag

(RUF010)


1091-1091: Do not catch blind exception: Exception

(BLE001)


1101-1101: Starting a process with a partial executable path

(S607)


1124-1124: subprocess call: check for execution of untrusted input

(S603)


1125-1125: Starting a process with a partial executable path

(S607)


1139-1139: Consider moving this statement to an else block

(TRY300)


1140-1140: Do not catch blind exception: Exception

(BLE001)


1149-1149: Do not catch blind exception: Exception

(BLE001)


1157-1157: subprocess call: check for execution of untrusted input

(S603)


1158-1158: Starting a process with a partial executable path

(S607)


1163-1163: Consider moving this statement to an else block

(TRY300)


1168-1168: Do not catch blind exception: Exception

(BLE001)


1178-1178: Starting a process with a partial executable path

(S607)


1184-1184: Unpacked variable stdout is never used

Prefix it with an underscore or any other dummy variable pattern

(RUF059)


1191-1191: Consider moving this statement to an else block

(TRY300)


1192-1192: Do not catch blind exception: Exception

(BLE001)


1231-1231: Do not catch blind exception: Exception

(BLE001)


1268-1268: subprocess call: check for execution of untrusted input

(S603)


1269-1269: Starting a process with a partial executable path

(S607)


1279-1280: try-except-pass detected, consider logging the exception

(S110)


1279-1279: Do not catch blind exception: Exception

(BLE001)


1286-1286: Do not catch blind exception: Exception

(BLE001)


1343-1343: Possible binding to all interfaces

(S104)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: lint-go
  • GitHub Check: e2e-test-operator
  • GitHub Check: e2e-tests (ubuntu-24.04)
  • GitHub Check: e2e-tests (ubuntu-24.04-arm)
  • GitHub Check: e2e-tests-release-0-7
  • GitHub Check: deploy-kind
  • GitHub Check: tests
🔇 Additional comments (6)
deploy/microshift-bootc/kustomization.yaml (1)

1-11: LGTM!

The kustomization file is well-structured with proper labels following Kubernetes conventions.

deploy/microshift-bootc/README.md (1)

1-420: Comprehensive and well-organized documentation.

The README provides thorough coverage of setup, usage, troubleshooting, and architecture. The community edition disclaimer and security notes are particularly helpful.

deploy/microshift-bootc/config.toml (1)

1-38: Configuration looks appropriate for the bootc deployment.

LVM setup with volume group myvg1 and XFS root filesystem follows sensible defaults for the MicroShift use case.

deploy/microshift-bootc/config-svc/update-banner.service (1)

1-19: LGTM!

The systemd service is properly configured as a oneshot with correct ordering dependencies to ensure the banner is updated before the login prompt appears.

deploy/microshift-bootc/config-svc/app.py (2)

1343-1343: Flask development server binds to all interfaces.

app.run(host='0.0.0.0', ...) exposes the service to all network interfaces. This is intentional for the config UI use case, but ensure the documentation reflects this security consideration (which it does in the README security notes).


1064-1093: Age calculation helper is well-implemented.

Clean implementation with proper timezone handling and graceful fallback on errors.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (9)
deploy/microshift-bootc/README.md (2)

55-64: Add language identifier to fenced code block.

The output example code block is missing a language identifier, which triggers markdownlint MD040.

Apply this diff:

 **Output example:**
-```
+```text
 MicroShift is running in a bootc container
 Hostname:  jumpstarter.10.0.2.2.nip.io

184-195: Add language identifier to architecture diagram code block.

The architecture diagram code block is missing a language identifier, which triggers markdownlint MD040.

Apply this diff:

 ### Components
 
-```
+```text
 ┌─────────────────────────────────────────────┐
 │  Bootc Container / Image                    │
deploy/microshift-bootc/Makefile (4)

14-17: Fix typo: "buinding" should be "building".

Apply this diff:

 bootc-build: ## Build the bootc image with MicroShift
-	@echo "Building bootc image: $(BOOTC_IMG): buinding as root to be on the container storage from root"
+	@echo "Building bootc image: $(BOOTC_IMG): building as root to be on the container storage from root"
 	sudo podman build -t $(BOOTC_IMG) -f Containerfile ../..

50-53: Add sudo to podman push for consistency.

Since bootc-build uses sudo podman build, the image is in root's container storage. The podman push command needs sudo to access it.

Apply this diff:

 bootc-push: ## Push the bootc image to registry
 	@echo "Pushing bootc image: $(BOOTC_IMG)"
-	podman push $(BOOTC_IMG)
+	sudo podman push $(BOOTC_IMG)

68-68: Fix missing space before comment marker.

The lack of space before ## causes bootc-stop## to be treated as a literal prerequisite name, preventing bootc-stop from running.

Apply this diff:

-bootc-rm: bootc-stop## Remove the MicroShift container
+bootc-rm: bootc-stop ## Remove the MicroShift container

86-89: Add sudo to podman rmi for consistency.

Since the image was built with sudo podman build, it's in root's storage and requires sudo to remove.

Apply this diff:

 clean: ## Clean up local images and build artifacts
 	@echo "Removing local images..."
-	-podman rmi $(BOOTC_IMG)
+	-sudo podman rmi $(BOOTC_IMG)
deploy/microshift-bootc/config-svc/app.py (3)

260-260: DOM XSS vulnerability: untrusted data injected via innerHTML.

User-controlled values from pod/route data and error messages are injected directly into the DOM via innerHTML, creating an XSS vulnerability. Pod names and other fields can be controlled by workload authors.

Replace innerHTML-based rendering with DOM node creation and textContent assignments to prevent XSS.

Also applies to: 273-284, 312-312, 325-336


884-971: Validate password input to prevent chpasswd injection.

The password is passed to chpasswd without validating for colon (:) or newline characters, which could cause command injection since chpasswd expects user:password\n format.

Add validation before calling set_root_password():

 def change_password():
     new_password = request.form.get('newPassword', '').strip()
     confirm_password = request.form.get('confirmPassword', '').strip()
+    
+    if any(c in new_password for c in (':', '\n', '\r')):
+        messages.append({'type': 'error', 'text': 'Password contains invalid characters'})
+        # return error response

974-1021: Validate base domain as proper hostname.

The baseDomain parameter is passed to set_hostname() without validation, which could result in invalid hostnames or unexpected behavior.

Add hostname validation:

+import re
+HOSTNAME_RE = re.compile(r"^(?=.{1,253}$)(?!-)([a-zA-Z0-9-]{1,63}(?<!-)\.)*[a-zA-Z0-9-]{1,63}(?<!-)$")
+
 def configure_jumpstarter():
     base_domain = request.form.get('baseDomain', '').strip()
     image = request.form.get('image', '').strip()
     
+    if base_domain and not HOSTNAME_RE.match(base_domain):
+        messages.append({'type': 'error', 'text': 'Base domain is not a valid hostname'})
+        # return error response
🧹 Nitpick comments (1)
deploy/microshift-bootc/Containerfile (1)

4-7: Pin python-pam version for reproducible builds.

The python-pam package is installed via pip without version pinning, which can lead to non-reproducible builds and unexpected behavior if the package is updated.

Consider applying this diff:

 RUN dnf install -y epel-release && \
     dnf install -y python3 iproute python3-flask python3-pip && \
-    pip3 install python-pam && \
+    pip3 install --no-cache-dir python-pam==2.0.2 && \
     dnf clean all

Note: Verify the appropriate version by checking PyPI or your project requirements.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 87c6824 and 0bc1fcc.

📒 Files selected for processing (10)
  • deploy/microshift-bootc/Containerfile (1 hunks)
  • deploy/microshift-bootc/Makefile (1 hunks)
  • deploy/microshift-bootc/README.md (1 hunks)
  • deploy/microshift-bootc/config-svc/app.py (1 hunks)
  • deploy/microshift-bootc/config-svc/config-svc.service (1 hunks)
  • deploy/microshift-bootc/config-svc/update-banner.service (1 hunks)
  • deploy/microshift-bootc/config-svc/update-banner.sh (1 hunks)
  • deploy/microshift-bootc/config.toml (1 hunks)
  • deploy/microshift-bootc/kustomization.yaml (1 hunks)
  • deploy/microshift-bootc/run-microshift.sh (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • deploy/microshift-bootc/kustomization.yaml
🚧 Files skipped from review as they are similar to previous changes (5)
  • deploy/microshift-bootc/config.toml
  • deploy/microshift-bootc/run-microshift.sh
  • deploy/microshift-bootc/config-svc/update-banner.sh
  • deploy/microshift-bootc/config-svc/config-svc.service
  • deploy/microshift-bootc/config-svc/update-banner.service
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-10-24T11:57:23.796Z
Learnt from: mangelajo
Repo: jumpstarter-dev/jumpstarter-controller PR: 170
File: deploy/operator/internal/controller/jumpstarter/jumpstarter_controller.go:328-333
Timestamp: 2025-10-24T11:57:23.796Z
Learning: In the jumpstarter-controller operator (deploy/operator/), the design allows only one Jumpstarter CR per namespace, which will be enforced by a validation webhook. This constraint eliminates concerns about resource name collisions within a namespace.

Applied to files:

  • deploy/microshift-bootc/config-svc/app.py
🪛 checkmake (0.2.2)
deploy/microshift-bootc/Makefile

[warning] 86-86: Target body for "clean" exceeds allowed length of 5 (6).

(maxbodylength)


[warning] 1-1: Missing required phony target "all"

(minphony)


[warning] 1-1: Missing required phony target "clean"

(minphony)


[warning] 1-1: Missing required phony target "test"

(minphony)

🪛 LanguageTool
deploy/microshift-bootc/README.md

[grammar] ~1-~1: Ensure spelling is correct
Context: # MicroShift Bootc Deployment This directory contains the...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)


[grammar] ~35-~35: Ensure spelling is correct
Context: ...ended ## Quick Start ### 1. Build the Bootc Image bash make bootc-build Th...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

🪛 markdownlint-cli2 (0.18.1)
deploy/microshift-bootc/README.md

56-56: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


184-184: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🪛 Ruff (0.14.8)
deploy/microshift-bootc/config-svc/app.py

40-40: subprocess call: check for execution of untrusted input

(S603)


41-41: Starting a process with a partial executable path

(S607)


46-46: Consider moving this statement to an else block

(TRY300)


47-47: Do not catch blind exception: Exception

(BLE001)


78-127: Possible hardcoded password assigned to: "PASSWORD_REQUIRED_TEMPLATE"

(S105)


1044-1044: subprocess call: check for execution of untrusted input

(S603)


1045-1045: Starting a process with a partial executable path

(S607)


1075-1075: Local variable e is assigned to but never used

Remove assignment to unused variable e

(F841)


1080-1080: Do not catch blind exception: Exception

(BLE001)


1080-1080: Local variable e is assigned to but never used

Remove assignment to unused variable e

(F841)


1097-1097: subprocess call: check for execution of untrusted input

(S603)


1098-1098: Starting a process with a partial executable path

(S607)


1154-1154: Do not catch blind exception: Exception

(BLE001)


1155-1155: Use explicit conversion flag

Replace with conversion flag

(RUF010)


1171-1171: subprocess call: check for execution of untrusted input

(S603)


1172-1172: Starting a process with a partial executable path

(S607)


1234-1234: Do not catch blind exception: Exception

(BLE001)


1235-1235: Use explicit conversion flag

Replace with conversion flag

(RUF010)


1253-1253: subprocess call: check for execution of untrusted input

(S603)


1254-1254: Starting a process with a partial executable path

(S607)


1267-1267: Do not catch blind exception: Exception

(BLE001)


1268-1268: Use explicit conversion flag

Replace with conversion flag

(RUF010)


1275-1275: Do not catch blind exception: Exception

(BLE001)


1395-1395: Do not catch blind exception: Exception

(BLE001)


1396-1396: Use explicit conversion flag

Replace with conversion flag

(RUF010)


1426-1426: Do not catch blind exception: Exception

(BLE001)


1436-1436: Starting a process with a partial executable path

(S607)


1459-1459: subprocess call: check for execution of untrusted input

(S603)


1460-1460: Starting a process with a partial executable path

(S607)


1474-1474: Consider moving this statement to an else block

(TRY300)


1475-1475: Do not catch blind exception: Exception

(BLE001)


1484-1484: Do not catch blind exception: Exception

(BLE001)


1492-1492: subprocess call: check for execution of untrusted input

(S603)


1493-1493: Starting a process with a partial executable path

(S607)


1498-1498: Consider moving this statement to an else block

(TRY300)


1503-1503: Do not catch blind exception: Exception

(BLE001)


1513-1513: Starting a process with a partial executable path

(S607)


1519-1519: Unpacked variable stdout is never used

Prefix it with an underscore or any other dummy variable pattern

(RUF059)


1526-1526: Consider moving this statement to an else block

(TRY300)


1527-1527: Do not catch blind exception: Exception

(BLE001)


1566-1566: Do not catch blind exception: Exception

(BLE001)


1633-1633: subprocess call: check for execution of untrusted input

(S603)


1634-1634: Starting a process with a partial executable path

(S607)


1644-1645: try-except-pass detected, consider logging the exception

(S110)


1644-1644: Do not catch blind exception: Exception

(BLE001)


1651-1651: Do not catch blind exception: Exception

(BLE001)


1708-1708: Possible binding to all interfaces

(S104)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: lint-go
  • GitHub Check: e2e-test-operator
  • GitHub Check: tests
  • GitHub Check: deploy-kind
  • GitHub Check: e2e-tests-release-0-7
  • GitHub Check: e2e-tests (ubuntu-24.04-arm)
  • GitHub Check: e2e-tests (ubuntu-24.04)
🔇 Additional comments (5)
deploy/microshift-bootc/Containerfile (5)

1-1: LGTM: Base image properly pinned.

The base image uses a specific version tag, which ensures reproducible builds.


9-12: LGTM: Manifest installation is correct.

The manifests are properly copied to the MicroShift manifests directory with appropriate naming convention.


14-18: LGTM: Firewall configuration is appropriate.

Correctly uses firewall-offline-cmd during the build phase, and the comment explains the rationale.


20-21: LGTM: Default password with forced change mechanism.

The default password is appropriately documented in the README, and the web UI (config-svc/app.py) enforces a password change on first use.


23-30: LGTM: Config service installation is correct.

All necessary components are copied, permissions are set, and systemd services are properly enabled.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
deploy/microshift-bootc/config-svc/config-svc.service (1)

6-6: Before= ordering may unnecessarily delay boot.

The [email protected] systemd-user-sessions.service directive forces this web UI service to start before login prompts appear. If the Flask app is slow to start or fails, it will delay all user logins. This ordering is typically reserved for essential early-boot services (like the update-banner script), not web UIs.

Consider removing this line unless the service must complete before any user can log in:

 After=network-online.target
 Wants=network-online.target
-[email protected] systemd-user-sessions.service
deploy/microshift-bootc/config-svc/app.py (1)

2031-2066: Prefer PyYAML over custom YAML serialization.

The custom json_to_yaml() and yaml_value() functions may not handle all YAML edge cases correctly (e.g., strings with quotes, newlines, unicode, or leading/trailing spaces). This could generate malformed YAML when applying the Jumpstarter CR.

Use an established YAML library instead:

+import yaml
+
 def json_to_yaml(obj, indent=0):
-    """Convert a JSON object to YAML format (simple implementation)."""
-    lines = []
-    indent_str = '  ' * indent
-    
-    if isinstance(obj, dict):
-        for key, value in obj.items():
-            if isinstance(value, (dict, list)):
-                lines.append(f"{indent_str}{key}:")
-                lines.append(json_to_yaml(value, indent + 1))
-            else:
-                lines.append(f"{indent_str}{key}: {yaml_value(value)}")
-    elif isinstance(obj, list):
-        for item in obj:
-            if isinstance(item, (dict, list)):
-                lines.append(f"{indent_str}-")
-                lines.append(json_to_yaml(item, indent + 1))
-            else:
-                lines.append(f"{indent_str}- {yaml_value(item)}")
-    
-    return '\n'.join(lines)
-
-
-def yaml_value(value):
-    """Format a value for YAML output."""
-    if value is None:
-        return 'null'
-    elif isinstance(value, bool):
-        return 'true' if value else 'false'
-    elif isinstance(value, str):
-        # Quote strings that contain special characters
-        if ':' in value or '#' in value or value.startswith('-'):
-            return f'"{value}"'
-        return value
-    else:
-        return str(value)
+    """Convert a JSON object to YAML format."""
+    return yaml.dump(obj, default_flow_style=False, sort_keys=False)

Then update the Containerfile to install PyYAML: RUN pip install flask pyyaml

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0bc1fcc and 57ed276.

📒 Files selected for processing (10)
  • deploy/microshift-bootc/Containerfile (1 hunks)
  • deploy/microshift-bootc/Makefile (1 hunks)
  • deploy/microshift-bootc/README.md (1 hunks)
  • deploy/microshift-bootc/config-svc/app.py (1 hunks)
  • deploy/microshift-bootc/config-svc/config-svc.service (1 hunks)
  • deploy/microshift-bootc/config-svc/update-banner.service (1 hunks)
  • deploy/microshift-bootc/config-svc/update-banner.sh (1 hunks)
  • deploy/microshift-bootc/config.toml (1 hunks)
  • deploy/microshift-bootc/kustomization.yaml (1 hunks)
  • deploy/microshift-bootc/run-microshift.sh (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • deploy/microshift-bootc/config-svc/update-banner.sh
  • deploy/microshift-bootc/run-microshift.sh
  • deploy/microshift-bootc/Containerfile
  • deploy/microshift-bootc/kustomization.yaml
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-10-24T11:57:23.796Z
Learnt from: mangelajo
Repo: jumpstarter-dev/jumpstarter-controller PR: 170
File: deploy/operator/internal/controller/jumpstarter/jumpstarter_controller.go:328-333
Timestamp: 2025-10-24T11:57:23.796Z
Learning: In the jumpstarter-controller operator (deploy/operator/), the design allows only one Jumpstarter CR per namespace, which will be enforced by a validation webhook. This constraint eliminates concerns about resource name collisions within a namespace.

Applied to files:

  • deploy/microshift-bootc/config-svc/app.py
🪛 checkmake (0.2.2)
deploy/microshift-bootc/Makefile

[warning] 86-86: Target body for "clean" exceeds allowed length of 5 (6).

(maxbodylength)


[warning] 1-1: Missing required phony target "all"

(minphony)


[warning] 1-1: Missing required phony target "clean"

(minphony)


[warning] 1-1: Missing required phony target "test"

(minphony)

🪛 LanguageTool
deploy/microshift-bootc/README.md

[grammar] ~1-~1: Ensure spelling is correct
Context: # MicroShift Bootc Deployment This directory contains the...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)


[grammar] ~35-~35: Ensure spelling is correct
Context: ...ended ## Quick Start ### 1. Build the Bootc Image bash make bootc-build Th...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

🪛 markdownlint-cli2 (0.18.1)
deploy/microshift-bootc/README.md

56-56: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


184-184: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🪛 Ruff (0.14.8)
deploy/microshift-bootc/config-svc/app.py

43-43: subprocess call: check for execution of untrusted input

(S603)


44-44: Starting a process with a partial executable path

(S607)


49-49: Consider moving this statement to an else block

(TRY300)


50-50: Do not catch blind exception: Exception

(BLE001)


81-130: Possible hardcoded password assigned to: "PASSWORD_REQUIRED_TEMPLATE"

(S105)


1211-1211: Starting a process with a partial executable path

(S607)


1225-1225: Starting a process with a partial executable path

(S607)


1230-1230: Starting a process with a partial executable path

(S607)


1244-1244: Starting a process with a partial executable path

(S607)


1248-1248: Starting a process with a partial executable path

(S607)


1267-1267: Starting a process with a partial executable path

(S607)


1273-1273: Starting a process with a partial executable path

(S607)


1277-1277: Starting a process with a partial executable path

(S607)


1290-1290: Starting a process with a partial executable path

(S607)


1324-1324: Do not catch blind exception: Exception

(BLE001)


1325-1325: Use explicit conversion flag

Replace with conversion flag

(RUF010)


1341-1341: subprocess call: check for execution of untrusted input

(S603)


1342-1342: Starting a process with a partial executable path

(S607)


1372-1372: Local variable e is assigned to but never used

Remove assignment to unused variable e

(F841)


1377-1377: Do not catch blind exception: Exception

(BLE001)


1377-1377: Local variable e is assigned to but never used

Remove assignment to unused variable e

(F841)


1394-1394: subprocess call: check for execution of untrusted input

(S603)


1395-1395: Starting a process with a partial executable path

(S607)


1451-1451: Do not catch blind exception: Exception

(BLE001)


1452-1452: Use explicit conversion flag

Replace with conversion flag

(RUF010)


1468-1468: subprocess call: check for execution of untrusted input

(S603)


1469-1469: Starting a process with a partial executable path

(S607)


1531-1531: Do not catch blind exception: Exception

(BLE001)


1532-1532: Use explicit conversion flag

Replace with conversion flag

(RUF010)


1548-1548: subprocess call: check for execution of untrusted input

(S603)


1549-1549: Starting a process with a partial executable path

(S607)


1563-1563: Do not catch blind exception: Exception

(BLE001)


1564-1564: Use explicit conversion flag

Replace with conversion flag

(RUF010)


1582-1582: subprocess call: check for execution of untrusted input

(S603)


1583-1583: Starting a process with a partial executable path

(S607)


1596-1596: Do not catch blind exception: Exception

(BLE001)


1597-1597: Use explicit conversion flag

Replace with conversion flag

(RUF010)


1604-1604: Do not catch blind exception: Exception

(BLE001)


1724-1724: Do not catch blind exception: Exception

(BLE001)


1725-1725: Use explicit conversion flag

Replace with conversion flag

(RUF010)


1755-1755: Do not catch blind exception: Exception

(BLE001)


1765-1765: Starting a process with a partial executable path

(S607)


1788-1788: subprocess call: check for execution of untrusted input

(S603)


1789-1789: Starting a process with a partial executable path

(S607)


1803-1803: Consider moving this statement to an else block

(TRY300)


1804-1804: Do not catch blind exception: Exception

(BLE001)


1813-1813: Do not catch blind exception: Exception

(BLE001)


1838-1838: subprocess call: check for execution of untrusted input

(S603)


1839-1839: Starting a process with a partial executable path

(S607)


1859-1859: Do not catch blind exception: Exception

(BLE001)


1867-1867: subprocess call: check for execution of untrusted input

(S603)


1868-1868: Starting a process with a partial executable path

(S607)


1873-1873: Consider moving this statement to an else block

(TRY300)


1878-1878: Do not catch blind exception: Exception

(BLE001)


1888-1888: Starting a process with a partial executable path

(S607)


1894-1894: Unpacked variable stdout is never used

Prefix it with an underscore or any other dummy variable pattern

(RUF059)


1901-1901: Consider moving this statement to an else block

(TRY300)


1902-1902: Do not catch blind exception: Exception

(BLE001)


1941-1941: Do not catch blind exception: Exception

(BLE001)


2008-2008: subprocess call: check for execution of untrusted input

(S603)


2009-2009: Starting a process with a partial executable path

(S607)


2019-2020: try-except-pass detected, consider logging the exception

(S110)


2019-2019: Do not catch blind exception: Exception

(BLE001)


2026-2026: Do not catch blind exception: Exception

(BLE001)


2083-2083: Possible binding to all interfaces

(S104)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: lint-go
  • GitHub Check: tests
  • GitHub Check: e2e-tests (ubuntu-24.04-arm)
  • GitHub Check: e2e-tests (ubuntu-24.04)
  • GitHub Check: e2e-test-operator
  • GitHub Check: e2e-tests-release-0-7
  • GitHub Check: deploy-kind

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

♻️ Duplicate comments (3)
deploy/microshift-bootc/config-svc/app.py (1)

675-689: DOM XSS vulnerability: Pod fields are still injected via template literals.

This is a duplicate of a previously raised concern. The code at line 675 uses innerHTML with template literals to render pod data:

tbody.innerHTML = data.pods.map(pod => `...${pod.name}...${pod.namespace}...`).join('');

Pod names, namespaces, and other fields can be controlled by workload authors in-cluster and may contain malicious scripts. These values should be rendered using DOM APIs with textContent instead of template literals with innerHTML.

deploy/microshift-bootc/run-microshift.sh (2)

65-78: Missing pvcreate before vgcreate (duplicate of previous comment).

This issue was previously flagged. Line 73 runs vgcreate directly on the loop device without initializing it as a physical volume first:

vgcreate -f -y '${vg_name}' "${LOOP_DEV}"

While modern LVM may handle this, explicit pvcreate is more robust.


85-86: Hardcoded hostname doesn't reflect actual host IP (duplicate).

This issue was previously flagged. Line 86 hardcodes the hostname:

local -r hostname="jumpstarter.127-0-0-1.nip.io"

This should detect the actual default route IP as suggested in the previous comment. The 127.0.0.1 address will not be accessible from outside the host.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 57ed276 and 5b50788.

📒 Files selected for processing (10)
  • deploy/microshift-bootc/Containerfile (1 hunks)
  • deploy/microshift-bootc/Makefile (1 hunks)
  • deploy/microshift-bootc/README.md (1 hunks)
  • deploy/microshift-bootc/config-svc/app.py (1 hunks)
  • deploy/microshift-bootc/config-svc/config-svc.service (1 hunks)
  • deploy/microshift-bootc/config-svc/update-banner.service (1 hunks)
  • deploy/microshift-bootc/config-svc/update-banner.sh (1 hunks)
  • deploy/microshift-bootc/config.toml (1 hunks)
  • deploy/microshift-bootc/kustomization.yaml (1 hunks)
  • deploy/microshift-bootc/run-microshift.sh (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • deploy/microshift-bootc/config-svc/update-banner.sh
  • deploy/microshift-bootc/config-svc/update-banner.service
  • deploy/microshift-bootc/kustomization.yaml
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-05-13T19:56:27.924Z
Learnt from: NickCao
Repo: jumpstarter-dev/jumpstarter-controller PR: 137
File: deploy/helm/jumpstarter/charts/jumpstarter-controller/templates/router-deployment.yaml:23-26
Timestamp: 2025-05-13T19:56:27.924Z
Learning: In the jumpstarter-controller project, the router service uses the same ConfigMap as the controller service (controller-cm.yaml) even though it has been moved to its own separate deployment.

Applied to files:

  • deploy/microshift-bootc/run-microshift.sh
📚 Learning: 2025-10-24T11:57:23.796Z
Learnt from: mangelajo
Repo: jumpstarter-dev/jumpstarter-controller PR: 170
File: deploy/operator/internal/controller/jumpstarter/jumpstarter_controller.go:328-333
Timestamp: 2025-10-24T11:57:23.796Z
Learning: In the jumpstarter-controller operator (deploy/operator/), the design allows only one Jumpstarter CR per namespace, which will be enforced by a validation webhook. This constraint eliminates concerns about resource name collisions within a namespace.

Applied to files:

  • deploy/microshift-bootc/config-svc/app.py
🪛 checkmake (0.2.2)
deploy/microshift-bootc/Makefile

[warning] 1-1: Missing required phony target "all"

(minphony)


[warning] 1-1: Missing required phony target "clean"

(minphony)


[warning] 1-1: Missing required phony target "test"

(minphony)


[warning] 86-86: Target body for "clean" exceeds allowed length of 5 (6).

(maxbodylength)

🪛 LanguageTool
deploy/microshift-bootc/README.md

[grammar] ~1-~1: Ensure spelling is correct
Context: # MicroShift Bootc Deployment This directory contains the...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)


[grammar] ~35-~35: Ensure spelling is correct
Context: ...ended ## Quick Start ### 1. Build the Bootc Image bash make bootc-build Th...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

🪛 markdownlint-cli2 (0.18.1)
deploy/microshift-bootc/README.md

56-56: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


184-184: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🪛 Ruff (0.14.8)
deploy/microshift-bootc/config-svc/app.py

123-123: subprocess call: check for execution of untrusted input

(S603)


124-124: Starting a process with a partial executable path

(S607)


129-129: Consider moving this statement to an else block

(TRY300)


130-130: Do not catch blind exception: Exception

(BLE001)


161-212: Possible hardcoded password assigned to: "PASSWORD_REQUIRED_TEMPLATE"

(S105)


1421-1421: Starting a process with a partial executable path

(S607)


1435-1435: Starting a process with a partial executable path

(S607)


1440-1440: Starting a process with a partial executable path

(S607)


1454-1454: Starting a process with a partial executable path

(S607)


1458-1458: Starting a process with a partial executable path

(S607)


1477-1477: Starting a process with a partial executable path

(S607)


1483-1483: Starting a process with a partial executable path

(S607)


1487-1487: Starting a process with a partial executable path

(S607)


1500-1500: Starting a process with a partial executable path

(S607)


1534-1534: Do not catch blind exception: Exception

(BLE001)


1535-1535: Use explicit conversion flag

Replace with conversion flag

(RUF010)


1551-1551: subprocess call: check for execution of untrusted input

(S603)


1552-1552: Starting a process with a partial executable path

(S607)


1582-1582: Local variable e is assigned to but never used

Remove assignment to unused variable e

(F841)


1587-1587: Do not catch blind exception: Exception

(BLE001)


1587-1587: Local variable e is assigned to but never used

Remove assignment to unused variable e

(F841)


1604-1604: subprocess call: check for execution of untrusted input

(S603)


1605-1605: Starting a process with a partial executable path

(S607)


1665-1665: Do not catch blind exception: Exception

(BLE001)


1666-1666: Use explicit conversion flag

Replace with conversion flag

(RUF010)


1682-1682: subprocess call: check for execution of untrusted input

(S603)


1683-1683: Starting a process with a partial executable path

(S607)


1745-1745: Do not catch blind exception: Exception

(BLE001)


1746-1746: Use explicit conversion flag

Replace with conversion flag

(RUF010)


1762-1762: subprocess call: check for execution of untrusted input

(S603)


1763-1763: Starting a process with a partial executable path

(S607)


1777-1777: Do not catch blind exception: Exception

(BLE001)


1778-1778: Use explicit conversion flag

Replace with conversion flag

(RUF010)


1796-1796: subprocess call: check for execution of untrusted input

(S603)


1797-1797: Starting a process with a partial executable path

(S607)


1810-1810: Do not catch blind exception: Exception

(BLE001)


1811-1811: Use explicit conversion flag

Replace with conversion flag

(RUF010)


1818-1818: Do not catch blind exception: Exception

(BLE001)


1938-1938: Do not catch blind exception: Exception

(BLE001)


1939-1939: Use explicit conversion flag

Replace with conversion flag

(RUF010)


1969-1969: Do not catch blind exception: Exception

(BLE001)


1979-1979: Starting a process with a partial executable path

(S607)


2002-2002: subprocess call: check for execution of untrusted input

(S603)


2003-2003: Starting a process with a partial executable path

(S607)


2017-2017: Consider moving this statement to an else block

(TRY300)


2018-2018: Do not catch blind exception: Exception

(BLE001)


2027-2027: Do not catch blind exception: Exception

(BLE001)


2052-2052: subprocess call: check for execution of untrusted input

(S603)


2053-2053: Starting a process with a partial executable path

(S607)


2073-2073: Do not catch blind exception: Exception

(BLE001)


2081-2081: subprocess call: check for execution of untrusted input

(S603)


2082-2082: Starting a process with a partial executable path

(S607)


2087-2087: Consider moving this statement to an else block

(TRY300)


2092-2092: Do not catch blind exception: Exception

(BLE001)


2102-2102: Starting a process with a partial executable path

(S607)


2108-2108: Unpacked variable stdout is never used

Prefix it with an underscore or any other dummy variable pattern

(RUF059)


2115-2115: Consider moving this statement to an else block

(TRY300)


2116-2116: Do not catch blind exception: Exception

(BLE001)


2155-2155: Do not catch blind exception: Exception

(BLE001)


2222-2222: subprocess call: check for execution of untrusted input

(S603)


2223-2223: Starting a process with a partial executable path

(S607)


2233-2234: try-except-pass detected, consider logging the exception

(S110)


2233-2233: Do not catch blind exception: Exception

(BLE001)


2240-2240: Do not catch blind exception: Exception

(BLE001)


2297-2297: Possible binding to all interfaces

(S104)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: e2e-tests (ubuntu-24.04)
  • GitHub Check: e2e-tests-release-0-7
  • GitHub Check: e2e-tests (ubuntu-24.04-arm)
  • GitHub Check: tests
  • GitHub Check: deploy-kind
  • GitHub Check: lint-go
  • GitHub Check: e2e-test-operator
🔇 Additional comments (2)
deploy/microshift-bootc/config-svc/config-svc.service (1)

1-21: Service configuration looks appropriate.

The systemd unit is well-structured with proper dependencies and ordering. The [email protected] directive ensures the config service starts before console login, which aligns with the banner update mechanism that displays the web UI URL.

deploy/microshift-bootc/run-microshift.sh (1)

116-139: Timeout implementation successfully addresses previous concern.

The kubeconfig wait loop now includes a configurable timeout (lines 118-138) with proper error handling:

local -r max_wait=${MICROSHIFT_KUBECONFIG_TIMEOUT:-300}
# ... time tracking ...
if [ "${elapsed}" -ge "${max_wait}" ]; then
    echo "ERROR: Timeout waiting for MicroShift kubeconfig..." >&2
    return 1
fi

This prevents indefinite hangs and provides clear error messages.

Creates a bootc based image based on MicroShift for evaluation
and small labs.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (4)
deploy/microshift-bootc/README.md (1)

55-64: Fix MD040: add languages to fenced code blocks.

-```
+```text
 MicroShift is running in a bootc container
 Hostname:  jumpstarter.10.0.2.2.nip.io
 Container: jumpstarter-microshift-okd
 LVM disk:  /var/lib/microshift-okd/lvmdisk.image
 VG name:   myvg1
 Ports:     HTTP:80, HTTPS:443, Config Service:8880

@@
- +text
┌─────────────────────────────────────────────┐
│ Bootc Container / Image │
├─────────────────────────────────────────────┤
│ • Fedora CoreOS 9 base │
│ • MicroShift 4.20 (OKD) │
│ • Jumpstarter Operator │
│ • TopoLVM CSI (storage) │
│ • Configuration Service (Python/Flask) │
│ • Firewalld (ports 22, 80, 443, 8880) │
└─────────────────────────────────────────────┘



Also applies to: 184-196

</blockquote></details>
<details>
<summary>deploy/microshift-bootc/config-svc/app.py (3)</summary><blockquote>

`624-736`: **DOM XSS: pods/routes/error strings are injected via `innerHTML` / template literals.**  
Any workload author can influence pod/route fields; render with DOM nodes + `textContent` instead.  


```diff
-                        errorContainer.innerHTML = '<div class="error">' + data.error + '</div>';
+                        const err = document.createElement('div');
+                        err.className = 'error';
+                        err.textContent = data.error;
+                        errorContainer.replaceChildren(err);
@@
-                    tbody.innerHTML = data.pods.map(pod => `
-                        <tr>
-                            <td>${pod.namespace}</td>
-                            <td>${pod.name}</td>
-                            <td>${pod.ready}</td>
-                            <td><span class="status-badge ${getStatusClass(pod.status)}">${pod.status}</span></td>
-                            <td>${pod.restarts}</td>
-                            <td>${pod.age}</td>
-                            <td>${pod.node}</td>
-                            <td>
-                                <a href="/logs/${pod.namespace}/${pod.name}" target="_blank" class="action-icon" title="View Logs">📋</a>
-                                <a href="#" onclick="restartPod('${pod.namespace}', '${pod.name}'); return false;" class="action-icon" title="Restart Pod">🔄</a>
-                            </td>
-                        </tr>
-                    `).join('');
+                    tbody.replaceChildren(...data.pods.map(pod => {
+                        const tr = document.createElement('tr');
+                        const tdNs = document.createElement('td'); tdNs.textContent = pod.namespace;
+                        const tdName = document.createElement('td'); tdName.textContent = pod.name;
+                        const tdReady = document.createElement('td'); tdReady.textContent = pod.ready;
+                        const tdStatus = document.createElement('td');
+                        const badge = document.createElement('span');
+                        badge.className = `status-badge ${getStatusClass(pod.status)}`;
+                        badge.textContent = pod.status;
+                        tdStatus.appendChild(badge);
+                        const tdRestarts = document.createElement('td'); tdRestarts.textContent = String(pod.restarts);
+                        const tdAge = document.createElement('td'); tdAge.textContent = pod.age;
+                        const tdNode = document.createElement('td'); tdNode.textContent = pod.node;
+                        const tdActions = document.createElement('td');
+                        const logs = document.createElement('a');
+                        logs.href = `/logs/${encodeURIComponent(pod.namespace)}/${encodeURIComponent(pod.name)}`;
+                        logs.target = '_blank';
+                        logs.className = 'action-icon';
+                        logs.title = 'View Logs';
+                        logs.textContent = '📋';
+                        const restart = document.createElement('a');
+                        restart.href = '#';
+                        restart.className = 'action-icon';
+                        restart.title = 'Restart Pod';
+                        restart.textContent = '🔄';
+                        restart.addEventListener('click', (e) => { e.preventDefault(); restartPod(pod.namespace, pod.name); });
+                        tdActions.append(logs, restart);
+                        tr.append(tdNs, tdName, tdReady, tdStatus, tdRestarts, tdAge, tdNode, tdActions);
+                        return tr;
+                    }));

(Apply the same pattern to routes + the remaining innerHTML error paths.)


523-603: Stored/reflective XSS risk in system stats rendering (innerHTML template literal).
At minimum, ensure user/cluster-controlled fields (e.g., data.system.hostname, interface names/IPs) are inserted via textContent or escaped.


110-133: su fallback auth is likely unreliable (TTY) and can lock out access.
Prefer: make PAM a hard dependency for the image, or fail closed with a clear error when pam isn’t available (instead of attempting su).

🧹 Nitpick comments (3)
deploy/microshift-bootc/config-svc/update-banner.service (1)

1-19: With DefaultDependencies=no, add explicit After=local-fs.target.
Ensures /etc/issue updates aren’t racing filesystem readiness on boot.

 [Unit]
 Description=Update Jumpstarter Login Banner
 Documentation=https://github.com/jumpstarter-dev/jumpstarter-controller
+After=local-fs.target
 After=network-online.target
 Wants=network-online.target
 [email protected] getty.target systemd-user-sessions.service
 DefaultDependencies=no
deploy/microshift-bootc/Makefile (1)

1-93: Use $(MAKE) + expand .PHONY to avoid surprising no-ops.

-.PHONY: help build bootc-build push bootc-push bootc-run bootc-stop bootc-sh bootc-rm
+.PHONY: help build bootc-build push bootc-push bootc-run bootc-stop bootc-sh bootc-rm \
+        bootc-reload-app build-image build-all push-all clean

@@
 build-image: bootc-build ## Build the bootc based qcow2 image
 	@echo "Building image: output/qcow2/disk.qcow2"
@@
 	sudo rm -f output/qcow2/disk.qcow2
-	make output/qcow2/disk.qcow2
+	$(MAKE) output/qcow2/disk.qcow2
 	@echo "Image built successfully in ./output/"
deploy/microshift-bootc/config-svc/app.py (1)

2283-2298: Consider running behind a real WSGI server (systemd + Flask dev server).
Even for “community edition”, the dev server is a frequent source of robustness issues; consider gunicorn/waitress and keep Flask as the app only.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5b50788 and 99bf0a7.

📒 Files selected for processing (10)
  • deploy/microshift-bootc/Containerfile (1 hunks)
  • deploy/microshift-bootc/Makefile (1 hunks)
  • deploy/microshift-bootc/README.md (1 hunks)
  • deploy/microshift-bootc/config-svc/app.py (1 hunks)
  • deploy/microshift-bootc/config-svc/config-svc.service (1 hunks)
  • deploy/microshift-bootc/config-svc/update-banner.service (1 hunks)
  • deploy/microshift-bootc/config-svc/update-banner.sh (1 hunks)
  • deploy/microshift-bootc/config.toml (1 hunks)
  • deploy/microshift-bootc/kustomization.yaml (1 hunks)
  • deploy/microshift-bootc/run-microshift.sh (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • deploy/microshift-bootc/config.toml
  • deploy/microshift-bootc/run-microshift.sh
  • deploy/microshift-bootc/config-svc/update-banner.sh
  • deploy/microshift-bootc/Containerfile
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-10-24T11:57:23.796Z
Learnt from: mangelajo
Repo: jumpstarter-dev/jumpstarter-controller PR: 170
File: deploy/operator/internal/controller/jumpstarter/jumpstarter_controller.go:328-333
Timestamp: 2025-10-24T11:57:23.796Z
Learning: In the jumpstarter-controller operator (deploy/operator/), the design allows only one Jumpstarter CR per namespace, which will be enforced by a validation webhook. This constraint eliminates concerns about resource name collisions within a namespace.

Applied to files:

  • deploy/microshift-bootc/kustomization.yaml
  • deploy/microshift-bootc/config-svc/app.py
🪛 checkmake (0.2.2)
deploy/microshift-bootc/Makefile

[warning] 86-86: Target body for "clean" exceeds allowed length of 5 (6).

(maxbodylength)


[warning] 1-1: Missing required phony target "all"

(minphony)


[warning] 1-1: Missing required phony target "clean"

(minphony)


[warning] 1-1: Missing required phony target "test"

(minphony)

🪛 LanguageTool
deploy/microshift-bootc/README.md

[grammar] ~1-~1: Ensure spelling is correct
Context: # MicroShift Bootc Deployment This directory contains the...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)


[grammar] ~35-~35: Ensure spelling is correct
Context: ...ended ## Quick Start ### 1. Build the Bootc Image bash make bootc-build Th...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

🪛 markdownlint-cli2 (0.18.1)
deploy/microshift-bootc/README.md

56-56: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


184-184: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🪛 Ruff (0.14.8)
deploy/microshift-bootc/config-svc/app.py

123-123: subprocess call: check for execution of untrusted input

(S603)


124-124: Starting a process with a partial executable path

(S607)


129-129: Consider moving this statement to an else block

(TRY300)


130-130: Do not catch blind exception: Exception

(BLE001)


161-212: Possible hardcoded password assigned to: "PASSWORD_REQUIRED_TEMPLATE"

(S105)


1421-1421: Starting a process with a partial executable path

(S607)


1435-1435: Starting a process with a partial executable path

(S607)


1440-1440: Starting a process with a partial executable path

(S607)


1454-1454: Starting a process with a partial executable path

(S607)


1458-1458: Starting a process with a partial executable path

(S607)


1477-1477: Starting a process with a partial executable path

(S607)


1483-1483: Starting a process with a partial executable path

(S607)


1487-1487: Starting a process with a partial executable path

(S607)


1500-1500: Starting a process with a partial executable path

(S607)


1534-1534: Do not catch blind exception: Exception

(BLE001)


1535-1535: Use explicit conversion flag

Replace with conversion flag

(RUF010)


1551-1551: subprocess call: check for execution of untrusted input

(S603)


1552-1552: Starting a process with a partial executable path

(S607)


1582-1582: Local variable e is assigned to but never used

Remove assignment to unused variable e

(F841)


1587-1587: Do not catch blind exception: Exception

(BLE001)


1587-1587: Local variable e is assigned to but never used

Remove assignment to unused variable e

(F841)


1604-1604: subprocess call: check for execution of untrusted input

(S603)


1605-1605: Starting a process with a partial executable path

(S607)


1665-1665: Do not catch blind exception: Exception

(BLE001)


1666-1666: Use explicit conversion flag

Replace with conversion flag

(RUF010)


1682-1682: subprocess call: check for execution of untrusted input

(S603)


1683-1683: Starting a process with a partial executable path

(S607)


1745-1745: Do not catch blind exception: Exception

(BLE001)


1746-1746: Use explicit conversion flag

Replace with conversion flag

(RUF010)


1762-1762: subprocess call: check for execution of untrusted input

(S603)


1763-1763: Starting a process with a partial executable path

(S607)


1777-1777: Do not catch blind exception: Exception

(BLE001)


1778-1778: Use explicit conversion flag

Replace with conversion flag

(RUF010)


1796-1796: subprocess call: check for execution of untrusted input

(S603)


1797-1797: Starting a process with a partial executable path

(S607)


1810-1810: Do not catch blind exception: Exception

(BLE001)


1811-1811: Use explicit conversion flag

Replace with conversion flag

(RUF010)


1818-1818: Do not catch blind exception: Exception

(BLE001)


1938-1938: Do not catch blind exception: Exception

(BLE001)


1939-1939: Use explicit conversion flag

Replace with conversion flag

(RUF010)


1969-1969: Do not catch blind exception: Exception

(BLE001)


1979-1979: Starting a process with a partial executable path

(S607)


2002-2002: subprocess call: check for execution of untrusted input

(S603)


2003-2003: Starting a process with a partial executable path

(S607)


2017-2017: Consider moving this statement to an else block

(TRY300)


2018-2018: Do not catch blind exception: Exception

(BLE001)


2027-2027: Do not catch blind exception: Exception

(BLE001)


2052-2052: subprocess call: check for execution of untrusted input

(S603)


2053-2053: Starting a process with a partial executable path

(S607)


2073-2073: Do not catch blind exception: Exception

(BLE001)


2081-2081: subprocess call: check for execution of untrusted input

(S603)


2082-2082: Starting a process with a partial executable path

(S607)


2087-2087: Consider moving this statement to an else block

(TRY300)


2092-2092: Do not catch blind exception: Exception

(BLE001)


2102-2102: Starting a process with a partial executable path

(S607)


2108-2108: Unpacked variable stdout is never used

Prefix it with an underscore or any other dummy variable pattern

(RUF059)


2115-2115: Consider moving this statement to an else block

(TRY300)


2116-2116: Do not catch blind exception: Exception

(BLE001)


2155-2155: Do not catch blind exception: Exception

(BLE001)


2222-2222: subprocess call: check for execution of untrusted input

(S603)


2223-2223: Starting a process with a partial executable path

(S607)


2233-2234: try-except-pass detected, consider logging the exception

(S110)


2233-2233: Do not catch blind exception: Exception

(BLE001)


2240-2240: Do not catch blind exception: Exception

(BLE001)


2297-2297: Possible binding to all interfaces

(S104)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: e2e-tests (ubuntu-24.04)
  • GitHub Check: e2e-tests (ubuntu-24.04-arm)
  • GitHub Check: e2e-tests-release-0-7
  • GitHub Check: lint-go
  • GitHub Check: e2e-test-operator
  • GitHub Check: deploy-kind
  • GitHub Check: tests
🔇 Additional comments (2)
deploy/microshift-bootc/kustomization.yaml (1)

1-11: Kustomization looks correct and minimal.
resources + commonLabels are sensible for consistent labeling across deployed objects.

deploy/microshift-bootc/config-svc/config-svc.service (1)

1-21: Service unit is reasonable; restart + journald wiring looks good.
Given the service’s responsibilities (hostname/password changes), I wouldn’t add aggressive systemd sandboxing here without testing.

Comment on lines +2160 to +2281
def apply_jumpstarter_cr(base_domain, image, image_pull_policy='IfNotPresent'):
"""Apply Jumpstarter Custom Resource using oc."""
try:
# Path to MicroShift kubeconfig
kubeconfig_path = KUBECONFIG_PATH

# Check if kubeconfig exists
if not os.path.exists(kubeconfig_path):
return False, 'MicroShift kubeconfig not found. Is MicroShift running?'

# Build the CR YAML
cr = {
'apiVersion': 'operator.jumpstarter.dev/v1alpha1',
'kind': 'Jumpstarter',
'metadata': {
'name': 'jumpstarter',
'namespace': 'default'
},
'spec': {
'baseDomain': base_domain,
'controller': {
'grpc': {
'endpoints': [
{
'address': f'grpc.{base_domain}',
'route': {
'enabled': True
}
}
]
},
'image': image,
'imagePullPolicy': image_pull_policy,
'replicas': 1
},
'routers': {
'grpc': {
'endpoints': [
{
'address': f'router.{base_domain}',
'route': {
'enabled': True
}
}
]
},
'image': image,
'imagePullPolicy': image_pull_policy,
'replicas': 1
},
'useCertManager': True
}
}

# Write CR to temporary file
with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:
yaml_content = json_to_yaml(cr)
f.write(yaml_content)
temp_file = f.name

try:
# Apply using oc with explicit kubeconfig
result = subprocess.run(
['oc', '--kubeconfig', kubeconfig_path, 'apply', '-f', temp_file],
capture_output=True,
text=True,
check=True
)
return True, result.stdout.strip()
finally:
# Clean up temp file
try:
os.unlink(temp_file)
except Exception:
pass

except subprocess.CalledProcessError as e:
error_msg = e.stderr.strip() if e.stderr else str(e)
print(f"Error applying Jumpstarter CR: {error_msg}", file=sys.stderr)
return False, error_msg
except Exception as e:
print(f"Error applying Jumpstarter CR: {e}", file=sys.stderr)
return False, str(e)


def json_to_yaml(obj, indent=0):
"""Convert a JSON object to YAML format (simple implementation)."""
lines = []
indent_str = ' ' * indent

if isinstance(obj, dict):
for key, value in obj.items():
if isinstance(value, (dict, list)):
lines.append(f"{indent_str}{key}:")
lines.append(json_to_yaml(value, indent + 1))
else:
lines.append(f"{indent_str}{key}: {yaml_value(value)}")
elif isinstance(obj, list):
for item in obj:
if isinstance(item, (dict, list)):
lines.append(f"{indent_str}-")
lines.append(json_to_yaml(item, indent + 1))
else:
lines.append(f"{indent_str}- {yaml_value(item)}")

return '\n'.join(lines)


def yaml_value(value):
"""Format a value for YAML output."""
if value is None:
return 'null'
elif isinstance(value, bool):
return 'true' if value else 'false'
elif isinstance(value, str):
# Quote strings that contain special characters
if ':' in value or '#' in value or value.startswith('-'):
return f'"{value}"'
return value
else:
return str(value)

Copy link
Contributor

@coderabbitai coderabbitai bot Dec 14, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Add json import and use JSON format instead of custom YAML conversion.
While json_to_yaml() produces technically valid YAML, using json.dumps() with JSON files is simpler and more reliable. The oc apply -f command accepts JSON manifests. However, the proposed change requires adding import json at the top of the file—ensure this import is included when applying the fix.

-        with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:
-            yaml_content = json_to_yaml(cr)
-            f.write(yaml_content)
+        with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False) as f:
+            f.write(json.dumps(cr))
             temp_file = f.name

Committable suggestion skipped: line range outside the PR's diff.

🧰 Tools
🪛 Ruff (0.14.8)

2222-2222: subprocess call: check for execution of untrusted input

(S603)


2223-2223: Starting a process with a partial executable path

(S607)


2233-2234: try-except-pass detected, consider logging the exception

(S110)


2233-2233: Do not catch blind exception: Exception

(BLE001)


2240-2240: Do not catch blind exception: Exception

(BLE001)

🤖 Prompt for AI Agents
In deploy/microshift-bootc/config-svc/app.py around lines 2160 to 2281, replace
the custom JSON->YAML conversion with standard JSON output and add the missing
import: insert "import json" at the top of the file, change the temp file
creation to use suffix='.json' and replace yaml_content = json_to_yaml(cr) with
json_content = json.dumps(cr, indent=2) and write json_content to the temp file,
and optionally remove the now-unused json_to_yaml and yaml_value helper
functions (or leave them if you prefer) so oc apply -f uses a valid JSON
manifest.

Copy link
Member Author

Choose a reason for hiding this comment

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

This is another option, probably better!

Copy link
Contributor

Choose a reason for hiding this comment

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

@mangelajo Great! Using JSON is definitely simpler and more maintainable. Here's the updated implementation:

def apply_jumpstarter_cr(base_domain, image, image_pull_policy='IfNotPresent'):
    """Apply Jumpstarter Custom Resource using oc."""
    try:
        # Path to MicroShift kubeconfig
        kubeconfig_path = KUBECONFIG_PATH
        
        # Check if kubeconfig exists
        if not os.path.exists(kubeconfig_path):
            return False, 'MicroShift kubeconfig not found. Is MicroShift running?'
        
        # Build the CR YAML
        cr = {
            'apiVersion': 'operator.jumpstarter.dev/v1alpha1',
            'kind': 'Jumpstarter',
            'metadata': {
                'name': 'jumpstarter',
                'namespace': 'default'
            },
            'spec': {
                'baseDomain': base_domain,
                'controller': {
                    'grpc': {
                        'endpoints': [
                            {
                                'address': f'grpc.{base_domain}',
                                'route': {
                                    'enabled': True
                                }
                            }
                        ]
                    },
                    'image': image,
                    'imagePullPolicy': image_pull_policy,
                    'replicas': 1
                },
                'routers': {
                    'grpc': {
                        'endpoints': [
                            {
                                'address': f'router.{base_domain}',
                                'route': {
                                    'enabled': True
                                }
                            }
                        ]
                    },
                    'image': image,
                    'imagePullPolicy': image_pull_policy,
                    'replicas': 1
                },
                'useCertManager': True
            }
        }
        
        # Write CR to temporary file
        with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False) as f:
            f.write(json.dumps(cr, indent=2))
            temp_file = f.name
        
        try:
            # Apply using oc with explicit kubeconfig
            result = subprocess.run(
                ['oc', '--kubeconfig', kubeconfig_path, 'apply', '-f', temp_file],
                capture_output=True,
                text=True,
                check=True
            )
            return True, result.stdout.strip()
        finally:
            # Clean up temp file
            try:
                os.unlink(temp_file)
            except Exception:
                pass
                
    except subprocess.CalledProcessError as e:
        error_msg = e.stderr.strip() if e.stderr else str(e)
        print(f"Error applying Jumpstarter CR: {error_msg}", file=sys.stderr)
        return False, error_msg
    except Exception as e:
        print(f"Error applying Jumpstarter CR: {e}", file=sys.stderr)
        return False, str(e)

Note: The import json statement is already present at the top of the file (line 10), so no additional import is needed.

Optional cleanup: If the json_to_yaml() and yaml_value() helper functions aren't used elsewhere in the codebase, you can remove them to keep the code cleaner.

@mangelajo mangelajo force-pushed the microshift-image branch 2 times, most recently from 5b50788 to 275d81f Compare December 14, 2025 20:24
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
deploy/microshift-bootc/Makefile (1)

15-15: Verify wording fix for the echo message on line 15.

The past review noted this line should use "use container storage" instead of "be on the container storage," and change the colon to a dash. The current code still shows the original phrasing. Please confirm if this was addressed or needs correction.

-	@echo "Building bootc image: $(BOOTC_IMG): building as root to be on the container storage from root"
+	@echo "Building bootc image: $(BOOTC_IMG) - building as root to use container storage from root"
🧹 Nitpick comments (1)
deploy/microshift-bootc/Makefile (1)

101-101: Potential fragility in losetup cleanup command.

The nested losetup -j ... | cut -d: -f1 assumes a single loop device. If multiple loop devices are attached to the same image, only the first one will be detached. Consider a more robust approach:

-	-sudo losetup -d $$(sudo losetup -j /var/lib/microshift-okd/lvmdisk.image | cut -d: -f1) 2>/dev/null || true
+	-sudo losetup -j /var/lib/microshift-okd/lvmdisk.image 2>/dev/null | cut -d: -f1 | xargs -r sudo losetup -d
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 99bf0a7 and 275d81f.

📒 Files selected for processing (1)
  • deploy/microshift-bootc/Makefile (1 hunks)
🧰 Additional context used
🪛 checkmake (0.2.2)
deploy/microshift-bootc/Makefile

[warning] 114-114: Target body for "clean" exceeds allowed length of 5 (8).

(maxbodylength)


[warning] 1-1: Missing required phony target "all"

(minphony)


[warning] 1-1: Missing required phony target "clean"

(minphony)


[warning] 1-1: Missing required phony target "test"

(minphony)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: deploy-kind
  • GitHub Check: e2e-test-operator
  • GitHub Check: lint-go
  • GitHub Check: tests
  • GitHub Check: e2e-tests (ubuntu-24.04)
  • GitHub Check: e2e-tests-release-0-7
  • GitHub Check: e2e-tests (ubuntu-24.04-arm)
🔇 Additional comments (1)
deploy/microshift-bootc/Makefile (1)

84-86: Clarify intent of build-all and push-all targets.

Based on the PR description mentioning a complete build-and-push workflow, these targets appear incomplete. Currently, build-all only builds the bootc image but doesn't build the QCOW2 or ISO images (which are built separately via build-image and build-iso). Similarly, push-all only pushes the bootc image. Should these targets orchestrate the full build pipeline?

-build-all: bootc-build ## Build bootc image
+build-all: bootc-build build-image build-iso ## Build all images (bootc, QCOW2, ISO)



# HTML template for forced password change
PASSWORD_REQUIRED_TEMPLATE = """<!DOCTYPE html>
Copy link
Collaborator

Choose a reason for hiding this comment

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

There are ways to do this in pure python: https://mesop-dev.github.io/mesop/, a lot more maintainable.

Copy link
Member Author

Choose a reason for hiding this comment

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

Very cool, but too new perhaps, and not sure how I would control styling properly there.

I know how to do flash + css + html, and Claude 4.5 seems to know too.. In fact I should add the Co-Authored flag to credit claude ':D

I did a lot of direction on api structure, functionality and design, but code is mostly Claude's.

What I think I should do, is really structure this app in sub-modules, and have it installed by uv on the system. instead of a big monolytic py.

#!/bin/bash
# Update login banner with Jumpstarter web UI URL

python3 << 'EOF'
Copy link
Collaborator

Choose a reason for hiding this comment

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

Use python directly in shebang?

Copy link
Member Author

Choose a reason for hiding this comment

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

horrible, yes, I need to improve this

firewall-offline-cmd --add-port=8880/tcp

# Set root password
RUN echo "root:jumpstarter" | chpasswd
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can't this be set in config.toml?

Copy link
Member Author

Choose a reason for hiding this comment

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

Then it doesn't work when ran as a container :D

Copy link
Member Author

Choose a reason for hiding this comment

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

Mor detail, we have make bootc-run that starts microshift+jumpstarter in a bootc container, it's quick and nice for iterating on the development before creating an image and flashing something.

build-iso: bootc-build ## Build the bootc based ISO image
@echo "Building ISO image: output/iso/disk.iso"
@echo "Cleaning up any existing LVM resources to avoid conflicts..."
-sudo vgs --noheadings -o vg_name,vg_uuid | grep myvg1 | while read vg uuid; do sudo vgremove -f --select vg_uuid=$$uuid 2>/dev/null || true; done
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't remember doing this when building bootc images, it lvm necessary?

Copy link
Member Author

Choose a reason for hiding this comment

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

this is something that needs to be cleaned up, if you ran the container locally the run-microshift.sh stolen from their repo and modified... creates a loop back device to mount the PVs.

Comment on lines +115 to +122
try:
# Try using PAM authentication first
import pam
p = pam.pam()
return p.authenticate(username, password)
except ImportError:
# Fallback: use subprocess to authenticate via su
try:
Copy link
Member Author

Choose a reason for hiding this comment

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

pam works, we should remove the fallbacks



# HTML template for forced password change
PASSWORD_REQUIRED_TEMPLATE = """<!DOCTYPE html>
Copy link
Member Author

Choose a reason for hiding this comment

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

Very cool, but too new perhaps, and not sure how I would control styling properly there.

I know how to do flash + css + html, and Claude 4.5 seems to know too.. In fact I should add the Co-Authored flag to credit claude ':D

I did a lot of direction on api structure, functionality and design, but code is mostly Claude's.

What I think I should do, is really structure this app in sub-modules, and have it installed by uv on the system. instead of a big monolytic py.

Comment on lines +349 to +350
5. **Production Use:** Consider additional hardening for production deployments

Copy link
Member Author

Choose a reason for hiding this comment

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

Suggested change
5. **Production Use:** Consider additional hardening for production deployments

Comment on lines +395 to +396
# For bare metal
dd if=output/qcow2/disk.qcow2 of=/dev/sdX bs=4M status=progress
Copy link
Member Author

Choose a reason for hiding this comment

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

you cannot flash a qcow2 to disk!

We need a section at the start explaining how to install into a baremetal device, by creating a raw and flashing into storage, or by using an iso.

Comment on lines +399 to +402
4. **First boot:**
- Console login will require password change from default `jumpstarter`
- Access web UI at `http://<host-ip>:8880` and set new password

Copy link
Member Author

Choose a reason for hiding this comment

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

Suggested change
4. **First boot:**
- Console login will require password change from default `jumpstarter`
- Access web UI at `http://<host-ip>:8880` and set new password

This is explained somewhere else..

We probably need good documentation (on the website side) about how to install into host and run..

Comment on lines +414 to +420
## Support

For issues and questions:
- File issues on the Jumpstarter GitHub repository
- Check container logs: `sudo podman logs jumpstarter-microshift-okd`
- Review systemd journals: `make bootc-sh` then `journalctl -xe`

Copy link
Member Author

Choose a reason for hiding this comment

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

Suggested change
## Support
For issues and questions:
- File issues on the Jumpstarter GitHub repository
- Check container logs: `sudo podman logs jumpstarter-microshift-okd`
- Review systemd journals: `make bootc-sh` then `journalctl -xe`

@@ -0,0 +1,179 @@
#!/bin/bash
Copy link
Member Author

Choose a reason for hiding this comment

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

Add a header that explains this script is used to run/test the bootc container as a container instead of installing it into a host.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d19de62 and 7a9a93c.

📒 Files selected for processing (2)
  • deploy/microshift-bootc/Containerfile (1 hunks)
  • deploy/microshift-bootc/Makefile (1 hunks)
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: mangelajo
Repo: jumpstarter-dev/jumpstarter-controller PR: 201
File: deploy/microshift-bootc/Makefile:24-24
Timestamp: 2025-12-16T20:28:48.388Z
Learning: The bootc-image-builder tool's official documentation recommends using `-it` flags with podman run commands when building images, as seen in deploy/microshift-bootc/Makefile.
📚 Learning: 2025-12-16T20:28:48.388Z
Learnt from: mangelajo
Repo: jumpstarter-dev/jumpstarter-controller PR: 201
File: deploy/microshift-bootc/Makefile:24-24
Timestamp: 2025-12-16T20:28:48.388Z
Learning: The bootc-image-builder tool's official documentation recommends using `-it` flags with podman run commands when building images, as seen in deploy/microshift-bootc/Makefile.

Applied to files:

  • deploy/microshift-bootc/Containerfile
📚 Learning: 2025-12-16T20:28:48.388Z
Learnt from: mangelajo
Repo: jumpstarter-dev/jumpstarter-controller PR: 201
File: deploy/microshift-bootc/Makefile:24-24
Timestamp: 2025-12-16T20:28:48.388Z
Learning: In deploy/microshift-bootc/Makefile, follow the bootc-image-builder docs and use -it with podman run when building images. This ensures an interactive TTY is allocated for prompts during image build steps. Apply this consideration to similar Makefiles that invoke podman run for image builds, verifying consistency with the official documentation.

Applied to files:

  • deploy/microshift-bootc/Makefile
📚 Learning: 2025-10-10T13:32:54.936Z
Learnt from: mangelajo
Repo: jumpstarter-dev/jumpstarter-controller PR: 169
File: deploy/operator/Makefile:62-67
Timestamp: 2025-10-10T13:32:54.936Z
Learning: Podman now supports the buildx command, making it compatible with Docker's buildx syntax for multi-platform builds. No special gating or conditional logic is needed when using buildx with CONTAINER_TOOL=podman in Makefiles.

Applied to files:

  • deploy/microshift-bootc/Makefile
🪛 checkmake (0.2.2)
deploy/microshift-bootc/Makefile

[warning] 145-145: Target body for "clean" exceeds allowed length of 5 (8).

(maxbodylength)


[warning] 1-1: Missing required phony target "all"

(minphony)


[warning] 1-1: Missing required phony target "clean"

(minphony)


[warning] 1-1: Missing required phony target "test"

(minphony)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: e2e-tests (ubuntu-24.04)
  • GitHub Check: e2e-test-operator
  • GitHub Check: lint-go
  • GitHub Check: e2e-tests-release-0-7
  • GitHub Check: tests
  • GitHub Check: deploy-kind
  • GitHub Check: e2e-tests (ubuntu-24.04-arm)
🔇 Additional comments (6)
deploy/microshift-bootc/Containerfile (3)

9-11: LGTM!

The manifest installation correctly uses paths relative to the build context (repository root), which aligns with the podman build command in the Makefile that sets the context to ../...


13-17: LGTM!

Using firewall-offline-cmd is the correct approach for configuring firewall rules in a container image build where firewalld isn't running. The comment clearly explains the rationale.


23-24: > Likely an incorrect or invalid review comment.

deploy/microshift-bootc/Makefile (3)

57-74: LGTM!

The ISO build target correctly mirrors the QCOW2 build pattern with appropriate volume mounts and the -it flags as recommended by bootc-image-builder documentation.

Based on learnings, the -it flags are intentional per bootc-image-builder documentation.


76-83: LGTM!

The LVM cleanup before building is a good defensive practice to avoid conflicts from previous builds. The use of rm -f correctly handles the case when the file doesn't exist.


139-143: Nice dev utility!

The bootc-reload-app target provides a quick development workflow by hot-reloading the config service without rebuilding the entire image. This is a good developer experience improvement.

Comment on lines +3 to +6
RUN dnf install -y epel-release && \
dnf install -y python3 iproute python3-flask python3-pip && \
pip3 install python-pam && \
dnf clean all
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Use dnf for python-pam instead of pip3.

The package python3-pam is available in EPEL and can be installed via dnf. Using system packages avoids version inconsistencies and missing dependencies. Apply this change:

 RUN dnf install -y epel-release && \
-    dnf install -y python3 iproute python3-flask python3-pip && \
-    pip3 install python-pam && \
+    dnf install -y python3 iproute python3-flask python3-pam && \
     dnf clean all
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
RUN dnf install -y epel-release && \
dnf install -y python3 iproute python3-flask python3-pip && \
pip3 install python-pam && \
dnf clean all
RUN dnf install -y epel-release && \
dnf install -y python3 iproute python3-flask python3-pam && \
dnf clean all
🤖 Prompt for AI Agents
In deploy/microshift-bootc/Containerfile around lines 3 to 6, the Dockerfile
installs python-pam via pip3 which should instead use the EPEL/system package;
replace the pip3 install python-pam step with the dnf package name (python3-pam)
so dnf installs it along with other system deps, ensuring the package list and
cleanup commands remain in the same RUN chain.

Comment on lines +18 to +36
bootc-build-multi: ## Build the bootc image for multiple architectures (amd64, arm64)
@echo "Building multiarch bootc image: $(BOOTC_IMG)"
@echo "This will build for linux/amd64 and linux/arm64"
@# Remove existing manifest if it exists
-podman manifest rm $(BOOTC_IMG) 2>/dev/null || true
@# Create a new manifest
podman manifest create $(BOOTC_IMG)
@# Build for amd64
@echo "Building for linux/amd64..."
podman build --platform linux/amd64 -t $(BOOTC_IMG)-amd64 -f Containerfile ../..
@# Build for arm64
@echo "Building for linux/arm64..."
podman build --platform linux/arm64 -t $(BOOTC_IMG)-arm64 -f Containerfile ../..
@# Add both images to the manifest
podman manifest add $(BOOTC_IMG) $(BOOTC_IMG)-amd64
podman manifest add $(BOOTC_IMG) $(BOOTC_IMG)-arm64
@echo "Multiarch manifest created successfully!"
@echo "To inspect: podman manifest inspect $(BOOTC_IMG)"
@echo "To push: make bootc-push-multi"
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Inconsistent sudo usage in multi-arch build.

The bootc-build-multi target uses podman without sudo (lines 22, 24, 27, 30, 32-33), while bootc-build uses sudo podman (line 16). This places images in different container storage locations (user vs. root), which can cause:

  1. The manifest won't include the base image if it was built with bootc-build first
  2. The bootc-push-multi target (line 105) won't find the images in root's storage

Apply this diff to ensure consistency:

 bootc-build-multi: ## Build the bootc image for multiple architectures (amd64, arm64)
 	@echo "Building multiarch bootc image: $(BOOTC_IMG)"
 	@echo "This will build for linux/amd64 and linux/arm64"
 	@# Remove existing manifest if it exists
-	-podman manifest rm $(BOOTC_IMG) 2>/dev/null || true
+	-sudo podman manifest rm $(BOOTC_IMG) 2>/dev/null || true
 	@# Create a new manifest
-	podman manifest create $(BOOTC_IMG)
+	sudo podman manifest create $(BOOTC_IMG)
 	@# Build for amd64
 	@echo "Building for linux/amd64..."
-	podman build --platform linux/amd64 -t $(BOOTC_IMG)-amd64 -f Containerfile ../..
+	sudo podman build --platform linux/amd64 -t $(BOOTC_IMG)-amd64 -f Containerfile ../..
 	@# Build for arm64
 	@echo "Building for linux/arm64..."
-	podman build --platform linux/arm64 -t $(BOOTC_IMG)-arm64 -f Containerfile ../..
+	sudo podman build --platform linux/arm64 -t $(BOOTC_IMG)-arm64 -f Containerfile ../..
 	@# Add both images to the manifest
-	podman manifest add $(BOOTC_IMG) $(BOOTC_IMG)-amd64
-	podman manifest add $(BOOTC_IMG) $(BOOTC_IMG)-arm64
+	sudo podman manifest add $(BOOTC_IMG) $(BOOTC_IMG)-amd64
+	sudo podman manifest add $(BOOTC_IMG) $(BOOTC_IMG)-arm64
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
bootc-build-multi: ## Build the bootc image for multiple architectures (amd64, arm64)
@echo "Building multiarch bootc image: $(BOOTC_IMG)"
@echo "This will build for linux/amd64 and linux/arm64"
@# Remove existing manifest if it exists
-podman manifest rm $(BOOTC_IMG) 2>/dev/null || true
@# Create a new manifest
podman manifest create $(BOOTC_IMG)
@# Build for amd64
@echo "Building for linux/amd64..."
podman build --platform linux/amd64 -t $(BOOTC_IMG)-amd64 -f Containerfile ../..
@# Build for arm64
@echo "Building for linux/arm64..."
podman build --platform linux/arm64 -t $(BOOTC_IMG)-arm64 -f Containerfile ../..
@# Add both images to the manifest
podman manifest add $(BOOTC_IMG) $(BOOTC_IMG)-amd64
podman manifest add $(BOOTC_IMG) $(BOOTC_IMG)-arm64
@echo "Multiarch manifest created successfully!"
@echo "To inspect: podman manifest inspect $(BOOTC_IMG)"
@echo "To push: make bootc-push-multi"
bootc-build-multi: ## Build the bootc image for multiple architectures (amd64, arm64)
@echo "Building multiarch bootc image: $(BOOTC_IMG)"
@echo "This will build for linux/amd64 and linux/arm64"
@# Remove existing manifest if it exists
-sudo podman manifest rm $(BOOTC_IMG) 2>/dev/null || true
@# Create a new manifest
sudo podman manifest create $(BOOTC_IMG)
@# Build for amd64
@echo "Building for linux/amd64..."
sudo podman build --platform linux/amd64 -t $(BOOTC_IMG)-amd64 -f Containerfile ../..
@# Build for arm64
@echo "Building for linux/arm64..."
sudo podman build --platform linux/arm64 -t $(BOOTC_IMG)-arm64 -f Containerfile ../..
@# Add both images to the manifest
sudo podman manifest add $(BOOTC_IMG) $(BOOTC_IMG)-amd64
sudo podman manifest add $(BOOTC_IMG) $(BOOTC_IMG)-arm64
@echo "Multiarch manifest created successfully!"
@echo "To inspect: podman manifest inspect $(BOOTC_IMG)"
@echo "To push: make bootc-push-multi"
🤖 Prompt for AI Agents
In deploy/microshift-bootc/Makefile around lines 18 to 36, the bootc-build-multi
target mixes non-root podman invocations while bootc-build uses sudo, causing
images to be placed in different container storages; update every podman
invocation in this target (manifest rm/create, build, and manifest add) to use
sudo (e.g., change podman ... to sudo podman ...) so all builds/manifests run as
root and reside in the same storage as bootc-build.

@echo "To push: make bootc-push-multi"

output/qcow2/disk.qcow2: ## Build a bootable QCOW2 image from the bootc image
@echo "Building QCOW2 image from: $(BOOTC_IMG)"a
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix typo: remove trailing 'a'.

Line 39 has a stray character at the end.

Apply this diff:

-	@echo "Building QCOW2 image from: $(BOOTC_IMG)"a
+	@echo "Building QCOW2 image from: $(BOOTC_IMG)"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@echo "Building QCOW2 image from: $(BOOTC_IMG)"a
@echo "Building QCOW2 image from: $(BOOTC_IMG)"
🤖 Prompt for AI Agents
In deploy/microshift-bootc/Makefile around line 39, there's a stray trailing 'a'
at the end of the echo command; remove the extraneous character so the line
reads the intended echo statement without the trailing 'a'.

Comment on lines +102 to +107
bootc-push-multi: ## Push the multiarch manifest to registry
@echo "Pushing multiarch manifest: $(BOOTC_IMG)"
@echo "This will push the manifest list with amd64 and arm64 images"
podman manifest push $(BOOTC_IMG) $(BOOTC_IMG)
@echo "Multiarch manifest pushed successfully!"
@echo "Images available for linux/amd64 and linux/arm64"
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

bootc-push-multi needs sudo for consistency.

Since bootc-build-multi should use sudo (per previous comment) to match where bootc-build stores images, this push target must also use sudo.

Apply this diff:

 bootc-push-multi: ## Push the multiarch manifest to registry
 	@echo "Pushing multiarch manifest: $(BOOTC_IMG)"
 	@echo "This will push the manifest list with amd64 and arm64 images"
-	podman manifest push $(BOOTC_IMG) $(BOOTC_IMG)
+	sudo podman manifest push $(BOOTC_IMG) $(BOOTC_IMG)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
bootc-push-multi: ## Push the multiarch manifest to registry
@echo "Pushing multiarch manifest: $(BOOTC_IMG)"
@echo "This will push the manifest list with amd64 and arm64 images"
podman manifest push $(BOOTC_IMG) $(BOOTC_IMG)
@echo "Multiarch manifest pushed successfully!"
@echo "Images available for linux/amd64 and linux/arm64"
bootc-push-multi: ## Push the multiarch manifest to registry
@echo "Pushing multiarch manifest: $(BOOTC_IMG)"
@echo "This will push the manifest list with amd64 and arm64 images"
sudo podman manifest push $(BOOTC_IMG) $(BOOTC_IMG)
@echo "Multiarch manifest pushed successfully!"
@echo "Images available for linux/amd64 and linux/arm64"
🤖 Prompt for AI Agents
In deploy/microshift-bootc/Makefile around lines 102 to 107, the podman manifest
push is missing sudo which makes its behavior inconsistent with
bootc-build-multi; update the target to run podman under sudo (e.g., prefix the
podman manifest push command with sudo and keep the leading @) so the push
operates with the same root-owned image store as the build step.

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.

3 participants