28 Commits
Author SHA1 Message Date
Tosone 8bee9b9b8c fix(builders): serve the stored log of stopped runs
The runner log endpoint returned the stored log only for succeeded and failed
runs, so a stopped build showed an empty log. Serve it for stopped runs too:
the build coordinator stores the log regardless of how the run ended.

Verification:
- go build -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./pkg/server/handlers/builders/... ./pkg/service/builders/...
- CI_DATABASE_TYPE=turso go test -parallel 1 -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./pkg/service/builders/...
- golangci-lint run --build-tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./pkg/server/handlers/builders/... ./pkg/service/builders/...
2026-10-28 16:48:36 +08:00
Tosone 194076bbe5 fix(distribution): resolve distribution handlers once at startup
Every /v2/*path request dispatched through the dig container: distribution.All
called factory.Initialize(c, digCon) and each factory ran digCon.Invoke to get
its handler. dig containers are not safe for concurrent use, so concurrent
pulls and pushes raced on the container's internal maps and crashed the
process with "concurrent map read and map write".

Split the factory contract into Prepare, which resolves the handler once at
startup, and Initialize, which only dispatches the request. handlers.
InitializeDistribution runs distribution.Prepare before registering the route,
so request goroutines no longer touch dig.

Verification:
- go build ./pkg/server/... ./pkg/app/...
- CI_DATABASE_TYPE=turso go test -parallel 1 ./pkg/server/handlers/...
- golangci-lint run ./pkg/server/handlers/...
- Sent 200 concurrent and then 180 mixed concurrent /v2 requests to a freshly
  built server: the process kept serving and the log had no fatal error.
2026-10-28 16:15:32 +08:00
Tosone 5c05104720 feat(coderepos): read branches on demand and track provider push time
A sync listed the branches of every repository it saw, one API call per
repository per page. For an account with a few hundred repositories that
alone exhausts the GitHub rate limit, and the result was stale the moment a
branch was pushed.

Store the provider's push time instead, and read branches only when a build
form asks for them:

- the daemon reconciles repositories and owners only; github, gitlab and
  gitea no longer page through branches, diffBranch is gone, and the
  code_repository_branches table and model are dropped from the baseline
- CodeRepository gains pushed_at, filled from github pushed_at, gitlab
  last_activity_at (falling back to updated_at) and gitea updated_at, and
  the list orders by it so "most recently active" means the provider's view
  rather than our own row's updated_at, which every sync touched
- ListCodeRepositoryBranches and GetCodeRepositoryBranch resolve the
  binding, the decrypted token and the repository, then query the provider,
  so branch names are always current; a repository id is user input and is
  now checked against the caller's binding instead of exposing another
  account's repository
- the list response also stops filling updated_at from created_at

Existing installations need the new column and the dropped table applied by
hand, as documented for the baseline migration edit.

Verification:
- go build -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./...
- CI_DATABASE_TYPE=turso go test -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./pkg/dal/repository/coderepo/... ./pkg/service/coderepos/... ./pkg/server/handlers/coderepos/... ./pkg/background/daemon/coderepo/...
- make gormgen
- make swagen
2026-10-27 22:47:28 +08:00
Tosone 93de2dac54 fix(coderepos): stop the credential validator from panicking
PUT /api/v1/coderepos/{provider}/credential returned a 500 and logged
"http: panic serving ...: Bad field type *string": validator's max tag
panics when it is combined with required_if on a pointer field. A token
request leaves ssh_key, username and password nil, required_if passes
because the condition is false, the chain moves on to max, and max receives
the nil *string without dereferencing it.

Enforce the size limits in the service instead, next to the required checks
that already lived there, and keep required_if on the request so an
incomplete body is still rejected before it reaches the service. Swagger no
longer advertises maxLength for these fields.

Add a binding test that drives the three credential shapes through
server.WrapRequest, which is the path the panic was reached on.

Verification:
- CI_DATABASE_TYPE=turso go test -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./pkg/server/handlers/coderepos/... ./pkg/service/coderepos/...
- golangci-lint run --build-tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./pkg/api/... ./pkg/service/coderepos/... ./pkg/server/handlers/coderepos/...
- make swagen
2026-10-27 21:26:39 +08:00
Tosone a80519d86f feat(coderepos): configure a per-provider SCM credential
Users had no way to supply their own access token: the only credential in
play was the OAuth token captured at login, which expires and which the
builders then copied into their own table. The clone credential table
existed but had no write path, so every lookup fell back to that token.

Give each provider an explicit credential:

- GET/PUT/DELETE /api/v1/coderepos/{provider}/credential plus
  POST .../credential/validate; the read endpoint returns a masked token and
  "has" flags, never the secret
- UpsertCodeRepositoryCredential validates a token against the provider,
  resolves the account id from it, ensures the third-party binding exists
  (409 when the account already belongs to another user) and seals
  token/ssh_key/password before storing them
- only token credentials can list repositories: ssh and username/password
  are clone credentials, so validate reports validated=false for them and
  no sync is queued
- ListCodeRepositoryProviders returns the configured providers joined with
  the caller's binding, credential and last sync state, so a provider that
  is configured but not linked yet is still offered by the UI
- fix the AccountID and UpdatedAt mistakes in the user3rdparty response,
  which dereferenced a nil pointer and reported the creation time twice
- regenerate the coderepos and user repository mocks and the operator
  swagger spec

Verification:
- make gormgen
- make swagen
- CI_DATABASE_TYPE=turso go test -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./pkg/service/coderepos/... ./pkg/server/handlers/coderepos/...
2026-10-27 21:07:37 +08:00
Tosone 187f5c4d97 refactor(server)!: remove the embedded MCP server
Sigma shipped three overlapping ways to operate a remote server: the
embedded MCP server, sigma-cli, and the sigma-api-operator skill. All
three wrapped the same HTTP API, yet each covered a different subset:
user CRUD existed only in the CLI, system-* only in MCP, and builders,
daemons, webhooks, validators, code repositories and tokens were
reachable only through raw HTTP. MCP was disabled by default and still
carried 1246 lines of production code plus 606 lines of tests to
maintain that partially overlapping surface.

Keep two surfaces instead: sigma-cli for execution and the skill for
API discovery.

- delete pkg/server/mcp and its mcp-go dependency, which also drops the
  jsonschema-go, jsonschema/v6 and uritemplate/v3 transitives
- drop ConfigurationMCP, its defaults and the authz/audit skipper
  bypasses that existed only to let the MCP endpoint bypass both
- remove the mcp section from conf/config*.yaml, docs/configuration.md,
  and the Helm chart values and configmap
- replace docs/mcp.md with docs/cli.md covering sigma-cli login, global
  flags, per-resource commands, jq composition and agent usage
- make sigma-cli the preferred path in the sigma-api-operator skill and
  rebuild its examples around the resources the CLI does not wrap yet,
  using the paths and request schemas from swagger.yaml

Lint was already red on dev for an unrelated reason: golangci-lint
v2.13.0 vendors golang.org/x/tools v0.49.0, which only decodes export
data version 4, so every import of a Go 1.27.2 standard library package
failed typecheck with "export data version 5 is greater than maximum
supported version 4". Bump to v2.15.0 (x/tools v0.52.0) and fix the two
modernize findings it reports for Go 1.27's strings.CutLast.

- .github/workflows/lint.yml: golangci-lint v2.13.0 -> v2.15.0, and
  document the export data constraint next to the pin
- pkg/authz/resolver.go, pkg/logger/logger.go: replace LastIndex slicing
  with strings.CutLast
- bump github.com/docker/cli v29.9.0 -> v29.9.1

BREAKING CHANGE: the `mcp` configuration section and the /api/v1/mcp
endpoint are gone. Use sigma-cli or the REST API for automation.

Verification:
- go build -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./...
- go vet -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./...
- golangci-lint v2.15.0 run --build-tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./... (0 issues)
- golangci-lint config verify
- go test -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./pkg/authz/... ./pkg/logger/... ./cmd/cli/... ./pkg/app/... ./pkg/background/build/...
- go test -run TestConfiguration -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./pkg/config/...
- go mod tidy
- make swagen
- helm template sigma ./deploy/sigma
- bun run docs:build
- make build
- make build-cli
2026-10-21 19:33:07 +08:00
Tosone 7b98fc29c0 refactor(server): simplify handler wrapping and request binding
Remove the unused Wrap/WrapHandle helpers and the HandlerFunc type; route
registration now passes handler method values directly. Drop the
unreachable application/x-www-form-urlencoded and multipart/form-data
branches in bindBody since every bound endpoint is JSON, and merge
adapter.go into request.go. Add tests for the query/param mapping error
paths, the nil-validator path, and non-JSON bodies, raising the package
coverage to 100%.

Verification:
- go build -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./...
- go vet -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./pkg/server/
- CI_DATABASE_TYPE=turso go test -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./pkg/server/...
- go tool cover -func: pkg/server 100.0% of statements
2026-10-07 21:07:06 +08:00
Tosone 7ad608c2f8 feat(handler): protect a user's own status and role
Reject self status or role changes with 403 in the user update handler,
and make the user service persist role updates so administrators can still
manage other users' roles.

Verification:
- go build -tags "..." ./pkg/service/users/... ./pkg/server/handlers/users/...
2026-10-04 16:35:04 +08:00
Tosone 3958a6b61d docs(swagger): align handler API annotations with implementation
Fix and complete Swagger annotations for the HTTP handlers so the
generated OpenAPI spec matches the registered routes and request
types:

- Correct path parameter types from number/int64 to string, since all
  resource IDs are UUID strings.
- Fix wrong router paths and methods (builders, coderepos, tags,
  webhooks, users, validators) and add missing path parameters.
- Fix request/response schema references (builder runner list, oauth2
  callback, webhook get/log) and a few summary/description typos.
- Add annotations for previously undocumented endpoints: artifacts,
  analytics, builder runner actions, and user self/signup/recovery.
- Rename the users and coderepos path parameters to user_id/repo_id and
  align the route registrations and request struct tags accordingly;
  mark BuilderRunnerItem.Log as swaggertype string so swag can parse it.
- Regenerate tools/skill/sigma-api-operator/swagger.yaml. The
  distribution handlers are intentionally left undocumented.

Verification:
- go test -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./pkg/server/handlers/users/ ./pkg/server/handlers/coderepos/ -run TestInitialize -count=1
- go tool swag fmt && go tool swag init --output tools/skill/sigma-api-operator --outputTypes yaml
- go build -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./pkg/server/handlers/... ./pkg/api/...
- gofmt -l pkg/server/handlers pkg/api
2026-10-03 21:51:37 +08:00
Tosone 20af519812 fix(handler): log original error instead of rebuilding it
Replace `errors.New(utils.UnwrapJoinedErrors(err))` with the original `err`
in slog error logging so the logged value keeps its error chain for
`errors.Is`/`errors.As` classification. Also drop the duplicated `err`
attribute in the namespace handlers.

Verification:
- go build -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./pkg/server/handlers/...
2026-10-03 21:14:08 +08:00
Tosone 1fefe15ea5 refactor(test): use t.Context in unit tests
Replace context.Background() with t.Context() so test contexts are
canceled when the test ends, which surfaces leaked background work. The
pkg/storage suites are intentionally left unchanged because they run
manually against cloud resources.

Verification:
- go vet ./...
2026-10-03 16:20:36 +08:00
Tosone 2cc50352ce refactor(clients): propagate request context through registry clients
Thread the caller context through ClientsFactory.New and
Clients.AuthToken so proxied blob and manifest requests keep
cancellation and trace propagation instead of starting from
context.Background(). Regenerate the mock and update callers and tests.
Document the intentionally background contexts in the one-shot builder
CLI.

Verification:
- go generate ./pkg/distribution/clients/... (no diff)
- go vet ./...
2026-10-03 16:20:36 +08:00
Tosone c6b0f93ff4 refactor: apply go fix modernizations
Adopt modern Go and stdlib idioms surfaced by the modernize analyzer:
promote embedded fields in struct literals, and replace hand-written
equivalents with maps.Copy, min, atomic.Int64, new(expr) and
slices.SortStableFunc.

Verification:
- go fix -diff ./... (no remaining changes)
- go vet ./...
2026-10-03 16:20:36 +08:00
Tosone 9ec5d37b28 refactor(server): move request validators under server
pkg/validators is the gin request-validation layer: it registers gin's
binding.Validator and is used by the HTTP handlers, so move it to
pkg/server/validators where the rest of the HTTP layer lives.

The only non-server consumer was pkg/background/daemon, which called
validators.Initialize() even though the worker never uses gin binding
validation. Drop that call so the worker does not depend on the server
package; the server still initializes validators through
handlers.Initialize.
2026-09-27 14:57:02 +08:00
Tosone fb7f20e8c4 refactor(service): move service mocks into per-domain mocks subpackages
Move every pkg/service/<domain>/*_mocks.go into pkg/service/<domain>/mocks/
(package mocks) so generated mocks are no longer part of the packages under
test and stop depressing their coverage. Update the //go:generate directives
and the tests that referenced the mocks.
2026-09-27 12:37:00 +08:00
Tosone 9cdeabcb2b test(handlers): add handler unit tests for four under-tested packages
Cover webhooks, builders, coderepos and daemons handler packages with
gomock-based tests that assert both the happy paths and the error and
authorization branches:

- webhooks: create/list/get/put/delete, ping, log list/get/delete/resend
- builders: builder CRUD plus runner list/get/run/rerun/stop/log guards
- coderepos: list/get/owners/branches/resync/providers/user3rdparty
- daemons: all 32 gc-* endpoints across blob/tag/repository/artifact

Package statement coverage after this change: webhooks 43.6%, builders
63.7%, coderepos 73.4%, daemons 86.9% (previously ~3-5%).

Verification:
CI_DATABASE_TYPE=turso go test -parallel 1 -failfast   -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp"   -timeout 30m ./pkg/server/handlers/webhooks/... ./pkg/server/handlers/builders/...   ./pkg/server/handlers/coderepos/... ./pkg/server/handlers/daemons/...
gofmt -w <new test files> && golangci-lint run --new
2026-09-14 20:36:36 +08:00
Tosone f677ad3f5f docs: complete placeholder doc comments across the codebase
Replace every `// <Identifier> ...` placeholder doc comment with a real
description of the declared symbol. 276 comments in 71 files were rewritten:
149 top-level placeholders first, then a follow-up scan caught another 127
indented ones (interface methods and const blocks) that a column-anchored
match had missed.

Comments now open with the declared identifier and record the actual
contract - behaviour, side effects, error/panic conditions, units, HTTP
endpoints, lock keys and cache prefixes - instead of restating the
signature. Three placeholders carried a stale identifier and were corrected
to the declared symbol: ConfigurationDatabasePostgresql, GetImageRef and
Initialize.

No functional change: every modified line is a comment.

Verification:
- grep '^\s*//\s+\S+\s+\.\.\.\s*$' over all *.go returns no matches
- gofmt -l over the changed files prints nothing
- CGO_ENABLED=1 go build -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./... exits 0
- git diff HEAD -U0 filtered to non-comment changed lines is empty
2026-09-14 14:58:06 +08:00
Tosone 2adc82c54b refactor(cache): rename package from cacher to cache
Rename the cache module package name from `cacher` to `cache` across all files, including:
- Update all internal package declarations
- Fix import aliases in dependent modules
- Correct mockgen package configuration
- Update cache interface and error type references

This aligns the package naming with the module directory structure and improves consistency across the codebase.
2026-09-13 14:48:06 +08:00
Tosone ac246ad163 feat(authn): throttle failed logins per username
Add a cache-backed failed-login throttler for Basic auth. Once a username
reaches auth.loginRateLimit.maxFailures failures within window, each
subsequent authentication attempt is delayed by delay (capped at 5s)
instead of being rejected; the counter is cleared on a successful login.

- add pkg/infra/ratelimit backed by pkg/infra/cache (inmemory/redis) with
  Count/Incr/Reset and Prometheus metrics for failures, delayed attempts,
  and cache errors
- wire ConfigurationAuthLoginRateLimit with defaults (5 failures, 5m window,
  1s delay) and document it in conf/config.yaml
- integrate the limiter into the authn middleware, counting all Basic
  failures including /v2/, and honor request context cancellation
- add unit tests for threshold behavior, delay, and cancellation
- mark the login rate limit item complete in TODO.md
2026-09-13 12:54:54 +08:00
Tosone c9ac979c95 refactor: migrate json encoding to json/v2 package across codebase
Replace all usages of standard encoding/json with encoding/json/v2 and jsontext
where applicable, update decoding logic to use json.UnmarshalRead and
json.MarshalWrite instead of manual encoder/decoder instances.

Verification:
go test -race ./pkg/... ./cmd/...
2026-08-27 14:28:01 +08:00
Tosone e0b9ea7dfe refactor(gc): consolidate garbage collection persistence
Replace the per-type GC rule, runner, and record tables with shared
daemon_gc_rules, daemon_gc_runners, and daemon_gc_records tables.

Store the GC daemon type on rules and use a unified resource field for
tag names, repository names, and artifact/blob digests. Keep existing
service and HTTP APIs intact by mapping the shared persistence models to
the existing type-specific contracts.

Regenerate GORM queries and mocks, and update GC repository tests.
2026-08-01 20:32:52 +08:00
Tosone 65797a1c5f test(distribution): simplify GET request test helper
Remove the unused method parameter from the shared distribution test
context
helper and align import grouping in related handler tests.

Verification:
make lint-go
2026-08-01 20:32:52 +08:00
Tosone bcfdd63b56 test(distribution): add handler coverage for registry endpoints
Add isolated GoMock-based tests for repository catalog, tag listing,
blob
downloads, manifest referrers, and blob upload lifecycle handlers.

Generate the Authorizer mock used by distribution handler tests and
retain its
go:generate directive.
2026-08-01 20:32:51 +08:00
Tosone acd82367b2 refactor(di): centralize service and handler registration
Convert service constructors into dig provider functions and let the service
bootstrap layer call Provide directly. This keeps dig container usage at the
composition boundary instead of passing the container into each service package.

Register API handlers explicitly from the handlers package and remove the blank
imports that previously triggered handler init functions from cmd/imports.go.
Handler packages now expose Initialize functions that are invoked by the root
handler registration flow.

Also update related tests and document the analytics service interface methods.

Verification:
go test -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./pkg/service/... ./pkg/app/bootstrap
go test -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./pkg/server/handlers/... ./pkg/app/server ./pkg/app/distribution ./cmd/...
2026-08-01 20:32:50 +08:00
Tosone ac2e582a2c refactor(service): standardize service wiring
Rename domain-specific service interfaces to package-local Service interfaces
and update handler, MCP, and test dependencies to use the new names.

Merge service parameter structs into implementation structs where possible,
including token service construction, and add explicit DI registration helpers
for token service wiring.

Also simplify authorizer dependency construction and regenerate service mocks
with stable mock type names.

Verification:
CI_DATABASE_TYPE=turso go test -p 1 -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./pkg/service/...
go test -p 1 -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./pkg/server/mcp ./pkg/server/handlers/...
go test -p 1 -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./pkg/service/token ./pkg/server/middlewares/authn ./pkg/background/buildrunner ./pkg/app/bootstrap
golangci-lint run --build-tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./pkg/service/... ./pkg/server/mcp ./pkg/server/handlers/... ./pkg/authz
golangci-lint run --build-tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./pkg/service/token ./pkg/server/middlewares/authn ./pkg/background/buildrunner ./pkg/app/bootstrap
git diff --check -- pkg/service pkg/server pkg/authz
git diff --check -- pkg/service/token pkg/app/bootstrap pkg/background/buildrunner pkg/server/middlewares/authn
2026-08-01 20:32:50 +08:00
Tosone 6269552efd test(mcp-server): add comprehensive unit tests for MCP server
Add complete test suites covering helper utilities, authorization logic, core tooling, and business functionality for the MCP server implementation.

Verification:
go test -tags "test" ./pkg/server/mcp/...
2026-08-01 20:32:50 +08:00
Tosone 73496fc5fe test(handlers): expand HTTP handler coverage
Add route registration tests for the major handler packages and behavior tests
for analytics and validator endpoints.

Rewrite the reusable artifact, tag, user authentication, webhook, and
distribution health tests using the current Gin, service mock, and dependency
injection patterns. Remove the migrated Echo and legacy testkit.DB test code.

Verification:
go test -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./pkg/server/handlers/...
golangci-lint run --build-tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./pkg/server/handlers/...
git diff --check -- pkg/server/handlers
2026-08-01 20:32:49 +08:00
Tosone c4ecfa80d9 chore: initial commit 2026-08-01 20:32:49 +08:00