Skip to content

Bump node from 22-bookworm-slim to 26-bookworm-slim in /web - #3

Closed
dependabot[bot] wants to merge 932 commits into
masterfrom
dependabot/docker/web/node-26-bookworm-slim
Closed

Bump node from 22-bookworm-slim to 26-bookworm-slim in /web#3
dependabot[bot] wants to merge 932 commits into
masterfrom
dependabot/docker/web/node-26-bookworm-slim

Conversation

@dependabot

@dependabot dependabot Bot commented on behalf of github Aug 29, 2026

Copy link
Copy Markdown

Warning

Cooldown could not be applied because no publication date was available from the registry.

Bumps node from 22-bookworm-slim to 26-bookworm-slim.

Dependabot compatibility score

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


Dependabot commands and options

You can trigger Dependabot actions by commenting on this PR:

  • @dependabot rebase will rebase this PR
  • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
  • @dependabot show <dependency name> ignore conditions will show all of the ignore conditions of the specified dependency
  • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)

The clone source is resolved as a Volume so a cloned Environment is placed at
all; `settle` gets the no-op guard every other status writer has, so a
permanently-broken object stops re-stamping its own condition; a terminating
stop request no longer reads as a landed push; and stopping a workspace no
longer waits on a disk it does not need.
The Snapshots page has no durable index today: it enumerates live Workspace and
Environment objects and joins snapshots onto them, so a volume whose parent was
deleted is invisible even though its records and blobs are all still there.

The records already live on the server tier at vol/{owner}/{name}. What was
missing is a user-facing way to read them: /vol-agent/* is per-volume only and
authenticates a region's agent token, which is not an authorization answer for
"may this person see these snapshots".

Two routes, each following the shape its scope demands. `volumes` is
owner-scoped like `images` and reads the shared object store alone -- one LIST
of repo/vol/{owner}/ names every volume without opening any of them, which is
what makes it safe to serve on whichever node receives it. `volumehistory` is
routed by the volume key like `imagetags` is by the image key, so it opens the
database only on the node that holds it.

Dating the list from object mtimes is deliberate and approximate: a compaction
can run ahead of the last real push. It is enough to sort and date a list by,
and volumehistory has the exact times.
The Snapshots page listed live Workspace and Environment objects and joined
snapshots onto them, so deleting a workspace hid every snapshot ever taken of
it -- and restore called my_ws() on the source first, so those snapshots could
not be restored either. Both followed from treating a live parent as the index.

A snapshot is a point in time. Its record and its bytes live on the server tier
and outlive the workspace, so that is what /v1/volumes, /history, /refs and
restore now read, through the browse routes over the peer credentials this
process already proxies browse reads with. SnapshotRequest goes back to being
only the push work item: nothing user-facing reads one, so a collected request
costs nothing.

The cluster is still asked one question -- is the parent still there -- and its
answer only sets `deleted` and names live rows. A kube outage degrades the page
to bare ids rather than emptying it.

Provenance rides in the commit record's state, written by the agent at push time
from the Volume's ownerReference, because once the workspace is gone that is the
only thing left that can say what the snapshot was of. Records without it fall
back to the volume id, which is what the page showed for everything before.

Restore now resolves a snapshot id against the caller's own histories and takes
the volume from it. Quota comes from a live source when there is one, else the
body, else the fallback; src_workspace is accepted and ignored so a web build
from before this change survives a roll.
The list rows now carry what the source was called, whether it still exists,
and when it was last written, so a volume outliving its workspace reads as
"api-scratch, source deleted" rather than vanishing from the page.

Restore moves to every row and sends only the snapshot id. It no longer names a
source workspace, because the case that matters most is the one where there is
none; the restored workspace takes the standard quota then, with no field to
fill in -- someone recovering a lost workspace is not sizing a disk.

The detail page drops the kind query param it used to gate restore on. It reads
by volume id, which needs no live parent.
karthik1729 and others added 22 commits August 29, 2026 09:13
A stream layer larger than 120 s of link bandwidth could never be restored:
`get_bytes` bounded the whole body with one deadline and every fetch error
carried the FETCH_FAILED marker, so the Volume settled Error/FetchFailed for
good. The deadline is now per chunk (the block path already did this) and
only a NotFound/PermissionDenied/Unauthenticated answer is permanent; a
timeout or 5xx comes back unmarked and is retried.

An agent restart mid-stop left the fixed-name `stop-{env}` request at
error/AgentRestarted, and with no /v1 delete for requests the environment
stayed parked until kubectl. That error is the agent's, not the push's, so
`await_stop_push` deletes it and creates a fresh one; a real PushFailed
still parks, and nothing is torn down until a push has landed.
…team website scheme

The emailed /verify/{token} link was a GET that redeemed the token and set the
session cookie, so anyone who could make a browser open a URL could sign it into
an account of their choosing. The page is now inert; a Server Action behind a
Continue button does the redeem and signIn, with next re-validated through
safeNext on the way through.

A team website now has to be an http(s) URL on both tiers: the api refuses
anything else with 400 (and caps the length), the settings form reports it as a
field error, and the public profile renders an already-stored bad value as text
rather than an href.
…arkers

The upload sweep aged a session by its staging object, which the fast path
writes empty at open and never touches again, so any push longer than the
grace window was swept out from under the client. Age a session by the
newer of its two objects, and abort the sidecar's multipart upload before
deleting it so its parts do not outlive the session in the bucket. The
bucket-side rule the code kept citing now exists, in deploy/README.md.

The marker reconcile compared the owner's clock stamp against the object
store's second-granular mtime for exact equality, rewriting every marker
once after every push. A gap only a missed push could open counts now.
…ound the feed fan-out and refuse traversing volume names

check_repo capped rows rather than work, so the same 25 lowest-numbered
open changes filled the cap on every pass and #26 onward were never
checked. merge_base collapsed a budget-exhausted walk into "unrelated",
which the sweep recorded as Dirty and the page read as no merge button.
/v1/activity asked each owning node in turn on the 15 s client timeout;
it now asks four at once under a 5 s deadline and returns what answered.
/v1/volumes/{name} and {snapshot} were spliced into peer URLs unchecked;
they now pass the same valid_segment rule as created names, or 400.
App::route answered Local for a repo whose object-store prefix was
still empty, so the first write to a new repo, image or volume opened
its database unleased, and every other node saw the same empty prefix
and opened it too until the manifest landed. Route on the ownership map
alone: a name the map does not know is claimed first, and a name that
really does not exist still 404s in the handler without opening
anything. This also puts api_create under its lease, since the
middleware claims before the handler runs. The negative cache existed
only to make the prefix probe cheap, so it goes with it.

Q-20 (delete racing a concurrent open) is untouched.
… on disk

Q-18: an environment's stop snapshot is taken after its StatefulSets are at
zero and their pods are gone, not under running databases; the deletes still
wait for the push to land. Q-52: a stopped environment that is restored is
observed at the new generation instead of pushing the restored subvolume as
an unrequested commit. Q-36: a claim leaves an object alone when the owner's
OwnerBinding names another node. Q-37/Q-38: a failed send deletes the RO
snapshot it took, the janitor sweeps unnamed recv/ subvolumes by their own
creation time, and the auto-squash child is reaped. S-10: spec.quotaGb is a
btrfs qgroup limit on the live subvolume, re-applied on every materialize
and restore; a pool without qgroups surfaces QuotaEnforced=False instead of
being silently uncapped, and format-pool.sh enables quotas on new pools.
…aming clients for disk faults

The agent ClusterRole is now the table at the top of agent-rbac.yaml: every kube call the
controller makes, one row each, and no verb outside it. `secrets` leaves the ClusterRole
entirely — the host-key grant is bound per `ws-*` namespace by the binding reconciler, the
same shape as the api's — and `events`, `nodes list/watch`, `update`/`delete` on kinds the
agent never edits or deletes are gone. What RBAC cannot express (field-level patch, who a
`bind` may be used for) is a ValidatingAdmissionPolicy in agent-admission.yaml: the agent
may change nothing in spec but `Volume.spec.restoreTo`, and may only write `ws-*`/`env-*`
namespaces, `ws-ssh-*` Secrets, and the two api/agent secret RoleBindings. CLAUDE.md,
README and crd.rs now say what the deployment actually enforces.

`/healthz` also requires the leader to have answered within one LEASE_TTL, cached from the
renew beat (which no longer skips an idle node), so a freshly rolled pod is not Ready before
it can claim.

Server-side io errors are 500 again: `is_client_fault` matches io kinds client input
produces rather than the io type, a Basic header that does not decode is refused on browse
instead of degrading to anonymous, and a connectivity walk propagates anything but a
missing object rather than telling the pusher their pack has holes.
A manifest GET by tag did a durable SlateDB put under a per-tag lock
before answering, so concurrent pulls of one tag queued behind a WAL
flush each. The counter is display only: tally it in a per-node map,
fold it into the image's database on the owning node's 30 s lane with
await_durable off, and accept losing one window to a crash.
Every fetch with a have and every push built the full object closure
of the repo (`reachable_set`) to answer "does this repo have X". A have
is a commit, so a commit walk from the tips that stops at the last
target answers it; an up-to-date fetch now costs one lookup. A push
walks only the trees the client sent, explains an unchanged subtree by
the trees of the commits the new history grows from, and pays for the
whole-repo closure only for an object neither explains. The gix#2935
merge workaround in pack.rs is untouched. `upload::WALKED` counts the
objects visited so tests/walk_cost.rs can pin the cost: a 1200-object
repo now walks 2 objects on an incremental fetch and 7 on a push of
one commit, where both used to walk all 1200.
The upload-pack reply now leaves as the pack is built: the protocol
writes into a channel-backed writer that holds back the first 64 KiB
(so a fence can still be retried and an error can still set the
status) and streams the rest as a chunked body, bounded by the channel
so a stalled client stalls the build rather than growing the pod.

The receive-pack body feeds gix-pack's indexer straight from the
request stream; an unlinked spool under the pack dir keeps the bytes
for the in-flight fence replay and is capped by max_body as it
streams. The receive semaphore, auth-before-body ordering, upload-pack
413 and the merge-commit pack workaround are unchanged.
Every push added a pack and nothing ever removed one; the only repack was
the admin command with the server stopped. The owner's lanes now fold a
repo's packs back into one once it holds more than RUSTIC_GIT_REPACK_PACKS
(default 32) of them.

The online shape copies every object of the packs it listed rather than
rebuilding from the refs: pushes are not serialised against each other,
so a rebuild from the refs could drop a push's objects in the window
between its pack upload and its ref update. The admin path keeps the
ref-based rebuild (which also collects garbage) over the same tail.

Both retire an old file from the pack index before the object store, so a
crash leaves duplicates rather than an index row naming a missing pack.
The repack lock is in-process now: the DB key outlived a crashed run and
blocked every repack after it.
The audit's I-4: the invariant violation, claim outcomes, 421s, merge outcomes
and reconcile errors were all kubectl-logs-only, and the log lines could not be
queried on a field.

One recorder and one JSON switch in rustic-git-core so the binaries cannot
drift: RUSTIC_GIT_LOG_FORMAT=json turns the shared subscriber into one object
per line, and the peer router (server) or a RUSTIC_GIT_METRICS_ADDR listener
(api, worker, agent, gateway) serves /metrics. Never a public listener: the
scrape text enumerates repository keys. Counters: HTTP count and latency by
listener, route class and status (413 and 421 named), git pack requests and
bytes in, registry blob bytes in/out, db_fence_detected_total at App::on_fenced
where every path lands, ownership map size and claims (granted/moved/heldby),
renew failures, merge outcomes and duration, reconciles per kind and result,
open gateway tunnels.

deploy/: prometheus.io scrape annotations (no Operator assumed) and
deploy/alerts.md with the PromQL an operator should set.
The image job now needs both build and test, so a red commit has no package at
all — not :latest, not :<sha> — and the deploy side can read "the tag exists"
as "the tests passed". Tests also run on pull requests; build and image stay
push-only. cargo runs --locked like the Dockerfile, every job has a 30 minute
ceiling, both workflows that run bun install or a release start read-only, cross
is a fixed version, kl releases carry a provenance attestation, a weekly audit
covers cargo advisories and bun, and Dependabot moves the SHA pins.
Bumps node from 22-bookworm-slim to 26-bookworm-slim.

---
updated-dependencies:
- dependency-name: node
  dependency-version: 26-bookworm-slim
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
@dependabot dependabot Bot added dependencies Pull requests that update a dependency file docker Pull requests that update docker code labels Aug 29, 2026
@dependabot @github

dependabot Bot commented on behalf of github Sep 4, 2026

Copy link
Copy Markdown
Author

Superseded by #14.

@dependabot dependabot Bot closed this Sep 4, 2026
@dependabot
dependabot Bot deleted the dependabot/docker/web/node-26-bookworm-slim branch September 4, 2026 15:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file docker Pull requests that update docker code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant