Skip to content

Release v0.12.0: promote dev 27776e8 to main (second prod promotion) - #1208

Merged
jozer-rami merged 203 commits into
mainfrom
chore/promote-v0.12.0-27776e8
Oct 28, 2026
Merged

jozer-rami merged 203 commits into
mainfrom
chore/promote-v0.12.0-27776e8

Conversation

@jozer-rami

Copy link
Copy Markdown
Contributor

Promotes dev at 27776e8 → main for the second v0.12.0 prod deploy. Merge with a merge commit, not squash.

v0.12.0 is not tagged yet. The tag goes on this PR's merge commit instead of 304766ab, so the release matches what prod will run. The release coordinates already say v0.12.0 from #1171 (releaseManifest.ts, the ghcr-images component, the desktop package), so this PR needs no version change.

The head branch chore/promote-v0.12.0-27776e8 is fixed at dev 27776e8ae, the tested head. Anything merged to dev later stays out of this promotion.

What dev verified

Included PRs

PR Area Tested
#1193 feat(control-api): bind OAuth broker and control token to the authenticated Host control-api Yes, by the team. Prod read-only checks are clean (see Deploy notes).
#1167 Fix EvenDrive folder drag-and-drop and inherited access visibility control-ui, desktop, gfs-interaction-policy Control UI: 11 drag-and-drop checks plus manual inherited-access sharing and a real Finder drop, all on dev. Desktop: not tested; desktop builds are held.
#858 fix(control-ui): Secrets connector tab affordances and footer copy control-ui Key rotation passed on dev. Attaching an existing Secret through the new picker was not tested.
#1195 fix: extend invitation links to one week control-api, control-ui, profile-ui The 7-day expiry shows in a dev invite email. Revoking pending invites when a Control Admin is retired was not tested.
#1198 fix(control-ui): keep test fixtures out of the image build context control-ui build, CI Build & Publish is green.

Deploy notes

  • No changes to charts/clerum-crds/**, deploy/**, database migrations, RBAC or ServiceAccounts. fix: extend invitation links to one week #1195 adds no migration: its two temporary migrations were removed before merge and never reached dev.
  • Every prod service restarts once. Every prod image pin moves to sha-27776e8. That covers all Hosts: 14 running, plus outreach-assistant, which is suspended.
  • feat(control-api): bind OAuth broker and control token to the authenticated Host #1193, OAuth broker:
    • Current Host control tokens have no host_uid, so each Host gets one 401 and one renewal after the apply.
    • The change assumes control-api runs replicas: 1 with Recreate, which deploy/base sets and the prod overlay keeps.
    • Prod read-only checks on 2026-10-27:
      • No McpServer uses spec.oauth, so no OAuth grant changes behaviour.
      • No Host is named standalone.
      • Every Host points at a Context that exists.
      • All 15 refresh tokens carry the HCC audience and a host_uid that matches the live Host.
    • Watch: on dev, product-stateless gets one workflow refresh 401 after each credential re-issue and recovers on the next one.
  • Host PVC layout merge: prod still has CONTEXT_MAPPER_WORKSPACE_LAYOUT_MERGE="true" because infra#128 is not merged. The merge init runs again on every Host restart. It exited 0 on every Host at the Oct 26 deploy and again after the node replacement that evening.
  • Desktop builds stay held while Electron is 41.10.7.

Follow-up

🤖 Generated with Claude Code

https://claude.ai/code/session_01Ua3JRtcTHSc4LDgPZNRnUf

miguelo-999 and others added 30 commits September 25, 2026 22:11
- Connector tab rows get a row actions menu: a functional Update action
  opening a new edit page that reuses the existing secret rotation API,
  and a disabled Delete with a neutral reason until an identity API for
  connector secrets exists
- Remove the internal implementation-status note from the tab footer
- Fix the footer spacing typo ("Click Addon a Missing row")
…dential panel

Address PR #858 review: the connector-secret edit page no longer runs a
parallel thinner rotation flow. It now resolves the connectors that
reference the Secret and embeds the existing UpdateConnectorCredentials
panel, so a rotation from the Secrets table gets the same guarantees as
the connector edit page:

- success is derived from the connector's own fresh DeploymentReady
  condition (bounded poll), never from the PUT's 200 alone
- a 404 on the rotate PUT latches into the recreate (set) form demanding
  every declared key, instead of a bare error
- inputs are limited to the connector's declared keys with aria-invalid
  validation and schema labels, removing the freeform key path that
  could silently ADD a typo'd key via merge-patch
- multiple referencing connectors get a chooser tab; the Secrets table
  Update action passes ?server= when exactly one connector is attached

Supporting changes:
- extract resolveEnvSecret/resolveRegistryCredentialSource from the
  mcp-servers edit page into
  UpdateConnectorCredentials/mcpServerCredentialResolvers so both pages
  share one derivation
- Secrets connector rows: drop the single-child wrapper div around the
  row actions menu
- restore the multi-line union/cast formatting reverted by the previous
  commit's formatter run (unrelated hunks only)

Note: committed with --no-verify; the pre-commit hook's prettier step
cannot resolve a root prettier install in this environment. Its steps
were run manually: version bump staged, all changed files formatted
with the provisioned prettier 3.9.9, style-rules green.
Execute the registry install Secret-name and envSecret expressions in frontend fixtures, and use the HCC-derived SecretResolved condition. Keep direct-CRD edge cases separate from registry-backed table coverage.
Connector credential-edit fixture contract (Round 4)

| Case | Source of truth | Allowed caller inputs | Use |
| Registry/API/HCC seam | Execute the registry install producer's Secret-name, envSecret, and McpServer metadata expressions from control-api/src/routes/admin/registry.ts; use HCC source-derived condition builders for reconciled status. The API response wrapper must carry the producer result without remapping it. | Registry entry identity, credential-schema key names, server name, and condition timestamp/phase only. | Certifies rendered Secret/connector row, credential key mapping in the edit page, affected connectors, and form behavior. |
| Direct CRD/adversarial shapes | Separate, explicitly named fixture builder. | Explicit metadata, Secret reference and key-to-env mapping; malformed names and shared Secret references are permitted here. | Tests UI behavior for legal direct-CRD mappings or invalid persisted references, without claiming registry-install provenance. |

Ownership: in registry installs, the credential schema key name becomes both envSecret.keys[].secretKey and envSecret.keys[].envVar; callers may choose schema input but may not rewrite either output. Registry/API own McpServer metadata and the API response envelope; HCC owns status.conditions and timestamps. A test may select an HCC-produced condition state, but may not hand-author its fields. Direct-CRD fixtures must never import or mutate a registry-produced envSecret. Producer drift must fail fixture construction or a visible UI assertion.

Implementation: split the current overloaded McpServer fixture into registry-backed and direct-CRD builders. Extend the source-derived registry producer helper to include metadata, and feed HCC-derived conditions only into the registry response builder. Update the table, edit-page, and affected-connector tests to use registry fixtures for registry claims; retain a separate direct-CRD builder for shared references and malformed identity cases. Resolve only merge-required changes in the page and its test.
Preserve the noncanonical Secret guard and the OAuth credentials panel in the MCP server edit page. Keep dev's higher Control UI version 0.1.663 and regenerate its lockfile from the matching dependency manifest. Derive registry fixture response metadata through the API test gateway shape.
Execute the registry producer's mcpServerSpec.managed expression when building credential contract fixtures. Reject ambiguous or later managed assignments, and assert the resulting managed state alongside rendered page and table behavior.
Fail fixture construction when the registry producer mutates managed after spec initialization, including computed property writes and mutating object calls. Cover an in-memory computed-property mutation that the prior fixture accepted.
# Conflicts:
#	control-ui/package-lock.json
#	control-ui/package.json
Pure, transport-independent move-adjudication core for the EvenDrive
drag-and-drop lanes (rev-2 F0): structure verdicts with the common-anchor
sufficient-negative proof, Control UI canonical-path guard with segment
boundaries, exact independent-bit authority verdicts, and the selective
move-convergence planner, plus a three-attempt-per-gesture network cap.
Property tests run on seeded random trees.
…chain

D1 core of the EvenDrive drag-and-drop lane (rev-2): one per-session
GfsDragSessionProvider holds the single active in-window drag source bound to
env:user:team scope and the shared access-state query (logout/revocation
clears the drag); drag constants move beside GFS_DRIVE_MAIN; the
gfs:moveResource IPC chain (preload/renderer types/ipc/appService/uriHandler)
gains an optional trailing newName for combined rename+move PATCHes.
…ar explorer

D1 of the EvenDrive drag-and-drop lane (rev-2): files AND folders drag from
both Desktop surfaces through one session-scoped coordinator; directory rows
adjudicate structure (common-anchor facts, <=2 bounded drop resolves) and
exact authority bits (destination write, source-parent write+delete) via the
shared TanStack affordances keys with a budgeted, debounced cold-check path;
folder drops stop at one impact/naming confirmation; every commit runs the
shared move dispatch (fresh ifMatch, whole-resource numbered rename within 3
network attempts, 412 new-gesture, transport-loss verify-by-resolve); move
receipts converge the shared cache selectively. Sidebar rows gain the Move
action (button + Shift+F10) into the existing Move dialog and hover-expand;
the tree's deferred click cancels on dragstart. Policy: destination-first
authority evaluation; null-tolerant ancestor chains in the shared package.
…tion

D2 of the EvenDrive drag-and-drop lane (rev-2): operator-plane browser rows
drag files AND folders; folder drops run the fresh canonical-path structural
guard (segment-boundary descendant/self/same-parent/root detection; null or
stale paths defer to the atomic server check) and stop at ONE impact dialog
that also records the numbered-name policy; the move loop is bounded to three
network attempts per gesture, whole-folder renames ride the same PATCH, and
folder moves carry the inherited-access info toast. Adds the cu-
GfsMoveConfirmDialog component and its token-scoped styles.
…ation runs

Mapping every non-'allowed' hover verdict to dropEffect 'none' made Chromium
cancel the drag at release — the drop event never fired, so the priority
adjudication on drop (rev-2 §4.1) could not run and any drop whose affordances
had not resolved within the hover dwell was silently swallowed on both the
Files page and the sidebar file explorer. Only an observed deny now refuses
the drop; checking stays landable and the drop check commits or toasts.
…cation

The browser fires dragend immediately after drop, while the drop handler is
still awaiting its affordances adjudication. Both surfaces bumped their gesture
counter in the dragend cleanup, so once the adjudication resolved the captured
generation never matched and the handler returned silently — cache-cold drops
(fresh folders, first-time targets) lost that race every time: no move, no
folder confirmation, no toast, no server call. The counter now marks gestures
only (dragstart), which still invalidates decisions from superseded drags.
Verified live against dev: file drags commit and folder drags open the one
confirmation.
miguelo-999 and others added 29 commits October 26, 2026 15:28
…roperty

The CI seed (-339556019) exposed a formula bug in the property: it
counted identical incoming attachments individually, so five copies of
one image at the cap were expected to overflow-drop even though the
merge classifies four of them as duplicates of the first (R2-L1/R4-L1:
incoming duplicates never count as drops — this property's own title).
The expectation now replays the documented sequential classification:
duplicates of anything already accepted are skipped, only
non-duplicates past the free slots are dropped.
The process documents have served their purpose: the implementation
they specified is merged and the wording contract lives in the code
and its regressions. control-ui's gfsDragFeedback comments keep the
historical citation.
…op-fix

Fix EvenDrive folder drag-and-drop and inherited access visibility
Finding: password-setup resends use member_invitation (168h); dedicated password resets
remain purpose=password_reset (48h).

Class-check: purpose selection -> setup resend producer and TTL store branch -> retain
seven days for setup and 48 hours for password_reset.

Repro-test: control-api/test/services.invitationTtl.test.ts (fails at
5df46a7: expected 168 hours, received 48).

Validation: actual producer tested on PostgreSQL 16; focused tests and full API suite pass.
Finding: Zach R2-L1 — the two defaults-only migrations were never deployed.

Class-check: migration version -> registry and deploy path -> remove unpublished 0130/0131.

Repro-test: control-api/test/db.invitationExpirationTtlMigration.test.ts

  (fails at 07ff7a5: migration list contains 0130/0131).

Validation: focused migration registry test passes; migration application is also covered by CI.
Finding: an invalid expiresAt must not be presented as a 48-hour link.

Class-check: expiry formatter -> helper and invitation consumer -> omit unknown durations.

Repro-test: profile-ui/app/components/__tests__/InvitationClient.reset.test.tsx

  (fails at 07ff7a5: the invalid timestamp renders a 48-hour notice).

Validation: formatter tests and the focused InvitationClient suite pass.
Finding: route persistence completes in an async continuation after the close event.

Class-check: ownership route restore and preview handoff -> 2 assertions -> await the existing
main.settle() signal in both paths.

Repro-test: desktop-app/ui/src/__tests__/App.sandboxUiOwnership.test.tsx:549 (CI observed
failure at fcafbe7, run 40389221221: expected '/inbox',
received undefined).

Validation: Node 24.22.1 and verified Electron; focused ownership suite passed 34/34.
Finding: bind the shared 168-hour Control Admin duration as data.

Class-check: interpolated INVITATION_TTL_HOURS -> Control Admin INSERT -> bind as integer $4.

Repro-test: control-api/test/services.controlAdminInvitationTtl.test.ts (fails at
427f3c1d940a52ef6a09a12f38ccc417ed197d25: SQL text lacks the bound TTL parameter).

Validation: focused parameterization test and full required-PostgreSQL API suite pass.
Class-check: `retireControlAdminInTransaction(` -> 2 production callers -> both revoke pending
and opened admin invitations with pending paired Desktop links.
Repro-test: `services.controlAdminReplaceInviter.realPostgres.integration.test.ts -t legacy paired`
fails at 3da6d69: expected revoked, received pending.
Class-check: credential-assignment pattern -> invitation TTL fixture -> mark as synthetic.

Repro-test: `bash scripts/tests/test-minikube-t2-public-boundary.sh` fails at

  `18f1d022b67ed42ddbe31297419f0a54f4afcc05` with a credential-assignment finding.
Class-check: invitation-row revocation race -> 1 completion path -> preserve coverage

Repro-test: PostgreSQL 16 integration test passes at 3a710ee; removing the guard in an isolated worktree makes it fail with an active admin instead of not_found.
…hdrawal (R3-M2)

Class-check: migration tail pin -> 1 test -> keep withdrawn-ID checks, drop tail assertion

Repro-test: npm test -- test/db.invitationMigrationHistory.test.ts (2/2 pass).
Old at(-1) assertion rejects PR #1197's 0130_password_login_success_admission fixture.
Class-check: package version parity -> 2 manifests -> bump one patch above origin/dev

Repro-test: node -e package/dev patch-parity check fails at 3a710ee; both are 0.1.748.
  It passes after package.json and package-lock.json move to 0.1.749.
Class-check: admin-deletion guidance -> 1 section -> match service revocation states

Repro-test: node -e guide wording assertions fail at 3a710ee; pass after this update.
Class-check: SQL-text assertions -> 2 tests in 2 files -> remove; fix reset expiry fixture

Repro-test: npm test -- test/services.adminAuthDelete.test.ts
  and test/services.controlAdminInvitationTtl.test.ts fails under isolated whitespace-only SQL
  mutation based on 3a710ee; both failures are exact-string assertions.

Post-change: producer-backed unit and PostgreSQL invitation suites passed 51/51.
Class-check: route-test names -> 1 mocked case -> describe 409 and suppressed send only

Repro-test: npm test -- test/routes.adminControlAdmins.test.ts (13/13 pass; no race claim).
…tab manage button

Replace the native Existing Secret select with the shared
SelectionDropdown primitive in single-select mode: roughly four visible
rows with their own scroll, real button/listbox semantics, and no
native-popup flicker on click. The Manage connector Secrets entry
point becomes a plain ghost button that navigates in the same tab and
disables while the flow is locked. Test helpers now open the dropdown
and click options, waiting for the picker to be enabled first.
fix(control-ui): Secrets connector tab affordances and footer copy
The control-ui image build on dev fails in `next build` type-checking:
test/fixtures/registryMcpServerProducer.ts imports
control-api/src/services/registryMutation, and control-api is not in the
Docker context.

Dockerfile.dockerignore reads as an allow-list, but `!control-ui/`
re-includes the whole directory through parent-path matching, so
control-ui/test/ reached the context. Exclude it explicitly, like the
other generated and report directories. PR CI's full-checkout next build
still type-checks the fixtures.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Build (control-ui) runs next build in the full checkout, where an import
that leaves the image's Docker context still resolves. The image itself
is built only by Build & Publish after a merge to dev, so #858 passed PR
CI and then broke the dev publish. Build the builder stage in the PR job,
as the shared matrix already does for profile-ui.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ne-week

fix: extend invitation links to one week
…test-fixtures

fix(control-ui): keep test fixtures out of the image build context
@jozer-rami
jozer-rami merged commit e6a2db7 into main Oct 28, 2026
246 checks passed
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.

4 participants