edf3c9824e
feat: workspaces — collaborative repo namespaces Backend - internal/models/workspace.go — Workspace (handle, displayName, description, createdBy) + WorkspaceMember (workspaceId, userId, username, role: owner/admin/member) - internal/models/repo.go — added nullable workspace_id column; existing user repos unaffected - internal/models/migrations/011_workspaces.go — syncs both tables + adds column to repository - internal/api/handlers/workspace.go — ListWorkspaces, CreateWorkspace, GetWorkspace, UpdateWorkspace, DeleteWorkspace (blocks if repos remain), ListRepos, ListMembers, AddMember, UpdateMember, RemoveMember - internal/api/handlers/repos.go — lookupRepo resolves workspace handles; Create accepts workspace field; List includes workspace member repos; withOwnerName uses workspace handle for workspace-owned repos - internal/api/handlers/dashboard.go — recentRuns + repo list include workspace repos the user is a member of - internal/api/router.go — /workspaces, /workspaces/:handle/* routes Workspace rules enforced: - Handle globally unique across usernames + workspace handles (409 on collision) - Creator auto-assigned owner role - Delete blocked if repos exist - Last owner cannot be demoted/removed --- feat: secret management hierarchy (Global → Workspace → Repo → Env) Backend - internal/models/secret.go — Secret struct + EncryptSecret/DecryptSecret with AES-256-GCM (key = SHA-256 of SESSION_SECRET); values never serialised to JSON - internal/models/migrations/012_secrets.go — syncs secret table - internal/api/handlers/secret.go — List/Upsert/Delete for all four scopes; ResolveSecretsForRun builds merged env map for CI - internal/domain/ci/executor.go — JobContext.Secrets field; secrets injected as --env KEY=VALUE into docker run; buildJobContext calls resolveSecrets(Global < Workspace < Repo < Env) - internal/domain/ci/runner_manager.go — passes cfg.SessionSecret to buildJobContext - internal/api/router.go — /repos/:owner/:repo/secrets, /environments/:envName/secrets, /workspaces/:handle/secrets, /admin/secrets --- feat: workspace + secret management UI Frontend - types/api.ts — Workspace, WorkspaceWithMeta, WorkspaceMember, SecretListItem types - api/queries/workspaces.ts — full CRUD hooks + WorkspaceRepo type - api/queries/secrets.ts — repo/env/workspace secret hooks - pages/WorkspacesPage.tsx — list + create modal - pages/WorkspacePage.tsx — workspace dashboard with repo list - pages/WorkspaceSettingsPage.tsx — general settings, members CRUD, workspace secrets, danger zone - pages/RepoSecretsPage.tsx — repo secrets + per-environment secret sections with priority hierarchy callout - pages/CreateRepoPage.tsx — ?workspace= query param pre-fills owner selector; only admin/owner workspaces shown - components/layout/Sidebar.tsx — "Workspaces" global nav item + workspace quick-links; "Secrets" in RepoSubNav; new SecretsIcon, WorkspaceIcon - App.tsx — routes for /workspaces, /workspaces/:handle, /workspaces/:handle/settings, /repos/:owner/:repo/secrets
12 KiB
12 KiB
Changelog
All notable changes to ForgeBucket are documented here.
Format follows Keep a Changelog. Versions follow Semantic Versioning.
Unreleased
In Progress — Phase 3C (Workspaces + Secret management hierarchy)
Workspacemodel — named collaborative namespace (handle, displayName, description, avatarUrl)WorkspaceMembermodel — user membership with owner/admin/member roles- Repos can be owned by a workspace; URL format stays
/{owner}/{repo}where owner is a workspace handle or username Secretmodel — AES-256-GCM encrypted, scoped to global / workspace / repo / env- Secret hierarchy resolution in CI executor: Env → Repo → Workspace → Global
- Full CRUD APIs for workspaces, workspace members, secrets at all scope levels
- WorkspacesPage, WorkspacePage, WorkspaceSettingsPage (settings + members)
- Workspace switcher in sidebar header
- Create repo: workspace owner selector
- RepoSecretsPage — write-only secret management per repo and per environment
- Sidebar "Secrets" nav item in repo context
Completed — Phase 3B (Unified Operational Timeline)
GET /api/v1/repos/:owner/:repo/timeline— merges commits, pipeline runs, and deployments into a single chronological feedRepoTimelinePageat/repos/:owner/:repo/timeline— vertical event feed with type filter tabs- Sidebar "Timeline" nav item between Environments and Settings
- Event types: commit (SHA, message, author), run (status, ref, duration), deployment (env, status, SHA)
Completed — Phase 3A (Environment model + deployment tracking)
Environmentmodel per repo (name, URL, protection rules)Deploymentmodel (sha, ref, status, triggered_by, run_id link)- Full CRUD API for environments
- Deployment trigger + status update API
- NATS event publishing for
deployment.*subjects EnvironmentsPageper repo — environment cards with live deployment status- Deployment history per environment
- Sidebar "Environments" nav item
- Repo page deployment status badges
Completed — Phase 2C (CI Legibility)
PipelinesPage— real cross-repo runs feed with status filter tabsRepoPipelinesPage— repo-scoped runs list at/repos/:owner/:repo/pipelinesPipelineRunPage— run detail with topological DAG visualization + step log viewerPipelineWaterfall— rewritten to accept realPipelineJob[]data withneedsgraph- Dashboard CI widget — live recent runs replacing "coming soon" placeholder
- Command palette — pipeline run results + Pipelines quick-nav
GET /api/v1/pipelines/runs— cross-repo recent runs endpoint- Dashboard
recentRuns[]field added
Planned — Phase 3 (GitOps + Observability + Federation)
- GitOps controller with reconciliation loops
- Environment model + deployment tracking
- Unified operational timeline (commits + deployments + CI failures merged)
- Drift detection and sync status
- Deployment promotion workflows (dev → staging → production)
- Rollback visualization and one-click rollbacks
- Canary and blue/green deployment support
- ActivityPub / ForgeFed federation handlers (inbox, outbox, cross-instance PRs)
- Secret management hierarchy (Global → Org → Repo → Env)
- Observability (Prometheus endpoint, health sparklines)
Planned — Phase 4
- AI diagnostics (pipeline failure root-cause analysis)
- Signed artifacts (Sigstore/Cosign)
- OCI package registry
- Secret and dependency vulnerability scanning
0.3.0 — 2026-05-11
Phase 2B complete. Full CI/CD execution backend operational.
Added — CI Orchestrator (internal/domain/ci/)
- DAG-based pipeline orchestrator (
orchestrator.go): subscribes to NATSpush.received, parses.forgebucket/workflows/*.yml, createsPipelineRun/PipelineJob/PipelineSteprecords, advances DAG onjob.completed/job.failed, recovers stale runs on startup - Docker executor (
executor.go): runs steps in isolated containers (docker run --rm), streams logs to DB and NATS viapipeline.logsubject, handlesgit archiveworkspace extraction - Runner manager (
runner_manager.go): semaphore-limited concurrent job dispatch (default 4), subscribes tojob.queued, calls executor when Docker is available - DAG engine (
dag.go): full topological sort (TopoSort) andReadyJobsfor dependency resolution - Workflow parser (
parser.go): reads.forgebucket/workflows/*.ymlfrom git ref,MatchesPushTriggerwith glob pattern support - CI types (
types.go):WorkflowFile,WorkflowJob,WorkflowStep, YAMLStringOrSliceunmarshaler
Added — CI API Handlers
GET /api/v1/repos/:owner/:repo/pipelines— list pipeline definitionsGET /api/v1/repos/:owner/:repo/runs— list pipeline runs (most recent first, limit 30)GET /api/v1/repos/:owner/:repo/runs/:runID— run detail with full job + step treePOST /api/v1/repos/:owner/:repo/runs/:runID/cancel— cancel queued or running runPOST /api/v1/repos/:owner/:repo/runs/:runID/jobs/:jobID/retry— re-queue failed/cancelled jobGET /api/v1/repos/:owner/:repo/runs/:runID/jobs/:jobID/logs— step-level log chunksGET /api/v1/repos/:owner/:repo/runs/:runID/artifacts— list artifacts for a runPOST /api/v1/repos/:owner/:repo/runs/:runID/artifacts— upload artifact (multipart, 512 MB max)GET /api/v1/repos/:owner/:repo/artifacts/:artifactID/download— artifact download with path traversal guardGET /api/v1/admin/runners— list registered runners (admin-only)POST /api/v1/admin/runners/register— register a new runner with bcrypt token hashing (admin-only)
Added — Database Models (migration 009_ci)
Pipeline— workflow definition record (name, filePath, repoId)PipelineRun— execution record (triggerRef, triggerSha, triggeredBy, status, startedAt, finishedAt)PipelineJob— single DAG node (name, image, needs JSON, status, timing)PipelineStep— single command within a job (seq, runCmd, usesAction, exitCode, timing)PipelineStepLog— append-only log chunk storage (stepId, chunkIndex, content)Runner— registered execution backend (name, labels, status, tokenHash, lastSeenAt)Artifact— build artifact (runId, repoId, name, storagePath, size, contentType)
0.2.0 — 2026-05-11
Phase 2A complete. Real-time event infrastructure and audit log operational.
Added — NATS Event Bus (internal/events/)
EventBusinterface:Publish,Subscribe,CloseNATSBus: NATS-backed implementation with auto-reconnect, max-reconnect disabledNoOpBus: silent fallback whenNATS_URLis not configured (app fully functional without NATS)New(url)factory: returnsNATSBusif URL is set,NoOpBusotherwise- Event subjects defined in
subjects.go:repo.*(created, deleted, pushed)push.receivedpr.*(opened, merged, closed)issue.*(opened, closed)pipeline.*(queued, started, succeeded, failed, cancelled)job.*(queued, started, completed, failed),pipeline.logdeployment.*,environment.*(Phase 3 stubs)audit.event
Added — WebSocket Hub (internal/api/handlers/ws.go)
GET /ws— upgrades HTTP to WebSocket (nhooyr.io/websocket)- Subscribes to all NATS subjects on connect, fans events to the client as JSON
- Optional session auth (
auth.Optionalmiddleware) — works for guests too - Phase 2B note: per-user event filtering is a planned upgrade
Added — Audit Log
AuditLogmodel (migration008_audit_log): actor, method, path, statusCode, requestBody, ipAddr, timestampAuditLogmiddleware: records every authenticated request to the DB and publishesaudit.eventGET /api/v1/audit— paginated audit log query (admin-only, filterable by actor/method/time range)
Fixed — Local development environment
DATABASE_URLwas using Docker-internal hostnamepostgres; corrected tolocalhostformake dev- Added
NATS_URL=nats://localhost:4222to.env(was missing; CI orchestrator requires it) REPO_ROOTcorrected to/tmp/forgebucket/repos(Docker path/var/lib/forgebucket/reposrequires sudo on macOS)
0.1.0 — 2026-05-11
Initial development milestone. Core Git hosting, collaboration, and frontend SPA are functional.
Added — Authentication & Security
- User registration and login with secure session cookies
- CSRF protection on all mutating routes via
X-CSRF-Tokenheader - Middleware chain: Logger → RealIP → Recoverer → CORS → CSRF → SessionAuth → RBAC → Handler
- SSH key management per user
- OIDC / OAuth2 optional integration (configurable via env)
- Scoped access tokens with optional expiration dates
- Repository deploy keys (read-only or read-write HTTP tokens)
- ENV-driven config with fail-fast validation on missing secrets
Added — Git Hosting
- Smart HTTP transport (git clone, push, pull over HTTP)
- AGit protocol support (
refs/for/push for instant PR creation without branch switching) - Branch management (list, create, delete, default branch configuration)
- Commit log and diff viewing
- Git LFS per-repository (configurable file size limits, locking)
- Branch protection rules (force-push blocking, required reviews)
- Repository visibility (public / private)
Added — Collaboration
- Pull requests (open / merged / closed states) with author tracking
- Issues (open / closed)
- Reviewer assignment (default reviewer per repo, per-PR reviewer assignment)
- Merge strategy selection per repository (merge commit / squash / rebase)
- Branching model configuration (feature / bugfix / release / hotfix prefixes)
- PR default description templates (per-repo)
- Excluded files from diffs (glob pattern configuration)
- Webhook system with event filtering (push, pull_request, issue)
- Repository member RBAC (read / write / admin roles)
Added — Frontend SPA
- React 18 + TypeScript + Vite, embedded into Go binary via
//go:embed - 20 route-level pages: Login, Register, Dashboard, Repos, CreateRepo, ImportRepo, Repo, RepoSettings, Blob, Commits, Branches, RepoIssues, RepoPRs, CreatePR, PRDetail, Starred, PRs (cross-repo), Pipelines (placeholder), Explore, Profile, Settings
- AppShell layout wrapper for all authenticated pages
- Triple-state sidebar: expanded (320px) / collapsed (56px) / mobile bottom bar
- Mobile-first responsive design (375px → 1440px)
- DiffViewer: side-by-side and unified views with syntax highlighting
- MobileComment: bottom-sheet overlay for inline code review on mobile
- TreeBrowser: repository file tree navigation
- PipelineWaterfall: placeholder pipeline visualization component
- Skeleton loading states for perceived performance
Added — Design System
- Custom semantic token palette in
frontend/src/ui/tokens.ts - Full dark/light mode support via Tailwind CSS v4
@variant dark - Brand colors:
#0052CC(light) /#3B82F6(dark) - 8px grid system (xs: 4px, sm: 8px, md: 16px, lg: 24px, xl: 32px, xxl: 48px)
- 44px minimum touch targets on all interactive elements (WCAG 2.5.5)
- Consistent border radius scale (subtle 3–8px, full 9999px)
- System font stack (Segoe UI, Roboto, sans-serif)
Added — Infrastructure
- PostgreSQL + XORM with 7 migration files covering: users, repositories, issues, SSH keys, access tokens, deploy keys, workflows, and LFS settings
- ActivityPub actor data model (FederationActor with inbox/outbox URLs and RSA key pairs) — data layer only
- Docker Compose setup for local PostgreSQL + NATS
- Makefile targets: dev, build, migrate, test, lint, docker-up
- WebSockets foundation for live logs and notifications