qo
Qovery
GitHub
console
Workspace
GitHub
CI Pipeline Executions
Filtered
Runs
Demo
Insights
Compare tasks
Analytics
Sign in
Toggle sidebar
Overview
⌘K
console
Loading workspace stats
Loading workspace insights...
Statistics interval
7 days
30 days
Latest CI Pipeline Executions
Status
Fix filter
Filter
Fuzzy
Filter range
Sort by
Sort by
Start time
Sort ascending
Sort descending
Succeeded
2912
b2ddcae8 fix(blueprint): show why an update preview timed out What: The preview socket's timeout branch now reads the frame's `message` and passes it to the failure panel as `reason`, exactly as the error branch already does. The domain outcome gains an optional `message` to carry it. Why: The engine now bounds a preview's terraform run and reports hitting that bound as a timeout naming which step ran out of time and after how long, which q-core publishes as `{"type":"timeout","message":...}` instead of an error. The console discarded that message, so shipping the backend work alone would have been a net regression: the same condition arrives today as `type=error`, whose message the console *does* render, so users would have gone from a specific reason to "The preview timed out before completing." and nothing else. Notes: `message` is optional because two producers have no reason to report: the 12min client-side watchdog, and the gateway's own synthesized frames. `TimeoutFrame` exists only because the pinned qovery-ws-typescript-axios (0.1.644) predates the field. The field is on the wire today, so reading it is correct before the client bump; the generated websocket schema now declares it `string | null` and not required, so the alias can be deleted once the client is regenerated. Worth knowing for the next person: nothing here could have failed a build. The WS layer is an unvalidated `JSON.parse`, ts-pattern matches structurally, and `.exhaustive()` checks variants rather than fields — so a dropped field is invisible to both the type checker and the tests.
by Antoine
A
Succeeded
2909
ed11a81c fix(blueprint): only read the pinned branch when it is shaped like a tag What: Add `isBlueprintTag` and gate the local-tag fallback on it, so a branch that is not `{PROVIDER}/{service}/{major}/{version}` is ignored rather than read. Why: Both tag accessors are positional — `getBlueprintServiceVersion` takes the second-to-last segment — so a three-segment branch such as `AWS/s3/1.2.3` would have rendered `vs3`, and a plain branch name would have rendered the repository owner. Wrong output is worse than none, and unlike `current_tag` the branch is read off the service rather than handed over by an API that already validated it. The shape checked here is the one q-core enforces before it will read a tag at all. Notes: - This should not fire in practice: the engine writes the blueprint tag verbatim as the branch, q-core rejects any tag that is not four segments, and the console blocks editing the git source of a blueprint-backed service. The guard is for when one of those stops holding. - It covers the list cell as well as the header — both resolve their tag through the same hook. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
by Antoine
A
Succeeded
2909
6a4f53bc refactor(blueprint): address naming and placement review points What: Rename the `useErrorBoundary` prop to `throwOnError`, move `useBlueprintUpdateState` into its own folder under `hooks/`, and rename `BlueprintHelmVersionSlot` to `BlueprintChartVersionSlot`. Why: - `use` is React's prefix for hooks, and the prop is not one. `throwOnError` is also what react-query calls the same option from v5 on, so the rename lines up with the eventual upgrade. It still maps to `useErrorBoundary` at the useQuery call, which is v4's name for it. - The hook was declared inline in a cell component, where the repo keeps every other hook in `hooks/<name>/<name>.ts` and exports it from the lib index. - "Helm" read as the catalog's `HELM/` provider directory, which is not what selects this path: q-core derives the service type from the manifest's engine spec (Blueprint.serviceTypeFrom), so a blueprint under any provider whose qbm.yml declares a helm engine produces a Helm service and lands here. The component renders a chart version, which is what its name now says, and the comment states the actual rule. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
by Antoine
A
Succeeded
2909
6a4f53bc refactor(blueprint): address naming and placement review points What: Rename the `useErrorBoundary` prop to `throwOnError`, move `useBlueprintUpdateState` into its own folder under `hooks/`, and rename `BlueprintHelmVersionSlot` to `BlueprintChartVersionSlot`. Why: - `use` is React's prefix for hooks, and the prop is not one. `throwOnError` is also what react-query calls the same option from v5 on, so the rename lines up with the eventual upgrade. It still maps to `useErrorBoundary` at the useQuery call, which is v4's name for it. - The hook was declared inline in a cell component, where the repo keeps every other hook in `hooks/<name>/<name>.ts` and exports it from the lib index. - "Helm" read as the catalog's `HELM/` provider directory, which is not what selects this path: q-core derives the service type from the manifest's engine spec (Blueprint.serviceTypeFrom), so a blueprint under any provider whose qbm.yml declares a helm engine produces a Helm service and lands here. The component renders a chart version, which is what its name now says, and the comment states the actual rule. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
by Antoine
A
Succeeded
2909
ce16be03 fix(blueprint): withhold the helm deploy action while the update check runs What: Treat the in-flight update check like a failed one in the helm blueprint version slot: the chart version still renders immediately, but its "deploy another version" action only appears once the check confirms the service is on a published tag. Why: The slot only withheld the action on failure, so during the request a service pinned to a prerelease still offered it. In flight the console knows exactly as little as it does on failure, and this is not a brief window — the endpoint reads catalog.json plus two manifests from GitHub before answering, and the pin it may be about to reveal is a tag that disappears when its pull request closes. Notes: - This does not bring back the delay fixed in the previous commit: the version is local data and still paints with the list. Only the action waits. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
by Antoine
A
Succeeded
2909
1d339075 fix(blueprint): stop the helm chart version waiting on the update check What: Render a helm blueprint service's chart version immediately again, and cut the update check's retry to a single 500ms attempt instead of two exponential ones. Why: The "Target version" cell got noticeably slower for helm blueprint services. Their chart version comes off the service payload and used to paint with the list, but the prerelease check put a skeleton in front of it: every row waited on `GET /blueprint/{id}/update`, which fetches catalog.json and two manifests from GitHub before it answers. The check can only ever downgrade what the console already knows, so it no longer gates the render — it swaps the badge in once it answers, and the loading state disappears. The retry made the other half of it: for a tag whose manifest is gone the API answers 502, not 404, so the failure path took two retries at the default 1s/2s backoff — about three seconds of skeleton before settling. Notes: - Helm blueprint rows still issue one update check each, which is new: it is the only way to recognise a prerelease there, since their generated service carries no tag. It is off the render path now, but on a list with many such services it is still N extra calls to a slow endpoint. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
by Antoine
A
Succeeded
2909
734844b8 fix(blueprint): tighten prerelease detection and review follow-ups What: Match the full prerelease marker instead of the `-rc` ending, keep bounded retries for non-404 update-check failures, make the RC badge reachable by keyboard, and drop the "deploy another version" action on a helm blueprint whose update check cannot answer. Why: Four issues raised in review, all confirmed: - catalog-gen releases whatever version a manifest declares — its own comment spells out that `1.2.3-rc` is a legal release — so `endsWith('-rc')` would have replaced a published blueprint's update badge with the RC one. The CI marker is `-pr{PR}.{short_sha}-rc` (validate.yml), which is what now matches. - `retry: false` applied to every failure, so a transient error dropped update data from the service list and pushed the suspense update flow straight to its error state. Only the deterministic 404 skips retries now. - The badge is a span, so Radix had no focusable trigger and the explanation was mouse-only. - A helm blueprint on a prerelease tag is undetectable when the update check 404s (its generated service carries no tag anywhere), and it was still being offered "deploy another version" on a pin whose tag disappears with its pull request. The chart version now renders read-only in that state. Notes: - The read-only fallback is deliberately not limited to prereleases: from the console there is no way to tell one from a retired major, and withholding a version-changing action under that uncertainty beats guessing a label — the mistake the previous revision made. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
by Antoine
A
Succeeded
2909
1d714998 fix(blueprint): handle services pinned to an unpublished catalog tag What: Stop the service overview from being replaced by the generic error page when the blueprint update check fails, and surface an orange "RC test" badge in the services table "Target version" cell for services running a prerelease blueprint version. Why: The service-catalog CI tags every pull request that touches a blueprint with a throwaway prerelease `{PROVIDER}/{service}/{major}/{version}-pr{PR}.{sha}-rc`, which is deliberately absent from catalog.json. `GET /blueprint/{id}/update` is the only endpoint that reports a blueprint service's tag, and q-core answers 404 (`Catalog entry not found`) or 502 (`manifest not found`) for those tags. react-query v4 makes a suspense query throw on error, and the overview header had no boundary between it and the organization layout, so a single unresolved tag blanked the whole page. The same failure left the table cell with no version and no badge, giving no hint that the service runs a test build. Notes: - The badge keys off the tag only, never off the failure. A 404 also covers a released tag whose major has been retired from the catalog (HELM/redis/7), and flagging those as prereleases was wrong. - When the update check cannot answer, a terraform blueprint's tag is still readable: the engine pins the generated service to it as its git branch (lib/blueprint/terraform/main.j2.tf). A helm blueprint's generated service has no git source and no other field carrying the tag, so a prerelease on a blueprint the catalog does not know at all goes unflagged there — it renders as it does today rather than guessing. - The update badge is suppressed for prereleases: the pin is a throwaway, and "updating" it to the released tag is misleading. For the same reason a helm prerelease loses its "deploy another version" action — the tag is deleted when the pull request closes. - `retry: false` on the update query: a catalog resolution failure is deterministic, and the retries delayed the overview's suspense fallback. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
by Antoine
A
Succeeded
2906
1a675016 fix(auth): stop the /login redirect loop left by a dead Auth0 session What: When Auth0 cannot mint a token, the request interceptor now clears the local session before redirecting, and it tags the login URL with `reason=session-expired`. The login route skips its "already authenticated, go back into the app" redirect when that reason is present, and shows the user why they were signed out. Session teardown is single-flight across every axios instance. The duplicate `useAuthInterceptor` registration on the Auth0 callback route is removed. `getSafeRedirect` and the new login-URL contract move into `@qovery/shared/routes` so both sides share one definition. Why: `Auth0Provider` runs with `cacheLocation="localstorage"`, and the SDK reads the cached user back with no expiry check — `checkSession()` swallows the refresh failure. So `isAuthenticated` stays true for a session that can no longer produce a token, and nothing ever clears it. That closed a loop: at `/` a query fires, the interceptor fails to get a token and does `window.location.assign('/login?redirect=%2F')` (a full page reload), the reload restores the same dead session, `/login` sees `isAuthenticated` and redirects to `/`, and round it goes. The tab is unrecoverable without manually wiping localStorage. Introduced by #2727, which added the redirect but no teardown. Notes: Teardown is awaited before navigating: a reload that outruns the cache wipe restores the dead session and the loop survives. That ordering is covered by a test. A 401 response does NOT clear the session, only tags the URL. Because `getAccessTokenSilently` refreshes proactively, an expired token never reaches the API, so a 401 is as likely to be an endpoint using 401 where it means 403 — clearing there would sign out a healthy user. The reason param is what breaks the loop on that path. Single-flight matters in practice, not just in theory: two axios instances plus React Query's default three retries turn one dead session into a dozen concurrent teardown attempts. The reason param, not the teardown, is also the only guard that works for the `qovery-e2e-auth-token` bypass, which forces `isAuthenticated` true and is immune to `logout()`. `libs/shared/routes` had a jest transform that could not parse the shared TypeScript setup file, so its suite could never run; aligned it with `shared-utils`. Out of scope, worth a follow-up: `router.invalidate()` on auth change, moving `/`'s component-level <Navigate> into a beforeLoad guard, and memoising the Auth0 context value. None are required for this loop.
by Antoine
A
Succeeded
2899
7e68d8cc fix(blueprint): center preview outcome messages and contain fake timers in specs What: The raw output container is now a flex column, and the no-changes and failure branches fill it with `flex-1` instead of `h-full`. The failure block carries `font-sans` on its wrapper instead of on the summary span alone. Both preview specs restore real timers in `afterEach` rather than on the last line of the fake-timer test. Why: `h-full` resolves a percentage height against the parent's height, and the container only sets `min-h-[180px]`, leaving its height `auto`. The percentage collapsed to the content height, so `justify-center` had no free space to work with: measured in Chromium, the child was 20px tall with 173px of dead space under it, top-aligning the message in the 180px band. Everything in the failure block except the summary line also inherited `font-mono` from the container. In the specs, `jest.useRealTimers()` sat after the final assertion, so a failing assertion would leave fake timers installed for every later test in the file. Notes: Verified in Chromium: the branch content is now 180px tall with symmetric 13px gaps. The diff branch is unaffected — its `pre` keeps its full height inside the fixed-height container and still scrolls, and its bottom padding is now honored, which flex scroll containers do and block ones truncate.
by Antoine
A
Succeeded
2899
bd587fd4 fix(blueprint): render every preview outcome instead of spinning forever What: The blueprint update preview now settles on an explicit outcome (pending / diff / no-changes / error / cancelled / timeout) instead of a raw output string plus three booleans. The hook matches all four BlueprintPreviewResult variants exhaustively, treats a diff with a blank payload as "no changes", surfaces the error frame's message, fails fast when the socket closes before any frame, and bounds the wait with a 12-minute watchdog. The step component renders one branch per outcome and gates "Confirm & deploy update" on a successful preview. Why: The websocket contract sends exactly one frame then closes, and it has four variants. The hook only handled `diff` and dropped `error`, `cancelled` and `timeout` through a catch-all, so the component — which keyed its render on whether the raw output string was non-empty — showed the loading skeleton forever in all three cases, and in the empty-diff case too. Confirm was gated on "a message arrived" rather than on the outcome, so it went live while the skeleton was still animating. A failed preview was therefore indistinguishable from one still running, and the user could deploy anyway. Notes: Verified by reproducing first: a temporary spec asserting the broken behaviour (skeleton rendered + Confirm enabled for error/cancelled/timeout and for an empty diff) passed against the unfixed code and fails against this change. The watchdog is 12min, deliberately above the gateway's own 11min limit, so the server's timeout frame wins in the normal case and the watchdog only catches a socket that dies without delivering anything. onOpen is gone: `pending` is now the initial state, so there was nothing left for it to set. This is the console half of a wider fix. The backend still needs two changes to make failures fast rather than merely visible: q-core's preview broker reads only `message.fullDetails` in its `Diff` branch, so engine errors — which arrive at step `Diff` with the text in `error.userLogMessage` — are skipped, and it ignores the engine's `Terminated` step, so a run that ends without a diff waits out the full 10-minute consumer timeout. Separately, the engine's DIFF path drops the resolved timeout and runs `terraform plan` unbounded.
by Antoine
A
Succeeded
2769/merge
c2c65f16 fix(typo): Remove s
by Antoine
A
Previous
Next