Skip to content

Releases: gombit-dev/gombit

v0.8.0

Choose a tag to compare

@github-actions github-actions released this 19 Oct 07:17
7ea62f1

v0.8.0

Manual: action required

  • Breaking. Every write refuses a float that is not finite (+Inf, -Inf, NaN), or beyond a float32 field's range, with a 422 on that field. (floats-must-be-finite, behavior, #449)

    It was stored on PostgreSQL and SQLite (and a 500 on MySQL). Code
    that stored a non-finite float on purpose in a column it never
    returns as JSON now gets a *database.ValidationError: store NULL
    (a pointer or sql.NullFloat64) instead. A row that already stores
    one keeps working for partial updates of other columns and for an
    admin edit that leaves the column alone, but a generic Save of it
    is a 422 on that field until the column is set to a finite value or
    NULL (docs/database.md § Floats).

  • Breaking. upgrade is a framework command, and a reserved management-command name. (reserved-upgrade-command, cli, #341)

    An app that registers its own upgrade command loses it: the
    framework's is added first, and Cobra resolves to it. Rename the
    app's command (and its internal/<pkg>/commands.go registration).

  • Breaking. gombit contract app refuses a framework replaced by a fork, and a go.mod the go command refuses. (contract-app-fork-unresolved, cli, #341)

    A replace of github.com/gombit-dev/gombit by another module used
    to report the fork's version as the framework's; it is now
    unresolved, like a local path. A go.mod requiring the framework
    twice, or replacing it twice with different targets, is an error.
    The replace that counts is the one the go command applies to the
    required version (an exact-version replace over an every-version
    one; a replace of another version does not apply), so a go.mod
    carrying several replaces can report a different version, or
    resolve where it used to fail. Build the contract against a
    framework release.

  • Breaking. Every write refuses text a column cannot store the same way on every driver (a NUL byte, invalid UTF-8, more than the column holds), with a 422 on that field. (text-storable-on-every-driver, behavior, #444)

    It was a 500 on PostgreSQL or MySQL and stored on SQLite. A
    size:n / varchar(n) column holds n characters, a text column
    65,535 bytes (MySQL's TEXT), and an unsized primary-key, indexed,
    unique or defaulted string 191 characters (MySQL's varchar(191)),
    now on every driver: PostgreSQL and SQLite stored more. A row that
    already stores such text stays editable through the admin, its form
    included, and partial updates (database.ScopeEdit with
    database.StoredValues judges only what an edit changes); a generic
    Save of it is a 422 on that field until the value is shortened or
    cleaned (docs/database.md § Text).

  • Breaking. database.Search takes a context and returns an error, like FilterEq: a search term with a NUL byte or invalid UTF-8 is a 422. (database-search-takes-context, api, #444)

    Code calling database.Search(q, columns, term) no longer builds:
    call database.Search(ctx, q, columns, term) and return its error.
    Run gombit generate to update an app's generated handler.gen.go,
    which also answers a get of an id over MaxInt64 with a 404.

  • A scaffolded internal/product/handler.go answers an id over MaxInt64 with a 404; an app scaffolded before answers a 500 on PostgreSQL. (scaffolded-get-id-over-maxint64, scaffold, #444)

    The handler is app-owned, so gombit generate does not update it. In
    its get, parse the id with strconv.ParseUint(input.ID, 10, 63)
    instead of 64: PostgreSQL's bigint cannot bind a larger id, and no
    row holds one. Apply the same to any hand-written handler that
    parses a uint id.

  • Breaking. With auth enabled, an app that registers the session routes, the auth-* session operation IDs or the AuthSession / AuthRevokeResult schema names fails at startup: the framework registers them. (auth-session-names-reserved, api, #335)

    With GOMBIT_JWT_SECRET set, registering a route at GET or
    DELETE {prefix}/auth/sessions or DELETE {prefix}/auth/sessions/{id}
    (through Huma or the raw Gin router), an operation
    auth-list-sessions, auth-revoke-session or auth-revoke-sessions,
    or a type Huma names AuthSession, DataListAuthSession,
    AuthRevokeResult or DataAuthRevokeResult now panics when the app
    starts. Drop the app's own session routes, which the framework's
    replace, or rename them. A resource named Session
    (gombit make resource Session) does not collide.

  • Breaking. With auth enabled, a GOMBIT_JWT_REFRESH_TTL shorter than GOMBIT_JWT_ACCESS_TTL fails config validation, so the app does not start. (refresh-ttl-at-least-access-ttl, config, #335)

    • Configuration: GOMBIT_JWT_REFRESH_TTL: some values are now refused.
    • Configuration: GOMBIT_JWT_ACCESS_TTL: some values are now refused.

    The refresh token's lifetime is the session's, and an access token
    must not outlive its session: it would stop authenticating when the
    session ends while its exp, expires_in and access cookie still
    promised more. Config validation (config.Load / Validate) and
    auth.NewService refuse that pair; equal TTLs are fine. Raise
    GOMBIT_JWT_REFRESH_TTL to at least GOMBIT_JWT_ACCESS_TTL, or
    lower GOMBIT_JWT_ACCESS_TTL. An access token also ends with its
    session: it stops authenticating when the session expires, not only
    when it is revoked, so a token issued before the upgrade under the
    old TTLs stops at its session's expiry, before its exp.

Automatic: applied by the upgrade tooling

  • gombit new records the app's upgrade baseline in a gombit: block of gombit.yaml. (record-upgrade-baseline, scaffold, action record-baseline, #341)

    An app generated before records none, and is detected as scaffold
    version 0. gombit upgrade baseline --write records it.

Informational

  • config.Load reads a .env file whole: a line longer than 64 KiB no longer silently stops it, so the assignments after one now apply. (dotenv-long-lines, config)

    Before, the first line over 64 KiB ended the read without an
    error, and every variable after it kept its process-environment
    or default value. If a .env has such a line, check the values
    set after it.

  • An admin relation field on a string key stores the string sent, byte for byte; a JSON number for it is a 422. (admin-relation-string-keys, behavior, #452)

    A numeric-looking key ("123", "007") was stored corrupted. A
    client that sends a string key as a JSON number now gets a 422 on the
    field, as for any string field: send it as a string. A uuid key must
    be the canonical form, as a uuid field (no braces, with hyphens).
    An integer key still accepts a number or its digits as a string.

  • An admin PATCH writes only the columns it (or a model hook) changed, never associations, and answers 404 for a row deleted meanwhile. (admin-patch-writes-changes-only, behavior, #450)

    It used to save the whole loaded row: a concurrent change to another
    column was reverted, a deleted row came back, and has_many
    children were written back. database.ScopeEdit now narrows any
    Select("*") update of the scoped row the same way.

  • On Windows, gombit make resource replaces files with a POSIX-semantics rename, so a file open with delete sharing no longer blocks it. (make-resource-windows-posix-rename, cli, #341)

    On a volume that refuses that rename (FAT or exFAT, a network share
    or mapped drive, a \\wsl$ path, or Windows before 10 1709) it keeps
    its previous plain rename and its rollback.

  • database.KeepStoredZeros is deprecated: use database.ScopeEdit with database.StoredValues. (keep-stored-zeros-deprecated, api, #444)

    ScopeEdit judges an edit of a loaded row on what it changes,
    compared after the model's hooks, for the text check as well as
    stored zero instants. KeepStoredZeros keeps working.

  • MapPersistError and MapLoadError answer a database data exception (a value too long or out of range for its column) with a 422 instead of a 500. (data-exceptions-are-422, behavior, #444)

    PostgreSQL 22001, 22003, 22007, 22008, 22021, 22P05 and MySQL 1264,
    1265, 1292, 1366, 1406 (database.IsDataException). A uint list
    filter over MaxInt64 is a 422 too.

  • Session management in both auth modes: GET {prefix}/auth/sessions lists the user's active sessions; DELETE {prefix}/auth/sessions/{id} and DELETE {prefix}/auth/sessions?scope=others|all revoke them. (auth-session-management, api, #335)

    auth.Service gains ListSessions (returning []auth.AuthSession),
    RevokeSession, RevokeAllSessions and ErrSessionNotFound. Cookie
    mode clears the session cookies when a request ends its own session
    (docs/auth.md § Sessions).

  • A refresh token revoked by logout or session revocation is a 401 that no longer revokes the user's other sessions; only an already-rotated token counts as reuse. (refresh-reuse-only-rotated-tokens, security, #335)

  • POST /auth/refresh answers 500, not 401, when the database fails while the rotation locks the user's row (a deadlock, a lock timeout, a lost co...

Read more

v0.7.1

Choose a tag to compare

@github-actions github-actions released this 06 Oct 14:42
34369fa

What's Changed

  • fix(cache): treat a non-positive janitor interval as no janitor by @leo-aa88 in #553
  • fix(cache): refuse to overflow in the memory driver's Increment by @leo-aa88 in #555
  • fix(framework): answer unknown paths and recovered panics with D10 errors by @leo-aa88 in #556
  • fix(contract): answer an unencodable response with a D10 500 by @leo-aa88 in #559
  • fix(database): log through the app's logger, never with parameter values in the SQL by @leo-aa88 in #557
  • fix(contract): saturate PageOffset instead of wrapping by @leo-aa88 in #558
  • fix(database): never store a decimal changed; respond with the stored row by @leo-aa88 in #560
  • fix(database): refuse timestamps and dates no driver can store and return, on every write by @leo-aa88 in #562
  • bench: refresh microbench snapshot after PERF-6 by @leo-aa88 in #565

Full Changelog: v0.7.0...v0.7.1

v0.7.0

Choose a tag to compare

@github-actions github-actions released this 04 Oct 20:45
4386171

What's Changed

  • fix: stop crash redelivery after MaxAttempts by @SamCT86 in #525
  • Add @Brunotlps as a code owner by @leo-aa88 in #533
  • [STORAGE-1] Storage abstraction by @leo-aa88 in #522
  • fix: retry each failed job once per invocation by @SamCT86 in #534
  • [STORAGE-2] Local and in-memory drivers by @leo-aa88 in #523
  • build(deps): bump github.com/go-sql-driver/mysql from 1.8.1 to 1.10.1 by @dependabot[bot] in #540
  • build(deps): bump github.com/mattn/go-sqlite3 from 1.14.28 to 1.14.52 by @dependabot[bot] in #536
  • [STORAGE-3] S3-compatible driver by @leo-aa88 in #524
  • [STORAGE-4] Secure upload API primitives by @leo-aa88 in #526
  • fix(admin): reject composite primary keys at Register by @tnalbant in #542
  • [STORAGE-5] Public/private objects and signed URLs by @leo-aa88 in #527
  • test: make staticcheck nil guards explicit by @SamCT86 in #541
  • [STORAGE-6] Direct browser-to-storage upload flow by @leo-aa88 in #528
  • fix(config): reject trust-all proxy CIDR combinations in production by @rupayon123 in #518
  • [STORAGE-7] Object metadata and lifecycle/cleanup semantics by @leo-aa88 in #529
  • fix(benchmarks): name raw k6 summaries by framework and benchmark by @leo-aa88 in #543
  • [MODEL-8] Storage-backed field kinds (file, image) by @leo-aa88 in #531
  • fix(benchmarks): judge the host before publishing a snapshot as canonical by @leo-aa88 in #544
  • fix(benchmarks): record the CRUD protocol per unit by @leo-aa88 in #545
  • fix(framework): deliver the handler's timeout response when HTTP.RequestTimeout is set by @leo-aa88 in #546
  • fix(framework): give stop hooks their own shutdown budget by @leo-aa88 in #547
  • fix(framework): keep text after a stray "<" when a value also has a real tag by @leo-aa88 in #548
  • fix(framework): count requests that panic in the HTTP metrics by @leo-aa88 in #549
  • [STORAGE-8] Admin integration for storage-backed fields by @leo-aa88 in #532
  • fix(framework): give every embedded HTML page the browser security policy by @leo-aa88 in #550
  • fix(framework): release what New and Run opened when they fail by @leo-aa88 in #551
  • docs: bring the README, agent guides, and user docs up to date with storage by @leo-aa88 in #561

New Contributors

Full Changelog: v0.6.1...v0.7.0

v0.6.1

Choose a tag to compare

@github-actions github-actions released this 29 Sep 07:28
6d45595

What's Changed

  • fix(cli): accurate help text and reserve every framework command name by @leo-aa88 in #447
  • docs: bring reference docs up to date with v0.6.0 by @leo-aa88 in #429
  • fix: avoid repeated client generation for unchanged specs by @charle-z in #517
  • docs: bring the README, changelog, and docs index up to v0.6.0 by @leo-aa88 in #428
  • docs: add the Claude Code onboarding skill by @Brunotlps in #520
  • fix: preserve caller options in DispatchAt by @SamCT86 in #521

New Contributors

Full Changelog: v0.6.0...v0.6.1

v0.6.0

Choose a tag to compare

@github-actions github-actions released this 28 Sep 08:09
617b487

What's Changed

  • [CHAOS-1] Deterministic fault-test primitives and a faulting database driver by @leo-aa88 in #417

Full Changelog: v0.5.0...v0.6.0

v0.5.0

Choose a tag to compare

@github-actions github-actions released this 27 Sep 20:51
7d1feb5

What's Changed

  • [JOBS-1] Job contract and registry by @leo-aa88 in #407
  • fix: data race in db check's timed-out database read by @leo-aa88 in #413
  • [JOBS-2] Queue abstraction and drivers (sync, in-memory, Redis) by @leo-aa88 in #408

Full Changelog: v0.4.0...v0.5.0

v0.4.0

Choose a tag to compare

@github-actions github-actions released this 27 Sep 11:49
6b7f2c7

What's Changed

  • fix: derive admin fields from the generated contract by @leo-aa88 in #399
  • feat: plan and gate destructive schema changes before a migration is written (SCHEMA-2) by @leo-aa88 in #402
  • feat: first-class table rename that keeps rows and the registry valid (SCHEMA-3) by @leo-aa88 in #403
  • feat: gombit db lint and repair, with acknowledgements persisted in migrations (SCHEMA-4) by @leo-aa88 in #404
  • feat: deletion is the database's deletion — hard delete (SCHEMA-5) by @leo-aa88 in #405
  • [SCHEMA-6] gombit db check — single schema-integrity gate by @leo-aa88 in #406

Full Changelog: v0.3.1...v0.4.0

v0.3.1

Choose a tag to compare

@github-actions github-actions released this 26 Sep 11:34
941d598

What's Changed

  • docs: bring the changelog and reference docs up to v0.3.0 by @leo-aa88 in #401

Full Changelog: v0.3.0...v0.3.1

v0.3.0

Choose a tag to compare

@github-actions github-actions released this 26 Sep 08:30
aeffafc

What's Changed

  • feat: share one logical field vocabulary by @leo-aa88 in #392
  • feat: generate uuid, json, date, and float fields by @leo-aa88 in #393
  • feat: field constraints for default, bounds, length, and regex by @leo-aa88 in #394
  • feat: generate email, url, slug, and ip fields by @leo-aa88 in #395
  • feat: one-to-one, nullable, and self-referential relations by @leo-aa88 in #396
  • feat: configurable integer or UUID primary keys by @leo-aa88 in #397
  • feat: duration, time of day, and enum labels by @leo-aa88 in #398
  • ci(release): install Node deps before the release test gate by @leo-aa88 in #400

Full Changelog: v0.2.1...v0.3.0

v0.2.1

Choose a tag to compare

@github-actions github-actions released this 24 Sep 03:09
bbb8317

What's Changed

  • build(deps): bump gorm.io/driver/postgres from 1.6.2 to 1.6.3 by @dependabot[bot] in #380
  • fix(bench): key run-crud rows and provenance on (framework, benchmark) (#361) by @Brunotlps in #371
  • fix: migration model-tracking papercuts — --forget-model + make-resource determinism (#300) by @leo-aa88 in #378
  • feat: data-preserving column rename for makemigrations — --rename (#299) by @leo-aa88 in #379

Full Changelog: v0.2.0...v0.2.1