Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6712fc1b65 | ||
|
|
72eb9c4b1e | ||
|
|
01a7c7ffdf | ||
|
|
adb6623c67 | ||
|
|
0e680c72fb | ||
|
|
a924b90caa | ||
|
|
a677b1306e |
8
.github/propagate-config.yml
vendored
8
.github/propagate-config.yml
vendored
@@ -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
|
||||
|
||||
23
.github/renovate.json
vendored
23
.github/renovate.json
vendored
@@ -7,7 +7,9 @@
|
||||
"helpers:pinGitHubActionDigests"
|
||||
],
|
||||
"baseBranches": [
|
||||
"feature/beta-release",
|
||||
"development"
|
||||
|
||||
],
|
||||
"timezone": "America/New_York",
|
||||
"dependencyDashboard": true,
|
||||
@@ -17,6 +19,10 @@
|
||||
"dependencies"
|
||||
],
|
||||
|
||||
"ignorePaths": [
|
||||
".docker/**"
|
||||
],
|
||||
|
||||
"rebaseWhen": "auto",
|
||||
|
||||
"vulnerabilityAlerts": {
|
||||
@@ -28,7 +34,7 @@
|
||||
],
|
||||
|
||||
"rangeStrategy": "bump",
|
||||
"automerge": true,
|
||||
"automerge": false,
|
||||
"automergeType": "pr",
|
||||
"platformAutomerge": true,
|
||||
|
||||
@@ -123,8 +129,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",
|
||||
|
||||
53
.github/workflows/nightly-build.yml
vendored
53
.github/workflows/nightly-build.yml
vendored
@@ -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
|
||||
|
||||
18
.github/workflows/playwright.yml
vendored
18
.github/workflows/playwright.yml
vendored
@@ -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:
|
||||
|
||||
4
.github/workflows/propagate-changes.yml
vendored
4
.github/workflows/propagate-changes.yml
vendored
@@ -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
5
.gitignore
vendored
@@ -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
14
.vscode/mcp.json
vendored
Normal 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": []
|
||||
}
|
||||
@@ -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
Reference in New Issue
Block a user