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
2 changes: 1 addition & 1 deletion .github/workflows/generate-docs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,6 @@ jobs:
run: |
git config user.name "github-actions"
git config user.email "github-actions@github.com"
git add CommandIndex.md Commands.md
git add Shared.Rcl/wwwroot/raw_docs/CommandIndex.md Shared.Rcl/wwwroot/raw_docs/Commands.md
git commit -m "Update CLI docs" || echo "No changes to commit"
git push
374 changes: 301 additions & 73 deletions AGENTS.md

Large diffs are not rendered by default.

7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[![RackPeek demo](./assets/rackpeek_banner_thin.png)](./assets/rackpeek_banner_thin.png)

![Version](https://img.shields.io/badge/Version-1.3.0-2ea44f) ![Status](https://img.shields.io/badge/Status-Stable-success)
![Version](https://img.shields.io/badge/Version-1.4.0-2ea44f) ![Status](https://img.shields.io/badge/Status-Stable-success)
[![Join our Discord](https://img.shields.io/badge/Discord-Join%20Us-7289DA?logo=discord&logoColor=white)](https://discord.gg/egXRPdesee) [![Live Demo](https://img.shields.io/badge/Live%20Demo-Try%20RackPeek%20Online-2ea44f?logo=githubpages&logoColor=white)](https://timmoth.github.io/RackPeek/) [![Docker Hub](https://img.shields.io/badge/Docker%20Hub-rackpeek-2496ED?logo=docker&logoColor=white)](https://hub.docker.com/r/aptacode/rackpeek/)

RackPeek is a webui & CLI tool for documenting and managing home lab and small-scale IT infrastructure.
Expand Down Expand Up @@ -53,9 +53,10 @@ services:
- rackpeek-config:/app/config
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "curl -s http://localhost:8080 | grep -q 'rackpeek' || exit 1"]
test: ["CMD", "curl", "-fsS", "http://localhost:8080/health"]
interval: 30s
timeout: 10s
timeout: 5s
start_period: 15s
retries: 3

volumes:
Expand Down
60 changes: 45 additions & 15 deletions RackPeek.Domain/Git/LibGit2GitRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@ public interface IGitCredentialsProvider {
CredentialsHandler GetHandler();
}

public sealed class GitHubTokenCredentialsProvider(string username, string token) : IGitCredentialsProvider {
/// <summary>
/// HTTP Basic auth using a personal access token as the password. Works with
/// any forge that accepts a token over HTTPS — GitHub, Gitea, GitLab, Bitbucket,
/// Forgejo, etc.
/// </summary>
public sealed class TokenCredentialsProvider(string username, string token) : IGitCredentialsProvider {
private readonly string _username = username ?? throw new ArgumentNullException(nameof(username));
private readonly string _token = token ?? throw new ArgumentNullException(nameof(token));

Expand All @@ -19,22 +24,47 @@ public CredentialsHandler GetHandler() {
}
}

public sealed class LibGit2GitRepository(
string configDirectory,
IGitCredentialsProvider credentialsProvider) : IGitRepository {
private readonly CredentialsHandler _credentials = credentialsProvider.GetHandler();
public sealed class LibGit2GitRepository : IGitRepository {
private readonly string _configDirectory;
private readonly CredentialsHandler _credentials;
private readonly CertificateCheckHandler? _certificateCheck;

public LibGit2GitRepository(
string configDirectory,
IGitCredentialsProvider credentialsProvider,
bool insecureTls = false) {
_configDirectory = configDirectory;
_credentials = credentialsProvider.GetHandler();
_isAvailable = Repository.IsValid(configDirectory);
// When insecureTls is true, accept any TLS certificate. Required for
// self-hosted forges (Gitea, GitLab) behind a private CA or self-signed
// cert. Public hosts already ship trusted certs; leave it off for them.
_certificateCheck = insecureTls
? (_, _, _) => true
: null;
}

private FetchOptions BuildFetchOptions() => new() {
CredentialsProvider = _credentials,
CertificateCheck = _certificateCheck
};

private PushOptions BuildPushOptions() => new() {
CredentialsProvider = _credentials,
CertificateCheck = _certificateCheck
};

private bool _isAvailable = Repository.IsValid(configDirectory);
private bool _isAvailable;

public bool IsAvailable => _isAvailable;

public void Init() {
Repository.Init(configDirectory);
Repository.Init(_configDirectory);

_isAvailable = true;
}

private Repository OpenRepo() => new(configDirectory);
private Repository OpenRepo() => new(_configDirectory);

private static Signature GetSignature(Repository repo) {
var name = repo.Config.Get<string>("user.name")?.Value ?? "RackPeek";
Expand Down Expand Up @@ -156,7 +186,7 @@ public GitSyncStatus FetchAndGetSyncStatus() {
repo,
remote.Name,
remote.FetchRefSpecs.Select(r => r.Specification),
new FetchOptions { CredentialsProvider = _credentials },
BuildFetchOptions(),
null);

// If the repo has no commits yet (unborn branch)
Expand Down Expand Up @@ -188,15 +218,15 @@ public void Push() {
repo.Network.Push(
remote,
refSpec,
new PushOptions { CredentialsProvider = _credentials });
BuildPushOptions());
}
catch (NonFastForwardException) {
PullInternal(repo);

repo.Network.Push(
remote,
refSpec,
new PushOptions { CredentialsProvider = _credentials });
BuildPushOptions());
}

if (repo.Head.TrackedBranch is null) {
Expand All @@ -220,7 +250,7 @@ private void PullInternal(Repository repo) {
repo,
remote.Name,
remote.FetchRefSpecs.Select(r => r.Specification),
new FetchOptions { CredentialsProvider = _credentials },
BuildFetchOptions(),
null);

Branch? remoteBranch = repo.Branches[$"{remote.Name}/{repo.Head.FriendlyName}"];
Expand Down Expand Up @@ -249,7 +279,7 @@ public void AddRemote(string name, string url) {
repo,
remote.Name,
remote.FetchRefSpecs.Select(r => r.Specification),
new FetchOptions { CredentialsProvider = _credentials },
BuildFetchOptions(),
null);

// detect if remote has a default branch
Expand Down Expand Up @@ -288,7 +318,7 @@ public void AddRemote(string name, string url) {
repo.Network.Push(
remote,
$"refs/heads/{importBranchName}:refs/heads/{importBranchName}",
new PushOptions { CredentialsProvider = _credentials });
BuildPushOptions());

repo.Branches.Update(importBranch,
b => b.TrackedBranch = $"refs/remotes/{remote.Name}/{importBranchName}");
Expand Down Expand Up @@ -316,7 +346,7 @@ public void AddRemote(string name, string url) {
repo.Network.Push(
remote,
$"refs/heads/{branchName}:refs/heads/{branchName}",
new PushOptions { CredentialsProvider = _credentials });
BuildPushOptions());

repo.Branches.Update(branch,
b => b.TrackedBranch = $"refs/remotes/{remote.Name}/{branchName}");
Expand Down
8 changes: 4 additions & 4 deletions RackPeek.Domain/RackPeek.Domain.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
<ItemGroup>
<PackageReference Include="DocMigrator.Yaml" Version="10.0.3" />
<PackageReference Include="LibGit2Sharp" Version="0.31.0" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="10.0.3" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="10.0.3" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="10.0.3" />
<PackageReference Include="YamlDotNet" Version="16.3.0" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="10.0.8" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="10.0.8" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="10.0.8" />
<PackageReference Include="YamlDotNet" Version="17.1.0" />
</ItemGroup>

</Project>
4 changes: 2 additions & 2 deletions RackPeek.Domain/RpkConstants.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
namespace RackPeek.Domain;

public static class RpkConstants {
public const string Version = "v1.3.1";
public const string Version = "v1.4.0";

public static bool HasGitServices = false;
public static bool HasGitServices { get; set; }
}
6 changes: 4 additions & 2 deletions RackPeek.Domain/ServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,15 @@ public static IServiceCollection AddGitServices(
var gitToken = config["GIT_TOKEN"];
if (!string.IsNullOrEmpty(gitToken) && !string.IsNullOrWhiteSpace(yamlPath)) {
var gitUsername = config["GIT_USERNAME"] ?? "git";
var insecureTls = string.Equals(
config["GIT_INSECURE_TLS"], "true", StringComparison.OrdinalIgnoreCase);

services.AddSingleton<IGitCredentialsProvider>(
_ => new GitHubTokenCredentialsProvider(gitUsername, gitToken));
_ => new TokenCredentialsProvider(gitUsername, gitToken));

services.AddSingleton<IGitRepository>(sp => {
IGitCredentialsProvider creds = sp.GetRequiredService<IGitCredentialsProvider>();
return new LibGit2GitRepository(yamlPath, creds);
return new LibGit2GitRepository(yamlPath, creds, insecureTls);
});
RpkConstants.HasGitServices = true;
}
Expand Down
8 changes: 4 additions & 4 deletions RackPeek.Web.Viewer/RackPeek.Web.Viewer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="10.0.3"/>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="10.0.3" PrivateAssets="all"/>
<PackageReference Include="Spectre.Console.Cli" Version="0.53.1"/>
<PackageReference Include="Spectre.Console.Testing" Version="0.54.0"/>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="10.0.8"/>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="10.0.8" PrivateAssets="all"/>
<PackageReference Include="Spectre.Console.Cli" Version="0.55.0"/>
<PackageReference Include="Spectre.Console.Testing" Version="0.55.2"/>
</ItemGroup>

<ItemGroup>
Expand Down
9 changes: 9 additions & 0 deletions RackPeek.Web/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ WORKDIR /app

USER root

# Install curl for the container HEALTHCHECK probe (the aspnet runtime image
# ships without curl/wget, so without this the HEALTHCHECK below cannot run).
RUN apt-get update \
&& apt-get install -y --no-install-recommends curl \
&& rm -rf /var/lib/apt/lists/*

# Create shared config directory safely
RUN mkdir -p /app/config \
&& chown -R ${APP_UID}:0 /app/config \
Expand All @@ -68,4 +74,7 @@ ENV RPK_YAML_DIR=/app/config
# Drop privileges
USER ${APP_UID}

HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \
CMD curl -fsS http://localhost:8080/health || exit 1

ENTRYPOINT ["dotnet", "RackPeek.Web.dll"]
80 changes: 0 additions & 80 deletions RackPeek.Web/RackPeek.Web.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -16,86 +16,6 @@
<ProjectReference Include="..\Shared.Rcl\Shared.Rcl.csproj"/>
</ItemGroup>

<ItemGroup>
<_ContentIncludedByDefault Remove="Components\Components\Desktops\DesktopCardComponent.razor"/>
<_ContentIncludedByDefault Remove="Components\Components\Desktops\DesktopsListComponent.razor"/>
<_ContentIncludedByDefault Remove="Components\FireWalls\FireWallCardComponent.razor"/>
<_ContentIncludedByDefault Remove="Components\FireWalls\FireWallsListComponent.razor"/>
<_ContentIncludedByDefault Remove="Components\FireWalls\FireWallsListPage.razor"/>
<_ContentIncludedByDefault Remove="Components\Laptops\LaptopCardComponent.razor"/>
<_ContentIncludedByDefault Remove="Components\Laptops\LaptopsListComponent.razor"/>
<_ContentIncludedByDefault Remove="Components\Laptops\LaptopsListPage.razor"/>
<_ContentIncludedByDefault Remove="Components\Routers\RouterCardComponent.razor"/>
<_ContentIncludedByDefault Remove="Components\Routers\RoutersListComponent.razor"/>
<_ContentIncludedByDefault Remove="Components\Routers\RoutersListPage.razor"/>
<_ContentIncludedByDefault Remove="Components\Servers\Components\HardwareDependencyTreeComponent.razor"/>
<_ContentIncludedByDefault Remove="Components\Servers\Components\ResourceBreadCrumbComponent.razor"/>
<_ContentIncludedByDefault Remove="Components\Servers\Components\ServerCardComponent.razor"/>
<_ContentIncludedByDefault Remove="Components\Servers\Components\ServersListComponent.razor"/>
<_ContentIncludedByDefault Remove="Components\Servers\Components\ServiceCardComponent.razor"/>
<_ContentIncludedByDefault Remove="Components\Servers\Components\ServicesListComponent.razor"/>
<_ContentIncludedByDefault Remove="Components\Servers\Components\SystemCardComponent.razor"/>
<_ContentIncludedByDefault Remove="Components\Servers\Components\SystemDependencyTreeComponent.razor"/>
<_ContentIncludedByDefault Remove="Components\Servers\Components\SystemsListComponent.razor"/>
<_ContentIncludedByDefault Remove="Components\AccessPoints\AccessPointCardComponent.razor"/>
<_ContentIncludedByDefault Remove="Components\AccessPoints\AccessPointsListComponent.razor"/>
<_ContentIncludedByDefault Remove="Components\AccessPoints\AccessPointsListPage.razor"/>
<_ContentIncludedByDefault Remove="Components\AccessPoints\AddAccessPointComponent.razor"/>
<_ContentIncludedByDefault Remove="Components\Components\HardwareDependencyTreeComponent.razor"/>
<_ContentIncludedByDefault Remove="Components\Components\ResourceBreadCrumbComponent.razor"/>
<_ContentIncludedByDefault Remove="Components\Desktops\AddDesktopComponent.razor"/>
<_ContentIncludedByDefault Remove="Components\Desktops\DesktopCardComponent.razor"/>
<_ContentIncludedByDefault Remove="Components\Desktops\DesktopsListComponent.razor"/>
<_ContentIncludedByDefault Remove="Components\Desktops\DesktopsListPage.razor"/>
<_ContentIncludedByDefault Remove="Components\Firewalls\AddFirewallComponent.razor"/>
<_ContentIncludedByDefault Remove="Components\Firewalls\FirewallListComponent.razor"/>
<_ContentIncludedByDefault Remove="Components\Firewalls\FirewallListPage.razor"/>
<_ContentIncludedByDefault Remove="Components\Hardware\HardwareDetailsPage.razor"/>
<_ContentIncludedByDefault Remove="Components\Hardware\HardwareTreePage.razor"/>
<_ContentIncludedByDefault Remove="Components\Laptops\AddLaptopComponent.razor"/>
<_ContentIncludedByDefault Remove="Components\Layout\MainLayout.razor"/>
<_ContentIncludedByDefault Remove="Components\Layout\ReconnectModal.razor"/>
<_ContentIncludedByDefault Remove="Components\Modals\ConfirmModal.razor"/>
<_ContentIncludedByDefault Remove="Components\Modals\CpuModal.razor"/>
<_ContentIncludedByDefault Remove="Components\Modals\DriveModal.razor"/>
<_ContentIncludedByDefault Remove="Components\Modals\GpuModal.razor"/>
<_ContentIncludedByDefault Remove="Components\Modals\HardwareSelectionModal.razor"/>
<_ContentIncludedByDefault Remove="Components\Modals\NicModal.razor"/>
<_ContentIncludedByDefault Remove="Components\Modals\PortModal.razor"/>
<_ContentIncludedByDefault Remove="Components\Modals\RamModal.razor"/>
<_ContentIncludedByDefault Remove="Components\Modals\StringValueModal.razor"/>
<_ContentIncludedByDefault Remove="Components\Modals\SystemSelectionModal.razor"/>
<_ContentIncludedByDefault Remove="Components\Pages\Error.razor"/>
<_ContentIncludedByDefault Remove="Components\Pages\Home.razor"/>
<_ContentIncludedByDefault Remove="Components\Pages\NotFound.razor"/>
<_ContentIncludedByDefault Remove="Components\Routers\AddRouterComponent.razor"/>
<_ContentIncludedByDefault Remove="Components\Routers\RouterListComponent.razor"/>
<_ContentIncludedByDefault Remove="Components\Routers\RouterListPage.razor"/>
<_ContentIncludedByDefault Remove="Components\Servers\AddServerComponent.razor"/>
<_ContentIncludedByDefault Remove="Components\Servers\ServerCardComponent.razor"/>
<_ContentIncludedByDefault Remove="Components\Servers\ServersListComponent.razor"/>
<_ContentIncludedByDefault Remove="Components\Servers\ServersListPage.razor"/>
<_ContentIncludedByDefault Remove="Components\Services\AddServiceComponent.razor"/>
<_ContentIncludedByDefault Remove="Components\Services\ServiceCardComponent.razor"/>
<_ContentIncludedByDefault Remove="Components\Services\ServiceDetailsPage.razor"/>
<_ContentIncludedByDefault Remove="Components\Services\ServicesListComponent.razor"/>
<_ContentIncludedByDefault Remove="Components\Services\ServicesListPage.razor"/>
<_ContentIncludedByDefault Remove="Components\Switches\AddSwitchComponent.razor"/>
<_ContentIncludedByDefault Remove="Components\Switches\SwitchCardComponent.razor"/>
<_ContentIncludedByDefault Remove="Components\Switches\SwitchListComponent.razor"/>
<_ContentIncludedByDefault Remove="Components\Switches\SwitchListPage.razor"/>
<_ContentIncludedByDefault Remove="Components\Systems\AddSystemComponent.razor"/>
<_ContentIncludedByDefault Remove="Components\Systems\SystemCardComponent.razor"/>
<_ContentIncludedByDefault Remove="Components\Systems\SystemDependencyTreeComponent.razor"/>
<_ContentIncludedByDefault Remove="Components\Systems\SystemsDetailsPage.razor"/>
<_ContentIncludedByDefault Remove="Components\Systems\SystemsListComponent.razor"/>
<_ContentIncludedByDefault Remove="Components\Systems\SystemsListPage.razor"/>
<_ContentIncludedByDefault Remove="Components\Ups\AddUpsComponent.razor"/>
<_ContentIncludedByDefault Remove="Components\Ups\UpsCardComponent.razor"/>
<_ContentIncludedByDefault Remove="Components\Ups\UpsListComponent.razor"/>
<_ContentIncludedByDefault Remove="Components\Ups\UpsListPage.razor"/>
</ItemGroup>

<ItemGroup>
<Content Include="..\.dockerignore">
<Link>.dockerignore</Link>
Expand Down
Loading
Loading