Skip to content

[platform] add custom proxmox bundle preset - #1927

Closed
Marian Koreniuk (themoriarti) wants to merge 98 commits into
cozystack:mainfrom
themoriarti:69-integration-with-proxmox-paas-proxmox-bundle
Closed

Marian Koreniuk (themoriarti) wants to merge 98 commits into
cozystack:mainfrom
themoriarti:69-integration-with-proxmox-paas-proxmox-bundle

Conversation

@themoriarti

@themoriarti Marian Koreniuk (themoriarti) commented Jan 28, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

  • add a reduced Proxmox bundle definition
  • add a preset values file to enable the custom bundle
  • document build steps and outcomes in the sprint log

Test plan

  • make build PUSH=0 LOAD=1 REGISTRY=localhost:5000

Summary by CodeRabbit

  • New Features

    • Added Proxmox VE integration enabling VM creation and management via Kubernetes API
    • Added Proxmox CSI storage driver for persistent volumes
    • Integrated Cluster API provider for Proxmox infrastructure provisioning
  • CI/CD

    • Configured GitHub Actions workflows for continuous integration and linting
  • Documentation

    • Comprehensive architecture and deployment guides for Proxmox integration
    • Testing plans, troubleshooting guides, and operational runbooks
  • Tests

    • Added integration test scripts and debugging utilities for Proxmox clusters

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

Signed-off-by: Andrei Kvapil <[email protected]>
* Add etcd-operator

Signed-off-by: Andrei Kvapil <[email protected]>

* Fix etcd-operator Makefile

---------

Signed-off-by: Andrei Kvapil <[email protected]>
Co-authored-by: Andrei Kvapil <[email protected]>
…h-proxmox-paas-proxmox-bundle

Add Managed Kubernetes - Proxmox version
* upd kubernetes (cozystack#134)

* Allow root login without password

* add ephemeral volumes for containerd and kubelet

* update kubernetes application

* etcd: Add quota-backend-bytes calculations (cozystack#133)

* Prepare release v0.6.0 (cozystack#135)

---------

Co-authored-by: Andrei Kvapil <[email protected]>
* upd kubernetes (cozystack#134)

* Allow root login without password

* add ephemeral volumes for containerd and kubelet

* update kubernetes application

* etcd: Add quota-backend-bytes calculations (cozystack#133)

* Prepare release v0.6.0 (cozystack#135)

* etcd: enable autocompact and defrag (cozystack#137)

Signed-off-by: Andrei Kvapil <[email protected]>

* switched place -maxdepth im Makefiles (cozystack#140)

* postgres: fix users and roles (cozystack#138)

Signed-off-by: Andrei Kvapil <[email protected]>

* kubernetes: enable bpf masqurade and tunnel routing (cozystack#144)

* Unhardcode cluster.local domain (cozystack#142)

Allow using other domains for the cluster

Signed-off-by: Andrei Kvapil <[email protected]>

* kamaji: unhardcode cluster.local domain (cozystack#145)

Signed-off-by: Andrei Kvapil <[email protected]>

* kubernetes: specify correct dns address (cozystack#147)

---------

Signed-off-by: Andrei Kvapil <[email protected]>
Co-authored-by: Andrei Kvapil <[email protected]>
Signed-off-by: Kingdon Barrett <[email protected]>
Signed-off-by: Andrei Kvapil <[email protected]>
Co-authored-by: Kingdon Barrett <[email protected]>
Co-authored-by: Andrei Kvapil <[email protected]>
Co-authored-by: Kingdon Barrett <[email protected]>
Add CI to testing proxmox integration

---------

Signed-off-by: Andrei Kvapil <[email protected]>
Signed-off-by: Kingdon Barrett <[email protected]>
Co-authored-by: Andrei Kvapil <[email protected]>
Co-authored-by: Nikita <[email protected]>
Co-authored-by: Kingdon Barrett <[email protected]>
Co-authored-by: Kingdon Barrett <[email protected]>
Signed-off-by: Andrei Kvapil <[email protected]>
Co-authored-by: Mr Khachaturov <[email protected]>
Co-authored-by: Andrei Kvapil <[email protected]>
Added NexCage v0.7.3+ to Proxmox integration plan for LXC as Pod pattern.

Changes to FRESH_INSTALL_PLAN.md:
==================================

Day 1 Extended (4h → 5h):
-------------------------
✅ Added Step 1.0: Install NexCage on Proxmox Host
  - Install Zig 0.15.1 compiler
  - Build NexCage from source
  - Configure systemd service
  - Enable Kubernetes CRI integration
  - Create /etc/nexcage/config.json
  - Verify installation and socket

Software Requirements Updated:
-------------------------------
✅ Added NexCage v0.7.3+ requirement
✅ Added dependencies: libcap-dev, libseccomp-dev, libyajl-dev
✅ Separated dev machine vs Proxmox host requirements

Week 2 Testing Expanded:
-------------------------
✅ Test 6: NexCage LXC Integration
  - Verify NexCage service running
  - Test LXC list via NexCage
  - Create test pod with LXC runtime annotation
  - Verify LXC container in Proxmox (pct list)

✅ Test 7: Database on LXC via NexCage
  - Deploy PostgreSQL with LXC runtime
  - Test runtime.cozystack.io/type: lxc annotation
  - Verify container isolation
  - Test database connectivity

✅ Test 8: Integration Tests
  - NexCage health checks
  - Runtime verification

Success Criteria Extended:
---------------------------
✅ Installation: NexCage installed and running
✅ Integration: NexCage LXC runtime tested
✅ Integration: Database on LXC verified

Quick Start Updated:
--------------------
✅ Step 0: Install NexCage on Proxmox host
✅ Updated verification to include NexCage

Comparison Table Enhanced:
--------------------------
✅ Container Runtime: containerd only → containerd + NexCage
✅ LXC Support: No → Yes (via NexCage)
✅ Database Isolation: Pods only → Pods + LXC

Timeline Adjusted:
------------------
✅ Day 1: 4h → 5h (NexCage install)
✅ Total: 44h → 45h

New File: NEXCAGE_INTEGRATION.md (630 lines):
==============================================

Complete documentation for NexCage:
-----------------------------------
✅ Overview and architecture
✅ Why NexCage (5 key benefits)
✅ Use cases (Database-as-a-Service)
✅ Step-by-step installation guide
✅ Kubernetes integration (2 methods)
✅ Database operator integration examples
✅ 8 comprehensive tests
✅ Troubleshooting (4 common issues)
✅ Performance comparison table
✅ When to use LXC vs Pods
✅ Monitoring and metrics
✅ Security best practices
✅ References and roadmap

Key Features:
=============
✅ LXC as Pod pattern for databases
✅ Hybrid isolation (pods + LXC)
✅ Runtime selection via annotations
✅ Better performance for stateful workloads
✅ Proxmox native integration

Architecture:
=============
Kubernetes → CozyStack → Database Operators
    ↓           ↓
  Pods     LXC (NexCage)
    ↓           ↓
containerd  Proxmox LXC

Benefits:
=========
✅ Near-native I/O performance (95-98%)
✅ Lower memory overhead (40% less)
✅ Stronger isolation for databases
✅ Multi-tenant support
✅ OCI compatible

References:
===========
- NexCage: https://github.com/CageForge/nexcage
- Architecture: Kubernetes CRI + Proxmox LXC
- Version: v0.7.3 (stable)

Next Steps:
===========
1. Install NexCage on Proxmox host
2. Test basic LXC functionality
3. Integrate with Kubernetes
4. Deploy database on LXC
5. Validate performance

Related: cozystack#69
Added NEXCAGE_INTEGRATION.md to Architecture Documents section.

Documentation includes:
- Complete NexCage installation guide
- Kubernetes CRI integration
- Database operators with LXC runtime
- Testing procedures
- Troubleshooting guide
- Performance comparison

Status: Documentation complete
Files: 34 markdown documents (~250KB total)

Related: cozystack#69
Integrated existing Proxmox automation from themoriarti/proxmox-hetzner repository.

Repository: https://github.com/themoriarti/proxmox-hetzner
Script: pve-install.sh

Changes to FRESH_INSTALL_PLAN.md:
==================================

Day 0.1: Simplified (2h → 1h):
==============================
✅ Removed manual Debian installation
✅ Removed manual network configuration
✅ Removed manual storage partitioning
✅ Kept only:
  - Server ordering
  - Rescue system activation
  - Hardware verification

Reason: All handled by pve-install.sh script

Day 0.2: Updated to use existing script (4h):
==============================================
✅ Replaced custom install-proxmox.sh with pve-install.sh
✅ Download from GitHub (single wget command)
✅ Interactive configuration prompts
✅ Automatic installation process

Script Features Documented:
============================
1. Interactive Configuration:
   - Network interface (auto-detected)
   - Hostname and FQDN
   - Timezone (Europe/Kiev)
   - Email address
   - Private subnet (10.0.0.0/24)
   - Root password

2. Automatic Network Detection:
   - IPv4 CIDR and gateway
   - IPv6 configuration
   - MAC address
   - Interface altnames support

3. Installation Process:
   - Downloads latest Proxmox VE ISO
   - Creates answer.toml
   - Generates autoinstall ISO
   - Installs via QEMU/KVM
   - UEFI and BIOS support
   - VNC monitoring (port 5901)

4. Post-Installation Configuration:
   - Network interfaces (public + vmbr0)
   - Hosts file
   - DNS resolvers (Hetzner specific: 185.12.64.1/2)
   - Sysctl tweaks (99-proxmox.conf)
   - APT sources (Debian + Proxmox no-subscription)
   - Disables rpcbind
   - Enterprise repo cleanup

5. Storage Configuration:
   - ZFS RAID1 (automatic)
   - /dev/vda, /dev/vdb detection

6. Template Files (auto-downloaded):
   - 99-proxmox.conf
   - hosts
   - interfaces
   - debian.sources
   - proxmox.sources

Timeline Updated:
=================
Week 0: 8h → 7h (saved 1 hour)
  Day 0.1: 2h → 1h
  Day 0.2: 4h (unchanged, but simpler)
  Day 0.3: 2h (unchanged)
Total: 52 hours (was 53 hours)

Quick Start Commands Updated:
==============================
✅ Section renamed: "For Proxmox on Hetzner (Automated - themoriarti/proxmox-hetzner)"
✅ 4-step process:
  1. Boot rescue system
  2. Download pve-install.sh
  3. Run with interactive prompts
  4. Verify after reboot

✅ Example configuration provided:
  - Hostname: proxmox-cozy
  - FQDN: proxmox-cozy.cp.if.ua
  - Timezone: Europe/Kiev
  - Email: [email protected]
  - Private subnet: 10.0.0.0/24

Monitoring Added:
=================
✅ Optional VNC access (port 5901)
✅ QEMU process monitoring
✅ Installation log (qemu-install.log)

References Updated:
===================
✅ Added: Proxmox-Hetzner Automation ⭐
✅ Added: Direct link to pve-install.sh script

Advantages:
===========
✅ Uses existing, tested automation
✅ Maintained by repository owner
✅ No need to maintain custom script
✅ Community-tested and proven
✅ Hetzner-specific optimizations
✅ Template files included
✅ DNS resolvers pre-configured for Hetzner

Script Capabilities:
====================
- Full Proxmox VE installation from rescue system
- ZFS RAID1 with 2 disks
- Network auto-configuration
- Public IP + private bridge (vmbr0)
- IPv4 and IPv6 support
- NAT/MASQUERADE for VMs
- Repository configuration
- Security basics
- SSH access configured

Time Savings:
=============
- Day 0.1: 1 hour saved (no manual Debian install)
- Simpler workflow
- Less manual configuration
- Proven automation

Next Action:
============
Run pve-install.sh in Hetzner rescue system

Status: READY TO EXECUTE
Repository: themoriarti/proxmox-hetzner
Script: pve-install.sh

Related: cozystack#69
Signed-off-by: Marian Koreniuk <[email protected]>
This PR synchronizes the latest changes from the main branch into the
Proxmox integration branch.
The goal is to align the codebase before continuing integration work,
reduce branch divergence, and avoid late-stage merge conflicts.
Add a reduced Proxmox bundle and preset values file, and document the build and bundle work in the sprint log.
@dosubot dosubot Bot added the size/XXL This PR changes 1000+ lines, ignoring generated files label Jan 28, 2026
@coderabbitai

coderabbitai Bot commented Jan 28, 2026 •

Copy link
Copy Markdown
Contributor

Important

Review skipped

Too many files!

This PR contains 154 files, which is 4 over the limit of 150.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

  • ✅ Full review completed - (🔄 Check again to review again)

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.

@dosubot dosubot Bot added the kind/feature Categorizes issue or PR as related to a new feature label Jan 28, 2026
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello Marian Koreniuk (@themoriarti), I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request delivers a critical architectural pivot for Proxmox integration, moving towards a more native and efficient CAPI-driven VM management. It introduces a refined bundle definition, extensive documentation, and a custom preset to streamline deployments. The changes ensure that the platform fully leverages Proxmox's capabilities, providing a robust foundation for future enhancements like LXC runtime support and advanced tenant cluster provisioning.

Highlights

  • Architectural Correction for Proxmox Integration: The pull request fundamentally corrects the approach to Proxmox integration, shifting from a KubeVirt-based VM management (VMs inside Kubernetes pods) to a native Cluster API (CAPI) approach where VMs are created directly in the Proxmox hypervisor. This change significantly improves performance, efficiency, and leverages native Proxmox features.
  • Updated paas-proxmox Bundle Definition: The paas-proxmox.yaml bundle has been updated to reflect the corrected architecture. This includes removing KubeVirt-related components, adding essential CozyStack core components (FluxCD, Cozy-Proxy, Cert-Manager, CozyStack API/Controller), and integrating key Proxmox-specific components like Proxmox CSI, Proxmox CCM, MetalLB, and LINSTOR for storage and networking.
  • Comprehensive Documentation Suite: A vast amount of documentation has been added, including detailed architectural explanations (PROXMOX_ARCHITECTURE.md), VM creation guides (PROXMOX_VM_CREATION_GUIDE.md), critical fix details (CRITICAL_FIX_PROXMOX_BUNDLE.md), and extensive roadmap and planning documents. This suite clarifies the new approach and provides practical guides.
  • New Custom Proxmox Bundle Preset: A new custom bundle preset, paas-proxmox-custom, has been introduced. This allows for a reduced set of components tailored for specific Proxmox deployments, offering more flexibility and control over the installed services.
  • CAPI Proxmox Provider Integration: The Cluster API Proxmox provider (capi-providers-proxmox) has been integrated, enabling Kubernetes to manage Proxmox VMs as nodes. This includes new Helm charts, example configurations, and test scripts to facilitate seamless VM lifecycle management directly from Kubernetes.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Ignored Files
  • Ignored by pattern: .github/workflows/** (4)
    • .github/workflows/ci.yml
    • .github/workflows/lint.yml
    • .github/workflows/linters/.markdown-lint.yml
    • .github/workflows/linters/.yaml-lint.yml
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment Gemini (@gemini-code-assist) Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on Gemini (@gemini-code-assist) comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces comprehensive support for Proxmox integration within CozyStack, including new Helm charts for the Cluster API Proxmox provider, CSI, and CCM. It also includes extensive documentation detailing the architecture, installation, testing, and troubleshooting for Proxmox-based deployments. The changes correctly pivot from a KubeVirt-centric approach to leveraging native Proxmox virtualization, which is a critical architectural improvement. The addition of a custom bundle variant (paas-proxmox-custom) and its corresponding values file provides flexibility for tailored deployments. The detailed roadmap and session logs demonstrate a thorough and iterative development process. Overall, this is a significant and well-documented enhancement to the platform's virtualization capabilities.

exec:
command: ["/bin/sh", "-c", "rm -rf /registration/csi.kubevirt.io-reg.sock /csi/csi.sock"]
env:
- name: ADDRESS

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

critical

The preStop command for csi-node-driver-registrar references csi.kubevirt.io-reg.sock. This appears to be a copy-paste error from a KubeVirt setup. It should likely be csi.proxmox.io-reg.sock to match the Proxmox CSI driver. This could lead to incorrect cleanup or registration issues.

                command: ["/bin/sh", "-c", "rm -rf /registration/csi.proxmox.io-reg.sock /csi/csi.sock"]

Comment on lines +145 to +161
```yaml
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
kind: ProxmoxMachine
metadata:
name: test-vm-1
namespace: default
spec:
nodeName: pve # Proxmox node
template: ubuntu-22.04 # VM template
cores: 2
memory: 4096 # MB
diskSize: 20 # GB
network:
default:
bridge: vmbr0
model: virtio
```

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The apiVersion for ProxmoxMachine is infrastructure.cluster.x-k8s.io/v1beta1. As noted previously, ensure consistency across all configurations and documentation for the Proxmox CAPI resources, as v1alpha1 is also seen.

Comment on lines +540 to +556
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
kind: ProxmoxMachine
metadata:
name: postgres-vm
namespace: tenant-db
spec:
nodeName: pve
template: ubuntu-22.04
cores: 8
memory: 32768 # 32GB
diskSize: 500 # 500GB for database
storage: local-ssd # Use SSD storage
network:
default:
bridge: vmbr0
vlan: 200 # Database VLAN
```

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The EOF markers are included within the code block, which is not standard for shell scripts. They should typically be outside the cat > command's input. While this is documentation, it's good practice to show correct syntax for copy-pasting.

#### Fix
```bash
# 1. Fix duplicate in paas-proxmox.yaml bundle
# Remove duplicate lines 88-92

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The comment # Remove duplicate lines 88-92 refers to line numbers that are not present in the current diff. This comment should be updated or removed to reflect the actual state of the paas-proxmox.yaml file after the architectural fix.

Comment on lines +145 to +155
cat >> /etc/containerd/config.toml <<EOF

[plugins."io.containerd.grpc.v1.cri".containerd]
default_runtime_name = "runc"

[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
runtime_type = "io.containerd.runc.v2"

[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
SystemdCgroup = true
EOF

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The EOF marker is included within the code block, which is not standard for shell scripts. It should typically be outside the cat command's input. While this is documentation, it's good practice to show correct syntax for copy-pasting.

matchLabels:
infraprovider-components: cozy
{{- end }}
{{- if .Values.providers.proxmox }}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The proxmox provider is conditionally enabled. This is a good approach for flexibility. Ensure that the values.yaml clearly indicates how to enable/disable this provider and that it's mutually exclusive with other infrastructure providers if intended.

Comment on lines +13 to +15
username: root@pam
password: your-secure-password
url: https://proxmox.example.com:8006/api2/json

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The stringData field is used for proxmox-credentials. While convenient, stringData is not suitable for sensitive data in production environments as it stores the data unencrypted in etcd. Consider using data with base64 encoded values and managing the secret securely, perhaps through a secret management solution like Vault or external secrets.

Comment on lines +47 to +49
- cert-manager dependencies fixed
- Proper namespace for proxmox-csi
- Added privileged flag where needed

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Similar to the + prefix, the - prefix in these lines within the YAML code block could be misleading. These are descriptive markers for fixes applied to paas-proxmox.yaml, not actual YAML syntax. Consider removing the - to avoid confusion.

tag=$$(git ls-remote --tags --sort="v:refname" https://github.com/sergelogvinov/proxmox-cloud-controller-manager | awk -F'[/^]' 'END{print $$3}') && \
curl -sSL https://github.com/sergelogvinov/proxmox-cloud-controller-manager/archive/refs/tags/$${tag}.tar.gz | \
tar xzvf - --strip 1 proxmox-cloud-controller-manager-$${tag#*v}/charts
sed -i 's/^ namespace: .*/ namespace: kube-system/' charts/proxmox-cloud-controller-manager/templates/rolebinding.yaml

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The sed command modifies the namespace in charts/proxmox-cloud-controller-manager/templates/rolebinding.yaml to kube-system. While this might be necessary for the CCM to function correctly, hardcoding the namespace within the chart's templates can limit flexibility. Consider making the namespace configurable via Helm values, or ensuring this is the universally desired namespace for CCM deployments.

Comment on lines +12 to +13
rm -f charts/proxmox-csi-plugin/templates/namespace.yaml
patch -p 3 < patches/namespace.patch

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Removing charts/proxmox-csi-plugin/templates/namespace.yaml and then applying a patch to handle namespaces indicates a potential conflict or desired override of the upstream chart's namespace management. Ensure this approach is robust and won't cause issues if the upstream chart changes its namespace handling in future versions. Documenting the reason for this override would be beneficial.

@themoriarti
Marian Koreniuk (themoriarti) marked this pull request as draft January 28, 2026 02:32

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 14

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

Caution

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

⚠️ Outside diff range comments (1)
packages/system/capi-providers-infraprovider/templates/providers.yaml (1)

1-16: Guard against enabling both infra providers simultaneously.

Both resources use the same fetchConfig.selector.matchLabels, so if both flags are true you can end up installing the same component set twice or wiring the wrong components to a provider. Add an explicit mutual-exclusion guard (or distinct selectors).

🐛 Suggested Helm guard
+{{- if and .Values.providers.kubevirt .Values.providers.proxmox }}
+{{- fail "Only one of providers.kubevirt or providers.proxmox can be true" }}
+{{- end }}
 {{- if .Values.providers.kubevirt }}
 ---
 apiVersion: operator.cluster.x-k8s.io/v1alpha2
 kind: InfrastructureProvider
 metadata:
   name: kubevirt
🤖 Fix all issues with AI agents
In @.github/workflows/lint.yml:
- Around line 23-24: The workflow step named "Run Super-Linter" is using an old
action reference (github/super-linter@v4); update the uses value to the current
namespace and tag by replacing that reference with
super-linter/[email protected], then run the workflow and adjust any linter
config if compatibility issues arise (verify the step name "Run Super-Linter"
and any inputs/options passed to it remain correct after the upgrade).

In @.github/workflows/linters/.yaml-lint.yml:
- Around line 1-55: Remove the leading blank first line and delete the
standalone "line-length: disable" entry so there is only the detailed
"line-length:" mapping block present; update the YAML to keep the later
line-length mapping (max: 130, allow-non-breakable-words,
allow-non-breakable-inline-mappings) and remove the duplicate key to avoid
yamllint key-duplicate errors.

In `@packages/core/platform/bundles/paas-proxmox.yaml`:
- Around line 1-73: The template uses lookup to fetch the ConfigMap into
$cozyConfig and then directly accesses $cozyConfig.data (e.g., in the kube-ovn
values and the telemetry check), which will nil-panic if the ConfigMap is
missing; change the initial lookup so $cozyConfig defaults to an empty dict (use
the existing default dict pattern) and then reference $cozyConfig.data safely
(or provide per-key defaults when calling index, e.g., for "cluster-domain",
"ipv4-pod-cidr", "ipv4-pod-gateway", "ipv4-svc-cidr", "ipv4-join-cidr", and
"telemetry-enabled") so that functions and conditionals like the cluster domain
substitution, kube-ovn POD_CIDR/JOIN_CIDR/SVC_CIDR/POD_GATEWAY, and the
telemetry check (the eq against index $cozyConfig.data "telemetry-enabled") work
on fresh installs without the ConfigMap present.

In `@packages/system/capi-providers-proxmox/examples/proxmox-cluster.yaml`:
- Around line 12-40: Add a credentials reference and fix the Secret field names:
create/use a Secret whose stringData contains "url" (full API URL), "token"
(token ID) and "secret" (token value) instead of "username"/"password", then
update ProxmoxCluster.spec to include credentialsRef pointing to that Secret
(e.g. set ProxmoxCluster.spec.credentialsRef.name to the Secret name and
credentialsRef.kind/namespace as needed) so the provider (ProxmoxCluster) can
authenticate using the expected fields.

In `@packages/system/capi-providers-proxmox/Makefile`:
- Around line 1-4: The Makefile sets NAME and NAMESPACE but includes the wrong
makefile path; update the include line in this Makefile so it uses
../../../hack/package.mk instead of ../../../scripts/package.mk (i.e., change
the include reference used alongside the NAME and NAMESPACE declarations to
point to hack/package.mk so the shared .PHONY and targets are picked up).

In `@packages/system/capi-providers-proxmox/templates/configmaps.yaml`:
- Around line 8-10: components.yaml in the ConfigMap currently contains only
comments but is selected by the CAPI provider via the label
"infraprovider-components: cozy" (see providers.yaml), so either populate
components.yaml with the actual Proxmox provider manifests (controller
Deployment, CRDs, RBAC, ServiceAccount, ClusterRoleBinding, webhook manifests as
required) or change the chart to load those files the same way the other
infraprovider ConfigMap does (use binaryData/data with .Files.Get to inject the
real component YAMLs); update the ConfigMap named "components.yaml" to include
the real manifests or add documentation and chart values to require upstream
injection so the CAPI InfrastructureProvider can find and apply the Proxmox
components.

In `@packages/system/capi-providers/docs/kube-ovn-cilium-setup.md`:
- Around line 99-102: The cilium install invocation pins an EOL release ("cilium
install --version 1.14.0"); update this to a currently maintained stable release
(for example use 1.18.x or another supported 1.16/1.17/1.18 tag) so users deploy
a supported Cilium version — replace the literal "--version 1.14.0" in the
install command with the chosen supported version string (e.g., "--version
1.18.0") or a documented variable placeholder to keep it up-to-date.

In `@packages/system/capi-providers/docs/proxmox-csi-setup.md`:
- Around line 20-25: Replace the incorrect installation URLs in
proxmox-csi-setup.md (the kubectl apply lines referencing prometheus-operator
and generic csi repos) with the official Proxmox CSI plugin manifest URL (use
the v0.7.0 release manifest) or add the provided Helm repo/add + helm install
commands for proxmox-csi-plugin; also find the deployment image reference
`image: proxmox/csi-driver:latest` and pin it to a specific release (e.g.,
`v0.7.0`) to avoid using the `latest` tag in production.

In `@packages/system/capi-providers/scripts/create-proxmox-cluster.sh`:
- Around line 1-6: Add shell safety flags to the script by enabling "set -e" and
"set -o pipefail" (optionally "set -u") right after the shebang in
create-proxmox-cluster.sh so the script exits on command failures and fails in
pipelines; update the top of the file (above or immediately before the
debug_log() function) to include these options to ensure intermediate errors
stop execution.

In `@packages/system/capi-providers/templates/proxmox-examples.yaml`:
- Around line 37-84: The Machine manifests for kind: Machine (metadata.name:
proxmox-control-plane and proxmox-worker) are missing the required
spec.clusterName field; add spec.clusterName to both Machine resources (e.g.,
spec.clusterName: ${CLUSTER_NAME} or the actual Cluster name) so the API can
associate each Machine with its Cluster.

In `@packages/system/proxmox-csi-node/templates/deploy.yaml`:
- Around line 1-9: The CSIDriver registration name and socket/path references
are inconsistent: change the CSIDriver metadata.name from "csi.kubevirt.io" to
"csi.proxmox.io", update the preStop hook socket reference from
"csi.kubevirt.io-reg.sock" to "csi.proxmox.io-reg.sock", and ensure all
plugin/socket path occurrences (e.g., /var/lib/kubelet/plugins/csi.proxmox.io
and any references in the StorageClass provisioner) use "csi.proxmox.io" so the
CSIDriver (metadata.name), StorageClass provisioner, preStop hook, and plugin
paths all match.
- Line 166: Replace the test image reference
`ghcr.io/kvaps/test:proxmox-csi-driver` in the deployment template with the
production-ready image used upstream (e.g.,
`ghcr.io/sergelogvinov/proxmox-csi-node` and an appropriate stable tag); locate
the image field in the deploy.yaml template (the line containing image:
ghcr.io/kvaps/test:proxmox-csi-driver) and update it to the official registry
path and a specific release tag prior to merging.

In
`@packages/system/proxmox-csi/charts/proxmox-cloud-controller-manager/.helmignore`:
- Around line 1-23: You modified the vendored chart
"proxmox-cloud-controller-manager" by adding a .helmignore directly in the
charts folder; revert this direct edit and instead apply the change via the
vendoring/update process for that upstream repository
(sergelogvinov/proxmox-cloud-controller-manager), e.g., add the .helmignore in
the upstream chart or include it during the vendoring step and re-run the
vendoring tooling so the chart in the vendor directory is updated from the
canonical source rather than edited in-place.

In `@Roadmap/TESTING_RESULTS.md`:
- Around line 3-6: Replace all real infrastructure identifiers in
TESTING_RESULTS.md (e.g., the “Cluster” and “Proxmox Server” entries that show
names like "mgr.cp.if.ua", node "mgr", and IP "10.0.0.1") with neutral
placeholders (e.g., <REDACTED_CLUSTER>, <REDACTED_NODE>, <REDACTED_IP>) or move
the sensitive sections into a private document; also scan and redact the other
occurrences called out around the ranges noted (near lines 192-199 and 295-312)
so no hostnames, usernames, or IP addresses remain in the public repo.
🟡 Minor comments (38)
Roadmap/TIME_TRACKING.md-14-14 (1)

14-14: Use headings instead of bold text for section labels

Markdownlint flags several bold lines used as headings (e.g., Line 14, Line 36, Line 54, Line 71, Line 88, Line 107, Line 124, Line 141, Line 158, Line 175, Line 194, Line 211). Converting them to proper heading levels will clear MD036.

✏️ Example fix (apply similarly to other lines)
-**Deliverables**:
+#### Deliverables

Also applies to: 36-36, 54-54, 71-71, 88-88, 107-107, 124-124, 141-141, 158-158, 175-175, 194-194, 211-211

packages/system/proxmox-csi/charts/proxmox-cloud-controller-manager/Chart.yaml-1-24 (1)

1-24: Remove manual Chart.yaml version bump and apply as patch instead

This vendored chart violates the chart vendoring policy. The Makefile's update target shows charts are downloaded fresh from upstream and modifications are applied via patches (currently only namespace.patch). However, the Chart.yaml version has been manually bumped to 0.3.0, while the upstream is at 0.2.11.

If you need a custom chart version locally, create a Chart.yaml patch file in patches/ instead of directly editing the vendored file. Alternatively, if this version bump should not be local, revert it to match the upstream version.

packages/system/capi-providers/docs/talos-proxmox-setup.md-141-142 (1)

141-142: Replace placeholder repository URLs

Lines 141 and 203 contain your-org placeholders that prevent copy-paste functionality. Update these to point to the actual CozyStack repository:

✏️ Suggested fixes
- git clone https://github.com/your-org/cozystack.git
+ git clone https://github.com/cozystack/cozystack.git
@@
-- [CozyStack Documentation](https://github.com/your-org/cozystack/docs)
+- [CozyStack Documentation](https://github.com/cozystack/cozystack/tree/main/docs)
packages/system/proxmox-csi/Makefile-1-4 (1)

1-4: Add .PHONY: update for explicit target declaration

The update target should be declared as phony. While the parent makefile app-helm.mk attempts to declare it, using .PHONY: update locally makes the intent explicit and uses correct Make syntax.

Proposed fix
 include ../../hack/app-helm.mk
+.PHONY: update
Roadmap/TESTING_RESULTS.md-65-66 (1)

65-66: Avoid “latest stable” wording in a dated test report.

Use “tested with Proxmox VE 9.0.10” to avoid future staleness.

✏️ Suggested wording
-**Result**: ✅ Proxmox VE 9.0.10 (latest stable, excellent compatibility)
+**Result**: ✅ Tested with Proxmox VE 9.0.10
...
-- **Proxmox VE 9.0.10** - Latest stable version
+- **Proxmox VE 9.0.10** - Tested version

Also applies to: 252-253

Roadmap/TESTING_RESULTS.md-103-109 (1)

103-109: Add language identifiers to fenced blocks (markdownlint MD040).

Several code fences don’t specify a language. Please add a language tag (e.g., text, yaml, bash) to keep markdownlint happy.

Also applies to: 148-153, 161-166, 169-174, 207-212, 296-302, 305-312, 314-324

Roadmap/COZYSTACK_UPGRADE_PLAN.md-216-229 (1)

216-229: kubectl apply -f Chart.yaml/values.yaml will fail.

Those files aren’t Kubernetes manifests. Use Helm directly or helm template + kubectl apply.

✅ Suggested fix
-# Apply updates
-kubectl apply -f Chart.yaml
-kubectl apply -f values.yaml
-
-# Or use Helm
-helm upgrade cozystack-platform . \
+# Use Helm
+helm upgrade cozystack-platform . \
   --namespace cozy-system \
   --values values.yaml \
   --wait --timeout=15m
packages/system/proxmox-csi/charts/proxmox-cloud-controller-manager/README.md.gotmpl-43-49 (1)

43-49: Fix example URL typo and CCM token name.

The example URL uses exmple.com (typo) and the token suffix csi in a CCM doc. Consider example.com and a CCM token suffix for clarity.

✏️ Suggested example fix
-    - url: https://cluster-api-1.exmple.com:8006/api2/json
+    - url: https://cluster-api-1.example.com:8006/api2/json
       insecure: false
-      token_id: "kubernetes@pve!csi"
+      token_id: "kubernetes@pve!ccm"
       token_secret: "key"
packages/system/proxmox-csi/charts/proxmox-cloud-controller-manager/ci/values.yaml-22-30 (1)

22-30: Use reserved example domains and explicit placeholder tokens.

exmple.com is a typo and can resolve to a real domain. Also, token_secret: "secret" can be misread as a real secret. Use example.com/.invalid and clear placeholders.

✏️ Suggested placeholders
-    - url: https://cluster-api-1.exmple.com:8006/api2/json
+    - url: https://cluster-api-1.example.com:8006/api2/json
       insecure: false
-      token_id: "user!token-id"
-      token_secret: "secret"
+      token_id: "<TOKEN_ID>"
+      token_secret: "<TOKEN_SECRET>"
       region: cluster-1
packages/system/proxmox-csi-node/Chart.yaml-1-2 (1)

1-2: Missing apiVersion field required for Helm 3.

While the naming convention is correct, the chart is missing the apiVersion field which is required for Helm 3 charts.

Suggested fix
+apiVersion: v2
 name: cozy-proxmox-csi-node
 version: 0.1.0
+description: Proxmox CSI Node Plugin
packages/system/proxmox-csi/Chart.yaml-1-2 (1)

1-2: Chart.yaml appears incomplete with placeholder values.

The chart uses a generic name app instead of a descriptive name like cozy-proxmox-csi, and is missing required fields for Helm 3:

  • apiVersion (required, should be v2 for Helm 3)
  • description (recommended)

Compare with the sibling chart proxmox-csi-node which uses cozy-proxmox-csi-node.

Suggested fix
+apiVersion: v2
-name: app
-version: 0.0.0
+name: cozy-proxmox-csi
+version: 0.1.0
+description: Proxmox CSI Plugin for Kubernetes

Based on learnings: "Use Helm Chart umbrella pattern with vendored upstream charts in charts/ directory" for packages/system/**.

packages/system/capi-providers/scripts/debug-proxmox-cluster.sh-63-70 (1)

63-70: Namespace mismatch when fetching machine logs.

The function retrieves machines from all namespaces (-A) but then attempts to fetch logs only from the default namespace. This will miss logs for machines deployed in other namespaces.

Proposed fix to preserve namespace context
 check_machine_logs() {
     debug_log "Checking machine logs..."
-    for machine in $(kubectl get machines -A -o jsonpath='{.items[*].metadata.name}'); do
+    kubectl get machines -A -o jsonpath='{range .items[*]}{.metadata.namespace}{" "}{.metadata.name}{"\n"}{end}' | while read -r ns machine; do
+        [ -z "$machine" ] && continue
         echo "=== Logs for machine $machine ==="
-        kubectl logs -n default -l cluster.x-k8s.io/machine-name=$machine --tail=100
+        kubectl logs -n "$ns" -l cluster.x-k8s.io/machine-name="$machine" --tail=100 2>/dev/null || echo "No logs found"
     done
 }
packages/system/proxmox-csi/charts/proxmox-cloud-controller-manager/README.md-47-47 (1)

47-47: Typo: "exmple.com" should be "example.com".

📝 Proposed fix
-    - url: https://cluster-api-1.exmple.com:8006/api2/json
+    - url: https://cluster-api-1.example.com:8006/api2/json
packages/system/capi-providers-proxmox/README.md-207-209 (1)

207-209: Update placeholder URLs to actual repository links.

The GitHub Issues URL contains a placeholder your-org that should be updated to the actual organization.

📝 Proposed fix
 ## Support
 
 - **Documentation**: https://docs.cozystack.io
-- **GitHub Issues**: https://github.com/your-org/cozystack/issues
+- **GitHub Issues**: https://github.com/cozystack/cozystack/issues
 - **Community**: https://community.cozystack.io
.github/workflows/ci.yml-41-45 (1)

41-45: Fix typo in step name.

"Build usig make" should be "Build using make".

Proposed fix
       - uses: actions/checkout@v3
-      - name: Build usig make
+      - name: Build using make
         run: |
           make
packages/system/capi-providers/docs/kube-ovn-cilium-setup.md-62-89 (1)

62-89: Remove duplicate keys in Kube-OVN ConfigMap example.

Lines 76-89 duplicate the keys from lines 62-75. In YAML, duplicate keys cause the second value to silently override the first. This appears to be a copy-paste error that will confuse users following the guide.

Proposed fix - remove duplicate lines 76-89
   default_vpc_subnet_pool_nat_outgoing: "true"
   default_vpc_subnet_pool_gateway_type: "distributed"
-  default_vpc_subnet_pool_allow_live_migration: "true"
-  default_vpc_subnet_pool_vlan_id: "0"
-  default_vpc_subnet_pool_vlan_range: "1,4095"
-  default_vpc_subnet_pool_u2o_interconnection: "false"
-  default_vpc_subnet_pool_logical_gateway: "false"
-  default_vpc_subnet_pool_gateway_check: "true"
-  default_vpc_subnet_pool_dns: "10.16.0.1"
-  default_vpc_subnet_pool_interface: "eth0"
-  default_vpc_subnet_pool_mtu: "1500"
-  default_vpc_subnet_pool_mac_address: ""
-  default_vpc_subnet_pool_dhcp_options: ""
-  default_vpc_subnet_pool_private: "false"
-  default_vpc_subnet_pool_nat_outgoing: "true"
-  default_vpc_subnet_pool_gateway_type: "distributed"
.github/workflows/lint.yml-27-31 (1)

27-31: Duplicate GITHUB_TOKEN environment variable.

GITHUB_TOKEN is defined twice in the env block (lines 27 and 31). The second definition is redundant and shadows the first. Remove the duplicate to avoid confusion.

Proposed fix
         env:
           # To report GitHub Actions status checks
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
           VALIDATE_ALL_CODEBASE: false  # Lint only changed files
           VALIDATE_TERRAFORM: false     # Disable Terraform linting (remove if you need it)
           DEFAULT_BRANCH: main          # Set your default branch
-          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
           # Enable only the linters you need for your project
           VALIDATE_JAVASCRIPT_ES: true
packages/system/capi-providers/docs/kube-ovn-cilium-setup.md-162-177 (1)

162-177: Remove triplicate keys in Cilium ConfigMap example.

enable-hubble-metrics and hubble-metrics appear three times each (lines 162-165, 167-171, 173-177). Only the last occurrence takes effect. Remove the duplicates to avoid misleading users.

Proposed fix - keep only the first occurrence
   # Enable Hubble metrics server
   enable-hubble-metrics: "true"

   # List of metrics to enable
   hubble-metrics: "dns,drop,tcp,flow,port-distribution,icmp,http"
-
-  # Enable Hubble metrics server
-  enable-hubble-metrics: "true"
-
-  # List of metrics to enable
-  hubble-metrics: "dns,drop,tcp,flow,port-distribution,icmp,http"
-
-  # Enable Hubble metrics server
-  enable-hubble-metrics: "true"
-
-  # List of metrics to enable
-  hubble-metrics: "dns,drop,tcp,flow,port-distribution,icmp,http"
Roadmap/FINAL_TESTING_REPORT.md-26-31 (1)

26-31: Replace the bare URL with a Markdown link.

Line 27 trips MD034; wrap the URL in a link or angle brackets.

💡 Suggested fix
-1. ✅ API Connectivity - Accessible at https://10.0.0.1:8006
+1. ✅ API Connectivity - Accessible at <https://10.0.0.1:8006>
Roadmap/PROXMOX_INTEGRATION_RUNBOOK.md-598-602 (1)

598-602: Format the email as a mailto link (MD034).

Line 601 is treated as a bare URL.

💡 Suggested fix
-- **Email**: [email protected]
+- **Email**: [[email protected]](mailto:[email protected])
Roadmap/README.md-223-227 (1)

223-227: Convert the email to a mailto link (MD034).

Line 226 is flagged as a bare URL.

💡 Suggested fix
-- **Email**: [email protected]
+- **Email**: [[email protected]](mailto:[email protected])
Roadmap/FINAL_TESTING_REPORT.md-94-101 (1)

94-101: Add a language to fenced code blocks (MD040).

Line 94 starts a fenced block without a language. Please add a language tag and mirror this across the other fenced blocks in this document.

💡 Suggested fix (apply similarly to other blocks)
-```
+```text
 Host: 10.0.0.1
 Port: 8006
 Node Name: mgr
 Version: Proxmox VE 9.0.10
 OS: Debian GNU/Linux 13 (trixie)
 Kernel: 6.14.11-2-pve
</details>

</blockquote></details>
<details>
<summary>Roadmap/SPRINT_TIMELINE.md-13-16 (1)</summary><blockquote>

`13-16`: **Use headings instead of bold text for section titles.**

Line 14 triggers MD036. Consider promoting these “Phase …” lines to headings and apply the same change throughout the file.  
<details>
<summary>💡 Suggested fix</summary>

```diff
-**Phase 1.1: Current Infrastructure Analysis**
+#### Phase 1.1: Current Infrastructure Analysis
Roadmap/NEXCAGE_INTEGRATION.md-12-12 (1)

12-12: Wrap bare URLs in Markdown links (MD034).

✏️ Proposed fix
-**GitHub**: https://github.com/CageForge/nexcage
+**GitHub**: [https://github.com/CageForge/nexcage](https://github.com/CageForge/nexcage)
@@
-- **NexCage GitHub**: https://github.com/CageForge/nexcage
-- **LXC Documentation**: https://linuxcontainers.org/lxc/
-- **Proxmox LXC**: https://pve.proxmox.com/wiki/Linux_Container
-- **OCI Runtime Spec**: https://github.com/opencontainers/runtime-spec
-- **Kubernetes CRI**: https://kubernetes.io/docs/concepts/architecture/cri/
+- **NexCage GitHub**: [https://github.com/CageForge/nexcage](https://github.com/CageForge/nexcage)
+- **LXC Documentation**: [https://linuxcontainers.org/lxc/](https://linuxcontainers.org/lxc/)
+- **Proxmox LXC**: [https://pve.proxmox.com/wiki/Linux_Container](https://pve.proxmox.com/wiki/Linux_Container)
+- **OCI Runtime Spec**: [https://github.com/opencontainers/runtime-spec](https://github.com/opencontainers/runtime-spec)
+- **Kubernetes CRI**: [https://kubernetes.io/docs/concepts/architecture/cri/](https://kubernetes.io/docs/concepts/architecture/cri/)

Also applies to: 687-691

Roadmap/SESSION_SUMMARY.md-246-251 (1)

246-251: Add language identifiers to fenced blocks (MD040).

✏️ Proposed fix
-```
+```text
 Start (0%) → Planning (25%) → Recovery (50%) → Testing (75%) → Validation (85%) → Fixes (→100%)
                                                                       ▲
                                                                    YOU ARE HERE

...
- +text
Roadmap/
├── COMPLETE_ROADMAP.md ← Full roadmap
├── CURRENT_STATE_AND_FIXES.md ← What to do next
├── RECOVERY_SUCCESS.md ← How we fixed cluster
└── PROJECT_SUMMARY.md ← Executive summary
@@
tests/proxmox-integration/
├── run-integrity-checks.sh ← Run this to validate
├── integrity_checker.py ← Detailed checks
└── INTEGRITY_CHECKS.md ← Documentation

Also applies to: 351-362

Roadmap/EXTENDED_INTEGRATION_PLAN.md-297-300 (1)

297-300: Wrap the bare URL in a Markdown link (MD034).

✏️ Proposed fix
-**Project**: https://github.com/lxc/incus  
+**Project**: [https://github.com/lxc/incus](https://github.com/lxc/incus)  
Roadmap/SESSION_SUMMARY.md-380-381 (1)

380-381: Convert bare URLs to Markdown links (MD034).

✏️ Proposed fix
-- **PR**: https://github.com/cozystack/cozystack/pull/107
-- **Issue**: https://github.com/cozystack/cozystack/issues/69
+- **PR**: [https://github.com/cozystack/cozystack/pull/107](https://github.com/cozystack/cozystack/pull/107)
+- **Issue**: [https://github.com/cozystack/cozystack/issues/69](https://github.com/cozystack/cozystack/issues/69)
Roadmap/NEXCAGE_INTEGRATION.md-458-465 (1)

458-465: Add a language tag to the output snippet (MD040).

✏️ Proposed fix
-```
+```text
 systemctl status nexcage
 ● nexcage.service - failed to start
</details>

</blockquote></details>
<details>
<summary>Roadmap/WORK_COMPLETE_SUMMARY.md-308-313 (1)</summary><blockquote>

`308-313`: **Remove the stray trailing quote.**

It reads like an accidental character at the end of the doc.


<details>
<summary>✂️ Proposed fix</summary>

```diff
-**Status**: Excellent foundation for future work!
-
-The path forward is clear and well-documented! 🎉"
+**Status**: Excellent foundation for future work!
+
+The path forward is clear and well-documented! 🎉
Roadmap/NEXCAGE_INTEGRATION.md-31-70 (1)

31-70: Add a language tag to the ASCII diagram fence (MD040).

✏️ Proposed fix
-```
+```text
 ┌─────────────────────────────────────────────────────────────┐
 │                      Kubernetes Cluster                      │
 │                                                              │
@@
         │  │  LXC Containers     │   │
         │  │  /var/lib/lxc/      │   │
         │  └─────────────────────┘   │
         └─────────────────────────────┘
</details>

</blockquote></details>
<details>
<summary>Roadmap/PROXMOX_ARCHITECTURE.md-9-21 (1)</summary><blockquote>

`9-21`: **Add a language identifier to the architecture fences (MD040).**


<details>
<summary>✏️ Proposed fix</summary>

```diff
-```
+```text
 User → Kubernetes API → KubeVirt → QEMU/KVM (in pods) → Storage

@@
- +text
User → Kubernetes API → Cluster API → Proxmox API → Proxmox VMs
↓
Proxmox CSI → Proxmox Storage
↓
Proxmox CCM → Proxmox Networking

Roadmap/PROXMOX_ARCHITECTURE.md-231-333 (1)

231-333: Use proper headings instead of bold text (MD036).

✏️ Proposed fix
-**Method 1: Via Kubernetes App (Recommended)**
+#### Method 1: Via Kubernetes App (Recommended)

@@
-**Method 2: Direct ProxmoxMachine (Advanced)**
+#### Method 2: Direct ProxmoxMachine (Advanced)

@@
-**Option A: In LXC Containers** (Future, requires proxmox-lxcri)
+#### Option A: In LXC Containers (Future, requires proxmox-lxcri)

@@
-**Option B: In Proxmox VMs**
+#### Option B: In Proxmox VMs

@@
-**Option C: In Kubernetes Pods** (Default, current)
+#### Option C: In Kubernetes Pods (Default, current)
Roadmap/COMPLETE_ROADMAP.md-312-313 (1)

312-313: Timeline dates may need updating.

The "Revised Schedule" references "Sept 15-29, 2025" but the document is dated October 2025. Consider updating the timeline section to reflect current planning dates.

Roadmap/COMPLETE_ROADMAP.md-5-5 (1)

5-5: Date inconsistency between header and footer.

The header shows Last Updated: 2025-10-24 (line 5) while the footer shows Last Updated: 2025-10-13 23:30 (line 709). Please reconcile these dates.

🐛 Suggested fix
 **Last Updated**: 2025-10-24
 ...
-**Last Updated**: 2025-10-13 23:30
+**Last Updated**: 2025-10-24

Also applies to: 709-709

packages/system/capi-providers-proxmox/scripts/test-proxmox-cluster.sh-49-54 (1)

49-54: Pipeline with grep -q may not trigger set -e on failure.

When using set -e, a pipeline like kubectl get pods | grep -q may not cause the script to exit if grep fails (no match), because only the last command's exit status is checked by default. Consider using set -o pipefail or restructuring.

🐛 Proposed fix
 #!/bin/bash
 
 # Test script for Proxmox Cluster API integration
 
 set -e
+set -o pipefail

Or use a different pattern:

-    if kubectl get pods -n cozy-cluster-api | grep -q "cluster-api-operator"; then
+    if kubectl get pods -n cozy-cluster-api 2>/dev/null | grep -q "cluster-api-operator"; then
packages/system/capi-providers-proxmox/INTEGRATION.md-9-21 (1)

9-21: Add a language tag to the architecture diagram fence.
markdownlint flags this block (MD040). Use text for the ASCII diagram.

📝 Example fix
-```
+```text
┌─────────────────────────────────────────────────────────────────┐
│                    CozyStack CAPI Architecture                  │
├─────────────────────────────────────────────────────────────────┤
│  capi-operator                                                  │
│  ├── cozy-capi-providers-core (Core Provider)                  │
│  ├── cozy-capi-providers-bootstrap (Bootstrap Provider)        │
│  ├── cozy-capi-providers-cpprovider (Control Plane Provider)   │
│  └── cozy-capi-providers-infraprovider (Infrastructure Provider)│
│      ├── kubevirt (existing)                                   │
│      └── proxmox (new)                                         │
└─────────────────────────────────────────────────────────────────┘
-```
+```
Roadmap/ARCHITECTURE_FIX_SUMMARY.md-139-199 (1)

139-199: Add language identifiers to fenced code blocks.
markdownlint flags these fences (MD040). Please add text (or yaml where appropriate) to all unlabeled code blocks in this file.

📝 Example fix
-```
+```text
User Request
    ↓
Kubernetes API
    ↓
VirtualMachine CRD (apps.cozystack.io)
    ↓
HelmRelease
    ↓
Chart creates:
├── DataVolume (CDI)
├── PVC
├── VirtualMachine (kubevirt.io)
└── Service
    ↓
KubeVirt creates:
├── VirtualMachineInstance
└── virt-launcher Pod
    ↓
Pod runs QEMU/KVM
    ↓
VM runs inside pod
-```
+```
Roadmap/PROXMOX_VM_CREATION_GUIDE.md-19-26 (1)

19-26: Add language identifiers to the short fenced blocks.
markdownlint flags these fences (MD040). Use text for the flow snippets.

📝 Example fix
-```
+```text
User → kubectl apply → CAPI → capmox provider → Proxmox API → Proxmox VM
-```
+```
@@
-```
+```text
User → kubectl apply → KubeVirt → Pod → QEMU → VM  ❌
-```
+```
🧹 Nitpick comments (36)
packages/system/capi-providers/docs/talos-proxmox-setup.md (1)

15-18: Pin Talos and CozyStack versions for reproducibility

Lines 17 and 135 use latest for version tags, which causes this guide to drift as upstream projects release new versions. Pin specific versions to ensure reproducibility and reduce maintenance burden when re-validating.

✏️ Suggested update
 1. Download the latest Talos Linux image for Proxmox:
 ```bash
+TALOS_VERSION=vX.Y.Z
-curl -LO https://github.com/siderolabs/talos/releases/latest/download/metal-amd64.raw.xz
+curl -LO https://github.com/siderolabs/talos/releases/download/${TALOS_VERSION}/metal-amd64.raw.xz

```diff
-export COZYSTACK_VERSION=latest
+export COZYSTACK_VERSION=vA.B.C
packages/system/proxmox-csi/charts/proxmox-cloud-controller-manager/ci/values.yaml (1)

1-4: Pin the CCM image for deterministic CI runs.

tag: edge plus pullPolicy: Always makes CI nondeterministic and can introduce flakiness. Prefer a fixed tag or digest for CI reproducibility.

✅ Example (pin to a version)
 image:
   repository: ghcr.io/sergelogvinov/proxmox-cloud-controller-manager
-  pullPolicy: Always
-  tag: edge
+  pullPolicy: IfNotPresent
+  tag: vX.Y.Z
Roadmap/PROXMOX_TESTING_PLAN.md (1)

373-375: Potential stale metadata.

The "Last Updated" date (2025-09-10) predates other documents in this PR (dated 2025-10-24). Consider updating to reflect the current state if this document has been modified recently.

Suggested update
-**Last Updated**: 2025-09-10  
+**Last Updated**: 2025-10-24  
Roadmap/UPGRADE_CRITICAL_FINDINGS.md (1)

24-34: Add language specifier to fenced code blocks.

Several fenced code blocks are missing language specifiers, which affects syntax highlighting and rendering. The static analysis flagged lines 24, 38, 68, 93, and 330.

Example fix for this block
-```
+```text
 Base Version: v0.28.0

Apply similar fixes to other unlabeled code blocks (lines 38, 68, 93, 330) using appropriate language identifiers (text, bash, or the relevant language).

Roadmap/UPGRADE_HEALTH_CHECK_REPORT.md (1)

24-30: Add language specifiers to fenced code blocks.

Similar to other documents in this PR, several code blocks lack language specifiers (lines 24, 44, 86, 108, 136, 159, 168, 180). Use text for output blocks or appropriate language identifiers.

Example fix
-```
+```text
 NAME           STATUS   ROLES           AGE    VERSION
Roadmap/UPGRADE_STATUS_FINAL.md (1)

54-57: Add language specifiers to code blocks for consistency.

Multiple code blocks in this document lack language identifiers. Consider using text for output/error messages and bash for shell commands to improve rendering.

packages/system/capi-providers/scripts/create-proxmox-cluster.sh (3)

24-39: Quote variables to prevent word splitting.

Variables used in kubectl commands should be quoted to prevent word splitting issues if values contain spaces or special characters.

Suggested fix
 check_provider_logs() {
     debug_log "Checking provider logs..."
     for namespace in capi-system capi-kubeadm-bootstrap-system capi-kubeadm-control-plane-system capi-proxmox-system; do
         echo "=== Logs from $namespace ==="
-        kubectl logs -n $namespace -l control-plane=controller-manager --tail=100
+        kubectl logs -n "$namespace" -l control-plane=controller-manager --tail=100
     done
 }
 
 check_machine_logs() {
     debug_log "Checking machine logs..."
     kubectl get machines -A -o wide
-    for machine in $(kubectl get machines -A -o jsonpath='{.items[*].metadata.name}'); do
+    while IFS= read -r machine; do
+        [ -z "$machine" ] && continue
         echo "=== Logs for machine $machine ==="
-        kubectl logs -n default -l cluster.x-k8s.io/machine-name=$machine --tail=100
+        kubectl logs -n default -l "cluster.x-k8s.io/machine-name=$machine" --tail=100
-    done
+    done < <(kubectl get machines -A -o jsonpath='{.items[*].metadata.name}' | tr ' ' '\n')
 }

64-70: Relative path may cause issues.

The template path templates/proxmox-examples.yaml is relative, which requires the script to be executed from a specific directory. Consider using SCRIPT_DIR to make the path relative to the script location.

Suggested fix
+# Get script directory for relative paths
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+
 # Process the manifests with environment variables
 debug_log "Processing manifests..."
-envsubst < templates/proxmox-examples.yaml > "$TEMP_DIR/processed-manifests.yaml"
+envsubst < "$SCRIPT_DIR/templates/proxmox-examples.yaml" > "$TEMP_DIR/processed-manifests.yaml"

77-84: Consider making cluster name configurable.

The cluster name proxmox-cluster is hardcoded. Consider making it configurable via an environment variable for flexibility across different deployments.

Suggested fix
+# Optional: default cluster name if not set
+CLUSTER_NAME="${CLUSTER_NAME:-proxmox-cluster}"
+
 echo "Waiting for cluster to be ready..."
-kubectl wait --for=condition=ready cluster/proxmox-cluster --timeout=300s || {
+kubectl wait --for=condition=ready "cluster/${CLUSTER_NAME}" --timeout=300s || {
packages/system/capi-providers/scripts/debug-proxmox-cluster.sh (2)

1-1: Consider adding bash strict mode options.

For debugging scripts that interact with cluster resources, adding set -euo pipefail helps catch errors early and prevents issues with undefined variables or failed commands silently continuing.

Suggested improvement
 #!/bin/bash
+set -euo pipefail
 
 # Colors for output

72-78: Secret lookup may fail without explicit namespace.

The proxmox-credentials secret namespace is not specified, which will default to the current context namespace. Consider specifying the expected namespace explicitly.

Suggested improvement
 check_proxmox_connection() {
     debug_log "Checking Proxmox connection..."
-    kubectl get secret proxmox-credentials -o jsonpath='{.data.url}' | base64 -d
+    kubectl get secret proxmox-credentials -n capi-proxmox-system -o jsonpath='{.data.url}' | base64 -d 2>/dev/null || echo "Secret not found"
     echo -e "\nChecking Proxmox provider pods..."
     kubectl get pods -n capi-proxmox-system -o wide
 }
packages/system/proxmox-csi/README.md (1)

5-6: Convert bare URLs to proper Markdown links.

Static analysis flags bare URLs. Using proper Markdown link syntax improves rendering consistency across different Markdown parsers.

Suggested fix
-- GitHub: https://github.com/sergelogvinov/proxmox-csi-plugin
-- Telegram: https://t.me/ru_talos
+- GitHub: <https://github.com/sergelogvinov/proxmox-csi-plugin>
+- Telegram: <https://t.me/ru_talos>
packages/system/capi-providers/docs/proxmox-csi-setup.md (1)

91-92: Avoid using :latest tag in documentation examples.

Using :latest in documentation examples can lead to non-reproducible deployments and unexpected behavior when the image is updated. Consider specifying a concrete version tag.

Suggested fix
-        image: proxmox/csi-driver:latest
+        image: ghcr.io/sergelogvinov/proxmox-csi-node:v0.9.0
packages/system/capi-providers/README.md (1)

24-35: Consider documenting a dedicated namespace for credentials.

The example creates the secret in the default namespace, which is not recommended for production deployments. Consider specifying a dedicated namespace (e.g., capi-proxmox-system or cozy-cluster-api) for better security isolation.

📝 Suggested improvement
 apiVersion: v1
 kind: Secret
 metadata:
   name: proxmox-credentials
-  namespace: default
+  namespace: capi-proxmox-system
 type: Opaque
 stringData:
   username: your-proxmox-username
.github/workflows/lint.yml (1)

18-21: Update actions/checkout to v4.

actions/checkout@v3 is outdated and may cause compatibility issues with newer GitHub Actions runners. Update to v4 for better support and security patches.

Proposed fix
       - name: Checkout code
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
         with:
           fetch-depth: 0
Roadmap/INTEGRATION_COMPLETE.md (1)

20-21: Wrap bare URL in angle brackets for Markdown compliance.

The API endpoint URL should be enclosed in angle brackets to comply with Markdown standards (MD034).

Proposed fix
-   - API: https://10.0.0.40:6443
+   - API: <https://10.0.0.40:6443>
.github/workflows/ci.yml (2)

41-42: Update actions/checkout to v4.

actions/checkout@v3 is outdated. Update to v4 for better compatibility and security.

Proposed fix
-      - uses: actions/checkout@v3
+      - uses: actions/checkout@v4

34-40: Redundant REGISTRY override logic.

The conditional at line 36 checks GITHUB_ACTIONS, which is always "true" when running in GitHub Actions. This makes the else branch unreachable, and line 37 simply re-sets REGISTRY to the same value already defined at line 17. Consider removing this step or clarifying the intent if local execution support is needed.

Proposed fix - remove redundant step
-      - name: Set up Docker Registry
-        run: |
-          if [ "$GITHUB_ACTIONS" = "true" ]; then
-            echo "REGISTRY=ghcr.io/${{ github.repository_owner }}" >> $GITHUB_ENV
-          else
-            echo "REGISTRY=localhost:5000/cozystack_local" >> $GITHUB_ENV
-          fi
-
       - uses: actions/checkout@v4

If local execution support is intended, consider using a separate workflow or environment-specific inputs.

Roadmap/INITIAL_ASSESSMENT.md (1)

18-27: Add language specifiers to fenced code blocks.

The code blocks at lines 21-27 and 62-67 lack language identifiers. Adding text or bash improves readability and enables syntax highlighting in rendered Markdown.

Proposed fix for lines 21-27
 ### Node Status
-```
+```text
 NAME           STATUS   ROLES           AGE    VERSION
 mgr-cozy1      Ready    control-plane   208d   v1.32.3
Roadmap/PROXMOX_INTEGRATION_RUNBOOK.md (1)

98-106: Avoid embedding literal passwords in examples.

Line 99 (and other examples later) embeds a plaintext password; this encourages insecure copy‑paste. Consider using placeholders or environment variables and add a short note to source secrets from a manager.

💡 Suggested fix (apply similarly elsewhere)
-pveum user add k8s-api@pve --password 'secure-password'
+pveum user add k8s-api@pve --password "${PROXMOX_PASSWORD}"
Roadmap/FINAL_SESSION_REPORT.md (1)

171-179: Add language specifier to fenced code block.

The code block displaying integrity check results should have a language specifier for proper syntax highlighting.

📝 Suggested fix
-```
+```text
 Total Checks: 18
 Passed: 13 (72%)
 Failed: 2 (11%)
 Warnings: 3 (17%)
 Success Rate: 72%
 
 Status: ⚠️ DEGRADED (but functional)
</details>

</blockquote></details>
<details>
<summary>packages/system/capi-providers-proxmox/SUMMARY.md (1)</summary><blockquote>

`34-43`: **Add language specifier to fenced code blocks.**

The architecture diagram and file structure blocks should have a language specifier (e.g., `text`) for consistency with markdown linting rules.



<details>
<summary>📝 Suggested fix for architecture diagram (line 34)</summary>

```diff
-```
+```text
 CozyStack CAPI Architecture:
 ├── capi-operator
 ├── cozy-capi-providers-core
 ├── cozy-capi-providers-bootstrap  
 ├── cozy-capi-providers-cpprovider
 └── cozy-capi-providers-infraprovider
     ├── kubevirt (existing)
     └── proxmox (new) ← Added
</details>

<details>
<summary>📝 Suggested fix for file structure (line 92)</summary>

```diff
-```
+```text
 packages/system/capi-providers-proxmox/
 ├── Chart.yaml
 ...
</details>

</blockquote></details>
<details>
<summary>Roadmap/CURRENT_STATE_AND_FIXES.md (2)</summary><blockquote>

`90-117`: **Ensure placeholder token secrets are clearly marked.**

The example values file contains `<token-secret>` placeholders which is good. However, consider adding a clear warning comment to prevent accidental commits with real secrets.



<details>
<summary>📝 Suggested improvement</summary>

```diff
 # 3. Create values file
+# WARNING: Replace <token-secret> with actual token - never commit real secrets!
 cat > custom-values.yaml <<EOF
 proxmox-cloud-controller-manager:
   config:

347-355: Add language specifiers to fenced code blocks.

Several code blocks displaying status output lack language specifiers.

📝 Suggested fixes

Line 347:

-```
+```text
 Total Checks: 50

Line 468:

-```
+```text
 Integration Completion: 100%

Line 574:

-```text
 Current (85%) 
     ↓

Also applies to: 468-474, 574-592

Roadmap/VM_CREATION_TEST_RESULTS.md (2)

229-247: Add language specifiers to architecture diagram code blocks.

The architecture validation diagrams should have a text language specifier for consistency.

📝 Suggested fix
-```
+```text
 ✅ User → kubectl apply ProxmoxMachine
    ↓
 ✅ capmox controller detects resource

And similarly for line 244:

-```
+```text
 ❌ User → KubeVirt → Pod → QEMU → VM

254-272: Add language specifier to workflow diagram.

📝 Suggested fix
-```
+```text
 1. Create Cluster CRD
    ↓
 2. Create ProxmoxCluster (infrastructure)
Roadmap/UPGRADE_EXECUTION_LOG.md (1)

59-59: Consider generalizing local filesystem paths.

The path /home/moriarti/repo/cozystack/docs/changelogs/ is user-specific and may confuse others reading this document. Consider using a relative path or a placeholder like <repo-root>/docs/changelogs/.

Roadmap/CRITICAL_FIX_PROXMOX_BUNDLE.md (2)

114-134: Table formatting has structural issues.

The table contains rows with single cells used as section headers (lines 116, 122, 125, 127, 130), which breaks proper Markdown table structure. Consider using proper table rows with merged content or restructuring as separate subsection tables.

♻️ Suggested restructuring

Instead of inline section headers, split into separate tables:

-| Component | paas-full | paas-proxmox | Reason |
-|-----------|-----------|--------------|--------|
-| **VM Management** |
-| kubevirt-operator | ✅ | ❌ | Not needed with Proxmox |
+### VM Management
+
+| Component | paas-full | paas-proxmox | Reason |
+|-----------|-----------|--------------|--------|
+| kubevirt-operator | ✅ | ❌ | Not needed with Proxmox |

15-22: Add language specifiers to fenced code blocks.

The ASCII diagrams lack language specifiers. While these are diagrams rather than code, adding text or leaving them empty with triple backticks helps linters and renders consistently.

♻️ Example fix
-```
+```text
 User → K8s API → KubeVirt → Pod → QEMU/KVM → VM
-```
+```
packages/system/capi-providers-proxmox/scripts/test-proxmox-cluster.sh (2)

74-79: Relative path assumes specific working directory.

The path examples/proxmox-cluster.yaml is relative and assumes the script is executed from a specific directory. Consider using $SCRIPT_DIR to make the path relative to the script location.

♻️ Proposed fix
+# Get script directory
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+
 # Test cluster creation
 test_cluster_creation() {
     print_status "Testing cluster creation..."
     
     # Apply example cluster configuration
-    if kubectl apply -f examples/proxmox-cluster.yaml; then
+    if kubectl apply -f "${SCRIPT_DIR}/../examples/proxmox-cluster.yaml"; then
         print_status "Cluster configuration applied successfully."

128-129: Interactive read may block in CI/automated environments.

The read -p command will block indefinitely waiting for user input, which can cause issues in CI pipelines or automated testing. Consider adding a timeout or making this behavior conditional.

♻️ Proposed fix
-        read -p "Press Enter to cleanup test resources..."
+        if [[ -t 0 ]]; then
+            read -p "Press Enter to cleanup test resources..."
+        else
+            print_status "Non-interactive mode: waiting 30 seconds before cleanup..."
+            sleep 30
+        fi
         cleanup
Roadmap/FRESH_INSTALL_PLAN.md (1)

517-525: Consider documenting version verification for external downloads.

The Zig installation downloads from an external URL with a specific version. Consider adding a note about verifying checksums or using the official Zig package manager where available.

♻️ Example enhancement
 # Install Zig 0.15.1 (required for NexCage)
 cd /tmp
 wget https://ziglang.org/download/0.15.1/zig-linux-x86_64-0.15.1.tar.xz
+# Verify checksum (get from https://ziglang.org/download/)
+# echo "EXPECTED_SHA256  zig-linux-x86_64-0.15.1.tar.xz" | sha256sum -c -
 tar -xf zig-linux-x86_64-0.15.1.tar.xz
Roadmap/VM_CREATION_FINAL_REPORT.md (1)

19-25: Add language specifier to code block.

This code block showing VM list output would benefit from a language specifier for consistency.

♻️ Suggested fix
-```
+```text
 VMID 124: control-plane-template (stopped)
 VMID 201: ubuntu22-k8s-template (stopped)
Roadmap/COMPLETE_ROADMAP.md (1)

200-245: Add language specifier to ASCII diagram.

The architecture diagram code block would benefit from a text language specifier for consistent rendering.

Roadmap/SESSION_2025-10-24_SUMMARY.md (1)

112-115: Add language specifiers to fenced code blocks.

Several code blocks throughout this document lack language specifiers, which improves readability and enables syntax highlighting. Static analysis flagged blocks at lines 112, 143, 256, 265, 277, 288, and 417.

Example fix for this block:

-```
+```text
 /run/openvswitch/kube-ovn-daemon.sock: no such file or directory
packages/system/proxmox-csi-node/templates/deploy.yaml (1)

146-154: Using namespace as app label is unconventional.

The matchLabels and pod labels use {{ .Release.Namespace }} as the app value. Typically, this would be a descriptive app name (e.g., proxmox-csi-node) for better observability and to avoid conflicts if multiple releases exist.

♻️ Proposed fix
   selector:
     matchLabels:
-      app: {{ .Release.Namespace }}
+      app: proxmox-csi-node
   updateStrategy:
     type: RollingUpdate
   template:
     metadata:
       labels:
-        app: {{ .Release.Namespace }}
+        app: proxmox-csi-node

Comment on lines +23 to +24
- name: Run Super-Linter
uses: github/super-linter@v4

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

github/super-linter latest version 2025

💡 Result:

The latest super-linter/super-linter release in 2025 is v8.3.2, published on 2025-12-24. [1]

Use in GitHub Actions: uses: super-linter/[email protected] [1]


Update Super-Linter to v8.3.2 (current latest).

github/super-linter@v4 is significantly outdated. The latest version is v8.3.2, available as super-linter/[email protected] (note the namespace changed from github/ to super-linter/). This upgrade includes substantial linter updates, bug fixes, and performance improvements across four major versions. Verify compatibility with your project and update accordingly.

🤖 Prompt for AI Agents
In @.github/workflows/lint.yml around lines 23 - 24, The workflow step named
"Run Super-Linter" is using an old action reference (github/super-linter@v4);
update the uses value to the current namespace and tag by replacing that
reference with super-linter/[email protected], then run the workflow and
adjust any linter config if compatibility issues arise (verify the step name
"Run Super-Linter" and any inputs/options passed to it remain correct after the
upgrade).

Comment on lines +1 to +55

yaml-files:
- '*.yaml'
- '*.yml'
- '.yamllint'

rules:
braces:
level: warning
min-spaces-inside: 0
max-spaces-inside: 0
min-spaces-inside-empty: 1
max-spaces-inside-empty: 5
brackets:
level: warning
min-spaces-inside: 0
max-spaces-inside: 0
min-spaces-inside-empty: 1
max-spaces-inside-empty: 5
colons:
level: warning
max-spaces-before: 0
max-spaces-after: 1
commas:
level: warning
max-spaces-before: 0
min-spaces-after: 1
max-spaces-after: 1
comments: disable
comments-indentation: disable
document-end: disable
document-start: disable
empty-lines:
level: warning
max: 2
max-start: 0
max-end: 0
hyphens:
level: warning
max-spaces-after: 1
indentation:
level: warning
spaces: consistent
indent-sequences: true
check-multi-line-strings: false
key-duplicates: enable
line-length: disable
new-line-at-end-of-file: disable
new-lines:
type: unix
trailing-spaces: disable
line-length:
max: 130
allow-non-breakable-words: true
allow-non-breakable-inline-mappings: false

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat -n .github/workflows/linters/.yaml-lint.yml | sed -n '1,60p'

Repository: cozystack/cozystack

Length of output: 1569


Remove duplicate line-length rule and leading blank line

Delete the blank first line and remove the standalone line-length: disable entry to prevent yamllint key-duplicate errors.

Suggested diff
-
 yaml-files:
@@
-  line-length: disable
   new-line-at-end-of-file: disable
📝 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
yaml-files:
- '*.yaml'
- '*.yml'
- '.yamllint'
rules:
braces:
level: warning
min-spaces-inside: 0
max-spaces-inside: 0
min-spaces-inside-empty: 1
max-spaces-inside-empty: 5
brackets:
level: warning
min-spaces-inside: 0
max-spaces-inside: 0
min-spaces-inside-empty: 1
max-spaces-inside-empty: 5
colons:
level: warning
max-spaces-before: 0
max-spaces-after: 1
commas:
level: warning
max-spaces-before: 0
min-spaces-after: 1
max-spaces-after: 1
comments: disable
comments-indentation: disable
document-end: disable
document-start: disable
empty-lines:
level: warning
max: 2
max-start: 0
max-end: 0
hyphens:
level: warning
max-spaces-after: 1
indentation:
level: warning
spaces: consistent
indent-sequences: true
check-multi-line-strings: false
key-duplicates: enable
line-length: disable
new-line-at-end-of-file: disable
new-lines:
type: unix
trailing-spaces: disable
line-length:
max: 130
allow-non-breakable-words: true
allow-non-breakable-inline-mappings: false
yaml-files:
- '*.yaml'
- '*.yml'
- '.yamllint'
rules:
braces:
level: warning
min-spaces-inside: 0
max-spaces-inside: 0
min-spaces-inside-empty: 1
max-spaces-inside-empty: 5
brackets:
level: warning
min-spaces-inside: 0
max-spaces-inside: 0
min-spaces-inside-empty: 1
max-spaces-inside-empty: 5
colons:
level: warning
max-spaces-before: 0
max-spaces-after: 1
commas:
level: warning
max-spaces-before: 0
min-spaces-after: 1
max-spaces-after: 1
comments: disable
comments-indentation: disable
document-end: disable
document-start: disable
empty-lines:
level: warning
max: 2
max-start: 0
max-end: 0
hyphens:
level: warning
max-spaces-after: 1
indentation:
level: warning
spaces: consistent
indent-sequences: true
check-multi-line-strings: false
key-duplicates: enable
new-line-at-end-of-file: disable
new-lines:
type: unix
trailing-spaces: disable
line-length:
max: 130
allow-non-breakable-words: true
allow-non-breakable-inline-mappings: false
🧰 Tools
🪛 actionlint (1.7.10)

2-2: "jobs" section is missing in workflow

(syntax-check)


2-2: "on" section is missing in workflow

(syntax-check)


2-2: unexpected key "yaml-files" for "workflow" section. expected one of "concurrency", "defaults", "env", "jobs", "name", "on", "permissions", "run-name"

(syntax-check)


7-7: unexpected key "rules" for "workflow" section. expected one of "concurrency", "defaults", "env", "jobs", "name", "on", "permissions", "run-name"

(syntax-check)

🪛 YAMLlint (1.38.0)

[warning] 1-1: too many blank lines (1 > 0)

(empty-lines)


[error] 52-52: duplication of key "line-length" in mapping

(key-duplicates)

🤖 Prompt for AI Agents
In @.github/workflows/linters/.yaml-lint.yml around lines 1 - 55, Remove the
leading blank first line and delete the standalone "line-length: disable" entry
so there is only the detailed "line-length:" mapping block present; update the
YAML to keep the later line-length mapping (max: 130, allow-non-breakable-words,
allow-non-breakable-inline-mappings) and remove the duplicate key to avoid
yamllint key-duplicate errors.

Comment on lines +1 to +73
{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }}
{{- $clusterDomain := (index $cozyConfig.data "cluster-domain") | default "cozy.local" }}

releases:
- name: fluxcd-operator
releaseName: fluxcd-operator
chart: cozy-fluxcd-operator
namespace: cozy-fluxcd
privileged: true
dependsOn: []

- name: fluxcd
releaseName: fluxcd
chart: cozy-fluxcd
namespace: cozy-fluxcd
dependsOn: [fluxcd-operator,cilium,kubeovn]
values:
flux-instance:
instance:
cluster:
domain: {{ $clusterDomain }}

- name: cilium
releaseName: cilium
chart: cozy-cilium
namespace: cozy-cilium
privileged: true
dependsOn: []

- name: kubeovn
releaseName: kubeovn
chart: cozy-kubeovn
namespace: cozy-kubeovn
privileged: true
dependsOn: [cilium]
values:
cozystack:
nodesHash: {{ include "cozystack.master-node-ips" . | sha256sum }}
kube-ovn:
ipv4:
POD_CIDR: "{{ index $cozyConfig.data "ipv4-pod-cidr" }}"
POD_GATEWAY: "{{ index $cozyConfig.data "ipv4-pod-gateway" }}"
SVC_CIDR: "{{ index $cozyConfig.data "ipv4-svc-cidr" }}"
JOIN_CIDR: "{{ index $cozyConfig.data "ipv4-join-cidr" }}"

- name: cozy-proxy
releaseName: cozystack
chart: cozy-cozy-proxy
namespace: cozy-system
dependsOn: [cilium,kubeovn]

- name: cert-manager-crds
releaseName: cert-manager-crds
chart: cozy-cert-manager-crds
namespace: cozy-cert-manager
dependsOn: [cilium, kubeovn]

- name: cozystack-api
releaseName: cozystack-api
chart: cozy-cozystack-api
namespace: cozy-system
dependsOn: [cilium,kubeovn,cozystack-controller]

- name: cozystack-controller
releaseName: cozystack-controller
chart: cozy-cozystack-controller
namespace: cozy-system
dependsOn: [cilium,kubeovn]
{{- if eq (index $cozyConfig.data "telemetry-enabled") "false" }}
values:
cozystackController:
disableTelemetry: true
{{- end }}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Check file existence and basic structure
cat -n packages/core/platform/bundles/paas-proxmox.yaml | head -50

Repository: cozystack/cozystack

Length of output: 1726


🏁 Script executed:

# Search for other uses of lookup in the codebase to see how it's typically handled
rg "lookup.*ConfigMap" --type yaml -A 2 -B 1

Repository: cozystack/cozystack

Length of output: 3934


🏁 Script executed:

# Check if there are similar patterns with default handling for lookup
rg "lookup.*default" --type yaml -A 2

Repository: cozystack/cozystack

Length of output: 521


🌐 Web query:

Helm lookup function nil error fresh install ConfigMap

💡 Result:

On a fresh install, lookup often returns nil because the target ConfigMap doesn’t exist yet at render time (or because you’re rendering without talking to the API server). If your template immediately dereferences fields like .data.*, Helm errors with nil pointer evaluating interface {}. (apipark.com)

Fix 1: Guard against nil (recommended)

{{- $cm := lookup "v1" "ConfigMap" .Release.Namespace "my-config" -}}
{{- if $cm -}}
value: {{ index $cm.data "MY_KEY" | quote }}
{{- else -}}
value: {{ default "fallback" .Values.myKey | quote }}
{{- end -}}

Reason: if the ConfigMap isn’t found, lookup returns nil. (apipark.com)

Fix 2: Don’t use .items for a single object

If you used something like (lookup ...).items.*, that’s wrong for a single named ConfigMap; use .data instead. (stackoverflow.com)

Fix 3: Ensure you’re actually querying the cluster

lookup can return nil when rendering locally (e.g., helm template / client-side dry-run) because there’s no live API lookup happening. Use a mode that renders against the cluster (server-side dry-run) or run against an actual cluster context. (github.com)

Fix 4 (design): Don’t lookup something you create in the same release

If the ConfigMap is created by this chart, it may not exist yet when another template tries to lookup it. Typically you:

  • reference the same values directly (instead of looking up), or
  • split into two releases (create CM first, then depend on it), or
  • use hooks/ordering only if you truly need runtime discovery (careful: hooks have tradeoffs).

If you paste the exact template line that fails (and how you install: helm install, helm template, Argo CD, etc.), I can give a precise patch.

Citations:


Guard ConfigMap lookups to prevent nil pointer errors on fresh installs where the ConfigMap doesn't exist yet.

lookup returns nil when the ConfigMap is not present, causing template render failures when accessing .data or using index. The codebase already uses the default dict pattern for this (e.g., in filer-statefulset.yaml), which safely provides an empty dict as fallback.

Apply the same pattern throughout this file:

🛠️ Suggested fix
-{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }}
-{{- $clusterDomain := (index $cozyConfig.data "cluster-domain") | default "cozy.local" }}
+{{- $cozyConfig := (lookup "v1" "ConfigMap" "cozy-system" "cozystack" | default dict) }}
+{{- $cozyData := (get $cozyConfig "data" | default dict) }}
+{{- $clusterDomain := (get $cozyData "cluster-domain" | default "cozy.local") }}
@@
-        POD_CIDR: "{{ index $cozyConfig.data "ipv4-pod-cidr" }}"
-        POD_GATEWAY: "{{ index $cozyConfig.data "ipv4-pod-gateway" }}"
-        SVC_CIDR: "{{ index $cozyConfig.data "ipv4-svc-cidr" }}"
-        JOIN_CIDR: "{{ index $cozyConfig.data "ipv4-join-cidr" }}"
+        POD_CIDR: "{{ get $cozyData "ipv4-pod-cidr" | default "" }}"
+        POD_GATEWAY: "{{ get $cozyData "ipv4-pod-gateway" | default "" }}"
+        SVC_CIDR: "{{ get $cozyData "ipv4-svc-cidr" | default "" }}"
+        JOIN_CIDR: "{{ get $cozyData "ipv4-join-cidr" | default "" }}"
@@
-  {{- if eq (index $cozyConfig.data "telemetry-enabled") "false" }}
+  {{- if eq (get $cozyData "telemetry-enabled") "false" }}
📝 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
{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }}
{{- $clusterDomain := (index $cozyConfig.data "cluster-domain") | default "cozy.local" }}
releases:
- name: fluxcd-operator
releaseName: fluxcd-operator
chart: cozy-fluxcd-operator
namespace: cozy-fluxcd
privileged: true
dependsOn: []
- name: fluxcd
releaseName: fluxcd
chart: cozy-fluxcd
namespace: cozy-fluxcd
dependsOn: [fluxcd-operator,cilium,kubeovn]
values:
flux-instance:
instance:
cluster:
domain: {{ $clusterDomain }}
- name: cilium
releaseName: cilium
chart: cozy-cilium
namespace: cozy-cilium
privileged: true
dependsOn: []
- name: kubeovn
releaseName: kubeovn
chart: cozy-kubeovn
namespace: cozy-kubeovn
privileged: true
dependsOn: [cilium]
values:
cozystack:
nodesHash: {{ include "cozystack.master-node-ips" . | sha256sum }}
kube-ovn:
ipv4:
POD_CIDR: "{{ index $cozyConfig.data "ipv4-pod-cidr" }}"
POD_GATEWAY: "{{ index $cozyConfig.data "ipv4-pod-gateway" }}"
SVC_CIDR: "{{ index $cozyConfig.data "ipv4-svc-cidr" }}"
JOIN_CIDR: "{{ index $cozyConfig.data "ipv4-join-cidr" }}"
- name: cozy-proxy
releaseName: cozystack
chart: cozy-cozy-proxy
namespace: cozy-system
dependsOn: [cilium,kubeovn]
- name: cert-manager-crds
releaseName: cert-manager-crds
chart: cozy-cert-manager-crds
namespace: cozy-cert-manager
dependsOn: [cilium, kubeovn]
- name: cozystack-api
releaseName: cozystack-api
chart: cozy-cozystack-api
namespace: cozy-system
dependsOn: [cilium,kubeovn,cozystack-controller]
- name: cozystack-controller
releaseName: cozystack-controller
chart: cozy-cozystack-controller
namespace: cozy-system
dependsOn: [cilium,kubeovn]
{{- if eq (index $cozyConfig.data "telemetry-enabled") "false" }}
values:
cozystackController:
disableTelemetry: true
{{- end }}
{{- $cozyConfig := (lookup "v1" "ConfigMap" "cozy-system" "cozystack" | default dict) }}
{{- $cozyData := (get $cozyConfig "data" | default dict) }}
{{- $clusterDomain := (get $cozyData "cluster-domain" | default "cozy.local") }}
releases:
- name: fluxcd-operator
releaseName: fluxcd-operator
chart: cozy-fluxcd-operator
namespace: cozy-fluxcd
privileged: true
dependsOn: []
- name: fluxcd
releaseName: fluxcd
chart: cozy-fluxcd
namespace: cozy-fluxcd
dependsOn: [fluxcd-operator,cilium,kubeovn]
values:
flux-instance:
instance:
cluster:
domain: {{ $clusterDomain }}
- name: cilium
releaseName: cilium
chart: cozy-cilium
namespace: cozy-cilium
privileged: true
dependsOn: []
- name: kubeovn
releaseName: kubeovn
chart: cozy-kubeovn
namespace: cozy-kubeovn
privileged: true
dependsOn: [cilium]
values:
cozystack:
nodesHash: {{ include "cozystack.master-node-ips" . | sha256sum }}
kube-ovn:
ipv4:
POD_CIDR: "{{ get $cozyData "ipv4-pod-cidr" | default "" }}"
POD_GATEWAY: "{{ get $cozyData "ipv4-pod-gateway" | default "" }}"
SVC_CIDR: "{{ get $cozyData "ipv4-svc-cidr" | default "" }}"
JOIN_CIDR: "{{ get $cozyData "ipv4-join-cidr" | default "" }}"
- name: cozy-proxy
releaseName: cozystack
chart: cozy-cozy-proxy
namespace: cozy-system
dependsOn: [cilium,kubeovn]
- name: cert-manager-crds
releaseName: cert-manager-crds
chart: cozy-cert-manager-crds
namespace: cozy-cert-manager
dependsOn: [cilium, kubeovn]
- name: cozystack-api
releaseName: cozystack-api
chart: cozy-cozystack-api
namespace: cozy-system
dependsOn: [cilium,kubeovn,cozystack-controller]
- name: cozystack-controller
releaseName: cozystack-controller
chart: cozy-cozystack-controller
namespace: cozy-system
dependsOn: [cilium,kubeovn]
{{- if eq (get $cozyData "telemetry-enabled") "false" }}
values:
cozystackController:
disableTelemetry: true
{{- end }}
🧰 Tools
🪛 YAMLlint (1.38.0)

[error] 1-1: syntax error: expected the node content, but found '-'

(syntax)

🤖 Prompt for AI Agents
In `@packages/core/platform/bundles/paas-proxmox.yaml` around lines 1 - 73, The
template uses lookup to fetch the ConfigMap into $cozyConfig and then directly
accesses $cozyConfig.data (e.g., in the kube-ovn values and the telemetry
check), which will nil-panic if the ConfigMap is missing; change the initial
lookup so $cozyConfig defaults to an empty dict (use the existing default dict
pattern) and then reference $cozyConfig.data safely (or provide per-key defaults
when calling index, e.g., for "cluster-domain", "ipv4-pod-cidr",
"ipv4-pod-gateway", "ipv4-svc-cidr", "ipv4-join-cidr", and "telemetry-enabled")
so that functions and conditionals like the cluster domain substitution,
kube-ovn POD_CIDR/JOIN_CIDR/SVC_CIDR/POD_GATEWAY, and the telemetry check (the
eq against index $cozyConfig.data "telemetry-enabled") work on fresh installs
without the ConfigMap present.

Comment on lines +12 to +40
stringData:
username: root@pam
password: your-secure-password
url: https://proxmox.example.com:8006/api2/json

---
# 2. Create the cluster
apiVersion: cluster.x-k8s.io/v1beta1
kind: Cluster
metadata:
name: proxmox-cluster
spec:
infrastructureRef:
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
kind: ProxmoxCluster
name: proxmox-cluster

---
# 3. Define Proxmox cluster infrastructure
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
kind: ProxmoxCluster
metadata:
name: proxmox-cluster
spec:
server: proxmox.example.com
insecure: false
controlPlaneEndpoint:
host: load-balancer.example.com
port: 6443

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find Proxmox provider related files and CRD definitions
find . -type f -name "*.yaml" -o -name "*.yml" | xargs grep -l "ProxmoxCluster" | head -20

Repository: cozystack/cozystack

Length of output: 198


🏁 Script executed:

#!/bin/bash
# Look for ProxmoxCluster CRD definition and API types
fd -e yaml -e go "proxmox" packages/system/capi-providers-proxmox --type f | head -30

Repository: cozystack/cozystack

Length of output: 131


🏁 Script executed:

#!/bin/bash
# Search for how 'url' and 'server' fields are documented or used
rg "(spec.*server|url.*proxmox)" packages/system/capi-providers-proxmox --type yaml -A 3 -B 3

Repository: cozystack/cozystack

Length of output: 690


🏁 Script executed:

#!/bin/bash
# List the structure of capi-providers-proxmox package
find packages/system/capi-providers-proxmox -type f | head -30

Repository: cozystack/cozystack

Length of output: 582


🏁 Script executed:

#!/bin/bash
# Check if there's a Chart.yaml or vendor reference
ls -la packages/system/capi-providers-proxmox/ | head -20

Repository: cozystack/cozystack

Length of output: 669


🏁 Script executed:

#!/bin/bash
# Look for any schema or CRD definitions
rg "ProxmoxCluster" packages/system/ --type yaml --type go -B 5 -A 10 | head -100

Repository: cozystack/cozystack

Length of output: 3848


🏁 Script executed:

#!/bin/bash
# Read Chart.yaml to understand dependencies
cat packages/system/capi-providers-proxmox/Chart.yaml

Repository: cozystack/cozystack

Length of output: 211


🏁 Script executed:

#!/bin/bash
# Read README for configuration guidance
cat packages/system/capi-providers-proxmox/README.md

Repository: cozystack/cozystack

Length of output: 5370


🏁 Script executed:

#!/bin/bash
# Read INTEGRATION.md for integration and field documentation
head -200 packages/system/capi-providers-proxmox/INTEGRATION.md

Repository: cozystack/cozystack

Length of output: 5002


🏁 Script executed:

#!/bin/bash
# Check the templates to understand secret and credential usage
cat packages/system/capi-providers-proxmox/templates/providers.yaml

Repository: cozystack/cozystack

Length of output: 353


🏁 Script executed:

#!/bin/bash
# Check configmaps template
cat packages/system/capi-providers-proxmox/templates/configmaps.yaml

Repository: cozystack/cozystack

Length of output: 334


🏁 Script executed:

#!/bin/bash
# Check the full example to understand how secret relates to ProxmoxCluster
cat packages/system/capi-providers-proxmox/examples/proxmox-cluster.yaml

Repository: cozystack/cozystack

Length of output: 3029


🏁 Script executed:

#!/bin/bash
# Search for credentialRef or secretRef patterns in proxmox examples
rg "(credentialRef|secretRef|credentials)" packages/system/capi-providers-proxmox --type yaml -B 3 -A 3

Repository: cozystack/cozystack

Length of output: 1054


🏁 Script executed:

#!/bin/bash
# Search for similar patterns in other CAPI provider examples
find packages/system -name "*.yaml" -exec grep -l "credentialRef\|secretRef" {} \; | head -10

Repository: cozystack/cozystack

Length of output: 1772


🏁 Script executed:

#!/bin/bash
# Check if ProxmoxCluster CRD is defined anywhere or search for schema references
rg "kind: ProxmoxCluster" packages/system -B 5 -A 20 | head -100

Repository: cozystack/cozystack

Length of output: 6997


🏁 Script executed:

#!/bin/bash
# Look for the upstream provider documentation or any schema/API reference
rg "credentialsRef|credentials" packages/system/capi-providers-proxmox --type yaml -B 5 -A 5

Repository: cozystack/cozystack

Length of output: 1355


🏁 Script executed:

#!/antml:thinking
# Let me also check if there are any docs or test scripts that show how credentials are actually passed
cat packages/system/capi-providers-proxmox/scripts/test-proxmox-cluster.sh

Repository: cozystack/cozystack

Length of output: 3551


🏁 Script executed:

#!/bin/bash
# Search for upstream provider references in comments or documentation
rg "ionos-cloud" packages/system/capi-providers-proxmox --type yaml --type md -B 2 -A 2

Repository: cozystack/cozystack

Length of output: 2122


🏁 Script executed:

#!/bin/bash
# Look for any credentialsRef or secretRef patterns in the entire capi-providers setup
rg "credentialsRef|secretRef|credentials" packages/system/capi-providers --type yaml | head -20

Repository: cozystack/cozystack

Length of output: 261


🏁 Script executed:

#!/bin/bash
# Check if there's any documentation about how upstream provider expects credentials
cat packages/system/capi-providers-proxmox/SUMMARY.md

Repository: cozystack/cozystack

Length of output: 3353


🌐 Web query:

ionos-cloud cluster-api-provider-proxmox ProxmoxCluster schema credentials

💡 Result:

In ionos-cloud/cluster-api-provider-proxmox (CAPMOX), the ProxmoxCluster credentials wiring is:

ProxmoxCluster schema field

spec.credentialsRef is an optional reference to a Kubernetes Secret (type corev1.SecretReference):

  • If omitted, CAPMOX uses the controller/manager credentials.
  • If namespace is not provided in the reference, CAPMOX uses the ProxmoxCluster’s namespace.
    [1]
apiVersion: infrastructure.cluster.x-k8s.io/v1alpha1
kind: ProxmoxCluster
metadata:
  name: my-cluster
  namespace: default
spec:
  # ...
  credentialsRef:
    name: my-proxmox-credentials
    # namespace: default  # optional

Secret “schema” (expected keys)

The referenced Secret is expected to contain these fields (commonly provided via stringData):

  • url: Proxmox VE API base URL (e.g. https://pve.example:8006)
  • token: Proxmox API token ID (e.g. user@pam!tokenname)
  • secret: token secret value
    [2]
apiVersion: v1
kind: Secret
metadata:
  name: my-proxmox-credentials
  namespace: default
type: Opaque
stringData:
  url: "https://pve.example:8006"
  token: "root@pam!capi"
  secret: "REDACTED"

Sources: [1] shows the ProxmoxClusterSpec.credentialsRef field and behavior; [2] shows the expected Secret keys used with CAPMOX.


🏁 Script executed:

#!/bin/bash
# Check if there's any additional documentation or examples in the codebase
find packages/system/capi-providers-proxmox -name "*.md" -exec cat {} \; | grep -i "url\|server\|credential" -B 2 -A 2

Repository: cozystack/cozystack

Length of output: 1037


🏁 Script executed:

#!/bin/bash
# Look at the entire INTEGRATION.md for any credential field documentation
cat packages/system/capi-providers-proxmox/INTEGRATION.md | grep -i "credential\|url\|server" -B 3 -A 3

Repository: cozystack/cozystack

Length of output: 587


🏁 Script executed:

#!/antml/bash
# Check if there's a credentialsRef example anywhere in the codebase
rg "credentialsRef" packages/system/ --type yaml

Repository: cozystack/cozystack

Length of output: 958


🏁 Script executed:

#!/bin/bash
# Look for any documentation about Secret credential format
rg "token.*secret" packages/system/capi-providers-proxmox --type yaml --type md

Repository: cozystack/cozystack

Length of output: 45


Add missing credentialsRef and correct Secret field names.

The example is missing the required credentialsRef field in ProxmoxCluster.spec and uses incorrect Secret field names. The upstream ionos-cloud/cluster-api-provider-proxmox provider expects:

  • ProxmoxCluster.spec.credentialsRef: A reference to a Secret containing Proxmox credentials
  • Secret fields: url (full API URL), token (token ID), and secret (token value)

The current example provides username and password instead of token and secret, and the ProxmoxCluster never references the Secret, making authentication impossible.

Corrected configuration
 apiVersion: v1
 kind: Secret
 metadata:
   name: proxmox-credentials
   namespace: default
 type: Opaque
 stringData:
-  username: root@pam
-  password: your-secure-password
   url: https://proxmox.example.com:8006
+  token: root@pam!capi
+  secret: your-token-secret

 ---
 apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
 kind: ProxmoxCluster
 metadata:
   name: proxmox-cluster
 spec:
   server: proxmox.example.com
   insecure: false
+  credentialsRef:
+    name: proxmox-credentials
   controlPlaneEndpoint:
     host: load-balancer.example.com
     port: 6443
🤖 Prompt for AI Agents
In `@packages/system/capi-providers-proxmox/examples/proxmox-cluster.yaml` around
lines 12 - 40, Add a credentials reference and fix the Secret field names:
create/use a Secret whose stringData contains "url" (full API URL), "token"
(token ID) and "secret" (token value) instead of "username"/"password", then
update ProxmoxCluster.spec to include credentialsRef pointing to that Secret
(e.g. set ProxmoxCluster.spec.credentialsRef.name to the Secret name and
credentialsRef.kind/namespace as needed) so the provider (ProxmoxCluster) can
authenticate using the expected fields.

Comment on lines +1 to +4
export NAME=capi-providers-proxmox
export NAMESPACE=cozy-cluster-api

include ../../../scripts/package.mk

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check scripts/package.mk for .PHONY and target definitions
echo "=== Checking for .PHONY declaration ==="
rg -n "^\.(PHONY|phony)" scripts/package.mk || echo "No .PHONY found"

echo ""
echo "=== Checking for all/clean/test targets ==="
rg -n "^(all|clean|test)\s*:" scripts/package.mk || echo "No matches found"

echo ""
echo "=== Full scripts/package.mk content ==="
cat scripts/package.mk

Repository: cozystack/cozystack

Length of output: 407


🏁 Script executed:

#!/bin/bash
# Find package.mk in the repository
echo "=== Searching for package.mk ==="
fd -n "package.mk" .

echo ""
echo "=== Directory structure around packages/system ==="
tree -L 3 packages/system/ 2>/dev/null || find packages/system -maxdepth 3 -type f -name "*.mk" -o -type d | head -20

Repository: cozystack/cozystack

Length of output: 24080


🏁 Script executed:

#!/bin/bash
# Read the capi-providers-proxmox Makefile
echo "=== capi-providers-proxmox/Makefile ==="
cat packages/system/capi-providers-proxmox/Makefile

echo ""
echo "=== Sample other Makefiles in packages/system ==="
for f in packages/system/capi-providers-bootstrap/Makefile packages/system/capi-providers-core/Makefile packages/system/cert-manager/Makefile; do
  echo "--- $f ---"
  cat "$f"
  echo ""
done

Repository: cozystack/cozystack

Length of output: 874


🏁 Script executed:

#!/bin/bash
# Find package.mk in hack directory
echo "=== Checking for package.mk in hack/ ==="
ls -la hack/package.mk 2>/dev/null && cat hack/package.mk || echo "File not found"

echo ""
echo "=== List hack directory ==="
ls -la hack/

Repository: cozystack/cozystack

Length of output: 2934


Fix the include path to use hack/package.mk instead of scripts/package.mk.

The Makefile currently includes ../../../scripts/package.mk, which doesn't exist. The correct path is ../../../hack/package.mk (which contains .PHONY declarations and the all, clean, and test targets). All other packages in packages/system/ correctly use this path.

Diff
-include ../../../scripts/package.mk
+include ../../../hack/package.mk
🧰 Tools
🪛 checkmake (0.2.2)

[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)

🤖 Prompt for AI Agents
In `@packages/system/capi-providers-proxmox/Makefile` around lines 1 - 4, The
Makefile sets NAME and NAMESPACE but includes the wrong makefile path; update
the include line in this Makefile so it uses ../../../hack/package.mk instead of
../../../scripts/package.mk (i.e., change the include reference used alongside
the NAME and NAMESPACE declarations to point to hack/package.mk so the shared
.PHONY and targets are picked up).

Comment on lines +37 to +84
# 4. Create a control plane machine
apiVersion: cluster.x-k8s.io/v1beta1
kind: Machine
metadata:
name: proxmox-control-plane
labels:
cluster.x-k8s.io/control-plane: "true"
spec:
version: ${KUBERNETES_VERSION}
bootstrap:
configRef:
apiVersion: bootstrap.cluster.x-k8s.io/v1beta1
kind: KubeadmConfig
name: proxmox-control-plane
infrastructureRef:
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
kind: ProxmoxMachine
name: proxmox-control-plane
---
# 5. Define Proxmox machine infrastructure for control plane
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
kind: ProxmoxMachine
metadata:
name: proxmox-control-plane
spec:
nodeName: ${PROXMOX_NODE}
template: ${VM_TEMPLATE}
cores: 2
memory: 4096
diskSize: 20
---
# 6. Create a worker machine
apiVersion: cluster.x-k8s.io/v1beta1
kind: Machine
metadata:
name: proxmox-worker
spec:
version: ${KUBERNETES_VERSION}
bootstrap:
configRef:
apiVersion: bootstrap.cluster.x-k8s.io/v1beta1
kind: KubeadmConfig
name: proxmox-worker
infrastructureRef:
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
kind: ProxmoxMachine
name: proxmox-worker
---

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's look at the actual file to confirm the content at lines 37-84
head -90 packages/system/capi-providers/templates/proxmox-examples.yaml | tail -60

Repository: cozystack/cozystack

Length of output: 1544


🌐 Web query:

CAPI Cluster API v1beta1 Machine spec clusterName required field

💡 Result:

In Cluster API (CAPI) v1beta1, Machine.spec.clusterName is a required, non-empty field (it identifies which Cluster the Machine belongs to). CAPI requires spec.clusterName on “cluster-dependent” objects (including Machine) and then controllers automatically apply the cluster.x-k8s.io/cluster-name label based on it. (release-1-0.cluster-api.sigs.k8s.io)

Example (note clusterName under spec):

apiVersion: cluster.x-k8s.io/v1beta1
kind: Machine
metadata:
  name: my-machine
  namespace: default
spec:
  clusterName: my-cluster
  bootstrap:
    configRef: ...
  infrastructureRef: ...

You’ll see the same requirement reflected in CAPI docs/examples (e.g., MachineHealthCheck.spec.clusterName is explicitly called out as required, and MachineDeployment templates set template.spec.clusterName for the Machines they create). (cluster-api.sigs.k8s.io)

Citations:


Add required spec.clusterName to Machine resources.

CAPI v1beta1 Machine requires spec.clusterName to identify which Cluster the machine belongs to; without it the API server will reject the resource. Add it to both control-plane and worker machines.

✅ Suggested fix
 kind: Machine
 metadata:
   name: proxmox-control-plane
   labels:
     cluster.x-k8s.io/control-plane: "true"
 spec:
+  clusterName: proxmox-cluster
   version: ${KUBERNETES_VERSION}
   bootstrap:
     configRef:
@@
 kind: Machine
 metadata:
   name: proxmox-worker
 spec:
+  clusterName: proxmox-cluster
   version: ${KUBERNETES_VERSION}
   bootstrap:
     configRef:
🤖 Prompt for AI Agents
In `@packages/system/capi-providers/templates/proxmox-examples.yaml` around lines
37 - 84, The Machine manifests for kind: Machine (metadata.name:
proxmox-control-plane and proxmox-worker) are missing the required
spec.clusterName field; add spec.clusterName to both Machine resources (e.g.,
spec.clusterName: ${CLUSTER_NAME} or the actual Cluster name) so the API can
associate each Machine with its Cluster.

Comment on lines +1 to +9
apiVersion: storage.k8s.io/v1
kind: CSIDriver
metadata:
name: csi.kubevirt.io
spec:
attachRequired: true
podInfoOnMount: true
fsGroupPolicy: ReadWriteOnceWithFSType
---

Copy link
Copy Markdown
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: CSIDriver name mismatch with StorageClass provisioner.

The CSIDriver is registered as csi.kubevirt.io but the StorageClass at line 275 references provisioner csi.proxmox.io. This mismatch will cause volume provisioning to fail since Kubernetes won't find a driver matching the provisioner name.

Additionally, the preStop hook at line 211 references csi.kubevirt.io-reg.sock while the plugin paths at lines 216 and 246 use csi.proxmox.io. These should all be consistent.

🐛 Proposed fix - align all names to csi.proxmox.io
 apiVersion: storage.k8s.io/v1
 kind: CSIDriver
 metadata:
-  name: csi.kubevirt.io
+  name: csi.proxmox.io
 spec:
   attachRequired: true
   podInfoOnMount: true
   fsGroupPolicy: ReadWriteOnceWithFSType

And at line 211:

             preStop:
               exec:
-                command: ["/bin/sh", "-c", "rm -rf /registration/csi.kubevirt.io-reg.sock /csi/csi.sock"]
+                command: ["/bin/sh", "-c", "rm -rf /registration/csi.proxmox.io-reg.sock /csi/csi.sock"]
📝 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
apiVersion: storage.k8s.io/v1
kind: CSIDriver
metadata:
name: csi.kubevirt.io
spec:
attachRequired: true
podInfoOnMount: true
fsGroupPolicy: ReadWriteOnceWithFSType
---
apiVersion: storage.k8s.io/v1
kind: CSIDriver
metadata:
name: csi.proxmox.io
spec:
attachRequired: true
podInfoOnMount: true
fsGroupPolicy: ReadWriteOnceWithFSType
---
🤖 Prompt for AI Agents
In `@packages/system/proxmox-csi-node/templates/deploy.yaml` around lines 1 - 9,
The CSIDriver registration name and socket/path references are inconsistent:
change the CSIDriver metadata.name from "csi.kubevirt.io" to "csi.proxmox.io",
update the preStop hook socket reference from "csi.kubevirt.io-reg.sock" to
"csi.proxmox.io-reg.sock", and ensure all plugin/socket path occurrences (e.g.,
/var/lib/kubelet/plugins/csi.proxmox.io and any references in the StorageClass
provisioner) use "csi.proxmox.io" so the CSIDriver (metadata.name), StorageClass
provisioner, preStop hook, and plugin paths all match.

privileged: true
allowPrivilegeEscalation: true
imagePullPolicy: Always
image: ghcr.io/kvaps/test:proxmox-csi-driver

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's check the file structure and locate the deploy.yaml file
fd -t f "deploy.yaml" | grep -i proxmox

Repository: cozystack/cozystack

Length of output: 117


🏁 Script executed:

# Read the deploy.yaml file to see the context around line 166
wc -l packages/system/proxmox-csi-node/templates/deploy.yaml

Repository: cozystack/cozystack

Length of output: 121


🏁 Script executed:

# Read the content around line 166 to see the image reference and context
sed -n '155,175p' packages/system/proxmox-csi-node/templates/deploy.yaml

Repository: cozystack/cozystack

Length of output: 713


🏁 Script executed:

# Check if this is a vendored chart and look for Chart.yaml
ls -la packages/system/proxmox-csi-node/

Repository: cozystack/cozystack

Length of output: 300


🏁 Script executed:

# Read the Chart.yaml to understand if this is a vendored chart
cat packages/system/proxmox-csi-node/Chart.yaml

Repository: cozystack/cozystack

Length of output: 105


🏁 Script executed:

# Check the templates directory to see all files
ls -la packages/system/proxmox-csi-node/templates/

Repository: cozystack/cozystack

Length of output: 235


🏁 Script executed:

# Check the parent system directory to see the overall structure
ls -la packages/system/ | head -20

Repository: cozystack/cozystack

Length of output: 1343


🏁 Script executed:

# Look for a charts directory in packages/system to see if there are vendored upstream charts
find packages/system -maxdepth 2 -type d -name "charts" 2>/dev/null

Repository: cozystack/cozystack

Length of output: 1769


🏁 Script executed:

# Check if proxmox-csi-node is related to proxmox-csi
ls -la packages/system/proxmox-csi*/

Repository: cozystack/cozystack

Length of output: 902


🏁 Script executed:

# Check the proxmox-csi chart structure to understand the umbrella pattern
ls -la packages/system/proxmox-csi/charts/

Repository: cozystack/cozystack

Length of output: 319


🏁 Script executed:

# Check the proxmox-csi plugin chart which might be the upstream
ls -la packages/system/proxmox-csi/charts/proxmox-csi-plugin/

Repository: cozystack/cozystack

Length of output: 795


🏁 Script executed:

# Check if proxmox-csi-node references or depends on proxmox-csi
cat packages/system/proxmox-csi-node/Chart.yaml

Repository: cozystack/cozystack

Length of output: 105


🏁 Script executed:

# Look for references to the kvaps/test image or kvaps in the codebase
rg "kvaps/test" packages/

Repository: cozystack/cozystack

Length of output: 172


🏁 Script executed:

# Search for other kvaps image references or proxmox-csi-driver images
rg "kvaps|proxmox-csi-driver" packages/system/proxmox-csi/ -A 1 -B 1

Repository: cozystack/cozystack

Length of output: 45


🏁 Script executed:

# Check the values.yaml of the proxmox-csi plugin chart
cat packages/system/proxmox-csi/charts/proxmox-csi-plugin/values.yaml | grep -i image

Repository: cozystack/cozystack

Length of output: 396


🏁 Script executed:

# Read the full values.yaml to understand the image configuration
cat packages/system/proxmox-csi/charts/proxmox-csi-plugin/values.yaml

Repository: cozystack/cozystack

Length of output: 9210


Test image must be replaced with production-ready image before merging.

The image ghcr.io/kvaps/test:proxmox-csi-driver uses a test registry path and is not suitable for production deployment. The upstream proxmox-csi chart uses ghcr.io/sergelogvinov/proxmox-csi-node as the proper image reference. Update the image to a stable, production-ready version.

🤖 Prompt for AI Agents
In `@packages/system/proxmox-csi-node/templates/deploy.yaml` at line 166, Replace
the test image reference `ghcr.io/kvaps/test:proxmox-csi-driver` in the
deployment template with the production-ready image used upstream (e.g.,
`ghcr.io/sergelogvinov/proxmox-csi-node` and an appropriate stable tag); locate
the image field in the deploy.yaml template (the line containing image:
ghcr.io/kvaps/test:proxmox-csi-driver) and update it to the official registry
path and a specific release tag prior to merging.

Comment on lines +1 to +23
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*.orig
*~
# Various IDEs
.project
.idea/
*.tmproj
.vscode/

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# Explore the proxmox-csi package structure
find packages/system/proxmox-csi -type f -name "Chart.yaml" | head -20

Repository: cozystack/cozystack

Length of output: 245


🏁 Script executed:

# Check the chart metadata for upstream source hints
cat packages/system/proxmox-csi/charts/proxmox-cloud-controller-manager/Chart.yaml 2>/dev/null || echo "File not found"

Repository: cozystack/cozystack

Length of output: 1191


🏁 Script executed:

# Look for vendoring-related files or comments in the proxmox-csi package
rg -n "vendor|upstream|source|home|repository" packages/system/proxmox-csi/ -g '*.yaml' -g '*.md' | head -30

Repository: cozystack/cozystack

Length of output: 5489


🏁 Script executed:

# Check if there's a Helmfile or other vendoring mechanism
find packages/system/proxmox-csi -type f \( -name "Helmfile*" -o -name "requirements.yaml" -o -name "Chart.lock" \)

Repository: cozystack/cozystack

Length of output: 45


Remove direct modifications to vendored charts; this change should go through the vendoring process.

The proxmox-cloud-controller-manager chart is vendored from upstream (https://github.com/sergelogvinov/proxmox-cloud-controller-manager). Per project guidelines, modifications to vendored code should be applied through the vendoring source/update process, not by directly editing files in the charts/ directory. If .helmignore is needed, it should be added when vendoring or managed separately.

🤖 Prompt for AI Agents
In
`@packages/system/proxmox-csi/charts/proxmox-cloud-controller-manager/.helmignore`
around lines 1 - 23, You modified the vendored chart
"proxmox-cloud-controller-manager" by adding a .helmignore directly in the
charts folder; revert this direct edit and instead apply the change via the
vendoring/update process for that upstream repository
(sergelogvinov/proxmox-cloud-controller-manager), e.g., add the .helmignore in
the upstream chart or include it during the vendoring step and re-run the
vendoring tooling so the chart in the vendor directory is updated from the
canonical source rather than edited in-place.

Comment on lines +3 to +6
**Date**: 2025-10-13 23:00
**Cluster**: mgr.cp.if.ua CozyStack
**Proxmox Server**: 10.0.0.1 (node: mgr)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Redact real infrastructure identifiers if this repo is public.

The report includes internal hostnames, usernames, and IPs. If this repository is public, replace these with placeholders or move the detailed report to a private location to avoid leaking infrastructure details.

🔧 Example redaction
-**Cluster**: mgr.cp.if.ua CozyStack  
-**Proxmox Server**: 10.0.0.1 (node: mgr)
+**Cluster**: <CLUSTER_NAME>  
+**Proxmox Server**: <PROXMOX_HOST> (node: <PROXMOX_NODE>)

Also applies to: 192-199, 295-312

🤖 Prompt for AI Agents
In `@Roadmap/TESTING_RESULTS.md` around lines 3 - 6, Replace all real
infrastructure identifiers in TESTING_RESULTS.md (e.g., the “Cluster” and
“Proxmox Server” entries that show names like "mgr.cp.if.ua", node "mgr", and IP
"10.0.0.1") with neutral placeholders (e.g., <REDACTED_CLUSTER>,
<REDACTED_NODE>, <REDACTED_IP>) or move the sensitive sections into a private
document; also scan and redact the other occurrences called out around the
ranges noted (near lines 192-199 and 295-312) so no hostnames, usernames, or IP
addresses remain in the public repo.

@github-actions

github-actions Bot commented May 2, 2026

Copy link
Copy Markdown

This PR has had no activity for 60 days and was marked lifecycle/stale.
It will be closed in 14 days unless commented or labelled lifecycle/frozen.

@github-actions github-actions Bot added the lifecycle/stale Denotes an issue or PR has remained open with no activity and has become stale label May 2, 2026
@lexfrei

Copy link
Copy Markdown
Contributor

Closing as stale — XXL draft conflicting with main, no activity since the lifecycle/stale warning. Re-file as a focused PR if the custom Proxmox bundle is still needed. Reopen if needed.

@github-actions github-actions Bot added the area/platform Issues or PRs related to platform infrastructure (bundle, flux, talos, installer) label Jun 25, 2026
@themoriarti

Copy link
Copy Markdown
Collaborator Author

Aleksei Sviridkin (@lexfrei)
I still have active work and existing implementation notes for the Proxmox bundle. I will sync with the latest main, split the scope into smaller focused PRs, and re-submit in a reviewable form.

I’ll update once the first reduced PR is ready.

@lexfrei

Copy link
Copy Markdown
Contributor

Checking in on this one. It is still a draft, it conflicts with main, and it carries 46 files of proxmox-csi plus the CAPI provider wiring. Nothing in that direction exists in the tree today, so there is no partial landing to rebase onto, and the platform has changed considerably in the six months since it was opened.

Is this still something you want to push? If so, it needs splitting before anyone can review it: the CAPI provider plumbing, the CSI package and the platform bundle wiring are separable and each reviewable on its own, whereas a single 32k-line draft is not. If you have moved on, say so and I will close it.

@lexfrei

Copy link
Copy Markdown
Contributor

Closing this one, and moving the topic to #3481 rather than dropping it.

The reason is not the code. It is that a 157-file draft, six months stale and conflicting with main, is not a format anyone can respond to, and the question it raises is bigger than the diff anyway: whether Proxmox becomes a supported way to run Cozystack, with someone maintaining and answering for it. That deserves a thread people can actually read and argue in.

Your own comment on #69 is the reason I did not try to review this as-is. You wrote that the lack of automated VM provisioning is a hard blocker rather than a remaining ten percent, and that is exactly right: the storage and networking parts here sit on a layer that was never specified. Reviewing them line by line would not have moved that.

#3481 records where the work stands and what a decision would need, with no position taken. If the direction gets picked up, the provisioning layer goes first and the rest is reviewable in pieces, at which point much of what you built here becomes directly useful.

Aleksei Sviridkin (lexfrei) added a commit that referenced this pull request Sep 25, 2026
…ster IPAM as optional packages (#4087)

## What this PR does

**Series behind #3481** — three separable pull requests:

1. **#4087 — Cluster API providers** (capmox + in-cluster IPAM)
2. #4088 — the `substrate` switch in `kubernetes` and `kubernetes-nodes`
3. #4089 — the Proxmox CSI driver and cloud-controller-manager

#4087 and #4088 share no files and can be reviewed in parallel. #4089
builds on #4088.

---

This is the provisioning layer #3481 asks to specify first: the part
that
creates the VMs. Neither of the other two is needed to review it.

### What it adds

Two Cluster API providers, packaged the way the existing KubeVirt
provider is —
vendored components, `gzip -9 -n` for a reproducible artifact, a `make
components` target that regenerates it from the upstream release and
checks
the downloads against the SHA-256 sums the Makefile pins:

| Package | Version | Contract |
|---|---|---|
| `capi-providers-infraprovider-proxmox` | capmox v0.7.7 | v1beta1 |
| `capi-providers-ipam-in-cluster` | CAIP v1.0.3 | v1beta1 |

capmox v0.7.7 rather than the current v0.9.x on purpose: from v0.8 it
declares
contract `v1beta2`, which the CAPI core shipped here (v1.10.1) does not
serve.

Both join the `iaas` bundle as **opt-in** packages, where the KubeVirt
infrastructure provider is unconditional. The asymmetry is deliberate:
capmox
drives a hypervisor outside the cluster and needs a Secret holding a
Proxmox API
token, which capi-operator reads before it installs anything — with no
Secret the
provider is never deployed at all. Enabling it by default would ask
every
Cozystack install that has no Proxmox to supply hypervisor credentials.

```yaml
bundles:
  enabledPackages:
    - cozystack.capi-provider-infra-proxmox     # brings IPAM with it
    - cozystack.capi-provider-ipam-in-cluster   # also enableable on its own
```

Enabling capmox emits the IPAM provider automatically — capmox allocates
worker
addresses from an `InClusterIPPool` and has no DHCP mode, so on its own
it never
gets a `ProxmoxCluster` to `Ready`. IPAM stays independently enableable,
since
assigning addresses is a generic Cluster API concern.

Naming capmox in `enabledPackages` while disabling IPAM stops the
render. The
cluster would catch that combination on its own — the capmox
`PackageSource`
depends on the IPAM `Package`, so with that `Package` absent capmox goes
`Ready=False` with `DependenciesNotReady` and no `HelmRelease` is
created — but
it would not say why. Failing the render names the two conflicting list
entries
at the moment someone writes them, instead of leaving a condition to
decode.

### Why the earlier attempt did not produce a VM

#1927's blocker — "ProxmoxMachine does not produce a VM" — was not a
capmox
incompatibility. It was four independent causes, each of which only
became
visible once the previous one was cleared:

1. **`PROXMOX_URL` included `/api2/json`.** capmox appends that itself,
so every
   call went to `/api2/json/api2/json/…` and returned 501.
2. **No IPAM provider.** `no matches for kind "InClusterIPPool"`; the
`ProxmoxCluster` never reached `Ready` and every `ProxmoxMachine` sat in
   `WaitingForClusterInfrastructure`.
3. **`templateSelector.matchTags` is set equality, not containment**
(`slices.Equal` after sort). A template carrying four tags is not
selected by
   naming one of them: `found 0 VM templates with tags`.
4. **capmox waits for the qemu-guest-agent, which Talos does not ship.**
   `error waiting for agent: timed out` — cleared with
   `checks.skipQemuGuestAgent` and `skipCloudInitStatus`.

None of these are in the provider. They are packaging and configuration,
which
is why the earlier work could look complete and still never boot a
machine.

### Evidence

Run on Proxmox VE 9.2.11 with Talos v1.13.6 and Cozystack's CAPI stack
(core v1.10.1, CABPT v0.6.12, Kamaji control-plane provider v0.19.0):

```
$ kubectl get proxmoxmachine,machine -n tenant-proxmox
proxmoxmachine/kubernetes-px-md0-…   Ready=True   VMProvisioned=True
machine/kubernetes-px-md0-…          Running      proxmox://0ef88cc1-6aea-4563-af64-344d8060d5c0

$ qm list
106 kubernetes-px-md0-jmzds-h9npx  running
```

The machine boots Talos from the nocloud ISO, reads the machineconfig
capmox
writes, and joins. That is the layer #69 called a hard blocker.

### What this PR does not claim

- One Proxmox node, one tenant cluster, manual runs — there is no e2e
coverage
  for Proxmox in CI, and this PR does not add any.
- It does not make Proxmox a supported platform. It makes the
provisioning layer
reviewable, which #3481 names as the precondition for that conversation.
- It does not touch `capi-providers-core`. The same drift check, pointed
at that
package, shows that the `startupProbe` from #2946 never reached the
shipped
blob; that fix changes what every new install runs and is #4483, with
its
  own release note.
- Nothing here exposes `ProxmoxCluster.spec.credentialsRef` to a tenant,
and
nothing should: `capmox-manager-role` grants get/list/watch/patch on
Secrets
  cluster-wide and that field takes a namespace. Whatever renders a
`ProxmoxCluster` for a tenant in the rest of the series has to keep the
field
  out of tenant hands.

### Testing

`make unit-tests` — exit 0. New suites:
`packages/core/platform/tests/sources_capi_provider_proxmox_test.yaml`
and
`bundles_proxmox_wiring_test.yaml` (both bundle paths, the
enable/disable
precedence, and the refusal above).

Every negated `containsDocument` in the wiring suite carries `any:
true`;
without it the negation passes whether or not the document is in the
render.
Three mutations, each reverted afterwards — emitting the capmox
`Package`
unconditionally, emitting the IPAM `Package` unconditionally, and
dropping the
`disabledPackages` check from `$proxmoxEnabled` — each turn red the
tests named
after the property they break, and the unmutated chart stays green (44
suites,
198 tests).

`hack/capi-provider-components_test.bats` covers both new provider
packages:
the blob and the YAML are the same bytes; the Makefile version, the
ConfigMap
name and `spec.version` are one value — `applied-spec-hash` covers the
provider
spec and the config Secret but not the ConfigMap, so a bump that
regenerates the
files while `spec.version` stays behind installs the old provider
silently; and
the vendored files match the SHA-256 sums the Makefile pins, so the pin
holds
even when nobody runs `make components`.

The render was compared against `main` for five configurations
(defaults,
`isp-full`, `isp-full-generic` with paas, an unrelated
`enabledPackages`, and
`disabledPackages` naming IPAM). No line is removed in any of them and
the
`Package` count is unchanged; the only additions are the two
`PackageSource`
objects, which the chart renders for every package, optional or not.

### Screenshots

Not applicable — no UI change.

### Downstream repositories

I walked the trigger map in `docs/agents/contributing.md` against this
diff, file by file. What it matches is below. **No box is ticked**,
because every follow-up it points at depends on a decision that is not
mine to make: #3481 asks whether Proxmox becomes a supported platform at
all, and writing its documentation or its Terraform schema before that
is answered would be work built on an assumption. I have not filed
speculative PRs or issues in those repositories for the same reason. If
the direction is accepted, I open them; a human should decide which.

**cozystack/website — matches, no follow-up yet.**

- `packages/core/platform/values.yaml` changed.
`content/en/docs/next/operations/configuration/platform-package.md` is a
hand-written table of the `spec.components.platform.values.*` keys; this
PR does not add a key, but it documents two new values that
`bundles.enabledPackages` now accepts, and the table is where a reader
would look for them.
- Two platform components are added
(`capi-providers-infraprovider-proxmox`,
`capi-providers-ipam-in-cluster`) → `guides/platform-stack/_index.md`,
`operations/configuration/licenses.md`.
- The `iaas` bundle gains two optional packages →
`operations/configuration/variants.md`.

**Everything else: no match.** Nothing under `packages/apps/` or
`packages/extra/` (terraform-provider, website app lists), no
`packages/core/installer/values.yaml` or `networking.*`/`publishing.*`
key the Ansible role sets, no `hack/` file or package-layout change
(ccp, external-apps-example), no `ApplicationDefinition` semantics, no
telemetry metric, no node prerequisites (talm, ansible), no
commit-convention change (community).

- [ ] No downstream repository is affected by this change
- [ ] [cozystack/website](https://github.com/cozystack/website) -
follow-up:
- [ ]
[cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack)
- follow-up:
- [ ]
[cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack)
- follow-up:
- [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up:
- [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up:
- [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) -
follow-up:
- [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) -
follow-up:
- [ ]
[cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server)
- follow-up:
- [ ]
[cozystack/external-apps-example](https://github.com/cozystack/external-apps-example)
- follow-up:
- [ ] [cozystack/examples](https://github.com/cozystack/examples) -
follow-up:
- [ ] [cozystack/community](https://github.com/cozystack/community) -
follow-up:

### Release note

```release-note
feat(cluster-api): add optional Cluster API packages for Proxmox — the capmox infrastructure provider and the in-cluster IPAM provider it requires. Neither is deployed unless named in `bundles.enabledPackages`, since capmox drives a hypervisor outside the cluster and does nothing without Proxmox API credentials. Enabling the Proxmox provider brings the IPAM provider with it.
```


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Added optional Proxmox infrastructure provider support for IaaS
clusters.
- Added in-cluster IP address management, usable independently or
alongside Proxmox.
- Proxmox deployments require a pre-created credentials Secret and
automatically include in-cluster IPAM.
  - Added validation for incompatible Proxmox and IPAM settings.

- **Tests**
- Added coverage for provider dependencies, package enablement,
disabling behavior, invalid configurations, and packaged provider
components.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/platform Issues or PRs related to platform infrastructure (bundle, flux, talos, installer) kind/feature Categorizes issue or PR as related to a new feature lifecycle/stale Denotes an issue or PR has remained open with no activity and has become stale size/XXL This PR changes 1000+ lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants