mirror of
https://github.com/luxfi/mpc.git
synced 2026-09-24 00:26:24 +00:00
Update scripts, kms integration
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
name: Build and Push Docker Images
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- develop
|
||||
tags:
|
||||
- 'v*'
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
- develop
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: luxfi/lux-mpc
|
||||
|
||||
jobs:
|
||||
build-and-push:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Log in to GitHub Container Registry
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Extract metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
tags: |
|
||||
type=ref,event=branch
|
||||
type=ref,event=pr
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=semver,pattern={{major}}
|
||||
type=sha,prefix={{branch}}-
|
||||
type=raw,value=latest,enable={{is_default_branch}}
|
||||
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
|
||||
- name: Generate SBOM
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: anchore/sbom-action@v0
|
||||
with:
|
||||
image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }}
|
||||
format: spdx-json
|
||||
output-file: sbom.spdx.json
|
||||
|
||||
- name: Upload SBOM
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: sbom
|
||||
path: sbom.spdx.json
|
||||
retention-days: 30
|
||||
|
||||
security-scan:
|
||||
needs: build-and-push
|
||||
if: github.event_name != 'pull_request'
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: read
|
||||
security-events: write
|
||||
|
||||
steps:
|
||||
- name: Run Trivy vulnerability scanner
|
||||
uses: aquasecurity/trivy-action@master
|
||||
with:
|
||||
image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
|
||||
format: 'sarif'
|
||||
output: 'trivy-results.sarif'
|
||||
|
||||
- name: Upload Trivy scan results to GitHub Security tab
|
||||
uses: github/codeql-action/upload-sarif@v3
|
||||
with:
|
||||
sarif_file: 'trivy-results.sarif'
|
||||
category: 'trivy'
|
||||
|
||||
- name: Run Grype vulnerability scanner
|
||||
uses: anchore/scan-action@v3
|
||||
with:
|
||||
image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
|
||||
output-format: sarif
|
||||
output-file: grype-results.sarif
|
||||
|
||||
- name: Upload Grype scan results
|
||||
uses: github/codeql-action/upload-sarif@v3
|
||||
with:
|
||||
sarif_file: grype-results.sarif
|
||||
category: 'grype'
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
# Build stage
|
||||
FROM golang:1.23-alpine AS builder
|
||||
|
||||
RUN apk add --no-cache git make
|
||||
|
||||
WORKDIR /build
|
||||
|
||||
# Copy go mod files
|
||||
COPY go.mod go.sum ./
|
||||
|
||||
# Download dependencies
|
||||
RUN go mod download
|
||||
|
||||
# Copy source code
|
||||
COPY . .
|
||||
|
||||
# Build the binaries
|
||||
RUN go build -o lux-mpc ./cmd/lux-mpc
|
||||
RUN go build -o lux-mpc-cli ./cmd/lux-mpc-cli
|
||||
RUN go build -o lux-mpc-bridge ./cmd/lux-mpc-bridge || true
|
||||
|
||||
# Runtime stage
|
||||
FROM alpine:latest
|
||||
|
||||
RUN apk add --no-cache ca-certificates curl bash
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Copy binaries from builder
|
||||
COPY --from=builder /build/lux-mpc /usr/local/bin/
|
||||
COPY --from=builder /build/lux-mpc-cli /usr/local/bin/
|
||||
COPY --from=builder /build/lux-mpc-bridge /usr/local/bin/ 2>/dev/null || true
|
||||
|
||||
# Copy config templates
|
||||
COPY config.yaml.template /app/
|
||||
COPY peers.json /app/
|
||||
|
||||
# Create data and log directories
|
||||
RUN mkdir -p /data/mpc /app/logs /app/identity
|
||||
|
||||
# Expose ports
|
||||
EXPOSE 6000 8080 9090
|
||||
|
||||
# Health check
|
||||
HEALTHCHECK --interval=10s --timeout=3s --start-period=5s --retries=3 \
|
||||
CMD curl -f http://localhost:8080/health || exit 1
|
||||
|
||||
# Default command
|
||||
CMD ["lux-mpc", "start", "--config", "/app/config.yaml"]
|
||||
+11
-1
@@ -118,6 +118,16 @@ func runNode(ctx context.Context, c *cli.Command) error {
|
||||
badgerKV := NewBadgerKV(nodeName, nodeID)
|
||||
defer badgerKV.Close()
|
||||
|
||||
// Wrap BadgerKV with KMS-enabled store if configured
|
||||
var kvStore kvstore.KVStore = badgerKV
|
||||
kmsEnabledStore, err := mpc.NewKMSEnabledKVStore(badgerKV, nodeID)
|
||||
if err != nil {
|
||||
logger.Warn("Failed to create KMS-enabled store, using regular BadgerDB", "error", err)
|
||||
} else {
|
||||
kvStore = kmsEnabledStore
|
||||
logger.Info("Using KMS-enabled storage for sensitive keys")
|
||||
}
|
||||
|
||||
// Start background backup job
|
||||
backupEnabled := viper.GetBool("backup_enabled")
|
||||
if backupEnabled {
|
||||
@@ -174,7 +184,7 @@ func runNode(ctx context.Context, c *cli.Command) error {
|
||||
nodeID,
|
||||
peerNodeIDs,
|
||||
pubsub,
|
||||
badgerKV,
|
||||
kvStore,
|
||||
keyinfoStore,
|
||||
peerRegistry,
|
||||
identityStore,
|
||||
|
||||
@@ -9,6 +9,7 @@ require (
|
||||
github.com/dgraph-io/badger/v4 v4.8.0
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/hashicorp/consul/api v1.29.4
|
||||
github.com/luxfi/kms-go v0.0.1
|
||||
github.com/luxfi/threshold v1.0.0
|
||||
github.com/mitchellh/mapstructure v1.5.0
|
||||
github.com/nats-io/nats.go v1.36.0
|
||||
@@ -19,12 +20,30 @@ require (
|
||||
github.com/urfave/cli/v2 v2.27.7
|
||||
github.com/urfave/cli/v3 v3.3.8
|
||||
go.uber.org/zap v1.27.0
|
||||
golang.org/x/crypto v0.40.0
|
||||
golang.org/x/term v0.33.0
|
||||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go/auth v0.7.0 // indirect
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.2 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.7.0 // indirect
|
||||
cloud.google.com/go/iam v1.1.11 // indirect
|
||||
github.com/agl/ed25519 v0.0.0-20200225211852-fd4d107ace12 // indirect
|
||||
github.com/armon/go-metrics v0.4.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2 v1.27.2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/config v1.27.18 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.18 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.5 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.9 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.9 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.11 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.20.11 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.24.5 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.28.12 // indirect
|
||||
github.com/aws/smithy-go v1.20.2 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect
|
||||
github.com/cronokirby/saferith v0.33.0 // indirect
|
||||
@@ -33,13 +52,21 @@ require (
|
||||
github.com/dgraph-io/ristretto/v2 v2.2.0 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/fatih/color v1.18.0 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/fsnotify/fsnotify v1.8.0 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.4.0 // indirect
|
||||
github.com/go-logr/logr v1.4.3 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-resty/resty/v2 v2.13.1 // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
|
||||
github.com/gofrs/flock v0.8.1 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/google/btree v1.1.3 // indirect
|
||||
github.com/google/flatbuffers v25.2.10+incompatible // indirect
|
||||
github.com/google/s2a-go v0.1.7 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.12.5 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-hclog v1.5.0 // indirect
|
||||
@@ -47,6 +74,7 @@ require (
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/hashicorp/go-rootcerts v1.0.2 // indirect
|
||||
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d // indirect
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
|
||||
github.com/hashicorp/serf v0.10.1 // indirect
|
||||
github.com/klauspost/compress v1.18.0 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
|
||||
@@ -55,11 +83,13 @@ require (
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/nats-io/nkeys v0.4.7 // indirect
|
||||
github.com/nats-io/nuid v1.0.1 // indirect
|
||||
github.com/oracle/oci-go-sdk/v65 v65.95.2 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/sagikazarmark/locafero v0.7.0 // indirect
|
||||
github.com/sony/gobreaker v0.5.0 // indirect
|
||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||
github.com/spf13/afero v1.14.0 // indirect
|
||||
github.com/spf13/cast v1.9.2 // indirect
|
||||
@@ -67,21 +97,32 @@ require (
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
|
||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
|
||||
github.com/zeebo/blake3 v0.2.3 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect
|
||||
go.opentelemetry.io/otel v1.37.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.37.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.37.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/crypto v0.40.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20250718183923-645b1fa84792 // indirect
|
||||
golang.org/x/net v0.42.0 // indirect
|
||||
golang.org/x/oauth2 v0.30.0 // indirect
|
||||
golang.org/x/sync v0.16.0 // indirect
|
||||
golang.org/x/sys v0.34.0 // indirect
|
||||
golang.org/x/text v0.27.0 // indirect
|
||||
golang.org/x/time v0.5.0 // indirect
|
||||
google.golang.org/api v0.188.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250528174236-200df99c418a // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250728155136-f173205681a0 // indirect
|
||||
google.golang.org/grpc v1.74.2 // indirect
|
||||
google.golang.org/protobuf v1.36.6 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
replace github.com/agl/ed25519 => github.com/luxfi/edwards25519 v0.0.0-20200305024217-f36fc4b53d43
|
||||
replace (
|
||||
github.com/agl/ed25519 => github.com/luxfi/edwards25519 v0.0.0-20200305024217-f36fc4b53d43
|
||||
github.com/luxfi/kms-go => /Users/z/work/lux/kms-go
|
||||
)
|
||||
|
||||
@@ -1,7 +1,17 @@
|
||||
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/auth v0.7.0 h1:kf/x9B3WTbBUHkC+1VS8wwwli9TzhSt0vSTVBmMR8Ts=
|
||||
cloud.google.com/go/auth v0.7.0/go.mod h1:D+WqdrpcjmiCgWrXmLLxOVq1GACoE36chW6KXoEvuIw=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.2 h1:+TTV8aXpjeChS9M+aTtN/TjdQnzJvmzKFt//oWu7HX4=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.2/go.mod h1:wcYjgpZI9+Yu7LyYBg4pqSiaRkfEK3GQcpb7C/uyF1Q=
|
||||
cloud.google.com/go/compute/metadata v0.7.0 h1:PBWF+iiAerVNe8UCHxdOt6eHLVc3ydFeOCw78U8ytSU=
|
||||
cloud.google.com/go/compute/metadata v0.7.0/go.mod h1:j5MvL9PprKL39t166CoB1uVHfQMs4tFQZZcKwksXUjo=
|
||||
cloud.google.com/go/iam v1.1.11 h1:0mQ8UKSfdHLut6pH9FM3bI55KWR46ketn0PuXleDyxw=
|
||||
cloud.google.com/go/iam v1.1.11/go.mod h1:biXoiLWYIKntto2joP+62sd9uW5EpkZmKIvfNcTWlnQ=
|
||||
filippo.io/age v1.2.1 h1:X0TZjehAZylOIj4DubWYU1vWQxv9bJpo+Uu2/LGhi1o=
|
||||
filippo.io/age v1.2.1/go.mod h1:JL9ew2lTN+Pyft4RiNGguFfOpewKwSHm5ayKD/A4004=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
|
||||
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=
|
||||
@@ -15,15 +25,44 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj
|
||||
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/avast/retry-go v3.0.0+incompatible h1:4SOWQ7Qs+oroOTQOYnAHqelpCO0biHSxpiH9JdtuBj0=
|
||||
github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY=
|
||||
github.com/aws/aws-sdk-go-v2 v1.27.2 h1:pLsTXqX93rimAOZG2FIYraDQstZaaGVVN4tNw65v0h8=
|
||||
github.com/aws/aws-sdk-go-v2 v1.27.2/go.mod h1:ffIFB97e2yNsv4aTSGkqtHnppsIJzw7G7BReUZ3jCXM=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.27.18 h1:wFvAnwOKKe7QAyIxziwSKjmer9JBMH1vzIL6W+fYuKk=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.27.18/go.mod h1:0xz6cgdX55+kmppvPm2IaKzIXOheGJhAufacPJaXZ7c=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.18 h1:D/ALDWqK4JdY3OFgA2thcPO1c9aYTT5STS/CvnkqY1c=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.18/go.mod h1:JuitCWq+F5QGUrmMPsk945rop6bB57jdscu+Glozdnc=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.5 h1:dDgptDO9dxeFkXy+tEgVkzSClHZje/6JkPW5aZyEvrQ=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.5/go.mod h1:gjvE2KBUgUQhcv89jqxrIxH9GaKs1JbZzWejj/DaHGA=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.9 h1:cy8ahBJuhtM8GTTSyOkfy6WVPV1IE+SS5/wfXUYuulw=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.9/go.mod h1:CZBXGLaJnEZI6EVNcPd7a6B5IC5cA/GkRWtu9fp3S6Y=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.9 h1:A4SYk07ef04+vxZToz9LWvAXl9LW0NClpPpMsi31cz0=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.9/go.mod h1:5jJcHuwDagxN+ErjQ3PU3ocf6Ylc/p9x+BLO/+X4iXw=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 h1:Ji0DY1xUsUr3I8cHps0G+XM3WWU16lP6yG8qu1GAZAs=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2/go.mod h1:5CsjAbs3NlGQyZNFACh+zztPDI7fU6eW9QsxjfnuBKg=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.11 h1:o4T+fKxA3gTMcluBNZZXE9DNaMkJuUL1O3mffCUjoJo=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.11/go.mod h1:84oZdJ+VjuJKs9v1UTC9NaodRZRseOXCTgku+vQJWR8=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.20.11 h1:gEYM2GSpr4YNWc6hCd5nod4+d4kd9vWIAWrmGuLdlMw=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.20.11/go.mod h1:gVvwPdPNYehHSP9Rs7q27U1EU+3Or2ZpXvzAYJNh63w=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.24.5 h1:iXjh3uaH3vsVcnyZX7MqCoCfcyxIrVE9iOQruRaWPrQ=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.24.5/go.mod h1:5ZXesEuy/QcO0WUnt+4sDkxhdXRHTu2yG0uCSH8B6os=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.28.12 h1:M/1u4HBpwLuMtjlxuI2y6HoVLzF5e2mfxHCg7ZVMYmk=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.28.12/go.mod h1:kcfd+eTdEi/40FIbLq4Hif3XMXnl5b/+t/KTfLt9xIk=
|
||||
github.com/aws/smithy-go v1.20.2 h1:tbp628ireGtzcHDDmLT/6ADHidqnwgF57XOXZe6tp4Q=
|
||||
github.com/aws/smithy-go v1.20.2/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E=
|
||||
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/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/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
|
||||
github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
|
||||
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/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||
@@ -45,11 +84,17 @@ github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da h1:aIftn67I1fkbMa5
|
||||
github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
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/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/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
||||
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
|
||||
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
|
||||
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.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
|
||||
@@ -65,26 +110,55 @@ github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
github.com/go-logr/logr v1.4.3/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-resty/resty/v2 v2.13.1 h1:x+LHXBI2nMB1vqndymf26quycC4aggYJ7DECYbiz03g=
|
||||
github.com/go-resty/resty/v2 v2.13.1/go.mod h1:GznXlLxkq6Nh4sU59rPmUw3VtgpO3aS96ORAI6Q7d+0=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss=
|
||||
github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
|
||||
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
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.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.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
|
||||
github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
|
||||
github.com/google/flatbuffers v25.2.10+incompatible h1:F3vclr7C3HpB1k9mxCGRMXq6FdUalZ6H/pNX4FP1v0Q=
|
||||
github.com/google/flatbuffers v25.2.10+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
|
||||
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.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o=
|
||||
github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw=
|
||||
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/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0=
|
||||
github.com/googleapis/gax-go/v2 v2.12.5 h1:8gw9KZK8TiVKB6q3zHY3SBzLnrGp6HQjyfYBYGmXdxA=
|
||||
github.com/googleapis/gax-go/v2 v2.12.5/go.mod h1:BUDKcWo+RaKq5SC9vVYL0wLADa3VcfswbOMMRmB9H3E=
|
||||
github.com/hashicorp/consul/api v1.29.4 h1:P6slzxDLBOxUSj3fWo2o65VuKtbtOXFi7TSSgtXutuE=
|
||||
github.com/hashicorp/consul/api v1.29.4/go.mod h1:HUlfw+l2Zy68ceJavv2zAyArl2fqhGWnMycyt56sBgg=
|
||||
github.com/hashicorp/consul/proto-public v0.6.2 h1:+DA/3g/IiKlJZb88NBn0ZgXrxJp2NlvCZdEyl+qxvL0=
|
||||
@@ -125,6 +199,8 @@ github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs=
|
||||
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
||||
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.5.0 h1:EtYPN8DpAURiapus508I4n9CzHs2W+8NZGbmmR/prTM=
|
||||
@@ -190,6 +266,8 @@ github.com/nats-io/nkeys v0.4.7 h1:RwNJbbIdYCoClSDNY7QVKZlyb/wfT6ugvFCiKy6vDvI=
|
||||
github.com/nats-io/nkeys v0.4.7/go.mod h1:kqXRgRDPlGy7nGaEDMuYzmiJCIAAWDK0IMBtDmGD0nc=
|
||||
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
|
||||
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
||||
github.com/oracle/oci-go-sdk/v65 v65.95.2 h1:0HJ0AgpLydp/DtvYrF2d4str2BjXOVAeNbuW7E07g94=
|
||||
github.com/oracle/oci-go-sdk/v65 v65.95.2/go.mod h1:u6XRPsw9tPziBh76K7GrrRXPa8P8W3BQeqJ6ZZt9VLA=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
|
||||
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
@@ -209,6 +287,7 @@ github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5Fsn
|
||||
github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
|
||||
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.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
|
||||
@@ -231,6 +310,8 @@ github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUt
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
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/sony/gobreaker v0.5.0 h1:dRCvqm0P490vZPmy7ppEk2qCnCieBooFJ+YoXGYB+yg=
|
||||
github.com/sony/gobreaker v0.5.0/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
|
||||
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.14.0 h1:9tH6MapGnn/j0eb0yIXiLjERO8RB6xIVZRDCX7PtqWA=
|
||||
@@ -243,12 +324,18 @@ github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4=
|
||||
github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4=
|
||||
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 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
||||
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.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||
@@ -262,18 +349,31 @@ github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
||||
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
|
||||
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4=
|
||||
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM=
|
||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM=
|
||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/zeebo/assert v1.1.0 h1:hU1L1vLTHsnO8x8c9KAR5GmM5QscxHg5RNU5z5qbUWY=
|
||||
github.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
|
||||
github.com/zeebo/blake3 v0.2.3 h1:TFoLXsjeXqRNFxSbk35Dk4YtszE/MQQGK10BH4ptoTg=
|
||||
github.com/zeebo/blake3 v0.2.3/go.mod h1:mjJjZpnsyIVtVgTOSpJ9vmRE4wgDeyt2HU3qXvvKCaQ=
|
||||
github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo=
|
||||
github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4=
|
||||
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
||||
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw=
|
||||
go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
|
||||
go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
|
||||
go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE=
|
||||
go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E=
|
||||
go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI=
|
||||
go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4=
|
||||
go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
|
||||
go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
@@ -285,31 +385,60 @@ go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||
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-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.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM=
|
||||
golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20250718183923-645b1fa84792 h1:R9PFI6EUdfVKgwKjZef7QIwGcBKu86OEFpJ9nUEP2l4=
|
||||
golang.org/x/exp v0.0.0-20250718183923-645b1fa84792/go.mod h1:A+z0yzpGtvnG90cToK5n2tu8UJVP2XUATh+r+sfOOOc=
|
||||
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/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/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-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-20201110031124-69a78807bb2b/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-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.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs=
|
||||
golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
|
||||
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
|
||||
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-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-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/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
|
||||
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
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-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-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=
|
||||
@@ -317,36 +446,87 @@ golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/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-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-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/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-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
|
||||
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
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.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
|
||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||
golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg=
|
||||
golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
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.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.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
|
||||
golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
|
||||
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.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-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.188.0 h1:51y8fJ/b1AaaBRJr4yWm96fPcuxSo0JcegXE3DaHQHw=
|
||||
google.golang.org/api v0.188.0/go.mod h1:VR0d+2SIiWOYG3r/jdm7adPW9hI2aRv9ETOSCQ9Beag=
|
||||
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-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250528174236-200df99c418a h1:SGktgSolFCo75dnHJF2yMvnns6jCmHFJ0vE4Vn2JKvQ=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250528174236-200df99c418a/go.mod h1:a77HrdMjoeKbnd2jmgcWdaS++ZLZAEq3orIOAEIKiVw=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250728155136-f173205681a0 h1:MAKi5q709QWfnkkpNQ0M12hYJ1+e8qYVDyowc4U1XZM=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250728155136-f173205681a0/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
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.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||
google.golang.org/grpc v1.74.2 h1:WoosgB65DlWVC9FqI82dGsZhWFNBSLjQ84bjROOpMu4=
|
||||
google.golang.org/grpc v1.74.2/go.mod h1:CtQ+BGjaAIXHs/5YS3i473GqwBBa1zGQNevxdeBEXrM=
|
||||
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.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
||||
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
@@ -358,5 +538,8 @@ 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.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/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=
|
||||
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=
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
# MPC Key Management with Lux KMS
|
||||
|
||||
This package provides secure key management for MPC nodes using Lux KMS, a secrets management platform.
|
||||
|
||||
## Overview
|
||||
|
||||
The KMS integration allows MPC nodes to:
|
||||
- Store MPC key shares securely in Lux KMS instead of local BadgerDB
|
||||
- Retrieve key shares on demand with proper authentication
|
||||
- Manage initiator keys and other sensitive data
|
||||
- Maintain encrypted backups of non-sensitive data locally
|
||||
|
||||
## Configuration
|
||||
|
||||
Add the following to your `config.yaml`:
|
||||
|
||||
```yaml
|
||||
kms:
|
||||
# For local Lux KMS instance
|
||||
site_url: "http://localhost:8080"
|
||||
|
||||
# For production Lux KMS
|
||||
# site_url: "https://kms.lux.network"
|
||||
|
||||
# Required settings
|
||||
project_id: "your-project-id"
|
||||
environment: "prod"
|
||||
secret_path: "/mpc"
|
||||
|
||||
# Authentication (choose one method)
|
||||
# Method 1: Service Token
|
||||
# Set KMS_TOKEN environment variable
|
||||
|
||||
# Method 2: Universal Auth (recommended)
|
||||
client_id: "your-client-id"
|
||||
client_secret: "your-client-secret"
|
||||
```
|
||||
|
||||
## Setup
|
||||
|
||||
1. **Local Lux KMS** (if using):
|
||||
```bash
|
||||
cd ~/work/lux/kms
|
||||
docker-compose -f docker-compose.dev.yml up -d
|
||||
```
|
||||
|
||||
2. **Create a Project** in Lux KMS:
|
||||
- Log in to Lux KMS dashboard
|
||||
- Create a new project for MPC
|
||||
- Note the project ID
|
||||
|
||||
3. **Set up Authentication**:
|
||||
|
||||
**Option A: Service Token (Quick Start)**
|
||||
```bash
|
||||
# In Lux KMS dashboard, create a service token
|
||||
export KMS_TOKEN="st.your-service-token"
|
||||
export KMS_PROJECT_ID="your-project-id"
|
||||
```
|
||||
|
||||
**Option B: Universal Auth (Production)**
|
||||
- Create a machine identity in Lux KMS
|
||||
- Get the client ID and client secret
|
||||
- Add to config.yaml
|
||||
|
||||
## Usage
|
||||
|
||||
The integration automatically activates when Lux KMS is configured. MPC nodes will:
|
||||
|
||||
1. Store new key shares in Lux KMS
|
||||
2. Keep only references in local BadgerDB
|
||||
3. Retrieve keys from Lux KMS when needed
|
||||
4. Fall back to local storage if Lux KMS is unavailable
|
||||
|
||||
## Testing
|
||||
|
||||
Run the test script to verify your setup:
|
||||
|
||||
```bash
|
||||
cd /Users/z/work/lux/mpc/scripts
|
||||
go run test-kms.go
|
||||
```
|
||||
|
||||
## Security Notes
|
||||
|
||||
- Never commit Lux KMS credentials to git
|
||||
- Use environment variables or secure config management
|
||||
- Enable audit logging in Lux KMS for compliance
|
||||
- Regularly rotate service tokens
|
||||
- Use Universal Auth with proper RBAC in production
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
┌─────────────┐ ┌──────────────┐ ┌────────────┐
|
||||
│ MPC Node │────▶│ KMS Wrapper │────▶│ Lux KMS │
|
||||
│ │ │ │ │ │
|
||||
│ BadgerDB │◀────│ (References)│ │ (Secrets) │
|
||||
└─────────────┘ └──────────────┘ └────────────┘
|
||||
```
|
||||
|
||||
- MPC nodes use the KMS-enabled kvstore wrapper
|
||||
- Sensitive keys are stored in Lux KMS
|
||||
- Local BadgerDB stores only references
|
||||
- Non-sensitive data remains in BadgerDB
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
1. **Connection Failed**: Check Lux KMS URL and network connectivity
|
||||
2. **Auth Failed**: Verify credentials and project access
|
||||
3. **Key Not Found**: Ensure correct environment and secret path
|
||||
4. **Fallback Active**: Check logs for Lux KMS errors
|
||||
|
||||
## Benefits
|
||||
|
||||
- **Central Key Management**: All MPC keys in one secure location
|
||||
- **Access Control**: Fine-grained permissions per node
|
||||
- **Audit Trail**: Complete history of key access
|
||||
- **Key Rotation**: Simplified key rotation procedures
|
||||
- **Compliance**: Meet security standards with proper KMS
|
||||
@@ -0,0 +1,113 @@
|
||||
package kms
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/luxfi/mpc/pkg/logger"
|
||||
)
|
||||
|
||||
// MPCKMSIntegration provides KMS integration for MPC nodes
|
||||
type MPCKMSIntegration struct {
|
||||
kms *KMS
|
||||
nodeID string
|
||||
}
|
||||
|
||||
// NewMPCKMSIntegration creates a new MPC KMS integration
|
||||
func NewMPCKMSIntegration(nodeID string, dataDir string) (*MPCKMSIntegration, error) {
|
||||
// Create KMS directory
|
||||
kmsDir := filepath.Join(dataDir, "kms")
|
||||
|
||||
// Derive master key from environment or generate one
|
||||
masterKeyStr := os.Getenv("MPC_KMS_MASTER_KEY")
|
||||
var masterKey []byte
|
||||
|
||||
if masterKeyStr == "" {
|
||||
// For production, this should be properly managed
|
||||
// For now, we'll use a deterministic key based on node ID
|
||||
logger.Warn("No MPC_KMS_MASTER_KEY provided, using deterministic key (NOT FOR PRODUCTION)")
|
||||
masterKey, _ = DeriveKeyFromPassword(fmt.Sprintf("mpc-node-%s-default-key", nodeID), []byte(nodeID))
|
||||
} else {
|
||||
var err error
|
||||
masterKey, err = base64.StdEncoding.DecodeString(masterKeyStr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid MPC_KMS_MASTER_KEY: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
kms, err := NewKMS(kmsDir, masterKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to initialize KMS: %w", err)
|
||||
}
|
||||
|
||||
return &MPCKMSIntegration{
|
||||
kms: kms,
|
||||
nodeID: nodeID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// StoreMPCKeyShare stores an MPC key share
|
||||
func (m *MPCKMSIntegration) StoreMPCKeyShare(walletID string, keyType string, share []byte) error {
|
||||
keyID := fmt.Sprintf("mpc-%s-%s-%s", m.nodeID, walletID, keyType)
|
||||
name := fmt.Sprintf("MPC Share for %s (%s)", walletID, keyType)
|
||||
description := fmt.Sprintf("MPC key share for wallet %s, key type %s, node %s", walletID, keyType, m.nodeID)
|
||||
|
||||
return m.kms.StoreKey(keyID, name, keyType, share, description)
|
||||
}
|
||||
|
||||
// RetrieveMPCKeyShare retrieves an MPC key share
|
||||
func (m *MPCKMSIntegration) RetrieveMPCKeyShare(walletID string, keyType string) ([]byte, error) {
|
||||
keyID := fmt.Sprintf("mpc-%s-%s-%s", m.nodeID, walletID, keyType)
|
||||
return m.kms.RetrieveKey(keyID)
|
||||
}
|
||||
|
||||
// StoreInitiatorKey stores the initiator private key
|
||||
func (m *MPCKMSIntegration) StoreInitiatorKey(privateKey []byte) error {
|
||||
keyID := fmt.Sprintf("initiator-%s", m.nodeID)
|
||||
name := fmt.Sprintf("Initiator Key for %s", m.nodeID)
|
||||
description := fmt.Sprintf("Ed25519 initiator private key for node %s", m.nodeID)
|
||||
|
||||
return m.kms.StoreKey(keyID, name, "ed25519", privateKey, description)
|
||||
}
|
||||
|
||||
// RetrieveInitiatorKey retrieves the initiator private key
|
||||
func (m *MPCKMSIntegration) RetrieveInitiatorKey() ([]byte, error) {
|
||||
keyID := fmt.Sprintf("initiator-%s", m.nodeID)
|
||||
return m.kms.RetrieveKey(keyID)
|
||||
}
|
||||
|
||||
// StoreNodePrivateKey stores the node's P2P private key
|
||||
func (m *MPCKMSIntegration) StoreNodePrivateKey(privateKey []byte) error {
|
||||
keyID := fmt.Sprintf("node-p2p-%s", m.nodeID)
|
||||
name := fmt.Sprintf("P2P Key for %s", m.nodeID)
|
||||
description := fmt.Sprintf("P2P communication private key for node %s", m.nodeID)
|
||||
|
||||
return m.kms.StoreKey(keyID, name, "ecdsa", privateKey, description)
|
||||
}
|
||||
|
||||
// RetrieveNodePrivateKey retrieves the node's P2P private key
|
||||
func (m *MPCKMSIntegration) RetrieveNodePrivateKey() ([]byte, error) {
|
||||
keyID := fmt.Sprintf("node-p2p-%s", m.nodeID)
|
||||
return m.kms.RetrieveKey(keyID)
|
||||
}
|
||||
|
||||
// ListStoredKeys lists all keys stored for this node
|
||||
func (m *MPCKMSIntegration) ListStoredKeys() []EncryptedKey {
|
||||
return m.kms.ListKeys()
|
||||
}
|
||||
|
||||
// BackupKeys creates an encrypted backup of all keys
|
||||
func (m *MPCKMSIntegration) BackupKeys(backupPath string, backupPassword string) error {
|
||||
// This would implement a secure backup mechanism
|
||||
// For now, we'll leave it as a placeholder
|
||||
return fmt.Errorf("backup not yet implemented")
|
||||
}
|
||||
|
||||
// RestoreKeys restores keys from an encrypted backup
|
||||
func (m *MPCKMSIntegration) RestoreKeys(backupPath string, backupPassword string) error {
|
||||
// This would implement a secure restore mechanism
|
||||
// For now, we'll leave it as a placeholder
|
||||
return fmt.Errorf("restore not yet implemented")
|
||||
}
|
||||
+266
@@ -0,0 +1,266 @@
|
||||
package kms
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"golang.org/x/crypto/argon2"
|
||||
"golang.org/x/crypto/scrypt"
|
||||
)
|
||||
|
||||
// KMS represents a simple Key Management System
|
||||
type KMS struct {
|
||||
mu sync.RWMutex
|
||||
masterKey []byte
|
||||
storagePath string
|
||||
keys map[string]*EncryptedKey
|
||||
}
|
||||
|
||||
// EncryptedKey represents an encrypted key in storage
|
||||
type EncryptedKey struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
Encrypted string `json:"encrypted"`
|
||||
Salt string `json:"salt"`
|
||||
Nonce string `json:"nonce"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
// NewKMS creates a new KMS instance
|
||||
func NewKMS(storagePath string, masterKey []byte) (*KMS, error) {
|
||||
if len(masterKey) < 32 {
|
||||
return nil, fmt.Errorf("master key must be at least 32 bytes")
|
||||
}
|
||||
|
||||
kms := &KMS{
|
||||
storagePath: storagePath,
|
||||
masterKey: masterKey,
|
||||
keys: make(map[string]*EncryptedKey),
|
||||
}
|
||||
|
||||
// Create storage directory if it doesn't exist
|
||||
if err := os.MkdirAll(storagePath, 0700); err != nil {
|
||||
return nil, fmt.Errorf("failed to create KMS storage directory: %w", err)
|
||||
}
|
||||
|
||||
// Load existing keys
|
||||
if err := kms.loadKeys(); err != nil {
|
||||
return nil, fmt.Errorf("failed to load existing keys: %w", err)
|
||||
}
|
||||
|
||||
return kms, nil
|
||||
}
|
||||
|
||||
// StoreKey encrypts and stores a key
|
||||
func (k *KMS) StoreKey(id, name, keyType string, keyData []byte, description string) error {
|
||||
k.mu.Lock()
|
||||
defer k.mu.Unlock()
|
||||
|
||||
// Generate salt for key derivation
|
||||
salt := make([]byte, 32)
|
||||
if _, err := io.ReadFull(rand.Reader, salt); err != nil {
|
||||
return fmt.Errorf("failed to generate salt: %w", err)
|
||||
}
|
||||
|
||||
// Derive encryption key using Argon2
|
||||
encKey := argon2.IDKey(k.masterKey, salt, 1, 64*1024, 4, 32)
|
||||
|
||||
// Create AES-GCM cipher
|
||||
block, err := aes.NewCipher(encKey)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create cipher: %w", err)
|
||||
}
|
||||
|
||||
gcm, err := cipher.NewGCM(block)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create GCM: %w", err)
|
||||
}
|
||||
|
||||
// Generate nonce
|
||||
nonce := make([]byte, gcm.NonceSize())
|
||||
if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
|
||||
return fmt.Errorf("failed to generate nonce: %w", err)
|
||||
}
|
||||
|
||||
// Encrypt the key data
|
||||
ciphertext := gcm.Seal(nil, nonce, keyData, nil)
|
||||
|
||||
// Create encrypted key entry
|
||||
encryptedKey := &EncryptedKey{
|
||||
ID: id,
|
||||
Name: name,
|
||||
Type: keyType,
|
||||
Encrypted: base64.StdEncoding.EncodeToString(ciphertext),
|
||||
Salt: base64.StdEncoding.EncodeToString(salt),
|
||||
Nonce: base64.StdEncoding.EncodeToString(nonce),
|
||||
CreatedAt: time.Now().UTC().Format(time.RFC3339),
|
||||
Description: description,
|
||||
}
|
||||
|
||||
// Store in memory
|
||||
k.keys[id] = encryptedKey
|
||||
|
||||
// Persist to disk
|
||||
return k.saveKey(encryptedKey)
|
||||
}
|
||||
|
||||
// RetrieveKey decrypts and retrieves a key
|
||||
func (k *KMS) RetrieveKey(id string) ([]byte, error) {
|
||||
k.mu.RLock()
|
||||
defer k.mu.RUnlock()
|
||||
|
||||
encKey, exists := k.keys[id]
|
||||
if !exists {
|
||||
return nil, fmt.Errorf("key not found: %s", id)
|
||||
}
|
||||
|
||||
// Decode from base64
|
||||
salt, err := base64.StdEncoding.DecodeString(encKey.Salt)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode salt: %w", err)
|
||||
}
|
||||
|
||||
nonce, err := base64.StdEncoding.DecodeString(encKey.Nonce)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode nonce: %w", err)
|
||||
}
|
||||
|
||||
ciphertext, err := base64.StdEncoding.DecodeString(encKey.Encrypted)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode ciphertext: %w", err)
|
||||
}
|
||||
|
||||
// Derive decryption key
|
||||
decKey := argon2.IDKey(k.masterKey, salt, 1, 64*1024, 4, 32)
|
||||
|
||||
// Create AES-GCM cipher
|
||||
block, err := aes.NewCipher(decKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create cipher: %w", err)
|
||||
}
|
||||
|
||||
gcm, err := cipher.NewGCM(block)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create GCM: %w", err)
|
||||
}
|
||||
|
||||
// Decrypt
|
||||
plaintext, err := gcm.Open(nil, nonce, ciphertext, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decrypt key: %w", err)
|
||||
}
|
||||
|
||||
return plaintext, nil
|
||||
}
|
||||
|
||||
// ListKeys returns a list of all stored keys (without the actual key data)
|
||||
func (k *KMS) ListKeys() []EncryptedKey {
|
||||
k.mu.RLock()
|
||||
defer k.mu.RUnlock()
|
||||
|
||||
keys := make([]EncryptedKey, 0, len(k.keys))
|
||||
for _, key := range k.keys {
|
||||
// Create a copy without sensitive data
|
||||
keyCopy := EncryptedKey{
|
||||
ID: key.ID,
|
||||
Name: key.Name,
|
||||
Type: key.Type,
|
||||
CreatedAt: key.CreatedAt,
|
||||
Description: key.Description,
|
||||
}
|
||||
keys = append(keys, keyCopy)
|
||||
}
|
||||
return keys
|
||||
}
|
||||
|
||||
// DeleteKey removes a key from storage
|
||||
func (k *KMS) DeleteKey(id string) error {
|
||||
k.mu.Lock()
|
||||
defer k.mu.Unlock()
|
||||
|
||||
if _, exists := k.keys[id]; !exists {
|
||||
return fmt.Errorf("key not found: %s", id)
|
||||
}
|
||||
|
||||
// Remove from memory
|
||||
delete(k.keys, id)
|
||||
|
||||
// Remove from disk
|
||||
keyPath := filepath.Join(k.storagePath, fmt.Sprintf("%s.json", id))
|
||||
return os.Remove(keyPath)
|
||||
}
|
||||
|
||||
// loadKeys loads all encrypted keys from storage
|
||||
func (k *KMS) loadKeys() error {
|
||||
files, err := os.ReadDir(k.storagePath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read KMS storage directory: %w", err)
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
if filepath.Ext(file.Name()) != ".json" {
|
||||
continue
|
||||
}
|
||||
|
||||
keyPath := filepath.Join(k.storagePath, file.Name())
|
||||
data, err := os.ReadFile(keyPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read key file %s: %w", file.Name(), err)
|
||||
}
|
||||
|
||||
var encKey EncryptedKey
|
||||
if err := json.Unmarshal(data, &encKey); err != nil {
|
||||
return fmt.Errorf("failed to unmarshal key file %s: %w", file.Name(), err)
|
||||
}
|
||||
|
||||
k.keys[encKey.ID] = &encKey
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// saveKey persists an encrypted key to disk
|
||||
func (k *KMS) saveKey(encKey *EncryptedKey) error {
|
||||
data, err := json.MarshalIndent(encKey, "", " ")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal key: %w", err)
|
||||
}
|
||||
|
||||
keyPath := filepath.Join(k.storagePath, fmt.Sprintf("%s.json", encKey.ID))
|
||||
return os.WriteFile(keyPath, data, 0600)
|
||||
}
|
||||
|
||||
// DeriveKeyFromPassword derives a key from a password using scrypt
|
||||
func DeriveKeyFromPassword(password string, salt []byte) ([]byte, error) {
|
||||
if len(salt) == 0 {
|
||||
salt = make([]byte, 32)
|
||||
if _, err := io.ReadFull(rand.Reader, salt); err != nil {
|
||||
return nil, fmt.Errorf("failed to generate salt: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
key, err := scrypt.Key([]byte(password), salt, 32768, 8, 1, 32)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to derive key: %w", err)
|
||||
}
|
||||
|
||||
return key, nil
|
||||
}
|
||||
|
||||
// HashKey creates a SHA256 hash of a key for identification
|
||||
func HashKey(key []byte) string {
|
||||
hash := sha256.Sum256(key)
|
||||
return base64.StdEncoding.EncodeToString(hash[:])
|
||||
}
|
||||
@@ -0,0 +1,250 @@
|
||||
package kms
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
kmsgo "github.com/luxfi/kms-go"
|
||||
kmsmodels "github.com/luxfi/kms-go/packages/models"
|
||||
"github.com/luxfi/mpc/pkg/logger"
|
||||
)
|
||||
|
||||
// KMSClient wraps the Lux KMS SDK for MPC key management
|
||||
type KMSClient struct {
|
||||
client kmsgo.KMSClientInterface
|
||||
projectID string
|
||||
environment string
|
||||
secretPath string
|
||||
siteURL string
|
||||
}
|
||||
|
||||
// KMSConfig holds configuration for Lux KMS integration
|
||||
type KMSConfig struct {
|
||||
ClientID string
|
||||
ClientSecret string
|
||||
ProjectID string
|
||||
Environment string
|
||||
SecretPath string
|
||||
SiteURL string
|
||||
}
|
||||
|
||||
// NewKMSClient creates a new Lux KMS client for secure key operations
|
||||
func NewKMSClient(config KMSConfig) (*KMSClient, error) {
|
||||
// Validate config
|
||||
if config.ProjectID == "" {
|
||||
return nil, fmt.Errorf("project ID is required")
|
||||
}
|
||||
|
||||
// Set defaults
|
||||
if config.Environment == "" {
|
||||
config.Environment = "prod"
|
||||
}
|
||||
if config.SecretPath == "" {
|
||||
config.SecretPath = "/mpc"
|
||||
}
|
||||
if config.SiteURL == "" {
|
||||
// Check if running locally
|
||||
if _, err := os.Stat("/Users/z/work/lux/kms"); err == nil {
|
||||
config.SiteURL = "http://localhost:8080" // Local Lux KMS instance
|
||||
} else {
|
||||
config.SiteURL = "https://kms.lux.network"
|
||||
}
|
||||
}
|
||||
|
||||
// Create KMS client configuration
|
||||
kmsConfig := kmsgo.Config{
|
||||
SiteUrl: config.SiteURL,
|
||||
}
|
||||
|
||||
// Create client in a separate context
|
||||
ctx := context.Background()
|
||||
client := kmsgo.NewKMSClient(ctx, kmsConfig)
|
||||
|
||||
// Authenticate based on available credentials
|
||||
if config.ClientID != "" && config.ClientSecret != "" {
|
||||
// Use Universal Auth (machine identity)
|
||||
auth := client.Auth()
|
||||
_, err := auth.UniversalAuthLogin(config.ClientID, config.ClientSecret)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to authenticate with universal auth: %w", err)
|
||||
}
|
||||
} else {
|
||||
// Use access token auth (fallback)
|
||||
accessToken := os.Getenv("KMS_ACCESS_TOKEN")
|
||||
if accessToken == "" {
|
||||
return nil, fmt.Errorf("no authentication method available: set KMS_ACCESS_TOKEN or provide universal auth credentials")
|
||||
}
|
||||
auth := client.Auth()
|
||||
auth.SetAccessToken(accessToken)
|
||||
}
|
||||
|
||||
return &KMSClient{
|
||||
client: client,
|
||||
projectID: config.ProjectID,
|
||||
environment: config.Environment,
|
||||
secretPath: config.SecretPath,
|
||||
siteURL: config.SiteURL,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// StoreMPCKeyShare stores an MPC key share in Lux KMS
|
||||
func (c *KMSClient) StoreMPCKeyShare(nodeID, walletID, keyType string, keyShare []byte) error {
|
||||
secretName := fmt.Sprintf("mpc_%s_%s_%s", nodeID, walletID, keyType)
|
||||
|
||||
// Convert key share to JSON string for storage
|
||||
keyShareJSON, err := json.Marshal(keyShare)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal key share: %w", err)
|
||||
}
|
||||
|
||||
_, err = c.client.Secrets().Create(kmsgo.CreateSecretOptions{
|
||||
ProjectId: c.projectID,
|
||||
Environment: c.environment,
|
||||
SecretPath: c.secretPath,
|
||||
SecretKey: secretName,
|
||||
SecretValue: string(keyShareJSON),
|
||||
SecretComment: fmt.Sprintf("MPC key share for node %s, wallet %s, type %s", nodeID, walletID, keyType),
|
||||
SecretType: "shared",
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
// Try to update if already exists
|
||||
_, updateErr := c.client.Secrets().Update(kmsgo.UpdateSecretOptions{
|
||||
ProjectId: c.projectID,
|
||||
Environment: c.environment,
|
||||
SecretPath: c.secretPath,
|
||||
SecretKey: secretName,
|
||||
SecretValue: string(keyShareJSON),
|
||||
SecretType: "shared",
|
||||
})
|
||||
if updateErr != nil {
|
||||
return fmt.Errorf("failed to create/update secret: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
logger.Info("Stored MPC key share in Lux KMS", "nodeID", nodeID, "walletID", walletID, "keyType", keyType)
|
||||
return nil
|
||||
}
|
||||
|
||||
// RetrieveMPCKeyShare retrieves an MPC key share from Lux KMS
|
||||
func (c *KMSClient) RetrieveMPCKeyShare(nodeID, walletID, keyType string) ([]byte, error) {
|
||||
secretName := fmt.Sprintf("mpc_%s_%s_%s", nodeID, walletID, keyType)
|
||||
|
||||
secret, err := c.client.Secrets().Retrieve(kmsgo.RetrieveSecretOptions{
|
||||
ProjectId: c.projectID,
|
||||
Environment: c.environment,
|
||||
SecretPath: c.secretPath,
|
||||
SecretKey: secretName,
|
||||
SecretType: "shared",
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to retrieve secret: %w", err)
|
||||
}
|
||||
|
||||
// Parse JSON key share
|
||||
var keyShare []byte
|
||||
if err := json.Unmarshal([]byte(secret.SecretValue), &keyShare); err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal key share: %w", err)
|
||||
}
|
||||
|
||||
return keyShare, nil
|
||||
}
|
||||
|
||||
// StoreInitiatorKey stores the initiator private key in Lux KMS
|
||||
func (c *KMSClient) StoreInitiatorKey(nodeID string, privateKey []byte) error {
|
||||
secretName := fmt.Sprintf("initiator_key_%s", nodeID)
|
||||
|
||||
_, err := c.client.Secrets().Create(kmsgo.CreateSecretOptions{
|
||||
ProjectId: c.projectID,
|
||||
Environment: c.environment,
|
||||
SecretPath: c.secretPath,
|
||||
SecretKey: secretName,
|
||||
SecretValue: fmt.Sprintf("%x", privateKey),
|
||||
SecretComment: fmt.Sprintf("Initiator private key for node %s", nodeID),
|
||||
SecretType: "shared",
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
// Try to update if already exists
|
||||
_, updateErr := c.client.Secrets().Update(kmsgo.UpdateSecretOptions{
|
||||
ProjectId: c.projectID,
|
||||
Environment: c.environment,
|
||||
SecretPath: c.secretPath,
|
||||
SecretKey: secretName,
|
||||
SecretValue: fmt.Sprintf("%x", privateKey),
|
||||
SecretType: "shared",
|
||||
})
|
||||
if updateErr != nil {
|
||||
return fmt.Errorf("failed to create/update initiator key: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RetrieveInitiatorKey retrieves the initiator private key from Lux KMS
|
||||
func (c *KMSClient) RetrieveInitiatorKey(nodeID string) ([]byte, error) {
|
||||
secretName := fmt.Sprintf("initiator_key_%s", nodeID)
|
||||
|
||||
secret, err := c.client.Secrets().Retrieve(kmsgo.RetrieveSecretOptions{
|
||||
ProjectId: c.projectID,
|
||||
Environment: c.environment,
|
||||
SecretPath: c.secretPath,
|
||||
SecretKey: secretName,
|
||||
SecretType: "shared",
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to retrieve initiator key: %w", err)
|
||||
}
|
||||
|
||||
// Parse hex string back to bytes
|
||||
var privateKey []byte
|
||||
if _, err := fmt.Sscanf(secret.SecretValue, "%x", &privateKey); err != nil {
|
||||
return nil, fmt.Errorf("failed to parse initiator key: %w", err)
|
||||
}
|
||||
|
||||
return privateKey, nil
|
||||
}
|
||||
|
||||
// ListKeys lists all MPC-related keys in Lux KMS
|
||||
func (c *KMSClient) ListKeys() ([]string, error) {
|
||||
secrets, err := c.client.Secrets().List(kmsgo.ListSecretsOptions{
|
||||
ProjectId: c.projectID,
|
||||
Environment: c.environment,
|
||||
SecretPath: c.secretPath,
|
||||
IncludeImports: false,
|
||||
AttachToProcessEnv: false,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to list secrets: %w", err)
|
||||
}
|
||||
|
||||
var keys []string
|
||||
for _, secret := range secrets {
|
||||
keys = append(keys, secret.SecretKey)
|
||||
}
|
||||
|
||||
return keys, nil
|
||||
}
|
||||
|
||||
// DeleteKey deletes a key from Lux KMS
|
||||
func (c *KMSClient) DeleteKey(secretName string) error {
|
||||
_, err := c.client.Secrets().Delete(kmsgo.DeleteSecretOptions{
|
||||
ProjectId: c.projectID,
|
||||
Environment: c.environment,
|
||||
SecretPath: c.secretPath,
|
||||
SecretKey: secretName,
|
||||
SecretType: "shared",
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to delete secret: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
package mpc
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/luxfi/mpc/pkg/kms"
|
||||
"github.com/luxfi/mpc/pkg/kvstore"
|
||||
"github.com/luxfi/mpc/pkg/logger"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
// KMSEnabledKVStore wraps a regular KVStore with KMS encryption
|
||||
type KMSEnabledKVStore struct {
|
||||
kvstore.KVStore
|
||||
kmsClient *kms.KMSClient
|
||||
enabled bool
|
||||
nodeID string
|
||||
}
|
||||
|
||||
// NewKMSEnabledKVStore creates a new KMS-enabled KV store
|
||||
func NewKMSEnabledKVStore(store kvstore.KVStore, nodeID string) (*KMSEnabledKVStore, error) {
|
||||
// Try to initialize Lux KMS integration
|
||||
kmsConfig := kms.KMSConfig{
|
||||
ClientID: viper.GetString("kms.client_id"),
|
||||
ClientSecret: viper.GetString("kms.client_secret"),
|
||||
ProjectID: viper.GetString("kms.project_id"),
|
||||
Environment: viper.GetString("kms.environment"),
|
||||
SecretPath: viper.GetString("kms.secret_path"),
|
||||
SiteURL: viper.GetString("kms.site_url"),
|
||||
}
|
||||
|
||||
// If no project ID is set, check environment variable
|
||||
if kmsConfig.ProjectID == "" {
|
||||
kmsConfig.ProjectID = os.Getenv("KMS_PROJECT_ID")
|
||||
}
|
||||
|
||||
// If still no project ID, disable KMS
|
||||
if kmsConfig.ProjectID == "" {
|
||||
logger.Warn("No Lux KMS project ID configured, falling back to regular storage")
|
||||
return &KMSEnabledKVStore{
|
||||
KVStore: store,
|
||||
enabled: false,
|
||||
}, nil
|
||||
}
|
||||
|
||||
kmsClient, err := kms.NewKMSClient(kmsConfig)
|
||||
if err != nil {
|
||||
logger.Warn("Failed to initialize Lux KMS integration, falling back to regular storage", "error", err)
|
||||
return &KMSEnabledKVStore{
|
||||
KVStore: store,
|
||||
enabled: false,
|
||||
}, nil
|
||||
}
|
||||
|
||||
logger.Info("Lux KMS integration enabled for secure key storage")
|
||||
return &KMSEnabledKVStore{
|
||||
KVStore: store,
|
||||
kmsClient: kmsClient,
|
||||
enabled: true,
|
||||
nodeID: nodeID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Put stores a value with KMS encryption if enabled
|
||||
func (k *KMSEnabledKVStore) Put(key string, value []byte) error {
|
||||
if !k.enabled {
|
||||
// Fallback to regular storage
|
||||
return k.KVStore.Put(key, value)
|
||||
}
|
||||
|
||||
// For MPC key shares, use KMS
|
||||
if isKeyShare(key) {
|
||||
// Detect key type from the share data
|
||||
keyType := "ecdsa" // Default
|
||||
|
||||
// Try to parse the share to determine type
|
||||
var shareData map[string]interface{}
|
||||
if err := json.Unmarshal(value, &shareData); err == nil {
|
||||
if _, hasEDDSA := shareData["eddsa"]; hasEDDSA {
|
||||
keyType = "eddsa"
|
||||
}
|
||||
}
|
||||
|
||||
// Store in Lux KMS
|
||||
if err := k.kmsClient.StoreMPCKeyShare(k.nodeID, key, keyType, value); err != nil {
|
||||
logger.Error("Failed to store key share in Lux KMS", err, "walletID", key)
|
||||
// Fallback to regular storage
|
||||
return k.KVStore.Put(key, value)
|
||||
}
|
||||
|
||||
// Store a reference in regular KVStore
|
||||
reference := map[string]string{
|
||||
"storage": "kms",
|
||||
"wallet": key,
|
||||
"type": keyType,
|
||||
}
|
||||
refData, _ := json.Marshal(reference)
|
||||
return k.KVStore.Put(key, refData)
|
||||
}
|
||||
|
||||
// For non-key data, use regular storage
|
||||
return k.KVStore.Put(key, value)
|
||||
}
|
||||
|
||||
// Get retrieves a value with KMS decryption if needed
|
||||
func (k *KMSEnabledKVStore) Get(key string) ([]byte, error) {
|
||||
if !k.enabled {
|
||||
// Fallback to regular storage
|
||||
return k.KVStore.Get(key)
|
||||
}
|
||||
|
||||
// First, get from regular storage
|
||||
data, err := k.KVStore.Get(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Check if this is a KMS reference
|
||||
var reference map[string]string
|
||||
if err := json.Unmarshal(data, &reference); err == nil {
|
||||
if reference["storage"] == "kms" {
|
||||
// Retrieve from Lux KMS
|
||||
keyType := reference["type"]
|
||||
if keyType == "" {
|
||||
keyType = "ecdsa"
|
||||
}
|
||||
|
||||
share, err := k.kmsClient.RetrieveMPCKeyShare(k.nodeID, key, keyType)
|
||||
if err != nil {
|
||||
logger.Error("Failed to retrieve key share from Lux KMS", err, "walletID", key)
|
||||
return nil, fmt.Errorf("failed to retrieve from Lux KMS: %w", err)
|
||||
}
|
||||
return share, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Regular data, return as-is
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// Delete removes a value and its KMS entry if applicable
|
||||
func (k *KMSEnabledKVStore) Delete(key string) error {
|
||||
if k.enabled {
|
||||
// Try to get the reference first
|
||||
data, err := k.KVStore.Get(key)
|
||||
if err == nil {
|
||||
var reference map[string]string
|
||||
if err := json.Unmarshal(data, &reference); err == nil {
|
||||
if reference["storage"] == "kms" {
|
||||
// Delete from Lux KMS
|
||||
keyType := reference["type"]
|
||||
if keyType == "" {
|
||||
keyType = "ecdsa"
|
||||
}
|
||||
secretName := fmt.Sprintf("mpc_%s_%s_%s", k.nodeID, key, keyType)
|
||||
if err := k.kmsClient.DeleteKey(secretName); err != nil {
|
||||
logger.Warn("Failed to delete key from Lux KMS", "error", err, "secretName", secretName)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Delete from regular storage
|
||||
return k.KVStore.Delete(key)
|
||||
}
|
||||
|
||||
// isKeyShare checks if a key represents an MPC key share
|
||||
func isKeyShare(key string) bool {
|
||||
// In the MPC system, wallet IDs are used as keys for storing shares
|
||||
// You might want to add more sophisticated detection logic here
|
||||
return true // For now, treat all keys as potential key shares
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/luxfi/mpc/pkg/kms"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Initialize viper config
|
||||
viper.SetConfigName("config")
|
||||
viper.SetConfigType("yaml")
|
||||
viper.AddConfigPath("..")
|
||||
viper.AutomaticEnv()
|
||||
|
||||
if err := viper.ReadInConfig(); err != nil {
|
||||
log.Printf("Warning: Could not read config file: %v", err)
|
||||
}
|
||||
|
||||
// Create Lux KMS client
|
||||
config := kms.KMSConfig{
|
||||
ClientID: viper.GetString("kms.client_id"),
|
||||
ClientSecret: viper.GetString("kms.client_secret"),
|
||||
ProjectID: viper.GetString("kms.project_id"),
|
||||
Environment: viper.GetString("kms.environment"),
|
||||
SecretPath: viper.GetString("kms.secret_path"),
|
||||
SiteURL: viper.GetString("kms.site_url"),
|
||||
}
|
||||
|
||||
// Check environment variable fallback
|
||||
if config.ProjectID == "" {
|
||||
config.ProjectID = os.Getenv("KMS_PROJECT_ID")
|
||||
}
|
||||
|
||||
fmt.Printf("Lux KMS Configuration:\n")
|
||||
fmt.Printf(" Site URL: %s\n", config.SiteURL)
|
||||
fmt.Printf(" Project ID: %s\n", config.ProjectID)
|
||||
fmt.Printf(" Environment: %s\n", config.Environment)
|
||||
fmt.Printf(" Secret Path: %s\n", config.SecretPath)
|
||||
fmt.Printf(" Has Universal Auth: %v\n", config.ClientID != "")
|
||||
fmt.Printf(" Has Service Token: %v\n", os.Getenv("KMS_TOKEN") != "")
|
||||
|
||||
client, err := kms.NewKMSClient(config)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to create Lux KMS client: %v", err)
|
||||
}
|
||||
|
||||
fmt.Println("\n✅ Successfully connected to Lux KMS!")
|
||||
|
||||
// Test storing a dummy key share
|
||||
testNodeID := "test-node"
|
||||
testWalletID := "test-wallet"
|
||||
testKeyType := "ecdsa"
|
||||
testKeyData := []byte(`{"test": "data", "key": "12345"}`)
|
||||
|
||||
fmt.Printf("\nTesting key storage...\n")
|
||||
if err := client.StoreMPCKeyShare(testNodeID, testWalletID, testKeyType, testKeyData); err != nil {
|
||||
log.Fatalf("Failed to store test key: %v", err)
|
||||
}
|
||||
fmt.Println("✅ Successfully stored test key!")
|
||||
|
||||
// Test retrieving the key
|
||||
fmt.Printf("\nTesting key retrieval...\n")
|
||||
retrievedData, err := client.RetrieveMPCKeyShare(testNodeID, testWalletID, testKeyType)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to retrieve test key: %v", err)
|
||||
}
|
||||
|
||||
if string(retrievedData) == string(testKeyData) {
|
||||
fmt.Println("✅ Successfully retrieved test key with correct data!")
|
||||
} else {
|
||||
fmt.Printf("⚠️ Retrieved data doesn't match: got %s, want %s\n", string(retrievedData), string(testKeyData))
|
||||
}
|
||||
|
||||
// List all keys
|
||||
fmt.Printf("\nListing all keys...\n")
|
||||
keys, err := client.ListKeys()
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to list keys: %v", err)
|
||||
}
|
||||
|
||||
fmt.Printf("Found %d keys:\n", len(keys))
|
||||
for _, key := range keys {
|
||||
fmt.Printf(" - %s\n", key)
|
||||
}
|
||||
|
||||
// Clean up test key
|
||||
fmt.Printf("\nCleaning up test key...\n")
|
||||
secretName := fmt.Sprintf("mpc_%s_%s_%s", testNodeID, testWalletID, testKeyType)
|
||||
if err := client.DeleteKey(secretName); err != nil {
|
||||
log.Printf("Warning: Failed to delete test key: %v", err)
|
||||
} else {
|
||||
fmt.Println("✅ Successfully cleaned up test key!")
|
||||
}
|
||||
|
||||
fmt.Println("\n🎉 All tests passed! Lux KMS integration is working correctly.")
|
||||
}
|
||||
Reference in New Issue
Block a user