Skip to content

Fix the four open CodeQL alerts - #2

Merged
pranavms13 merged 3 commits into
mainfrom
codeql-alerts
Sep 2, 2026
Merged

pranavms13 merged 3 commits into
mainfrom
codeql-alerts

Conversation

@pranavms13

Copy link
Copy Markdown
Collaborator

Closes the four code scanning alerts open on main. Two independent fixes, one commit each.

Parse dropped column ids at the width they are stored in (#4, High)

readSchemaVersion used strconv.Atoi — a 64-bit int — and narrowed the
result to core.ColID (uint32), discarding the parse error; the dropped
unmarshal just above discarded its own error too.

This is a real defect, not a lint nit. nextColID derives the next column id
from v.Columns and v.Dropped together, so the Dropped half exists
precisely to stop an id an earlier epoch retired from being reissued (§10.5
rule 2). An entry that truncates or fails to parse silently vanishes from that
set, and the next ALTER can then hand out an id whose sidecar column still
holds the retired column's values. Sidecar columns are append-only and named by
column id, so the new column would write into the old one's history.

Now ParseUint(k, 10, 32) — the exact width of core.ColID, so a key that does
not fit is an error rather than a different number — with both errors returned
in the style of the colsJSON error above it. The write side already
round-trips safely: a uint32 always fits the int that Itoa takes.

Drop the CI token to read-only (#1, #2, #3, Medium)

build, property and frozen ran with whatever the default GITHUB_TOKEN
scope happens to be. None of them needs write — they check out, build, and run
tests. Declared permissions: contents: read once at the workflow level rather
than three times per job, so a job added later inherits read-only and has to ask
for write explicitly. sdk.yml and sdk-release.yml already declare their own,
which is why only ci.yml was flagged.

Verification

go build ./... clean and make lint passes, including the internal/model
import rule. The 80-test integration suite passes against PostgreSQL 16,
PostgreSQL 17 and MySQL 8.4 — that is where the store's coverage lives, since
internal/store has no unit tests of its own.

🤖 Generated with Claude Code

pranavms13 and others added 3 commits September 2, 2026 21:55
CodeQL flagged the conversion in readSchemaVersion, and it is a real defect
rather than a lint nit. strconv.Atoi returns a 64-bit int that was narrowed to
core.ColID (uint32), and the loop discarded the parse error while the unmarshal
above it discarded its own.

The consequence is column id reuse. nextColID derives the next id from
v.Columns and v.Dropped together, so the Dropped half exists precisely to stop
an id an earlier epoch retired from being handed out again (§10.5 rule 2). An
entry that truncates or fails to parse silently vanishes from that set, and the
next ALTER can then reissue an id whose sidecar column still holds the old
column's values. Sidecar columns are append-only and named by column id, so the
new column would write into the retired one's history.

Now parsed with ParseUint(k, 10, 32) — the exact width of core.ColID, so a key
that does not fit is an error instead of a different number — and both errors
are returned in the style of the colsJSON error just above. The write side
already round-trips safely: a uint32 always fits the int that Itoa takes.

Covered by test/integration, which is where the store's coverage lives;
internal/store has no unit tests of its own. Passes on PostgreSQL 16,
PostgreSQL 17 and MySQL 8.4.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
CodeQL opened one alert per job in ci.yml: build, property and frozen all ran
with whatever the default GITHUB_TOKEN scope happens to be, rather than a scope
the workflow states.

None of the three needs write. They check out the repository, build, and run
tests; nothing pushes, comments, or publishes. sdk.yml and sdk-release.yml
already declare their own permissions, which is why only this file was flagged.

Declared once at the workflow level instead of three times per job. That closes
all three alerts and, more usefully, means a job added to this file later
inherits read-only by default and has to ask for write explicitly.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
CodeQL opened a new high alert on the previous commit, at the write side of the
same round-trip: dropped[strconv.Itoa(int(id))]. The commit message asserted
that half was already safe because "a uint32 always fits the int that Itoa
takes". That is true on a 64-bit build and false on a 32-bit one, where int is
32 bits and a ColID above 2^31-1 converts to a negative number. Itoa would then
write a key with a minus sign that the new ParseUint on the read side rejects,
turning a silent truncation into a hard read failure of the schema version.

The alert only appeared now because ParseUint is a source the query tracks and
Atoi's int result was not, so fixing the read side is what exposed the write
side rather than what broke it.

Both conversions now widen instead of narrowing, which is safe on every
platform: FormatUint(uint64(id), 10) as the exact mirror of ParseUint(k, 10,
32), and int64 for the mask width, which is only ever written to a column and
never read back into Go.

Worth recording that 32-bit is theoretical for this project today: GOARCH=386
does not build at all, on pre-existing MaxSeqValue overflows in retention.go
that have nothing to do with schema. That makes this a latent bug rather than a
live one, and the correct conversion is free either way.

Integration suite passes on PostgreSQL 16, PostgreSQL 17 and MySQL 8.4.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@pranavms13
pranavms13 merged commit 04e842a into main Sep 2, 2026
8 checks passed
@pranavms13
pranavms13 deleted the codeql-alerts branch September 2, 2026 16:46
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.

1 participant