Skip to content

chore: Release release/2026-W36 - #7347

Open
github-actions[bot] wants to merge 727 commits into
masterfrom
release/2026-W36
Open

chore: Release release/2026-W36#7347
github-actions[bot] wants to merge 727 commits into
masterfrom
release/2026-W36

Conversation

@github-actions

Copy link
Copy Markdown

Weekly release PR

phot0n and others added 30 commits August 12, 2026 16:55
Two transitions driving MariaDB at once would race, so each job takes the
row before it starts. All three take it, since a lock only one of them
takes excludes nothing.

The lock releases at the first commit, so it covers the plays rather than
the whole job. The reload before each save is what keeps a concurrent
writer from failing the save.
fix(database-server): Fix the audit transition jobs racing the row
The price sits inside a sentence rather than a pricing table, where a bare
symbol is easy to skim past, so it spells out the currency code instead.
fix(dashboard): Name the currency in the audit log price
fix: Ensure trusted apps are added implicitly
The Ansible constructor can raise before the play is recorded (SSH
lookup, playbook parse, Ansible Play insert), and play.run() can raise
after. Either way the server row stayed Running with no play to poll, so
the update never terminated and halt_agent_jobs stayed on.

Catch it and mark the row Failure so it rolls back, or Fatal if the
rollback play is the one that failed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Some servers must not get a new agent right now. The Agent Update tool
skips them, both when picking servers and again before it starts a
server's play, since the flag is usually set after the plan exists.

Manual updates throw instead of skipping quietly, so whoever clicked the
button knows why nothing happened.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
feat(agent-update): Handle play failures and let servers opt out
fix: Allow updates if other app versions changed
Getting into a server means reading the IP, the SSH user and the port
off the form, then remembering whether the server needs a jump host.
`get_ssh_command` builds the same command Ansible connects with, and
the desk form and the dashboard copy it to the clipboard.

Only system users can call it. Team members have write access to their
own servers, so the UI condition is not enough.
…oard

The Console Access button showed the command in a dialog, which you then
had to select by hand. It now also copies it, and keeps the dialog so you
can still read it.
The command connected straight to the server IP, which nobody can do
from their laptop. Servers are reachable only from the press server,
and only through the proxy server of their cluster.

Same shape as break_glass, plus the outer hop:
`ssh frappe@frappe.cloud -t 'ssh -J root@n2-mumbai root@f74-mumbai'`
Picking any active proxy in the cluster gave the wrong one when a
cluster has more than one - `get_value` orders by `modified desc`, so a
newer proxy won over the one the server is attached to. Fall back to
the cluster lookup only for database servers, which have no
`proxy_server` field.
`check_dashboard_actions` only lets through methods registered by
`dashboard_whitelist`, so the dashboard button got "Not permitted".
The decorator applies `frappe.whitelist` too, so the desk button keeps
working.
feat(server): Add a button to copy the SSH command
SiteBackup.get_list_query hides successful backups once retention
removes their files, so a team cannot show an auditor that a backup ran
on an old date. The audit trail lists every day in a range with what is
held for it, and exports the list to CSV.

Days are answered from Site Backup records, which survive retention for
live sites, and the cluster's bucket is listed only for days no record
covers. The agent's jobs.sqlite3 carries the same data but has no
endpoint to filter jobs by site or date.

Filter controls marked local drive the page rather than the query, which
is what lets the one tab hold both lists.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Remote File already sends reads to the replication target when a Backup
Bucket has one, because the primary can expire an object the replica
still holds. The audit trail listed the primary regardless, so a site on
a replicated bucket reported old backups as Not Available.

Resolution lives on Backup Bucket rather than beside the listing code,
since Remote File carries three copies of the same swap and can adopt it
later. Writes are untouched and still go to the primary.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Five gaps found while walking through how an audit actually goes.

A site whose plan has no offsite backups showed a wall of Not Available,
which reads as missing backups rather than a plan that never uploaded
any, so the list now carries a banner saying so. Dates before the site
existed and dates in the future are trimmed off both ends, since neither
can hold a backup and the picker has no min or max to stop them.

Buckets are per cluster, so a site moved to another cluster lost sight
of its older objects. Every bucket the site's Remote Files point at is
now walked, its current cluster first. A year of daily backups also put
a few thousand names in one IN clause, now batched.

Finished ranges are cached for an hour, because an audit means opening
the same range repeatedly. Ranges reaching today stay uncached, since
today can still gain a backup.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Records and buckets can only show a backup that still exists. The agent
keeps its own job history, so it can tell a day whose files are long
gone from a day no backup was ever attempted, and it knows which runs
failed.

The server is asked last and only for days the other two could not
answer, so a site with its objects intact never triggers the call. A day
that failed and was retried reports the run that got furthest, and a
stored object always outranks what the server remembers.

An unreachable server fails the request rather than leaving those days
as Not Available. A day nobody could check is not a day without a
backup, and an audit trail that quietly says otherwise is worse than one
that errors.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Most servers run an agent predating the endpoint and will for a while,
and Agent.request answers a missing route by swallowing the error,
writing an Error Log and returning None. So the audit trail threw on
those servers, and logged once per page view while doing it.

Failing the page is the wrong trade when only the days nothing is stored
for are affected. Those now stay Not Available and the response carries
an unconfirmed flag, which the list turns into a banner, so nobody reads
them as a backup that never ran. A server that could not answer is left
alone for an hour rather than retried on every view, and an unconfirmed
range is not cached so an upgraded agent is picked up.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The endpoint now says when it hit its row limit, which means it dropped
the oldest days in the range. Those days would otherwise read as days no
backup ran, so the trail marks them unconfirmed the same way it does for
a server it could not reach.

Also silences a server that answers with nothing. Agent.request turns a
missing route into None rather than an exception, so that path skipped
the retry guard and asked again on every page view.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The filter bar normalises a control's value with `value == ''`, and that
is true for `false`, so unchecking a checkbox reports undefined rather
than false. The mode switch tested the value, saw undefined and did
nothing, leaving the trail on screen with the box unticked. It tests for
the key instead, which is always present for the control that changed.

The banners asked for a gray alert, which is not one of the types
AlertBanner defines, so it threw reading a colour off undefined and took
the page with it. They ask for general now, and AlertBanner falls back
to it rather than throwing. The upsell banner asked for the same missing
type and would have done the same.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Both banners described the data model rather than what the reader is
looking at. They now name the words on screen, so the sentence lands
against the rows underneath it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
balamurali27 and others added 22 commits August 27, 2026 15:53
The checks in restore_tables are judgement calls: no fatal update on the site,
a newer update after it, or a database server that does not report itself up.
An operator on the desk can see more than the checks can, so the button now
opens a dialog with a Force option that skips them.

Force never skips the concurrent-restore check, and only a System User can use
it. The dashboard button stays unforced.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
fix(site): Skip rate limit on all dedicated server plans
fix: Add press_otp and press_otp_sent cache to persistent cache keys
fix(site-update): Replace the automatic table restore with a button
refactor(invoice): Invoice finalisation flow
The merge of develop into this branch kept the import, but 1bb82d2 had
already removed its only use — get_plan_config now checks
dedicated_server_plan instead. UNLIMITED_PLANS no longer exists in
site_plan.py, so this was an ImportError, not only a ruff F401.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
fix(site-config): Require JSON config values to be an object or array
This fixes an issue where the user is not able to enable/disable
fiewalls. The root cause is a missing editable field declaration.
fix(firewall): Permission error on toggle
fix(virtual-machine): Fix TypeError in OCI attach_to_firewall
Every other destructive action in the dashboard uses the word drop: drop
site, drop server, drop bench group. The bench action menu was the only
place that said archive, so the same operation had two names.

Only the labels change. The backend method stays `archive`.
fix(dashboard): Say drop bench, not archive bench
@mergify

mergify Bot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

@github-actions[bot], thanks for the contribution, but we do not accept pull requests on a master. Please close this PR and raise PR on an develop branch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.