Skip to content

test(database): exercise #440 stdout-leak guard + SQL backfill for #351 admin group (closes #545, #546)#579

Open
cristim wants to merge 2 commits into
feat/multicloud-web-frontendfrom
test/db-coverage-gaps
Open

test(database): exercise #440 stdout-leak guard + SQL backfill for #351 admin group (closes #545, #546)#579
cristim wants to merge 2 commits into
feat/multicloud-web-frontendfrom
test/db-coverage-gaps

Conversation

@cristim
Copy link
Copy Markdown
Member

@cristim cristim commented May 20, 2026

Summary

Hardens two database regression tests that did not actually exercise the code they claimed to guard, plus a SQL-level backfill for the #351 admin-group assignment.

Fixes

Migration

New migration 000053_backfill_admin_group_ids (up + down). Verified 000053 is free on base (highest prior is 000052 from the MFA PR).

Test plan

Closes #545, #546.

Summary by CodeRabbit

  • Bug Fixes

    • Admin accounts now automatically have correct group assignments restored during system upgrades, ensuring no admin accounts lack proper group associations.
  • Chores

    • Improved logging output for administrative group assignment operations.

Review Change Stack

cristim added 2 commits May 20, 2026 18:37
The #440 stdout-leak fix routed the per-user admin messages to the stdlib
logger (stderr) but left the group_ids backfill line in assignAdminGroupAndWarn
on fmt.Printf, which writes to stdout. The existing unit regression test could
not catch it because it uses an unreachable pool, so the backfill branch never
runs.

- migrate.go: switch the "Backfilled ..." line from fmt.Printf to log.Printf so
  every admin-activity message in the file stays on the stderr-bound logger.
- Add integration regression test TestAssignAdminGroup_BackfillLogsToStderr_NotStdout
  that seeds a drifted admin against a real container, runs the real
  ensureAdminUser path, and asserts the backfill message lands on stderr and
  never on stdout. Verified to fail when the line is reverted to fmt.Printf.

Refs #545
… + test

Issue #351 acceptance criterion 2 asked for a migration-level idempotent
backfill. PR #533 backfilled only in Go (assignAdminGroupAndWarn), which fires
only when RunMigrations gets a non-empty admin email. A DB restored from a
backup, or migrated without ADMIN_EMAIL set, never re-applied the backfill to
pre-existing drifted admin rows. Migration 000024's backfill is one-shot at its
version and does not re-run on an already-migrated DB.

- Add migration 000053_backfill_admin_group_ids: the same idempotent backfill
  as 000024 (DISTINCT unnest dedupe, EXISTS guard, only touches empty group_ids
  so operator customisation is preserved), applied at migrate time regardless of
  how the deployment invokes migrations. Down is a documented no-op (additive
  backfill has no safe reverse).
- Add integration test TestMigration_BackfillAdminGroupIDs covering the
  restore / no-admin-email path: it runs migrations with NO admin email so the
  Go backfill cannot fire, proving the SQL migration repairs a drifted admin row,
  and asserts idempotency on re-apply. Verified to fail when 000053 is neutered.

The #351 group-assignment invariant already runs in default CI: ci.yml's
integration-tests job runs `go test -tags=integration ./...` against a postgres
service and is required by the ci-success gate, so TestEnsureAdminUser_GroupAssignment
is exercised on every PR.

Refs #546
@cristim cristim added triaged Item has been triaged priority/p2 Backlog-worthy severity/low Minor harm urgency/this-quarter Within the quarter impact/internal Team-internal only effort/m Days type/bug Defect type/chore Maintenance / non-user-visible labels May 20, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 20, 2026

📝 Walkthrough

Walkthrough

This PR adds an idempotent Postgres migration (000053) to backfill the Administrators group UUID into users.group_ids for admin users with empty or null group_ids. A companion logging change redirects backfill messages from stdout to the standard logger, with integration tests validating both the SQL migration behavior and logging output stream.

Changes

Admin Group ID Backfill and Logging

Layer / File(s) Summary
SQL migration 000053: admin group_ids backfill
internal/database/postgres/migrations/000053_backfill_admin_group_ids.up.sql, 000053_backfill_admin_group_ids.down.sql, backfill_admin_group_ids_test.go
Migration 000053 idempotently appends the Administrators group UUID to users.group_ids rows where role='admin' and group_ids is NULL or empty, with deduplication and an EXISTS guard. Down migration is a no-op with explanation. Integration test validates backfill works even when Go-level admin assignment is not triggered.
Logging redirection: fmt.Printf → log.Printf with test coverage
internal/database/postgres/migrations/migrate.go, migrate_security_integration_test.go
Updates assignAdminGroupAndWarn to route backfill messages from stdout to standard logger. Adds stdout and logger capture test helpers and an integration test that verifies "Backfilled" appears in logger output but not stdout.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related issues

  • #546: Directly addresses the gap where admin group_ids backfill lived only in Go by adding an idempotent SQL migration and integration tests to exercise the migration behavior.
  • #545: Addresses the same logging regression in migrate.go by ensuring log.Printf is used instead of fmt.Printf and advocates for integration tests that exercise real migration functions.

Possibly related PRs

  • LeanerCloud/CUDly#520: Both PRs update logging in migrate.go's assignAdminGroupAndWarn to route messages from stdout to logger/stderr.
  • LeanerCloud/CUDly#393: Both PRs implement idempotent backfill of admin group_ids via assignAdminGroupAndWarn and ensureAdminUser logic with corresponding integration tests.

Suggested labels

urgency/this-sprint, effort/s

Poem

🐰 A migration hops in line,
Administrators' groups align,
Empty arrays fill with care,
Logging streams flow everywhere—
No stdout hopping, stderr's fair!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately summarizes the main changes: adding tests for a stdout-leak guard (#440) and a SQL backfill migration for admin group assignment (#351), with clear issue references (#545, #546).
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch test/db-coverage-gaps

Comment @coderabbitai help to get the list of available commands and usage tips.

@cristim
Copy link
Copy Markdown
Member Author

cristim commented May 20, 2026

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 20, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cristim
Copy link
Copy Markdown
Member Author

cristim commented May 22, 2026

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 22, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cristim
Copy link
Copy Markdown
Member Author

cristim commented May 22, 2026

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 22, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
internal/database/postgres/migrations/migrate_security_integration_test.go (1)

19-52: ⚡ Quick win

Consider consolidating duplicate capture helpers.

The captureStdoutIntegration and captureLogOutputIntegration functions are duplicates of captureStdout and captureLogOutput from migrate_security_test.go (shown in relevant snippets). Since both files are in package migrations_test and migrate_security_test.go has no build tag, those helpers should be available to this integration test file when running with -tags=integration.

Consider removing the duplicates here and reusing the originals, or moving all capture helpers to a shared location like helpers_test.go (similar to getMigrationsPath()).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/database/postgres/migrations/migrate_security_integration_test.go`
around lines 19 - 52, Duplicate test helpers captureStdoutIntegration and
captureLogOutputIntegration should be removed and the tests should reuse the
existing captureStdout and captureLogOutput helpers; either delete these two
functions from migrate_security_integration_test.go and import/use the originals
in migrate_security_test.go (they live in the same package migrations_test and
are available under -tags=integration), or move the shared helpers into a new
helpers_test.go so both files reference the same captureStdout and
captureLogOutput symbols. Ensure references in
migrate_security_integration_test.go are updated to call captureStdout and
captureLogOutput (or the new shared names) and remove the duplicated
implementations.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@internal/database/postgres/migrations/migrate_security_integration_test.go`:
- Around line 19-52: Duplicate test helpers captureStdoutIntegration and
captureLogOutputIntegration should be removed and the tests should reuse the
existing captureStdout and captureLogOutput helpers; either delete these two
functions from migrate_security_integration_test.go and import/use the originals
in migrate_security_test.go (they live in the same package migrations_test and
are available under -tags=integration), or move the shared helpers into a new
helpers_test.go so both files reference the same captureStdout and
captureLogOutput symbols. Ensure references in
migrate_security_integration_test.go are updated to call captureStdout and
captureLogOutput (or the new shared names) and remove the duplicated
implementations.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 329edcfb-2237-4ab3-91ed-8a6de8d7b27d

📥 Commits

Reviewing files that changed from the base of the PR and between bc8831b and 83ba93a.

📒 Files selected for processing (5)
  • internal/database/postgres/migrations/000053_backfill_admin_group_ids.down.sql
  • internal/database/postgres/migrations/000053_backfill_admin_group_ids.up.sql
  • internal/database/postgres/migrations/backfill_admin_group_ids_test.go
  • internal/database/postgres/migrations/migrate.go
  • internal/database/postgres/migrations/migrate_security_integration_test.go

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

Labels

effort/m Days impact/internal Team-internal only priority/p2 Backlog-worthy severity/low Minor harm triaged Item has been triaged type/bug Defect type/chore Maintenance / non-user-visible urgency/this-quarter Within the quarter

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant