Commit Graph

31 Commits

Author SHA1 Message Date
Stanko K.R. 500dd78e40 Fix failing OSS tests 2026-04-15 17:39:13 +02:00
Rob Zolkos 4a91e45aa5 Cover bearer-authenticated export download URLs 2026-04-08 15:03:25 -04:00
Rob Zolkos dd67f4171d Add regression tests for bearer-authenticated blob downloads 2026-04-08 14:36:34 -04:00
Mike Dalessio 7446eed4e1 Add representation proxy public Cache-Control test 2026-03-26 15:38:27 -04:00
Mike Dalessio e12f3e3917 Add representation proxy Cache-Control test 2026-03-26 15:34:54 -04:00
Mike Dalessio 14e6832507 Add regression test for public blob Cache-Control 2026-03-26 15:22:21 -04:00
Mike Dalessio 628571fc79 Don't set public Cache-Control on proxied non-public blobs
Rails' ActiveStorage proxy controllers hardcode `http_cache_forever public: true`,
which sets `Cache-Control: public, immutable`. For non-public blobs behind auth,
this allows CDN caching that serves responses without authorization checks.

Override `http_cache_forever` in the Authorize concern to downgrade `public` to
`false` for non-public blobs.

See https://github.com/basecamp/fizzy/pull/2251 for context
2026-03-26 14:58:40 -04:00
Mike Dalessio 71b99c1e18 Fix path traversal vulnerability in ActiveStorage blob key import
BlobRecordSet#import_batch preserved blob keys from exported ZIP files
verbatim. A crafted ZIP with a traversal key like "../../config/deploy.yml"
would create a blob whose key resolves to an arbitrary filesystem path
when served by ActiveStorage's DiskService, allowing an attacker to read
local files.

Fix: generate fresh blob keys on import, discarding whatever key was in
the ZIP. This is safe because nothing else in the import pipeline
references blobs by key — attachments use blob_id, ActionText uses GIDs
based on record IDs, and only FileRecordSet used the old key for file
data lookup.

Update FileRecordSet to build an old_key→blob_id mapping from the blob
JSON metadata in the ZIP, then look up blobs by ID instead of by key.
Both check_record and import_batch are now fail-closed: they raise
IntegrityError for unmapped storage files, missing blobs, and duplicate
keys in the export.

Backfill test coverage for BlobRecordSet and FileRecordSet import, and
add a round-trip test verifying blob data survives export/import with
regenerated keys.
2026-03-10 11:03:53 -04:00
Rosa Gutierrez 92cb749e16 Fix tests for renamed fixtures and new stacked notifications
Clear assignee's existing notifications in setup since Notifier now
uses create_or_find_by instead of create, and reload the association
to avoid caching after destroy_all.

Update fixture references after rebase: use `logo_assignment_kevin`
as base notification and `logo_mentioned_david` for mention tests.
Update source to `logo_published` in tests that need generic card events.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-25 19:31:13 +01:00
Rosa Gutierrez 126ccb5e3a Add integration test for notification delivery and simplify test helpers
- Add comprehensive integration test covering card assignment, comments,
  mentions, email bundling, and edge cases (system user, inactive user)
- Inline push notification test helpers into the only test that uses them
- Remove separate PushNotificationTestHelper module

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-25 19:31:13 +01:00
Mike Dalessio cb61b36715 Allow boosts on cards (#2411)
* Add reactions association to Card model

Adds `has_many :reactions` to Card, matching the implementation in Comment.
This allows cards to be reacted to directly with emoji reactions.

The association:
- Orders reactions chronologically
- Uses polymorphic `:reactable` interface
- Deletes reactions when card is destroyed

Includes test coverage for the new association.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Add reactions UI to card detail view

- Create Cards::ReactionsController with turbo stream responses
- Add card reactions views (reactions list, new form, menu partial)
- Position reaction button flush-right when no reactions exist
- Show reactions on bottom-left when present, with button inline
- Handle narrow viewports by flowing button below meta section
- Add controller tests for card reactions

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Add boost count to card preview

Display reaction count alongside comment count on card tiles in board
columns. Introduces a .card__counts wrapper to group both counts with
proper positioning on all viewport sizes.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Consolidate reaction views for cards and comments

Extract shared views to app/views/reactions/ using polymorphic routing.
Both card and comment reactions now render the same partials, with a
helper to compute the correct path prefix for nested routes.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Fix emoji picker width in card reactions

Override .card .popup { inline-size: 260px } for the reaction popup
so the emoji grid displays without horizontal scrollbar.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Hide boost count where comment count is hidden

Add .card__boosts alongside .card__comments in:
- Tray view (display: none)
- Cards with background images (opacity toggle on hover)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Fix reactions button overlap with zoom button in card footer

When a card has a background image, the footer contains both a reactions
button and a zoom button. Previously they would overlap because the
reactions button was absolutely positioned to the bottom-right.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Tighten up previews

* Move card reactions from meta partial to container

Fixes two issues:

1. Reactions were duplicated each time a card was assigned because the
   turbo stream replaced the meta div with the full perma/meta partial,
   which included reactions outside the replaced element.

2. Draft cards incorrectly showed the boost button because the meta
   partial was shared between published and draft containers.

Moving reactions to _container.html.erb (published cards only) fixes
both issues and keeps the meta partial focused on meta content.

Fixes https://app.fizzy.do/5986089/cards/3837
Fixes https://app.fizzy.do/5986089/cards/3835

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* WIP adjust perma page

* Position and style the footer

* Render the stamp in the card body instead of the footer

* Fix undefined local variable in public cards view

Changed `card` to `@card` when rendering the stamp partial.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Preload card reactions to avoid N+1 queries

Include reactions and their reacters in the preloaded scope, matching
what we already do for comments.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Add model tests for card and comment reaction cleanup

Test that:
- Creating a card reaction touches the card's last_active_at
- Reactions are deleted when their parent comment is destroyed
- Reactions are deleted when their parent card is destroyed

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Minor improvements to reactions code

- Use size instead of count in boosts partial to avoid extra SQL query
  on already-loaded collection
- Add else clause to reaction_path_prefix_for to raise ArgumentError
  for unknown reactable types instead of silently returning nil

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Bump specificity of reaction popup in the card perma

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Andy Smith <andy@37signals.com>
2026-01-23 13:25:55 -05:00
Rosa Gutierrez f66a2dc1ba Consider user avatars always public
Avatars are purposely accessible without authentication
(5e3b5b6d7c) because they can be in public
collections. Trying to restrict this by checking whether they're in fact
present in some public collection is rather expensive, so let's keep
them public.
2025-12-26 19:33:26 +01:00
Rosa Gutierrez 196d685f8d Implement authorization for Active Storage endpoints
Consider blobs attached to any public records accessible to anyone with
the URL.
2025-12-25 21:22:36 +01:00
Stanko K.R. 79b012f319 Add Join Codes 2025-10-31 16:24:30 +01:00
Stanko K.R. 5cef4ffeb0 Add sign in flow using magic links 2025-10-31 16:22:12 +01:00
Mike Dalessio 1277cc065b Introduce untenanted Identity and Membership models
The new integration test shows the desired user-facing behavior, which
is to make it easy to login without a tenanted URL and to jump between
tenants.

Note that we track two things in the identity_token cookie: a signed
id, and the updated_at for the underlying Identity object. This allows
us to effectively cache on the Identity without having to hit the
database, by using an Identity::Mock object that is compatible with
etag and cache methods.
2025-10-31 16:22:12 +01:00
Mike Dalessio 3399e45130 Introduce an "Identity" model to ease login
- New untenanted Identity and Membership models
- New `identity_token` cookie with path "/" holds state across tenants

We're not sure whether the untenanted database will be sqlite or
MySQL, and so I've been careful to minimize

- database reads, placing them behind etags and caching
- database writes, only writing when a new Session is created (login)

Note that we track two things in the identity_token cookie: a signed
id, and the updated_at for the underlying Identity object. This allows
us to effectively cache on the Identity without having to hit the
database, by using an Identity::Mock object that is compatible with
etag and cache methods.

The new integration test shows the desired user-facing behavior, which
is to make it easy to login without a tenanted URL and to jump between
tenants.

- the untenanted "login_help" page shows all linked memberships
- the jump menu shows all linked memberships (except the current)

Also introduced a utility script to populate existing employee
Identities, grouping accounts by email address.
2025-10-10 10:12:25 -04:00
Jorge Manrubia b6c3e5c090 Add tests and clean unused events 2025-04-30 09:45:41 +02:00
Jorge Manrubia e03f1f7f9b Rename test that was being skipped 2025-04-29 19:23:56 +02:00
Jorge Manrubia 18cc24e1d3 Add an event prefix named after the model now that events are generic 2025-04-24 13:20:09 +02:00
David Heinemeier Hansson 3d28203224 Use singular staging resource and beef up testing 2025-04-22 14:44:55 +02:00
David Heinemeier Hansson dbf61f4fc3 Use _path in all cases where we are not potentially changing the domain 2025-04-13 08:17:36 +02:00
David Heinemeier Hansson 760cbb6c99 Drop boosts
Killed by design.
2025-04-12 18:52:54 +02:00
Jorge Manrubia 723e6d94f5 Rename bubbles => cards 2025-04-09 14:50:58 +02:00
David Heinemeier Hansson bcd6c6dd66 Move bubble stagings out from double nesting 2025-04-07 14:00:30 +02:00
David Heinemeier Hansson c06802856e Move boosts under bubbles
But also remove the need for a bucket nesting
2025-04-06 21:04:28 +02:00
Jason Zimdars bbcbb77082 Update tests 2025-03-27 17:09:05 -05:00
Jason Zimdars 28a569c49b Tickets 2025-03-17 21:24:08 -05:00
Jose Farias a64752e573 Clear up messages integration test 2024-10-27 20:21:32 -06:00
Jose Farias 9e60362ca7 Write messages integration test 2024-10-27 20:17:34 -06:00
Kevin McConnell 564a0f48ae New Rails app 2024-06-21 13:19:56 +01:00