Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .claude/settings.local.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"permissions": {
"allow": [
"Bash(docker stop:*)",
"Bash(docker rm:*)"
]
Comment on lines +3 to +6
Copy link

Copilot AI Jan 25, 2026

Choose a reason for hiding this comment

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

The .claude/settings.local.json file appears to contain local development configuration and should be excluded from version control by adding it to .gitignore. Local settings files are typically environment-specific and should not be shared across different development environments.

Suggested change
"allow": [
"Bash(docker stop:*)",
"Bash(docker rm:*)"
]
"allow": []

Copilot uses AI. Check for mistakes.
}
}
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -487,3 +487,5 @@ $RECYCLE.BIN/

# Intellij
*.iml
*.db
/cli/src/Vdk/images
19 changes: 18 additions & 1 deletion cli/src/Vdk/Commands/UpdateClustersCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,21 @@ public class UpdateClustersCommand : Command
private readonly IKindClient _kind;
private readonly IFileSystem _fileSystem;
private readonly Func<string, IKubernetesClient> _clientFunc;
private readonly IReverseProxyClient _reverseProxy;

public UpdateClustersCommand(
IConsole console,
IKindClient kind,
IFileSystem fileSystem,
Func<string, IKubernetesClient> clientFunc)
Func<string, IKubernetesClient> clientFunc,
IReverseProxyClient reverseProxy)
: base("clusters", "Update cluster configurations (certificates, etc.)")
{
_console = console;
_kind = kind;
_fileSystem = fileSystem;
_clientFunc = clientFunc;
_reverseProxy = reverseProxy;

var verboseOption = new Option<bool>("--verbose") { Description = "Enable verbose output for debugging" };
verboseOption.Aliases.Add("-v");
Expand Down Expand Up @@ -72,6 +75,20 @@ public async Task InvokeAsync(bool verbose = false)
}

_console.WriteLine("Cluster certificate update complete.");

// Regenerate nginx configuration for all clusters (adds WebSocket support, etc.)
_console.WriteLine();
if (_reverseProxy.Exists())
{
_reverseProxy.RegenerateConfigs();
}
else
{
if (verbose)
{
_console.WriteLine("[DEBUG] Reverse proxy not running, skipping nginx config regeneration.");
}
}
}

private async Task UpdateClusterCertificates(string clusterName, byte[] localCert, byte[] localKey, bool verbose)
Expand Down
27 changes: 27 additions & 0 deletions cli/src/Vdk/ConfigMounts/zot-config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"distSpecVersion": "1.1.0",
"storage": {
"rootDirectory": "/var/lib/registry",
"gc": true,
"gcDelay": "1h",
"gcInterval": "24h"
},
"http": {
"address": "0.0.0.0",
"port": "5000"
},
"log": {
"level": "info"
},
"extensions": {
"ui": {
"enable": true
},
"search": {
"enable": true,
"cve": {
"updateInterval": "24h"
}
}
}
}
6 changes: 3 additions & 3 deletions cli/src/Vdk/Constants/Containers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ namespace Vdk.Constants;
public static class Containers
{
public const string RegistryName = "vega-registry";
public const string RegistryImage = "registry:2";
public const string RegistryImage = "ghcr.io/project-zot/zot-linux-amd64:v2.1.0";
public const int RegistryContainerPort = 5000;
public const int RegistryHostPort = 50000;
public const int RegistryHostPort = 5000;
Copy link

Copilot AI Jan 25, 2026

Choose a reason for hiding this comment

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

Breaking change: The registry host port has been changed from 50000 to 5000. This is a breaking change for existing installations that may have the registry running on port 50000. Users will need to recreate their registry container after this update. Consider documenting this breaking change in release notes or migration guide, or implementing a migration strategy to handle existing registries.

Copilot uses AI. Check for mistakes.
public const string ProxyName = "vega-proxy";
public const string ProxyImage = "nginx:latest";
public const string ProxyImage = "nginx:1.27";
public const string CloudProviderKindName = "cloud-provider-kind";
public const string CloudProviderKindImage = "registry.k8s.io/cloud-provider-kind/cloud-controller-manager:v0.6.0";
}
21 changes: 19 additions & 2 deletions cli/src/Vdk/Services/DockerHubClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,30 @@ public class DockerHubClient(IDockerEngine docker, IConsole console) : IHubClien
public void CreateRegistry()
{
if (ExistRegistry()) return;
console.WriteLine("Creating Vega VDK Registry");
console.WriteLine("Creating Vega VDK Registry (Zot)");
console.WriteLine(" - This may take a few minutes...");

// Mount the config file and images directory for persistence
var configFile = new FileInfo(Path.Combine("ConfigMounts", "zot-config.json"));
var imagesDir = new DirectoryInfo("images");

Copy link

Copilot AI Jan 25, 2026

Choose a reason for hiding this comment

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

Missing validation for config file existence. If the zot-config.json file doesn't exist at runtime, the Docker container creation will fail. Add a check to verify the config file exists before attempting to mount it, similar to how the images directory is validated.

Suggested change
// Ensure config file exists
if (!configFile.Exists)
{
console.WriteWarning($"Config file '{configFile.FullName}' not found. Skipping Vega VDK Registry creation.");
return;
}

Copilot uses AI. Check for mistakes.
// Ensure images directory exists
if (!imagesDir.Exists)
{
imagesDir.Create();
}

var volumes = new[]
{
new FileMapping { Source = configFile.FullName, Destination = "/etc/zot/config.json" },
new FileMapping { Source = imagesDir.FullName, Destination = "/var/lib/registry" }
};

docker.Run(Containers.RegistryImage,
Containers.RegistryName,
[PortMapping.DefaultRegistryPortMapping],
null,
null,
volumes,
null);
}

Expand Down
6 changes: 6 additions & 0 deletions cli/src/Vdk/Services/IReverseProxyClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,10 @@ public interface IReverseProxyClient
void List();

bool Exists();

/// <summary>
/// Regenerates the nginx configuration for all VDK clusters.
/// Useful for applying config changes (like WebSocket support) to existing clusters.
/// </summary>
void RegenerateConfigs();
}
42 changes: 42 additions & 0 deletions cli/src/Vdk/Services/ReverseProxyClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
if (tuple is { isVdk: true, master: not null } && tuple.master.HttpsHostPort.HasValue)
{
_console.WriteLine($" - Adding cluster {tuple.name} to reverse proxy configuration");
UpsertCluster(tuple.name, tuple.master.HttpsHostPort.Value, tuple.master.HttpHostPort.Value, false);

Check warning on line 63 in cli/src/Vdk/Services/ReverseProxyClient.cs

View workflow job for this annotation

GitHub Actions / build

Nullable value type may be null.
}
});
}
Expand Down Expand Up @@ -103,7 +103,7 @@
return true;
}

return false;

Check warning on line 106 in cli/src/Vdk/Services/ReverseProxyClient.cs

View workflow job for this annotation

GitHub Actions / build

Unreachable code detected
}

private void InitConfFile(FileInfo conf)
Expand Down Expand Up @@ -175,6 +175,11 @@
writer.WriteLine(" proxy_set_header X-Real-IP $remote_addr;");
writer.WriteLine(" proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;");
writer.WriteLine(" proxy_set_header X-Forwarded-Proto $scheme;");
writer.WriteLine();
writer.WriteLine(" # Support WebSocket protocol upgrades");
writer.WriteLine(" proxy_http_version 1.1;");
writer.WriteLine(" proxy_set_header Upgrade $http_upgrade;");
writer.WriteLine(" proxy_set_header Connection \"upgrade\";");
writer.WriteLine(" }");
writer.WriteLine("}");
writer.WriteLine($"##### END {clusterName}");
Expand Down Expand Up @@ -415,6 +420,43 @@
throw new NotImplementedException();
}

public void RegenerateConfigs()
{
var conf = new FileInfo(NginxConf);
if (!conf.Exists)
{
_console.WriteWarning("Nginx configuration file does not exist. Run 'vega create proxy' first.");
return;
}

_console.WriteLine("Regenerating nginx configuration for all VDK clusters...");

// Reinitialize the conf file with the hub server block
conf.Delete();
InitConfFile(conf);

// Iterate through all VDK clusters and add their server blocks
var clusters = _kind.ListClusters();
var vdkClusters = clusters.Where(c => c.isVdk && c.master != null && c.master.HttpsHostPort.HasValue).ToList();

if (vdkClusters.Count == 0)
{
_console.WriteLine("No VDK clusters found to configure.");
ReloadConfigs();
return;
}

foreach (var cluster in vdkClusters)
{
_console.WriteLine($" Adding cluster '{cluster.name}' to nginx configuration");
PatchNginxConfig(cluster.name, cluster.master!.HttpsHostPort!.Value);
}

_console.WriteLine($"Regenerated configuration for {vdkClusters.Count} cluster(s).");
ReloadConfigs();
_console.WriteLine("Nginx configuration reloaded.");
}
Comment on lines +423 to +458
Copy link

Copilot AI Jan 25, 2026

Choose a reason for hiding this comment

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

The new RegenerateConfigs method lacks test coverage. The project has comprehensive tests for ReverseProxyClient (ReverseProxyClientTests.cs), and this new public method should have tests to verify it correctly regenerates configurations for all clusters, handles the case when no VDK clusters exist, and properly handles errors during regeneration.

Copilot uses AI. Check for mistakes.

private static int GetEnvironmentVariableAsInt(string variableName, int defaultValue = 0)
{
string strValue = Environment.GetEnvironmentVariable(variableName);
Expand Down
7 changes: 7 additions & 0 deletions cli/src/Vdk/Vdk.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,13 @@
<None Update="ConfigMounts\hosts.toml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="ConfigMounts\zot-config.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>

<ItemGroup>
<Content Include="images\**" CopyToOutputDirectory="PreserveNewest" LinkBase="images" />
Copy link

Copilot AI Jan 25, 2026

Choose a reason for hiding this comment

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

The Content directive with wildcard pattern for the images directory is unusual and may cause unexpected behavior during builds. The images directory is meant to be user data (excluded in .gitignore), so it's unclear why it should be copied to the output. Consider whether this is necessary, as it could copy large amounts of registry data during build operations. If persistence is needed, the application should reference the directory by relative path at runtime rather than copying it.

Copilot uses AI. Check for mistakes.
</ItemGroup>

</Project>
Expand Down
42 changes: 42 additions & 0 deletions cli/src/Vdk/vega.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@

server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name hub.dev-k8s.cloud;
ssl_certificate /etc/certs/fullchain.pem;
ssl_certificate_key /etc/certs/privkey.pem;
location / {
client_max_body_size 0;
proxy_pass http://host.docker.internal:5000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}


##### START idp
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name idp.dev-k8s.cloud;
ssl_certificate /etc/certs/fullchain.pem;
ssl_certificate_key /etc/certs/privkey.pem;
location / {
proxy_pass https://host.docker.internal:40237;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;

# Support WebSocket protocol upgrades
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
Comment on lines +1 to +40
Copy link

Copilot AI Jan 25, 2026

Choose a reason for hiding this comment

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

The vega.conf file appears to be a generated runtime artifact (created by ReverseProxyClient.InitConfFile) but is being committed to the repository. This file should be excluded from version control by adding it to .gitignore to prevent conflicts and avoid committing environment-specific configurations.

Suggested change
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name hub.dev-k8s.cloud;
ssl_certificate /etc/certs/fullchain.pem;
ssl_certificate_key /etc/certs/privkey.pem;
location / {
client_max_body_size 0;
proxy_pass http://host.docker.internal:5000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
##### START idp
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name idp.dev-k8s.cloud;
ssl_certificate /etc/certs/fullchain.pem;
ssl_certificate_key /etc/certs/privkey.pem;
location / {
proxy_pass https://host.docker.internal:40237;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Support WebSocket protocol upgrades
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
# vega.conf - example reverse proxy configuration
#
# This file is intentionally kept as a *template* configuration and should
# not contain environment-specific or runtime-generated values.
#
# In many deployments, a component such as ReverseProxyClient.InitConfFile
# is responsible for generating the actual configuration used at runtime.
# To avoid merge conflicts and leaking environment details, copy this file
# and customize it outside of version control (for example, in a deployment
# repository or via your configuration management system).
#
# To use this template:
# 1. Copy it to an appropriate location for your environment.
# 2. Replace placeholder values (example.com, backend:port, cert paths).
# 3. Enable or adjust the server blocks as needed.
#
# NOTE: All configuration below is commented out and uses placeholder
# values. Adjust and uncomment in your own, non-committed copy.
# server {
# listen 443 ssl;
# listen [::]:443 ssl;
# http2 on;
# server_name app.example.com;
#
# # Paths to your TLS certificate and key for this host.
# # Replace with the correct locations for your environment.
# ssl_certificate /path/to/your/fullchain.pem;
# ssl_certificate_key /path/to/your/privkey.pem;
#
# location / {
# # Adjust maximum request body size to your needs.
# client_max_body_size 0;
#
# # Upstream application endpoint.
# # Replace "backend-app" and port with your actual backend.
# proxy_pass http://backend-app:5000;
#
# proxy_set_header Host $host;
# proxy_set_header X-Real-IP $remote_addr;
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# proxy_set_header X-Forwarded-Proto $scheme;
# }
# }
##### START idp (example Identity Provider endpoint)
# server {
# listen 443 ssl;
# listen [::]:443 ssl;
# http2 on;
# server_name idp.example.com;
#
# # Paths to your TLS certificate and key for this host.
# ssl_certificate /path/to/your/fullchain.pem;
# ssl_certificate_key /path/to/your/privkey.pem;
#
# location / {
# # Upstream IDP/authorization server endpoint.
# proxy_pass https://identity-provider:443;
#
# proxy_set_header Host $host;
# proxy_set_header X-Real-IP $remote_addr;
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# proxy_set_header X-Forwarded-Proto $scheme;
#
# # Support WebSocket protocol upgrades, if required by the IDP.
# proxy_http_version 1.1;
# proxy_set_header Upgrade $http_upgrade;
# proxy_set_header Connection "upgrade";
# }
# }

Copilot uses AI. Check for mistakes.
##### END idp

Loading