Skip to content

Update dependencies: erb 6.0.4, marcel 1.2.1#2911

Merged
flavorjones merged 2 commits into
mainfrom
update-deps-2026-05-31
May 31, 2026
Merged

Update dependencies: erb 6.0.4, marcel 1.2.1#2911
flavorjones merged 2 commits into
mainfrom
update-deps-2026-05-31

Conversation

@flavorjones

@flavorjones flavorjones commented May 31, 2026

Copy link
Copy Markdown
Member

Summary

Routine dependency updates (2026-05-31). Each gem analyzed commit-by-commit; full unit suite green after each.

Gem From To Commits Mitigations Transitive
erb 6.0.2 6.0.4 12 0 0
marcel 1.1.0 1.2.1 37 0 0
  • erb: range is mostly CI/dependabot noise. Lone runtime change (9d017be4, block def_method on marshal-loaded ERB) doesn't affect Fizzy.
  • marcel: transitive dep via ActiveStorage; public API unchanged. None of the changed MIME detections intersect Fizzy's accepted upload types. Also clears the frozen-string-literal warnings emitted by marcel 1.1.0.

Tests: 1506 runs, 5729 assertions, 0 failures after each upgrade.

Upgrade Plans

Full per-gem analysis in 37signals-hq upgrade-analysis/ and posted as PR comments below.

🤖 Assisted by Claude

Copilot AI review requested due to automatic review settings May 31, 2026 15:09

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot wasn't able to review any files in this pull request.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@flavorjones

Copy link
Copy Markdown
Member Author

🤖 Upgrade Plan: erb v6.0.2..v6.0.4

Upgrade Plan: erb v6.0.2..v6.0.4 for fizzy

  • Date: 2026-05-31
  • Gem: erb
  • Range: v6.0.2..v6.0.4 (12 commits)
  • Target: fizzy

Summary

  • Total commits: 12
  • No impact: 11 (skipped at recon — CI workflow, gemspec packaging, version/NEWS bumps)
  • Analyzed, not affected: 1
  • Requires mitigation: 0

This is a low-risk patch upgrade. Of the 12 commits, 11 touch only CI workflows (.github/), gemspec packaging metadata, NEWS.md, or lib/erb/version.rb — none change runtime behavior. The single runtime change is a security-hardening guard on ERB#def_method that only affects ERB instances reconstructed via Marshal.load, a pattern Fizzy does not use.

Commits Requiring Mitigation

None.

Analyzed — No App Impact

9d017be4: Prohibit def_method on marshal-loaded ERB instances

Impact: unlikely impact

ERB#def_method now raises ArgumentError, "not initialized" unless @_init matches the instance singleton class. def_module and def_class delegate to def_method and are covered by the same guard. This blocks eval of arbitrary src on an ERB object created via Marshal.load (which bypasses initialize).

Searched and NOT matched in fizzy:

  • App ERB usage is limited to ERB::Util.html_escape (app/helpers/html_helper.rb:9), the ERB::Util mixin (app/models/event/description.rb:3, app/models/card/eventable/system_commenter.rb:2), and ERB.new(...).result (config/database.yml:9, config/storage.yml:9). None call def_method/def_module/def_class, and none marshal ERB instances.
  • Gem dependencies (173 lib/app dirs): no ERB#def_method/def_module/def_class calls. The parser and prism gems contain builder.def_method/def_class/def_module calls, but those operate on AST builder objects, not ERB instances — false positives.
  • No Marshal.load/Marshal.dump of ERB instances anywhere in app or dependencies.

The guard fires only for the pathological case of calling these methods on an uninitialized (marshal-loaded) ERB instance. Standard usage is unaffected.

Commit Summary Impact Level
9d017be4 Prohibit def_method on marshal-loaded ERB instances unlikely impact

No Impact (Skipped)

11 commits assessed as "no impact" during recon — not analyzed against the app:

Commit Summary
677f418f Bump step-security/harden-runner 2.14.1->2.15.0 (CI)
4359937d Fix a missing action tag (CI)
bf1ded95 Use tag instead of branch for lewagon/wait-on-check-action (CI)
2fd0a6b7 Exclude test/.git/.github from published gem (gemspec packaging)
afc32b6d Fix dependabot auto-merge using GH_TOKEN env var (CI)
890d87f0 Use github.token instead of missing secret (CI)
26113660 Bump lewagon/wait-on-check-action 1.5.0->1.6.0 (CI)
98208023 Bump actions/create-github-app-token 2->3 (CI)
25a729a9 Bump step-security/harden-runner 2.15.0->2.16.1 (CI)
0ebc6aef Bump rubygems/release-gem 1.1.2->1.2.0 (CI)
9c8fa8a3 Version 6.0.3 (NEWS.md + version.rb)
4d2b45e1 Version 6.0.4 (NEWS.md + version.rb)

Recommendation

Safe to upgrade erb from v6.0.2 to v6.0.4 with no code changes. Run the standard test suite (bin/rails test) to confirm. No mitigations required.

Note on analysis method

This environment did not expose a subagent-dispatch tool (Task/Agent), so recon and app-impact analysis were performed inline rather than via parallel subagents. The commit range is small (12 commits, 1 runtime change), so direct analysis was tractable without exhausting context.

@flavorjones flavorjones force-pushed the update-deps-2026-05-31 branch from 4c04a29 to e665d1d Compare May 31, 2026 15:10
Copilot AI review requested due to automatic review settings May 31, 2026 15:17

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot wasn't able to review any files in this pull request.

@flavorjones flavorjones changed the title Upgrade erb to 6.0.4 Update dependencies: erb 6.0.4, marcel 1.2.1 May 31, 2026
@flavorjones

Copy link
Copy Markdown
Member Author

🤖 Upgrade Plan: marcel v1.1.0..v1.2.1

Upgrade Plan: marcel v1.1.0..v1.2.1 for fizzy

  • Date: 2026-05-31
  • Gem: marcel
  • Range: v1.1.0..v1.2.1 (37 commits)
  • Target: fizzy

Summary

  • Total commits: 37
  • No impact: 32 (skipped at recon)
  • Analyzed, not affected: 5
  • Requires mitigation: 0

Marcel is a transitive dependency in fizzy, pulled in via ActiveStorage (marcel (~> 1.0)). Fizzy has no direct references to Marcel:: (confirmed: only Gemfile.lock mentions it). It is exercised indirectly: ActiveStorage calls Marcel::MimeType.for(io, name:, declared_type:), Marcel::Magic.new, Marcel::Magic.child?, and Marcel::Magic.by_extension when identifying/serving attachments.

Public API is unchanged across this range. The entire public surface (Marcel::MimeType.for/.extend, Marcel::Magic.new/.by_magic/.by_path/.by_extension/.child?/.add/.remove/.extend) is identical between v1.1.0 and v1.2.1. Marcel::Magic.remove already existed in v1.1.0 — it is not new.

The changes in this range are (a) MIME-type detection-table data updates and (b) a new internal regexp magic-match mechanism. MimeType.for always runs magic-byte detection first and prefers it over the declared type, so changed detection rules can alter the content type assigned to an upload. However, none of the changed detections intersect the content types fizzy actually accepts or references.

Fizzy's attachment surface (the only way marcel runs)

  • User::Avatar::ALLOWED_AVATAR_CONTENT_TYPES = %w[image/jpeg image/png image/gif image/webp] (app/models/user/avatar.rb:6) — magic for jpeg/png/gif/webp is unchanged in this range.
  • Card#image (app/models/card.rb:11), accept list image/png, image/jpeg, image/jpg, image/webp (app/views/cards/container/_image.html.erb:14) — unchanged magic.
  • Export#file, Account::Import#file, ZipFile all use an explicit content_type: "application/zip" (app/models/export.rb:5, app/models/zip_file.rb:38,51,79) — zip magic is unchanged.
  • Identity#avatar (app/models/identity.rb:12).

No fizzy code references text/html, image/svg, application/x-bzip2, audio/ogg, audio/mpeg, text/markdown, image/bmp, application/pkcs8, application/gpx+xml, or image/x-raw-sony as content-type strings (the content-type^= references in attachments.css/lexxy.css and account/seeder.rb are ActionText attachment HTML attributes, unrelated to marcel detection).

Conclusion: this upgrade is safe to apply with no code changes.

Commits Requiring Mitigation

None.

Analyzed — No App Impact

Commit Summary Impact Level
5cba16fc Improve HTML detection (add <html>, leading-whitespace/DOCTYPE variants; HTML magic → anchored regexp) unlikely impact
631b3281 Improve SVG detection (narrow magic from offset 0..4096 to anchored offset 0) unlikely impact
61957fc0 Stop mutating source IO encoding during magic-byte detection (use String#b buffer instead of binmode/set_encoding on caller IO) unlikely impact
bc33f495 Add regexp magic-match support; convert bzip2 (and internal dbf/matlab/aac) magic to Ruby Regexp; remove untested regex-string entries unlikely impact
65a6a56d image/bmp magic refinement; add audio/mpeg (mp3) ID3 magic; remap markdown extensions text/x-web-markdowntext/markdown unlikely impact

Why none affect fizzy:

  • HTML / SVG detection changes (5cba16fc, 631b3281): change what resolves to text/html / image/svg+xml. Fizzy accepts neither — avatar and card-image allowlists are jpeg/png/gif/webp only. An SVG with a leading XML prolog will no longer detect as image/svg+xml (now requires literal <svg at byte 0), but this is moot for fizzy.
  • IO-encoding fix (61957fc0): strictly safer — marcel no longer calls binmode/set_encoding(BINARY) on the caller's IO. ActiveStorage passes a fresh identify/download chunk, so there is no observable change. No regression risk.
  • Regexp magic + bzip2 (bc33f495): new internal Magic.match_regex (private) matches Regexp patterns against the first 256 bytes; bzip2 now detected correctly and several never-matching regex-string entries (dbf, matlab, some aac) were removed. Fizzy does not accept bzip2/dbf/matlab/aac uploads.
  • bmp/mp3/markdown (65a6a56d): .md/.mkd/.markdown/.mdtext now map to text/markdown (was text/x-web-markdown); mp3 detects as audio/mpeg; bmp magic refined. None of these MIME strings or extensions are referenced by fizzy or appear in its upload allowlists.

No Impact (Skipped)

32 commits assessed as "no impact" during recon — not analyzed against the app. These are test fixtures, build/data-regeneration scripts (generate_tables.rb, tika.xml/custom.xml), version bumps (1.1.1, 1.2.0, 1.2.1), merge commits, and additive type/extension additions (pkcs8 9f11bea9/2b957616, Sony RAW b5a2f240/8fcf98f0, gpx 2410e570/8058fd5c, ogg/opus 8bf76906) for formats fizzy does not handle, plus whitespace/trailing-name table cleanups (9f9833c3, 5a3fbac1, 6ea009af, hprof) whose runtime data effect is already covered by the analyzed commits above.

Recommendation

Bump marcel from 1.1.0 to 1.2.1 in Gemfile.lock (bundle update marcel). No application code changes required. Standard test suite run (bin/rails test, including ActiveStorage attachment system tests) is sufficient verification; pay light attention to avatar/card-image upload tests, though no behavior change is expected for the accepted image types.

@flavorjones flavorjones force-pushed the update-deps-2026-05-31 branch from b771506 to 4f6d09c Compare May 31, 2026 15:19
@flavorjones flavorjones merged commit 1416038 into main May 31, 2026
13 checks passed
@flavorjones flavorjones deleted the update-deps-2026-05-31 branch May 31, 2026 15:23
joshyorko pushed a commit to joshyorko/fizzy that referenced this pull request Jun 2, 2026
* Return updated board on PUT /boards/:id (basecamp#2848)

* Return the updated board on PUT /:account_slug/boards/:id

The JSON response was `204 No Content`, forcing clients to make a
follow-up GET to observe their own write. The Smithy contract the
SDKs are generated from already declares `UpdateBoard` returns a
Board, so the server was out of sync with the documented shape.

Render `show` for the JSON format so PUT returns the same payload
as GET. The HTML format is unchanged.

Updated test asserts the returned body matches the updated state.
Updated API docs to show the 200 response shape.

* Handle board update access loss for JSON

* Return no content after self-removal on JSON update

* Update flat JSON board response test

* Document 204 response for board self-removal

* Update dependencies: erb 6.0.4, marcel 1.2.1 (basecamp#2911)

* Upgrade erb 6.0.2 → 6.0.4

* Upgrade marcel 1.1.0 → 1.2.1

* Bump the github-actions group across 1 directory with 7 updates (basecamp#2910)

Bumps the github-actions group with 7 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [ruby/setup-ruby](https://github.com/ruby/setup-ruby) | `1.300.0` | `1.310.0` |
| [zizmorcore/zizmor-action](https://github.com/zizmorcore/zizmor-action) | `0.5.2` | `0.5.6` |
| [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) | `4.0.0` | `4.1.0` |
| [docker/login-action](https://github.com/docker/login-action) | `4.1.0` | `4.2.0` |
| [docker/metadata-action](https://github.com/docker/metadata-action) | `6.0.0` | `6.1.0` |
| [docker/build-push-action](https://github.com/docker/build-push-action) | `7.1.0` | `7.2.0` |
| [sigstore/cosign-installer](https://github.com/sigstore/cosign-installer) | `4.1.1` | `4.1.2` |



Updates `ruby/setup-ruby` from 1.300.0 to 1.310.0
- [Release notes](https://github.com/ruby/setup-ruby/releases)
- [Changelog](https://github.com/ruby/setup-ruby/blob/master/release.rb)
- [Commits](ruby/setup-ruby@e65c17d...afeafc3)

Updates `zizmorcore/zizmor-action` from 0.5.2 to 0.5.6
- [Release notes](https://github.com/zizmorcore/zizmor-action/releases)
- [Commits](zizmorcore/zizmor-action@71321a2...5f14fd0)

Updates `docker/setup-buildx-action` from 4.0.0 to 4.1.0
- [Release notes](https://github.com/docker/setup-buildx-action/releases)
- [Commits](docker/setup-buildx-action@4d04d5d...d7f5e7f)

Updates `docker/login-action` from 4.1.0 to 4.2.0
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](docker/login-action@4907a6d...650006c)

Updates `docker/metadata-action` from 6.0.0 to 6.1.0
- [Release notes](https://github.com/docker/metadata-action/releases)
- [Commits](docker/metadata-action@030e881...80c7e94)

Updates `docker/build-push-action` from 7.1.0 to 7.2.0
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](docker/build-push-action@bcafcac...f9f3042)

Updates `sigstore/cosign-installer` from 4.1.1 to 4.1.2
- [Release notes](https://github.com/sigstore/cosign-installer/releases)
- [Commits](sigstore/cosign-installer@cad07c2...6f9f177)

---
updated-dependencies:
- dependency-name: ruby/setup-ruby
  dependency-version: 1.310.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
- dependency-name: zizmorcore/zizmor-action
  dependency-version: 0.5.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
- dependency-name: docker/setup-buildx-action
  dependency-version: 4.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
- dependency-name: docker/login-action
  dependency-version: 4.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
- dependency-name: docker/metadata-action
  dependency-version: 6.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
- dependency-name: docker/build-push-action
  dependency-version: 7.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
- dependency-name: sigstore/cosign-installer
  dependency-version: 4.1.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump the development-dependencies group across 1 directory with 2 updates (basecamp#2903)

* Bump the development-dependencies group across 1 directory with 2 updates

Bumps the development-dependencies group with 2 updates in the / directory: [faker](https://github.com/faker-ruby/faker) and [selenium-webdriver](https://github.com/SeleniumHQ/selenium).


Updates `faker` from 3.6.1 to 3.8.0
- [Release notes](https://github.com/faker-ruby/faker/releases)
- [Changelog](https://github.com/faker-ruby/faker/blob/main/CHANGELOG.md)
- [Commits](faker-ruby/faker@v3.6.1...v3.8.0)

Updates `selenium-webdriver` from 4.43.0 to 4.44.0
- [Release notes](https://github.com/SeleniumHQ/selenium/releases)
- [Changelog](https://github.com/SeleniumHQ/selenium/blob/trunk/rb/CHANGES)
- [Commits](SeleniumHQ/selenium@selenium-4.43.0...selenium-4.44.0)

---
updated-dependencies:
- dependency-name: faker
  dependency-version: 3.8.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: development-dependencies
- dependency-name: selenium-webdriver
  dependency-version: 4.44.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: development-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>

* Sync Gemfile.saas.lock

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* Bump jwt from 3.1.2 to 3.2.0 (basecamp#2902)

* Bump jwt from 3.1.2 to 3.2.0

Bumps [jwt](https://github.com/jwt/ruby-jwt) from 3.1.2 to 3.2.0.
- [Release notes](https://github.com/jwt/ruby-jwt/releases)
- [Changelog](https://github.com/jwt/ruby-jwt/blob/main/CHANGELOG.md)
- [Commits](jwt/ruby-jwt@v3.1.2...v3.2.0)

---
updated-dependencies:
- dependency-name: jwt
  dependency-version: 3.2.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

* Sync Gemfile.saas.lock

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* Bump sqlite3 from 2.9.2 to 2.9.3 (basecamp#2883)

* Bump sqlite3 from 2.9.2 to 2.9.3

Bumps [sqlite3](https://github.com/sparklemotion/sqlite3-ruby) from 2.9.2 to 2.9.3.
- [Release notes](https://github.com/sparklemotion/sqlite3-ruby/releases)
- [Changelog](https://github.com/sparklemotion/sqlite3-ruby/blob/main/CHANGELOG.md)
- [Commits](sparklemotion/sqlite3-ruby@v2.9.2...v2.9.3)

---
updated-dependencies:
- dependency-name: sqlite3
  dependency-version: 2.9.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* Sync Gemfile.saas.lock

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* Bump aws-sdk-s3 from 1.218.0 to 1.219.0 (basecamp#2858)

* Bump aws-sdk-s3 from 1.218.0 to 1.219.0

Bumps [aws-sdk-s3](https://github.com/aws/aws-sdk-ruby) from 1.218.0 to 1.219.0.
- [Release notes](https://github.com/aws/aws-sdk-ruby/releases)
- [Changelog](https://github.com/aws/aws-sdk-ruby/blob/version-3/gems/aws-sdk-s3/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-ruby/commits)

---
updated-dependencies:
- dependency-name: aws-sdk-s3
  dependency-version: 1.219.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* Sync Gemfile.saas.lock

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* Bump bootsnap from 1.23.0 to 1.24.3 (basecamp#2900)

* Bump bootsnap from 1.23.0 to 1.24.3

Bumps [bootsnap](https://github.com/rails/bootsnap) from 1.23.0 to 1.24.3.
- [Release notes](https://github.com/rails/bootsnap/releases)
- [Changelog](https://github.com/rails/bootsnap/blob/main/CHANGELOG.md)
- [Commits](rails/bootsnap@v1.23.0...v1.24.3)

---
updated-dependencies:
- dependency-name: bootsnap
  dependency-version: 1.24.3
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* Sync Gemfile.saas.lock

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* Bump propshaft from 1.3.1 to 1.3.2 (basecamp#2882)

* Bump propshaft from 1.3.1 to 1.3.2

Bumps [propshaft](https://github.com/rails/propshaft) from 1.3.1 to 1.3.2.
- [Release notes](https://github.com/rails/propshaft/releases)
- [Commits](rails/propshaft@v1.3.1...v1.3.2)

---
updated-dependencies:
- dependency-name: propshaft
  dependency-version: 1.3.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* Sync Gemfile.saas.lock

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* Improve CI output (basecamp#2912)

* Update bundle-drift to handle net-new gems

* Improve CI output

- rubocop simple output
- minitest progress bar

* Return updated user on PUT /users/:id (basecamp#2853)

* Return the updated user on PUT /:account_slug/users/:user_id

The JSON response was `204 No Content`, forcing clients to follow
up with a GET. The Smithy contract the SDKs are generated from
already declares `UpdateUser` returns a User, so the server was
out of sync with the documented shape.

Render `show` for the JSON format so PUT returns the same payload
as GET. The HTML redirect behavior is unchanged. Only name and
avatar are accepted on this endpoint, neither of which affects
the acting user's access, so no access-check branch is needed.

Updated test asserts the returned body matches the updated state.
Updated API docs to describe the 200 response shape.

* Update flat JSON user response test for 200 body

Mirrors the nested-params test in users_controller_test.rb — flat
JSON PUTs now return the updated user as the body instead of 204
No Content.

* Return the updated comment on PUT /:account_slug/cards/:card_number/comments/:comment_id (basecamp#2852)

The JSON response was `204 No Content`, which conflicted with both
the API docs ("Returns the updated comment") and the Smithy
contract the SDKs are generated from (`UpdateCommentResponseContent`).

Render `show` for the JSON format so PUT returns the same payload
as GET. The Turbo Stream format is unchanged.

Docs already describe the correct response shape, so no doc change
is needed here. Tests now assert the returned body content.

* Return updated column on PUT /boards/:id/columns/:id (basecamp#2851)

* Return the updated column on PUT /:account_slug/boards/:board_id/columns/:column_id

The JSON response was `204 No Content`, forcing clients to follow
up with a GET. The Smithy contract that the SDKs are generated
from already declares `UpdateColumn` returns a Column, so the
server was out of sync with the documented shape.

Render `show` for the JSON format so PUT returns the same payload
as GET. The Turbo Stream format is unchanged.

Updated test asserts the returned body matches the updated state.
Updated API docs to describe the 200 response shape.

* Update flat JSON column response test for 200 body

Mirrors the nested-params test in boards/columns_controller_test.rb —
flat JSON PUTs now return the updated column as the body instead
of 204 No Content.

* Return the moved card on PUT /:account_slug/cards/:card_number/board (basecamp#2849)

The JSON response was `204 No Content`, which forced clients to
make a follow-up GET to see the card on its new board. The Smithy
contract the SDKs are generated from already declares `MoveCard`
returns a Card, so the server was out of sync with the documented
shape.

Render `cards/show` for the JSON format so the response carries
the moved card (with the new `board` reference). The HTML format
is unchanged.

Added assertions on the returned body and added an API doc entry
for the endpoint, which was previously undocumented.

* Stub DNS in notification delivery tests (basecamp#2838)

* Stub DNS in notification delivery tests

* Clarify DNS stubbing in notification delivery tests

* Extract shared FCM DNS test helper

* Rename shared DNS test helper for web push

* Add :account_slug prefix to account, my/pins and my/timezone API doc paths (basecamp#2889)

* Add :account_slug prefix to account and my/pins API doc paths

The /account/* routes (settings, join_code, entropy, exports) and
/my/pins are mounted inside the per-account scope (see namespace
:account and namespace :my in config/routes.rb). They are reachable
in production as /:account_slug/account/... and /:account_slug/my/...
— the same convention the surrounding paths in these files already
follow (e.g. POST /:account_slug/cards/:card_number/pin, PUT
/:account_slug/boards/:board_id/entropy, POST
/:account_slug/users/:user_id/data_exports). Without the prefix the
client hits the root web app and gets 302'd to /session/menu, which
in turn yields 406 Not Acceptable when Accept: application/json is
set.

* Add :account_slug prefix to my/timezone API doc path

PATCH /my/timezone is mounted inside the per-account scope alongside
/my/pins (see namespace :my in config/routes.rb). It is reachable in
production as PATCH /:account_slug/my/timezone — without the prefix the
client hits the root web app and gets 302'd to /session/menu, which in
turn yields 406 Not Acceptable when Accept: application/json is set.

Same fix as the previous commit on this branch; this one was missed.

* fix: Add tooltip controller to reactions trigger button (basecamp#2763)

* fix: Add tooltip controller to reactions trigger button

* review

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Rob Zolkos <rob@zolkos.com>
Co-authored-by: Mike Dalessio <mike@37signals.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Rogério Vicente <rogerio@hey.com>
Co-authored-by: Michal Landsman <landsman@insuit.cz>
joshyorko added a commit to joshyorko/fizzy that referenced this pull request Jun 2, 2026
* Return updated board on PUT /boards/:id (basecamp#2848)

* Return the updated board on PUT /:account_slug/boards/:id

The JSON response was `204 No Content`, forcing clients to make a
follow-up GET to observe their own write. The Smithy contract the
SDKs are generated from already declares `UpdateBoard` returns a
Board, so the server was out of sync with the documented shape.

Render `show` for the JSON format so PUT returns the same payload
as GET. The HTML format is unchanged.

Updated test asserts the returned body matches the updated state.
Updated API docs to show the 200 response shape.

* Handle board update access loss for JSON

* Return no content after self-removal on JSON update

* Update flat JSON board response test

* Document 204 response for board self-removal

* Update dependencies: erb 6.0.4, marcel 1.2.1 (basecamp#2911)

* Upgrade erb 6.0.2 → 6.0.4

* Upgrade marcel 1.1.0 → 1.2.1

* Bump the github-actions group across 1 directory with 7 updates (basecamp#2910)

Bumps the github-actions group with 7 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [ruby/setup-ruby](https://github.com/ruby/setup-ruby) | `1.300.0` | `1.310.0` |
| [zizmorcore/zizmor-action](https://github.com/zizmorcore/zizmor-action) | `0.5.2` | `0.5.6` |
| [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) | `4.0.0` | `4.1.0` |
| [docker/login-action](https://github.com/docker/login-action) | `4.1.0` | `4.2.0` |
| [docker/metadata-action](https://github.com/docker/metadata-action) | `6.0.0` | `6.1.0` |
| [docker/build-push-action](https://github.com/docker/build-push-action) | `7.1.0` | `7.2.0` |
| [sigstore/cosign-installer](https://github.com/sigstore/cosign-installer) | `4.1.1` | `4.1.2` |



Updates `ruby/setup-ruby` from 1.300.0 to 1.310.0
- [Release notes](https://github.com/ruby/setup-ruby/releases)
- [Changelog](https://github.com/ruby/setup-ruby/blob/master/release.rb)
- [Commits](ruby/setup-ruby@e65c17d...afeafc3)

Updates `zizmorcore/zizmor-action` from 0.5.2 to 0.5.6
- [Release notes](https://github.com/zizmorcore/zizmor-action/releases)
- [Commits](zizmorcore/zizmor-action@71321a2...5f14fd0)

Updates `docker/setup-buildx-action` from 4.0.0 to 4.1.0
- [Release notes](https://github.com/docker/setup-buildx-action/releases)
- [Commits](docker/setup-buildx-action@4d04d5d...d7f5e7f)

Updates `docker/login-action` from 4.1.0 to 4.2.0
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](docker/login-action@4907a6d...650006c)

Updates `docker/metadata-action` from 6.0.0 to 6.1.0
- [Release notes](https://github.com/docker/metadata-action/releases)
- [Commits](docker/metadata-action@030e881...80c7e94)

Updates `docker/build-push-action` from 7.1.0 to 7.2.0
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](docker/build-push-action@bcafcac...f9f3042)

Updates `sigstore/cosign-installer` from 4.1.1 to 4.1.2
- [Release notes](https://github.com/sigstore/cosign-installer/releases)
- [Commits](sigstore/cosign-installer@cad07c2...6f9f177)

---
updated-dependencies:
- dependency-name: ruby/setup-ruby
  dependency-version: 1.310.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
- dependency-name: zizmorcore/zizmor-action
  dependency-version: 0.5.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
- dependency-name: docker/setup-buildx-action
  dependency-version: 4.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
- dependency-name: docker/login-action
  dependency-version: 4.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
- dependency-name: docker/metadata-action
  dependency-version: 6.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
- dependency-name: docker/build-push-action
  dependency-version: 7.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
- dependency-name: sigstore/cosign-installer
  dependency-version: 4.1.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump the development-dependencies group across 1 directory with 2 updates (basecamp#2903)

* Bump the development-dependencies group across 1 directory with 2 updates

Bumps the development-dependencies group with 2 updates in the / directory: [faker](https://github.com/faker-ruby/faker) and [selenium-webdriver](https://github.com/SeleniumHQ/selenium).


Updates `faker` from 3.6.1 to 3.8.0
- [Release notes](https://github.com/faker-ruby/faker/releases)
- [Changelog](https://github.com/faker-ruby/faker/blob/main/CHANGELOG.md)
- [Commits](faker-ruby/faker@v3.6.1...v3.8.0)

Updates `selenium-webdriver` from 4.43.0 to 4.44.0
- [Release notes](https://github.com/SeleniumHQ/selenium/releases)
- [Changelog](https://github.com/SeleniumHQ/selenium/blob/trunk/rb/CHANGES)
- [Commits](SeleniumHQ/selenium@selenium-4.43.0...selenium-4.44.0)

---
updated-dependencies:
- dependency-name: faker
  dependency-version: 3.8.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: development-dependencies
- dependency-name: selenium-webdriver
  dependency-version: 4.44.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: development-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>

* Sync Gemfile.saas.lock

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* Bump jwt from 3.1.2 to 3.2.0 (basecamp#2902)

* Bump jwt from 3.1.2 to 3.2.0

Bumps [jwt](https://github.com/jwt/ruby-jwt) from 3.1.2 to 3.2.0.
- [Release notes](https://github.com/jwt/ruby-jwt/releases)
- [Changelog](https://github.com/jwt/ruby-jwt/blob/main/CHANGELOG.md)
- [Commits](jwt/ruby-jwt@v3.1.2...v3.2.0)

---
updated-dependencies:
- dependency-name: jwt
  dependency-version: 3.2.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

* Sync Gemfile.saas.lock

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* Bump sqlite3 from 2.9.2 to 2.9.3 (basecamp#2883)

* Bump sqlite3 from 2.9.2 to 2.9.3

Bumps [sqlite3](https://github.com/sparklemotion/sqlite3-ruby) from 2.9.2 to 2.9.3.
- [Release notes](https://github.com/sparklemotion/sqlite3-ruby/releases)
- [Changelog](https://github.com/sparklemotion/sqlite3-ruby/blob/main/CHANGELOG.md)
- [Commits](sparklemotion/sqlite3-ruby@v2.9.2...v2.9.3)

---
updated-dependencies:
- dependency-name: sqlite3
  dependency-version: 2.9.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* Sync Gemfile.saas.lock

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* Bump aws-sdk-s3 from 1.218.0 to 1.219.0 (basecamp#2858)

* Bump aws-sdk-s3 from 1.218.0 to 1.219.0

Bumps [aws-sdk-s3](https://github.com/aws/aws-sdk-ruby) from 1.218.0 to 1.219.0.
- [Release notes](https://github.com/aws/aws-sdk-ruby/releases)
- [Changelog](https://github.com/aws/aws-sdk-ruby/blob/version-3/gems/aws-sdk-s3/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-ruby/commits)

---
updated-dependencies:
- dependency-name: aws-sdk-s3
  dependency-version: 1.219.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* Sync Gemfile.saas.lock

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* Bump bootsnap from 1.23.0 to 1.24.3 (basecamp#2900)

* Bump bootsnap from 1.23.0 to 1.24.3

Bumps [bootsnap](https://github.com/rails/bootsnap) from 1.23.0 to 1.24.3.
- [Release notes](https://github.com/rails/bootsnap/releases)
- [Changelog](https://github.com/rails/bootsnap/blob/main/CHANGELOG.md)
- [Commits](rails/bootsnap@v1.23.0...v1.24.3)

---
updated-dependencies:
- dependency-name: bootsnap
  dependency-version: 1.24.3
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* Sync Gemfile.saas.lock

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* Bump propshaft from 1.3.1 to 1.3.2 (basecamp#2882)

* Bump propshaft from 1.3.1 to 1.3.2

Bumps [propshaft](https://github.com/rails/propshaft) from 1.3.1 to 1.3.2.
- [Release notes](https://github.com/rails/propshaft/releases)
- [Commits](rails/propshaft@v1.3.1...v1.3.2)

---
updated-dependencies:
- dependency-name: propshaft
  dependency-version: 1.3.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* Sync Gemfile.saas.lock

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* Improve CI output (basecamp#2912)

* Update bundle-drift to handle net-new gems

* Improve CI output

- rubocop simple output
- minitest progress bar

* Return updated user on PUT /users/:id (basecamp#2853)

* Return the updated user on PUT /:account_slug/users/:user_id

The JSON response was `204 No Content`, forcing clients to follow
up with a GET. The Smithy contract the SDKs are generated from
already declares `UpdateUser` returns a User, so the server was
out of sync with the documented shape.

Render `show` for the JSON format so PUT returns the same payload
as GET. The HTML redirect behavior is unchanged. Only name and
avatar are accepted on this endpoint, neither of which affects
the acting user's access, so no access-check branch is needed.

Updated test asserts the returned body matches the updated state.
Updated API docs to describe the 200 response shape.

* Update flat JSON user response test for 200 body

Mirrors the nested-params test in users_controller_test.rb — flat
JSON PUTs now return the updated user as the body instead of 204
No Content.

* Return the updated comment on PUT /:account_slug/cards/:card_number/comments/:comment_id (basecamp#2852)

The JSON response was `204 No Content`, which conflicted with both
the API docs ("Returns the updated comment") and the Smithy
contract the SDKs are generated from (`UpdateCommentResponseContent`).

Render `show` for the JSON format so PUT returns the same payload
as GET. The Turbo Stream format is unchanged.

Docs already describe the correct response shape, so no doc change
is needed here. Tests now assert the returned body content.

* Return updated column on PUT /boards/:id/columns/:id (basecamp#2851)

* Return the updated column on PUT /:account_slug/boards/:board_id/columns/:column_id

The JSON response was `204 No Content`, forcing clients to follow
up with a GET. The Smithy contract that the SDKs are generated
from already declares `UpdateColumn` returns a Column, so the
server was out of sync with the documented shape.

Render `show` for the JSON format so PUT returns the same payload
as GET. The Turbo Stream format is unchanged.

Updated test asserts the returned body matches the updated state.
Updated API docs to describe the 200 response shape.

* Update flat JSON column response test for 200 body

Mirrors the nested-params test in boards/columns_controller_test.rb —
flat JSON PUTs now return the updated column as the body instead
of 204 No Content.

* Return the moved card on PUT /:account_slug/cards/:card_number/board (basecamp#2849)

The JSON response was `204 No Content`, which forced clients to
make a follow-up GET to see the card on its new board. The Smithy
contract the SDKs are generated from already declares `MoveCard`
returns a Card, so the server was out of sync with the documented
shape.

Render `cards/show` for the JSON format so the response carries
the moved card (with the new `board` reference). The HTML format
is unchanged.

Added assertions on the returned body and added an API doc entry
for the endpoint, which was previously undocumented.

* Stub DNS in notification delivery tests (basecamp#2838)

* Stub DNS in notification delivery tests

* Clarify DNS stubbing in notification delivery tests

* Extract shared FCM DNS test helper

* Rename shared DNS test helper for web push

* Add :account_slug prefix to account, my/pins and my/timezone API doc paths (basecamp#2889)

* Add :account_slug prefix to account and my/pins API doc paths

The /account/* routes (settings, join_code, entropy, exports) and
/my/pins are mounted inside the per-account scope (see namespace
:account and namespace :my in config/routes.rb). They are reachable
in production as /:account_slug/account/... and /:account_slug/my/...
— the same convention the surrounding paths in these files already
follow (e.g. POST /:account_slug/cards/:card_number/pin, PUT
/:account_slug/boards/:board_id/entropy, POST
/:account_slug/users/:user_id/data_exports). Without the prefix the
client hits the root web app and gets 302'd to /session/menu, which
in turn yields 406 Not Acceptable when Accept: application/json is
set.

* Add :account_slug prefix to my/timezone API doc path

PATCH /my/timezone is mounted inside the per-account scope alongside
/my/pins (see namespace :my in config/routes.rb). It is reachable in
production as PATCH /:account_slug/my/timezone — without the prefix the
client hits the root web app and gets 302'd to /session/menu, which in
turn yields 406 Not Acceptable when Accept: application/json is set.

Same fix as the previous commit on this branch; this one was missed.

* fix: Add tooltip controller to reactions trigger button (basecamp#2763)

* fix: Add tooltip controller to reactions trigger button

* review

* Enable Kamal GHA build cache

* Use Node 24 GitHub runtime cache action

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Rob Zolkos <rob@zolkos.com>
Co-authored-by: Mike Dalessio <mike@37signals.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Rogério Vicente <rogerio@hey.com>
Co-authored-by: Michal Landsman <landsman@insuit.cz>
Co-authored-by: Josh Yorko <joshyorko@users.noreply.github.com>
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.

2 participants