Files
Dušan Borovčanin 09a56575c1
Property Based Tests / api-test (push) Has been cancelled
Continuous Delivery / lint-and-build (push) Has been cancelled
Deploy GitHub Pages / swagger-ui (push) Has been cancelled
CI Pipeline / Lint Proto (push) Has been cancelled
CI Pipeline / Detect Changes (push) Has been cancelled
Continuous Delivery / Build and Push Docker Images (push) Has been cancelled
CI Pipeline / lint-and-build (push) Has been cancelled
CI Pipeline / Test ${{ matrix.module }} (push) Has been cancelled
CI Pipeline / Upload Coverage (push) Has been cancelled
NOISSUE - Use Atom access tokens (#3540)
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2026-07-01 19:41:01 +02:00

148 lines
3.7 KiB
Go

// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package main
import (
"bufio"
"encoding/base64"
"fmt"
"os"
"strings"
)
// dbConn is one source/target Postgres connection target.
type dbConn struct {
Host string
Port string
User string
Pass string
Name string
SSL string
}
func (d dbConn) DSN() string {
ssl := d.SSL
if ssl == "" {
ssl = "disable"
}
return fmt.Sprintf("host=%s port=%s user=%s password=%s dbname=%s sslmode=%s",
d.Host, d.Port, d.User, d.Pass, d.Name, ssl)
}
// config holds every source DB plus the Atom target DSN.
type config struct {
Domains dbConn
Users dbConn
Clients dbConn
Channels dbConn
Groups dbConn
Auth dbConn
RE dbConn // rules engine
Reports dbConn
AtomDSN string
UnmappedAction string
AtomKeyEncryptionKey []byte
AtomKeyEncryptionKeyID string
}
// loadConfig reads docker/.env for MG_*_DB_* keys. When fromHost is true the
// service-name hosts are rewritten to 127.0.0.1 with the mapped host port (the
// caller is then responsible for exposing those ports in compose).
func loadConfig(envPath, atomDSN string, fromHost bool) (config, error) {
env, err := parseEnvFile(envPath)
if err != nil {
return config{}, err
}
mk := func(prefix string) dbConn {
c := dbConn{
Host: env[prefix+"_DB_HOST"],
Port: orDef(env[prefix+"_DB_PORT"], "5432"),
User: orDef(env[prefix+"_DB_USER"], "magistrala"),
Pass: orDef(env[prefix+"_DB_PASS"], "magistrala"),
Name: env[prefix+"_DB_NAME"],
SSL: orDef(env[prefix+"_DB_SSL_MODE"], "disable"),
}
if fromHost {
c.Host = "127.0.0.1"
}
return c
}
cfg := config{
Domains: mk("MG_DOMAINS"),
Users: mk("MG_USERS"),
Clients: mk("MG_CLIENTS"),
Channels: mk("MG_CHANNELS"),
Groups: mk("MG_GROUPS"),
Auth: mk("MG_AUTH"),
RE: mk("MG_RE"),
Reports: mk("MG_REPORTS"),
AtomDSN: atomDSN,
}
if key := strings.TrimSpace(firstNonEmpty(env["ATOM_KEY_ENCRYPTION_KEY"], os.Getenv("ATOM_KEY_ENCRYPTION_KEY"))); key != "" {
decoded, err := base64.StdEncoding.DecodeString(key)
if err != nil {
return config{}, fmt.Errorf("ATOM_KEY_ENCRYPTION_KEY must be base64 encoded: %w", err)
}
if len(decoded) != 32 {
return config{}, fmt.Errorf("ATOM_KEY_ENCRYPTION_KEY must decode to exactly 32 bytes")
}
cfg.AtomKeyEncryptionKey = decoded
}
cfg.AtomKeyEncryptionKeyID = orDef(strings.TrimSpace(firstNonEmpty(env["ATOM_KEY_ENCRYPTION_KEY_ID"], os.Getenv("ATOM_KEY_ENCRYPTION_KEY_ID"))), "local:v1")
// Default names if .env omitted them.
defName := map[*string]string{
&cfg.Domains.Name: collectionDomains, &cfg.Users.Name: "users",
&cfg.Clients.Name: "clients", &cfg.Channels.Name: "channels",
&cfg.Groups.Name: collectionGroups, &cfg.Auth.Name: "auth",
&cfg.RE.Name: "rules_engine", &cfg.Reports.Name: "reports",
}
for p, n := range defName {
if *p == "" {
*p = n
}
}
if cfg.AtomDSN == "" {
// Fall back to Atom compose defaults; override with --atom-dsn or
// ATOM_DATABASE_URL for real runs.
cfg.AtomDSN = "host=127.0.0.1 port=5432 user=atom password=atom dbname=atom sslmode=disable"
}
return cfg, nil
}
func parseEnvFile(path string) (map[string]string, error) {
f, err := os.Open(path)
if err != nil {
return nil, fmt.Errorf("open %s: %w", path, err)
}
defer f.Close()
out := map[string]string{}
sc := bufio.NewScanner(f)
for sc.Scan() {
line := strings.TrimSpace(sc.Text())
if line == "" || strings.HasPrefix(line, "#") {
continue
}
k, v, ok := strings.Cut(line, "=")
if !ok {
continue
}
out[strings.TrimSpace(k)] = strings.Trim(strings.TrimSpace(v), `"'`)
}
return out, sc.Err()
}
func orDef(v, def string) string {
if v == "" {
return def
}
return v
}