Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion helm-chart/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ type: application

# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
version: 11.6.0
version: 11.7.0-rc.3
10 changes: 5 additions & 5 deletions helm-chart/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ ingress:
- host: datalab.my-domain.net
EOF

helm install onyxia onyxia/onyxia --version "11.6.0" -f onyxia-values.yaml
helm install onyxia onyxia/onyxia --version "11.7.0-rc.3" -f onyxia-values.yaml
```

To expose Onyxia with the Kubernetes Gateway API instead of an Ingress, use an `HTTPRoute`.
Expand All @@ -40,7 +40,7 @@ httpRoute:
- datalab.my-domain.net
EOF

helm install onyxia onyxia/onyxia --version "11.6.0" -f onyxia-values.yaml
helm install onyxia onyxia/onyxia --version "11.7.0-rc.3" -f onyxia-values.yaml
```

### Using the Keycloak Theme (Optional)
Expand All @@ -62,7 +62,7 @@ extraInitContainers: |
args:
- -c
- |
curl -L -f -S -o /extensions/onyxia.jar https://github.com/InseeFrLab/onyxia/releases/download/v11.6.0/keycloak-theme.jar
curl -L -f -S -o /extensions/onyxia.jar https://github.com/InseeFrLab/onyxia/releases/download/v11.7.0-rc.3/keycloak-theme.jar
volumeMounts:
- name: extensions
mountPath: /extensions
Expand Down Expand Up @@ -97,7 +97,7 @@ api:
```

- [The REST API (`api`)](https://github.com/InseeFrLab/onyxia-api/blob/v4.12.0/README.md#configuration)
- [The Web Application (`web`)](https://github.com/InseeFrLab/onyxia/blob/web-v5.6.0/web/.env)
- [The Web Application (`web`)](https://github.com/InseeFrLab/onyxia/blob/web-v5.7.0-rc.3/web/.env)

Below is a sample `onyxia-values.yaml` file that illustrates where to specify the `api` and `web` configuration parameters.

Expand Down Expand Up @@ -150,4 +150,4 @@ httpRoute:
If you are building your own service catalog for Onyxia ([learn how](https://docs.onyxia.sh/catalog-of-services)).
Here are defined the onyxia reserved parameter and the structure of the dynamic context:

[`values.schema.json` `"x-onyxia"` specifications](https://github.com/InseeFrLab/onyxia/blob/web-v5.6.0/web/src/core/ports/OnyxiaApi/XOnyxia.ts)
[`values.schema.json` `"x-onyxia"` specifications](https://github.com/InseeFrLab/onyxia/blob/web-v5.7.0-rc.3/web/src/core/ports/OnyxiaApi/XOnyxia.ts)
2 changes: 1 addition & 1 deletion helm-chart/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ web:
replicaCount: 1
image:
repository: inseefrlab/onyxia-web
tag: 5.6.0
tag: 5.7.0-rc.3
pullPolicy: IfNotPresent

imagePullSecrets: []
Expand Down
2 changes: 1 addition & 1 deletion web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "onyxia-web",
"homepage": "https://onyxia.sh",
"type": "module",
"version": "5.6.0",
"version": "5.7.0-rc.3",
"license": "MIT",
"scripts": {
"postinstall": "yarn install-git-hooks && yarn postinstall:code-gen",
Expand Down
10 changes: 7 additions & 3 deletions web/scripts/unyamlify-env-local.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,24 +54,28 @@ if (!fs.existsSync(envLocalYamlFilePath)) {
` roleSessionName: ""`,
` }`,
` },`,
` anonymousProfileName: "anonymous",`,
` bookmarks: [`,
` {`,
` s3Uri: "s3://$1/",`,
` title: "Personal Bucket",`,
` claimName: "preferred_username"`,
` claimName: "preferred_username",`,
` forProfileName: "default"`,
` },`,
` {`,
` s3Uri: "s3://projet-$1/",`,
` title: "Projet $1",`,
` claimName: "groups",`,
` excludedClaimPattern: "^USER_ONYXIA.*"`,
` excludedClaimPattern: "^USER_ONYXIA.*",`,
` forProfileName: "default"`,
` },`,
` {`,
` s3Uri: "s3://donnees-insee/diffusion/",`,
` title: {`,
` fr: "Données de diffusion",`,
` en: "Dissemination Data"`,
` }`,
` },`,
` forProfileName: "default"`,
` }`,
` ]`,
` }`,
Expand Down
16 changes: 6 additions & 10 deletions web/src/core/bootstrap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,15 @@ export async function bootstrapCore(
const { createOnyxiaApi } = await import("core/adapters/onyxiaApi/mock");

const oidcParams = (() => {
const [entry] = s3Config.entries;
const sts = s3Config.entries
.map(entry => entry.sts)
.find(sts => sts !== undefined);

if (entry === undefined) {
if (sts === undefined) {
return undefined;
}

const { issuerUri, clientId, ...rest } = entry.sts.oidcParams;
const { issuerUri, clientId, ...rest } = sts.oidcParams;

assert(issuerUri !== undefined, "Missing OIDC Issuer URI");
assert(clientId !== undefined, "Missing OIDC Client ID");
Expand Down Expand Up @@ -339,13 +341,7 @@ export async function bootstrapCore(
await dispatch(usecases.userProfileForm.protectedThunks.initialize());
}

init_s3ProfilesManagement: {
if (!oidc.isUserLoggedIn) {
break init_s3ProfilesManagement;
}

await dispatch(usecases.s3ProfilesManagement.protectedThunks.initialize());
}
await dispatch(usecases.s3ProfilesManagement.protectedThunks.initialize());

pluginSystemInitCore({ core, context });

Expand Down
199 changes: 114 additions & 85 deletions web/src/core/ports/OnyxiaApi/S3Config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ type S3Config_S3_EnvValue_ExpectedShape = ArrayOrNot<{
>;
oidcConfiguration?: Partial<ApiTypes.OidcConfiguration>;
};
anonymousProfileName?: string;
bookmarks?: ({
s3Uri: string;
title: LocalizedString;
Expand Down Expand Up @@ -98,6 +99,7 @@ const zS3Config_S3_EnvValue_ExpectedShape = (() => {
oidcConfiguration: zOidcConfiguration.optional()
})
.optional(),
anonymousProfileName: z.string().optional(),
bookmarks: z.array(zBookmark).optional()
});

Expand All @@ -122,49 +124,60 @@ export namespace S3Config {
url: string;
pathStyleAccess: boolean;
region: string | undefined;
sts: {
url: string | undefined;
durationSeconds: number | undefined;
roles: Entry.StsRole[];
oidcParams: OidcParams_Partial;
};
// NOTE: sts and anonymousProfileName cannot be undefined at the same time.
sts:
| {
url: string | undefined;
durationSeconds: number | undefined;
roles: Entry.StsRole[];
oidcParams: OidcParams_Partial;
}
| undefined;
anonymousProfileName: string | undefined;
bookmarks: Entry.Bookmark[];
};

export namespace Entry {
export type StsRole = {
roleARN: string;
roleSessionName: string;
profileName: string;
} & (
| {
claimName: undefined;
includedClaimPattern?: never;
excludedClaimPattern?: never;
}
| {
claimName: string;
includedClaimPattern: string | undefined;
excludedClaimPattern: string | undefined;
}
);
export type StsRole = StsRole.NonTemplated | StsRole.Templated;

export type Bookmark = {
s3UriStr_templated: string;
title: LocalizedString;
forProfileNames: string[];
} & (
| {
claimName: undefined;
includedClaimPattern?: never;
excludedClaimPattern?: never;
}
| {
claimName: string;
includedClaimPattern: string | undefined;
excludedClaimPattern: string | undefined;
}
);
export namespace StsRole {
type Common = {
roleARN: string;
roleSessionName: string;
profileName: string;
};

export type NonTemplated = Common & {
isTemplated: false;
};

export type Templated = Common & {
isTemplated: true;
claimName: string;
includedClaimPattern: string | undefined;
excludedClaimPattern: string | undefined;
};
}

export type Bookmark = Bookmark.NonTemplated | Bookmark.Templated;
export namespace Bookmark {
type Common = {
s3UriStr: string;
title: LocalizedString;
forProfileNames: string[];
};

export type NonTemplated = Common & {
isTemplated: false;
};

export type Templated = Common & {
isTemplated: true;
claimName: string;
includedClaimPattern: string | undefined;
excludedClaimPattern: string | undefined;
};
}
}
}

Expand Down Expand Up @@ -198,60 +211,73 @@ export function parseS3ConfigFromEnvValue(params: { envValue: string }): S3Confi
const parsedValue_arr = parsedValue instanceof Array ? parsedValue : [parsedValue];

const entries = parsedValue_arr
.filter(s3Config => s3Config.sts !== undefined)
.filter(
s3Config =>
s3Config.sts !== undefined || s3Config.anonymousProfileName !== undefined
)
.map((s3Config): S3Config.Entry => {
const { sts } = s3Config;

assert(sts !== undefined);

const roles = Array.isArray(sts.role) ? sts.role : [sts.role];

return {
url: s3Config.URL,
pathStyleAccess: s3Config.pathStyleAccess ?? true,
region: s3Config.region,
sts: {
url: sts.URL,
durationSeconds: sts.durationSeconds,
roles: roles.map(
(role): S3Config.Entry.StsRole => ({
roleARN: role.roleARN,
roleSessionName: role.roleSessionName,
profileName: role.profileName,
...(role.claimName === undefined
? { claimName: undefined }
: {
claimName: role.claimName,
includedClaimPattern: role.includedClaimPattern,
excludedClaimPattern: role.excludedClaimPattern
sts:
sts === undefined
? undefined
: {
url: sts.URL,
durationSeconds: sts.durationSeconds,
roles: (Array.isArray(sts.role)
? sts.role
: [sts.role]
).map(
(role): S3Config.Entry.StsRole => ({
roleARN: role.roleARN,
roleSessionName: role.roleSessionName,
profileName: role.profileName,
...(role.claimName === undefined
? { isTemplated: false }
: {
isTemplated: true,
claimName: role.claimName,
includedClaimPattern:
role.includedClaimPattern,
excludedClaimPattern:
role.excludedClaimPattern
})
})
})
),
oidcParams: {
issuerUri: sts.oidcConfiguration?.issuerURI || undefined,
clientId: sts.oidcConfiguration?.clientID || undefined,
extraQueryParams_raw:
sts.oidcConfiguration?.extraQueryParams || undefined,
scope_spaceSeparated: sts.oidcConfiguration?.scope || undefined,
idleSessionLifetimeInSeconds: (() => {
const value =
sts.oidcConfiguration?.idleSessionLifetimeInSeconds;

if (value === "" || value === undefined) {
return undefined;
}

if (typeof value === "number") {
return value;
}

return parseInt(value);
})()
}
},
),
oidcParams: {
issuerUri:
sts.oidcConfiguration?.issuerURI || undefined,
clientId: sts.oidcConfiguration?.clientID || undefined,
extraQueryParams_raw:
sts.oidcConfiguration?.extraQueryParams ||
undefined,
scope_spaceSeparated:
sts.oidcConfiguration?.scope || undefined,
idleSessionLifetimeInSeconds: (() => {
const value =
sts.oidcConfiguration
?.idleSessionLifetimeInSeconds;

if (value === "" || value === undefined) {
return undefined;
}

if (typeof value === "number") {
return value;
}

return parseInt(value);
})()
}
},
anonymousProfileName: s3Config.anonymousProfileName,
bookmarks: (s3Config.bookmarks ?? []).map(
(bookmark): S3Config.Entry.Bookmark => ({
s3UriStr_templated: bookmark.s3Uri,
s3UriStr: bookmark.s3Uri,
title: bookmark.title,
forProfileNames:
bookmark.forProfileName === undefined
Expand All @@ -260,8 +286,9 @@ export function parseS3ConfigFromEnvValue(params: { envValue: string }): S3Confi
? [bookmark.forProfileName]
: bookmark.forProfileName,
...(bookmark.claimName === undefined
? { claimName: undefined }
? { isTemplated: false }
: {
isTemplated: true,
claimName: bookmark.claimName,
includedClaimPattern: bookmark.includedClaimPattern,
excludedClaimPattern: bookmark.excludedClaimPattern
Expand All @@ -272,8 +299,10 @@ export function parseS3ConfigFromEnvValue(params: { envValue: string }): S3Confi
});

const s3ConfigForCreationForm =
parsedValue_arr.find(s3Config => s3Config.sts === undefined) ??
parsedValue_arr[0];
parsedValue_arr.find(
s3Config =>
s3Config.sts === undefined && s3Config.anonymousProfileName === undefined
) ?? parsedValue_arr[0];

return {
entries,
Expand Down
Loading