diff --git a/api/fs/fs.go b/api/fs/fs.go new file mode 100644 index 0000000..dbd7bfc --- /dev/null +++ b/api/fs/fs.go @@ -0,0 +1,52 @@ +package fs + +import ( + "io/fs" + "os" + "path/filepath" +) + +func DiscoverFiles(paths []string, ext string) ([]string, error) { + var files []string + + for _, path := range paths { + pathFiles, err := listFiles(path, ext) + if err != nil { + return nil, err + } + files = append(files, pathFiles...) + } + + return files, nil +} + +func listFiles(path string, ext string) ([]string, error) { + var files []string + err := filepath.WalkDir(path, func(file string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + + match, err := filepath.Match(ext, filepath.Ext(d.Name())) + if err != nil { + return err + } + if match { + files = append(files, file) + } + + return nil + }) + if err != nil { + return nil, err + } + return files, nil +} + +func WriteFile(file string, bytes []byte) error { + err := os.WriteFile("/tmp/dat1", bytes, 0644) + if err != nil { + return err + } + return nil +} diff --git a/api/kv/encrypted.go b/api/kv/encrypted.go new file mode 100644 index 0000000..2d2158e --- /dev/null +++ b/api/kv/encrypted.go @@ -0,0 +1,86 @@ +package kv + +import ( + "dsl/api/security" + "errors" +) + +type EncryptedKV struct { + kv KV + encryption security.Encryption +} + +func NewEncryptedKV(kv KV, encryption security.Encryption) *EncryptedKV { + return &EncryptedKV{ + kv: kv, + encryption: encryption, + } +} + +func (v *EncryptedKV) Get(key string) (string, error) { + encrypted, err := v.kv.Get(key) + if errors.Is(err, KVKeyNotExistsError{}) { + return "", NewKVKeyNotExistsError(key) + } else if err != nil { + return "", err + } + + decrypted, err := v.Decrypt([]byte(encrypted)) + if err != nil { + return "", err + } + return string(decrypted), nil +} + +func (v *EncryptedKV) Set(key, value string) error { + var encrypted = []byte("") + var err error + + if value != "" { + // validation hook isAgeArmor + // NewAlreadyEncryptedError + if encrypted, err = v.Encrypt([]byte(value)); err != nil { + return err + } + } + + if err = v.kv.Set(key, string(encrypted)); err != nil { + return err + } + return nil +} + +func (v *EncryptedKV) GetBatch(keys []string) (KV, error) { + kv, err := v.kv.GetBatch(keys) + if err != nil { + return nil, err + } + return kv, nil +} + +func (v *EncryptedKV) SetBatch(kv KV) error { + if err := v.kv.SetBatch(kv); err != nil { + return err + } + return nil +} + +func (v *EncryptedKV) GetKeys() []string { + return v.GetKeys() +} + +func (v *EncryptedKV) Encrypt(data []byte) ([]byte, error) { + encrypted, err := v.encryption.Encrypt(data) + if err != nil { + return nil, err + } + return encrypted, nil +} + +func (v *EncryptedKV) Decrypt(data []byte) ([]byte, error) { + decrypted, err := v.encryption.Decrypt(data) + if err != nil { + return nil, err + } + return decrypted, nil +} diff --git a/api/kv/kv.go b/api/kv/kv.go new file mode 100644 index 0000000..b4a76d6 --- /dev/null +++ b/api/kv/kv.go @@ -0,0 +1,35 @@ +package kv + +import ( + "dsl/api/security" + "fmt" +) + +type KV interface { + Get(key string) (string, error) + Set(key, value string) error + GetBatch(keys []string) (KV, error) + SetBatch(kv KV) error + GetKeys() []string +} + +type SealedKV interface { + KV + security.Encryption +} + +// Defenition of kv errors +// KVKeyNotExistsError +type KVKeyNotExistsError struct { + key string +} + +func NewKVKeyNotExistsError(key string) KVKeyNotExistsError { + return KVKeyNotExistsError{ + key: key, + } +} + +func (e KVKeyNotExistsError) Error() string { + return fmt.Sprintf("kv key '%s' not exists", e.key) +} diff --git a/api/kv/plain.go b/api/kv/plain.go new file mode 100644 index 0000000..d5809c4 --- /dev/null +++ b/api/kv/plain.go @@ -0,0 +1,95 @@ +package kv + +import ( + "fmt" +) + +type PlainKV struct { + kv map[string]string + AllowOverride bool +} + +type Opts func(kv *PlainKV) + +func OptOverride(kv *PlainKV) { + kv.AllowOverride = true +} + +func DefaultOpts(kv *PlainKV) { + kv.kv = make(map[string]string) + kv.AllowOverride = false +} + +func NewPlainKV(opts ...Opts) *PlainKV { + var kv *PlainKV + DefaultOpts(kv) + for _, setOpt := range opts { + setOpt(kv) + } + return kv +} + +func PlainKVFromMap(fromMap map[string]string, opts ...Opts) KV { + kv := &PlainKV{kv: fromMap} + for _, setOpt := range opts { + setOpt(kv) + } + return kv +} + +func (p *PlainKV) Get(key string) (string, error) { + kv, exists := p.kv[key] + if !exists { + return "", NewKVKeyNotExistsError(key) + } + return kv, nil +} + +func (p *PlainKV) Set(key string, value string) error { + if value == "" { + delete(p.kv, key) + } + if valueKV, exists := p.kv[key]; exists && valueKV != value && !p.AllowOverride { + return fmt.Errorf("key '%s' in KV with defferent value assignment found. Overriding prohibited by opt", key) + } + p.kv[key] = value + return nil +} + +func (p *PlainKV) GetBatch(keys []string) (KV, error) { + var kv PlainKV + for _, key := range keys { + val, err := p.Get(key) + if err != nil { + return nil, err + } + if err := kv.Set(key, val); err != nil { + return nil, err + } + } + return &kv, nil +} + +func (p *PlainKV) SetBatch(kv KV) error { + for _, key := range kv.GetKeys() { + val, err := kv.Get(key) + if err != nil { + return err + } + if err := p.Set(key, val); err != nil { + return err + } + } + + return nil +} + +func (p *PlainKV) GetKeys() []string { + keys := make([]string, len(p.kv)) + i := 0 + for key := range p.kv { + keys[i] = key + i++ + } + return keys +} diff --git a/api/launchr/global.go b/api/launchr/global.go new file mode 100644 index 0000000..7aaa478 --- /dev/null +++ b/api/launchr/global.go @@ -0,0 +1,7 @@ +package launchr + +const ( + CmdOutDefault = true + CmdSilentDefault = false + CmdManifestExtDefault = ".yaml" +) diff --git a/api/launchr/secret.go b/api/launchr/secret.go new file mode 100644 index 0000000..fb70450 --- /dev/null +++ b/api/launchr/secret.go @@ -0,0 +1,253 @@ +package launchr + +import ( + "dsl/api/security" + "dsl/service" + "errors" + "fmt" + "github.com/launchrctl/launchr" +) + +const ( + CmdSecretExtDefault = ".yaml" + CmdSecretInteractiveDefault = false + CmdSecretEncryptionDefault = true +) + +func NewCmdSecretGet(cmd *launchr.Command, args []string) error { + if len(args) == 0 { + return errors.New("no manifests provided") + } + + key, err := cmd.Flags().GetString("key") + if err != nil { + return err + } + if key == "" { + return errors.New("no key provided") + } + + cmd.SilenceUsage, err = cmd.Flags().GetBool("help") + if err != nil { + return err + } + + out, err := cmd.Flags().GetBool("out") + if err != nil { + return err + } + + ext, err := cmd.Flags().GetString("ext") + if err != nil { + return err + } + + encryption, err := cmd.Flags().GetBool("encryption") + if err != nil { + return err + } + + var manifests service.ManifestService + + var encrypt security.Encryption + + if encryption { + privKey, err := cmd.Flags().GetString("privkey") + if err != nil { + return err + } + if privKey == "" { + return errors.New("no privKey provided") + } + + pubKey, err := cmd.Flags().GetString("pubkey") + if err != nil { + return err + } + if pubKey == "" { + return errors.New("no pubKey provided") + } + + encrypt, err = security.NewAgeKeyPair(privKey, pubKey) + if err != nil { + panic(err) + } + } + + if err := manifests.ReadManifestFiles(args, ext); err != nil { + return fmt.Errorf("error reading manifests: %v\n", err) + } + + secret, err := manifests.GetSecret(key, encrypt) + if err != nil { + return err + } + + if out { + cmd.Println(secret) + } + + return nil +} + +func NewCmdSecretSet(cmd *launchr.Command, args []string) error { + if len(args) == 0 { + return errors.New("no manifests provided") + } + + key, err := cmd.Flags().GetString("key") + if err != nil { + return err + } + if key == "" { + return errors.New("no key provided") + } + + secret, err := cmd.Flags().GetString("secret") + if err != nil { + return err + } + if secret == "" { + return fmt.Errorf("no value value provided for key '%s'", key) + } + + out, err := cmd.Flags().GetBool("out") + if err != nil { + return err + } + + ext, err := cmd.Flags().GetString("ext") + if err != nil { + return err + } + + cmd.SilenceUsage, err = cmd.Flags().GetBool("help") + if err != nil { + return err + } + + encryption, err := cmd.Flags().GetBool("encryption") + if err != nil { + return err + } + + var manifests service.ManifestService + + var encrypt security.Encryption + + if encryption { + privKey, err := cmd.Flags().GetString("privkey") + if err != nil { + return err + } + if privKey == "" { + return errors.New("no privKey provided") + } + + pubKey, err := cmd.Flags().GetString("pubkey") + if err != nil { + return err + } + if pubKey == "" { + return errors.New("no pubKey provided") + } + + encrypt, err = security.NewAgeKeyPair(privKey, pubKey) + if err != nil { + panic(err) + } + } + + save := true + + if err := manifests.ReadManifestFiles(args, ext); err != nil { + return fmt.Errorf("Error reading manifests: %v\n", err) + } + + if err := manifests.SetSecret(key, secret, encrypt, save); err != nil { + return err + } + + if out { + cmd.Println(secret) + } + + return nil +} + +func NewCmdSecretList(cmd *launchr.Command, args []string) error { + if len(args) == 0 { + return errors.New("no manifests provided") + } + + keys, err := cmd.Flags().GetStringArray("keys") + if err != nil { + return err + } + if len(keys) == 0 { + return errors.New("no keys provided") + } + + cmd.SilenceUsage, err = cmd.Flags().GetBool("help") + if err != nil { + return err + } + + out, err := cmd.Flags().GetBool("out") + if err != nil { + return err + } + + ext, err := cmd.Flags().GetString("ext") + if err != nil { + return err + } + + encryption, err := cmd.Flags().GetBool("encryption") + if err != nil { + return err + } + + var manifests service.ManifestService + + var encrypt security.Encryption + + if encryption { + privKey, err := cmd.Flags().GetString("privkey") + if err != nil { + return err + } + if privKey == "" { + return errors.New("no privKey provided") + } + + pubKey, err := cmd.Flags().GetString("pubkey") + if err != nil { + return err + } + if pubKey == "" { + return errors.New("no pubKey provided") + } + + encrypt, err = security.NewAgeKeyPair(privKey, pubKey) + if err != nil { + panic(err) + } + } + + if err := manifests.ReadManifestFiles(args, ext); err != nil { + fmt.Printf("Error reading manifests: %v\n", err) + return err + } + + secrets, err := manifests.GetSecretList(keys, encrypt) + if err != nil { + return err + } + + if out { + cmd.Println(secrets) + } + + return nil +} diff --git a/api/launchr/validate.go b/api/launchr/validate.go new file mode 100644 index 0000000..3af4f59 --- /dev/null +++ b/api/launchr/validate.go @@ -0,0 +1,47 @@ +package launchr + +import ( + "dsl/service" + "errors" + "fmt" + "github.com/launchrctl/launchr" +) + +func NewCmdValidate(cmd *launchr.Command, args []string) error { + if len(args) == 0 { + return errors.New("no manifests provided") + } + + ext, err := cmd.Flags().GetString("ext") + if err != nil { + return err + } + + out, err := cmd.Flags().GetBool("out") + if err != nil { + return err + } + + cmd.SilenceUsage, err = cmd.Flags().GetBool("help") + if err != nil { + return err + } + + var manifests service.ManifestService + + if err := manifests.ReadManifestFiles(args, ext); err != nil { + return err + } + + if out { + for file, manifest := range manifests.GetManifests() { + serialized, err := manifest.Marshal() + if err != nil { + return fmt.Errorf("error '%s' while serializing '%s'", err.Error(), file) + } + cmd.Printf("# Content of '%s'\n%s\n", file, string(serialized)) + } + } + + return nil +} diff --git a/api/manifest/definition/component.go b/api/manifest/definition/component.go new file mode 100644 index 0000000..3d57593 --- /dev/null +++ b/api/manifest/definition/component.go @@ -0,0 +1,78 @@ +package definition + +import ( + "bytes" + "dsl/api/kv" + "dsl/api/security" + "fmt" + "gopkg.in/yaml.v3" +) + +type Manifest[T Schema] struct { + Schema T `yaml:",inline" validate:"required"` + validator *Validator[T] +} + +func NewManifest[T Schema]() (*Manifest[T], error) { + validator, err := NewValidator[T]() + manifest := &Manifest[T]{ + validator: validator, + } + if err != nil { + return nil, fmt.Errorf("unable to create validator for type: '%+v'\ndue to error '%s'\n", manifest.Schema, err) + } + return manifest, nil +} + +func (m *Manifest[T]) Unmarshal(deserialized []byte) error { + reader := bytes.NewReader(deserialized) + yamlDecoder := yaml.NewDecoder(reader) + yamlDecoder.KnownFields(true) + if err := yamlDecoder.Decode(&m.Schema); err != nil { + return err + } + return nil +} + +func (m *Manifest[T]) Marshal() ([]byte, error) { + serialized, err := yaml.Marshal(&m.Schema) + if err != nil { + return nil, err + } + return serialized, err +} + +func (m *Manifest[T]) Validate() error { + if err := m.validator.Validate(&m.Schema); err != nil { + return err + } + return nil +} + +func (m *Manifest[T]) GetSecrets(encryption security.Encryption) kv.KV { + secretsKV := m.Schema.GetCore().GetSecrets() + secrets := kv.PlainKVFromMap(secretsKV) + if encryption == nil { + return secrets + } + return kv.NewEncryptedKV(secrets, encryption) +} + +func (m *Manifest[T]) GetSecret(key string, encryption security.Encryption) (string, error) { + secrets := m.GetSecrets(encryption) + secret, err := secrets.Get(key) + if err != nil { + return "", err + } + return secret, nil +} + +func (m *Manifest[T]) SetSecret(key, value string, encryption security.Encryption) error { + secrets := m.GetSecrets(encryption) + return secrets.Set(key, value) +} + +func (m *Manifest[T]) UpdateSecrets(kv kv.KV, encryption security.Encryption) error { + secrets := m.GetSecrets(encryption) + return secrets.SetBatch(kv) +} diff --git a/api/manifest/definition/component_test.go b/api/manifest/definition/component_test.go new file mode 100644 index 0000000..a20e4e8 --- /dev/null +++ b/api/manifest/definition/component_test.go @@ -0,0 +1,77 @@ +package definition + +import ( + "dsl/api/fs" + "dsl/api/reader" + "log" + "os" + "path/filepath" + "testing" +) + +const ( + TestdataPath = "testdata" + TestfileExt = ".yaml" +) + +var Testdata []string + +func init() { + workDir, err := os.Getwd() + if err != nil { + log.Fatalf("unable to determine current work dir") + } + + testPath := filepath.Join(workDir, TestdataPath) + + if _, err := os.Stat(testPath); os.IsNotExist(err) { + log.Fatalf("testdata path %s is not exists", testPath) + } + + Testdata, err = fs.DiscoverFiles([]string{testPath}, TestfileExt) + if err != nil { + log.Fatalf(err.Error()) + } +} + +func TestKindDetection(t *testing.T) { + for _, file := range Testdata { + t.Logf("testing of kind detection of file '%s'\n", file) + yamlData, err := os.ReadFile(file) + if err != nil { + t.Fatalf("unable to extract schema from yaml %s: %s", string(yamlData), err.Error()) + } + + component, err := reader.ParseComponent(yamlData) + + if err != nil { + t.Fatalf("error while creating component from '%s': '%s'", file, err.Error()) + } + if component == nil { + t.Fatalf("component created from '%s' is nil", file) + } + } +} + +func TestValidate(t *testing.T) { + for _, file := range Testdata { + t.Logf("testing deserizlization of %s", file) + yamlData, err := os.ReadFile(file) + if err != nil { + t.Fatalf("unable to extract schema from yaml %s: %s", string(yamlData), err.Error()) + } + + component, err := reader.ParseComponent(yamlData) + if err != nil { + t.Fatalf("error when creating component: '%s'", err.Error()) + } + + if err := component.Unmarshal(yamlData); err != nil { + t.Fatalf("unable to deserizlize %s: %s", file, err.Error()) + } + + if err := component.Validate(); err != nil { + t.Fatalf("unable to deserizlize %s: %s", file, err.Error()) + } + } +} diff --git a/api/manifest/definition/contracts.go b/api/manifest/definition/contracts.go new file mode 100644 index 0000000..c594c92 --- /dev/null +++ b/api/manifest/definition/contracts.go @@ -0,0 +1,38 @@ +package definition + +import ( + "dsl/api/kv" + "dsl/api/schema/plasma/v1" + "dsl/api/security" +) + +type ComponentMarshaller interface { + Marshal() ([]byte, error) + Unmarshal(serialized []byte) error +} + +type ComponentValidator interface { + Validate() error +} + +type ComponentSecretKV interface { + GetSecrets(encryption security.Encryption) kv.KV + GetSecret(key string, encryption security.Encryption) (string, error) + SetSecret(key, value string, encryption security.Encryption) error + UpdateSecrets(kv kv.KV, encryption security.Encryption) error +} + +type Component interface { + ComponentMarshaller + ComponentValidator + ComponentSecretKV +} + +type HasCore interface { + GetCore() *v1.Core +} + +type Schema interface { + v1.Application | v1.Entity | v1.Flow | v1.Function | v1.Library | v1.Metric | v1.Model | v1.Node | v1.Package | v1.Platform | v1.Service | v1.Skill | v1.Software + HasCore +} diff --git a/api/manifest/definition/enums.go b/api/manifest/definition/enums.go new file mode 100644 index 0000000..3eacfb3 --- /dev/null +++ b/api/manifest/definition/enums.go @@ -0,0 +1,84 @@ +package definition + +type Enum map[string]bool + +func (e Enum) Exists(elem string) bool { + if exists, ok := e[elem]; !exists || !ok { + return false + } + return true +} + +const ( + KindApplication = "Application" + KindEntity = "Entity" + KindFlow = "Flow" + KindFunction = "Function" + KindLibrary = "Library" + KindMetric = "Metric" + KindModel = "Model" + KindNode = "Node" + KindPackage = "Package" + KindPlatform = "Platform" + KindService = "Service" + KindSkill = "Skill" + KindSoftware = "Software" +) + +var ( + EnumKind = Enum{ + KindApplication: true, + KindEntity: true, + KindFlow: true, + KindFunction: true, + KindLibrary: true, + KindMetric: true, + KindModel: true, + KindNode: true, + KindPackage: true, + KindPlatform: true, + KindService: true, + KindSkill: true, + KindSoftware: true, + } + + EnumPcl = Enum{ + "Platform": true, + "Foundation": true, + "Integration": true, + "Interaction": true, + "Cognition": true, + "Conversation": true, + "Stabilization": true, + } + + EnumFlowType = Enum{ + "lake": true, + "data": true, + "http": true, + "schedule": true, + "event": true, + } + + EnumConcurrencyMode = Enum{ + "sync": true, + "async": true, + } + + EnumSkillStage = Enum{ + "data": true, + "information": true, + "knowledge": true, + "wisdom": true, + } + + EnumServiceBuilderContext = Enum{ + "cluster": true, + "image": true, + } + + EnumServiceScope = Enum{ + "local": true, + "cluster": true, + } +) diff --git a/api/manifest/definition/testdata/application_test.yaml b/api/manifest/definition/testdata/application_test.yaml new file mode 100644 index 0000000..dc715fd --- /dev/null +++ b/api/manifest/definition/testdata/application_test.yaml @@ -0,0 +1,34 @@ +# YAML representation of the exampleApp + +kind: Application +metadata: + pcn: cognition.applications.dashboards + pcsn: dashboards + pck: Application + pcl: Cognition + pcc: cognition.applications.dashboards + pcln: /usr/local/bin/applications + pct: + - dashboard + - analytics + pcv: 1.2.3 + pci: registry.example.com/cognition/dashboards:latest + +name: cognition.applications.dashboards +shortName: dashboards +namespace: cognition +owner: Operations Team +apiVersion: v1 +description: An application for managing dashboards and providing real-time analytics. + +dependencies: + - cognition.services.dashboards-grafana + - cognition.services.dashboards-postgres + +hooks: + initialize: "plasmactl cognition.applications.dashboards:initialize" + build: "plasmactl cognition.applications.dashboards:build" + expose: "plasmactl cognition.applications.dashboards:expose" + +settings: + maxRetries: 3 diff --git a/api/manifest/definition/testdata/entity_test.yaml b/api/manifest/definition/testdata/entity_test.yaml new file mode 100644 index 0000000..67421d6 --- /dev/null +++ b/api/manifest/definition/testdata/entity_test.yaml @@ -0,0 +1,32 @@ +kind: Entity +metadata: + pcn: cognition.entities.analytics + pcsn: analytics + pck: Entity + pcl: Cognition + pcc: cognition.entities.analytics + pcln: /usr/local/bin/entities + pct: + - analytics + - data-processing + pcv: 3.0.0 + pci: registry.example.com/cognition/analytics:latest + +name: cognition.entities.analytics +shortName: analytics +namespace: cognition +owner: Data Science Team +apiVersion: v3 +description: An entity for handling and processing analytics data. + +settings: + schemaVersion: 1 + +dependencies: + - cognition.services.data-ingestion + - cognition.services.data-storage + +hooks: + initialize: plasmactl cognition.entities.analytics:initialize + build: plasmactl cognition.entities.analytics:build + expose: plasmactl cognition.entities.analytics:expose diff --git a/api/manifest/definition/testdata/flow_test.yaml b/api/manifest/definition/testdata/flow_test.yaml new file mode 100644 index 0000000..1873f98 --- /dev/null +++ b/api/manifest/definition/testdata/flow_test.yaml @@ -0,0 +1,39 @@ +kind: Flow +metadata: + pcn: cognition.flows.data-processing + pcsn: data-flow + pck: Flow + pcl: Cognition + pcc: cognition.flows.data-processing + pcln: /usr/local/bin/flows + pct: + - data-processing + - automation + pcv: 1.5.0 + pci: registry.example.com/cognition/data-flow:latest + +name: cognition.flows.data-processing +shortName: data-flow +namespace: cognition +owner: Data Engineering Team +apiVersion: v1 +description: A flow for processing data and handling automation tasks. + +flowType: data +flowName: data-processing-flow +flowInput: raw-data.csv +flowOutput: processed-data.json + +settings: + postgresVersion: 13.2.0 + grafanaAlerting: true + timeout: 120 + +dependencies: + - cognition.services.postgres + - cognition.services.grafana + +hooks: + initialize: plasmactl cognition.flows.data-processing:initialize + build: plasmactl cognition.flows.data-processing:build + expose: plasmactl cognition.flows.data-processing:expose diff --git a/api/manifest/definition/testdata/function_test.yaml b/api/manifest/definition/testdata/function_test.yaml new file mode 100644 index 0000000..7fd06a5 --- /dev/null +++ b/api/manifest/definition/testdata/function_test.yaml @@ -0,0 +1,32 @@ +kind: Function +metadata: + pcn: cognition.functions.data-processing + pcsn: data-processing-function + pck: Function + pcl: Cognition + pcc: cognition.functions.data-processing + pcln: /usr/local/bin/functions + pct: + - data-processing + - functions + pcv: 1.0.0 + pci: registry.example.com/cognition/data-function:latest + +name: cognition.functions.data-processing +shortName: data-processing-function +namespace: cognition +owner: Data Processing Team +apiVersion: v1 +description: A function for synchronous and asynchronous data processing tasks. + +settings: + operationMode: async + +dependencies: + - cognition.services.data-ingestion + - cognition.services.data-validation + +hooks: + initialize: plasmactl cognition.functions.data-processing:initialize + build: plasmactl cognition.functions.data-processing:build + expose: plasmactl cognition.functions.data-processing:expose diff --git a/api/manifest/definition/testdata/library_test.yaml b/api/manifest/definition/testdata/library_test.yaml new file mode 100644 index 0000000..52b36cb --- /dev/null +++ b/api/manifest/definition/testdata/library_test.yaml @@ -0,0 +1,32 @@ +kind: Library +metadata: + pcn: cognition.libraries.data-processing + pcsn: data-processing-library + pck: Library + pcl: Cognition + pcc: cognition.libraries.data-processing + pcln: /usr/local/bin/libraries + pct: + - data-processing + - plugins + pcv: 1.1.0 + pci: registry.example.com/cognition/data-library:stable + +name: cognition.libraries.data-processing +shortName: data-processing-library +namespace: cognition +owner: Data Science Team +apiVersion: v1 +description: A library for data processing tasks, with plugin support. + +settings: + pluginPath: "/usr/local/bin/plugins" + +dependencies: + - cognition.services.plugin-manager + - cognition.services.data-storage + +hooks: + initialize: plasmactl cognition.libraries.data-processing:initialize + build: plasmactl cognition.libraries.data-processing:build + expose: plasmactl cognition.libraries.data-processing:expose diff --git a/api/manifest/definition/testdata/metric_test.yaml b/api/manifest/definition/testdata/metric_test.yaml new file mode 100644 index 0000000..a9e5e61 --- /dev/null +++ b/api/manifest/definition/testdata/metric_test.yaml @@ -0,0 +1,32 @@ +kind: Metric +metadata: + pcn: cognition.metrics.response-times + pcsn: response-time-metric + pck: Metric + pcl: Cognition + pcc: cognition.metrics.response-times + pcln: /usr/local/bin/metrics + pct: + - performance + - monitoring + pcv: 2.0.0 + pci: registry.example.com/cognition/response-metric:stable + +name: cognition.metrics.response-times +shortName: response-time-metric +namespace: cognition +owner: Monitoring Team +apiVersion: v2 +description: A metric for tracking response times and performance of services. + +settings: + aggregationInterval: "5m" + +dependencies: + - cognition.services.monitoring + - cognition.services.alerting + +hooks: + initialize: plasmactl cognition.metrics.response-times:initialize + build: plasmactl cognition.metrics.response-times:build + expose: plasmactl cognition.metrics.response-times:expose diff --git a/api/manifest/definition/testdata/model_test.yaml b/api/manifest/definition/testdata/model_test.yaml new file mode 100644 index 0000000..f48ef18 --- /dev/null +++ b/api/manifest/definition/testdata/model_test.yaml @@ -0,0 +1,120 @@ +kind: Model +metadata: + pcn: cognition.model.analytics + pcsn: analytics-model + pck: Model + pcl: Cognition + pcc: cognition.model.analytics + pcln: /usr/local/bin/models + pct: + - analytics + - processing + pcv: 1.3.5 + pci: registry.example.com/cognition/analytics-model:latest + +name: "cognition.model.analytics" +shortName: analytics-model +namespace: cognition +owner: Data Science Team +apiVersion: v1 +description: A model to perform large-scale data analytics and machine learning operations. + +settings: + globalMonitoringEnabled: true + defaultTheme: dark + + +platform: + foundation: + cluster: + - component: master-node + clusterSettings: + nodeKind: master + - component: worker-node + clusterSettings: + nodeKind: worker + storage: + - s3-bucket + - hdfs-storage + network: + ingress: + - nginx + - traefik + observability: + - prometheus + - grafana + security: + - firewall + - encryption + core: + - linux-os + - pki-infrastructure + + interaction: + observability: + - component: grafana + settings: + grafanaURL: http://grafana.example.com + dashboardRefreshInterval: 30s + monitoringEnabled: true + activeTheme: light + management: + - component: erp-system + settings: + erpDatabaseURL: postgresql://erp-db.example.com + communication: + - slack + - email + operations: + - monitoring-service + - alerting-system + marketing: + - component: landing-page + settings: + landingPageTitle: Welcome to Our Analytics Platform + trackVisitor: true + + integration: + core: + - auth-service + - api-gateway + organization: + - hr-flow + - sales-flow + operations: + - ci-cd-pipeline + - deployment-automation + + cognition: + core: + - natural-language-processing + - image-recognition + data: + - data-ingestion-pipeline + - data-warehouse + knowledge: + - knowledge-graph + wisdom: + - ai-decision-engine + + conversation: + core: + - chatbot + - voice-assistant + +packages: + - name: data-ingestion + source: + type: git + tag: v1.2.0 + url: https://git.example.com/data-ingestion.git + - name: data-analytics + source: + type: git + tag: v2.1.0 + url: https://git.example.com/data-analytics.git + - name: ml-training + source: + type: docker + tag: latest + url: https://registry.example.com/cognition/ml-training:latest diff --git a/api/manifest/definition/testdata/node_test.yaml b/api/manifest/definition/testdata/node_test.yaml new file mode 100644 index 0000000..17aa685 --- /dev/null +++ b/api/manifest/definition/testdata/node_test.yaml @@ -0,0 +1,40 @@ +kind: Node +metadata: + pcn: cognition.nodes.compute + pcsn: compute-node + pck: Node + pcl: Cognition + pcc: cognition.nodes.compute + pcln: /usr/local/bin/nodes + pct: + - infrastructure + - compute + pcv: 3.0.0 + pci: registry.example.com/cognition/compute-node:stable + +name: cognition.nodes.compute +shortName: compute-node +namespace: cognition +owner: Infrastructure Team +apiVersion: v3 +description: A node responsible for high-performance computing tasks. + +settings: + region: "us-west-1" + cpu: 64 + ram: "256GiB" + storage: "2000GiB" + privateIP: "192.168.1.10" + publicIP: "203.0.113.10" + chassis: + - chassis-1 + - chassis-2 + +dependencies: + - cognition.services.compute-scheduler + - cognition.services.monitoring + +hooks: + initialize: plasmactl cognition.nodes.compute:initialize + build: plasmactl cognition.nodes.compute:build + expose: plasmactl cognition.nodes.compute:expose diff --git a/api/manifest/definition/testdata/package_test.yaml b/api/manifest/definition/testdata/package_test.yaml new file mode 100644 index 0000000..32d428c --- /dev/null +++ b/api/manifest/definition/testdata/package_test.yaml @@ -0,0 +1,34 @@ +kind: Package +metadata: + pcn: cognition.packages.data-analysis + pcsn: data-analysis-package + pck: Package + pcl: Cognition + pcc: cognition.packages.data-analysis + pcln: /usr/local/bin/packages + pct: + - data-analysis + - packages + pcv: 1.0.0 + pci: registry.example.com/cognition/data-analysis-package:stable + +name: cognition.packages.data-analysis +shortName: data-analysis-package +namespace: cognition +owner: Data Engineering Team +apiVersion: v1 +description: A package for data analysis tools and libraries. + +settings: + type: library + tag: v2.3.0 + url: https://example.com/packages/data-analysis-library-v2.3.0.tar.gz + +dependencies: + - cognition.services.data-storage + - cognition.services.analytics + +hooks: + initialize: plasmactl cognition.packages.data-analysis:initialize + build: plasmactl cognition.packages.data-analysis:build + expose: plasmactl cognition.packages.data-analysis:expose diff --git a/api/manifest/definition/testdata/platform_test.yaml b/api/manifest/definition/testdata/platform_test.yaml new file mode 100644 index 0000000..43342b1 --- /dev/null +++ b/api/manifest/definition/testdata/platform_test.yaml @@ -0,0 +1,29 @@ +kind: Platform +metadata: + pcn: cognition.platforms.cloud + pcsn: cloud-platform + pck: Platform + pcl: Cognition + pcc: cognition.platforms.cloud + pcln: /usr/local/bin/platforms + pct: + - cloud + - infrastructure + pcv: 2.1.0 + pci: registry.example.com/cognition/cloud-platform:stable + +name: cognition.platforms.cloud +shortName: cloud-platform +namespace: cognition +owner: Cloud Infrastructure Team +apiVersion: v2 +description: A platform responsible for managing cloud-based infrastructure and services. + +dependencies: + - cognition.services.cloud-provisioner + - cognition.services.networking + +hooks: + initialize: plasmactl cognition.platforms.cloud:initialize + build: plasmactl cognition.platforms.cloud:build + expose: plasmactl cognition.platforms.cloud:expose diff --git a/api/manifest/definition/testdata/service_test.yaml b/api/manifest/definition/testdata/service_test.yaml new file mode 100644 index 0000000..d67689c --- /dev/null +++ b/api/manifest/definition/testdata/service_test.yaml @@ -0,0 +1,35 @@ +kind: Service +metadata: + pcn: cognition.services.logging + pcsn: logging-service + pck: Service + pcl: Cognition + pcc: cognition.services.logging + pcln: /usr/local/bin/services + pct: + - logging + - monitoring + pcv: 2.0.0 + pci: registry.example.com/cognition/logging:stable + +name: cognition.services.logging +shortName: logging-service +namespace: cognition +owner: DevOps Team +apiVersion: v2 +description: A service responsible for managing and aggregating logs. + +settings: + serviceBuilderContextType: image + serviceScope: cluster + retryLimit: 5 + grafanaApiKey: "grafana-api-key-here" + +dependencies: + - cognition.services.database + - cognition.services.monitoring + +hooks: + initialize: plasmactl cognition.services.logging:initialize + build: plasmactl cognition.services.logging:build + expose: plasmactl cognition.services.logging:expose diff --git a/api/manifest/definition/testdata/skill_test.yaml b/api/manifest/definition/testdata/skill_test.yaml new file mode 100644 index 0000000..59864dc --- /dev/null +++ b/api/manifest/definition/testdata/skill_test.yaml @@ -0,0 +1,36 @@ +kind: Skill +metadata: + pcn: cognition.skills.data-insights + pcsn: data-insights-skill + pck: Skill + pcl: Cognition + pcc: cognition.skills.data-insights + pcln: /usr/local/bin/skills + pct: + - data + - insights + pcv: 1.5.0 + pci: registry.example.com/cognition/data-insights-skill:stable + +name: cognition.skills.data-insights +shortName: data-insights-skill +namespace: cognition +owner: Data Science Team +apiVersion: v1 +description: A skill for transforming raw data into actionable insights using advanced analytics. + +settings: + skillValidationRequired: true + skillStage: knowledge + +secrets: + - {apiKey: "topsecretapikey", authToken: "verysecrettoken" } + +dependencies: + - cognition.services.data-pipeline + - cognition.services.analytics + +hooks: + initialize: plasmactl cognition.skills.data-insights:initialize + build: plasmactl cognition.skills.data-insights:build + expose: plasmactl cognition.skills.data-insights:expose diff --git a/api/manifest/definition/testdata/software_test.yaml b/api/manifest/definition/testdata/software_test.yaml new file mode 100644 index 0000000..1c189b3 --- /dev/null +++ b/api/manifest/definition/testdata/software_test.yaml @@ -0,0 +1,34 @@ +kind: Software +metadata: + pcn: cognition.software.data-processing + pcsn: data-processing-software + pck: Software + pcl: Cognition + pcc: cognition.software.data-processing + pcln: /usr/local/bin/software + pct: + - data + - processing + pcv: 2.2.0 + pci: registry.example.com/cognition/data-processing-software:stable + +name: cognition.software.data-processing +shortName: data-processing-software +namespace: cognition +owner: Software Development Team +apiVersion: v1 +description: A software package for processing and analyzing large datasets efficiently. + +settings: + serviceBuilderContextType: cluster + serviceScope: local + port: 8080 + +dependencies: + - cognition.services.data-ingestion + - cognition.services.data-storage + +hooks: + initialize: plasmactl cognition.software.data-processing:initialize + build: plasmactl cognition.software.data-processing:build + expose: plasmactl cognition.software.data-processing:expose diff --git a/api/manifest/definition/validation.go b/api/manifest/definition/validation.go new file mode 100644 index 0000000..8de8a5a --- /dev/null +++ b/api/manifest/definition/validation.go @@ -0,0 +1,152 @@ +package definition + +import ( + "fmt" + "github.com/go-playground/validator/v10" + "gopkg.in/yaml.v3" + "regexp" + "strconv" + "strings" +) + +// Generic validation function that accepts an enum type +func validateEnum(enum Enum) func(fl validator.FieldLevel) bool { + return func(fl validator.FieldLevel) bool { + value := fl.Field().String() + return enum.Exists(value) + } +} + +func validateMilliCPU(fl validator.FieldLevel) bool { + cpu := fl.Field().String() + + // Check if value is in millis + if strings.HasSuffix(cpu, "m") { + cpu = strings.TrimSuffix(cpu, "m") + intNum, err := strconv.Atoi(cpu) + if err != nil || intNum <= 0 { + return false + } + if err == nil { + return true + } + } + + // value cannot have precision lower 1 mCPU (0.001 CPU) + // According to docs https://kubernetes.io/docs/tasks/configure-pod-container/assign-cpu-resource/#cpu-units + floatNum, err := strconv.ParseFloat(cpu, 64) + if err != nil || floatNum < 0.001 { + return false + } + + return true +} + +func validateInfoUnits(fl validator.FieldLevel) bool { + ram := fl.Field().String() + + // Regular expression to match valid Kubernetes memory formats like "128Mi", "2Gi", etc. + // Excluding zero as the first character + re := regexp.MustCompile(`^[1-9][0-9]{0,3}(Ei|Pi|Ti|Gi|Mi|Ki|EiB|PiB|TiB|GiB|MiB|KiB)$`) + + return re.MatchString(ram) +} + +func validateTimeInterval(fl validator.FieldLevel) bool { + interval := fl.Field().String() + + // Regular expression to match valid time intervals like "1min", "60s", "1h", "1d", "1w". Default is min if no time units specified + // Not excluding zero as the first character, because some software may interpret it as a valid or none value + re := regexp.MustCompile(`^[0-9]+(s|m|h|d|w)?$`) + + return re.MatchString(interval) +} + +func validateTCPv4Port(fl validator.FieldLevel) bool { + portNum := fl.Field().Uint() + + var maxPortNum uint64 = (2 << 15) - 1 + + if portNum == 0 || portNum > maxPortNum { + return false + } + return true +} + +var DefaultValidatorFuncs = map[string]validator.Func{ + "isKind": validateEnum(EnumKind), + "isPcl": validateEnum(EnumPcl), + "isConcurrencyMode": validateEnum(EnumConcurrencyMode), + "isFlowType": validateEnum(EnumFlowType), + "isServiceScope": validateEnum(EnumServiceScope), + "isServiceBuilderCtx": validateEnum(EnumServiceBuilderContext), + "isSkillStage": validateEnum(EnumSkillStage), + "isTCPv4Port": validateTCPv4Port, + "milliCPU": validateMilliCPU, + "infoUnits": validateInfoUnits, + "timeInterval": validateTimeInterval, +} + +type validationError struct { + Namespace string `yaml:"namespace"` // can differ when a custom TagNameFunc is registered or + Field string `yaml:"field"` // by passing alt name to ReportError like below + StructNamespace string `yaml:"structNamespace"` + StructField string `yaml:"structField"` + Tag string `yaml:"tag"` + ActualTag string `yaml:"actualTag"` + Kind string `yaml:"kind"` + Type string `yaml:"type"` + Value string `yaml:"value"` + Param string `yaml:"param"` + Message string `yaml:"message"` +} + +type Validator[T Schema] struct { + validator *validator.Validate +} + +func NewValidator[T Schema]() (*Validator[T], error) { + validate := validator.New(validator.WithRequiredStructEnabled()) + + // Register custom validation functions + for tag, validatorFunc := range DefaultValidatorFuncs { + if err := validate.RegisterValidation(tag, validatorFunc); err != nil { + return nil, fmt.Errorf("error registration custom validation function %s: %s", tag, err.Error()) + } + } + + return &Validator[T]{validator: validate}, nil +} + +func (v *Validator[T]) Validate(schema *T) error { + err := v.validator.Struct(schema) + if err != nil { + if _, ok := err.(*validator.InvalidValidationError); ok { + return err.(*validator.InvalidValidationError) + } + + for _, err := range err.(validator.ValidationErrors) { + e := validationError{ + Namespace: err.Namespace(), + Field: err.Field(), + StructNamespace: err.StructNamespace(), + StructField: err.StructField(), + Tag: err.Tag(), + ActualTag: err.ActualTag(), + Kind: fmt.Sprintf("%v", err.Kind()), + Type: fmt.Sprintf("%v", err.Type()), + Value: fmt.Sprintf("%v", err.Value()), + Param: err.Param(), + Message: err.Error(), + } + + yamlOutput, err := yaml.Marshal(e) + if err != nil { + return fmt.Errorf("error while log yaml marshalling: %s", err.Error()) + } + + fmt.Println(string(yamlOutput)) + } + } + return err +} diff --git a/api/manifest/definition/validation_test.go b/api/manifest/definition/validation_test.go new file mode 100644 index 0000000..3a7afbd --- /dev/null +++ b/api/manifest/definition/validation_test.go @@ -0,0 +1,176 @@ +package definition + +import ( + "github.com/go-playground/validator/v10" + "log" + "testing" +) + +var validate *validator.Validate + +func init() { + validate = validator.New(validator.WithRequiredStructEnabled()) + + for tag, validatorFunc := range DefaultValidatorFuncs { + if err := validate.RegisterValidation(tag, validatorFunc); err != nil { + log.Fatalf("error registration custom validation function '%s': '%s'", tag, err.Error()) + } + } +} + +func TestValidateMilliCPU(t *testing.T) { + tests := []struct { + name string + value string + want bool + }{ + {"Valid CPU - 64", "64", true}, + {"Valid CPU - 128", "128", true}, + {"Valid CPU - 512m", "512m", true}, + {"Valid CPU - 1m", "1m", true}, + {"Valid CPU - 0.001", "0.001", true}, + {"Invalid CPU - 0", "0", false}, + {"Invalid CPU - m0", "m0", false}, + {"Invalid CPU - Too small", "0.0001", false}, + {"Invalid CPU - negative cpu", "-1", false}, + {"Invalid CPU - negative mCPU", "-1m", false}, + {"Invalid CPU - fractional CPU", "-0.0001", false}, + {"Invalid CPU - negative fractional CPU", "-0.0001", false}, + {"Invalid CPU - wrong case", "M1", false}, + {"Invalid CPU - wrong formatting", "mi1", false}, + } + + for _, tt := range tests { + err := validate.Var(tt.value, "milliCPU") + if (err == nil) != tt.want { + t.Errorf("%s: expected %v, got %v", tt.name, tt.want, err == nil) + } + } +} + +func TestValidateInfoUnits(t *testing.T) { + tests := []struct { + name string + value string + want bool + }{ + {"Valid RAM - 128Mi", "128Mi", true}, + {"Valid RAM - 2Gi", "2Gi", true}, + {"Invalid RAM - 128", "128", false}, + {"Invalid RAM - random string", "abc", false}, + {"Valid Storage - 1Ti", "1Ti", true}, + {"Invalid Storage - -100Gi", "-100Gi", false}, + {"Invalid Storage - 0Gi", "0Gi", false}, + {"Invalid Storage - 0", "0", false}, + {"Invalid Storage - 01", "01", false}, + {"Invalid Storage - 01Gi", "01Gi", false}, + {"Invalid Storage - 1i", "1i", false}, + } + + for _, tt := range tests { + err := validate.Var(tt.value, "infoUnits") + if (err == nil) != tt.want { + t.Errorf("%s: expected %v, got %v", tt.name, tt.want, err == nil) + } + } +} + +func TestValidateTimeInterval(t *testing.T) { + tests := []struct { + name string + value string + want bool + }{ + {"Valid Interval - 60s", "60s", true}, + {"Valid Interval - 1m", "1m", true}, + {"Valid Interval - 1h", "1h", true}, + {"Invalid Interval - 1min", "1min", false}, + {"Invalid Interval - 10seconds", "10seconds", false}, + {"Invalid Interval - random string", "abc", false}, + } + + for _, tt := range tests { + err := validate.Var(tt.value, "timeInterval") + if (err == nil) != tt.want { + t.Errorf("%s: expected %v, got %v", tt.name, tt.want, err == nil) + } + } +} + +func TestValidateTCPv4Port(t *testing.T) { + tests := []struct { + name string + value uint64 + want bool + }{ + {"Valid TCPv4Port - 1", 1, true}, + {"Valid TCPv4Port - 22", 22, true}, + {"Valid TCPv4Port - 65535", 65535, true}, + {"Invalid TCPv4Port - 0", 0, false}, + {"Invalid TCPv4Port - 65536", 65536, false}, + } + + for _, tt := range tests { + err := validate.Var(tt.value, "isTCPv4Port") + if (err == nil) != tt.want { + t.Errorf("%s: expected %v, got %v", tt.name, tt.want, err == nil) + } + } +} + +func TestValidateServiceBuilderContextType(t *testing.T) { + tests := []struct { + name string + value string + want bool + }{ + {"Valid ServiceBuilderContextType - cluster", "cluster", true}, + {"Valid ServiceBuilderContextType - image", "image", true}, + {"Invalid ServiceBuilderContextType - random", "random", false}, + } + + for _, tt := range tests { + err := validate.Var(tt.value, "isServiceBuilderCtx") + if (err == nil) != tt.want { + t.Errorf("%s: expected %v, got %v", tt.name, tt.want, err == nil) + } + } +} + +func TestValidateServiceScope(t *testing.T) { + tests := []struct { + name string + value string + want bool + }{ + {"Valid ServiceScope - local", "local", true}, + {"Valid ServiceScope - cluster", "cluster", true}, + {"Invalid ServiceScope - random", "random", false}, + } + + for _, tt := range tests { + err := validate.Var(tt.value, "isServiceScope") + if (err == nil) != tt.want { + t.Errorf("%s: expected %v, got %v", tt.name, tt.want, err == nil) + } + } +} + +func TestValidateFlowType(t *testing.T) { + tests := []struct { + name string + value string + want bool + }{ + {"Valid FlowType - lake", "lake", true}, + {"Valid FlowType - data", "data", true}, + {"Invalid FlowType - random", "random", false}, + } + + for _, tt := range tests { + err := validate.Var(tt.value, "isFlowType") + if (err == nil) != tt.want { + t.Errorf("%s: expected %v, got %v", tt.name, tt.want, err == nil) + } + } +} diff --git a/api/reader/parser.go b/api/reader/parser.go new file mode 100644 index 0000000..3e94989 --- /dev/null +++ b/api/reader/parser.go @@ -0,0 +1,63 @@ +package reader + +import ( + "dsl/api/manifest/definition" + v1 "dsl/api/schema/plasma/v1" + "fmt" + "gopkg.in/yaml.v3" +) + +func ParseComponent(serialized []byte) (definition.Component, error) { + kind, err := parseKind(serialized) + if err != nil { + return nil, err + } + switch kind { + case definition.KindApplication: + return definition.NewManifest[v1.Application]() + case definition.KindEntity: + return definition.NewManifest[v1.Entity]() + case definition.KindFlow: + return definition.NewManifest[v1.Flow]() + case definition.KindFunction: + return definition.NewManifest[v1.Function]() + case definition.KindLibrary: + return definition.NewManifest[v1.Library]() + case definition.KindMetric: + return definition.NewManifest[v1.Metric]() + case definition.KindModel: + return definition.NewManifest[v1.Model]() + case definition.KindNode: + return definition.NewManifest[v1.Node]() + case definition.KindPackage: + return definition.NewManifest[v1.Package]() + case definition.KindPlatform: + return definition.NewManifest[v1.Platform]() + case definition.KindService: + return definition.NewManifest[v1.Service]() + case definition.KindSkill: + return definition.NewManifest[v1.Skill]() + case definition.KindSoftware: + return definition.NewManifest[v1.Software]() + default: + return nil, fmt.Errorf("not allowed component kind '%s' - incorrect manifest definition:\n%s\n", kind, string(serialized)) + } +} + +func parseKind(serialized []byte) (string, error) { + kindField := &struct { + Kind string `yaml:"kind" validate:"isKind"` + }{ + Kind: "", + } + + if err := yaml.Unmarshal(serialized, kindField); err != nil { + return "", fmt.Errorf("unable to parse kind from content:\n%s\n", string(serialized)) + } + + if kindField.Kind == "" { + return "", fmt.Errorf("parsed empty kind from content:\n%s\n", string(serialized)) + } + + return kindField.Kind, nil +} diff --git a/api/schema/plasma/v1/application.go b/api/schema/plasma/v1/application.go new file mode 100644 index 0000000..2ac2233 --- /dev/null +++ b/api/schema/plasma/v1/application.go @@ -0,0 +1,14 @@ +package v1 + +type Application struct { + Core `yaml:",inline" validate:"required"` + ApplicationSettings `yaml:"settings" validate:"required"` +} + +type ApplicationSettings struct { + MaxRetries uint `yaml:"maxRetries"` +} + +func (a Application) GetCore() *Core { + return &a.Core +} diff --git a/api/schema/plasma/v1/core.go b/api/schema/plasma/v1/core.go new file mode 100644 index 0000000..6645dfd --- /dev/null +++ b/api/schema/plasma/v1/core.go @@ -0,0 +1,41 @@ +package v1 + +type Core struct { + Kind string `yaml:"kind" validate:"isKind,eqcsfield=Metadata.Pck"` + Metadata Metadata `yaml:"metadata" validate:"required"` + Name string `yaml:"name" validate:"required,max=63,eqcsfield=Metadata.Pcn"` + ShortName string `yaml:"shortName" validate:"required,max=63,eqcsfield=Metadata.Pcsn"` + Namespace string `yaml:"namespace" validate:"required,max=63"` + Owner string `yaml:"owner" validate:"required"` + APIVersion string `yaml:"apiVersion" validate:"required"` + Description string `yaml:"description" validate:"required"` + Dependencies []string `yaml:"dependencies"` + Hooks Hooks `yaml:"hooks"` + Secrets map[string]string `yaml:"secrets,flow"` +} + +func (c *Core) GetSecrets() map[string]string { + return c.Secrets +} + +type Metadata struct { + Pcn string `yaml:"pcn" validate:"required,max=63"` + Pcsn string `yaml:"pcsn" validate:"required,max=63"` + Pck string `yaml:"pck" validate:"required"` + Pcl string `yaml:"pcl" validate:"isPcl"` + Pcc string `yaml:"pcc" validate:"required,max=63"` + Pcln string `yaml:"pcln" validate:"required,max=63"` + Pct []string `yaml:"pct,flow"` + Pcv string `yaml:"pcv" validate:"required,semver"` + Pci string `yaml:"pci"` +} + +type Hooks struct { + Initialize string `yaml:"initialize"` + ResolveDependencies string `yaml:"resolveDependencies"` + Build string `yaml:"build"` + AwaitReadiness string `yaml:"awaitReadiness"` + Configure string `yaml:"configure"` + Expose string `yaml:"expose"` + Decommission string `yaml:"decommission"` +} diff --git a/api/schema/plasma/v1/entity.go b/api/schema/plasma/v1/entity.go new file mode 100644 index 0000000..bf9f403 --- /dev/null +++ b/api/schema/plasma/v1/entity.go @@ -0,0 +1,14 @@ +package v1 + +type Entity struct { + Core `yaml:",inline" validate:"required"` + EntitySettings `yaml:"settings" validate:"required"` +} + +type EntitySettings struct { + SchemaVersion string `yaml:"schemaVersion"` +} + +func (e Entity) GetCore() *Core { + return &e.Core +} diff --git a/api/schema/plasma/v1/flow.go b/api/schema/plasma/v1/flow.go new file mode 100644 index 0000000..a665793 --- /dev/null +++ b/api/schema/plasma/v1/flow.go @@ -0,0 +1,24 @@ +package v1 + +type Flow struct { + Core `yaml:",inline" validate:"required"` + FlowAttributes `yaml:",inline" validate:"required"` + FlowSettings `yaml:"settings" validate:"required"` +} + +type FlowAttributes struct { + FlowType string `yaml:"flowType" validate:"required,isFlowType"` + FlowName string `yaml:"flowName" validate:"required"` + FlowInput string `yaml:"flowInput" validate:"required"` + FlowOutput string `yaml:"flowOutput"` +} + +type FlowSettings struct { + PostgresVersion string `yaml:"postgresVersion" validate:"semver"` + GrafanaAlerting bool `yaml:"grafanaAlerting"` + Timeout string `yaml:"timeout,omitempty" validate:"timeInterval"` +} + +func (f Flow) GetCore() *Core { + return &f.Core +} diff --git a/api/schema/plasma/v1/function.go b/api/schema/plasma/v1/function.go new file mode 100644 index 0000000..77815c2 --- /dev/null +++ b/api/schema/plasma/v1/function.go @@ -0,0 +1,14 @@ +package v1 + +type Function struct { + Core `yaml:",inline" validate:"required"` + FunctionSettings `yaml:"settings" validate:"required"` +} + +type FunctionSettings struct { + OperationMode string `yaml:"operationMode" validate:"isConcurrencyMode"` +} + +func (f Function) GetCore() *Core { + return &f.Core +} diff --git a/api/schema/plasma/v1/library.go b/api/schema/plasma/v1/library.go new file mode 100644 index 0000000..d945876 --- /dev/null +++ b/api/schema/plasma/v1/library.go @@ -0,0 +1,14 @@ +package v1 + +type Library struct { + Core `yaml:",inline" validate:"required"` + LibrarySettings `yaml:"settings" validate:"required"` +} + +type LibrarySettings struct { + PluginPath string `yaml:"pluginPath"` +} + +func (l Library) GetCore() *Core { + return &l.Core +} diff --git a/api/schema/plasma/v1/metric.go b/api/schema/plasma/v1/metric.go new file mode 100644 index 0000000..6955070 --- /dev/null +++ b/api/schema/plasma/v1/metric.go @@ -0,0 +1,14 @@ +package v1 + +type Metric struct { + Core `yaml:",inline" validate:"required"` + MetricSettings `yaml:"settings" validate:"required"` +} + +type MetricSettings struct { + AggregationInterval string `yaml:"aggregationInterval" validate:"timeInterval"` +} + +func (m Metric) GetCore() *Core { + return &m.Core +} diff --git a/api/schema/plasma/v1/model.go b/api/schema/plasma/v1/model.go new file mode 100644 index 0000000..3219b61 --- /dev/null +++ b/api/schema/plasma/v1/model.go @@ -0,0 +1,108 @@ +package v1 + +type Model struct { + Core `yaml:",inline" validate:"required"` + Settings ModelSettings `yaml:"settings"` + Platform PlatformComponents `yaml:"platform"` + Packages []PackageRef `yaml:"packages"` +} + +func (m Model) GetCore() *Core { + return &m.Core +} + +type ModelSettings struct { + GlobalMonitoringEnabled bool `yaml:"globalMonitoringEnabled" validate:"required"` + DefaultTheme string `yaml:"defaultTheme" validate:"required"` +} + +type PlatformComponents struct { + Foundation FoundationComponent `yaml:"foundation"` + Interaction InteractionComponent `yaml:"interaction"` + Integration IntegrationComponent `yaml:"integration"` + Cognition CognitionComponent `yaml:"cognition"` + Conversation ConversationComponent `yaml:"conversation"` +} + +type FoundationComponent struct { + Cluster []ClusterComponent `yaml:"cluster" validate:"required"` + Network NetworkComponent `yaml:"network"` + Storage []string `yaml:"storage"` + Observability []string `yaml:"observability" validate:"required"` + Security []string `yaml:"security"` + Core []string `yaml:"core"` +} + +type ClusterComponent struct { + Component string `yaml:"component" validate:"required"` + ClusterSettings ClusterSettings `yaml:"clusterSettings"` +} + +type ClusterSettings struct { + NodeKind string `yaml:"nodeKind" validate:"required"` +} + +type NetworkComponent struct { + Ingress []string `yaml:"ingress"` +} + +type InteractionComponent struct { + Observability []ObservabilityComponent `yaml:"observability"` + Management []ManagementComponent `yaml:"management"` + Communication []string `yaml:"communication"` + Operations []string `yaml:"operations"` + Marketing []MarketingComponent `yaml:"marketing"` +} + +type ObservabilityComponent struct { + Component string `yaml:"component"` + Settings ObservabilitySettings `yaml:"settings" validate:"required"` +} + +type ObservabilitySettings struct { + GrafanaURL string `yaml:"grafanaURL" validate:"required"` + DashboardRefreshInterval string `yaml:"dashboardRefreshInterval" validate:"required"` + MonitoringEnabled bool `yaml:"monitoringEnabled" validate:"required"` + ActiveTheme string `yaml:"activeTheme" validate:"required"` +} + +type ManagementComponent struct { + Component string `yaml:"component" validate:"required"` + Settings ManagementSettings `yaml:"settings"` +} + +type ManagementSettings struct { + ERPDatabaseURL string `yaml:"erpDatabaseURL"` +} + +type MarketingComponent struct { + Component string `yaml:"component"` + Settings MarketingSettings `yaml:"settings"` +} + +type MarketingSettings struct { + LandingPageTitle string `yaml:"landingPageTitle" validate:"required"` + TrackVisitor bool `yaml:"trackVisitor"` +} + +type IntegrationComponent struct { + Core []string `yaml:"core"` + Organization []string `yaml:"organization"` + Operations []string `yaml:"operations"` +} + +type CognitionComponent struct { + Core []string `yaml:"core"` + Data []string `yaml:"data"` + Knowledge []string `yaml:"knowledge"` + Wisdom []string `yaml:"wisdom"` +} + +type ConversationComponent struct { + Core []string `yaml:"core"` +} + +type PackageRef struct { + Name string `yaml:"name" validate:"required"` + Source PackageSettings `yaml:"source" validate:"required"` +} diff --git a/api/schema/plasma/v1/node.go b/api/schema/plasma/v1/node.go new file mode 100644 index 0000000..6059394 --- /dev/null +++ b/api/schema/plasma/v1/node.go @@ -0,0 +1,21 @@ +package v1 + +type Node struct { + Core `yaml:",inline" validate:"required"` + NodeSettings `yaml:"settings" validate:"required"` +} + +// NodeSettings holds settings specific to nodes +type NodeSettings struct { + Region string `yaml:"region"` + CPU string `yaml:"cpu" validate:"milliCPU"` + RAM string `yaml:"ram" validate:"infoUnits"` + Storage string `yaml:"storage" validate:"infoUnits"` + PrivateIP string `yaml:"privateIP" validate:"ipv4|ipv6"` + PublicIP string `yaml:"publicIP" validate:"ipv4|ipv6"` + Chassis []string `yaml:"chassis"` +} + +func (n Node) GetCore() *Core { + return &n.Core +} diff --git a/api/schema/plasma/v1/package.go b/api/schema/plasma/v1/package.go new file mode 100644 index 0000000..4f5a214 --- /dev/null +++ b/api/schema/plasma/v1/package.go @@ -0,0 +1,16 @@ +package v1 + +type Package struct { + Core `yaml:",inline" validate:"required"` + PackageSettings `yaml:"settings" validate:"required"` +} + +type PackageSettings struct { + PackageType string `yaml:"type" validate:"required"` + PackageTag string `yaml:"tag" validate:"required"` + PackageUrl string `yaml:"url" validate:"required"` +} + +func (p Package) GetCore() *Core { + return &p.Core +} diff --git a/api/schema/plasma/v1/platform.go b/api/schema/plasma/v1/platform.go new file mode 100644 index 0000000..20a0643 --- /dev/null +++ b/api/schema/plasma/v1/platform.go @@ -0,0 +1,9 @@ +package v1 + +type Platform struct { + Core `yaml:",inline" validate:"required"` +} + +func (p Platform) GetCore() *Core { + return &p.Core +} diff --git a/api/schema/plasma/v1/service.go b/api/schema/plasma/v1/service.go new file mode 100644 index 0000000..2fa18da --- /dev/null +++ b/api/schema/plasma/v1/service.go @@ -0,0 +1,17 @@ +package v1 + +type Service struct { + Core `yaml:",inline" validate:"required"` + ServiceSettings `yaml:"settings" validate:"required"` +} + +type ServiceSettings struct { + ServiceBuilderContext string `yaml:"serviceBuilderContextType" validate:"isServiceBuilderCtx"` + ServiceScope string `yaml:"serviceScope" validate:"isServiceScope"` + RetryLimit uint `yaml:"retryLimit"` + GrafanaApiKey string `yaml:"grafanaApiKey"` +} + +func (s Service) GetCore() *Core { + return &s.Core +} diff --git a/api/schema/plasma/v1/skill.go b/api/schema/plasma/v1/skill.go new file mode 100644 index 0000000..37c3ba0 --- /dev/null +++ b/api/schema/plasma/v1/skill.go @@ -0,0 +1,16 @@ +package v1 + +type Skill struct { + Core `yaml:",inline" validate:"required"` + SkillSettings `yaml:"settings" validate:"required"` +} + +type SkillSettings struct { + SkillValidationRequired bool `yaml:"skillValidationRequired"` + SkillStage string `yaml:"skillStage" validate:"isSkillStage"` + // "\(pcsn)_log_verbosity" `yaml:"logVerbosity""` +} + +func (s Skill) GetCore() *Core { + return &s.Core +} diff --git a/api/schema/plasma/v1/software.go b/api/schema/plasma/v1/software.go new file mode 100644 index 0000000..9592144 --- /dev/null +++ b/api/schema/plasma/v1/software.go @@ -0,0 +1,16 @@ +package v1 + +type Software struct { + Core `yaml:",inline" validate:"required"` + SoftwareSettings `yaml:"settings" validate:"required"` +} + +type SoftwareSettings struct { + ServiceBuilderContext string `yaml:"serviceBuilderContextType" validate:"isServiceBuilderCtx"` + ServiceScope string `yaml:"serviceScope" validate:"isServiceScope"` + Port uint16 `yaml:"port" validate:"isTCPv4Port"` +} + +func (s Software) GetCore() *Core { + return &s.Core +} diff --git a/api/security/age.go b/api/security/age.go new file mode 100644 index 0000000..d510b8a --- /dev/null +++ b/api/security/age.go @@ -0,0 +1,109 @@ +package security + +import ( + "bytes" + "fmt" + "io" + "os" + + "filippo.io/age" + "filippo.io/age/armor" +) + +// Vault encapsulates encryption and decryption logic +type AgeKeyPair struct { + privateKey age.Identity + publicKey age.Recipient +} + +// NewVault initializes a new Vault with the given private and public keys +func NewAgeKeyPair(privateKeySource, publicKeyPath string) (*AgeKeyPair, error) { + privateKey, err := loadPrivateKey(privateKeySource) + if err != nil { + return nil, err + } + + publicKey, err := loadPublicKey(publicKeyPath) + if err != nil { + return nil, err + } + + return &AgeKeyPair{ + privateKey: privateKey, + publicKey: publicKey, + }, nil +} + +// Encrypt encrypts data using the public key +func (m *AgeKeyPair) Encrypt(data []byte) ([]byte, error) { + buf := &bytes.Buffer{} + armorWriter := armor.NewWriter(buf) + w, err := age.Encrypt(armorWriter, m.publicKey) + if err != nil { + return nil, err + } + + _, err = w.Write(data) + if err != nil { + return nil, err + } + + err = w.Close() + if err != nil { + return nil, err + } + + err = armorWriter.Close() + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +// Decrypt decrypts encrypted data using the private key +func (m *AgeKeyPair) Decrypt(encryptedData []byte) ([]byte, error) { + buf := bytes.NewReader(encryptedData) + armorReader := armor.NewReader(buf) + rc, err := age.Decrypt(armorReader, m.privateKey) + if err != nil { + return nil, err + } + decryptedData, err := io.ReadAll(rc) + if err != nil { + return nil, err + } + return decryptedData, nil +} + +// loadPrivateKey loads the private key from a file, command-line argument, or environment variable +func loadPrivateKey(source string) (age.Identity, error) { + var keyData []byte + var err error + + // Check if source is a file + if _, err = os.Stat(source); err == nil { + keyData, err = os.ReadFile(source) + //fmt.Println(string(keyData)) + if err != nil { + return nil, fmt.Errorf("failed to read private key from file: %w", err) + } + } //else if value, found := os.LookupEnv(source); found { + // // Check if source is an environment variable + // keyData = []byte(value) + //} else { + // // Fallback: treat as direct key input + // keyData = []byte(source) + //} + + return age.ParseX25519Identity(string(keyData)) +} + +// loadPublicKey loads the public key from the file +func loadPublicKey(path string) (age.Recipient, error) { + keyData, err := os.ReadFile(path) + if err != nil { + return nil, fmt.Errorf("failed to read public key from file: %w", err) + } + return age.ParseX25519Recipient(string(keyData)) +} diff --git a/api/security/encryption.go b/api/security/encryption.go new file mode 100644 index 0000000..3742876 --- /dev/null +++ b/api/security/encryption.go @@ -0,0 +1,6 @@ +package security + +type Encryption interface { + Encrypt(data []byte) ([]byte, error) + Decrypt(data []byte) ([]byte, error) +} diff --git a/api/security/keypair.go b/api/security/keypair.go new file mode 100644 index 0000000..4610d19 --- /dev/null +++ b/api/security/keypair.go @@ -0,0 +1,35 @@ +package security + +import "fmt" + +type KeyPair struct { + Encryption +} + +type PrivateKeyEmptyError struct { + msg string +} + +func NewPrivateKeyEmptyError() PrivateKeyEmptyError { + return PrivateKeyEmptyError{ + msg: "no private key provided", + } +} + +func (e PrivateKeyEmptyError) Error() string { + return e.msg +} + +type PrivateKeyInvalidFormat struct { + msg string +} + +func NewPrivateKeyInvalidFormatError(key string) PrivateKeyInvalidFormat { + return PrivateKeyInvalidFormat{ + msg: fmt.Sprintf("private key provided has invalid format '%s'", key), + } +} + +func (e PrivateKeyInvalidFormat) Error() string { + return e.msg +} diff --git a/api/security/masterkey.go b/api/security/masterkey.go new file mode 100644 index 0000000..ec162a1 --- /dev/null +++ b/api/security/masterkey.go @@ -0,0 +1,5 @@ +package security + +type MasterKey struct { + Encryption +} diff --git a/cmd/dsl/main.go b/cmd/dsl/main.go new file mode 100644 index 0000000..1de57f7 --- /dev/null +++ b/cmd/dsl/main.go @@ -0,0 +1,10 @@ +package main + +import ( + _ "dsl/plugins/dsl" + "github.com/launchrctl/launchr" +) + +func main() { + launchr.RunAndExit() +} diff --git a/cmd/dsl/testdata/skill_test.yaml b/cmd/dsl/testdata/skill_test.yaml new file mode 100644 index 0000000..f387eac --- /dev/null +++ b/cmd/dsl/testdata/skill_test.yaml @@ -0,0 +1,55 @@ +kind: Skill +metadata: + pcn: cognition.skills.data-insights + pcsn: data-insights-skill + pck: Skill + pcl: Cognition + pcc: cognition.skills.data-insights + pcln: /usr/local/bin/skills + pct: + - data + - insights + pcv: 1.5.0 + pci: registry.example.com/cognition/data-insights-skill:stable + +name: cognition.skills.data-insights +shortName: data-insights-skill +namespace: cognition +owner: Data Science Team +apiVersion: v1 +description: A skill for transforming raw data into actionable insights using advanced analytics. + +settings: + skillValidationRequired: true + skillStage: knowledge + +secrets: + apiKey: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBOVlB0bjRqMUNwbzRRTmor + clUrVG0xNHllZnNJSFpSVUVlUm9iQXFnTlJZCk1idWI3VTFjVFQ5M2Q2WUhLclFj + MmtmTmdqUkkzQUJSa2VWNGZrYnVYdE0KLT4gWDI1NTE5IFlyZE85ZVc3enloZ0Iz + T1A5Wk9ycnJyNVFrSTdhek5BV1lsc0g5djZNaUEKUmVVU0UxWGdvWS81ZFFPeHdj + K0hEcGtLRjBuQ3lDanZlZGhZbFVtaVVMcwotLS0gNXZObWpPakpMOTlQczVwUUFo + Zk1oN01LOWdEcEM2OHlPQTRiME96UzlXdwrKzsR1W5/XSGJ4OKpMv6f1ilLaKeKI + JgaHoRiPPgECnNO0C1O0Yw== + -----END AGE ENCRYPTED FILE----- + authToken: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBIcVZRaUlNNjdrYklsUVF5 + UWFZTHRFNndGUWZGeVF4OGMvSTBrYWU5UEZvCkM0b2EvbjhIdnBHREdSSDJqOGc1 + Q2hsd0t2em1iTGxsSUhhaWdqeDhtVWMKLT4gWDI1NTE5IDVJT3BTYk0zeWd3Q0My + bFhFbFdnLzlwdDhTd28vTHVxYitRZkkrRXFDaXcKOXlwQ2I3a3lpczZsMWFZNERl + Vnp5a1p5RC9OSm1CK2FHV3hwMENsbUpUVQotLS0gRXZ5VmxxVkE3UTRQR1NGRk1k + T2tEOTVPVEhDM0dTVURUUWxLWDNtWjQ5MArfc+PTEYptAGMQuVN3m1m2ojumaTJ4 + AbOGVVAbvmsZlUVOyg== + -----END AGE ENCRYPTED FILE----- + +dependencies: + - cognition.services.data-pipeline + - cognition.services.analytics + +hooks: + initialize: plasmactl cognition.skills.data-insights:initialize + build: plasmactl cognition.skills.data-insights:build + expose: plasmactl cognition.skills.data-insights:expose diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..f000e71 --- /dev/null +++ b/go.mod @@ -0,0 +1,92 @@ +module dsl + +go 1.23.2 + +replace github.com/mstrielnikov/keyring => github.com/launchrctl/keyring v0.2.6 + +require ( + github.com/go-playground/validator/v10 v10.23.0 + github.com/launchrctl/launchr v0.16.4 + github.com/mstrielnikov/keyring v0.2.6 + github.com/spf13/cobra v1.8.1 + github.com/spf13/viper v1.19.0 + golang.org/x/crypto v0.31.0 + gopkg.in/yaml.v3 v3.0.1 +) + +require ( + atomicgo.dev/cursor v0.2.0 // indirect + atomicgo.dev/keyboard v0.2.9 // indirect + atomicgo.dev/schedule v0.1.0 // indirect + filippo.io/age v1.2.1 // indirect + github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect + github.com/Microsoft/go-winio v0.6.2 // indirect + github.com/containerd/console v1.0.4 // indirect + github.com/containerd/log v0.1.0 // indirect + github.com/distribution/reference v0.6.0 // indirect + github.com/docker/docker v27.3.1+incompatible // indirect + github.com/docker/go-connections v0.5.0 // indirect + github.com/docker/go-units v0.5.0 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.3 // indirect + github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/gookit/color v1.5.4 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/klauspost/compress v1.17.11 // indirect + github.com/knadh/koanf v1.5.0 // indirect + github.com/leodido/go-urn v1.4.0 // indirect + github.com/lithammer/fuzzysearch v1.1.8 // indirect + github.com/magiconair/properties v1.8.7 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/moby/docker-image-spec v1.3.1 // indirect + github.com/moby/patternmatcher v0.6.0 // indirect + github.com/moby/sys/sequential v0.6.0 // indirect + github.com/moby/sys/signal v0.7.1 // indirect + github.com/moby/sys/user v0.3.0 // indirect + github.com/moby/sys/userns v0.1.0 // indirect + github.com/moby/term v0.5.0 // indirect + github.com/morikuni/aec v1.0.0 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.1.0 // indirect + github.com/pelletier/go-toml/v2 v2.2.2 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pterm/pterm v0.12.79 // indirect + github.com/rivo/uniseg v0.4.7 // indirect + github.com/sagikazarmark/locafero v0.4.0 // indirect + github.com/sagikazarmark/slog-shim v0.1.0 // indirect + github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect + github.com/sourcegraph/conc v0.3.0 // indirect + github.com/spf13/afero v1.11.0 // indirect + github.com/spf13/cast v1.6.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/subosito/gotenv v1.6.0 // indirect + github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 // indirect + go.opentelemetry.io/otel v1.32.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.32.0 // indirect + go.opentelemetry.io/otel/metric v1.32.0 // indirect + go.opentelemetry.io/otel/sdk v1.32.0 // indirect + go.opentelemetry.io/otel/trace v1.32.0 // indirect + go.opentelemetry.io/proto/otlp v1.4.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + go.uber.org/mock v0.5.0 // indirect + go.uber.org/multierr v1.9.0 // indirect + golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect + golang.org/x/mod v0.21.0 // indirect + golang.org/x/net v0.31.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/term v0.27.0 // indirect + golang.org/x/text v0.21.0 // indirect + google.golang.org/protobuf v1.35.2 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..61008ca --- /dev/null +++ b/go.sum @@ -0,0 +1,642 @@ +atomicgo.dev/assert v0.0.2 h1:FiKeMiZSgRrZsPo9qn/7vmr7mCsh5SZyXY4YGYiYwrg= +atomicgo.dev/assert v0.0.2/go.mod h1:ut4NcI3QDdJtlmAxQULOmA13Gz6e2DWbSAS8RUOmNYQ= +atomicgo.dev/cursor v0.2.0 h1:H6XN5alUJ52FZZUkI7AlJbUc1aW38GWZalpYRPpoPOw= +atomicgo.dev/cursor v0.2.0/go.mod h1:Lr4ZJB3U7DfPPOkbH7/6TOtJ4vFGHlgj1nc+n900IpU= +atomicgo.dev/keyboard v0.2.9 h1:tOsIid3nlPLZ3lwgG8KZMp/SFmr7P0ssEN5JUsm78K8= +atomicgo.dev/keyboard v0.2.9/go.mod h1:BC4w9g00XkxH/f1HXhW2sXmJFOCWbKn9xrOunSFtExQ= +atomicgo.dev/schedule v0.1.0 h1:nTthAbhZS5YZmgYbb2+DH8uQIZcTlIrd4eYr3UQxEjs= +atomicgo.dev/schedule v0.1.0/go.mod h1:xeUa3oAkiuHYh8bKiQBRojqAMq3PXXbJujjb0hw8pEU= +c2sp.org/CCTV/age v0.0.0-20240306222714-3ec4d716e805 h1:u2qwJeEvnypw+OCPUHmoZE3IqwfuN5kgDfo5MLzpNM0= +c2sp.org/CCTV/age v0.0.0-20240306222714-3ec4d716e805/go.mod h1:FomMrUJ2Lxt5jCLmZkG3FHa72zUprnhd3v/Z18Snm4w= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +filippo.io/age v1.2.0 h1:vRDp7pUMaAJzXNIWJVAZnEf/Dyi4Vu4wI8S1LBzufhE= +filippo.io/age v1.2.0/go.mod h1:JL9ew2lTN+Pyft4RiNGguFfOpewKwSHm5ayKD/A4004= +filippo.io/age v1.2.1 h1:X0TZjehAZylOIj4DubWYU1vWQxv9bJpo+Uu2/LGhi1o= +filippo.io/age v1.2.1/go.mod h1:JL9ew2lTN+Pyft4RiNGguFfOpewKwSHm5ayKD/A4004= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/MarvinJWendt/testza v0.1.0/go.mod h1:7AxNvlfeHP7Z/hDQ5JtE3OKYT3XFUeLCDE2DQninSqs= +github.com/MarvinJWendt/testza v0.2.1/go.mod h1:God7bhG8n6uQxwdScay+gjm9/LnO4D3kkcZX4hv9Rp8= +github.com/MarvinJWendt/testza v0.2.8/go.mod h1:nwIcjmr0Zz+Rcwfh3/4UhBp7ePKVhuBExvZqnKYWlII= +github.com/MarvinJWendt/testza v0.2.10/go.mod h1:pd+VWsoGUiFtq+hRKSU1Bktnn+DMCSrDrXDpX2bG66k= +github.com/MarvinJWendt/testza v0.2.12/go.mod h1:JOIegYyV7rX+7VZ9r77L/eH6CfJHHzXjB69adAhzZkI= +github.com/MarvinJWendt/testza v0.3.0/go.mod h1:eFcL4I0idjtIx8P9C6KkAuLgATNKpX4/2oUqKc6bF2c= +github.com/MarvinJWendt/testza v0.4.2/go.mod h1:mSdhXiKH8sg/gQehJ63bINcCKp7RtYewEjXsvsVUPbE= +github.com/MarvinJWendt/testza v0.5.2 h1:53KDo64C1z/h/d/stCYCPY69bt/OSwjq5KpFNwi+zB4= +github.com/MarvinJWendt/testza v0.5.2/go.mod h1:xu53QFE5sCdjtMCKk8YMQ2MnymimEctc4n3EjyIYvEY= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/atomicgo/cursor v0.0.1/go.mod h1:cBON2QmmrysudxNBFthvMtN32r3jxVRIvzkUiF/RuIk= +github.com/aws/aws-sdk-go-v2 v1.9.2/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4= +github.com/aws/aws-sdk-go-v2/config v1.8.3/go.mod h1:4AEiLtAb8kLs7vgw2ZV3p2VZ1+hBavOc84hqxVNpCyw= +github.com/aws/aws-sdk-go-v2/credentials v1.4.3/go.mod h1:FNNC6nQZQUuyhq5aE5c7ata8o9e4ECGmS4lAXC7o1mQ= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.6.0/go.mod h1:gqlclDEZp4aqJOancXK6TN24aKhT0W0Ae9MHk3wzTMM= +github.com/aws/aws-sdk-go-v2/internal/ini v1.2.4/go.mod h1:ZcBrrI3zBKlhGFNYWvju0I3TR93I7YIgAfy82Fh4lcQ= +github.com/aws/aws-sdk-go-v2/service/appconfig v1.4.2/go.mod h1:FZ3HkCe+b10uFZZkFdvf98LHW21k49W8o8J366lqVKY= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.3.2/go.mod h1:72HRZDLMtmVQiLG2tLfQcaWLCssELvGl+Zf2WVxMmR8= +github.com/aws/aws-sdk-go-v2/service/sso v1.4.2/go.mod h1:NBvT9R1MEF+Ud6ApJKM0G+IkPchKS7p7c2YPKwHmBOk= +github.com/aws/aws-sdk-go-v2/service/sts v1.7.2/go.mod h1:8EzeIqfWt2wWT4rJVu3f21TfrhJ8AEMzVybRNSb/b4g= +github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= +github.com/containerd/console v1.0.4 h1:F2g4+oChYvBTsASRTz8NP6iIAi97J3TtSAsLbIFn4ro= +github.com/containerd/console v1.0.4/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk= +github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= +github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= +github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= +github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= +github.com/docker/docker v27.3.1+incompatible h1:KttF0XoteNTicmUtBO0L2tP+J7FGRFTjaEF4k6WdhfI= +github.com/docker/docker v27.3.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= +github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= +github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.23.0 h1:/PwmTwZhS0dPkav3cdK9kV1FsAmrL8sThn8IHr/sO+o= +github.com/go-playground/validator/v10 v10.23.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ= +github.com/gookit/color v1.5.0/go.mod h1:43aQb+Zerm/BWh2GnrgOQm7ffz7tvQXEKV6BFMl7wAo= +github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0= +github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 h1:TmHmbvxPmaegwhDubVz0lICL0J5Ka2vwTzhoePEXsGE= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0/go.mod h1:qztMSjm835F2bXf+5HKAPIS5qsmQDqZna/PgVt4rWtI= +github.com/hashicorp/consul/api v1.13.0/go.mod h1:ZlVrynguJKcYr54zGaDbaL3fOvKC9m72FhPvA8T35KQ= +github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI= +github.com/hashicorp/go-hclog v0.8.0/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= +github.com/hashicorp/go-plugin v1.0.1/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY= +github.com/hashicorp/go-retryablehttp v0.5.4/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-rootcerts v1.0.1/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= +github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= +github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= +github.com/hashicorp/vault/api v1.0.4/go.mod h1:gDcqh3WGcR1cpF5AJz/B1UFheUEneMoIospckxBxk6Q= +github.com/hashicorp/vault/sdk v0.1.13/go.mod h1:B+hVj7TpuQY1Y/GPbCpffmgd+tSEwvhkWnjtSYCaS2M= +github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= +github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= +github.com/hjson/hjson-go/v4 v4.0.0 h1:wlm6IYYqHjOdXH1gHev4VoXCaW20HdQAGCxdOEEg2cs= +github.com/hjson/hjson-go/v4 v4.0.0/go.mod h1:KaYt3bTw3zhBjYqnXkYywcYctk0A2nxeEFTse3rH13E= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= +github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= +github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.0.10/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= +github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= +github.com/klauspost/cpuid/v2 v2.2.3 h1:sxCkb+qR91z4vsqw4vGGZlDgPz3G7gjaLyK3V8y70BU= +github.com/klauspost/cpuid/v2 v2.2.3/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= +github.com/knadh/koanf v1.5.0 h1:q2TSd/3Pyc/5yP9ldIrSdIz26MCcyNQzW0pEAugLPNs= +github.com/knadh/koanf v1.5.0/go.mod h1:Hgyjp4y8v44hpZtPzs7JZfRAW5AhN7KfZcwv1RYggDs= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/launchrctl/keyring v0.2.6 h1:R4MbNmlTw7M+Oz/ai/ikTPsbY3k+DVtnAvInYsO83PA= +github.com/launchrctl/keyring v0.2.6/go.mod h1:VIjbUHBeMRkbp9gmRWpyIiRzSU9cdiSPCXdJl1RItCk= +github.com/launchrctl/launchr v0.16.4 h1:uVbRLZZQuTGhjDBN8kLpdPGeZZkpBjiiSjCxDEmeM6g= +github.com/launchrctl/launchr v0.16.4/go.mod h1:EGMn1cGbaGEpo+eQyJVdlq9BO3OSIDP60BOPS2odDxo= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +github.com/lithammer/fuzzysearch v1.1.8 h1:/HIuJnjHuXS8bKaiTMeeDlW2/AyIWk2brx1V8LFgLN4= +github.com/lithammer/fuzzysearch v1.1.8/go.mod h1:IdqeyBClc3FFqSzYq/MXESsS4S0FsZ5ajtkr5xPLts4= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= +github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= +github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= +github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= +github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= +github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU= +github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko= +github.com/moby/sys/signal v0.7.1 h1:PrQxdvxcGijdo6UXXo/lU/TvHUWyPhj7UOpSo8tuvk0= +github.com/moby/sys/signal v0.7.1/go.mod h1:Se1VGehYokAkrSQwL4tDzHvETwUZlnY7S5XtQ50mQp8= +github.com/moby/sys/user v0.3.0 h1:9ni5DlcW5an3SvRSx4MouotOygvzaXbaSrc/wGDFWPo= +github.com/moby/sys/user v0.3.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs= +github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g= +github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28= +github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= +github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/npillmayer/nestext v0.1.3/go.mod h1:h2lrijH8jpicr25dFY+oAJLyzlya6jhnuG+zWp9L0Uk= +github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= +github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pelletier/go-toml v1.7.0 h1:7utD74fnzVc/cpcyy8sjrlFr5vYpypUixARcHIMIGuI= +github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= +github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= +github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= +github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/pterm/pterm v0.12.27/go.mod h1:PhQ89w4i95rhgE+xedAoqous6K9X+r6aSOI2eFF7DZI= +github.com/pterm/pterm v0.12.29/go.mod h1:WI3qxgvoQFFGKGjGnJR849gU0TsEOvKn5Q8LlY1U7lg= +github.com/pterm/pterm v0.12.30/go.mod h1:MOqLIyMOgmTDz9yorcYbcw+HsgoZo3BQfg2wtl3HEFE= +github.com/pterm/pterm v0.12.31/go.mod h1:32ZAWZVXD7ZfG0s8qqHXePte42kdz8ECtRyEejaWgXU= +github.com/pterm/pterm v0.12.33/go.mod h1:x+h2uL+n7CP/rel9+bImHD5lF3nM9vJj80k9ybiiTTE= +github.com/pterm/pterm v0.12.36/go.mod h1:NjiL09hFhT/vWjQHSj1athJpx6H8cjpHXNAK5bUw8T8= +github.com/pterm/pterm v0.12.40/go.mod h1:ffwPLwlbXxP+rxT0GsgDTzS3y3rmpAO1NMjUkGTYf8s= +github.com/pterm/pterm v0.12.79 h1:lH3yrYMhdpeqX9y5Ep1u7DejyHy7NSQg9qrBjF9dFT4= +github.com/pterm/pterm v0.12.79/go.mod h1:1v/gzOF1N0FsjbgTHZ1wVycRkKiatFvJSJC4IGaQAAo= +github.com/rhnvrm/simples3 v0.6.1/go.mod h1:Y+3vYm2V7Y4VijFoJHHTrja6OgPrJ2cBti8dPGkC3sA= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= +github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= +github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= +github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= +github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4= +github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= +github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= +github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= +github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= +github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= +github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= +github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs= +github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= +github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.etcd.io/etcd/api/v3 v3.5.4/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A= +go.etcd.io/etcd/client/pkg/v3 v3.5.4/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/v3 v3.5.4/go.mod h1:ZaRkVgBZC+L+dLCjTcF1hRXpgZXQPOvnA/Ak/gq3kiY= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 h1:UP6IpuHFkUgOQL9FFQFrZ+5LiwhhYRbi7VZSIx6Nj5s= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0/go.mod h1:qxuZLtbq5QDtdeSHsS7bcf6EH6uO6jUAgk764zd3rhM= +go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U= +go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.32.0 h1:IJFEoHiytixx8cMiVAO+GmHR6Frwu+u5Ur8njpFO6Ac= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.32.0/go.mod h1:3rHrKNtLIoS0oZwkY2vxi+oJcwFRWdtUyRII+so45p8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.31.0 h1:lUsI2TYsQw2r1IASwoROaCnjdj2cvC2+Jbxvk6nHnWU= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.31.0/go.mod h1:2HpZxxQurfGxJlJDblybejHB6RX6pmExPNe517hREw4= +go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M= +go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8= +go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4= +go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU= +go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM= +go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= +go.opentelemetry.io/proto/otlp v1.4.0 h1:TA9WRvW6zMwP+Ssb6fLoUIuirti1gGbP28GcKG1jgeg= +go.opentelemetry.io/proto/otlp v1.4.0/go.mod h1:PPBWZIP98o2ElSqI35IHfu7hIhSwvc5N38Jw8pXuGFY= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= +go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= +go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= +go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.30.0 h1:RwoQn3GkWiMkzlX562cLB7OxWvjH1L8xutO2WoJcRoY= +golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= +golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= +golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= +golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 h1:9+tzLLstTlPTRyJTh+ah5wIMsBW5c4tQwGTN3thOW9Y= +google.golang.org/genproto/googleapis/api v0.0.0-20241118233622-e639e219e697 h1:pgr/4QbFyktUv9CtQ/Fq4gzEE6/Xs7iCXbktaGzLHbQ= +google.golang.org/genproto/googleapis/api v0.0.0-20241118233622-e639e219e697/go.mod h1:+D9ySVjN8nY8YCVjc5O7PZDIdZporIDY3KaGfJunh88= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697 h1:LWZqQOEjDyONlF1H6afSWpAL/znlREo2tHfLoe+8LMA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= +google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.68.0 h1:aHQeeJbo8zAkAa3pRzrVjZlbz6uSfeOXlJNQM0RAbz0= +google.golang.org/grpc v1.68.0/go.mod h1:fmSPC5AsjSBCK54MyHRx48kpOti1/jRfOlwEWywNjWA= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io= +google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= +gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/plugins/dsl/plugin.go b/plugins/dsl/plugin.go new file mode 100644 index 0000000..5d0b929 --- /dev/null +++ b/plugins/dsl/plugin.go @@ -0,0 +1,136 @@ +package dsl + +import ( + cli "dsl/api/launchr" + "github.com/launchrctl/launchr" +) + +func init() { + launchr.RegisterPlugin(&Plugin{}) +} + +// Plugin is [launchr.Plugin] plugin providing compose. +type Plugin struct { + wd string +} + +// PluginInfo implements [launchr.Plugin] interface. +func (p *Plugin) PluginInfo() launchr.PluginInfo { + return launchr.PluginInfo{Weight: 10} +} + +// OnAppInit implements [launchr.OnAppInitPlugin] interface. +func (p *Plugin) OnAppInit(app launchr.App) error { + //app.GetService(&p.k) + p.wd = app.GetWD() + //buildDir := filepath.Join(p.wd, compose.BuildDir) + //app.RegisterFS(action.NewDiscoveryFS(os.DirFS(BuildDir), p.wd)) + return nil +} + +// CobraAddCommands implements [launchr.CobraPlugin] interface to provide compose functionality. +func (p *Plugin) CobraAddCommands(rootCmd *launchr.Command) error { + var flagValidateExt string + var flagValidateOut bool + var flagValidateSilent bool + + var validateCmd = &launchr.Command{ + Use: "validate [...manifests] --ext --out", + Short: "validation utility for schema and components according to schema", + Long: `command to perform Plasma Component yaml schema validation`, + RunE: func(cmd *launchr.Command, args []string) error { + return cli.NewCmdValidate(cmd, args) + }, + } + validateCmd.Flags().StringVarP(&flagValidateExt, "ext", "x", cli.CmdManifestExtDefault, "file extension regex to read plasma manifests") + validateCmd.Flags().BoolVarP(&flagValidateOut, "out", "o", !cli.CmdOutDefault, "stdout validated manifests") + validateCmd.Flags().BoolVarP(&flagValidateSilent, "help", "h", cli.CmdSilentDefault, "show help on failure") + rootCmd.AddCommand(validateCmd) + + //var flagInteractive bool + var secretCmd = &launchr.Command{ + Use: "secret [...manifests]", + Short: "secret management utility for secret containing yaml fields", + Long: `command to set encrypted secret value by key`, + } + rootCmd.AddCommand(secretCmd) + + var flagSecretGetExt string + var flagSecretGetOut bool + var flagSecretGetSilent bool + var flagSecretGetKey string + var flagSecretGetEncryption bool + var flagSecretGetPrivateKey string + var flagSecretGetPublicKey string + + var secretGetCmd = &launchr.Command{ + Use: "get --key [KEY] --privkey [PRIVKEY] --encryption --out [...MANIFESTS]", + Short: "subcommand to get secret value by key", + Long: `command to get decrypted secret value by key in kv and user private key`, + RunE: func(cmd *launchr.Command, args []string) error { + return cli.NewCmdSecretGet(cmd, args) + }, + } + secretGetCmd.Flags().StringVarP(&flagSecretGetExt, "ext", "x", cli.CmdSecretExtDefault, "file extensions to read plasma components") + secretGetCmd.Flags().BoolVarP(&flagSecretGetOut, "out", "o", cli.CmdOutDefault, "stdout secret value by key") + secretGetCmd.Flags().BoolVarP(&flagSecretGetSilent, "help", "h", cli.CmdSilentDefault, "show help on failure") + secretGetCmd.Flags().StringVarP(&flagSecretGetKey, "key", "k", "", "key to get value by") + secretGetCmd.Flags().BoolVarP(&flagSecretGetEncryption, "encryption", "c", cli.CmdSecretEncryptionDefault, "enable encrypted mode. Will decrypted secret for output. It will out encrypted value otherwise") + secretGetCmd.Flags().StringVarP(&flagSecretGetPrivateKey, "privkey", "d", "", "provide private (decrypt) key of key pair") + secretGetCmd.Flags().StringVarP(&flagSecretGetPublicKey, "pubkey", "e", "", "provide public (encrypt) key of key pair") + secretCmd.AddCommand(secretGetCmd) + + var flagSecretSetOut bool + var flagSecretSetExt string + var flagSecretSetSilent bool + var flagSecretSetKey string + var flagSecretSetSecret string + var flagSecretSetEncryption bool + var flagSecretSetPrivateKey string + var flagSecretSetPublicKey string + + var secretSetCmd = &launchr.Command{ + Use: "set --key [KEY] --value [VALUE] [...manifests]", + Short: "subcommand to set secret value by key and update manifest secrets", + Long: `setting of empty string deletes key-value. Setting of unexistent key creates new key-value. All [...manifests] provided are affected by this utility`, + RunE: func(cmd *launchr.Command, args []string) error { + return cli.NewCmdSecretSet(cmd, args) + }, + } + secretSetCmd.Flags().StringVarP(&flagSecretSetExt, "ext", "x", cli.CmdSecretExtDefault, "file extensions to read plasma manifests") + secretSetCmd.Flags().BoolVarP(&flagSecretSetOut, "out", "o", cli.CmdOutDefault, "stdout updated secret") + secretSetCmd.Flags().BoolVarP(&flagSecretSetSilent, "help", "h", cli.CmdSilentDefault, "show help on failure") + secretSetCmd.Flags().StringVarP(&flagSecretSetKey, "key", "k", "", "key to set value") + secretSetCmd.Flags().StringVarP(&flagSecretSetSecret, "secret", "s", "", "plain value to update secret by key") + secretSetCmd.Flags().BoolVarP(&flagSecretSetEncryption, "encryption", "c", cli.CmdSecretEncryptionDefault, "enable encrypted mode. Consider secret fields are encrypted values. The mode performs encryption of new secret before appending (if it's not encrypted already). Otherwise, secrets considered plain and no encryption enforced. Recommended if you are updating secret with already encrypted value") + secretSetCmd.Flags().StringVarP(&flagSecretSetPrivateKey, "privkey", "d", "", "provide private (decryption) key") + secretSetCmd.Flags().StringVarP(&flagSecretSetPublicKey, "pubkey", "e", "", "provide public (encryption) key") + secretCmd.AddCommand(secretSetCmd) + + var flagSecretListExt string + var flagSecretListEncryption bool + var flagSecretListOut bool + var flagSecretListSilent bool + var flagSecretListKeys []string + var flagSecretListPrivateKey string + var flagSecretListPublicKey string + + var secretListCmd = &launchr.Command{ + Use: "list [...manifests]", + Short: "secret management utility for secret containing yaml fields", + Long: `command to list secret KV in encrypted and plain modes`, + RunE: func(cmd *launchr.Command, args []string) error { + return cli.NewCmdSecretList(cmd, args) + }, + } + secretListCmd.Flags().StringVarP(&flagSecretListExt, "ext", "x", cli.CmdSecretExtDefault, "file extensions to read plasma components") + secretListCmd.Flags().BoolVarP(&flagSecretListOut, "out", "o", cli.CmdOutDefault, "stdout queried secrets as list") + secretListCmd.Flags().BoolVarP(&flagSecretListSilent, "help", "h", cli.CmdSilentDefault, "show help on failure") + secretListCmd.Flags().StringArrayVarP(&flagSecretListKeys, "keys", "k", []string{}, "list of keys to lookup") + secretListCmd.Flags().BoolVarP(&flagSecretListEncryption, "encryption", "c", cli.CmdSecretEncryptionDefault, "enable encrypted mode. Will decrypted secret for output. It will out encrypted value otherwise") + secretListCmd.Flags().StringVarP(&flagSecretListPrivateKey, "privkey", "d", "", "provide private (decryption) key") + secretListCmd.Flags().StringVarP(&flagSecretListPublicKey, "pubkey", "e", "", "provide public (encryption) key") + secretCmd.AddCommand(secretListCmd) + + return nil +} diff --git a/service/manifest.go b/service/manifest.go new file mode 100644 index 0000000..202e318 --- /dev/null +++ b/service/manifest.go @@ -0,0 +1,139 @@ +package service + +import ( + "dsl/api/fs" + "dsl/api/kv" + "dsl/api/manifest/definition" + "dsl/api/reader" + "dsl/api/security" + "errors" + "fmt" + "os" +) + +type ManifestService struct { + manifests map[string]definition.Component +} + +func (s *ManifestService) ReadManifestFiles(paths []string, ext string) error { + files, err := fs.DiscoverFiles(paths, ext) + if err != nil { + return err + } + + s.manifests = make(map[string]definition.Component, len(files)) + + for _, file := range files { + manifest, err := s.readManifestFile(file) + if err != nil { + return err + } + + s.manifests[file] = manifest + } + + return nil +} + +func (s *ManifestService) readManifestFile(file string) (definition.Component, error) { + serialized, err := os.ReadFile(file) + if err != nil { + return nil, fmt.Errorf("error while reading '%s': '%s'", file, err.Error()) + } + + component, err := reader.ParseComponent(serialized) + if err != nil { + return nil, fmt.Errorf("error while creating component from file '%s':\n%s\n", file, err.Error()) + } + + if err := component.Unmarshal(serialized); err != nil { + return nil, fmt.Errorf("error '%s' while deserializing '%s' with following content:\n```\n%s\n```", err.Error(), file, string(serialized)) + } + + if err := component.Validate(); err != nil { + return nil, fmt.Errorf("validation error invalid component file '%s': '%s'", file, err.Error()) + } + + return component, nil +} + +func (s *ManifestService) SaveManifestFile(file string) error { + manifest, ok := s.manifests[file] + if !ok { + return fmt.Errorf("manifest save error. No such manifest file '%s'", file) + } + + if err := manifest.Validate(); err != nil { + return fmt.Errorf("validation error invalid component file '%s': '%s'", file, err.Error()) + } + + serialized, err := manifest.Marshal() + if err != nil { + return fmt.Errorf("error '%s' while serializing '%s' with following content:\n```\n%s\n```", err.Error(), file, string(serialized)) + } + + if err := fs.WriteFile(file, serialized); err != nil { + return fmt.Errorf("error while saving manifest. Error writing to file '%s' of content:\n%s\nerror processing data: '%s'", file, err, err.Error()) + } + + return nil +} + +func (s *ManifestService) GetManifests() map[string]definition.Component { + return s.manifests +} + +func (s *ManifestService) GetSecret(key string, encryption security.Encryption) (string, error) { + for _, manifest := range s.manifests { + secrets := manifest.GetSecrets(encryption) + + secret, err := secrets.Get(key) + if !errors.Is(err, kv.KVKeyNotExistsError{}) && err != nil { + return "", err + } else { + return secret, nil + } + } + + return "", kv.NewKVKeyNotExistsError(key) +} + +func (s *ManifestService) SetSecret(key, value string, encryption security.Encryption, save bool) error { + for file, manifest := range s.manifests { + secrets := manifest.GetSecrets(encryption) + + if err := secrets.Set(key, value); err != nil { + return err + } + + if err := manifest.UpdateSecrets(secrets, encryption); err != nil { + return err + } + + if save { + if err := s.SaveManifestFile(file); err != nil { + return err + } + } + } + + return nil +} + +func (s *ManifestService) GetSecretList(keys []string, encryption security.Encryption) (kv.KV, error) { + var secretKV kv.KV + for _, manifest := range s.manifests { + secrets := manifest.GetSecrets(encryption) + + batch, err := secrets.GetBatch(keys) + if !errors.Is(err, kv.KVKeyNotExistsError{}) && err != nil { + return nil, err + } + + if err := secretKV.SetBatch(batch); err != nil { + return nil, err + } + } + + return secretKV, nil +}