Commit Graph

3 Commits (v1.3.68)

Author SHA1 Message Date
nexxo 823eeaf413 Refuse a key that does not belong to the slot it sits in
put('stripe.secret', 'sk_live_REALMONEY') in test mode was accepted,
get() handed it out, billing.stripe_secret reported satisfied, and the
badge above it said "Testbetrieb". The strict rule closed the automatic
route into that state (no fallback); the typed one stayed open.

The prefix decides it without touching the network, and that rule now
lives in ONE place — OperatingMode::ofStripeKey() — called by the three
that were answering it separately: the slot migration (unchanged verdict,
`?? Live` for a value it cannot place), StripeCheck's `live` flag
(unchanged verdict, null stays false), and the readiness check, which
never asked at all. A key it cannot place is not reported as a
contradiction: this check only says what it can prove.

The two directions get their own `breaks` sentence, because the
consequences are opposite — real money moving while the console says
test, versus no money moving while the order looks paid.

The "Prüfen" button no longer contradicts the check either: the page
rendered only ok/reason, so a live key in the test slot answered
"Geprüft: in Ordnung". It now names the account the key belongs to.

Red first:

  ⨯ it refuses a live key sitting in the test slot
  ⨯ it refuses a test key sitting in the live slot
  ⨯ it says what the wrong key does, not that a field is empty

Guard tests (ConfirmInModal, ModalHeight, IconLayout, DisplayTimezone)
run with the blade change: green.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-30 17:05:58 +02:00
nexxo 49d528dbea Fix round: point at the real tab, hide the button nobody can press, prove the quiet page load
Fixes four Important findings from the review of Task 12.

Corrected nine check `tab` values at the source (BillingChecks was already
correct; OnboardingChecks/ProvisioningChecks/DeliveryChecks all carried the
pre-redesign 'integrations' value, which is not a member of
Integrations::TABS): four onboarding checks now point at 'platform' or 'env'
depending on where their field actually is, five provisioning/delivery
checks point at 'services'. checkUrl()'s match-block resolver — praised as
correct for the six checks that point at a genuinely different admin page —
is unchanged; its `default` arm is now a pure safety net, not a route any
check actually relies on.

Wrapped the "Prüfen" button in @can('secrets.manage'): mount() admits
hosts.manage OR secrets.manage, but runCheck() requires secrets.manage alone,
so an Admin-role operator could see a button that 403s on press.

Fixed a docblock on HEARTBEAT_KEYS that asserted a staleness threshold was
kept in sync with OperationChecks::STALE_AFTER_MINUTES — that constant is a
key/settings-name map with no threshold of its own, and no such
synchronisation exists.

Three new tests, each confirmed red against a deliberately reintroduced
version of the bug it covers before being confirmed green: every check's tab
value against where its field actually lives, the run-check button hidden
from an operator who cannot press it, and Http::assertNothingSent() after a
plain page load.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-30 16:26:10 +02:00
nexxo e83b17ec37 Put every missing field on one page before a customer pays
Admin\Readiness renders App\Support\Readiness::byGroup() end to end: state,
label, breaks sentence and a fix link for every check, a button on the four
that have to ask a real service (DnsTokenCheck, WireguardEndpointCheck,
VmTemplateCheck, StripeCheck) and only ever run on demand, and one headline
line — ready for the operator's current mode, or how many blocking items are
still open. Wired into the nav and into Overview's own notice list beside the
same gate as Admin\Integrations, since both halves it configures come back
together on this page.

Fixed two check keys the guard test caught for real: onboarding.ssh_key and
delivery.inbound_password did not textually contain the vault key they check
(ssh.private_key, inbound_mail.password), which is exactly the kind of silent
gap this whole task exists to catch. Renamed to onboarding.ssh_private_key
and delivery.inbound_mail_password, with the two existing test files that
referenced the old keys updated to match.

Also fixed the guard test's own assertion: Pest's toContain() is variadic, so
a second string argument is a second required substring, not a failure
message (the same trap tests/Feature/ModalHeightTest.php already documents
about itself) — it failed on every entry, including ones already covered.
Replaced with str_contains()+toBeTrue(), which keeps the check and the
message both.

Two pre-existing Overview tests assumed a bare install has nothing to report;
it now correctly always starts with a readiness gap, so both were narrowed to
what they actually test — no invented data, no invented incident.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-30 15:59:34 +02:00