Skip to content

fix: widen credential_prop.value column to an unbounded text type#4393

Open
reinkrul wants to merge 4 commits into
masterfrom
fix/4392-credential-prop-value-text-type
Open

fix: widen credential_prop.value column to an unbounded text type#4393
reinkrul wants to merge 4 commits into
masterfrom
fix/4392-credential-prop-value-text-type

Conversation

@reinkrul

@reinkrul reinkrul commented Jul 6, 2026

Copy link
Copy Markdown
Member

Fixes #4392

Problem

credential_prop.value was capped at varchar(500) — an arbitrary limit picked when the table was introduced (storage/sql_migrations/001_credential.sql). credentialSubject property values have no natural max length, so on PostgreSQL (and MySQL/SQL Server) inserting a VC whose property value exceeds 500 characters fails with a database error.

Fix

Widens the column to an unbounded text type via a goose Go migration.

ALTER TABLE ... ALTER/MODIFY COLUMN syntax to change an existing column's type is not portable across the databases this project supports (Postgres, MySQL, SQL Server/Azure SQL, SQLite), and SQLite has no such syntax at all (it also doesn't enforce varchar length, so nothing needs to change there). Rather than templating the SQL with per-dialect env vars, this uses goose's own mechanism for exactly this case — a Go migration (goose.NewGoMigration + goose.WithGoMigrations) that runs plain Go instead of SQL, so the right statement is picked with an ordinary map/switch on dbType.

The migration lives in storage/sql_migrations/011_credential_prop_value_type.go, colocated with the other numbered migrations (Migration011CredentialPropValueType), which engine.go registers via goose.WithGoMigrations.

It runs via RunTx (not RunDB): RunDB needs to acquire a second connection from the pool to run the migration, which deadlocks against SQLite's single-connection pool (db.SetMaxOpenConns(1), set for correctness reasons elsewhere in engine.go) — this is a documented edge case in goose itself. RunTx reuses the connection/transaction goose already holds, avoiding it.

Testing

  • go test ./storage/....
  • Manually verified against real Postgres and MySQL containers, through the actual engine startup path (migrations + insert): a 2000-character value that would have failed under the old varchar(500) cap inserts cleanly.
  • Ran the e2e-tests/oauth-flow/rfc021 suite against SQL Server with a locally built image from this branch — full VC issuance/storage/status-list/discovery/OAuth/revocation flow passed, confirming the migration applies cleanly on startup there too.

The column was capped at varchar(500), an arbitrary limit picked when the
table was introduced. credentialSubject property values have no natural
max length, so on PostgreSQL (and other non-SQLite backends) inserting a
VC with a longer property value fails.

ALTER COLUMN syntax to change an existing column's type differs per
database and SQLite has none at all, so the new migration builds the
statement from per-dialect env vars and ships a "_sqlite.sql" no-op
counterpart at the same version, swapped in automatically by engine.go.

Fixes #4392

Assisted by AI
@qltysh

qltysh Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Qlty


Coverage Impact

⬇️ Merging this pull request will decrease total coverage on master by 0.02%.

Modified Files with Diff Coverage (2)

RatingFile% DiffUncovered Line #s
Coverage rating: D Coverage rating: D
storage/engine.go100.0%
New Coverage rating: F
storage/sql_migrations/011_credential_prop_value_type.go0.0%67-82
Total16.7%
🤖 Increase coverage with AI coding...
In the `fix/4392-credential-prop-value-text-type` branch, add test coverage for this new code:

- `storage/sql_migrations/011_credential_prop_value_type.go` -- Line 67-82

🚦 See full report on Qlty Cloud »

🛟 Help
  • Diff Coverage: Coverage for added or modified lines of code (excludes deleted files). Learn more.

  • Total Coverage: Coverage for the whole repository, calculated as the sum of all File Coverage. Learn more.

  • File Coverage: Covered Lines divided by Covered Lines plus Missed Lines. (Excludes non-executable lines including blank lines and comments.)

    • Indirect Changes: Changes to File Coverage for files that were not modified in this PR. Learn more.

reinkrul added 3 commits July 6, 2026 14:10
ALTER TABLE syntax to change an existing column's type isn't portable across
databases, and goose already ships a mechanism for exactly this: Go migrations
registered via WithGoMigrations, which run plain Go instead of SQL. That's a
much smaller diff than templating the SQL with per-dialect env vars and
shipping a parallel "_sqlite.sql" no-op file, so replace that approach here.

Uses RunTx (not RunDB): the latter needs to acquire a second connection from
the pool, which deadlocks against SQLite's single-connection pool.

Assisted by AI
Colocates it with the other numbered migrations (naming now matches: 011_...),
and includes the migration number in the function names so they're easy to
match against the version passed to goose.NewGoMigration. References the
originating issue in the doc comment.

Assisted by AI
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PostgreSQL: credential_prop.value column too small, fails when adding VCs with long property values

1 participant