mirror of
https://github.com/go-sigma/sigma.git
synced 2026-10-28 13:34:34 +08:00
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
18 KiB
18 KiB
AGENTS.md
Guidance for AI agents working in the sigma repository.
Project Overview
sigma is an OCI artifact storage and distribution system written in Go. It implements the OCI Distribution Specification 1.1 and acts as a private/public container registry. It supports docker registry v2 protocol, OCI images/artifacts/sboms, security scanning, registry proxy, namespace quotas, garbage collection, image signing (cosign), and image building via docker/podman/kubernetes.
- Module path:
github.com/go-sigma/sigma - Go version: 1.27.0 (godebug default=go1.27)
- License: Apache 2.0
- Entry point:
main.go->cmd.Execute() - Default port: 3000
- Default credentials:
sigma/Admin@123
Build & Run
# Build the binary (requires CGO_ENABLED=1 for sqlite)
make build
# Run via docker
docker run --name sigma -p 3000:3000 --rm tosone/sigma:nightly-alpine
# Run locally (needs a config file, default /etc/sigma/config.yaml)
go run . server -c conf/config.yaml
# Subcommands: server, worker, builder, distribution, tools
Build tags required for tests/lint/build:
netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp
Common Commands
# Lint
make lint # runs golangci-lint + hadolint
make lint-go # golangci-lint only (timeout 10m)
# Tests (set CI_DATABASE_TYPE=sqlite3|turso|mysql|postgresql)
# Prefer turso for local unit-test verification.
CI_DATABASE_TYPE=turso go test -parallel 1 -failfast \
-tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" \
-timeout 30m ./...
# Code generation
make gormgen # regenerate gorm models/queries from DB
make swagen # format Swagger comments and regenerate skill swagger.yaml
make migration-create MIGRATION_NAME=<name> # new SQL migration
# Formatting
make sql-format # format all SQL migrations
make addlicense # add Apache license headers
# Vendor / clean
make vendor
make clean
Git Commit Messages
- Generated commit messages must use Conventional Commits and be written entirely in English, including the subject, body, footer, and verification notes.
- Include a body with what changed and why when the change needs more than a
one-line subject, and put executed validation commands under
Verification:.
Test Conventions
- Tests use
github.com/stretchr/testify/require(preferred overassert). - For DI setup in tests, construct a fresh
dig.New()container and provideconfig.Configuration{}plustestkit.NewGinbefore callingfactory{}.Initialize(digCon). - Use
testkit.NewGin()(inpkg/testkit/gin.go) to get a gin engine inTestMode; do not callgin.New()directly in tests. - Repository tests must import the target repository domain package with a
semantic
repo-prefixed alias, such asreporegistry,reponamespace, orrepouser. - Generate cryptographic keys (e.g., Ed25519) at runtime in tests; do not hardcode base64 keys.
- Tests are excluded for generated or infrastructure-only packages such as
pkg/api,pkg/dal/models,pkg/dal/query,pkg/dal/cmd,pkg/testkit,pkg/version, and variousmockssubpackages. - Some storage tests (
pkg/storage/cos,pkg/storage/oss) are skipped on PRs and require secret env vars (COS_*,OSS_*). - The
pkg/storage/...test suites are not run as automated unit tests because they depend on cloud/object-storage resources. Maintainers run them manually with real credentials. Do not run or modify these test files as part of unrelated changes. - Mocks are generated via
go.uber.org/mockinto amockssubpackage asmocks/*_mocks.gowith package namemocks(for examplepkg/service/token/mocks/token_mocks.go), and are regenerated withgo generate ./...from the//go:generatedirective on the interface file.
Code Conventions
Import aliases
- Repository package aliases use the
repoprefix followed by the domain name, such asrepouser,reponamespace,reporegistry, andrepowebhook. - Service package aliases use the
svcprefix followed by the domain name, such assvcnamespace,svcrepository,svcmanifest, andsvcaudit. - Do not use suffix-style aliases such as
userrepo,namespacesvc, orauditrepo.
Web import order (web/)
TypeScript/TSX imports are grouped into two blocks separated by a blank line, and each block is sorted alphabetically by module specifier:
- Third-party (open-source) packages.
- This repository's modules, i.e. the
@/alias and relative paths.
import axios from "axios";
import dayjs from "dayjs";
import { Link } from "react-router-dom";
import Header from "@/components/Header";
import IMenu from "@/components/Menu";
import { cn } from "@/lib/utils";
import { useTranslation } from "@/i18n/useTranslation";
- Keep the two blocks separate; do not interleave third-party and local imports.
- Sort alphabetically within each block.
Variable scope and unused parameters
- Do not shadow an outer
errwitherr := ...in nested blocks, goroutines, or deferred cleanup functions. Use assignment (err = ...) when updating the outer error is intentional, or use a short local name such asefor isolated cleanup/logging errors. - In deferred cleanup, log the cleanup error variable itself, not an unrelated
outer
err. - If a required method signature includes an unused
context.Context, name the parameter_ context.Contextin the signature. Do not add_ = ctxinside the function body just to silence unused parameter checks.
Error handling
- Use
errcode.AsType[T](err)(inpkg/server/errcode/astype.go) instead oferrors.As(err, &e)for typed error assertions. The canonical usage:errcode.AsType[errcode.ErrCode](err). - Handlers have the gin signature
func(c *gin.Context)and are registered directly on the route group. Endpoints with a typed, validated request object are wrapped viaserver.WrapRequest(h). Seepkg/server/request.go. - Return
errcode.NewHTTPError(c, ...)from handlers for structured HTTP errors.
Dependency Injection
- DI is powered by
go.uber.org/dig. Handlers declaredig.Inand request services by field. - Resolve ad hoc dependencies with
digCon.Invoke(func(deps ...) error { ... })instead of adding global container helpers. - Handler factories register routes via
handlers.Routers.Register(path.Base(reflect.TypeFor[factory]().PkgPath()), &factory{})in aninit().
Handler structure
- Each handler package (e.g.
pkg/server/handlers/systems) defines aHandlerinterface, a privatehandlerstruct embeddingdig.In, and afactory{}withInitialize(dig.Container) error. - The
systemshandler uses fieldSystemsServiceof typeservice.SystemsServiceFactory. Do not use a field namedconfig. - Routes are grouped under
consts.APIV1(i.e./api/v1).
IDs & crypto
- All application IDs must be time-ordered UUIDv7 strings.
- Generate UUIDs through
pkg/utils/uuid.NewV7String()instead of calling an external UUID package directly. pkg/utils/uuidis backed by the Go standard libraryuuidpackage.
Modernize Go
- Prefer modern Go idioms over legacy patterns. This project targets Go 1.27 and
follows the modernizations that
go fixapplies. Rungo fix ./...after a toolchain bump to keep the codebase current (usego fix -diff ./...to preview first). See commitfeat: update with go fix modernize. - Concretely, prefer:
anyoverinterface{}.- the
min/maxbuiltins over hand-written if/else comparisons. for i := range nover C-stylefor i := 0; i < n; i++loops.slices/mapsstdlib helpers (e.g.slices.Contains,slices.Sort,maps.Keys) over manual loops andsort.Slice.strings.Cut/strings.CutPrefixoverstrings.Index/HasPrefix+TrimPrefixslicing.fmt.Appendfover[]byte(fmt.Sprintf(...)).reflect.TypeFor[T]()overreflect.TypeOf.t.Context()in tests overcontext.WithCancelboilerplate.
- These are also reinforced elsewhere in this file:
log/slogfor logging (see Logging) andcontext.Contextthreaded through the call chain (see Tracing).
Configuration
- Config is loaded from YAML (default
/etc/sigma/config.yaml, override with-c). Seeconf/config.yamlfor the full schema. - Supports
sqlite3,turso,mysql,postgresql;redis(none/external); cache (inmemory/redis); workqueue (inmemory/redis/database); locker (inmemory/redis); storage (filesystem/s3/cos/oss);trace(enabled/endpoint/protocol/insecure/sampleRatio/serviceName).
Logging
- Uses the standard library
log/slog. Get the logger viaslog.Default()(global) orslog.FromContext(ctx)(context-aware, falls back to default). - Configure the level via
logger.SetLevel(levelStr)frompkg/logger— installs aslog.TextHandlerwriting to stdout withAddSource: true. - For fatal errors, use
logger.Fatal(msg, args...)frompkg/logger(logs at Error thenos.Exit(1)); do not callslog.Errorfollowed byos.Exitdirectly. - The gorm adapter
logger.ZLogger{}is wired inpkg/dal/dal.go. - Avoid re-introducing
log.Logger.WithContext(ctx)calls — they are no longer needed; slog's default global logger is used everywhere.
Tracing
- Distributed tracing is powered by OpenTelemetry. Initialization lives in
pkg/telemetry/trace.goand is invoked from each long-lived subcommand (server,worker,distribution) viatelemetry.Init(*config.GetConfig()). Thebuildersubcommand is a one-shot CLI and intentionally skips trace init. - The tracer provider is configured from the
trace:section of the config:enabled,endpoint(OTLP collector),protocol(grpcorhttp),insecure(TLS off),sampleRatio(0..1),serviceName. - Sampler is
ParentBased(TraceIDRatioBased(sampleRatio))— root spans respect the ratio, child spans always inherit the parent's sampling decision. - Propagator is W3C
TraceContext + Baggage. - Instrumentation is attached at the integration points (no manual spans in
handlers/services):
- Gin:
otelgin.Middleware(consts.AppName)is the first middleware inpkg/app/helper.go. - GORM:
tracing.NewPlugin()fromgorm.io/plugin/opentelemetry/tracingis applied to everygorm.Opensite inpkg/dal/dal.go. - Redis:
redisotel.InstrumentTracing(cli)is called inpkg/dal/redis/redis.goandpkg/infra/cache/cacher_redis.go. - Outbound HTTP (resty): the
http.Clienttransport is wrapped withotelhttp.NewTransport(...)inpkg/distribution/clients/clients.goandpkg/background/daemon/webhook/webhook.go.
- Gin:
- Always pass
context.Contextthrough the call chain so spans propagate. Do not callcontext.Background()mid-request unless you intentionally want to break the trace.
Linting rules (.golangci.yml)
- Enabled linters: asciicheck, bidichk, bodyclose, copyloopvar, cyclop (max 50), gocritic, gosec, misspell, prealloc, unconvert, unparam, varnamelen, whitespace.
- Imports ordered by: standard, blank, default,
github.com/go-sigma/sigmaprefix, dot. (enforced bygci/goimports). cyclopis disabled for*_test.go.
Project Structure
cmd/ CLI entrypoints (server, worker, builder, distribution, tools, cli)
main.go Program entry; calls cmd.Execute()
pkg/
app/ Application assembly layer
bootstrap/ Bootstrapping (dig container, signing keys, initial user)
distribution/ Distribution-only process startup
server/ Server process startup
worker/ Worker process startup
api/ HTTP/API DTOs
enums/ Shared API and configuration enums
background/ Background execution domain
builder/ Image build backends (docker, kubernetes, podman)
cronjob/ Scheduled jobs
daemon/ Background daemons (gc, scan, webhook, transfer, coderepo)
config/ Config structs & defaults
consts/ Constants (API paths, regex, HTTP codes, settings)
dal/ Data access layer
models/ GORM models
query/ Generated gorm/gen queries (do not hand-edit)
repository/ Repository layer grouped by domain
analytics/ Analytics metrics repositories
audit/ Audit log repositories
builder/ Builder repositories
coderepo/ Source code repository repositories
daemon/ Background daemon repositories
namespace/ Namespace and namespace member repositories
registry/ OCI registry repositories (artifact/blob/repository/tag)
setting/ System setting repositories
user/ User repositories
webhook/ Webhook repositories
migrations/ SQL migrations per DB (mysql/postgresql/sqlite3)
redis/ Redis client
server/
request.go Handler wrap + request binding/validation
errcode/ Error types, AsType generic, HTTP error mapping
handlers/ HTTP handlers grouped by domain
<domain>/
handler.go Handler interface + factory + route registration
handler_test.go Factory/DI test
<action>.go Individual route handlers
middlewares/ authn, authz, etag, extractor, healthz, metrics
validators/ Request validators (gin binding)
service/ Business logic layer (interfaces + impls + mocks)
password/, token/ Auth helpers
authz/ Authorizer, permission, resolver, cache
distribution/ OCI distribution protocol domain
clients/ Distribution/proxy clients
reference/ Image reference helpers
signing/ Cosign signing integration
infra/ Infrastructure modules
cache/ Cache implementations
lock/ Locker implementations
registry/ Generic factory/implementation registries
timewheel/ Time wheel module
workq/ Work queue implementations
logger/ slog setup + glog adapter
testkit/ Test helpers (NewGin, CI database setup)
telemetry/ OpenTelemetry tracer provider init + shutdown
utils/ Misc utilities
version/ Build-time version info (set via -ldflags)
conf/ Example config files & TLS certs
deploy/sigma/ Helm chart
build/ Dockerfile and entrypoint for server/builder image targets
docs/ VitePress documentation site
e2e/ End-to-end test scripts
tools/skill/ External AI/CLI agent skills and packaged API specs
Directory rules:
- New repository code must be added to the matching
pkg/dal/repository/<domain>package instead of the repository root. - Handler package names must match their directory names.
- Handlers should not import
pkg/background/*directly; expose background behavior through the service layer unless the code is an explicit startup or boundary adapter.
CI Workflows (.github/workflows/)
- lint.yml: Go 1.27 + Bun web build + golangci-lint v2.15.0 + hadolint on
build/Dockerfile. Triggers onmain/devPRs. - test.yml: Go 1.27 + Bun web build; runs application tests on PostgreSQL and database tests on
sqlite3,turso,postgresql, andmysql. Uses MySQL 8.0, Postgres 15, Redis 7, and rs3 services. Uploads coverage to Coveralls. - govulncheck.yml: runs the pinned
go tool govulncheck(with the project build tags) to scan for known reachable vulnerabilities, writing the report to the job summary. Non-blocking (continue-on-error): findings are reported but do not fail the workflow. Triggers ondevpush/PR. - e2e.yml, image-build.yml, gh-pages.yml: end-to-end, image build, docs deploy.
Important Files
pkg/server/request.go-RequestHandlerFunc/WrapRequest+BindRequestrequest binding/validation.pkg/server/errcode/astype.go-AsType[T error]generic helper.pkg/server/errcode/xerrors.go-NewHTTPError,ErrCode,HTTPErrCodeInternalError.pkg/dal/dig.go- DI registration for all repositories + authorizer.pkg/server/handlers/systems/handler.go- canonical handler example.pkg/testkit/gin.go-NewGin()test helper.pkg/telemetry/trace.go- OpenTelemetry tracer provider init + shutdown.Makefile- all build/lint/test/generation targets..golangci.yml- lint configuration.
Things to Avoid
- Do not use
errors.Asdirectly when anerrcode.AsType[T]variant exists. - Do not introduce non-UUID or unordered UUID generators. Use
pkg/utils/uuid.NewV7String()so new IDs remain UUIDv7 and time-ordered. - Do not add a
configfield to handler structs; use the appropriate service factory field (e.g.,SystemsService). - Do not import the repository root package in tests; import the target repository domain package with a semantic alias.
- Do not hand-edit generated files under
pkg/dal/query/*.gen.go; regenerate withmake gormgen. - Do not create new test files that hardcode cryptographic material; generate at runtime.
- Do not import
github.com/rs/zerolog; uselog/slog. - Do not use
interface{}; useany(see Modernize Go). - Do not add
log.Logger.WithContext(ctx)calls; use the context directly orslog.FromContext(ctx). - Do not call
telemetry.Initfrom thebuildersubcommand — it is a one-shot CLI and uses env vars, not the YAML config. - Do not create manual spans in handlers/services; rely on the auto-instrumentation in
pkg/telemetryandpkg/app/helper.go.