Repository navigation
Release v0.12.0 (dev to main, prod promotion) - #1089
Merged
Merged
Conversation
Contributor
|
@jozer-rami — exact-head review of this promotion PR (base Findings
Verified clean
Evidence and limitsCI was green at the fetched head (mcp-host, workflow-recipes, and control-api suites; Real Postgres 16; CodeQL; image gates). Review lanes did not run local tests or runtime/T2/E2E; those remain separate evidence lanes. This comment is the only PR mutation performed; the full sanitized review record is local. |
Ownership of the native sandbox-ui view moves from refs and effect ordering
in the renderer to an explicit (state, event) -> { state, effects } reducer
keyed by launch id. Every event/condition pair is decided by a total table;
unlisted pairs are a no-op by reference. Level rules run after each
transition in a fixed order: sweep non-owner records (drop pre-IPC ones,
close the rest by CAS), advance the owner once its tab has no predecessor in
main, release handoffs whose views are gone, and settle every launch that
left the pending set exactly once.
Not wired into the app yet.
The table suite has one case per row, a totality sweep, one case per level
rule and fast-check properties for settle-once and close-after-open; every
row and rule was mutated and turns the suite red (two equivalent/unreachable
guards kept as hardening).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…gainst the real main process EmbedOwnershipMachine is an external store around the ownership reducer: synchronous dispatch, events raised while effects run are queued, and open and close IPCs are issued synchronously in effect order so a close can never reach main ahead of its own open. A launch that never reaches main (invalid app reference, open throwing synchronously) settles as failed ahead of already-queued events. whenSettled keeps its outcome after settlement so a launch that settles inside the same dispatch can still be awaited. The sandbox-ui Electron fakes move to a shared fixture without behaviour change (lifecycle suite 62/62 before and after). A property suite drives the reducer and interpreter through the real ipc.ts handlers, AppService and driver under fc.scheduler interleavings (mints, measurements, navigation, crashes, renderer reloads, session changes, throwing cleanups, parent window close, deep-link handoff continuations) and checks the ownership invariants on every transition and at rest. The previous renderer-level ownership scenarios are ported as named cases. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… seam Strip select and close, keyboard shortcuts, grid and deep-link app launches and composer focus now activate tabs through activateAndLaunch, which commits the store update and the launch state together under flushSync. The legacy deactivation effect therefore still sees the incoming launch in the same commit, and behaviour is unchanged (the existing ownership suite passes untouched). Every caller passes an updater instead of a value computed from the last committed tabs, so a pending store update absorbed by flushSync (identity reset, embed title, saved route) is no longer silently undone. No other writer of the tab store can activate an app tab; a runtime guard in the new seam suite fails on any app-tab activation outside the seam, on flushSync warnings from a lifecycle, and on a second flushSync call site. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… app view Wire the EmbedOwnershipMachine into App and SandboxUiPage so the renderer no longer emulates main's atomic read-persist-close with refs and effect ordering. - The activation seam dispatches intent/relaunch after its flushSync, with the launch built from the committed tab (reveal gestures) or the new tab (grid, deep link); closing a tab launches only when the commit changed the active app tab. - `projected` comes from a single layout effect; activeSandboxUiApp and the mounted flag are derived from the machine. - Removed the four ownership refs, the deactivation effect, readOutgoingRouteDecision, the handoff copy, the opening/closed/openFailed handlers, and the page-side launch bookkeeping (launchRef, launchSeqRef, release, onClosed, openApp, sandboxUi.reload). - Refresh, Reopen (after a crash) and Retry (session banner) relaunch through the seam; re-clicking a live app tab is a no-op. - A crash while the owner is still opening now shows the crash failure and settles the launch as failed instead of leaving a blank tab. - Deep links await their launch outcome: mounted acks, failed defers, abandoned acks and restores the team. - capturePreview races a 500 ms timeout before hiding the view under an overlay. - App integration tests now cover wiring only; ownership stays covered by the property tests against the real main process. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The renderer now learns about every view's end through sandboxUi:released, so the channels that emulated ownership from the renderer side go away: - sandboxUi:close requires a launchId; closing whatever is live stays available only to main's own callers (session change, renderer replaced). - sandboxUi:getLocation and AppService.getSandboxUiLocation are removed; the final location travels in released. - The sandboxUi:closed event to the renderer is removed; the driver's internal unsolicited-close hook still cancels the session refresh and unpins plugin surfaces. - sandboxUi:reload and AppService.reloadSandboxUi are removed (Refresh now relaunches). The internal reload on a top-level 401 stays. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…on intent A pending same-chat selection advances the selection intent revision but leaves the active switch request in place. When its catalog load fails, the selection effect returns without a switch, and the superseded click returns on its stale revision without confirming or withdrawing the mark. Send and load-older then matched the leftover mark and were refused silently on a blank view. The guards now also require the mark's revision to be current. Row 15 of the provisional-selection suite covers it for both Host kinds; without the revision check both cases fail (send dispatched 0 times). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…3-H1) The split-layout signature accepted any state/state.db*.pre-*.bak name, so a user file such as state/state.dbX.pre-1.bak next to a real workspace/ made a stateful Host run the merge and flatten both folders into the PVC root. The base init writes only state.db.pre-<ts>.bak, state.db-wal.pre-<ts>.bak and state.db-shm.pre-<ts>.bak, so the signature and the database-entry checks now name exactly those three. Class-check: globs in the merge script that decide which names the base init wrote -> 2 sites (signature loop, database-entry refusal loop) -> both narrowed to the three exact .pre-*.bak names; the mcp-host agent-tool prefix rule (protectedPaths.ts, shell.ts) stays wide on purpose, because protection must cover every state.db* name. Repro-test: the no-op case "user state/ folder with .pre-*.bak names the base init never writes" fails at d983af8 (tree changed); restoring the old signature glob alone turns it red again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tted Case 16 opens a chat on another Host from the sidebar while the click's write is pending, then returns to the first chat while its catalog load fails. The superseded click must not leave a provisional mark that refuses send. Runs for chatllm and chatllm-stateless; removing the selection intent revision check turns it red. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The boot retention sweep sent one sweep_closed_sessions operation that ran a single unchunked DELETE with its message cascade and FTS triggers. With a large backlog that one statement outlasts the worker progress bound (CLERUM_DB_WORKER_STALL_TIMEOUT_MS), so the queue latched "db worker made no progress", the Host exited 1, the transaction rolled back, and every restart repeated the same sweep. The operation now takes a required limit and deletes at most that many rows: expired sessions' messages first, then expired sessions once none of their messages remain. sweepRetention repeats it with 250 rows per batch until a batch deletes nothing, so the worker acknowledges every batch. PersistQueue and its progress bound are unchanged. Between batches an expired session can show part of its history until a later batch removes it. Class-check: worker operations whose single ACK covers work that grows with retained history -> 1 op with a live caller (sweep_closed_sessions, from main.ts boot) -> converted; the processing and expired-approval reaps grow with in-flight sessions and pending approvals, not history (27 ms per 500-session chunk measured), and are unchanged. Repro-test: sweepRetention.realWorker.test.ts seeds 300k expired messages and runs the sweep on the real worker with a 1000 ms bound; at 3158019 it fails with "db worker made no progress for 1000ms". sessionSearch.test.ts #13 fails there with one operation. Ignoring the limit in the dispatcher, an unbounded batch size or dropping the caller loop each turn both tests red. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
persistFailureExit.test.ts runs the real factory, queue and handler, but re-implements main.ts's shutdown flag and final process.exit, so nothing executed main.ts's own wiring: process.exit(exitCode) -> process.exit(0) or () => isShuttingDown -> () => false stayed green and type-checked. The new test compiles the real main.ts and dbWorker.ts and boots the Host in dev mode with the SQLite store. A test-side --require preload replaces worker_threads.Worker so the DB worker is still the real one and only controls one delivery: it withholds the shutdown message (graceful shutdown whose store close stalls) or terminates the worker on SIGUSR2 (worker exit while serving). No production code changes. Class-check: main.ts lines that decide the process exit code on a persist failure -> 3 (the onPersistFailure option, the shutdown-flag getter, the final process.exit) -> each pinned by one scenario. Repro-test: the wiring is correct at 3158019, so red-first is by mutation, each of which type-checks: process.exit(0) turns the shutdown scenario red (exit 0), () => false turns it red (the in-service handler logs), removing onPersistFailure turns the serving scenario red (no handler line). Unmutated: 5/5 green. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The sidebar now paints the local cache before the Host catalogs arrive, so a
chat hydrated from the server showed its placeholder title ("New Chat") until
the Host answered, which for a suspended stateless Host means the whole wake.
The server title only lived in the in-memory catalog merge.
The existing freshness write (chat:reconcileSessions -> upsertServerSessions)
now carries the server's own title, and the store writes it into entries that
are already in the index without moving updatedAt. Server-only sessions and
deleted chats are still never created. A chat with a pending local rename
does not send a title, so the optimistic title is not overwritten. The
cross-Host publication writes its Host's titles too, so a Host the user never
selects keeps them across restarts. The next catalog page overwrites the
stored value, so it follows server-side renames.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A chat that exists only on the server enters the local index when the user opens it, through ChatStore.createChat, which stored 'New Chat'. The catalog page that carried its server title had already been reconciled before the chat was in the index, so the title reached the index only on the next launch's catalog load, and that launch still painted 'New Chat' from the cache first. upsertServerSessions now keeps the titles of server-only sessions in memory, and createChat uses (and drops) the remembered title for a new entry. A session reported without a title (a pending local rename) forgets the remembered one, so an outdated server title is never written. No entry is created for a server-only session, and a locally deleted chat is still refused by createChat. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Installations upgrading from 0.10.x/0.11.x rely on CONTEXT_MAPPER_WORKSPACE_LAYOUT_MERGE staying at its default to merge split stateless PVC trees; a shipped overlay that set "false" would start those Hosts on an empty database with no error. scripts/tests/test-hcc-layout-merge-flag-render.sh reads the four rendered minikube overlays and requires the HCC container to exist with CONTEXT_MAPPER_HOST_IMAGE (liveness) and the flag to be unset or "true". A negative control injects "false" into one render and must be rejected, and every expected overlay must be checked. deploy-manifest-check renders the two ghcr overlays as well and runs it; no cluster is involved. Refs #825 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Installations upgrading from 0.10.x/0.11.x already have stateless Host Deployments with the split template: workspace-layout-init, workspace and state subPath mounts, CLERUM_SESSION_DB_DIR=/var/lib/clerum/state and a RollingUpdate strategy. Nothing tested that this HCC replaces them. The fixtures are the Deployments v0.11.0's HostReconciler renders for a stateless active and a suspended Host with the lifecycle test mocks; they differ from this head's render only in the storage fields. The test persists each one as the live Deployment, reconciles once and requires one replacement with workspace-layout-merge, no subPath, the root DB dir, Recreate and the replicas kept (1 and 0). A second reconcile must not replace it again. Refs #825 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
deploy/scripts/host-layout-merge.sh tells an operator, on any cluster, what the workspace-layout-merge init will do to every Host PVC before an upgrade (inventory) and whether CONTEXT_MAPPER_WORKSPACE_LAYOUT_MERGE can be turned off (verify). Each PVC is classified by a short-lived read-only Pod that runs the merge script itself with the moves removed: deploy/scripts/workspace-layout-merge.sh is the exact output of buildWorkspaceLayoutMergeScript(), and check-script rewrites it line by line with counted asserts, so a changed merge script stops the check instead of drifting from it. Writability is read from mode bits because the check mount is read-only. - inventory reports WILL_MERGE, WILL_REFUSE_F1..F4 (with the init's own line), NO_SPLIT_SIGNATURE or UNREADABLE per PVC, PRE_825, the desktop export warning, UPGRADE_BLOCKERS, orphan PVCs (reported, not blocking) and FLAG_FALSE_WITH_SPLIT_TREES. - verify reads the merge init status of running Host Pods and checks every other PVC; it passes only when every Host Deployment renders the merge init and no tree still carries the split-layout signature. - Every kubectl call names --context; check Pods run as uid/gid 1001 with no service-account token and are deleted after their log is read. Tests: deploy/scripts/host-layout-merge.test.mjs (fake kubectl, 17 tests, wired into the ci-public #825 helpers step). Every tree in the HCC merge test file is also run through the check and must agree with the real merge, and the committed copy must equal the builder output. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
S5 seeds the inventoried split tree on a suspended Host: before the wake, deploy/scripts/host-layout-merge.sh must read that PVC as WILL_MERGE (inventory) and SPLIT (verify); after the merge, verify must read it as POD_OK. S6 seeds the T5 shape (root database, state/state.db, workspace/): before the wake, inventory must predict WILL_REFUSE_F2 with the init's own line, and its check Pod runs between the two tree hashes, so the existing "tree unchanged" assertion also covers it; while the Host is in Init:Error, verify must report MERGE_REFUSED with the F2 line. The assertions read only that PVC's row and the exit code; the fleet verdict depends on the other Hosts of the profile. Exit 2 always fails. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Opening a chat with an empty local cache whose history starts at turn 1
replaced its title with the first user message, even when the index
already held the server's title. The first message now names the chat
only while it has no title yet ('New Chat'); the title stays ephemeral.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Installations that run v0.10.x or v0.11.x have stateless Hosts with split PVC trees. The new note explains how to run host-layout-merge.sh before and after the upgrade, what each result means, how to repair a Host the merge refuses (including a Host switched from stateless to stateful on those releases), when the flag can be turned off in the installation's own overlay, and the rollback rule. host-storage-layout.md: criterion 4 of the turn-off is now "no Host PVC still carries the split-layout signature", checked by the script; the F2 case names the pre-upgrade origin; the Tests section lists the script tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…T-002) ensureFontsReady marked itself ready before loading the bundled Roboto faces, so one failed load left the process on system faces for good. A failed load is now tried again after 30 seconds, 5 minutes and 30 minutes, registering only the faces still missing; after the last try the system faces are used for the life of the process and that is logged once. The system faces register once, as before. Refs #1118
…-004) A sparkline Chart.js refused was removed with its container, so the KPI lost its trend without a word. It is now replaced by a short fixed note, 'Trend could not be drawn', set as text and without the error's details; a sparkline that draws is unchanged. Refs #1116
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…into HEAD # Conflicts: # README.md
# Conflicts: # mcp-host/package-lock.json # mcp-host/package.json
# Conflicts: # docs/surfaces/desktop-app.md
Adds scripts/e2e/e2e-hcc-layout-upgrade.sh and the Makefile target test-e2e-hcc-layout-upgrade, an opt-in lane on its own fresh branch profile (plan A7.40, commit 2b). main installs v0.11.0 (published images; this tree's manifests and CRDs, checked equal to the tag), seeds one Host per row (T1 stateful, T2 stateless active, T3 stateless suspended, T5 stateless switched to stateful by a CommunicationChannel, T6 stateless -> stateful -> stateless), checks host-layout-merge.sh inventory, upgrades to this head with the database kept, checks verify, wakes T3, repairs T5 with the upgrade-note procedure, and checks the history and seed file of every row. control upgrades with CONTEXT_MAPPER_WORKSPACE_LAYOUT_MERGE=false and must see inventory report FLAG_FALSE_WITH_SPLIT_TREES and the history check fail; E2E_UPGRADE_RESULT=PASS needs the main log of the same HEAD. The helpers shared with e2e-hcc-storage-layout-switch.sh move to scripts/e2e/e2e-825-lib.sh. Unit tests cover the main-evidence check and the mode and context refusals. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e guard Rework scripts/validate-nginx-images.sh after the consolidated review of #1177 (C-01..C-05, C-07..C-11, C-13 in part): - One scanner: grep lists the files that mention nginx, then the tagged, untagged, shell-array and same-line image: rules run on that list. The rg branch, the awk YAML reader and the unchecked find are gone; every grep listing goes through scan_or_fail, which fails on status > 1. - Kustomizations are found by filename (kustomization.yaml, .yml and Kustomization) and their images: entries are read with yq, so flow lists, flow maps and JSON bodies are checked. The NGINX rule applies to the resulting image (newName, else name). - Untagged NGINX names are rejected in an image field, a Dockerfile FROM (any case, with flags) and shell arrays; an image: key with its value on the next line is rejected. A trailing '@' is an error. - Registry-qualified references keep their registry in --list-digest-pins. - The release floors, the tag grammar and the NGINX name test move to scripts/nginx-image-policy.sh, shared with the digest verifier. FIXED_NGINX_IMAGE_DIGEST is removed: the Dockerfile must have exactly one FROM, FIXED_NGINX_IMAGE pinned by a well-formed digest, and the verifier proves the digest is that release. - Scan scope: surfaces that are deployed, pulled or copied by users. Unit-test files that never pull an image leave the list; tests/e2e/playwright/control-ui/recipe-scope-copy.spec.ts joins it. The contract test copies the policy file, compares the scan list with its own, and covers each new rule with a negative case and a positive one (208 cases). nginx-egress-proxy/README.md no longer repeats the base version and documents the bump procedure. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rror scripts/verify-nginx-image-digests.sh now sources the shared NGINX policy, rejects a reference with a policy problem or without a digest before any registry call, and inspects each pin once under the name it is written with, so a registry-qualified pin is read from its own registry (C-09). With NGINX_REGISTRY_MIRROR set, Docker Hub names are inspected on that mirror at the same digest; a failed inspect is an error, with no retry and no second registry (C-06). New offline contract scripts/tests/test-verify-nginx-image-digests.sh (C-12): a fake docker records every call and answers with inline image configs. 15 cases cover a match, mismatches on one or both platforms, a missing platform, an inspect failure, rejections with zero registry calls, an empty reference list, the mirror rewrite and a registry-qualified pin. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Docker Hub throttles anonymous pulls, and the rest of ci-public.yml already pulls Docker Hub images through mirror.gcr.io (C-06): - Validate platform NGINX images: timeout-minutes 10, a step for the offline verifier contract, and NGINX_REGISTRY_MIRROR=mirror.gcr.io for the registry check. - Egress proxy TLS: timeout-minutes 20 and the same variable. With the variable set, test-nginx-egress-proxy-tls.sh builds the proxy with --build-context mapping the Dockerfile FROM to the mirror reference at the same digest, fails unless the build log names that reference (a non-matching key is ignored by BuildKit, which then pulls Docker Hub), and starts the upstream from the mirror reference. Unset, the test is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rship refactor(desktop-app): own the embedded app view in a state machine
…under entra-v2 (BR2-M1) ENTRA_BLOCKED_RESOURCE_APPS missed several high-impact Microsoft first-party APIs, so their GUID-form scopes classified as an unknown 'guid': reported as unverified at discovery, confirmable at install and accepted at runtime. A GUID names no host, so a confirmed one would let Entra mint a token for that API and hand it to whatever MCP host the CR points at. Add Dynamics CRM, Azure SQL Database, Log Analytics API, Skype and Teams Tenant Admin API and Microsoft Teams Services (16 entries). The classifier logic is unchanged; only the closed table grows. Only the GUID form is blocked. A first-party MCP server whose audience lives on its own host (e.g. Dataverse at <org>.crm.dynamics.com/api/mcp) is still connected with that host's URL-form scope, which the host rule accepts. The map comment and the how-to doc no longer claim these APIs never host an MCP server. Deliberately not blocked, because their URL-form audience lives on a host other than their MCP server, so the confirmed GUID form is the only way to connect them: - Azure DevOps (499b84ac-1321-427f-aa17-267ca6975798), MCP server at mcp.dev.azure.com; - Power BI Service (00000009-0000-0000-c000-000000000000), MCP server at api.fabric.microsoft.com, URL audience on analysis.windows.net (which classifies as 'foreign'). Both stay unknown GUIDs that need confirmation; the map comment, the doc and a test pin that decision. Collateral (intended): - discovery now reports these scopes as a violation instead of unverified; - install returns 400 scope_audience_mismatch for them even when the operator confirms the scope; - an existing CR carrying one of these GUIDs stops resolving at runtime (409 remote_oauth_spec_incoherent, reason scope_audience_mismatch) on authorize-url, user-token, the callbacks and the refresh reader; revoke and sweep still get the grant coordinate. Class-check: `ENTRA_BLOCKED_RESOURCE_APPS` across evenfire (src, test, ui, docs) -> 1 reader (classifyEntraScope, asProfiles.ts) plus 3 literal mirrors (BLOCKED_LITERAL and blockedGuids in test/oauth.asProfiles.test.ts, the "Blocked APIs" paragraph in docs/how-to/connect-oauth-connector.md) -> all 3 mirrors updated; no other reader exists (control-ui only renders control-api verdicts). No pattern rule added by design. Repro-test: control-api/test/oauth.asProfiles.test.ts:450 and control-api/test/oauth.remoteSpecCoherence.test.ts:309 (fail at b001d28: profileScopeViolation returns null instead of the scope for all 10 new GUID scopes, the 16-entry table equality fails, and the Azure SQL runtime case resolves instead of throwing remote_oauth_spec_incoherent; 30 assertion failures, 0 setup errors; the Azure DevOps / Power BI pins pass there by design) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
T0 runs npm test in the nearest package of every changed file and skips only tests/e2e/**. workflow-recipes/tests/e2e is a live-cluster suite whose context defaults to clerum-test; T0 runs before any profile is bootstrapped, so a diff touching it stops the T2 lane with context "clerum-test" does not exist (19/19 files failed). Skip */tests/e2e/** as well. In the current tree that adds only workflow-recipes/tests/e2e. Refs #1184 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Conflicts limited to control-api and control-ui package.json/package-lock.json version fields: kept the branch's higher version; dev's Node engine bump (>=24.22.1) merged cleanly. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
feat: remote OAuth lane for Microsoft Entra ID (entra-v2 profile)
Resolve the control-api and control-ui version conflicts to the dev version plus one patch (0.1.815, 0.1.744), so both packages stay bumped against the base. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ubuntu-latest now resolves to ubuntu-26.04, where Playwright 1.58 cannot
install Chromium ("Playwright does not support chromium on
ubuntu26.04-x64"), so the desktop-app and external-rest-api legs fail in
`npx playwright install --with-deps chromium`. Pin the job until
Playwright supports 26.04.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…de properties
- A '*' tag is no longer skipped as a policy glob. No scanned file holds
one, and `nginx:${NGINX_TAG:-1.30.*}` in a shell script passed.
- A Kustomize newName that carries its own tag or digest is classified by
its repository part, so `newName: "nginx:1.30.5-alpine"` is checked.
- `COPY --from=nginx` and `RUN --mount=...,from=nginx` count as untagged
image positions.
- An untagged name after a YAML anchor or tag (`&a`, `!!str`) is rejected.
Each rule has negative cases in the contract test and a recorded vacuity
mutation. A name reached through a YAML alias or a shell variable is
still not resolved; the header says so.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The verifier joined platform and version into text lines and compared the second whitespace field, so `NGINX_VERSION=1.30.6 extra` passed and a value with an embedded newline could stand in for a missing arm64 manifest. Each required platform is now looked up in jq and its value is compared whole, still JSON-encoded; an absent platform is null. The contract test reads the release from FIXED_NGINX_IMAGE instead of a literal, so a bump or a floor raise needs no edit there, and adds the two cases above. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tyContext The TLS test hand-copied the docker flags for the egress-proxy container. It now builds the Deployment with the HCC reconciler, maps the egress-proxy securityContext to docker flags, and stops on any field or value it does not map. After start it checks the NGINX master's /proc/1/status: generated uid/gid, empty CapEff and CapBnd, NoNewPrivs 1 and Seccomp 2 (RuntimeDefault is the engine default profile). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…est in the bump steps Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rity-upgrade fix(nginx): upgrade platform NGINX images to 1.30.6 for October 2026 advisories
# Conflicts: # external-rest-api/src/releaseManifest.ts
feat(control-api): return secret identity in the mcp-secrets list
Brings dev up to 49ed0f1 (1537 commits). Three files conflicted; each resolution keeps BOTH sides where the changes are disjoint, and follows dev's newer model where the two genuinely overlap. useComposerAttachments.ts - dev replaced the image-only mirror with `composerImagesRef` / `composerReferencesRef` and the `commitComposerImages` / `commitComposerFiles` helpers, and added the document-attachment model. This branch's STORY-38 restore path had added its own `composerImageAttachmentsRef` / `composerReferenceAttachmentsRef` mirrors with the same purpose (written inside every state updater, so they reflect committed transitions), and its own exported merge functions. The restore path now uses dev's mirrors and commits through `commitComposerImages`; a matching `commitComposerReferences` helper keeps the reference mirror live (dev's own reference handlers did not write theirs inside the updater). - dev renamed `COMPOSER_MAX_IMAGE_ATTACHMENTS` to `COMPOSER_MAX_ATTACHMENTS` and made images and documents SHARE one per-message count. The image merge now takes the documents already attached as occupied slots, so a restore cannot push the composer past the shared ceiling; the cancel-restore toast names the shared "20-attachment limit" instead of the old image-only limit. - dev removed `clearComposerDraftAfterSend` and the `clearComposerAfterSend` wrapper, and returns `clearComposerDraft` from the hook instead. This branch used that wrapper only through dev's own send-path cleanup, which dev has since rewritten, so the wrapper is gone with it. - The reference merge keeps `FILE_REFERENCE_MAX_COUNT`: dev still caps the Global Files a message may reference at that number. useAgentChatController.ts - the parked-restoration queue (R2-M1 / R3-M4) and dev's `readyComposerFiles` memo are disjoint, so both are kept. - the cancel path keeps this branch's `restoreComposerAttachmentsAfterCancel` call and dev's note that a snapshot holding documents the Host never received stays for Recover files. - dev's own send-path cleanup (origin-scoped draft clearing, `sendStillAuthorized`, `resetComposerAttachments`) is taken as-is: this branch never changed it, so nothing of this branch's is lost. ComposerPanel.test.tsx - the type import list is the union of both sides. Also: dev raised the Node floor to 24.22.1 (.nvmrc), so the local toolchain was moved to it, and mcp-host's dependencies were installed because dev's new native-canvas tests need @napi-rs/canvas.
…on bumps) The dev merge's pre-commit hook reformatted 11 of dev's files: the repo's LOCKED prettier (3.8.2, per package-lock.json) breaks long unions onto one member per line, while dev's tree is formatted with prettier 3.9.9, which keeps them inline. The reformat is cosmetic, but it made this PR differ from dev in four backend services — and `validate-release-version-bumps` reads that as "external-rest-api code changed but its version stayed at 0.1.136", which reddened CI. This restores dev's exact bytes for all 11 files, so the PR's diff against dev is again only the Desktop lane's own work, and realigns the lane's own files to the prettier dev's tree actually uses. The pre-commit hook bumps the version of every service whose files are staged, so restoring these files bumps control-api, control-ui, external-rest-api, host-context-controller and mcp-host. Their CODE is byte-identical to dev again, so those bumps are reverted in the next commit: nothing in this PR changes those services.
The previous commit restored dev's exact bytes for the eleven files the dev merge's pre-commit hook had reformatted. The hook bumps the version of every service whose files are staged, so that restoration bumped control-api, control-ui, external-rest-api, host-context-controller and mcp-host — even though their code is byte-identical to dev again. This returns those five versions, their lockfiles and the release manifest to dev's values, so this PR changes no service at all: the only difference between this branch and dev is the Desktop lane's own work. `validate-release-version-bumps` now finds no changed service code against dev, and the release manifest matches the package versions.
fix(desktop): keep attachments on cancel, folder zip download, chat pill pointer, centered gear
chore(release): prepare v0.12.0
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Promotes
dev→mainfor the v0.12.0 prod deploy and tag (merge commit, not squash).One merge serves both the prod promotion and the release. The release-prep commit (#1171) lands on
devfirst, so the images prod promotes already reportreleaseId: v0.12.0. The v0.11.0 cycle promoted first (#1063) and bumped after (#1067), and needed two extra prod applies to fix the reported version.Dev HEAD
88479f5(#1171) is the pin set dev deployed and verified (infrapin-status.yaml:verified: true, infra commit825da97, pipeline run 40287842008 attempt 2). Dev'sexternal-rest-apirunssha-88479f5and reportsreleaseId: v0.12.0.Attempt 1 of that dev deploy failed with the Codex/JWT guard's
inputs_changed(phase: migration,verdict: UNAVAILABLE). The guard started 2 seconds after the inter-service token step restarted the Deployments it reads. The same failure happened on Oct 19 (infra run 39257220008). A rerun passed.Release prep
Included PRs
Deploy notes
charts/clerum-crds/**changed (4 CRDs):mcpserveraddsspec.oauth.asProfile(enumentra-v2) and its CEL rules (feat: remote OAuth lane for Microsoft Entra ID (entra-v2 profile) #1176). This is a schema change, and prod's CRD does not have the field yet (checked read-only on 2026-10-23).host,llmhookandglobalfilesystemare description-only (chore: fix stale references, CRD descriptions and dead config keys #1075).gcp-prod-deploy-crdsafter this merges and beforemode=apply.mode=diffconfirms the mismatch first.deploy/base: the NGINX gateway images move tonginx:1.30.6-alpine(fix(nginx): upgrade platform NGINX images to 1.30.6 for October 2026 advisories #1177), and HCC no longer sets the staleSTDIO_BRIDGE_IMAGEenv (chore: fix stale references, CRD descriptions and dead config keys #1075). Smaller edits touch the profiles ConfigMaps, webhook-ingress (proxy and NetworkPolicy), cloudflared, and the workflow-output PVC.CONTEXT_MAPPER_WORKSPACE_LAYOUT_MERGE="true"ingcp-prod(infra#126). Runbook: infradocs/deploy/hcc-workspace-layout-merge.md.mode=apply: rundeploy/scripts/host-layout-merge.sh inventoryagainst prod and expectUPGRADE_BLOCKERS=0. AnyWILL_REFUSE_F<n>Host goes toInit:Errorat the deploy unless repaired first.WILL_SUPERSEDEis not a blocker.DESKTOP_HOSTSis above 0, copy/workspace/state.db*out of those live Pods first. The first rollout of fix(storage): one pvc storage layout for every host lifecycle #1111's HCC otherwise loses their conversation history.verifyon prod. OnHOST_LAYOUT_VERIFY=PASSandORPHAN_SPLIT=0, merge infra#128 (prod switch off) and dispatch prod again.deploy/base.🤖 Generated with Claude Code