5 Commits

Author SHA1 Message Date
mr
157e76699e env.env 2026-03-12 13:45:20 +01:00
mr
af4893dd76 better data set for demo docker testing 2026-03-06 08:46:11 +01:00
mr
880e3564f1 Deploy OAuth2 2026-02-24 08:52:12 +01:00
mr
724e729e3b clients 2026-02-19 14:59:33 +01:00
mr
67fc433ab5 New OAUTH2 Docker deployment 2026-02-19 14:57:14 +01:00
36 changed files with 353 additions and 471 deletions

View File

@@ -1,4 +1,5 @@
# RUN DOCKER DEMO # RUN DOCKER DEMO
http://localhost:8000/hydra/oauth2/auth?client_id=2171304d-d15e-45b7-8cc0-1f8e18235ccb&scope=openid offline profile email&response_type=code&redirect_uri=http://localhost:8094/swagger&state=xyz
ADD a clean argo ADD a clean argo
``` ```

View File

@@ -1,40 +0,0 @@
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
name: chu-pipeline
namespace: default
spec:
entrypoint: chu-steps
volumeClaimTemplates:
- metadata:
name: chu-data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 1Gi
templates:
- name: chu-steps
steps:
- - name: chu-statistics
template: chu-statistics
- - name: chu-analyzer
template: chu-analyzer
- name: chu-statistics
container:
image: opencloudregistry/chu-statistics:latest
command: ["chu-statistics"]
volumeMounts:
- name: chu-data
mountPath: /data
- name: chu-analyzer
container:
image: opencloudregistry/chu-analyzer:latest
command: ["chu-analyzer"]
volumeMounts:
- name: chu-data
mountPath: /data

View File

@@ -1,12 +0,0 @@
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY go.mod .
COPY main.go .
RUN go build -o chu-analyzer .
FROM alpine:latest
RUN apk --no-cache add ca-certificates tzdata
RUN mkdir -p /data
WORKDIR /app
COPY --from=builder /app/chu-analyzer /usr/local/bin/chu-analyzer
ENTRYPOINT ["chu-analyzer"]

View File

@@ -1,3 +0,0 @@
module chu-stats-analyzer
go 1.22

View File

@@ -1,204 +0,0 @@
package main
import (
"encoding/json"
"fmt"
"log"
"math"
"os"
"strings"
"time"
)
const dataFile = "/data/chu_stats.json"
type CHUStats struct {
GeneratedAt time.Time `json:"generated_at"`
HospitalName string `json:"hospital_name"`
Date string `json:"date"`
BedsTotal int `json:"beds_total"`
BedsOccupied int `json:"beds_occupied"`
OccupancyRate float64 `json:"occupancy_rate"`
PatientsAdmitted int `json:"patients_admitted"`
PatientsDischarge int `json:"patients_discharged"`
EmergencyVisits int `json:"emergency_visits"`
AvgERWaitMinutes int `json:"avg_er_wait_minutes"`
SurgeriesPerformed int `json:"surgeries_performed"`
ICUBeds int `json:"icu_beds"`
ICUOccupied int `json:"icu_occupied"`
MortalityRate float64 `json:"mortality_rate"`
InfectionRate float64 `json:"infection_rate"`
StaffPresent int `json:"staff_present"`
StaffRequired int `json:"staff_required"`
PatientSatisfaction float64 `json:"patient_satisfaction"`
}
type Check struct {
Indicator string `json:"indicator"`
Value float64 `json:"value"`
Unit string `json:"unit"`
Threshold string `json:"threshold"`
Conformant bool `json:"conformant"`
Severity string `json:"severity"`
Message string `json:"message"`
}
type Analysis struct {
AnalyzedAt time.Time `json:"analyzed_at"`
HospitalName string `json:"hospital_name"`
StatsDate string `json:"stats_date"`
Conformant bool `json:"conformant"`
Score int `json:"score"`
PassingChecks int `json:"passing_checks"`
TotalChecks int `json:"total_checks"`
CriticalAlerts int `json:"critical_alerts"`
WarningAlerts int `json:"warning_alerts"`
Checks []Check `json:"checks"`
Summary string `json:"summary"`
}
func round2(v float64) float64 {
return math.Round(v*100) / 100
}
func analyze(s CHUStats) Analysis {
var checks []Check
occ := Check{Indicator: "Taux d'occupation des lits", Value: s.OccupancyRate, Unit: "%", Threshold: "< 85%"}
switch {
case s.OccupancyRate < 85:
occ.Conformant, occ.Severity, occ.Message = true, "ok", "Taux d'occupation normal"
case s.OccupancyRate < 95:
occ.Conformant, occ.Severity, occ.Message = false, "warning", "Taux d'occupation élevé, risque de saturation"
default:
occ.Conformant, occ.Severity, occ.Message = false, "critical", "Saturation critique des lits hospitaliers"
}
checks = append(checks, occ)
er := Check{Indicator: "Temps d'attente aux urgences", Value: float64(s.AvgERWaitMinutes), Unit: "min", Threshold: "< 60 min"}
switch {
case s.AvgERWaitMinutes < 60:
er.Conformant, er.Severity, er.Message = true, "ok", "Temps d'attente aux urgences acceptable"
case s.AvgERWaitMinutes < 120:
er.Conformant, er.Severity, er.Message = false, "warning", "Temps d'attente aux urgences trop long"
default:
er.Conformant, er.Severity, er.Message = false, "critical", "Saturation critique des urgences"
}
checks = append(checks, er)
icuRate := round2(float64(s.ICUOccupied) / float64(s.ICUBeds) * 100)
icu := Check{Indicator: "Taux d'occupation ICU", Value: icuRate, Unit: "%", Threshold: "< 85%"}
switch {
case icuRate < 85:
icu.Conformant, icu.Severity, icu.Message = true, "ok", "Capacité de réanimation suffisante"
case icuRate < 95:
icu.Conformant, icu.Severity, icu.Message = false, "warning", "Taux d'occupation ICU élevé"
default:
icu.Conformant, icu.Severity, icu.Message = false, "critical", "Réanimation en situation critique"
}
checks = append(checks, icu)
mort := Check{Indicator: "Taux de mortalité hospitalière", Value: s.MortalityRate, Unit: "%", Threshold: "< 2%"}
switch {
case s.MortalityRate < 2.0:
mort.Conformant, mort.Severity, mort.Message = true, "ok", "Taux de mortalité dans les normes"
case s.MortalityRate < 4.0:
mort.Conformant, mort.Severity, mort.Message = false, "warning", "Taux de mortalité supérieur au seuil recommandé"
default:
mort.Conformant, mort.Severity, mort.Message = false, "critical", "Taux de mortalité critique — investigation requise"
}
checks = append(checks, mort)
infect := Check{Indicator: "Taux d'infection nosocomiale", Value: s.InfectionRate, Unit: "%", Threshold: "< 5%"}
switch {
case s.InfectionRate < 5.0:
infect.Conformant, infect.Severity, infect.Message = true, "ok", "Taux d'infection nosocomiale acceptable"
case s.InfectionRate < 8.0:
infect.Conformant, infect.Severity, infect.Message = false, "warning", "Taux d'infection nosocomiale préoccupant"
default:
infect.Conformant, infect.Severity, infect.Message = false, "critical", "Risque infectieux critique — mesures d'urgence requises"
}
checks = append(checks, infect)
staffRate := round2(float64(s.StaffPresent) / float64(s.StaffRequired) * 100)
staff := Check{Indicator: "Taux de couverture du personnel", Value: staffRate, Unit: "%", Threshold: ">= 80%"}
switch {
case staffRate >= 80:
staff.Conformant, staff.Severity, staff.Message = true, "ok", "Personnel suffisant"
case staffRate >= 70:
staff.Conformant, staff.Severity, staff.Message = false, "warning", "Manque de personnel, vigilance requise"
default:
staff.Conformant, staff.Severity, staff.Message = false, "critical", "Sous-effectif critique"
}
checks = append(checks, staff)
sat := Check{Indicator: "Satisfaction des patients", Value: s.PatientSatisfaction, Unit: "/ 5", Threshold: ">= 3.5 / 5"}
switch {
case s.PatientSatisfaction >= 3.5:
sat.Conformant, sat.Severity, sat.Message = true, "ok", "Satisfaction des patients satisfaisante"
case s.PatientSatisfaction >= 3.0:
sat.Conformant, sat.Severity, sat.Message = false, "warning", "Satisfaction des patients insuffisante"
default:
sat.Conformant, sat.Severity, sat.Message = false, "critical", "Satisfaction des patients très mauvaise"
}
checks = append(checks, sat)
passing, critical, warning := 0, 0, 0
for _, c := range checks {
if c.Conformant {
passing++
}
switch c.Severity {
case "critical":
critical++
case "warning":
warning++
}
}
total := len(checks)
score := passing * 100 / total
return Analysis{
AnalyzedAt: time.Now().UTC(),
HospitalName: s.HospitalName,
StatsDate: s.Date,
Conformant: passing == total,
Score: score,
PassingChecks: passing,
TotalChecks: total,
CriticalAlerts: critical,
WarningAlerts: warning,
Checks: checks,
Summary: fmt.Sprintf(
"%d/%d indicateurs conformes (score: %d%%) — %d alerte(s) critique(s), %d avertissement(s)",
passing, total, score, critical, warning,
),
}
}
func main() {
for i := range []int{0, 1} {
data, err := os.ReadFile(strings.ReplaceAll(dataFile, "stats", "stats"+fmt.Sprintf("%v", i)))
if err != nil {
if os.IsNotExist(err) {
log.Fatalf("stats file not found at %s — run chu-stats-generator first", dataFile)
}
log.Fatalf("failed to read stats file: %v", err)
}
var stats CHUStats
if err := json.Unmarshal(data, &stats); err != nil {
log.Fatalf("failed to parse stats file: %v", err)
}
analysis := analyze(stats)
result, err := json.MarshalIndent(analysis, "", " ")
if err != nil {
log.Fatalf("failed to marshal analysis: %v", err)
}
log.Printf("Analysis complete: %s", analysis.Summary)
fmt.Println(string(result))
}
}

View File

@@ -1,12 +0,0 @@
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY go.mod .
COPY main.go .
RUN go build -o chu-statistics .
FROM alpine:latest
RUN apk --no-cache add ca-certificates tzdata
RUN mkdir -p /data
WORKDIR /app
COPY --from=builder /app/chu-statistics /usr/local/bin/chu-statistics
ENTRYPOINT ["chu-statistics"]

View File

@@ -1,3 +0,0 @@
module chu-stats-generator
go 1.22

View File

@@ -1,96 +0,0 @@
package main
import (
"encoding/json"
"fmt"
"log"
"math"
"math/rand"
"os"
"strings"
"time"
)
const dataFile = "/data/chu_stats.json"
type CHUStats struct {
GeneratedAt time.Time `json:"generated_at"`
HospitalName string `json:"hospital_name"`
Date string `json:"date"`
BedsTotal int `json:"beds_total"`
BedsOccupied int `json:"beds_occupied"`
OccupancyRate float64 `json:"occupancy_rate"`
PatientsAdmitted int `json:"patients_admitted"`
PatientsDischarge int `json:"patients_discharged"`
EmergencyVisits int `json:"emergency_visits"`
AvgERWaitMinutes int `json:"avg_er_wait_minutes"`
SurgeriesPerformed int `json:"surgeries_performed"`
ICUBeds int `json:"icu_beds"`
ICUOccupied int `json:"icu_occupied"`
MortalityRate float64 `json:"mortality_rate"`
InfectionRate float64 `json:"infection_rate"`
StaffPresent int `json:"staff_present"`
StaffRequired int `json:"staff_required"`
PatientSatisfaction float64 `json:"patient_satisfaction"`
}
func round2(v float64) float64 {
return math.Round(v*100) / 100
}
func generateStats() CHUStats {
rng := rand.New(rand.NewSource(time.Now().UnixNano()))
bedsTotal := 800 + rng.Intn(400)
occupancyPct := 0.65 + rng.Float64()*0.32
bedsOccupied := int(float64(bedsTotal) * occupancyPct)
icuBeds := 40 + rng.Intn(30)
icuOccupancyPct := 0.60 + rng.Float64()*0.38
icuOccupied := int(float64(icuBeds) * icuOccupancyPct)
staffRequired := 600 + rng.Intn(300)
staffCoverage := 0.65 + rng.Float64()*0.40
staffPresent := int(float64(staffRequired) * staffCoverage)
return CHUStats{
GeneratedAt: time.Now().UTC(),
HospitalName: "CHU Demo",
Date: time.Now().Format("2006-01-02"),
BedsTotal: bedsTotal,
BedsOccupied: bedsOccupied,
OccupancyRate: round2(occupancyPct * 100),
PatientsAdmitted: 50 + rng.Intn(120),
PatientsDischarge: 40 + rng.Intn(120),
EmergencyVisits: 80 + rng.Intn(150),
AvgERWaitMinutes: 15 + rng.Intn(130),
SurgeriesPerformed: 10 + rng.Intn(50),
ICUBeds: icuBeds,
ICUOccupied: icuOccupied,
MortalityRate: round2(0.3 + rng.Float64()*4.5),
InfectionRate: round2(0.5 + rng.Float64()*9.0),
StaffPresent: staffPresent,
StaffRequired: staffRequired,
PatientSatisfaction: round2(2.0 + rng.Float64()*3.0),
}
}
func main() {
for i, stats := range []CHUStats{generateStats(), generateStats()} {
data, err := json.MarshalIndent(stats, "", " ")
if err != nil {
log.Fatalf("failed to marshal stats: %v", err)
}
if err := os.MkdirAll("/data", 0755); err != nil {
log.Fatalf("failed to create data dir: %v", err)
}
if err := os.WriteFile(strings.ReplaceAll(dataFile, "stats", "stats"+fmt.Sprintf("%v", i)), data, 0644); err != nil {
log.Fatalf("failed to write stats file: %v", err)
}
log.Printf("Stats saved to %s", dataFile)
fmt.Println(string(data))
}
}

View File

@@ -1,22 +0,0 @@
#!/bin/bash
DB="DC_myDC"
CONTAINER="mongo"
echo "📌 Dropping database '$DB'..."
docker exec -i $CONTAINER mongosh --eval "db.getSiblingDB('$DB').dropDatabase()"
echo "📌 Copying datas/ to container..."
docker cp ./datas $CONTAINER:/datas
echo "📌 Importing JSON files..."
for i in ./datas/*.json; do
filename=$(basename "$i")
collection="${filename%.json}"
echo "→ Importing '$filename' into collection '$collection'..."
docker exec -i $CONTAINER sh -c \
"mongoimport --jsonArray --db $DB --collection $collection --file /datas/$filename --drop"
done
echo "✔ Done!"

View File

@@ -1 +0,0 @@
[{"_id":"0b6a375f-be3e-49a9-9827-3c2d5eddb057","abstractobject":{"id":"0b6a375f-be3e-49a9-9827-3c2d5eddb057","name":"test","is_draft":false,"creator_id":"c0cece97-7730-4c2a-8c20-a30944564106","creation_date":{"$date":"2025-01-27T10:41:47.741Z"},"update_date":{"$date":"2025-01-27T10:41:47.741Z"},"updater_id":"c0cece97-7730-4c2a-8c20-a30944564106","access_mode":0},"description":"Proto Collaborative area example","collaborative_area":{},"workflows":["58314c99-c595-4ca2-8b5e-822a6774efed"],"allowed_peers_group":{"c0cece97-7730-4c2a-8c20-a30944564106":["*"]},"workspaces":[]}]

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
[{"_id":"c0cece97-7730-4c2a-8c20-a30944564106","failed_execution":null,"abstractobject":{"update_date":{"$date":"2025-03-27T09:13:13.230Z"},"access_mode":0,"id":"c0cece97-7730-4c2a-8c20-a30944564106","name":"local","is_draft":false,"creation_date":{"$date":"2025-03-27T09:13:13.230Z"}},"url":"http://localhost:8000","wallet_address":"my-wallet","public_key":"-----BEGIN RSA PUBLIC KEY-----\nMIICCgKCAgEAw2pdG6wMtuLcP0+k1LFvIb0DQo/oHW2uNJaEJK74plXqp4ztz2dR\nb+RQHFLeLuqk4i/zc3b4K3fKPXSlwnVPJCwzPrnyT8jYGOZVlWlETiV9xeJhu6s/\nBh6g1PWz75XjjwV50iv/CEiLNBT23f/3J44wrQzygqNQCiQSALdxWLAEl4l5kHSa\n9oMyV70/Uql94/ayMARZsHgp9ZvqQKbkZPw6yzVMfCBxQozlNlo315OHevudhnhp\nDRjN5I7zWmqYt6rbXJJC7Y3Izdvzn7QI88RqjSRST5I/7Kz3ndCqrOnI+OQUE5NT\nREyQebphvQfTDTKlRPXkdyktdK2DH28Zj6ZF3yjQvN35Q4zhOzlq77dO5IhhopI7\nct8dZH1T1nYkvdyCA/EVMtQsASmBOitH0Y0ACoXQK5Kb6nm/TcM/9ZSJUNiEMuy5\ngBZ3YKE9oa4cpTpPXwcA+S/cU7HPNnQAsvD3iJi8GTW9uJs84pn4/WhpQqmXd4rv\nhKWECCN3fHy01fUs/U0PaSj2jDY/kQVeXoikNMzPUjdZd9m816TIBh3v3aVXCH/0\niTHHAxctvDgMRb2fpvRJ/wwnYjFG9RpamVFDMvC9NffuYzWAA9IRIY4cqgerfHrV\nZ2HHiPTDDvDAIsvImXZc/h7mXN6m3RCQ4Qywy993wd9gUdgg/qnynHcCAwEAAQ==\n-----END RSA PUBLIC KEY-----\n","state":1}]

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
[{"_id":"04bc70b5-8d7b-44e6-9015-fadfa0fb102d","abstractinstanciatedresource":{"abstractresource":{"type":"storage","abstractobject":{"id":"04bc70b5-8d7b-44e6-9015-fadfa0fb102d","name":"IRT risk database","is_draft":false,"creator_id":"c0cece97-7730-4c2a-8c20-a30944564106","creation_date":"2021-09-30T14:00:00.000Z","update_date":"2021-09-30T14:00:00.000Z","updater_id":"c0cece97-7730-4c2a-8c20-a30944564106","access_mode":1},"logo":"https://cloud.o-forge.io/core/deperecated-oc-catalog/raw/branch/main/scripts/local_imgs/IRT risk database.png","description":"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.","short_description":"S3 compliant IRT file storage","owners":[{"name":"IRT"}]},"instances":[{"env":[{"attr":"source","readonly":true}],"resourceinstance":{"abstractobject":{"id":"7fdccb9c-7090-40a5-bacd-7435bc56c90d","name":"IRT local file storage Marseille"},"location":{"latitude":50.62925,"longitude":3.057256},"country":250,"partnerships":[{"resourcepartnership":{"namespace":"default","peer_groups":{"c0cece97-7730-4c2a-8c20-a30944564106":["*"]},"pricing_profiles":[{"pricing":{"price":50,"currency":"EUR","buying_strategy":0,"time_pricing_strategy":0}}]}}]},"source":"/mnt/vol","local":false,"security_level":"public","size":50,"size_type":3,"redundancy":"RAID5","throughput":"r:200,w:150"}]},"storage_type":5,"acronym":"DC_myDC"},{"_id":"e726020a-b68e-4abc-ab36-c3640ea3f557","abstractinstanciatedresource":{"abstractresource":{"type":"storage","abstractobject":{"id":"e726020a-b68e-4abc-ab36-c3640ea3f557","name":"IRT local file storage","is_draft":false,"creator_id":"c0cece97-7730-4c2a-8c20-a30944564106","creation_date":"2021-09-30T14:00:00.000Z","update_date":"2021-09-30T14:00:00.000Z","updater_id":"c0cece97-7730-4c2a-8c20-a30944564106","access_mode":1},"logo":"https://cloud.o-forge.io/core/deperecated-oc-catalog/raw/branch/main/scripts/local_imgs/IRT local file storage.png","description":"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.","short_description":"S3 compliant IRT file storage","owners":[{"name":"IRT"}]},"instances":[{"resourceinstance":{"env":[{"attr":"source","readonly":true}],"abstractobject":{"id":"7fdccb9c-7090-40a5-bacd-7435bc56c90d","name":"IRT local file storage Marseille"},"location":{"latitude":50.62925,"longitude":3.057256},"country":250,"partnerships":[{"resourcepartnership":{"namespace":"default","peer_groups":{"c0cece97-7730-4c2a-8c20-a30944564106":["*"]},"pricing_profiles":[{"pricing":{"price":50,"currency":"EUR","buying_strategy":0,"time_pricing_strategy":0}}]}}]},"source":"/mnt/vol","local":true,"security_level":"public","size":500,"size_type":0,"encryption":true,"redundancy":"RAID5S","throughput":"r:300,w:350"}]},"storage_type":5,"acronym":"DC_myDC"}]

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
[{"_id":"0b6a375f-be3e-49a9-9827-3c2d5eddb057","abstractobject":{"id":"0b6a375f-be3e-49a9-9827-3c2d5eddb057","name":"test","is_draft":false,"creator_id":"c0cece97-7730-4c2a-8c20-a30944564106","creation_date":{"$date":"2025-01-27T10:41:47.741Z"},"update_date":{"$date":"2025-01-27T10:41:47.741Z"},"updater_id":"c0cece97-7730-4c2a-8c20-a30944564106","access_mode":0},"description":"Proto Collaborative area example","collaborative_area":{},"workflows":["58314c99-c595-4ca2-8b5e-822a6774efed"],"allowed_peers_group":{"c0cece97-7730-4c2a-8c20-a30944564106":["*"]},"workspaces":[]}]

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1 +1,32 @@
[{"_id":"c0cece97-7730-4c2a-8c20-a30944564106","failed_execution":null,"abstractobject":{"update_date":{"$date":"2025-03-27T09:13:13.230Z"},"access_mode":0,"id":"c0cece97-7730-4c2a-8c20-a30944564106","name":"local","is_draft":false,"creation_date":{"$date":"2025-03-27T09:13:13.230Z"}},"url":"http://localhost:8000","wallet_address":"my-wallet","public_key":"-----BEGIN RSA PUBLIC KEY-----\nMIICCgKCAgEAw2pdG6wMtuLcP0+k1LFvIb0DQo/oHW2uNJaEJK74plXqp4ztz2dR\nb+RQHFLeLuqk4i/zc3b4K3fKPXSlwnVPJCwzPrnyT8jYGOZVlWlETiV9xeJhu6s/\nBh6g1PWz75XjjwV50iv/CEiLNBT23f/3J44wrQzygqNQCiQSALdxWLAEl4l5kHSa\n9oMyV70/Uql94/ayMARZsHgp9ZvqQKbkZPw6yzVMfCBxQozlNlo315OHevudhnhp\nDRjN5I7zWmqYt6rbXJJC7Y3Izdvzn7QI88RqjSRST5I/7Kz3ndCqrOnI+OQUE5NT\nREyQebphvQfTDTKlRPXkdyktdK2DH28Zj6ZF3yjQvN35Q4zhOzlq77dO5IhhopI7\nct8dZH1T1nYkvdyCA/EVMtQsASmBOitH0Y0ACoXQK5Kb6nm/TcM/9ZSJUNiEMuy5\ngBZ3YKE9oa4cpTpPXwcA+S/cU7HPNnQAsvD3iJi8GTW9uJs84pn4/WhpQqmXd4rv\nhKWECCN3fHy01fUs/U0PaSj2jDY/kQVeXoikNMzPUjdZd9m816TIBh3v3aVXCH/0\niTHHAxctvDgMRb2fpvRJ/wwnYjFG9RpamVFDMvC9NffuYzWAA9IRIY4cqgerfHrV\nZ2HHiPTDDvDAIsvImXZc/h7mXN6m3RCQ4Qywy993wd9gUdgg/qnynHcCAwEAAQ==\n-----END RSA PUBLIC KEY-----\n","state":1}] [{
"_id":"c0cece97-7730-4c2a-8c20-a30944564106",
"failed_execution":null,
"api_url":"http://beta.opencloud.com:9600",
"nats_address": "nats://nats:4222",
"stream_address":"/ip4/172.40.0.9/tcp/4009/p2p/12D3KooWGnQfKwX9E4umCPE8dUKZuig4vw5BndDowRLEbGmcZyta",
"wallet_address":"my-wallet",
"public_key":"MCowBQYDK2VwAyEAZ4F3KqOp/5QrPdZGqqX6PYYEGd2snX4Q3AUt9XAG3v8=",
"peer_id": "12D3KooWGnQfKwX9E4umCPE8dUKZuig4vw5BndDowRLEbGmcZyta",
"relation": 1,
"abstractobject":{
"update_date":{"$date":"2025-03-27T09:13:13.230Z"},"access_mode":0,
"id":"c0cece97-7730-4c2a-8c20-a30944564106",
"name":"opencloud-demo-1","is_draft":false,
"creation_date":{"$date":"2025-03-27T09:13:13.230Z"}
}
}, {
"_id":"b87318c9-f5f8-44bb-8d48-913f4ddd6c31",
"failed_execution":null,
"abstractobject":{
"update_date":{"$date":"2025-03-27T09:13:13.230Z"},"access_mode":0,
"id":"b87318c9-f5f8-44bb-8d48-913f4ddd6c31",
"name":"opencloud-demo-2","is_draft":false,
"creation_date":{"$date":"2025-03-27T09:13:13.230Z"}},
"api_url":"http://localhost:8000",
"nats_address": "nats://nats:4222",
"stream_address":"/ip4/172.40.0.10/tcp/4010/p2p/12D3KooWB4jGjyhr8idBehfpkwvfuvEKvubSDu3VPgxFeeXSwEgZ",
"peer_id": "12D3KooWB4jGjyhr8idBehfpkwvfuvEKvubSDu3VPgxFeeXSwEgZ",
"wallet_address":"my-wallet",
"public_key":"MCowBQYDK2VwAyEAEomuEQGmGsYVw35C6DB5tfY8LI8jm359ceAxRX8eQ0o",
"relation": 2
}]

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
[{"_id":"0b6a375f-be3e-49a9-9827-3c2d5eddb057","abstractobject":{"id":"0b6a375f-be3e-49a9-9827-3c2d5eddb057","name":"test","is_draft":false,"creator_id":"c0cece97-7730-4c2a-8c20-a30944564106","creation_date":{"$date":"2025-01-27T10:41:47.741Z"},"update_date":{"$date":"2025-01-27T10:41:47.741Z"},"updater_id":"c0cece97-7730-4c2a-8c20-a30944564106","access_mode":0},"description":"Proto Collaborative area example","collaborative_area":{},"workflows":["58314c99-c595-4ca2-8b5e-822a6774efed"],"allowed_peers_group":{"c0cece97-7730-4c2a-8c20-a30944564106":["*"]},"workspaces":[]}]

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
[{"_id":"c0cece97-7730-4c2a-8c20-a30944564106","failed_execution":null,"abstractobject":{"update_date":{"$date":"2025-03-27T09:13:13.230Z"},"access_mode":0,"id":"c0cece97-7730-4c2a-8c20-a30944564106","name":"local","is_draft":false,"creation_date":{"$date":"2025-03-27T09:13:13.230Z"}},"url":"http://localhost:8000","wallet_address":"my-wallet","public_key":"-----BEGIN RSA PUBLIC KEY-----\nMIICCgKCAgEAw2pdG6wMtuLcP0+k1LFvIb0DQo/oHW2uNJaEJK74plXqp4ztz2dR\nb+RQHFLeLuqk4i/zc3b4K3fKPXSlwnVPJCwzPrnyT8jYGOZVlWlETiV9xeJhu6s/\nBh6g1PWz75XjjwV50iv/CEiLNBT23f/3J44wrQzygqNQCiQSALdxWLAEl4l5kHSa\n9oMyV70/Uql94/ayMARZsHgp9ZvqQKbkZPw6yzVMfCBxQozlNlo315OHevudhnhp\nDRjN5I7zWmqYt6rbXJJC7Y3Izdvzn7QI88RqjSRST5I/7Kz3ndCqrOnI+OQUE5NT\nREyQebphvQfTDTKlRPXkdyktdK2DH28Zj6ZF3yjQvN35Q4zhOzlq77dO5IhhopI7\nct8dZH1T1nYkvdyCA/EVMtQsASmBOitH0Y0ACoXQK5Kb6nm/TcM/9ZSJUNiEMuy5\ngBZ3YKE9oa4cpTpPXwcA+S/cU7HPNnQAsvD3iJi8GTW9uJs84pn4/WhpQqmXd4rv\nhKWECCN3fHy01fUs/U0PaSj2jDY/kQVeXoikNMzPUjdZd9m816TIBh3v3aVXCH/0\niTHHAxctvDgMRb2fpvRJ/wwnYjFG9RpamVFDMvC9NffuYzWAA9IRIY4cqgerfHrV\nZ2HHiPTDDvDAIsvImXZc/h7mXN6m3RCQ4Qywy993wd9gUdgg/qnynHcCAwEAAQ==\n-----END RSA PUBLIC KEY-----\n","state":1}]

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
[{"_id":"04bc70b5-8d7b-44e6-9015-fadfa0fb102d","abstractinstanciatedresource":{"abstractresource":{"type":"storage","abstractobject":{"id":"04bc70b5-8d7b-44e6-9015-fadfa0fb102d","name":"IRT risk database","is_draft":false,"creator_id":"c0cece97-7730-4c2a-8c20-a30944564106","creation_date":"2021-09-30T14:00:00.000Z","update_date":"2021-09-30T14:00:00.000Z","updater_id":"c0cece97-7730-4c2a-8c20-a30944564106","access_mode":1},"logo":"https://cloud.o-forge.io/core/deperecated-oc-catalog/raw/branch/main/scripts/local_imgs/IRT risk database.png","description":"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.","short_description":"S3 compliant IRT file storage","owners":[{"name":"IRT"}]},"instances":[{"env":[{"attr":"source","readonly":true}],"resourceinstance":{"abstractobject":{"id":"7fdccb9c-7090-40a5-bacd-7435bc56c90d","name":"IRT local file storage Marseille"},"location":{"latitude":50.62925,"longitude":3.057256},"country":250,"partnerships":[{"resourcepartnership":{"namespace":"default","peer_groups":{"c0cece97-7730-4c2a-8c20-a30944564106":["*"]},"pricing_profiles":[{"pricing":{"price":50,"currency":"EUR","buying_strategy":0,"time_pricing_strategy":0}}]}}]},"source":"/mnt/vol","local":false,"security_level":"public","size":50,"size_type":3,"redundancy":"RAID5","throughput":"r:200,w:150"}]},"storage_type":5,"acronym":"DC_myDC"},{"_id":"e726020a-b68e-4abc-ab36-c3640ea3f557","abstractinstanciatedresource":{"abstractresource":{"type":"storage","abstractobject":{"id":"e726020a-b68e-4abc-ab36-c3640ea3f557","name":"IRT local file storage","is_draft":false,"creator_id":"c0cece97-7730-4c2a-8c20-a30944564106","creation_date":"2021-09-30T14:00:00.000Z","update_date":"2021-09-30T14:00:00.000Z","updater_id":"c0cece97-7730-4c2a-8c20-a30944564106","access_mode":1},"logo":"https://cloud.o-forge.io/core/deperecated-oc-catalog/raw/branch/main/scripts/local_imgs/IRT local file storage.png","description":"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.","short_description":"S3 compliant IRT file storage","owners":[{"name":"IRT"}]},"instances":[{"resourceinstance":{"env":[{"attr":"source","readonly":true}],"abstractobject":{"id":"7fdccb9c-7090-40a5-bacd-7435bc56c90d","name":"IRT local file storage Marseille"},"location":{"latitude":50.62925,"longitude":3.057256},"country":250,"partnerships":[{"resourcepartnership":{"namespace":"default","peer_groups":{"c0cece97-7730-4c2a-8c20-a30944564106":["*"]},"pricing_profiles":[{"pricing":{"price":50,"currency":"EUR","buying_strategy":0,"time_pricing_strategy":0}}]}}]},"source":"/mnt/vol","local":true,"security_level":"public","size":500,"size_type":0,"encryption":true,"redundancy":"RAID5S","throughput":"r:300,w:350"}]},"storage_type":5,"acronym":"DC_myDC"}]

File diff suppressed because one or more lines are too long

23
docker/tools/clients.json Normal file
View File

@@ -0,0 +1,23 @@
[
{
"client_id": "test-client",
"client_secret": "oc-auth-got-secret",
"client_name": "test-client",
"grant_types": [
"implicit",
"refresh_token",
"authorization_code",
"client_credentials"
],
"response_types": [
"id_token",
"token",
"code"
],
"scope": "openid profile email roles",
"redirect_uris": [
"http://localhost:8000/l"
],
"token_endpoint_auth_method": "client_secret_post"
}
]

View File

@@ -1,4 +1,4 @@
version: '3.4' version: '3.9'
services: services:
mongo: mongo:
@@ -76,12 +76,31 @@ services:
SECRETS_SYSTEM: oc-auth-got-secret SECRETS_SYSTEM: oc-auth-got-secret
LOG_LEAK_SENSITIVE_VALUES: true LOG_LEAK_SENSITIVE_VALUES: true
# OAUTH2_TOKEN_HOOK_URL: http://oc-auth:8080/oc/claims # OAUTH2_TOKEN_HOOK_URL: http://oc-auth:8080/oc/claims
URLS_SELF_ISSUER: http://hydra:4444 HYDRA_ADMIN_URL: http://hydra:4445
URLS_SELF_PUBLIC: http://hydra:4444 URLS_SELF_ISSUER: http://localhost:8000/hydra
URLS_SELF_PUBLIC: http://localhost:8000/hydra
URLS_LOGIN: http://localhost:8000/auth/login
URLS_CONSENT: http://localhost:8000/auth/consent
URLS_LOGOUT: http://localhost:8000/auth/logout
URLS_ERROR: http://localhost:8000/l
WEBFINGER_OIDC_DISCOVERY_SUPPORTED_SCOPES: profile,email,phone,roles WEBFINGER_OIDC_DISCOVERY_SUPPORTED_SCOPES: profile,email,phone,roles
WEBFINGER_OIDC_DISCOVERY_SUPPORTED_CLAIMS: name,family_name,given_name,nickname,email,phone_number WEBFINGER_OIDC_DISCOVERY_SUPPORTED_CLAIMS: name,family_name,given_name,nickname,email,phone_number
DSN: memory DSN: memory
command: serve all --dev user: root
entrypoint: >
sh -c "
hydra serve all --dev &
echo '⏳ Waiting for Hydra admin API...' &&
until wget -q --spider http://localhost:4445/health/ready; do
sleep 2;
done &&
echo '✅ Hydra is ready. Importing clients...' &&
hydra import oauth2-client /clients.json -e http://hydra:4445 &&
echo '🚀 Clients imported.' &&
wait
"
volumes:
- ./clients.json:/clients.json
networks: networks:
- oc - oc
ports: ports:
@@ -90,6 +109,13 @@ services:
deploy: deploy:
restart_policy: restart_policy:
condition: on-failure condition: on-failure
labels:
- "traefik.enable=true"
- "traefik.http.routers.hydra.entrypoints=web"
- "traefik.http.routers.hydra.rule=PathPrefix(`/hydra`)"
- "traefik.http.services.hydra.loadbalancer.server.port=4444"
- "traefik.http.middlewares.hydra-stripprefix.stripprefix.prefixes=/hydra"
- "traefik.http.routers.hydra.middlewares=hydra-stripprefix"
ldap: ldap:
image: pgarrett/ldap-alpine image: pgarrett/ldap-alpine
container_name: ldap container_name: ldap
@@ -116,44 +142,22 @@ services:
container_name: keto container_name: keto
networks: networks:
- oc - oc
login-app:
hydra-client: image: nginx:alpine
image: oryd/hydra:v2.2.0 container_name: login-app
container_name: hydra-client ports:
environment: - "9090:80"
HYDRA_ADMIN_URL: http://hydra:4445
ORY_SDK_URL: http://hydra:4445
command:
- create
- oauth2-client
- --skip-tls-verify
- --name
- test-client
- --secret
- oc-auth-got-secret
- --response-type
- id_token,token,code
- --grant-type
- implicit,refresh_token,authorization_code,client_credentials
- --scope
- openid,profile,email,roles
- --token-endpoint-auth-method
- client_secret_post
- --redirect-uri
- http://localhost:3000
networks: networks:
- oc - oc
deploy: volumes:
restart_policy: - ./html:/usr/share/nginx/html:ro
condition: none labels:
depends_on: - "traefik.enable=true"
- hydra - "traefik.http.routers.login.entrypoints=web"
healthcheck: - "traefik.http.routers.login.rule=PathPrefix(`/l`)"
test: ["CMD", "curl", "-f", "http://hydra:4445"] - "traefik.http.services.login.loadbalancer.server.port=80"
interval: 10s - "traefik.http.middlewares.login-stripprefix.stripprefix.prefixes=/l"
timeout: 10s - "traefik.http.routers.login.middlewares=login-stripprefix"
retries: 10
volumes: volumes:
oc-data: oc-data:
@@ -161,3 +165,4 @@ volumes:
networks: networks:
oc: oc:
external: true external: true

View File

@@ -24,3 +24,4 @@ volumes:
networks: networks:
oc: oc:
external: true external: true

View File

@@ -0,0 +1,117 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>Login</title>
<style>
body {
font-family: Arial, sans-serif;
background: #f4f6f9;
display: flex;
height: 100vh;
align-items: center;
justify-content: center;
}
.login-container {
background: white;
padding: 40px;
border-radius: 8px;
box-shadow: 0 5px 20px rgba(0,0,0,0.1);
width: 300px;
}
h2 {
text-align: center;
}
input {
width: 100%;
padding: 10px;
margin-top: 10px;
border-radius: 4px;
border: 1px solid #ccc;
}
button {
width: 100%;
margin-top: 20px;
padding: 10px;
background: #007BFF;
border: none;
color: white;
border-radius: 4px;
cursor: pointer;
}
button:hover {
background: #0056b3;
}
.error {
color: red;
margin-top: 10px;
text-align: center;
}
</style>
</head>
<body>
<div class="login-container">
<h2>Connexion</h2>
<form id="loginForm">
<input type="text" id="username" placeholder="Username" required />
<input type="password" id="password" placeholder="Password" required />
<button type="submit">Login</button>
<div class="error" id="error"></div>
</form>
</div>
<script>
function getLoginChallenge() {
const params = new URLSearchParams(window.location.search);
return params.get("login_challenge");
}
document.getElementById("loginForm").addEventListener("submit", async function(event) {
event.preventDefault();
const username = document.getElementById("username").value;
const password = document.getElementById("password").value;
const loginChallenge = getLoginChallenge();
if (!loginChallenge) {
document.getElementById("error").innerText = "Missing login_challenge in URL";
return;
}
try {
const response = await fetch("http://localhost:8000/auth/login", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
login_challenge: loginChallenge,
username: username,
password: password
})
});
if (!response.ok) {
throw new Error("Login failed");
}
const data = await response.json();
console.log("Success:", data);
alert("Login success");
} catch (err) {
document.getElementById("error").innerText = "Login failed";
}
});
</script>
</body>
</html>

View File

@@ -1,19 +1,19 @@
[{ [{
"_id":"c0cece97-7730-4c2a-8c20-a30944564106", "_id":"c0cece97-7730-4c2a-8c20-a30944564106",
"failed_execution":null, "failed_execution":null,
"abstractobject":{ "api_url":"http://beta.opencloud.com:9600",
"update_date":{"$date":"2025-03-27T09:13:13.230Z"},"access_mode":0,
"id":"c0cece97-7730-4c2a-8c20-a30944564106",
"name":"local","is_draft":false,
"creation_date":{"$date":"2025-03-27T09:13:13.230Z"}},
"api_url":"http://192.168.1.1",
"nats_address": "nats://nats:4222", "nats_address": "nats://nats:4222",
"stream_address":"/ip4/192.168.1.1/tcp/4001/p2p/QmXkKz9kE7pY3Yw4m6x9FhJ3JY5P2QJpX9C7Yz2T4H8WvA", "stream_address":"/ip4/192.168.1.1/tcp/4001/p2p/QmXkKz9kE7pY3Yw4m6x9FhJ3JY5P2QJpX9C7Yz2T4H8WvA",
"wallet_address":"my-wallet", "wallet_address":"my-wallet",
"public_key":"MCowBQYDK2VwAyEAZ2nLJBL8a5opfa8nFeVj0SZToW8pl4+zgcSUkeZFRO4=", "public_key":"MCowBQYDK2VwAyEAZ2nLJBL8a5opfa8nFeVj0SZToW8pl4+zgcSUkeZFRO4=",
"state":1,
"peer_id": "QmXkKz9kE7pY3Yw4m6x9FhJ3JY5P2QJpX9C7Yz2T4H8WvA", "peer_id": "QmXkKz9kE7pY3Yw4m6x9FhJ3JY5P2QJpX9C7Yz2T4H8WvA",
"relation": 1 "relation": 1,
"abstractobject":{
"update_date":{"$date":"2025-03-27T09:13:13.230Z"},"access_mode":0,
"id":"c0cece97-7730-4c2a-8c20-a30944564106",
"name":"local","is_draft":false,
"creation_date":{"$date":"2025-03-27T09:13:13.230Z"}
}
}, { }, {
"_id":"6a3fc74d-8c06-4dbb-ad11-d5c53562775b", "_id":"6a3fc74d-8c06-4dbb-ad11-d5c53562775b",
"failed_execution":null, "failed_execution":null,
@@ -22,12 +22,12 @@
"id":"6a3fc74d-8c06-4dbb-ad11-d5c53562775b", "id":"6a3fc74d-8c06-4dbb-ad11-d5c53562775b",
"name":"local","is_draft":false, "name":"local","is_draft":false,
"creation_date":{"$date":"2025-03-27T09:13:13.230Z"}}, "creation_date":{"$date":"2025-03-27T09:13:13.230Z"}},
"api_url":"http://192.168.1.2", "api_url":"http://beta.opencloud.com:9700",
"nats_address": "nats://nats:4222", "nats_address": "nats://nats:4222",
"stream_address":"/ip4/192.168.1.1/tcp/4002/p2p/QmTzQ1NwFz9bYH7Kp8Zs4XyJQk3E6C5R9H1m2A8L7V", "stream_address":"/ip4/192.168.1.1/tcp/4002/p2p/QmTzQ1NwFz9bYH7Kp8Zs4XyJQk3E6C5R9H1m2A8L7V",
"peer_id": "QmTzQ1NwFz9bYH7Kp8Zs4XyJQk3E6C5R9H1m2A8L7V", "peer_id": "QmTzQ1NwFz9bYH7Kp8Zs4XyJQk3E6C5R9H1m2A8L7V",
"wallet_address":"my-wallet", "wallet_address":"my-wallet",
"public_key":"MCowBQYDK2VwAyEAZ2nLJBL8a5opfa8nFeVj0SZToW8pl4+zgcSUkeZFRO4=", "public_key":"MCowBQYDK2VwAyEAZ2nLJBL8a5opfa8nFeVj0SZToW8pl4+zgcSUkeZFRO4=",
"state":2, "state":1,
"relation": 1 "relation": 2
}] }]

View File

@@ -6,11 +6,11 @@
"id":"c0cece97-7730-4c2a-8c20-a30944564106", "id":"c0cece97-7730-4c2a-8c20-a30944564106",
"name":"local","is_draft":false, "name":"local","is_draft":false,
"creation_date":{"$date":"2025-03-27T09:13:13.230Z"}}, "creation_date":{"$date":"2025-03-27T09:13:13.230Z"}},
"url":"http://192.168.1.1", "url":"http://beta.opencloud.com:9600",
"wallet_address":"my-wallet", "wallet_address":"my-wallet",
"public_key":"-----BEGIN RSA PUBLIC KEY-----\nMIICCgKCAgEAw2pdG6wMtuLcP0+k1LFvIb0DQo/oHW2uNJaEJK74plXqp4ztz2dR\nb+RQHFLeLuqk4i/zc3b4K3fKPXSlwnVPJCwzPrnyT8jYGOZVlWlETiV9xeJhu6s/\nBh6g1PWz75XjjwV50iv/CEiLNBT23f/3J44wrQzygqNQCiQSALdxWLAEl4l5kHSa\n9oMyV70/Uql94/ayMARZsHgp9ZvqQKbkZPw6yzVMfCBxQozlNlo315OHevudhnhp\nDRjN5I7zWmqYt6rbXJJC7Y3Izdvzn7QI88RqjSRST5I/7Kz3ndCqrOnI+OQUE5NT\nREyQebphvQfTDTKlRPXkdyktdK2DH28Zj6ZF3yjQvN35Q4zhOzlq77dO5IhhopI7\nct8dZH1T1nYkvdyCA/EVMtQsASmBOitH0Y0ACoXQK5Kb6nm/TcM/9ZSJUNiEMuy5\ngBZ3YKE9oa4cpTpPXwcA+S/cU7HPNnQAsvD3iJi8GTW9uJs84pn4/WhpQqmXd4rv\nhKWECCN3fHy01fUs/U0PaSj2jDY/kQVeXoikNMzPUjdZd9m816TIBh3v3aVXCH/0\niTHHAxctvDgMRb2fpvRJ/wwnYjFG9RpamVFDMvC9NffuYzWAA9IRIY4cqgerfHrV\nZ2HHiPTDDvDAIsvImXZc/h7mXN6m3RCQ4Qywy993wd9gUdgg/qnynHcCAwEAAQ==\n-----END RSA PUBLIC KEY-----\n", "public_key":"-----BEGIN RSA PUBLIC KEY-----\nMIICCgKCAgEAw2pdG6wMtuLcP0+k1LFvIb0DQo/oHW2uNJaEJK74plXqp4ztz2dR\nb+RQHFLeLuqk4i/zc3b4K3fKPXSlwnVPJCwzPrnyT8jYGOZVlWlETiV9xeJhu6s/\nBh6g1PWz75XjjwV50iv/CEiLNBT23f/3J44wrQzygqNQCiQSALdxWLAEl4l5kHSa\n9oMyV70/Uql94/ayMARZsHgp9ZvqQKbkZPw6yzVMfCBxQozlNlo315OHevudhnhp\nDRjN5I7zWmqYt6rbXJJC7Y3Izdvzn7QI88RqjSRST5I/7Kz3ndCqrOnI+OQUE5NT\nREyQebphvQfTDTKlRPXkdyktdK2DH28Zj6ZF3yjQvN35Q4zhOzlq77dO5IhhopI7\nct8dZH1T1nYkvdyCA/EVMtQsASmBOitH0Y0ACoXQK5Kb6nm/TcM/9ZSJUNiEMuy5\ngBZ3YKE9oa4cpTpPXwcA+S/cU7HPNnQAsvD3iJi8GTW9uJs84pn4/WhpQqmXd4rv\nhKWECCN3fHy01fUs/U0PaSj2jDY/kQVeXoikNMzPUjdZd9m816TIBh3v3aVXCH/0\niTHHAxctvDgMRb2fpvRJ/wwnYjFG9RpamVFDMvC9NffuYzWAA9IRIY4cqgerfHrV\nZ2HHiPTDDvDAIsvImXZc/h7mXN6m3RCQ4Qywy993wd9gUdgg/qnynHcCAwEAAQ==\n-----END RSA PUBLIC KEY-----\n",
"state":2, "state":1,
"relation": 1 "relation": 2
}, { }, {
"_id":"6a3fc74d-8c06-4dbb-ad11-d5c53562775b", "_id":"6a3fc74d-8c06-4dbb-ad11-d5c53562775b",
"failed_execution":null, "failed_execution":null,
@@ -19,7 +19,7 @@
"id":"6a3fc74d-8c06-4dbb-ad11-d5c53562775b", "id":"6a3fc74d-8c06-4dbb-ad11-d5c53562775b",
"name":"local","is_draft":false, "name":"local","is_draft":false,
"creation_date":{"$date":"2025-03-27T09:13:13.230Z"}}, "creation_date":{"$date":"2025-03-27T09:13:13.230Z"}},
"url":"http://192.168.1.2", "url":"http://beta.opencloud.com:9700",
"wallet_address":"my-wallet", "wallet_address":"my-wallet",
"public_key":"-----BEGIN RSA PUBLIC KEY-----\nMIICCgKCAgEAw2pdG6wMtuLcP0+k1LFvIb0DQo/oHW2uNJaEJK74plXqp4ztz2dR\nb+RQHFLeLuqk4i/zc3b4K3fKPXSlwnVPJCwzPrnyT8jYGOZVlWlETiV9xeJhu6s/\nBh6g1PWz75XjjwV50iv/CEiLNBT23f/3J44wrQzygqNQCiQSALdxWLAEl4l5kHSa\n9oMyV70/Uql94/ayMARZsHgp9ZvqQKbkZPw6yzVMfCBxQozlNlo315OHevudhnhp\nDRjN5I7zWmqYt6rbXJJC7Y3Izdvzn7QI88RqjSRST5I/7Kz3ndCqrOnI+OQUE5NT\nREyQebphvQfTDTKlRPXkdyktdK2DH28Zj6ZF3yjQvN35Q4zhOzlq77dO5IhhopI7\nct8dZH1T1nYkvdyCA/EVMtQsASmBOitH0Y0ACoXQK5Kb6nm/TcM/9ZSJUNiEMuy5\ngBZ3YKE9oa4cpTpPXwcA+S/cU7HPNnQAsvD3iJi8GTW9uJs84pn4/WhpQqmXd4rv\nhKWECCN3fHy01fUs/U0PaSj2jDY/kQVeXoikNMzPUjdZd9m816TIBh3v3aVXCH/0\niTHHAxctvDgMRb2fpvRJ/wwnYjFG9RpamVFDMvC9NffuYzWAA9IRIY4cqgerfHrV\nZ2HHiPTDDvDAIsvImXZc/h7mXN6m3RCQ4Qywy993wd9gUdgg/qnynHcCAwEAAQ==\n-----END RSA PUBLIC KEY-----\n", "public_key":"-----BEGIN RSA PUBLIC KEY-----\nMIICCgKCAgEAw2pdG6wMtuLcP0+k1LFvIb0DQo/oHW2uNJaEJK74plXqp4ztz2dR\nb+RQHFLeLuqk4i/zc3b4K3fKPXSlwnVPJCwzPrnyT8jYGOZVlWlETiV9xeJhu6s/\nBh6g1PWz75XjjwV50iv/CEiLNBT23f/3J44wrQzygqNQCiQSALdxWLAEl4l5kHSa\n9oMyV70/Uql94/ayMARZsHgp9ZvqQKbkZPw6yzVMfCBxQozlNlo315OHevudhnhp\nDRjN5I7zWmqYt6rbXJJC7Y3Izdvzn7QI88RqjSRST5I/7Kz3ndCqrOnI+OQUE5NT\nREyQebphvQfTDTKlRPXkdyktdK2DH28Zj6ZF3yjQvN35Q4zhOzlq77dO5IhhopI7\nct8dZH1T1nYkvdyCA/EVMtQsASmBOitH0Y0ACoXQK5Kb6nm/TcM/9ZSJUNiEMuy5\ngBZ3YKE9oa4cpTpPXwcA+S/cU7HPNnQAsvD3iJi8GTW9uJs84pn4/WhpQqmXd4rv\nhKWECCN3fHy01fUs/U0PaSj2jDY/kQVeXoikNMzPUjdZd9m816TIBh3v3aVXCH/0\niTHHAxctvDgMRb2fpvRJ/wwnYjFG9RpamVFDMvC9NffuYzWAA9IRIY4cqgerfHrV\nZ2HHiPTDDvDAIsvImXZc/h7mXN6m3RCQ4Qywy993wd9gUdgg/qnynHcCAwEAAQ==\n-----END RSA PUBLIC KEY-----\n",
"state":1, "state":1,