Adopter-side review for the auction house. Two open-source Rails engines were cloned with full history and read: auctify (the auction domain, HEAD a1b60f0, 2024-11-15) and folio (the CMS, HEAD 71084c9, 2026-09-14, VERSION 7.7.2). The production app, Auctea, is closed and combines both; it is not in the clone, so every finding states what was proved from public code and what still depends on Auctea's private configuration.
Four detailed reviews sit beside this file: review-auction-domain.md, review-auctify-security.md, review-folio.md, review-quality.md. This document is the verdict layer, and it marks which findings were verified by hand for this summary.
| Area | Score | Basis |
|---|---|---|
| Auction-domain correctness (auctify) | 4 | Sound arithmetic, no lock on the bid path |
| Security (auctify) | 3 | No authorisation layer in the engine; money-ceiling bypass |
| Security (folio) | 4 | Unauthenticated download controller; authorisation is opt-in |
| Maintainability (folio) | 6 | Long methods and single-author concentration at scale |
| Test strength — auctify / folio | 4 / 7 | auctify has an excellent bid test, no concurrency test |
| Code health — auctify / folio | 7 / 6 | auctify is small and clean; folio is large and normal |
| Documentation — auctify / folio | 3 / 9 | auctify README example raises; folio has 29 doc files |
| Release discipline — auctify / folio | 2 / 7 | auctify: 3 tags, no release in 24 months |
| Project health — auctify / folio | 1 / 8 | auctify has no CI ever and does not install on a modern Rails |
Two different objects. folio is a mature project: continuous integration, a release every three weeks for years, breaking changes documented in advance, 19 contributors this year. auctify is a well-written 2 500-line engine that has been left alone since mid-2022: 8 commits in four years, bus factor 1, no CI in its entire history.
app/models/auctify/sale/auction.rb:158 — bid! opens a transaction and takes no row lock. There is no lock!, no with_lock, no SELECT … FOR UPDATE, no lock_version column, no unique index on the bid table anywhere in the repository. BidsAppender reads the current bid set (bids_appender.rb:123), computes the minimum next bid (:98) and the winner in Ruby from that snapshot. Under PostgreSQL READ COMMITTED, two bids that arrive together both read the same snapshot and both commit. The only advisory lock in the codebase guards auction closing (app/jobs/auctify/bidding_closer_job.rb:19), not bidding.
Consequence for the house: at the closing second of a lot at a few million CZK, two near- simultaneous bids can both be accepted at the same price, or one can overwrite the other's price. That is a disputed hammer and a possible refund or lawsuit. There is no concurrency test in the suite that would catch a regression here.
Caveat. Auctea is closed. If Auctea wraps every bid in its own with_advisory_lock — the gem already depends on with_advisory_lock and uses it for closing, so the team knows the tool — this risk is handled outside the public engine and does not apply. This one question decides the severity, and only Auctea's code answers it. Ask the vendor: is bid submission serialised, and where.
app/models/auctify/bid.rb:7 orders by price: :desc, id: :desc. Two bidders reaching the same price: the row inserted second wins. Auction convention is that the first bid at a price holds. Low money impact, but wrong by the rules of a saleroom.
app/models/auctify/sale/base.rb:96 and :106 — percent 0.01 price. Prices themselves are decimal(12,2) (db/migrate/20210223152139_create_auctify_bids.rb:7) and clean; this Float is only on the commission path. It cannot move a hammer price. It makes invoice totals carry binary noise, so they stop tying out against a spreadsheet. Fix is one token: BigDecimal("0.01").
Auctify::ApplicationController (app/controllers/auctify/application_controller.rb:1-8) has only protect_from_forgery — no authentication, no authorisation. config/routes.rb:5-7 mounts resources :bids, :bidder_registrations, :sales as full CRUD, and bids_controller.rb:61 permits registration_id (the actor). Read literally, anyone could bid as anyone and delete the winning bid.
But: I probed the live site. GET /auctify/bids, /auctify/bidder_registrations, /auctify/sales all return 404 on www.acb.cz. Auctea does not mount these routes. The flaw is real in the gem and would be catastrophic if the routes were exposed; on acb.cz they are not. This is the clearest example of why the engine's score and the live site's exposure are different numbers.
app/services/auctify/bids_appender.rb — the ceiling check can be avoided by sending max_price alongside price. On the public engine this needs the API bid path, which does authenticate (api/v1/auctions_controller.rb). Confirm against Auctea's bid endpoint.
app/controllers/folio/downloads_controller.rb runs on bare ActionController::Base, no auth filter, finds a file by slug and redirects to its S3 URL (config/routes.rb:343, GET /download/:slug). The review claims numeric slugs enumerate the whole file table across tenants. That part is SUSPECTED and partly overstated: file.rb:453 deliberately forces a non-numeric slug to prevent slug/id collision, so a file cannot have a numeric slug. Enumeration by primary key could still work through FriendlyId's own PK fallback, which I did not run. I did not probe file enumeration on the live site, because retrieving files that may belong to another party is the attack, not a review. Confirm internally: is /download/:id reachable, and are files scoped to a site.
grep -rn check_authorization app lib test returns nothing. CanCanCan's check_authorization, which raises when an action finishes without an authorize! call, is not enabled. A new console action that forgets authorisation fails open. There is no default_scope for tenant isolation (app/models/folio/current.rb:98 maps host→site; scoping is per-query by_site). Whether this produces a real cross-tenant read depends on the association graph and on whether acb.cz truly shares one Folio deployment with the other auction houses — which I cannot see from outside.
auctify.gemspec — spec.add_dependency "rails", "~> 6.1.4" (i.e. >= 6.1.4, < 6.2). Folio runs Rails 8.0.4.1. The two cannot be installed in one app. The highest Rails constraint on any of the 25 branches is ~> 6.1. So the public auctify is not the engine running acb.cz — Auctea runs a private fork. Rails 6.1 is past end of security support. The MIT engine you could legally take is a 2023-era snapshot on an EOL framework, not the live code.
review-folio.md reports several CRITICAL cross-tenant findings: a site admin granting themselves admin on another tenant (ability.rb:71 + users_controller.rb:174), a transports controller that exports any record of any tenant (transports_controller.rb:42), order_scope reaching unscoped via send, an embed system that runs editor <script> on the site origin. Each is a plausible reading of real code, and each is marked in that review with the console check that would confirm it. Two things hold them back from being called live vulnerabilities:
auctea S3 bucket and by another tenant's theme inside ACB's stylesheet, but it is not proven.They are worth handing to whoever runs Auctea as a checklist. They are not, on this evidence, confirmed exposures on acb.cz.
decimal(12,2) throughout the bid tables.cancelled flag (bid.rb:8-9,23), restrict-on-destroy is set; a dispute can be reconstructed.test/services/auctify/bid_appender_test.rb, the "ultimate bidding test").UPGRADING.md, documented breaking changes, dependabot merged.Folio: yes, mature. auctify: no, dormant. The auction engine is well-built and then abandoned; the CMS is actively maintained by one company with a bus factor near one.
Keep it. Do not replace it, and do not take it in-house. The reasoning:
inside Auctea (the closing path uses the very lock the bid path lacks). Confirm it with one question to the vendor rather than assuming the worst.
site** (the scaffold routes 404) or are conditional on a deployment you cannot see.
modern Rails, plus a 45 000-line CMS that one company on earth understands. That is more risk, not less.
The exit-cost correction. Earlier I estimated an open-source exit at 2,0–2,75 M CZK partly because "you inherit a working, tested bid engine for free". That was too optimistic: the public auctify is a 2023 snapshot on an EOL Rails and needs porting before it boots. Realistic exit, open-source route, is now 2,4–3,6 M CZK, and you would own two Rails upgrade treadmills you did not write.
GET /download/:id reachable on the deployment, and are Folio files scoped per site?