diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index f37e95e84b24e3..4f7b8fe9b33a15 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -311,7 +311,7 @@ RUN curl -fsSL "https://get.sdkman.io" | bash \ # above, we are adding the sdkman init to .bashrc (executing sdkman-init.sh does that), because one is executed on interactive shells, the other for non-interactive shells (e.g. plugin-host) ENV GRADLE_USER_HOME=/workspace/.gradle/ -ENV NODE_VERSION=18.18.2 +ENV NODE_VERSION=18.20.4 ENV PNPM_HOME=/root/.pnpm ENV PATH=/root/.nvm/versions/node/v${NODE_VERSION}/bin:/root/.yarn/bin:${PNPM_HOME}:$PATH diff --git a/WORKSPACE.yaml b/WORKSPACE.yaml index 7c4d5ec863d8ac..9de49cef54f5a2 100644 --- a/WORKSPACE.yaml +++ b/WORKSPACE.yaml @@ -13,15 +13,15 @@ defaultArgs: codeWebExtensionCommit: 7ff72a2938a7a06cbdf3964590f7e9b7525958f3 xtermCommit: 8f10c5febf0162a3c2309076302f770fbad38fde noVerifyJBPlugin: false - intellijDownloadUrl: "https://download.jetbrains.com/idea/ideaIU-2024.2.1.tar.gz" - golandDownloadUrl: "https://download.jetbrains.com/go/goland-2024.2.1.1.tar.gz" - pycharmDownloadUrl: "https://download.jetbrains.com/python/pycharm-professional-2024.2.1.tar.gz" + intellijDownloadUrl: "https://download.jetbrains.com/idea/ideaIU-2024.2.2.tar.gz" + golandDownloadUrl: "https://download.jetbrains.com/go/goland-2024.2.2.tar.gz" + pycharmDownloadUrl: "https://download.jetbrains.com/python/pycharm-professional-2024.2.2.tar.gz" phpstormDownloadUrl: "https://download.jetbrains.com/webide/PhpStorm-2024.2.1.tar.gz" - rubymineDownloadUrl: "https://download.jetbrains.com/ruby/RubyMine-2024.2.1.tar.gz" - webstormDownloadUrl: "https://download.jetbrains.com/webstorm/WebStorm-2024.2.1.tar.gz" + rubymineDownloadUrl: "https://download.jetbrains.com/ruby/RubyMine-2024.2.2.tar.gz" + webstormDownloadUrl: "https://download.jetbrains.com/webstorm/WebStorm-2024.2.2.tar.gz" riderDownloadUrl: "https://download.jetbrains.com/rider/JetBrains.Rider-2024.1.4.tar.gz" - clionDownloadUrl: "https://download.jetbrains.com/cpp/CLion-2024.2.1.tar.gz" - rustroverDownloadUrl: "https://download.jetbrains.com/rustrover/RustRover-2024.2.tar.gz" + clionDownloadUrl: "https://download.jetbrains.com/cpp/CLion-2024.2.2.tar.gz" + rustroverDownloadUrl: "https://download.jetbrains.com/rustrover/RustRover-2024.2.1.tar.gz" jbBackendVersion: "latest" dockerVersion: "20.10.24" dockerComposeVersion: "2.27.0-gitpod.0" diff --git a/components/blobserve/leeway.Dockerfile b/components/blobserve/leeway.Dockerfile index d486a0e8349731..dda74e00848f35 100644 --- a/components/blobserve/leeway.Dockerfile +++ b/components/blobserve/leeway.Dockerfile @@ -2,7 +2,7 @@ # Licensed under the GNU Affero General Public License (AGPL). # See License.AGPL.txt in the project root for license information. -FROM cgr.dev/chainguard/wolfi-base:latest@sha256:0f1d81605bda6e2388c3c7f731700d8c12e17259d58ffba11f36ddc81d9c0a76 +FROM cgr.dev/chainguard/wolfi-base:latest@sha256:7574456f268bc839ac78828865087c04a4297ca226b0eb5d051d4222e7690081 # Ensure latest packages are present, like security updates. RUN apk upgrade --no-cache \ diff --git a/components/content-service/leeway.Dockerfile b/components/content-service/leeway.Dockerfile index 0500691ff1136c..21850f8c483ef7 100644 --- a/components/content-service/leeway.Dockerfile +++ b/components/content-service/leeway.Dockerfile @@ -2,7 +2,7 @@ # Licensed under the GNU Affero General Public License (AGPL). # See License.AGPL.txt in the project root for license information. -FROM cgr.dev/chainguard/wolfi-base:latest@sha256:0f1d81605bda6e2388c3c7f731700d8c12e17259d58ffba11f36ddc81d9c0a76 +FROM cgr.dev/chainguard/wolfi-base:latest@sha256:7574456f268bc839ac78828865087c04a4297ca226b0eb5d051d4222e7690081 # Ensure latest packages are present, like security updates. RUN apk upgrade --no-cache \ diff --git a/components/dashboard/leeway.Dockerfile b/components/dashboard/leeway.Dockerfile index d68437cea0359b..367d0e0b5aa236 100644 --- a/components/dashboard/leeway.Dockerfile +++ b/components/dashboard/leeway.Dockerfile @@ -2,7 +2,7 @@ # Licensed under the GNU Affero General Public License (AGPL). # See License.AGPL.txt in the project root for license information. -FROM cgr.dev/chainguard/wolfi-base:latest@sha256:0f1d81605bda6e2388c3c7f731700d8c12e17259d58ffba11f36ddc81d9c0a76 as compress +FROM cgr.dev/chainguard/wolfi-base:latest@sha256:7574456f268bc839ac78828865087c04a4297ca226b0eb5d051d4222e7690081 as compress RUN apk add brotli gzip diff --git a/components/dashboard/src/repositories/detail/ConfigurationDetailPrebuilds.tsx b/components/dashboard/src/repositories/detail/ConfigurationDetailPrebuilds.tsx index dbaf86af8ffcfc..876e669d2155b9 100644 --- a/components/dashboard/src/repositories/detail/ConfigurationDetailPrebuilds.tsx +++ b/components/dashboard/src/repositories/detail/ConfigurationDetailPrebuilds.tsx @@ -58,7 +58,17 @@ export const ConfigurationDetailPrebuilds: FC = ({ configuration }) => { <> Prebuilds - Prebuilds reduce wait time for new workspaces. + + Prebuilds reduce wait time for new workspaces.{" "} + + Learn more + + = ({ error, onReconnect }) => { // We need to authorize with the provider to acquire the correct scopes to install webhooks if (error instanceof ApplicationError && error.code === ErrorCodes.NOT_AUTHENTICATED) { return ( - @@ -63,11 +63,11 @@ const GenericErrorMessage: FC = ({ message }) => { ); }; -type RepositoryUnauthroizedErrorMessageProps = { +type RepositoryUnauthorizedErrorMessageProps = { error: RepositoryUnauthorizedError; onReconnect: () => void; }; -const RepositoryUnauthroizedErrorMessage: FC = ({ error, onReconnect }) => { +const RepositoryUnauthorizedErrorMessage: FC = ({ error, onReconnect }) => { const { toast } = useToast(); const authorizeWithProvider = useCallback(async () => { @@ -106,7 +106,7 @@ const RepositoryUnauthroizedErrorMessage: FC ) : ( - Unable to enable prebuilds. This could be because you don’t have admin/write premissions for + Unable to enable prebuilds. This could be because you don’t have admin/write permissions for this repo or it could be an invalid token. Please try to reconnect. If the problem persists, you can contact support. diff --git a/components/dashboard/src/repositories/detail/prebuilds/PrebuildSettingsForm.tsx b/components/dashboard/src/repositories/detail/prebuilds/PrebuildSettingsForm.tsx index b958f245e67c2b..78a5b6a36ea281 100644 --- a/components/dashboard/src/repositories/detail/prebuilds/PrebuildSettingsForm.tsx +++ b/components/dashboard/src/repositories/detail/prebuilds/PrebuildSettingsForm.tsx @@ -12,6 +12,7 @@ import { import { FC, FormEvent, useCallback, useMemo, useState } from "react"; import { ConfigurationSettingsField } from "../ConfigurationSettingsField"; import { Heading3, Subheading } from "@podkit/typography/Headings"; +import { Text } from "@podkit/typography/Text"; import { InputField } from "../../../components/forms/InputField"; import { PartialConfiguration, useConfigurationMutation } from "../../../data/configurations/configuration-queries"; import { useToast } from "../../../components/toasts/Toasts"; @@ -28,6 +29,8 @@ import { trackEvent } from "../../../Analytics"; import dayjs from "dayjs"; import { SwitchInputField } from "@podkit/switch/Switch"; import { useFeatureFlag } from "../../../data/featureflag-query"; +import { TextMuted } from "@podkit/typography/TextMuted"; +import { InfoIcon } from "lucide-react"; const DEFAULT_PREBUILD_COMMIT_INTERVAL = 20; @@ -224,6 +227,22 @@ export const PrebuildSettingsForm: FC = ({ configuration }) => { )} +
+ Prebuild trigger strategy + + {configuration.prebuildSettings?.triggerStrategy === PrebuildTriggerStrategy.ACTIVITY_BASED + ? "Activity-based" + : "Webhook-based"} + + + + +
+ Machine type Choose the workspace machine type for your prebuilds. diff --git a/components/ee/agent-smith/leeway.Dockerfile b/components/ee/agent-smith/leeway.Dockerfile index c3678a2ca0c5d6..48fc3f6f9cec9f 100644 --- a/components/ee/agent-smith/leeway.Dockerfile +++ b/components/ee/agent-smith/leeway.Dockerfile @@ -4,7 +4,7 @@ -FROM cgr.dev/chainguard/wolfi-base:latest@sha256:0f1d81605bda6e2388c3c7f731700d8c12e17259d58ffba11f36ddc81d9c0a76 +FROM cgr.dev/chainguard/wolfi-base:latest@sha256:7574456f268bc839ac78828865087c04a4297ca226b0eb5d051d4222e7690081 RUN apk add --no-cache git bash ca-certificates COPY components-ee-agent-smith--app/agent-smith /app/ diff --git a/components/gitpod-cli/cmd/validate.go b/components/gitpod-cli/cmd/validate.go index 049ba15bdabee8..4cb451a0fb2eb8 100644 --- a/components/gitpod-cli/cmd/validate.go +++ b/components/gitpod-cli/cmd/validate.go @@ -6,6 +6,7 @@ package cmd import ( "bufio" + "bytes" "context" "encoding/json" "fmt" @@ -16,6 +17,7 @@ import ( "path/filepath" "strings" "time" + "unicode/utf8" "github.com/gitpod-io/gitpod/common-go/log" "github.com/gitpod-io/gitpod/gitpod-cli/pkg/supervisor" @@ -564,59 +566,85 @@ func pipeTask(ctx context.Context, task *api.TaskStatus, supervisor *supervisor. } } -func listenTerminal(ctx context.Context, task *api.TaskStatus, supervisor *supervisor.SupervisorClient, runLog *logrus.Entry) error { - listen, err := supervisor.Terminal.Listen(ctx, &api.ListenTerminalRequest{ - Alias: task.Terminal, - }) - if err != nil { - return err - } +// TerminalReader is an interface for anything that can receive terminal data (this is abstracted for use in testing) +type TerminalReader interface { + Recv() ([]byte, error) +} - pr, pw := io.Pipe() - defer pr.Close() - defer pw.Close() +type LinePrinter func(string) - scanner := bufio.NewScanner(pr) - const maxTokenSize = 1 * 1024 * 1024 // 1 MB - buf := make([]byte, maxTokenSize) - scanner.Buffer(buf, maxTokenSize) +// processTerminalOutput reads from a TerminalReader, processes the output, and calls the provided LinePrinter for each complete line. +// It handles UTF-8 decoding of characters split across chunks and control characters (\n \r \b). +func processTerminalOutput(reader TerminalReader, printLine LinePrinter) error { + var buffer, line bytes.Buffer - go func() { - defer pw.Close() - for { - resp, err := listen.Recv() - if err != nil { - _ = pw.CloseWithError(err) - return - } + flushLine := func() { + if line.Len() > 0 { + printLine(line.String()) + line.Reset() + } + } - title := resp.GetTitle() - if title != "" { - task.Presentation.Name = title + for { + data, err := reader.Recv() + if err != nil { + if err == io.EOF { + flushLine() + return nil } + return err + } + + buffer.Write(data) - exitCode := resp.GetExitCode() - if exitCode != 0 { - runLog.Infof("%s: exited with code %d", task.Presentation.Name, exitCode) + for { + r, size := utf8.DecodeRune(buffer.Bytes()) + if r == utf8.RuneError && size == 0 { + break // incomplete character at the end } - data := resp.GetData() - if len(data) > 0 { - _, err := pw.Write(data) - if err != nil { - _ = pw.CloseWithError(err) - return + char := buffer.Next(size) + + switch r { + case '\r': + flushLine() + case '\n': + flushLine() + case '\b': + if line.Len() > 0 { + line.Truncate(line.Len() - 1) } + default: + line.Write(char) } } - }() + } +} - for scanner.Scan() { - line := scanner.Text() +func listenTerminal(ctx context.Context, task *api.TaskStatus, supervisor *supervisor.SupervisorClient, runLog *logrus.Entry) error { + listen, err := supervisor.Terminal.Listen(ctx, &api.ListenTerminalRequest{Alias: task.Terminal}) + if err != nil { + return err + } + + terminalReader := &TerminalReaderAdapter{listen} + printLine := func(line string) { runLog.Infof("%s: %s", task.Presentation.Name, line) } - return scanner.Err() + return processTerminalOutput(terminalReader, printLine) +} + +type TerminalReaderAdapter struct { + client api.TerminalService_ListenClient +} + +func (t *TerminalReaderAdapter) Recv() ([]byte, error) { + resp, err := t.client.Recv() + if err != nil { + return nil, err + } + return resp.GetData(), nil } var validateOpts struct { diff --git a/components/gitpod-cli/cmd/validate_test.go b/components/gitpod-cli/cmd/validate_test.go new file mode 100644 index 00000000000000..502ca1962cc6c6 --- /dev/null +++ b/components/gitpod-cli/cmd/validate_test.go @@ -0,0 +1,103 @@ +// Copyright (c) 2024 Gitpod GmbH. All rights reserved. +// Licensed under the GNU Affero General Public License (AGPL). +// See License.AGPL.txt in the project root for license information. + +package cmd + +import ( + "io" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/stretchr/testify/assert" +) + +type MockTerminalReader struct { + Data [][]byte + Index int + Errors []error +} + +func (m *MockTerminalReader) Recv() ([]byte, error) { + if m.Index >= len(m.Data) { + return nil, io.EOF + } + data := m.Data[m.Index] + err := m.Errors[m.Index] + m.Index++ + return data, err +} + +func TestProcessTerminalOutput(t *testing.T) { + tests := []struct { + name string + input [][]byte + expected []string + }{ + { + name: "Simple line", + input: [][]byte{[]byte("Hello, World!\n")}, + expected: []string{"Hello, World!"}, + }, + { + name: "Windows line ending", + input: [][]byte{[]byte("Hello\r\nWorld\r\n")}, + expected: []string{"Hello", "World"}, + }, + { + name: "Updating line", + input: [][]byte{ + []byte("Hello, World!\r"), + []byte("Hello, World 2!\r"), + []byte("Hello, World 3!\n"), + }, + expected: []string{"Hello, World!", "Hello, World 2!", "Hello, World 3!"}, + }, + { + name: "Backspace", + input: [][]byte{[]byte("Helloo\bWorld\n")}, + expected: []string{"HelloWorld"}, + }, + { + name: "Partial UTF-8", + input: [][]byte{[]byte("Hello, 世"), []byte("界\n")}, + expected: []string{"Hello, 世界"}, + }, + { + name: "Partial emoji", + input: [][]byte{ + []byte("Hello "), + {240, 159}, + {145, 141}, + []byte("!\n"), + }, + expected: []string{"Hello 👍!"}, + }, + { + name: "Multiple lines in one receive", + input: [][]byte{[]byte("Line1\nLine2\nLine3\n")}, + expected: []string{"Line1", "Line2", "Line3"}, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + reader := &MockTerminalReader{ + Data: test.input, + Errors: make([]error, len(test.input)), + } + + var actual []string + printLine := func(line string) { + actual = append(actual, line) + } + + err := processTerminalOutput(reader, printLine) + assert.NoError(t, err) + + if diff := cmp.Diff(test.expected, actual); diff != "" { + t.Errorf("processTerminalOutput() mismatch (-want +got):\n%s", diff) + } + }) + } +} diff --git a/components/gitpod-cli/go.mod b/components/gitpod-cli/go.mod index b2e5697ed24f18..8a5fb1b7b2f8bf 100644 --- a/components/gitpod-cli/go.mod +++ b/components/gitpod-cli/go.mod @@ -23,6 +23,7 @@ require ( github.com/sirupsen/logrus v1.9.3 github.com/sourcegraph/jsonrpc2 v0.0.0-20200429184054-15c2290dcb37 github.com/spf13/cobra v1.6.1 + github.com/stretchr/testify v1.8.4 golang.org/x/sync v0.2.0 golang.org/x/term v0.15.0 golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f @@ -33,6 +34,7 @@ require ( require ( github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect github.com/gitpod-io/gitpod/components/scrubber v0.0.0-00010101000000-000000000000 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect github.com/hashicorp/golang-lru v1.0.2 // indirect @@ -43,12 +45,14 @@ require ( github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/onsi/ginkgo v1.16.5 // indirect github.com/onsi/gomega v1.24.2 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.16.0 // indirect github.com/prometheus/client_model v0.3.0 // indirect github.com/prometheus/common v0.42.0 // indirect golang.org/x/crypto v0.16.0 // indirect golang.org/x/sys v0.15.0 // indirect google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) require ( diff --git a/components/gitpod-protocol/src/protocol.ts b/components/gitpod-protocol/src/protocol.ts index 497d387796b776..5e138830d3adb2 100644 --- a/components/gitpod-protocol/src/protocol.ts +++ b/components/gitpod-protocol/src/protocol.ts @@ -1282,6 +1282,10 @@ export interface Repository { // The direct parent of this fork parent: Repository; }; + /** + * Optional date when the repository was last pushed to. + */ + pushedAt?: string; } export interface RepositoryInfo { diff --git a/components/ide-metrics/leeway.Dockerfile b/components/ide-metrics/leeway.Dockerfile index c387719dce157a..c6bb27fbda2c52 100644 --- a/components/ide-metrics/leeway.Dockerfile +++ b/components/ide-metrics/leeway.Dockerfile @@ -2,7 +2,7 @@ # Licensed under the GNU Affero General Public License (AGPL). # See License.AGPL.txt in the project root for license information. -FROM cgr.dev/chainguard/wolfi-base:latest@sha256:0f1d81605bda6e2388c3c7f731700d8c12e17259d58ffba11f36ddc81d9c0a76 +FROM cgr.dev/chainguard/wolfi-base:latest@sha256:7574456f268bc839ac78828865087c04a4297ca226b0eb5d051d4222e7690081 # Ensure latest packages are present, like security updates. RUN apk upgrade --no-cache \ diff --git a/components/ide-proxy/Dockerfile b/components/ide-proxy/Dockerfile index ad5110866b415e..baecbf57b15eb5 100644 --- a/components/ide-proxy/Dockerfile +++ b/components/ide-proxy/Dockerfile @@ -2,7 +2,7 @@ # Licensed under the GNU Affero General Public License (AGPL). # See License.AGPL.txt in the project root for license information. -FROM cgr.dev/chainguard/wolfi-base:latest@sha256:0f1d81605bda6e2388c3c7f731700d8c12e17259d58ffba11f36ddc81d9c0a76 as compress +FROM cgr.dev/chainguard/wolfi-base:latest@sha256:7574456f268bc839ac78828865087c04a4297ca226b0eb5d051d4222e7690081 as compress RUN apk add brotli gzip curl diff --git a/components/ide-service/leeway.Dockerfile b/components/ide-service/leeway.Dockerfile index 794e994ed74592..ee15f1e09b4ca0 100644 --- a/components/ide-service/leeway.Dockerfile +++ b/components/ide-service/leeway.Dockerfile @@ -2,7 +2,7 @@ # Licensed under the GNU Affero General Public License (AGPL). # See License.AGPL.txt in the project root for license information. -FROM cgr.dev/chainguard/wolfi-base:latest@sha256:0f1d81605bda6e2388c3c7f731700d8c12e17259d58ffba11f36ddc81d9c0a76 +FROM cgr.dev/chainguard/wolfi-base:latest@sha256:7574456f268bc839ac78828865087c04a4297ca226b0eb5d051d4222e7690081 # Ensure latest packages are present, like security updates. RUN apk upgrade --no-cache \ diff --git a/components/ide/jetbrains/backend-plugin/BUILD.yaml b/components/ide/jetbrains/backend-plugin/BUILD.yaml index 5e5c19b54ef7b8..e96154dc7b94fd 100644 --- a/components/ide/jetbrains/backend-plugin/BUILD.yaml +++ b/components/ide/jetbrains/backend-plugin/BUILD.yaml @@ -147,7 +147,8 @@ packages: - "build.sh" env: - JB_QUALIFIER=stable-rider - - NO_VERIFY_JB_PLUGIN=${noVerifyJBPlugin} + # Force skip plugin verification for Rider + - NO_VERIFY_JB_PLUGIN=true config: commands: - ["mv", "build.gradle-stable.kts", "build.gradle.kts"] diff --git a/components/ide/jetbrains/backend-plugin/gradle-latest.properties b/components/ide/jetbrains/backend-plugin/gradle-latest.properties index 95074f69674336..64feec2edf3b0f 100644 --- a/components/ide/jetbrains/backend-plugin/gradle-latest.properties +++ b/components/ide/jetbrains/backend-plugin/gradle-latest.properties @@ -1,10 +1,11 @@ # Code generated by gha-update-image/index-jb-platform-update.ts. DO NOT EDIT. # See https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html # for insight into build numbers and IntelliJ Platform versions. -pluginSinceBuild=242.19533 -pluginUntilBuild=242.* +# revert pluginSinceBuild if it's unnecessary +pluginSinceBuild=243.15521 +pluginUntilBuild=243.* # Plugin Verifier integration -> https://github.com/JetBrains/gradle-intellij-plugin#plugin-verifier-dsl # See https://jb.gg/intellij-platform-builds-list for available build versions. -pluginVerifierIdeVersions=2024.2 +pluginVerifierIdeVersions=2024.3 # Version from "com.jetbrains.intellij.idea" which can be found at https://www.jetbrains.com/intellij-repository/snapshots -platformVersion=242.21829.142 +platformVersion=243.15521.24 diff --git a/components/ide/jetbrains/backend-plugin/gradle.properties b/components/ide/jetbrains/backend-plugin/gradle.properties index e348979a8261ed..21cbcefd39e9df 100644 --- a/components/ide/jetbrains/backend-plugin/gradle.properties +++ b/components/ide/jetbrains/backend-plugin/gradle.properties @@ -1,7 +1,7 @@ pluginVersion=0.0.1 gitpodVersion=dev # Supported environments: stable, latest (via https://github.com/stevesaliman/gradle-properties-plugin) -environmentName=stable-rider +environmentName=latest # IntelliJ Platform Artifacts Repositories # -> https://plugins.jetbrains.com/docs/intellij/intellij-artifacts.html pluginGroup=io.gitpod.jetbrains diff --git a/components/ide/jetbrains/backend-plugin/leeway.Dockerfile b/components/ide/jetbrains/backend-plugin/leeway.Dockerfile index 20e7e7e6ec713d..55786be4928fd8 100644 --- a/components/ide/jetbrains/backend-plugin/leeway.Dockerfile +++ b/components/ide/jetbrains/backend-plugin/leeway.Dockerfile @@ -2,11 +2,11 @@ # Licensed under the GNU Affero General Public License (AGPL). # See License.AGPL.txt in the project root for license information. -FROM cgr.dev/chainguard/wolfi-base:latest@sha256:0f1d81605bda6e2388c3c7f731700d8c12e17259d58ffba11f36ddc81d9c0a76 as base_builder +FROM cgr.dev/chainguard/wolfi-base:latest@sha256:7574456f268bc839ac78828865087c04a4297ca226b0eb5d051d4222e7690081 as base_builder RUN mkdir /ide-desktop-plugins # for debugging -# FROM cgr.dev/chainguard/wolfi-base:latest@sha256:0f1d81605bda6e2388c3c7f731700d8c12e17259d58ffba11f36ddc81d9c0a76 +# FROM cgr.dev/chainguard/wolfi-base:latest@sha256:7574456f268bc839ac78828865087c04a4297ca226b0eb5d051d4222e7690081 FROM scratch ARG JETBRAINS_BACKEND_QUALIFIER # ensures right permissions for /ide-desktop-plugins diff --git a/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/AbstractGitpodMetricControlProvider.kt b/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/AbstractGitpodMetricControlProvider.kt index 465145ce9f3821..53b5cff8d80894 100644 --- a/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/AbstractGitpodMetricControlProvider.kt +++ b/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/AbstractGitpodMetricControlProvider.kt @@ -5,24 +5,27 @@ package io.gitpod.jetbrains.remote import com.jetbrains.ide.model.uiautomation.BeControl -import com.jetbrains.ide.model.uiautomation.BeMargin import com.jetbrains.ide.model.uiautomation.DefiniteProgress import com.jetbrains.rd.platform.codeWithMe.unattendedHost.metrics.Metric import com.jetbrains.rd.ui.bedsl.dsl.* -import com.jetbrains.rd.ui.bedsl.dsl.util.BeMarginsBuilder import com.jetbrains.rd.util.lifetime.Lifetime import com.jetbrains.rd.util.reactive.Property -import com.jetbrains.rdserver.diagnostics.BackendDiagnosticsService import com.jetbrains.rdserver.unattendedHost.customization.controlCenter.performance.MetricControlProvider import com.jetbrains.rdserver.unattendedHost.customization.controlCenter.performance.createProgressBar +interface IBackendDiagnosticsService { + fun getMetric(name: String): com.jetbrains.rd.platform.codeWithMe.unattendedHost.metrics.Metric +} + abstract class AbstractGitpodMetricControlProvider : MetricControlProvider { override val id: String = "gitpodMetricsControl" abstract fun setMargin(element: BeControl, left: Int, top: Int, right: Int, bottom: Int): BeControl; + abstract fun getBackendDiagnosticsService(): IBackendDiagnosticsService + override fun getControl(lifetime: Lifetime): BeControl { - val backendDiagnosticsService = BackendDiagnosticsService.Companion.getInstance() + val backendDiagnosticsService = this.getBackendDiagnosticsService() return verticalGrid { row { horizontalGrid { @@ -49,7 +52,7 @@ abstract class AbstractGitpodMetricControlProvider : MetricControlProvider { } } - private fun createWorkspaceHeaderRow(ctx: VerticalGridBuilder, backendDiagnosticsService: BackendDiagnosticsService, lifetime: Lifetime) { + private fun createWorkspaceHeaderRow(ctx: VerticalGridBuilder, backendDiagnosticsService: IBackendDiagnosticsService, lifetime: Lifetime) { val labelProperty = Property("") val workspaceClassMetric = backendDiagnosticsService.getMetric("gitpod_workspace_class") @@ -78,7 +81,7 @@ abstract class AbstractGitpodMetricControlProvider : MetricControlProvider { } } - private fun createCpuControl(ctx: VerticalGridBuilder, backendDiagnosticsService: BackendDiagnosticsService, lifetime: Lifetime) { + private fun createCpuControl(ctx: VerticalGridBuilder, backendDiagnosticsService: IBackendDiagnosticsService, lifetime: Lifetime) { val cpuUsed = backendDiagnosticsService.getMetric("gitpod_workspace_cpu_used") val cpuTotal = backendDiagnosticsService.getMetric("gitpod_workspace_cpu_total") val cpuPercentage = backendDiagnosticsService.getMetric("gitpod_workspace_cpu_percentage") @@ -100,7 +103,7 @@ abstract class AbstractGitpodMetricControlProvider : MetricControlProvider { createProgressControl(ctx, lifetime, label, cpuPercentage, labelProperty, cpuPercentageProperty, progressBar) } - private fun createMemoryControl(ctx: VerticalGridBuilder, backendDiagnosticsService: BackendDiagnosticsService, lifetime: Lifetime) { + private fun createMemoryControl(ctx: VerticalGridBuilder, backendDiagnosticsService: IBackendDiagnosticsService, lifetime: Lifetime) { val memoryUsed = backendDiagnosticsService.getMetric("gitpod_workspace_memory_used") val memoryTotal = backendDiagnosticsService.getMetric("gitpod_workspace_memory_total") val memoryPercentage = backendDiagnosticsService.getMetric("gitpod_workspace_memory_percentage") diff --git a/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/GitpodCLIService.kt b/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/GitpodCLIService.kt index 0a97da3720b21d..e4bd69c3efca77 100644 --- a/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/GitpodCLIService.kt +++ b/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/GitpodCLIService.kt @@ -27,7 +27,10 @@ import io.netty.channel.ChannelHandlerContext import io.netty.handler.codec.http.FullHttpRequest import io.netty.handler.codec.http.QueryStringDecoder import io.prometheus.client.exporter.common.TextFormat -import kotlinx.coroutines.* +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking import org.jetbrains.ide.RestService import org.jetbrains.io.response import java.io.OutputStreamWriter @@ -113,7 +116,9 @@ class GitpodCLIService : RestService() { GlobalScope.launch { getClientSessionAndProjectAsync().let { (session, project) -> ClientId.withClientId(session.clientId) { - action(project) + runBlocking { + action(project) + } sendOk(request, context) } } diff --git a/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/latest/GitpodMetricControlProvider.kt b/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/latest/GitpodMetricControlProvider.kt index b956968905a4d5..cb86ddc49e5887 100644 --- a/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/latest/GitpodMetricControlProvider.kt +++ b/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/latest/GitpodMetricControlProvider.kt @@ -7,15 +7,27 @@ package io.gitpod.jetbrains.remote.latest import com.jetbrains.ide.model.uiautomation.BeControl import com.jetbrains.ide.model.uiautomation.DefiniteProgress import com.jetbrains.rd.platform.codeWithMe.unattendedHost.metrics.Metric -import com.jetbrains.rd.ui.bedsl.dsl.* +import com.jetbrains.rd.ui.bedsl.dsl.VerticalGridBuilder +import com.jetbrains.rd.ui.bedsl.dsl.withMargin import com.jetbrains.rd.util.lifetime.Lifetime import com.jetbrains.rd.util.reactive.Property import com.jetbrains.rdserver.unattendedHost.customization.controlCenter.performance.createProgressRow +import com.jetbrains.rdserver.unattendedHost.diagnostics.BackendDiagnosticsService import io.gitpod.jetbrains.remote.AbstractGitpodMetricControlProvider +import io.gitpod.jetbrains.remote.IBackendDiagnosticsService class GitpodMetricControlProvider: AbstractGitpodMetricControlProvider() { override fun setMargin(element: BeControl, left: Int, top: Int, right: Int, bottom: Int) = element.withMargin(left, top, right, bottom) + override fun getBackendDiagnosticsService(): IBackendDiagnosticsService { + val obj = BackendDiagnosticsService.Companion.getInstance() + return object : IBackendDiagnosticsService { + override fun getMetric(name: String): Metric { + return obj.getMetric(name) + } + } + } + override fun createProgressControl(ctx: VerticalGridBuilder, lifetime: Lifetime, label: String, cpuPercentage: Metric, labelProperty: Property, cpuPercentageProperty: Property, progressBar: DefiniteProgress) { createProgressRow(ctx, id, lifetime, label, cpuPercentage.statusProperty, labelProperty, cpuPercentageProperty, progressBar) } diff --git a/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/stable/GitpodMetricControlProvider.kt b/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/stable/GitpodMetricControlProvider.kt index 03d08e5bab335e..baa133d3668fa5 100644 --- a/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/stable/GitpodMetricControlProvider.kt +++ b/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/stable/GitpodMetricControlProvider.kt @@ -8,12 +8,15 @@ import com.jetbrains.ide.model.uiautomation.BeControl import com.jetbrains.ide.model.uiautomation.BeMargin import com.jetbrains.ide.model.uiautomation.DefiniteProgress import com.jetbrains.rd.platform.codeWithMe.unattendedHost.metrics.Metric -import com.jetbrains.rd.ui.bedsl.dsl.* +import com.jetbrains.rd.ui.bedsl.dsl.VerticalGridBuilder import com.jetbrains.rd.ui.bedsl.dsl.util.BeMarginsBuilder +import com.jetbrains.rd.ui.bedsl.dsl.withMargin import com.jetbrains.rd.util.lifetime.Lifetime import com.jetbrains.rd.util.reactive.Property import com.jetbrains.rdserver.unattendedHost.customization.controlCenter.performance.createProgressRow +import com.jetbrains.rdserver.diagnostics.BackendDiagnosticsService import io.gitpod.jetbrains.remote.AbstractGitpodMetricControlProvider +import io.gitpod.jetbrains.remote.IBackendDiagnosticsService class GitpodMetricControlProvider: AbstractGitpodMetricControlProvider() { override fun setMargin(element: BeControl, left: Int, top: Int, right: Int, bottom: Int): BeControl { @@ -22,6 +25,15 @@ class GitpodMetricControlProvider: AbstractGitpodMetricControlProvider() { return element } + override fun getBackendDiagnosticsService(): IBackendDiagnosticsService { + val obj = BackendDiagnosticsService.Companion.getInstance() + return object : IBackendDiagnosticsService { + override fun getMetric(name: String): Metric { + return obj.getMetric(name) + } + } + } + override fun createProgressControl(ctx: VerticalGridBuilder, lifetime: Lifetime, label: String, cpuPercentage: Metric, labelProperty: Property, cpuPercentageProperty: Property, progressBar: DefiniteProgress) { createProgressRow(ctx, id, lifetime, label, cpuPercentage.statusProperty, labelProperty, cpuPercentageProperty, progressBar) } diff --git a/components/ide/jetbrains/image/leeway.Dockerfile b/components/ide/jetbrains/image/leeway.Dockerfile index fc911121885eb4..ddf19c4681f7e4 100644 --- a/components/ide/jetbrains/image/leeway.Dockerfile +++ b/components/ide/jetbrains/image/leeway.Dockerfile @@ -2,7 +2,7 @@ # Licensed under the GNU Affero General Public License (AGPL). # See License.AGPL.txt in the project root for license information. -FROM cgr.dev/chainguard/wolfi-base:latest@sha256:0f1d81605bda6e2388c3c7f731700d8c12e17259d58ffba11f36ddc81d9c0a76 as base_builder +FROM cgr.dev/chainguard/wolfi-base:latest@sha256:7574456f268bc839ac78828865087c04a4297ca226b0eb5d051d4222e7690081 as base_builder ARG JETBRAINS_DOWNLOAD_QUALIFIER ARG SUPERVISOR_IDE_CONFIG ARG JETBRAINS_BACKEND_VERSION @@ -19,7 +19,7 @@ RUN mkdir /ide-desktop \ && cp /tmp/supervisor-ide-config.json /ide-desktop/${JETBRAINS_DOWNLOAD_QUALIFIER}/supervisor-ide-config.json # for debugging -# FROM cgr.dev/chainguard/wolfi-base:latest@sha256:0f1d81605bda6e2388c3c7f731700d8c12e17259d58ffba11f36ddc81d9c0a76 +# FROM cgr.dev/chainguard/wolfi-base:latest@sha256:7574456f268bc839ac78828865087c04a4297ca226b0eb5d051d4222e7690081 FROM scratch ARG JETBRAINS_BACKEND_VERSION ARG JETBRAINS_DOWNLOAD_QUALIFIER diff --git a/components/ide/jetbrains/launcher/leeway.Dockerfile b/components/ide/jetbrains/launcher/leeway.Dockerfile index 2af1fe10a2273b..0baf8d119ca46b 100644 --- a/components/ide/jetbrains/launcher/leeway.Dockerfile +++ b/components/ide/jetbrains/launcher/leeway.Dockerfile @@ -2,11 +2,11 @@ # Licensed under the GNU Affero General Public License (AGPL). # See License.AGPL.txt in the project root for license information. -FROM cgr.dev/chainguard/wolfi-base:latest@sha256:0f1d81605bda6e2388c3c7f731700d8c12e17259d58ffba11f36ddc81d9c0a76 as base_builder +FROM cgr.dev/chainguard/wolfi-base:latest@sha256:7574456f268bc839ac78828865087c04a4297ca226b0eb5d051d4222e7690081 as base_builder RUN mkdir /ide-desktop # for debugging -# FROM cgr.dev/chainguard/wolfi-base:latest@sha256:0f1d81605bda6e2388c3c7f731700d8c12e17259d58ffba11f36ddc81d9c0a76 +# FROM cgr.dev/chainguard/wolfi-base:latest@sha256:7574456f268bc839ac78828865087c04a4297ca226b0eb5d051d4222e7690081 FROM scratch ARG JETBRAINS_BACKEND_VERSION # ensures right permissions for /ide-desktop diff --git a/components/image-builder-mk3/leeway.Dockerfile b/components/image-builder-mk3/leeway.Dockerfile index b1ef2da71cd4f4..21f506a0c2b755 100644 --- a/components/image-builder-mk3/leeway.Dockerfile +++ b/components/image-builder-mk3/leeway.Dockerfile @@ -2,7 +2,7 @@ # Licensed under the GNU Affero General Public License (AGPL). # See License.AGPL.txt in the project root for license information. -FROM cgr.dev/chainguard/wolfi-base:latest@sha256:0f1d81605bda6e2388c3c7f731700d8c12e17259d58ffba11f36ddc81d9c0a76 +FROM cgr.dev/chainguard/wolfi-base:latest@sha256:7574456f268bc839ac78828865087c04a4297ca226b0eb5d051d4222e7690081 # Ensure latest packages are present, like security updates. RUN apk upgrade --no-cache \ diff --git a/components/leeway.Dockerfile b/components/leeway.Dockerfile index e3779f9bd25575..ee50dd48de9259 100644 --- a/components/leeway.Dockerfile +++ b/components/leeway.Dockerfile @@ -2,5 +2,5 @@ # Licensed under the GNU Affero General Public License (AGPL). # See License.AGPL.txt in the project root for license information. -FROM cgr.dev/chainguard/wolfi-base:latest@sha256:0f1d81605bda6e2388c3c7f731700d8c12e17259d58ffba11f36ddc81d9c0a76 +FROM cgr.dev/chainguard/wolfi-base:latest@sha256:7574456f268bc839ac78828865087c04a4297ca226b0eb5d051d4222e7690081 COPY components--all-docker/versions.yaml components--all-docker/provenance-bundle.jsonl / diff --git a/components/local-app/leeway.Dockerfile b/components/local-app/leeway.Dockerfile index 35d7f7d2c797d7..927cfa2c62a125 100644 --- a/components/local-app/leeway.Dockerfile +++ b/components/local-app/leeway.Dockerfile @@ -2,7 +2,7 @@ # Licensed under the GNU Affero General Public License (AGPL). # See License.AGPL.txt in the project root for license information. -FROM cgr.dev/chainguard/wolfi-base:latest@sha256:0f1d81605bda6e2388c3c7f731700d8c12e17259d58ffba11f36ddc81d9c0a76 +FROM cgr.dev/chainguard/wolfi-base:latest@sha256:7574456f268bc839ac78828865087c04a4297ca226b0eb5d051d4222e7690081 WORKDIR /app COPY components-local-app--app-with-manifest/bin/* ./ diff --git a/components/node-labeler/leeway.Dockerfile b/components/node-labeler/leeway.Dockerfile index 37467adc4f5a6c..9a91624780adcc 100644 --- a/components/node-labeler/leeway.Dockerfile +++ b/components/node-labeler/leeway.Dockerfile @@ -2,7 +2,7 @@ # Licensed under the GNU Affero General Public License (AGPL). # See License.AGPL.txt in the project root for license information. -FROM cgr.dev/chainguard/wolfi-base:latest@sha256:0f1d81605bda6e2388c3c7f731700d8c12e17259d58ffba11f36ddc81d9c0a76 +FROM cgr.dev/chainguard/wolfi-base:latest@sha256:7574456f268bc839ac78828865087c04a4297ca226b0eb5d051d4222e7690081 COPY components-node-labeler--app/node-labeler /app/node-labeler diff --git a/components/openvsx-proxy/leeway.Dockerfile b/components/openvsx-proxy/leeway.Dockerfile index 0536e846dcc5cf..da10fb3c11c1a7 100644 --- a/components/openvsx-proxy/leeway.Dockerfile +++ b/components/openvsx-proxy/leeway.Dockerfile @@ -2,7 +2,7 @@ # Licensed under the GNU Affero General Public License (AGPL). # See License.AGPL.txt in the project root for license information. -FROM cgr.dev/chainguard/wolfi-base:latest@sha256:0f1d81605bda6e2388c3c7f731700d8c12e17259d58ffba11f36ddc81d9c0a76 +FROM cgr.dev/chainguard/wolfi-base:latest@sha256:7574456f268bc839ac78828865087c04a4297ca226b0eb5d051d4222e7690081 # Ensure latest packages are present, like security updates. RUN apk upgrade --no-cache \ diff --git a/components/proxy/Dockerfile b/components/proxy/Dockerfile index bf72a5ed0be79f..33f0ab55fb667d 100644 --- a/components/proxy/Dockerfile +++ b/components/proxy/Dockerfile @@ -22,7 +22,7 @@ RUN xcaddy build v2.7.6 \ --with github.com/gitpod-io/gitpod/proxy/plugins/sshtunnel=/plugins/sshtunnel \ --with github.com/gitpod-io/gitpod/proxy/plugins/frontend_dev=/plugins/frontend_dev -FROM cgr.dev/chainguard/wolfi-base:latest@sha256:0f1d81605bda6e2388c3c7f731700d8c12e17259d58ffba11f36ddc81d9c0a76 +FROM cgr.dev/chainguard/wolfi-base:latest@sha256:7574456f268bc839ac78828865087c04a4297ca226b0eb5d051d4222e7690081 # Ensure latest packages are present, like security updates. RUN apk upgrade --no-cache \ diff --git a/components/public-api-server/leeway.Dockerfile b/components/public-api-server/leeway.Dockerfile index a7da5511c538c2..c6fbb6f7ae1479 100644 --- a/components/public-api-server/leeway.Dockerfile +++ b/components/public-api-server/leeway.Dockerfile @@ -2,7 +2,7 @@ # Licensed under the GNU Affero General Public License (AGPL). # See License.AGPL.txt in the project root for license information. -FROM cgr.dev/chainguard/wolfi-base:latest@sha256:0f1d81605bda6e2388c3c7f731700d8c12e17259d58ffba11f36ddc81d9c0a76 +FROM cgr.dev/chainguard/wolfi-base:latest@sha256:7574456f268bc839ac78828865087c04a4297ca226b0eb5d051d4222e7690081 # Ensure latest packages are present, like security updates. RUN apk upgrade --no-cache \ diff --git a/components/registry-facade/leeway.Dockerfile b/components/registry-facade/leeway.Dockerfile index 6d3ffa79a4c52e..4f24e1251d0d55 100644 --- a/components/registry-facade/leeway.Dockerfile +++ b/components/registry-facade/leeway.Dockerfile @@ -2,7 +2,7 @@ # Licensed under the GNU Affero General Public License (AGPL). # See License.AGPL.txt in the project root for license information. -FROM cgr.dev/chainguard/wolfi-base:latest@sha256:0f1d81605bda6e2388c3c7f731700d8c12e17259d58ffba11f36ddc81d9c0a76 +FROM cgr.dev/chainguard/wolfi-base:latest@sha256:7574456f268bc839ac78828865087c04a4297ca226b0eb5d051d4222e7690081 # Ensure latest packages are present, like security updates. RUN apk upgrade --no-cache \ diff --git a/components/server/src/auth/host-context-provider-impl.ts b/components/server/src/auth/host-context-provider-impl.ts index e16dd2685bb5f3..05ccd24880fdfd 100644 --- a/components/server/src/auth/host-context-provider-impl.ts +++ b/components/server/src/auth/host-context-provider-impl.ts @@ -14,6 +14,7 @@ import { log } from "@gitpod/gitpod-protocol/lib/util/logging"; import { HostContainerMapping } from "./host-container-mapping"; import { TraceContext } from "@gitpod/gitpod-protocol/lib/util/tracing"; import { repeat } from "@gitpod/gitpod-protocol/lib/util/repeat"; +import { RepositoryService } from "../repohost/repo-service"; @injectable() export class HostContextProviderImpl implements HostContextProvider { @@ -152,6 +153,7 @@ export class HostContextProviderImpl implements HostContextProvider { const container = parentContainer.createChild(); container.bind(AuthProviderParams).toConstantValue(authProviderConfig); container.bind(HostContext).toSelf().inSingletonScope(); + container.bind(RepositoryService).toSelf().inSingletonScope(); const hostContainerMapping = parentContainer.get(HostContainerMapping); const containerModules = hostContainerMapping.get(authProviderConfig.type); diff --git a/components/server/src/github/github-container-module.ts b/components/server/src/github/github-container-module.ts index 46ab7b9985f031..b6ba17e111ac67 100644 --- a/components/server/src/github/github-container-module.ts +++ b/components/server/src/github/github-container-module.ts @@ -16,6 +16,8 @@ import { GithubRepositoryProvider } from "./github-repository-provider"; import { GitHubTokenHelper } from "./github-token-helper"; import { IGitTokenValidator } from "../workspace/git-token-validator"; import { GitHubTokenValidator } from "./github-token-validator"; +import { RepositoryService } from "../repohost/repo-service"; +import { GitHubService } from "../prebuilds/github-service"; export const githubContainerModule = new ContainerModule((bind, _unbind, _isBound, rebind) => { bind(RepositoryHost).toSelf().inSingletonScope(); @@ -32,4 +34,5 @@ export const githubContainerModule = new ContainerModule((bind, _unbind, _isBoun bind(GitHubTokenHelper).toSelf().inSingletonScope(); bind(GitHubTokenValidator).toSelf().inSingletonScope(); bind(IGitTokenValidator).toService(GitHubTokenValidator); + rebind(RepositoryService).to(GitHubService).inSingletonScope(); }); diff --git a/components/server/src/github/github-repository-provider.ts b/components/server/src/github/github-repository-provider.ts index 239ebd278e62a4..8395acd0e3a050 100644 --- a/components/server/src/github/github-repository-provider.ts +++ b/components/server/src/github/github-repository-provider.ts @@ -26,7 +26,8 @@ export class GithubRepositoryProvider implements RepositoryProvider { const avatarUrl = repository.owner.avatar_url; const webUrl = repository.html_url; const defaultBranch = repository.default_branch; - return { host, owner, name: repo, cloneUrl, description, avatarUrl, webUrl, defaultBranch }; + const pushedAt = repository.pushed_at; + return { host, owner, name: repo, cloneUrl, description, avatarUrl, webUrl, defaultBranch, pushedAt }; } async getBranch(user: User, owner: string, repo: string, branch: string): Promise { diff --git a/components/server/src/prebuilds/bitbucket-app.ts b/components/server/src/prebuilds/bitbucket-app.ts index 6dfce65b8f7fc6..07987b186e2755 100644 --- a/components/server/src/prebuilds/bitbucket-app.ts +++ b/components/server/src/prebuilds/bitbucket-app.ts @@ -130,6 +130,20 @@ export class BitbucketApp { try { const projectOwner = await this.findProjectOwner(project, user); + if (project.settings?.prebuilds?.triggerStrategy === "activity-based") { + await this.projectService.updateProject(projectOwner, { + id: project.id, + settings: { + ...project.settings, + prebuilds: { + ...project.settings.prebuilds, + triggerStrategy: "webhook-based", + }, + }, + }); + log.info(`Reverted configuration ${project.id} to webhook-based prebuilds`); + } + const contextURL = this.createContextUrl(data); span.setTag("contextURL", contextURL); const context = (await this.contextParser.handle({ span }, user, contextURL)) as CommitContext; diff --git a/components/server/src/prebuilds/bitbucket-server-app.ts b/components/server/src/prebuilds/bitbucket-server-app.ts index 3d624103073170..598e934c42ccac 100644 --- a/components/server/src/prebuilds/bitbucket-server-app.ts +++ b/components/server/src/prebuilds/bitbucket-server-app.ts @@ -127,6 +127,20 @@ export class BitbucketServerApp { try { const projectOwner = await this.findProjectOwner(project, user); + if (project.settings?.prebuilds?.triggerStrategy === "activity-based") { + await this.projectService.updateProject(projectOwner, { + id: project.id, + settings: { + ...project.settings, + prebuilds: { + ...project.settings.prebuilds, + triggerStrategy: "webhook-based", + }, + }, + }); + log.info(`Reverted configuration ${project.id} to webhook-based prebuilds`); + } + const contextUrl = this.createBranchContextUrl(payload); span.setTag("contextUrl", contextUrl); const context = await this.contextParser.handle({ span }, user, contextUrl); diff --git a/components/server/src/prebuilds/bitbucket-server-service.ts b/components/server/src/prebuilds/bitbucket-server-service.ts new file mode 100644 index 00000000000000..9d3f5eb8d977d5 --- /dev/null +++ b/components/server/src/prebuilds/bitbucket-server-service.ts @@ -0,0 +1,54 @@ +/** + * Copyright (c) 2024 Gitpod GmbH. All rights reserved. + * Licensed under the GNU Affero General Public License (AGPL). + * See License.AGPL.txt in the project root for license information. + */ + +import { RepositoryService } from "../repohost/repo-service"; +import { User } from "@gitpod/gitpod-protocol"; +import { inject, injectable } from "inversify"; +import { BitbucketServerApi } from "../bitbucket-server/bitbucket-server-api"; +import { BitbucketServerContextParser } from "../bitbucket-server/bitbucket-server-context-parser"; +import { Config } from "../config"; +import { BitbucketServerApp } from "./bitbucket-server-app"; + +@injectable() +export class BitbucketServerService extends RepositoryService { + constructor( + @inject(BitbucketServerApi) private readonly api: BitbucketServerApi, + @inject(Config) private readonly config: Config, + @inject(BitbucketServerContextParser) private readonly contextParser: BitbucketServerContextParser, + ) { + super(); + } + + public async isGitpodWebhookEnabled(user: User, cloneUrl: string): Promise { + try { + const { owner, repoName, repoKind } = await this.contextParser.parseURL(user, cloneUrl); + const existing = await this.api.getWebhooks(user, { + repoKind, + repositorySlug: repoName, + owner, + }); + if (!existing.values) { + return false; + } + const hookUrl = this.getHookUrl(); + + return existing.values.some((hook) => hook.url && hook.url.includes(hookUrl)); + } catch (error) { + console.error("Failed to check if Gitpod webhook is enabled.", error, { cloneUrl }); + + return false; + } + } + + protected getHookUrl() { + return this.config.hostUrl + .asPublicServices() + .with({ + pathname: BitbucketServerApp.path, + }) + .toString(); + } +} diff --git a/components/server/src/prebuilds/bitbucket-service.ts b/components/server/src/prebuilds/bitbucket-service.ts new file mode 100644 index 00000000000000..6a363b8515e849 --- /dev/null +++ b/components/server/src/prebuilds/bitbucket-service.ts @@ -0,0 +1,52 @@ +/** + * Copyright (c) 2024 Gitpod GmbH. All rights reserved. + * Licensed under the GNU Affero General Public License (AGPL). + * See License.AGPL.txt in the project root for license information. + */ + +import { RepositoryService } from "../repohost/repo-service"; +import { User } from "@gitpod/gitpod-protocol"; +import { inject, injectable } from "inversify"; +import { BitbucketApiFactory } from "../bitbucket/bitbucket-api-factory"; +import { BitbucketApp } from "./bitbucket-app"; +import { Config } from "../config"; +import { BitbucketContextParser } from "../bitbucket/bitbucket-context-parser"; + +@injectable() +export class BitbucketService extends RepositoryService { + constructor( + @inject(BitbucketApiFactory) private readonly api: BitbucketApiFactory, + @inject(Config) private readonly config: Config, + @inject(BitbucketContextParser) private readonly bitbucketContextParser: BitbucketContextParser, + ) { + super(); + } + + public async isGitpodWebhookEnabled(user: User, cloneUrl: string): Promise { + try { + const api = await this.api.create(user); + const { owner, repoName } = await this.bitbucketContextParser.parseURL(user, cloneUrl); + const hooks = await api.repositories.listWebhooks({ + repo_slug: repoName, + workspace: owner, + }); + if (!hooks.data.values) { + return false; + } + return hooks.data.values.some((hook) => hook.url === this.getHookUrl()); + } catch (error) { + console.error("Failed to check if Gitpod webhook is enabled.", error, { cloneUrl }); + + return false; + } + } + + protected getHookUrl() { + return this.config.hostUrl + .asPublicServices() + .with({ + pathname: BitbucketApp.path, + }) + .toString(); + } +} diff --git a/components/server/src/prebuilds/github-app.ts b/components/server/src/prebuilds/github-app.ts index 97f4cc72f67149..6ca30d52feb5e5 100644 --- a/components/server/src/prebuilds/github-app.ts +++ b/components/server/src/prebuilds/github-app.ts @@ -289,6 +289,20 @@ export class GithubApp { const user = await this.findProjectOwner(project, installationOwner); const config = await this.prebuildManager.fetchConfig({ span }, user, context, project?.teamId); + if (project.settings?.prebuilds?.triggerStrategy === "activity-based") { + await this.projectService.updateProject(user, { + id: project.id, + settings: { + ...project.settings, + prebuilds: { + ...project.settings.prebuilds, + triggerStrategy: "webhook-based", + }, + }, + }); + log.info(`Reverted configuration ${project.id} to webhook-based prebuilds`); + } + await this.webhookEvents.updateEvent(event.id, { authorizedUserId: user.id, projectId: project.id, diff --git a/components/server/src/prebuilds/github-enterprise-app.ts b/components/server/src/prebuilds/github-enterprise-app.ts index d140ec8941a21b..572bf302e7ecb7 100644 --- a/components/server/src/prebuilds/github-enterprise-app.ts +++ b/components/server/src/prebuilds/github-enterprise-app.ts @@ -162,6 +162,20 @@ export class GitHubEnterpriseApp { try { const projectOwner = await this.findProjectOwner(project, user); + if (project.settings?.prebuilds?.triggerStrategy === "activity-based") { + await this.projectService.updateProject(projectOwner, { + id: project.id, + settings: { + ...project.settings, + prebuilds: { + ...project.settings.prebuilds, + triggerStrategy: "webhook-based", + }, + }, + }); + log.info(`Reverted configuration ${project.id} to webhook-based prebuilds`); + } + await this.webhookEvents.updateEvent(event.id, { authorizedUserId: user.id, projectId: project.id, diff --git a/components/server/src/prebuilds/github-service.ts b/components/server/src/prebuilds/github-service.ts new file mode 100644 index 00000000000000..e6f5b7bc4d7c7a --- /dev/null +++ b/components/server/src/prebuilds/github-service.ts @@ -0,0 +1,55 @@ +/** + * Copyright (c) 2024 Gitpod GmbH. All rights reserved. + * Licensed under the GNU Affero General Public License (AGPL). + * See License.AGPL.txt in the project root for license information. + */ + +import { RepositoryService } from "../repohost/repo-service"; +import { inject, injectable } from "inversify"; +import { GitHubApiError, GitHubRestApi } from "../github/api"; +import { GitHubEnterpriseApp } from "./github-enterprise-app"; +import { GithubContextParser } from "../github/github-context-parser"; +import { User } from "@gitpod/gitpod-protocol"; +import { Config } from "../config"; +import { RepoURL } from "../repohost"; +import { UnauthorizedError } from "../errors"; +import { GitHubOAuthScopes } from "@gitpod/public-api-common/lib/auth-providers"; + +@injectable() +export class GitHubService extends RepositoryService { + constructor( + @inject(GitHubRestApi) protected readonly githubApi: GitHubRestApi, + @inject(Config) private readonly config: Config, + @inject(GithubContextParser) private readonly githubContextParser: GithubContextParser, + ) { + super(); + } + + async isGitpodWebhookEnabled(user: User, cloneUrl: string): Promise { + try { + const { owner, repoName: repo } = await this.githubContextParser.parseURL(user, cloneUrl); + const webhooks = (await this.githubApi.run(user, (gh) => gh.repos.listWebhooks({ owner, repo }))).data; + return webhooks.some((webhook) => webhook.config.url === this.getHookUrl()); + } catch (error) { + if (GitHubApiError.is(error)) { + throw UnauthorizedError.create({ + host: RepoURL.parseRepoUrl(cloneUrl)!.host, + providerType: "GitHub", + repoName: RepoURL.parseRepoUrl(cloneUrl)!.repo, + requiredScopes: GitHubOAuthScopes.Requirements.DEFAULT, + providerIsConnected: true, + }); + } + throw error; + } + } + + protected getHookUrl() { + return this.config.hostUrl + .asPublicServices() + .with({ + pathname: GitHubEnterpriseApp.path, + }) + .toString(); + } +} diff --git a/components/server/src/prebuilds/gitlab-app.ts b/components/server/src/prebuilds/gitlab-app.ts index 9ce6e5c30788f8..7dfb310dda40b3 100644 --- a/components/server/src/prebuilds/gitlab-app.ts +++ b/components/server/src/prebuilds/gitlab-app.ts @@ -151,6 +151,20 @@ export class GitLabApp { try { const projectOwner = await this.findProjectOwner(project, user); + if (project.settings?.prebuilds?.triggerStrategy === "activity-based") { + await this.projectService.updateProject(projectOwner, { + id: project.id, + settings: { + ...project.settings, + prebuilds: { + ...project.settings.prebuilds, + triggerStrategy: "webhook-based", + }, + }, + }); + log.info(`Reverted configuration ${project.id} to webhook-based prebuilds`); + } + const contextURL = this.createBranchContextUrl(body); log.debug({ userId: user.id }, "GitLab push hook: Context URL", { context: body, contextURL }); span.setTag("contextURL", contextURL); diff --git a/components/server/src/prebuilds/gitlab-service.ts b/components/server/src/prebuilds/gitlab-service.ts new file mode 100644 index 00000000000000..95f6bd0f8d394a --- /dev/null +++ b/components/server/src/prebuilds/gitlab-service.ts @@ -0,0 +1,57 @@ +/** + * Copyright (c) 2024 Gitpod GmbH. All rights reserved. + * Licensed under the GNU Affero General Public License (AGPL). + * See License.AGPL.txt in the project root for license information. + */ + +import { RepositoryService } from "../repohost/repo-service"; +import { User } from "@gitpod/gitpod-protocol"; +import { inject, injectable } from "inversify"; +import { GitLabApi, GitLab } from "../gitlab/api"; +import { GitLabApp } from "./gitlab-app"; +import { Config } from "../config"; +import { GitlabContextParser } from "../gitlab/gitlab-context-parser"; +import { RepoURL } from "../repohost"; +import { UnauthorizedError } from "../errors"; +import { GitLabOAuthScopes } from "@gitpod/public-api-common/lib/auth-providers"; + +@injectable() +export class GitlabService extends RepositoryService { + constructor( + @inject(GitLabApi) protected api: GitLabApi, + @inject(Config) private readonly config: Config, + @inject(GitlabContextParser) private readonly gitlabContextParser: GitlabContextParser, + ) { + super(); + } + + public async isGitpodWebhookEnabled(user: User, cloneUrl: string): Promise { + try { + const { owner, repoName } = await this.gitlabContextParser.parseURL(user, cloneUrl); + const hooks = (await this.api.run(user, (g) => + g.ProjectHooks.all(`${owner}/${repoName}`), + )) as unknown as GitLab.ProjectHook[]; + return hooks.some((hook) => hook.url === this.getHookUrl()); + } catch (error) { + if (GitLab.ApiError.is(error)) { + throw UnauthorizedError.create({ + host: RepoURL.parseRepoUrl(cloneUrl)!.host, + providerType: "GitLab", + repoName: RepoURL.parseRepoUrl(cloneUrl)!.repo, + requiredScopes: GitLabOAuthScopes.Requirements.REPO, + providerIsConnected: true, + }); + } + throw error; + } + } + + private getHookUrl() { + return this.config.hostUrl + .asPublicServices() + .with({ + pathname: GitLabApp.path, + }) + .toString(); + } +} diff --git a/components/server/src/prebuilds/prebuild-manager.spec.ts b/components/server/src/prebuilds/prebuild-manager.spec.ts index 466a9ad3a65b19..e6604a51676d11 100644 --- a/components/server/src/prebuilds/prebuild-manager.spec.ts +++ b/components/server/src/prebuilds/prebuild-manager.spec.ts @@ -9,7 +9,7 @@ import { Container, ContainerModule } from "inversify"; import "mocha"; import * as chai from "chai"; import { PrebuildManager } from "./prebuild-manager"; -import { TracedWorkspaceDB } from "@gitpod/gitpod-db/lib"; +import { TracedWorkspaceDB, WebhookEventDB } from "@gitpod/gitpod-db/lib"; import { WorkspaceService } from "../workspace/workspace-service"; import { HostContextProvider } from "../auth/host-context-provider"; import { ConfigProvider } from "../workspace/config-provider"; @@ -41,6 +41,7 @@ const containerModule = new ContainerModule((bind) => { bind(ContextParser).toConstantValue({} as any); bind(IAnalyticsWriter).toConstantValue({} as any); bind(RedisSubscriber).toConstantValue({} as any); + bind(WebhookEventDB).toConstantValue({} as any); // #endregion }); diff --git a/components/server/src/projects/projects-service.ts b/components/server/src/projects/projects-service.ts index 769baa32d4f035..98d2c79936bf20 100644 --- a/components/server/src/projects/projects-service.ts +++ b/components/server/src/projects/projects-service.ts @@ -5,7 +5,7 @@ */ import { inject, injectable } from "inversify"; -import { DBWithTracing, ProjectDB, TracedWorkspaceDB, WorkspaceDB } from "@gitpod/gitpod-db/lib"; +import { DBWithTracing, ProjectDB, TracedWorkspaceDB, WebhookEventDB, WorkspaceDB } from "@gitpod/gitpod-db/lib"; import { Branch, PrebuildWithStatus, @@ -13,6 +13,8 @@ import { FindPrebuildsParams, Project, User, + CommitContext, + WebhookEvent, } from "@gitpod/gitpod-protocol"; import { HostContextProvider } from "../auth/host-context-provider"; import { RepoURL } from "../repohost"; @@ -34,6 +36,9 @@ import { runWithSubjectId } from "../util/request-context"; import { InstallationService } from "../auth/installation-service"; import { IDEService } from "../ide-service"; import type { PrebuildManager } from "../prebuilds/prebuild-manager"; +import { TraceContext } from "@gitpod/gitpod-protocol/lib/util/tracing"; +import { ContextParser } from "../workspace/context-parser-service"; +import { UnauthorizedError } from "../errors"; // to resolve circular dependency issues export const LazyPrebuildManager = Symbol("LazyPrebuildManager"); @@ -51,6 +56,8 @@ export class ProjectsService { @inject(Authorizer) private readonly auth: Authorizer, @inject(IDEService) private readonly ideService: IDEService, @inject(LazyPrebuildManager) private readonly prebuildManager: LazyPrebuildManager, + @inject(ContextParser) private readonly contextParser: ContextParser, + @inject(WebhookEventDB) private readonly webhookEventDb: WebhookEventDB, @inject(InstallationService) private readonly installationService: InstallationService, ) {} @@ -536,6 +543,62 @@ export class ProjectsService { return project; } } + + /** + * getRecentWebhookEvent checks if the webhook integration is active for the given user and project by querying the webhook event database and seeing if for the latest commit on the repository there exists a webhook event. Additionally, if the necessary SCM permissions are given, the latest commit check is skipped and the most recent event is returned. + */ + public async getRecentWebhookEvent( + ctx: TraceContext, + user: User, + project: Project, + maxAge?: number, + ): Promise { + const context = (await this.contextParser.handle(ctx, user, project.cloneUrl)) as CommitContext; + + // We fetch the most recent 50 events so to maximalize the propability + // of hitting a commit on the default branch and not just one on some + // separate feature branch. + const events = await this.webhookEventDb.findByCloneUrl(project.cloneUrl, 50); + const hostContext = this.hostContextProvider.get(context.repository.host); + const repoService = hostContext?.services?.repositoryService; + if (repoService) { + try { + const webhookEnabled = await repoService.isGitpodWebhookEnabled(user, project.cloneUrl); + return webhookEnabled + ? events[0] ?? { + commit: "n/a", + creationTime: "", + id: "initial_data", + type: "initial_data", + rawEvent: "{}", + status: "processed", + } + : undefined; + } catch (error) { + if (!UnauthorizedError.is(error) && error.message !== "unsupported") { + throw error; + } + } + 1; + } + + const matchingEvent = events.find((event) => { + if (maxAge && Date.now() - new Date(event.creationTime).getTime() > maxAge) { + return false; + } + + // If we know when the source repository was last pushed to, we can figure out if we received the push event after that + if (context.repository.pushedAt && new Date(event.creationTime) >= new Date(context.repository.pushedAt)) { + return true; + } + + // If we know the commit hash, we can check if latest commit in the event matches the one we know. + // We do this check second, because pushing to the non-default branch might throw this off. + return context.revision === event.commit; + }); + + return matchingEvent; + } } /** diff --git a/components/server/src/repohost/repo-service.ts b/components/server/src/repohost/repo-service.ts new file mode 100644 index 00000000000000..016c318011931f --- /dev/null +++ b/components/server/src/repohost/repo-service.ts @@ -0,0 +1,15 @@ +/** + * Copyright (c) 2020 Gitpod GmbH. All rights reserved. + * Licensed under the GNU Affero General Public License (AGPL). + * See License.AGPL.txt in the project root for license information. + */ + +import { User } from "@gitpod/gitpod-protocol"; +import { injectable } from "inversify"; + +@injectable() +export class RepositoryService { + async isGitpodWebhookEnabled(user: User, cloneUrl: string): Promise { + throw new Error("unsupported"); + } +} diff --git a/components/server/src/repohost/repository-host.ts b/components/server/src/repohost/repository-host.ts index e87752ab0d1655..eba852ee0bf488 100644 --- a/components/server/src/repohost/repository-host.ts +++ b/components/server/src/repohost/repository-host.ts @@ -8,9 +8,11 @@ import { inject, injectable } from "inversify"; import { FileProvider } from "./file-provider"; import { RepositoryProvider } from "./repository-provider"; +import { RepositoryService } from "./repo-service"; @injectable() export class RepositoryHost { @inject(FileProvider) fileProvider: FileProvider; @inject(RepositoryProvider) repositoryProvider: RepositoryProvider; + @inject(RepositoryService) repositoryService: RepositoryService; } diff --git a/components/server/src/workspace/workspace-service.ts b/components/server/src/workspace/workspace-service.ts index 3a31d6845aa141..f437d31bf8aaf7 100644 --- a/components/server/src/workspace/workspace-service.ts +++ b/components/server/src/workspace/workspace-service.ts @@ -6,7 +6,7 @@ import { inject, injectable } from "inversify"; import * as grpc from "@grpc/grpc-js"; -import { RedisPublisher, WorkspaceDB } from "@gitpod/gitpod-db/lib"; +import { ProjectDB, RedisPublisher, WorkspaceDB } from "@gitpod/gitpod-db/lib"; import { CommitContext, GetWorkspaceTimeoutResult, @@ -106,6 +106,7 @@ export class WorkspaceService { @inject(Authorizer) private readonly auth: Authorizer, @inject(ContextParser) private readonly contextParser: ContextParser, @inject(LazyPrebuildManager) private readonly prebuildManager: LazyPrebuildManager, + @inject(ProjectDB) private readonly projectDB: ProjectDB, @inject(RedisSubscriber) private readonly subscriber: RedisSubscriber, @inject(PublicAPIConverter) private readonly apiConverter: PublicAPIConverter, @@ -175,7 +176,7 @@ export class WorkspaceService { await this.workspaceClassChecking(ctx, user.id, organizationId, undefined, project, workspaceClass); // We don't want to be doing this in a transaction, because it calls out to external systems. - // TODO(gpl) Would be great to sepearate workspace creation from external calls + // TODO(gpl) Would be great to separate workspace creation from external calls const workspace = await this.factory.createForContext( ctx, user, @@ -225,6 +226,7 @@ export class WorkspaceService { this.asyncUpdateDeletionEligabilityTime(user.id, workspace.id); this.asyncUpdateDeletionEligabilityTimeForUsedPrebuild(user.id, workspace); if (project && workspace.type === "regular") { + this.asyncHandleUpdatePrebuildTriggerStrategy({ ctx, project, workspace, user }); this.asyncStartPrebuild({ ctx, project, workspace, user }); } return workspace; @@ -472,6 +474,47 @@ export class WorkspaceService { ); } + private asyncHandleUpdatePrebuildTriggerStrategy({ + ctx, + project, + workspace, + user, + }: { + ctx: TraceContext; + project: Project; + workspace: Workspace; + user: User; + }): void { + if (project.settings?.prebuilds?.triggerStrategy === "activity-based") { + return; + } + + const logCtx = { userId: user.id, workspaceId: workspace.id, projectId: project.id }; + + (async () => { + const event = await this.projectsService.getRecentWebhookEvent(ctx, user, project); + if (!event) { + await this.projectDB.updateProject({ + id: project.id, + settings: { + ...project.settings, + prebuilds: { + ...project.settings?.prebuilds, + triggerStrategy: "activity-based", + }, + }, + }); + log.info(logCtx, "Updated project prebuild trigger strategy to 'activity-based'"); + } + })().catch((err) => + log.error( + { userId: user.id, workspaceId: workspace.id }, + "Failed to update prebuild trigger strategy after workspace creation", + err, + ), + ); + } + private asyncUpdateDeletionEligabilityTime(userId: string, workspaceId: string): void { this.updateDeletionEligabilityTime(userId, workspaceId).catch((err) => log.error({ userId, workspaceId }, "Failed to update deletion eligibility time", err), @@ -479,7 +522,7 @@ export class WorkspaceService { } /** - * Sets the deletionEligibilityTime of the workspace, depening of the current state of the workspace and the configuration. + * Sets the deletionEligibilityTime of the workspace, depending on the current state of the workspace and the configuration. * * @param userId sets the * @param workspaceId diff --git a/components/service-waiter/leeway.Dockerfile b/components/service-waiter/leeway.Dockerfile index 5c480cfce1d52f..a87a7d5b49cd85 100644 --- a/components/service-waiter/leeway.Dockerfile +++ b/components/service-waiter/leeway.Dockerfile @@ -2,7 +2,7 @@ # Licensed under the GNU Affero General Public License (AGPL). # See License.AGPL.txt in the project root for license information. -FROM cgr.dev/chainguard/wolfi-base:latest@sha256:0f1d81605bda6e2388c3c7f731700d8c12e17259d58ffba11f36ddc81d9c0a76 +FROM cgr.dev/chainguard/wolfi-base:latest@sha256:7574456f268bc839ac78828865087c04a4297ca226b0eb5d051d4222e7690081 # Ensure latest packages are present, like security updates. RUN apk upgrade --no-cache \ diff --git a/components/usage/leeway.Dockerfile b/components/usage/leeway.Dockerfile index 6482123339ba79..28bdffd5b8b822 100644 --- a/components/usage/leeway.Dockerfile +++ b/components/usage/leeway.Dockerfile @@ -2,7 +2,7 @@ # Licensed under the GNU Affero General Public License (AGPL). # See License.AGPL.txt in the project root for license information. -FROM cgr.dev/chainguard/wolfi-base:latest@sha256:0f1d81605bda6e2388c3c7f731700d8c12e17259d58ffba11f36ddc81d9c0a76 +FROM cgr.dev/chainguard/wolfi-base:latest@sha256:7574456f268bc839ac78828865087c04a4297ca226b0eb5d051d4222e7690081 # Ensure latest packages are present, like security updates. RUN apk upgrade --no-cache \ diff --git a/components/ws-daemon/leeway.Dockerfile b/components/ws-daemon/leeway.Dockerfile index 16e8a4ec1d410b..fe324f7f836282 100644 --- a/components/ws-daemon/leeway.Dockerfile +++ b/components/ws-daemon/leeway.Dockerfile @@ -2,7 +2,7 @@ # Licensed under the GNU Affero General Public License (AGPL). # See License.AGPL.txt in the project root for license information. -FROM cgr.dev/chainguard/wolfi-base:latest@sha256:0f1d81605bda6e2388c3c7f731700d8c12e17259d58ffba11f36ddc81d9c0a76 as dl +FROM cgr.dev/chainguard/wolfi-base:latest@sha256:7574456f268bc839ac78828865087c04a4297ca226b0eb5d051d4222e7690081 as dl WORKDIR /dl RUN apk add --no-cache curl file \ && curl -OsSL https://github.com/opencontainers/runc/releases/download/v1.1.12/runc.amd64 \ diff --git a/components/ws-daemon/seccomp-profile-installer/leeway.Dockerfile b/components/ws-daemon/seccomp-profile-installer/leeway.Dockerfile index 3dd61059fc3dba..2ed075b7ad9fd9 100644 --- a/components/ws-daemon/seccomp-profile-installer/leeway.Dockerfile +++ b/components/ws-daemon/seccomp-profile-installer/leeway.Dockerfile @@ -2,7 +2,7 @@ # Licensed under the GNU Affero General Public License (AGPL). # See License.AGPL.txt in the project root for license information. -FROM cgr.dev/chainguard/wolfi-base:latest@sha256:0f1d81605bda6e2388c3c7f731700d8c12e17259d58ffba11f36ddc81d9c0a76 +FROM cgr.dev/chainguard/wolfi-base:latest@sha256:7574456f268bc839ac78828865087c04a4297ca226b0eb5d051d4222e7690081 # Ensure latest packages are present, like security updates. RUN apk upgrade --no-cache diff --git a/components/ws-manager-mk2/leeway.Dockerfile b/components/ws-manager-mk2/leeway.Dockerfile index ec0576daa9d8ba..3815c0f2d9b42c 100644 --- a/components/ws-manager-mk2/leeway.Dockerfile +++ b/components/ws-manager-mk2/leeway.Dockerfile @@ -2,7 +2,7 @@ # Licensed under the GNU Affero General Public License (AGPL). # See License-AGPL.txt in the project root for license information. -FROM cgr.dev/chainguard/wolfi-base:latest@sha256:0f1d81605bda6e2388c3c7f731700d8c12e17259d58ffba11f36ddc81d9c0a76 +FROM cgr.dev/chainguard/wolfi-base:latest@sha256:7574456f268bc839ac78828865087c04a4297ca226b0eb5d051d4222e7690081 # Ensure latest packages are present, like security updates. RUN apk upgrade --no-cache \ diff --git a/components/ws-proxy/leeway.Dockerfile b/components/ws-proxy/leeway.Dockerfile index 56427c680c03eb..b0966d739e9db9 100644 --- a/components/ws-proxy/leeway.Dockerfile +++ b/components/ws-proxy/leeway.Dockerfile @@ -2,7 +2,7 @@ # Licensed under the GNU Affero General Public License (AGPL). # See License.AGPL.txt in the project root for license information. -FROM cgr.dev/chainguard/wolfi-base:latest@sha256:0f1d81605bda6e2388c3c7f731700d8c12e17259d58ffba11f36ddc81d9c0a76 +FROM cgr.dev/chainguard/wolfi-base:latest@sha256:7574456f268bc839ac78828865087c04a4297ca226b0eb5d051d4222e7690081 # Ensure latest packages are present, like security updates. RUN apk upgrade --no-cache \ diff --git a/dev/changelog/leeway.Dockerfile b/dev/changelog/leeway.Dockerfile index e22fad6d6db5c1..acfc593e687b9a 100644 --- a/dev/changelog/leeway.Dockerfile +++ b/dev/changelog/leeway.Dockerfile @@ -2,7 +2,7 @@ # Licensed under the GNU Affero General Public License (AGPL). # See License.AGPL.txt in the project root for license information. -FROM cgr.dev/chainguard/wolfi-base:latest@sha256:0f1d81605bda6e2388c3c7f731700d8c12e17259d58ffba11f36ddc81d9c0a76 +FROM cgr.dev/chainguard/wolfi-base:latest@sha256:7574456f268bc839ac78828865087c04a4297ca226b0eb5d051d4222e7690081 # Ensure latest packages are present, like security updates. RUN apk upgrade --no-cache \ diff --git a/dev/image/Dockerfile b/dev/image/Dockerfile index e21ffbf1dc55c4..d85944910e9f69 100644 --- a/dev/image/Dockerfile +++ b/dev/image/Dockerfile @@ -124,7 +124,7 @@ RUN install-packages netcat USER gitpod # Fix node version we develop against -ARG GITPOD_NODE_VERSION=18.20.2 +ARG GITPOD_NODE_VERSION=18.20.4 RUN bash -c ". .nvm/nvm.sh \ && nvm install $GITPOD_NODE_VERSION \ && npm install -g typescript yarn" diff --git a/install/installer/leeway.Dockerfile b/install/installer/leeway.Dockerfile index d89815cd97a31c..6514c880dbc494 100644 --- a/install/installer/leeway.Dockerfile +++ b/install/installer/leeway.Dockerfile @@ -2,7 +2,7 @@ # Licensed under the GNU Affero General Public License (AGPL). # See License.AGPL.txt in the project root for license information. -FROM cgr.dev/chainguard/helm:latest@sha256:137d0b7604675bc3881ae68fa9ba52989a2fd71a64bb7fdfa4c1fa2f9128c9b0 +FROM cgr.dev/chainguard/helm:latest@sha256:211560894ece2194825d52f791ee58144da58d03c56b8997541ee4c86ce09779 COPY install-installer--app/installer install-installer--app/provenance-bundle.jsonl /app/ diff --git a/install/installer/pkg/components/ide-service/ide-configmap.json b/install/installer/pkg/components/ide-service/ide-configmap.json index 1d0b75fcd03926..9d25b4e66c175e 100644 --- a/install/installer/pkg/components/ide-service/ide-configmap.json +++ b/install/installer/pkg/components/ide-service/ide-configmap.json @@ -182,6 +182,14 @@ ], "allowPin": true, "versions": [ + { + "version": "2024.2.1", + "image": "{{.Repository}}/ide/intellij:commit-d54058956db3274084249bdbc4f508ab111b8c51", + "imageLayers": [ + "{{.Repository}}/ide/jb-backend-plugin:commit-d54058956db3274084249bdbc4f508ab111b8c51", + "{{.Repository}}/ide/jb-launcher:commit-93f81feb1576d690040be79d1eff44d670be740d" + ] + }, { "version": "2024.2", "image": "{{.Repository}}/ide/intellij:commit-f3193519fdae872d64a2a708f5338eeaabb3b6b7", @@ -259,6 +267,14 @@ ], "allowPin": true, "versions": [ + { + "version": "2024.2.1.1", + "image": "{{.Repository}}/ide/goland:commit-3037306124242f17be677319a84b1203074d81e1", + "imageLayers": [ + "{{.Repository}}/ide/jb-backend-plugin:commit-d54058956db3274084249bdbc4f508ab111b8c51", + "{{.Repository}}/ide/jb-launcher:commit-93f81feb1576d690040be79d1eff44d670be740d" + ] + }, { "version": "2024.2.1", "image": "{{.Repository}}/ide/goland:commit-ee9bda60ffb3d400a3f6b9d812026548638b6587", @@ -337,6 +353,14 @@ ], "allowPin": true, "versions": [ + { + "version": "2024.2.1", + "image": "{{.Repository}}/ide/pycharm:commit-d54058956db3274084249bdbc4f508ab111b8c51", + "imageLayers": [ + "{{.Repository}}/ide/jb-backend-plugin:commit-d54058956db3274084249bdbc4f508ab111b8c51", + "{{.Repository}}/ide/jb-launcher:commit-93f81feb1576d690040be79d1eff44d670be740d" + ] + }, { "version": "2024.1.4", "image": "{{.Repository}}/ide/pycharm:commit-f3193519fdae872d64a2a708f5338eeaabb3b6b7", @@ -475,6 +499,14 @@ ], "allowPin": true, "versions": [ + { + "version": "2024.2.1", + "image": "{{.Repository}}/ide/rubymine:commit-d54058956db3274084249bdbc4f508ab111b8c51", + "imageLayers": [ + "{{.Repository}}/ide/jb-backend-plugin:commit-d54058956db3274084249bdbc4f508ab111b8c51", + "{{.Repository}}/ide/jb-launcher:commit-93f81feb1576d690040be79d1eff44d670be740d" + ] + }, { "version": "2024.1.4", "image": "{{.Repository}}/ide/rubymine:commit-f3193519fdae872d64a2a708f5338eeaabb3b6b7", @@ -544,6 +576,14 @@ ], "allowPin": true, "versions": [ + { + "version": "2024.2.1", + "image": "{{.Repository}}/ide/webstorm:commit-d54058956db3274084249bdbc4f508ab111b8c51", + "imageLayers": [ + "{{.Repository}}/ide/jb-backend-plugin:commit-d54058956db3274084249bdbc4f508ab111b8c51", + "{{.Repository}}/ide/jb-launcher:commit-93f81feb1576d690040be79d1eff44d670be740d" + ] + }, { "version": "2024.1.5", "image": "{{.Repository}}/ide/webstorm:commit-f3193519fdae872d64a2a708f5338eeaabb3b6b7", @@ -674,6 +714,14 @@ ], "allowPin": true, "versions": [ + { + "version": "2024.2.1", + "image": "{{.Repository}}/ide/clion:commit-d54058956db3274084249bdbc4f508ab111b8c51", + "imageLayers": [ + "{{.Repository}}/ide/jb-backend-plugin:commit-d54058956db3274084249bdbc4f508ab111b8c51", + "{{.Repository}}/ide/jb-launcher:commit-93f81feb1576d690040be79d1eff44d670be740d" + ] + }, { "version": "2024.1.4", "image": "{{.Repository}}/ide/clion:commit-f3193519fdae872d64a2a708f5338eeaabb3b6b7", @@ -735,6 +783,14 @@ ], "allowPin": true, "versions": [ + { + "version": "2024.2", + "image": "{{.Repository}}/ide/rustrover:commit-d54058956db3274084249bdbc4f508ab111b8c51", + "imageLayers": [ + "{{.Repository}}/ide/jb-backend-plugin:commit-d54058956db3274084249bdbc4f508ab111b8c51", + "{{.Repository}}/ide/jb-launcher:commit-93f81feb1576d690040be79d1eff44d670be740d" + ] + }, { "version": "2024.1.6", "image": "{{.Repository}}/ide/rustrover:commit-f3193519fdae872d64a2a708f5338eeaabb3b6b7", diff --git a/install/installer/pkg/components/redis/constants.go b/install/installer/pkg/components/redis/constants.go index e3eb8381054406..79e1e974922cd4 100644 --- a/install/installer/pkg/components/redis/constants.go +++ b/install/installer/pkg/components/redis/constants.go @@ -14,10 +14,10 @@ const ( RegistryImage = "chainguard/redis" ContainerName = "redis" - ImageDigest = "sha256:424ad3816206dba9b9215e8bd32360e59ef2640718e39e9614bac0b93367c0cd" + ImageDigest = "sha256:25217912829ca7d21c62a57a824babf60f4a52f587d25c44b29597b74a0437c3" ExporterRegistryImage = "chainguard/prometheus-redis-exporter" - ExporterImageDigest = "sha256:fce635e1ed3747c747c357fd27db9a54ef7fc5af15f164492a9813057b33523c" + ExporterImageDigest = "sha256:ab7458c5fbaf43798cbfdde87ce7a6556a04b78682f4028e4868826653f4663c" ExporterContainerName = "exporter" ExporterPortName = "exporter" diff --git a/test/leeway.Dockerfile b/test/leeway.Dockerfile index 225ba33fb65229..39a574ea734ab6 100644 --- a/test/leeway.Dockerfile +++ b/test/leeway.Dockerfile @@ -2,7 +2,7 @@ # Licensed under the GNU Affero General Public License (AGPL). # See License.AGPL.txt in the project root for license information. -FROM cgr.dev/chainguard/wolfi-base:latest@sha256:0f1d81605bda6e2388c3c7f731700d8c12e17259d58ffba11f36ddc81d9c0a76 +FROM cgr.dev/chainguard/wolfi-base:latest@sha256:7574456f268bc839ac78828865087c04a4297ca226b0eb5d051d4222e7690081 # Ensure latest packages are present, like security updates. RUN apk upgrade --no-cache \