You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(codegen): validate every identifier before interpolation into DDL (#83)
Closes#39.
`generate_sidecar_schema` interpolated `table.name` and PK column names
directly into raw SQL via `format!()`. A table named
`posts'); DROP TABLE x;--` would be injected verbatim into the metadata
seed INSERT. The DDL generator was a SQL-injection sink wide open to
whatever the schema parser handed it.
Add a `crate::codegen::ident::validate_identifier` helper:
- Accepts `^[A-Za-z_][A-Za-z0-9_]*$` with a 63-character length cap
(Postgres' NAMEDATALEN minus null terminator).
- Returns `anyhow::Error` whose message names the offending
identifier (truncated to 60 chars for legibility) and the kind
label ("table name" / "column name") so users can find it in
their schema input.
Gate every identifier at the entry of `generate_sidecar_schema` —
every `table.name` and every `column.name` — so downstream `format!()`
sites are safe by construction. Return type becomes
`anyhow::Result<String>`.
Update call sites:
- `main.rs` Generate command: `?` propagates the error to the user.
- In-module tests: `.expect("test schema must validate")`.
- `tests/integration_test.rs`: same.
New tests in `codegen::ident::tests`:
- `valid_identifiers_pass`: 7 happy-path cases.
- `injection_strings_rejected`: 16 attack strings including the
canonical `posts'); DROP TABLE x;--`, semicolons, quotes,
comments, whitespace, non-ASCII, dots, parens.
- `overlong_identifiers_rejected`: 64-char input fails.
- `error_names_offending_identifier`: error message includes both
the bad identifier and the kind label.
`cargo clippy --all-targets -- -D warnings` clean; 42 unit tests pass
(up from 38).
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
0 commit comments