diff --git a/components/blobserve/leeway.Dockerfile b/components/blobserve/leeway.Dockerfile index e1a57926db26c6..b62cff28e3da72 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:490977f0fd3d8596d173839dbb314153797312553b43f6a24b0e341cf2e8d473 +FROM cgr.dev/chainguard/wolfi-base:latest@sha256:5dcb7597e50978fc9dea77d96665bcd47ab0600386710c6e8dab35adf1102122 # 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 472fa4c4ff9923..e2354082b4bbe6 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:490977f0fd3d8596d173839dbb314153797312553b43f6a24b0e341cf2e8d473 +FROM cgr.dev/chainguard/wolfi-base:latest@sha256:5dcb7597e50978fc9dea77d96665bcd47ab0600386710c6e8dab35adf1102122 # 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 e77ff4bb5c5ccd..08fa54be822bc9 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:490977f0fd3d8596d173839dbb314153797312553b43f6a24b0e341cf2e8d473 as compress +FROM cgr.dev/chainguard/wolfi-base:latest@sha256:5dcb7597e50978fc9dea77d96665bcd47ab0600386710c6e8dab35adf1102122 as compress RUN apk add brotli gzip diff --git a/components/dashboard/src/components/InputWithCopy.tsx b/components/dashboard/src/components/InputWithCopy.tsx index b3c29ead4a657a..080d574078e8d7 100644 --- a/components/dashboard/src/components/InputWithCopy.tsx +++ b/components/dashboard/src/components/InputWithCopy.tsx @@ -27,13 +27,11 @@ export function InputWithCopy(props: { value: string; tip?: string; className?: type="text" value={props.value} /> -
handleCopyToClipboard(props.value)}> -
- - copy icon - -
-
+ ); } diff --git a/components/dashboard/src/data/featureflag-query.ts b/components/dashboard/src/data/featureflag-query.ts index 84502dcb51d9a8..3c6cfdf34d9c31 100644 --- a/components/dashboard/src/data/featureflag-query.ts +++ b/components/dashboard/src/data/featureflag-query.ts @@ -24,6 +24,7 @@ const featureFlags = { enableDedicatedOnboardingFlow: false, usageDownload: false, phoneVerificationByCall: false, + doRetryUserLoader: true, }; export const useFeatureFlag = (featureFlag: keyof typeof featureFlags) => { diff --git a/components/dashboard/src/hooks/use-user-loader.ts b/components/dashboard/src/hooks/use-user-loader.ts index 0c2724f19092f8..918b4346803b38 100644 --- a/components/dashboard/src/hooks/use-user-loader.ts +++ b/components/dashboard/src/hooks/use-user-loader.ts @@ -11,9 +11,12 @@ import { trackLocation } from "../Analytics"; import { refreshSearchData } from "../components/RepositoryFinder"; import { useQuery } from "@tanstack/react-query"; import { noPersistence } from "../data/setup"; +import { ErrorCodes } from "@gitpod/gitpod-protocol/lib/messaging/error"; +import { useFeatureFlag } from "../data/featureflag-query"; export const useUserLoader = () => { const { user, setUser } = useContext(UserContext); + const doRetryUserLoader = useFeatureFlag("doRetryUserLoader"); // For now, we're using the user context to store the user, but letting react-query handle the loading // In the future, we should remove the user context and use react-query to access the user @@ -27,8 +30,15 @@ export const useUserLoader = () => { // We'll let an ErrorBoundary catch the error useErrorBoundary: true, // It's important we don't retry as we want to show the login screen as quickly as possible if a 401 - // TODO: In the future we can consider retrying for non 401 errors - retry: false, + retry: (_failureCount: number, error: Error & { code?: number }) => { + if (!doRetryUserLoader) { + return false; + } + return error.code !== ErrorCodes.NOT_AUTHENTICATED; + }, + // docs: https://tanstack.com/query/v4/docs/react/guides/query-retries + // backoff by doubling, max. 10s + retryDelay: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 10000), cacheTime: 1000 * 60 * 60 * 1, // 1 hour staleTime: 1000 * 60 * 60 * 1, // 1 hour onSuccess: (loadedUser) => { diff --git a/components/dashboard/src/index.css b/components/dashboard/src/index.css index db48bcdd27e2dd..d2783dd8fa2d09 100644 --- a/components/dashboard/src/index.css +++ b/components/dashboard/src/index.css @@ -55,6 +55,11 @@ button { @apply cursor-pointer px-4 py-2 my-auto bg-green-600 dark:bg-green-700 hover:bg-green-700 dark:hover:bg-green-600 text-gray-100 dark:text-green-100 text-sm font-medium rounded-md focus:outline-none focus:ring transition ease-in-out; } + button.reset { + @apply bg-transparent hover:bg-transparent font-normal rounded-none; + padding: unset; + text-align: start; + } button.secondary { @apply bg-gray-100 dark:bg-gray-700 hover:bg-gray-200 dark:hover:bg-gray-600 text-gray-500 dark:text-gray-100 hover:text-gray-600; } diff --git a/components/dashboard/src/teams/git-integrations/GitIntegrationModal.tsx b/components/dashboard/src/teams/git-integrations/GitIntegrationModal.tsx index d76fb3ef6370c3..7f345182d0a7b6 100644 --- a/components/dashboard/src/teams/git-integrations/GitIntegrationModal.tsx +++ b/components/dashboard/src/teams/git-integrations/GitIntegrationModal.tsx @@ -42,19 +42,7 @@ export const GitIntegrationModal: FunctionComponent = (props) => { const isNew = !savedProvider; // This is a readonly value to copy and plug into external oauth config - const redirectURL = useMemo(() => { - let url = ""; - - // Once it's saved, use what's stored - if (!isNew) { - url = savedProvider?.oauth.callBackUrl ?? url; - } else { - // Otherwise construct it w/ their provided host value or example - url = callbackUrl(host || getPlaceholderForIntegrationType(type)); - } - - return url; - }, [host, isNew, savedProvider?.oauth.callBackUrl, type]); + const redirectURL = callbackUrl(); // "bitbucket.org" is set as host value whenever "Bitbucket" is selected useEffect(() => { @@ -281,13 +269,8 @@ export const GitIntegrationModal: FunctionComponent = (props) => { ); }; -const callbackUrl = (host: string) => { - // Negative Lookahead (?!\/) - // `\/` matches the character `/` - // "https://foobar:80".replace(/:(?!\/)/, "_") - // => 'https://foobar_80' - host = host.replace(/:(?!\/)/, "_"); - const pathname = `/auth/${host}/callback`; +const callbackUrl = () => { + const pathname = `/auth/callback`; return gitpodHostUrl.with({ pathname }).toString(); }; diff --git a/components/dashboard/src/user-settings/Integrations.test.tsx b/components/dashboard/src/user-settings/Integrations.test.tsx index c8ec9362642c49..f5d1887f5402b3 100644 --- a/components/dashboard/src/user-settings/Integrations.test.tsx +++ b/components/dashboard/src/user-settings/Integrations.test.tsx @@ -20,5 +20,5 @@ test("should update redirectURL preview", async () => { const redirectURL = screen.getByLabelText(/Redirect/i); // screen.debug(redirectURL); - expect((redirectURL as HTMLInputElement).value).toEqual("http://localhost/auth/gitlab.gitpod.io_80/callback"); + expect((redirectURL as HTMLInputElement).value).toEqual("http://localhost/auth/callback"); }); diff --git a/components/dashboard/src/user-settings/Integrations.tsx b/components/dashboard/src/user-settings/Integrations.tsx index d396aef3b0d849..59a29096744c30 100644 --- a/components/dashboard/src/user-settings/Integrations.tsx +++ b/components/dashboard/src/user-settings/Integrations.tsx @@ -504,13 +504,8 @@ export function GitIntegrationModal( onAuthorize?: (payload?: string) => void; }, ) { - const callbackUrl = (host: string) => { - // Negative Lookahead (?!\/) - // `\/` matches the character `/` - // "https://foobar:80".replace(/:(?!\/)/, "_") - // => 'https://foobar_80' - host = host.replace(/:(?!\/)/, "_"); - const pathname = `/auth/${host}/callback`; + const callbackUrl = () => { + const pathname = `/auth/callback`; return gitpodHostUrl.with({ pathname }).toString(); }; @@ -519,7 +514,7 @@ export function GitIntegrationModal( const [type, setType] = useState("GitLab"); const [host, setHost] = useState(""); - const [redirectURI, setRedirectURI] = useState(callbackUrl("gitlab.example.com")); + const [redirectURI, setRedirectURI] = useState(callbackUrl()); const [clientId, setClientId] = useState(""); const [clientSecret, setClientSecret] = useState(""); const [busy, setBusy] = useState(false); @@ -632,7 +627,6 @@ export function GitIntegrationModal( } setHost(newHostValue); - setRedirectURI(callbackUrl(newHostValue)); setErrorMessage(undefined); } }; diff --git a/components/ee/agent-smith/leeway.Dockerfile b/components/ee/agent-smith/leeway.Dockerfile index 8ef77a703bb9d3..fd6b7a513ef8e6 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:490977f0fd3d8596d173839dbb314153797312553b43f6a24b0e341cf2e8d473 +FROM cgr.dev/chainguard/wolfi-base:latest@sha256:5dcb7597e50978fc9dea77d96665bcd47ab0600386710c6e8dab35adf1102122 RUN apk add --no-cache git bash ca-certificates COPY components-ee-agent-smith--app/agent-smith /app/ diff --git a/components/ide-metrics/leeway.Dockerfile b/components/ide-metrics/leeway.Dockerfile index 2049862165a369..538dbbd6155a4b 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:490977f0fd3d8596d173839dbb314153797312553b43f6a24b0e341cf2e8d473 +FROM cgr.dev/chainguard/wolfi-base:latest@sha256:5dcb7597e50978fc9dea77d96665bcd47ab0600386710c6e8dab35adf1102122 # 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 0928bed2b76165..10ba37508e64c6 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:490977f0fd3d8596d173839dbb314153797312553b43f6a24b0e341cf2e8d473 as compress +FROM cgr.dev/chainguard/wolfi-base:latest@sha256:5dcb7597e50978fc9dea77d96665bcd47ab0600386710c6e8dab35adf1102122 as compress RUN apk add brotli gzip diff --git a/components/ide-service/leeway.Dockerfile b/components/ide-service/leeway.Dockerfile index a8c3efd5e3091a..8f964ff41e67ba 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:490977f0fd3d8596d173839dbb314153797312553b43f6a24b0e341cf2e8d473 +FROM cgr.dev/chainguard/wolfi-base:latest@sha256:5dcb7597e50978fc9dea77d96665bcd47ab0600386710c6e8dab35adf1102122 # Ensure latest packages are present, like security updates. RUN apk upgrade --no-cache \ diff --git a/components/ide/jetbrains/backend-plugin/leeway.Dockerfile b/components/ide/jetbrains/backend-plugin/leeway.Dockerfile index 3d90a059b1d819..7b727cc45a29a0 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:490977f0fd3d8596d173839dbb314153797312553b43f6a24b0e341cf2e8d473 as base_builder +FROM cgr.dev/chainguard/wolfi-base:latest@sha256:5dcb7597e50978fc9dea77d96665bcd47ab0600386710c6e8dab35adf1102122 as base_builder RUN mkdir /ide-desktop-plugins # for debugging -# FROM cgr.dev/chainguard/wolfi-base:latest@sha256:490977f0fd3d8596d173839dbb314153797312553b43f6a24b0e341cf2e8d473 +# FROM cgr.dev/chainguard/wolfi-base:latest@sha256:5dcb7597e50978fc9dea77d96665bcd47ab0600386710c6e8dab35adf1102122 FROM scratch ARG JETBRAINS_BACKEND_QUALIFIER # ensures right permissions for /ide-desktop-plugins diff --git a/components/ide/jetbrains/image/leeway.Dockerfile b/components/ide/jetbrains/image/leeway.Dockerfile index 220c026aed6740..4de82615f7bca9 100644 --- a/components/ide/jetbrains/image/leeway.Dockerfile +++ b/components/ide/jetbrains/image/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:490977f0fd3d8596d173839dbb314153797312553b43f6a24b0e341cf2e8d473 as base_builder +FROM cgr.dev/chainguard/wolfi-base:latest@sha256:5dcb7597e50978fc9dea77d96665bcd47ab0600386710c6e8dab35adf1102122 as base_builder RUN mkdir /ide-desktop # for debugging -# FROM cgr.dev/chainguard/wolfi-base:latest@sha256:490977f0fd3d8596d173839dbb314153797312553b43f6a24b0e341cf2e8d473 +# FROM cgr.dev/chainguard/wolfi-base:latest@sha256:5dcb7597e50978fc9dea77d96665bcd47ab0600386710c6e8dab35adf1102122 FROM scratch ARG JETBRAINS_DOWNLOAD_QUALIFIER ARG JETBRAINS_BACKEND_QUALIFIER diff --git a/components/ide/jetbrains/launcher/leeway.Dockerfile b/components/ide/jetbrains/launcher/leeway.Dockerfile index 7df86b5179633b..031ffaa9086dc2 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:490977f0fd3d8596d173839dbb314153797312553b43f6a24b0e341cf2e8d473 as base_builder +FROM cgr.dev/chainguard/wolfi-base:latest@sha256:5dcb7597e50978fc9dea77d96665bcd47ab0600386710c6e8dab35adf1102122 as base_builder RUN mkdir /ide-desktop # for debugging -# FROM cgr.dev/chainguard/wolfi-base:latest@sha256:490977f0fd3d8596d173839dbb314153797312553b43f6a24b0e341cf2e8d473 +# FROM cgr.dev/chainguard/wolfi-base:latest@sha256:5dcb7597e50978fc9dea77d96665bcd47ab0600386710c6e8dab35adf1102122 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 1f8cc24bcdcdb8..2abe5a2998ae79 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:490977f0fd3d8596d173839dbb314153797312553b43f6a24b0e341cf2e8d473 +FROM cgr.dev/chainguard/wolfi-base:latest@sha256:5dcb7597e50978fc9dea77d96665bcd47ab0600386710c6e8dab35adf1102122 # Ensure latest packages are present, like security updates. RUN apk upgrade --no-cache \ diff --git a/components/installation-telemetry/leeway.Dockerfile b/components/installation-telemetry/leeway.Dockerfile index 131dc4fd2e54d0..25f9f54bc5cc29 100644 --- a/components/installation-telemetry/leeway.Dockerfile +++ b/components/installation-telemetry/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:490977f0fd3d8596d173839dbb314153797312553b43f6a24b0e341cf2e8d473 +FROM cgr.dev/chainguard/wolfi-base:latest@sha256:5dcb7597e50978fc9dea77d96665bcd47ab0600386710c6e8dab35adf1102122 COPY components-installation-telemetry--app/installation-telemetry /app/installation-telemetry ENTRYPOINT [ "/app/installation-telemetry" ] CMD [ "help" ] diff --git a/components/leeway.Dockerfile b/components/leeway.Dockerfile index 90321e291d0ab9..01c76a838b17fd 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:490977f0fd3d8596d173839dbb314153797312553b43f6a24b0e341cf2e8d473 +FROM cgr.dev/chainguard/wolfi-base:latest@sha256:5dcb7597e50978fc9dea77d96665bcd47ab0600386710c6e8dab35adf1102122 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 0e56aaabbc15b9..6bc5627b6ca68d 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:490977f0fd3d8596d173839dbb314153797312553b43f6a24b0e341cf2e8d473 +FROM cgr.dev/chainguard/wolfi-base:latest@sha256:5dcb7597e50978fc9dea77d96665bcd47ab0600386710c6e8dab35adf1102122 WORKDIR /app COPY components-local-app--app/components-local-app--app-linux-amd64/local-app local-app-linux diff --git a/components/node-labeler/leeway.Dockerfile b/components/node-labeler/leeway.Dockerfile index d3c05fc02d1f28..842ead0923c1d8 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:490977f0fd3d8596d173839dbb314153797312553b43f6a24b0e341cf2e8d473 +FROM cgr.dev/chainguard/wolfi-base:latest@sha256:5dcb7597e50978fc9dea77d96665bcd47ab0600386710c6e8dab35adf1102122 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 e9536ba580c474..59b3641eafaeb5 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:490977f0fd3d8596d173839dbb314153797312553b43f6a24b0e341cf2e8d473 +FROM cgr.dev/chainguard/wolfi-base:latest@sha256:5dcb7597e50978fc9dea77d96665bcd47ab0600386710c6e8dab35adf1102122 # Ensure latest packages are present, like security updates. RUN apk upgrade --no-cache \ diff --git a/components/proxy/Dockerfile b/components/proxy/Dockerfile index edc9c70cb8e214..db634b0996b019 100644 --- a/components/proxy/Dockerfile +++ b/components/proxy/Dockerfile @@ -22,7 +22,7 @@ RUN xcaddy build v2.6.3 \ --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:490977f0fd3d8596d173839dbb314153797312553b43f6a24b0e341cf2e8d473 +FROM cgr.dev/chainguard/wolfi-base:latest@sha256:5dcb7597e50978fc9dea77d96665bcd47ab0600386710c6e8dab35adf1102122 # Ensure latest packages are present, like security updates. RUN apk upgrade --no-cache \ diff --git a/components/proxy/conf/Caddyfile b/components/proxy/conf/Caddyfile index 97352e0482d10b..22f7e3cbfd8350 100644 --- a/components/proxy/conf/Caddyfile +++ b/components/proxy/conf/Caddyfile @@ -146,6 +146,13 @@ } } +# Internal configcat endpoint +:9547 { + handle /configcat* { + gitpod.configcat + } +} + # public-api api.{$GITPOD_DOMAIN} { log { diff --git a/components/public-api-server/leeway.Dockerfile b/components/public-api-server/leeway.Dockerfile index cfde6943d0eda0..d4846a6ddd41ee 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:490977f0fd3d8596d173839dbb314153797312553b43f6a24b0e341cf2e8d473 +FROM cgr.dev/chainguard/wolfi-base:latest@sha256:5dcb7597e50978fc9dea77d96665bcd47ab0600386710c6e8dab35adf1102122 # 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 6f37cd2f0a0c9c..df09d09e13ea44 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:490977f0fd3d8596d173839dbb314153797312553b43f6a24b0e341cf2e8d473 +FROM cgr.dev/chainguard/wolfi-base:latest@sha256:5dcb7597e50978fc9dea77d96665bcd47ab0600386710c6e8dab35adf1102122 # Ensure latest packages are present, like security updates. RUN apk upgrade --no-cache \ diff --git a/components/server/src/auth/auth-provider-service.ts b/components/server/src/auth/auth-provider-service.ts index 69fa54d8c51ad3..2b61dfabe1e13f 100644 --- a/components/server/src/auth/auth-provider-service.ts +++ b/components/server/src/auth/auth-provider-service.ts @@ -175,7 +175,7 @@ export class AuthProviderService { } const oauth: AuthProviderEntry["oauth"] = { ...urls, - callBackUrl: this.callbackUrl(host), + callBackUrl: this.callbackUrl(), clientId: clientId!, clientSecret: clientSecret!, }; @@ -239,9 +239,8 @@ export class AuthProviderService { } } - protected callbackUrl = (host: string) => { - const safeHost = host.replace(":", "_"); - const pathname = `/auth/${safeHost}/callback`; + protected callbackUrl = () => { + const pathname = `/auth/callback`; return this.config.hostUrl.with({ pathname }).toString(); }; diff --git a/components/server/src/auth/authenticator.ts b/components/server/src/auth/authenticator.ts index d7032acb8d8286..3df3a4bbe57be9 100644 --- a/components/server/src/auth/authenticator.ts +++ b/components/server/src/auth/authenticator.ts @@ -12,7 +12,7 @@ import { log } from "@gitpod/gitpod-protocol/lib/util/logging"; import { TeamDB, UserDB } from "@gitpod/gitpod-db/lib"; import { Config } from "../config"; import { HostContextProvider } from "./host-context-provider"; -import { AuthProvider } from "./auth-provider"; +import { AuthFlow, AuthProvider } from "./auth-provider"; import { TokenProvider } from "../user/token-provider"; import { AuthProviderService } from "./auth-provider-service"; import { UserService } from "../user/user-service"; @@ -72,18 +72,59 @@ export class Authenticator { }); } protected async authCallbackHandler(req: express.Request, res: express.Response, next: express.NextFunction) { - if (req.url.startsWith("/auth/")) { - const hostContexts = this.hostContextProvider.getAll(); - for (const { authProvider } of hostContexts) { - const authCallbackPath = authProvider.authCallbackPath; - if (req.url.startsWith(authCallbackPath)) { - log.info(`Auth Provider Callback. Path: ${authCallbackPath}`); - await authProvider.callback(req, res, next); - return; + // Should match: + // * /auth/callback + // * /auth//callback + if (req.path.startsWith("/auth/") && req.path.endsWith("/callback")) { + const stateParam = req.query.state; + try { + const flowState = await this.parseState(`${stateParam}`); + const host = flowState.host; + if (!host) { + throw new Error("Auth flow state is missing 'host' attribute."); + } + const hostContext = this.hostContextProvider.get(host); + if (!hostContext) { + throw new Error("No host context found."); } + + // remember parsed state to be availble in the auth provider implementation + req.authFlow = flowState; + + log.info(`Auth Provider Callback. Host: ${host}`); + await hostContext.authProvider.callback(req, res, next); + } catch (error) { + log.error(`Failed to handle callback.`, error, { url: req.url }); } + } else { + // Otherwise proceed with other handlers + return next(); } - return next(); + } + + private async parseState(state: string): Promise { + // In preview environments, we prepend the current development branch to the state, to allow + // our preview proxy to route the Auth callback appropriately. + // See https://github.com/gitpod-io/ops/pull/9398/files + // + // We need to strip the branch out of the state, if it's present + if (state.indexOf(",") >= 0) { + const [, actualState] = state.split(",", 2); + state = actualState; + } + + return await this.signInJWT.verify(state as string); + } + + private deriveAuthState(state: string): string { + // In preview environments, we prepend the current development branch to the state, to allow + // our preview proxy to route the Auth callback appropriately. + // See https://github.com/gitpod-io/ops/pull/9398/files + if (this.config.devBranch) { + return `${this.config.devBranch},${state}`; + } + + return state; } protected async getAuthProviderForHost(host: string): Promise { @@ -141,7 +182,7 @@ export class Authenticator { }); // authenticate user - authProvider.authorize(req, res, next, state); + authProvider.authorize(req, res, next, this.deriveAuthState(state)); } async deauthorize(req: express.Request, res: express.Response, next: express.NextFunction) { @@ -256,7 +297,7 @@ export class Authenticator { // authorize Gitpod log.info(`(doAuthorize) wanted scopes (${override ? "overriding" : "merging"}): ${wantedScopes.join(",")}`); const state = await this.signInJWT.sign({ host, returnTo, overrideScopes: override }); - authProvider.authorize(req, res, next, state, wantedScopes); + authProvider.authorize(req, res, next, this.deriveAuthState(state), wantedScopes); } protected mergeScopes(a: string[], b: string[]) { const set = new Set(a); diff --git a/components/server/src/auth/generic-auth-provider.ts b/components/server/src/auth/generic-auth-provider.ts index 90c3c853df27bf..7e4d4c823c71e0 100644 --- a/components/server/src/auth/generic-auth-provider.ts +++ b/components/server/src/auth/generic-auth-provider.ts @@ -13,7 +13,7 @@ import { AuthProviderInfo, Identity, Token, User } from "@gitpod/gitpod-protocol import { log, LogContext } from "@gitpod/gitpod-protocol/lib/util/logging"; import { oauth2tokenCallback, OAuth2 } from "oauth"; import { URL } from "url"; -import { AuthFlow, AuthProvider, AuthUser } from "../auth/auth-provider"; +import { AuthProvider, AuthUser } from "../auth/auth-provider"; import { AuthProviderParams, AuthUserSetup } from "../auth/auth-provider"; import { AuthException, @@ -157,7 +157,8 @@ export abstract class GenericAuthProvider implements AuthProvider { ) { const handler = passport.authenticate(this.getStrategy() as any, { ...this.defaultStrategyOptions, - ...{ state: this.deriveAuthState(state), scope }, + state, + scope, }); handler(req, res, next); @@ -277,14 +278,12 @@ export abstract class GenericAuthProvider implements AuthProvider { return; } - let authFlow: AuthFlow; - try { - authFlow = await this.parseState(state as string); - } catch (error) { - log.error(cxt, `(${strategyName}) Failed to parse state JWT from request.`, { clientInfo }); - increaseLoginCounter("failed", this.host); + const authFlow = request.authFlow; + if (!authFlow) { + log.error(`(${strategyName}) Auth flow state is missing.`); - response.redirect(this.getSorryUrl(`OAuth2 error. (${error})`)); + increaseLoginCounter("failed", this.host); + response.redirect(this.getSorryUrl(`Auth flow state is missing.`)); return; } @@ -539,12 +538,10 @@ export abstract class GenericAuthProvider implements AuthProvider { let currentGitpodUser: User | undefined = User.is(req.user) ? req.user : undefined; let candidate: Identity; - let authFlow: AuthFlow; - try { - authFlow = await this.parseState((req.query.state as string) || ""); - } catch (err) { - log.error(`(${strategyName}) Failed to extract auth flow from state`, err); - done(err, undefined); + const authFlow = req.authFlow; + if (!authFlow) { + log.error(`(${strategyName}) Auth flow state is missing.`); + done(AuthException.create("authflow-missing", "Auth flow state is missing.", {}), undefined); return; } @@ -784,31 +781,6 @@ export abstract class GenericAuthProvider implements AuthProvider { } throw lastError; }; - - private deriveAuthState(state: string): string { - // In preview environments, we prepend the current development branch to the state, to allow - // our preview proxy to route the Auth callback appropriately. - // See https://github.com/gitpod-io/ops/pull/9398/files - if (this.config.devBranch) { - return `${this.config.devBranch},${state}`; - } - - return state; - } - - private async parseState(state: string): Promise { - // In preview environments, we prepend the current development branch to the state, to allow - // our preview proxy to route the Auth callback appropriately. - // See https://github.com/gitpod-io/ops/pull/9398/files - // - // We need to strip the branch out of the state, if it's present - if (state.indexOf(",") >= 0) { - const [, actualState] = state.split(",", 2); - state = actualState; - } - - return await this.signInJWT.verify(state as string); - } } interface VerifyResult { diff --git a/components/server/src/authorization/checks.ts b/components/server/src/authorization/checks.ts index e08724a4433001..8e797498579036 100644 --- a/components/server/src/authorization/checks.ts +++ b/components/server/src/authorization/checks.ts @@ -31,3 +31,6 @@ export const WriteOrganizationInfo = check("user", "write_info", "organization") export const ReadOrganizationMembers = check("user", "read_members", "organization"); export const WriteOrganizationMembers = check("user", "write_members", "organization"); + +export const ReadOrganizationSettings = check("user", "read_settings", "organization"); +export const WriteOrganizationSettings = check("user", "write_settings", "organization"); diff --git a/components/server/src/authorization/definitions.ts b/components/server/src/authorization/definitions.ts index 546e72eb2312c5..5a54f3001c431d 100644 --- a/components/server/src/authorization/definitions.ts +++ b/components/server/src/authorization/definitions.ts @@ -15,11 +15,12 @@ export type ProjectRelation = "org"; export type Relation = OrganizationRelation | ProjectRelation; export type OrganizationPermission = - | "membership" | "read_info" | "write_info" | "read_members" | "write_members" + | "read_settings" + | "write_settings" | "create_project"; export type ProjectPermission = "write_info" | "read_info"; export type Permission = OrganizationPermission; diff --git a/components/server/src/express.ts b/components/server/src/express.ts index 84a835eda2848d..5589d4d6b13e74 100644 --- a/components/server/src/express.ts +++ b/components/server/src/express.ts @@ -5,10 +5,15 @@ */ import { User as GitpodUser } from "@gitpod/gitpod-protocol"; +import { AuthFlow } from "./auth/auth-provider"; // use declaration merging (https://www.typescriptlang.org/docs/handbook/declaration-merging.html) to augment the standard passport/express definitions declare global { namespace Express { export interface User extends GitpodUser {} + + interface Request { + authFlow?: AuthFlow; + } } } diff --git a/components/server/src/workspace/gitpod-server-impl.ts b/components/server/src/workspace/gitpod-server-impl.ts index ade695e2cd1ff1..6c1ef1a63f2858 100644 --- a/components/server/src/workspace/gitpod-server-impl.ts +++ b/components/server/src/workspace/gitpod-server-impl.ts @@ -3043,7 +3043,7 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable { async getOrgSettings(ctx: TraceContextWithSpan, orgId: string): Promise { const user = await this.checkAndBlockUser("getOrgSettings"); traceAPIParams(ctx, { orgId, userId: user.id }); - await this.guardTeamOperation(orgId, "get", "not_implemented"); + await this.guardTeamOperation(orgId, "get", "read_settings"); const settings = await this.teamDB.findOrgSettings(orgId); // TODO: make a default in protocol return settings ?? { workspaceSharingDisabled: false }; @@ -3056,7 +3056,7 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable { ): Promise { const user = await this.checkAndBlockUser("updateOrgSettings"); traceAPIParams(ctx, { orgId, userId: user.id }); - await this.guardTeamOperation(orgId, "update", "not_implemented"); + await this.guardTeamOperation(orgId, "update", "write_settings"); await this.teamDB.setOrgSettings(orgId, settings); return (await this.teamDB.findOrgSettings(orgId))!; } diff --git a/components/service-waiter/leeway.Dockerfile b/components/service-waiter/leeway.Dockerfile index 2aa1c4da02d018..83203ccc74c0f5 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:490977f0fd3d8596d173839dbb314153797312553b43f6a24b0e341cf2e8d473 +FROM cgr.dev/chainguard/wolfi-base:latest@sha256:5dcb7597e50978fc9dea77d96665bcd47ab0600386710c6e8dab35adf1102122 # 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 ab0c716f414c81..03075133b75dc3 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:490977f0fd3d8596d173839dbb314153797312553b43f6a24b0e341cf2e8d473 +FROM cgr.dev/chainguard/wolfi-base:latest@sha256:5dcb7597e50978fc9dea77d96665bcd47ab0600386710c6e8dab35adf1102122 # 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 edc6fe2ac0a69b..316d5069a6458f 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:490977f0fd3d8596d173839dbb314153797312553b43f6a24b0e341cf2e8d473 as dl +FROM cgr.dev/chainguard/wolfi-base:latest@sha256:5dcb7597e50978fc9dea77d96665bcd47ab0600386710c6e8dab35adf1102122 as dl WORKDIR /dl RUN apk add --no-cache curl file \ && curl -OsSL https://github.com/opencontainers/runc/releases/download/v1.1.7/runc.amd64 \ diff --git a/components/ws-daemon/seccomp-profile-installer/leeway.Dockerfile b/components/ws-daemon/seccomp-profile-installer/leeway.Dockerfile index 0fa543e9340306..d79c2fa0fdf790 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:490977f0fd3d8596d173839dbb314153797312553b43f6a24b0e341cf2e8d473 +FROM cgr.dev/chainguard/wolfi-base:latest@sha256:5dcb7597e50978fc9dea77d96665bcd47ab0600386710c6e8dab35adf1102122 # 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 96ed2cb80408d0..105f22aa372ae9 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:490977f0fd3d8596d173839dbb314153797312553b43f6a24b0e341cf2e8d473 +FROM cgr.dev/chainguard/wolfi-base:latest@sha256:5dcb7597e50978fc9dea77d96665bcd47ab0600386710c6e8dab35adf1102122 # 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 e09f82ce984bdb..9543ec32b5fe06 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:490977f0fd3d8596d173839dbb314153797312553b43f6a24b0e341cf2e8d473 +FROM cgr.dev/chainguard/wolfi-base:latest@sha256:5dcb7597e50978fc9dea77d96665bcd47ab0600386710c6e8dab35adf1102122 # Ensure latest packages are present, like security updates. RUN apk upgrade --no-cache \ diff --git a/install/installer/pkg/common/common.go b/install/installer/pkg/common/common.go index cb46f65bd7beee..36df115023ebab 100644 --- a/install/installer/pkg/common/common.go +++ b/install/installer/pkg/common/common.go @@ -431,7 +431,7 @@ func ConfigcatEnv(ctx *RenderContext) []corev1.EnvVar { }, { Name: "CONFIGCAT_BASE_URL", - Value: "https://" + ctx.Config.Domain + "/configcat", + Value: ClusterURL("http", ProxyComponent, ctx.Namespace, ProxyConfigcatPort) + "/configcat", }, } } diff --git a/install/installer/pkg/common/constants.go b/install/installer/pkg/common/constants.go index 81cfae0d129ce0..053621f5d5702f 100644 --- a/install/installer/pkg/common/constants.go +++ b/install/installer/pkg/common/constants.go @@ -28,6 +28,7 @@ const ( MinioServiceAPIPort = 9000 MonitoringChart = "monitoring" ProxyComponent = "proxy" + ProxyConfigcatPort = 9547 ProxyContainerHTTPPort = 80 ProxyContainerHTTPName = "http" ProxyContainerHTTPSPort = 443 @@ -61,6 +62,8 @@ const ( AnnotationConfigChecksum = "gitpod.io/checksum_config" DatabaseConfigMountPath = "/secrets/database-config" AuthPKISecretName = "auth-pki" + IDEServiceComponent = "ide-service" + OpenVSXProxyComponent = "openvsx-proxy" ) var ( diff --git a/install/installer/pkg/components/ide-service/constants.go b/install/installer/pkg/components/ide-service/constants.go index f8bd50f7b4d498..95c604fa9c7d35 100644 --- a/install/installer/pkg/components/ide-service/constants.go +++ b/install/installer/pkg/components/ide-service/constants.go @@ -4,8 +4,10 @@ package ide_service +import "github.com/gitpod-io/gitpod/installer/pkg/common" + const ( - Component = "ide-service" + Component = common.IDEServiceComponent VolumeConfig = "config" GRPCPortName = "grpc" diff --git a/install/installer/pkg/components/openvsx-proxy/constants.go b/install/installer/pkg/components/openvsx-proxy/constants.go index 6c8755b5be20bc..02d14074a30fe4 100644 --- a/install/installer/pkg/components/openvsx-proxy/constants.go +++ b/install/installer/pkg/components/openvsx-proxy/constants.go @@ -4,8 +4,10 @@ package openvsx_proxy +import "github.com/gitpod-io/gitpod/installer/pkg/common" + const ( - Component = "openvsx-proxy" + Component = common.OpenVSXProxyComponent ContainerPort = 8080 ServicePort = 8080 PortName = "http" diff --git a/install/installer/pkg/components/proxy/constants.go b/install/installer/pkg/components/proxy/constants.go index 942fedd7a489d8..c9517d1bc3b970 100644 --- a/install/installer/pkg/components/proxy/constants.go +++ b/install/installer/pkg/components/proxy/constants.go @@ -24,4 +24,6 @@ const ( RegistryTLSCertSecret = common.RegistryTLSCertSecret ContainerAnalyticsPort = 9546 ContainerAnalyticsName = "analytics" + ContainerConfigcatPort = common.ProxyConfigcatPort + ContainerConfigcatName = "configcat" ) diff --git a/install/installer/pkg/components/proxy/deployment.go b/install/installer/pkg/components/proxy/deployment.go index 66159efd1eec55..1dcf68d9f367bc 100644 --- a/install/installer/pkg/components/proxy/deployment.go +++ b/install/installer/pkg/components/proxy/deployment.go @@ -238,6 +238,9 @@ func deployment(ctx *common.RenderContext) ([]runtime.Object, error) { }, prometheusPort, { ContainerPort: ContainerAnalyticsPort, Name: ContainerAnalyticsName, + }, { + ContainerPort: ContainerConfigcatPort, + Name: ContainerConfigcatName, }}, SecurityContext: &corev1.SecurityContext{ Privileged: pointer.Bool(false), diff --git a/install/installer/pkg/components/proxy/networkpolicy.go b/install/installer/pkg/components/proxy/networkpolicy.go index 63d2ebf6922a80..bb9d49ce05274e 100644 --- a/install/installer/pkg/components/proxy/networkpolicy.go +++ b/install/installer/pkg/components/proxy/networkpolicy.go @@ -71,6 +71,36 @@ func networkpolicy(ctx *common.RenderContext) ([]runtime.Object, error) { "component": common.WSProxyComponent, }}, }}, + }, { + Ports: []networkingv1.NetworkPolicyPort{{ + Protocol: common.TCPProtocol, + Port: &intstr.IntOrString{IntVal: ContainerConfigcatPort}, + }}, + From: []networkingv1.NetworkPolicyPeer{{ + PodSelector: &metav1.LabelSelector{MatchLabels: map[string]string{ + "component": common.ServerComponent, + }}, + }, { + PodSelector: &metav1.LabelSelector{MatchLabels: map[string]string{ + "component": common.WSManagerBridgeComponent, + }}, + }, { + PodSelector: &metav1.LabelSelector{MatchLabels: map[string]string{ + "component": common.IDEServiceComponent, + }}, + }, { + PodSelector: &metav1.LabelSelector{MatchLabels: map[string]string{ + "component": common.PublicApiComponent, + }}, + }, { + PodSelector: &metav1.LabelSelector{MatchLabels: map[string]string{ + "component": common.UsageComponent, + }}, + }, { + PodSelector: &metav1.LabelSelector{MatchLabels: map[string]string{ + "component": common.OpenVSXProxyComponent, + }}, + }}, }}, }, }}, nil diff --git a/install/installer/pkg/components/proxy/service.go b/install/installer/pkg/components/proxy/service.go index a29417cb60a2a2..d477d20e65e2a4 100644 --- a/install/installer/pkg/components/proxy/service.go +++ b/install/installer/pkg/components/proxy/service.go @@ -75,6 +75,11 @@ func service(ctx *common.RenderContext) ([]runtime.Object, error) { ContainerPort: ContainerAnalyticsPort, ServicePort: ContainerAnalyticsPort, }, + { + Name: ContainerConfigcatName, + ContainerPort: ContainerConfigcatPort, + ServicePort: ContainerConfigcatPort, + }, } if ctx.Config.SSHGatewayHostKey != nil { ports = append(ports, common.ServicePort{ diff --git a/install/installer/pkg/components/spicedb/data/schema.yaml b/install/installer/pkg/components/spicedb/data/schema.yaml index fcb43965324242..13fc5bca64d3f2 100644 --- a/install/installer/pkg/components/spicedb/data/schema.yaml +++ b/install/installer/pkg/components/spicedb/data/schema.yaml @@ -6,23 +6,26 @@ schema: |- definition user {} definition organization { - // Organization specific roles - relation owner: user + // Every user in an organization is automatically a member relation member: user - - // Membership is the union of all organization specific roles - permission membership = owner + member + // Some users in an organization may additionally have the `owner` role + // granting them more privilidges with respect to the organization. + relation owner: user // General operations on organization - permission read_info = owner + member + permission read_info = member + owner permission write_info = owner // Operations on Organization's Members - permission read_members = owner + member - permission write_members = owner + member + permission read_members = member + owner + permission write_members = member + owner // Only owners can create new projects permission create_project = owner + + // Only owners can change settings + permission read_settings = owner + permission write_settings = owner } definition project { @@ -33,8 +36,8 @@ schema: |- relation editor: user // A subject is a viewer, if: // * the user is directly assigned as a viewer - // * the project has granted access to everyone who has membership in an organization - relation viewer: user | organization#membership + // * the project has granted access to everyone in an organization + relation viewer: user | organization#member // Project can be modified by: // * Organization owners @@ -49,6 +52,7 @@ schema: |- # relationships to be used for assertions & validation relationships: |- // We have an organization org_1, which has some members & owners + organization:org_1#member@user:user_0 organization:org_1#owner@user:user_0 organization:org_1#member@user:user_1 organization:org_1#member@user:user_2 @@ -56,10 +60,11 @@ relationships: |- // org_1 has a project project:project_1#org@organization:org_1 // project_1 can be accessed by anyone in the organization - it's visibility is public - project:project_1#viewer@organization:org_1#membership + project:project_1#viewer@organization:org_1#member // We have another organization org_2, which has some users, some of which are also members of org_1 + organization:org_2#member@user:user_0 organization:org_2#owner@user:user_0 organization:org_2#member@user:user_1 organization:org_2#member@user:user_10 @@ -73,36 +78,36 @@ relationships: |- # assertions should assert that a particular permission holds, or not assertions: assertTrue: - - "organization:org_1#read_info@user:user_0" + - organization:org_1#read_info@user:user_0 # user 0 can edit project_0, because they are the Org Owner - - "project:project_1#write_info@user:user_0" - + - project:project_1#write_info@user:user_0 + - organization:org_1#write_settings@user:user_0 assertFalse: # user 10 cannot access project_1 - - "project:project_1#read_info@user:user_10" - - "project:project_2#write_info@user:user_10" - + - project:project_1#read_info@user:user_10 + - project:project_2#write_info@user:user_10 # non-member/owner cannot access organization - - "organization:org1#read_info@user:user3" - - "organization:org1#write_info@user:user3" - - "organization:org1#read_members@user:user3" - - "organization:org1#write_members@user:user3" - + - organization:org_1#read_info@user:user_3 + - organization:org_1#write_info@user:user_3 + - organization:org_1#read_members@user:user_3 + - organization:org_1#write_members@user:user_3 + - organization:org_1#write_settings@user:user_1 # validation should assert that a particular relation exists between an entity, and a subject # validations are not used to assert that a permission exists validation: organization:org_1#member: - - "[user:user_1] is " - - "[user:user_2] is " - organization:org_1#membership: - - "[user:user_0] is " + - "[user:user_0] is " - "[user:user_1] is " - "[user:user_2] is " organization:org_1#owner: - "[user:user_0] is " - project:project_1#read_info: - - "[organization:org_1#membership] is " + organization:org_1#read_settings: + - "[user:user_0] is " + organization:org_1#write_settings: - "[user:user_0] is " + project:project_1#read_info: + - "[organization:org_1#member] is " + - "[user:user_0] is /" - "[user:user_1] is " - "[user:user_2] is " project:project_2#read_info: diff --git a/test/leeway.Dockerfile b/test/leeway.Dockerfile index 04d623d7129a82..3cc703c702ace1 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:490977f0fd3d8596d173839dbb314153797312553b43f6a24b0e341cf2e8d473 +FROM cgr.dev/chainguard/wolfi-base:latest@sha256:5dcb7597e50978fc9dea77d96665bcd47ab0600386710c6e8dab35adf1102122 # Ensure latest packages are present, like security updates. RUN apk upgrade --no-cache \