feat(cli): add backfill-repo-axis migration command (#23 follow-up)#37
Conversation
Add `security-scanner backfill-repo-axis` to run the repo-axis GSI1 backfill (issue #23) against the configured DynamoDB-compatible endpoint: - `--dry-run`: per-entity legacy inventory, no mutation - apply: in-place conditional backfill, per-entity inventory/backfilled/skipped/failed/remaining report, and a gate status line (exit 1 if legacy rows remain or any update failed) - dynamodb backend only; jsonl is rejected with exit 2 before any table build The backfill mutates only existing items' GSI key fields (never copies rows or writes payload data); it is idempotent across re-runs. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Code Review
This pull request introduces the backfill-repo-axis CLI subcommand to migrate legacy unsharded repository GSI1 rows to sharded partitions, along with corresponding unit tests. The feedback recommends improving CLI error handling by importing sys and directing error messages to standard error (sys.stderr) instead of standard output, updating the tests to assert on standard error, and adding a new test case to verify the failure path when the backfill operation fails.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
Address PR #37 review (gemini-code-assist): - route the non-dynamodb backend rejection message to sys.stderr so diagnostics don't mix with stdout when piping/redirecting - assert the rejection on stderr in the backend-guard test - add a test for the backfill failure path (update_item raises -> exit 1, "gate: NOT CLEAR") Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
What
Add a
security-scanner backfill-repo-axisCLI command to run the repo-axisGSI1 backfill from #23 against the configured DynamoDB-compatible endpoint
(local Dynalite /
amazon/dynamodb-local).Follow-up to #23 (merged in #34): #23 shipped the backfill mechanics
(
repo_axis_migration.backfill_repo_axis); this exposes them as an operatorcommand so the migration can actually be run on the runtime host.
Why
After #23, rows written before the change still live on the unsharded
REPO#<repo>GSI1 partition. An operator needs a one-shot, observable way tomigrate them (and to inventory first) without writing ad-hoc scripts.
Changes
cli/commands/migrate.py: newbackfill-repo-axissubcommand.--dry-run: per-entity legacy inventory, no mutation.inventory/backfilled/skipped/failed/remaining+ agate: CLEAR|NOT CLEARline; exit
1if legacy rows remain or any update failed.jsonlis rejected with exit2before any table isbuilt.
cli/app.py: register the command module.tests/test_cli_backfill_repo_axis.py(dry-run, apply, idempotentre-run, backend guard) + updated
test_cli.pyregistration-order lock.The backfill mutates only existing items' GSI key fields — never copies rows or
writes finding payload data — and is idempotent across re-runs.
Run (on the runtime host with DynamoDB-local up)
Test
uv run pytest— full suite green (626 passed)ruff(E,F,I,UP);advisory/ruffis non-blocking.Related to #23.