Skip to content

Commit 64037ba

Browse files
Merge branch 'main' into renovate/node-22
2 parents 89820d8 + bff581d commit 64037ba

File tree

9 files changed

+124
-41
lines changed

9 files changed

+124
-41
lines changed

.env.template

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,6 @@ SESSION_SECRET=
2020

2121
FEEDBACK_SLACK_URL=
2222
FEEDBACK_URL_LINK=
23+
24+
# frame-ancestors attribute of CSP. Separate multiple values with a space
25+
FRAME_ANCESTORS=

README.md

Lines changed: 52 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,44 +2,72 @@
22

33
# ui-frontend
44

5-
## About this project
5+
## About This Project
66

77
This repository contains code relevant for the frontend component required in the Managed Control Plane UI (MCP UI), which is part of the @openmcp-project, more info [here](https://github.com/openmcp-project).
88

99
The MCP UI enables endusers to work with Managed Control Planes, without having to use kubectl. Note that the current focus of the UI is on displaying information about the various managed resources, as well as the MCP instances themselves. It is also possible to check the status of the resources, and display / copy their YAML representations.
1010

1111
Overall, the UI provides an easy jump-start for everyone interested in checking the status of Managed Control Planes, without having to use kubectl.
1212

13-
## Requirements and Setup
13+
## Getting Started
1414

15-
### Development
15+
### Development Setup
1616

17-
1. install dependencies: `npm i`
17+
#### Install Dependencies
1818

19-
1. Copy the `frontend-config.json` to `public/frontend-config.json` and adapt the `backendUrl` according to your setup (see section Dynamic Frontend Config).
19+
```bash
20+
npm i
21+
```
22+
23+
#### Configure Frontend
24+
25+
- Copy `frontend-config.json` to `public/frontend-config.json` and adapt the `backendUrl` according to your setup (see section Dynamic Frontend Config).
26+
- Copy `.env.template` to `.env` and fill in the missing values.
2027

21-
1. Connect to the ui-backend server
22-
**Run it locally**:
23-
- See `https://github.com/openmcp-project/ui-backend`
28+
#### Run the Application
29+
30+
```bash
31+
npm run dev
32+
```
2433

25-
1. Start the application:
34+
The UI will be served on http://localhost:5173.
2635

27-
Run `npm run dev`
2836

29-
### Build
37+
#### Safari Support
3038

31-
1. Build the application:
39+
**Note:** The frontend is currently incompatible with Safari when running locally on `localhost`.
3240

33-
Run `npm run build`
41+
To enable local development with Safari, follow these steps on your local machine:
3442

35-
2. Serve the application locally:
43+
1. **Update Cookie Settings:**
44+
In [`server/encrypted-session.js`](server/encrypted-session.js), set the `secure` property to `false` in both occurrences.
3645

37-
Run `npm run preview`
46+
2. **Disable Helmet Registration:**
47+
In [`server.js`](server.js), comment out or remove the registration of `helmet`.
3848

39-
3. For production:
4049

41-
Use the docker image which uses nginx for best performance and small bundle size.
42-
`docker build -t my-label .`
50+
### Build & Production
51+
52+
#### Build the Application
53+
54+
```bash
55+
npm run build
56+
```
57+
58+
#### Serve the Production Build Locally
59+
60+
```bash
61+
npm run preview
62+
```
63+
64+
#### Production Deployment
65+
66+
Use the docker image which uses nginx for best performance and small bundle size.
67+
68+
```bash
69+
docker build -t my-label .
70+
```
4371

4472
### Dynamic FrontendConfig
4573

@@ -50,11 +78,11 @@ An example docker run command would be
5078
docker run -p 5001:80 -e BACKEND_CONFIG="$(cat frontend-config.json)" -t ui-test
5179
```
5280

53-
## Support, Feedback, Contributing
81+
## Support & Contributing
5482

5583
This project is open to feature requests/suggestions, bug reports etc. via [GitHub issues](https://github.com/openmcp-project/ui-frontend/issues). Contribution and feedback are encouraged and always welcome. For more information about how to contribute, the project structure, as well as additional contribution information, see our [Contribution Guidelines](CONTRIBUTING.md).
5684

57-
## Security / Disclosure
85+
## Security & Disclosure
5886
If you find any bug that may be a security problem, please follow our instructions at [in our security policy](https://github.com/openmcp-project/ui-frontend/security/policy) on how to report it. Please do not create GitHub issues for security-related doubts or problems.
5987

6088
## Code of Conduct
@@ -64,3 +92,7 @@ We as members, contributors, and leaders pledge to make participation in our com
6492
## Licensing
6593

6694
Copyright 2025 SAP SE or an SAP affiliate company and ui-frontend contributors. Please see our [LICENSE](LICENSE) for copyright and license information. Detailed information including third-party components and their licensing/copyright information is available [via the REUSE tool](https://api.reuse.software/info/github.com/openmcp-project/ui-frontend).
95+
96+
---
97+
98+
**Happy contributing! 🚀**

index.html

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,9 @@
88
<title>MCP</title>
99
</head>
1010

11-
<script>
12-
window.global ||= window;
13-
</script>
14-
1511
<body>
1612
<div id="root"></div>
1713
<script type="module" src="/src/mount.ts"></script>
1814
</body>
1915

20-
</html>
16+
</html>

package-lock.json

Lines changed: 30 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"npm": "^11.0.0"
88
},
99
"scripts": {
10-
"dev": "node server.js --dev",
10+
"dev": "node server.js --local-dev",
1111
"start": "node server.js",
1212
"build": "tsc && vite build",
1313
"lint": "eslint ./src --report-unused-disable-directives --max-warnings 0",
@@ -23,9 +23,10 @@
2323
"@fastify/autoload": "^6.3.0",
2424
"@fastify/cookie": "^11.0.2",
2525
"@fastify/env": "^5.0.2",
26+
"@fastify/helmet": "^13.0.1",
2627
"@fastify/http-proxy": "^11.1.2",
27-
"@fastify/sensible": "^6.0.3",
2828
"@fastify/secure-session": "^8.2.0",
29+
"@fastify/sensible": "^6.0.3",
2930
"@fastify/session": "^11.1.0",
3031
"@fastify/static": "^8.1.1",
3132
"@fastify/vite": "^8.1.3",

server.js

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,22 @@
11
import Fastify from 'fastify';
22
import FastifyVite from '@fastify/vite';
3+
import helmet from '@fastify/helmet';
34
import { fileURLToPath } from 'node:url';
45
import path from 'node:path';
56
import dotenv from 'dotenv';
67
import proxy from './server/app.js';
8+
import envPlugin from "./server/config/env.js";
79
import { copyFileSync } from 'node:fs';
810

911
dotenv.config();
1012

11-
const isDev = process.argv.includes('--dev');
13+
const isLocalDev = process.argv.includes('--local-dev');
1214

1315
const __filename = fileURLToPath(import.meta.url);
1416
const __dirname = path.dirname(__filename);
15-
const frontendConfigLocation = isDev ? 'public/frontend-config.json' : 'dist/client/frontend-config.json';
17+
const frontendConfigLocation = isLocalDev
18+
? 'public/frontend-config.json'
19+
: 'dist/client/frontend-config.json';
1620

1721
if (process.env.FRONTEND_CONFIG_PATH !== undefined && process.env.FRONTEND_CONFIG_PATH.length > 0) {
1822
console.log('FRONTEND_CONFIG_PATH is specified. Will copy the frontend-config from there.');
@@ -24,13 +28,28 @@ const fastify = Fastify({
2428
logger: true,
2529
});
2630

31+
await fastify.register(envPlugin);
32+
33+
fastify.register(
34+
helmet,
35+
{
36+
contentSecurityPolicy: {
37+
directives: {
38+
"connect-src": ["'self'", "sdk.openui5.org"],
39+
"script-src": isLocalDev ? ["'self'", "'unsafe-inline'"] : ["'self'"],
40+
"frame-ancestors": [fastify.config.FRAME_ANCESTORS]
41+
},
42+
}
43+
}
44+
)
45+
2746
fastify.register(proxy, {
2847
prefix: '/api',
2948
});
3049

3150
await fastify.register(FastifyVite, {
3251
root: __dirname,
33-
dev: isDev,
52+
dev: isLocalDev,
3453
spa: true,
3554
});
3655

server/app.js

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
1-
import path, { join, dirname } from 'node:path';
2-
import { fileURLToPath } from 'node:url';
3-
import AutoLoad from '@fastify/autoload';
4-
import envPlugin from './config/env.js';
5-
import encryptedSession from './encrypted-session.js';
1+
import path, { join, dirname } from "node:path";
2+
import { fileURLToPath } from "node:url";
3+
import AutoLoad from "@fastify/autoload";
4+
import encryptedSession from "./encrypted-session.js";
65

76
export const options = {};
87

98
const __filename = fileURLToPath(import.meta.url);
109
const __dirname = dirname(__filename);
1110

1211
export default async function (fastify, opts) {
13-
await fastify.register(envPlugin);
1412
fastify.register(encryptedSession, {
1513
...opts,
1614
});

server/config/env.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ const schema = {
1313
'COOKIE_SECRET',
1414
'SESSION_SECRET',
1515
'API_BACKEND_URL',
16+
'FRAME_ANCESTORS',
1617
],
1718
properties: {
1819
// Application variables (.env)
@@ -27,6 +28,7 @@ const schema = {
2728
API_BACKEND_URL: { type: 'string' },
2829
FEEDBACK_SLACK_URL: { type: 'string' },
2930
FEEDBACK_URL_LINK: { type: 'string' },
31+
FRAME_ANCESTORS: { type: 'string' },
3032

3133
// System variables
3234
NODE_ENV: { type: 'string', enum: ['development', 'production'] },

server/encrypted-session.js

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export const ENCRYPTED_COOKIE_KEY_ENCRYPTION_KEY = 'encryptionKey';
2020
export const SESSION_COOKIE_NAME = 'session-cookie';
2121

2222
async function encryptedSession(fastify) {
23-
const { COOKIE_SECRET, SESSION_SECRET, NODE_ENV } = fastify.config;
23+
const { COOKIE_SECRET, SESSION_SECRET } = fastify.config;
2424

2525
await fastify.register(fastifyCookie);
2626

@@ -31,8 +31,9 @@ async function encryptedSession(fastify) {
3131
cookie: {
3232
path: '/',
3333
httpOnly: true,
34-
sameSite: 'lax',
35-
secure: NODE_ENV === 'production',
34+
sameSite: "None", // cross-site cookies are needed for the session to work when embedded. By setting CORS to None and CSP.frame-anchestors we restrict the api calls from the browser that contain the cookies to originating from our site only.
35+
partitioned: true, // use for modern isolation of third party cookies when embedded, every embedded iframe (or not embedded) gets its own cookie partition
36+
secure: true,
3637
maxAge: 60 * 60 * 24 * 7, // 7 days
3738
},
3839
});
@@ -43,8 +44,9 @@ async function encryptedSession(fastify) {
4344
cookie: {
4445
path: '/',
4546
httpOnly: true,
46-
sameSite: 'lax',
47-
secure: NODE_ENV === 'production',
47+
sameSite: "None", // see secureSession cookie for explanation
48+
partitioned: true, // see secureSession cookie for explanation
49+
secure: true,
4850
maxAge: 60 * 60 * 24 * 7, // 7 days
4951
},
5052
});

0 commit comments

Comments
 (0)