@paakd/config 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/index.js +20 -0
- package/gen/go/addresses/Address.pkl.go +10 -0
- package/gen/go/addresses/Addresses.pkl.go +43 -0
- package/gen/go/addresses/BillingAddress.pkl.go +8 -0
- package/gen/go/addresses/Field.pkl.go +43 -0
- package/gen/go/addresses/addressgroup/AddressGroup.pkl.go +43 -0
- package/gen/go/addresses/fieldtype/FieldType.pkl.go +61 -0
- package/gen/go/addresses/init.pkl.go +11 -0
- package/gen/go/cloudflare/Cloudflare.pkl.go +37 -0
- package/gen/go/cloudflare/R2Bucket.pkl.go +22 -0
- package/gen/go/cloudflare/TerraformBackend.pkl.go +16 -0
- package/gen/go/cloudflare/Turnstile.pkl.go +8 -0
- package/gen/go/cloudflare/init.pkl.go +11 -0
- package/gen/go/db/DB.pkl.go +43 -0
- package/gen/go/db/DBConnection.pkl.go +12 -0
- package/gen/go/db/init.pkl.go +9 -0
- package/gen/go/dune/Dune.pkl.go +47 -0
- package/gen/go/dune/init.pkl.go +8 -0
- package/gen/go/enterprise/Enterprise.pkl.go +118 -0
- package/gen/go/enterprise/init.pkl.go +8 -0
- package/gen/go/enterprise/taxonomyversion/TaxonomyVersion.pkl.go +37 -0
- package/gen/go/redis/Redis.pkl.go +41 -0
- package/gen/go/redis/init.pkl.go +8 -0
- package/gen/go/shared/Build.pkl.go +46 -0
- package/gen/go/shared/Shared.pkl.go +35 -0
- package/gen/go/shared/init.pkl.go +9 -0
- package/gen/go/worker/Worker.pkl.go +55 -0
- package/gen/go/worker/WorkerConnect.pkl.go +6 -0
- package/gen/go/worker/init.pkl.go +9 -0
- package/gen/js/development/basket_eco_packages_config_addresses.pkl.ts +106 -0
- package/gen/js/development/basket_eco_packages_config_checkout.pkl.ts +73 -0
- package/gen/js/development/basket_eco_packages_config_cloudflare.pkl.ts +69 -0
- package/gen/js/development/basket_eco_packages_config_cms.pkl.ts +119 -0
- package/gen/js/development/basket_eco_packages_config_db.pkl.ts +47 -0
- package/gen/js/development/basket_eco_packages_config_dune.pkl.ts +36 -0
- package/gen/js/development/basket_eco_packages_config_enterprise.pkl.ts +290 -0
- package/gen/js/development/basket_eco_packages_config_feature.pkl.ts +58 -0
- package/gen/js/development/basket_eco_packages_config_redis.pkl.ts +30 -0
- package/gen/js/development/basket_eco_packages_config_renderer_development_cms.pkl.ts +28 -0
- package/gen/js/development/basket_eco_packages_config_shared.pkl.ts +73 -0
- package/gen/js/development/basket_eco_packages_config_worker.pkl.ts +53 -0
- package/gen/js/production/basket_eco_packages_config_addresses.pkl.ts +106 -0
- package/gen/js/production/basket_eco_packages_config_checkout.pkl.ts +73 -0
- package/gen/js/production/basket_eco_packages_config_cloudflare.pkl.ts +69 -0
- package/gen/js/production/basket_eco_packages_config_cms.pkl.ts +119 -0
- package/gen/js/production/basket_eco_packages_config_db.pkl.ts +47 -0
- package/gen/js/production/basket_eco_packages_config_dune.pkl.ts +36 -0
- package/gen/js/production/basket_eco_packages_config_enterprise.pkl.ts +290 -0
- package/gen/js/production/basket_eco_packages_config_feature.pkl.ts +58 -0
- package/gen/js/production/basket_eco_packages_config_kiosk_host.pkl.ts +72 -0
- package/gen/js/production/basket_eco_packages_config_redis.pkl.ts +30 -0
- package/gen/js/production/basket_eco_packages_config_renderer_production_cms.pkl.ts +28 -0
- package/gen/js/production/basket_eco_packages_config_renderer_production_dune_config.pkl.ts +29 -0
- package/gen/js/production/basket_eco_packages_config_renderer_production_workflow_config.pkl.ts +29 -0
- package/gen/js/production/basket_eco_packages_config_renderer_staging_dune_config.pkl.ts +29 -0
- package/gen/js/production/basket_eco_packages_config_shared.pkl.ts +73 -0
- package/gen/js/production/basket_eco_packages_config_worker.pkl.ts +49 -0
- package/gen/js/staging/basket_eco_packages_config_addresses.pkl.ts +106 -0
- package/gen/js/staging/basket_eco_packages_config_checkout.pkl.ts +77 -0
- package/gen/js/staging/basket_eco_packages_config_cloudflare.pkl.ts +74 -0
- package/gen/js/staging/basket_eco_packages_config_cms.pkl.ts +119 -0
- package/gen/js/staging/basket_eco_packages_config_db.pkl.ts +47 -0
- package/gen/js/staging/basket_eco_packages_config_dune.pkl.ts +40 -0
- package/gen/js/staging/basket_eco_packages_config_enterprise.pkl.ts +290 -0
- package/gen/js/staging/basket_eco_packages_config_feature.pkl.ts +58 -0
- package/gen/js/staging/basket_eco_packages_config_redis.pkl.ts +30 -0
- package/gen/js/staging/basket_eco_packages_config_renderer_staging_cms.pkl.ts +28 -0
- package/gen/js/staging/basket_eco_packages_config_renderer_staging_dune_config.pkl.ts +29 -0
- package/gen/js/staging/basket_eco_packages_config_renderer_staging_workflow_config.pkl.ts +29 -0
- package/gen/js/staging/basket_eco_packages_config_shared.pkl.ts +69 -0
- package/gen/js/staging/basket_eco_packages_config_worker.pkl.ts +53 -0
- package/package.json +66 -0
- package/src/addresses.ts +90 -0
- package/src/authorization/policy.conf +15 -0
- package/src/authorization/policy.csv +26 -0
- package/src/chk.spec.ts +61 -0
- package/src/chk.ts +88 -0
- package/src/cms.test.ts +52 -0
- package/src/cms.ts +65 -0
- package/src/index.ts +4 -0
- package/src/pkl/PklProject +21 -0
- package/src/pkl/development/Addresses.pkl +2114 -0
- package/src/pkl/development/CMS.pkl +37 -0
- package/src/pkl/development/Checkout.pkl +32 -0
- package/src/pkl/development/Cloudflare.pkl +20 -0
- package/src/pkl/development/Db.pkl +14 -0
- package/src/pkl/development/Dune.pkl +12 -0
- package/src/pkl/development/Enterprise.pkl +158 -0
- package/src/pkl/development/Feature.pkl +4 -0
- package/src/pkl/development/Redis.pkl +6 -0
- package/src/pkl/development/Shared.pkl +16 -0
- package/src/pkl/development/Worker.pkl +43 -0
- package/src/pkl/development/renderer/CMS.pkl +59 -0
- package/src/pkl/production/Addresses.pkl +2114 -0
- package/src/pkl/production/CMS.pkl +34 -0
- package/src/pkl/production/Checkout.pkl +32 -0
- package/src/pkl/production/Cloudflare.pkl +20 -0
- package/src/pkl/production/Db.pkl +14 -0
- package/src/pkl/production/Dune.pkl +12 -0
- package/src/pkl/production/Enterprise.pkl +158 -0
- package/src/pkl/production/Feature.pkl +8 -0
- package/src/pkl/production/KioskHost.pkl +5 -0
- package/src/pkl/production/Redis.pkl +6 -0
- package/src/pkl/production/Shared.pkl +15 -0
- package/src/pkl/production/Worker.pkl +43 -0
- package/src/pkl/production/renderer/CMS.pkl +59 -0
- package/src/pkl/production/renderer/Dune.pkl +52 -0
- package/src/pkl/production/renderer/Feature.pkl +51 -0
- package/src/pkl/production/renderer/Workflow.pkl +51 -0
- package/src/pkl/staging/Addresses.pkl +2114 -0
- package/src/pkl/staging/CMS.pkl +35 -0
- package/src/pkl/staging/Checkout.pkl +32 -0
- package/src/pkl/staging/Cloudflare.pkl +20 -0
- package/src/pkl/staging/Db.pkl +14 -0
- package/src/pkl/staging/Dune.pkl +12 -0
- package/src/pkl/staging/Enterprise.pkl +158 -0
- package/src/pkl/staging/Feature.pkl +8 -0
- package/src/pkl/staging/Redis.pkl +6 -0
- package/src/pkl/staging/Shared.pkl +16 -0
- package/src/pkl/staging/Worker.pkl +43 -0
- package/src/pkl/staging/renderer/CMS.pkl +59 -0
- package/src/pkl/staging/renderer/Dune.pkl +52 -0
- package/src/pkl/staging/renderer/Feature.pkl +51 -0
- package/src/pkl/staging/renderer/Workflow.pkl +51 -0
- package/src/pkl/tmpl/AddressesTmpl.pkl +44 -0
- package/src/pkl/tmpl/CMSTmpl.pkl +64 -0
- package/src/pkl/tmpl/CheckoutTmpl.pkl +34 -0
- package/src/pkl/tmpl/CloudflareTmpl.pkl +33 -0
- package/src/pkl/tmpl/DbTmpl.pkl +18 -0
- package/src/pkl/tmpl/DuneTmpl.pkl +124 -0
- package/src/pkl/tmpl/EnterpriseTmpl.pkl +105 -0
- package/src/pkl/tmpl/FeatureTmpl.pkl +90 -0
- package/src/pkl/tmpl/KioskHostTmpl.pkl +194 -0
- package/src/pkl/tmpl/RedisTmpl.pkl +9 -0
- package/src/pkl/tmpl/SharedTmpl.pkl +40 -0
- package/src/pkl/tmpl/WorkerTmpl.pkl +27 -0
- package/src/pkl-reader/main.go +167 -0
- package/src/shared.ts +65 -0
- package/src/vault.spec.ts +62 -0
- package/src/vault.ts +68 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
@go.Package { name = "paakd.com/packages/config/gen/go/shared" }
|
|
2
|
+
module paakd.com.packages.config.Shared
|
|
3
|
+
|
|
4
|
+
import "package://pkg.pkl-lang.org/pkl-go/pkl.golang@0.12.1#/go.pkl"
|
|
5
|
+
|
|
6
|
+
class Build {
|
|
7
|
+
enterpriseEnv: String
|
|
8
|
+
envPath: String
|
|
9
|
+
hidden envFileContent:Mapping = read*(envPath)
|
|
10
|
+
hidden envData = envFileContent[envPath].text.split("\n").map((it) -> it.split("=")).toMap((it) -> it[0].trim(), (it) -> if (it.length == 2) it[1].trim() else "")
|
|
11
|
+
const binUser: String = "owe"
|
|
12
|
+
const binUserGroup: String = "kiosk"
|
|
13
|
+
const binUserId: UInt16 = 10001
|
|
14
|
+
certPath: String
|
|
15
|
+
const serviceDomainName: String = "shofluent.com"
|
|
16
|
+
vaultUrl: String = "https://vault.shofluent.xyz"
|
|
17
|
+
goEnv: String
|
|
18
|
+
nodeEnv: String
|
|
19
|
+
shopId: String = envData.getOrNull("SHOP_ID")
|
|
20
|
+
hidden vaultToken: String = envData.getOrNull("VAULT_TOKEN")
|
|
21
|
+
tenant: String = "\(shopId).\(serviceDomainName)"
|
|
22
|
+
envFilePath: String
|
|
23
|
+
shopBucketName: String = "shop-bucket-\(shopId)"
|
|
24
|
+
const productTaxonomyIndexBucket: String = "taxonomy-index"
|
|
25
|
+
fixed apiVersion: String = "v0.1"
|
|
26
|
+
|
|
27
|
+
envFile: String
|
|
28
|
+
version: String
|
|
29
|
+
storefrontHost: String
|
|
30
|
+
storefrontPort: UInt16
|
|
31
|
+
secureCookiePassword: String
|
|
32
|
+
|
|
33
|
+
function getAssetsDomain(): String = "assets.\(shopId).\(serviceDomainName)"
|
|
34
|
+
function getAssetsURL():String = "https://\(getAssetsDomain())"
|
|
35
|
+
function shopVaultEnvPath(val: String): String = "vault:\(vaultToken)~shops/\(shopId)/env~\(val)"
|
|
36
|
+
function shopVaultThirdpartyPath(val: String): String = "vault:\(vaultToken)~services/third_party~\(val)"
|
|
37
|
+
function shopVaultInternalEnvPath(val: String): String = "vault:\(vaultToken)~shops/\(shopId)/internal/env~\(val)"
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
build: Build
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
@go.Package { name = "paakd.com/packages/config/gen/go/worker" }
|
|
2
|
+
module paakd.com.packages.config.Worker
|
|
3
|
+
|
|
4
|
+
import "package://pkg.pkl-lang.org/pkl-go/pkl.golang@0.12.1#/go.pkl"
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class WorkerConnect {
|
|
8
|
+
endpoint: String
|
|
9
|
+
hidden user: String
|
|
10
|
+
hidden password: String
|
|
11
|
+
local baseValue: String = "\(user):\(password)".base64
|
|
12
|
+
|
|
13
|
+
function getBasicAuth(): String = "Basic \(baseValue)"
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
breeze:WorkerConnect
|
|
17
|
+
orchestrator:WorkerConnect
|
|
18
|
+
mesh:WorkerConnect
|
|
19
|
+
tfState:WorkerConnect
|
|
20
|
+
tfStateShopBackend:WorkerConnect
|
|
21
|
+
tfStateServiceBackend:WorkerConnect
|
|
22
|
+
tfStateHostsBackend:WorkerConnect
|
|
23
|
+
|
|
24
|
+
orchestratorAuth: String
|
|
25
|
+
shopBackendAuth: String
|
|
26
|
+
serviceBackendAuth: String
|
|
27
|
+
hostBackendAuth: String
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"errors"
|
|
5
|
+
"fmt"
|
|
6
|
+
"io"
|
|
7
|
+
"net/http"
|
|
8
|
+
"net/url"
|
|
9
|
+
"os"
|
|
10
|
+
"strings"
|
|
11
|
+
"sync"
|
|
12
|
+
"time"
|
|
13
|
+
|
|
14
|
+
"github.com/apple/pkl-go/pkl"
|
|
15
|
+
json_encoding "github.com/segmentio/encoding/json"
|
|
16
|
+
"go.uber.org/zap"
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
var (
|
|
20
|
+
VAULT_ADDR = os.Getenv("VAULT_ADDR")
|
|
21
|
+
VAULT_TOKEN = os.Getenv("VAULT_TOKEN")
|
|
22
|
+
CACHE_TTL_MIN = 15 * time.Minute
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
type (
|
|
26
|
+
vaultReader struct {
|
|
27
|
+
logger *zap.Logger
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
ResStore struct {
|
|
31
|
+
Data map[string]map[string]interface{}
|
|
32
|
+
CreatedAt time.Time
|
|
33
|
+
sync.Mutex
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
VaultRes struct {
|
|
37
|
+
Data map[string]interface{} `json:"data"`
|
|
38
|
+
}
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
var (
|
|
42
|
+
_ pkl.ResourceReader = &vaultReader{logger: zap.NewNop()}
|
|
43
|
+
|
|
44
|
+
responseCache = ResStore{
|
|
45
|
+
Data: make(map[string]map[string]interface{}),
|
|
46
|
+
}
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
func main() {
|
|
50
|
+
if VAULT_ADDR == "" {
|
|
51
|
+
VAULT_ADDR = "https://vault.shofluent.xyz"
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
logger, _ := zap.NewDevelopment()
|
|
55
|
+
client, err := pkl.NewExternalReaderClient(pkl.WithExternalClientResourceReader(vaultReader{
|
|
56
|
+
logger: logger,
|
|
57
|
+
}))
|
|
58
|
+
if err != nil {
|
|
59
|
+
logger.Fatal("create pkl client", zap.Error(err))
|
|
60
|
+
}
|
|
61
|
+
if err := client.Run(); err != nil {
|
|
62
|
+
logger.Fatal("run pkl client", zap.Error(err))
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
func (r vaultReader) Scheme() string {
|
|
67
|
+
return "vault"
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
func (r vaultReader) HasHierarchicalUris() bool {
|
|
71
|
+
return false
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
func (r vaultReader) IsGlobbable() bool {
|
|
75
|
+
return false
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
func (r vaultReader) ListElements(baseURI url.URL) ([]pkl.PathElement, error) {
|
|
79
|
+
r.logger.Debug("vaultReader.ListElements", zap.String("baseURI", baseURI.String()))
|
|
80
|
+
return nil, nil
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
func (r vaultReader) makeAPICallToVault(vaultToken, path string) (map[string]interface{}, error) {
|
|
84
|
+
if VAULT_TOKEN == "" {
|
|
85
|
+
VAULT_TOKEN = vaultToken
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
var (
|
|
89
|
+
header = map[string]string{
|
|
90
|
+
"X-Vault-Token": VAULT_TOKEN,
|
|
91
|
+
}
|
|
92
|
+
url = VAULT_ADDR + "/v1/secret/data/" + path
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
responseCache.Lock()
|
|
96
|
+
defer responseCache.Unlock()
|
|
97
|
+
if data, found := responseCache.Data[url]; found && time.Since(responseCache.CreatedAt) < CACHE_TTL_MIN {
|
|
98
|
+
return data, nil
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
r.logger.Debug("vaultReader.makeAPICallToVault", zap.String("url", url))
|
|
102
|
+
req, err := http.NewRequest("GET", url, nil)
|
|
103
|
+
if err != nil {
|
|
104
|
+
r.logger.Error("create request", zap.Error(err))
|
|
105
|
+
return nil, err
|
|
106
|
+
}
|
|
107
|
+
for key, value := range header {
|
|
108
|
+
req.Header.Add(key, value)
|
|
109
|
+
}
|
|
110
|
+
client := &http.Client{}
|
|
111
|
+
resp, err := client.Do(req)
|
|
112
|
+
if err != nil {
|
|
113
|
+
r.logger.Error("make request", zap.Error(err))
|
|
114
|
+
return nil, err
|
|
115
|
+
}
|
|
116
|
+
defer func() { _ = resp.Body.Close() }()
|
|
117
|
+
if resp.StatusCode != http.StatusOK {
|
|
118
|
+
// ready body string
|
|
119
|
+
bodyBytes, _ := io.ReadAll(resp.Body)
|
|
120
|
+
r.logger.Error("get data from vault", zap.String("body", string(bodyBytes)))
|
|
121
|
+
return nil, fmt.Errorf("get data from vault %w", err)
|
|
122
|
+
}
|
|
123
|
+
var res VaultRes
|
|
124
|
+
if err := json_encoding.NewDecoder(resp.Body).Decode(&res); err != nil {
|
|
125
|
+
r.logger.Error("decode response", zap.Error(err))
|
|
126
|
+
return nil, err
|
|
127
|
+
}
|
|
128
|
+
if res.Data == nil {
|
|
129
|
+
r.logger.Error("no data found in vault")
|
|
130
|
+
return nil, errors.New("no data found in vault")
|
|
131
|
+
}
|
|
132
|
+
if data, ok := res.Data["data"].(map[string]interface{}); ok {
|
|
133
|
+
responseCache.Data[url] = data
|
|
134
|
+
responseCache.CreatedAt = time.Now()
|
|
135
|
+
return data, nil
|
|
136
|
+
} else {
|
|
137
|
+
return nil, errors.New("invalid data format")
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
func (r vaultReader) Read(uri url.URL) ([]byte, error) {
|
|
142
|
+
path := strings.Split(uri.Opaque, "~")
|
|
143
|
+
if len(path) != 3 {
|
|
144
|
+
r.logger.Error("invalid vault path", zap.String("path", uri.Opaque))
|
|
145
|
+
return nil, errors.New("invalid vault path")
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if os.Getenv("ENTERPRISE_ENV") == "docker" || os.Getenv("CI") != "" {
|
|
149
|
+
return []byte(path[2]), nil
|
|
150
|
+
}
|
|
151
|
+
data, err := r.makeAPICallToVault(path[0], path[1])
|
|
152
|
+
if err != nil {
|
|
153
|
+
r.logger.Error("read vault secret", zap.Error(err))
|
|
154
|
+
return nil, err
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
switch data[path[2]].(type) {
|
|
158
|
+
case string:
|
|
159
|
+
return []byte(data[path[2]].(string)), nil
|
|
160
|
+
case []byte:
|
|
161
|
+
return data[path[2]].([]byte), nil
|
|
162
|
+
case nil:
|
|
163
|
+
return nil, nil
|
|
164
|
+
default:
|
|
165
|
+
return nil, errors.New("invalid data type")
|
|
166
|
+
}
|
|
167
|
+
}
|
package/src/shared.ts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import * as pklTypescript from '@pkl-community/pkl-typescript'
|
|
2
|
+
import { load as devLoad } from '../gen/js/development/basket_eco_packages_config_shared.pkl'
|
|
3
|
+
import {
|
|
4
|
+
load as prodLoad,
|
|
5
|
+
type Shared,
|
|
6
|
+
} from '../gen/js/production/basket_eco_packages_config_shared.pkl'
|
|
7
|
+
import { load as stgLoad } from '../gen/js/staging/basket_eco_packages_config_shared.pkl'
|
|
8
|
+
import { vaultReader } from './vault'
|
|
9
|
+
|
|
10
|
+
export const getSharedConfig: () => Promise<Shared> = async () => {
|
|
11
|
+
const evaluator = await pklTypescript.newEvaluator({
|
|
12
|
+
allowedResources: [
|
|
13
|
+
'http:',
|
|
14
|
+
'https:',
|
|
15
|
+
'file:',
|
|
16
|
+
'env:',
|
|
17
|
+
'prop:',
|
|
18
|
+
'modulepath:',
|
|
19
|
+
'package:',
|
|
20
|
+
'projectpackage:',
|
|
21
|
+
'vault:',
|
|
22
|
+
],
|
|
23
|
+
allowedModules: [
|
|
24
|
+
'pkl:',
|
|
25
|
+
'repl:',
|
|
26
|
+
'file:',
|
|
27
|
+
'http:',
|
|
28
|
+
'https:',
|
|
29
|
+
'modulepath:',
|
|
30
|
+
'package:',
|
|
31
|
+
'projectpackage:',
|
|
32
|
+
],
|
|
33
|
+
projectDir: '../../packages/config/src/pkl/production',
|
|
34
|
+
declaredProjectDependencies: {
|
|
35
|
+
localDependencies: {},
|
|
36
|
+
remoteDependencies: {},
|
|
37
|
+
},
|
|
38
|
+
resourceReaders: [
|
|
39
|
+
{
|
|
40
|
+
scheme: 'vault',
|
|
41
|
+
isGlobbable: false,
|
|
42
|
+
hasHierarchicalUris: false,
|
|
43
|
+
listElements: (uri: URL): any => {
|
|
44
|
+
return []
|
|
45
|
+
},
|
|
46
|
+
read: vaultReader,
|
|
47
|
+
},
|
|
48
|
+
],
|
|
49
|
+
})
|
|
50
|
+
try {
|
|
51
|
+
let load = devLoad
|
|
52
|
+
let sourcePath = '../../packages/config/src/pkl/development/Shared.pkl'
|
|
53
|
+
if (process.env.BUILD_ENV === 'staging') {
|
|
54
|
+
load = stgLoad
|
|
55
|
+
sourcePath = '../../packages/config/src/pkl/staging/Shared.pkl'
|
|
56
|
+
} else if (process.env.BUILD_ENV === 'production') {
|
|
57
|
+
load = prodLoad
|
|
58
|
+
sourcePath = '../../packages/config/src/pkl/production/Shared.pkl'
|
|
59
|
+
}
|
|
60
|
+
const result = await load(evaluator, pklTypescript.FileSource(sourcePath))
|
|
61
|
+
return result
|
|
62
|
+
} finally {
|
|
63
|
+
evaluator.close()
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { vaultReader } from './vault'
|
|
2
|
+
|
|
3
|
+
describe('vaultReader', () => {
|
|
4
|
+
const OLD_ENV = process.env
|
|
5
|
+
|
|
6
|
+
beforeEach(() => {
|
|
7
|
+
process.env = { ...OLD_ENV }
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
afterEach(() => {
|
|
11
|
+
process.env = OLD_ENV
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
it('returns CI_ENVIRONMENT buffer in CI', async () => {
|
|
15
|
+
process.env.CI = '1'
|
|
16
|
+
const olVal = process.env.VITEST
|
|
17
|
+
delete process.env.VITEST // Ensure VITEST is not set
|
|
18
|
+
const uri = new URL('vault://dummy/vaultkey~datapath~field')
|
|
19
|
+
const result = await vaultReader(uri)
|
|
20
|
+
expect(Buffer.from(result).toString()).toBe('CI_ENVIRONMENT')
|
|
21
|
+
process.env.VITEST = olVal // Restore VITEST
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
it('returns empty Uint8Array for invalid path', async () => {
|
|
25
|
+
const uri = new URL('vault://dummy/vaultkey~datapath')
|
|
26
|
+
const result = await vaultReader(uri)
|
|
27
|
+
expect(result).toBeInstanceOf(Uint8Array)
|
|
28
|
+
expect(result.length).toBe(0)
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
it('returns empty Uint8Array for non-ok fetch', async () => {
|
|
32
|
+
global.fetch = vi.fn().mockResolvedValue({ ok: false, statusText: 'fail' })
|
|
33
|
+
const uri = new URL('vault://dummy/vaultkey~datapath~field')
|
|
34
|
+
delete process.env.CI
|
|
35
|
+
const result = await vaultReader(uri)
|
|
36
|
+
expect(result).toBeInstanceOf(Uint8Array)
|
|
37
|
+
expect(result.length).toBe(0)
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
it('returns empty Uint8Array for missing field', async () => {
|
|
41
|
+
global.fetch = vi.fn().mockResolvedValue({
|
|
42
|
+
ok: true,
|
|
43
|
+
json: async () => ({ data: { data: { other: 'value' } } }),
|
|
44
|
+
})
|
|
45
|
+
const uri = new URL('vault://dummy/vaultkey~datapath~field')
|
|
46
|
+
const result = await vaultReader(uri)
|
|
47
|
+
expect(result).toBeInstanceOf(Uint8Array)
|
|
48
|
+
expect(result.length).toBe(0)
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
it('returns decoded buffer for valid field', async () => {
|
|
52
|
+
global.fetch = vi.fn().mockResolvedValue({
|
|
53
|
+
ok: true,
|
|
54
|
+
json: async () => ({
|
|
55
|
+
data: { data: { field2: Buffer.from('hello').toString() } },
|
|
56
|
+
}),
|
|
57
|
+
})
|
|
58
|
+
const uri = new URL('vault://dummy/vaultkey2~datapath2~field2')
|
|
59
|
+
const result = await vaultReader(uri)
|
|
60
|
+
expect(Buffer.from(result).toString()).toBe('hello')
|
|
61
|
+
})
|
|
62
|
+
})
|
package/src/vault.ts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// Simple in-memory cache using a Map
|
|
2
|
+
export const vaultPathCache = new Map()
|
|
3
|
+
// const vaultPathCache = new Map<string, Uint8Array>();
|
|
4
|
+
export const vaultReader = async (uri: URL): Promise<Uint8Array> => {
|
|
5
|
+
// Remove leading slash if present
|
|
6
|
+
const cleanPath = uri.pathname.startsWith('/')
|
|
7
|
+
? uri.pathname.slice(1)
|
|
8
|
+
: uri.pathname
|
|
9
|
+
const path = cleanPath.split('~')
|
|
10
|
+
if (path.length !== 3) {
|
|
11
|
+
console.error(`Invalid vault path: ${uri}`)
|
|
12
|
+
return new Uint8Array()
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (process.env.CI && !process.env.VITEST) {
|
|
16
|
+
// In CI, we don't want to access the vault, so we return an empty Uint8Array
|
|
17
|
+
// This is useful for testing purposes where we don't want to hit the actual vault
|
|
18
|
+
console.warn('Skipping vault access in CI environment')
|
|
19
|
+
return new Uint8Array(Buffer.from('CI_ENVIRONMENT', 'utf-8'))
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const [vaultKey, dataPath, fieldName] = path
|
|
23
|
+
let resData = vaultPathCache.get(`${vaultKey}~${dataPath}`)
|
|
24
|
+
if (!resData || process.env.CI) {
|
|
25
|
+
const vaultAddr = process.env.VAULT_PATH || 'https://vault.shofluent.xyz'
|
|
26
|
+
const url = `${vaultAddr}/v1/secret/data/${dataPath}`
|
|
27
|
+
const headers = {
|
|
28
|
+
'X-Vault-Token': vaultKey,
|
|
29
|
+
'Content-Type': 'application/json',
|
|
30
|
+
Accept: 'application/json',
|
|
31
|
+
}
|
|
32
|
+
const res = await fetch(url, {
|
|
33
|
+
method: 'GET',
|
|
34
|
+
headers,
|
|
35
|
+
})
|
|
36
|
+
if (!res.ok) {
|
|
37
|
+
console.error(`fetch from vault: ${res.statusText}`)
|
|
38
|
+
return new Uint8Array()
|
|
39
|
+
}
|
|
40
|
+
const { data } = await res.json()
|
|
41
|
+
resData = data?.data
|
|
42
|
+
// Store value with timestamp for manual expiration
|
|
43
|
+
vaultPathCache.set(`${vaultKey}~${dataPath}`, {
|
|
44
|
+
value: resData,
|
|
45
|
+
expires: Date.now() + 15 * 60 * 1000, // 15 minutes
|
|
46
|
+
})
|
|
47
|
+
} else if (resData.expires && resData.expires < Date.now()) {
|
|
48
|
+
// Expired, remove and fetch again
|
|
49
|
+
vaultPathCache.delete(`${vaultKey}~${dataPath}`)
|
|
50
|
+
return vaultReader(uri) // Recursively re-fetch
|
|
51
|
+
} else {
|
|
52
|
+
resData = resData.value
|
|
53
|
+
}
|
|
54
|
+
if (!resData?.[fieldName]) {
|
|
55
|
+
console.error(
|
|
56
|
+
`Invalid data from vault: ${JSON.stringify(resData)}, ${Object.keys(resData)}`
|
|
57
|
+
)
|
|
58
|
+
return new Uint8Array()
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const fieldData = resData[fieldName]
|
|
62
|
+
if (typeof fieldData !== 'string') {
|
|
63
|
+
console.error(`Invalid field data from vault: ${JSON.stringify(fieldData)}`)
|
|
64
|
+
return new Uint8Array()
|
|
65
|
+
}
|
|
66
|
+
const decodedData = Buffer.from(fieldData)
|
|
67
|
+
return decodedData as Uint8Array
|
|
68
|
+
}
|