Compare commits

...

6 Commits

9 changed files with 1187 additions and 709 deletions

View File

@@ -6,7 +6,11 @@
sensitive_paths:
- scripts/history-rewrite/
- data/backups
- docs/plans/history_rewrite.md
- .github/workflows/
- docs/plans/
- .github/agents/
- .github/instructions/
- .github/prompts/
- .github/skills/
- .vscode/
- scripts/history-rewrite/preview_removals.sh
- scripts/history-rewrite/clean_history.sh

19
.github/renovate.json vendored
View File

@@ -7,7 +7,9 @@
"helpers:pinGitHubActionDigests"
],
"baseBranches": [
"feature/beta-release",
"development"
],
"timezone": "America/New_York",
"dependencyDashboard": true,
@@ -28,7 +30,7 @@
],
"rangeStrategy": "bump",
"automerge": true,
"automerge": false,
"automergeType": "pr",
"platformAutomerge": true,
@@ -123,8 +125,19 @@
"pin",
"digest"
],
"groupName": "weekly-non-major-updates",
"automerge": true
"groupName": "weekly-non-major-updates"
},
{
"description": "Feature branches: Always require manual approval",
"matchBaseBranches": ["feature/*"],
"automerge": false
},
{
"description": "Development branch: Auto-merge non-major updates after proven stable",
"matchBaseBranches": ["development"],
"matchUpdateTypes": ["minor", "patch", "pin", "digest"],
"automerge": true,
"minimumReleaseAge": "3 days"
},
{
"description": "Preserve your custom Caddy patch labels but allow them to group into the weekly PR",

View File

@@ -136,6 +136,8 @@ jobs:
labels: ${{ steps.meta.outputs.labels }}
build-args: |
VERSION=nightly-${{ github.sha }}
VCS_REF=${{ github.sha }}
BUILD_DATE=${{ github.event.repository.pushed_at }}
cache-from: type=gha
cache-to: type=gha,mode=max
provenance: true
@@ -232,50 +234,13 @@ jobs:
docker stop charon-nightly
docker rm charon-nightly
build-nightly-release:
needs: test-nightly-image
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout nightly branch
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: nightly
fetch-depth: 0
- name: Set up Go
uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0
with:
go-version: '1.25.6'
- name: Set up Node.js
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version: '24.13.0'
- name: Build frontend
working-directory: ./frontend
run: |
npm ci
npm run build
- name: Run GoReleaser (snapshot mode)
uses: goreleaser/goreleaser-action@e435ccd777264be153ace6237001ef4d979d3a7a # v6.4.0
with:
distribution: goreleaser
version: '~> v2'
args: release --snapshot --skip=publish --clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Upload nightly binaries
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: nightly-binaries
path: dist/*
retention-days: 30
# NOTE: Standalone binary builds removed - Charon uses Docker-only deployment
# The build-nightly-release job that ran GoReleaser for Windows/macOS/Linux binaries
# was removed because:
# 1. Charon is distributed exclusively via Docker images
# 2. Cross-compilation was failing due to Unix-specific syscalls
# 3. No users download standalone binaries (all use Docker)
# If standalone binaries are needed in the future, re-add the job with Linux-only targets
verify-nightly-supply-chain:
needs: build-and-push-nightly

View File

@@ -3,6 +3,24 @@
name: Playwright E2E Tests
on:
push:
branches:
- main
- development
- 'feature/**'
paths:
- 'frontend/**'
- 'backend/**'
- 'tests/**'
- 'playwright.config.js'
- '.github/workflows/playwright.yml'
pull_request:
branches:
- main
- development
- 'feature/**'
workflow_run:
workflows: ["Docker Build, Publish & Test"]
types:

View File

@@ -86,7 +86,9 @@ jobs:
}
// Load propagation config (list of sensitive paths) from .github/propagate-config.yml when available
let configPaths = ['scripts/history-rewrite/', 'data/backups', 'docs/plans/history_rewrite.md', '.github/workflows/'];
// NOTE: .github/workflows/ was removed from defaults - workflow updates SHOULD propagate
// to ensure downstream branches have correct CI/CD configurations
let configPaths = ['scripts/history-rewrite/', 'data/backups', 'docs/plans/history_rewrite.md'];
try {
const configResp = await github.rest.repos.getContent({ owner: context.repo.owner, repo: context.repo.repo, path: '.github/propagate-config.yml', ref: src });
const contentStr = Buffer.from(configResp.data.content, 'base64').toString('utf8');

5
.gitignore vendored
View File

@@ -9,11 +9,6 @@
docs/reports/performance_diagnostics.md
docs/plans/chores.md
# -----------------------------------------------------------------------------
# VS Code
# -----------------------------------------------------------------------------
.vscode/**
# -----------------------------------------------------------------------------
# Python (pre-commit, tooling)
# -----------------------------------------------------------------------------

14
.vscode/mcp.json vendored Normal file
View File

@@ -0,0 +1,14 @@
{
"servers": {
"microsoft/playwright-mcp": {
"type": "stdio",
"command": "npx",
"args": [
"@playwright/mcp@latest"
],
"gallery": "https://api.mcp.github.com",
"version": "0.0.1-seed"
}
},
"inputs": []
}

View File

@@ -1,53 +1,324 @@
# Architecture Analysis: Docker-Only vs Cross-Platform Binaries
# Expose Build Version to Users - Implementation Plan
**Date:** 2026-01-30
**Status:** Analysis Complete - Recommendation Ready
**Decision Type:** Critical Path Simplification
**Priority:** High (Blocks unnecessary complexity)
**Date:** January 30, 2026
**Status:** 📋 READY FOR IMPLEMENTATION
**Goal:** Enable nightly build users to easily report their exact version for bug triage
---
## Executive Summary
**RECOMMENDATION: Remove Windows/macOS build targets from GoReleaser and simplify to Docker-only distribution.**
This plan details how to expose build version information (including SHA, build date) to users via:
1. A backend `/health` endpoint (already exists, already exposes version)
2. A frontend UI footer display (already implemented in Layout.tsx)
Charon is documented, architected, and distributed **exclusively as a Docker container**. The cross-platform binary builds in `.goreleaser.yaml` are **artifacts from template boilerplate** that serve no practical purpose and waste CI resources.
**Finding:** The version exposure is **already fully implemented**. This document confirms the existing implementation and identifies minor enhancements.
---
## Evidence Gathered
## 1. Backend Analysis
### 1. Architecture Verification ✅
### 1.1 Version Package
**File:** [backend/internal/version/version.go](../../backend/internal/version/version.go)
**Source:** `ARCHITECTURE.md` (Lines 1-1300)
```go
package version
```markdown
## System Architecture
Charon follows a **monolithic architecture** with an embedded reverse proxy,
packaged as a single Docker container.
const Name = "Charon"
### Single Container Architecture
**Rationale:** Simplicity over scalability - target audience is home users and small teams
var (
Version = "0.3.0" // Overwritten via ldflags at build time
BuildTime = "unknown" // Overwritten via ldflags at build time
GitCommit = "unknown" // Overwritten via ldflags at build time
)
**Container Contents:**
- Frontend static files (Vite build output)
- Go backend binary
- Embedded Caddy server
- SQLite database file
- Caddy certificates
- CrowdSec local database
func Full() string {
if BuildTime != "unknown" && GitCommit != "unknown" {
return Version + " (commit: " + GitCommit + ", built: " + BuildTime + ")"
}
return Version
}
```
**Verdict:** Documented as Docker-only, single-container architecture.
**Status:** ✅ Already has `Version`, `BuildTime`, and `GitCommit` variables that are injected at build time.
### 1.2 Health Handler
**File:** [backend/internal/api/handlers/health_handler.go](../../backend/internal/api/handlers/health_handler.go#L27-L36)
```go
func HealthHandler(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"status": "ok",
"service": version.Name,
"version": version.Version,
"git_commit": version.GitCommit,
"build_time": version.BuildTime,
"internal_ip": getLocalIP(),
})
}
```
**Status:** ✅ Already exposes version, git_commit, and build_time in `/health` endpoint.
### 1.3 Build Time Injection (Dockerfile)
**File:** [Dockerfile](../../Dockerfile#L142-L156)
```dockerfile
ARG VERSION=dev
ARG VCS_REF=unknown
ARG BUILD_DATE=unknown
# ldflags injection:
-X github.com/Wikid82/charon/backend/internal/version.Version=${VERSION}
-X github.com/Wikid82/charon/backend/internal/version.GitCommit=${VCS_REF}
-X github.com/Wikid82/charon/backend/internal/version.BuildTime=${BUILD_DATE}
```
**Status:** ✅ Dockerfile accepts `VERSION`, `VCS_REF`, and `BUILD_DATE` build args and injects them via ldflags.
---
### 2. User Documentation ✅
## 2. Build Pipeline Analysis
**Source:** `README.md` (Lines 1-150)
### 2.1 Nightly Build Workflow
**File:** [.github/workflows/nightly-build.yml](../../.github/workflows/nightly-build.yml#L137-L139)
**Installation Methods Documented:**
1. Docker Compose (Recommended)
```yaml
build-args: |
VERSION=nightly-${{ github.sha }}
```
**Current State:**
-`VERSION` is passed as `nightly-${{ github.sha }}` (full 40-char SHA)
-`VCS_REF` is NOT passed (will default to "unknown")
-`BUILD_DATE` is NOT passed (will default to "unknown")
**Expected Response from `/health` for nightly builds:**
```json
{
"status": "ok",
"service": "Charon",
"version": "nightly-abc123def456...", // Full SHA (not ideal)
"git_commit": "unknown", // Missing!
"build_time": "unknown" // Missing!
}
```
### 2.2 Recommended Fix for Nightly Workflow
Update [.github/workflows/nightly-build.yml](../../.github/workflows/nightly-build.yml#L137-L139) to pass all build args:
```yaml
build-args: |
VERSION=nightly-${{ github.sha }}
VCS_REF=${{ github.sha }}
BUILD_DATE=${{ github.event.head_commit.timestamp || github.event.repository.pushed_at }}
```
Or more reliably with a timestamp step:
```yaml
- name: Set build date
id: build_date
run: echo "date=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_OUTPUT
# Then in build-push-action:
build-args: |
VERSION=nightly-${{ github.sha }}
VCS_REF=${{ github.sha }}
BUILD_DATE=${{ steps.build_date.outputs.date }}
```
---
## 3. Frontend Analysis
### 3.1 Health API Client
**File:** [frontend/src/api/health.ts](../../frontend/src/api/health.ts)
```typescript
export interface HealthResponse {
status: string;
service: string;
version: string;
git_commit: string;
build_time: string;
}
export const checkHealth = async (): Promise<HealthResponse> => {
const { data } = await client.get<HealthResponse>('/health');
return data;
};
```
**Status:** ✅ Already fetches version, git_commit, and build_time from backend.
### 3.2 Layout Component (Footer Display)
**File:** [frontend/src/components/Layout.tsx](../../frontend/src/components/Layout.tsx#L293-L302)
```tsx
const { data: health } = useQuery({
queryKey: ['health'],
queryFn: checkHealth,
staleTime: 1000 * 60 * 60, // 1 hour
});
// In sidebar footer (lines 293-302):
<div className="text-xs text-gray-500 dark:text-gray-500 text-center mb-2 flex flex-col gap-0.5">
<span>Version {health?.version || 'dev'}</span>
{health?.git_commit && health.git_commit !== 'unknown' && (
<span className="text-[10px] opacity-75 font-mono">
({health.git_commit.substring(0, 7)})
</span>
)}
</div>
```
**Status:** ✅ Already displays version and short commit hash in sidebar footer.
**Display behavior:**
- Shows: `Version nightly-abc123def456...` (full SHA from VERSION)
- Shows: `(abc1234)` only if `git_commit` is set (currently "unknown" for nightly)
---
## 4. Gap Analysis
| Component | Status | Issue |
|-----------|--------|-------|
| Backend version package | ✅ Complete | None |
| Backend health handler | ✅ Complete | None |
| Dockerfile ldflags | ✅ Complete | None |
| Nightly workflow | ⚠️ Incomplete | Missing `VCS_REF` and `BUILD_DATE` |
| Frontend API client | ✅ Complete | None |
| Frontend UI display | ✅ Complete | None |
---
## 5. Implementation Tasks
### Task 1: Update Nightly Build Workflow (REQUIRED)
**File:** `.github/workflows/nightly-build.yml`
**Lines:** ~137-139 (build-args section)
**Change:**
```yaml
# FROM:
build-args: |
VERSION=nightly-${{ github.sha }}
# TO:
build-args: |
VERSION=nightly-${{ github.sha }}
VCS_REF=${{ github.sha }}
BUILD_DATE=${{ github.event.head_commit.timestamp }}
```
**Alternative with reliable timestamp:**
```yaml
# Add step before build-push-action:
- name: Set build metadata
id: build_meta
run: |
echo "date=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_OUTPUT
echo "short_sha=${GITHUB_SHA::7}" >> $GITHUB_OUTPUT
# Update build-args:
build-args: |
VERSION=nightly-${{ steps.build_meta.outputs.short_sha }}
VCS_REF=${{ github.sha }}
BUILD_DATE=${{ steps.build_meta.outputs.date }}
```
### Task 2: (OPTIONAL) Improve Version Display Format
If a shorter nightly version is preferred (e.g., `nightly-abc1234` instead of full SHA):
**Option A:** Use short SHA in workflow (recommended):
```yaml
VERSION=nightly-${GITHUB_SHA::7}
```
**Option B:** Truncate in frontend (already partially done for git_commit display)
---
## 6. Expected Result After Implementation
### `/health` Response:
```json
{
"status": "ok",
"service": "Charon",
"version": "nightly-abc1234",
"git_commit": "abc1234def5678901234567890abcdef12345678",
"build_time": "2026-01-30T09:00:00Z",
"internal_ip": "172.17.0.2"
}
```
### UI Footer Display:
```
Version nightly-abc1234
(abc1234)
```
---
## 7. Files to Modify
| File | Line(s) | Change |
|------|---------|--------|
| `.github/workflows/nightly-build.yml` | 137-139 | Add `VCS_REF` and `BUILD_DATE` build-args |
### No Changes Required:
- `backend/internal/version/version.go` - Already complete
- `backend/internal/api/handlers/health_handler.go` - Already complete
- `frontend/src/api/health.ts` - Already complete
- `frontend/src/components/Layout.tsx` - Already complete
- `Dockerfile` - Already complete
---
## 8. Testing Verification
After implementation, verify with:
```bash
# 1. Build with test args
docker build --build-arg VERSION=nightly-test123 \
--build-arg VCS_REF=abc123def456 \
--build-arg BUILD_DATE=2026-01-30T09:00:00Z \
-t charon:test .
# 2. Run container
docker run -d -p 8080:8080 charon:test
# 3. Check health endpoint
curl http://localhost:8080/health | jq
# Expected output:
# {
# "status": "ok",
# "service": "Charon",
# "version": "nightly-test123",
# "git_commit": "abc123def456",
# "build_time": "2026-01-30T09:00:00Z",
# ...
# }
```
---
## 9. Summary
The version exposure feature is **90% complete**. The only missing piece is passing `VCS_REF` and `BUILD_DATE` in the nightly build workflow. A single file change (`.github/workflows/nightly-build.yml`) will complete the implementation.
| Component | Lines of Code | Effort |
|-----------|--------------|--------|
| Workflow fix | ~3 lines | 5 min |
| Testing | N/A | 10 min |
| **Total** | **~3 lines** | **15 min** |
2. Docker Run (One Command)
3. Alternative: GitHub Container Registry

File diff suppressed because it is too large Load Diff