# Changelog All notable changes to ForgeBucket are documented here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). Versions follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html). --- ## [Unreleased] ### Planned — Phase 4 (Intelligence + Artifacts) - AI failure diagnosis (pipeline failure root-cause analysis via Claude API) - AI deployment risk scoring - Signed artifacts (Sigstore/Cosign) - SBOM generation (CycloneDX/SPDX) - OCI container registry - Secret scanning (commit-level pattern detection) - Dependency vulnerability scanning - Cross-instance pull requests (ForgeFed ActivityPub extension) --- ## [0.9.0] — 2026-05-12 Phase 3F complete. ForgeBucket is now a first-class ActivityPub node — interoperable with Mastodon, Forgejo, and any fediverse server. ### Added — ActivityPub Federation (`internal/domain/federation/`) - **`GET /.well-known/webfinger`** — resolves `acct:user@domain` to the actor URL; returns `application/jrd+json` - **`GET /users/{username}`** — returns a JSON-LD actor document (`Person` type) including public key object for HTTP signature verification - **`POST /users/{username}/inbox`** — receives and dispatches inbound ActivityPub activities; HTTP signature verification enforced in production (skipped in `DEBUG=true` mode for local testing) - **`GET /users/{username}/outbox`** — serves an `OrderedCollection` (summary on page 0, paginated `OrderedCollectionPage` on page ≥ 1, 20 activities per page) - **`GET /users/{username}/followers`** — stub `OrderedCollection` (zero items; social graph in Phase 4) - **`GET /users/{username}/following`** — stub `OrderedCollection` ### Added — HTTP Signatures (`internal/domain/federation/signatures.go`) - `Sign(req, keyID, privateKeyPEM)` — signs outgoing HTTP requests with RSA-SHA256; covers `(request-target)`, `host`, and `date` headers - `Verify(r, db, instanceURL)` — parses `Signature` header, resolves sender's public key (local `FederationActor` first, then network fetch via `FetchActor`), verifies RSA-SHA256 digest ### Added — Actor Lifecycle (`internal/domain/federation/actor.go`) - `GetOrCreate` — lazily creates a `FederationActor` for a local user; generates a fresh RSA-2048 key pair and derives `InboxURL`, `OutboxURL`, `APID` from `INSTANCE_URL`; stable across requests - `ActorJSON` — returns the JSON-LD document shape expected by all ActivityPub clients - `APID(instanceURL, username)` — canonical `{instanceURL}/users/{username}` helper ### Added — Follow / Accept Flow (`internal/domain/federation/inbox.go`) - Incoming `Follow` activities are auto-accepted: remote actor is fetched (or retrieved from cache), an `Accept` activity is signed and delivered to their inbox asynchronously - Both the inbound `Follow` and outbound `Accept` are persisted to `FederationActivity` for audit ### Added — Remote Actor Cache (`internal/domain/federation/remote.go`) - `FetchActor` — HTTP GET with `Accept: application/activity+json`, extracts inbox URL and public key PEM, stores in `RemoteActor` table to avoid repeated fetches - `DeliverActivity` — marshals activity JSON, signs the request, POSTs to recipient inbox with 15-second timeout ### Added — Database Models (migration `014_federation`) - `FederationActivity` — append-only log of all inbound and outbound activities: `ActorAPID`, `Type`, `ObjectJSON`, `Direction` (inbound/outbound), `RemoteActor`, `Published` - `RemoteActor` — cache for remote actor documents: `APID` (unique), `InboxURL`, `PublicKey`, `FetchedAt` --- ## [0.8.0] — 2026-05-12 Phase 3E complete. Prometheus metrics, structured health checks, and per-repo operational health are operational. ### Added — Prometheus Metrics (`internal/observability/`) - `GET /metrics` — Prometheus text format endpoint (standard root-level path for k8s/Prometheus scraping) - `GET /health` — upgraded from static `{"status":"ok"}` to a structured liveness response: `{"status":"healthy","checks":{"database":"ok","nats":"ok"},"version":"0.8.0"}` Returns HTTP 503 when any dependency is degraded - `internal/observability/metrics.go` — metric definitions: - `forgebucket_http_requests_total{method,path,status}` — counter - `forgebucket_http_request_duration_seconds{method,path}` — histogram (Prometheus default buckets) - `forgebucket_pipeline_runs_total{status}` — counter (succeeded/failed/cancelled), pre-initialized to 0 - `forgebucket_deployments_total{status}` — counter (pending/success/failure/cancelled), pre-initialized to 0 - `forgebucket_active_pipeline_runs` — gauge (in-flight runs) - `internal/observability/health.go` — `Check(db, bus)` pings PostgreSQL and calls `bus.Healthy()` - HTTP instrumentation middleware inserted after `Recoverer`, before `CORS` — records every request - Path normalization prevents label cardinality explosion: `/repos/alice/myrepo/runs/42` → `/api/v1/repos/:owner/:repo/runs/:id` - NATS metric watcher subscribes to `pipeline.>` and `deployment.>` and increments counters ### Added — Per-Repo Operational Health (`GET /api/v1/repos/{owner}/{repo}/health`) - Returns a JSON summary for the repo page operational header: - `ciPassRate7d` — fraction of pipeline runs that succeeded in the last 7 days - `totalRuns7d` — total run count in the last 7 days - `latestRun` — most recent `PipelineRun` record - `latestDeployments` — one entry per environment showing latest deploy (envName, status, sha, finishedAt) - `openDriftCount` — GitOpsConfigs in `drifted` state - `openPRCount` — open pull request count ### Added — EventBus `Healthy() bool` - Added to the `EventBus` interface; `NATSBus` returns `nc.IsConnected()`; `NoOpBus` returns `true` ### Changed — Middleware chain - `observability.Middleware()` added between `Recoverer` and `CORS` (applies to all requests including `/health` and `/metrics`) --- ## [0.7.0] — 2026-05-12 Phase 3D complete. Git is now the source of truth for environment deployment state. ### Added — GitOps Controller (`internal/domain/gitops/`) - `controller.go` — starts as a background goroutine; subscribes to `push.received`, `deployment.succeeded`, `deployment.failed`; runs a periodic reconciliation ticker (interval configurable via `GITOPS_RECONCILE_INTERVAL`); recovers stale `syncing` configs to `drifted` on startup - `drift.go` — `CheckDrift` calls `git rev-parse` via the existing git domain wrapper; `handlePush` queries all GitOpsConfigs matching the pushed branch and evaluates drift; `periodicCheck` iterates configs whose `SyncInterval` has elapsed; publishes `environment.drift_detected` when drift is found - `reconciler.go` — `TriggerSync` creates a `Deployment` record and publishes `deployment.started` (same lifecycle path as manual deployments, `TriggeredBy="gitops"`); `handleDeploymentSucceeded` resolves open drift events and marks config `synced` for both GitOps and manual deployments; `handleDeploymentFailed` reverts to `drifted` ### Added — GitOps HTTP API (`internal/api/handlers/gitops.go`) All routes live under `/api/v1/repos/{owner}/{repo}/environments/{envName}/gitops/`: - `GET /gitops` — current GitOpsConfig or 404 if not configured - `PUT /gitops` — idempotent upsert (branch, autoSync, syncInterval) - `DELETE /gitops` — remove config without deleting deployments - `POST /gitops/sync` — manual reconciliation trigger; creates deployment record - `GET /gitops/drift` — current sync status: syncStatus, desiredSha, actualSha, isDrifted - `GET /gitops/drift/history` — paginated drift event log (newest first) - `POST /gitops/drift/{driftID}/acknowledge` — acknowledge without syncing ### Added — Database Models (migration `013_gitops`) - `GitOpsConfig` — links environment to a branch; tracks `DesiredSHA`, `ActualSHA`, `SyncStatus` (`unknown/synced/drifted/syncing`), `AutoSync`, `SyncInterval`, `LastCheckedAt` - `GitOpsDriftEvent` — append-only drift record: `DesiredSHA`, `ActualSHA`, `SyncStatus` (`drifted/synced/acknowledged`), `DetectedAt`, `ResolvedAt` ### Added — Supporting Changes - `git.RevParse(repoPath, ref)` — new function in `internal/domain/git/binary.go` used by `CheckDrift` to resolve branch HEAD SHA - `events.DeploymentEvent` + `events.DriftEvent` types added to `internal/events/types.go` - `EnvironmentHandler.publishDeployEvent` updated to use shared `events.DeploymentEvent` so the GitOps controller can unmarshal deployment lifecycle events correctly - `GITOPS_RECONCILE_INTERVAL` env var (default `300`s); `0` disables the periodic ticker - `ArtifactRoot` config field + `ARTIFACT_ROOT` env var --- ## [0.6.0] — 2026-05-12 Phase 3C complete. Multi-tenant workspaces and a full secret management hierarchy operational. ### Added — Workspaces - `Workspace` model (migration `011`): globally unique handle, display name, description, avatarUrl - `WorkspaceMember` model: owner/admin/member roles per workspace - Repository `workspace_id` column (optional; null = personal repo) - Full workspace CRUD API: `GET/POST /api/v1/workspaces`, `GET/PATCH/DELETE /api/v1/workspaces/{handle}` - Workspace member management: list, add, update role, remove - `GET /api/v1/workspaces/{handle}/repos` — repos in workspace - Workspace frontend: WorkspacesPage, WorkspacePage, workspace switcher in sidebar header - Workspace owner selector in repo create flow ### Added — Secret Management (`internal/api/handlers/secret.go`) - `Secret` model (migration `012`): `Scope` (global/workspace/repo/env), `ScopeID`, `Name`, `EncryptedValue` (AES-256-GCM, never returned by API) - Unique constraint on (scope, scope_id, name) - CRUD at all scope levels: - `GET/POST/DELETE /api/v1/admin/secrets` (global, admin-only) - `GET/POST/DELETE /api/v1/workspaces/{handle}/secrets` (workspace-scoped) - `GET/POST/DELETE /api/v1/repos/{owner}/{repo}/secrets` (repo-scoped) - `GET/POST/DELETE /api/v1/repos/{owner}/{repo}/environments/{envName}/secrets` (env-scoped) - `ResolveSecretsForRun(db, repoID, workspaceID, envID, sessionSecret)` — hierarchy resolution for CI executor: Env > Repo > Workspace > Global - CI executor updated to inject resolved secrets as Docker `--env` flags - RepoSecretsPage — write-only UI, values never displayed after creation - Sidebar "Secrets" nav item in repo context --- ## [0.5.0] — 2026-05-11 Phases 3A and 3B complete. Environments, deployments, and the operational timeline are operational. ### Added — Environments + Deployments (Phase 3A) - `Environment` model (migration `010`): repoId, name, URL, protectionRules (JSON) - `Deployment` model: envId, repoId, sha, ref, status lifecycle (`pending → in_progress → success/failure/cancelled`), triggeredBy, description, runId link - CRUD API for environments: `GET/POST /environments`, `GET/PATCH/DELETE /environments/{envName}` - Deployment API: `GET/POST /environments/{envName}/deployments`, `PATCH /environments/{envName}/deployments/{id}/status` - NATS events published on status transitions: `deployment.started`, `deployment.succeeded`, `deployment.failed` - `EnvironmentsPage` — environment cards each showing latest deployment status, SHA, actor, and time since deploy; deployment history per env - Sidebar "Environments" nav item in repo context - Repo page deployment status badges (latest deploy per env at a glance) ### Added — Unified Operational Timeline (Phase 3B) - `GET /api/v1/repos/{owner}/{repo}/timeline` — merged chronological feed of commits, pipeline runs, and deployments; default 60 events, max 200 - `RepoTimelinePage` at `/repos/:owner/:repo/timeline` — vertical event feed with type filter tabs (all / commits / runs / deployments) - Sidebar "Timeline" nav item between Environments and Settings - Answers "what changed before things broke?" without navigating between separate pages --- ## [0.4.0] — 2026-05-11 Phase 2C complete. CI results are legible in the UI; the dashboard is an operational command center. ### Added — Pipeline Visualization - `PipelinesPage` — cross-repo pipeline runs feed with status filter tabs (all / running / failed / succeeded) - `RepoPipelinesPage` — repo-scoped runs list at `/repos/:owner/:repo/pipelines` - `PipelineRunPage` — run detail with topological DAG visualization using real `PipelineJob[]` + `needs` graph; step log viewer (collapsible per step, ANSI color, auto-scroll with lock toggle) - `PipelineWaterfall` — rewritten to accept live job data instead of static mock stages - `GET /api/v1/pipelines/runs` — cross-repo recent runs for the dashboard ### Added — Dashboard CI Command Center - Dashboard CI widget replaced "coming soon" with live recent pipeline runs - Dashboard `recentRuns[]` field added to the `/api/v1/dashboard` response ### Added — Command Palette Wiring - Pipeline run results surfaced in command palette results - "Pipelines" quick-nav action --- ## [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 NATS `push.received`, parses `.forgebucket/workflows/*.yml`, creates `PipelineRun/Job/Step` records, advances DAG on `job.completed/failed`, recovers stale runs on startup - Docker executor (`executor.go`): steps run in isolated containers (`docker run --rm`), logs stream to DB and NATS via `pipeline.log`, workspace extracted via `git archive` - Runner manager (`runner_manager.go`): semaphore-limited (default 4 concurrent), subscribes to `job.queued`, skips gracefully if Docker is unavailable - DAG engine (`dag.go`): `TopoSort`, `ReadyJobs` - Workflow parser (`parser.go`): `.forgebucket/workflows/*.yml` from git ref, `MatchesPushTrigger` with glob branch patterns; `StringOrSlice` YAML unmarshaler ### Added — CI API Handlers - `GET /api/v1/repos/:owner/:repo/pipelines` — pipeline definitions - `GET /api/v1/repos/:owner/:repo/runs` — pipeline runs (newest first) - `GET /api/v1/repos/:owner/:repo/runs/:runID` — run detail with job + step tree - `POST /api/v1/repos/:owner/:repo/runs/:runID/cancel` - `POST /api/v1/repos/:owner/:repo/runs/:runID/jobs/:jobID/retry` - `GET /api/v1/repos/:owner/:repo/runs/:runID/jobs/:jobID/logs` — step log chunks - `GET/POST /api/v1/repos/:owner/:repo/runs/:runID/artifacts` - `GET /api/v1/repos/:owner/:repo/artifacts/:artifactID/download` — path-traversal guarded - `GET/POST /api/v1/admin/runners` — runner list + registration (admin-only, bcrypt token) ### Added — Database Models (migration `009_ci`) - `Pipeline`, `PipelineRun`, `PipelineJob`, `PipelineStep`, `PipelineStepLog` - `Runner` (name, labels, status, tokenHash, lastSeenAt) - `Artifact` (runId, repoId, name, storagePath, size, contentType) ### Changed — Git HTTP handler - `parseAndCheckBody` replaces `checkProtectionsFromBody` — now also returns parsed `refUpdate` structs for publishing `push.received` after each successful receive-pack --- ## [0.2.0] — 2026-05-11 Phase 2A complete. Real-time event infrastructure and audit log operational. ### Added — NATS Event Bus (`internal/events/`) - `EventBus` interface: `Publish`, `Subscribe`, `Close` - `NATSBus`: NATS-backed with auto-reconnect; `NoOpBus` fallback when `NATS_URL` unset - `New(url)` factory: returns `NATSBus` or `NoOpBus` - 40+ event subjects in `subjects.go` covering repo, push, PR, issue, pipeline, job, deployment, environment, and audit namespaces ### Added — WebSocket Hub - `GET /ws` — NATS wildcard subscription (`>`) fans all events to connected clients as JSON - `{ subject, payload }` envelope format - Goroutine per client with buffered send channel (64 events); slow clients drop events ### Added — Audit Log (migration `008_audit_log`) - `AuditLog` model: actorId, actorName, method, path, statusCode, ipAddress, userAgent - Middleware records every POST/PUT/PATCH/DELETE in the protected route group - Writes DB row + publishes `audit.event` asynchronously (never blocks the response) - `GET /api/v1/audit` — paginated, filterable by actor/method/since (admin-only) --- ## [0.1.0] — 2026-05-11 Initial development milestone. Core Git hosting, collaboration, and frontend SPA functional. ### Added — Authentication & Security - User registration and login with secure session cookies - CSRF protection via double-submit cookie pattern (`X-CSRF-Token`) - SSH key management per user - OIDC / OAuth2 optional integration - Scoped access tokens with optional expiration - Repository deploy keys (read-only or read-write) - ENV-driven config with fail-fast on missing secrets ### Added — Git Hosting - Smart HTTP transport (clone, push, pull over HTTP) - AGit protocol (`refs/for/` push for instant PR creation) - Branch management, commit log, diff viewing - Git LFS per-repository (configurable file size limits) - Branch protection rules (force-push blocking) - Repository visibility (public / private) ### Added — Collaboration - Pull requests (open / merged / closed) with author tracking - Issues (open / closed) - Reviewer assignment (default reviewer per repo, per-PR overrides) - Merge strategy selection per repository (merge / squash / rebase) - Branching model configuration (feature / bugfix / release / hotfix prefixes) - PR default description templates + excluded-files configuration - Webhook system with event filtering (push, pull_request, issue) - Repository member RBAC (read / write / admin) ### Added — Frontend SPA - React 18 + TypeScript + Vite, embedded into Go binary via `//go:embed` - 20 route-level pages covering auth, dashboard, repos, code, PRs, issues, and settings - Triple-state sidebar: expanded (320px) / collapsed (56px) / mobile bottom bar - Mobile-first responsive design (375px → 1440px) - DiffViewer (side-by-side + unified), MobileComment (bottom-sheet), TreeBrowser ### Added — Design System - Custom semantic token palette in `frontend/src/ui/tokens.ts` - Full dark/light mode via Tailwind CSS v4 `@variant dark` - 8px grid system; 44px minimum touch targets (WCAG 2.5.5) - System font stack (Segoe UI, Roboto, sans-serif) ### Added — Infrastructure - PostgreSQL + XORM with migrations 001–007 - ActivityPub actor data model (FederationActor) — data layer only - Docker Compose for local PostgreSQL + NATS - Makefile: dev, build, migrate, test, lint, docker-up --- [Unreleased]: https://github.com/forgeo/forgebucket/compare/v0.9.0...HEAD [0.9.0]: https://github.com/forgeo/forgebucket/compare/v0.8.0...v0.9.0 [0.8.0]: https://github.com/forgeo/forgebucket/compare/v0.7.0...v0.8.0 [0.7.0]: https://github.com/forgeo/forgebucket/compare/v0.6.0...v0.7.0 [0.6.0]: https://github.com/forgeo/forgebucket/compare/v0.5.0...v0.6.0 [0.5.0]: https://github.com/forgeo/forgebucket/compare/v0.4.0...v0.5.0 [0.4.0]: https://github.com/forgeo/forgebucket/compare/v0.3.0...v0.4.0 [0.3.0]: https://github.com/forgeo/forgebucket/compare/v0.2.0...v0.3.0 [0.2.0]: https://github.com/forgeo/forgebucket/compare/v0.1.0...v0.2.0 [0.1.0]: https://github.com/forgeo/forgebucket/releases/tag/v0.1.0