mirror of
https://github.com/dadosfera/maestro.git
synced 2026-11-10 12:39:08 +00:00
Compare commits
23
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9c8c761529 | ||
|
|
740540d4dc | ||
|
|
94c9ab7939 | ||
|
|
a211b8593e | ||
|
|
25661613d5 | ||
|
|
3d8ea3576d | ||
|
|
e3a2eba5c3 | ||
|
|
81c446354b | ||
|
|
bf0314f5b1 | ||
|
|
c97180ac95 | ||
|
|
cac36f2c60 | ||
|
|
cd21fd0b7b | ||
|
|
a5a685ee3f | ||
|
|
a16fefe691 | ||
|
|
9c57485031 | ||
|
|
7051b21d86 | ||
|
|
0c4888ccdb | ||
|
|
e1b0e88bd8 | ||
|
|
cef1184908 | ||
|
|
31dda867d1 | ||
|
|
8a92da470c | ||
|
|
b89909ad66 | ||
|
|
2bb280e8de |
@@ -101,6 +101,17 @@ spec:
|
||||
value: {{ .Values.maestro.dedicated_proxy }}
|
||||
- name: COOKIE_SECRET
|
||||
value: {{ .Values.maestro.cookie_secret }}
|
||||
# Browser session cookies (ddf-auth*, ddf-refresh-auth*, ddf-user-id*).
|
||||
# Scoped per environment so a staging login never overwrites a
|
||||
# production session in the same browser (both live under dadosfera.ai).
|
||||
- name: COOKIE_DOMAIN
|
||||
value: {{ .Values.maestro.cookie_domain | default ".dadosfera.ai" | quote }}
|
||||
- name: AUTH_COOKIE_SUFFIX
|
||||
value: {{ .Values.maestro.auth_cookie_suffix | default "" | quote }}
|
||||
- name: SESSION_COOKIE_MAX_AGE_DAYS
|
||||
value: {{ .Values.maestro.session_cookie_max_age_days | default "30" | quote }}
|
||||
- name: AUTH_RPC_TIMEOUT_MS
|
||||
value: {{ .Values.maestro.auth_rpc_timeout_ms | default "10000" | quote }}
|
||||
- name: REDIS_DATABASE
|
||||
value: "{{ .Values.maestro.redis_database }}"
|
||||
- name: REDIS_HOST
|
||||
|
||||
@@ -7,6 +7,12 @@ maestro:
|
||||
open_customer_id: b3e3dfe5-b992-4586-a73c-c0b0c00f615d
|
||||
open_group_id: e3f98a2f-7748-4981-8505-7695c8ca8218
|
||||
cookie_secret: "ff7bc13823edb2ae50d248e5780bddc9d4b31c36"
|
||||
# Session cookies: staging gets its own names AND domain so that
|
||||
# app.stg.dadosfera.ai and app.dadosfera.ai sessions never collide.
|
||||
cookie_domain: ".stg.dadosfera.ai"
|
||||
auth_cookie_suffix: "-stg"
|
||||
session_cookie_max_age_days: "30"
|
||||
auth_rpc_timeout_ms: "10000"
|
||||
redis_database: "1"
|
||||
platform_api_url: https://xs2hkhq07k.execute-api.us-east-1.amazonaws.com
|
||||
connections_api_url: https://iy40eans64.execute-api.us-east-1.amazonaws.com
|
||||
|
||||
@@ -55,7 +55,14 @@ maestro:
|
||||
redis_database: "0"
|
||||
redis_tls: "true"
|
||||
cookie_secret: "13cc5e136d3074bcc05bec8697092ec1f5f376bf"
|
||||
# Session cookies: production keeps the historical names on the apex domain.
|
||||
cookie_domain: ".dadosfera.ai"
|
||||
auth_cookie_suffix: ""
|
||||
session_cookie_max_age_days: "30"
|
||||
auth_rpc_timeout_ms: "10000"
|
||||
firebase_base_url: https://feature-flag-25bf6-default-rtdb.firebaseio.com/prd
|
||||
connections_api_url: https://wv6fw7ayj4.execute-api.us-east-1.amazonaws.com
|
||||
|
||||
autoscaling:
|
||||
enabled: false
|
||||
minReplicas: 1
|
||||
|
||||
+234
@@ -900,6 +900,9 @@
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -949,6 +952,9 @@
|
||||
"connections"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -997,6 +1003,9 @@
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -1033,6 +1042,9 @@
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -1066,6 +1078,9 @@
|
||||
"connections"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -2403,6 +2418,9 @@
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -2486,6 +2504,9 @@
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -2525,6 +2546,9 @@
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -2564,6 +2588,9 @@
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -2601,6 +2628,9 @@
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -2640,6 +2670,9 @@
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -2681,6 +2714,9 @@
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -2722,6 +2758,9 @@
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -3071,6 +3110,9 @@
|
||||
"PipelinesV2"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -3120,6 +3162,9 @@
|
||||
"PipelinesV2"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -3190,6 +3235,9 @@
|
||||
"PipelinesV2"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -3230,6 +3278,9 @@
|
||||
"PipelinesV2"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -3270,6 +3321,9 @@
|
||||
"PipelinesV2"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -3310,6 +3364,9 @@
|
||||
"PipelinesV2"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -3350,6 +3407,9 @@
|
||||
"PipelinesV2"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -3397,6 +3457,9 @@
|
||||
"PipelinesV2"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -3442,6 +3505,9 @@
|
||||
"PipelinesV2"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -3490,6 +3556,9 @@
|
||||
"PipelinesV2"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -3528,6 +3597,9 @@
|
||||
"PipelinesV2"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -3586,6 +3658,9 @@
|
||||
"PipelinesV2"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -3634,6 +3709,9 @@
|
||||
"PipelinesV2"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -3674,6 +3752,9 @@
|
||||
"PipelinesV2"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -3716,6 +3797,9 @@
|
||||
"PipelinesV2"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -3765,6 +3849,9 @@
|
||||
"PipelinesV2"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -3814,6 +3901,9 @@
|
||||
"PipelinesV2"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -3861,6 +3951,9 @@
|
||||
"PipelinesV2"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -4031,6 +4124,9 @@
|
||||
"Platform API"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -4056,6 +4152,9 @@
|
||||
"Platform API"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -4092,6 +4191,9 @@
|
||||
"Platform API"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -4126,6 +4228,9 @@
|
||||
"Platform API"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -4160,6 +4265,9 @@
|
||||
"Platform API"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -4187,6 +4295,9 @@
|
||||
"Platform API"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -4214,6 +4325,9 @@
|
||||
"Platform API"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -4241,6 +4355,9 @@
|
||||
"Platform API"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -4277,6 +4394,9 @@
|
||||
"Platform API"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -4313,6 +4433,9 @@
|
||||
"Platform API"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -4340,6 +4463,9 @@
|
||||
"Platform API"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -4367,6 +4493,9 @@
|
||||
"Platform API"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -4404,6 +4533,9 @@
|
||||
"Platform API"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -4440,6 +4572,9 @@
|
||||
"Platform API"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -4484,6 +4619,9 @@
|
||||
"Platform API"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -4520,6 +4658,9 @@
|
||||
"Platform API"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -4564,6 +4705,9 @@
|
||||
"Platform API"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -4656,6 +4800,9 @@
|
||||
"Platform API"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -4690,6 +4837,9 @@
|
||||
"Platform API"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -4726,6 +4876,9 @@
|
||||
"Platform API"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -4762,6 +4915,9 @@
|
||||
"Platform API"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -4799,6 +4955,9 @@
|
||||
"Platform API"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -4826,6 +4985,9 @@
|
||||
"Platform API"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -4853,6 +5015,9 @@
|
||||
"Platform API"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -5264,6 +5429,9 @@
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -5307,6 +5475,9 @@
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -5416,6 +5587,9 @@
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -5448,6 +5622,9 @@
|
||||
"Catalog"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -5490,6 +5667,9 @@
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -5625,6 +5805,9 @@
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -5683,6 +5866,9 @@
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -5731,6 +5917,9 @@
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -5824,6 +6013,9 @@
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -5874,6 +6066,9 @@
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -5932,6 +6127,9 @@
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -5988,6 +6186,9 @@
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -6048,6 +6249,9 @@
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -6088,6 +6292,9 @@
|
||||
"Catalog"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -6128,6 +6335,9 @@
|
||||
"Catalog"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -6188,6 +6398,9 @@
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -6246,6 +6459,9 @@
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -6622,6 +6838,9 @@
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -7075,6 +7294,9 @@
|
||||
"Connection Test"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -7111,6 +7333,9 @@
|
||||
"Connection Test"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -7147,6 +7372,9 @@
|
||||
"Connection Test"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -7183,6 +7411,9 @@
|
||||
"Connection Test"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
@@ -7219,6 +7450,9 @@
|
||||
"Connection Test"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ const config: Config.InitialOptions = {
|
||||
'<rootDir>/node_modules/',
|
||||
'.*\\.module\\.[jt]s$',
|
||||
],
|
||||
setupFiles: ['<rootDir>/jest.setup.ts'],
|
||||
// moduleDirectories: ['node_modules'], // default is already 'node_modules'
|
||||
// rootDir: '.', //No need
|
||||
// testEnvironment: 'node', //Defaults to 'node'
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
process.env.DUC_URL="duc:50051"
|
||||
process.env.INFACTORY_URL="in-factory:50052"
|
||||
process.env.PIFACTORY_URL="pi-factory:50053"
|
||||
Generated
+5
-4
@@ -16,7 +16,7 @@
|
||||
"@aws-sdk/lib-dynamodb": "^3.414.0",
|
||||
"@aws-sdk/signature-v4": "^3.370.0",
|
||||
"@dadosfera/dadosfera-logs": "^1.0.0-beta.4",
|
||||
"@dadosfera/protospack-v2": "^3.40.0-beta.14",
|
||||
"@dadosfera/protospack-v2": "3.40.0",
|
||||
"@grpc/grpc-js": "^1.9.3",
|
||||
"@grpc/proto-loader": "^0.7.9",
|
||||
"@nestjs/cli": "^9.5.0",
|
||||
@@ -1735,9 +1735,10 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@dadosfera/protospack-v2": {
|
||||
"version": "3.40.0-beta.14",
|
||||
"resolved": "https://dadosfera-611330257153.d.codeartifact.us-east-1.amazonaws.com/npm/dadosfera-npm/@dadosfera/protospack-v2/-/protospack-v2-3.40.0-beta.14.tgz",
|
||||
"integrity": "sha512-pv3pxq0x1XcBgf3ajD6QOFRLOduh8iEozKFA3AKlIW4gid+gT4iL0GcU2M+O7h0QFeO4JIzRZe/nEMN82nqk7A==",
|
||||
"version": "3.40.0",
|
||||
"resolved": "https://dadosfera-611330257153.d.codeartifact.us-east-1.amazonaws.com/npm/dadosfera-npm/@dadosfera/protospack-v2/-/protospack-v2-3.40.0.tgz",
|
||||
"integrity": "sha512-tzYAGosFjGUgi3pAvXqv+Eqqjca9tH1kU9kJdRI5d1rLXNimo0fIuPWxWng0C4OBH/2sIgC1WLHseq+DZ6qgdw==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@grpc/grpc-js": "^1.9.3",
|
||||
"rxjs": "^7.5.5"
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@
|
||||
"@aws-sdk/lib-dynamodb": "^3.414.0",
|
||||
"@aws-sdk/signature-v4": "^3.370.0",
|
||||
"@dadosfera/dadosfera-logs": "^1.0.0-beta.4",
|
||||
"@dadosfera/protospack-v2": "^3.40.0-beta.14",
|
||||
"@dadosfera/protospack-v2": "3.40.0",
|
||||
"@grpc/grpc-js": "^1.9.3",
|
||||
"@grpc/proto-loader": "^0.7.9",
|
||||
"@nestjs/cli": "^9.5.0",
|
||||
|
||||
@@ -722,6 +722,8 @@ export const DADOSFERA_MODULES_KEYS = {
|
||||
PII: 'pii',
|
||||
EMBED: 'embedded-analytics',
|
||||
EMBED_ASSIGNED: 'embed-assigned',
|
||||
CATALOG: 'catalog',
|
||||
COLLECT: 'collect',
|
||||
}
|
||||
|
||||
export const DADOSFERA_MODULES: Array<DadosferaModule> = [
|
||||
|
||||
@@ -35,4 +35,45 @@ So in order to have an SSO login, besides configuring the Strategy, we must have
|
||||
// ... Rest of the logic
|
||||
return { url: url.href };
|
||||
}
|
||||
```
|
||||
```
|
||||
|
||||
## Browser session cookies
|
||||
|
||||
Besides the tokens returned in the sign-in body (kept by the frontend in
|
||||
`localStorage` and sent as `Authorization`), Maestro also persists the session
|
||||
as httpOnly cookies so that apps which cannot hold a token themselves —
|
||||
Orchest / Intelligence / Process behind an nginx `auth_request` pointing at
|
||||
`GET /auth/me` — can authenticate the browser.
|
||||
|
||||
| Cookie | Content |
|
||||
| --- | --- |
|
||||
| `ddf-auth<suffix>` | DUC access token |
|
||||
| `ddf-refresh-auth<suffix>` | IdP refresh token |
|
||||
| `ddf-user-id<suffix>` | DUC user id |
|
||||
|
||||
All three are `HttpOnly; Secure; SameSite=None; Path=/` and live for
|
||||
`SESSION_COOKIE_MAX_AGE_DAYS` (default 30 — keep it aligned with the IdP
|
||||
refresh-token validity). See `session-cookies.ts`.
|
||||
|
||||
They are **environment-scoped** so that a login on `app.stg.dadosfera.ai`
|
||||
never overwrites a production session in the same browser:
|
||||
|
||||
| Env | `AUTH_COOKIE_SUFFIX` | `COOKIE_DOMAIN` |
|
||||
| --- | --- | --- |
|
||||
| prd | `""` | `.dadosfera.ai` |
|
||||
| stg | `-stg` | `.stg.dadosfera.ai` |
|
||||
|
||||
`GET /auth/me` behaviour:
|
||||
|
||||
- valid access token → `200` + user (permissions are the raw seqids from the JWT);
|
||||
- expired/invalid access token but refresh token present → refresh, rewrite the
|
||||
cookies (`Set-Cookie`, access token first — nginx `auth_request` only relays
|
||||
the first one) and `200`;
|
||||
- refresh impossible (expired/revoked/foreign token, unknown user) → `401` and the
|
||||
cookies are expired so the browser stops presenting a dead session;
|
||||
- DUC unreachable / slower than `AUTH_RPC_TIMEOUT_MS` (default 10s) → `503`,
|
||||
cookies untouched (transient, retry);
|
||||
- resource belongs to another customer → `403`; new terms of use pending → `403`.
|
||||
|
||||
`POST /auth/refresh-access-token` re-writes all three cookies from the session
|
||||
the frontend is actually using, and `POST /auth/sign-out` expires them.
|
||||
|
||||
@@ -14,6 +14,8 @@ import {
|
||||
Param,
|
||||
Res,
|
||||
UnauthorizedException,
|
||||
HttpException,
|
||||
ServiceUnavailableException,
|
||||
} from '@nestjs/common';
|
||||
import {
|
||||
ApiHeaders,
|
||||
@@ -37,6 +39,7 @@ import {
|
||||
RequireAllPermissions,
|
||||
} from 'src/decorators/authentication.decorator';
|
||||
import { AuthClientService } from './auth.service';
|
||||
import { UserDTO } from './dtos/login';
|
||||
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
|
||||
import { GrpcToHttpExceptionFilter } from '../../error/grpc-to-http-exception.filter';
|
||||
import { RequestUser, User } from 'src/decorators/user.decorator';
|
||||
@@ -50,7 +53,10 @@ import {
|
||||
import { PackTheMetadata } from 'src/utils/PackTheMetadata';
|
||||
import { AuthGuard } from '@nestjs/passport';
|
||||
import { Request, Response } from 'express';
|
||||
import { status as GrpcStatus } from '@grpc/grpc-js';
|
||||
import ErrorCodes, { OauthErrors } from 'src/utils/errorCodes';
|
||||
import ErrorBuilder from 'src/utils/ErrorBuilder';
|
||||
import { clearSessionCookies, readAuthSession } from './session-cookies';
|
||||
import jwt, { JwtPayload } from 'jsonwebtoken';
|
||||
import { LanguageEnum } from 'src/utils/languages.enum';
|
||||
import { Language } from 'src/decorators/language.decorator';
|
||||
@@ -128,14 +134,16 @@ export class AuthController {
|
||||
) {
|
||||
try {
|
||||
this.logger.info('/auth - SignOut');
|
||||
|
||||
this.authClient.cleanUpAuthSession(res);
|
||||
|
||||
return res.send();
|
||||
this.authClient.cleanUpAuthSession(res);
|
||||
} catch (error) {
|
||||
this.logger.error('/auth - SignIn - ERROR', error);
|
||||
this.logger.error('/auth - SignOut - ERROR', error);
|
||||
}
|
||||
|
||||
// Always answer: a sign-out that hangs leaves the frontend logout
|
||||
// waiting on a request that never completes.
|
||||
return res.send();
|
||||
|
||||
}
|
||||
|
||||
@Post('refresh-access-token')
|
||||
@@ -148,7 +156,7 @@ export class AuthController {
|
||||
@Res() res: Response,
|
||||
) {
|
||||
this.logger.info('/auth - RefreshAccessToken');
|
||||
const frontHost = origin.replace(/^https?:\/\//, '');
|
||||
const frontHost = (origin || '').replace(/^https?:\/\//, '');
|
||||
const { refreshToken, userId } = body;
|
||||
|
||||
const metadata = PackTheMetadata({
|
||||
@@ -158,10 +166,14 @@ export class AuthController {
|
||||
|
||||
const data = await this.authClient.refreshAccessToken({ refreshToken, userId }, metadata);
|
||||
|
||||
// Re-sync ALL session cookies with the session the frontend is actually
|
||||
// using. The IdP does not rotate refresh tokens (DUC returns an empty
|
||||
// refreshToken), so fall back to the one that just proved valid — this
|
||||
// heals cookies left behind by an older login or by another environment.
|
||||
this.authClient.writeAuthSession(res, {
|
||||
accessToken: data.accessToken,
|
||||
refreshToken: data.refreshToken,
|
||||
userId
|
||||
refreshToken: data.refreshToken || refreshToken,
|
||||
userId,
|
||||
});
|
||||
|
||||
return res.send(data);
|
||||
@@ -477,16 +489,28 @@ export class AuthController {
|
||||
|
||||
@Get('me')
|
||||
async getMe(@Req() req: Request, @Res() res: Response) {
|
||||
this.logger.info('GET /auth/me ')
|
||||
this.logger.info(JSON.stringify(req.headers));
|
||||
const resourceHost = (req.headers['x-original-url'] as string) || '';
|
||||
// Never dump req.headers here: it contains the session cookies.
|
||||
this.logger.info('GET /auth/me', { resourceHost });
|
||||
|
||||
// Check for API key header first
|
||||
const apiKey = req.get('X-Api-key');
|
||||
if (apiKey) {
|
||||
this.logger.info('Authenticating via X-Api-key header');
|
||||
const { api_key } = await this.apiKeyService.get(apiKey);
|
||||
let api_key: Awaited<ReturnType<ApiKeyService['get']>>['api_key'];
|
||||
try {
|
||||
({ api_key } = await this.apiKeyService.get(apiKey));
|
||||
} catch (error) {
|
||||
if (this.isTransportError(error)) {
|
||||
throw this.identityProviderUnavailable(error);
|
||||
}
|
||||
this.logger.error('/auth/me - invalid API key', {
|
||||
error: error?.message,
|
||||
});
|
||||
throw new UnauthorizedException('Invalid API key');
|
||||
}
|
||||
|
||||
const userDto = {
|
||||
const userDto: UserDTO = {
|
||||
id: api_key.user_id,
|
||||
name: api_key.username,
|
||||
email: api_key.username,
|
||||
@@ -494,41 +518,105 @@ export class AuthController {
|
||||
id: api_key.customer_id,
|
||||
name: api_key.customer_name,
|
||||
tier: api_key.customer_tier,
|
||||
}
|
||||
},
|
||||
permissions: [],
|
||||
};
|
||||
|
||||
return res.status(200).json(userDto);
|
||||
}
|
||||
|
||||
// Get token and headers
|
||||
const accessToken = req.cookies['ddf-auth'];
|
||||
const refreshToken = req.cookies['ddf-refresh-auth'];
|
||||
const userId = req.cookies['ddf-user-id'];
|
||||
const resourceHost = req.headers["x-original-url"] as string || "" ;
|
||||
const { accessToken, refreshToken, userId } = readAuthSession(req);
|
||||
const canRefresh = Boolean(refreshToken) && Boolean(userId);
|
||||
this.logger.info('Has User Session: ' + Boolean(accessToken || canRefresh));
|
||||
|
||||
const hasUserSession = Boolean(accessToken) && Boolean(userId);
|
||||
this.logger.info('Has User Session: ' + hasUserSession);
|
||||
if (!accessToken && !canRefresh) {
|
||||
throw new UnauthorizedException();
|
||||
}
|
||||
|
||||
if (!hasUserSession) {
|
||||
throw new UnauthorizedException()
|
||||
if (accessToken) {
|
||||
try {
|
||||
const userDto = await this.authClient.validateUserSession(
|
||||
accessToken,
|
||||
resourceHost,
|
||||
);
|
||||
return res.status(200).json(userDto);
|
||||
} catch (error) {
|
||||
// Definitive answers (e.g. 403: resource belongs to another
|
||||
// customer) must not be masked by a refresh attempt.
|
||||
if (error instanceof HttpException) throw error;
|
||||
if (this.isTransportError(error)) {
|
||||
throw this.identityProviderUnavailable(error);
|
||||
}
|
||||
if (!canRefresh) {
|
||||
this.logger.error(
|
||||
'/auth/me - access token rejected and no refresh token',
|
||||
{ error: error?.message },
|
||||
);
|
||||
clearSessionCookies(res);
|
||||
throw new ErrorBuilder(ErrorCodes.AUTH.INVALID_REFRESH_TOKEN);
|
||||
}
|
||||
this.logger.info('/auth/me - access token rejected, refreshing', {
|
||||
error: error?.message,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const userDto = await this.authClient.validateUserSession(accessToken, resourceHost);
|
||||
return res.status(200).json(userDto);
|
||||
} catch (error) {
|
||||
|
||||
if (!refreshToken) {
|
||||
this.logger.error('Invalid refresh token or customer name');
|
||||
throw new UnauthorizedException("Invalid refresh token or customer name");
|
||||
};
|
||||
|
||||
const {
|
||||
authSession,
|
||||
user
|
||||
} = await this.authClient.refreshUserSession(refreshToken, userId, resourceHost);
|
||||
this.authClient.writeAuthSession(res, authSession);
|
||||
const { authSession, user } = await this.authClient.refreshUserSession(
|
||||
refreshToken,
|
||||
userId,
|
||||
resourceHost,
|
||||
);
|
||||
// Refresh tokens are not rotated by the IdP (DUC returns ''), so keep
|
||||
// the one that just worked; this also slides the cookie lifetime.
|
||||
this.authClient.writeAuthSession(res, {
|
||||
...authSession,
|
||||
refreshToken: authSession.refreshToken || refreshToken,
|
||||
});
|
||||
return res.status(200).json(user);
|
||||
} catch (error) {
|
||||
if (error instanceof HttpException) throw error;
|
||||
if (this.isTransportError(error)) {
|
||||
throw this.identityProviderUnavailable(error);
|
||||
}
|
||||
|
||||
const code =
|
||||
typeof error?.details === 'string' ? error.details : undefined;
|
||||
if (code === ErrorCodes.TERMS_OF_USE.REQUIRED) {
|
||||
// The session is fine; the user has to accept the new terms first.
|
||||
throw new ErrorBuilder(code);
|
||||
}
|
||||
|
||||
// Expired, revoked, or minted by another environment / user pool.
|
||||
// Answer 401 (never 500) and drop the dead cookies so the browser
|
||||
// does not keep presenting them on every request.
|
||||
this.logger.error('/auth/me - session refresh failed', {
|
||||
code,
|
||||
error: error?.message,
|
||||
});
|
||||
clearSessionCookies(res);
|
||||
throw new ErrorBuilder(ErrorCodes.AUTH.INVALID_REFRESH_TOKEN);
|
||||
}
|
||||
}
|
||||
|
||||
/** DUC unreachable or too slow — a transient failure, not an auth answer. */
|
||||
private isTransportError(error: any): boolean {
|
||||
return (
|
||||
error?.name === 'TimeoutError' ||
|
||||
error?.code === GrpcStatus.UNAVAILABLE ||
|
||||
error?.code === GrpcStatus.DEADLINE_EXCEEDED
|
||||
);
|
||||
}
|
||||
|
||||
private identityProviderUnavailable(error: any): HttpException {
|
||||
this.logger.error('/auth/me - identity provider unavailable', {
|
||||
code: error?.code,
|
||||
error: error?.message,
|
||||
});
|
||||
// 503 (not 500): callers such as nginx auth_request / Orchest's
|
||||
// auth-server treat it as "retry later" instead of a broken session.
|
||||
return new ServiceUnavailableException(
|
||||
'Identity provider temporarily unavailable',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
} from '@nestjs/common';
|
||||
import { ClientGrpc } from '@nestjs/microservices';
|
||||
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
|
||||
import { lastValueFrom } from 'rxjs';
|
||||
import { lastValueFrom, timeout } from 'rxjs';
|
||||
|
||||
import { ProtoServices } from '@dadosfera/protospack-v2/dist/lib/Duc';
|
||||
import {
|
||||
@@ -35,12 +35,24 @@ import { BulkEditResponse, UserDTO } from './dtos/login';
|
||||
import jwt, { JwtPayload } from 'jsonwebtoken';
|
||||
import { PackTheMetadata } from 'src/utils/PackTheMetadata';
|
||||
import { Request, Response } from 'express';
|
||||
import {
|
||||
AuthSession,
|
||||
clearSessionCookies,
|
||||
writeSessionCookies,
|
||||
} from './session-cookies';
|
||||
|
||||
type AuthSession = {
|
||||
accessToken?: string;
|
||||
refreshToken?: string;
|
||||
userId?: string;
|
||||
};
|
||||
export type { AuthSession };
|
||||
|
||||
/**
|
||||
* Upper bound for the DUC round-trips on the session-validation path
|
||||
* (`GET /auth/me`). Without it a hung DUC keeps every `auth_request`
|
||||
* subrequest open until the ingress gives up (minutes), which surfaces to
|
||||
* users as 500/504 pages instead of a fast, retryable 503.
|
||||
*/
|
||||
function authRpcTimeoutMs(): number {
|
||||
const ms = Number(process.env.AUTH_RPC_TIMEOUT_MS);
|
||||
return Number.isFinite(ms) && ms > 0 ? ms : 10_000;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class AuthClientService implements OnModuleInit {
|
||||
@@ -70,7 +82,9 @@ export class AuthClientService implements OnModuleInit {
|
||||
async getPublicKeys() {
|
||||
this.logger.info('GetPublicKeys');
|
||||
|
||||
return lastValueFrom(this.authService.AuthGetPublicKeys({}));
|
||||
return lastValueFrom(
|
||||
this.authService.AuthGetPublicKeys({}).pipe(timeout(authRpcTimeoutMs())),
|
||||
);
|
||||
}
|
||||
|
||||
async snowflakeSignIn(input: AuthSnowflakeSignInRequest) {
|
||||
@@ -132,10 +146,9 @@ export class AuthClientService implements OnModuleInit {
|
||||
this.logger.info('RefreshAccessToken');
|
||||
|
||||
return lastValueFrom(
|
||||
this.authService.AuthRefreshAccessToken(
|
||||
{ refreshToken, userId },
|
||||
metadata,
|
||||
),
|
||||
this.authService
|
||||
.AuthRefreshAccessToken({ refreshToken, userId }, metadata)
|
||||
.pipe(timeout(authRpcTimeoutMs())),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -346,67 +359,18 @@ export class AuthClientService implements OnModuleInit {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Persists the session in the browser as httpOnly cookies. Names, domain
|
||||
* and lifetime are environment-scoped — see `session-cookies.ts`.
|
||||
*/
|
||||
public writeAuthSession(res: Response, data: AuthSession) {
|
||||
let exp = 1000 * 60 * 5; // 5 minutes
|
||||
|
||||
if (data.accessToken) {
|
||||
const { exp: expiration } = jwt.decode(data.accessToken) as JwtPayload;
|
||||
exp = (expiration - 30) * 1000; // exp em segundos, maxAge em ms
|
||||
|
||||
this.logger.info('Set Cookie ddf-auth');
|
||||
res.cookie('ddf-auth', data.accessToken, {
|
||||
domain: '.dadosfera.ai',
|
||||
maxAge: exp,
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
sameSite: 'none', // Necessário para cookies em requisições cross-site
|
||||
});
|
||||
}
|
||||
|
||||
if (data.refreshToken) {
|
||||
this.logger.info('Set Cookie ddf-refresh-auth');
|
||||
res.cookie('ddf-refresh-auth', data.refreshToken, {
|
||||
domain: '.dadosfera.ai',
|
||||
maxAge: exp,
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
sameSite: 'none', // Necessário para cookies em requisições cross-site
|
||||
});
|
||||
}
|
||||
|
||||
if (data.userId) {
|
||||
this.logger.info('Set Cookie ddf-refresh-auth');
|
||||
res.cookie('ddf-user-id', data.userId, {
|
||||
domain: '.dadosfera.ai',
|
||||
maxAge: exp,
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
sameSite: 'none', // Necessário para cookies em requisições cross-site
|
||||
});
|
||||
}
|
||||
this.logger.info('Set session cookies');
|
||||
writeSessionCookies(res, data);
|
||||
}
|
||||
|
||||
/** Expires every session cookie this environment writes. */
|
||||
public cleanUpAuthSession(res: Response) {
|
||||
const exp = 1000 * 60 * 3;
|
||||
|
||||
res.cookie('ddf-auth', '', {
|
||||
domain: 'dadosfera.ai',
|
||||
maxAge: Date.now() - exp,
|
||||
expires: new Date(),
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
sameSite: 'none', // Necessário para cookies em requisições cross-site
|
||||
});
|
||||
|
||||
res.cookie('ddf-refresh-auth', '', {
|
||||
domain: 'dadosfera.ai',
|
||||
maxAge: Date.now() - exp,
|
||||
expires: new Date(),
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
sameSite: 'none', // Necessário para cookies em requisições cross-site
|
||||
});
|
||||
|
||||
clearSessionCookies(res);
|
||||
this.logger.info('Clean cookie sessions');
|
||||
}
|
||||
|
||||
@@ -432,9 +396,16 @@ export class AuthClientService implements OnModuleInit {
|
||||
});
|
||||
|
||||
const { user } = await lastValueFrom(
|
||||
this.userService.UserFindOneById({ id: payload.user_id }, metadata),
|
||||
this.userService
|
||||
.UserFindOneById({ id: payload.user_id }, metadata)
|
||||
.pipe(timeout(authRpcTimeoutMs())),
|
||||
);
|
||||
|
||||
if (!user) {
|
||||
// Deleted/unknown user: a definitive "no session", not a crash.
|
||||
throw new HttpException('User not found', HttpStatus.UNAUTHORIZED);
|
||||
}
|
||||
|
||||
const userDto: UserDTO = {
|
||||
id: user.id,
|
||||
name: user.name,
|
||||
@@ -447,6 +418,9 @@ export class AuthClientService implements OnModuleInit {
|
||||
name: payload.customer_name,
|
||||
tier: payload.customer_tier,
|
||||
},
|
||||
// Raw permission seqids from the JWT. Consumers own the seqid->meaning
|
||||
// mapping (e.g. Orchest's auth-server); Maestro reports them as-is.
|
||||
permissions: payload.permissions ?? [],
|
||||
};
|
||||
|
||||
return userDto;
|
||||
|
||||
@@ -152,5 +152,6 @@ export type UserDTO = {
|
||||
id: string,
|
||||
name: string,
|
||||
tier: string,
|
||||
}
|
||||
},
|
||||
permissions: number[],
|
||||
}
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
import {
|
||||
clearSessionCookies,
|
||||
readAuthSession,
|
||||
sessionCookieMaxAgeMs,
|
||||
sessionCookieNames,
|
||||
sessionCookieOptions,
|
||||
writeSessionCookies,
|
||||
} from './session-cookies';
|
||||
|
||||
const DAY_MS = 24 * 60 * 60 * 1000;
|
||||
|
||||
function fakeResponse() {
|
||||
const cookie = jest.fn();
|
||||
const clearCookie = jest.fn();
|
||||
return { cookie, clearCookie };
|
||||
}
|
||||
|
||||
describe('session cookies', () => {
|
||||
it('uses the legacy names and domain when nothing is configured (production)', () => {
|
||||
const env = {};
|
||||
expect(sessionCookieNames(env)).toEqual({
|
||||
accessToken: 'ddf-auth',
|
||||
refreshToken: 'ddf-refresh-auth',
|
||||
userId: 'ddf-user-id',
|
||||
});
|
||||
expect(sessionCookieOptions(env)).toMatchObject({
|
||||
domain: '.dadosfera.ai',
|
||||
path: '/',
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
sameSite: 'none',
|
||||
});
|
||||
});
|
||||
|
||||
it('scopes names and domain per environment so staging never clobbers production', () => {
|
||||
const env = { AUTH_COOKIE_SUFFIX: '-stg', COOKIE_DOMAIN: '.stg.dadosfera.ai' };
|
||||
expect(sessionCookieNames(env)).toEqual({
|
||||
accessToken: 'ddf-auth-stg',
|
||||
refreshToken: 'ddf-refresh-auth-stg',
|
||||
userId: 'ddf-user-id-stg',
|
||||
});
|
||||
expect(sessionCookieOptions(env).domain).toBe('.stg.dadosfera.ai');
|
||||
});
|
||||
|
||||
it('treats maxAge as a duration (30 days by default), not as the token epoch', () => {
|
||||
expect(sessionCookieMaxAgeMs({})).toBe(30 * DAY_MS);
|
||||
expect(sessionCookieMaxAgeMs({ SESSION_COOKIE_MAX_AGE_DAYS: '7' })).toBe(7 * DAY_MS);
|
||||
expect(sessionCookieMaxAgeMs({ SESSION_COOKIE_MAX_AGE_DAYS: 'nope' })).toBe(30 * DAY_MS);
|
||||
expect(sessionCookieMaxAgeMs({ SESSION_COOKIE_MAX_AGE_DAYS: '-1' })).toBe(30 * DAY_MS);
|
||||
});
|
||||
|
||||
it('reads the session using the environment-specific names', () => {
|
||||
const env = { AUTH_COOKIE_SUFFIX: '-stg' };
|
||||
const req = {
|
||||
cookies: {
|
||||
'ddf-auth': 'prod-token',
|
||||
'ddf-auth-stg': 'stg-token',
|
||||
'ddf-refresh-auth-stg': 'stg-refresh',
|
||||
'ddf-user-id-stg': 'u-stg',
|
||||
},
|
||||
};
|
||||
expect(readAuthSession(req as any, env)).toEqual({
|
||||
accessToken: 'stg-token',
|
||||
refreshToken: 'stg-refresh',
|
||||
userId: 'u-stg',
|
||||
});
|
||||
expect(readAuthSession({ cookies: undefined } as any, env)).toEqual({
|
||||
accessToken: undefined,
|
||||
refreshToken: undefined,
|
||||
userId: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
it('writes the access-token cookie first and only the parts that are present', () => {
|
||||
const res = fakeResponse();
|
||||
writeSessionCookies(res as any, { accessToken: 'a', userId: 'u' }, {});
|
||||
|
||||
expect(res.cookie.mock.calls.map((c) => c[0])).toEqual(['ddf-auth', 'ddf-user-id']);
|
||||
expect(res.cookie.mock.calls[0][2]).toMatchObject({
|
||||
domain: '.dadosfera.ai',
|
||||
path: '/',
|
||||
maxAge: 30 * DAY_MS,
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
sameSite: 'none',
|
||||
});
|
||||
});
|
||||
|
||||
it('clears all three cookies with the same domain and path they were set with', () => {
|
||||
const res = fakeResponse();
|
||||
const env = { AUTH_COOKIE_SUFFIX: '-stg', COOKIE_DOMAIN: '.stg.dadosfera.ai' };
|
||||
clearSessionCookies(res as any, env);
|
||||
|
||||
expect(res.clearCookie.mock.calls.map((c) => c[0])).toEqual([
|
||||
'ddf-auth-stg',
|
||||
'ddf-refresh-auth-stg',
|
||||
'ddf-user-id-stg',
|
||||
]);
|
||||
for (const call of res.clearCookie.mock.calls) {
|
||||
expect(call[1]).toMatchObject({ domain: '.stg.dadosfera.ai', path: '/' });
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,131 @@
|
||||
import { CookieOptions, Request, Response } from 'express';
|
||||
|
||||
/**
|
||||
* Browser session cookies written by Maestro and consumed by every app that
|
||||
* authenticates through `GET /auth/me` (Orchest auth-server, nginx
|
||||
* `auth_request` ingresses, ...).
|
||||
*
|
||||
* The names and the domain are environment-scoped so that a staging login
|
||||
* never overwrites (or is confused with) a production session in the same
|
||||
* browser: both platforms live under `dadosfera.ai`, so a cookie on the
|
||||
* registrable domain is sent to *both* environments.
|
||||
*
|
||||
* ENV | AUTH_COOKIE_SUFFIX | COOKIE_DOMAIN
|
||||
* prd | "" | .dadosfera.ai -> ddf-auth
|
||||
* stg | "-stg" | .stg.dadosfera.ai -> ddf-auth-stg
|
||||
*/
|
||||
export type AuthSession = {
|
||||
accessToken?: string;
|
||||
refreshToken?: string;
|
||||
userId?: string;
|
||||
};
|
||||
|
||||
export type SessionCookieNames = {
|
||||
accessToken: string;
|
||||
refreshToken: string;
|
||||
userId: string;
|
||||
};
|
||||
|
||||
type Env = Record<string, string | undefined>;
|
||||
|
||||
const DEFAULT_COOKIE_DOMAIN = '.dadosfera.ai';
|
||||
const DEFAULT_SESSION_COOKIE_MAX_AGE_DAYS = 30;
|
||||
|
||||
export function cookieDomain(env: Env = process.env): string {
|
||||
return env.COOKIE_DOMAIN || DEFAULT_COOKIE_DOMAIN;
|
||||
}
|
||||
|
||||
export function cookieSuffix(env: Env = process.env): string {
|
||||
return env.AUTH_COOKIE_SUFFIX || '';
|
||||
}
|
||||
|
||||
export function sessionCookieNames(env: Env = process.env): SessionCookieNames {
|
||||
const suffix = cookieSuffix(env);
|
||||
return {
|
||||
accessToken: `ddf-auth${suffix}`,
|
||||
refreshToken: `ddf-refresh-auth${suffix}`,
|
||||
userId: `ddf-user-id${suffix}`,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* How long the browser keeps the session cookies. This is a *duration*
|
||||
* (express `maxAge` is in milliseconds from now), independent from the
|
||||
* access token's own `exp`: an expired access token in the cookie is
|
||||
* harmless — `/auth/me` transparently refreshes it — while a refresh token
|
||||
* that outlives the cookie would make the browser forget a still-valid
|
||||
* session. Keep it aligned with the IdP refresh-token validity.
|
||||
*/
|
||||
export function sessionCookieMaxAgeMs(env: Env = process.env): number {
|
||||
const days = Number(env.SESSION_COOKIE_MAX_AGE_DAYS);
|
||||
const safeDays =
|
||||
Number.isFinite(days) && days > 0
|
||||
? days
|
||||
: DEFAULT_SESSION_COOKIE_MAX_AGE_DAYS;
|
||||
return safeDays * 24 * 60 * 60 * 1000;
|
||||
}
|
||||
|
||||
export function sessionCookieOptions(env: Env = process.env): CookieOptions {
|
||||
return {
|
||||
domain: cookieDomain(env),
|
||||
path: '/',
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
// Required: the cookies are sent cross-site (app.* -> maestro.*) and
|
||||
// from embedded iframes (app.* embedding app-intelligence-*.*).
|
||||
sameSite: 'none',
|
||||
};
|
||||
}
|
||||
|
||||
export function readAuthSession(
|
||||
req: Pick<Request, 'cookies'>,
|
||||
env: Env = process.env,
|
||||
): AuthSession {
|
||||
const names = sessionCookieNames(env);
|
||||
const cookies = req.cookies ?? {};
|
||||
return {
|
||||
accessToken: cookies[names.accessToken] || undefined,
|
||||
refreshToken: cookies[names.refreshToken] || undefined,
|
||||
userId: cookies[names.userId] || undefined,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* (Re)writes whichever parts of the session are present. The access-token
|
||||
* cookie is written first on purpose: nginx `auth_request` relays only the
|
||||
* first `Set-Cookie` of the auth subrequest (`$upstream_http_set_cookie`),
|
||||
* and the access token is the one that changes on refresh.
|
||||
*/
|
||||
export function writeSessionCookies(
|
||||
res: Pick<Response, 'cookie'>,
|
||||
session: AuthSession,
|
||||
env: Env = process.env,
|
||||
): void {
|
||||
const names = sessionCookieNames(env);
|
||||
const options: CookieOptions = {
|
||||
...sessionCookieOptions(env),
|
||||
maxAge: sessionCookieMaxAgeMs(env),
|
||||
};
|
||||
|
||||
if (session.accessToken) {
|
||||
res.cookie(names.accessToken, session.accessToken, options);
|
||||
}
|
||||
if (session.refreshToken) {
|
||||
res.cookie(names.refreshToken, session.refreshToken, options);
|
||||
}
|
||||
if (session.userId) {
|
||||
res.cookie(names.userId, session.userId, options);
|
||||
}
|
||||
}
|
||||
|
||||
/** Expires all three session cookies (same name/domain/path they were set with). */
|
||||
export function clearSessionCookies(
|
||||
res: Pick<Response, 'clearCookie'>,
|
||||
env: Env = process.env,
|
||||
): void {
|
||||
const names = sessionCookieNames(env);
|
||||
const options = sessionCookieOptions(env);
|
||||
res.clearCookie(names.accessToken, options);
|
||||
res.clearCookie(names.refreshToken, options);
|
||||
res.clearCookie(names.userId, options);
|
||||
}
|
||||
@@ -85,6 +85,9 @@ export class CatalogController {
|
||||
PERMISSIONS_GROUPS.CATALOG.permissions.GET,
|
||||
PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER,
|
||||
)
|
||||
@RequireModule(
|
||||
DADOSFERA_MODULES_KEYS.CATALOG
|
||||
)
|
||||
async searchCatalog(
|
||||
@User() user: RequestUser,
|
||||
@Query() query: ICatalogAllRequest,
|
||||
@@ -124,6 +127,9 @@ export class CatalogController {
|
||||
PERMISSIONS_GROUPS.CATALOG.permissions.GET,
|
||||
PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER,
|
||||
)
|
||||
@RequireModule(
|
||||
DADOSFERA_MODULES_KEYS.CATALOG
|
||||
)
|
||||
async dowloadAsserts(
|
||||
@User() user: RequestUser,
|
||||
@Query() query: ICatalogAllRequest,
|
||||
@@ -167,6 +173,9 @@ export class CatalogController {
|
||||
|
||||
@ApiInternalOnlyEndpoint()
|
||||
@Get('data-asset')
|
||||
@RequireModule(
|
||||
DADOSFERA_MODULES_KEYS.CATALOG
|
||||
)
|
||||
async findByPipelineAndObject(@User() user: RequestUser, @Query() query) {
|
||||
const { username, user_id, customer_id, customer_name, permissions } = user;
|
||||
const { pipeline, object } = query;
|
||||
@@ -225,6 +234,9 @@ export class CatalogController {
|
||||
PERMISSIONS_GROUPS.CATALOG.permissions.GET,
|
||||
PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER,
|
||||
)
|
||||
@RequireModule(
|
||||
DADOSFERA_MODULES_KEYS.CATALOG
|
||||
)
|
||||
async findAllTags(@Body() body) {
|
||||
this.logger.info(`/catalog - ON FIND ALL TAGS ROUTE`, {
|
||||
user: body.info.user_id,
|
||||
@@ -293,6 +305,9 @@ export class CatalogController {
|
||||
PERMISSIONS_GROUPS.CATALOG.permissions.GET,
|
||||
PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER,
|
||||
)
|
||||
@RequireModule(
|
||||
DADOSFERA_MODULES_KEYS.CATALOG
|
||||
)
|
||||
async getDataAsset(
|
||||
@User() user: RequestUser,
|
||||
@Param('id') id: string,
|
||||
@@ -404,6 +419,9 @@ export class CatalogController {
|
||||
PERMISSIONS_GROUPS.CATALOG.permissions.GET,
|
||||
PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER,
|
||||
)
|
||||
@RequireModule(
|
||||
DADOSFERA_MODULES_KEYS.CATALOG
|
||||
)
|
||||
async getDataAssetColumnsMetadata(
|
||||
@User() user: RequestUser,
|
||||
@Language() language: LanguageEnum,
|
||||
@@ -435,6 +453,9 @@ export class CatalogController {
|
||||
PERMISSIONS_GROUPS.CATALOG.permissions.GET,
|
||||
PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER,
|
||||
)
|
||||
@RequireModule(
|
||||
DADOSFERA_MODULES_KEYS.CATALOG
|
||||
)
|
||||
async getDataAssetPreview(
|
||||
@User() user: RequestUser,
|
||||
@Language() language: LanguageEnum,
|
||||
@@ -466,6 +487,9 @@ export class CatalogController {
|
||||
PERMISSIONS_GROUPS.CATALOG.permissions.GET,
|
||||
PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER,
|
||||
)
|
||||
@RequireModule(
|
||||
DADOSFERA_MODULES_KEYS.CATALOG
|
||||
)
|
||||
async getDataAssetDocs(
|
||||
@User() user: RequestUser,
|
||||
@Language() language: LanguageEnum,
|
||||
@@ -497,6 +521,9 @@ export class CatalogController {
|
||||
PERMISSIONS_GROUPS.CATALOG.permissions.UPDATE,
|
||||
PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER,
|
||||
)
|
||||
@RequireModule(
|
||||
DADOSFERA_MODULES_KEYS.CATALOG
|
||||
)
|
||||
async updateDataAsset(
|
||||
@User() user: RequestUser,
|
||||
@Language() language: LanguageEnum,
|
||||
@@ -532,6 +559,9 @@ export class CatalogController {
|
||||
PERMISSIONS_GROUPS.CATALOG.permissions.CERTIFY,
|
||||
PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER,
|
||||
)
|
||||
@RequireModule(
|
||||
DADOSFERA_MODULES_KEYS.CATALOG
|
||||
)
|
||||
async updateDataAssetCertificationStatus(
|
||||
@User() user: RequestUser,
|
||||
@Language() language: LanguageEnum,
|
||||
@@ -559,6 +589,9 @@ export class CatalogController {
|
||||
PERMISSIONS_GROUPS.CATALOG.permissions.UPDATE,
|
||||
PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER,
|
||||
)
|
||||
@RequireModule(
|
||||
DADOSFERA_MODULES_KEYS.CATALOG
|
||||
)
|
||||
async manageDataAssetDocs(
|
||||
@User() user: RequestUser,
|
||||
@Headers() headers,
|
||||
@@ -596,6 +629,9 @@ export class CatalogController {
|
||||
|
||||
@ApiInternalOnlyEndpoint()
|
||||
@Put('data-asset/:id/manage-permissions')
|
||||
@RequireModule(
|
||||
DADOSFERA_MODULES_KEYS.CATALOG
|
||||
)
|
||||
async manageDataAssetPermissions(
|
||||
@Param('id') id: string,
|
||||
@User() user: RequestUser,
|
||||
@@ -618,6 +654,9 @@ export class CatalogController {
|
||||
|
||||
@ApiInternalOnlyEndpoint()
|
||||
@Put('data-asset/:id/revoke-permissions')
|
||||
@RequireModule(
|
||||
DADOSFERA_MODULES_KEYS.CATALOG
|
||||
)
|
||||
async revokeDataAssetPermissions(
|
||||
@Param('id') id: string,
|
||||
@User() user: RequestUser,
|
||||
@@ -643,6 +682,9 @@ export class CatalogController {
|
||||
PERMISSIONS_GROUPS.CATALOG.permissions.CREATE,
|
||||
PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER,
|
||||
)
|
||||
@RequireModule(
|
||||
DADOSFERA_MODULES_KEYS.CATALOG
|
||||
)
|
||||
async createDataAsset(
|
||||
@User() user: RequestUser,
|
||||
@Body() body: ICreateDataAsset,
|
||||
@@ -667,6 +709,9 @@ export class CatalogController {
|
||||
PERMISSIONS_GROUPS.CATALOG.permissions.UPDATE,
|
||||
PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER,
|
||||
)
|
||||
@RequireModule(
|
||||
DADOSFERA_MODULES_KEYS.CATALOG
|
||||
)
|
||||
async commentOnDataAsset(
|
||||
@Param('id') id: string,
|
||||
@User() user: RequestUser,
|
||||
@@ -693,6 +738,9 @@ export class CatalogController {
|
||||
PERMISSIONS_GROUPS.CATALOG.permissions.DELETE,
|
||||
PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER,
|
||||
)
|
||||
@RequireModule(
|
||||
DADOSFERA_MODULES_KEYS.CATALOG
|
||||
)
|
||||
async deleteDataAsset(@Param('id') id: string, @User() user: RequestUser) {
|
||||
const { customer_id, customer_name, user_id, username } = user;
|
||||
const metadata = PackTheMetadata({
|
||||
@@ -714,6 +762,9 @@ export class CatalogController {
|
||||
PERMISSIONS_GROUPS.CATALOG.permissions.UPDATE,
|
||||
PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER,
|
||||
)
|
||||
@RequireModule(
|
||||
DADOSFERA_MODULES_KEYS.CATALOG
|
||||
)
|
||||
async deleteComment(
|
||||
@Param('id') id: string,
|
||||
@User() user: RequestUser,
|
||||
@@ -867,6 +918,9 @@ export class CatalogController {
|
||||
|
||||
@Get('nimbus-dashboards')
|
||||
@RequireAllPermissions(PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER)
|
||||
@RequireModule(
|
||||
DADOSFERA_MODULES_KEYS.CATALOG
|
||||
)
|
||||
async getNimbusDashboards(
|
||||
@User() user: RequestUser,
|
||||
@Body() body: GetNimbusDashboardsRequest,
|
||||
|
||||
@@ -27,15 +27,19 @@ import {
|
||||
RefreshCatalogStatusReq,
|
||||
} from './dto/connection-test';
|
||||
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
|
||||
import { Authenticated } from 'src/decorators/authentication.decorator';
|
||||
import { Authenticated, RequireModule } from 'src/decorators/authentication.decorator';
|
||||
import { GrpcToHttpExceptionFilter } from 'src/error/grpc-to-http-exception.filter';
|
||||
import { ApiInternalOnlyController } from 'src/decorators/swagger.decorator';
|
||||
import { DADOSFERA_MODULES_KEYS } from 'src/authentication/permissions.enum';
|
||||
|
||||
@ApiInternalOnlyController()
|
||||
@ApiTags('Connection Test')
|
||||
@Controller('connection-test')
|
||||
@UseFilters(new GrpcToHttpExceptionFilter())
|
||||
@Authenticated()
|
||||
@RequireModule(
|
||||
DADOSFERA_MODULES_KEYS.COLLECT
|
||||
)
|
||||
export class ConnectionTestController {
|
||||
logger: any;
|
||||
constructor(
|
||||
|
||||
@@ -16,8 +16,9 @@ import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
|
||||
import {
|
||||
Authenticated,
|
||||
RequireAllPermissions,
|
||||
RequireModule,
|
||||
} from 'src/decorators/authentication.decorator';
|
||||
import { PERMISSIONS_GROUPS } from 'src/authentication/permissions.enum';
|
||||
import { DADOSFERA_MODULES_KEYS, PERMISSIONS_GROUPS } from 'src/authentication/permissions.enum';
|
||||
import { RequestUser, User } from 'src/decorators/user.decorator';
|
||||
import { ValidationPipe } from '../../pipes/object-validation.pipe';
|
||||
import {
|
||||
@@ -39,6 +40,9 @@ const connectionPermissions = PERMISSIONS_GROUPS.CONNECTION.permissions;
|
||||
@ApiTags('connections')
|
||||
@Authenticated()
|
||||
@Controller('connections')
|
||||
@RequireModule(
|
||||
DADOSFERA_MODULES_KEYS.COLLECT
|
||||
)
|
||||
export class ConnectionController {
|
||||
logger: any;
|
||||
constructor(
|
||||
|
||||
@@ -25,9 +25,10 @@ import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
|
||||
import {
|
||||
Authenticated,
|
||||
RequireAllPermissions,
|
||||
RequireModule,
|
||||
RequireSomePermission,
|
||||
} from 'src/decorators/authentication.decorator';
|
||||
import { PERMISSIONS_GROUPS } from 'src/authentication/permissions.enum';
|
||||
import { DADOSFERA_MODULES_KEYS, PERMISSIONS_GROUPS } from 'src/authentication/permissions.enum';
|
||||
import { Language } from 'src/decorators/language.decorator';
|
||||
import { LanguageEnum } from 'src/utils/languages.enum';
|
||||
import { ApiInternalOnlyController } from 'src/decorators/swagger.decorator';
|
||||
@@ -99,6 +100,9 @@ export class ConnectorController {
|
||||
PERMISSIONS_GROUPS.PIPELINE.permissions.UPDATE,
|
||||
PERMISSIONS_GROUPS.PIPELINE.permissions.DELETE,
|
||||
)
|
||||
@RequireModule(
|
||||
DADOSFERA_MODULES_KEYS.COLLECT
|
||||
)
|
||||
async getAllConnectors(
|
||||
@Language() language: LanguageEnum,
|
||||
@Query() queries: GetAllDto,
|
||||
@@ -131,6 +135,9 @@ export class ConnectorController {
|
||||
PERMISSIONS_GROUPS.PIPELINE.permissions.UPDATE,
|
||||
PERMISSIONS_GROUPS.PIPELINE.permissions.DELETE,
|
||||
)
|
||||
@RequireModule(
|
||||
DADOSFERA_MODULES_KEYS.COLLECT
|
||||
)
|
||||
async getConnectorsTags() {
|
||||
return await this.connectorClientService.getConnectorsTags();
|
||||
}
|
||||
@@ -143,6 +150,9 @@ export class ConnectorController {
|
||||
PERMISSIONS_GROUPS.PIPELINE.permissions.UPDATE,
|
||||
PERMISSIONS_GROUPS.PIPELINE.permissions.DELETE,
|
||||
)
|
||||
@RequireModule(
|
||||
DADOSFERA_MODULES_KEYS.COLLECT
|
||||
)
|
||||
async getConnector(
|
||||
@Language() language: LanguageEnum,
|
||||
@Param('plugin') plugin: string,
|
||||
@@ -171,6 +181,9 @@ export class ConnectorController {
|
||||
PERMISSIONS_GROUPS.PIPELINE.permissions.UPDATE,
|
||||
PERMISSIONS_GROUPS.PIPELINE.permissions.DELETE,
|
||||
)
|
||||
@RequireModule(
|
||||
DADOSFERA_MODULES_KEYS.COLLECT
|
||||
)
|
||||
async getConnectorDetails(
|
||||
@Language() language: LanguageEnum,
|
||||
@Param('plugin') plugin: string,
|
||||
@@ -193,6 +206,9 @@ export class ConnectorController {
|
||||
@Put('/:plugin')
|
||||
@RequireAllPermissions(PERMISSIONS_GROUPS.CONNECTORS.permissions.UPDATE)
|
||||
@ApiConsumes('multipart/form-data')
|
||||
@RequireModule(
|
||||
DADOSFERA_MODULES_KEYS.COLLECT
|
||||
)
|
||||
async updateConnector(
|
||||
@Param('plugin') plugin: string,
|
||||
@Body() body: UpdateDto,
|
||||
@@ -214,6 +230,9 @@ export class ConnectorController {
|
||||
|
||||
@Put('/:plugin/add-tag')
|
||||
@RequireAllPermissions(PERMISSIONS_GROUPS.CONNECTORS.permissions.UPDATE)
|
||||
@RequireModule(
|
||||
DADOSFERA_MODULES_KEYS.COLLECT
|
||||
)
|
||||
async addTagOnConnector(
|
||||
@Param('plugin') plugin: string,
|
||||
@Body() body: AddTagDto,
|
||||
@@ -241,6 +260,9 @@ export class ConnectorController {
|
||||
|
||||
@Put('/:plugin/remove-tag')
|
||||
@RequireAllPermissions(PERMISSIONS_GROUPS.CONNECTORS.permissions.UPDATE)
|
||||
@RequireModule(
|
||||
DADOSFERA_MODULES_KEYS.COLLECT
|
||||
)
|
||||
async removeTagOnConnector(
|
||||
@Param('plugin') plugin: string,
|
||||
@Body() body: RemoveTagDto,
|
||||
@@ -269,6 +291,9 @@ export class ConnectorController {
|
||||
|
||||
@Delete('/:plugin')
|
||||
@RequireAllPermissions(PERMISSIONS_GROUPS.CONNECTORS.permissions.DELETE)
|
||||
@RequireModule(
|
||||
DADOSFERA_MODULES_KEYS.COLLECT
|
||||
)
|
||||
async deleteConnector(
|
||||
@Param('plugin') plugin: string,
|
||||
@Query('version') version: string,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ClientsModule } from '@nestjs/microservices';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
// import { DucClient } from 'src/clients/duc/client.config';
|
||||
// import { DucClient } from '../duc/client.config'
|
||||
import { PermissionsController } from './permissions.controller';
|
||||
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
|
||||
import { PermissionsService } from './permissions.service';
|
||||
@@ -22,7 +22,7 @@ describe.skip('PermissionsController', () => {
|
||||
provide: DadosferaLogger,
|
||||
useValue: { logger },
|
||||
},
|
||||
PermissionsService,
|
||||
PermissionsService
|
||||
],
|
||||
}).compile();
|
||||
|
||||
|
||||
@@ -25,9 +25,10 @@ import {
|
||||
} from '@nestjs/swagger';
|
||||
import {
|
||||
RequireAllPermissions,
|
||||
RequireModule,
|
||||
RequireSomePermission,
|
||||
} from 'src/decorators/authentication.decorator';
|
||||
import { PERMISSIONS_GROUPS } from '../../authentication/permissions.enum';
|
||||
import { DADOSFERA_MODULES_KEYS, PERMISSIONS_GROUPS } from '../../authentication/permissions.enum';
|
||||
import { PipelinesService } from './pipelines.service';
|
||||
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
|
||||
import { Messages } from '@dadosfera/protospack-v2/dist/lib/PipelineV2';
|
||||
@@ -57,6 +58,9 @@ type PipelineTablesConfig = { input_id?: string; tables: PipelineTable[] };
|
||||
@ApiHeaders([{ name: 'dadosfera-lang', enum: LanguageEnum, required: false }])
|
||||
@UseFilters(new GrpcToHttpExceptionFilter())
|
||||
@Controller('pipelinesV2')
|
||||
@RequireModule(
|
||||
DADOSFERA_MODULES_KEYS.COLLECT
|
||||
)
|
||||
export class PipelinesController {
|
||||
logger: DadosferaLogger;
|
||||
constructor(
|
||||
|
||||
@@ -20,10 +20,11 @@ import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
|
||||
import {
|
||||
Authenticated,
|
||||
RequireAllPermissions,
|
||||
RequireModule,
|
||||
} from '../../decorators/authentication.decorator';
|
||||
import { User, RequestUser } from '../../decorators/user.decorator';
|
||||
import { PlatformApiService } from './platform-api.service';
|
||||
import { PERMISSIONS_GROUPS } from '../../authentication/permissions.enum';
|
||||
import { DADOSFERA_MODULES_KEYS, PERMISSIONS_GROUPS } from '../../authentication/permissions.enum';
|
||||
import { ElasticsearchService } from '../../services/elasticsearch';
|
||||
import { DynamoDBService, ReferenceColumn } from '../../services/dynamodb';
|
||||
import { CustomersService } from '../customers/customers.service';
|
||||
@@ -49,6 +50,7 @@ type RenameTablesBody = {
|
||||
|
||||
@ApiTags('Platform API')
|
||||
@Controller('platform')
|
||||
@RequireModule(DADOSFERA_MODULES_KEYS.COLLECT)
|
||||
export class PlatformApiController {
|
||||
private logger: any;
|
||||
|
||||
|
||||
@@ -1,14 +1,25 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { ReleaseNoteController } from './release_note.controller';
|
||||
import { ReleaseNoteService } from './release_note.service';
|
||||
import DadosferaLogger from '@dadosfera/dadosfera-logs';
|
||||
|
||||
describe('ReleaseNoteController', () => {
|
||||
let controller: ReleaseNoteController;
|
||||
const logger = {
|
||||
info: (...args) => args,
|
||||
error: (...args) => args,
|
||||
};
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
controllers: [ReleaseNoteController],
|
||||
providers: [ReleaseNoteService],
|
||||
providers: [
|
||||
{
|
||||
provide: DadosferaLogger,
|
||||
useValue: { logger },
|
||||
},
|
||||
ReleaseNoteService
|
||||
],
|
||||
}).compile();
|
||||
|
||||
controller = module.get<ReleaseNoteController>(ReleaseNoteController);
|
||||
|
||||
@@ -1,12 +1,23 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { ReleaseNoteService } from './release_note.service';
|
||||
import DadosferaLogger from '@dadosfera/dadosfera-logs';
|
||||
|
||||
describe('ReleaseNoteService', () => {
|
||||
let service: ReleaseNoteService;
|
||||
const logger = {
|
||||
info: (...args) => args,
|
||||
error: (...args) => args,
|
||||
};
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [ReleaseNoteService],
|
||||
providers: [
|
||||
{
|
||||
provide: DadosferaLogger,
|
||||
useValue: { logger },
|
||||
},
|
||||
ReleaseNoteService
|
||||
],
|
||||
}).compile();
|
||||
|
||||
service = module.get<ReleaseNoteService>(ReleaseNoteService);
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"exclude": ["node_modules", "test", "dist", "**/*spec.ts", "jest.config.ts"]
|
||||
"exclude": ["node_modules", "test", "dist", "**/*spec.ts", "jest.*.ts"]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user