Skip to content

fix(sql): validate referential actions, and repair the publishing workflow#5

Merged
JustGodWork merged 2 commits into
developfrom
fix/ddl-actions-and-ci
Jul 22, 2026
Merged

fix(sql): validate referential actions, and repair the publishing workflow#5
JustGodWork merged 2 commits into
developfrom
fix/ddl-actions-and-ci

Conversation

@JustGodWork

Copy link
Copy Markdown
Owner

The two items left open after the audit follow-up. Based on #4.

Referential actions were concatenated into the DDL unvalidated

onDelete and onUpdate were upper-cased and appended verbatim to the FOREIGN KEY clause:

belongsTo("users", { key = "user_id", onDelete = "cascade, add x int" })
-> FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE, ADD X INT

This was the last unvalidated path left in the SQL builder after the operator and sort-direction whitelists, and it matters as soon as a schema is built from configuration rather than written by hand. Actions now go through a whitelist (CASCADE, RESTRICT, NO ACTION, SET NULL, SET DEFAULT) and accept the usual spellings: set null, set_null, SET NULL.

The publishing workflow fired twice per merge and could not push

Three pre-existing defects in build.yml:

Merging a PR into master triggered the workflow twice, once as a push to master and once as pull_request/closed with merged == true. The concurrency group did not collapse them because github.ref differs between the two events (refs/heads/master versus refs/pull/N/merge), so both jobs rebuilt and both raced to push the same commit.

The pull_request run could not have pushed anyway: on that event actions/checkout leaves a detached HEAD, and the bare git push fails with You are not currently on a branch as soon as dist/ has actually changed, which is the normal case.

The comment presented github.actor != 'github-actions[bot]' as the primary guard against an infinite build loop. It never fired: actions/checkout persists SUBMODULES_PAT, so the bot's push is attributed to the PAT owner, never to the bot. The only thing breaking the loop was the [skip ci] in the commit message, described in the comment as a mere "second safety net". Anyone editing that message would have re-armed the loop while believing the actor check protected them.

Fixed by keeping a single trigger (the push to master already covers a merge), making the concurrency group a constant, pushing with an explicit refspec, and dropping the check that did nothing. The comment now describes the guard that actually works.

Note

On a push to master, test.yml and build.yml both build and run the suites, so the work is duplicated. It is harmless, and it does mean the bundle is verified twice before publication, but test.yml could drop master from its push trigger if you would rather save the minutes.

Suite: 364 passing, 357 before this branch.

@JustGodWork
JustGodWork force-pushed the fix/ddl-actions-and-ci branch from e0d4492 to 62981a9 Compare July 22, 2026 00:45
@JustGodWork
JustGodWork force-pushed the fix/ddl-actions-and-ci branch from be40904 to dffbe86 Compare July 22, 2026 01:00
Both were upper-cased and concatenated straight into the FOREIGN KEY
clause, so anything in them landed in the DDL:

  belongsTo("users", { key = "user_id", onDelete = "cascade, add x int" })
  -> FOREIGN KEY (`user_id`) REFERENCES `users` (`id`)
     ON DELETE CASCADE, ADD X INT

This was the last unvalidated identifier path in the SQL builder, and it
matters as soon as a schema is generated from configuration. Actions now
go through a whitelist, on the model of safe_op and safe_dir, and accept
the usual spellings (set null, set_null, SET NULL).
Three defects in the publishing workflow, all pre-existing.

Merging a PR into master fired the workflow twice: once as a push to
master, once as pull_request/closed with merged == true. The concurrency
group did not collapse them, because github.ref differs between the two
(refs/heads/master and refs/pull/N/merge), so both jobs rebuilt and both
raced to push. The pull_request run could not push anyway: on that event
the checkout is on a detached HEAD, and a bare `git push` fails with
"You are not currently on a branch" as soon as dist/ has changed.

The pull_request trigger is gone, since the push to master already covers
the merge, the concurrency group is a constant, and the push carries an
explicit refspec.

The comment claimed the actor check was the primary loop guard. It never
fired: actions/checkout persists SUBMODULES_PAT, so the bot's push is
attributed to the PAT owner. What actually breaks the loop is the
"[skip ci]" in the commit message, which GitHub honours by not creating a
run. The check is removed and the comment says what really happens.

Open pull requests are covered by test.yml, which publishes nothing.
@JustGodWork
JustGodWork force-pushed the fix/ddl-actions-and-ci branch from dffbe86 to 1ba866b Compare July 22, 2026 01:07
@JustGodWork
JustGodWork changed the base branch from fix/audit-followup to develop July 22, 2026 01:07
@JustGodWork JustGodWork reopened this Jul 22, 2026
@JustGodWork
JustGodWork merged commit 2b2c15c into develop Jul 22, 2026
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