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/...
The cached repository decorator seeded every row returned by the list queries
and by GetByName, but only Get preloads the builder relations. Any list or
distribution request therefore cached a repository without its builder, and a
later Get by id returned builder=null, so the builder page believed the
repository had no builder.
Preload the same relations in GetByName, keep seeding only for Get, GetByName
and FindRecentlyUpdated (which now preloads as well, since it feeds the cache
prewarm), and stop seeding from the other list queries.
Verification:
- CI_DATABASE_TYPE=turso go test -parallel 1 -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./pkg/dal/repository/registry/...
- golangci-lint run --build-tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./pkg/dal/repository/registry/...
- Requested /v2/library/rrr/tags/list (GetByName) and then the repository API:
the builder is still returned for a repository that has one.
The builder container and the daemons on the host resolve the server
differently: internalEndpoint is used by syft and grype on the host, so in a
setup where the server runs on the host and the builder runs in docker it
cannot be host.docker.internal for both.
Use the previously unused internalDistributionEndpoint for the builder's
ENDPOINT and for the buildkit insecure registries, falling back to
internalEndpoint when it is not set. The dev config keeps internalEndpoint on
127.0.0.1 for the host daemons and points the distribution endpoint at
host.docker.internal.
Verification:
- go test -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./pkg/config/...
- go build -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./pkg/config/... ./pkg/background/build/...
- golangci-lint run --build-tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./pkg/config/... ./pkg/background/build/...
The builder image ships cosign v3, which uses a signing config by default and
rejects the deprecated --tlog-upload flag, so every build failed at the signing
step with "--tlog-upload=false is not supported with --signing-config or
--use-signing-config".
Pass a signing config without transparency log services instead. Sigma keeps
the generated signatures as OCI artifacts in its own registry, so nothing
should be uploaded to a public log. The key and the signing config are written
to temporary files that are removed afterwards; the key file is closed now as
well.
Verification:
- go build ./pkg/distribution/signing/...
- golangci-lint run ./pkg/distribution/signing/...
- Ran the resulting cosign v3.1.4 command (signing config, http registry,
registry token, referrers mode) from the builder image: no flag or
transparency log error, only the expected connection error to a dead
registry.
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.
The docker, podman and kubernetes runtimes started the builder container with
a sigma-builder binary, but the builder image only ships the sigma binary, so
the container failed with "executable file not found in $PATH". Run
"sigma builder" instead, and skip the YAML config load for that subcommand:
the builder takes every input from the environment and the image has no sigma
config file.
The kubernetes runtime also uses the configured builder image now instead of a
hardcoded one.
Verification:
- go build ./cmd/... ./pkg/background/build/...
- go test ./pkg/background/build/runtime/docker/...
daemon.builder.docker.sock was documented but never used: the docker client
was created from the environment only, so pointing the builder at another
engine (OrbStack, Colima, a remote host) required DOCKER_HOST.
Read the socket from the config, treat a bare path as a unix socket, and let
it win over the environment. The dev config now uses the local socket, the
published builder image, the bridge network and a host.docker.internal
internal endpoint, because the server runs on the host while the builder runs
in a container.
Verification:
- go test -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./pkg/background/build/runtime/docker/...
- golangci-lint run --build-tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./pkg/background/build/runtime/docker/...
The repository payload embeds its builder and repository reads are cached by
id and name. Creating or updating a builder left the cached copy without (or
with the old) builder, so the page that reads the repository right after the
create still got builder=null and rendered the setup form again until another
code path refreshed the cache.
Invalidate the repository cache entry once the builder transaction commits,
using RepositoryCacheInvalidator like the repository and manifest services
already do.
Verification:
- 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/service/builders/...
- Created a builder in the web UI and confirmed the run list with the build
duration chart renders right after the create.
Long running daemons poll the database for pending work every few seconds,
which drowns the debug log in "call database" entries with zero rows.
Mark those queries with a context flag: logger.WithQuietDatabaseTrace
downgrades their gorm trace log one level below debug (the new LevelTrace)
and skips the caller stack walk. log.level=trace now enables that level
instead of being an alias of debug, so the polled queries stay available
when they are actually wanted.
The builder cron query and the vulnerability claim transaction mark their
context, so their SQL only shows up when trace logging is on.
Verification:
- go test -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./pkg/logger/...
- CI_DATABASE_TYPE=turso go test -parallel 1 -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./pkg/dal/repository/builder/... ./pkg/dal/repository/registry/...
- golangci-lint run --build-tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./pkg/logger/... ./pkg/dal/repository/builder/... ./pkg/dal/repository/registry/...
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
Repositories.List is deprecated: with an empty user it forwards to
ListByAuthenticatedUser anyway, so the call was a wrapper around the API we
want, and it was silenced with a stale "nolint: staticcheck" that the
enabled linters no longer need.
Call ListByAuthenticatedUser directly. Both hit GET /user/repos and keep the
same ListOptions pagination, so the returned repositories and the existing
"owned by this account" filter are unchanged.
Verification:
- go build -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./...
- golangci-lint run --enable staticcheck --build-tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./pkg/background/...
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
The authorization token, signing key and SCM credentials handed to a build
runner were encrypted with AES-CTR, which has no integrity protection: a
tampered environment value decrypted into garbage that downstream code
would only fail on much later.
Use crypt.Seal/crypt.Open for those values. The key stays the same
per-build key derived from the builder and runner IDs, and every secret is
sealed once up front instead of inline in the env list, so a failure is
reported before the runner starts.
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/background/build/...
The daemon read the OAuth access token straight from user_3rdparty, so a
sync that ran more than two hours after the last login failed with a 401
and the reason was never surfaced: the status row said Failed with an empty
message, and nobody could tell that a token had expired.
- load and decrypt the credential, and fail with a message that tells the
user what to do when it is missing or cannot be opened
- reject non-token credentials for syncing, since listing repositories is an
API call that an SSH key or username/password cannot make
- resolve the provider base URL from scm.providers and pass it to the
GitLab and Gitea clients instead of letting them default to the hosted
endpoints
- truncate the stored error message to the column size, so a long provider
error does not fail the status update that is supposed to explain it
Verification:
- go build -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./...
Creating a builder fell back to the login OAuth token whenever the clone
credential lookup found nothing, which copied a login credential into
builders.scm_token and then into the build pod environment. The same block
logged a real database error and carried on, producing a builder with no
credentials at all.
Read only the credential store now, and fail loudly instead:
- decryptedCredential loads the row, rejects type none, and opens the sealed
token, ssh key and password before they are handed to the builder
- a missing credential returns 400 with an actionable message instead of
silently creating a credential-less builder, and other lookup errors are
returned rather than logged
Verification:
- CI_DATABASE_TYPE=turso go test -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./pkg/service/builders/...
The callback stored the access and refresh token on user_3rdparty and
re-issued the code repository sync on every login, which only worked
because the login refreshed an expiring token. Credentials now live in the
clone credential table, so the tokens have no reader left.
- drop the token update on repeated login and the token fields from both
binding-creation paths; Oauth2UserInfo no longer carries them
- stop publishing a sync task when a binding is created: there is no
credential at that point, so the task could only report a failure
- derive the GitLab and Gitea OAuth endpoints from scm.providers[].baseUrl
instead of hardcoding gitlab.com, and point Gitea at its own
/login/oauth endpoints and redirect callback
Verification:
- CI_DATABASE_TYPE=turso go test -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./pkg/service/oauth2/...
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/...
auth.credentialKey is optional, so a deployment must work without operator
input. Generate a random 32-byte key on first start and persist it in the
settings table, which keeps the credential service able to decrypt values
written by an earlier process.
- run the task right after the services are registered, before signing
- take a distributed lock around the check-then-create and re-read inside
it, otherwise two replicas starting together would generate different
keys and leave half the credentials unreadable
- when auth.credentialKey is set it is authoritative: only its length is
validated and nothing is written to the settings table
Verification:
- go test -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./pkg/app/bootstrap/...
user_3rdparty held the OAuth access and refresh token issued at login and
three different consumers read the access token from it: the code
repository daemon to list repositories, the builder to clone, and login to
issue a JWT. Access tokens expire (GitLab after two hours) and refresh
tokens were written but never read, so syncing and building silently broke
a couple of hours after the user last signed in.
Split identity from credentials:
- drop token and refresh_token from user_3rdparty, leaving a pure identity
binding, and stop auto-updating cr_last_update_timestamp so unrelated
writes no longer fake a sync
- make code_repository_clone_credentials usable: one live row per
third-party account through a (user_3rdparty_id, deleted_at) unique
constraint, wider token/password columns for the sealed values, and
UpsertCredential/DeleteCredential built on clause.OnConflict
- add UserRepository.UpsertUser3rdPartyByAccountID so a user who only ever
pastes a token still gets a binding, without duplicating rows when two
requests race
The baseline 0001 migration is edited in place for all four dialects
instead of adding an increment: fresh installs get the final schema, while
existing installations have to apply the constraint manually (documented in
the migration design notes).
Verification:
- make gormgen
- CI_DATABASE_TYPE=turso go test -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./pkg/dal/repository/coderepo/... ./pkg/dal/repository/user/...
Every consumer that needs an access token would otherwise have to resolve
the master key itself and remember to hash it before calling crypt. Keep
that knowledge in one place:
- service/credential resolves the key once at construction time:
auth.credentialKey when configured, otherwise the value the credential
bootstrap task persists in the settings table
- it fails fast when neither exists or when the configured key is shorter
than 32 bytes, because storing credentials that can never be decrypted
is worse than refusing to start
- Seal/Open delegate to crypt.Seal/crypt.Open so stored values are
authenticated
Verification:
- go test -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./pkg/service/credential/...
The source-code providers a deployment can use were implied by
auth.oauth2.*, so disabling OAuth login also disabled code repository sync
and every build that clones source code, and there was nowhere to configure
a self-hosted GitLab or Gitea at all: the gitea client was created with an
empty base URL.
Make provider capability explicit and independent from login:
- add scm.providers[] with provider and baseUrl; github and gitlab default
to their hosted endpoints, gitea and other self-hosted instances require
a base URL and are skipped with a warning when it is missing
- derive the provider list from the enabled OAuth2 providers when
scm.providers is empty, so existing configurations keep working
- expose Configuration.ResolveScmProviders and Configuration.ScmProvider
- add auth.credentialKey for the master key that encrypts SCM credentials
at rest, plus the credential.master_key settings key used as fallback
conf/config.yaml, both configuration docs and the Helm chart (values and
configmap) document the two new sections.
Verification:
- go test -run "TestConfigurationScm|TestConfigurationResolveScm" -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./pkg/config/...
- helm template test ./deploy/sigma
Encrypt/Decrypt are AES-CTR without a MAC, so a stored ciphertext can be
altered without detection. The only current caller derives a per-build key
from the builder and runner IDs, which is fine for the short-lived build
environment but cannot be used for values that outlive a process.
Add Seal/Open on top of AES-256-GCM (base64(nonce|ciphertext|tag)) next to
the existing helpers instead of changing them: the builder image still
decrypts the CTR format with crypt.Decrypt. The key is derived with
sha256 like Encrypt, so operators only deal with one key convention.
Verification:
- go test -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./pkg/utils/crypt/...
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
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
"Deactive" is not a valid English word; the standard antonym of "Active"
is "Inactive". Restore the enum value, regenerate the go-enum output,
update the CLI test expectation, sync the generated swagger enum and
x-enum-varnames, and fix the web UI request payload and label.
Note: persisted rows and API clients using the old "Deactive" value must
switch to "Inactive"; no data migration is included.
Verification:
- go build -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./...
- go vet -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./pkg/api/enums/... ./cmd/cli/...
- CI_DATABASE_TYPE=turso go test -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./pkg/server/validators/...
Update github.com/sigstore/cosign from v2.6.5 to v3.1.3 and switch the
import path in the signing bootstrap to the v3 module. go.sum also picks
up the transitive lib/pq and go.step.sm/crypto bumps.
Verification:
- go build -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./...
- go vet -tags "..." ./pkg/app/bootstrap/...
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/...
Rename the UserStatus enum value Inactive to Deactive, regenerate the
go-enum output, update the CLI test expectation and sync the generated
swagger enum and x-enum-varnames.
Verification:
- go build -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./...
- go test -tags "..." ./cmd/cli/... ./pkg/server/validators/...
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
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/...
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 ./...
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 ./...
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 ./...
Drop the coverage_test.go catch-all and distribute its cases to the test
files matching the units they exercise: logger_test.go for logger.go,
glog_test.go for glog.go, and a new trace_handler_test.go for the trace
handler.
Verification:
- go test -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./pkg/logger/
- golangci-lint run --build-tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./pkg/logger/...
Delete the checked-in ci.txt and test.txt fixtures and write them into
t.TempDir() inside the hash and compress tests, keeping the fixture content
in package constants so the expected digests stay unchanged.
Verification:
- go test -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./pkg/utils/hash/ ./pkg/utils/compress/
Move the cache, counter, lock, and workq mock files from their package
directories into a `mocks` subpackage, matching the existing service and
storage layout. Update the `//go:generate` directives to emit into
`mocks/*_mocks.go` with package `mocks`, regenerate the files, and document
the convention in AGENTS.md.
Verification:
- go test -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./pkg/infra/...
- go vet -tags "netgo,timetzdata,exclude_graphdriver_btrfs,containers_image_openpgp" ./pkg/infra/...
Add tests for SetLevel branches, source trimming, the log writer error path,
formatLogLine error branches, gorm trace logging, the Logger methods, both
Fatal helpers (via a re-exec subprocess) and the trace handler.
Split databaseTraceCall into a thin wrapper plus databaseTraceCallFrom(caller)
so the stack walk can be tested with a fake caller; the behavior is unchanged.
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.
Move pkg/storage/storage_mocks.go to pkg/storage/mocks/ (package mocks) so the
generated mock is not counted in the storage package coverage, and update the
//go:generate directive and the tests that referenced the mock.
Add tests for every context helper and for Init across disabled, http, grpc
and invalid protocol configurations, raising coverage from 21.6% to 98.6%.
This also surfaced a real bug: Init failed when tracing was enabled because
resource.Default() (schema 1.43.0) conflicted with semconv.SchemaURL
(1.26.0). Build the service name resource schemaless so Init succeeds.
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.
Raise the validators package coverage from 49.2% to 97.1% with table-driven
tests for every validation function and fold the repetitive RegisterValidation
checks in newValidator into one loop.
Move the repository mocks out of the packages under test into per-domain mocks
subpackages, update the //go:generate directives and test imports, skip the
mocks packages in the CI test matrix and drop the unused Codecov config.
Default InitializeIntegration to the turso dialect so integration tests run
locally without a PostgreSQL server.
Replace the hard-coded library namespace seed with an idempotent bootstrap
task driven by a new namespace.initialize config list, so users can declare
any number of namespaces and set the visibility of each one (public or
private). The task only creates namespaces that do not exist yet.
Remove the seed INSERT from the four 0001 migrations and wire the new config
into the example configs, the docs and the Helm chart (values + configmap).
Add an explicit TableName() for UserRecoverCode and document that the
password recovery backend is wired up (endpoints, service, repository and
generated query) but the code is never delivered to users and the web UI has
no recover pages. Track the remaining work in TODO.md.
pkg/dal/models/locker.go is dead code: it is absent from the gorm-gen model
list in pkg/dal/cmd/gen.go, has no generated query, and no migration creates
a lockers table. Locking is handled by pkg/infra/lock instead.