@venizia/ardor 0.4.1 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/presets/app/files/.configs/builders/Dockerfile +7 -2
- package/dist/presets/app/files/.configs/builders/docker-entrypoint.d/45-api-proxy.sh +36 -0
- package/dist/presets/app/files/.configs/builders/nginx-snippets/api-proxy.conf +14 -0
- package/dist/presets/app/files/.configs/builders/nginx-snippets/security-headers.conf +11 -0
- package/dist/presets/app/files/.configs/builders/nginx.conf.template +31 -13
- package/dist/presets/app/preset.json +8 -8
- package/dist/presets/lib/preset.json +3 -3
- package/package.json +5 -5
|
@@ -60,8 +60,9 @@ ARG APP_BUILD_COMMIT=
|
|
|
60
60
|
LABEL org.opencontainers.image.revision="${APP_BUILD_COMMIT}"
|
|
61
61
|
|
|
62
62
|
# The base image's entrypoint turns every /etc/nginx/templates/*.template into /etc/nginx/conf.d/*,
|
|
63
|
-
#
|
|
63
|
+
# leaving nginx's own variables ($uri, $host) as they are. The template includes the two snippets below.
|
|
64
64
|
COPY --from=builder /home/bun/app/{{appPath}}/.configs/builders/nginx.conf.template /etc/nginx/templates/default.conf.template
|
|
65
|
+
COPY --from=builder /home/bun/app/{{appPath}}/.configs/builders/nginx-snippets /etc/nginx/snippets
|
|
65
66
|
COPY --from=builder --chown=101:101 /home/bun/app/{{appPath}}/dist /usr/share/nginx/html
|
|
66
67
|
|
|
67
68
|
# The runtime config: this script writes /usr/share/nginx/html/config.js from the VITE_ environment variables
|
|
@@ -69,7 +70,11 @@ COPY --from=builder --chown=101:101 /home/bun/app/{{appPath}}/dist /usr/share/ng
|
|
|
69
70
|
# file it rewrites is the one the build copied from src/public, owned by 101 above.
|
|
70
71
|
COPY --from=builder --chmod=0755 /home/bun/app/{{appPath}}/.configs/builders/docker-entrypoint.d/40-runtime-config.sh /docker-entrypoint.d/40-runtime-config.sh
|
|
71
72
|
|
|
72
|
-
#
|
|
73
|
+
# The /api proxy: this script writes it from snippets/api-proxy.conf when API_UPSTREAM is set and not empty.
|
|
74
|
+
COPY --from=builder --chmod=0755 /home/bun/app/{{appPath}}/.configs/builders/docker-entrypoint.d/45-api-proxy.sh /docker-entrypoint.d/45-api-proxy.sh
|
|
75
|
+
|
|
76
|
+
# Where /api goes: a compose service name, a cluster service, an address (an origin, with no path). An app
|
|
77
|
+
# served behind a gateway sets it empty (`ENV API_UPSTREAM=` or `-e API_UPSTREAM=`), and then has no /api.
|
|
73
78
|
ENV API_UPSTREAM=http://api:3000
|
|
74
79
|
|
|
75
80
|
# The variables the app cannot run without, comma separated. A container that starts without one of them,
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# Writes the /api proxy of nginx only when the container has an upstream: `docker run -e API_UPSTREAM=http://api:3000`.
|
|
3
|
+
# With API_UPSTREAM unset or empty no /api location exists, which is what an app served behind a gateway wants.
|
|
4
|
+
#
|
|
5
|
+
# The nginx image runs every executable file of /docker-entrypoint.d/ in `sort -V` order before it starts nginx; the
|
|
6
|
+
# 45 puts this after the runtime-config script. nginx.conf.template includes /etc/nginx/conf.d/*.locations, and a
|
|
7
|
+
# glob that matches nothing is not an error. A script without the executable bit is skipped, hence `COPY --chmod=0755`
|
|
8
|
+
# in the Dockerfile.
|
|
9
|
+
#
|
|
10
|
+
# The upstream is written into the nginx configuration, so it must be an address and nothing else: a value with a
|
|
11
|
+
# character outside letters, digits, brackets (an IPv6 address) and `._:/@%+-` stops the container, naming the variable and never the value.
|
|
12
|
+
#
|
|
13
|
+
# API_PROXY_SOURCE and API_PROXY_TARGET name other files, for the tests; they are not VITE_ names, so never published.
|
|
14
|
+
set -eu
|
|
15
|
+
|
|
16
|
+
SOURCE="${API_PROXY_SOURCE:-/etc/nginx/snippets/api-proxy.conf}"
|
|
17
|
+
TARGET="${API_PROXY_TARGET:-/etc/nginx/conf.d/api-proxy.locations}"
|
|
18
|
+
|
|
19
|
+
# A file left from an earlier start must not outlive the variable that asked for it.
|
|
20
|
+
rm -f "$TARGET"
|
|
21
|
+
|
|
22
|
+
if [ -z "${API_UPSTREAM:-}" ]; then
|
|
23
|
+
echo "[api-proxy] API_UPSTREAM is empty: no /api proxy"
|
|
24
|
+
exit 0
|
|
25
|
+
fi
|
|
26
|
+
|
|
27
|
+
case "$API_UPSTREAM" in
|
|
28
|
+
*[!][A-Za-z0-9._:/@%+-]*)
|
|
29
|
+
echo "[api-proxy] FATAL: API_UPSTREAM has a character that is not part of an address" >&2
|
|
30
|
+
exit 1
|
|
31
|
+
;;
|
|
32
|
+
esac
|
|
33
|
+
|
|
34
|
+
# Only these two: nginx's own variables ($api_upstream, $host) stay as they are.
|
|
35
|
+
envsubst '${API_UPSTREAM} ${NGINX_LOCAL_RESOLVERS}' < "$SOURCE" > "$TARGET"
|
|
36
|
+
echo "[api-proxy] /api goes to the upstream of API_UPSTREAM"
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# The /api proxy. The script 45-api-proxy.sh fills in the two variables API_UPSTREAM and NGINX_LOCAL_RESOLVERS and
|
|
2
|
+
# writes the result to /etc/nginx/conf.d/api-proxy.locations, only when API_UPSTREAM is set and not empty.
|
|
3
|
+
#
|
|
4
|
+
# The path is kept: /api/hello reaches the upstream at /api/hello. The upstream is a variable that a resolver
|
|
5
|
+
# looks up per request, so nginx starts when the host does not resolve yet and only /api answers 502 until it does.
|
|
6
|
+
location /api/ {
|
|
7
|
+
resolver ${NGINX_LOCAL_RESOLVERS} valid=10s ipv6=off;
|
|
8
|
+
set $api_upstream ${API_UPSTREAM};
|
|
9
|
+
proxy_pass $api_upstream;
|
|
10
|
+
proxy_http_version 1.1;
|
|
11
|
+
proxy_set_header Host $host;
|
|
12
|
+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
13
|
+
proxy_set_header X-Forwarded-Proto $scheme;
|
|
14
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# The response headers of the app, included by every location of nginx.conf.template. `always` sends
|
|
2
|
+
# them on error responses too.
|
|
3
|
+
add_header X-Content-Type-Options "nosniff" always;
|
|
4
|
+
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
|
5
|
+
add_header X-Frame-Options "SAMEORIGIN" always;
|
|
6
|
+
|
|
7
|
+
# A Content-Security-Policy depends on what the app loads, so none is sent. An example to adapt: start with
|
|
8
|
+
# Content-Security-Policy-Report-Only, watch the browser console, then switch to the enforcing header. Admin
|
|
9
|
+
# libraries often need 'unsafe-inline' for styles. `frame-ancestors` replaces X-Frame-Options where both exist.
|
|
10
|
+
#
|
|
11
|
+
# add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'" always;
|
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
# The nginx configuration of {{app}}, rendered by the base image at start
|
|
2
|
-
# $
|
|
1
|
+
# The nginx configuration of {{app}}, rendered by the base image at start. Its own variables ($uri,
|
|
2
|
+
# $host) are nginx's, not the image's. Two things are included from /etc/nginx/snippets and
|
|
3
|
+
# /etc/nginx/conf.d, both put there by the Dockerfile and the entrypoint script 45-api-proxy.sh:
|
|
4
|
+
#
|
|
5
|
+
# security-headers.conf the response headers every location sends
|
|
6
|
+
# *.locations the /api proxy, written only when API_UPSTREAM is set and not empty
|
|
3
7
|
server {
|
|
4
8
|
listen 8080;
|
|
5
9
|
server_name _;
|
|
@@ -7,22 +11,34 @@ server {
|
|
|
7
11
|
root /usr/share/nginx/html;
|
|
8
12
|
index index.html;
|
|
9
13
|
|
|
10
|
-
#
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
14
|
+
# Text is compressed (html always is). Images and fonts are already compressed: leave them out.
|
|
15
|
+
gzip on;
|
|
16
|
+
gzip_vary on;
|
|
17
|
+
gzip_min_length 256;
|
|
18
|
+
gzip_types text/plain text/css text/xml text/javascript application/javascript application/json application/manifest+json application/xml image/svg+xml;
|
|
19
|
+
|
|
20
|
+
# nginx inherits add_header from the server only into a location that sets none of its own, and every
|
|
21
|
+
# location below sets Cache-Control. So each one includes the same snippet again: a header added to
|
|
22
|
+
# the snippet reaches all of them.
|
|
23
|
+
include /etc/nginx/snippets/security-headers.conf;
|
|
24
|
+
|
|
25
|
+
# For a load balancer or an orchestrator: answers from nginx alone, never from the backend.
|
|
26
|
+
location = /health {
|
|
27
|
+
access_log off;
|
|
28
|
+
default_type text/plain;
|
|
29
|
+
add_header Cache-Control "no-store";
|
|
30
|
+
include /etc/nginx/snippets/security-headers.conf;
|
|
31
|
+
return 200 "ok\n";
|
|
21
32
|
}
|
|
22
33
|
|
|
34
|
+
# The backend, when API_UPSTREAM is set: /api/hello reaches the upstream at /api/hello. An app that is served
|
|
35
|
+
# behind a gateway leaves API_UPSTREAM empty, and no /api location exists. See snippets/api-proxy.conf.
|
|
36
|
+
include /etc/nginx/conf.d/*.locations;
|
|
37
|
+
|
|
23
38
|
# The runtime config is written when the container starts and has no hash in its name: never cached.
|
|
24
39
|
location = /config.js {
|
|
25
40
|
add_header Cache-Control "no-store";
|
|
41
|
+
include /etc/nginx/snippets/security-headers.conf;
|
|
26
42
|
try_files $uri =404;
|
|
27
43
|
}
|
|
28
44
|
|
|
@@ -30,12 +46,14 @@ server {
|
|
|
30
46
|
location /assets/ {
|
|
31
47
|
expires 1y;
|
|
32
48
|
add_header Cache-Control "public, immutable";
|
|
49
|
+
include /etc/nginx/snippets/security-headers.conf;
|
|
33
50
|
try_files $uri =404;
|
|
34
51
|
}
|
|
35
52
|
|
|
36
53
|
# A route of the app, opened or reloaded directly, is served by the app.
|
|
37
54
|
location / {
|
|
38
55
|
add_header Cache-Control "no-cache";
|
|
56
|
+
include /etc/nginx/snippets/security-headers.conf;
|
|
39
57
|
try_files $uri $uri/ /index.html;
|
|
40
58
|
}
|
|
41
59
|
}
|
|
@@ -13,12 +13,12 @@
|
|
|
13
13
|
"dependencies": {
|
|
14
14
|
"@reduxjs/toolkit": "^2.13.0",
|
|
15
15
|
"@tanstack/react-query": "^5.104.5",
|
|
16
|
-
"@venizia/ardor": "0.4.
|
|
17
|
-
"@venizia/ignis-connectors": "0.4.
|
|
18
|
-
"@venizia/ignis-filter": "0.4.
|
|
19
|
-
"@venizia/ignis-helpers": "0.4.
|
|
20
|
-
"@venizia/ignis-inversion": "0.4.
|
|
21
|
-
"@venizia/ignis-kernel": "0.4.
|
|
16
|
+
"@venizia/ardor": "0.4.2",
|
|
17
|
+
"@venizia/ignis-connectors": "0.4.2",
|
|
18
|
+
"@venizia/ignis-filter": "0.4.2",
|
|
19
|
+
"@venizia/ignis-helpers": "0.4.2",
|
|
20
|
+
"@venizia/ignis-inversion": "0.4.2",
|
|
21
|
+
"@venizia/ignis-kernel": "0.4.2",
|
|
22
22
|
"class-variance-authority": "^0.7.1",
|
|
23
23
|
"clsx": "^2.1.1",
|
|
24
24
|
"ra-core": "^5.15.5",
|
|
@@ -35,8 +35,8 @@
|
|
|
35
35
|
"@types/bun": "^1.4.3",
|
|
36
36
|
"@types/react": "^19",
|
|
37
37
|
"@types/react-dom": "^19",
|
|
38
|
-
"@venizia/dev-configs": "0.4.
|
|
39
|
-
"@venizia/ignis-boot": "0.4.
|
|
38
|
+
"@venizia/dev-configs": "0.4.2",
|
|
39
|
+
"@venizia/ignis-boot": "0.4.2",
|
|
40
40
|
"@vitejs/plugin-react": "^6.1.2",
|
|
41
41
|
"eslint": "^10.13.0",
|
|
42
42
|
"oxlint": "1.89.0",
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
"devDependencies": {
|
|
6
6
|
"@types/bun": "^1.4.3",
|
|
7
7
|
"@types/react": "^19",
|
|
8
|
-
"@venizia/ardor": "^0.4.
|
|
9
|
-
"@venizia/dev-configs": "0.4.
|
|
8
|
+
"@venizia/ardor": "^0.4.2",
|
|
9
|
+
"@venizia/dev-configs": "0.4.2",
|
|
10
10
|
"eslint": "^10.13.0",
|
|
11
11
|
"oxlint": "1.89.0",
|
|
12
12
|
"oxlint-tsgolint": "7.0.2004",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"typescript": "^6.0.3"
|
|
18
18
|
},
|
|
19
19
|
"peerDependencies": {
|
|
20
|
-
"@venizia/ardor": "^0.4.
|
|
20
|
+
"@venizia/ardor": "^0.4.2",
|
|
21
21
|
"react": "^19.3.1",
|
|
22
22
|
"react-dom": "^19.3.1",
|
|
23
23
|
"react-router-dom": "^7.18.4",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@venizia/ardor",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.2",
|
|
4
4
|
"description": "ARDOR - frontend application framework for the VENIZIA family. One entry point over ardor-kernel, ardor-react and ardor-admin: IGNIS inversion of control, a REST data layer, auth and i18n providers, and the React bindings for a react-admin application.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ardor",
|
|
@@ -65,13 +65,13 @@
|
|
|
65
65
|
"prepublishOnly": "make rebuild"
|
|
66
66
|
},
|
|
67
67
|
"dependencies": {
|
|
68
|
-
"@venizia/ardor-admin": "0.4.
|
|
69
|
-
"@venizia/ardor-kernel": "0.4.
|
|
70
|
-
"@venizia/ardor-react": "0.4.
|
|
68
|
+
"@venizia/ardor-admin": "0.4.2",
|
|
69
|
+
"@venizia/ardor-kernel": "0.4.2",
|
|
70
|
+
"@venizia/ardor-react": "0.4.2"
|
|
71
71
|
},
|
|
72
72
|
"devDependencies": {
|
|
73
73
|
"@size-limit/preset-small-lib": "^14.2.0",
|
|
74
|
-
"@venizia/dev-configs": "^0.4.
|
|
74
|
+
"@venizia/dev-configs": "^0.4.2",
|
|
75
75
|
"eslint": "^10.13.0",
|
|
76
76
|
"oxlint": "1.89.0",
|
|
77
77
|
"oxlint-tsgolint": "7.0.2004",
|