Serguey Asael Shinder: \"Safe upgrade\" is a claim about the vendor's promise, not about your application
Patch release notes say some version of it every week: this should be a safe upgrade for anyone already on this stream. It is a true and useful sentence, and it is routinely read as something it does not say.
What the vendor is claiming is bounded and honest: within this release, nothing changed that the compatibility policy said would not change. No API removed, no default flipped, no wire format altered. That is a statement about the diff, checked against a written promise, and the people making it are the ones in the best position to make it.
What it cannot be is a statement about your application, because the vendor has never seen it.

The gap is the behaviour nobody promised
Every dependency has a documented surface and a much larger observed surface, and applications bind to both. Iteration order that was never specified. A timeout that was never a default, just a value. An exception type thrown from a path the docs describe only as "fails". The number of threads a pool creates on startup. A log line a monitor greps for.
None of that is covered by a compatibility promise, because none of it was promised. A patch release can change all of it without violating anything, and a team that depended on it did not do anything unreasonable either — they wrote code against the behaviour they observed, which is what everyone does.
So the useful question is never "is this release safe". It is "what would my test suite notice if it were not?" And that question has an answer you already know, for free, before the upgrade: it is the coverage you have of the integration points, not of your own logic. A service with thorough unit tests and one smoke test against a real database has almost no ability to detect a change in a database driver, however green the build goes.
What follows in practice
Apply security patch releases quickly, and run something. The two are not in tension. The whole point of a vendor keeping a strict compatibility promise on a patch stream is to make the upgrade a decision you take in minutes rather than a project. Take it in minutes — and then run whatever you have, because "what you have" is the only instrument that can see your half of the question.
Know which of your dependencies you have no test for. Not as an audit exercise; as a list. For most systems it is short and it is stable: the ones with an out-of-process peer on the other side. Those are the upgrades where reading the changelog is worth the ten minutes, and the rest genuinely are not.
Write down the behaviour you depend on that was never specified. When you discover you rely on something undocumented — and you discover it the hard way, once — the fix is not only to stop relying on it. It is a test that fails if it changes, so the next upgrade tells you instead of production telling you.
Do not let the phrase do your thinking. "Safe upgrade" is shorthand for "we held our end". Yours is a separate question, it is the one that actually determines the outcome, and nobody outside your organisation is in a position to answer it.