Skip to content

v3.3.2

Choose a tag to compare

@GkhanKINAY GkhanKINAY released this 09 Aug 10:39
· 86 commits to main since this release
a4f6b12

The recorded follow-up backlog, cleared rather than carried into launch. Four PRs, one release.

What a lapsed subscription used to do

It destroyed scheduled posts in silence. getPost answers falsy for an org with no subscription exactly as it does for a post that no longer exists; the publish workflow turns either into ERROR / 'No Post'; and that string is on the silence list, so nothing reached the customer. The hourly recovery sweep could not save it either, because it only collects posts still in QUEUE. Content someone scheduled and paid for was gone, with no notification and no reason they would recognise on the calendar. The reason written now is Subscription required, and it notifies. The post stays in error rather than returning to the queue on purpose: a post scheduled three weeks ago should not fire the instant someone resubscribes.

It switched channels off with nothing to switch them back on. A returning customer found their channels dark and had to click through them one at a time, while team members — disabled two branches below the channel branch in the same method — came back on their own. Telling "the system took this away" from "I turned this off deliberately" needed a new column, so an upgrade cannot override someone's own choice. Only channels a plan change disabled are returned, oldest-lost first, never past the new limit, never one that needs reconnecting. Autopost rules are deliberately not resumed: enabling a channel publishes nothing by itself, an autopost rule does.

The safety net had none of its own

missingPostWorkflow is the only thing in the product that catches a post the normal path dropped, and it had no try/catch and no continueAsNew. One exhausted activity ended it, and nothing restarted it until the next backend restart — silently, with the first symptom being posts not going out days later. History growth would have terminated it eventually anyway. v2 follows the shape autoPostWorkflowV2 already established.

Separately, TEMPORAL_TLS=true skipped registering the two search attributes that both the start path and the cancel sweep address workflows through, so a TLS install would quietly schedule nothing.

Four places that trusted the caller

None exploitable, all the same mistake: third-party's function dispatch applied any name off the URL to the provider instance; an OAuth app's logo could point at another org's media, on the screen where a user decides whether to trust the app; the five R2 multipart endpoints acted on any key handed to them; and local upload filenames came from Math.random, which is the only thing guarding a file served from a public directory.

Also

An uploaded mp4 was published to Google Business and Telegram as a still image — updateMedia labelled every attachment as an image. Enabling an autopost rule now needs a plan that includes autopost; switching one off still needs nothing.

Three items on the follow-up list turned out to be already fixed. They are struck through in docs/ui-migration-log.md rather than deleted, because a list nobody re-verifies sends the next pass chasing finished work.

Upgrading

Integration.autoDisabledAt is a new nullable column. After deploying, terminate the old missing-post-workflow execution in Temporal — it is an infinite loop that never ends on its own, so until then both the old and new sweep run.

Full diff: v3.3.1...v3.3.2