Skip to content

Harden subscriber links, account deletion, and external requests - #77

Open
philipithomas wants to merge 12 commits into
mainfrom
codex/postcard-backlog-fixes
Open

Harden subscriber links, account deletion, and external requests#77
philipithomas wants to merge 12 commits into
mainfrom
codex/postcard-backlog-fixes

Conversation

@philipithomas

@philipithomas philipithomas commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Account settings crashed because they called a nonexistent provider attribute; the normal Devise current-password check now works, with a password-reset link for Google signups. Subscriber confirmation links remained valid indefinitely and could reactivate someone after removal. Invalid unsubscribe links raised errors, while account deletion missed subscriber email history and archived posts. This adds locked token verification, 48-hour expiry explained in confirmation emails, token revocation on unsubscribe, safe repeated/deleted-subscription unsubscribe responses, and deletion of those account-owned records.

Updates-list cleanup follows the account's audited email changes so historical memberships and their mail do not survive account deletion. It preserves shared recipient rows, other authors' mail, addresses now used by another account, and memberships with subsequent signup, verification, or pending confirmation activity.

The backlog review also identified several small fixes that had no regression coverage: restore Google OAuth state validation, validate and normalize modern custom domains before provider registration, serialize registration JSON, remove the unrelated development localhost domain, set explicit HTTP connection/read/write budgets, prevent queued newsletters from locked accounts, propagate fatal newsletter-delivery exceptions, and handle an unset theme color. These fixes now have focused tests.

Account deletion uses Solid Queue's execution-locking discard API to cancel pending jobs whose serialized GlobalIDs all belong to that account, including feedback mail. It also recognizes the exact legacy signup-newsletter signature. Claimed/current and mixed-account jobs are preserved. Five jobs that process independent records now deserialize each top-level record separately: a missing record is skipped while live records still run, and transient lookup failures remain failed/retryable. The analytics scheduler enqueues one account per job.

The retired Ghost integration removal from #94 is included: password signup, Google signup, and subscriber verification no longer enqueue external newsletter requests, and signup no longer offers the external newsletter checkbox. The legacy job class remains inert so persisted jobs, including deleted-account GlobalIDs, can drain without external requests. Local Postcard updates subscriptions remain intact.

Fresh confirmation after unsubscribe refreshes subscriber ordering; replaying an already-active confirmation does not. Scheduled tracking cleanup retains email unsubscribe records and all unfinished/retryable queue work, using Solid Queue's supported finished-job retention API instead of deleting operational rows by age.

Validation at c7a7b1d:

  • Full SOLO suite: 92 tests, 409 assertions, passing.
  • Full MULTIUSER suite: 92 tests, 409 assertions, passing.
  • Zeitwerk eager loading passes; assets compiled on the preceding implementation.
  • Brakeman: zero reported warnings (seven existing ignored warnings).
  • Mixed-batch and pending-confirmation regressions reproduced the failures before their fixes. Tests exercise real serialized job payloads and the test mailer against an isolated PostgreSQL database with external HTTP blocked.
  • Combined with all retained PRs on Rails 8.1: SOLO 225 tests / 1,688 assertions; MULTIUSER 233 / 1,752; six Chrome tests; all passing.

Fixes #15, fixes #21, fixes #22, fixes #24, fixes #25, fixes #27, fixes #29.
Supersedes the implementations in #52, #55, #57, #58, #61, #62, #65, and #66. The remote-image SSRF work in #16 and CSP rollout in #18 remain separate open work.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 5, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-05T20:24:53.474734Z c7a7b1d New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 069d485ee7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread app/jobs/application_job.rb Outdated
Comment thread app/jobs/destroy_account_job.rb Outdated
Comment thread app/jobs/destroy_account_job.rb Outdated
Comment thread app/models/subscription.rb

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 52ebd35c20

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread app/jobs/subscribe_to_contraption_ghost_job.rb Outdated
Comment thread app/jobs/destroy_account_job.rb
@philipithomas

philipithomas commented Sep 5, 2026

Copy link
Copy Markdown
Contributor Author

Merged #94 into this reliability branch so either merge order preserves the retired Ghost integration. Password signup, Google signup, and verification no longer enqueue Ghost; the legacy job class is an inert drain for existing serialized jobs, including missing-account GlobalIDs. Generic token expiry/revocation, OAuth validation, and account-owned queue cleanup remain covered.

Removed the obsolete Ghost HTTP/enqueue expectations and retained the seven retirement regressions. Both isolated suites pass: SOLO and MULTIUSER each 82 tests / 360 assertions, no failures/errors/skips. Zeitwerk passes; Brakeman reports zero warnings (seven existing ignored). All four current-head CI checks pass on ac1b16e: the push and PR test suites and both production Docker smoke checks. The branch remains open and mergeable. CI: https://github.com/contraptionco/postcard/actions/runs/33988642714

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ac1b16ed56

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread app/jobs/cleanup_tracking_data_job.rb
Comment thread app/jobs/application_job.rb
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant